专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
stormzhang  ·  又被平均了? ·  昨天  
鸿洋  ·  Android系统native进程之我是in ... ·  2 天前  
郭霖  ·  Android ... ·  4 天前  
郭霖  ·  Android 跨进程+解耦的数据持久化方案 ·  1 周前  
郭霖  ·  Android ... ·  1 周前  
51好读  ›  专栏  ›  郭霖

ffmpeg源码简析之结构总览

郭霖  · 公众号  · android  · 2017-08-01 08:00

正文

今日科技快讯

昨日腾讯市值突破3万亿港元(3841亿美元),近期腾讯股价接连创新高,今年的上涨幅度已经超过了60%。专家称:微信“小程序”正在取得进展,以及最近模糊搜索与附近地点搜索等新功能的推出,使得多家机构看好腾讯。不过,腾讯市值仍低于阿里巴巴。

作者简介

本篇来自 小码哥_WS 的投稿,主要介绍了ffmpeg源码结构,为作者博客精彩ffmpeg系列的开篇,如果大家对ffmpeg感兴趣,可以访问下面的博客地址。

小码哥_WS 的博客地址:

http://blog.csdn.net/king1425

概述

未毕业通过校招进入了某做机的公司从事 camera 方面的工作。比较悲剧的是做了将近一年的 Camera 之后,正要研究 Camera 上下层打通任督二脉的时候,公司架构调整加上OS版本大变动,被调到了多媒体组(不过也好,我对编码解码这块也是向往已久)。以前大学的时候用 vitamio 写过一个播放器项目,后来 ijkplayer 出来之后也实践过一两个小项目,它们都是基于 ffmpeg 的框架。

悬窗播放视频,让你聊天看视频两不误

http://blog.csdn.net/king1425/article/details/59527229

学习 ffmpeg 也有段时间了,ffmpeg 这个框架实在是大,源码看着注释着忘着,很是凌乱。好记性不如烂笔头,古人诚不欺我啊。以后就整理下学习过的东西,分享出来,方便了自己也帮助了他人,真是快乐。

感谢雷神,中国音视频技术领域无私的拓荒者传承者,您的博文治学态度令我敬佩,文章使我受益良多

本系列前办部分应该是对雷神和其他资料的总结。如果对 ffmpeg 不了解的客官进这里,ffmpeg 必知道的知点:

http://blog.csdn.net/king1425/article/details/70348374

ffmpeg API变更

雷神记录获取媒体信息使用的函数是 av_find_stream_info()。但是较新的版本中,av_find_stream_info() 函数已经无法使用了,取而代之的是 avformat_find_stream_info()。

再比如,早一些的程序中,打开解码器可以使用 avcodec_open(),但是新版本的程序中必须使用 avcodec_open2()。而早期版本的 FFmpeg 中打开媒体的函数 av_open_input_file() 也已经被 avformat_open_input() 所取代。可以看出一些与 libavformat 相关的 av_***() 都变更为了 avformat_***(),这一趋势也说明 FFmpeg 的 API 正在慢慢朝着“名称更加规范”的方向发展。

这里也更了一篇

ffmpeg API变更 2009-03-01—— 2017-05-09变更

http://blog.csdn.net/King1425/article/details/71439943

大家务必对着新的API学习。

ffmpeg源码结构图

编码

引自雷神,图片较大建议保存为本地文件,然后再查看:

函数背景色

函数在图中以方框的形式表现出来。不同的背景色标志了该函数不同的作用:

粉红色背景函数:FFmpeg的API函数。

白色背景的函数:FFmpeg的内部函数。

黄色背景的函数:URLProtocol结构体中的函数,包含了读写各种协议的功能。

绿色背景的函数:AVOutputFormat结构体中的函数,包含了读写各种封装格式的功能。

蓝色背景的函数:AVCodec结构体中的函数,包含了编解码的功能。

区域

整个关系图可以分为以下几个区域:

左边区域——架构函数区域:这些函数并不针对某一特定的视频格式。

右上方黄色区域——协议处理函数区域:不同的协议(RTP,RTMP,FILE)会调用不同的协议处理函数。

右边中间绿色区域——封装格式处理函数区域:不同的封装格式(MKV,FLV,MPEG2TS,AVI)会调用不同的封装格式处理函数。

