ffmpeg学习笔记-初识ffmpeg
ffmpeg用来对音视频进行处理,那么在使用ffmpeg前就需要ffmpeg有一个大概的了解,这里使用雷神的ppt素材进行整理,以便于复习
音视频基础知识
视频播放器的原理
播放视频的流程大致如下:

常用播放器
- 跨平台
VLC,Mplayer,ffplay等
- Windows平台
完美解码,终极解码,暴风影音
- 跨平台
信息查看工具
- 综合信息查看:
MediaInfo - 二进制信息查看:
UltraEdit - 单项详细信息分析
- 封装格式:
Elecard Format Analyzer - 视频编码数据:
Elecard Stream Eye - 视频像素数据:
YUV Player - 音频采样数据:
Adobe Audition
- 封装格式:
- 综合信息查看:
封装格式
封装格式的作用:视频码流和音频码流按照一定的格式存储在一个文件中
封装格式分析工具:Elecard Format Analyzer

| 名称 | 推出机构 | 目前使用领域 |
|---|---|---|
AVI |
Microsoft Inc. |
BT下载影视 |
MP4 |
MPEG |
互联网视频网站 |
TS |
MPEG |
IPTV,数字电视 |
FLV |
Adobe Inc. |
互联网视频网站 |
MKV |
CoreCodec Inc. |
互联网视频网站 |
RMVB |
Real Networks Inc. |
BT下载影视 |
MPEG2-TS格式简介
不包含文件头。数据大小固定(188Byte)的TS Packet构成

FLV格式简介
包含文件头。数据由大小不固定的Tag构成

视频编码数据
视频编码的作用:将视频像素数据(
RGB,YUV等)压缩成为视频码流,从而降低视频的数据量视频编码分析工具:
Elecard Stream Eye
| 名称 | 推出机构 | 推出时间 | 目前使用领域 |
|---|---|---|---|
HEVC(H.265) |
MPEG/ITU-T |
2013 |
研发中 |
H.264 |
MPEG/ITU-T |
2003 |
各个领域 |
MPEG4 |
MPEG |
2001 |
不温不火 |
MPEG2 |
MPEG |
1994 |
数字电视 |
VP9 |
Google |
2013 |
研发中 |
VP8 |
Google |
2008 |
不普及 |
VC-1 |
Microsoft Inc. |
2006 |
微软平台 |
- H.264格式简介
数据由大小不固定的NALU构成
最常见的情况下,1个NALU存储了1帧画面的压缩编码后的数据

- H.264压缩方法
比较复杂。包含了帧内预测、帧间预测、熵编码、环路滤波等环节构成
可以将图像数据压缩100倍以上
音频编码数据
音频编码的作用:将音频采样数据(PCM等)压缩成为音频码流,从而降低音频的数据量
| 名称 | 推出机构 | 推出时间 | 目前使用领域 |
|---|---|---|---|
AAC |
MPEG |
1997 |
各个领域(新) |
AC-3 |
Dolby Inc. |
1992 |
电影 |
MP3 |
MPEG |
1993 |
各个领域(旧) |
WMA |
Microsoft Inc. |
1999 |
微软平台 |
- AAC格式简介
数据由大小不固定的ADTS构成

- AAC压缩方法
比较复杂
可以将音频数据压缩10倍以上
视频像素数据
视频像素数据作用:保存了屏幕上每个像素点的像素值
格式:
常见的像素数据格式有RGB24,RGB32,YUV420P,YUV422P,YUV444P等
压缩编码中一般使用的是YUV格式的像素数据,最为常见的格式为YUV420P特点
频像素数据体积很大,一般情况下1小时高清视频的RGB24格式的数据体积为:
3600*25*1920*1080*3=559.9GByte
PS:这里假定帧率为25Hz,取样精度8bitYUV格式像素数据查看工具:
YUV PlayerRGB格式简介
Red、Green、Blue三种颜色,可以混合成世界上所有的颜色
彩色图像中每个点,由R、G、B三个分量组成
以RGB24为例,图像像素数据的存储方式如下:

