From 01b4727ba45b52ebb13bb5b667e572888a6b8db9 Mon Sep 17 00:00:00 2001 From: DingWei Date: Tue, 3 May 2016 13:32:09 +0000 Subject: [PATCH] [avsd] 1. change avs_impl CMakeLists.txt 2. add libavs.a && libavs.so, which used in avsd_api.c 3. update avsd_api.c && avsd_parse.c which interface of between libavs.a and mpp_dec git-svn-id: https://10.10.10.66:8443/svn/MediaProcessPlatform/trunk/mpp@678 6e48237b-75ef-9749-8fc9-41990f28c85a --- mpp/codec/CMakeLists.txt | 31 +-- mpp/codec/dec/avs/CMakeLists.txt | 15 +- mpp/codec/dec/avs/avsd_api.c | 386 ++++++++++++++++++++++++++---- mpp/codec/dec/avs/avsd_parse.c | 214 +++++++++++++++++ mpp/codec/dec/avs/avsd_parse.h | 171 +++++++++++++ mpp/codec/dec/avs/libavs.a | Bin 0 -> 1189396 bytes mpp/codec/dec/avs/libavs.so | Bin 0 -> 897796 bytes mpp/codec/inc/avsd_api.h | 52 +++- mpp/hal/inc/hal_avsd_api.h | 54 ++++- mpp/hal/rkdec/avsd/hal_avsd_api.c | 100 ++++++-- mpp/test/avsd_test.c | 117 ++++----- 11 files changed, 968 insertions(+), 172 deletions(-) create mode 100644 mpp/codec/dec/avs/avsd_parse.c create mode 100644 mpp/codec/dec/avs/avsd_parse.h create mode 100644 mpp/codec/dec/avs/libavs.a create mode 100644 mpp/codec/dec/avs/libavs.so diff --git a/mpp/codec/CMakeLists.txt b/mpp/codec/CMakeLists.txt index cb2e2058..a5fa94fa 100644 --- a/mpp/codec/CMakeLists.txt +++ b/mpp/codec/CMakeLists.txt @@ -15,25 +15,14 @@ add_subdirectory(dec) add_subdirectory(enc) -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/dec/avs_impl/") -add_subdirectory(dec/avs_impl) -target_link_libraries(mpp_codec - codec_h264d - codec_vp9d - codec_h265d - codec_avsd - codec_avsd_impl - codec_dummy_enc - codec_dummy_dec - mpp) -else() -target_link_libraries(mpp_codec - codec_h264d - codec_vp9d - codec_h265d - codec_avsd - codec_dummy_enc - codec_dummy_dec - mpp) -endif() + +target_link_libraries(mpp_codec + codec_h264d + codec_vp9d + codec_h265d + codec_avsd + codec_dummy_enc + codec_dummy_dec + mpp) + diff --git a/mpp/codec/dec/avs/CMakeLists.txt b/mpp/codec/dec/avs/CMakeLists.txt index 8eb72fd8..ca3557a4 100644 --- a/mpp/codec/dec/avs/CMakeLists.txt +++ b/mpp/codec/dec/avs/CMakeLists.txt @@ -11,12 +11,13 @@ set(AVSD_COMMON # avs decoder header set(AVSD_HDR - + avsd_parse.h ) # avs decoder sourse set(AVSD_SRC avsd_api.c + avsd_parse.c ) add_library(codec_avsd STATIC @@ -26,6 +27,18 @@ add_library(codec_avsd STATIC ${AVSD_SRC} ) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/avs_impl/") +add_subdirectory(avs_impl) +target_link_libraries(codec_avsd codec_avsd_impl) +else() +set(LIBAVS "${CMAKE_CURRENT_SOURCE_DIR}/libavs.a") +add_library(codec_avsd_impl STATIC IMPORTED) +set_target_properties(codec_avsd_impl PROPERTIES IMPORTED_LOCATION ${LIBAVS}) +target_link_libraries(codec_avsd codec_avsd_impl) +endif() target_link_libraries(codec_avsd mpp) set_target_properties(codec_avsd PROPERTIES FOLDER "mpp/codec") + + + diff --git a/mpp/codec/dec/avs/avsd_api.c b/mpp/codec/dec/avs/avsd_api.c index 2e420f4f..033e1a42 100644 --- a/mpp/codec/dec/avs/avsd_api.c +++ b/mpp/codec/dec/avs/avsd_api.c @@ -21,17 +21,217 @@ #include #include -#include "mpp_packet.h" -#include "mpp_packet_impl.h" #include "mpp_mem.h" #include "mpp_log.h" #include "mpp_env.h" +#include "mpp_packet.h" +#include "mpp_packet_impl.h" +#include "mpp_buffer_impl.h" + #include "avsd_api.h" +#include "avsd_parse.h" + RK_U32 avsd_parse_debug = 0; + + +static MPP_RET free_input_ctx(AvsdInputCtx_t *p_inp) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_inp); + AVSD_PARSE_TRACE("In."); + + MPP_FCLOSE(p_inp->fp_log); +__RETURN: + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +} +static MPP_RET init_input_ctx(AvsdInputCtx_t *p_inp, ParserCfg *init) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_inp && !init); + AVSD_PARSE_TRACE("In."); + + p_inp->init = *init; +#if defined(_WIN32) + if ((p_inp->fp_log = fopen("F:/avs_log/avs_runlog.txt", "wb")) == 0) { + mpp_log("Wanning, open file, %s(%d)", __FUNCTION__, __LINE__); + } +#endif +__RETURN: + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +} + + +static MPP_RET free_cur_ctx(AvsdCurCtx_t *p_cur) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_cur); + AVSD_PARSE_TRACE("In."); + + +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +} +static MPP_RET init_cur_ctx(AvsdCurCtx_t *p_cur) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + AvsdCurStream_t *p_strm = NULL; + + INP_CHECK(ret, !p_cur); + AVSD_PARSE_TRACE("In."); + + p_strm = &p_cur->m_strm; + p_strm->prefixdata = 0xffffffff; + +__RETURN: + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; + +} + + +static MPP_RET free_vid_ctx(AvsdVideoCtx_t *p_vid) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_vid); + AVSD_PARSE_TRACE("In."); + + +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +} +static MPP_RET init_vid_ctx(AvsdVideoCtx_t *p_vid) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_vid); + AVSD_PARSE_TRACE("In."); + +__RETURN: + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +} + +static MPP_RET free_bitstream(AvsdBitstream_t *p) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p); + AVSD_PARSE_TRACE("In."); + + MPP_FREE(p->pbuf); + +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +} + +static MPP_RET init_bitstream(AvsdBitstream_t *p) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p); + AVSD_PARSE_TRACE("In."); + p->size = MAX_BITSTREAM_SIZE; + p->pbuf = mpp_malloc(RK_U8, MAX_BITSTREAM_SIZE); + MEM_CHECK(ret, p->pbuf); + +__RETURN: + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +__FAILED: + return ret; +} + + +static MPP_RET free_dec_ctx(Avs_DecCtx_t *p_dec) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, NULL == p_dec); + AVSD_PARSE_TRACE("In."); + lib_avsd_free(p_dec->libdec); + mpp_packet_deinit(&p_dec->task_pkt); + free_bitstream(p_dec->bitstream); + MPP_FREE(p_dec->mem); + +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +} + + + +static MPP_RET init_dec_ctx(Avs_DecCtx_t *p_dec) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + INP_CHECK(ret, !p_dec); + AVSD_PARSE_TRACE("In."); + + mpp_buf_slot_setup(p_dec->frame_slots, 4); + p_dec->mem = mpp_calloc(AvsdMemory_t, 1); + MEM_CHECK(ret, p_dec->mem); + p_dec->bitstream = &p_dec->mem->bitstream; + FUN_CHECK(ret = init_bitstream(p_dec->bitstream)); + //!< malloc mpp packet + mpp_packet_init(&p_dec->task_pkt, p_dec->bitstream->pbuf, p_dec->bitstream->size); + mpp_packet_set_length(p_dec->task_pkt, 0); + MEM_CHECK(ret, p_dec->task_pkt); + //!< malloc libavsd.so + p_dec->libdec = lib_avsd_malloc(p_dec); + MEM_CHECK(ret, p_dec->libdec); +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +__FAILED: + free_dec_ctx(p_dec); + + return ret; +} +/*! +*********************************************************************** +* \brief +* free all buffer +*********************************************************************** +*/ +MPP_RET avsd_deinit(void *decoder) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; + + INP_CHECK(ret, !decoder); + AVSD_PARSE_TRACE("In."); + avsd_flush(decoder); + free_input_ctx(p_dec->p_inp); + MPP_FREE(p_dec->p_inp); + free_cur_ctx(p_dec->p_cur); + MPP_FREE(p_dec->p_cur); + free_vid_ctx(p_dec->p_vid); + MPP_FREE(p_dec->p_vid); + free_dec_ctx(p_dec); +__RETURN: + (void)decoder; + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +} + /*! *********************************************************************** * \brief @@ -39,48 +239,64 @@ RK_U32 avsd_parse_debug = 0; *********************************************************************** */ -MPP_RET avsd_init(void *ctx, ParserCfg *init) +MPP_RET avsd_init(void *decoder, ParserCfg *init) { MPP_RET ret = MPP_ERR_UNKNOW; + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; - mpp_env_get_u32("avsd_debug", &avsd_parse_debug, 0); + AVSD_PARSE_TRACE("In."); + INP_CHECK(ret, !p_dec); + memset(p_dec, 0, sizeof(Avs_DecCtx_t)); + // init logctx + mpp_env_get_u32("avsd_debug", &avsd_parse_debug, 0); + //!< get init frame_slots and packet_slots + p_dec->frame_slots = init->frame_slots; + p_dec->packet_slots = init->packet_slots; + //!< malloc decoder buffer + p_dec->p_inp = mpp_calloc(AvsdInputCtx_t, 1); + p_dec->p_cur = mpp_calloc(AvsdCurCtx_t, 1); + p_dec->p_vid = mpp_calloc(AvsdVideoCtx_t, 1); + MEM_CHECK(ret, p_dec->p_inp && p_dec->p_cur && p_dec->p_vid); - AVSD_PARSE_TRACE("In."); + p_dec->p_inp->p_dec = p_dec; + p_dec->p_inp->p_cur = p_dec->p_cur; + p_dec->p_inp->p_vid = p_dec->p_vid; + FUN_CHECK(ret = init_input_ctx(p_dec->p_inp, init)); + p_dec->p_cur->p_dec = p_dec; + p_dec->p_cur->p_inp = p_dec->p_inp; + p_dec->p_cur->p_vid = p_dec->p_vid; + FUN_CHECK(ret = init_cur_ctx(p_dec->p_cur)); + p_dec->p_vid->p_dec = p_dec; + p_dec->p_vid->p_inp = p_dec->p_inp; + p_dec->p_vid->p_cur = p_dec->p_cur; + FUN_CHECK(ret = init_vid_ctx(p_dec->p_vid)); + FUN_CHECK(ret = init_dec_ctx(p_dec)); +__RETURN: + (void)decoder; + (void)init; + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +__FAILED: + avsd_deinit(decoder); - (void)ctx; - (void)init; - return ret = MPP_OK; + return ret; } - -/*! -*********************************************************************** -* \brief -* free all buffer -*********************************************************************** -*/ -MPP_RET avsd_deinit(void *ctx) -{ - MPP_RET ret = MPP_ERR_UNKNOW; - - AVSD_PARSE_TRACE("In."); - - (void)ctx; - return ret = MPP_OK; -} - /*! *********************************************************************** * \brief * reset *********************************************************************** */ -MPP_RET avsd_reset(void *ctx) +MPP_RET avsd_reset(void *decoder) { MPP_RET ret = MPP_ERR_UNKNOW; + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; AVSD_PARSE_TRACE("In."); + lib_reset(p_dec->libdec); - (void)ctx; + AVSD_PARSE_TRACE("Out."); + (void)decoder; return ret = MPP_OK; } @@ -90,13 +306,16 @@ MPP_RET avsd_reset(void *ctx) * flush *********************************************************************** */ -MPP_RET avsd_flush(void *ctx) +MPP_RET avsd_flush(void *decoder) { MPP_RET ret = MPP_ERR_UNKNOW; - + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; AVSD_PARSE_TRACE("In."); - (void)ctx; + lib_flush(p_dec->libdec); + + AVSD_PARSE_TRACE("Out."); + (void)decoder; return ret = MPP_OK; } @@ -106,16 +325,17 @@ MPP_RET avsd_flush(void *ctx) * control/perform *********************************************************************** */ -MPP_RET avsd_control(void *ctx, RK_S32 cmd_type, void *param) +MPP_RET avsd_control(void *decoder, RK_S32 cmd_type, void *param) { MPP_RET ret = MPP_ERR_UNKNOW; AVSD_PARSE_TRACE("In."); - (void)ctx; + + (void)decoder; (void)cmd_type; (void)param; - + AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } @@ -126,19 +346,53 @@ MPP_RET avsd_control(void *ctx, RK_S32 cmd_type, void *param) * prepare *********************************************************************** */ -MPP_RET avsd_prepare(void *ctx, MppPacket pkt, HalDecTask *task) +MPP_RET avsd_prepare(void *decoder, MppPacket pkt, HalDecTask *task) { MPP_RET ret = MPP_ERR_UNKNOW; + AvsdInputCtx_t *p_inp = NULL; + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; - AVSD_PARSE_TRACE("In."); + AVSD_PARSE_TRACE("In."); + INP_CHECK(ret, !decoder && !pkt && !task); + p_inp = p_dec->p_inp; + if (p_inp->has_get_eos) { + mpp_packet_set_length(pkt, 0); + goto __RETURN; + } + p_inp->in_pkt = pkt; + p_inp->in_task = task; - mpp_packet_set_length(pkt, 0); + if (mpp_packet_get_eos(pkt)) { + if (mpp_packet_get_length(pkt) < 4) { + avsd_flush(decoder); + } + p_inp->has_get_eos = 1; + } + AVSD_DBG(AVSD_DBG_INPUT, "[pkt_in_timeUs] in_pts=%lld, pkt_eos=%d, len=%d, pkt_no=%d", + mpp_packet_get_pts(pkt), mpp_packet_get_eos(pkt), mpp_packet_get_length(pkt), p_inp->pkt_no++); + if (mpp_packet_get_length(pkt) > MAX_STREM_IN_SIZE) { + AVSD_DBG(AVSD_DBG_ERROR, "[pkt_in_timeUs] input error, stream too large"); + mpp_packet_set_length(pkt, 0); + ret = MPP_NOK; + goto __FAILED; + } + p_inp->in_pts = mpp_packet_get_pts(pkt); + p_inp->in_dts = mpp_packet_get_dts(pkt); - (void)ctx; - (void)pkt; - (void)task; - return ret = MPP_OK; + memset(task, 0, sizeof(HalDecTask)); + do { + (ret = avsd_parse_prepare(p_inp, p_dec->p_cur)); + + } while (mpp_packet_get_length(pkt) && !task->valid); +__RETURN: + (void)decoder; + (void)pkt; + (void)task; + AVSD_PARSE_TRACE("Out."); + return ret = MPP_OK; +__FAILED: + return ret; } @@ -148,14 +402,30 @@ MPP_RET avsd_prepare(void *ctx, MppPacket pkt, HalDecTask *task) * parser *********************************************************************** */ -MPP_RET avsd_parse(void *ctx, HalDecTask *in_task) +MPP_RET avsd_parse(void *decoder, HalDecTask *task) { MPP_RET ret = MPP_ERR_UNKNOW; - + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; AVSD_PARSE_TRACE("In."); - (void)ctx; - (void)in_task; + task->valid = 0; + memset(task->refer, -1, sizeof(task->refer)); + + lib_parse_one_frame(p_dec->libdec, task); + + if (task->flags.eos) { + avsd_flush(decoder); + goto __RETURN; + } + task->valid = 1; // register valid flag + if (task->valid) { + lib_init_one_frame(p_dec->libdec, task); + } + +__RETURN: + (void)decoder; + (void)task; + AVSD_PARSE_TRACE("Out."); return ret = MPP_OK; } @@ -167,14 +437,27 @@ MPP_RET avsd_parse(void *ctx, HalDecTask *in_task) */ MPP_RET avsd_callback(void *decoder, void *info) { - MPP_RET ret = MPP_ERR_UNKNOW; + MPP_RET ret = MPP_ERR_UNKNOW; + HalTaskInfo *task = (HalTaskInfo *)info; + Avs_DecCtx_t *p_dec = (Avs_DecCtx_t *)decoder; + AVSD_PARSE_TRACE("In."); - AVSD_PARSE_TRACE("In."); + AVSD_PARSE_TRACE("[avsd_parse_decode] frame_dec_no=%d", p_dec->dec_no++); + lib_decode_one_frame(p_dec->libdec, &task->dec); + { + MppBuffer mbuffer = NULL; + mpp_buf_slot_get_prop(p_dec->frame_slots, task->dec.output, SLOT_BUFFER, &mbuffer); + if (mbuffer) { + RK_U8 *p = (RK_U8 *)mpp_buffer_get_ptr(mbuffer); + nv12_copy_buffer(p_dec->libdec, p); + } + } + (void)task; + (void)decoder; + (void)info; + AVSD_PARSE_TRACE("Out."); - (void)decoder; - (void)info; - - return ret = MPP_OK; + return ret = MPP_OK; } /*! @@ -183,11 +466,10 @@ MPP_RET avsd_callback(void *decoder, void *info) * api struct interface *********************************************************************** */ - const ParserApi api_avsd_parser = { "avsd_parse", MPP_VIDEO_CodingAVS, - 200,//sizeof(AvsCodecContext), + sizeof(Avs_DecCtx_t), 0, avsd_init, avsd_deinit, diff --git a/mpp/codec/dec/avs/avsd_parse.c b/mpp/codec/dec/avs/avsd_parse.c new file mode 100644 index 00000000..e12a966a --- /dev/null +++ b/mpp/codec/dec/avs/avsd_parse.c @@ -0,0 +1,214 @@ +/* +* +* 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_parse" + +#include +#include + +#include "vpu_api.h" +#include "mpp_mem.h" +#include "mpp_log.h" +#include "mpp_packet.h" +#include "mpp_packet_impl.h" +#include "hal_task.h" + +#include "avsd_api.h" +#include "avsd_parse.h" + +#if 0 +#define START_PREFIX_3BYTE (3) + +static void reset_curstream(AvsdCurStream_t *p_strm) +{ + p_strm->p_start = NULL; + p_strm->len = 0; + p_strm->got_frame_flag = 0; + p_strm->got_nalu_flag = 0; +} + +static MPP_RET add_nalu_header(AvsdCurCtx_t *p_cur) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + RK_U32 add_size = sizeof(AvsdNalu_t); + AvsdBitstream_t *p_bitstream = p_cur->p_dec->bitstream; + + if ((p_bitstream->offset + add_size) > p_bitstream->size) { + AVSD_DBG(AVSD_DBG_ERROR, "error, head_offset is larger than %d", p_bitstream->size); + goto __FAILED; + } + p_cur->cur_nalu = (AvsdNalu_t *)&p_bitstream->pbuf[p_bitstream->offset]; + p_cur->cur_nalu->eof = 1; + p_cur->cur_nalu->header = 0; + p_cur->cur_nalu->pdata = NULL; + p_cur->cur_nalu->length = 0; + p_cur->cur_nalu->start_pos = 0; + p_bitstream->offset += add_size; + + (void)p_cur; + return ret = MPP_OK; +__FAILED: + return ret; +} + + + +static MPP_RET store_cur_nalu(AvsdCurCtx_t *p_cur, AvsdCurStream_t *p_strm) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + + AvsdNalu_t *p_nalu = p_cur->cur_nalu; + AvsdBitstream_t *p_bitstream = p_cur->p_dec->bitstream; + + //!< fill bitstream buffer + RK_U32 add_size = p_strm->len; + + if ((p_bitstream->offset + add_size) > p_bitstream->size) { + AVSD_DBG(AVSD_DBG_ERROR, "error, head_offset is larger than %d", p_bitstream->size); + goto __FAILED; + } + p_nalu->length += p_strm->len; + p_nalu->pdata = &p_bitstream->pbuf[p_bitstream->offset]; + memcpy(p_nalu->pdata, p_strm->p_start, p_strm->len); + p_bitstream->offset += add_size; + + return ret = MPP_OK; +__FAILED: + return ret; +} + +/*! +*********************************************************************** +* \brief +* prepare function for parser +*********************************************************************** +*/ + + +MPP_RET avsd_parse_prepare(AvsdInputCtx_t *p_inp, AvsdCurCtx_t *p_cur) +{ + MPP_RET ret = MPP_ERR_UNKNOW; + RK_U8 *p_curdata = NULL; + + HalDecTask *in_task = p_inp->in_task; + MppPacket *in_pkt = p_inp->in_pkt; + MppPacketImpl *pkt_impl = (MppPacketImpl *)p_inp->in_pkt; + AvsdCurStream_t *p_strm = &p_cur->m_strm; + AvsdBitstream_t *p_bitstream = p_cur->p_dec->bitstream; + + AVSD_PARSE_TRACE("In."); + //!< check input + if (!mpp_packet_get_length(in_pkt)) { + AVSD_DBG(AVSD_DBG_WARNNING, "input have no stream."); + goto __RETURN; + } + + in_task->valid = 0; + in_task->flags.eos = 0; + + //!< check eos + if (mpp_packet_get_eos(in_pkt)) { + FUN_CHECK(ret = add_nalu_header(p_cur)); + in_task->valid = 1; + in_task->flags.eos = 1; + AVSD_DBG(AVSD_DBG_LOG, "end of stream."); + goto __RETURN; + } + + p_strm->p_start = p_curdata = (RK_U8 *)mpp_packet_get_pos(p_inp->in_pkt); + while (pkt_impl->length > 0) { + //!< found next picture start code + if (((*p_curdata) == I_PICTURE_START_CODE) + || ((*p_curdata) == PB_PICTURE_START_CODE)) { + if (p_strm->got_frame_flag) { + FUN_CHECK(ret = add_nalu_header(p_cur)); + in_task->valid = 1; + pkt_impl->length += START_PREFIX_3BYTE; + p_bitstream->len = p_bitstream->offset; + //!< reset value + p_bitstream->offset = 0; + reset_curstream(p_strm); + break; + } + p_strm->got_frame_flag = 1; + } + //!< found next nalu start code + p_strm->prefixdata = (p_strm->prefixdata << 8) | (*p_curdata); + if ((p_strm->prefixdata & 0xFFFFFF00) == 0x00000100) { + if (p_strm->got_nalu_flag) { + p_strm->len = (RK_U32)(p_curdata - p_strm->p_start) - START_PREFIX_3BYTE; + FUN_CHECK(ret = store_cur_nalu(p_cur, p_strm)); + FPRINT(p_cur->p_inp->fp_log, "g_nalu_no=%d, length=%d, header=0x%02x \n", g_nalu_no++, p_cur->cur_nalu->length, p_cur->cur_nalu->header); + + } + FUN_CHECK(ret = add_nalu_header(p_cur)); + p_cur->cur_nalu->header = (*p_curdata); + p_cur->cur_nalu->eof = 0; + p_cur->cur_nalu->start_pos = START_PREFIX_3BYTE; + + p_strm->p_start = p_curdata - START_PREFIX_3BYTE; + p_strm->got_nalu_flag = 1; + } + p_curdata++; + pkt_impl->length--; + } + if (!pkt_impl->length) { + p_strm->len = (RK_U32)(p_curdata - p_strm->p_start) - 1; + FUN_CHECK(ret = store_cur_nalu(p_cur, p_strm)); + } +__RETURN: + AVSD_PARSE_TRACE("Out."); + + return ret = MPP_OK; +__FAILED: + return ret; +} +#else + +MPP_RET avsd_parse_prepare(AvsdInputCtx_t *p_inp, AvsdCurCtx_t *p_cur) +{ + RK_S32 ret_val = 0; + MPP_RET ret = MPP_ERR_UNKNOW; + + Avs_DecCtx_t *p_dec = p_inp->p_dec; + HalDecTask *in_task = p_inp->in_task; + AvsdBitstream_t *pb = p_dec->bitstream; + + AVSD_PARSE_TRACE("In."); + + in_task->input_packet = p_dec->task_pkt; + ret_val = lib_prepare_one_frame(p_dec->libdec, p_inp->in_pkt, in_task); + if (ret_val < 0) { + goto __FAILED; + } + if (in_task->valid) { + mpp_packet_set_pos(in_task->input_packet, pb->pbuf); + mpp_packet_set_length(in_task->input_packet, 0); + } + + AVSD_PARSE_TRACE("Out."); + (void)p_cur; + return ret = MPP_OK; +__FAILED: + mpp_packet_set_pos(p_dec->task_pkt, pb->pbuf); + mpp_packet_set_length(p_dec->task_pkt, 0); + return ret; +} +#endif + + diff --git a/mpp/codec/dec/avs/avsd_parse.h b/mpp/codec/dec/avs/avsd_parse.h new file mode 100644 index 00000000..4b8c1249 --- /dev/null +++ b/mpp/codec/dec/avs/avsd_parse.h @@ -0,0 +1,171 @@ +/* + * Copyright 2010 Rockchip Electronics S.LSI 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. + */ + +#ifndef __AVSD_PARSE_H__ +#define __AVSD_PARSE_H__ + + +#include "rk_type.h" +#include "parser_api.h" + +#include "mpp_err.h" +#include "mpp_packet.h" +#include "mpp_buf_slot.h" + +#include "hal_task.h" + +#define MAX_STREM_IN_SIZE (2*1024*1024) +#define MAX_BITSTREAM_SIZE (2*1024*1024) + +//!< NALU type +#define SLICE_START_CODE_MIN 0x00 +#define SLICE_START_CODE_MAX 0xAF + +#define I_PICTURE_START_CODE 0xB3 +#define PB_PICTURE_START_CODE 0xB6 + +#define USER_DATA_START_CODE 0xB2 +#define SEQUENCE_HEADER_CODE 0xB0 +#define EXTENSION_START_CODE 0xB5 + +#define SEQUENCE_END_CODE 0xB1 //!< no in ffmpeg +#define VIDEO_EDIT_CODE 0xB7 //!< no in ffmpeg + + +#define FPRINT(fp, ...) do{ if (fp) { fprintf(fp, ## __VA_ARGS__); fflush(fp);} }while(0) + + +//!< input parameter +typedef struct avsd_input_ctx_t { + FILE *fp_log; + + ParserCfg init; + MppPacket in_pkt; + HalDecTask *in_task; + + RK_S64 in_pts; + RK_S64 in_dts; + + RK_U8 has_get_eos; + RK_U64 pkt_no; + struct avsd_cur_ctx_t *p_cur; + struct avsd_video_ctx_t *p_vid; + struct avs_dec_ctx_t *p_dec; +} AvsdInputCtx_t; + +//!< current stream +typedef struct avsd_cur_strm_t { + RK_U8 *p_start; //!< store read nalu data + RK_U32 len; + + RK_U32 prefixdata; + + RK_U8 got_frame_flag; + RK_U8 got_nalu_flag; +} AvsdCurStream_t; + +typedef struct avsd_nalu_t +{ + RK_U8 header; + RK_U8 *pdata; + RK_U32 size; + RK_U32 length; + RK_U8 start_pos; + RK_U8 eof; //!< end of frame stream +}AvsdNalu_t; + +//!< current parameters +typedef struct avsd_cur_ctx_t { + struct avsd_cur_strm_t m_strm; + struct avsd_nalu_t *cur_nalu; //!< current nalu + + struct avsd_input_ctx_t *p_inp; + struct avsd_video_ctx_t *p_vid; + struct avs_dec_ctx_t *p_dec; +} AvsdCurCtx_t; + + +//!< decoder parameters +typedef struct avsd_video_ctx_t { + + struct img_par *img; + + struct avsd_input_ctx_t *p_inp; + struct avsd_cur_ctx_t *p_cur; + struct avs_dec_ctx_t *p_dec; +}AvsdVideoCtx_t; + + +typedef struct avsd_bitstream_t { + RK_U8 *pbuf; + RK_U32 size; + RK_U32 len; + RK_U32 offset; //!< start from the offset byte +}AvsdBitstream_t; + + +typedef struct avsd_memory_t { + + struct avsd_bitstream_t bitstream; +} AvsdMemory_t; + + +//!< decoder parameters +typedef struct avs_dec_ctx_t { + MppBufSlots frame_slots; + MppBufSlots packet_slots; + + MppPacket task_pkt; + struct avsd_memory_t *mem; //!< resotre slice data to decoder + struct avsd_bitstream_t *bitstream; + + struct avsd_input_ctx_t *p_inp; + struct avsd_cur_ctx_t *p_cur; + struct avsd_video_ctx_t *p_vid; + //!< use in libavs.so + void *libdec; + RK_U32 dec_no; + //mpp_list + +} Avs_DecCtx_t; + + + +#ifdef __cplusplus +extern "C" { +#endif + +MPP_RET avsd_parse_prepare(AvsdInputCtx_t *p_inp, AvsdCurCtx_t *p_cur); + +//!< used in libavs.so +MPP_RET lib_avsd_free(void *decoder); +void *lib_avsd_malloc(void *decoder); +RK_S32 lib_prepare_one_frame(void *decoder, MppPacket pkt, HalDecTask *task); +RK_S32 lib_parse_one_frame(void *decoder, HalDecTask *task); +RK_S32 lib_init_one_frame(void *decoder, HalDecTask *task); +RK_S32 lib_decode_one_frame(void *decoder, HalDecTask *task); +RK_S32 lib_flush(void *decoder); +RK_S32 lib_reset(void *decoder); + +RK_S32 nv12_copy_buffer(void *p_dec, RK_U8 *des); + + + +#ifdef __cplusplus +} +#endif + +#endif /*__AVSD_PARSE_H__*/ diff --git a/mpp/codec/dec/avs/libavs.a b/mpp/codec/dec/avs/libavs.a new file mode 100644 index 0000000000000000000000000000000000000000..3ad664dbc44ed79661cf0b5d5d11de673a649d58 GIT binary patch literal 1189396 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