PHP:iPad 不能播放由 PHP 提供的 MP4 视频,但如果直接访问它可以

时间:2022-11-29
本文介绍了PHP:iPad 不能播放由 PHP 提供的 MP4 视频,但如果直接访问它可以的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我已经尝试为这个问题寻找解决方案好几天了,我尝试了所有可以在 stackoverflow 和其他平台上找到的建议.仍然没有解决方案.

我正在通过 HTML5 视频标签嵌入视频:

 

我尝试通过 PHP 提供 MP4 视频文件,而不是直接链接它.直接链接mp4文件即可播放文件!

测试:

  1. 视频文件::

    、.


    **2.第二个问题**

    在生产环境中,我总是使用 PHP 来检查引用者.正如我发现的,iPad 不会发送推荐人信息.这也会阻止流式传输,您还会看到无法播放符号(带删除线的播放图标).


    **3.第三个问题**

    我不知道为什么,但 iPad 只接受来自这个脚本的视频流http://ideone.com/NPSlw5

    我希望这些信息能帮助其他人解决问题.


    更新:三个月后,在生产环境中,我的一些用户仍然报告播放问题.Safari 似乎还有另一个问题.我建议他们使用 Chrome for iPad,这就解决了.



    PS:几天的研究和麻烦只是为了播放一个视频文件,顺便说一下,它可以在所有其他设备上运行.这再次向我证明,Apple 的成功只是因为出色的营销,而不是因为出色的软件.

    I am trying to find a solution for this problem for some days already, I tried all advices I could find here on stackoverflow and other platforms. And still, there is no solution.

    I am embedding a video via HTML5 video tag:

     <video poster="thumb.png" controls="controls" preload="none" width="640" height="480">
        <source src="provider.php?secure=12345" type="video/mp4">
     </video>
    

    I try to deliver the MP4 video file by PHP instead of linking it directly. Linking the mp4 file directly works and plays the file!

    Testing:

    1. the video file: https://github.com/q2apro/videotest-ipad/raw/master/video.mp4 (plays on iPad)
    2. the video file loaded by PHP with same headers: https://github.com/q2apro/videotest-ipad/blob/master/test-headers.php (not playing on iPad) - Sourcecode
    3. the video file loaded by PHP with Byte Ranges: https://github.com/q2apro/videotest-ipad/blob/master/test-byterange.php (not playing on iPad) - Sourcecode
    4. the video file loaded by PHP with Byte Ranges (another script): https://github.com/q2apro/videotest-ipad/blob/master/test-byterange-2.php (not playing on iPad, alert "The operation could not be completed") - Sourcecode

    Notes:

    • all links above are directly accessing/playing the video file without embed tag
    • video works on all browsers in Windows (but not in Safari/Chrome on iPad, probably not iPhone either)

    My Setup:

    • testing device: iPad iOS 6 (I don't have a mac, cannot debug)
    • iPad with Safari and Chrome (tried both browsers)
    • my server is shared-hosting from domainfactory
    • tool for debugging: Firefox 29 Web Developer Console / WIN7

    The .htaccess in the test folder sets the MIME type and Accept-Ranges:

    AddType video/mp4 .mp4 
    
    <IfModule mod_headers.c>
       Header set Accept-Ranges "bytes"
    </IfModule>
    


    Even though I created the same header (compare test URLs 1. and 2.), the iPad is not playing the file through the PHP request.

    Instead I always get this strikedthrough play button:

    The headers of 1. (direct mp4 call):

    The headers of 2. The same headers as above, but set up by PHP (mp4 delivered by PHP):

    --

    I have also tried reading the entire video file and sending it to the browser using PHP's fread(), fpassthru() and file_get_contents() but the iPad is always showing the cannot-play-icon.

    --

    My hosted server does not supply Connection keep-alive, could this be a problem? Is the iPad interpreting .php different from .mp4?

    Can somebody help me out of pain? I am totally stuck.



    PS: What I tried to consider:

    • Byte range requests (206 partial content) 01 02 03
    • correct video encoding 04
    • used other encoded videos while testing
    • disabled zlib.output_compression in php scripts



    UPDATE: Debug Console

    I finally got a MAC of a friend, connected the iPad, opened the Debug Console in Safari on the Mac, loaded the page on the iPad and checked the error messages appearing on the Mac (btw, how more complicated could apple force us to develop...). For all test scripts this error appears:

    Failed to load resource: Plug-in handled load
    

    解决方案

    Wow, that was tough!


    **1. First major Problem**

    It turned out to be no encoding problem but a problem with the mp4 container header set during the video conversion process - iPad has obviously a problem with MP4 videos that are prepared for progressive streaming.

    First I discovered that in a conversation here. After converting a video I always used the tool MP4 Fast Start to prepare the video file for progressive stream. This was necessary to stream the video file to the Flash Player in pieces (progressively), so it did not load the entire file (and the user had to wait).

    With Handbrake there is a similar setting, that is called Web Optimized. It does the same:

    Web Optimized
    Also known as "Fast Start"
    This places the container header at the start of the file, optimizing it for streaming across the web.
    

    If you enable this and convert your video, the iPad will not play the video file! Instead you get the error "The operation could not be completed".

    Check out and test it yourself: video test resources.


    **2. Second Problem**

    In production environment I always used PHP to check the referer. As I found out, the iPad does not send the referer information. This also prevents the streaming and you will also see the cannot-play-symbol (striked-through play icon).


    **3. Third Problem**

    I could not find out why, but the iPad only accepts the video streaming from this script http://ideone.com/NPSlw5

    <?php
    // disable zlib so that progress bar of player shows up correctly
    if(ini_get('zlib.output_compression')) {
        ini_set('zlib.output_compression', 'Off'); 
    }
    
    $folder = '.'; 
    $filename = 'video.mp4';
    $path = $folder.'/'.$filename;
    
    // from: http://licson.net/post/stream-videos-php/
    if (file_exists($path)) {
        // Clears the cache and prevent unwanted output
        ob_clean();
    
        $mime = "video/mp4"; // The MIME type of the file, this should be replaced with your own.
        $size = filesize($path); // The size of the file
    
        // Send the content type header
        header('Content-type: ' . $mime);
    
        // Check if it's a HTTP range request
        if(isset($_SERVER['HTTP_RANGE'])){
            // Parse the range header to get the byte offset
            $ranges = array_map(
                'intval', // Parse the parts into integer
                explode(
                    '-', // The range separator
                    substr($_SERVER['HTTP_RANGE'], 6) // Skip the `bytes=` part of the header
                )
            );
    
            // If the last range param is empty, it means the EOF (End of File)
            if(!$ranges[1]){
                $ranges[1] = $size - 1;
            }
    
            // Send the appropriate headers
            header('HTTP/1.1 206 Partial Content');
            header('Accept-Ranges: bytes');
            header('Content-Length: ' . ($ranges[1] - $ranges[0])); // The size of the range
    
            // Send the ranges we offered
            header(
                sprintf(
                    'Content-Range: bytes %d-%d/%d', // The header format
                    $ranges[0], // The start range
                    $ranges[1], // The end range
                    $size // Total size of the file
                )
            );
    
            // It's time to output the file
            $f = fopen($path, 'rb'); // Open the file in binary mode
            $chunkSize = 8192; // The size of each chunk to output
    
            // Seek to the requested start range
            fseek($f, $ranges[0]);
    
            // Start outputting the data
            while(true){
                // Check if we have outputted all the data requested
                if(ftell($f) >= $ranges[1]){
                    break;
                }
    
                // Output the data
                echo fread($f, $chunkSize);
    
                // Flush the buffer immediately
                @ob_flush();
                flush();
            }
        }
        else {
            // It's not a range request, output the file anyway
            header('Content-Length: ' . $size);
    
            // Read the file
            @readfile($path);
    
            // and flush the buffer
            @ob_flush();
            flush();
        }
    
    }
    die();
    
    ?>
    

    I hope this information will help others to cope with the problem.


    Update: Three months later in production environment, some of my users still reported playback issues. There seems to be another problem with Safari. I advised them to use Chrome for iPad, this fixed it.



    PS: A couple of days of research and hassle only to play a video file that, by the way, runs on all other devices. This again proves to me that Apple got successful just because of great marketing, not because of great software.

    这篇关于PHP:iPad 不能播放由 PHP 提供的 MP4 视频,但如果直接访问它可以的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:我的 PHP 登录系统有多安全? 下一篇:如何添加 Javascript 侦听器以捕获从蓝牙条码扫描器到 iPad 的输入?

相关文章

最新文章