右边下方蓝色区域——编解码函数区域:不同的编码标准(HEVC,H.264,MPEG2)会调用不同的编解码函数。

箭头线

为了把调用关系表示的更明显,图中的箭头线也使用了不同的颜色:

红色的箭头线:标志了编码的流程。

其他颜色的箭头线:标志了函数之间的调用关系。其中:

调用 URLProtocol 结构体中的函数用黄色箭头线标识;

调用 AVOutputFormat 结构体中的函数用绿色箭头线标识;

调用 AVCodec 结构体中的函数用蓝色箭头线标识。

函数所在的文件

每个函数标识了它所在的文件路径。

*左边区域(架构函数) 后续详细分析~~~

右上区域(URLProtocol协议处理函数)

URLProtocol结构体包含如下协议处理函数指针:

url_open():打开
url_read():读取
url_write():写入
url_seek():调整进度
url_close():关闭

【例子】不同的协议对应着上述接口有不同的实现函数,举几个例子: 
File协议(即文件)对应的 URLProtocol 结构体 ff_file_protocol: 
url_open() -> file_open() -> open()

url_read() -> file_read() -> read()

url_write() -> file_write() -> write()

url_seek() -> file_seek() -> lseek()

url_close() -> file_close() -> close()

RTMP协议(libRTMP)对应的 URLProtocol 结构体 ff_librtmp_protocol: 

url_open() -> rtmp_open() -> RTMP_Init(), RTMP_SetupURL(), RTMP_Connect(), RTMP_ConnectStream() 

url_read() -> rtmp_read() -> RTMP_Read()

url_write() -> rtmp_write() -> RTMP_Write()

url_seek() -> rtmp_read_seek() -> RTMP_SendSeek()

url_close() -> rtmp_close() -> RTMP_Close()

UDP协议对应的 URLProtocol 结构体 ff_udp_protocol:

url_open() -> udp_open()

url_read() -> udp_read()

url_write() -> udp_write()

url_seek() -> udp_close()

url_close() -> udp_close()

右中区域(AVOutputFormat封装格式处理函数)

AVOutputFormat 包含如下封装格式处理函数指针:

write_header():写文件头
write_packet():写一帧数据
write_trailer():写文件尾

【例子】不同的封装格式对应着上述接口有不同的实现函数,举几个例子: 
FLV封装格式对应的 AVOutputFormat 结构体 ff_flv_muxer:

write_header() -> flv_write_header()

write_packet() –> flv_write_packet()

write_trailer() -> flv_write_trailer()

MKV封装格式对应的 AVOutputFormat 结构体 ff_matroska_muxer:

write_header() -> mkv_write_header()

write_packet() –> mkv_write_flush_packet()

write_trailer() -> mkv_write_trailer()

MPEG2TS封装格式对应的 AVOutputFormat 结构体 ff_mpegts_muxer:

write_header() -> mpegts_write_header()

write_packet() –> mpegts_write_packet()

write_trailer() -> mpegts_write_end()

AVI封装格式对应的 AVOutputFormat 结构体 ff_avi_muxer:

write_header() -> avi_write_header()

write_packet() –> avi_write_packet()

write_trailer() -> avi_write_trailer()

右下区域(AVCodec编解码函数)

AVCodec 包含如下编解码函数指针:

init():初始化
encode2():编码一帧数据
close():关闭

【例子】不同的编解码器对应着上述接口有不同的实现函数,举几个例子:

HEVC编码器对应的 AVCodec 结构体 ff_libx265_encoder:

init() -> libx265_encode_init() -> x265_param_alloc(), x265_param_default_preset(), x265_encoder_open()

encode2() -> libx265_encode_frame() -> x265_encoder_encode()

close() -> libx265_encode_close() -> x265_param_free(), x265_encoder_close() 

H.264编码器对应的 AVCodec 结构体 ff_libx264_encoder:

init() -> X264_init() -> x264_param_default(), x264_encoder_open(), x264_encoder_headers()

encode2() -> X264_frame() -> x264_encoder_encode()

close() -> X264_close() -> x264_encoder_close()

VP8编码器(libVPX)对应的 AVCodec 结构体 ff_libvpx_vp8_encoder:

init() -> vpx_init() -> vpx_codec_enc_config_default()

encode2() -> vp8_encode() -> vpx_codec_enc_init(), vpx_codec_encode()

