flv的格式

flv封裝單元是以tag來表示的,一個tag可以是音頻tag或者視頻tag,或者腳本tag及其其他類型。

一、flv的格式

  • flvheader
  • 腳本tag(metadata)
  • 第一個視頻tag(h264_spspps)
  • 第一個音頻tag(aac_header)
  • 第二個視頻tag(h264第一個關鍵幀)
  • 後面就是音頻和視頻tag交互存在

二、tag的格式:

  • [TYPE] (1byte)
  • [body size] (3byte)
  • [timestamp] (4byte)
  • [stream ID] (3byte)
  • [body data]
  • [previousTagSize] (4byte)

三、flv header

文件頭由 9 bytes 組成

  • [1-3] 前3個 bytes 是文件類型,總是“FLV”,也就是(0x46 0x4C 0x56)。
  • [4] 第4 btye 是版本號,目前一般是 0x01。
  • [5] 第5 byte 是流的信息:倒數第一 bit 是1表示有視頻(0x01),倒數第三 bit 是1表示有音頻(0x4),有視頻又有音頻就是 0x01 | 0x04(0x05),其他都應該是0。
  • [6-9] 最後 4 bytes 表示 FLV 頭的長度,3+1+1+4 = 9。

四、flv body

由若干個 tag (tag header+tag data)組成

[4 bytes 記錄着上一個 tag 的長度]+[11 bytes的tag header]+[tag data]

4.1 tag header

  • [1] 第1個 byte 爲記錄着 tag 的類型,音頻(0x8),視頻(0x9),腳本(0x12);
  • [2-4] 第2到4 bytes 是數據區的長度,也就是 tag data 的長度;
  • [5-7] 再後面3個 bytes 是時間戳,單位是毫秒,類型爲0x12則時間戳爲0;
  • [8] 時間戳後面一個 byte 是擴展時間戳,時間戳不夠長的時候用;
  • [9-11] 最後3 bytes 是 streamID,但是總爲0

第一個tag的前面沒有tag,所以第一個tag前面的previousTagSize就是 00 00 00 00

4.2 tag data

4.2.1 腳本tag data

該類型 Tag 又通常被稱爲Metadata(元數據) Tag,會放一些關於 FLV 視頻和音頻的參數信息,如duration、width、height等。通常該類型 Tag 會跟在 File Header 後面作爲第一個 Tag 出現,而且只有一個。

包含兩個 AMF 包。AMF(Action Message Format)是 Adobe 設計的一種通用數據封裝格式,在Adobe 的很多產品中應用,簡單來說,AMF 將不同類型的數據用統一的格式來描述。

第一個 AMF 包封裝字符串類型數據,用來裝入一個“onMetaData”標誌

第二個 AMF 包封裝一個數組類型,這個數組中包含了音視頻信息項的名稱和值

第一個 AMF 包:

  • [1] 第1個字節表示 AMF 包類型,一般總是0x02,表示字符串,其他值表示意義請查閱文檔。
  • [2-3] 第2-3個字節爲 UI16 類型值,表示字符串的長度,一般總是 0x000A(“onMetaData”長度)。
  • [4-…] 後面字節爲字符串數據,一般總爲“onMetaData”。

第二個AMF包:

  • [1] 第1個字節表示 AMF 包類型,一般總是 0x08,表示數組。
  • [2-5] 第2-5個字節爲 UI32 類型值,表示數組元素的個數。
  • [6-…] 後面即爲各數組元素的封裝,

數組元素爲元素名稱和值組成的對。表示方法如下:

  • [1-2] 第1-2個字節表示元素名稱的長度,假設爲L。
  • [3- L+2] 後面跟着爲長度爲L的字符串。
  • [L+3] 第L+3個字節表示元素值的類型。
  • [L+4-…] 後面跟着爲對應值,佔用字節數取決於值的類型。
4.2.2 音頻tag data

