ffmpeg简介

FFmpeg库的基本组成

  • libavcodec: 提供各种音频,视频,字幕等编码和解码功能。
  • libavformat: 用于音视频封装格式的生成和解析, 包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能。
  • libavutil: 包括了hash器,解码器和各类工具函数。
  • libavfilter: 音视频滤镜库,提供了音频特效和视频特效的处理。
  • libavdevice: 提供了访问捕获设备和回放设备的接口。
  • libswresample: 用于混音和音频重采样,对数字音频进行声道数,数据格式 采样率等多种基本信息的转换。
  • libswscale: 用于视频场景比例缩放、色彩映射转换。比如YUV转换为RGB的数据
  • libpostproc:用于后期效果处理,当使用avfilter的时候需要打开该模块的开关,因为它会使用该模块的一些移除函数。

ffmpeg中的结构体

结构体很多,最关键的可以分为以下几类

解协议(http,rtsp,rtmp,mms)
AVIOContext,URLProtocol,URLcontext主要用于存储音视频使用的协议类型以及状态。URLProtocol存储输入音视频使用的封装格式。每一种协议都对应一个URLProtocol结构。
解封装(flv、avi、rmvb、mp4)
AVFormatContext主要存储音视频封装格式中包含的信息。
AVInputFormat存储输入音视频使用的封装格式。每种音视频的封装格式都对应一个AVInputFormat结构。
解码(h264,mpeg2,aac,mp3)
每个AVStream存储一个视频流/音频流的相关数据,每个AVStream对应一个AVCodecContext,存储该视频流/音频流使用解码方式的相关数据;每个AVcodecContext对应一个AVCodec,包含该音频流/视频流对应的解码器,每种解码器都对应一个AVcodec结构。
存数据
视频的每个结构一般是存一帧,音频可能有好几帧。
解码前数据格式:AVPacket;

  • 音频的话一个AVPacket中可能有好几个AVFrame
  • 视频的话一个AVPacket中只有一个个AVFrame
    解码后数据格式:AVFrame;

他们之间的对应关系:

命令行tools的使用

注册协议、格式与编解码器
使用FFmpeg的API首先要调用FFmpeg的注册协议,格式与编解码器的方法。确保所有的格式和编解码器都被注册到了FFmpeg框架中。
av_register_all();
这个方法里会还会调用 avfilter_register_all 和 avcodec_register_all avformat_register_all
如果需要用到网络的操作,也要注册网络协议
avformat_network_init();

ffmpeg API

利用FFmpeg解码的全部过程:
0.注册协议、格式与编解码器
1.打开媒体文件
2.寻找各个流,并且打开对应的解码器
3.初始化解码后数据的结构体
4.读取流内容并且解码
5.处理解码后的裸数据
6.关闭所有资源

通用API解析

1.av_register_all

编译静态库的时候有一些编译条件,通过enable,disable进行了了一些开关的控制,其中就包括协议或者一些编解码器,上边提到的注册协议,就是注册这里开开的也就是enable的部分。

2.av_find_codec

这里包含了两部分内容,一部分是寻找解码器,另一部分是寻找编码器,av_register_all中已经把编码器和解码器都存放到一个链表中了,泽库其实就是从这个构造的链表中进行遍历通过Codec的ID或者name进行条件匹配,最终返回对应的Codec。

3.avcodec_open2

该函数是打开编解码器的函数,无论编码,还是解码,都会用到。输入参数有三个

  • AVCodecContext
  • av_find_codec寻找出来的编解码器
  • 第三个一般传NULL
    该函数的具体实现文件是如何找到的?需要看第一部中如何注册的。可能会调用x264或者lame库中的API。
3.avcodec_close

就是avcodec_open的一个逆过程,找到对应的实现文件的close指针所指向的函数。然后调用对应的第三方库的API来关闭对应的编码库。

调用FFmpeg解码时用到的函数

1.avformat_open_input

通过文件路径判断文件格式,根据格式选择Demuxer(解轨器)。然后对应的关键生命周期的方法,read_header、read_packet、read_seek、read_close都会使用找到的解轨器中的函数指针指定的函数。
其中read_header会构建好AVStream的结构体,以便后续传参使用。

2.avformat_find_stream_info

它的作用就是把所有stream的metaData信息填充好。利用选择好的Demuxer中的read_packet函数读取一段数据进行解码。它

3.av_read_frame

该方法读取出来的数据是AVPacket(数据包)。这个函数的实现首先会委托到Demuxer的read_packet方法中去。
对于音频流一个AVPacket可能包含多个AVFrame,但是对于视频流一个AVPacket只包含一个AVFrame。该函数最终就返回一个AVPacket结构体

4.avcodec_decode

该方法包含两部分内容

  • 解码音频
  • 解码视频
    解码其实是委托给对应的解码器来实施的,在打开解码器的时候就找到了对应的解码器的实现。解码器中会有对应的生命周期的函数的实现,最重要的就是
  • init 打开解码器
  • decoder 解码
  • close 关闭解码器
5.avformat_close_input

该函数负责释放对应的资源,首先就会调用对应的Demuxer的read_close方法,然后释放掉AVFormatContext,最后关闭文件或者远程连接。

调用FFmpeg编码时用到的函数

1.avformat_alloc_output_context2

该函数内部会调用avformat_alloc_context来分配一个AVFormatContext结构体,然后找到注册的Muxer和Demuxer,也就是封装格式部分,去找到对应的封装格式。如果找不到返回对应的错误提示。

2.avio_open2

首先调用函数ffurl_open,构造出URLContext结构体,这个结构体中包含了URLProtocol(需要去第一步register_protocol中已经注册的协议链表中寻找);接着会调用avio_alloc_context方法,分配出AVIOContext结构体,并将上一步构造出来的URLProtocol传递进来;然后把上一步分配出来AVIOContext结构体赋值给AVFormatContext的属性,其实这就是图3-2表示的结构了。而该过程恰好是上面所分析的avformat_open_input函数的实现过程的一个逆过程。之前就提到过,编码过程和解码过程从逻辑上来讲本来就是一个逆过程,所以在FFmpeg的实现过程中它们也是一个逆过程。

后面的步骤也都是解码的一个逆过程,解码过程中的av_f ind_stream_info对应到这里就是avformat_new_stream和avformat_write_header。avformat_new_stream函数会将音频流或者视频流的信息填充好,分配出AVStream结构体,在音频流中分配声道、采样率、表示格式、编码器等信息,在视频流中分配宽、高、帧率、表示格式、编码器等信息;avformat_write_header函数与解码过程中的read_header恰好是一个逆过程,因此这里将不再介绍。接下来就是编码的阶段了,开发者需要将手动封装好的AVFrame结构体,作为avcodec_encode_video方法的输入,将其编码成为AVPacket,然后调用av_write_frame方法输出到媒体文件中。而av_write_frame方法会将编码后的AVPacket结构体作为Muxer中的write_packet生命周期方法的输入,write_packet函数会加上自己封装格式的头信息,然后调用协议层写到本地文件或者网络服务器上。最后一步就是av_write_trailer,该函数有一个非常大的坑,如果没有执行write_header操作,就直接执行write_trailer操作,程序会直接崩溃(即Crash掉),所以必须保证这两个函数成对出现。write_trailer函数的实现会把没有输出的AVPacket全部丢给协议层去做输出,然后会调用Muxer的write_trailer生命周期方法,对于不同的格式写出的尾部也不尽相同,这里不再逐一介绍。

FFmpeg的库函数源代码分析
FFmpeg结构体分析

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342