FFmpeg知识库
FFmpeg是一个开源免费跨平台的视频和音频流方案,采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。
最近做解码相关,需要用到FFmpeg的api。有幸拜读雷霄骅(leixiaohua1020)的专栏,以下大部分内容是阅读专栏摘录内容加上自己的整理和总结。缅怀雷神
常用API
获取库版本
方法:avcodec_version()
swscale_version()
avutil_version()
avformat_version()
swresample_version()
返回:十进制数字,如3835492
转换成版本号:3835492 -> 0x3a8664 -> 58 134 100 -> 58.134.100
参考:版本转换方法、FFMPEG版本对应的库版本、Library Version Macros
注册:av_register_all
注册所有的编解码器、复用/解复用组件等
1 | av_register_all() |
注:FFmpeg4.0 以上的版本,这个函数已经被废弃。
打开文件:avformat_open_input
打开多媒体数据并且根据header获得一些相关的信息
1 | int res = avformat_open_input(&pFormatCtx, filepath, fmt, options); |
需以 avformat_close_input() 方法结束
查找码流:avformat_find_stream_info
读取媒体文件的packets以获取stream信息
1 | int res = avformat_find_stream_info(pFormatCtx, NULL); |
查找解码器:avcodec_find_decoder
查找编码器
1 | AVCodec *pCodec = avcodec_find_decoder(codec_id); |
打开解码器:avcodec_open2
使用给定的编解码器初始化一个视音频编解码器的AVCodecContext
1 | int res = avcodec_open2(pCodecCtx, pCodec, NULL); |
读取:av_read_frame
读取码流中的若干帧音频或者一帧视频
1 | int res = av_read_frame(pFormatCtx, packet); |
解码:avcodec_decode_video2
从AVPacket解码一帧视频数据到AVPFrame
1 | int res = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); |
缩放:sws_scale
将源图片进行缩放,存入目标图片
1 | int res = sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, |
使用时,调用sws_getContext() 开始,调用sws_freeContext() 結束。
查找并跳转:av_seek_frame
视频跳转到指定时间戳
1 | int res = av_seek_frame(pFormatCtx,videoindex,pos,AVSEEK_FLAG_ANY); |
结构体
FFmpeg 中结构体很多。最关键的结构体可以分成以下几类:
解协议(http, rtsp, rtmp, mms)
AVIOContext,URLProtocol,URLContext 主要存储音视频使用的协议的类型以及状态。URLProtocol 存储输入音视频使用的封装格式。每种协议都对应一个 URLProtocol 结构。(注意:FFmpeg 中文件也被当做一种协议 “file”)解封装(flv, avi, rmvb, mp4)
AVFormatContext 主要存储音视频封装格式中包含的信息;AVInputFormat 存储输入音视频使用的封装格式。每种音视频封装格式都对应一个 AVInputFormat 结构。解码(h264, mpeg2, aac, mp3)
每个 AVStream 存储一个视频/音频流的相关数据;每个 AVStream 对应一个 AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个 AVCodecContext 中对应一个 AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个 AVCodec 结构。存数据
视频的话,每个结构一般是存一帧;音频可能有好几帧。解码前数据:AVPacket;解码后数据:AVFrame。
AVFormatContext
AVFormatContext 是存储音视频封装格式中包含的信息的结构体。
1 | AVIOContext *pb:输入数据的缓存 |
AVFrame
AVFrame 结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是 YUV,RGB,对音频来说是 PCM),此外还包含了一些相关的信息。比如说,解码的时候存储了宏块类型表,QP 表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用 FFmpeg 进行码流分析的时候,AVFrame 是一个很重要的结构体。
1 | int8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM) |
AVCodecContext
AVCodecContext 是一个描述编解码器上下文的结构体,包含了众多编解码器需要的参数信息。
1 | enum AVMediaType codec_type:编解码器的类型(视频,音频...) |
AVCodec
AVCodec 是存储编码器信息的结构体。
1 | const char *name:编解码器的名字,比较短 |
AVStream
AVStream是存储每一个视频/音频流信息的结构体
1 | int index:标识该视频/音频流 |
AVPacket
AVPacket是存储压缩编码数据相关信息的结构体。
1 | uint8_t *data:压缩编码的数据。 |
AVIOContext
AVIOContext 是 FFmpeg 管理输入输出数据的结构体。
1 | unsigned char *buffer; // 缓存开始位置 |
编解码器常用命令
FFmpeg 的命令行参数可以分成五个部分
1 | $ ffmpeg {1} {2} -i {3} {4} {5} |
分别是:全局参数、输入文件参数、输入文件、输出文件参数、输出文件
控制b帧
(仅针对x264解码器)
去除b帧
1 | ffmpeg -i test.mp4 -vcodec libx264 -bf 0 out.mp4 |
如果希望控制I帧P帧B帧的频率和规律,可以通过控制GOP中B帧的帧数来实现,P帧的频率可以通过x264的参数b-adapt进行设置。
利用sc_threshold解决场景切换会强制插入GOP问题。
例如设置GOP中,每2个P帧之间存放3个B帧:
1 | ffmpeg -i input.mp4 -c:v libx264 -x264opts "bframes=3:b-adapt=0" -g 50 -sc_threshold 0 output.mp4 |
缩放视频
1 | 普通缩放 |
显示媒体流信息
ffprobe 是ffmpeg的一个工具包,主要用于探测音视频文件的各种信息
1 | 查看基本信息 |