duancongduo4109 2014-04-11 14:05
浏览 124
已采纳

通过PHP加载时,WebM文件在Chrome中无法搜索(其他浏览器工作)

I am having a mind-boggling problem, I just can't seem to resolve.

Providing a WebM file through PHP is nothing new in my world, and I even know how to work with HTTP 206 Partial Content. But for some reason Chrome does not like it.

A simple HTML5 video playback

<video width="640" height="360" poster="picture/preview/V00000006.jpg" controls="controls" preload>
    <source type="video/webm" src="/video/V00000006.webm">
</video>

where /video/V00000006.webm is rewritten to a PHP-file in Apache, will playback just fine. But in Chrome the seekbar is not effective. When clicking on the seekbar the player will freeze and no longer playback until page is refreshed. Firefox handles it just fine!

If I change /video/V00000006.webm to be a direct link to the same video it works just fine. I even compared the network requests between the two versions (with and without PHP) and there is barely any difference in the first request, but the second is failing in the PHP-delivered video.

Initial request and seek request for Apache-delivered video file:

    Request URL:http://mytestserver.net/movie1152x720.webm
    Request Method:GET
    Status Code:206 Partial Content
    Request Headers
    Accept:*/*
    Accept-Encoding:identity;q=1, *;q=0
    Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4
    Cache-Control:no-cache
    Connection:keep-alive
    Cookie:PHPSESSID=i562540rek172mnv3nk528acj0; userPassword=; userEmail=
    Host:mytestserver.net
    Pragma:no-cache
    Range:bytes=0-
    Referer:http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
    Response Headers
    Accept-Ranges:bytes
    Connection:close
    Content-Length:4446451
    Content-Range:bytes 0-4446450/4446451
    Content-Type:video/webm
    Date:Fri, 11 Apr 2014 13:07:30 GMT
    ETag:"d2d0027-43d8f3-b91417c0"
    Last-Modified:Fri, 11 Apr 2014 12:46:31 GMT
    Server:Apache/2.2.3 (CentOS)

    --

    Request URL:http://mytestserver.net/movie1152x720.webm
    Request Method:GET
    Status Code:206 Partial Content
    Request Headers
    Accept:*/*
    Accept-Encoding:identity;q=1, *;q=0
    Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4
    Cache-Control:no-cache
    Connection:keep-alive
    Cookie:PHPSESSID=i562540rek172mnv3nk528acj0; userPassword=; userEmail=
    Host:mytestserver.net
    Pragma:no-cache
    Range:bytes=4445881-
    Referer:http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
    Response Headers
    Accept-Ranges:bytes
    Connection:close
    Content-Length:570
    Content-Range:bytes 4445881-4446450/4446451
    Content-Type:video/webm
    Date:Fri, 11 Apr 2014 13:09:02 GMT
    ETag:"d2d0027-43d8f3-b91417c0"
    Last-Modified:Fri, 11 Apr 2014 12:46:31 GMT
    Server:Apache/2.2.3 (CentOS)

