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

news2025/5/12 20:34:09

目录

一、图像的成像原理:

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主线程槽函数接收

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2308636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue+Elementui 全局配置el-table表格列宽可拖拽

1、需求分析 如何让表格列宽可以拖动 elementui的el-table如果想要列宽可以拖动的话 有一个属性叫 border 在模板里添加这个属性即可实现 但是系统里面的表格我不可能一个一个去添加border太麻烦 如果能够全局配置岂不是非常省时间吗 我们在main.js里面通过全局混入的方式来…

SQL命令详解之增删改数据

目录 简介 1 添加数据 1.1 基础语法 1.2 SQL 练习 2 修改数据 2.1 基础语法 2.2 SQL 练习 ​3 删除数据 3.1 基础语法 3.2 SQL 练习 总结 简介 在数据库操作中&#xff0c;增、删、改是最基础的操作&#xff0c;它们通常对应着SQL中的INSERT、DELETE和UPDATE命令。…

鸿蒙开发第4篇__关于在鸿蒙应用中使用Java语言进行设计

本博文对于鸿蒙APP程序员来说&#xff0c;很重要 HarmonyOS从 API8 开始不再支持使用Java作为开发语言&#xff0c;未来的新功能将在ArkTS中实现. API 8对应的是HarmonyOS 3.0.0版本, 2022年7月27日&#xff0c; 华为发布了HarmonyOS 3.0。 请看下图&#xff1a; 因此&#…

Linux三种网络方式

前言 发现运维啥都得会&#xff0c;这周就遇到了网络问题自己无法解决&#xff0c;因此痛定思痛学一下。 参考文献 你管这破玩意叫网络&#xff1f; 桥接模式、NAT模式、仅主机模式&#xff0c;原来是这样工作的 交换机 构成局域网&#xff0c;实现所有设备之间的通信。 …

Spring DIIoC

一.IoC 1.简介 什么是IoC&#xff1f;IoC&#xff0c;全称 Inversion of Control&#xff0c;控制反转。IoC是Spring的核心思想&#xff0c;Spring是⼀个“控制反转”的容器。 如果我们需要一个对象&#xff0c;正常来说我们是通过new一个对象&#xff0c;这个时候我们依赖的…

【前端基础】Day 2 CSS层叠样式表

目录 1.CSS简历 2.CSS 基础选择器 2.1标签选择器 2.2类选择器 2.3 id选择器 2.4通配符选择器 2.5总结 3.CSS字体属性 字体属性总结 4.CSS文本属性 4.1颜色 4.2对齐文本 4.3装饰文本 4.4文本缩进 4.5行间距 4.6文本属性总结 5.CSS的引入方式 5.1内部样式表 …

计算机毕业设计SpringBoot+Vue.js汽车资讯网站(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

nuxt常用组件库html-validator、@nuxtjs/i18n、@nuxt/image、@unocss/nuxt使用解析

html-validator 主要用于自动验证nuxt服务器呈现的HTML(SSR和SSG)&#xff0c;以检测可能导致水合错误的HTML常见问题&#xff0c;有助于减少水合错误&#xff0c;检测常见的可访问性错误。 安装 npx nuxilatest module add html-validator配置 若自动更新nuxt.config.ts配置文…

Leetcode-最大矩形(单调栈)

一、题目描述 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 输入&#xff1a;matrix [["1","0","1","0","0"],["1","0&…

Vue核心知识:动态路由实现完整方案

在Vue中实现动态路由&#xff0c;并结合后端接口和数据库表设计&#xff0c;是一个复杂的项目&#xff0c;需要多个技术栈和步骤的配合。以下将详细描述整个实现过程&#xff0c;包括数据库设计、后端接口设计、前端路由配置以及如何实现动态路由的功能。 目录 一、需求分析二…

【Docker】使用Docker搭建-MySQL数据库服务

零、更换Docker镜像源 因为国内现在封锁了Docker默认拉取镜像的站点&#xff08;DockerHub&#xff09;&#xff0c;而且国内大部分Docker镜像站已全部下线&#xff0c;导致现在很多朋友在拉取镜像的时候会出现无法拉取的现象&#xff0c;这时候就需要进行更换Docker镜像源。 可…

DHCP配置和地址

DHCP&#xff1a;动态主机配置协议 DHCP系统组成 DHCP报文结构 DHCP报文类型 DHCP工作流程 DHCP租期更新 DHCP重绑定 自动保留IP 租期设置建议 IP地址释放 DHCP地址池 DHCP配置 DHCP接口地址池配置 DHCP全局地址池配置

基于trl复现DeepSeek-R1的GRPO训练过程

1. 引入 huggingface开发了强化学习训练Transformer的库trl&#xff08;参考3&#xff09;&#xff0c;借助这个trl&#xff0c;可以用来做GRPO的强化学习训练。魔搭ModelScope社区的文章&#xff08;参考2&#xff09;给出了基于Qwen基座模型Qwen2.5-0.5B-Instruct&#xff0…

常用的 pip 命令

pip 是 Python 的包管理工具&#xff0c;可用于安装、卸载、更新和管理 Python 包。以下是一些常用的 pip 命令&#xff1a; 1. 安装包 安装最新版本的包 pip install package_namepackage_name 是你要安装的 Python 包的名称&#xff0c;例如 pip install requests 可以安装…

基于C#的CANoe CLR Adapter开发指南

一、引言 CANoe 是一款广泛应用于汽车电子开发和测试的工具&#xff0c;它支持多种编程接口&#xff0c;方便开发者进行自定义扩展。CANoe CLR Adapter 允许我们使用 C# 语言与 CANoe 进行交互&#xff0c;充分利用 C# 的强大功能和丰富的类库。本文将详细介绍如何基于 C# 进行…

eMMC安全简介

1. 引言 术语“信息安全”涵盖多种不同的设计特性。一般而言&#xff0c; 信息安全是指通过实践防止信息遭受未经授权的访问、使用、披露、中断、篡改、检查、记录或销毁。 信息安全的三大核心目标为 机密性&#xff08;Confidentiality&#xff09;、完整性&#xff08;Integr…

从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(六) 导航栏 和 个人信息设置

1.导航栏&#xff08;navbar&#xff09; 在components下面 创建NavBar.jsx import { MessageSquare,Settings,User,LogOut} from "lucide-react" import {Link} from "react-router-dom" import { useAuthStore } from "../store/useAuthStore&qu…

数据库MySQL,在终端输入后,提示不是内部命令等

【解决问题】mysql提示不是内部或外部命令&#xff0c;也不是可运行的程序 一般这种问题是因为没有在系统变量里面添加MySQL的可执行路径 以下是添加可执行路径的方法&#xff1a; 第一步&#xff1a;winR输入services.msc 然后找到MySQL&#xff0c;右击属性并复制MySQL的可执…

C语言生成二维码

1. 效果 2. 需要的代码&#xff08;QRCode&#xff09; qrcode.cqrcode.h 代码 3. 代码 #include <stdio.h> #include "qrcode.h"int main() {//拓展编码SetConsoleOutputCP(437);QRCode qrcode;uint8_t qrcodeBytes[qrcode_getBufferSize(3)];qrcode_initT…

[Web 安全] PHP 反序列化漏洞 —— POP 链构造思路

关注这个专栏的其他相关笔记&#xff1a;[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客 0x01&#xff1a;什么是 POP 链&#xff1f; POP 链&#xff08;Payload On Purpose Chain&#xff09;是一种利用 PHP 中的魔法方法进行多次跳转以获取敏感数据的技术。它通常出现在 CTF…