C
Qt Quick Ultralite imagedecoder Example
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "rh850_jpeg.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "r_jcua_api.h"
#include <platforminterface/printf.h>
#include <platforminterface/imagedecoder.h>
#include <platform/platform.h>
static volatile char jpegEventGroup = 0x0;
static unsigned char inputSplitBuffer[INPUT_SPLIT_BUFFER_SIZE] __attribute__((aligned(8)));
static const char *toString(int eventId)
{
static const char *toStr[] = {"R_JCUA_CB_FACTOR_DECODE_COMPLETE",
"R_JCUA_CB_FACTOR_DECODE_INPUT_PAUSED",
"R_JCUA_CB_FACTOR_DECODE_OUTPUT_PAUSED",
"R_JCUA_CB_FACTOR_DECODE_SIZEOVER",
"R_JCUA_CB_FACTOR_DECODE_ERRORED",
"R_JCUA_CB_FACTOR_FATAL_ERROR",
"R_JCUA_CB_FACTOR_HEADER_TIMEOUT",
"R_JCUA_CB_FACTOR_DECODE_TIMEOUT"};
return toStr[eventId];
}
//This callback is called from interrupt context of JCUA interrupt
void jpegDecoderCallback(uint32_t unit, r_jcua_CallbackReason_t factor, uint32_t param)
{
(void) unit;
(void) param;
switch (factor) {
case R_JCUA_CB_FACTOR_DECODE_COMPLETE:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_COMPLETE_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_DECODE_INPUT_PAUSED:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_INPUT_PAUSED_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_DECODE_OUTPUT_PAUSED:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_OUTPUT_PAUSED_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_DECODE_SIZEOVER:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_SIZEOVER_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_DECODE_ERRORED:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_ERRORED_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_FATAL_ERROR:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_FATAL_ERROR_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_HEADER_TIMEOUT:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_HEADER_TIMEOUT_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_DECODE_TIMEOUT:
SET_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_TIMEOUT_EVENT_ID);
break;
case R_JCUA_CB_FACTOR_NONE:
break;
default:
DEBUG_PRINTF("Error: Invalid Callback factor\r\n");
break;
}
}
const uint16_t decodeBuffPixelLines()
{
return DECODE_BUFFER_PIXEL_LINES;
}
r_jcua_Error_t jpegDecode_Init()
{
r_jcua_Error_t ret = R_JCUA_ERR_OK;
ret = R_JCUA_Init(JCUA_HW_UNIT);
if (ret != R_JCUA_ERR_OK)
return ret;
ret = R_JCUA_DecoderOpen(JCUA_HW_UNIT, jpegDecoderCallback, 0);
return ret;
}
r_jcua_Error_t jpegDecode_Start(Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback,
void *outputBufferAddr,
uint32_t outputBufferSize,
void *processBuffer,
uint32_t outputBufferStride,
r_jcua_ImageInfo_t jpegInfo)
{
r_jcua_Error_t ret = R_JCUA_ERR_OK;
r_jcua_FrameBuffer_t fb;
r_jcua_DecodeSetting_t decodeOptions;
bool useInputSplitMode = false;
uint32_t inputBlockCount = 0;
uint32_t outputBlockCount = 0;
volatile uint32_t nDecodedImageBlock = 0;
uint32_t inputSplitBufferOffset = 0;
const unsigned char *inputBuffer = callback.rawData();
if (!inputBuffer) {
/* The images are not in the addressable memory.
* Use input split mode and retrieve the image chunk by chunk.
*/
useInputSplitMode = true;
} else {
if ((uint32_t) inputBuffer % 8 != 0) {
DEBUG_PRINTF("Error: inputBuffer is not multiple of 8\r\n");
return R_JCUA_ERR_NG;
}
}
if ((uint32_t) outputBufferAddr % 8 != 0) {
DEBUG_PRINTF("Error: outputBufferAddr is not multiple of 8\r\n");
return R_JCUA_ERR_NG;
}
if (outputBufferSize % 8 != 0) {
DEBUG_PRINTF("Error: outputBufferSize is not multiple of 8\r\n");
return R_JCUA_ERR_NG;
}
if ((uint32_t) processBuffer % 8 != 0) {
DEBUG_PRINTF("Error: Process framebuffer is not multiple of 8\r\n");
return R_JCUA_ERR_NG;
}
fb.Address = processBuffer;
fb.Size = (jpegInfo.DecodeWidth) * (jpegInfo.DecodeHeight) * 4;
fb.Stride = jpegInfo.Stride;
fb.Format = R_JCUA_OUTPUT_FORMAT_ARGB8888;
fb.Swap = R_JCUA_SWAP_LONG;
decodeOptions.ImgInfo = &jpegInfo;
decodeOptions.OptionFlag = R_JCUA_DECODE_OPTION_DIVISION_MODE;
if (useInputSplitMode) {
decodeOptions.DivisionMode.InputBuffer.IsEnable = true;
decodeOptions.DivisionMode.InputBuffer.IsInitAddress = true;
decodeOptions.DivisionMode.InputBuffer.RestartAddress = (uint32_t *) inputSplitBuffer;
decodeOptions.DivisionMode.InputBuffer.DataCount = INPUT_SPLIT_BUFFER_SIZE;
} else {
decodeOptions.DivisionMode.InputBuffer.IsEnable = false;
}
//Configure Output buffer for division mode
#ifdef USE_OUTPUT_SPLIT_MODE
decodeOptions.DivisionMode.OutputBuffer.IsEnable = true;
decodeOptions.DivisionMode.OutputBuffer.IsInitAddress = true;
decodeOptions.DivisionMode.OutputBuffer.RestartAddress = (uint32_t *) processBuffer;
decodeOptions.DivisionMode.OutputBuffer.DataCount = decodeBuffPixelLines();
#else
decodeOptions.DivisionMode.OutputBuffer.IsEnable = false;
#endif
jpegEventGroup = 0;
if (useInputSplitMode) {
inputSplitBufferOffset += callback.readData(inputSplitBuffer, inputSplitBufferOffset, INPUT_SPLIT_BUFFER_SIZE);
ret = R_JCUA_DecoderStart(JCUA_HW_UNIT, inputSplitBuffer, &fb, &decodeOptions);
} else {
ret = R_JCUA_DecoderStart(JCUA_HW_UNIT, inputBuffer, &fb, &decodeOptions);
}
if (ret != R_JCUA_ERR_OK) {
DEBUG_PRINTF("Decoder Error Code %d\r\n", ret);
return ret;
}
while (1) {
if (jpegEventGroup) {
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_COMPLETE_EVENT_ID)) {
int remainingLines = jpegInfo.Height - nDecodedImageBlock * decodeBuffPixelLines();
//clear event bit
CLEAR_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_COMPLETE_EVENT_ID);
#ifdef USE_OUTPUT_SPLIT_MODE
DEBUG_PRINTF("RemainingLines:%d\r\n", remainingLines);
if (remainingLines > 0) {
memcpy(static_cast<unsigned char *>(outputBufferAddr)
+ nDecodedImageBlock * decodeBuffPixelLines() * outputBufferStride,
(uint8_t *) (processBuffer),
outputBufferStride * remainingLines);
}
#else
memcpy(outputBufferAddr, processBuffer, outputBufferSize);
#endif
DEBUG_PRINTF("Decode_Complete_Callback\r\n");
return R_JCUA_ERR_OK;
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_INPUT_PAUSED_EVENT_ID)) {
if (useInputSplitMode)
inputSplitBufferOffset += callback.readData(inputSplitBuffer,
inputSplitBufferOffset,
INPUT_SPLIT_BUFFER_SIZE);
//clear event bit
CLEAR_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_INPUT_PAUSED_EVENT_ID);
inputBlockCount++;
DEBUG_PRINTF("Input Paused %d\r\n", inputBlockCount);
R_JCUA_DecoderContinue(JCUA_HW_UNIT, R_JCUA_PAUSE_FACTOR_INPUT_PAUSED);
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_OUTPUT_PAUSED_EVENT_ID)) {
#ifdef USE_OUTPUT_SPLIT_MODE
volatile size_t copyLength = outputBufferStride * decodeBuffPixelLines();
// if image is encoded with YCrCb420, then for first decoded image block 0,
// the decoded data length is twice than all other subsequent blocks.
if (jpegInfo.EncodedFormat == R_JCUA_JPEG_FORMAT_YCBCR420)
copyLength *= (nDecodedImageBlock == 0 ? 2 : 1);
memcpy(static_cast<unsigned char *>(outputBufferAddr)
+ nDecodedImageBlock * decodeBuffPixelLines() * outputBufferStride,
(uint8_t *) (processBuffer),
copyLength);
//Decoded length is twice for block number 0
if (nDecodedImageBlock == 0 && jpegInfo.EncodedFormat == R_JCUA_JPEG_FORMAT_YCBCR420)
nDecodedImageBlock = nDecodedImageBlock + 2;
else
nDecodedImageBlock = nDecodedImageBlock + 1;
#endif
//clear event bit
CLEAR_EVENT_BIT(jpegEventGroup, CALLBACK_FACTOR_DECODE_OUTPUT_PAUSED_EVENT_ID);
outputBlockCount++;
DEBUG_PRINTF("Output Paused %d\r\n", outputBlockCount);
R_JCUA_DecoderContinue(JCUA_HW_UNIT, R_JCUA_PAUSE_FACTOR_OUTPUT_PAUSED);
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_SIZEOVER_EVENT_ID)) {
DEBUG_PRINTF("Error: SizeOver Error with FrameBuffer size %d\r\n", fb.Size);
return R_JCUA_ERR_NG;
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_ERRORED_EVENT_ID)) {
DEBUG_PRINTF("Decoder Callback Error code: %s\r\n", toString(CALLBACK_FACTOR_DECODE_ERRORED_EVENT_ID));
return R_JCUA_ERR_NG;
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_FATAL_ERROR_EVENT_ID)) {
DEBUG_PRINTF("Decoder Callback Error code: %s\r\n", toString(CALLBACK_FACTOR_FATAL_ERROR_EVENT_ID));
return R_JCUA_ERR_NG;
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_HEADER_TIMEOUT_EVENT_ID)) {
DEBUG_PRINTF("Decoder Callback Error code: %s\r\n", toString(CALLBACK_FACTOR_HEADER_TIMEOUT_EVENT_ID));
return R_JCUA_ERR_NG;
}
if (EVENT(jpegEventGroup, CALLBACK_FACTOR_DECODE_TIMEOUT_EVENT_ID)) {
DEBUG_PRINTF("Decoder Callback Error code: %s\r\n", toString(CALLBACK_FACTOR_DECODE_TIMEOUT_EVENT_ID));
return R_JCUA_ERR_NG;
}
} else {
//enter sleep power mode
__HALT();
}
}
}