/* * * 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 "h263d_api" #include #include "mpp_mem.h" #include "mpp_debug.h" #include "mpp_common.h" #include "h263d_api.h" #include "h263d_parser.h" #define h263d_INIT_STREAM_SIZE SZ_64K typedef struct { // parameter interact with mpp_dec MppBufSlots frame_slots; MppBufSlots packet_slots; MppDecCfgSet *cfg; RK_U8 *stream; size_t stream_size; MppPacket task_pkt; RK_S64 task_pts; RK_U32 task_eos; // runtime parameter RK_U32 need_split; RK_U32 frame_count; // parser context H263dParser parser; } H263dCtx; MPP_RET h263d_init(void *dec, ParserCfg *cfg) { H263dParser parser = NULL; MppPacket task_pkt = NULL; H263dCtx *p; MPP_RET ret; RK_U8 *stream; size_t stream_size = h263d_INIT_STREAM_SIZE; if (NULL == dec) { mpp_err_f("found NULL intput dec %p cfg %p\n", dec, cfg); return MPP_ERR_NULL_PTR; } stream = mpp_malloc_size(RK_U8, stream_size); if (NULL == stream) { mpp_err_f("failed to malloc stream buffer size %d\n", stream_size); return MPP_ERR_MALLOC; } ret = mpp_packet_init(&task_pkt, stream, stream_size); if (ret) { mpp_err_f("failed to create mpp_packet for task\n"); goto ERR_RET; } // reset task packet length to zero // NOTE: set length must after set pos mpp_packet_set_pos(task_pkt, stream); mpp_packet_set_length(task_pkt, 0); ret = mpp_h263_parser_init(&parser, cfg->frame_slots); if (ret) { mpp_err_f("failed to init parser\n"); goto ERR_RET; } p = (H263dCtx *)dec; p->frame_slots = cfg->frame_slots; p->packet_slots = cfg->packet_slots; p->cfg = cfg->cfg; p->need_split = p->cfg->base.split_parse; p->stream = stream; p->stream_size = stream_size; p->task_pkt = task_pkt; p->parser = parser; return MPP_OK; ERR_RET: if (task_pkt) { mpp_packet_deinit(&task_pkt); } if (stream) { mpp_free(stream); stream = NULL; } return ret; } MPP_RET h263d_deinit(void *dec) { H263dCtx *p; if (NULL == dec) { mpp_err_f("found NULL intput\n"); return MPP_ERR_NULL_PTR; } p = (H263dCtx *)dec; if (p->parser) { mpp_h263_parser_deinit(p->parser); p->parser = NULL; } if (p->task_pkt) { mpp_packet_deinit(&p->task_pkt); } if (p->stream) { mpp_free(p->stream); p->stream = NULL; } return MPP_OK; } MPP_RET h263d_reset(void *dec) { if (NULL == dec) { mpp_err_f("found NULL intput\n"); return MPP_ERR_NULL_PTR; } H263dCtx *p = (H263dCtx *)dec; return mpp_h263_parser_reset(p->parser); } MPP_RET h263d_flush(void *dec) { if (NULL == dec) { mpp_err_f("found NULL intput\n"); return MPP_ERR_NULL_PTR; } H263dCtx *p = (H263dCtx *)dec; return mpp_h263_parser_flush(p->parser); } MPP_RET h263d_control(void *dec, MpiCmd cmd_type, void *param) { if (NULL == dec) { mpp_err_f("found NULL intput\n"); return MPP_ERR_NULL_PTR; } (void)cmd_type; (void)param; return MPP_OK; } MPP_RET h263d_prepare(void *dec, MppPacket pkt, HalDecTask *task) { H263dCtx *p; RK_U8 *pos; size_t length; RK_U32 eos; if (NULL == dec || NULL == pkt || NULL == task) { mpp_err_f("found NULL intput dec %p pkt %p task %p\n", dec, pkt, task); return MPP_ERR_NULL_PTR; } p = (H263dCtx *)dec; pos = mpp_packet_get_pos(pkt); length = mpp_packet_get_length(pkt); eos = mpp_packet_get_eos(pkt); if (eos && !length) { task->valid = 0; task->flags.eos = 1; mpp_log("h263d flush eos"); h263d_flush(dec); return MPP_OK; } if (NULL == p->stream) { mpp_err("failed to malloc task buffer for hardware with size %d\n", length); return MPP_ERR_UNKNOW; } if (!p->need_split) { /* * Copy packet mode: * Decoder's user will insure each packet is one frame for process * Parser will just copy packet to the beginning of stream buffer */ if (length > p->stream_size) { // NOTE: here we double the buffer length to reduce frequency of realloc do { p->stream_size <<= 1; } while (length > p->stream_size); mpp_free(p->stream); p->stream = mpp_malloc_size(RK_U8, p->stream_size); mpp_assert(p->stream); mpp_packet_set_data(p->task_pkt, p->stream); mpp_packet_set_size(p->task_pkt, p->stream_size); } memcpy(p->stream, pos, length); mpp_packet_set_pos(p->task_pkt, p->stream); mpp_packet_set_length(p->task_pkt, length); // set input packet length to 0 here // indicate that the input packet has been all consumed mpp_packet_set_pos(pkt, pos + length); // always use latest pts for current packet p->task_pts = mpp_packet_get_pts(pkt); p->task_eos = mpp_packet_get_eos(pkt); /* this step will enable the task and goto parse stage */ task->valid = 1; } else { /* * Split packet mode: * Input packet can be any length and no need to be bound of on frame * Parser will do split frame operation to find the beginning and end of one frame */ /* * NOTE: on split mode total length is the left size plus the new incoming * packet length. */ size_t remain_length = mpp_packet_get_length(p->task_pkt); size_t total_length = remain_length + length; if (total_length > p->stream_size) { RK_U8 *dst; do { p->stream_size <<= 1; } while (length > p->stream_size); // NOTE; split mode need to copy remaining stream to new buffer dst = mpp_malloc_size(RK_U8, p->stream_size); mpp_assert(dst); memcpy(dst, p->stream, remain_length); mpp_free(p->stream); p->stream = dst; mpp_packet_set_data(p->task_pkt, p->stream); mpp_packet_set_size(p->task_pkt, p->stream_size); } // start parser split if (MPP_OK == mpp_h263_parser_split(p->parser, p->task_pkt, pkt)) { task->valid = 1; } p->task_pts = mpp_packet_get_pts(p->task_pkt); p->task_eos = mpp_packet_get_eos(p->task_pkt); } mpp_packet_set_pts(p->task_pkt, p->task_pts); task->input_packet = p->task_pkt; task->flags.eos = p->task_eos; return MPP_OK; } MPP_RET h263d_parse(void *dec, HalDecTask *task) { MPP_RET ret; H263dCtx *p; if (NULL == dec || NULL == task) { mpp_err_f("found NULL intput dec %p task %p\n", dec, task); return MPP_ERR_NULL_PTR; } p = (H263dCtx *)dec; ret = mpp_h263_parser_decode(p->parser, task->input_packet); if (ret) { // found error on decoding drop this task and clear remaining length task->valid = 0; task->output = -1; mpp_packet_set_length(task->input_packet, 0); return MPP_NOK; } mpp_h263_parser_setup_syntax(p->parser, &task->syntax); mpp_h263_parser_setup_hal_output(p->parser, &task->output); mpp_h263_parser_setup_refer(p->parser, task->refer, MAX_DEC_REF_NUM); mpp_h263_parser_update_dpb(p->parser); p->frame_count++; return MPP_OK; } MPP_RET h263d_callback(void *dec, void *err_info) { (void)dec; (void)err_info; return MPP_OK; } const ParserApi api_h263d_parser = { .name = "api_h263d_parser", .coding = MPP_VIDEO_CodingH263, .ctx_size = sizeof(H263dCtx), .flag = 0, .init = h263d_init, .deinit = h263d_deinit, .prepare = h263d_prepare, .parse = h263d_parse, .reset = h263d_reset, .flush = h263d_flush, .control = h263d_control, .callback = h263d_callback, };