Initial request and seek request for PHP-streamed video:

    Request URL:http://mytestserver.net/video/V00000006.webm
    Request Method:GET
    Status Code:206 Partial Content
    Request Headers
    Accept:*/*
    Accept-Encoding:identity;q=1, *;q=0
    Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4
    Cache-Control:no-cache
    Connection:keep-alive
    Cookie:PHPSESSID=i562540rek172mnv3nk528acj0; userPassword=; userEmail=
    Host:mytestserver.net
    Pragma:no-cache
    Range:bytes=0-
    Referer:http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36
    Response Headers
    Accept-Ranges:bytes
    Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Connection:close
    Content-Length:8566268
    Content-Range:bytes 0-8566267/8566268
    Content-Type:video/webm
    Date:Fri, 11 Apr 2014 13:31:27 GMT
    Expires:Thu, 19 Nov 1981 08:52:00 GMT
    Pragma:no-cache
    Server:Apache/2.2.3 (CentOS)
    X-Powered-By:PHP/5.3.27

    --

    Request URL:http://mytestserver.net/video/V00000006.webm
    Request Headers CAUTION: Provisional headers are shown.
    Accept-Encoding:identity;q=1, *;q=0
    Cache-Control:no-cache
    Pragma:no-cache
    Range:bytes=4338314-
    Referer:http://mytestserver.net/video.html
    User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36

Notice how the second request does not complete, Provisional headers are shown.

I have tried altering the cache headers, setting it to the future, setting them blank and using file attachment headers.

I tried fiddling around a lot with the serving code, but lately I have ended up with a simple example.

<?php

$path = 'test.webm';

$size=filesize($path);

$fm=@fopen($path,'rb');
if(!$fm) {
  header ("HTTP/1.0 404 Not Found");
  die();
}

$begin=0;
$end = $size-1;

if(isset($_SERVER['HTTP_RANGE'])) {
  if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
    $begin=intval($matches[0]);
    if(!empty($matches[1])) {
      $end=intval($matches[1]);
    }
  }
}

if($begin>0||$end<$size)
  header('HTTP/1.0 206 Partial Content');
else
  header('HTTP/1.0 200 OK');

header("Content-Type: video/webm");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin+1));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary
");
header('Connection: close');

ob_get_clean();
flush();

$f = fopen($path, 'r');
fseek($f, $offset);

$pos = 0;
$length = $end-$begin;

while($pos < $length)
{
    $chunk = min($length-$pos, 1024);

    echo fread($f, $chunk);
    flush();

    $pos += $chunk;
}
?>

Please note, entering the PHP-delivered video URL directly into the browser does not make a difference from showing it in a HTML page.

I hope someone has an answer to why seeking might not work. Let me know if you have any suggestions.

Thanks!

  • 写回答

1条回答 默认 最新

  • dongpeng8994 2014-04-13 17:41
    关注

    For everyone's future reference:

    1. Online examples of HTTP_RANGE in PHP are full of faults
    2. Chrome is very bad at explaining network errors
    3. Size matters!

    In short, my problem was due to my PHP script calculating and returning bad numbers. Chrome would simply act like it didn't even try to complete the network request, making it hard to debug.

    Now I took all my network calls and pulled them through cURL (in my Linux console). Here I would get a more useful error such as curl: (18) transfer closed with 1 bytes remaining to read

    This 1-byte error in content length makes Chrome cancel the network request and not show you the response headers it got and why it canceled the request.

    Here is my working code, with working calculations of Content-Range and Content-Length. $filesize = filesize($file);

    $offset = 0;
    $length = $filesize;
    
    $partialContent = false;
    
    if(isset($_SERVER['HTTP_RANGE']))
    {
        $partialContent = true;
    
        if(!preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches))
        {
            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            header('Content-Range: bytes */' . $filesize);
            exit;
        }
    
        $offset = intval($matches[1]);
    
        if(isset($matches[2]))
        {
            $end = $intval($matches[2]);
            if($offset > $end)
            {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
                header('Content-Range: bytes */' . $filesize);
                exit;
            }
    
            $length = $end - $offset;
        }
        else
            $length = $filesize - $offset;
    }
    
    header('Content-Length: ' . $length);
    
    if($partialContent)
    {
         header('HTTP/1.1 206 Partial Content');
         header('Content-Range: bytes ' . $offset . '-' . ($offset + $length - 1) . '/' . $filesize);
         // A full-length file will indeed be "bytes 0-x/x+1", think of 0-indexed array counts
    }
    

    please note the above snippet only contains code related to the Partial Content, you will still need other headers, etc. to actually do something with it.

    In case anyone is interested, below is my code for reading out the file. I saw many bad and faulty suggestions to this on the web, but I think mine is pretty clean.

    $f = fopen($file, 'r');
    fseek($f, $offset);
    
    $pos = 0;
    
    while($pos < $length)
    {
        $chunk = min($length-$pos, 1024*8);
    
        echo fread($f, $chunk);
        flush();
        ob_flush();
    
        $pos += $chunk;
    }
    

    Case closed, Good luck to all :-)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 ROS系统搭建请教(跨境电商用途)
  • ¥15 AIC3204的示例代码有吗,想用AIC3204测量血氧,找不到相关的代码。
  • ¥20 CST怎么把天线放在座椅环境中并仿真
  • ¥15 任务A:大数据平台搭建(容器环境)怎么做呢?
  • ¥15 YOLOv8obb获取边框坐标时报错AttributeError: 'NoneType' object has no attribute 'xywhr'
  • ¥15 r语言神经网络自变量重要性分析
  • ¥15 基于双目测规则物体尺寸
  • ¥15 wegame打不开英雄联盟
  • ¥15 公司的电脑,win10系统自带远程协助,访问家里个人电脑,提示出现内部错误,各种常规的设置都已经尝试,感觉公司对此功能进行了限制(我们是集团公司)
  • ¥15 救!ENVI5.6深度学习初始化模型报错怎么办?