C

Qt Quick Ultralite imagedecoder Example

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial

#include "traveot2gimagedecoder.h"
#include <ut_class_surface.h>

extern "C" uint32_t Jpeg_DecStart(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
extern "C" uint32_t tvii_convert_decoded_buffers(
    unsigned char *, uint32_t, uint32_t, uint32_t, uint32_t, CYGFX_SM_FORMAT);
static int16_t img_width, img_height;

bool jpegInformation(Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback,
                     int16_t *width,
                     int16_t *height,
                     Qul::PixelFormat *actualPixelFormat,
                     Qul::PixelFormat optimalOpaquePixelFormat,
                     Qul::PixelFormat optimalAlphaPixelFormat);

TviiImageDecoder::TviiImageDecoder() {}
TviiImageDecoder::~TviiImageDecoder() {}

bool TviiImageDecoder::imageInformation(RequestDataCallback &callback,
                                        int16_t *width,
                                        int16_t *height,
                                        Qul::PixelFormat *actualPixelFormat,
                                        Qul::PixelFormat optimalOpaquePixelFormat,
                                        Qul::PixelFormat optimalAlphaPixelFormat)
{
    bool ret = jpegInformation(callback,
                               width,
                               height,
                               actualPixelFormat,
                               optimalOpaquePixelFormat,
                               optimalAlphaPixelFormat);
    img_width = *width;
    img_height = *height;
    return ret;
}

static CYGFX_SM_FORMAT convertFormat(Qul::PixelFormat format)
{
    CYGFX_SM_FORMAT result = CYGFX_SM_FORMAT_A8R8G8B8;
    switch (format) {
    case Qul::PixelFormat_ARGB32:
    case Qul::PixelFormat_ARGB32_Premultiplied:
        result = CYGFX_SM_FORMAT_A8R8G8B8;
        break;
    case Qul::PixelFormat_RGB32:
        result = CYGFX_SM_FORMAT_X8R8G8B8;
        break;
    case Qul::PixelFormat_RGB888:
        result = CYGFX_SM_FORMAT_R8G8B8;
        break;
    case Qul::PixelFormat_RGB16:
        result = CYGFX_SM_FORMAT_R5G6B5;
        break;
    case Qul::PixelFormat_Alpha8:
        result = CYGFX_SM_FORMAT_A8;
        break;
    default:
        Qul::PlatformInterface::log("[%s] Unsupported Format! (%d)\n\r", __PRETTY_FUNCTION__, format);
    }
    return result;
}

int TviiImageDecoder::decodeImage(RequestDataCallback &callback,
                                  unsigned char *outbuffer,
                                  uint32_t outbufferSize,
                                  Qul::PixelFormat pixelFormat,
                                  uint32_t requiredBytesPerLine)
{
    if (img_width % 64 != 0) {
        Qul::PlatformInterface::log("JPEG decoder requires source images width to be multiples of 64.");
        return -1;
    }

    unsigned int addr = reinterpret_cast<uintptr_t>(callback.rawData());
    unsigned int size = callback.totalAvailableDataSize();

    const uint32_t yBufferSize = img_width * img_height;
    const uint32_t uvBufferSize = img_width * img_height / 2;
    const uint32_t yuvBufferSize = yBufferSize + uvBufferSize;
    void *yuvBuffer = utVideoAlloc(yuvBufferSize, 64, nullptr);
    if (!yuvBuffer) {
        Qul::PlatformInterface::log("JPEG decoder failed to allocate YUV buffer of size %d\n", yuvBufferSize);
        return -1;
    }

    const uint32_t storeAddress0 = reinterpret_cast<uintptr_t>(yuvBuffer);
    const uint32_t storeLength0 = yBufferSize;

    const uint32_t storeAddress1 = storeAddress0 + storeLength0;
    const uint32_t storeLength1 = uvBufferSize;

    const uint32_t stride = img_width;
    uint32_t ret = Jpeg_DecStart(addr, size, storeAddress0, storeAddress1, storeLength0, storeLength1, stride);

    if (ret != 0) {
        Qul::PlatformInterface::log("Jpeg_DecStart failed with return code %x\n", ret);
        utVideoFree(yuvBuffer);
        return -1;
    }

    ret = tvii_convert_decoded_buffers(outbuffer,
                                       (uint32_t) img_width,
                                       (uint32_t) img_height,
                                       storeAddress0,
                                       storeAddress1,
                                       convertFormat(pixelFormat));
    utVideoFree(yuvBuffer);

    if (ret != 0) {
        Qul::PlatformInterface::log("tvii_convert_decoded_buffers failed with return code %x\n", ret);
    }
    return ret;
}