【FFmpeg+Qt开发】解码流程 详细分析+代码示例

这篇具有很好参考价值的文章主要介绍了【FFmpeg+Qt开发】解码流程 详细分析+代码示例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、FFMPEG 概述

​二、FFMPEG 解码

2.1解码流程

2.2解码示例


一、FFMPEG 概述

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

下载链接:Download FFmpeg

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

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

​二、FFMPEG 解码

2.1解码流程

🔴解码:将带有封装格式的视频解封装后得到的压缩码流数据(编码数据)经过解码得到像素数据的过程。
例如:解码 H.264 压缩码流数据得到 YUV (或者 RGB )的像素数据。
解码的流程图,如下所示:

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

🔴解码思路分析:

  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:
};

具体实现如下:

🟢注册所有组件

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;
    }

🟢获取视频文件信息

    //打开视频文件成功,获取文件信息
    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;
    }

🟢根据编解码上下文中的编码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);

    //开的空间用来保存YUV RGB像素数据大小
    uint8_t *buffer_RGB=(uint8_t *)av_malloc(numByte_RGB*sizeof(uint8_t));
    uint8_t *buffer_YUV=(uint8_t *)av_malloc(numByte_YUV*sizeof(uint8_t));

    //像素数据的填充
    avpicture_fill((AVPicture *)pictureRGB,buffer_RGB,AV_PIX_FMT_RGB32,codec->width,codec->height);
    avpicture_fill((AVPicture *)pictureYUV,buffer_YUV,AV_PIX_FMT_YUV420P,codec->width,codec->height);

    //转换规则
    SwsContext *sws_RGB=nullptr;//保存转换规则的结构体
    SwsContext *sws_YUV=nullptr;//保存转换规则的结构体

    //转换规则的设置              AV_PIX_FMT_YUV420P   AV_PIX_FMT_RGB32
    sws_RGB=sws_getContext(codec->width,codec->height,codec->pix_fmt,
                           codec->width,codec->height,AV_PIX_FMT_RGB32,  //目标格式
                           SWS_BICUBIC,nullptr,nullptr,nullptr);         //转换规则
    sws_YUV=sws_getContext(codec->width,codec->height,codec->pix_fmt,
                           codec->width,codec->height,AV_PIX_FMT_YUV420P,//目标格式
                           SWS_BICUBIC,nullptr,nullptr,nullptr);         //转换规则
    
    //保存h.264压缩码流数据的文件
    FILE *fp=fopen("fileout/alenH264.h264","wb+");//文件名字可以自行定义
    //保存yuv像素数据的文件
    FILE *fp_yuv=fopen("fileout/alenyuv.yuv","wb+");//文件名字可以自行定义

🟢一帧一帧的读取压缩数据 保存码流数据和YUV、RGB像素数据

    int count=0;//存图片
    //一帧一帧的读取压缩数据
    while(av_read_frame(forContent,pkt)==0)//读到数据
    {
        if(pkt->stream_index == videoType)//判断一帧码流数据是不是需要得到的视频流
        {
            fwrite(pkt->data,pkt->size,1,fp);//写入文件中
            int got_picture_ptr=-1;
            //解码得到YUV
            res = avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);
            if(res < 0)
            {
                qDebug()<<"解码错误"<<endl;
                return;
            }
            //压缩码流数据,解码后的像素数据,判断有没有数据可以解码,对谁进行解码
            if(got_picture_ptr!=0)//解码操作
            {
                //把解码得到的坏数据剔除
                sws_scale(sws_RGB,picture->data,picture->linesize,0,picture->height,
                          pictureRGB->data,pictureRGB->linesize);//RGB
                sws_scale(sws_YUV,picture->data,picture->linesize,0,picture->height,
                          pictureYUV->data,pictureYUV->linesize);//YUV

                //输出的YUV文件
                //AVFrame像素帧写入文件
                fwrite(pictureYUV->data[0],size,1,fp_yuv);  //y数据
                fwrite(pictureYUV->data[1],size/4,1,fp_yuv);//u数据
                fwrite(pictureYUV->data[2],size/4,1,fp_yuv);//v数据

                //设置每25帧输出一张图片
                count++;
                if(count%25==0)
                {
                    QImage image((uchar *)pictureRGB->data[0],pictureRGB->width,pictureRGB->height,QImage::Format_RGB32);//像素数据
                    QString imageName = QString("image/test%1.jpg").arg(count);
                    image.save(imageName);//保存图片函数
                }
            }
        }
        //释放包以及AVFrame资源
        av_packet_unref(pkt);
        av_frame_unref(picture);
    }
    qDebug()<<"保存码流数据成功"<<endl;

