C
Qt Quick Ultralite imagedecoder Example
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "rh850imagedecoder.h"
#include "rh850_jpeg.h"
#include <platforminterface/memoryallocator.h>
#include <platform/platform.h>
#include <memory>
bool jpegInformation(Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback,
int16_t *width,
int16_t *height,
Qul::PixelFormat *actualPixelFormat,
Qul::PixelFormat optimalOpaquePixelFormat,
Qul::PixelFormat optimalAlphaPixelFormat);
void Rh850ImageDecoder::setJpegInfo(r_jcua_JpegFormat_t format, int16_t width, int16_t height, uint8_t bytesPerPixel)
{
switch (format) {
case R_JCUA_JPEG_FORMAT_YCBCR420:
//MCU size: 16x16
m_jpegInfo.DecodeWidth = (width % 16) ? 16 * ((width / 16) + 1) : width;
m_jpegInfo.DecodeHeight = (height % 16) ? 16 * ((height / 16) + 1) : height;
break;
case R_JCUA_JPEG_FORMAT_YCBCR411:
//MCU size: 8x32
m_jpegInfo.DecodeWidth = (width % 8) ? 8 * ((width / 8) + 1) : width;
m_jpegInfo.DecodeHeight = (height % 32) ? 32 * ((height / 32) + 1) : height;
break;
case R_JCUA_JPEG_FORMAT_YCBCR422:
//MCU size: 8x16
m_jpegInfo.DecodeWidth = (width % 8) ? 8 * ((width / 8) + 1) : width;
m_jpegInfo.DecodeHeight = (height % 16) ? 16 * ((height / 16) + 1) : height;
break;
case R_JCUA_JPEG_FORMAT_YCBCR444:
//MCU size: 8x8
m_jpegInfo.DecodeWidth = (width % 8) ? 8 * ((width / 8) + 1) : width;
m_jpegInfo.DecodeHeight = (height % 8) ? 8 * ((height / 8) + 1) : height;
break;
default:
Qul::PlatformInterface::log("Decode Error: Invalid chroma-subsampling format\r\n");
break;
}
m_jpegInfo.EncodedFormat = format;
m_jpegInfo.Width = width;
m_jpegInfo.Height = height;
m_jpegInfo.StridePixel = m_jpegInfo.DecodeWidth;
m_jpegInfo.Stride = m_jpegInfo.DecodeWidth * bytesPerPixel;
}
Rh850ImageDecoder::Rh850ImageDecoder() {}
Rh850ImageDecoder::~Rh850ImageDecoder() {}
bool Rh850ImageDecoder::imageInformation(RequestDataCallback &callback,
int16_t *width,
int16_t *height,
int16_t *bytesPerLine,
Qul::PixelFormat *actualPixelFormat,
Qul::PixelFormat optimalOpaquePixelFormat,
Qul::PixelFormat optimalAlphaPixelFormat)
{
bool ret = jpegInformation(callback,
width,
height,
actualPixelFormat,
optimalOpaquePixelFormat,
optimalAlphaPixelFormat);
*actualPixelFormat = Qul::PixelFormat_ARGB32;
const uint8_t decodeBuffer_bpp = 4;
setJpegInfo(CHROMA_SUBSAMPLING, *width, *height, decodeBuffer_bpp);
*bytesPerLine = m_jpegInfo.Stride;
return ret;
}
int Rh850ImageDecoder::decodeImage(RequestDataCallback &callback,
unsigned char *outBuffer,
uint32_t outBufferSize,
Qul::PixelFormat pixelFormat,
uint32_t requiredBytesPerLine)
{
const uint8_t decodeBuffer_bpp = 4;
if (pixelFormat != Qul::PixelFormat_ARGB32) {
Qul::PlatformInterface::log("Decode Error: PixelFormat not supported\r\n");
return 1;
}
#ifdef USE_OUTPUT_SPLIT_MODE
/* if JPEG Decoder is configured for division mode, use a image block with pixel lines which is multiples of 16
* for storing decoded output. JPEG decoder resues this image block to avoid allocating large process buffer.
*/
uint32_t processBufferSize = m_jpegInfo.DecodeWidth * decodeBuffPixelLines() * decodeBuffer_bpp;
/* For images with YCrCb420 subsampling, the buffer must be atleast TWICE of this block size,
* hence the factor 2.
*/
if (m_jpegInfo.EncodedFormat == R_JCUA_JPEG_FORMAT_YCBCR420)
processBufferSize *= 2;
#else
uint32_t processBufferSize = m_jpegInfo.DecodeWidth * m_jpegInfo.DecodeHeight * decodeBuffer_bpp;
#endif
/* Allocate the process buffer from VRAM.
* Renesas JCUA hardware does not allow decoder output framebuffer from internal RAM.
*/
Qul::PlatformInterface::MemoryAllocator *allocator = Qul::Platform::getPlatformInstance()->memoryAllocator(
Qul::PlatformInterface::MemoryAllocator::Custom);
if (!allocator) {
Qul::PlatformInterface::log("Decode Error: NULL Allocator\r\n");
return 1;
}
/*Renesas JCUA driver requires 8 byte alignment for buffers*/
const size_t alignment = 8;
const size_t offset = alignment - 1;
unsigned char *addr = static_cast<unsigned char *>(allocator->allocate(processBufferSize + offset));
if (!addr) {
Qul::PlatformInterface::log("Decode Error: allocation failed\r\n");
return 1;
}
void *processBufferAligned = (void *) ((size_t) addr);
size_t space = processBufferSize + offset;
std::align(alignment, processBufferSize, processBufferAligned, space);
#ifdef RH850_JPEG_DEBUG_LOGS
Qul::PlatformInterface::log("ProcessWidth: %d, ProcessHeight %d\r\n",
m_jpegInfo.DecodeWidth,
m_jpegInfo.DecodeHeight);
Qul::PlatformInterface::log("PixelFormat: %d, OutBufferSize %d, AllocatedBffer 0x%x, Req Bpl: %d, Size: %d\r\n",
pixelFormat,
outBufferSize,
processBufferAligned,
requiredBytesPerLine,
processBufferSize);
#endif
r_jcua_Error_t ret
= jpegDecode_Start(callback, outBuffer, outBufferSize, processBufferAligned, requiredBytesPerLine, m_jpegInfo);
allocator->free(addr);
if (ret != R_JCUA_ERR_OK) {
r_jcua_ErrorDetail_t errorCode;
R_JCUA_ErrorInfoGet(JCUA_HW_UNIT, &errorCode);
Qul::PlatformInterface::log("Decoder failed with error Code 0x%X\r\n", errorCode);
return 1;
}
return 0;
}