从图中可以看出,RGB24依次存储了每个像素点的R、G、B信息
PS:BMP文件中存储的就是RGB格式的像素数据YUV格式简介
相关实验表明,人眼对亮度敏感而对色度不敏感。因而可以将亮度信息和色度信息分离,并对色度信息采用更“狠”一点的压缩方案,从而提高压缩效率
YUV格式中,Y只包含亮度信息,而UV只包含色度信息
以YUV420P为例,图像像素数据的存储方式如图所示

从图中可以看出,YUV420P首先存储了整张图像的Y信息,然后存储整张图像的U信息,最后存储了整张图像的V信息
音频采样数据
音频采样数据作用:保存了音频中每个采样点的值
特点
音频采样数据体积很大,一般情况下一首4分钟的PCM格式的歌曲体积为:
4*60*44100*2*2=42.3MByte
PS:这里假定采样率为44100Hz,采样精度为16bit音频采样数据查看工具:
Adobe AuditionPCM格式简介
单声道的情况下按照顺序存储每个采样点的数据
双声道的情况下按照“左右、左右”的顺序存储每个采样点两个声道的数据

在Windows下使用
背景
使用广泛
使用FFmpeg作为内核的视频播放器
Mplayer,射手播放器,暴风影音,KMPlayer,QQ影音...使用FFmpeg作为内核的转码器
格式工厂,狸窝视频转换器,暴风转码...
总而言之,FFmpeg是视频行业中的"瑞士军刀"
- 特点
基于命令行:FFmpeg界面不太人性化,操作相对复杂,但是也更加灵活
开源:可以吸引全世界优秀的开发者加入其中进行开发
FFmpeg命令行工具的获取
下载地址
访问FFmpeg官网ffmpeg官网→选择Download→选择 Windows Package→进入Zeranoe FFmpeg网站
注意不要直接从FFmpeg官网下载源代码版本说明
Zeranoe网站中的FFmpeg分为3个版本:
Static:只包含3个体积很大的exe
Shared:除了3个体积较小的exe之外,还包含了dll动态库文件
Dev:只包含了开发用的头文件(*.h)和导入库文件(*.lib)
PS: 命令行使用的时候下载Static或者Shared版本就可以了使用
将下载下来的压缩包解压到任意目录(例如D:\ffmpeg)
打开命令行工具,切换到ffmpeg的bin文件夹
命令行中输入ffmpeg.exe,查看弹出的信息
ffmpeg.exe的使用
命令格式
功能ffmpeg.exe用于视频的转码
最简单的命令ffmpeg -i input.avi -b:v 640k output.ts
该命令将当前文件夹下的input.avi文件转换为output.ts文件,并将output.ts文件视频的码率设置为640kbps命令格式
ffmpeg -i {输入文件路径} -b:v {输出视频码率} {输出文件路径}
所有的参数都是以键值对的形式指定的。例如输入文件参数是"-i",而参数值是文件路径;输出视频码率参数是"-b:v",而参数值是视频的码率值。但是注意位于最后面的输出文件路径前面不包含参数名称命令参数
| 参数 | 说明 |
|---|---|
-h |
帮助 |
-i filename |
输入文件 |
-t duration |
设置处理时间,格式为hh:mm:ss |
-ss position |
设置起始时间,格式为hh:mm:ss |
-b:v bitrate |
设置视频码率 |
-b:a bitrate |
设置音频码率 |
-r fps |
设置帧率 |
-s wxh |
设置帧大小,格式为WxH |
-c:v codec |
设置视频编码器 |
-c:a codec |
设置音频编码器 |
-ar freq |
设置音频采样率 |
PS:详细的参数可以访问http://ffmpeg.org/ffmpeg.html
ffplay.exe的使用
命令格式
功能ffplay.exe用于视频的播放
最简单的命令ffplay input.avi
该命令将播放当前文件夹下的input.avi文件命令格式
ffplay {输入文件路径}
ffplay.exe的参数格式和ffmpeg.exe是类似的。所有的参数都是以键值对的形式指定的(由于不包含输出文件,所以只能指定输入参数)。注意位于最后面的输入文件路径前面不包含参数名称快捷键
| 快捷键 | 说明 |
|---|---|
| q, ESC | 退出 |
| f | 全屏 |
| p, 空格 | 暂停 |
| 鼠标点击屏幕 | 跳转到指定位置 |
PS:详细的参数可以访问http://ffmpeg.org/ffplay.html
视频解码器
视频解码知识
纯净的视频解码流程
压缩编码数据 -> 像素数据
例如解码H.264,就是"H.264码流 -> YUV"一般的视频解码流程
视频码流一般存储在一定的封装格式(例如MP4、AVI等)中。封装格式中通常还包含音频码流等内容
对于封装格式中的视频,需要先从封装格式中提取中视频码流,然后再进行解码
例如解码MKV格式的视频文件,就是"MKV -> H.264码流 -> YUV"
VC下FFmpeg开发环境的搭建
新建控制台工程
打开VC++
文件 -> 新建 -> 项目 -> Win32控制台应用程序拷贝FFmpeg开发文件
头文件(*.h)拷贝至项目文件夹的include子文件夹下
导入库文件(*.lib)拷贝至项目文件夹的lib子文件夹下
动态库文件(*.dll)拷贝至项目文件夹下
PS:如果直接使用官网上下载的FFmpeg开发文件。则可能还需要将MinGW安装目录中的inttypes.h,stdint.h,_mingw.h三个文件拷贝至项目文件夹的include子文件夹下配置开发文件
打开属性面板
解决方案资源管理器 -> 右键单击项目 -> 属性
头文件配置
配置属性 -> C/C++ -> 常规 -> 附加包含目录,输入"include"(刚才拷贝头文件的目录)
导入库配置
配置属性 -> 链接器 -> 常规 -> 附加库目录,输入"lib"(刚才拷贝库文 件的目录
配置属性 -> 链接器 -> 输入 -> 附加依赖项,输入"avcodec.lib; avformat.lib; avutil.lib; avdevice.lib; avfilter.lib; postproc.lib; swresample.lib; swscale.lib"(导入库的文件名)
动态库不用配置测试
创建源代码文件
在工程中创建一个包含main()函数的C/C++文件(如果已经有了可以跳过这一步)
包含头文件
如果是C语言中使用FFmpeg,则直接使用下面代码
# include "libavcodec/avcodec.h"
如果是C++语言中使用FFmpeg,则使用下面代码
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
}
main()中调用一个FFmpeg的接口函数
例如下面代码打印出了FFmpeg的配置信息
int main(int argc, char* argv [])
{
printf("%s", avcodec_configuration());
return 0;
}
如果运行无误,则代表FFmpeg已经配置完成
FFmpeg库简介 FFmpeg一共包含8个库
avcodec:编解码(最重要的库)
avformat:封装格式处理
avfilter:滤镜特效处理
avdevice:各种设备的输入输出
avutil:工具库(大部分库都需要这个库的支持)
postproc:后加工
swresample:音频采样数据格式转换
swscale:视频像素数据格式转换
FFmpeg解码的函数
FFmpeg解码的流程图如下所示

