ffmpeg 学习:002-代码架构
前言
使用 ffmpeg 库时,最好先理解好ffmpeg的代码结构图。
下面这张图表明了FFmpeg在解码一个视频的时候的函数调用流程,为了保证结构清晰,其中仅列出了最关键的函数,剔除了其它不是特别重要的函数。

多媒体处理基本流程
只有真正了解了多媒体处理的基本流程,研读 ffmpeg 源代码才能事半功倍。
下面分析一下多媒体中最基本最核心的视频解码过程,平常我们从网上下载一部电影或者一首歌曲,那么相应的多 媒体播放器为我们做好了一切工作,我们只用欣赏就 ok 了。目前几乎所有的主流多媒体播放器都是基于开源多媒 体框架 ffmpeg 来做的,可见 ffmpeg 的强大。下面是对一个媒体文件进行解码的主要流程:
A(Media file) --> B(Demux, 解复用)
B(解码, Decode) --> C(YUV/RGB, 数据)
解复用(Demux)
当我们打开一个多媒体文件之后,第一步就是解复用,称之为 Demux。为什么需要这一步,这一步究竟是做什么的?
我们知道在一个多媒体文件中,既包括音频也包括视频,而且音频和视频都是分开进行压缩的,因为音频和视频的压缩算法不一样,既然压缩算法不一样,那么肯定解码也不一样,所以需要对音频和视频分别进行解码。虽然音频和视频是分开进行压缩的,但是为了传输过程的方便,将压缩过的音频和视频捆绑在一起进行传输。所以我们解码的第一步就是将这些绑在一起的音频和视频流分开来,也就是传说中的解复用:所以一句话,解复用这一步就是将文件中捆绑在一起的音频流和视频流分开来以方便后面分别对它们进行解码。
解码(Decode)
这一步不用多说,一个多媒体文件肯定是经过某种或几种格式的压缩的,也就是通常所说的视频和音频编码,编码是为了减少数据量,否则的话对我们的存储设备是一个挑战,如果是流媒体的话对网络带宽也是一个几乎不可能完 成的任务。所以我们必须对媒体信息进行尽可能的压缩。
FFmpeg 中解码流程对应的 API 函数
了解了上面的一个媒体文件从打开到解码的流程,就可以很轻松的阅读 ffmpeg 代码,ffmpeg 的框架也基本是按照这个流程来的,但不是每个流程对应一个 API,下面这副图是我分析 ffmpeg 并根据自己的理解得到的 ffmpeg 解码 流程对应的 API,我想这幅图应该对理解 ffmpeg 和编解码有一些帮助。
A[Media file 容器] -->|avformat_open_input| B{Video Strems}
A[Media file 容器] --> C{Audio Strems}
A[Media file 容器] --> |demux|D{Subtitle Strems}
B{Video Strems} --> |av_read_frame| E[数据流的数据包]
E[数据流的数据包]-->|avcodec_decode_video2| 解码之后的视频帧
C{Audio Strems} --> F[音频流的数据包]
F[音频流的数据包]-->|avcodec_decode_audio4| 解码之后的音频帧
D{Subtitle Strems} --> G[字幕流的数据包]
G[字幕流的数据包]-->|avcodec_decode_subtitttle2,Decode| 解码之后的字幕
Ffmpeg 中 Demux 这一步是通过 avformat_open_input()这个 api 来做的,这个 api 读出文件的头部信息,并做 demux, 在此之后我们就可以读取媒体文件中的音频和视频流,然后通过 av_read_frame()从音频和视频流中读取出基本数据 流 packet,然后将 packet 送到 avcodec_decode_video2()和相对应的 api 进行解码。
流媒体数据流程讲解

