ffmpeg是一个开源的音视频编解码工具,很多音视频播放器和转码器都将其作为内核。
ffmpeg的组成结构
- libavcodec encoding/decoding library
- libavutil common utility library
- libavformat I/O and muxing/demuxing library
- libavfilter graph-based frame editing library
- libavdevice special devices muxing/demuxing library
- libswscale color conversion and scaling library
- libswresample audio resampling, format conversion and mixing
- libpostproc post processing library
环境部署
ffmpeg官网提供三个不同版本的下载,
版本 | 介绍 | 总结 |
---|---|---|
static | 包含了三个体积较大的exe:ffmpeg.exe、ffplay.exe和ffprobe.exe,所有dll已经编译到exe中去了 | 产品化的东西,小型项目直接使用 |
shared | 也包含了这三个exe,体积更小,运行时动态调用dll链接库 | 产品化的东西,适用于大型项目 |
dev | 包含的是lib包和头文件 | 适用于开发使用 |
从官网上下载dev版本,然后将include目录添加到项目的包含目录中,lib目录添加到项目的库文件目录中,将几个lib文件的名字添加到编译器的输入中。
shared版exe程序的使用
常见使用命令参数
如果仅仅想实现功能上的快速开发,可以直接调用exe:
- ffmpeg是用来转码的
- ffplay是用来播放的
- ffprobe是用来查看文件格式的
参数选项 | 解释 | 总结 |
---|---|---|
-i filename | 输入文件 | 可以输入多个 |
-y | 当输出文件已经存在时,是否执行覆盖 | 缺省时,文件已存在会触发异常 |
-ss start_time -to end_time | 截取时间 | 时间的格式既可以是xx:xx:xx也可以是浮点数xxx.xxx |
-ss start_time -t duration | 截取时间 | |
-r fps | 设置视频的帧率 | |
-vcodec codec | 强制使用codec编解码方式 | codec可以设置为copy |
-b bitrate | 设置比特率,缺省200kb/s |
踩坑记录:
音视频混流时,音频文件必须在视频文件前面
dev版ffmpeg播放视频的流程
播放一个视频的全部流程:
- 解协议:如果视频数据是通过网络传输,那么第一步就是解协议。解协议将流媒体协议的数据,解析为标准的相应的封装格式数据。常见的解协议有HTTP,RTMP,或是MMS等等
- 解封装demux:将封装格式数据(e.g. MKV)中的视频压缩数据(e.g. H.264)和音频压缩数据(e.g. AAC)分离开,这个过程中不涉及编码和解码。将读取一个媒体文件,然后将其拆分为数据块(data chunk)
- 解码:就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据
- 音视频同步:播放一个视频的最后一步就是音视频同步。这个过程将根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来
除此之外,在处理完视频帧后,
- 音视频编码:将视频像素数据(RGB,YUV等)压缩成为视频码流,将音频采样数据(PCM等)压缩成为音频码流,从而降低音视频的数据量
常用API(根据原官方文档做了个性化翻译,具体以官方文档为准)
av_register_all 注册所有组件
打开和关闭视频
int avformat_open_input(AVFormatContext **ptr, const char * filename, AVInputFormat *fmt, AVDictionary **options)
打开一个媒体文件,将格式上下文保存在ptr指向的结构体中
fmt
forces file format if not NULL.options
附加的选项,可以为NULL- 函数执行成功,返回大于等于0的值
void avformat_close_input(AVFormatContex ** s)
关闭一个打开的AVFormatContext
寻找流信息,获取帧信息
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary ** options)
读取媒体文件的packets来获取流信息,成功时返回值大于等于0
int av_read_frame(AVFormatContext * s, AVPacket * pkt)
读取流中的下一帧,只返回的只是文件存储的东西,可能对解码器是无效的一帧
如果pkt->buf是NULL,那么直到下一个av_read_frame()或者直到avformat_open_input,当前packet都是有效的
对于视频来说packet只包含一帧,但是对于音频来说,如果每帧的大小是已知的,那么包含的是帧数,如果大小是变量,那么包含一帧。
int av_parse_video_size(int * width_ptr, int * height_ptr, const char * str)
解析str,并将解析得到的长度和宽度保存在height_ptr和width_ptr中
缩放视频
struct SwsContext * sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter * srcFilter, SwsFilter * dstFilter, const double * param)
部署和运行SwsContext
- srcW/srcH/srcFormat 原图片的宽度、高度和格式
- dstW/dstH/dstFormat 目标图片的宽度、高度和格式
- flags 指定使用哪种算法和选项来重缩放
- param 额外的参数
int sws_scale(struct SwsContext * c, const uint8_t * const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t * const dst[], const int dstStride[])
在srcSlice中缩放图像切片
- c 使用sws_getContext()创建的缩放上下文
- srcSlice 包含指向原切片指针的数组
- srcStride 包含原图像步长的数组
- srcSliceY
- srcSliceH
- dst
- dstStride
返回输出切片的高度
void sws_freeContext(struct SwsContext * swsContext)
释放
avcodec_find_decoder 找到解码器
avcodec_open2 打开解码器
av_read_frame 读取帧
avcodec_decode_video2 开始解码
常用的结构体
1. AVFormatContext类
格式化IO上下文,在使用FFMPEG进行开发的时候,AVFormatContext是一个贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体
属性:
- AVStream** AVFormatContext::streams
包含文件中所有流的一个列表,在解封装demux的时候,创建方法有两种:avformat_open_input()和av_read_frame();在mux的时候,在avformat_writer_header()前通过用户创建
- unsigned int AVFormatContext::nb_streams
AVFormatContext.streams中元素的个数
- int AVFormatContext::ctx_flags
标记符号流属性
- int64_t AVFormatContext::start_time
组成部分中第一个帧的位置
- int64_t AVFormatContext::duration
流的时长
- int64_t AVFormatContext::bit_rate
码率bit/s
- int64_t AVFormatContext::packet_size
2. AVInputFormat
每种封装格式例如FLV\MKV\MP4\AVI对应一个该结构体
3. AVStream 每个视频流、音频流对应一个结构体
- int index stream index in AVFormatContext
- int id
- void* priv_data
- AVRational time_base
- int64_t start_time
- int64_t duration
- int64_t nb_frames 当前流中的帧数
- int disposition
- AVCodecParameters * codecpar