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

一、背景介绍

在流媒体应用中,视频编码是必不可少的一环。视频编码的作用是将高带宽、高码率的原始视频流压缩成低带宽、低码率的码流,以便于传输和存储。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数据转换为YUV420PyuvData.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.rhkb.cn/news/130113.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于人工智能与边缘计算Aidlux的工业表面缺陷检测

一&#xff1a;训练yolov8得到onnx模型&#xff08;相关教程有很多&#xff09; 二&#xff1a;模型转化&#xff1a; 网站&#xff1a; https://aimo.aidlux.com/ 输入试用账号和密码: 账号:AIMOTC001&#xff0c;密码:AIMOTC001 我们选择 TensorFlowLite 一步步完成转化 …

JVM GC垃圾回收

一、GC垃圾回收算法 标记-清除算法 算法分为“标记”和“清除”阶段&#xff1a;标记存活的对象&#xff0c; 统一回收所有未被标记的对象(一般选择这种)&#xff1b;也可以反过来&#xff0c;标记出所有需要回收的对象&#xff0c;在标记完成后统一回收所有被标记的对象 。它…

node.js下载安装环境配置以及快速使用

目录 一、下载 二、安装 三、测试安装是否成功 四、配置环境 五、测试配置环境是否成功 六、安装淘宝镜像 七、快速上手 1、建立一个自己的工作目录 2、下载工作代码 八、各种配置文件匹配问题入坑 九、总结 一、下载 Node.js 中文网 想选择其他版本或者其他系统使用…

从零开始学习软件测试-第39天笔记

接口测试 http消息结构 请求报文 请求行 请求方式 url 协议版本请求头空行请求体响应报文 响应行 协议版本 状态码 状态消息响应头空行响应体 请求参数类型 path参数 写在路径中的 https://xxx.xxx.com/参数值query参数 写在url问号后面&#xff0c;以键值对形式存在 h…

多线程之基础篇(一)

一、Thread类 1、线程的创建 大家都熟知创建单个线程的三种方式&#xff0c;通过继承Thread类创建线程并重写该类的run()方法&#xff1b;通过实现Runnable接口创建线程一样要重写run()方法&#xff1b;以上的两个run()方法都是线程的执行体&#xff1b;第三&#xff0c;使用…

【数据结构】前言概况 - 树

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;数据结构 &#x1f525;该文章针对树形结构作出前言&#xff0c;以保证可以对树初步认知。 目录&#xff1a; &#x1f30d;前言:&#x1f3…

极光笔记 | 推送服务数据中心选择:合规性与传输效率的双重考量

随着全球化进程的深入&#xff0c;跨境数据传输与存储问题已经变得愈发重要。推送服务的数据中心节点选择不仅关乎数据访问速度和用户体验&#xff0c;同时也直接牵扯到数据合规性和安全保障。EngageLab Push深知这一点&#xff0c;为了满足更多国际客户和全球用户触达需求&…

将本地jar包手动添加到Maven仓库依赖处理

一、起因 在日常开发中&#xff0c;经常会遇到一些情况&#xff0c;就是在更新Maven时&#xff0c;从网上下载jar包的时候网络不稳定或者其他原因导致jar包数据缺失而导致的依赖无法正常引入的情况. 还有一些其他情况如个人jar包一类的。 二、解决 以前以上这些情况&#x…

Android12之/proc/pid/status参数含义(一百六十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

微服务·数据一致-seata

微服务数据一致-seata 概述 Seata&#xff08;Simple Extensible Autonomous Transaction Architecture&#xff09;是一个开源的分布式事务解决方案&#xff0c;旨在帮助应用程序分布式事务管理的挑战。Seata提供了一套全面的工具和框架&#xff0c;可用于实现跨多个数据库和…

网络安全之认识网络安全网格架构(CSMA)

“网络安全网格&#xff08;CyberSecurity Mesh&#xff09;”是 Gartner 提出的网络安全技术发展新趋势&#xff0c;近两年连续入选其年度重要战略技术趋势研究报告&#xff0c;成为当前网络安全领域流行的热词&#xff0c;受到网络安全从业者的高度关注。 一、概念产生的背景…

软件测试/测试开发丨Web自动化 PageObject设计模式

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27167 一、page object 模式简介 马丁福勒个人博客 selenium 官网 1.1、传统 UI 自动化的问题 无法适应 UI 频繁变化无法清晰表达业务用例场景大量的样…

python 学习笔记(5)——SMTP 使用QQ邮箱发送邮件

目录 发送邮件 1、准备工作&#xff1a; 2、发送纯文本信息内容&#xff1a; 3、发送 HTML 格式的内容&#xff1a; 4、发送带附件的邮件&#xff1a; 5、群发&#xff08;一个邮件&#xff0c;发给多个人&#xff09;&#xff1a; 发送邮件 以下都 以 QQ邮箱 为发送方举…

Nginx+Tomcat(多实例)实现动静分离和负载均衡

一、Tomcat 多实例部署 1.在安装好jdk环境后&#xff0c;添加两例tomcat服务 #解压安装包 cd /opt tar zxvf apache-tomcat-9.0.16.tar.gz#移动并复制一例 mkdir /usr/local/tomcat mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1 cp -a /usr/local/tomcat/tomcat1 /usr…

记录一次开机内存分析的全过程

作者&#xff1a;zzy的学习笔记 记录一次开机内存分析的全过程&#xff0c;尽量详尽的介绍常用内存分析工具和命令行的使用&#xff0c;结合具体问题探讨开机内存分析的实践经验。通过这篇文章我会介绍开机内存的常用测试分析工具的基本使用方法&#xff0c;以及如何通过抓取出…

在Ubuntu上建立博客网站,利用Cpolar+Inis快速实现专业写作

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

springboot+redis

1.pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 2.yml配置 # redis 配置redis:host: 127.0.0.1#超时连接timeout: 1000msjedis:pool:#最大连…

盲打键盘的正确指法指南

简介 很多打字初学者&#xff0c;并不了解打字的正确指法规范&#xff0c;很容易出现只用两根手指交替按压键盘的“二指禅”情况。虽然这样也能实现打字&#xff0c;但是效率极低。本文将简单介绍盲打键盘的正确指法&#xff0c;以便大家在后续的学习和工作中能够提高工作效率…

Pytorch Advanced(三) Neural Style Transfer

神经风格迁移在之前的博客中已经用keras实现过了&#xff0c;比较复杂&#xff0c;keras版本。 这里用pytorch重新实现一次&#xff0c;原理图如下&#xff1a; from __future__ import division from torchvision import models from torchvision import transforms from PIL…

2024年java面试--mysql(2)

系列文章目录 2024年java面试&#xff08;一&#xff09;–spring篇2024年java面试&#xff08;二&#xff09;–spring篇2024年java面试&#xff08;三&#xff09;–spring篇2024年java面试&#xff08;四&#xff09;–spring篇2024年java面试–集合篇2024年java面试–redi…