赞
踩
- 首语:学习三步:是什么?怎么用?为什么?
- 一、概念
- 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--帧 :流中的数据元素
-
- 二、解码流程图
- 三、视频解码步骤:
- 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 <libavcodec\avcodec.h>
- # include <libavformat\avformat.h>
- # include <libswscale\swscale.h>
- }
- //后续会更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。