FFmpeg之FLV Muxing Demuxing
1、FLV簡介
FLV是Adobe發布的一種可作為直播也可作為點播的封裝格式,其封裝格式非常簡單,并且每個tag獨立存在。常應用于網絡的點播與直播場景中,比如常見的流媒體協議rtmp與flv格式兼容的非常好,比如rtmp與flv封裝數據packet格式是一樣的。查看資料發現rtmp與flv出自于一家,都是Adobe公司的產品。
2 、flv標準格式介紹
flv = flv header +body 構成,body則是有一個個 tag 組成。常見的tag類型有三種,script tag,audio/video tag。其中script tag是第一個tag,存到媒體信息,比如視頻寬高,duration等等。
本文福利, 免費領取C++音視頻學習資料包、技術視頻/代碼,內容包括(音視頻開發,面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點擊免費領取↓↓
3 、flv muxing
在FFmpeg? 中,muxing flv 的文件位于libavformat/flvenc.c , 其主要開出三支API 給上層調用,flv_write_header(),flv_write_packet(),flv_write_trailer()。
AVOutputFormat ff_flv_muxer = {.name = "flv",.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),.mime_type = "video/x-flv",.extensions = "flv",.priv_data_size = sizeof(FLVContext),.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF,.video_codec = AV_CODEC_ID_FLV1,.write_header = flv_write_header,.write_packet = flv_write_packet,.write_trailer = flv_write_trailer,.codec_tag = (const AVCodecTag* const []) {flv_video_codec_ids, flv_audio_codec_ids, 0},.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |AVFMT_TS_NONSTRICT,.priv_class = &flv_muxer_class, }; ##3.1 flv_write_header()
flv_write_header() 主要是對flv header 以及存放meta 的script tag 寫入。其主要流程如下:
flv_write_header() ,可以看到調用avio_write(pb,“FLV”,3);寫入FLV 表示頭,然后還調其他幾個avio_xxx() 函數寫入FLV header。具體代碼如下:
avio_write(pb, "FLV", 3);//寫入"FLV"標識avio_w8(pb, 1);//版本號1,占一個字節avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_par +FLV_HEADER_FLAG_HASVIDEO * !!flv->video_par);//音頻,視頻是否存在flag 位avio_wb32(pb, 9);//data offset ,表明flv header 占9個字節avio_wb32(pb, 0);//previos tag len 仍為0我們在來看下一個具體的FLV header 對應的二進制:
可以看出FFMPEG 是完全符合FLV header 協議規范的。
我們在來看看write_metadata()函數,它寫入的是script tag ,是FLV 文件的第一個tag ,存放meta 信息。如下代碼刪減不重要的行數 并加入注釋:
static void write_metadata(AVFormatContext *s, unsigned int ts) {AVIOContext *pb = s->pb;//文件IO函數FLVContext *flv = s->priv_data;//AVFormatContext中的priv_data 實際存放是就是FLVContext/* write meta_tag */avio_w8(pb, FLV_TAG_TYPE_META); //Script tag標識 0x12flv->metadata_size_pos = avio_tell(pb);avio_wb24(pb, 0); // size of data part (sum of all parts below)avio_wb24(pb, ts); // timestampavio_wb32(pb, 0); // reserved/*在了解script data 之前,先自行學習下AMF(Action Message Format),它是一種標準的的Flash 與服務端通信格式,meta 信息就是AMF格格式來存放的 。*/avio_w8(pb, AMF_DATA_TYPE_STRING);//AMFput_amf_string(pb, "onMetaData"); // 12 bytes/* mixed array (hash) with size and string/type/data tuples */avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);//相當于鍵值對,key,value 形式。avio_wb32(pb, metadata_count);//寫入鍵值對個數put_amf_string(pb, "duration");flv->duration_offset = avio_tell(pb);put_amf_double(pb, s->duration / AV_TIME_BASE);put_amf_string(pb, "width");put_amf_double(pb, flv->video_par->width);put_amf_string(pb, "height");put_amf_double(pb, flv->video_par->height);..............................接著是flv_write_codec_header()函數,主要針對特殊的編解碼格式寫入一些info , 比如針對AAC 格式寫入ADTS頭,因為每一幀AAC 數據都需要加入這個頭才能播放.而對應的AAC Audio frame 可能無此信息。
3.2 flv_write_packet()
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt), 其作用是加入tag 頭 ,并將Audio/video data 寫入FLV 文件中,其流程為:1 寫入TAG 類型,2 寫入datasize, 3 寫入timestamp, 4 寫入streameID ,5 寫入TAG Data,6 寫入previous tag size
3.2 flv_write_trailer()
static int flv_write_trailer(AVFormatContext *s) 也是寫入一些meta 信息,與flv_write_header() 不同的是,Flv_write_trailer() 寫入是一些只有Muxing才能知道的信息,比如Videodatasize,Audiodatasize,Filesize,duration 等等。
?
4 補充部分
1 看flv_write_packet() 函數,是有存放字幕功能的。
if (par->codec_type == AVMEDIA_TYPE_DATA ||par->codec_type == AVMEDIA_TYPE_SUBTITLE ) {int data_size;int64_t metadata_size_pos = avio_tell(pb);if (par->codec_id == AV_CODEC_ID_TEXT) {// legacy FFmpeg magic?avio_w8(pb, AMF_DATA_TYPE_STRING);put_amf_string(pb, "onTextData");avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);avio_wb32(pb, 2);put_amf_string(pb, "type");avio_w8(pb, AMF_DATA_TYPE_STRING);put_amf_string(pb, "Text");put_amf_string(pb, "text");avio_w8(pb, AMF_DATA_TYPE_STRING);put_amf_string(pb, pkt->data);put_amf_string(pb, "");avio_w8(pb, AMF_END_OF_OBJECT);} else {// just pass the metadata throughavio_write(pb, data ? data : pkt->data, size);}2 標準的FLV 文件是不帶keyframe 索引信息的,但應其廣泛使用,已經稱為常用字段,因此FFMPEG 也支持這功能。
for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) {put_amf_double(pb, newflv_posinfo->keyframe_position + flv->keyframe_index_size); } for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) {put_amf_double(pb, newflv_posinfo->keyframe_timestamp); }?3 FLV script tag 的 metadata 信息是以AMF 格式存儲的。它是它是一種標準的的Flash 與服務端通信格式,應用范圍很廣。
typedef enum {AMF_DATA_TYPE_NUMBER = 0x00,//double 類型,8個字節AMF_DATA_TYPE_BOOL = 0x01,//bool 類型,1 字節AMF_DATA_TYPE_STRING = 0x02,//string 類型,len 需指定AMF_DATA_TYPE_OBJECT = 0x03,//key / value形式,AMF_DATA_TYPE_NULL = 0x05,AMF_DATA_TYPE_UNDEFINED = 0x06,AMF_DATA_TYPE_REFERENCE = 0x07,AMF_DATA_TYPE_MIXEDARRAY = 0x08,//存放多個key/value,FLV meta info 就是這樣存放的AMF_DATA_TYPE_OBJECT_END = 0x09,AMF_DATA_TYPE_ARRAY = 0x0a,AMF_DATA_TYPE_DATE = 0x0b,AMF_DATA_TYPE_LONG_STRING = 0x0c,AMF_DATA_TYPE_UNSUPPORTED = 0x0d, } AMFDataType;本文福利, 免費領取C++音視頻學習資料包、技術視頻/代碼,內容包括(音視頻開發,面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點擊免費領取↓↓?
總結
以上是生活随笔為你收集整理的FFmpeg之FLV Muxing Demuxing的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Test Fore
- 下一篇: Linux开发环境部署