◆葉遠(yuǎn)清
(廣州市第十二人民醫(yī)院 廣東 510620)
Flash 曾經(jīng)為互聯(lián)網(wǎng)富媒體領(lǐng)域的主流解決方案,但由于其安全性不斷受到詬病,且隨著HTML5、WebGL 等技術(shù)的不斷成熟,現(xiàn)代瀏覽器已有足夠高的性能和安全的解決方案替代Flash 技術(shù)。Adobe公司宣布于2020 年12 月31 日結(jié)束對FlashPlayer 的分發(fā)和更新,并建議用戶卸載Flash Player;主流的瀏覽器如IE/Edge/Chrome/Firefox等也于該日期后無法使用Flash 技術(shù)。而在過去的20 多年,由于Flash技術(shù)的流行,以及視頻網(wǎng)站的蓬勃發(fā)展,在瀏覽器的HTML 5 技術(shù)還未成熟之時,眾多的公司和視頻網(wǎng)站都是采用服務(wù)器后端存儲FLV視頻格式文件,前端瀏覽器使用Flash Player 播放視頻的技術(shù)架構(gòu)。在Flash 技術(shù)被結(jié)束生命周期后,導(dǎo)致網(wǎng)絡(luò)上以及企業(yè)中已存的FLV格式視頻無法在瀏覽器上正常播放。通常,傳統(tǒng)的方案可以通過使用ffmpeg/mencode 等視頻處理工具將FLV 格式視頻轉(zhuǎn)換成MP4 文件格式,但當(dāng)有大量FLV 視頻文件內(nèi)容時,則需要大量的計算資源對FLV視頻格式進行重新編碼并使用MP4 文件格式重新封裝。本文通過分析FLV 視頻文件格式和MP4 視頻文件格式的特點,研究出一種給原有FLV 視頻文件添加一個合適的MP4 頭部以實現(xiàn)網(wǎng)絡(luò)播放的方案,作為傳統(tǒng)方案的補充方案。
介紹本方案前,先簡單介紹FLV 視頻格式和MP4 格式的基本特點,為了方便述說本方案,以下對FLV 視頻文件格式和MP4 視頻文件格式的介紹都做了簡化,突出本方案使用到的關(guān)鍵部分,其他無關(guān)部分則弱化處理。
FLV 視頻文件是Adobe 開發(fā)的視頻文件格式,可以在網(wǎng)絡(luò)上以流的形式播放。如圖1 所示,F(xiàn)LV 文件主要分為FLV 頭部和FLV 文件主體兩大部分。FLV頭部主要用來標(biāo)識文件是否為FLV格式文件,以及是否包含視頻流、音頻流等情況。FLV 文件主體則包含了具體的視頻流和音頻流等媒體數(shù)據(jù),這些媒體數(shù)據(jù)都封裝在Tag 中,視頻數(shù)據(jù)為Video Tag,音頻數(shù)據(jù)為Audio Tag,Video Tag 和AudioTag 以間隔方式出現(xiàn),一個Video Tag 銜接一個Audio Tag[1-2]。
圖1 FLV 和MP4 的文件格式
Video Tag 中包含Tag Header、Tag Metadata 以及Video Data。Tag Header 標(biāo)識本Tag 是視頻,以及該視頻數(shù)據(jù)所處的時間點等屬性;Tag Metadata 則標(biāo)識本 Tag 所包含的 Video Data 的幀類型(FrameType 如是key frame 還是inter frame),視頻編碼類型(CodecID,如7 表示AVC 編碼)等解碼該視頻數(shù)據(jù)所必須的信息;Video Data 則是包含的具體視頻數(shù)據(jù)。
Audio Tag 也類似,包含Tag Header、Tag Metadata 以及 Audio Data。Tag Header 標(biāo)識本Tag 是音頻,以及該音頻數(shù)據(jù)所處的時間點等屬性;Tag Metadata 則標(biāo)識本Tag 所包含的Audio Data 的音頻格式(SoundFormat,如10 表示AAC 編碼)、音頻采樣率(SoundRate,如3 表示44kHZ)等;Audio Data 則是包含具體的音頻數(shù)據(jù)。
MP4 文件格式與FLV 文件格式相差甚大,其不像FLV 文件那樣,多媒體的Metadata 分布在Video Tag 和Audio Tag 中,而Video Tag和Audio Tag 間隔分布在整個文件中。如圖1 所示,MP4 文件格式主要包含三個數(shù)據(jù)節(jié)點(通常叫box):ftype box:文件類型,描述MP4文件所遵從的規(guī)范版本;moov box:包含正確播放媒體數(shù)據(jù)所需的元數(shù)據(jù)(metadata);mdata box:存儲具體的視頻和音頻等媒體數(shù)據(jù)(有時候還會有多條字幕數(shù)據(jù))[3-4]。
moov box 內(nèi)包含關(guān)鍵的Box 為Trak Box,可以是Video 類型,包含視頻數(shù)據(jù),可以是Audio 類型,包含音頻數(shù)據(jù);每個Trak Box內(nèi)包含stbl box(sample table box):包含媒體樣本(sample)的序號、時間、文件位置映射的信息。stbl box 包含三類關(guān)鍵的box:stsz(sample size box),記錄每個sample 的字節(jié)大??;stsc(sample to chunk box),sample-chunk 的映射表,表示一個chunk 包含了哪些sample;stco(chunk offset box),每個chunk 在mp4 文件中的偏移量,這個偏移量通常是指向mdata 區(qū)的某個位置,如圖2 所示,stco 中的偏移量索引了mdata 中的數(shù)據(jù)塊,而stsz 中的數(shù)據(jù)塊則表示了對應(yīng)數(shù)據(jù)塊的長度,結(jié)合stco 和stsz 就能讀取到對應(yīng)的chunk。當(dāng)播放器播放視頻時,即根據(jù)stco 的chunk offset 找到對應(yīng)的數(shù)據(jù)塊,根據(jù)stsz 和stsc 的信息讀取相應(yīng)的媒體sample 數(shù)據(jù),并對這些數(shù)據(jù)進行解碼播放。
圖2 MP4 頭部中stco 和mdata 的映射關(guān)系
一個MP4 文件包含若干個Trak,一個Trak 包含若干個chunk,一個chunk 包含若干個連續(xù)的sample,而sample 則是媒體數(shù)據(jù)的存儲單位,其可以是video sample,也可以是audio sample,取決于Trak是Video Trak 還Audio Trak。
方案的核心理念則是針對MP4 文件格式的特點,利用其媒體數(shù)據(jù)sample 文件都存儲在mdata 段,而具體索引這些媒體sample 數(shù)據(jù)所需的地址集合、大小、chunk-sample 映射都包含在MP4 文件頭部中的stco、stsz、stcs box 中的特點,考慮到FLV 文件的文件格式是一個video sample 和一個audio sample 間隔排列的特點,我們可以生成一種符合MP4 規(guī)范,但又比較特殊的MP4 文件頭部,拼接在FLV文件的頭部,形成一個MP4 文件。
MP4 文件中的video/audio sample 對應(yīng)FLV 文件中的video/audio data,都是具體為某種編碼的媒體數(shù)據(jù)。如圖3 所示,F(xiàn)LV 文件的一個video/audio tag 數(shù)據(jù)塊包含了tag header、metadata 以及video/audio data,由于tag data、metadata 的存在,在FLV 文件中,video/audio data是不連續(xù)的,導(dǎo)致生成的對應(yīng)的MP4 文件頭部中的stsc box 比較特殊,其中每項表示的每一個chunk 只包含一個sample;而stsz 中的每項則表示了該sample 的大小,stco 中每項表示的偏移量則指向每一個間隔分布在FLV 文件中的video/audio data。
圖3 MP4 頭部stsz/stco 和FLV 文件的映射關(guān)系
具體實現(xiàn)時,對于MP4 文件格式的解析代碼,可具體采用ffmpeg中對應(yīng)的MP4 格式文件解封裝代碼,對于FLV 文件格式的解析代碼,亦可具體采用ffmpeg 中對應(yīng)的FLV 格式文件解封代碼。通過掃描FLV 文件,記錄每個video/audio data 塊的位置和大小,按照MP4 的規(guī)范生成對應(yīng)的MP4 頭部,并將該MP4 頭部拼接在FLV 文件的頭部(類似Linux 命令:cat mp4_header file.flv >>file.mp4),生成的該文件是個標(biāo)準(zhǔn)的MP4 文件,可直接使用支持MP4 格式的播放器進行播放。
對于使用網(wǎng)絡(luò)瀏覽器播放的情況,不需要真實地將該MP4 頭部與FLV 文件進行拼接,可通過Webserver(如nginx)在輸出文件時,先輸出已生成的MP4 頭部,再繼續(xù)輸出對應(yīng)的FLV 文件的方式。從瀏覽器的角度,這就是從后端輸出的一個完整的,符合MP4 規(guī)范的視頻文件,可正常地通過video 標(biāo)簽進行引用,并且能正常地拖動播放,與普通的MP4 文件并無不同[5]。
傳統(tǒng)的處理方案是將FLV 文件重新編碼和封裝成MP4,因為視頻的編解碼本身就是對視頻的有損壓縮,需要大量的計算才能重新對視頻進行編解碼,對于大量的FLV 視頻文件而言,這樣的方案需要大量的計算資源,速度慢,需時長,且生成的新MP4 文件也與原FLV文件大小基本相同,導(dǎo)致占用的存儲空間翻倍。而本文所提供的方案則不需要對原有的FLV 視頻文件做重新編碼,而是基于FLV 以及MP4 格式的封裝特點,只需要掃描FLV 文件生成一個很小的MP4文件頭部,直接索引FLV 文件中的媒體數(shù)據(jù)即可,不會占用大量的服務(wù)器計算資源,也不會占用大量的服務(wù)器存儲空間,方便快捷。對于網(wǎng)絡(luò)上存在的海量FLV 視頻而言,有重大的現(xiàn)實意義。