предаване на аудио/видео файлове от 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 Range заявки можете да правите това доста ефективно.

person Derick    schedule 12.08.2013
comment
Хей Дерик. Опитах се да пусна аудиото, но напразно. Вече написах горния код, за да съответства на моя код, но все пак получавам плейър, но не и файла за възпроизвеждане. Можете ли да ми помогнете? - person theAndDev; 12.08.2013
comment
Възпроизвеждам файла, но не мога да пропусна, което се прави от seek(file_handle,length). Въпросът ми е, ако потребителят щракне върху времевата линия на играча, тогава как да се погрижа за отместването на мястото, на което е щракнал? - person theAndDev; 12.08.2013
comment
@user2610503 Ще трябва да закачите интерфейс за почивка в приложението си, което може да поеме представянето на flash/html5 изисква пропускане от файла - person Sammaye; 12.08.2013
comment
@Sammaye благодаря за отговора. Дори се натъкнах на този nginx, докато се опитвах да търся решение, за да осъществя стрийминг без да използвам външно приложение за стрийминг. И така, този nginx сървър помага ли за това? Защото изпълнявам php в apache. - person theAndDev; 13.08.2013
comment
@user2610503 Nginx може да е по-подходящ тук, ако съм честен, вярвам, че всъщност има плъгин и за това, като: github.com/arut/nginx-rtmp-module, така че това може да е маршрут - person Sammaye; 13.08.2013
comment
@Sammaye Това е кодът, който използвах $stream = $file-›getResource(); докато (!feof($stream)) { echo fread($stream, 8192); }, но изтегля файла в моята система само ако използвам тип съдържание като „audio/mpeg“ и възпроизвежда целия файл в браузъра, ако типът съдържание е даден като „audio/mpeg3“. Искам да възпроизведа файла с помощта на html5 аудио таг. Моля, помогнете ми. - person theAndDev; 13.08.2013
comment
@user2610503 Това наистина започва да е съвсем друг въпрос относно използването на html5 - person Sammaye; 13.08.2013
comment
@Sammaye Съжалявам, че ви безпокоя с промяната на моите планове за внедряване. Аз съм пълен новобранец в тази тема и наистина трябва да науча начин да извличам аудио/видео от mongodb GridFS и след това да го използвам в създаването на API за поточно предаване от телефонно приложение. Моля, предложете някакъв начин, по който мога да направя това - person theAndDev; 13.08.2013
comment
@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);
}

FYI:

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

  • Файлът не се осъществява чрез името на файла, а вместо това се осъществява чрез номер, съхранен в метаданните. Съвет: Можете да зададете уникален индекс, за да сте сигурни, че нито едно число не може да се използва два пъти.
  • Content-Type също се чете от GridFS, така че не е необходимо да го кодирате твърдо.
  • Кеширането на NginX е изключено, за да се активира поточно предаване.

По този начин можете дори да обработвате други неща като видео или html страници. Ако искате да активирате кеширането на NginX, може би извеждайте само X-Accel-Buffering при по-големи размери.

person Tino    schedule 06.03.2017