1. 程式人生 > >在網頁上實現任意格式的音視訊快速播放功能的開發總結。

在網頁上實現任意格式的音視訊快速播放功能的開發總結。

開發重點在pc端,手機端不考慮。

要實現使用者上傳音視訊到伺服器,上傳完畢即可隨意拖動進度條觀看。

h5自帶的video標籤不支援大多數格式的音視訊格式,不考慮。

考慮使用流媒體播放,把源視訊轉成視訊流推到網頁播放器。

使用nginx+nginx-rtmp-module+ffmpeg搭建了個流媒體伺服器,使用rtmp和hls兩種推流方式做實驗,用vlc進行播放併成功,但是發現這是直播,沒有進度,空歡喜一場,不過也瞭解了直播功能的實現。此方案行不通,捨棄。

hls流媒體方式,是一個m3u8檔案,裡面是一個個的視訊片段檔案列表,一堆ts格式的小檔案,所以想用這種方式來實現。

用ffmpeg進行視訊的m3u8自動分段,會生成一個m3u8檔案和一堆ts檔案。

命令: ffmpeg -i 檔名  -c:v libx264 -c:a aac -hls_time 10 -hls_list_size 0  -strict -2 -f hls output.m3u8

-c:v -c:a:分別是視訊音訊的編碼型別

-hls_time n: 設定每片的長度,預設值為2。單位為秒

-hls_list_size n:設定播放列表儲存的最多條目,設定為0會儲存有所片資訊,預設值為5

-hls_wrap n:設定多少片之後開始覆蓋,如果設定為0則不會覆蓋,預設值為0.這個選項能夠避免在磁碟上儲存過多的
片,而且能夠限制寫入磁碟的最多的片的數量
-hls_start_number n:設定播放列表中sequence number的值為number,預設值為0

首先,生成好了檔案,要想辦法能在網頁上進行播放,試了好幾款播放器,最後用了ckplayer,官方幫助文件裡有如何播放m3u8流媒體的方法,原理是使用flash進行播放,一個swf播放器。播放器先請求m3u8檔案,根據檔案列表中的時長算出該視訊的總進度。拖動進度時請求相應的ts檔案。一系列的請求都是由播放器發出的。

嘗試獲取播放器的請求,使用django建立一個工程,設定一個靜態資料夾,把生成好的視訊檔案放進去,網頁上寫好m3u8檔案路徑,就可以正常播放了,但是無法監聽播放器請求。所以就把視訊檔案放到普通資料夾,根據播放器的請求連結,設定一個url對應後臺一個方法,每次請求都會走這個方法,可以獲取到請求的是哪個檔案,請求哪個檔案,我就找到此檔案,以流的方式開啟(open(tsfilepath, 'rb'))並返回,成功播放。

實現任意進度播放,就要根據所請求的檔案,計算出該檔案是從原始檔第幾秒開始,從此處往後擷取視訊片段返回就可以了。

關鍵程式碼如下:

先生成一個臨時檔案

os.system("ffmpeg -i %s -ss %d -t %d  -c:v libx264 -c:a aac -g 5 -sc_threshold 0 %s" % (原始檔路徑, 第幾個ts檔案* 每段多長, 每段多長, 生成ts路徑))
設定此檔案的start_time才能正常播放,具體原理不是很清楚。
os.system("ffmpeg -i %s/%s -ss %d -t %d  -c:v copy -c:a copy -g 5 -sc_threshold 0 %s/%s" % (tsdirpath, tsname, -tsnum * cuttime, cuttime * (tsnum + 1), tsdirpath,  tsfile))
os.system("rm -f %s/%s" % (tsdirpath, tsname))

-ss 開始時間

-t開始時間後的幾秒,也就是這個片段的長度

視訊擷取時-i 和 -ss的前後位置影響很大。

-i在前是根據關鍵幀進行查詢,速度快。

-i在後是逐幀查詢,速度非常慢,精度高,適合小檔案。

詳情見:http://trac.ffmpeg.org/wiki/Seeking點選開啟連結

總結:

1、手動生成m3u8檔案,需要獲取檔案總時長,設定每個片段長度。
 filemsg = os.popen("ffprobe -v error -show_entries format=duration -print_format json %s" % srcvideopath).read()
print(filemsg)
length = float(json.loads(filemsg)['format']['duration'])

2、根據請求生成對應ts檔案並返回。