/* * 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 "avsd_api" #include #include #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_debug.h" #include "mpp_packet_impl.h" #include "avsd_syntax.h" #include "avsd_api.h" #include "avsd_parse.h" #include "mpp_dec_cb_param.h" RK_U32 avsd_parse_debug = 0; /*! *********************************************************************** * \brief * free all buffer *********************************************************************** */ MPP_RET avsd_deinit(void *decoder) { MPP_RET ret = MPP_ERR_UNKNOW; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; INP_CHECK(ret, !decoder); AVSD_PARSE_TRACE("In."); mpp_packet_deinit(&p_dec->task_pkt); MPP_FREE(p_dec->streambuf); MPP_FREE(p_dec->mem); __RETURN: (void)decoder; AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * alloc all buffer *********************************************************************** */ static MPP_RET avsd_init(void *decoder, ParserCfg *init) { MPP_RET ret = MPP_ERR_UNKNOW; RK_S32 i = 0; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; AVSD_PARSE_TRACE("In."); INP_CHECK(ret, !p_dec); memset(p_dec, 0, sizeof(AvsdCtx_t)); mpp_env_get_u32("avsd_debug", &avsd_parse_debug, 0); //!< restore init parameters p_dec->init = *init; p_dec->frame_slots = init->frame_slots; p_dec->packet_slots = init->packet_slots; //!< decoder parameters mpp_buf_slot_setup(p_dec->frame_slots, 12); p_dec->mem = mpp_calloc(AvsdMemory_t, 1); MEM_CHECK(ret, p_dec->mem); p_dec->syn = &p_dec->mem->syntax; p_dec->stream_size = MAX_STREAM_SIZE; p_dec->streambuf = mpp_malloc(RK_U8, p_dec->stream_size); MEM_CHECK(ret, p_dec->streambuf); mpp_packet_init(&p_dec->task_pkt, p_dec->streambuf, p_dec->stream_size); mpp_packet_set_length(p_dec->task_pkt, 0); MEM_CHECK(ret, p_dec->task_pkt); for (i = 0; i < 3; i++) { AvsdFrame_t *frm = &p_dec->mem->save[i]; memset(frm, 0, sizeof(*frm)); frm->idx = i; frm->slot_idx = -1; } p_dec->bx = &p_dec->mem->bitctx; p_dec->need_split = 1; __RETURN: AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; __FAILED: avsd_deinit(decoder); return ret; } /*! *********************************************************************** * \brief * reset *********************************************************************** */ static MPP_RET avsd_reset(void *decoder) { MPP_RET ret = MPP_ERR_UNKNOW; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; AVSD_PARSE_TRACE("In."); avsd_reset_parameters(p_dec); p_dec->got_vsh = 0; p_dec->got_ph = 0; p_dec->got_keyframe = 0; p_dec->vec_flag = 0; p_dec->got_eos = 0; p_dec->left_length = 0; p_dec->state = 0xFFFFFFFF; p_dec->vop_header_found = 0; mpp_packet_set_length(p_dec->task_pkt, 0); mpp_packet_set_flag(p_dec->task_pkt, 0); AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * flush *********************************************************************** */ static MPP_RET avsd_flush(void *decoder) { AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; AVSD_PARSE_TRACE("In."); set_frame_output(p_dec, p_dec->dpb[1]); set_frame_output(p_dec, p_dec->dpb[0]); set_frame_output(p_dec, p_dec->cur); p_dec->got_eos = 0; AVSD_PARSE_TRACE("Out."); return MPP_OK; } /*! *********************************************************************** * \brief * control/perform *********************************************************************** */ static MPP_RET avsd_control(void *decoder, MpiCmd cmd_type, void *param) { MPP_RET ret = MPP_ERR_UNKNOW; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; AVSD_PARSE_TRACE("In."); switch (cmd_type) { case MPP_DEC_SET_DISABLE_ERROR: { p_dec->disable_error = *((RK_U32 *)param); } break; case MPP_DEC_SET_DIS_ERR_CLR_MARK: { p_dec->dis_err_clr_mark = *((RK_U32 *)param); } break; default : { } break; } AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * prepare *********************************************************************** */ static MPP_RET avsd_prepare(void *decoder, MppPacket pkt, HalDecTask *task) { MPP_RET ret = MPP_ERR_UNKNOW; AVSD_PARSE_TRACE("In."); INP_CHECK(ret, !decoder && !pkt && !task); AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; RK_U8 *pos = mpp_packet_get_pos(pkt); size_t length = mpp_packet_get_length(pkt); RK_U32 eos = mpp_packet_get_eos(pkt); task->valid = 0; if (p_dec->got_eos) { AVSD_DBG(AVSD_DBG_INPUT, "got eos packet.\n"); mpp_packet_set_length(pkt, 0); goto __RETURN; } AVSD_DBG(AVSD_DBG_INPUT, "[pkt_in] pts=%lld, eos=%d, len=%d, pkt_no=%d\n", mpp_packet_get_pts(pkt), eos, (RK_U32)length, (RK_U32)p_dec->pkt_no); p_dec->pkt_no++; if (mpp_packet_get_eos(pkt)) { if (mpp_packet_get_length(pkt) < 4) { avsd_flush(decoder); } p_dec->got_eos = 1; task->flags.eos = p_dec->got_eos; goto __RETURN; } if (mpp_packet_get_length(pkt) > MAX_STREAM_SIZE) { AVSD_DBG(AVSD_DBG_ERROR, "[pkt_in_timeUs] input error, stream too large"); mpp_packet_set_length(pkt, 0); ret = MPP_NOK; goto __RETURN; } mpp_packet_set_length(p_dec->task_pkt, p_dec->left_length); RK_U32 total_length = MPP_ALIGN(p_dec->left_length + length, 16) + 64; if (total_length > p_dec->stream_size) { do { p_dec->stream_size <<= 1; } while (total_length > p_dec->stream_size); RK_U8 *dst = mpp_malloc_size(RK_U8, p_dec->stream_size); mpp_assert(dst); if (p_dec->left_length > 0) { memcpy(dst, p_dec->streambuf, p_dec->left_length); } mpp_free(p_dec->streambuf); p_dec->streambuf = dst; mpp_packet_set_data(p_dec->task_pkt, p_dec->streambuf); mpp_packet_set_size(p_dec->task_pkt, p_dec->stream_size); } if (!p_dec->need_split) { p_dec->got_eos = eos; // empty eos packet if (eos && (length < 4)) { avsd_flush(decoder); goto __RETURN; } // copy packet direct memcpy(p_dec->streambuf, pos, length); mpp_packet_set_data(p_dec->task_pkt, p_dec->streambuf); mpp_packet_set_length(p_dec->task_pkt, length); mpp_packet_set_pts(p_dec->task_pkt, mpp_packet_get_pts(pkt)); mpp_packet_set_dts(p_dec->task_pkt, mpp_packet_get_dts(pkt)); // set input packet length to 0 here mpp_packet_set_length(pkt, 0); /* this step will enable the task and goto parse stage */ task->valid = 1; } else { /* Split packet mode */ if (MPP_OK == avsd_parser_split(p_dec, p_dec->task_pkt, pkt)) { p_dec->left_length = 0; task->valid = 1; } else { task->valid = 0; p_dec->left_length = mpp_packet_get_length(p_dec->task_pkt); } p_dec->got_eos = mpp_packet_get_eos(p_dec->task_pkt); } task->input_packet = p_dec->task_pkt; task->flags.eos = p_dec->got_eos; __RETURN: AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * parser *********************************************************************** */ static MPP_RET avsd_parse(void *decoder, HalDecTask *task) { MPP_RET ret = MPP_ERR_UNKNOW; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; AVSD_PARSE_TRACE("In."); task->valid = 0; memset(task->refer, -1, sizeof(task->refer)); avsd_parse_stream(p_dec, task); if (task->valid) { avsd_fill_parameters(p_dec, p_dec->syn); avsd_set_dpb(p_dec, task); avsd_commit_syntaxs(p_dec->syn, task); avsd_update_dpb(p_dec); } AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * callback *********************************************************************** */ static MPP_RET avsd_callback(void *decoder, void *info) { MPP_RET ret = MPP_ERR_UNKNOW; AvsdCtx_t *p_dec = (AvsdCtx_t *)decoder; DecCbHalDone *ctx = (DecCbHalDone *)info; MppFrame mframe = NULL; HalDecTask *task_dec = (HalDecTask *)ctx->task; AVSD_PARSE_TRACE("In."); mpp_buf_slot_get_prop(p_dec->frame_slots, task_dec->output, SLOT_FRAME_PTR, &mframe); if (mframe) { if (ctx->hard_err || task_dec->flags.ref_err) { if (task_dec->flags.used_for_ref) { mpp_frame_set_errinfo(mframe, MPP_FRAME_FLAG_PAIRED_FIELD); } else { mpp_frame_set_discard(mframe, MPP_FRAME_FLAG_PAIRED_FIELD); } } } if (!ctx->hard_err && p_dec->ph.picture_coding_type == I_PICTURE) p_dec->vsh.version_checked = 1; AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } /*! *********************************************************************** * \brief * api struct interface *********************************************************************** */ const ParserApi api_avsd_parser = { .name = "avsd_parse", .coding = MPP_VIDEO_CodingAVS, .ctx_size = sizeof(AvsdCtx_t), .flag = 0, .init = avsd_init, .deinit = avsd_deinit, .prepare = avsd_prepare, .parse = avsd_parse, .reset = avsd_reset, .flush = avsd_flush, .control = avsd_control, .callback = avsd_callback, }; const ParserApi api_avsd_plus_parser = { .name = "avsd_parse", .coding = MPP_VIDEO_CodingAVSPLUS, .ctx_size = sizeof(AvsdCtx_t), .flag = 0, .init = avsd_init, .deinit = avsd_deinit, .prepare = avsd_prepare, .parse = avsd_parse, .reset = avsd_reset, .flush = avsd_flush, .control = avsd_control, .callback = avsd_callback, };