219 lines
5.9 KiB
C
219 lines
5.9 KiB
C
/**
|
|
* @file mjpeg.c
|
|
*
|
|
* Copyright (c) 2020 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*
|
|
* Description:
|
|
*
|
|
* Revision History:
|
|
* -----------------
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <debug.h>
|
|
#include "mjpeg.h"
|
|
|
|
#include "projdefs.h"
|
|
#include "portable.h"
|
|
|
|
#ifdef __FATFS_SUPPORTED__
|
|
#include "ff.h"
|
|
#endif
|
|
|
|
static const uint8_t jpg_signature[] = {0xFF, 0xD8};
|
|
|
|
static inline size_t mjpeg_in_func(JDEC *jd, uint8_t *buff, size_t nbyte)
|
|
{
|
|
jpg_session *dev = (jpg_session *)jd->device;
|
|
|
|
if (buff) {
|
|
if (dev->bits_offset + nbyte > dev->bit_size) {
|
|
nbyte = dev->bit_size - dev->bits_offset;
|
|
}
|
|
memcpy(buff, dev->bit_stream + dev->bits_offset, nbyte);
|
|
dev->bits_offset += nbyte;
|
|
|
|
return nbyte;
|
|
} else { /* skip data from input stream */
|
|
if (dev->bits_offset + nbyte > dev->bit_size) {
|
|
nbyte = dev->bit_size - dev->bits_offset;
|
|
}
|
|
dev->bits_offset += nbyte;
|
|
|
|
return nbyte;
|
|
}
|
|
}
|
|
|
|
static inline jformat mjpeg_get_subsample_format(JDEC *jdec)
|
|
{
|
|
uint8_t sample = 0;
|
|
|
|
sample = (jdec->msx << 4) | jdec->msy;
|
|
|
|
if (sample == 0x11)
|
|
return JDF_444;
|
|
else if (sample == 0x21)
|
|
return JDF_422;
|
|
else if (sample == 0x22)
|
|
return JDF_420;
|
|
|
|
return JDF_420; /* default to yuv420 now */
|
|
}
|
|
|
|
/* if the input is from the file, load the file into ram,
|
|
otherwise use the input data directly
|
|
*/
|
|
jpg_session *mjpeg_dec_init(io_source_type type, const void *data,
|
|
uint32_t size)
|
|
{
|
|
jpg_session *dec_session = NULL;
|
|
if (data == NULL)
|
|
return NULL;
|
|
|
|
dec_session = (jpg_session *)pvPortMalloc(sizeof(jpg_session));
|
|
if (dec_session == NULL)
|
|
return NULL;
|
|
|
|
memset(dec_session, 0x00, sizeof(jpg_session));
|
|
dec_session->src_type = type;
|
|
dec_session->bits_offset = 0;
|
|
dec_session->work_buf = pvPortMalloc(MJPEG_WORKBUFF_SIZE);
|
|
if (dec_session->work_buf == NULL) {
|
|
vPortFree(dec_session);
|
|
return NULL;
|
|
}
|
|
|
|
if (dec_session->src_type == JPEG_IO_SOURCE_C_ARRAY) {
|
|
// input data is stored in the ram already
|
|
dec_session->bit_stream = (uint8_t *)data;
|
|
dec_session->bit_size = size;
|
|
}
|
|
#ifdef __FATFS_SUPPORTED__
|
|
else if (dec_session->src_type == JPEG_IO_SOURCE_DISK) {
|
|
FIL fp;
|
|
FRESULT rc;
|
|
UINT count = 0;
|
|
char file_name[128] = {0};
|
|
strcpy(file_name, (char *)data);
|
|
rc = f_open(&fp, file_name, FA_READ);
|
|
|
|
if (rc) {
|
|
vPortFree(dec_session->work_buf);
|
|
vPortFree(dec_session);
|
|
ssdk_printf(0, "file open failed (rc=%d)\n", rc);
|
|
return NULL;
|
|
}
|
|
|
|
dec_session->bit_size = f_size(&fp);
|
|
|
|
dec_session->bit_stream =
|
|
(uint8_t *)pvPortMallocAligned(dec_session->bit_size, 32);
|
|
f_read(&fp, dec_session->bit_stream, dec_session->bit_size, &count);
|
|
f_close(&fp); /* close the MJPEG file */
|
|
}
|
|
#endif
|
|
return dec_session;
|
|
}
|
|
|
|
JRESULT mjpeg_dec_get_header_info(jpg_session *dec_session,
|
|
jpg_out_info *out_info)
|
|
{
|
|
JRESULT res;
|
|
|
|
/* prepare to decompress header info*/
|
|
res = jd_prepare(&dec_session->jdec, mjpeg_in_func, dec_session->work_buf,
|
|
MJPEG_WORKBUFF_SIZE, dec_session);
|
|
|
|
if (res == JDR_OK) {
|
|
/* it is ready to dcompress and image info is available here */
|
|
out_info->width = dec_session->jdec.aligned_width;
|
|
out_info->height = dec_session->jdec.aligned_height;
|
|
out_info->crop.x = 0;
|
|
out_info->crop.y = 0;
|
|
out_info->crop.w = dec_session->jdec.width;
|
|
out_info->crop.h = dec_session->jdec.height;
|
|
out_info->format = mjpeg_get_subsample_format(&dec_session->jdec);
|
|
dec_session->first_parse = 1;
|
|
} else {
|
|
ssdk_printf(0, "jd_prepare() failed (rc=%d)\n", res);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
JRESULT mjpeg_dec_parser_next_frame(jpg_session *dec_session)
|
|
{
|
|
JRESULT res;
|
|
uint32_t search_range = dec_session->bit_size;
|
|
uint8_t *bits = NULL;
|
|
|
|
if (dec_session->first_parse) {
|
|
/* prepare return with ok, so we do not need to parser the first frame*/
|
|
dec_session->first_parse = 0;
|
|
return JDR_OK;
|
|
}
|
|
|
|
/* the previous decoding might have read more data than it needed, rewind */
|
|
dec_session->bits_offset -= CONFIG_JD_SZBUF;
|
|
|
|
if (dec_session->bits_offset + sizeof(jpg_signature) <
|
|
dec_session->bit_size) {
|
|
search_range -= sizeof(jpg_signature);
|
|
} else {
|
|
return JDR_INP;
|
|
}
|
|
|
|
for (bits = dec_session->bit_stream + dec_session->bits_offset;
|
|
dec_session->bits_offset < search_range;
|
|
dec_session->bits_offset++, bits++) {
|
|
|
|
if (bits[0] == 0xFF && bits[1] == 0xD8) {
|
|
/* find the start of next jpeg */
|
|
res = jd_prepare(&dec_session->jdec, mjpeg_in_func,
|
|
dec_session->work_buf, MJPEG_WORKBUFF_SIZE,
|
|
dec_session);
|
|
if (res == JDR_OK) {
|
|
return JDR_OK;
|
|
} else {
|
|
return JDR_INP;
|
|
}
|
|
}
|
|
}
|
|
|
|
return JDR_INP;
|
|
}
|
|
|
|
JRESULT mjpeg_dec_process_frame(jpg_session *dec_session, uint8_t *buf,
|
|
uint32_t y_size, uint32_t u_size)
|
|
{
|
|
JRESULT res;
|
|
|
|
res = jd_decomp_opt(&dec_session->jdec, buf, buf + y_size,
|
|
buf + y_size + u_size);
|
|
if (res == JDR_OK) {
|
|
/* the decompressed image in the frame buffer here. */
|
|
//ssdk_printf(0, "\rDecompression succeeded.\n");
|
|
} else {
|
|
ssdk_printf(0, "\rjd_decomp() failed (rc=%d)\n", res);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void mjpeg_dec_deinit(jpg_session *dec_session)
|
|
{
|
|
if (dec_session && dec_session->work_buf)
|
|
vPortFree(dec_session->work_buf);
|
|
|
|
#ifdef __FATFS_SUPPORTED__
|
|
if (dec_session && dec_session->src_type == JPEG_IO_SOURCE_DISK &&
|
|
dec_session->bit_stream)
|
|
vPortFree(dec_session->bit_stream);
|
|
#endif
|
|
|
|
vPortFree(dec_session);
|
|
}
|