🟢资源释放

    //关闭h.264
    fclose(fp);
    //关闭YUV文件
    fclose(fp_yuv);
    //释放AVFrame
    av_frame_free(&picture);
    //关闭解码器
    avcodec_close(codec);
    //释放视频信息结构体
    avformat_free_context(forContent);

🟢测试主函数代码,如下所示:

int main(int argc, char *argv[])
{
    //QApplication a(argc, argv);
    //Widget w;
    //w.show();
    fdecode *decode = new fdecode;
    decode->registerFFmpeg();
    decode->openVIdeoStream("filein/alen.avi");
    //return a.exec();
}

保存的H.264、yuv文件以及图片数据,如下所示:

🔵H.264、yuv文件

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

🔵图片数据(每25帧截图一张)

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

🔵 利用以下应用程序可以播放我们得到的H.264YUV文件

 qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

🔵来播放博主喜欢的日漫吧!

效果如下:

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

 qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++

🚀​FFMPEG技术---环境配置,详见:

FFmpeg+Qt开发(一):Windows下 环境搭建 详细步骤_猿力猪的博客-CSDN博客_ffmpeg库

🚀​FFMPEG技术---编码流程,详见:

【FFmpeg+Qt开发】编码流程 普通视频编码+示例详解 一学就会_猿力猪的博客-CSDN博客

🚀​FFMPEG技术---转码流程,详见:

【FFmpeg+Qt开发】转码流程 H.264 转(mov、mp4、avi、flv)等视频格式 示例详解_猿力猪的博客-CSDN博客

✍ 本文主要介绍了FFmpeg技术中的解码部分,如有疑问,欢迎各位评论区学习交流!     

✍  觉得博主写的不错的,麻烦!😀点赞!😀评论!😀收藏!支持一下哈!蟹蟹你们! 

qt ffmpeg,FFmpeg音视频编解码,视频编解码,音视频,qt5,qt,c++文章来源地址https://www.toymoban.com/news/detail-817312.html

