簡體   English   中英

如何通過在瀏覽器中粘貼URL來創建動態m3u8?

[英]How to create dynamic m3u8 by pasting the URL in browser?

我想在調用PHP腳本時創建動態m3u8。 我不想將結果m3u8保存在服務器上,而是我想送到瀏覽器以便可下載。 有誰能告訴我如何才能完成這項任務?

要調用的PHP腳本示例:

http://www.asite.com/makeM3u8.php?videoId=1234

可下載的動態m3u8結構:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=900000
http://someserver/channelNameBandwith900000.m3u8?session=3495732948523984eriuwehiurweirew

在進入腳本之前,您必須先決定一些事情:

1.- .ts和.aac文件存儲在哪里,它們的保護方案是什么?PHP是否能夠創建能夠訪問它們的URL?

2.-存儲原始m3u8信息的位置(每個段的目標持續時間,extinf和名稱)。 在這種情況下,數據庫比解析現有文件更快。

3.-如果處理多比特率,你需要一個腳本,它也生成指向所有其他的主m3u8。

話雖這么說,這是我提出的解決方案,並且已經使用了一段時間沒有問題。 但有兩點,我使用AWS S3進行存儲,並使用ffmpeg轉換現有的視頻文件。 這是一個相當漫長的過程 - 對你想要的東西來說可能有些過分 - 但它確實有效。

第1部分 - 編碼文件系統接收MP4視頻並將其轉換為必需的格式。

function ffConvert($origin,$basedir,$res) {
switch($res) {
    // SET THE VARIABLES
    case "240p": $size = "426x240"; $vbit = "360k"; $level = "3.0"; $abit = "80k"; break;
    case "480p": $size = "854x480"; $vbit = "784k"; $level = "3.1"; $abit = "128k"; break;
    case "720p": $size = "1280x720"; $vbit = "1648k"; $level = "3.1"; $abit = "192k"; break;
}
// CONVERT THE FILES
exec('/usr/local/bin/ffmpeg -y -async 1 -vsync -1 -analyzeduration 999999999 -i "'.$origin.'" -force_key_frames "expr:gte(t,n_forced*10)" -pix_fmt yuv420p -s '.$size.' -r:v 30 -b:v '.$vbit.' -c:v libx264 -profile:v baseline -level '.$level.' -c:a libfaac -ac 2 -ar 48000 -b:a '.$abit.' -g 90 '.$base.$res.'.mp4');
// VERIFY AND RETURN
if(file_exists($basedir.$res.'.mp4')) {
    return TRUE;
} else {
    return FALSE;
}
}

第2部分 - 分割文件系統采用轉換后的MP4並對其進行分段。

function ffSegment($basedir,$res) {
// CREATE THE SEGMENTS
mkdir($basedir.$res, 0775);
exec('/usr/local/bin/ffmpeg -y -analyzeduration 999999999 -i "'.$basedir.$res.'.mp4" -codec copy -map 0 -f segment -segment_list "'.$basedir.$res.'/stream.m3u8" -segment_time 10 -segment_list_type m3u8 -bsf:v h264_mp4toannexb "'.$basedir.$res.'/segment%05d.ts"');
if(file_exists($basedir.$res.'/stream.m3u8')) {
    return TRUE;
} else {
    return FALSE;
}
}

第3部分 - 存儲數據系統解析生成的m3u8並將相關信息存儲在數據庫中。

表:

CREATE TABLE IF NOT EXISTS `data_contenido_archivos` (
    `id` bigint(20) unsigned NOT NULL,
    `240p` mediumtext NOT NULL,
    `480p` mediumtext NOT NULL,
    `720p` mediumtext NOT NULL,
    `aac` mediumtext NOT NULL,
    UNIQUE KEY `id` (`id`)
) ENGINE=TokuDB DEFAULT CHARSET=utf8;

解析功能:

function parseHLS($file) {
$return = array();
$i = 0;
$handle = fopen($file, "r");
if($handle) {
    while(($line = fgets($handle)) !== FALSE) {
        if(strpos($line,"#EXTINF") !== FALSE) {
            $return['data'][$i]['inf'] = str_replace(array("#EXTINF:",",","\r","\n"),array("","","",""),$line);
        }
        if(strpos($line,".ts") !== FALSE) {
            $return['data'][$i]['ts'] = str_replace(array(".ts","segment","\r","\n"),array("","","",""),$line);
            $i++;
        }
        if(strpos($line,"TARGETDURATION") !== FALSE) {
            $return['duration'] = str_replace(array("#EXT-X-TARGETDURATION:","\r","\n"),array("","","",""),$line);
        }
    }
    fclose($handle);
} else {
    $retorno = FALSE;
}
return $return;
}