FFMpeg 的 output_example.c 例子分析
该例子讲了如何输出一个 libavformat 库所支持格式的媒体文件。
(1)av_regis ter_all(),初始化 libavcodec 库,并注册所有的编解码器和格式。
(2)guess_form at(),根据文件名来获取输出文件格式,默认为 mpeg。
(3)av_alloc_form at_context()分配输出媒体内容。 ov->oform at = fm t; s nprintf( oc->filename, sizeof(oc->filename), “%s ”, filenam e );
(4)add_video_s tream ()使用默认格式的编解码器来增加一个视频流,并初始化编解码器。 (4.1)av_new_s tream ()增加一个新的流到一个媒体文件。
(4.2)初始化编解码器: c = s t->codec; c->codec_id = codec_id; c->codec_type = CODEC_TYPE_ VIDEO; c->bit_rate = 400000; c->width = 352; c->height = 288; c->tim e_base.den = STREAM_FR AME_RATE ; //每秒 25 副图像 c->tim e_base.num = 1; c->gop_size = 12; c->pix_fm t = STREAM_PIX_FMT; //默认格式为 P IX_FMT_ YUV420P …… ……
(5)av_s et_parameters ()设置输出参数,即使没有参数,该函数也必须被调用。
(6)dum p_form at()输出格式信息,用于调试。
(7)open_video()打开视频编解码器并分配必要的编码缓存。
(7.1)avcodec_find_encoder()寻找 c->codec_id 指定的视频编码器。
(7.2)avcodec_open()打开编码器。
(7.3)分配视频输出缓存: video_outbuf_s ize = 200000; video_outbuf = av_m alloc( video_outbuf_s ize );
(7.4)picture = alloc_picture()分配原始图像。
(7.4.1)avcodec_alloc_frame()分配一个 AVFram e 并设置默认值。
(7.4.2)s ize = avpicture_get_s ize()计算对于给定的图片格式以及宽和高,所需占用多少 内存。
(7.4.3)picture_buf = av_malloc( s ize )分配所需内存。
(7.4.4)avpicture_fill()填充 AVPicture 的域。
(7.5)可选。如果输出格式不是 YUV420P,那么临时的 YU V420P 格式的图像也是需要的,由 此再转换为 我们所需的格式,因此需要为临时的 YU V420P 图像分配缓存: tm p_picture = alloc_picture() 说明:tm p_picture,picture,video_outbuf。如果输出格式为 YUV420P,则直接通过 avcodec_ encode_video()函数将 picture 缓存中的原始图像编码保存到 video_outbuf 缓存中;如果输出格式不 是 YU V420P,则需要先通过 sws _s cale()函数,将 YUV420P 格式转换为目标格式,此时 tm p_picture 缓 存存放的是 YU V420P 格式的图像,而 picture 缓存为转换为目标格式后保存的图像,进而再将 picture 缓 存中的图像编码保存到 video_outbuf 缓存中。
(8)url_fopen()打开输出文件,如果需要的话。
(9)av_write_header()写流动头部。
(10)LOOP 循环{ 计算当前视频时间 video_pts 是否超时退出循环? write_video_fram e()视频编码 }
(10.1)write_video_frame() 如果图片不是 YU V420P,则需要用 sws _s cale()函数先进行格式转换。 若需要原始图像: av_init_packet()初始化一个包的选项域。 av_write_fram e()向输出媒体文件写一个包,该包会包含一个视频帧。 若需要编码图像: avcodec_encode_video()编码一视频帧。 av_init_packet() av_write_fram e()
(11)close_video()关闭每个编解码器。
(12)av_write_trailer()写流的尾部。
(13)释放资源 av_freep()释放 AVForm atContext 下的 AVS tream ->AVCodecContext 和 AVStream : for( i = 0; i < oc->nb_s treams ; i++ ){ av_freep( &oc->s treams [i]->codec ); av_freep( &oc->s treams [i] ); } url_fclose()关闭输出文件。 av_free()释放 AVForm atContext
ffmpeg 学习:002-代码架构的更多相关文章
- FFmpeg学习5:多线程播放视音频
在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...
- 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程
原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ UART HCI_UART H4 HCI L2CAP ...
- JavaWeb学习之三层架构实例(三)
引言 通过上一篇博客JavaWeb学习之三层架构实例(二)我们基本上已经实现了对学生信息列表的增删改查操作(UI除外),但是不难看出,代码冗余度太高了,尤其是StudentDao这个类,其中的增删改查 ...
- ML平台_小米深度学习平台的架构与实践
(转载:http://www.36dsj.com/archives/85383)机器学习与人工智能,相信大家已经耳熟能详,随着大规模标记数据的积累.神经网络算法的成熟以及高性能通用GPU的推广,深度学 ...
- Libvirt代码架构
Libvirt介绍 参考资料 Libvirt学习 通过virsh了解libvirt api的调用方式 通过virHypervisorDriver了解libvirt api的实现 virsh代码阅读 通 ...
- (转)MyBatis框架的学习(二)——MyBatis架构与入门
http://blog.csdn.net/yerenyuan_pku/article/details/71699515 MyBatis框架的架构 MyBatis框架的架构如下图: 下面作简要概述: S ...
- FFmpeg 学习(五):FFmpeg 编解码 API 分析
在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编 ...
- FFmpeg 学习(七):FFmpeg 学习整理总结
一.FFmpeg 播放视频的基本流程整理 播放流程: video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Fra ...
- 20145314郑凯杰 《Java程序设计》第2周学习总结 代码开始!
---恢复内容开始--- 20145314郑凯杰 <Java程序设计>第2周学习总结 代码开始! 教材学习内容总结 跟着教材的顺序开始总结我学过的内容: 1编辑.编译.运行教材上代码 这部 ...
- FFmpeg学习起步 —— 环境搭建
下面是我搭建FFmpeg学习环境的步骤. 一.在Ubuntu下 从http://www.ffmpeg.org/download.html下载最新的FFmpeg版本,我的版本是ffmpeg-2.7.2. ...
随机推荐
- openjudge 和为给定数(二分答案)
嗯... 题目链接:http://noi.openjudge.cn/ch0111/07/ 这道题是一道不太明显,但很好二分的二分答案的一道题... 首先排序(二分要满足单调性),然后枚举每一个数,在[ ...
- scp 远程文件拷贝命令
Linux scp命令用于Linux之间复制文件和目录. scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令. 1.从本地复制到远程 命令格式: ...
- Python 基础之正则之一 单字符,多字符匹配及开头结尾匹配
一.正则表达式之单个字符匹配 格式:lst = re.findall(正则表达式,要匹配的字符串)预定义字符集 匹配内容 .匹配任意字符,除了换行符\n \d匹配数字 \D匹配非数字 \w匹配字母或数 ...
- 如何安装部署和优化Tomcat?(Tomcat部署和优化与压测,虚拟主机配置,Tomcat处理请求的过程)
文章目录 前言 一:Tomcat安装部署 1.1:Tomcat简介 1.2:Tomcat核心组件 1.3:Tomcat处理请求的过程 1.3.1:请求过程基本解释 1.3.2:请求过程详细解释 1.4 ...
- loadrunner 接口测试实战
直接上代码: web_reg_save_param("Name", //这个函数是为了获取服务器返回的值.我这个接口的返回值是这样子的 //将服务器返回的值放在Name里,Na ...
- c++子类父类关系(翁恺c++公开课[15-16]学习笔记)
关于类的继承有三种:public继承.private继承.protected继承 首先说明,关于类的成员变量.函数的权限有三种(public.private.protected) 我们通常会让所有的成 ...
- 好用的log打印类
package com.huawei.network.ott.weixin.util; import android.util.Log; public final class DebugLog { / ...
- Day11 - I - 取石子游戏 HDU - 2516
1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win".先取者胜输出&q ...
- 5.使用Redis+Flask维护动态Cookies池
1.为什么要用Cookies池? 网站需要登录才可爬取,例如新浪微博 爬取过程中如果频率过高会导致封号 需要维护多个账号的Cookies池实现大规模爬取 2.Cookies池的要求 自动登录更新 定时 ...
- 运行cmd直接进入指定目录下的命令
新建一个.bat批处理文件,文件命令为@ECHO OFF cmd /k cd /d c:data 运行该批处理文件cmd就可进入指定的文件夹,感兴趣的朋友可以参考下啊 新建一个.bat批处理文件,文件 ...