FFmpeg解码函数简介
av_register_all():注册所有组件
avformat_open_input():打开输入视频文件
avformat_find_stream_info():获取视频文件信息
avcodec_find_decoder():查找解码器
avcodec_open2():打开解码器
av_read_frame():从输入文件读取一帧压缩数据
avcodec_decode_video2():解码一帧压缩数据
avcodec_close():关闭解码器
avformat_close_input():关闭输入视频文件
FFmpeg解码的数据结构
FFmpeg解码的数据结构如下所示

FFmpeg数据结构简介
AVFormatContext:封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVInputFormat:每种封装格式(例如FLV,MKV,MP4,AVI)对应一个该结构体
AVStream:视频文件中每个视频(音频)流对应一个该结构体
AVCodecContext:编码器上下文结构体,保存了视频(音频)编解码相关信息
AVCodec:每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体
AVPacket:存储一帧压缩编码数据
AVFrame:存储一帧解码后像素(采样)数据FFmpeg数据结构分析
AVFormatContextiformat:输入视频的AVInputFormatnb_streams:输入视频的AVStream个数streams:输入视频的AVStream []数组duration:输入视频的时长(以微秒为单位)bit_rate:输入视频的码率
AVInputFormatname:封装格式名称long_name:封装格式的长名称extensions:封装格式的扩展名id:封装格式ID- 一些封装格式处理的接口函数
FFmpeg数据结构分析
AVStreamid:序号codec:该流对应的AVCodecContexttime_base:该流的时基r_frame_rate:该流的帧率
AVCodecContextcodec:编解码器的AVCodecwidth, height:图像的宽高(只针对视频)pix_fmt:像素格式(只针对视频)sample_rate:采样率(只针对音频)channels:声道数(只针对音频)sample_fmt:采样格式(只针对音频)
AVCodecname:编解码器名称long_name:编解码器长名称type:编解码器类型id:编解码器ID- 一些编解码的接口函数
FFmpeg数据结构分析
AVPacketpts:显示时间戳dts:解码时间戳data:压缩编码数据size:压缩编码数据大小stream_index:所属的AVStream
AVFramedata:解码后的图像像素数据(音频采样数据)linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小width, height:图像的宽高(只针对视频)key_frame:是否为关键帧(只针对视频)pict_type:帧类型(只针对视频)。例如I,P,B
补充小知识
- 解码后的数据为什么要经过
sws_scale()函数处理?
解码后YUV格式的视频像素数据保存在AVFrame的data[0]、data[1]、data[2]中。但是这些像素值并不是连续存储的,每行有效像素之后存储了一些无效像素。以亮度Y数据为例,data[0]中一共包含了linesize[0]*height个数据。但是出于优化等方面的考虑,linesize[0]实际上并不等于宽度width,而是一个比宽度大一些的值。因此需要使用sws_scale()进行转换。转换后去除了无效数据,width和linesize[0]取值相等

