我有一个客户端,其中包含数千个内部流式传输的音频/视频文件,所有这些文件都是分段的(.ts),并保存在一个S3数据库中,并在SQL数据库中包含适当的元数据。现在他们已经要我创建两个" live"流,一个用于音频,一个用于视频,可以设置和忘记。
不想重新分割所有内容或连接我试图入侵的所有文件" live" m3u8滑过现有文件(它们的编码方式完全相同)。
我所做的是生成一个"广播播放列表"以40秒的间隔(x3 .ts / m3u8)保存到数据库中,每个标记有开始和结束时间以及适当的EXT-X-MEDIA-SEQUENCE。然后我在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);
}
}
我遍历它们以创建组
$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;
答案 0 :(得分:1)
我相信我已经解决了。我刚刚离开这场比赛过去的16个小时而且还在继续,我的AWS日志确认了这一点。
我原本是以错误的方式接近这个,试图生成罐装m3u8文件;我真正需要做的是知道两件事:
1.-现在应该播放哪个片段(不管原始文件)?
2.-从“流”开始播放了多少段(文件0,段0)?
新方法现在采用原始播放列表并为每个段创建一行,指示其开始时间,持续时间,段文件和流中的位置。然后生成m3u8,后面有几个段,后面几个,从流的开头计算正确的EXT-X-MEDIA-SEQUENCE。我还在文件之间添加了EXT-X-DISCONTINUITY,因此在收到意外标题时不会挂断。
现在,我从原始表中获取文件/段列表:
<form action="" method = "POST">
<input type="radio" name="someName" value="ip"> IP<br>
<input type="radio" name="someName" value="uid"> UID<br>
Enter Name: <input type="text" name="name" > <br>
<input type="submit" name="submit">
</form>
这给了我一张这样的表格:
<?php
error_reporting(E_ALL);
$submit=isset($_POST['submit']);
if($submit)
{
$name=$_POST['somename'];
$username=$_POST['username'];
$con = new PDO('mysql:host='.$db_hostname.';dbname='.$db_database.';charset=utf8mb4', $db_termname,$db_password, array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$stm=$con->prepare('SELECT * FROM users WHERE username = ?');
$stm->bind_param("s",$username);
$stmt->execute();
$row = $stm->fetch(PDO::FETCH_ASSOC);
if($name=='ip')
{ echo $row['ip'];
}
else if($name=='uid')
{
echo $row['uid];
}
}
这会创建数千个db行(24小时无线电流约为9000),但它们会按时间编制索引,因此SELECTing是即时的。
最终的m3u8脚本执行此操作:
$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++;
}
}
注意这里发生了两件事,EXT-X-MEDIA-SEQUENCE的计算方法是从列表中减去当前段的位置,并在文件更改之间放入XT-X-DISCONTINUITY。
我要做更多的测试,看看它是否适用于各种浏览器(到目前为止我只测试过Chrome和IEG);但我相信这是一个可行的解决方案。
答案 1 :(得分:0)
如果您要循环播放单个视频,也可以尝试使用类似以下php脚本的简单方法:
<?php
// lets assume that we have stream splitted to parts named testXXXXX.ts
// and all parts have 2.4 seconds and we want to play in loop part
// from test0.ts to test29.ts forever in a live stream
header('Content-Type: application/x-mpegURL');
$time = intval(time() / 2.40000);
$s1 = ($time + 1) % 30;
$s2 = ($time + 2) % 30;
$s3 = ($time + 3) % 30;
$s4 = ($time + 4) % 30;
?>
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:<?php echo "$time\n"; ?>
#EXTINF:2.40000,
test<?php echo $s1; ?>.ts
<?php if ($s2 < $s1) echo "#EXT-X-DISCONTINUITY\n"; ?>
#EXTINF:2.40000,
test<?php echo $s2; ?>.ts
<?php if ($s3 < $s2) echo "#EXT-X-DISCONTINUITY\n"; ?>
#EXTINF:2.40000,
test<?php echo $s3; ?>.ts
<?php if ($s4 < $s3) echo "#EXT-X-DISCONTINUITY\n"; ?>
#EXTINF:2.40000,
test<?php echo $s4; ?>.ts