前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Qt加载本地图片转为YUV420P格式数据

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

作者头像
DS小龙哥
发布2023-09-13 08:16:17
5340
发布2023-09-13 08:16:17
举报
文章被收录于专栏:嵌入式项目开发

一、背景介绍

在流媒体应用中,视频编码是必不可少的一环。视频编码的作用是将高带宽、高码率的原始视频流压缩成低带宽、低码率的码流,以便于传输和存储。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协议推流到流媒体服务器。

二、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类来实现:

代码语言:javascript
复制
#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对象:

代码语言:javascript
复制
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分量时,使用的公式:

代码语言:javascript
复制
Y = (66 * R + 129 * G + 25 * B + 128) >> 8 + 16

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

代码语言:javascript
复制
U = (-38 * R - 74 * G + 112 * B + 128) >> 8 + 128
V = (112 * R - 94 * G - 18 * B + 128) >> 8 + 128

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景介绍
  • 二、YUV420P格式介绍
  • 三、图片转为YUV420P
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档