/* * * Copyright 2015 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "jpegd_parser" #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_soc.h" #include "mpp_debug.h" #include "mpp_bitread.h" #include "mpp_packet_impl.h" #include "jpegd_api.h" #include "jpegd_parser.h" RK_U32 jpegd_debug = 0x0; /* return the 8 bit start code value and update the search state. Return 0 if no start code found */ static RK_U8 jpegd_find_marker(const RK_U8 **pbuf_ptr, const RK_U8 *buf_end) { const RK_U8 *buf_ptr = NULL; RK_U8 val = 0; RK_U8 start_code = 0xff; RK_U32 buf_size = buf_end - *pbuf_ptr + 1; while (*pbuf_ptr < buf_end) { buf_ptr = memchr(*pbuf_ptr, start_code, buf_size); if (!buf_ptr) { mpp_err("Start codec not found!\n"); return 0; } RK_U8 marker = *(buf_ptr + 1); if (marker >= 0xc0 && marker <= 0xfe) { val = *(buf_ptr + 1); jpegd_dbg_marker("find_marker skipped %d bytes\n", buf_ptr - *pbuf_ptr); *pbuf_ptr = buf_ptr; return val; } else { jpegd_dbg_marker("0x%x is not a marker\n", marker); (*pbuf_ptr)++; } } return 0; } static MPP_RET jpegd_find_eoi(const RK_U8 **pbuf_ptr, const RK_U8 *buf_end) { const RK_U8 *buf_ptr = NULL; RK_S32 eoi = 0xffd9; RK_U32 buf_size = buf_end - *pbuf_ptr + 1; buf_ptr = memchr(*pbuf_ptr, eoi, buf_size); if (buf_ptr && (buf_end > buf_ptr)) { return MPP_OK; } return MPP_NOK; } static MPP_RET jpeg_judge_yuv_mode(JpegdCtx *ctx) { MPP_RET ret = MPP_OK; JpegdSyntax *s = ctx->syntax; /* check input format */ if (s->nb_components == 3) { 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) { jpegd_dbg_marker("YCbCr Format: YUV420(2*2:1*1:1*1)\n"); s->yuv_mode = JPEGDEC_YUV420; s->output_fmt = MPP_FMT_YUV420SP; } 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) { jpegd_dbg_marker("YCbCr Format: YUV422(2*1:1*1:1*1)\n"); s->yuv_mode = JPEGDEC_YUV422; s->output_fmt = MPP_FMT_YUV422SP; /* check if fill needed */ if ((s->height & 0xf) && ((s->height & 0xf) <= 8)) { s->fill_bottom = 1; } } 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) { jpegd_dbg_marker("YCbCr Format: YUV440(1*2:1*1:1*1)\n"); s->yuv_mode = JPEGDEC_YUV440; s->output_fmt = MPP_FMT_YUV440SP; /* check if fill needed */ if ((s->width & 0xf) && ((s->width & 0xf) <= 8)) { s->fill_right = 1; } } 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) { jpegd_dbg_marker("YCbCr Format: YUV444(1*1:1*1:1*1)\n"); s->yuv_mode = JPEGDEC_YUV444; s->output_fmt = MPP_FMT_YUV444SP; /* check if fill needed */ if ((s->width & 0xf) && ((s->width & 0xf) <= 8)) { s->fill_right = 1; } if ((s->height & 0xf) && ((s->height & 0xf) <= 8)) { s->fill_bottom = 1; } } 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) { jpegd_dbg_marker("YCbCr Format: YUV411(4*1:1*1:1*1)\n"); s->yuv_mode = JPEGDEC_YUV411; s->output_fmt = MPP_FMT_YUV411SP; /* check if fill needed */ if ((s->height & 0xf) && ((s->height & 0xf) <= 8)) { s->fill_bottom = 1; } } else { mpp_err_f("Unsupported YCbCr Format: (%d*%d:%d*%d:%d*%d)\n", s->h_count[0], s->v_count[0], s->h_count[1], s->v_count[1], s->h_count[2], s->v_count[2]); ret = MPP_ERR_STREAM; } } else if (s->nb_components == 1) { if (s->h_count[0] == s->v_count[0] && s->h_count[0] != 0) { s->yuv_mode = JPEGDEC_YUV400; s->output_fmt = MPP_FMT_YUV400; if (s->output_fmt != ctx->output_fmt) { mpp_err_f("unsupported upsampling(%d*%d)\n", s->output_fmt, ctx->output_fmt); ret = MPP_ERR_STREAM; } /* check if fill needed */ if ((s->width & 0xf) && ((s->width & 0xf) <= 8)) { s->fill_right = 1; } if ((s->height & 0xf) && ((s->height & 0xf) <= 8)) { s->fill_bottom = 1; } } else { mpp_err_f("unsupported format(%d*%d)\n", s->h_count[0], s->v_count[0]); ret = MPP_ERR_STREAM; } } else { mpp_err_f("unsupported format, nb_components=%d\n", s->nb_components); ret = MPP_ERR_STREAM; } return ret; } static inline RK_U16 jpegd_read_len(BitReadCtx_t *gb) { RK_U8 lh, ll; READ_BITS(gb, 8, &lh); READ_BITS(gb, 8, &ll); return (((RK_U16)lh) << 8) | ((RK_U16)ll); __BITREAD_ERR: return 0; } static MPP_RET jpegd_skip_section(JpegdCtx *ctx) { BitReadCtx_t *gb = ctx->bit_ctx; RK_U16 len = 0; if (gb->bytes_left_ < 2) return MPP_ERR_READ_BIT; len = jpegd_read_len(gb); if (len < 2 /* invalid marker */ || (RK_U32)len - 2 > gb->bytes_left_) { /* too short length or bytes is not enough */ return MPP_ERR_READ_BIT; } if (len > 2) SKIP_BITS(gb, (len - 2) * 8); return MPP_OK; __BITREAD_ERR: return MPP_NOK; } static MPP_RET jpegd_decode_dht(JpegdCtx *ctx) { MPP_RET ret = MPP_NOK; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *syntax = ctx->syntax; RK_U32 len, num, value; RK_U32 table_type, table_id; RK_U32 i, code_max; len = jpegd_read_len(gb); len -= 2; /* Huffman Table Length */ if (len > gb->bytes_left_) { mpp_err_f("dht: len %d is too large\n", len); return MPP_ERR_STREAM; } jpegd_dbg_marker("dht: huffman tables length=%d\n", len); while (len > 0) { if (len < MAX_HUFFMAN_CODE_BIT_LENGTH + 1) { mpp_err_f("dht: len %d is too small\n", len); return MPP_ERR_STREAM; } READ_BITS(gb, 4, &table_type); /* 0 - DC; 1 - AC */ if (table_type >= HUFFMAN_TABLE_TYPE_BUTT) { mpp_err_f("table type %d error\n", table_type); return MPP_ERR_STREAM; } READ_BITS(gb, 4, &table_id); if (table_id >= HUFFMAN_TABLE_ID_TWO) { mpp_err_f("table id %d is unsupported for baseline\n", table_id); return MPP_ERR_STREAM; } num = 0; if (table_type == HUFFMAN_TABLE_TYPE_DC) { DcTable *ptr = &(syntax->dc_table[table_id]); for (i = 0; i < MAX_HUFFMAN_CODE_BIT_LENGTH; i++) { READ_BITS(gb, 8, &value); ptr->bits[i] = value; num += value; } ptr->actual_length = num; } else { AcTable *ptr = &(syntax->ac_table[table_id]); for (i = 0; i < MAX_HUFFMAN_CODE_BIT_LENGTH; i++) { READ_BITS(gb, 8, &value); ptr->bits[i] = value; num += value; } ptr->actual_length = num; } len -= 17; if (len < num || (num > MAX_DC_HUFFMAN_TABLE_LENGTH && table_type == HUFFMAN_TABLE_TYPE_DC) || (num > MAX_AC_HUFFMAN_TABLE_LENGTH && table_type == HUFFMAN_TABLE_TYPE_AC)) { mpp_err_f("table type %d, code word number %d error\n", table_type, num); return MPP_ERR_STREAM; } code_max = 0; if (table_type == HUFFMAN_TABLE_TYPE_DC) { DcTable *ptr = &(syntax->dc_table[table_id]); syntax->htbl_entry++; for (i = 0; i < num; i++) { READ_BITS(gb, 8, &value); ptr->vals[i] = value; if (ptr->vals[i] > code_max) code_max = ptr->vals[i]; } } else { AcTable *ptr = &(syntax->ac_table[table_id]); syntax->htbl_entry++; for (i = 0; i < num; i++) { READ_BITS(gb, 8, &value); ptr->vals[i] = value; if (ptr->vals[i] > code_max) code_max = ptr->vals[i]; } } len -= num; jpegd_dbg_marker("dht: type=%d id=%d code_word_num=%d, code_max=%d, len=%d\n", table_type, table_id, num, code_max, len); } ret = MPP_OK; __BITREAD_ERR: if (ret != MPP_OK) jpegd_dbg_syntax("bit read error!\n"); return ret; } /* quantize tables */ static MPP_RET jpegd_decode_dqt(JpegdCtx *ctx) { MPP_RET ret = MPP_NOK; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *syntax = ctx->syntax; RK_U32 len; int index, i; RK_U16 value; len = jpegd_read_len(gb); len -= 2; /* quantize tables length */ if (len > gb->bytes_left_) { mpp_err_f("dqt: len %d is too large\n", len); return MPP_ERR_STREAM; } while (len >= 65) { RK_U16 pr; READ_BITS(gb, 4, &pr); if (pr > 1) { mpp_err_f("dqt: invalid precision\n"); return MPP_ERR_STREAM; } READ_BITS(gb, 4, &index); if (index >= 4) { mpp_err_f("dqt: invalid quantize tables ID\n"); return -1; } jpegd_dbg_marker("quantize tables ID=%d\n", index); /* read quant table */ for (i = 0; i < QUANTIZE_TABLE_LENGTH; i++) { READ_BITS(gb, pr ? 16 : 8, &value); syntax->quant_matrixes[index][i] = value; } syntax->qtbl_entry++; if (syntax->qtbl_entry > MAX_COMPONENTS) mpp_err_f("%d entries qtbl is not supported\n", syntax->qtbl_entry); if (jpegd_debug & JPEGD_DBG_TABLE) { /* debug code */ mpp_log("******Start to print quantize table %d******\n", index); for (i = 0; i < QUANTIZE_TABLE_LENGTH; i += 8) { mpp_log("%2d~%2d 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", i, i + 7, syntax->quant_matrixes[index][i + 0], syntax->quant_matrixes[index][i + 1], syntax->quant_matrixes[index][i + 2], syntax->quant_matrixes[index][i + 3], syntax->quant_matrixes[index][i + 4], syntax->quant_matrixes[index][i + 5], syntax->quant_matrixes[index][i + 7], syntax->quant_matrixes[index][i + 7]); } mpp_log("******Quantize table %d End******\n", index); } // XXX FIXME fine-tune, and perhaps add dc too syntax->qscale[index] = MPP_MAX(syntax->quant_matrixes[index][1], syntax->quant_matrixes[index][8]) >> 1; jpegd_dbg_marker("qscale[%d]: %d\n", index, syntax->qscale[index]); len -= 1 + 64 * (1 + pr); } ret = MPP_OK; __BITREAD_ERR: if (ret != MPP_OK) jpegd_dbg_syntax("bit read error!\n"); return ret; } static MPP_RET jpegd_decode_sof(JpegdCtx *ctx) { MPP_RET ret = MPP_NOK; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *syntax = ctx->syntax; RK_U32 len, bits, i; RK_U32 width, height; RK_U32 nb_components, value; len = jpegd_read_len(gb); if (len > gb->bytes_left_) { mpp_err_f("len %d is too large\n", len); return MPP_ERR_STREAM; } READ_BITS(gb, 8, &bits); if (bits > 16 || bits < 1) { /* usually bits is 8 */ mpp_err_f("bits %d is invalid\n", bits); return MPP_ERR_STREAM; } syntax->sample_precision = bits; READ_BITS(gb, 16, &height); READ_BITS(gb, 16, &width); syntax->height = height; syntax->width = width; syntax->hor_stride = MPP_ALIGN(width, 16); syntax->ver_stride = MPP_ALIGN(height, 16); jpegd_dbg_marker("sof0: picture: %dx%d, stride: %dx%d\n", width, height, syntax->hor_stride, syntax->ver_stride); READ_BITS(gb, 8 , &nb_components); if ((nb_components != 1) && (nb_components != MAX_COMPONENTS)) { mpp_err_f("components number %d error\n", nb_components); return MPP_ERR_STREAM; } if (len != (8 + (3 * nb_components))) mpp_err_f("decode_sof0: error, len(%d) mismatch nb_components(%d)\n", len, nb_components); syntax->nb_components = nb_components; syntax->h_max = 1; syntax->v_max = 1; for (i = 0; i < nb_components; i++) { /* component id */ READ_BITS(gb, 8 , &value); syntax->component_id[i] = value - 1; /* start from zero */ READ_BITS(gb, 4, &value); syntax->h_count[i] = value; /* Horizontal sampling factor */ READ_BITS(gb, 4, &value); syntax->v_count[i] = value; /* Vertical sampling factor */ if (!syntax->h_count[i] || !syntax->v_count[i]) { mpp_err_f("Invalid sampling factor in component %d %d:%d\n", i, syntax->h_count[i], syntax->v_count[i]); return MPP_ERR_STREAM; } /* compute hmax and vmax (only used in interleaved case) */ if (syntax->h_count[i] > syntax->h_max) syntax->h_max = syntax->h_count[i]; if (syntax->v_count[i] > syntax->v_max) syntax->v_max = syntax->v_count[i]; /* Quantization table destination selector */ READ_BITS(gb, 8, &value); syntax->quant_index[i] = value; if (syntax->quant_index[i] >= QUANTIZE_TABLE_ID_BUTT) { mpp_err_f("quant_index %d is invalid\n", syntax->quant_index[i]); return MPP_ERR_STREAM; } jpegd_dbg_marker("component %d %d:%d id: %d quant_id:%d\n", i, syntax->h_count[i], syntax->v_count[i], syntax->component_id[i], syntax->quant_index[i]); } /* judge yuv mode from sampling factor */ ret = jpeg_judge_yuv_mode(ctx); __BITREAD_ERR: if (ret != MPP_OK) jpegd_dbg_syntax("bit read error!\n"); return ret; } static MPP_RET jpegd_decode_sos(JpegdCtx *ctx) { MPP_RET ret = MPP_NOK; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *syntax = ctx->syntax; RK_U32 len, nb_components, value; RK_U32 id, i, index; len = jpegd_read_len(gb); if (len > gb->bytes_left_) { mpp_err_f("len %d is too large\n", len); return MPP_ERR_STREAM; } syntax->sos_len = len; /* used for calculating stream offset */ READ_BITS(gb, 8, &nb_components); if ((nb_components != 1) && (nb_components != MAX_COMPONENTS)) { mpp_err_f("decode_sos: nb_components %d unsupported\n", nb_components); return MPP_ERR_STREAM; } if (len != 6 + 2 * nb_components) { mpp_err_f("decode_sos: invalid len (%d), nb_components:%d\n", len, nb_components); return MPP_ERR_STREAM; } syntax->qtable_cnt = nb_components; for (i = 0; i < nb_components; i++) { READ_BITS(gb, 8, &value); id = value - 1; jpegd_dbg_marker("sos component: %d\n", id); /* find component index */ for (index = 0; index < syntax->nb_components; index++) if (id == syntax->component_id[index]) break; if (index == syntax->nb_components) { mpp_err_f("decode_sos: index(%d) out of components\n", index); return MPP_ERR_STREAM; } READ_BITS(gb, 4, &value); syntax->dc_index[i] = value; READ_BITS(gb, 4, &value); syntax->ac_index[i] = value; jpegd_dbg_marker("component:%d, dc_index:%d, ac_index:%d\n", id, syntax->dc_index[i], syntax->ac_index[i]); if (syntax->dc_index[i] > HUFFMAN_TABLE_ID_ONE || syntax->ac_index[i] > HUFFMAN_TABLE_ID_ONE) { /* for baseline */ mpp_err_f("Huffman table id error\n"); return MPP_ERR_STREAM; } } READ_BITS(gb, 8, &value); syntax->scan_start = value; READ_BITS(gb, 8, &value); syntax->scan_end = value; READ_BITS(gb, 4, &value); syntax->prev_shift = value; READ_BITS(gb, 4, &value); syntax->point_transform = value; if (syntax->scan_start != 0 || syntax->scan_end != 0x3F || syntax->prev_shift != 0 || syntax->point_transform != 0) { /* for baseline */ mpp_err_f("unsupported sos parameter: scan_start:%d,\n" "\t\tscan_end:%d, prev_shift:%d, point_transform:%d\n", syntax->scan_start, syntax->scan_end, syntax->prev_shift, syntax->point_transform); return MPP_ERR_STREAM; } ret = MPP_OK; __BITREAD_ERR: if (ret != MPP_OK) jpegd_dbg_syntax("bit read error!\n"); return ret; } static MPP_RET jpegd_decode_dri(JpegdCtx *ctx) { MPP_RET ret = MPP_NOK; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *s = ctx->syntax; RK_U32 len; len = jpegd_read_len(gb); if (len != DRI_MARKER_LENGTH) { mpp_err_f("DRI length %d error\n", len); return MPP_ERR_STREAM; } READ_BITS(gb, 16, &s->restart_interval); jpegd_dbg_marker("restart interval: %d\n", s->restart_interval); ret = MPP_OK; __BITREAD_ERR: if (ret != MPP_OK) jpegd_dbg_syntax("bit read error!\n"); return ret; } static MPP_RET jpegd_setup_default_dht(JpegdCtx *ctx) { jpegd_dbg_func("enter\n"); JpegdSyntax *s = ctx->syntax; AcTable *ac_ptr = NULL; DcTable *dc_ptr = NULL; const RK_U8 *bits_tmp = NULL; const RK_U8 *val_tmp = NULL; RK_U32 tmp_len = 0; RK_U32 i, k; /* Set up the standard Huffman tables (cf. JPEG standard section K.3) * IMPORTANT: these are only valid for 8-bit data precision! */ static const RK_U8 bits_dc_luminance[MAX_HUFFMAN_CODE_BIT_LENGTH] = { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; /* luminance and chrominance all use it */ static const RK_U8 val_dc[MAX_DC_HUFFMAN_TABLE_LENGTH] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; static const RK_U8 bits_dc_chrominance[MAX_HUFFMAN_CODE_BIT_LENGTH] = { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; static const RK_U8 bits_ac_luminance[MAX_HUFFMAN_CODE_BIT_LENGTH] = { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; /* 162 Bytes */ static const RK_U8 val_ac_luminance[MAX_AC_HUFFMAN_TABLE_LENGTH] = { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; static const RK_U8 bits_ac_chrominance[MAX_HUFFMAN_CODE_BIT_LENGTH] = { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; static const RK_U8 val_ac_chrominance[MAX_AC_HUFFMAN_TABLE_LENGTH] = { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; const RK_U8 *bits_table[4] = { bits_ac_luminance, bits_ac_chrominance, bits_dc_luminance, bits_dc_chrominance }; const RK_U8 *val_table[4] = { val_ac_luminance, val_ac_chrominance, val_dc, val_dc }; /* AC Table */ for (k = 0; k < 2; k++) { ac_ptr = &(s->ac_table[k]); bits_tmp = bits_table[k]; val_tmp = val_table[k]; tmp_len = 0; for (i = 0; i < MAX_HUFFMAN_CODE_BIT_LENGTH; i++) { /* read in the values of list BITS */ tmp_len += ac_ptr->bits[i] = bits_tmp[i]; } ac_ptr->actual_length = tmp_len; /* set the table length */ for (i = 0; i < tmp_len; i++) { /* read in the HUFFVALs */ ac_ptr->vals[i] = val_tmp[i]; } } /* DC Table */ for (k = 0; k < 2; k++) { dc_ptr = &(s->dc_table[k]); bits_tmp = bits_table[k + 2]; val_tmp = val_table[k + 2]; tmp_len = 0; for (i = 0; i < MAX_HUFFMAN_CODE_BIT_LENGTH; i++) { /* read in the values of list BITS */ tmp_len += dc_ptr->bits[i] = bits_tmp[i]; } dc_ptr->actual_length = tmp_len; /* set the table length */ for (i = 0; i < tmp_len; i++) { /* read in the HUFFVALs */ dc_ptr->vals[i] = val_tmp[i]; } } jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_decode_frame(JpegdCtx *ctx) { jpegd_dbg_func("enter\n"); MPP_RET ret = MPP_OK; const RK_U8 *const buf = ctx->buffer; RK_U32 buf_size = ctx->buf_size; BitReadCtx_t *gb = ctx->bit_ctx; JpegdSyntax *syntax = ctx->syntax; RK_S32 start_code = 0xffd8; const RK_U8 *buf_ptr = buf; const RK_U8 *const buf_end = buf + buf_size; syntax->htbl_entry = 0; syntax->qtbl_entry = 0; if (buf_size < 8 || !memchr(buf_ptr, start_code, 8)) { // not jpeg ret = MPP_ERR_STREAM; goto fail; } while (buf_ptr < buf_end) { /* find start marker */ start_code = jpegd_find_marker(&buf_ptr, buf_end); if (start_code <= 0) { jpegd_dbg_marker("start code not found\n"); break; } else { buf_ptr += 2; } jpegd_dbg_marker("marker = 0x%x, avail_size_in_buf = %d\n", start_code, buf_end - buf_ptr); ctx->start_code = start_code; /* setup bit read context */ mpp_set_bitread_ctx(gb, (RK_U8 *)buf_ptr, buf_end - buf_ptr); /* process markers */ if (start_code >= RST0 && start_code <= RST7) { /* nothing to do with RSTn */ jpegd_dbg_syntax("restart marker: %d\n", start_code & 0x0f); } switch (start_code) { case SOI: /* nothing to do on SOI */ syntax->dht_found = 0; syntax->eoi_found = 0; syntax->qtable_cnt = 0; syntax->qtbl_entry = 0; syntax->htbl_entry = 0; break; case DHT: if ((ret = jpegd_decode_dht(ctx)) != MPP_OK) { mpp_err_f("huffman table decode error\n"); goto fail; } syntax->dht_found = 1; break; case DQT: if ((ret = jpegd_decode_dqt(ctx)) != MPP_OK) { mpp_err_f("quantize tables decode error\n"); goto fail; } break; case SOF0: if ((ret = jpegd_decode_sof(ctx)) != MPP_OK) { mpp_err_f("sof0 decode error\n"); goto fail; } if (ctx->syntax->sample_precision != 8) { mpp_err_f("Illegal sample precision %d.\n\ For baseline, it should be 8\n", ctx->syntax->sample_precision); goto fail; } break; case EOI: syntax->eoi_found = 1; jpegd_dbg_marker("still exists %d bytes behind EOI marker\n", buf_end - buf_ptr); goto done; break; case SOS: if ((ret = jpegd_decode_sos(ctx)) != MPP_OK) { mpp_err_f("sos decode error\n"); goto fail; } /* stream behind SOS is decoded by hardware */ syntax->strm_offset = buf_ptr - buf + syntax->sos_len; syntax->cur_pos = (RK_U8 *)buf + syntax->strm_offset; syntax->pkt_len = ctx->buf_size; jpegd_dbg_marker("This packet owns %d bytes,\n" "\t\thas been decoded %d bytes by software\n" "\t\tbuf_ptr:%p, buf:%p, sos_len:%d\n" "\t\thardware start address:%p", syntax->pkt_len, syntax->strm_offset, buf_ptr, buf, syntax->sos_len, syntax->cur_pos); if (syntax->strm_offset >= ctx->buf_size) { mpp_err_f("stream offset %d is larger than buffer size %d\n", syntax->strm_offset, ctx->buf_size); ret = MPP_ERR_UNKNOW; goto fail; } if ((syntax->strm_offset + 2) < ctx->buf_size && buf_ptr[syntax->sos_len] == 0xff && buf_ptr[syntax->sos_len + 1] == 0xd8) { jpegd_dbg_marker("Encontered SOI again, parse again!\n"); break; } if (!ctx->scan_all_marker) { jpegd_dbg_marker("just scan parts of markers!\n"); goto done; } break; case DRI: if ((ret = jpegd_decode_dri(ctx)) != MPP_OK) { mpp_err_f("dri decode error\n"); goto fail; } break; default: jpegd_dbg_marker("unhandled coding type(0x%x) in switch..case..\n", start_code); if ((ret = jpegd_skip_section(ctx)) != MPP_OK) { jpegd_dbg_marker("Fail to skip section 0xFF%02x!\n", start_code); goto fail; } break; } buf_ptr = ctx->bit_ctx->data_; } done: if (!syntax->dht_found) { jpegd_dbg_marker("sorry, DHT is not found!\n"); jpegd_setup_default_dht(ctx); syntax->htbl_entry = syntax->nb_components; } else { syntax->htbl_entry /= 2; } if (!syntax->eoi_found) { if (MPP_OK != jpegd_find_eoi(&buf_ptr, buf_end)) { mpp_err_f("EOI marker not found!\n"); ret = MPP_ERR_STREAM; } } jpegd_dbg_func("exit\n"); return ret; fail: ret = MPP_ERR_STREAM; jpegd_dbg_func("exit\n"); return ret; } static MPP_RET jpegd_split_frame(RK_U8 *src, RK_U32 src_size, RK_U8 *dst, RK_U32 *dst_size) { jpegd_dbg_func("enter\n"); MPP_RET ret = MPP_OK; if (NULL == src || NULL == dst || src_size <= 0) { mpp_err_f("NULL pointer or wrong src_size(%d)", src_size); return MPP_ERR_NULL_PTR; } RK_U8 *tmp; RK_U32 str_size = (src_size + 255) & (~255); if (src[6] == 0x41 && src[7] == 0x56 && src[8] == 0x49 && src[9] == 0x31) { //distinguish 310 from 210 camera RK_U32 i; RK_U32 copy_len = 0; tmp = src; jpegd_dbg_parser("distinguish 310 from 210 camera"); for (i = 0; i < src_size - 4; i++) { if (tmp[i] == 0xff) { if (tmp[i + 1] == 0x00 && tmp[i + 2] == 0xff && ((tmp[i + 3] & 0xf0) == 0xd0)) i += 2; } *dst++ = tmp[i]; copy_len++; } for (; i < src_size; i++) { *dst++ = tmp[i]; copy_len++; } if (copy_len < src_size) memset(dst, 0, src_size - copy_len); *dst_size = copy_len; } else { memcpy(dst, src, src_size); memset(dst + src_size, 0, str_size - src_size); *dst_size = src_size; } jpegd_dbg_func("exit\n"); return ret; } static MPP_RET jpegd_prepare(void *ctx, MppPacket pkt, HalDecTask *task) { jpegd_dbg_func("enter\n"); MPP_RET ret = MPP_OK; JpegdCtx *JpegCtx = (JpegdCtx *)ctx; if (!JpegCtx->copy_flag) { /* no need to copy stream, handle packet from upper application directly*/ JpegCtx->input_packet = pkt; } MppPacket input_packet = JpegCtx->input_packet; RK_U32 copy_length = 0; void *base = mpp_packet_get_pos(pkt); RK_U8 *pos = base; RK_U32 pkt_length = (RK_U32)mpp_packet_get_length(pkt); RK_U32 eos = (pkt_length) ? (mpp_packet_get_eos(pkt)) : (1); JpegCtx->pts = mpp_packet_get_pts(pkt); task->valid = 0; task->flags.eos = eos; JpegCtx->eos = eos; jpegd_dbg_parser("pkt_length %d eos %d\n", pkt_length, eos); if (!pkt_length) { jpegd_dbg_parser("it is end of stream."); return ret; } if (pkt_length > JpegCtx->bufferSize) { jpegd_dbg_parser("Huge Frame(%d Bytes)! bufferSize:%d", pkt_length, JpegCtx->bufferSize); mpp_free(JpegCtx->recv_buffer); JpegCtx->recv_buffer = NULL; JpegCtx->recv_buffer = mpp_calloc(RK_U8, pkt_length + 1024); if (NULL == JpegCtx->recv_buffer) { mpp_err_f("no memory!"); return MPP_ERR_NOMEM; } JpegCtx->bufferSize = pkt_length + 1024; } if (JpegCtx->copy_flag) jpegd_split_frame(base, pkt_length, JpegCtx->recv_buffer, ©_length); pos += pkt_length; mpp_packet_set_pos(pkt, pos); if (copy_length != pkt_length) { jpegd_dbg_parser("packet prepare, pkt_length:%d, copy_length:%d\n", pkt_length, copy_length); } /* debug information */ if (jpegd_debug & JPEGD_DBG_IO) { static FILE *jpg_file; static char name[32]; snprintf(name, sizeof(name) - 1, "/data/input%02d.jpg", JpegCtx->input_jpeg_count); jpg_file = fopen(name, "wb+"); if (jpg_file) { jpegd_dbg_io("frame_%02d input jpeg(%d Bytes) saving to %s\n", JpegCtx->input_jpeg_count, pkt_length, name); fwrite(base, pkt_length, 1, jpg_file); fclose(jpg_file); JpegCtx->input_jpeg_count++; } } if (JpegCtx->copy_flag) { mpp_packet_set_data(input_packet, JpegCtx->recv_buffer); mpp_packet_set_size(input_packet, pkt_length); mpp_packet_set_length(input_packet, pkt_length); memcpy(base, JpegCtx->recv_buffer, pkt_length); } JpegCtx->streamLength = pkt_length; task->input_packet = input_packet; task->valid = 1; jpegd_dbg_parser("input_packet:%p, recv_buffer:%p, pkt_length:%d", input_packet, JpegCtx->recv_buffer, pkt_length); jpegd_dbg_func("exit\n"); return ret; } static MPP_RET jpegd_allocate_frame(JpegdCtx *ctx) { jpegd_dbg_func("enter\n"); JpegdSyntax *s = ctx->syntax; MppBufSlots slots = ctx->frame_slots; MppFrame output = ctx->output_frame; RK_S32 slot_idx = ctx->frame_slot_index; if (slot_idx == -1) { RK_U32 value; MppFrameFormat fmt = MPP_FMT_YUV420SP; switch (s->yuv_mode) { case JPEGDEC_YUV420: { fmt = MPP_FMT_YUV420SP; } break; case JPEGDEC_YUV422: { fmt = MPP_FMT_YUV422SP; } break; case JPEGDEC_YUV444: { fmt = MPP_FMT_YUV444SP; } break; case JPEGDEC_YUV400: { fmt = MPP_FMT_YUV400; } break; default : { fmt = MPP_FMT_YUV420SP; } break; } mpp_frame_set_fmt(output, fmt); mpp_frame_set_width(output, s->width); mpp_frame_set_height(output, s->height); mpp_frame_set_hor_stride(output, s->hor_stride); mpp_frame_set_ver_stride(output, s->ver_stride); mpp_frame_set_pts(output, ctx->pts); if (ctx->eos) mpp_frame_set_eos(output, 1); mpp_buf_slot_get_unused(slots, &slot_idx); ctx->frame_slot_index = slot_idx; jpegd_dbg_parser("frame_slot_index:%d\n", slot_idx); value = 2; mpp_slots_set_prop(slots, SLOTS_NUMERATOR, &value); value = 1; mpp_slots_set_prop(slots, SLOTS_DENOMINATOR, &value); if (mpp_buf_slot_set_prop(slots, slot_idx, SLOT_FRAME, output)) return MPP_ERR_VALUE; mpp_buf_slot_set_flag(slots, slot_idx, SLOT_CODEC_USE); mpp_buf_slot_set_flag(slots, slot_idx, SLOT_HAL_OUTPUT); } jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_update_frame(JpegdCtx *ctx) { jpegd_dbg_func("enter\n"); mpp_buf_slot_clr_flag(ctx->frame_slots, ctx->frame_slot_index, SLOT_CODEC_USE); ctx->frame_slot_index = -1; jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_parse(void *ctx, HalDecTask *task) { jpegd_dbg_func("enter\n"); MPP_RET ret = MPP_OK; JpegdCtx *JpegCtx = (JpegdCtx *)ctx; task->valid = 0; JpegCtx->buffer = (RK_U8 *)mpp_packet_get_data(JpegCtx->input_packet); JpegCtx->buf_size = (RK_U32)mpp_packet_get_size(JpegCtx->input_packet); memset(JpegCtx->syntax, 0, sizeof(JpegdSyntax)); ret = jpegd_decode_frame(JpegCtx); if (MPP_OK == ret) { if (jpegd_allocate_frame(JpegCtx)) return MPP_ERR_VALUE; task->syntax.data = (void *)JpegCtx->syntax; task->syntax.number = sizeof(JpegdSyntax); task->output = JpegCtx->frame_slot_index; task->valid = 1; jpegd_update_frame(JpegCtx); } jpegd_dbg_func("exit\n"); return ret; } static MPP_RET jpegd_deinit(void *ctx) { jpegd_dbg_func("enter\n"); JpegdCtx *JpegCtx = (JpegdCtx *)ctx; if (JpegCtx->recv_buffer) { mpp_free(JpegCtx->recv_buffer); JpegCtx->recv_buffer = NULL; } if (JpegCtx->output_frame) { mpp_frame_deinit(&JpegCtx->output_frame); } if (JpegCtx->copy_flag) { if (JpegCtx->input_packet) { mpp_packet_deinit(&JpegCtx->input_packet); } } else { JpegCtx->input_packet = NULL; } if (JpegCtx->bit_ctx) { mpp_free(JpegCtx->bit_ctx); JpegCtx->bit_ctx = NULL; } if (JpegCtx->syntax) { mpp_free(JpegCtx->syntax); JpegCtx->syntax = NULL; } JpegCtx->output_fmt = MPP_FMT_YUV420SP; JpegCtx->pts = 0; JpegCtx->eos = 0; JpegCtx->input_jpeg_count = 0; jpegd_dbg_func("exit\n"); return 0; } static MPP_RET jpegd_init(void *ctx, ParserCfg *parser_cfg) { jpegd_dbg_func("enter\n"); JpegdCtx *JpegCtx = (JpegdCtx *)ctx; if (NULL == JpegCtx) { JpegCtx = (JpegdCtx *)mpp_calloc(JpegdCtx, 1); if (NULL == JpegCtx) { mpp_err_f("NULL pointer"); return MPP_ERR_NULL_PTR; } } mpp_env_get_u32("jpegd_debug", &jpegd_debug, 0); // mpp only support baseline JpegCtx->scan_all_marker = 0; const char* soc_name = NULL; soc_name = mpp_get_soc_name(); if (soc_name && (strstr(soc_name, "1108") || strstr(soc_name, "356"))) { /* * no need to copy stream when decoding jpeg; * just scan parts of markers to reduce CPU's occupancy */ JpegCtx->copy_flag = 0; } else { // TODO: do not copy if input provides valid fd and virtual ptr JpegCtx->copy_flag = 1; } JpegCtx->frame_slots = parser_cfg->frame_slots; JpegCtx->packet_slots = parser_cfg->packet_slots; JpegCtx->frame_slot_index = -1; mpp_buf_slot_setup(JpegCtx->frame_slots, 1); JpegCtx->recv_buffer = mpp_calloc(RK_U8, JPEGD_STREAM_BUFF_SIZE); if (NULL == JpegCtx->recv_buffer) { mpp_err_f("no memory!"); return MPP_ERR_NOMEM; } JpegCtx->bufferSize = JPEGD_STREAM_BUFF_SIZE; if (JpegCtx->copy_flag) { mpp_packet_init(&JpegCtx->input_packet, JpegCtx->recv_buffer, JPEGD_STREAM_BUFF_SIZE); } else { JpegCtx->input_packet = NULL; } mpp_frame_init(&JpegCtx->output_frame); if (!JpegCtx->output_frame) { mpp_err_f("Failed to allocate output frame buffer"); return MPP_ERR_NOMEM; } JpegCtx->bit_ctx = mpp_calloc(BitReadCtx_t, 1); if (JpegCtx->bit_ctx == NULL) { mpp_err_f("allocate bit_ctx failed\n"); return MPP_ERR_MALLOC; } JpegCtx->syntax = mpp_calloc(JpegdSyntax, 1); if (JpegCtx->syntax == NULL) { mpp_err_f("allocate syntax failed\n"); return MPP_ERR_MALLOC; } memset(JpegCtx->syntax, 0, sizeof(JpegdSyntax)); JpegCtx->output_fmt = MPP_FMT_YUV420SP; JpegCtx->pts = 0; JpegCtx->eos = 0; JpegCtx->input_jpeg_count = 0; jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_flush(void *ctx) { jpegd_dbg_func("enter\n"); JpegdCtx *JpegCtx = (JpegdCtx *)ctx; (void)JpegCtx; jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_reset(void *ctx) { jpegd_dbg_func("enter\n"); JpegdCtx *JpegCtx = (JpegdCtx *)ctx; (void)JpegCtx; jpegd_dbg_func("exit\n"); return MPP_OK; } static MPP_RET jpegd_control(void *ctx, MpiCmd cmd, void *param) { jpegd_dbg_func("enter\n"); MPP_RET ret = MPP_OK; JpegdCtx *JpegCtx = (JpegdCtx *)ctx; if (NULL == JpegCtx) { mpp_err_f("NULL pointer"); return MPP_ERR_NULL_PTR; } switch (cmd) { case MPP_DEC_SET_OUTPUT_FORMAT: { JpegCtx->output_fmt = *((RK_U32 *)param); jpegd_dbg_parser("output_format:%d\n", JpegCtx->output_fmt); } break; default : ret = MPP_NOK; } jpegd_dbg_func("exit\n"); return ret; } static MPP_RET jpegd_callback(void *ctx, void *err_info) { jpegd_dbg_func("enter\n"); (void) ctx; (void) err_info; jpegd_dbg_func("exit\n"); return MPP_OK; } const ParserApi api_jpegd_parser = { .name = "jpegd_parse", .coding = MPP_VIDEO_CodingMJPEG, .ctx_size = sizeof(JpegdCtx), .flag = 0, .init = jpegd_init, .deinit = jpegd_deinit, .prepare = jpegd_prepare, .parse = jpegd_parse, .reset = jpegd_reset, .flush = jpegd_flush, .control = jpegd_control, .callback = jpegd_callback, };