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

MPEG2-TS格式简介

不包含文件头。数据大小固定(188Byte)的TS Packet构成

FLV格式简介

包含文件头。数据由大小不固定的Tag构成

视频编码数据

  • 视频编码的作用:将视频像素数据(RGBYUV等)压缩成为视频码流,从而降低视频的数据量
  • 视频编码分析工具:Elecard Stream Eye

H.264格式简介

数据由大小不固定的NALU构成

最常见的情况下,1个NALU存储了1帧画面的压缩编码后的数据

H.264压缩方法
比较复杂。包含了帧内预测、帧间预测、熵编码、环路滤波等环节构成
可以将图像数据压缩100倍以上

音频编码数据

音频编码的作用:将音频采样数据(PCM等)压缩成为音频码流,从而降低音频的数据量

AAC格式简介

数据由大小不固定的ADTS构成

AAC压缩方法
比较复杂
可以将音频数据压缩10倍以上

视频像素数据

视频像素数据作用:保存了屏幕上每个像素点的像素值

格式:

常见的像素数据格式有RGB24,RGB32,YUV420P,YUV422P,YUV444P等

压缩编码中一般使用的是YUV格式的像素数据,最为常见的格式为YUV420P

特点

频像素数据体积很大,一般情况下1小时高清视频的RGB24格式的数据体积为:

3600*25*1920*1080*3=559.9GByte

PS:这里假定帧率为25Hz,取样精度8bit

YUV格式像素数据查看工具:YUV Player

RGB格式简介

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 Audition

PCM格式简介

单声道的情况下按照顺序存储每个采样点的数据

双声道的情况下按照“左右、左右”的顺序存储每个采样点两个声道的数据

在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",而参数值是视频的码率值。但是注意位于最后面的输出文件路径前面不包含参数名称

命令参数

PS:详细的参数可以访问http://ffmpeg.org/ffmpeg.html

ffplay.exe的使用

命令格式

功能 ffplay.exe用于视频的播放

最简单的命令 ffplay input.avi

该命令将播放当前文件夹下的input.avi文件

命令格式

ffplay {输入文件路径}

ffplay.exe的参数格式和ffmpeg.exe是类似的。所有的参数都是以键值对的形式指定的(由于不包含输出文件,所以只能指定输入参数)。注意位于最后面的输入文件路径前面不包含参数名称

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数据结构分析

AVFormatContext

iformat:输入视频的AVInputFormat

nb_streams:输入视频的AVStream个数

streams:输入视频的AVStream []数组

duration:输入视频的时长(以微秒为单位)

bit_rate:输入视频的码率

AVInputFormat

name:封装格式名称

long_name:封装格式的长名称

extensions:封装格式的扩展名

id:封装格式ID

一些封装格式处理的接口函数

FFmpeg数据结构分析

AVStream

id:序号

codec:该流对应的AVCodecContext

time_base:该流的时基

r_frame_rate:该流的帧率

AVCodecContext

codec:编解码器的AVCodec

width, height:图像的宽高(只针对视频)

pix_fmt:像素格式(只针对视频)

sample_rate:采样率(只针对音频)

channels:声道数(只针对音频)

sample_fmt:采样格式(只针对音频)

AVCodec

name:编解码器名称

long_name:编解码器长名称

type:编解码器类型

id:编解码器ID

一些编解码的接口函数

FFmpeg数据结构分析

AVPacket

pts:显示时间戳

dts:解码时间戳

data:压缩编码数据

size:压缩编码数据大小

stream_index:所属的AVStream

AVFrame

data:解码后的图像像素数据(音频采样数据)

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"画"在系统的窗口中

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_cj5785的博客-CSDN博客

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

猜你喜欢

转载自blog.csdn.net/yinshipin007/article/details/131146281