Использование php для вывода видео в формате mp4
Хорошо, в основном у меня есть проект, который требует, чтобы видео были скрыты от пользователей, но при этом они могли видеть их (используя php). вот что я получил так далеко:
Файл 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();
?>
и HTML-файл, который должен отображать это, использует HTML5, как и следовало ожидать. теперь вот в чем дело.. когда я прямо встраиваю это (не) это работает. но он не работает на моем iPhone и не работает в теге... если я использую прямой файл вместо обертки php, все работает нормально, на моем iPhone тоже...
поэтому я предполагаю, что мой вопрос по этому вопросу таков: какова надлежащая информация header() для идеальной репликации mp4, которую можно передавать через iPhone и HMTL5?
Решение получено от: http://mobiforge.com/developing/story/content-delivery-mobile-devices
файл 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();
?>
4 ответа
Iphones используют так называемые диапазоны байтов для аудио и видео запросов. Смотрите эту ссылку для решения. Это в приложении А.
http://mobiforge.com/developing/story/content-delivery-mobile-devices
Вот фрагмент кода, который будет делать то, что вы хотите ( из этого вопроса). Решение PHP кажется более элегантным, и оно добавляет более эффективное решение, которое может работать, использующее веб-сервер для обслуживания контента.
<?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();
Больше производительности
Обратите внимание, что это не самый эффективный способ сделать это, потому что весь файл должен проходить через PHP, поэтому вам просто нужно попробовать, как он работает для вас.
Предполагая, что причина, по которой вы хотите это сделать, заключается в том, чтобы ограничить доступ, и в дальнейшем вам потребуется больше эффективности, вы можете использовать флаг для веб-сервера.
Apache с модулем X-Sendfile или lightty ( информация о nginx здесь)
$path = 'file.mp4';
header("X-Sendfile: $path");
die();
Это немного сложнее, и вы должны использовать его только тогда, когда вам это нужно, но приятно знать, что у вас есть опция обновления, когда вы начинаете с чего-то, что довольно просто, но имеет посредственную производительность.
Этот код был очень удобен для меня, но у меня возникли проблемы, потому что я использую сеансовые переменные и PHP-очереди доступа к сеансам. Если загружалось видео, все запросы AJAX были невозможны и т. Д. Поэтому обязательно позвоните session_write_close()
прежде чем начать вывод.
Да, это легко сделать. Нет необходимости устанавливать эти заголовки вручную. Пусть сервер сделает это автоматически.
Вот рабочий сценарий -
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);