Qt加载本地图片转为YUV420P格式数据

news2024/10/5 16:29:18

一、背景介绍

在流媒体应用中,视频编码是必不可少的一环。视频编码的作用是将高带宽、高码率的原始视频流压缩成低带宽、低码率的码流,以便于传输和存储。H264是一种高效的视频编码标准,具有良好的压缩性能和广泛的应用范围,在实时流媒体应用中得到了广泛的应用。

在将本地图片编码成H264并通过RTMP推流到流媒体服务器时,需要经过以下步骤:

【1】使用图像处理库(如Qt)加载本地图片,并将其转换为YUV420P格式。转换后的YUV420P数据可以作为H264编码器的输入。

【2】使用H264编码器对YUV420P数据进行编码。H264编码器将YUV420P数据压缩成H264码流,并将码流输出。

【3】使用RTMP协议将H264码流推送到流媒体服务器。RTMP协议是一种实时流媒体传输协议,可以将音视频数据推送到流媒体服务器,并提供流媒体回放和点播功能。

在实现上述功能时,使用第三方库(FFmpeg)来完成H264编码和RTMP推流的功能。FFmpeg是一种跨平台的开源多媒体框架,它提供了丰富的音视频处理功能,包括视频编码、解码、转换、推流、拉流等功能。使用FFmpeg,可以方便地将本地图片编码成H264,并通过RTMP协议推流到流媒体服务器。

image-20230720162116737

二、YUV420P格式介绍

YUV420P和RGB888都是常见的像素格式,分别代表了不同的色彩空间表示方式。

RGB888是一种直接将像素的颜色信息表示为红、绿、蓝三种颜色通道的格式。它使用24位(3字节)来表示一个像素,其中每个字节表示一个颜色通道的强度,取值范围为0~255。因此,RGB888格式的像素可以表示16777216种不同的颜色。

YUV420P则是一种将像素的颜色信息表示为亮度和色度两个分量的格式。其中,Y代表亮度分量(Luma),U和V代表色度分量(Chroma)。它使用12位(1.5字节)来表示一个像素,其中前面的8位(1字节)表示亮度分量Y,后面的4位(0.5字节)分别表示U和V色度分量。YUV420P将颜色信息分成了两个部分,亮度信息占据了大部分数据,而色度信息则只占据了一小部分。

YUV420P格式的设计是为了在视频压缩中提高压缩率,因为在视频中,相邻像素的颜色通常非常接近。YUV420P将亮度信息和色度信息分开存储,可以在保证图像质量的前提下,使压缩率更高。同时,它也比RGB888格式更适合在视频传输和处理中使用,因为它的数据量更小,传输和处理的效率更高。

YUV420P和RGB888是不同的色彩空间表示方式,它们的值域范围和表示方式也不同。在将YUV420P转换为RGB888时,需要使用一定的算法进行转换,因为YUV420P和RGB888之间存在非线性的转换关系。

三、图片转为YUV420P

下面通过Qt代码实现加载本地图片、提取RGB数据并将其转换为YUV420P格式。

使用Qt中的QImage和QByteArray类来实现:

#include <QtGui/QImage>
#include <QtCore/QByteArray>