每個文件的結果都存儲在每個視頻大小的相對列中,作為json編碼的字符串,請注意我存儲了可能的最小信息,以便最大限度地縮短讀取時間並使dB盡可能小。 在此步驟中,速度並不重要,因為這是在提供文件之前完成的。

第4部分 - 提供文件系統讀取數據庫並為每個大小提供正確的文件。

為此,我有一個m3u8.domain.com設置,它將所有* .m3u8文件發送到PHP解釋器,所以我不打擾重命名,這只提供以下文件:

  • crossdomain.xml的
  • 240p.m3u8:240p分辨率的腳本
  • 480p.m3u8:480p分辨率的腳本
  • 720p.m3u8:720p分辨率的腳本
  • aac.m3u8:僅用於音頻的腳本
  • master.m3u8:主m3u8的腳本

每個都是它自己的文件,因為如果不同的帶寬m3u8都具有相同的名稱,一些播放器會出現問題。

master.m3u8這樣做:

if($sesion !== FALSE) {
$hls = sql("SELECT A.240p,A.480p,A.720p,A.aac,B.duracion FROM data_contenido_archivos A, data_contenido B WHERE A.id = '".limpia($_GET['i'])."' AND B.id = '".limpia($_GET['i'])."'");
if($hls['status'] == "OK") {
    $return = "#EXTM3U\n";
    if($hls['data'][0]['240p'] != "{}") {
        $return .= "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=440000, RESOLUTION=426x240\n";
        $return .= $domains['m3u8']."/240p.m3u8?i=".$id."&s=".$sesion."\n";
    }
    if($hls['data'][0]['480p'] != "{}") {
        $return .= "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=912000, RESOLUTION=854x480\n";
        $return .= $domains['m3u8']."/480p.m3u8?i=".$id."&s=".$sesion."\n";
    }
    if($hls['data'][0]['720p'] != "{}") {
        $return .= "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1840000, RESOLUTION=1280x720\n";
        $return .= $domains['m3u8']."/720p.m3u8?i=".$id."&s=".$sesion."\n";
    }
    if($hls['data'][0]['aac'] != "{}") {
        $retorno .= "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=64000\n";
        $retorno .= $domains['m3u8']."/aac.m3u8?i=".$id."&s=".$sesion."\n";
    }
}
}
header("Content-type: application/x-mpegURL");
echo $return;

它,在數據庫中查詢所有不同的分辨率,並為每個分辨率回顯正確的URL。 如果它不存在(在我的方案中設置為{}),則不會回顯。

然后每個res.m3u8執行以下操作(調用時):

if($sesion) {
$hls = sql("SELECT A.240p,B.duracion FROM data_contenido_archivos A, data_contenido B WHERE A.id = '".limpia($_GET['i'])."' AND B.id = '".limpia($_GET['i'])."'");
if($hls['estado'] == "OK") {
    $data = json_decode($hls['data'][0]['240p'],TRUE);
    // INICIAMOS EL ARCHIVO
    $retorno = "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-MEDIA-SEQUENCE:0\n#EXT-X-ALLOW-CACHE:YES\n#EXT-X-TARGETDURATION:".$data['duration']."\n";
    // CALCULAMOS EL VENCIMIENTO (1.5x DURACION DEL VIDEO)
    $vence = "+".floor($hls['data'][0]['duracion'] / 60)." minutes";
    foreach($data['data'] as $k=>$v) {
        $retorno .= "#EXTINF:".$v['inf'].",\n";
        $retorno .= S3URL("<BUCKET>",$_GET['i']."/240p/segment".$v['ts'].".ts",$vence)."\n";
    }
    $retorno .= "#EXT-X-ENDLIST\n";
}
}
header("Content-type: application/x-mpegURL");
echo $retorno;

這里發生了一些事情,讓我解釋一下:

a.-首先腳本檢查一個有效的會話,如果一個不存在,它會為一個小的10秒視頻提供一個m3u8,說“你沒有權限查看這個”。

b.-如果會話簽出,它會查詢數據庫並獲取所有必需的JSON。 它還查詢另一個表,我存儲文件的持續時間,以便填充TARGETDURATION字符串,並計算要生成的安全S3 URL的生命周期。 我將URL的生命周期設置為視頻長度的1.5倍,它對我有用,您的體驗可能會有所不同。

c.-然后它從數據庫中遍歷每個組,回顯EXTINF並為每個組生成一個安全的URL。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM