php 使用php输出mp4视频
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5924061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using php to output an mp4 video
提问by Jubair
Ok basically I have a project that requires that videos are hidden from the users while still able to see them (by using php). here's what i got so far:
好的,基本上我有一个项目要求视频对用户隐藏,同时仍然能够看到它们(通过使用 php)。这是我到目前为止所得到的:
The video.php file has this:
video.php 文件有这个:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'path/to/movie.mp4');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$out = curl_exec($ch);
curl_close($ch);
header('Content-type: video/mp4');
header('Content-type: video/mpeg');
header('Content-disposition: inline');
header("Content-Transfer-Encoding:- binary");
header("Content-Length: ".filesize($out));
echo $out;
exit();
?>
and the html file that is supposed to display this is using html5 as it would expect. now here's the thing.. when I straight embed this (not ) it works. but it doesn't work on my iPhone and doesn't work in the tag... if I use the direct file instead of the php wrapper, everything works fine, on my iPhone too...
并且应该显示它的 html 文件正在使用 html5,正如它所期望的那样。现在事情是这样的..当我直接嵌入这个(不是)时,它就起作用了。但它在我的 iPhone 上不起作用并且在标签中不起作用......如果我使用直接文件而不是 php 包装器,一切正常,在我的 iPhone 上也是如此......
so I guess my question for this one is this: what are the proper header() information to perfectly replicate an mp4 that can be streamed via iPhone and HMTL5?
所以我想我对这个问题的问题是:完美复制可以通过 iPhone 和 HMTL5 流式传输的 mp4 的正确 header() 信息是什么?
Solution derived from: http://mobiforge.com/developing/story/content-delivery-mobile-devices
解决方案源自:http: //mobiforge.com/developing/story/content-delivery-mobile-devices
video.php file:
video.php 文件:
<?php
$file = 'path/to/videofile.mp4';
$fp = @fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
header("Accept-Ranges: 0-$length");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
?>
采纳答案by sreimer
Iphones use something called byte-ranges for audio and video requests. See this link for a solution. It's in Appendix A.
Iphone 使用称为字节范围的东西来处理音频和视频请求。请参阅此链接以获取解决方案。它在附录 A 中。
http://mobiforge.com/developing/story/content-delivery-mobile-devices
http://mobiforge.com/developing/story/content-delivery-mobile-devices
回答by cmc
Here is a code snippet that will do what you want (from this question). The PHP solution seems more elegant, and it adds a more efficient solution that might work that uses the web server to serve the content.
这是一个代码片段,可以做你想做的事情(来自这个问题)。PHP 解决方案看起来更优雅,它添加了一个更有效的解决方案,该解决方案可能会使用 Web 服务器来提供内容。
<?php
$path = 'file.mp4';
$size=filesize($path);
$fm=@fopen($path,'rb');
if(!$fm) {
// You can also redirect here
header ("HTTP/1.0 404 Not Found");
die();
}
$begin=0;
$end=$size;
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/mp4");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Connection: close');
$cur=$begin;
fseek($fm,$begin,0);
while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
$cur+=1024*16;
usleep(1000);
}
die();
More Performance
更多性能
Note that this is not the most efficient way to do it, because the whole file needs to go through PHP, so you will just need to try how it goes for you.
请注意,这不是最有效的方法,因为整个文件都需要通过 PHP,所以您只需要尝试一下它是如何进行的。
Assuming the reason you want to do this is to restrict access, and you need more efficiency later, you can use a flag for the web server.
假设您要这样做的原因是限制访问,并且您以后需要更高的效率,则可以为 Web 服务器使用一个标志。
Apache with X-Sendfile module or lightty (nginx info here)
带有 X-Sendfile 模块或 lightty 的 Apache(此处为 nginx 信息)
$path = 'file.mp4';
header("X-Sendfile: $path");
die();
This is a bit more advanced and you should only use it if you need it, but it is relaxing to know you have an upgrade option when you start out with something that is rather easy but has mediocre performance.
这有点高级,您应该只在需要时使用它,但是当您开始使用相当简单但性能平庸的东西时,知道您有升级选项是令人放松的。
回答by jefftimesten
This code was very handy for me, but I ran into trouble because I am using session vars, and PHP queues access to sessions. If a video was loading, all AJAX requests were impossible, etc. So make sure to call session_write_close()
before you start output.
这段代码对我来说非常方便,但我遇到了麻烦,因为我使用的是会话变量,并且 PHP 对会话的访问进行了排队。如果正在加载视频,则所有 AJAX 请求都是不可能的,等等。因此请确保session_write_close()
在开始输出之前调用。
回答by Admin at dekho-ji.com
Yes, its easy to do. No need to set those headers manually. Let the server do it automatically.
是的,这很容易做到。无需手动设置这些标题。让服务器自动完成。
Heres a working script -
这是一个工作脚本 -
ob_start();
if( isset($_SERVER['HTTP_RANGE']) )
$opts['http']['header']="Range: ".$_SERVER['HTTP_RANGE'];
$opts['http']['method']= "HEAD";
$conh=stream_context_create($opts);
$opts['http']['method']= "GET";
$cong= stream_context_create($opts);
$out[]= file_get_contents($real_file_location_path_or_url,false,$conh);
$out[]= $http_response_header;
ob_end_clean();
array_map("header",$http_response_header);
readfile($real_file_location_path_or_url,false,$cong);