Files
luban-lite-t3e-pro/packages/artinchip/mpp/ve/decoder/jpeg/mjpeg_decoder.c
刘可亮 803cac77d5 V1.0.6
2024-09-03 11:16:08 +08:00

908 lines
29 KiB
C

/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* author: <qi.xu@artinchip.com>
* Desc:jpeg decode
*
*/
#define LOG_TAG "jpeg_decoder"
#include <stdlib.h>
#include "mjpeg.h"
#include "mjpeg_decoder.h"
#include "jpeg_hal.h"
#include "mpp_log.h"
#include "ve.h"
#include "mpp_mem.h"
static void fill_huffman_startcode(struct mjpeg_dec_ctx *s, int class, int index, const uint8_t *bits_table)
{
int i,j,k,nb,code;
code = 0;
k = 0;
for(i=1;i<=16;i++) {
nb = bits_table[i];
s->huffman_table[class][index].start_code[i - 1] = code;
s->huffman_table[class][index].max_code[i - 1] = code + nb-1;
for(j=0;j<nb;j++) {
s->huffman_table[class][index].code[k] = code;
s->huffman_table[class][index].len[k] = i;
k++;
code++;
}
code <<= 1;
}
s->huffman_table[class][index].total_code = k;
for(i=16;i>=1;i--) {
if (bits_table[i] == 0) {
s->huffman_table[class][index].start_code[i - 1] = 0xffff;
s->huffman_table[class][index].max_code[i - 1] = 0xffff;
}
else
break;
}
}
/*
___________________________ _______________________________
| | | | |
| real data | | rotate 180 | |---------------------------|
|-----------------------| | --------------> | | real data |
|_________________________| |_|___________________________|
*/
static void get_start_offset(struct mjpeg_dec_ctx *s)
{
int rotate = MPP_ROTATION_GET(s->decoder.rotmir_flag);
int flip_v = MPP_FLIP_V_GET(s->decoder.rotmir_flag);
int flip_h = MPP_FLIP_H_GET(s->decoder.rotmir_flag);
s->h_offset[0] = s->h_offset[1] = s->h_offset[2] = 0;
s->v_offset[0] = s->v_offset[1] = s->v_offset[2] = 0;
if ((rotate == MPP_ROTATION_270 && !flip_h && !flip_v) // 0001
|| (rotate == MPP_ROTATION_90 && (flip_h && flip_v))) { // 1111
for(int k=0; k<3; k++)
s->v_offset[k] = s->rm_v_stride[k] - s->rm_v_real_size[k];
} else if ((rotate == MPP_ROTATION_180 && !flip_h && !flip_v) // 0010
|| (rotate == MPP_ROTATION_0 && (flip_h && flip_v))) { //1100
for (int k = 0; k < 3; k++) {
s->v_offset[k] = s->rm_v_stride[k] - s->rm_v_real_size[k];
s->h_offset[k] = s->rm_h_stride[k] - s->rm_h_real_size[k];
}
} else if ((rotate == MPP_ROTATION_90 && !flip_h && !flip_v) // 0011
|| (rotate == MPP_ROTATION_270 && (flip_h && flip_v))) { //1101
for (int k = 0; k<3; k++)
s->h_offset[k] = s->rm_h_stride[k] - s->rm_h_real_size[k];
} else if ((rotate == MPP_ROTATION_0 && flip_v) //0100
|| (rotate == MPP_ROTATION_180 && flip_h)) { // 1010
for (int k = 0; k<3; k++)
s->v_offset[k] = s->rm_v_stride[k] - s->rm_v_real_size[k];
} else if ((rotate == MPP_ROTATION_0 && flip_h) // 1000
|| (rotate == MPP_ROTATION_180 && flip_v)) { // 0110
for (int k = 0; k<3; k++)
s->h_offset[k] = s->rm_h_stride[k] - s->rm_h_real_size[k];
} else if ((rotate == MPP_ROTATION_90 && flip_h) // 1011
|| (rotate == MPP_ROTATION_270 && flip_v)) { // 0101
for (int k = 0; k < 3; k++) {
s->h_offset[k] = s->rm_h_stride[k] - s->rm_h_real_size[k];
s->v_offset[k] = s->rm_v_stride[k] - s->rm_v_real_size[k];
}
}
// do nothing for the cases below
// (rotate == MPP_ROTATION_270 && s->mirror == MPP_FLIP_H) //1001
// (rotate == MPP_ROTATION_90 && s->mirror == MPP_FLIP_V) // 0111
// (rotate == MPP_ROTATION_0 && s->mirror == 0) // 0000
// (rotate == MPP_ROTATION_180 && s->mirror == (MPP_FLIP_V | MPP_FLIP_H)) // 1110
}
/* quantize tables */
int mjpeg_decode_dqt(struct mjpeg_dec_ctx *s)
{
int len, index, i;
len = read_bits(&s->gb, 16) - 2;
if (8 * len > read_bits_left(&s->gb)) {
loge("dqt: len %d is too large", len);
return -1;
}
while (len >= 65) {
int pr = read_bits(&s->gb, 4);
if (pr > 1) {
loge("dqt: invalid precision");
return -1;
}
if (pr != 0) {
loge("dqt: only support 8 bit precision");
return -1;
}
index = read_bits(&s->gb, 4);
if (index >= 4)
return -1;
logd("index=%d", index);
/* read quant table */
for (i = 0; i < 64; i++) {
s->q_matrixes[index][i] = read_bits(&s->gb, pr ? 16 : 8);
}
len -= 1 + 64 * (1 + pr);
}
return 0;
}
/* decode huffman tables and build VLC decoders */
int mjpeg_decode_dht(struct mjpeg_dec_ctx *s)
{
int len, index, i, class, n, v, code_max;
uint8_t bits_table[17];
logd("====== DHT (huffman table) ======");
len = read_bits(&s->gb, 16) - 2;
if (8*len > read_bits_left(&s->gb)) {
loge("dht: len %d is too large", len);
return -1;
}
while (len > 0) {
if (len < 17)
return -1;
class = read_bits(&s->gb, 4);
if (class >= 2)
return -1;
index = read_bits(&s->gb, 4);
if (index >= 4)
return -1;
logi("class: %d, index: %d", class, index);
// initial huffman table
for (i = 0; i < 16; i++) {
s->huffman_table[class][index].offset[i] = 0;
s->huffman_table[class][index].start_code[i] = 0;
}
for (i = 0; i < 256; i++)
s->huffman_table[class][index].symbol[i] = 0;
n = 0;
// number of huffman code with code length i
bits_table[0] = 0;
// 1. parse BITS(BITS is the number of huffman code which is the same
// code length,
// the max code length is 16), generate HUFFSIZE according BITS
// table
for (i = 1; i <= 16; i++) {
s->huffman_table[class][index].offset[i - 1] = n;
bits_table[i] = read_bits(&s->gb, 8);
s->huffman_table[class][index].bits_table[i - 1] = bits_table[i];
n += bits_table[i];
}
len -= 17;
if (len < n || n > 256)
return -1;
code_max = 0;
// 2.parse HUFFVAL table, the huffman code to symbol
for (i = 0; i < n; i++) {
v = read_bits(&s->gb, 8);
if (v > code_max)
code_max = v;
s->huffman_table[class][index].symbol[i] = v;
}
len -= n;
// 3. generate HUFFCODE table, it is used for config ve
fill_huffman_startcode(s, class, index, bits_table);
}
return 0;
}
int mjpeg_decode_sof(struct mjpeg_dec_ctx *s)
{
int len, nb_components, i, bits;
int phy_h_stride[4]; // hor stride ( before post-process)
int phy_v_stride[4]; // ver stride ( before post-process)
int h_real_size[4]; // hor real size ( before post-process)
int v_real_size[4]; // hor real size ( before post-process)
logd("===== ff_mjpeg_decode_sof ====== ");
len = read_bits(&s->gb, 16);
bits = read_bits(&s->gb, 8);
if (bits > 16 || bits < 1) {
loge("bits %d is invalid", bits);
return -1;
}
/* only 8 bits/component accepted */
if (bits != 8) {
loge("only support 8 bits, bits %d is invalid", bits);
return -1;
}
s->height = read_bits(&s->gb, 16);
s->width = read_bits(&s->gb, 16);
if (s->width < 1 || s->height < 1) {
loge("size too small: width %d, height %d", s->width, s->height);
return -1;
}
nb_components = read_bits(&s->gb, 8);
if (nb_components <= 0 || nb_components > MAX_COMPONENTS) {
return -1;
}
if (len != 8 + 3 * nb_components) {
loge("decode_sof0: error, len(%d) mismatch %d components", len, nb_components);
return -1;
}
s->nb_components = nb_components;
for (i = 0; i < nb_components; i++) {
/* component id */
s->component_id[i] = read_bits(&s->gb, 8) - 1;
s->h_count[i] = read_bits(&s->gb, 4);
s->v_count[i] = read_bits(&s->gb, 4);
s->quant_index[i] = read_bits(&s->gb, 8);
if (s->quant_index[i] >= 4) {
loge("quant_index is invalid");
return -1;
}
if (!s->h_count[i] || !s->v_count[i]) {
loge("Invalid sampling factor in component %d %d:%d",
i, s->h_count[i], s->v_count[i]);
return -1;
}
logd("component %d %d:%d id: %d quant:%d",i, s->h_count[i], s->v_count[i],
s->component_id[i], s->quant_index[i]);
}
logi("s->width %d, s->height %d", s->width, s->height);
logi("s->uv_interleave: %d, out_pix_fmt: %d", s->uv_interleave, s->out_pix_fmt);
if (s->h_count[0] == 2 && s->v_count[0] == 2 && s->h_count[1] == 1 &&
s->v_count[1] == 1 && s->h_count[2] == 1 && s->v_count[2] == 1) {
// not support NV21
if (s->out_pix_fmt == MPP_FMT_NV12 || s->out_pix_fmt == MPP_FMT_NV21) {
s->uv_interleave = 1;
s->pix_fmt = MPP_FMT_NV12;
} else {
s->pix_fmt = MPP_FMT_YUV420P;
}
logi("pixel format: yuv420");
} else if (s->h_count[0] == 4 && s->v_count[0] == 1 && s->h_count[1] == 1 &&
s->v_count[1] == 1 && s->h_count[2] == 1 && s->v_count[2] == 1) {
logi("not support pixel format: yuv411");
return -1;
} else if (s->h_count[0] == 2 && s->v_count[0] == 1 && s->h_count[1] == 1 &&
s->v_count[1] == 1 && s->h_count[2] == 1 && s->v_count[2] == 1) {
if (s->out_pix_fmt == MPP_FMT_NV16 || s->out_pix_fmt == MPP_FMT_NV61) {
s->uv_interleave = 1;
s->pix_fmt = MPP_FMT_NV16;
} else {
s->pix_fmt = MPP_FMT_YUV422P;
}
logi("pixel format: yuv422");
} else if (s->h_count[0] == 1 && s->v_count[0] == 1 && s->h_count[1] == 1 &&
s->v_count[1] == 1 && s->h_count[2] == 1 && s->v_count[2] == 1) {
#ifdef AIC_VE_DRV_V10
s->pix_fmt = MPP_FMT_YUV444P;
#else
s->pix_fmt = MPP_FMT_RGBA_8888;
s->yuv2rgb = 1;
logi("pixel format: yuv444, must convert to RGBA");
#endif
} else if (s->h_count[0] == 1 && s->v_count[0] == 2 && s->h_count[1] == 1 &&
s->v_count[1] == 2 && s->h_count[2] == 1 && s->v_count[2] == 2) {
#ifdef AIC_VE_DRV_V10
s->pix_fmt = MPP_FMT_YUV444P;
#else
s->pix_fmt = MPP_FMT_RGBA_8888;
s->yuv2rgb = 1;
logi("pixel format: ffmpeg yuv444, must convert to RGBA");
#endif
} else if (s->h_count[0] == 1 && s->v_count[0] == 2 && s->h_count[1] == 1 &&
s->v_count[1] == 1 && s->h_count[2] == 1 && s->v_count[2] == 1) {
//logi("not support pixel format: yuv422t");
s->pix_fmt = MPP_FMT_YUV422P;
} else if (s->h_count[1] == 0 && s->v_count[1] == 0 && s->h_count[2] == 0 &&
s->v_count[2] == 0) {
s->pix_fmt = MPP_FMT_YUV400;
logi("pixel format: yuv400");
} else {
loge("Not support format! h_count: %d %d %d, v_count: %d %d %d",
s->h_count[0], s->h_count[1], s->h_count[2],
s->v_count[0], s->v_count[1], s->v_count[2]);
return -1;
}
#ifndef AIC_VE_DRV_V10
if(s->out_pix_fmt == MPP_FMT_ARGB_8888 || s->out_pix_fmt == MPP_FMT_ABGR_8888
|| s->out_pix_fmt == MPP_FMT_RGBA_8888 || s->out_pix_fmt == MPP_FMT_BGRA_8888
|| s->out_pix_fmt == MPP_FMT_RGB_888 || s->out_pix_fmt == MPP_FMT_BGR_888
|| s->out_pix_fmt == MPP_FMT_RGB_565 || s->out_pix_fmt == MPP_FMT_BGR_565) {
s->pix_fmt = s->out_pix_fmt;
s->yuv2rgb = 1;
}
#endif
// get the output size of scale down
s->nb_mcu_width = (s->width + 8 * s->h_count[0] - 1) / (8 * s->h_count[0]);
s->nb_mcu_height = (s->height + 8 * s->v_count[0] - 1) / (8 * s->v_count[0]);
int h_stride_y = (s->nb_mcu_width * s->h_count[0] * 8) >> s->decoder.hor_scale;
int v_stride_y = (s->nb_mcu_height * s->v_count[0] * 8) >> s->decoder.ver_scale;
phy_h_stride[0] = phy_h_stride[1] = phy_h_stride[2] = (h_stride_y + 15) / 16 * 16;
phy_v_stride[0] = phy_v_stride[1] = phy_v_stride[2] = (v_stride_y + 15) / 16 * 16;
h_real_size[0] = s->width >> s->decoder.hor_scale;
v_real_size[0] = s->height >> s->decoder.ver_scale;
if (s->pix_fmt == MPP_FMT_YUV420P) {
phy_h_stride[1] = phy_h_stride[2] = phy_h_stride[0] / 2;
phy_v_stride[1] = phy_v_stride[2] = phy_v_stride[0] / 2;
h_real_size[1] = h_real_size[2] = h_real_size[0] / 2;
v_real_size[1] = v_real_size[2] = v_real_size[0] / 2;
} else if (s->pix_fmt == MPP_FMT_YUV444P || s->pix_fmt == MPP_FMT_YUV400) {
phy_h_stride[0] = (h_stride_y + 7) / 8 * 8;
phy_v_stride[0] = (v_stride_y + 7) / 8 * 8;
phy_h_stride[1] = phy_h_stride[2] = phy_h_stride[0];
phy_v_stride[1] = phy_v_stride[2] = phy_v_stride[0];
h_real_size[1] = h_real_size[2] = h_real_size[0];
v_real_size[1] = v_real_size[2] = v_real_size[0];
} else if (s->pix_fmt == MPP_FMT_YUV422P) {
phy_h_stride[1] = phy_h_stride[2] = phy_h_stride[0] / 2;
phy_v_stride[1] = phy_v_stride[2] = phy_v_stride[0];
h_real_size[1] = h_real_size[2] = h_real_size[0] / 2;
v_real_size[1] = v_real_size[2] = v_real_size[0];
}
// get the output size of rotate
if (MPP_ROTATION_GET(s->decoder.rotmir_flag) == MPP_ROTATION_270 ||
MPP_ROTATION_GET(s->decoder.rotmir_flag) == MPP_ROTATION_90) {
for (int k = 0; k < 3; k++) {
s->rm_h_real_size[k] = v_real_size[k];
s->rm_v_real_size[k] = h_real_size[k];
s->rm_h_stride[k] = phy_v_stride[k];
s->rm_v_stride[k] = phy_h_stride[k];
}
} else {
for (int k = 0; k < 3; k++) {
s->rm_h_real_size[k] = h_real_size[k];
s->rm_v_real_size[k] = v_real_size[k];
s->rm_h_stride[k] = phy_h_stride[k];
s->rm_v_stride[k] = phy_v_stride[k];
}
}
#ifndef AIC_VE_DRV_V10
if(s->pix_fmt == MPP_FMT_BGR_888 || s->pix_fmt == MPP_FMT_RGB_888) {
s->rm_h_stride[0] = ALIGN_16B(s->rm_h_stride[0] * 3);
} else if(s->pix_fmt == MPP_FMT_BGR_565 || s->pix_fmt == MPP_FMT_RGB_565) {
s->rm_h_stride[0] = ALIGN_16B(s->rm_h_stride[0] * 2);
} else if(s->out_pix_fmt == MPP_FMT_ARGB_8888 || s->out_pix_fmt == MPP_FMT_ABGR_8888
|| s->out_pix_fmt == MPP_FMT_RGBA_8888 || s->out_pix_fmt == MPP_FMT_BGRA_8888) {
s->rm_h_stride[0] = ALIGN_16B(s->rm_h_stride[0] * 4);
}
#endif
// get the start offset of output
get_start_offset(s);
s->got_picture = 1;
return 0;
}
static void set_frame_info(struct mjpeg_dec_ctx *s)
{
if(s->curr_packet->flag & PACKET_FLAG_EOS)
s->curr_frame->mpp_frame.flags |= FRAME_FLAG_EOS;
s->curr_frame->mpp_frame.buf.flags |= MPP_COLOR_SPACE_BT601_FULL_RANGE;
s->curr_frame->mpp_frame.buf.crop_en = 1;
s->curr_frame->mpp_frame.buf.crop.x = 0;
s->curr_frame->mpp_frame.buf.crop.y = 0;
s->curr_frame->mpp_frame.buf.crop.width = s->width;
s->curr_frame->mpp_frame.buf.crop.height = s->height;
s->curr_frame->mpp_frame.pts = s->curr_packet->pts;
}
int mjpeg_decode_sos(struct mjpeg_dec_ctx *s,
const uint8_t *mb_bitmask,
int mb_bitmask_size)
{
int len, nb_components, i;
int index, id;
logd("===== ff_mjpeg_decode_sos ====== ");
if (!s->got_picture) {
logw("Can not process SOS before SOF, skipping");
return -1;
}
// 1. parse SOS info
len = read_bits(&s->gb, 16);
nb_components = read_bits(&s->gb, 8);
if (nb_components == 0 || nb_components > MAX_COMPONENTS) {
return -1;
}
if (len != 6 + 2 * nb_components) {
loge("decode_sos: invalid len (%d)", len);
return -1;
}
for (i = 0; i < nb_components; i++) {
id = read_bits(&s->gb, 8) - 1;
/* find component index */
for (index = 0; index < s->nb_components; index++)
if (id == s->component_id[index])
break;
if (index == s->nb_components) {
loge("decode_sos: index(%d) out of components", index);
return -1;
}
s->dc_index[i] = read_bits(&s->gb, 4);
s->ac_index[i] = read_bits(&s->gb, 4);
if (s->dc_index[i] < 0 || s->ac_index[i] < 0 ||
s->dc_index[i] >= 4 || s->ac_index[i] >= 4) {
loge("index out of range");
return -1;
}
}
read_bits(&s->gb, 8); /* JPEG Ss / lossless JPEG predictor /JPEG-LS NEAR */
read_bits(&s->gb, 8); /* JPEG Se / JPEG-LS ILV */
read_bits(&s->gb, 4); /* Ah */
read_bits(&s->gb, 4); /* Al */
int sos_size = read_bits_count(&s->gb) / 8;
logd("sos_size %d, s->pix_fmt: %d", sos_size, s->pix_fmt);
if(s->decoder.fm == NULL) {
struct frame_manager_init_cfg cfg;
cfg.frame_count = 1 + s->extra_frame_num;
cfg.height = s->height;
cfg.width = s->width;
cfg.height_align = s->rm_v_stride[0];
cfg.stride = s->rm_h_stride[0];
cfg.pixel_format = s->pix_fmt;
cfg.allocator = s->decoder.allocator;
s->decoder.fm = fm_create(&cfg);
}
s->curr_frame = fm_decoder_get_frame(s->decoder.fm);
if(s->curr_frame == NULL) {
pm_reclaim_ready_packet(s->decoder.pm, s->curr_packet);
return DEC_NO_EMPTY_FRAME;
}
#ifdef COPY_DATA
s->sos_length = s->raw_scan_buffer_size - sos_size;
s->sos_buf = ve_buffer_alloc(s->ve_buf_handle, (s->sos_length / 512 +1) * 512, ALLOC_NEED_VIR_ADDR);
memcpy(s->sos_buf->vir_addr, s->raw_scan_buffer+sos_size, s->sos_length);
ve_buffer_sync(s->sos_buf, CACHE_CLEAN);
#endif
int offset = (s->raw_scan_buffer - s->curr_packet->data) + sos_size;
logw("offste: %d", offset);
if(ve_decode_jpeg(s, offset)) {
s->error = JPEG_DECODER_ERROR_HARDWARE;
printf("[%s:%d]\n",__FUNCTION__,__LINE__);
return -1;
}
set_frame_info(s);
fm_decoder_frame_to_render(s->decoder.fm, s->curr_frame, 1);
fm_decoder_put_frame(s->decoder.fm, s->curr_frame);
return 0;
}
static int mjpeg_decode_dri(struct mjpeg_dec_ctx *s)
{
if (read_bits(&s->gb, 16) != 4)
return -1;
s->restart_interval = read_bits(&s->gb, 16);
s->restart_count = 0;
logd("restart interval: %d", s->restart_interval);
return 0;
}
/* return the 8 bit start code value and update the search
state. Return -1 if no start code found */
static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
{
const uint8_t *buf_ptr;
unsigned int v, v2;
int val;
int skipped = 0;
buf_ptr = *pbuf_ptr;
while (buf_end - buf_ptr > 1) {
v = *buf_ptr++;
v2 = *buf_ptr;
if ((v == 0xff) && (v2 >= SOF0) && (v2 <= COM) && buf_ptr < buf_end) {
val = *buf_ptr++;
goto found;
}
skipped++;
}
buf_ptr = buf_end;
val = -1;
found:
*pbuf_ptr = buf_ptr;
return val;
}
int mjpeg_find_marker(struct mjpeg_dec_ctx *s,
const uint8_t **buf_ptr, const uint8_t *buf_end,
const uint8_t **unescaped_buf_ptr,
int *unescaped_buf_size)
{
int start_code;
start_code = find_marker(buf_ptr, buf_end);
*unescaped_buf_ptr = *buf_ptr;
*unescaped_buf_size = buf_end - *buf_ptr;
return start_code;
}
static void skip_variable_marker(struct mjpeg_dec_ctx *s)
{
int left = read_bits(&s->gb, 16);
left -= 2;
while(left) {
skip_bits(&s->gb, 8);
left --;
}
}
void mjpeg_print_decoder_error(struct mpp_decoder *ctx)
{
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx*)ctx;
switch (s->error) {
case JPEG_DECODER_ERROR_NONE:
loge("ok\n");
break;
case JPEG_DECODER_ERROR_INPUTLEN:
loge("input packet too small\n");
break;
case JPEG_DECODER_ERROR_INPUTERROR:
loge("input packet data error\n");
break;
case JPEG_DECODER_ERROR_INVPTR:
loge("invalid (null) buffer pointer\n");
break;
case JPEG_DECODER_ERROR_NOEMPTYFRAME:
loge("no empty frame for decoder\n");
break;
case JPEG_DECODER_ERROR_UNSUPPORTTYPE:
loge("unsupport type\n");
break;
case JPEG_DECODER_ERROR_HARDWARE:
loge("an error happen whlie hard decoder processing \n");
break;
default:
loge("unknown error\n");
break;
}
}
int __mjpeg_decode_frame(struct mpp_decoder *ctx)
{
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx*)ctx;
int buf_size;
const uint8_t *buf_end, *buf_ptr;
const uint8_t *unescaped_buf_ptr;
int unescaped_buf_size;
int start_code;
int ret = 0;
s->error = JPEG_DECODER_ERROR_NONE;
s->got_picture = 0;
s->curr_packet = pm_dequeue_ready_packet(s->decoder.pm);
if(s->curr_packet == NULL) {
loge("pm_dequeue_ready_packet error, ready_packet num: %d", pm_get_ready_packet_num(s->decoder.pm));
return DEC_NO_READY_PACKET;
}
buf_size = s->curr_packet->size;
buf_ptr = s->curr_packet->data;
buf_end = buf_ptr + buf_size;
start_code = 0xffd8;
if (buf_size < 8) {
s->error = JPEG_DECODER_ERROR_INPUTLEN;
loge("data error is too short !");
ret = -1;
goto _exit;
}
if (!memchr(buf_ptr, start_code, 8)) {
s->error = JPEG_DECODER_ERROR_INPUTERROR;
loge("The file is not jpeg!");
ret = -1;
goto _exit;
}
while (buf_ptr < buf_end) {
/* find start next marker */
start_code = mjpeg_find_marker(s, &buf_ptr, buf_end,
&unescaped_buf_ptr,
&unescaped_buf_size);
/* EOF */
if (start_code < 0) {
s->error = JPEG_DECODER_ERROR_INPUTERROR;
loge("no start_code means\n");
ret = -1;
goto _exit;
} else if (unescaped_buf_size > INT_MAX / 8) {
loge("MJPEG packet 0x%x too big (%d/%d), corrupt data?",
start_code, unescaped_buf_size, buf_size);
s->error = JPEG_DECODER_ERROR_INPUTERROR;
ret = -1;
goto _exit;
}
ret = init_read_bits(&s->gb, unescaped_buf_ptr, unescaped_buf_size*8);
if (ret < 0) {
s->error = JPEG_DECODER_ERROR_INVPTR;
loge("invalid buffer");
goto _exit;
}
s->start_code = start_code;
logi("startcode: %02x", start_code);
/* process markers */
if (start_code >= RST0 && start_code <= RST7) {
//logd("restart marker: %d", start_code & 0xff);
/* APP fields */
} else if (start_code >= APP0 && start_code <= APP15) {
logd("app marker: %d", start_code & 0xff);
/* Comment */
} else if (start_code == COM) {
logd("com marker: %d", start_code & 0xff);
}
ret = -1;
switch (start_code) {
case DQT:
ret = mjpeg_decode_dqt(s);
if (ret < 0) {
s->error = JPEG_DECODER_ERROR_INPUTERROR;
goto _exit;
}
break;
case SOI:
s->restart_interval = 0;
s->restart_count = 0;
/* nothing to do on SOI */
break;
case DHT:
s->have_dht = 1;
if ((ret = mjpeg_decode_dht(s)) < 0) {
loge("huffman table decode error");
s->error = JPEG_DECODER_ERROR_INPUTERROR;
goto _exit;
}
break;
case SOF0:
logi("baseline");
case SOF1:
logi("SOF1");
if ((ret = mjpeg_decode_sof(s)) < 0) {
loge("mjpeg_decode_sof");
s->error = JPEG_DECODER_ERROR_INPUTERROR;
goto _exit;
}
break;
case SOF2:
loge("progressive, not support");
if ((ret = mjpeg_decode_sof(s)) < 0) {
loge("mjpeg_decode_sof");
s->error = JPEG_DECODER_ERROR_INPUTERROR;
goto _exit;
}
break;
case LSE:
break;
case EOI:
if (!s->got_picture) {
loge("Found EOI before any SOF, skip");
break;
}
ret = 0;
s->got_picture = 0;
goto _exit;
case SOS:
s->raw_scan_buffer = buf_ptr;
s->raw_scan_buffer_size = buf_end - buf_ptr;
if ((ret = mjpeg_decode_sos(s, NULL, 0)) != 0) {
if (ret == DEC_NO_EMPTY_FRAME) {
s->error = JPEG_DECODER_ERROR_NOEMPTYFRAME;
} else {
loge("mjpeg_decode_sos error\n");
}
}
goto _exit;
case DRI:
if ((ret = mjpeg_decode_dri(s)) < 0) {
loge("mjpeg_decode_dri error\n");
s->error = JPEG_DECODER_ERROR_INPUTERROR;
goto _exit;
}
break;
case SOF3:
case SOF48:
case SOF5:
case SOF6:
case SOF7:
case SOF9:
case SOF10:
case SOF11:
case SOF13:
case SOF14:
case SOF15:
case JPG:
loge("mjpeg: unsupported coding type (%x)", start_code);
break;
default:
logi("skip this marker: %02x", start_code);
skip_variable_marker(s);
break;
}
/* eof process start code */
buf_ptr += (read_bits_count(&s->gb) + 7) / 8;
//logd("marker parser used %d bytes (%d bits)", (read_bits_count(&s->gb) + 7) / 8, read_bits_count(&s->gb));
}
_exit:
s->got_picture = 0;
if (s->error == JPEG_DECODER_ERROR_HARDWARE) {
fm_decoder_put_frame(s->decoder.fm, s->curr_frame);
fm_decoder_frame_to_render(s->decoder.fm, s->curr_frame, 0);
}
if (s->error != JPEG_DECODER_ERROR_NOEMPTYFRAME) {
pm_enqueue_empty_packet(s->decoder.pm, s->curr_packet);
if (s->error != JPEG_DECODER_ERROR_NONE) {
mjpeg_print_decoder_error(ctx);
}
}
return ret;
}
int __mjpeg_decode_init(struct mpp_decoder *ctx, struct decode_config *config)
{
if (!ctx)
return -1;
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx *)ctx;
s->out_pix_fmt = config->pix_fmt;
logw("output pix format: %d", config->pix_fmt);
s->ve_fd = ve_open_device();
if(s->ve_fd < 0)
{
loge("ve open failed");
return -1;
}
s->regs_base = ve_get_reg_base();
s->ve_buf_handle = ve_buffer_allocator_create(VE_BUFFER_TYPE_DMA);
struct packet_manager_init_cfg cfg;
cfg.ve_buf_handle = s->ve_buf_handle;
cfg.buffer_size = config->bitstream_buffer_size;
cfg.packet_count = config->packet_count;
s->decoder.pm = pm_create(&cfg);
if (!s->decoder.pm) {
loge("pm_create error");
return -1;
}
s->extra_frame_num = config->extra_frame_num;
s->start_code = -1;
s->first_picture = 1;
s->got_picture = 0;
if (s->out_pix_fmt == MPP_FMT_YUV420P)
logw("default pix fmt %d", MPP_FMT_YUV420P);
s->reg_list = mpp_alloc(sizeof(jpg_reg_list));
if (!s->reg_list) {
loge("mpp_alloc jpg_reg_list error");
return -1;
}
memset(s->reg_list, 0, sizeof(jpg_reg_list));
return 0;
}
int __mjpeg_decode_destroy(struct mpp_decoder *ctx)
{
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx *)ctx;
if (s->reg_list)
mpp_free(s->reg_list);
if(s->decoder.fm)
fm_destory(s->decoder.fm);
if(s->decoder.pm)
pm_destroy(s->decoder.pm);
#ifdef COPY_DATA
if(s->sos_buf)
ve_buffer_free(s->ve_buf_handle, s->sos_buf);
#endif
if(s->ve_buf_handle)
ve_buffer_allocator_destroy(s->ve_buf_handle);
ve_close_device();
mpp_free(s);
return 0;
}
int __mjpeg_decode_control(struct mpp_decoder *ctx, int cmd, void *param)
{
// TODO
return 0;
}
int __mjpeg_decode_reset(struct mpp_decoder *ctx)
{
// TODO
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx *)ctx;
fm_decoder_reclaim_all_used_frame(s->decoder.fm);
fm_reset(s->decoder.fm);
pm_reset(s->decoder.pm);
return 0;
}
struct dec_ops mjpeg_decoder = {
.name = "mjpeg",
.init = __mjpeg_decode_init,
.destory = __mjpeg_decode_destroy,
.decode = __mjpeg_decode_frame,
.control = __mjpeg_decode_control,
.reset = __mjpeg_decode_reset,
};
struct mpp_decoder* create_jpeg_decoder()
{
struct mjpeg_dec_ctx *s = (struct mjpeg_dec_ctx*)mpp_alloc(sizeof(struct mjpeg_dec_ctx));
if(s == NULL)
return NULL;
memset(s, 0, sizeof(struct mjpeg_dec_ctx));
s->decoder.ops = &mjpeg_decoder;
return &s->decoder;
}