当前位置: 首页 > news >正文

【Qt】ffmpeg照片提取、视频播放▲

目录

一、图像的成像原理:

RGB成像原理:

YUV成像原理:

二、多线程

三、ffmpeg解码(照片提取)

1.准备工作

(1)在工程文件夹里面新建三个文件夹

(2)在main函数中加入这两个

(3)在要解码的多线程子线程中加入

(4)在.pro文件工程里面加入

2.注册主键

3.打开视频文件

4.获取视频信息

5.判断是否有视频流

6.查找编码器

7.打开编码器

8.读取一帧压缩数据

9.读取一帧压缩数据,解码一帧数据

四、视频播放

1.paintEvent界面重绘事件

2.普通类如何使用信号与槽

3.在子线程中发送图片信号

4.在UI主线程槽函数接收


一、图像的成像原理:

RGB 和 YUV 是两种常见的颜色空间模型

  • RGB成像原理:

RGB 即红(Red)、绿(Green)、蓝(Blue),是一种基于三原色原理的颜色空间,在显示设备(如电脑显示屏、手机屏幕等)中,每个像素点都由红、绿、蓝三个子像素组成。通过控制这三个子像素的发光强度,就可以混合出各种不同的颜色

  • YUV成像原理:

YUV 是一种将亮度和色度分离的颜色空间。其中,Y 表示亮度,它反映了图像的明亮程度;U 和 V 表示色度,用于描述颜色的色调和饱和度,它们携带了图像的颜色信息

二、多线程

因为耗时逻辑就会造成UI卡顿,卡死或则白屏,所以不能在槽函数里面做太耗时操作(文件、解码都不行),所以使用了多线程,在UI主线程中,不执行耗时逻辑,耗时逻辑放在子线程去完成

三、ffmpeg解码(照片提取)

1.准备工作

(1)在工程文件夹里面新建三个文件夹

(2)在main函数中加入这两个

(3)在要解码的多线程子线程中加入

(4)在.pro文件工程里面加入

2.注册主键

av_register_all();

3.打开视频文件

    AVFormatContext *formatContext;

    //开空间

    formatContext=avformat_alloc_context();

    //打开输入视频文件

    int res=avformat_open_input(&formatContext,"../video/Warcraft3_End.avi",nullptr,nullptr);

    if(res<0)

    {

        qDebug()<<"open avformat_open_input fail";

    }

    else {

        qDebug()<<"success";

    }

4.获取视频信息

 res=avformat_find_stream_info(formatContext,nullptr);

    if(res<0)

    {

        qDebug()<<"avformat_find_stream_info fail";

    }

    else {

        qDebug()<<"avformat_find_stream_info success";

    }

5.判断是否有视频流

 int video_input=-1;

    //nb_streams:输入视频的AVStream个数

    for(int i=0;i<formatContext->nb_streams;i++)

    {

        /*

         * streams :输入视频的AVStream []数组

         *   有0或者1:0表示视频,1表示音频

         * codec:编码器

         * codec_type:编码的类型:

         * (1)AVMEDIA_TYPE_VIDEO:表示视频类型。

           (2)AVMEDIA_TYPE_AUDIO:表示音频类型。

           (3)AVMEDIA_TYPE_SUBTITLE:表示字幕类型。

        */

        if(formatContext->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)

        {

            video_input=i;

            break;

        }

    }

    if(video_input==-1)

    {

        qDebug()<<"video not find";

    }

    else {

        qDebug()<<formatContext->streams[video_input]->nb_frames;

        qDebug()<<"video_input"<<video_input;

    }

6.查找编码器

保存视频编解码相关信息,存储解码器上下文信息的结构体

 AVCodecContext* codecContext=formatContext->streams[video_input]->codec;

    //通过文件信息中编码id找到解码器

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

    AVCodec* decoder=avcodec_find_decoder(codecContext->codec_id);

    if(decoder==nullptr)

    {

        qDebug()<<"avcodec_find_decoder fail";

    }

    else {

        qDebug()<<"avcodec_find_decoder success";

    }

7.打开编码器

 res=avcodec_open2(codecContext,decoder,nullptr);

    if(res!=0)

    {

        qDebug()<<"avcodec_open2 fail";

    }

    else {

        qDebug()<<"avcodec_open2 success";

    }

8.读取一帧压缩数据

