#include "QtWidgetsApplication1.h"
#include <QDebug>
QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
/***********************************************解码所需要的主要参数(结构体)*******************************************************/
//(编解码器参数)AVFormatContext结构体包含了容器的所有信息,如流信息、元数据等,是多媒体文件的顶级上下文对象
AVFormatContext *formatontext = avformat_alloc_context();
AVIOContext* pd; //输入数据的缓存
AVStream** streams; //视频音频流
unsigned int* nb_streams; //视频音频流的个数
AVDictionary* metadata; //元数据
int64_t duration; //时长
char filename[1024]; //文件名
int bit_rate; //比特率
//(编解码器上下文)AVCodecContext结构体表示一个编解码器的上下文,包含了编解码器的所有状态信息
AVCodecContext* codecContext;
enum AvmediaType codec_type; //编解码器的类型(视频、音频)
int bit_rate; //平均比特率
uint8_t* extrdata; int extrdata_size; //针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
AVRational time_base; //根据该参数,可以把PTS转化为实际的时间(单位为秒s)
int width, height; //如果是视频的话,代表宽和高(分辨率)
int sample_rate; //音频的采样率
int channels; //音频的声道数
enum Avsamplerate_t sample_fmt; //音频的采样格式
int profile; //型(H.264里面就有,其他编码标准应该也有)
int level; //级(和profile差不太多)
//AVPacket结构体用于存储一个编解码的数据包,它可以包含视频帧或音频帧的数据
AVPacket *packet = av_packet_alloc();
uint8_t* data; //压缩编码的数据
int size; //data的大小
int64_t pts; //显示时间戳
int64_t dts; //解码时间戳
int stream_index; //标识该AVPacket所属的视频/音频流
//AVFrame结构体用于存储解码后的原始数据,它可以包含视频帧或音频帧的原始数据
AVFrame *frame = av_frame_alloc();
uint8_t* data[AV_NUM_DATA_POINTERS]; //解码后的原始数据(对视频来说是YUV,RGB,对音频来说是PCM)
int linesize[AV_NUM_DATA_POINTERS]; //data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽
int width, height; //视频帧的的宽高
int nb_samples; //音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
int format; //解码后的原始数据类型
int key_frame; //是否为关键帧
enum AVPictureType picture_type; //帧的类型
AVRational sample_aspect_ratio; //宽高比
int64_t pts; //显示时间戳
int coded_picture_number; //编码帧序号
int display_picture_number; //显示帧序号
int8_t* qscale_table; //QP表
uint8_t* mbskip_table; //跳过宏块表
int16_t(*motion_val[2][2]); //运动矢量表
uint32_t* mb_type; //宏块类型表
short* dct_coeff; //DCT系数表
int8_t* ref_index[2]; //运动估计参考帧索引表
int interlaced_frame; //是否为隔行扫描
uint8_t motion_subsample_log2; //运动矢量采样个数,取log的
//AVCodec结构体表示一个编解码器的描述信息,包含了编解码器的各种属性和方法,用于识别和使用编解码器
const AVCodec* codec;
const char* name; //编解码器的名称
const char* long_name; //编解码器的详细描述
enum Avcodec_t codec_type; //指明了类型,是视频,音频,还是字幕
enum Avcodec_t codec_id; //编解码器的ID
const AVRational* supported_framerates; //支持的帧率(视频)
const enum Avpixelformat_t* pix_fmts; //支持的像素格式(视频)
const int* supported_samplerates; //支持的采样率(音频)
const enum Avsamplerate_t* sample_fmts; //支持的采样格式(音频)
const uint64_t* channel_layouts; //支持的声道数(音频)
int priv_data_size; //私有数据大小
//对象复制函数,用于将 AVCodecParameters 对象的内容复制到 AVCodecContext 对象中
avcodec_parameters_to_context(codecContext, formatontext->streams[0]->codecpar); //新版本写法
//查解码器函数
codec = avcodec_find_decoder(codecContext->codec_id);
/****************************************************解码所调用函数*******************************************************/
///av_register_all(); 新版本移除不需要调用,旧版本需要调用
///实例:int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); //第一个参数是结构体的地址,第二个参数是文件名,三四默认
int avformat_open_ret=avformat_open_input(&formatontext,filename,NULL,NULL); //2、打开多媒体文件
if(avformat_open_ret<0) //如果返回值小于0,说明打开失败
{
char* result = new char[64];
av_strerror(avformat_open_ret, result, 64);
qDebug() << QString("错误信息:%1").arg(result);
} else qDebug() << "打开文件成功";
///实例:int avformat_find_stream_info(AVFormatContext * ic, AVDictionary * *options);
int avformat_find_ret=avformat_find_stream_info(formatontext,NULL); //3、获取音视频码流信息
if(avformat_find_ret<0) //如果返回值小于0,说明获取失败
{
char* result = new char[64];
av_strerror(avformat_find_ret, result, 64);
qDebug() << QString("错误信息:%1").arg(result);
} else qDebug() << "获取音视频码流信息成功";
///函数的参数是一个解码器的ID,返回查找到的解码器(没有找到就返回NULL)
///实例:AVCodec *avcodec_find_decoder(enum AVCodecID id);
AVCodec* avcodec_find_decoder(enum AVCodecID id); //4、查找解码器,上文有实例,与参数介绍
int streamIndex = -1;
for(int i=0;i<formatontext->nb_streams;i++)
{
//若流的类型为视频流,保存该视频流的索引
if(formatontext->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO)
{
streamIndex = i;
break;
}
}
if(streamIndex==-1)
{
qDebug() << "找不到视频流";
return;
}
///实例:int avcodec_open2(AVCodecContext *avctx,const AVCodec *codec,AVDictionary **options);
int avcodec_open_ret=avcodec_open2(codecContext, codec,NULL); //5、打开找到的解码器
if(avcodec_open_ret<0) //如果返回值小于0,说明打开失败
{
char* result = new char[64];
av_strerror(avcodec_open_ret, result, 64);
qDebug() << QString("错误信息:%1").arg(result);
} else qDebug() << "打开解码器成功";
///通过while循环不断调用该函数,将音视频帧读取到数据包中
///实例:int av_read_frame(AVFormatContext *s,AVPacket *pkt);
while (av_read_frame(formatontext,packet)>=0) { } //6、读取媒体文件中的数据
qDebug() << "读取媒体文件中的数据成功";
///将数据包发送到编解码器上下文
///实例:int avcodec_send_packet(AVCodecContext *avctx,const AVPacket *avpkt);
avcodec_send_packet(codecContext,packet); //7、将数据包发送到编解码器上下文,直到数据包为空
qDebug() << "将数据包发送到编解码器上下文成功";
///实例:int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
int avcodec_receive_index = avcodec_receive_frame(codecContext,frame); //8、从编解码器上下文中接收解码后的帧
}
QtWidgetsApplication1::~QtWidgetsApplication1()
{}
借鉴:孤生i-CSDN博客