/* * Copyright 2021 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 "avs2d_api" #include #include #include #include "mpp_mem.h" #include "mpp_log.h" #include "mpp_debug.h" #include "mpp_env.h" #include "mpp_packet_impl.h" #include "mpp_buffer_impl.h" #include "avs2d_syntax.h" #include "avs2d_api.h" #include "avs2d_parse.h" #include "avs2d_dpb.h" #include "mpp_dec_cb_param.h" // for avs2d max ctu size 64 static RK_U32 rkv_ctu_64_align(RK_U32 val) { return MPP_ALIGN(val, 64); } RK_U32 avs2d_parse_debug = 0; MPP_RET avs2d_deinit(void *decoder) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; INP_CHECK(ret, !decoder); AVS2D_PARSE_TRACE("In."); MPP_FREE(p_dec->p_stream->pbuf); MPP_FREE(p_dec->p_header->pbuf); MPP_FREE(p_dec->mem); MPP_FREE(p_dec->p_nals); mpp_packet_deinit(&p_dec->task_pkt); avs2d_dpb_destroy(p_dec); __RETURN: AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_init(void *decoder, ParserCfg *init) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; AVS2D_PARSE_TRACE("In."); INP_CHECK(ret, !p_dec); memset(p_dec, 0, sizeof(Avs2dCtx_t)); mpp_env_get_u32("avs2d_debug", &avs2d_parse_debug, 0); //!< restore init parameters p_dec->init = *init; // p_dec->init.cfg->base.split_parse = 1; p_dec->frame_slots = init->frame_slots; p_dec->packet_slots = init->packet_slots; //!< decoder parameters mpp_buf_slot_setup(p_dec->frame_slots, AVS2_MAX_BUF_NUM); p_dec->mem = mpp_calloc(Avs2dMemory_t, 1); MEM_CHECK(ret, p_dec->mem); p_dec->p_header = &p_dec->mem->headerbuf; p_dec->p_header->size = MAX_HEADER_SIZE; p_dec->p_header->pbuf = mpp_calloc(RK_U8, p_dec->p_header->size); MEM_CHECK(ret, p_dec->p_header->pbuf); p_dec->p_stream = &p_dec->mem->streambuf; p_dec->p_stream->size = MAX_STREAM_SIZE; p_dec->p_stream->pbuf = mpp_calloc(RK_U8, p_dec->p_stream->size); MEM_CHECK(ret, p_dec->p_stream->pbuf); p_dec->p_nals = mpp_calloc(Avs2dNalu_t, MAX_NALU_NUM); MEM_CHECK(ret, p_dec->p_nals); p_dec->nal_allocated = MAX_NALU_NUM; p_dec->nal_cnt = 0; mpp_packet_init(&p_dec->task_pkt, p_dec->p_stream->pbuf, p_dec->p_stream->size); mpp_packet_set_length(p_dec->task_pkt, 0); MEM_CHECK(ret, p_dec->task_pkt); mpp_slots_set_prop(p_dec->frame_slots, SLOTS_WIDTH_ALIGN, rkv_ctu_64_align); __RETURN: AVS2D_PARSE_TRACE("Out."); return ret; __FAILED: avs2d_deinit(decoder); return ret; } MPP_RET avs2d_reset(void *decoder) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; AVS2D_PARSE_TRACE("In."); //!< flush dpb avs2d_dpb_flush(p_dec); //!< reset parser parameters avs2d_reset_parser(p_dec); //!< reset decoder parameters p_dec->pkt_no = 0; p_dec->frame_no = 0; p_dec->has_get_eos = 0; AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_flush(void *decoder) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; AVS2D_PARSE_TRACE("In."); dpb_remove_unused_frame(p_dec); AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_control(void *decoder, MpiCmd cmd_type, void *param) { MPP_RET ret = MPP_OK; AVS2D_PARSE_TRACE("In."); (void)decoder; (void)cmd_type; (void)param; AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_prepare(void *decoder, MppPacket pkt, HalDecTask *task) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; RK_S64 pts = -1; RK_S64 dts = -1; RK_U32 length = 0; RK_U32 pkt_eos = 0; AVS2D_PARSE_TRACE("In."); INP_CHECK(ret, !decoder && !pkt && !task); task->valid = 0; pkt_eos = mpp_packet_get_eos(pkt); pts = mpp_packet_get_pts(pkt); dts = mpp_packet_get_dts(pkt); length = (RK_U32)mpp_packet_get_length(pkt); AVS2D_DBG(AVS2D_DBG_INPUT, "[pkt_in_timeUs] in_pts=%lld, dts=%lld, len=%d, eos=%d, pkt_no=%lld\n", pts, dts, length, pkt_eos, p_dec->pkt_no); p_dec->pkt_no++; AVS2D_DBG(AVS2D_DBG_INPUT, "packet length %d, eos %d\n", length, pkt_eos); if (pkt_eos) { p_dec->has_get_eos = 1; task->flags.eos = 1; } if (!length) { AVS2D_PARSE_TRACE("Input have no stream."); task->valid = 0; if (pkt_eos) avs2d_dpb_flush(p_dec); goto __RETURN; } if (!p_dec->init.cfg->base.split_parse) { ret = avs2d_parse_prepare_fast(p_dec, pkt, task); } else { ret = avs2d_parse_prepare_split(p_dec, pkt, task); } if (task->valid) { //!< bit stream RK_U32 align_len = MPP_ALIGN(p_dec->p_stream->len + 32, 16); mpp_assert(p_dec->p_stream->size > align_len); memset(p_dec->p_stream->pbuf + p_dec->p_stream->len, 0, align_len - p_dec->p_stream->len); p_dec->syntax.bitstream_size = align_len; p_dec->syntax.bitstream = p_dec->p_stream->pbuf; mpp_packet_set_data(p_dec->task_pkt, p_dec->syntax.bitstream); mpp_packet_set_length(p_dec->task_pkt, p_dec->syntax.bitstream_size); mpp_packet_set_size(p_dec->task_pkt, p_dec->p_stream->size); 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)); task->input_packet = p_dec->task_pkt; p_dec->p_stream->len = 0; p_dec->p_header->len = 0; } else { task->input_packet = NULL; } __RETURN: AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_parse(void *decoder, HalDecTask *task) { MPP_RET ret = MPP_OK; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; AVS2D_PARSE_TRACE("In."); task->valid = 0; ret = avs2d_parse_stream(p_dec, task); if (ret) { mpp_err_f("Parse stream failed!"); } if (task->valid) { AVS2D_PARSE_TRACE("-------- Frame %lld--------", p_dec->frame_no); avs2d_dpb_insert(p_dec, task); avs2d_fill_parameters(p_dec, &p_dec->syntax); avs2d_commit_syntaxs(&p_dec->syntax, task); AVS2D_PARSE_TRACE("--------------------------"); } else { task->flags.parse_err = 1; } if (p_dec->has_get_eos) avs2d_dpb_flush(p_dec); AVS2D_PARSE_TRACE("Out."); return ret; } MPP_RET avs2d_callback(void *decoder, void *info) { MPP_RET ret = MPP_ERR_UNKNOW; Avs2dCtx_t *p_dec = (Avs2dCtx_t *)decoder; DecCbHalDone *ctx = (DecCbHalDone *)info; HalDecTask *task_dec = (HalDecTask *)ctx->task; MppFrame mframe = NULL; MppFrame ref_frm = NULL; RK_U32 i = 0; RK_U32 error = 0; RK_U32 discard = 0; RK_U32 ref_used = task_dec->flags.ref_info_valid ? task_dec->flags.ref_used : 0xff; RK_U32 ref_used_flag = 0; AVS2D_PARSE_TRACE("In."); mpp_buf_slot_get_prop(p_dec->frame_slots, task_dec->output, SLOT_FRAME_PTR, &mframe); if (!mframe) { ret = MPP_ERR_UNKNOW; AVS2D_DBG(AVS2D_DBG_CALLBACK, "[CALLBACK]: failed to get frame\n"); goto __FAILED; } if (ctx->hard_err || task_dec->flags.ref_err) { if (task_dec->flags.used_for_ref) { error = 1; } else { discard = 1; } } else { if (task_dec->flags.ref_miss & ref_used) { discard = 1; AVS2D_DBG(AVS2D_DBG_CALLBACK, "[CALLBACK]: fake ref used, miss 0x%x used 0x%x\n", task_dec->flags.ref_miss, ref_used); } } for (i = 0; i < AVS2_MAX_REFS; i++) { if (task_dec->refer[i] < 0) continue; mpp_buf_slot_get_prop(p_dec->frame_slots, task_dec->refer[i], SLOT_FRAME_PTR, &ref_frm); if (!ref_frm) continue; ref_used_flag = (ref_used >> i) & 1; //TODO: In fast mode, ref list isn't kept sync with task flag.ref_used AVS2D_DBG(AVS2D_DBG_CALLBACK, "[CALLBACK]: ref_frm poc %d, err %d, dis %d, ref_used %d\n", mpp_frame_get_poc(ref_frm), mpp_frame_get_errinfo(ref_frm), mpp_frame_get_discard(ref_frm), ref_used_flag); if (ref_used_flag) { discard |= mpp_frame_get_discard(ref_frm); error |= mpp_frame_get_errinfo(ref_frm); } } mpp_frame_set_errinfo(mframe, error); mpp_frame_set_discard(mframe, discard); AVS2D_DBG(AVS2D_DBG_CALLBACK, "[CALLBACK]: frame poc %d, ref=%d, dpberr=%d, harderr=%d, err:dis=%d:%d\n", mpp_frame_get_poc(mframe), task_dec->flags.used_for_ref, task_dec->flags.ref_err, ctx->hard_err, error, discard); __FAILED: AVS2D_PARSE_TRACE("Out."); return ret; } const ParserApi api_avs2d_parser = { .name = "avs2d_parse", .coding = MPP_VIDEO_CodingAVS2, .ctx_size = sizeof(Avs2dCtx_t), .flag = 0, .init = avs2d_init, .deinit = avs2d_deinit, .prepare = avs2d_prepare, .parse = avs2d_parse, .reset = avs2d_reset, .flush = avs2d_flush, .control = avs2d_control, .callback = avs2d_callback, };