/* * 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 "jpege_api_v2" #include #include "mpp_err.h" #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_common.h" #include "mpp_2str.h" #include "mpp_enc_cfg.h" #include "mpp_bitwrite.h" #include "mpp_soc.h" #include "jpege_debug.h" #include "jpege_api_v2.h" #include "jpege_syntax.h" typedef struct { MppEncCfgSet *cfg; JpegeSyntax syntax; } JpegeCtx; /* * from RFC435 spec. */ RK_U32 jpege_debug = 0; static MPP_RET jpege_init_v2(void *ctx, EncImplCfg *cfg) { JpegeCtx *p = (JpegeCtx *)ctx; mpp_env_get_u32("jpege_debug", &jpege_debug, 0); jpege_dbg_func("enter ctx %p\n", ctx); p->cfg = cfg->cfg; mpp_assert(cfg->coding = MPP_VIDEO_CodingMJPEG); { /* init default rc config */ MppEncRcCfg *rc = &p->cfg->rc; MppEncJpegCfg *jpeg_cfg = &p->cfg->jpeg; rc->fps_in_flex = 0; rc->fps_in_num = 30; rc->fps_in_denom = 1; rc->fps_out_flex = 0; rc->fps_out_num = 30; rc->fps_out_denom = 1; rc->rc_mode = MPP_ENC_RC_MODE_FIXQP; /* set quant to invalid value */ jpeg_cfg->quant = -1; jpeg_cfg->quant_ext = -1; } jpege_dbg_func("leave ctx %p\n", ctx); return MPP_OK; } static MPP_RET jpege_deinit_v2(void *ctx) { jpege_dbg_func("enter ctx %p\n", ctx); jpege_dbg_func("leave ctx %p\n", ctx); return MPP_OK; } static MPP_RET jpege_proc_cfg(void *ctx, MpiCmd cmd, void *param) { MPP_RET ret = MPP_OK; jpege_dbg_func("enter ctx %p cmd %x param %p\n", ctx, cmd, param); switch (cmd) { case MPP_ENC_SET_CFG : case MPP_ENC_SET_IDR_FRAME : case MPP_ENC_SET_OSD_PLT_CFG : case MPP_ENC_SET_OSD_DATA_CFG : case MPP_ENC_GET_SEI_DATA : case MPP_ENC_SET_SEI_CFG : { } break; default: mpp_err_f("No correspond cmd(%08x) found, and can not config!", cmd); ret = MPP_NOK; break; } jpege_dbg_func("leave ret %d\n", ret); return ret; } static MPP_RET jpege_start(void *ctx, HalEncTask *task) { JpegeCtx *p = (JpegeCtx *)ctx; JpegeSyntax syntax = p->syntax; MppPacket pkt = task->packet; RK_U8 *ptr = mpp_packet_get_pos(pkt); size_t buf_size = mpp_packet_get_size(pkt); RK_S32 size = 0; MppWriteCtx bit_ctx; MppWriteCtx *bits = &bit_ctx; mpp_writer_init(bits, ptr, buf_size); /* add SOI and APP0 data */ /* SOI */ mpp_writer_put_raw_bits(bits, 0xFFD8, 16); /* APP0 */ mpp_writer_put_raw_bits(bits, 0xFFE0, 16); /* length */ mpp_writer_put_raw_bits(bits, 0x0010, 16); /* "JFIF" ID */ /* Ident1 */ mpp_writer_put_raw_bits(bits, 0x4A46, 16); /* Ident2 */ mpp_writer_put_raw_bits(bits, 0x4946, 16); /* Ident3 */ mpp_writer_put_raw_bits(bits, 0x00, 8); /* Version */ mpp_writer_put_raw_bits(bits, 0x0102, 16); if (syntax.density_x && syntax.density_y) { /* Units */ mpp_writer_put_raw_bits(bits, syntax.units_type, 8); /* Xdensity */ mpp_writer_put_raw_bits(bits, syntax.density_x, 16); /* Ydensity */ mpp_writer_put_raw_bits(bits, syntax.density_y, 16); } else { /* Units */ mpp_writer_put_raw_bits(bits, 0, 8); /* Xdensity */ mpp_writer_put_raw_bits(bits, 0, 8); mpp_writer_put_raw_bits(bits, 1, 8); /* Ydensity */ mpp_writer_put_raw_bits(bits, 1, 16); } /* XThumbnail */ mpp_writer_put_raw_bits(bits, 0x00, 8); /* YThumbnail */ mpp_writer_put_raw_bits(bits, 0x00, 8); /* Do NOT write thumbnail */ size = mpp_writer_bytes(bits); mpp_packet_set_length(pkt, size); task->length += size; return MPP_OK; } static MPP_RET init_jpeg_component_info(JpegeSyntax *syntax) { MPP_RET ret = MPP_OK; JPEGCompInfo *comp_info = (JPEGCompInfo *)syntax->comp_info; jpege_dbg_input("Chroma format %d\n", syntax->format_out); if (syntax->format_out == MPP_CHROMA_UNSPECIFIED) syntax->format_out = MPP_CHROMA_420; memset(comp_info, 0, sizeof(JPEGCompInfo) * MAX_NUMBER_OF_COMPONENTS); switch (syntax->format_out) { case MPP_CHROMA_400: syntax->nb_components = 1; comp_info[0].val = 1 | 1 << 8 | 1 << 16; break; case MPP_CHROMA_420: syntax->nb_components = 3; comp_info[0].val = 1 | 2 << 8 | 2 << 16; comp_info[1].val = 2 | 1 << 8 | 1 << 16 | 1 << 24; comp_info[2].val = 3 | 1 << 8 | 1 << 16 | 1 << 24; break; case MPP_CHROMA_422: syntax->nb_components = 3; comp_info[0].val = 1 | 2 << 8 | 1 << 16; comp_info[1].val = 2 | 1 << 8 | 1 << 16 | 1 << 24; comp_info[2].val = 3 | 1 << 8 | 1 << 16 | 1 << 24; break; case MPP_CHROMA_444: syntax->nb_components = 3; comp_info[0].val = 1 | 1 << 8 | 1 << 16; comp_info[1].val = 2 | 1 << 8 | 1 << 16 | 1 << 24; comp_info[2].val = 3 | 1 << 8 | 1 << 16 | 1 << 24; break; default: syntax->nb_components = 1; comp_info[0].val = 1 | 1 << 8 | 1 << 16; mpp_err("Unsupported chroma format %d\n", syntax->format_out); ret = MPP_ERR_VALUE; break; } syntax->mcu_width = comp_info[0].h_sample_factor * DCT_SIZE; syntax->mcu_height = comp_info[0].v_sample_factor * DCT_SIZE; syntax->mcu_hor_cnt = (syntax->width + syntax->mcu_width - 1) / syntax->mcu_width; syntax->mcu_ver_cnt = (syntax->height + syntax->mcu_height - 1) / syntax->mcu_height; syntax->mcu_cnt = syntax->mcu_hor_cnt * syntax->mcu_ver_cnt; return ret; } static MPP_RET jpege_proc_hal(void *ctx, HalEncTask *task) { JpegeCtx *p = (JpegeCtx *)ctx; MppFrame frame = task->frame; JpegeSyntax *syntax = &p->syntax; MppEncCfgSet *cfg = p->cfg; MppEncPrepCfg *prep = &cfg->prep; MppEncJpegCfg *jpeg = &cfg->jpeg; MppEncSliceSplit *split = &cfg->split; jpege_dbg_func("enter ctx %p\n", ctx); syntax->width = prep->width; syntax->height = prep->height; syntax->hor_stride = prep->hor_stride; syntax->ver_stride = prep->ver_stride; syntax->format = prep->format; syntax->format_out = prep->format_out; syntax->color = prep->color; syntax->rotation = prep->rotation; syntax->mirroring = prep->mirroring; syntax->offset_x = mpp_frame_get_offset_x(frame); syntax->offset_y = mpp_frame_get_offset_y(frame); syntax->q_mode = jpeg->q_mode; syntax->quant = jpeg->quant; syntax->q_factor = jpeg->q_factor; syntax->qf_min = jpeg->qf_min; syntax->qf_max = jpeg->qf_max; syntax->qtable_y = jpeg->qtable_y; syntax->qtable_u = jpeg->qtable_u; syntax->qtable_v = jpeg->qtable_v; syntax->part_rows = 0; syntax->restart_ri = 0; syntax->low_delay = 0; init_jpeg_component_info(syntax); if (split->split_mode) { RK_U32 mb_w = syntax->mcu_hor_cnt; RK_U32 mb_h = syntax->mcu_ver_cnt; RK_U32 part_rows = 0; if (split->split_mode == MPP_ENC_SPLIT_BY_CTU) { RK_U32 part_mbs = split->split_arg; if (part_mbs > 0 && part_mbs <= syntax->mcu_cnt) { part_rows = (part_mbs + mb_w - 1) / mb_w; if (part_rows >= mb_h) part_rows = 0; } else { mpp_err_f("warning: invalid split arg %d > max %d\n", part_mbs, syntax->mcu_cnt); } } else { mpp_err_f("warning: only mcu split is supported\n"); } if (part_rows) { syntax->part_rows = part_rows; if (mpp_get_soc_type() == ROCKCHIP_SOC_RK3576 && split->split_arg <= syntax->mcu_cnt) syntax->restart_ri = split->split_arg; else syntax->restart_ri = syntax->mcu_hor_cnt * part_rows; syntax->low_delay = cfg->base.low_delay && part_rows; jpege_dbg_func("Split by CTU, part_rows %d, restart_ri %d", syntax->part_rows, syntax->restart_ri); } } task->valid = 1; task->syntax.data = syntax; task->syntax.number = 1; jpege_dbg_func("leave ctx %p\n", ctx); return MPP_OK; } static MPP_RET jpege_add_Prefix(MppPacket pkt, RK_S32 *len, RK_U8 uuid[16], const void *data, RK_S32 size) { RK_U8 *ptr = mpp_packet_get_pos(pkt); size_t length = mpp_packet_get_length(pkt); size_t buf_size = mpp_packet_get_size(pkt); MppWriteCtx bit_ctx; MppWriteCtx *bits = &bit_ctx; const RK_U8 *user_data = data; RK_S32 i = 0, app_size = 0; mpp_writer_init(bits, ptr + length, buf_size - length); if ((size > 8) && user_data[0] == 0xFF && user_data[1] == 0xE1 && user_data[4] == 0x45 && user_data[5] == 0x78 && user_data[6] == 0x69 && user_data[7] == 0x66) { jpege_dbg_func("write EXIF data, total length %d\n", size); } else if ((size > 8) && user_data[0] == 0xFF && user_data[1] == 0xE2 && user_data[4] == 0x4D && user_data[5] == 0x50 && user_data[6] == 0x46 && user_data[7] == 0x00) { jpege_dbg_func("write MPF data, total length %d\n", size); } else { /* add user data to APP7 */ mpp_writer_put_raw_bits(bits, 0xFFE7, 16); /* length */ mpp_writer_put_raw_bits(bits, size + 2, 16); } /* data */ for (i = 0; i < size; i++) mpp_writer_put_raw_bits(bits, user_data[i], 8); app_size = mpp_writer_bytes(bits); *len = app_size; length += app_size; mpp_packet_set_length(pkt, length); (void)uuid; return MPP_OK; } const EncImplApi api_jpege = { .name = "jpege_control", .coding = MPP_VIDEO_CodingMJPEG, .ctx_size = sizeof(JpegeCtx), .flag = 0, .init = jpege_init_v2, .deinit = jpege_deinit_v2, .proc_cfg = jpege_proc_cfg, .gen_hdr = NULL, .start = jpege_start, .proc_dpb = NULL, .proc_hal = jpege_proc_hal, .add_prefix = jpege_add_Prefix, .sw_enc = NULL, };