close() -> vp8_free() -> vpx_codec_destroy()

MPEG2编码器对应的 AVCodec 结构体 ff_mpeg2video_encoder:

init() -> encode_init()

encode2() -> ff_mpv_encode_picture()

close() -> ff_mpv_encode_end()

解码

右上区域(URLProtocol协议处理函数)

URLProtocol结构体包含如下协议处理函数指针:

url_open():打开
url_read():读取
url_write():写入
url_seek():调整进度
url_close():关闭

【例子】不同的协议对应着上述接口有不同的实现函数,举几个例子:

File协议(即文件)对应的 URLProtocol 结构体 ff_file_protocol:

url_open() -> file_open() -> open()

url_read() -> file_read() -> read()

url_write() -> file_write() -> write()

url_seek() -> file_seek() -> lseek()

url_close() -> file_close() -> close()

RTMP协议(libRTMP)对应的 URLProtocol 结构体 ff_librtmp_protocol:

url_open() -> rtmp_open() -> RTMP_Init(), RTMP_SetupURL(), RTMP_Connect(), RTMP_ConnectStream()

url_read() -> rtmp_read() -> RTMP_Read()

url_write() -> rtmp_write() -> RTMP_Write()

url_seek() -> rtmp_read_seek() -> RTMP_SendSeek()

url_close() -> rtmp_close() -> RTMP_Close()

UDP协议对应的URLProtocol结构体ff_udp_protocol:

url_open() -> udp_open()

url_read() -> udp_read()

url_write() -> udp_write()

url_seek() -> udp_close()

url_close() -> udp_close()

右中区域(AVInputFormat封装格式处理函数)

AVInputFormat 包含如下封装格式处理函数指针:

read_probe():检查格式
read_header():读取文件头
read_packet():读取一帧数据
read_seek():调整进度
read_close():关闭

【例子】不同的封装格式对应着上述接口有不同的实现函数,举几个例子:

FLV封装格式对应的 AVInputFormat 结构体 ff_flv_demuxer:

read_probe() -> flv_probe() –> probe()

read_header() -> flv_read_header() -> create_stream() -> avformat_new_stream()

read_packet() -> flv_read_packet()

read_seek() -> flv_read_seek()

read_close() -> flv_read_close()

MKV封装格式对应的AVInputFormat结构体ff_matroska_demuxer:

read_probe() -> matroska_probe()

read_header() -> matroska_read_header()

read_packet() -> matroska_read_packet()

read_seek() -> matroska_read_seek()

read_close() -> matroska_read_close()

MPEG2TS封装格式对应的 AVInputFormat 结构体 ff_mpegts_demuxer:

read_probe() -> mpegts_probe()

read_header() -> mpegts_read_header()

read_packet() -> mpegts_read_packet() 

read_close() -> mpegts_read_close()

AVI封装格式对应的 AVInputFormat 结构体 ff_avi_demuxer:

read_probe() -> avi_probe()

read_header() -> avi_read_header()

read_packet() -> avi_read_packet()

read_seek() -> avi_read_seek()

read_close() -> avi_read_close()

右下区域(AVCodec编解码函数)

AVCodec 包含如下编解码函数指针:

init():初始化
decode():解码一帧数据
close():关闭

【例子】不同的编解码器对应着上述接口有不同的实现函数,举几个例子:

HEVC解码对应的 AVCodec 结构体 ff_hevc_decoder:

init() -> hevc_decode_init()

decode() -> hevc_decode_frame() -> decode_nal_units()

close() -> hevc_decode_free()

H.264解码对应的 AVCodec 结构体 ff_h264_decoder:

init() -> ff_h264_decode_init()

decode() -> h264_decode_frame() -> decode_nal_units()

close() -> h264_decode_end()

VP8解码(libVPX)对应的 AVCodec 结构体 ff_libvpx_vp8_decoder:

init() -> vpx_init() -> vpx_codec_dec_init()

decode() -> vp8_decode() -> vpx_codec_decode(), vpx_codec_get_frame()

close() -> vp8_free() -> vpx_codec_destroy()

MPEG2解码对应的 AVCodec 结构体 ff_mpeg2video_decoder:

init() -> mpeg_decode_init()

decode() -> mpeg_decode_frame()

close() -> mpeg_decode_end()

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号: