【问题标题】:WebM file not seekable in Chrome when loaded through PHP (other browsers work)通过 PHP 加载时无法在 Chrome 中查找 WebM 文件(其他浏览器也可以)
【发布时间】:2014-05-25 17:54:24
【问题描述】:

我遇到了一个令人难以置信的问题,我似乎无法解决。

通过 PHP 提供 WebM 文件对我来说并不是什么新鲜事,我什至知道如何使用 HTTP 206 Partial Content。但出于某种原因,Chrome 不喜欢它。

一个简单的 HTML5 视频播放

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

/video/V00000006.webm 在 Apache 中被重写为 PHP 文件,可以正常播放。 但在 Chrome 中,搜索栏无效。单击搜索栏时,播放器将冻结并且在页面刷新之前不再播放。 Firefox 处理得很好!

如果我将/video/V00000006.webm 更改为指向同一视频的直接链接,它就可以正常工作。我什至比较了两个版本(使用和不使用 PHP)之间的网络请求,第一个请求几乎没有任何差异,但第二个请求在 PHP 交付的视频中失败。

对 Apache 提供的视频文件的初始请求和搜索请求:

请求网址:http://mytestserver.net/movie1152x720.webm 请求方法:GET 状态码:206 部分内容 请求标头 接受:*/* 接受编码:身份;q=1,*;q=0 接受语言:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接:保持活动 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户邮箱= 主机:mytestserver.net 杂注:无缓存 范围:字节=0- 参考:http://mytestserver.net/video.html 用户代理:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36 响应标头 接受范围:字节 连接:关闭 内容长度:4446451 内容范围:字节 0-4446450/4446451 内容类型:video/webm 日期:格林威治标准时间 2014 年 4 月 11 日星期五 13:07:30 ETag:“d2d0027-43d8f3-b91417c0” 最后修改时间:格林威治标准时间 2014 年 4 月 11 日星期五 12:46:31 服务器:Apache/2.2.3 (CentOS) -- 请求网址:http://mytestserver.net/movie1152x720.webm 请求方法:GET 状态码:206 部分内容 请求标头 接受:*/* 接受编码:身份;q=1,*;q=0 接受语言:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接:保持活动 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户邮箱= 主机:mytestserver.net 杂注:无缓存 范围:字节=4445881- 参考:http://mytestserver.net/video.html 用户代理:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36 响应标头 接受范围:字节 连接:关闭 内容长度:570 内容范围:字节 4445881-4446450/4446451 内容类型:video/webm 日期:格林威治标准时间 2014 年 4 月 11 日星期五 13:09:02 ETag:“d2d0027-43d8f3-b91417c0” 最后修改时间:格林威治标准时间 2014 年 4 月 11 日星期五 12:46:31 服务器:Apache/2.2.3 (CentOS)

PHP 流视频的初始请求和搜索请求:

请求网址:http://mytestserver.net/video/V00000006.webm 请求方法:GET 状态码:206 部分内容 请求标头 接受:*/* 接受编码:身份;q=1,*;q=0 接受语言:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接:保持活动 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户邮箱= 主机:mytestserver.net 杂注:无缓存 范围:字节=0- 参考:http://mytestserver.net/video.html 用户代理:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36 响应标头 接受范围:字节 Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0 连接:关闭 内容长度:8566268 内容范围:字节 0-8566267/8566268 内容类型:video/webm 日期:格林威治标准时间 2014 年 4 月 11 日星期五 13:31:27 过期时间:1981 年 11 月 19 日星期四 08:52:00 GMT 杂注:无缓存 服务器:Apache/2.2.3 (CentOS) X-Powered-By:PHP/5.3.27 -- 请求网址:http://mytestserver.net/video/V00000006.webm 请求标头 注意:显示临时标头。 接受编码:身份;q=1,*;q=0 缓存控制:无缓存 杂注:无缓存 范围:字节=4338314- 参考:http://mytestserver.net/video.html 用户代理:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36

注意第二个请求没有完成,临时标头显示

我已尝试更改 缓存标头,将其设置为未来,将它们设置为空白并使用 文件附件标头

我试着摆弄了很多服务代码,但最近我得到了一个简单的例子。

<?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\n");
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;
}
?>

请注意,将 PHP 提供的视频 URL 直接输入到浏览器中与在 HTML 页面中显示没有区别。

我希望有人能回答为什么寻找可能不起作用。如果您有任何建议,请告诉我。

谢谢!

【问题讨论】:

    标签: php google-chrome ffmpeg html5-video webm


    【解决方案1】:

    供大家日后参考:

    1. PHP中HTTP_RANGE的在线示例故障百出
    2. Chrome 不善于解释网络错误
    3. 尺寸很重要!

    简而言之,我的问题是由于我的 PHP 脚本计算并返回了错误的数字。 Chrome 只会表现得好像它甚至没有尝试完成网络请求,因此很难调试。

    现在我接受了所有网络调用并通过 cURL(在我的 Linux 控制台中)提取它们。 在这里我会得到一个更有用的错误,例如 curl: (18) transfer closed with 1 bytes to read

    这个 1 字节的内容长度错误使 Chrome 取消网络请求,并且不向您显示它获得的响应标头以及取消请求的原因。

    这是我的工作代码,内容范围和内容长度的工作计算。 $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
    }
    

    请注意,上面的 sn-p 只包含与 Partial Content 相关的代码,您仍然需要其他 headers 等来实际使用它。

    如果有人感兴趣,下面是我读取文件的代码。我在网上看到了很多不好的和错误的建议,但我认为我的建议很干净。

    $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;
    }
    

    结案, 祝大家好运:-)

    【讨论】:

    • 你介意发布更完整的。我无法让您的示例起作用。
    猜你喜欢
    • 2021-07-03
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    相关资源
    最近更新 更多