如果你看过FFmpeg的代码,就很容易发现,FFmpeg里有各式各样的结构体,有一类结构体的命名规则比较类似,都是XxxxContext。
- AVFormatContext
- AVCodecContext
- AVCodecParserContext
- AVIOContext
- AVFilterContext
当然还有很多Context,上面只是列出比较典型的几种,一看这种命名规则就和面向对象中的命名很类似。 Context是持有的上下文,是数据链路传递过程中的持有数据的对象。 其实这是FFmpeg在运用面向对象的思想来编程。XxxxContext可以看做是C语言“类”的实现。 C语言没有类的语法特征,但可以用结构体struct来描述一组元素的集合。如果把XxxxContext看做类,成员变量显然可以用结构体struct来模拟。 下面一个简单的例子表示下:
struct AVFormatContext {
iformat;
oformat;
}
avformat_alloc_context();
avformat_free_context();
class AVFormatContext {
private:
iformat;
oformat;
public:
AVFormatContext();
~AVFormatContext();
}
其实FFmpeg中的XxxxContext的写法就是按照面向对象的语法设计的。对面向对象比较熟悉的同学其实看到这些命名应该比较亲切。
AVFormatContext
AVFormatContext是FFmpeg中打开文件必备的一个结构体。 之前介绍过,格式Format_是音视频的一个核心概念,所以在FFmpeg里你需要经常与AVFormatContext打交道。因为一般不是直接操作_解封装器Demuxer_和_封装器Muxer,而是通过AVFormatContext来操作它们。
常用的 AVFormatContext 的操作,可以分为3类:
- 通用的函数,例如创建和销毁,等价于C++的构造函数和析构函数。
- 对输入视频流的读操作,用于输入处理,也就是使用_解封装器Demuxer_对视频流进行操作,是读操作。
- 对输出视频流的写操作,用于输出处理,也就是使用_封装器Muxer_对视频流进行操作,是写操作。
iformat对应的是AVInputFormat,oformat对应的是AVOutputFormat,正好说一下AVFormatContext和AVInputFormat/AVOutputFormat的区别。 AVFormatContext持有的是传递过程中的数据,这些数据在整个传递路径上都存在,或者都可以复用,AVInputFormat/AVOutputFormat中包含的是动作,包含着如何解析得到的这些数据。
AVStream **streams; 是媒体文件中包含的流数据,几条流,媒体流中分别是音频、视频、字幕等等。
- avformat_alloc_context() 创建输入媒体文件的AVFormatContext
- avformat_alloc_output_context2() 创建输出媒体文件的AVFormatContext
- av_dump_format() 打印format详情
- avformat_open_input() 打开媒体文件,探知媒体文件的封装格式。
- avformat_close_input() 关闭媒体文件
- avformat_find_stream_info() 探知媒体文件中的流信息,几条流,每条流的基本信息。
- av_read_frame() 读取媒体文件中每一帧数据,这是未解码之前的帧
- avformat_write_header() 写入输出文件的媒体头部信息
- av_interleaved_write_frame() 写入输出文件的帧信息,此帧信息已经调整了帧与帧之间的关联了。
- av_write_uncoded_frame() 写入输出文件的未编码的帧信息
- av_write_frame() 写入输出文件的已编码的帧信息
- av_write_trailer() 写入输出文件的媒体尾部信息
对于AVFormatContext的使用,主要就是读视频和写视频,下面是基本的流程:
读视频流程:
- 1.创建avformat上下文
AVFormatContext *ifmt_ctx = avformat_alloc_context()
- 2.打开视频文件
avformat_open_input(&ifmt_ctx, in_filename, 0, 0)
- 3.持续读取视频帧
while(…) { av_read_frame(ifmt_ctx, &pkt) }
- 4.关闭avformat上下文
avformat_close_input(&ifmt_ctx)
写视频流程:
- 1.创建输出上下文
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename)
- 2.写格式头部
avformat_write_header(ofmt_ctx, NULL)
- 3.持续输出帧
while(…) { av_interleaved_write_frame(ofmt_ctx, &pkt) }
- 4.写格式尾部
av_write_trailer(ofmt_ctx)
- 5.关闭上下文
avformat_free_context(ofmt_ctx)
AVInputFormat
解封装器Demuxer,正式的结构体是AVInputFormat,其实是一个接口,功能是对封装后的格式容器解开获得编码后的音视频的工具。简单说,就是拆包工具。
我们所知道的各种多媒体格式,例如MP4、MP3、FLV等格式的读取,都有AVInputFormat的具体实现。
demuxer的种类很多,而且是可配置的,demuxer有多少,可以看一下demuxer_list.c文件,太多了,不一一列举了,我们举一个mp4 demuxer的例子。
下面是mp4视频格式的解封装器ff_mov_demuxer,在mov.c中:
AVInputFormat ff_mov_demuxer = {
.name = “mov,mp4,m4a,3gp,3g2,mj2”,
.long_name = NULL_IF_CONFIG_SMALL(“QuickTime / MOV”),
.priv_class = &mov_class,
.priv_data_size = sizeof(MOVContext),
.extensions = “mov,mp4,m4a,3gp,3g2,mj2”,
.read_probe = mov_probe,
.read_header = mov_read_header,
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
.flags = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS,
};
看到了有几个函数指针:
- read_probe
探测一下什么封装格式
- read_header
读取格式头部数据
- read_packet
读取解封装之后的数据包
- read_close
关闭对象
- read_seek
格式的seek读取控制
你可以看到AVInputFormat提供的是类似接口一样的功能,而ff_mov_demuxer是其的一个具体实现。FFmpeg其实本身的逻辑并不复杂,只是由于支持的格式特别丰富,所以代码才如此多。如果我们先把大部分格式忽略掉,重点关注FFmpeg对其中几个格式的实现,可以更好理解FFmpeg。
AVOutputFormat
封装器 Muxer,对应的结构体是AVOutputFormat,也是一个接口,功能是对编码后的音视频封装进格式容器的工具。简单说,就是打包工具。
跟_解封装器 Demuxer_类似,也是MP4、MP3、FLV等格式的实现,差别是_封装器 Muxer_用于输出。
与demuxer类似,muxer的种类很多,可以看一下muxer_list.c文件。 下面看一下mp3的muxer,在mp3enc.c中:
AVOutputFormat ff_mp3_muxer = {
.name = “mp3”,
.long_name = NULL_IF_CONFIG_SMALL(“MP3 (MPEG audio layer 3)”),
.mime_type = “audio/mpeg”,
.extensions = “mp3”,
.priv_data_size = sizeof(MP3Context),
.audio_codec = AV_CODEC_ID_MP3,
.video_codec = AV_CODEC_ID_PNG,
.write_header = mp3_write_header,
.write_packet = mp3_write_packet,
.write_trailer = mp3_write_trailer,
.query_codec = query_codec,
.flags = AVFMT_NOTIMESTAMPS,
.priv_class = &mp3_muxer_class,
};
上面也有对应的指针函数,是demuxer的反过程。
AVCodecContext
跟AVFormatContext类似,我们也是通过AVCodecContext对_编码器Encoder_和_解码器Decoder_操作,一般也不直接操作编解码器。所以需要实现编解码,一般都要跟AVCodecContext打交道。
和demuxer与muxer一样,codec也有decode和encode之分,具体可以参考codec_list.c文件: 查看ff_libx264_encoder,在libx264.c中:
AVCodec ff_libx264_encoder = {
.name = “libx264”,
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
文末
好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
这里放上一部分我工作以来以及参与过的大大小小的面试收集总结出来的相关的几十套腾讯、头条、阿里、美团等公司21年的面试专题,其中把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分免费分享给大家,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【延伸Android必备知识点】
这里只是整理出来的部分面试题,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。喜欢的话麻烦点击一个喜欢在关注一下~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
这里只是整理出来的部分面试题,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。喜欢的话麻烦点击一个喜欢在关注一下~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!