基于 FFmpeg 与SDL 的视频播放器 (2)—FFmpeg视频解码
文章目录
视频解码知识
-
解码h.264格式类型的纯净码流
具体就是讲压缩的视屏编码数据转化为视频像素数据,例如解码H.264,就是H.264码流解码为YUV格式的数据。
-
解码封装后的视频文件
我们所观看的视频,码流大部分都存储在一定的封装格式(例如MP4、AVI等)中。封装格式中通常还包含音频码流等内容。对于封装格式中的视频,需要先从封装格式中提取视频码流,然后再进行解码。例如解码avi格式的视频文件,就是“avi->H.264码流->YUV”。
基于QT搭建FFmpeg开发环境
-
获取FFmpeg
根据自己的需要选择相应版本,其中其中 Static 顾名思义就是静态库版本了,Shared则是动态库版本,Dev则是提供给开发者用的Lib文件。这里我们下载的是Shared和Dev。
- 在项目中引用FFmpeg
项目的创建过程这里不再描述,只讲解FFmpeg引入部分,首先解压刚才下载的Shared和Dev压缩包,其中Shared压缩包中只有一个项目运行时所需要的.dll文件,Dev压缩包解压后我们只需要其中的include和lib文件夹,直接复制到我们的工程目录下面
然后就是在.pro文件中引入
INCLUDEPATH += $$PWD/lib/ffmpeg/include
LIBS += $$PWD/lib/ffmpeg/lib/avcodec.lib\
$$PWD/lib/ffmpeg/lib/avdevice.lib\
$$PWD/lib/ffmpeg/lib/avfilter.lib\
$$PWD/lib/ffmpeg/lib/avformat.lib\
$$PWD/lib/ffmpeg/lib/avutil.lib\
$$PWD/lib/ffmpeg/lib/postproc.lib\
$$PWD/lib/ffmpeg/lib/swresample.lib\
$$PWD/lib/ffmpeg/lib/swscale.lib
由于我们建立的是C++的工程,编译的时候使用的C++的编译器编译,而FFMPEG是C的库,因此这里需要加上extern “C”。
extern "C" {
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
#include <libswscale\swscale.h>
#include <libswresample\swresample.h>
}
解码相关函数和数据结构介绍
函数
-
**av_register_all():**注册所有文件格式和编解码库
-
**avformat_open_input():**打开文件或URL,并使基于字节流的底层输入模块得到初始化;解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关键字段,依次为各个原始流建立AVStream结构。
-
**avformat_find_stream_info():**获取视频文件信息。
-
**avcodec_find_decoder():**查找解码器。
-
*int av_seek_frame(AVFormatContext s, int stream_index, int64_t timestamp, int flags):
作用:通过改变媒体文件的读写指针来实现对媒体文件的随机访问,大多源于媒体播放器的快进、快退等功能。
参数:s:AVFormatContext指针;
avformat_open_input返回得到。
stream_index:指定媒体流。
timestamp:时间标签。
flags:定位方式 -
**avcodec_open2():**打开解码器。
-
**av_read_frame():**从输入文件读取一帧压缩数据。
-
**avcodec_decode_video2():**解码一帧压缩数据。
-
**avcodec_close():**关闭解码器。
-
**avformat_close_input():**关闭输入视频文件。
数据结构
- AVFormatContext : 封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装 格式相关信息
- iformat:输入视频的AVInputFormat
- nb_streams :输入视频的AVStream 个数
- streams :输入视频的AVStream []数组
- duration :输入视频的时长(以微秒为单位)
- bit_rate :输入视频的码率
- **AVInputFormat :**每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体
- name:封装格式名称
- long_name:封装格式的长名称
- extensions:封装格式的扩展名
- id:封装格式ID
- 一些封装格式处理的接口函数
- **AVStream :**视频文件中每个视频(音频)流对应一个该结构体。
- id:序号
- codec:该流对应的AVCodecContext
- time_base:该流的时基
- r_frame_rate:该流的帧率
- **AVCodecContext :**编码器上下文结构体,保存了视频(音频)编解码相关信息。
- codec:编解码器的AVCodec
- width, height:图像的宽高(只针对视频)
- pix_fmt:像素格式(只针对视频)
- sample_rate:采样率(只针对音频)
- channels:声道数(只针对音频)
- sample_fmt:采样格式(只针对音频)
- **AVCodec :**每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体。
- name:编解码器名称
- long_name:编解码器长名称
- type:编解码器类型
- id:编解码器ID
- 一些编解码的接口函数
- **AVPacket :**存储一帧压缩编码数据。
- pts:显示时间戳
- dts :解码时间戳
- data :压缩编码数据
- size :压缩编码数据大小
- stream_index :所属的AVStream
- **AVFrame :**存储一帧解码后像素(采样)数据。
- data:解码后的图像像素数据(音频采样数据)。
- linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音 频帧的大小。
- width, height:图像的宽高(只针对视频)。
- key_frame:是否为关键帧(只针对视频) 。
- pict_type:帧类型(只针对视频) 。例如I,P,B。
FFmpeg解码的流程
解码视频并保存50张图片的完整代码
#include <iostream>
using namespace std;
#define __STDC_CONSTANT_MACROS
extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"