Advertisement

C C++最全【FFmpeg+Qt开发】解码流程 详细分析+代码示例_qt ffmpeg(2),2024年最新2024年C C++开发陷入饱和

阅读量:

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

2.1解码流程

2.2解码示例


一、FFMPEG 概述

  • FFmpeg 是一套可以用来记录、转换,数字音频、视频,并能将其转化为流的开源计算机程序。
  • FFmpeg 采用 LGPL 或 GPL 许可证;它提供了录制、转换以及流化音视频的完整解决案;它还包含了非常先进的音频\视频编解码库 libavcodec,为了保证高可移植性和编解码质量,libavcodec 里很多 code 都是从头开发的。
  • FFmpeg 在 Linux 平台下开发,但它同样也可以在其它操作系统环境中编译,包括 Windows、Mac OS X 等。
  • FFmpeg最早由 Fabrice Bellard 发起,2004 年至 2015 年间由 Michael Niedermayer 主要负责维护。许多 FFmpeg 的开发人员都来自 MPlayer 项目,而且当前 FFmpeg 也是放在MPlayer 项目组的服务器上。
  • FFmpeg名称来自 MPEG 视频编码标准,前面的"FF" 代表"Fast Forward"。

下载链接:Download FFmpeg

具体下载详见:Qt+FFmpeg----windows下环境搭建_猿力猪的博客-博客_ffmpeg开发环境搭建

​二、FFMPEG 解码

2.1解码流程

🔴解码 :将带有封装格式的视频解封装后得到的压缩码流数据(编码数据)经过解码得到像素数据的过程。

例如:解码
H.264
压缩码流数据得到
YUV
(或者
RGB
)的像素数据。

解码的流程图,如下所示:

🔴解码思路分析:

  1. 注册所有的组件 av_register_all()
  2. 打开视频文件 avformat_open_input() 有可能打开失败
  3. 获取视频信息 视频码流、音频码流、文字码流
  4. 查找流信息 avformat_find_stream_info()
  5. 找到解码器 avcodec_find_decoder() 有可能没找到
  6. 打开解码器 avcodec_open2()
  7. 读取码流中的一帧码流数据 av_read_frame()
  8. 解码读到一帧码流数据 得到一帧的像素数据 YUV RGB
  9. 重复7-8的动作 直到视频所有的帧都处理完
  10. 关闭解码器
  11. 关闭视频文件

🔴解码过程中几个重要的结构体:

  • AVFormatContext

封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息。

  • AVInputFormat//AVOutpufFormat

每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体。

  • AVStream

视频文件中每个视频(音频)流对应一个该结构体。

  • AVCodecContext

编码器上下文结构体,保存了视频(音频)编解码相关信息。

  • AVCodec

每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体。

  • AVPacket

存储一帧压缩编码数据。

  • AVFrame

存储一帧解码后像素(采样)数据。

2.2解码示例

🟢解码类的定义

复制代码
    //ffmpeg使用c语言实现的,引入用c写的代码就要用extern
    extern "C"   
    {
    #include <libavcodec/avcodec.h>   //编码
    #include <libavdevice/avdevice.h>  
    #include <libavformat/avformat.h>  //封装格式处理
    #include <libavutil/error.h>  
    #include <libswscale/swscale.h>  //像素处理
    #include <libswresample/swresample.h>  //缩放
    }
    class fdecode
    {
    public:
    fdecode();
    //注册组件
    void registerFFmpeg();
    //打开视频流
    void openVIdeoStream(QString filename);
    //视频名称
    QString filename;
    protected:
    private:
    };
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-19/lJORtQId3urHzNLYh2pjEyG0oUsi.png)

具体实现如下:

🟢注册所有组件

复制代码
    void fdecode::registerFFmpeg()
    {
    //注册所有的组件
    av_register_all();
    }
    
    

🟢打开视频文件

复制代码
    AVFormatContext *forContent;//用来保存视频相关信息的结构体
    forContent=avformat_alloc_context();//分配空间
    
    //打开视频文件
    int res=avformat_open_input(&forContent,filename.toStdString().c_str(),nullptr,nullptr);
    if(res!=0)//判断是否打开视频文件
    {
        qDebug()<<"无法打开视频文件";
        return;
    }
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-19/SNZhvGrwURAgDFbTHxq9osL7u8iC.png)

🟢****获取视频文件信息

复制代码
    //打开视频文件成功,获取文件信息
    res = avformat_find_stream_info(forContent,nullptr);//查看有没有相关视频流信息
    if(res<0)
    {
        qDebug()<<"没有流媒体信息"<<endl;
        return;
    }
    
    //一个视频流有多股码流,存在forContentext中streams数组中
    int videoType=-1;
    //nb_streams代表封装格式里面的结构体信息有几个,正常两个:音频信息、视频信息
    for(int i=0;i<forContent->nb_streams;i++) //i小于流的个数
    {
        if(forContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//视频流
        {
            videoType=i;//标识类型
            break;
        }
    }
    //判断是否有视频流信息
    if(videoType==-1)
    {
        qDebug()<<"没有视频流相关信息"<<endl;
        return;
    }
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-19/0w7sVUpMRvJAdEIGDrzyFHPokY3x.png)

🟢****根据编解码上下文中的编码ID查找对应解码器

复制代码
    //编解码器对应的上下文对象结构体:保存解码器信息以及图形的宽高、像素信息
    AVCodecContext *codec=forContent->streams[videoType]->codec;
    //查找对应的视频流解码器
    AVCodec *decoder = avcodec_find_decoder(codec->codec_id);
    if(decoder==nullptr)//判断是否找到解码器
    {
        qDebug()<<"没有对应的解码器"<<endl;
        return;
    }
    
    

🟢打开解码器

复制代码
    //找到了解码器,打开解码器
    res = avcodec_open2(codec,decoder,nullptr);
    if(res!=0)
    {
        qDebug()<<"解码器打开失败"<<endl;
        return;
    }
    
    

🟢读取准备 获取YUV和RGB像素数据

复制代码
    //为准备读取帧数据做准备--AVPacket 用来存储一帧一帧的压缩数据(h264)
    AVPacket *pkt=nullptr;
    //设置缓冲区,开空间
    pkt=(AVPacket *) malloc(sizeof(AVPacket));
    int size=codec->width*codec->height;//计算一张图片数据大小
    av_new_packet(pkt,size);
    
    /* pictureRGB 保存解码后的RGB像素数据
        * pictureYUV 保存解码后的YUV像素数据
        * picture    保存未处理的像素数据
        */
    AVFrame *pictureRGB,*pictureYUV,*picture=nullptr;
    
    //内存分配
    pictureRGB=av_frame_alloc();
    pictureYUV=av_frame_alloc();
    picture=av_frame_alloc();
    
    //大小以及格式设置RGB
    pictureRGB->width=codec->width;//宽度
    pictureRGB->height=codec->height;//高度
    pictureRGB->format=codec->pix_fmt;//格式设置
    
    //大小以及格式设置YUV
    pictureYUV->width=codec->width;//宽度
    pictureYUV->height=codec->height;//高度
    pictureYUV->format=codec->pix_fmt;//格式设置
    
    //一帧码流数据解码后得到YUV RGB像素数据有多大
    int numByte_RGB=avpicture_get_size(AV_PIX_FMT_RGB32,codec->width,codec->height);
    int numByte_YUV=avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);
![img]()
![img]()
    
    **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取]()**
    
    dth,codec->height);
    
    
    
    [外链图片转存中...(img-63hQvfd9-1715701380431)]
    [外链图片转存中...(img-BmmxWKhI-1715701380431)]
    
    **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取]()**
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-19/OZTvJ8nfdQoi6e7yG4NM0sPmVFqg.png)

全部评论 (0)

还没有任何评论哟~