потоковое аудио / видео файлы из gridFS в браузере

Я пытался прочитать аудиофайл из mongoDB, который я сохранил с помощью GridFS. Я мог загрузить файл в систему и воспроизвести из него, но я хотел передавать эти аудио/видео файлы из самой БД и воспроизводить их в браузере. Можно ли как-то это сделать без загрузки файла в систему? Любая помощь была бы хороша.


person theAndDev    schedule 12.08.2013    source источник


Ответы (2)


Поддержка PHP GridFS включает функцию MongoGridFSFile::getResource(), которая позволяет вам получить поток как ресурс, который не загружает весь файл в память. В сочетании с fread/echo или stream_copy_to_stream вы можете предотвратить весь файл от загрузки в память. С помощью stream_copy_to_stream вы можете просто скопировать ресурс потока GridFSFile в поток STDOUT:

<?php
$m = new MongoClient;
$images = $m->my_db->getGridFS('images');

$image = $images->findOne('mongo.png');

header('Content-type: image/png;');
$stream = $image->getResource();

stream_copy_to_stream( $stream, STDOUT );
?>

В качестве альтернативы вы можете использовать fseek() для возвращаемого ресурса $stream, чтобы отправлять обратно клиенту только части потока. В сочетании с запросами диапазона HTTP вы можете это довольно эффективно.

person Derick    schedule 12.08.2013
comment
Привет, Дерик. Я пытался заставить звук воспроизводиться, но тщетно. Я уже написал приведенный выше код, чтобы он соответствовал моему коду, но я получаю проигрыватель, но не файл для воспроизведения. Не могли бы вы мне помочь? - person theAndDev; 12.08.2013
comment
Я запускаю воспроизведение файла, но не могу его пропустить, что делается с помощью seek(file_handle,length). Мой вопрос: если пользователь нажимает на временную шкалу игрока, как мне позаботиться о смещении места, где он щелкнул? - person theAndDev; 12.08.2013
comment
@user2610503 user2610503 Вам нужно будет подключить оставшийся интерфейс к вашему приложению, которое может принимать представление flash/html5, запрашивающее пропуск из файла - person Sammaye; 12.08.2013
comment
@Sammaye спасибо за ответ. Я даже столкнулся с этим nginx, пытаясь найти решение для потоковой передачи без использования внешнего приложения для потоковой передачи. Так помогает ли этот сервер nginx в этом? Потому что я запускаю php в apache. - person theAndDev; 13.08.2013
comment
@user2610503 user2610503 Если честно, Nginx может подойти здесь лучше, я считаю, что у него действительно есть плагин для этого, например: github.com/arut/nginx-rtmp-module, так что это может быть маршрут - person Sammaye; 13.08.2013
comment
@Sammaye Это код, который я использовал $stream = $file->getResource(); while (!feof($stream)) { echo fread($stream, 8192); } но он загружает файл в мою систему только в том случае, если я использую тип контента «аудио/mpeg» и воспроизводит весь файл в браузере, если тип контента указан как «аудио/mpeg3». Я хочу воспроизвести файл с помощью аудиотега html5. Пожалуйста, помогите мне. - person theAndDev; 13.08.2013
comment
@user2610503 user2610503 Это действительно становится совершенно другим вопросом об использовании html5. - person Sammaye; 13.08.2013
comment
@Sammaye Прошу прощения за беспокойство по поводу изменения моих планов реализации. Я полный новичок в этом вопросе, и мне действительно нужно научиться извлекать аудио/видео из mongodb GridFS, а затем использовать его для создания API для потоковой передачи из приложения для телефона. Пожалуйста, предложите, как я могу это сделать - person theAndDev; 13.08.2013
comment
@user2610503 user2610503 Я бы предложил создать новый вопрос, основанный на этом, поскольку он требует немало работы. - person Sammaye; 13.08.2013
comment
stackoverflow.com/questions/18206715/ Это ссылка, по которой я разместил дополнительные запросы для этого сообщения. Если у вас есть решения, пожалуйста, ответьте. Спасибо. - person theAndDev; 13.08.2013

Если другой рецепт не работает, например, с NginX и php-fpm, поскольку STDOUT недоступен в fpm, вы можете использовать

fpassthru($stream);

вместо

stream_copy_to_stream( $stream, STDOUT );

Таким образом, полное решение выглядит так:

function img($nr)
{
  $mongo = new MongoClient();
  $img = $mongo->ai->getGridFS('img')->findOne(array('metadata.nr'=>$nr));
  if (!$img)
    err("not found");

  header('X-Accel-Buffering: no');
  header("Content-type: ".$img->file["contentType"]);
  header("Content-length: ".$img->getSize());
  fpassthru($img->getResource());

  exit(0);
}

К вашему сведению:

В этом примере:

  • Доступ к файлу осуществляется не по имени файла, а по номеру, хранящемуся в метаданных. Подсказка: Вы можете установить уникальный индекс, чтобы гарантировать, что ни один номер не может быть использован дважды.
  • Content-Type также считывается из GridFS, поэтому вам не нужно жестко кодировать это.
  • Кэширование NginX отключено, чтобы включить потоковую передачу.

Таким образом, вы даже можете обрабатывать другие вещи, такие как видео или html-страницы. Если вы хотите включить кэширование NginX, возможно, выведите X-Accel-Buffering только для больших размеров.

person Tino    schedule 06.03.2017