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

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 时已经计算出来了,并留好空间,在此写入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);/*下面写入关键帧的位置,以便于加快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);}/*下面写入关键帧的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);}/* 给每个video stream 写入EOS tag, 疑问audio tag 不需要EOS tag 吗?假如audio 早于video 结束,是否会出现有画面无声音 */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 到此结束
}

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相关推荐

  1. [转]web实时视频流从0到1(ffmpeg+nginx-http-flv-module+flv.js)

    海康威视视频流rtsp,需要在web(Vue)页面显示,探索了很多方法,考虑到兼容,最终确定 ffmpeg+nginx-http-flv-module+flv.js 这一套方案,也推荐大家使用这一套方 ...

  2. 用ffmpeg转换flv至mpeg

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 原贴:h ...

  3. (保姆级)利用ffmpeg将flv批量转mp4

    文章目录 1. 下载ffmpeg 2. 安装ffmpeg 3. flv转mp4 4. 批量转换 1. 下载ffmpeg 进入ffmpeg官网,选择需要的版本进行下载: 以windows为例,点击下图红 ...

  4. 采用ffmpeg转换flv视频到mp4格式时报错的解决方案

    1. ffmpeg支持如下格式转换视频 $ffmpeg -i 源文件  目标文件 如: $ffmpeg -i hello.flv hello.mpeg $ffmpeg -i hello.flv hel ...

  5. 使用FFmpeg + nginx + flv.js 实现RTSP格式视频流在web网页进行播放

    近期,出于项目需要,要求支持web网页播放RTSP格式的监控视频.因之前并没有相关的项目经验及技术积累.并且H5中的video默认并不支持RTSP格式的视频播放,接下来花了一周时间,都在进行调研和实践 ...

  6. vlc搭建rtsp直播Demo ffmpeg + nginx + flv.js实现rtsp网页播放Demo

    文章目录 学习链接 本地视频文件作为数据源 推流步骤 拉流步骤 本地摄像头作为数据源 拉流步骤 vlc + ffmpeg + nginx + flv.js 实现网页视频直播 概括 vlc打开摄像头,提 ...

  7. web实时视频流从0到1(ffmpeg+nginx-http-flv-module+flv.js)

    海康威视视频流rtsp,需要在web(Vue)页面显示,探索了很多方法,考虑到兼容,最终确定 ffmpeg+nginx-http-flv-module+flv.js 这一套方案,也推荐大家使用这一套方 ...

  8. android ffmpeg 编码h264,Mac系统下ffmpeg+h264+flv编码的android录制屏幕实现2

    接上一篇. activity_flv.xml xmlns:tools="http://schemas.android.com/tools" android:layout_width ...

  9. ffmpeg 转换flv压缩大小_ffmpeg转换参数和压缩输出大小的比率 参考 最新版本FFMPEG...

    https://blog.cnlabs.NET/3668.html ffmpeg 转换压缩比例 FFMPEG如果是压缩为FLV文件 3个编码可选 1. -c:v flv 标准FLV编码 这个好处是速度 ...

最新文章

  1. Mysql INSERT、REPLACE、UPDATE的区别
  2. SQL Developer更改日期显示格式
  3. 局部图像描述子——Harris角点检测器
  4. mysql格式化小数保留小数点后两位(小数点格式化)
  5. java循环基础知识_java基础知识—循环结构
  6. Android junit单元测试
  7. c++ string长度_String.format()的简单使用
  8. router中获取vuex_JS每日一题: 什么情况下适合使合vuex?Vuex使用中有几个步骤?...
  9. Android四大组件之 --- Service入门
  10. 五月天歌曲下载【专辑整理版】
  11. vs2019怎么样建立头文件_VS2019库头文件的使用
  12. Android apk签名
  13. w10计算机恢复出厂设置,如何给win10系统的电脑强制恢复出厂设置
  14. Python脚本调用谷歌浏览器的谷歌翻译
  15. 【NOIP模拟赛】【数学真奇妙系列】纸盒子
  16. 蓝桥杯 ADV-222 求arccos
  17. obs直播软件 android,斗鱼游戏直播教程-OBS直播软件篇
  18. java获得指定时间的时间戳
  19. EasyNVR HLS流播放中断是什么原因?该如何解决?
  20. 解决mac上Xmind8编辑卡顿的问题

热门文章

  1. SAS2x28扩展卡
  2. 首师大附中互测题:LJX的校园:入学典礼【C003】
  3. 【区块链论文整理】SIGMOD 篇 (二)
  4. sigmod 函数与softmax 函数对比
  5. 教你六种方式实现聊天室
  6. 清华大学计算机学院院庆,清华计算机系2014年校庆系列活动
  7. 洛谷P5520 [yLOI2019] 青原樱 题解
  8. 80老翁谈人生(40):加快步伐,坚定信念,继续前行
  9. [练气期]计算机视觉之从矩阵本质修炼图像几何变换秘籍
  10. HDU 6438 Buy and Resell【贪心】