我遇到了一个令人难以置信的问题,我似乎无法解决。
通过PHP提供WebM文件在我的世界里并不是什么新鲜事,我什至知道如何使用HTTP 206部分内容。但出于某种原因,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中,搜索栏无效。单击搜索栏时,播放器将冻结并不再播放,直到页面刷新。火狐处理得很好!
如果我/video/V00000006.webm
更改为指向同一视频的直接链接,它可以正常工作。我什至比较了两个版本(有和没有 PHP(之间的网络请求,第一个请求几乎没有任何区别,但第二个请求在 PHP 交付的视频中失败。
Apache交付的视频文件的初始请求和搜索请求:
请求网址:http://mytestserver.net/movie1152x720.webm 请求方式:获取 状态代码:206 部分内容 请求标头 接受:*/* Accept-Encoding:identity;q=1, *;q=0 Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接方式:保持活动状态 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户电子邮件= 主机:我的测试服务器网 杂注:无缓存 范围:字节=0- Referer: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 内容类型:视频/网络 日期:2014年4月11日星期五 13:07:30 GMT ETag:"d2d0027-43d8f3-b91417c0" 最后修订日期:星期五, 11 四月 2014 12:46:31 GMT 服务器:Apache/2.2.3 (CentOS( -- 请求网址:http://mytestserver.net/movie1152x720.webm 请求方式:获取 状态代码:206 部分内容 请求标头 接受:*/* Accept-Encoding:identity;q=1, *;q=0 Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接方式:保持活动状态 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户电子邮件= 主机:我的测试服务器网 杂注:无缓存 范围:字节=4445881- Referer: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 内容类型:视频/网络 日期:2014年4月11日星期五 13:09:02 GMT ETag:"d2d0027-43d8f3-b91417c0" 最后修订日期:星期五, 11 四月 2014 12:46:31 GMT 服务器:Apache/2.2.3 (CentOS(
PHP 流视频的初始请求和查找请求:
请求网址:http://mytestserver.net/video/V00000006.webm 请求方式:获取 状态代码:206 部分内容 请求标头 接受:*/* Accept-Encoding:identity;q=1, *;q=0 Accept-Language:da-DK,da;q=0.8,en-US;q=0.6,en;q=0.4 缓存控制:无缓存 连接方式:保持活动状态 Cookie:PHPSESSID=i562540rek172mnv3nk528acj0;用户密码=;用户电子邮件= 主机:我的测试服务器网 杂注:无缓存 范围:字节=0- Referer: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 响应标头 接受范围:字节 缓存控制:无存储、无缓存、必须重新验证、检查后=0、预检查=0 连接方式:关闭 内容长度:8566268 内容范围:字节 0-8566267/8566268 内容类型:视频/网络 日期:2014年4月11日星期五 13:31:27 GMT 到期:星期四, 19 十一月 1981 08:52:00 GMT 杂注:无缓存 服务器:Apache/2.2.3 (CentOS( X-Powered-by:PHP/5.3.27 -- 请求网址:http://mytestserver.net/video/V00000006.webm 请求标头 注意:显示临时标头。 Accept-Encoding:identity;q=1, *;q=0 缓存控制:无缓存 杂注:无缓存 范围:字节=4338314- Referer: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 中HTTP_RANGE的在线示例充满了错误
- Chrome在解释网络错误方面非常糟糕
- 尺寸很重要!
简而言之,我的问题是由于我的PHP脚本计算并返回了错误的数字。Chrome 会表现得好像它甚至没有尝试完成网络请求,这使得调试变得困难。
现在,我接听了所有网络调用,并通过cURL(在我的Linux控制台中(拉取它们。在这里,我会得到一个更有用的错误,例如 curl:(18( 传输关闭,剩余 1 个字节要读取
内容长度的 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
}
请注意,上面的代码片段仅包含与部分内容相关的代码,您仍然需要其他标头等才能实际使用它。
如果有人感兴趣,下面是我读出文件的代码。我在网上看到了很多不好和错误的建议,但我认为我的建议很干净。
$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;
}
结案,祝大家好运:-(