到了这里,关于【FFmpeg+Qt开发】解码流程 详细分析+代码示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FFmpeg音频解码流程详解及简单demo参考

            本文主要讲解FFmpeg的音频解码具体流程,API使用。最后再以一个非常简单的demo演示将一个mp3格式的音频文件解码为原始数据pcm文件。 本文主要基于FFmpeg音频解码新接口。    API接口简单大体讲解如下:         这一步是ffmpeg的任何程序的第一步都是需要先注

    2023年04月08日
    浏览(32)
  • ffmpeg cuda硬件解码后处理使用opengl渲染,全硬件流程

    使用硬件解码后不要transfer到内存,使用cuda转化nv12 - bgr24 转化完毕后cuda里面存了一份bgr24 如果需要opencv gpumat直接使用cuda内存,则可以手动构造gpumat 可以使用gpumat的各种函数 ptr(0)、ptr(1)和ptr(2)分别获取了R、G、B三个通道的数据指针。 使用reinterpret_cast将uchar 指针转换为ucha

    2024年04月12日
    浏览(36)
  • 【Qt+FFmpeg】鼠标滚轮放大、缩小、移动——解码播放本地视频(三)

     上一期我们实现了播放、暂停、重播、倍速功能,这期来谈谈如何实现鼠标滚轮放大缩小和移动;如果还没看过上期,请移步 【Qt+FFmpeg】解码播放本地视频(一)_logani的博客-CSDN博客【Qt+FFmpeg】解码播放本地视频(二)——实现播放、暂停、重播、倍速功能_logani的博客-C

    2024年02月10日
    浏览(29)
  • Qt基于FFmpeg解码本地视频生成H264文件并播放

    用eseye_u.exe 打开H264文件并播放 本文福利, 免费领取C++音视频学习资料包、技术视频 ,内容包括(音视频开发,面试题, FFmpeg , webRTC , rtmp , hls , rtsp , ffplay , srs ) ↓↓↓↓↓↓ 见下面↓↓文章底部点击免费领取↓↓   三、核心代码:  main中创建对象即可测试:

    2023年04月17日
    浏览(27)
  • 【OpenCV】Qt + OpenCV 开发配置 + 入门知识(代码示例)

    前言  一、OpenCV简介 二、OpenCV + QT 开发环境搭建 🚀资源下载 三、OpenCV图像原理 🌭位图模式  🌭灰度模式 🌭RGB模式 四、OpenCV基础图像操作 🍔读图像 🍔显示图片  🍔保存图片 🍔Mat类 🍔像素 五、案例实现  🌈毛玻璃效果 🌈高斯模糊 🌈XY轴模糊 🌈中值滤波 🌈灰度处

    2024年02月03日
    浏览(47)
  • 视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用

    在当今这个信息爆炸、沟通无界的时代,视频会议技术已成为连接人与人、企业与企业之间沟通的重要桥梁。正如计算机科学家 Andrew S. Tanenbaum 曾指出:“计算机网络存在的唯一理由是连接人们。” 这一点在视频会议技术的发展中表现得尤为明显。不仅仅是技术的连接,更重

    2024年02月21日
    浏览(27)
  • FFmpeg 开发(14):Android FFmpeg + MediaCodec 实现视频硬解码

    FFmpeg 开发系列连载: FFmpeg 开发(01):FFmpeg 编译和集成 FFmpeg 开发(02):FFmpeg + ANativeWindow 实现视频解码播放 FFmpeg 开发(03):FFmpeg + OpenSLES 实现音频解码播放 FFmpeg 开发(04):FFmpeg + OpenGLES 实现音频可视化播放 FFmpeg 开发(05):FFmpeg + OpenGLES 实现视频解码播放和视频滤镜 FFmpeg 开发

    2024年02月09日
    浏览(25)
  • FFmpeg的HEVC解码器源代码学习笔记-1

    一直想写一个HEVC的码流解析工具,看了雷神264码流解析工具,本来想尝试模仿写一个相似的265码流分析工具,但是发现265的解码过程和结构体和264的不太一样,很多结构体并没有完全暴露出来,没有想到很好的方法获得量化参数,运动向量等这些信息。想着从头学习一下ff

    2024年02月22日
    浏览(35)
  • C++/Qt音视频通话开发MetaRTC源码解读,dtls交互流程,dtls抓包分析

    本章内容解读MetaRTC开源代码,无任何二次开发,用于学习交流。 MetaRTC是国人开发的开源项目,适用各种场景音视频二次开发,可以去git阅读README,我们使用相对成熟的版本测试: Release v5.0-b4。 本章解读dtls交互流程,dtls抓包分析,dlts概念介绍。 DTLS (Datagram Transport Layer Se

    2023年04月09日
    浏览(36)
  • python实现+leetcode题+合并两个有序列表超详细流程图分析以及代码思路

    给你两个按非递减顺序排列的整数列表nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你合并nums2到nums1中,使合并后的数组同样按非递减顺序排列。 注意 :最终,合并后数组不应由函数返回,而是存储在数组nums1中。为了应对这种情况,nums1的初始长度为

    2023年04月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包