void convertRGBToYUV420P(const QString& imagePath, int width, int height, QByteArray& yuvData)
{
    QImage image(imagePath);
    if (image.isNull()) {
        // 加载图片失败
        return;
    }

    // 将图片转换为指定大小
    image = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

    // 提取RGB数据
    QByteArray rgbData;
    const int bytesPerLine = image.width() * 3;
    for (int y = 0; y < image.height(); ++y) {
        const uchar* scanline = image.constScanLine(y);
        rgbData.append(reinterpret_cast<const char*>(scanline), bytesPerLine);
    }

    // 将RGB数据转换为YUV420P
    yuvData.resize(width * height * 3 / 2);
    uchar* yuvPtr = reinterpret_cast<uchar*>(yuvData.data());
    const uchar* rgbPtr = reinterpret_cast<const uchar*>(rgbData.constData());
    const int uvOffset = width * height;

    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            const int yIndex = y * width + x;
            const int uvIndex = uvOffset + (y / 2) * (width / 2) + (x / 2) * 2;

            const int r = *rgbPtr++;
            const int g = *rgbPtr++;
            const int b = *rgbPtr++;

            // 计算Y分量
            yuvPtr[yIndex] = static_cast<uchar>((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;

            // 计算U和V分量
            if ((y % 2 == 0) && (x % 2 == 0)) {
                yuvPtr[uvIndex] = static_cast<uchar>((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
                yuvPtr[uvIndex + 1] = static_cast<uchar>((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
            }
        }
    }
}

调用函数时,需要传入要加载的图片的路径、目标宽度和高度,以及一个用于存储YUV420P数据的QByteArray对象:

QByteArray yuvData;
convertRGBToYUV420P("path/to/image.png", 640, 480, yuvData);

在函数内部,使用QImage类加载指定路径的图片。如果加载失败,直接返回。

然后,将图片缩放到指定的大小,并使用一个QByteArray对象存储提取出的RGB数据。为了提高效率,使用了QImage的constScanLine()函数来遍历每一行像素数据,并将其追加到QByteArray对象中。

将RGB数据转换为YUV420P格式时,使用QByteArray::resize()函数调整QByteArray对象的大小,以便能够存储YUV420P数据。然后,使用两个指针分别指向目标YUV420P数据和源RGB数据的开头。使用两个嵌套的循环遍历每个像素,并将其转换为YUV420P格式。

在计算Y分量时,使用的公式:

Y = (66 * R + 129 * G + 25 * B + 128) >> 8 + 16

在计算U和V分量时,我们使用以下公式:

U = (-38 * R - 74 * G + 112 * B + 128) >> 8 + 128
V = (112 * R - 94 * G - 18 * B + 128) >> 8 + 128

最后,将转换后的YUV420P数据存储在传入的QByteArray对象中,并在函数返回前完成。

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

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

相关文章

《C++ primer》练习3.20:输出vector相邻元素的和输出vector头尾对象的和

最近看《C primer》&#xff0c;有这样一个题目 输出vector相邻元素的和 读入一组整数并把它们存入一个vector对象&#xff0c;将每对相邻整数的和输出出来。 这里要注意输入的奇数个和偶数个的数的区别。偶数个整数的话刚好数全部用完&#xff0c;奇数个整数最后一个数空出来…

淘宝平台开放接口API接口

淘宝平台开放接口API接口是指淘宝平台提供给第三方开发者的一组接口&#xff0c;用于实现与淘宝平台的数据交互和功能扩展。通过API接口&#xff0c;第三方开发者可以获取淘宝平台上的商品信息、订单信息、用户信息等数据&#xff0c;也可以实现商品的发布、订单的创建和支付等…

【图解RabbitMQ-7】图解RabbitMQ五种队列模型(简单模型、工作模型、发布订阅模型、路由模型、主题模型)及代码实现

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

2023年世界机器人大会回顾

1、前记&#xff1a; 本次记录是我自己去世界机器人博览会参观的一些感受&#xff0c;所有回顾为个人感兴趣部分的机器人产品分享。整个参观下来最大的感受就是科学技术、特别是机器人技术和人工智能毫无疑问地、广泛的应用在我们日常生活的方方面面&#xff0c;在安全巡检、特…

【洛谷算法题】P5704-字母转换【入门1顺序结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5704-字母转换【入门1顺序结构】&#x1f30f;题目描述&#x1f30f;输入格式&a…

ClickHouse进阶(十三):Clickhouse数据字典-3-文件数据源及Mysql数据源

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…

metinfo __ 6.0.0 __ file-read

metinfo __ 6.0.0 __ file-read 说明内容漏洞编号–漏洞名称MetInfo 6.0.0 任意文件读取漏洞漏洞评级高危影响范围6.0.0.0漏洞描述MetInfo 存在任意文件读取漏洞&#xff0c;攻击者利用该漏洞&#xff0c;在具有权限的情况下&#xff0c;可以读取网站任意文件&#xff0c;包括…

ASP.NET+sqlserver公司项目管理系统

一、源码描述 这是一款简洁十分美观的ASP.NETsqlserver源码&#xff0c;界面十分美观&#xff0c;功能也比较全面&#xff0c;比较适合 作为毕业设计、课程设计、使用&#xff0c;感兴趣的朋友可以下载看看哦 二、功能介绍 该源码功能十分的全面&#xff0c;具体介绍如下&…

centos定期清理磁盘

centos/linux定期清理磁盘 要定时清理空间&#xff0c;我们需要了解一个命令&#xff0c;find 命令&#xff0c;这个命令可以查询目录下特定文件名&#xff0c;生成日期的文件 小白教程&#xff0c;一看就会&#xff0c;一做就成。 1.查找需要删除的 find /data_back/zhhyba…

buuctf crypto 【Cipher】解题记录

1.打开题目就有密文 2.一点思路没有&#xff0c;看看大佬的wp&#xff08;BUUCTF Cipher 1_cipher buuctf_玥轩_521的博客-CSDN博客&#xff09;&#xff0c;捏麻麻的原来玄机就在“公平的玩吧”这句话里&#xff0c;playfair也是一种加密方式&#xff0c;密钥猜测也是playfair…

SMB 协议详解之-NTLM身份认证

前面的文章说明了SMB协议交互的过程,在SMB交互的Session Setup Request/Response会对请求者的身份进行验证,这其中涉及到两个主要的协议NTLM以及Kerberos,本文将对NTLM协议进行详细的说明。 什么是NTLM NTLM是 NT LAN Manager (NTLM) Authentication Protocol 的缩写,主要…

MediaCodec源码分析 configure流程

前言 本文梳理MediaCodec configure流程,基于7.0代码,这里只分析AVC和HEVC的视频硬解,流程图如下。 代码见: frameworks/base/media/java/android/media/MediaCodec.java frameworks/base/media/jni/android_media_MediaCodec.h frameworks/base/media/jni/android_media_…

C#,数值计算——指数微分(exponential deviates)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 指数偏差 /// Structure for exponential deviates. /// </summary> public class Expondev : Ran { private double beta { get; set; } /// <s…

windows或者任何系统通过二进制安装最新的Protocol Buffer Compiler

此处使用二进制法安装,适用于任何操作系统 安装预编译的二进制文件&#xff08;任何操作系统&#xff09; 要从预编译的二进制文件安装最新版本的协议编译器&#xff0c;请按照以下说明操作&#xff1a; 1.从 github.com/google/protobuf/releases 手动下载与您的操作系统和计…

学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《推荐】Spring与Mybatis集成整合》 ⛺️ 生活的理想&#xff0c;不断更新自己 ! 1.JSR303 1.1JSR303是什么 JSR 303是Java规范请求&#xff08;Java Specification Request&#xff09;…

【AI理论学习】语言模型Performer:一种基于Transformer架构的通用注意力框架

语言模型Performer&#xff1a;一种基于Transformer架构的通用注意力框架 Performer论文解读Regular Attention MechanismFAVOR&#xff1a;通过矩阵相关性实现快速注意力 Attention的时间复杂性绕过softmax瓶颈通过Gaussian kernel求Softmax kernel寻找更稳定的Softmax内核使用…

单链表(Single Link Table)——单文件实现

一、单链表前言 上篇文章我们讲述了顺序表&#xff0c;认真学习我们会发现顺序表优缺点。 缺点1&#xff1a;头部和中部的插入删除效率都不行&#xff0c;时间和空间复杂度都为O(N); 缺点2&#xff1a;空间不够了扩容有一定的消耗(尤其是realloc的异地扩容)&#xff1b; 缺…

Linux网络编程:网络协议及网络传输的基本流程

目录 一. 计算机网络的发展 二. 网络协议的认识 2.1 对于协议分层的理解 2.2 TCP/IP五层协议模型 2.3 OSI七层模型 三. 网络传输的流程 3.1 同一网段中计算机通信的流程 3.2 不同网段中计算机设备的通信 3.3 对于IP地址和MAC地址的理解 3.4 数据的封装和解包 四. 总结…

2.linux的组管理和权限管理

一、组管理 1.Linux组的介绍 在linux中每个用户必须属于一个组&#xff0c;不能独立于组外。在linux中每个文件有所有者&#xff0c;所有组&#xff0c;其他组的概念 ①所有者 ②所在组 ③其他组 ④改变用户所在组 2.文件/目录 所有者 哪个用户创建了文件&#xff0c;就…

使用rpm重新安装包

#查询 rpm -qa | grep cloudstack #卸载 rpm -e cloudstack-agent-4.18.0.0-1.x86_64 #安装 rpm -ivh cloudstack-agent-4.18.0.0-1.x86_64.rpm