2016-05-20 2 views
2

У меня есть клиент с тысячами аудио/видео файлов, которые они передают изнутри, все сегментированы (.ts) и сохраняются в ведре S3 с соответствующими метаданными в базе данных SQL. Теперь они попросили меня создать два «живых» потока, один для аудио, один для видео, который они могут установить и забыть.HLS в прямом эфире из статических файлов

Не желая перегруппировать все или объединить все файлы, которые я пытаюсь взломать в «живом» m3u8, который просматривает уже существующие файлы (все они закодированы точно так же).

Что я сделал, это генерировать «радио-список воспроизведения», который сохраняется в базе данных с 40-секундными интервалами (x3 .ts на m3u8), каждый из которых помечен временем начала и окончания и соответствующим EXT-X-MEDIA -ПОСЛЕДОВАТЕЛЬНОСТЬ. Затем я выбираю между NOW() и нажимаю файл.

Работает, но иногда время правильное, и оно попадает в одну и ту же группу для первого и последнего файлов и буферов. У меня есть полный контроль над игроком (VideoJS) и сервером, чтобы он работал.

Это код, который у меня есть до сих пор ... любым способом я мог бы сделать эту работу? Я не пробовал играть с буферами на VJS пока (не знаю, как ...)

Вся основная информация о файле хранится в базе данных, как это

INSERT INTO `contenido_audio_hls` (`id`, `audio_s`, `duration`) VALUES ('f2z7dcwc0l7rleig', '["10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","10.000000","4.100000"]', 10); 

Когда генерируется список воспроизведения Я вытащить необходимые данные

$radio = sql("SELECT lista_contenido.orden,lista_contenido.contenido,contenido_audio_hls.audio_s FROM lista_listas LEFT JOIN lista_contenido ON (lista_listas.id = lista_contenido.lista) LEFT JOIN contenido_audio_hls ON (lista_contenido.contenido = contenido_audio_hls.id) WHERE (lista_listas.tipo = 'radio') ORDER BY lista_contenido.orden ASC"); 
foreach($radio['data'] as $k=>$v) { 
    $arreglo = json_decode($v['audio_s'],TRUE); 
    foreach($arreglo as $kk=>$vv) { 
     $puro[] = array("extinf"=>'#EXTINF:'.$vv.',',"id"=>$v['contenido'],"segment"=>$kk); 
    } 
} 

I цикл через них, чтобы создать группы

$segundos = 0; 
$grupo = 1; 
$contador = 1; 
foreach($puro as $k=>$v) { 
    if($segundos <= 30) { 
     $m3u8[$grupo][] = $puro[$k]; 
     $contador++; 
    } else { 
     $m3u8[$grupo][] = $puro[$k]; 
     $grupo = $grupo + $contador; 
     $segundos = 0; 
    } 
    $segundos = $segundos + 10; 
} 

Затем положить их в свою собственную таблицу

$largo = 0; 
foreach($m3u8 as $k=>$v) { 
    $ini = sprintf('%02d:%02d:%02d',($largo/3600),($largo/60%60),$largo%60); 
    $localfin = $largo + 40; 
    $fin = sprintf('%02d:%02d:%02d',($localfin/3600),($localfin/60%60),$localfin%60); 

    $query = "INSERT INTO lista_m3u8 (ini,fin,tipo,sequence,data) VALUES('".$ini."','".$fin."','radio','".$k."','".json_encode($v)."')"; 

    sql($query); 

    $largo = $largo + 40; 
} 

Который дает мне это

INSERT INTO `lista_m3u8` (`ini`, `fin`, `tipo`, `sequence`, `data`) VALUES ('06:54:00', '06:54:40', 'radio', 580636, '[{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":14},{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":15},{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":16},{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":17}]'); 
INSERT INTO `lista_m3u8` (`ini`, `fin`, `tipo`, `sequence`, `data`) VALUES ('06:54:40', '06:55:20', 'radio', 582504, '[{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":18},{"extinf":"#EXTINF:10.000000,","id":"f2z7de0quwgehw23","segment":19},{"extinf":"#EXTINF:0.766667,","id":"f2z7de0quwgehw23","segment":20},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":0}]'); 
INSERT INTO `lista_m3u8` (`ini`, `fin`, `tipo`, `sequence`, `data`) VALUES ('06:55:20', '06:56:00', 'radio', 584375, '[{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":1},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":2},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":3},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":4}]'); 
INSERT INTO `lista_m3u8` (`ini`, `fin`, `tipo`, `sequence`, `data`) VALUES ('06:56:00', '06:56:40', 'radio', 586249, '[{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":5},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":6},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":7},{"extinf":"#EXTINF:10.000000,","id":"f2z7dft8c217xyp","segment":8}]'); 

Тогда m3u8 генерируется

$audio = sql("SELECT sequence, data FROM lista_m3u8 WHERE tipo = 'radio' AND ini <= DATE_FORMAT(NOW(),'%H:%i:%s') AND fin >= DATE_FORMAT(NOW(),'%H:%i:%s')"); 

$sale = '#EXTM3U'.PHP_EOL; 
$sale .= '#EXT-X-VERSION:3'.PHP_EOL; 
$sale .= '#EXT-X-MEDIA-SEQUENCE:'.$audio['data'][0]['sequence'].PHP_EOL; 
$sale .= '#EXT-X-TARGETDURATION:10'.PHP_EOL; 

