C
Qt Quick Ultralite imagedecoder Example
/****************************************************************************** ** ** Copyright (C) 2024 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/#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(); } } }