日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FFmpeg之FLV Muxing Demuxing

發(fā)布時(shí)間:2024/3/13 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FFmpeg之FLV Muxing Demuxing 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、FLV簡介

FLV是Adobe發(fā)布的一種可作為直播也可作為點(diǎn)播的封裝格式,其封裝格式非常簡單,并且每個(gè)tag獨(dú)立存在。常應(yīng)用于網(wǎng)絡(luò)的點(diǎn)播與直播場(chǎng)景中,比如常見的流媒體協(xié)議rtmp與flv格式兼容的非常好,比如rtmp與flv封裝數(shù)據(jù)packet格式是一樣的。查看資料發(fā)現(xiàn)rtmp與flv出自于一家,都是Adobe公司的產(chǎn)品。

2 、flv標(biāo)準(zhǔn)格式介紹

flv = flv header +body 構(gòu)成,body則是有一個(gè)個(gè) tag 組成。常見的tag類型有三種,script tag,audio/video tag。其中script tag是第一個(gè)tag,存到媒體信息,比如視頻寬高,duration等等。

本文福利, 免費(fèi)領(lǐng)取C++音視頻學(xué)習(xí)資料包、技術(shù)視頻/代碼,內(nèi)容包括(音視頻開發(fā),面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點(diǎn)擊免費(fèi)領(lǐng)取↓↓

3 、flv muxing

在FFmpeg? 中,muxing flv 的文件位于libavformat/flvenc.c , 其主要開出三支API 給上層調(diào)用,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() 主要是對(duì)flv header 以及存放meta 的script tag 寫入。其主要流程如下:

flv_write_header() ,可以看到調(diào)用avio_write(pb,“FLV”,3);寫入FLV 表示頭,然后還調(diào)其他幾個(gè)avio_xxx() 函數(shù)寫入FLV header。具體代碼如下:

avio_write(pb, "FLV", 3);//寫入"FLV"標(biāo)識(shí)avio_w8(pb, 1);//版本號(hào)1,占一個(gè)字節(jié)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個(gè)字節(jié)avio_wb32(pb, 0);//previos tag len 仍為0

我們?cè)趤砜聪乱粋€(gè)具體的FLV header 對(duì)應(yīng)的二進(jìn)制:

可以看出FFMPEG 是完全符合FLV header 協(xié)議規(guī)范的。

我們?cè)趤砜纯磜rite_metadata()函數(shù),它寫入的是script tag ,是FLV 文件的第一個(gè)tag ,存放meta 信息。如下代碼刪減不重要的行數(shù) 并加入注釋:

static void write_metadata(AVFormatContext *s, unsigned int ts) {AVIOContext *pb = s->pb;//文件IO函數(shù)FLVContext *flv = s->priv_data;//AVFormatContext中的priv_data 實(shí)際存放是就是FLVContext/* write meta_tag */avio_w8(pb, FLV_TAG_TYPE_META); //Script tag標(biāo)識(shí) 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 之前,先自行學(xué)習(xí)下AMF(Action Message Format),它是一種標(biāo)準(zhǔn)的的Flash 與服務(wù)端通信格式,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);//相當(dāng)于鍵值對(duì),key,value 形式。avio_wb32(pb, metadata_count);//寫入鍵值對(duì)個(gè)數(shù)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()函數(shù),主要針對(duì)特殊的編解碼格式寫入一些info , 比如針對(duì)AAC 格式寫入ADTS頭,因?yàn)槊恳粠珹AC 數(shù)據(jù)都需要加入這個(gè)頭才能播放.而對(duì)應(yīng)的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

static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) {avio_w8(pb, FLV_TAG_TYPE_VIDEO);//寫入Video /Audio tag typeavio_wb24(pb, size + flags_size);put_timestamp(pb, ts);//ts = pkt->dts, genavio_wb24(pb, flv->reserved);//保留位avio_write(pb, data ? data : pkt->data, size);//寫入video/audio dataavio_wb32(pb, size + flags_size + 11); // 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 等等。
?

static int flv_write_trailer(AVFormatContext *s) {avio_seek(pb, flv->videosize_offset, SEEK_SET);//videosize_offset 在寫header 時(shí)已經(jīng)計(jì)算出來了,并留好空間,在此寫入put_amf_double(pb, flv->videosize);//video sizeavio_seek(pb, flv->audiosize_offset, SEEK_SET);put_amf_double(pb, flv->audiosize);//audio sizeavio_seek(pb, flv->lasttimestamp_offset, SEEK_SET);put_amf_double(pb, flv->lasttimestamp);avio_seek(pb, flv->lastkeyframetimestamp_offset, SEEK_SET);put_amf_double(pb, flv->lastkeyframetimestamp);avio_seek(pb, flv->lastkeyframelocation_offset, SEEK_SET);put_amf_double(pb, flv->lastkeyframelocation + flv->keyframe_index_size);avio_seek(pb, cur_pos, SEEK_SET);avio_seek(pb, flv->keyframes_info_offset, SEEK_SET);/*下面寫入關(guān)鍵幀的位置,以便于加快seek速度,存放位置在頭部的Script tag 中 */put_amf_string(pb, "filepositions");put_amf_dword_array(pb, flv->filepositions_count);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);}/*下面寫入關(guān)鍵幀的timestamp,存放位置也在頭部的Script tag 中 */put_amf_string(pb, "times");put_amf_dword_array(pb, flv->filepositions_count);for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) {put_amf_double(pb, newflv_posinfo->keyframe_timestamp);}/* 給每個(gè)video stream 寫入EOS tag, 疑問audio tag 不需要EOS tag 嗎?假如audio 早于video 結(jié)束,是否會(huì)出現(xiàn)有畫面無聲音 */for (i = 0; i < s->nb_streams; i++) {if (par->codec_type == AVMEDIA_TYPE_VIDEO &&(par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4))put_avc_eos_tag(pb, sc->last_ts);}file_size = avio_tell(pb);put_amf_double(pb, file_size);//最后寫入file size ,FLV Muxing 到此結(jié)束 }

4 補(bǔ)充部分

1 看flv_write_packet() 函數(shù),是有存放字幕功能的。

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 標(biāo)準(zhǔn)的FLV 文件是不帶keyframe 索引信息的,但應(yīng)其廣泛使用,已經(jīng)稱為常用字段,因此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 格式存儲(chǔ)的。它是它是一種標(biāo)準(zhǔn)的的Flash 與服務(wù)端通信格式,應(yīng)用范圍很廣。

typedef enum {AMF_DATA_TYPE_NUMBER = 0x00,//double 類型,8個(gè)字節(jié)AMF_DATA_TYPE_BOOL = 0x01,//bool 類型,1 字節(jié)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,//存放多個(gè)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;

本文福利, 免費(fèi)領(lǐng)取C++音視頻學(xué)習(xí)資料包、技術(shù)視頻/代碼,內(nèi)容包括(音視頻開發(fā),面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點(diǎn)擊免費(fèi)領(lǐng)取↓↓?

總結(jié)

以上是生活随笔為你收集整理的FFmpeg之FLV Muxing Demuxing的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。