$arreglo = json_decode($audio['data'][0]['data'],TRUE); 
foreach($arreglo as $k=>$v) { 
    $sale .= $v['extinf'].PHP_EOL; 
    $sale .= S3URL("bucket-audio",$v['id']."/segment".sprintf('%05d',$v['segment']).".ts",(count($arreglo) * 25)).PHP_EOL; 
} 

header("Content-type: application/x-mpegURL"); 
echo $sale.PHP_EOL; 

ответ

1

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

Я изначально искал это, пытаясь создать консервированные файлы m3u8; мне действительно нужно было знать две вещи:

1.- Какой сегмент (независимо от исходного файла) должен воспроизводиться сейчас?

2.- Сколько сегментов было бы воспроизведено с начала «потока» (файл 0, сегмент 0)?

Новый метод теперь принимает исходный список воспроизведения и создает строку для каждого сегмента с указанием времени начала, продолжительности, файла сегмента и положения в потоке. Затем m3u8 генерируется с несколькими сегментами позади и несколькими после, вычисляя правильную EXT-X-MEDIA-SEQUENCE с начала потока. Я также добавил EXT-X-DISCONTINUITY между файлами, чтобы он не зависал при получении неожиданных заголовков.

Так что теперь, я получаю список файлов/сегментов из моей исходной таблицы:

$ini = 0; 
$conteo = 0; 
$radio = sql("SELECT lista_contenido.orden,lista_contenido.contenido,contenido_audio_hls.audio_s FROM lista_listas LEFT JOIN lista_contenido ON (lista_listas.id = lista_contenido.lista) LEFT JOIN contenido_audio_hls ON (lista_contenido.contenido = contenido_audio_hls.id) WHERE (lista_listas.tipo = 'radio') ORDER BY lista_contenido.orden ASC"); 
foreach($radio['data'] as $k=>$v) { 
    $arreglo = json_decode($v['audio_s'],TRUE); 
    $seg = 0; 
    foreach($arreglo as $kk=>$vv) { 
     sql("INSERT INTO lista_m3u8 (tipo,orden,contenido,segmento,extinf,ini) VALUES('radio','".$conteo."','".$v['contenido']."','segment".sprintf('%05d',$seg).".ts','".$vv."','".sprintf('%02d:%02d:%02d',($ini/3600),($ini/60%60),$ini%60)."')"); 
     $ini = $ini + ceil($vv * 1); 
     $seg++; 
     $conteo++; 
    } 
} 

Который дает мне таблицу, как так:

INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 20, 'f2z7ddw7r6bb7gfy', 'segment00018.ts', 10.000000000000, '00:03:11'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 21, 'f2z7ddw7r6bb7gfy', 'segment00019.ts', 10.000000000000, '00:03:21'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 22, 'f2z7ddw7r6bb7gfy', 'segment00020.ts', 6.066667079926, '00:03:31'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 23, 'f2z7df1bb66be7h3', 'segment00000.ts', 10.000000000000, '00:03:38'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 24, 'f2z7df1bb66be7h3', 'segment00001.ts', 10.000000000000, '00:03:48'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 25, 'f2z7df1bb66be7h3', 'segment00002.ts', 10.000000000000, '00:03:58'); 
INSERT INTO `lista_m3u8` (`tipo`, `orden`, `contenido`, `segmento`, `extinf`, `ini`) VALUES ('radio', 26, 'f2z7df1bb66be7h3', 'segment00003.ts', 10.000000000000, '00:04:08'); 

Это создает тысячи дб строк (~ 9000 для 24-часового радиопотока), но они индексируются по времени, поэтому SELECTing является мгновенным.

Окончательный m3u8 скрипт делает это:

$actual = sql("SELECT orden, extinf, contenido, segmento, ini FROM lista_m3u8 WHERE tipo = 'radio' AND ini >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MINUTE),'%H:%i:%s') AND ini <= DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 3 MINUTE),'%H:%i:%s') ORDER BY orden ASC"); 

$sale = '#EXTM3U'.PHP_EOL; 
$sale .= '#EXT-X-VERSION:3'.PHP_EOL; 
$sale .= '#EXT-X-MEDIA-SEQUENCE:'.($actual['data'][$actual['total']-1]['orden'] - $actual['total']).PHP_EOL; 
$sale .= '#EXT-X-TARGETDURATION:10'.PHP_EOL; 

$contenido = $actual['data'][0]['contenido']; 
foreach($actual['data'] as $k=>$v) { 
    if($v['contenido'] != $contenido) { $sale .= "#EXT-X-DISCONTINUITY".PHP_EOL; } 
    $sale .= "#EXTINF:".$v['extinf'].",".PHP_EOL; 
    $sale .= S3URL("audio-bucket",$v['contenido']."/".$v['segmento'],180).PHP_EOL; 
    $contenido = $v['contenido']; 
} 

header("Content-type: application/x-mpegURL"); 
echo $sale.PHP_EOL; 

Обратите внимание две вещи, происходящие здесь, EXT-X-MEDIA-ПОСЛЕДОВАТЕЛЬНОСТЬ рассчитывается путем вычитания позиции текущего сегмента из списка в целом и XT-X -DISCONTINUITY помещается между изменениями файлов.

Я собираюсь провести еще несколько тестов, чтобы увидеть, работает ли это в разных браузерах (пока я тестировал только Chrome и IEG); но я считаю, что это приемлемое решение.

Смежные вопросы