Использование php для вывода видео в формате mp4 - PullRequest
27 голосов
/ 08 мая 2011

Хорошо, в основном у меня есть проект, который требует, чтобы видео были скрыты от пользователей, но при этом они могли видеть их (используя 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 ]

14 голосов
/ 08 мая 2011

Iphones используют так называемые байтовые диапазоны для аудио и видео запросов.Смотрите эту ссылку для решения.Это в Приложении А.

http://mobiforge.com/developing/story/content-delivery-mobile-devices

6 голосов
/ 04 апреля 2013

Вот фрагмент кода, который будет делать то, что вы хотите ( из этого вопроса ). Решение 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();

Это немного сложнее, и вы должны использовать его только тогда, когда вам это нужно, но приятно знать, что у вас есть опция обновления, когда вы начинаете с чего-то, что довольно просто, но имеет посредственную производительность.

2 голосов
/ 16 февраля 2012

Этот код был очень удобен для меня, но у меня возникли проблемы, потому что я использую сеансовые переменные и PHP-очереди доступа к сеансам.Если загружалось видео, все AJAX-запросы были невозможны и т. Д. Поэтому обязательно вызовите session_write_close(), прежде чем начать вывод.

1 голос
/ 16 августа 2013

Да, это легко сделать. Нет необходимости устанавливать эти заголовки вручную. Пусть сервер сделает это автоматически.

Вот рабочий скрипт -

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);
...