FFmpeg基础编程-学习笔记(十二)

首语:学习三步:是什么?怎么用?为什么?
一、概念
1、FFmpeg:
(1)FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它包括了目前领先的音/视频编码库libavcodec。
(2)FFmpeg是领先的多媒体框架,提供音视频的编解码播放等功能,支持几乎所有音视频格式。含有多个模块库,如AVFormate,AVCodec,AVFilter,AVDivice,AVUtile等,并且提供了基于这些库的三个命令行工具ffmpeg,ffplay,ffprobe
使用ffmpeg方式有2种,一为直接用命令行工具,二为用ffmpeg封装的库做二次开发。
AVFormate:实现当前媒体领域绝大多数媒体封装格式,如MP3,mkv等,也可自定义封装格式。
模块库:
AVCodec:实现当前媒体领域大多数编解码格式
AVFilter:提供通用的音频,视频,字幕等滤镜处理框架
AVDivice:包含音视频采集和渲染相关的输入输出接口
AVUtile:提供基本工具,如文件操作,时间操作等。
2、CODEC--编解码器:
能够进行视频和音频压缩(CO)与解压缩(DEC),是视频编解码的核心部分。
3、Container/File --容器/多媒体文件:
下载的电影文件的后缀(avi,mkv,rmvb等)并不是视频的编码方式,只是其封装的格式。一个视频文件通常有视频数据、音频数据以及字幕等,封装的格式决定这些数据在文件中是如何的存放的。多媒体文件,也可以叫做容器,就是封装在一起音频、视频等数据的集合体。所以,只看多媒体文件的后缀名是难以知道视音频的编码方式的。
4、Stream--流数据 :如视频流(Video Stream),音频流(Audio Stream)。
5、Frame--帧 :流中的数据元素

二、解码流程图

FFmpeg基础编程-学习笔记(十二)_第1张图片

三、视频解码步骤:
1、av_register_all();//调用注册库,获取其支持的所有文件(容器)格式及其对应的CODEC(编解码器)
2、avformat_open_input();//打开视频文件
3、avformat_find_stream_info();//从视频文件中提取视频流
在多个数据流中找到视频流(video stream),类型为MEDIA_TYPE_VIDEO
4、avcodec_find_decoder();//查找视频流对应的解码器
   avcodec_open2();//打开视频流解码器
5、av_frame_alloc();//为解码帧分配内存
6、av_read_frame();//从视频流中读取读取数据到Packet中
   avcodec_decode_video2();//对视频流帧进行解码
7、avcodec_close(pCodecCtxOrg);//关闭解码器
   avformat_close_input(&pFormatCtx); //关闭输入流

四、FFmpeg视频解码详解
1、调用av_register_all(),注册库中含有所有可用的文件格式和编解码器。只需要调用一次,故一般放在main函数中。也可以注册某个特定的容器格式,但通常来说不需要这么做。
2、打开媒体文件,avformat_open_input();//读取文件的头信息,并将其信息保存到AVFormatContext结构体中。该函数通过解析多媒体文件或流的头信息及其他的辅助数据,能够获取到足够多的关于文件、流和CODEC的信息,并将这些信息填充到AVFormatContext结构体中。
函数原型:avformat_open_input(&pFormatContext, filepath, NULL, NULL);成功返回0
用法:
AVFormatContext* pFormatCtx = nullptr;//定义结构体类型指针变量
avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr);
参数1:pFormatCtx--AVFormatContext结构体类型的指针
参数2:filenName--文件路径
参数3:设定输入文件的格式,设为null,将自动检测文件格式
参数4:用于填充AVFormatContext一些字段以及Demuxer的private选项
3、获取文件中的流信息并找到视频流的索引(获取必要的编解码器参数),
avformat_find_stream_info();
//从视频文件中提取数据流信息。在多个数据流中找到视频流(video stream),类型为MEDIA_TYPE_VIDEO。
函数原型:
avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);//获取视频流信息
avformat_find_stream_info(pFormatContext, NULL);//查找视频流编码索引
int i;
for (i = 0; i < pFormatContext->nb_streams; i++)//nb_streams表示视频文件中有几种流
{    //遍历多媒体文件中的每一个流,判断是否为视频
    if (pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    {
        videoIndex = i;
        break;
    }
}
4、获取视频流的编解码信息并通过编解码信息打开对应的编解码器
pCodec = avcodec_find_decoder(pCodecContext->codec_id);//查找和视频流对应的解码器
avcodec_open2(pCodecContext, pCodec, nullptr);//打开该解码器
5、开始解码 -为解码帧分配内存
pFrame = av_frame_alloc();//存放原始帧
pFrameYUV = av_frame_alloc();//存放解码后的yuv
packet = (AVPacket*)av_malloc(sizeof(AVPacket));//开辟空间,存放编码后,解码前的数据
6、读取数据帧并解码。有了相应的解码器,接下里打开视频流读数据,通过读取包来读取整个视频流,并解码为没有压缩的原始数据。
调用av_read_frame将数据从流中读取数据到packet中,读取的AvPacket如果是视频帧的话,可以用avcodec_decode_video2来解码一个AvPacket到一个AVFrame 中。
AVPacket packet; 
//读取码流中的视频一帧,放入编码后,解码前的数据到packet中
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
    if (packet.stream_index == videoStream)//如果读取的是视频流
    {
        int frameFinished = 0;
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
        if (frameFinished)
        {
            doSomething();
        }
    }
} 
6、关闭
avcodec_close(pCodecCtxOrg);//关闭由avcodec_open2打开的CODEC
avformat_close_input(&pFormatCtx); //关闭由avformat_open_input打开的输入流
附注:
在配置好FFmpeg的开发环境后,在C++中使用FFmpeg的库函数,会出现解析不出函数的名称链接错误,这是由于FFmpeg库是C语言实现,要在C++调用C函数需要 extern "C"的声明。
extern "C"
{
    # include 
    # include 
    # include 
}
//后续会更新

 

 

 

 

 

 

你可能感兴趣的:(Linux,学习笔记)