Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()
ffmpeg 源代码简单分析 : av_read_frame()
http://blog.csdn.net/leixiaohua1020/article/details/12678577
ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如,解码视频的时候,每解码一个视频帧,需要先调 用 av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码(例如H.264中一帧压缩数据通常对应一个NAL)。
对该函数源代码的分析是很久之前做的了,现在翻出来,用博客记录一下。
上代码之前,先参考了其他人对av_read_frame()的解释,在此做一个参考:
通
过av_read_packet(***),读取一个包,需要说明的是此函数必须是包含整数帧的,不存在半帧的情况,以ts流为例,是读取一个完整的
PES包(一个完整pes包包含若干视频或音频es包),读取完毕后,通过av_parser_parse2(***)分析出视频一帧(或音频若干帧),
返回,下次进入循环的时候,如果上次的数据没有完全取完,则st =
s->cur_st;不会是NULL,即再此进入av_parser_parse2(***)流程,而不是下面的
av_read_packet(**)流程,这样就保证了,如果读取一次包含了N帧视频数据(以视频为例),则调用
av_read_frame(***)N次都不会去读数据,而是返回第一次读取的数据,直到全部解析完毕。
http://hi.baidu.com/cuihuanyubupt/item/75f21dfbd2f18e1fff358229
Ffmpeg解析media容器过程
1)调用av_read_frame函数
如果packet_buffer存在数据,根据pts返回AVPacket
如果packet_buffer不存在数据调用函数av_read_frame_internal
在 ffmpeg中实现了将format格式的packet,最终转换成一帧帧的packet,并解析填充了packet的pts,dts,等信息,为最终解 码提供了重要的数据,av_read_frame_internal,调用av_read_packet,每次只读取一个包,然后直到parser完这个 包的所有数据,才开始读取下一个包,parser完的数据被保存在parser结构的数据缓冲中,这样即使av_read_packet读取的下一包和前 一包的流不一样,由于parser也不一样,所以实现了av_read_frame_internal这个函数调用,可以解析出不同流的es流,而 av_read_frame_internal函数除非出错否则必须解析出一帧数据才能返回
调用函数av_parser_parse2(***)分析出视频一帧(或音频若干帧)
2)ffmpeg对媒体容器格式封装在AVInputFormat结构体中,如:
AVInputFormat ff_w64_demuxer = {
"w64",
NULL_IF_CONFIG_SMALL("SonyWave64 format"),
sizeof(WAVContext),
w64_probe,
w64_read_header,
wav_read_packet,
NULL,
wav_read_seek,
.flags = AVFMT_GENERIC_INDEX,
.codec_tag = (const AVCodecTag*const []){ff_codec_wav_tags, 0},
};
对格式定义了read_header,read_packet,read_seek函数,来读数据
3)ffmpeg定义AVCodecParser用来对不同视频编码标准,分析出一个完整的一帧,如
AVCodecParser ff_h264_parser = {
{ CODEC_ID_H264 },
sizeof(H264Context),
init,
h264_parse,
close,
h264_split,
};
h.264的parser
4)h.264 decoder
AVCodec ff_h264_decoder = {
"h264",
AVMEDIA_TYPE_VIDEO,
CODEC_ID_H264,
sizeof(H264Context),
ff_h264_decode_init,
NULL,
ff_h264_decode_end,
decode_frame,
/*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |
CODEC_CAP_FRAME_THREADS |
CODEC_CAP_SLICE_THREADS,
.flush= flush_dpb,
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
.profiles = NULL_IF_CONFIG_SMALL(profiles),
};
最新文章
- 【填坑】bzoj3224 splay裸题
- 关于C#垃圾回收
- linux之PATH环境变量
- position定位
- https协议了解,以及相关协议的解析
- C++ inline
- NuGet更新引用Dll
- ios pyudaren
- 转: Div与table的区别
- ligerui grid行编辑示例
- linux 使用sudo开放普通用户权限
- 在程序加载过程中显示ProgressDialog 对话框
- ROS_Kinetic_10 ROS程序基础Eclipse_C++(一)
- The Beam Model:Stream &;amp; Tables翻译(上)
- MATLAB程序:用FCM分割脑图像
- 库数据有则修改,无则新增sql
- STL之partition学习
- java子类数组的引用转换成超类数组的引用
- Kudu原理-kudu的底层数据模型
- Paxos算法1-算法形成理论[转载]
热门文章
- [转]IP_ADD_MEMBERSHIP : 组播错误 的解决方法:
- NPOI导出Excel文件,对单元格的一些设置
- ASCII Table
- c++ 中static关键字
- P3382: [Usaco2004 Open]Cave Cows 3 洞穴里的牛之三
- 【工作总结】LLDB调试技巧 - 篇一
- 软件工程课后作业——四则运算Ⅲ(C++)
- 为什么Linux的fdisk分区时第一块磁盘分区的First Sector是2048?
- MyEclipse运行很慢的原因
- sourceInsight使用技巧,持续更新中~~~