VS2022+QT6.7+FFmpeg 学习(详细注释)(复习)

#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博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值