//********AVPacket开始**********

    //AVPacket 是 FFmpeg 中用于存储压缩数据的结构体

    AVPacket* pkt;

    pkt=(AVPacket*)malloc(sizeof (AVPacket));

    int size=codecContext->width * codecContext->height;

    res=av_new_packet(pkt,size);

    if(res!=0)

    {

        qDebug()<<"av_new_packet fail";

    }

    else {

        qDebug()<<"av_new_packet success";

    }

    //********AVPacket准备工作完成**********

    //********AVFrame RGB准备工作**********

    //AVFrame 用于存储解码后的原始数据

    AVFrame* pictureRGB;

    AVFrame* picture;

    picture=av_frame_alloc();

    pictureRGB=av_frame_alloc();

    //解码画面信息按原图信息设置

    pictureRGB->width=codecContext->width;

    pictureRGB->height=codecContext->height;

    pictureRGB->format=codecContext->pix_fmt;//帧画面信息

    //设置缓冲区

    int imgByteRGB=avpicture_get_size(AV_PIX_FMT_RGB32,codecContext->width,codecContext->height);

    uint8_t *bufferRGB=(uint8_t*)av_malloc(imgByteRGB* sizeof (uint8_t));

    //填充缓冲区

    avpicture_fill((AVPicture*)pictureRGB,bufferRGB,AV_PIX_FMT_RGB32,codecContext->width,codecContext->height);

    //制定一个图像规则

    //转换前的视频宽高到转换后的视频宽高

    SwsContext* SwsContextRGB=sws_getContext(codecContext->width,codecContext->height,codecContext->pix_fmt,

                                             codecContext->width,codecContext->height,AV_PIX_FMT_RGB32,

                                             SWS_BICUBIC,nullptr,nullptr,nullptr);

    //********AVFrame准备工作完成**********

9.读取一帧压缩数据,解码一帧数据

int x=0;

    //从输入文件读取一帧压缩数据,操作正常返回0

    while(av_read_frame(formatContext,pkt)==0)

    {

        //判断压缩数据是否为图像压缩数据

        if(pkt->stream_index==video_input)

        {

            //参数默认配置

            int get_picture_ptr=-1;

          /*解码一帧压缩:

          *  codecContext:AVCodecContext 包含了编解码器的上下文信息

          *  picture:AVFrame 用于存储解码后的视频帧数据

       *  get_picture_ptr:一个指向整数的指针,用于指示是否成功解码出一帧完整的视频图像

          * 如果解码成功并得到了一个完整的视频帧,该指针所指向的变量会被设置为非零值

          *  如果没有得到完整的帧,该变量会被设置为零

          *  pkt:AVPacket 用于存储压缩的视频数据包

          */

            avcodec_decode_video2(codecContext,picture,&get_picture_ptr,pkt);

            if(get_picture_ptr!=0)

            {

                //删除无效数据,转RGB存储

                //picture:原图    pictureRGB:转换后的图

                sws_scale(SwsContextRGB,picture->data,picture->linesize,0,picture->height,pictureRGB->data,pictureRGB->linesize);

                this->img=QImage((uchar *)bufferRGB,codecContext->width,codecContext->height,QImage::Format_RGB32);

                this->img.save(QString("../fileout/%1.jpg").arg(x));//保存进文件夹

//                emit sendImage(this->img);

//                msleep(40);//设置发送间隔时间

                x++;

            }

        }

        av_packet_unref(pkt);

    }

    //关闭解码器

    avcodec_close(codecContext);

    //释放关闭文件

    avformat_close_input(&formatContext);

四、视频播放

1.paintEvent界面重绘事件

Qt UI窗口存在事件循环机制,在QWidget类中,子类需要实现这个paintEvent事件,在窗口产生显示/切换/最大化/最小化自动调用,不需要自己调用,而update函数可以手动触发paintEvent重绘事件

2.普通类如何使用信号与槽

普通类在debug文件夹中不会生成moc_开头的文件,而信号与槽的核心机制为moc

第一步:删除工程项目下debug文件夹里的全部东西

3.在子线程中发送图片信号

4.在UI主线程槽函数接收

相关文章:

  • 【Java 基础(人话版)】Java SE vs Java EE
  • 请解释 Node.js 中的网络模块(http、https),如何创建 HTTP服务器?
  • ESP32+Mixly+温湿度传感器DHT11
  • LangChain项目实战1——基于公司制度RAG回答机器人
  • PHP的学习
  • 如何通过 LlamaIndex 将数据导入 Elasticsearch
  • DAY09 Map接口、斗地主案例(有序版本)、冒泡排序
  • Mysql100道高频面试题
  • DeepSeek开源周-汇总
  • CSS浮动详解
  • 稀疏数组学习
  • Vue3项目如何使用TailWind CSS保姆级教程
  • 使用Python开发以太坊智能合约:轻松入门与深度探索
  • Linux与UDP应用1:翻译软件
  • C++Primer学习(4.8位运算符)
  • Qt中如果槽函数运行时间久,避免阻塞主线程的做法
  • 250301-OpenWebUI配置DeepSeek-火山方舟+硅基流动+联网搜索+推理显示
  • 【数据结构】链表与顺序表的比较
  • Python精进系列:divmod 函数
  • 安装 Open WebUI
  • 深圳做h5网站设计/企业营销策划是做什么的
  • 公司网站建设指南/免费外链工具
  • 京网站建设/seo在线优化
  • 做网店的进货网站/制作网页
  • 销售网站免费做/如何做网站推广
  • 网站建设 技术要求/爱站网关键词工具