tag data 如果是音頻數據,第一個 byte 記錄 audio 信息:
前 4 bits 表示音頻格式(全部格式請看官方文檔):

  • 0 – 未壓縮
  • 1 – ADPCM
  • 2 – MP3
  • 4 – Nellymoser 16-kHz mono
  • 5 – Nellymoser 8-kHz mono
  • 10 – AAC

下面兩個 bits 表示 samplerate:

  • 0 – 5.5KHz
  • 1 – 11kHz
  • 2 – 22kHz
  • 3 – 44kHz

下面1 bit 表示採樣長度:

  • 0 – snd8Bit
  • 1 – snd16Bit

下面1 bit 表示類型:

  • 0 – sndMomo
  • 1 – sndStereo

之後是數據。

4.2.3 視頻tag data

如果是視頻數據,第一個 byte 記錄 video 信息:
前4 bits 表示類型:

  • 1 – keyframe
  • 2 – inner frame
  • 3 – disposable inner frame (h.263 only)
  • 4 – generated keyframe

後4 bits 表示解碼器 ID:

  • 2 – seronson h.263
  • 3 – screen video
  • 4 – On2 VP6
  • 5 – On2 VP6 with alpha channel
  • 6 – Screen video version 2
  • 7 – AVC (h.264)

之後是數據。

五、實例代碼

char body[1024] = {0}; 
char * p = (char *)body;  
 p = put_byte(p, AMF_STRING );
 p = put_amf_string(p , "@setDataFrame" );

 p = put_byte( p, AMF_STRING );
 p = put_amf_string( p, "onMetaData" );

 p = put_byte(p, AMF_OBJECT );  
 p = put_amf_string( p, "title" );  
 p = put_byte(p, AMF_STRING );  
 p = put_amf_string( p, "ipc" );  

 p =put_amf_string( p, "width");
 p =put_amf_double( p, lpMetaData->nWidth);

 p =put_amf_string( p, "height");
 p =put_amf_double( p, lpMetaData->nHeight);

 p =put_amf_string( p, "framerate" );
 p =put_amf_double( p, lpMetaData->nFrameRate); 

 p =put_amf_string( p, "videocodecid" );
 p =put_amf_double( p, FLV_CODECID_H264 );

 p =put_amf_string( p, "" );
 p =put_byte( p, AMF_OBJECT_END  );

// int index = p-body;

 SendPacket(RTMP_PACKET_TYPE_INFO,(unsigned char*)body,p-body,0);

 int i = 0;
 body[i++] = 0x17; // 1:keyframe  7:AVC
 body[i++] = 0x00; // AVC sequence header

 body[i++] = 0x00;
 body[i++] = 0x00;
 body[i++] = 0x00; // fill in 0;

 // AVCDecoderConfigurationRecord.
 body[i++] = 0x01; // configurationVersion
 body[i++] = lpMetaData->Sps[1]; // AVCProfileIndication
 body[i++] = lpMetaData->Sps[2]; // profile_compatibility
 body[i++] = lpMetaData->Sps[3]; // AVCLevelIndication 
    body[i++] = 0xff; // lengthSizeMinusOne  

    // sps nums
 body[i++] = 0xE1; //&0x1f
 // sps data length
 body[i++] = lpMetaData->nSpsLen>>8;
 body[i++] = lpMetaData->nSpsLen&0xff;
 // sps data
 memcpy(&body[i],lpMetaData->Sps,lpMetaData->nSpsLen);
 i= i+lpMetaData->nSpsLen;

 // pps nums
 body[i++] = 0x01; //&0x1f
 // pps data length 
 body[i++] = lpMetaData->nPpsLen>>8;
 body[i++] = lpMetaData->nPpsLen&0xff;
 // sps data
 memcpy(&body[i],lpMetaData->Pps,lpMetaData->nPpsLen);
 i= i+lpMetaData->nPpsLen;

 return SendPacket(RTMP_PACKET_TYPE_VIDEO,(unsigned char*)body,i,0);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章