FFmpeg
libavformat
用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能;音视频的格式解析协议,为 libavcodec 分析码流提供独立的音频或视频码流源
libavcodec
用于各种类型声音/图像编解码;该库是音视频编解码核心,实现了市面上可见的绝大部分解码器的功能,libavcodec 库被其他各大解码器 ffdshow,Mplayer 等所包含或应用
libavfilter
音视频滤镜库,该模块提供了包括音频特效和视频特效的处理,在使用FFmpeg的API进行编解码的过程中,直接使用该模块为音视频数据做特效处理是非常方便和高效的方式
libavutil
核心工具库,该模块是最基础的模块之一,许多其他模块都会依赖该库做一些基本的音视频处理操作
libswresample
该模块可用于音频重采样,可以对数字音频进行音声道、数据格式、采样率等多种进本信息的转换
libswscale
(原始视频格式转换)用于视频场景比例缩放、色彩映射转换;图像颜色空间或格式转换,如 rgb565,rgb888 等与 yuv420 等之间转换。
版本查看
int main(){
unsigned codecVer = avcodec_version();
int ver_major,ver_minor,ver_micro;
ver_major = (codecVer>>16)&0xff;
ver_minor = (codecVer>>8)&0xff;
ver_micro = (codecVer)&0xff;
printf("FFmpeg version is: %s .\navcodec version is: %d=%d.%d.%d.\n",FFMPEG_VERSION,codecVer,ver_major,ver_minor,ver_micro);
return 0;
}
FFmpeg
分为各个模块,每个模块的版本都不一致且与FFmpeg
的主版本号没有关联,不过我们可以查看各个模块的版本号,如:avcodec
,然后根据模块的版本号去官网查看对应的主版本号
每个各占8位
查看视频流信息
我们可以将多媒体文件看作是一个容器,其中存放着各种流(视频流、音频流、字幕流)
每种流都是由不同的编码器进行编码,比如视频流编码有h.264、MPEG4、H.265等,这些信息我们都可以通过FFmpeg
的av_dump_format
函数打印
示例代码
extern "C"{
#include"libavformat/avformat.h"
}
int main() {
AVFormatContext* fmt_ctx = avformat_alloc_context();//创建对象并初始化
int ret = 0;
//文件地址
const char* filePath = ".\\target.mp4";
do {
//打开文件
if ((ret = avformat_open_input(&fmt_ctx, filePath, NULL, NULL)) < 0)
break;//Cannot open video file
//查找流信息(音频流和视频流)
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
printf("Cannot find stream information\n");
break;
}
av_dump_format(fmt_ctx, 0, filePath, 0);//输出视频信息
} while (0);
avformat_close_input(&fmt_ctx);//关闭文件
return 0;
}
输出结果:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'target.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.48.100
Duration: 00:03:10.36, start: 0.000000, bitrate: 773 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x720, 442 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 325 kb/s (default)
Metadata:
handler_name : SoundHandler
文件使用完成之后要及时关闭。可以使用goto语句进行错误处理,但是在开发C++时不推荐使用goto语句
可以使用do{}while(0),实现类似效果,此语句只会执行{}中的代码一次,将释放资源的代码放在do-while代码段之外,出现异常就进行break即可
代码解析
结构体
avformat_alloc_context
用于创建AVFormatContext
结构体的方法,AVFormatContext
是结构上下文,内部存放着描述媒体文件或媒体流的构成和基本信息,贯穿ffmpeg使用整个流程
// 截取出部分较为重要的数据
typedef struct AVFormatContext {
struct AVInputFormat *iformat;
struct AVOutputFormat *oformat;//输入或者输出流的格式(只能存在一个)
AVIOContext *pb;//管理输入输出数据
unsigned int nb_streams;//音视频流的个数
AVStream **streams;//音视频流
char *url;//文件名
int64_t duration;//时长
int bit_rate;//比特率(单位bite/s)
AVDictionary *metadata;//元数据(查看元数据:ffprobe filename)
...
}
其中存放着
AVStream
结构体,存储音频流或视频流// 截取出部分较为重要的数据 typedef struct AVStream { int index;//音频流或视频流的索引 AVRational time_base;//计算pts或dts是使用的时间戳基本单位(显示时间:pt = av_q2d(video_stream->time_base) * frame->pts) int64_t duration;//该视频||音频流长度 AVRational avg_frame_rate;//平均帧率(对于视频来说,frame_rate=avg_frame_rate.num / avg_frame_rate.den) AVCodecParameters *codecpar;//解码器参数 ... } AVStream;
函数
avformat_open_input
函数用于打开一个多媒体文件,可以是本地文件也可以是网络文件
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
参数:
- AVFormatContext **ps:
AVFormatContext
结构体,注意此处为指针的指针,也就是在该方法中为AVFormatContext
数据赋值 - const char *url:文件路径
- AVInputFormat *fmt:输入格式,若为NULL,则会通过 url 文件后缀去寻找对应格式
- AVDictionary **options:指定各种参数,比如:探测时间、超时时间、最大延时、支持的协议的白名单等等,一般填NULL即可
return:
返回0则代表成功,失败则会返回一个负数
与之对应的就是
avformat_close_input
,该函数会去释放AVFormatContext
所持有的资源
avformat_find_stream_info
函数用于查找流信息(音频流和视频流)
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
参数:
- AVFormatContext *ic:
AVFormatContext
结构体 - AVDictionary **options:与上述方法作用一致,基本都是填NULL
return:
返回数值 ≥ 0时代表成功,其余则代表失败
av_dump_format
函数会打印多媒体文件中的Meta信息,如:时长、比特率、编解码器等
void av_dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output);
参数:
- AVFormatContext *ic:
AVFormatContext
结构体 - int index:要转储信息的流的索引,只是打印没什么影响
- const char *url:url只是打印结果的显示,所以输入什么不影响
- int is_output:指定上下文是输入(0)还是输出(1)
注意:有的流需要经过avformat_find_stream_info才能打印出信息,有些流则不需要