flv.js的使用方法

這篇文章主要介紹了flv.js的使用方法,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創新互聯是專業的浠水網站建設公司,浠水接單;提供成都網站制作、成都網站建設,網頁設計,網站設計,建網站,PHP網站建設等專業做網站服務;采用PHP框架,可快速的進行浠水網站開發網頁制作和功能擴展;專業做搜索引擎喜愛的網站,專業的做網站團隊,希望更多企業前來合作!

flv.js項目的代碼有一定規模,如果要研究的話,我建議從demux入手,理解了demux就掌握了媒體數據處理的關鍵步驟,前面的媒體數據下載和后面的媒體數據播放就變得容易理解了。

  先普及點背景知識,為什么HTML5視頻播放要用 flv 格式?

  因為Flash。我標題圖片用的是“flash RIP”,flash快死了,但是它的影響力還在,flash技術是過去10多年的互聯網視頻基礎技術,大量相關基礎設施都是圍繞Flash構建的,比如 cdn 普遍支持的 RTMP 和 flv over http協議。做互聯網直播的公司為了能兼容Web上的Flash播放,不約而同地選擇了flv的媒體格式。在從Flash到 HTML5過渡的時期,如果HTML5能支持flash的協議是再好不過了,可以平滑過渡,然而HTML5并不原生支持flash協議。flv.js這個項目解決了HTML5支持flash協議的問題,這就是flv.js應運而生短期爆紅的歷史背景。

  flv.js 中的demux就是一套 FLV 媒體數據格式的解析器,如果要理解FLV格式,下面的文檔是必須熟讀的。
Adobe官方的flv格式說明
http://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf

flv.js怎么用? 下面進入正題,flv.js代碼解讀:demux部分

  打開代碼 https://github.com/Bilibili/flv.js/blob/master/src/demux/flv-demuxer.js

 static probe(buffer) {
        let data = new Uint8Array(buffer);
        let mismatch = {match: false};

        if (data[0] !== 0x46 || data[1] !== 0x4C || data[2] !== 0x56 || data[3] !== 0x01) {
            return mismatch;
        }

  0x46 0x4c 0x56 這幾個數字其實就是 'F' 'L' 'V' 的ascii碼,表示flv文件頭,后面的0x01是flv格式的版本號,用這來檢測數據是不是 flv 格式。

let hasAudio = ((data[4] & 4) >>> 2) !== 0;
let hasVideo = (data[4] & 1) !== 0;

  取出第五個字節,它的第六 和 第八 bit 分別表示是否存在 音頻和視頻數據,其它位是保留位可以忽略。

  這個probe是被 parseChunks 調用的,當讀取了至少13個字節后,就判斷下是否是一個flv數據,然后再繼續后面的分析。為什么是13,因為flv的文件頭就是13個字節,參考 上面 PDF里的 “The FLV header”,這13個字節包括了后面的一個四字節的size,這個size表示前一個tag的大小,但是由于第一個tag是不存在前一個的,所以第一個size總是 0。

  parseChunks 后面的代碼就是在不斷解析 tag,flv把一段媒體數據稱為 TAG,每個tag有不同的type,實際上真正用到的只有三種type,8、9、18 分別對應,音頻、視頻和Script Data。

 if (tagType !== 8 && tagType !== 9 && tagType !== 18) {
                Log.w(this.TAG, `Unsupported tag type ${tagType}, skipped`);
                // consume the whole tag (skip it)
                offset += 11 + dataSize + 4;
                continue;
            }

  這段代碼就在判斷tag type,注意看 那個 數字 11,因為tag header是11個字節,后面就是tag body了,所以offset加上這些偏移是為了跳到下一個tag的位置。

  tag header的格式為:UI 表示 unsigned int,后面的是bit數。

UI8 tag type
UI24 data size
UI24 timestamp
UI8 TimestampExtended
UI24 StreamID

  你看是不是正好 11 個字節,adobe為了節約流量,能用24bit表示的絕不用32bit,但是還是給timestamp設置了一個 擴展位存放最高位的字節,這個設計很蛋疼,于是導致了下面這段奇葩代碼,先取三個字節按照Big-Endian轉換成整數再在高位放上第四個字節。

let ts2 = v.getUint8(4);
let ts1 = v.getUint8(5);
let ts0 = v.getUint8(6);
let ts3 = v.getUint8(7);
let timestamp = ts0 | (ts1 << 8) | (ts2 << 16) | (ts3 << 24);

  解析完了 tag header后面分別按照不同的 tag type調用不同的解析函數。

switch (tagType) {
    case 8:  // Audio
        this._parseAudioData(chunk, dataOffset, dataSize, timestamp);
        break;
    case 9:  // Video
        this._parseVideoData(chunk, dataOffset, dataSize, timestamp, byteStart + offset);
        break;
    case 18:  // ScriptDataObject
        this._parseScriptData(chunk, dataOffset, dataSize);
        break;
}

TAG type:8 音頻

  音頻結構比較簡單,AUDIODATA的第一個字節表示音頻格式,其實基本都是 ACC 16bit 立體聲 44.1kHz采樣,所以最常見的數字就是 0xAF,后面一般就是 AACAUDIODATA了

TAG type : 9 視頻

  重點看的是視頻,

let frameType = (spec & 240) >>> 4;
let codecId = spec & 15;

  這里取兩個重要的值,frameType表示幀類型 1 是關鍵幀 2 是非關鍵幀,codeId是編碼類型。雖然flv支持 六種視頻格式,但是實際上互聯網點播直播真正在用的基本只有H.264一種。所以codecId基本都是7。這里作者用了十進制的數,其實就是按位取值,用16進制的數會更好理解。

  _parseAVCVideoPacket 用來解析 AVCVIDEOPACKET 結構,就是H.264的視頻包

let packetType = v.getUint8(0);
let cts = v.getUint32(0, !le) & 0x00FFFFFF;

  解釋下 CTS的概念,CompositionTime,我們前面在tag header里拿到過一個 timestamp,這個在視頻里對應于DTS,就是解碼時間戳,而CTS實際上是一個offset,表示 PTS相對于DTS的偏移量,就是 PTS和DTS的差值。

  這里有個坑,參考adobe的文檔,這是CTS是個有符號的24位整數,SI24,就是說它有可能是個負數,所以我懷疑flv.js解析cts的代碼有bug,沒有處理負數情況。因為負數的24位整型到32位負數轉換的時候要手工處理高位的符號位和補碼問題。(我只是懷疑,沒有調試確認過,但是我在處理YY直播數據的時候是踩過這個坑的,個別包含 B frame的視頻是會出現CTS為負數的情況的)

flv.js的使用方法

  packetType有兩種,0 表示 AVCDecoderConfigurationRecord,這個是H.264的視頻信息頭,包含了 sps 和 pps,AVCDecoderConfigurationRecord的格式不是flv定義的,而是264標準定義的,如果用ffmpeg去解碼,這個結構可以直接放到 codec的extradata里送給ffmpeg去解釋。

  flv.js作者選擇了自己來解析這個數據結構,也是迫不得已,因為JS環境下沒有ffmpeg,解析這個結構主要是為了提取 sps和pps。雖然理論上sps允許有多個,但其實一般就一個。

let config = SPSParser.parseSPS(sps);

  pps的信息沒什么用,所以作者只實現了sps的分析器,說明作者下了很大功夫去學習264的標準,其中的Golomb解碼還是挺復雜的,能解對不容易,我在PC和手機平臺都是用ffmpeg去解析的。SPS里面包括了視頻分辨率,幀率,profile level等視頻重要信息。

  packetTtype 為 1 表示 NALU,NALU= network abstract layer unit,這是H.264的概念,網絡抽象層數據單元,其實簡單理解就是一幀視頻數據。

  NALU的頭有兩種標準,一種是用 00 00 00 01四個字節開頭這叫 start code,另一個叫mp4風格以Big-endian的四字節size開頭,flv用了后一種,而我們在H.264的裸流里常見的是前一種。

TAG type : 18 Script Data

  除了音視頻數據外還有 ScriptData,這是一種類似二進制json的對象描述數據格式,JavaScript比較慘只能自己寫實現,其它平臺可以用 librtmp的代碼去做。

  我覺得作者處理解決flv播放問題外,也為前端貢獻了 amf 解析,sps解析,Golomb解碼等基礎代碼,這些是可以用在其他項目里的。

  在用傳輸協議獲取了flv數據流后,用demux分離出音視頻數據的屬性和數據包,這為后面的播放打下了基礎,從demux入手去讀代碼是個不錯的切入點,而且一定要配合 flv file format spec一起看,反復多看幾遍爭取熟記在心。我現在已經可以從wireshark的抓包數據里人肉分析flv數據包了,對于debug相當有幫助。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“flv.js的使用方法”這篇文章對大家有幫助,同時也希望大家多多支持創新互聯,關注創新互聯行業資訊頻道,更多相關知識等著你來學習!

新聞標題:flv.js的使用方法
文章來源:http://m.kartarina.com/article46/jedphg.html

成都網站建設公司_創新互聯,為您提供網站維護網站導航網站策劃Google網站收錄微信公眾號

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

h5響應式網站建設
主站蜘蛛池模板: 亚洲午夜无码毛片av久久京东热| 亚洲GV天堂无码男同在线观看| 亚洲AV综合色区无码一二三区 | 五月丁香六月综合缴清无码| 日本无码小泬粉嫩精品图| 无码国产精品一区二区免费式芒果| 亚洲日韩精品无码AV海量| 亚洲人成无码网WWW| 人妻丰满熟妇AV无码片| 永久免费无码网站在线观看个| 国产激情无码一区二区| 久久亚洲中文无码咪咪爱| 色偷偷一区二区无码视频| 免费无码又爽又刺激毛片| 亚洲av无码av制服另类专区| 亚洲中文字幕久久精品无码2021| 精品久久久久久中文字幕无码| 精品无码久久久久久久久 | 亚洲VA中文字幕无码毛片 | 亚洲gv猛男gv无码男同短文 | 大胆日本无码裸体日本动漫| 亚洲国产精品无码久久久秋霞2| 精品久久久久久无码人妻| 久久久久亚洲精品无码蜜桃| 亚洲AV无码国产精品麻豆天美| 无码人妻精品一区二区蜜桃百度 | 亚洲AV无码专区在线亚| 国产乱子伦精品无码码专区| 国产精品一区二区久久精品无码| 久久久久久久久免费看无码| 无码中文字幕乱码一区| 亚洲精品无码专区在线播放| 一本大道在线无码一区| 亚洲av无码片在线观看| 亚洲成无码人在线观看| 久久AV无码精品人妻糸列| 人妻无码一区二区不卡无码av| 亚洲av成人无码久久精品| 午夜不卡无码中文字幕影院| 无码av最新无码av专区| 日韩精品久久无码人妻中文字幕|