SDL显示
视频显示知识
- 视频显示的流程
视频显示的流程,就是将像素数据"画"在屏幕上的过程
例如显示YUV,就是将YUV"画"在系统的窗口中
SDL简介
作用
SDL(Simple DirectMedia Layer)库的作用说白了就是封装了复杂的视音频底层交互工作,简化了视音频处理的难度特点
跨平台
开源结构
SDL结构如下所示
可以看出它实际上还是调用了DirectX等底层的API完成了和硬件的交互

VC下SDL开发环境的搭建
新建控制台工程
打开VC++
文件 -> 新建 -> 项目 -> Win32控制台应用程序拷贝SDL开发文件
头文件(*.h)拷贝至项目文件夹的include子文件夹下
导入库文件(*.lib)拷贝至项目文件夹的lib子文件夹下
动态库文件(*.dll)拷贝至项目文件夹下配置开发文件
打开属性面板
解决方案资源管理器 -> 右键单击项目 -> 属性
头文件配置
配置属性 -> C/C++ -> 常规 -> 附加包含目录,输入"include"(刚才拷贝文件的目录)
导入库配置
配置属性 -> 链接器 -> 常规 -> 附加库目录,输入"lib"(刚才拷贝文件的目录)
配置属性 -> 链接器 -> 输入 -> 附加依赖项,输入"SDL2.lib; SDL2main.lib"(导入库的文件名)
动态库不用配置测试
创建源代码文件
在工程中创建一个包含main()函数的C/C++文件(如果已经有了可以跳过这一步),后续步骤在该文件中编写源代码
包含头文件
如果是C语言中使用SDL,则直接使用下面代码
#include "SDL2/SDL.h"
如果是C++语言中使用SDL,则使用下面代码
extern "C"
{
#include "SDL2/SDL.h"
}
main()中调用一个SDL的接口函数
例如下面代码初始化了SDL
int main(int argc, char* argv [])
{
if(SDL_Init(SDL_INIT_VIDEO))
{
printf("Could not initialize SDL - %s\n", SDL_GetError());
} else {
printf("Success init SDL");
}
return 0;
}
如果运行无误,则代表SDL已经配置完成
SDL视频显示的函数
SDL视频显示的流程图如下所示

