Потоковая передача mp4 через php-файл постепенно

Я работаю над более безопасным потоковым методом для нашего видеоплеера. Поскольку для каждого файла требуется специальная аутентификация по токену, а также только каждый загрузочный токен загружается один раз, я запускаю MP4 через контейнер php. Это отлично работает внутри тега HTML5 и не позволяет пользователям легко загружать источник.

Я адаптирую код отсюда

<?php include('...'); //include site functions /* Here I connect to the database, and retrieve the location of the video which is returned as $video = "http://domain.tld/folder/file.mp4" This has been removed for this SO example. */ $file = $video; $fp = @fopen($file, 'rb'); $head = array_change_key_case(get_headers($file, TRUE)); $size = $head['content-length']; //$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"); header("Accept-Ranges: bytes"); 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(); ?> 

Сейчас возникают проблемы, поскольку я хотел бы иметь возможность искать видео. Пропуск к области в видео, который не был загружен, вызывает тег <video> (и хром).

Я бы предположил, что, поскольку игрок HTML5 ищет в секундах, а PHP загружается в байтах, это невозможно сделать. Вот почему я спрашиваю здесь.

Что я могу сделать (если угодно), чтобы обеспечить прогрессивную передачу?
Есть ли более подходящий формат контейнера, который я мог бы использовать, который будет служить той же цели?

Я думаю, что у вас есть концептуальный провал. Вы обрабатываете файл mp4, как если бы это был «файл необработанных данных». Я пытаюсь объяснить себя.

Представьте, что у вас есть текстовый файл, и вы хотите получить символы из позиции X. Вы можете открыть файл, навести курсор на нужную позицию, а затем прочитать байт по вашему тексту. Это будет работать нормально.

Но теперь изображение, которое вы хотите сделать так же, но с файлом текстового процессора. Вы ожидаете тех же результатов? Нет, потому что у вас много метаданных в файле, которые мешают вам это делать.

Ваша проблема в основном такая же. Вы должны учитывать формат файла, управлять файлом с помощью библиотек, предназначенных для него, или делать сами.

Другой вариант – работать с необработанными файлами данных, но в случае с видеофайлами это будут действительно большие файлы.

Надеюсь, я помог тебе.

В дополнение к тому, что сказал dlopez, я рекомендую использовать стороннее решение для прогрессивной загрузки с возможностями поиска (псевдопотока AKA). Вы можете взглянуть на решения PD, перечисленные в Википедии: https://en.wikipedia.org/wiki/Progressive_download

Большинство из них также могут препятствовать защите видео хотлинков.

У меня возникла аналогичная проблема. Использование stream_get_content($fp, $start) вместо fseek исправило проблему. Я смог получить видео для потокового воспроизведения во всех браузерах, и поиск (или пропуски) по всему видео работал без проблем.

Вы не можете использовать fseek (5654), если вы используете путь к файлу с помощью http://example.com … Вместо этого вы должны использовать c: /file/abc.mp4. Это может решить вашу проблему …

Полностью функциональный код

 $file = "z.mp4"; $length= filesize($file); $offset = 0; $f = fopen($file, 'r'); stream_get_contents($f, $offset); $pos = 0; while($pos < $length){ $chunk = min($length-$pos, 1024*8); echo fread($f, $chunk); flush(); ob_flush(); $pos += $chunk; }