SDL视频显示函数简介
SDL_Init():初始化SDL系统
SDL_CreateWindow():创建窗口SDL_Window
SDL_CreateRenderer():创建渲染器SDL_Renderer
SDL_CreateTexture():创建纹理SDL_Texture
SDL_UpdateTexture():设置纹理的数据
SDL_RenderCopy():将纹理的数据拷贝给渲染器
SDL_RenderPresent():显示
SDL_Delay():工具函数,用于延时
SDL_Quit():退出SDL系统
SDL视频显示的数据结构
SDL视频显示的数据结构如下所示

SDL数据结构简介
SDL_Window:代表了一个"窗口"
SDL_Renderer:代表了一个"渲染器"
SDL_Texture:代表了一个"纹理"
SDL_Rect:一个简单的矩形结构
进阶-SDL中事件和多线程
SDL多线程
函数:SDL_CreateThread():创建一个线程
数据结构:SDL_Thread:线程的句柄SDL事件
函数
SDL_WaitEvent()等待一个事件
SDL_PushEvent()发送一个事件
数据结构
SDL_Event:代表一个事件
fffmpeg + SDL视频播放器
FFmpeg和SDL整合实现视频播放器
- 整合方式
FFmpeg解码器实现了:视频文件 -> YUV
SDL视频显示实现了:YUV -> 屏幕
FFmpeg+SDL整合之后实现了:视频文件 -> YUV -> 屏幕
进阶:脱离开发环境的独立播放器
main()函数的参数
argc argv:全称为ARGument Counter和ARGument Vector。其中argv存储了来自于命令行的参数;而argc存储了参数的个数
例如在命令行中输入ffmpeg -i test.mkv test.ts,则argc取值为4,而argv[]数组取值如下:
argv [0] = "ffmpeg";
argv [1] = "-i";
argv [2] = "test.mkv";
argv [3] = "test.ts";
动态链接库(*.dll)
动态链接库不能被编译进应用程序。因而使用应用程序的时候必须在相同目录下保存用到的动态链接库文件
MFC知识
创建MFC工程的方法
打开VC++
文件 -> 新建 -> 项目 -> MFC应用程序
应用程序类型 -> 基于对话框
取消勾选"使用Unicode库"(暂不详细介绍)设置控件
找到"工具箱",就可以将相应的控件拖拽至应用程序对话框中
常用控件有:Button,Edit Control,Static Text等
找到"属性"选项卡
可以在"Caption"属性上修改控件上的文字
可以在"ID"属性上修改控件上的ID(ID是控件的标识,不可重复)添加消息响应函数
双击Button控件,就可以给该控件添加消息响应函数
在菜单栏的"项目 -> 类向导"处,可以添加更多种类的消息响应函数
MFC最简单的弹出消息框的函数是AfxMessageBox("HelloWorld")
FFmpeg + SDL + MFC实现图形界面视频播放器
FFmpeg解码器与MFC的整合
需要将视频文件路径从MFC界面上的Edit Control控件传递给FFmpeg解码器
GetWindowText()SDL与MFC的整合
需要将SDL显示的画面绘制到MFC的Picture Control控件上
SDL_CreateWindowFrom()
PS:SDL2有一个Bug。在系统退出的时候会把显示图像的控件隐藏起来,因此需要调用该控件的ShowWindow()方法将控件显示出来
ffmpeg学习笔记-初识ffmpeg的更多相关文章
- FFmpeg 学习(五):FFmpeg 编解码 API 分析
在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编 ...
- FFmpeg学习笔记之安装
本随笔原文出自:一叶知秋0830链接:https://www.jianshu.com/p/ab469a2ffd28 1.下载FFmpeg 先进入要存放下载文件的目录,比如要放在/Users/qinji ...
- FFmpeg 学习(七):FFmpeg 学习整理总结
一.FFmpeg 播放视频的基本流程整理 播放流程: video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Fra ...
- Arduino学习笔记① 初识Arduino
1.前言 近段时间,博主陆续更新了ESP8266学习笔记,主要开发平台是Arduino.但是,对于很多无基础的初学者来说,甚至不了解Arduino是什么.因此,博主决定加入一个Arduino学 ...
- ffmpeg学习笔记
对于每一个刚開始学习的人,刚開始接触ffmpeg时,想必会有三个问题最为关心,即ffmpeg是什么?能干什么?怎么開始学习?本人前段时间開始接触ffmpeg,在刚開始学习过程中.这三个问 ...
- ffmpeg学习笔记-多线程音视频解码
之前的视频解码仍然存在问题,那就是是在主线程中去完成解码的,会造成线程阻塞,这里将其改为多线程解码,使其主线程不被阻塞 前面介绍了音视频的主线程解码,那样会阻塞主线程,在前面学习了多线程以后,就可以对 ...
- ffmpeg学习笔记-编译脚本
之前已经用他人的编译脚本对ffmpeg进行了成功编译,那么在裁剪ffmpeg的时候需要指定文件,这时候应该怎么编写编译脚本呢?本文目的在于说明ffmpeg编译脚本的编写 首先在ffmpeg的目录下新建 ...
- ffmpeg学习笔记-音频播放
前文讲到音频解码,将音频解码,并且输入到PCM文件,这里将音频通过AudioTrack直接输出 音频播放说明 在Android中自带的MediaPlayer也可以对音频播放,但其支持格式太少 使用ff ...
- ffmpeg学习笔记-音频解码
在之前的文章已经初步对视频解码有个初步的认识了,接下来来看一看音频解码 音频解码步骤 音频解码与视频解码一样,有者固有的步骤,只要按照步骤来,就能顺利的解码音频 以上是ffmpeg的解码流程图,可以看 ...
随机推荐
- C#中'??'符的使用
?? 用于判断当前对象是否为null. 语法: 对象 ?? "当前对象为null时赋的默认值". string nullString = null; string Kong = ...
- [JSOI2018]潜入行动 (树形背包)
题目链接 题意: 外星人的母舰可以看成是一棵 n 个节点. n−1 条边的无向树,树上的节点用 1,2,⋯,n 编号.JYY 的特工已经装备了隐形模块,可以在外星人母舰中不受限制地活动,可以神不知鬼不 ...
- P2168 [NOI2015]荷马史诗 k叉哈夫曼树
思路:哈夫曼编码 提交:1次(参考题解) 题解:类似合并果子$QwQ$ 取出前$k$小(注意如果叶子结点不满的话要补全),合并起来再扔回堆里去. #include<cstdio> #inc ...
- [USACO19OPEN]Snakes
题目链接 题目简介:有n组,每组有若干个蛇的蛇队伍.(也可以理解为n条长度若干的蛇.)我们要用网捕捉,中途可以改变网的大小.目标是浪费空间最小. 解法:首先明确方法:DP.设f[i][t]为捕捉了n条 ...
- pat 甲级 1057 Stack(30) (树状数组+二分)
1057 Stack (30 分) Stack is one of the most fundamental data structures, which is based on the princi ...
- Codeforces 1221 F Choose a Square
题面 不知道大佬们怎么想的,反正我看到这种区间包含性质的并且score只和包含的区间与询问区间挂钩的题,马上就想到了扫描线23333 虽然革命方向无比正确,但却因为SB错误交了5次才 A. WA第一发 ...
- Git出现 fatal: Pathspec 'xxx' is in submodule 'xxx' 异常的解决方案
今天在使用git的时候,发现无论怎么改.gitignore文件都无法添加文件到版本控制,最后发现是缓存的原因,需要删除缓存再重新add git rm -rf --cached xxx
- 1656:Combination
一本通1656:Combination 1656:Combination 时间限制: 1000 ms 内存限制: 524288 KB提交数: 89 通过数: 49 [题目描述] ...
- 集合家族——stack
一.概述 在 Java 中 Stack 类表示后进先出(LIFO)的对象堆栈.栈是一种非常常见的数据结构,它采用典型的先进后出的操作方式完成的 它通过五个操作对类 Vector 进行了扩展 ,允许将向 ...
- Robot Framework(十九) 附录
6附录 6.1测试数据中的所有可用设置 6.1.1设置表 Setting表用于导入测试库,资源文件和变量文件,以及定义测试套件和测试用例的元数据.它可以包含在测试用例文件和资源文件中.请注意,在资源文 ...