[mpp_dec]: Support no thread decode

1. Use cmd MPP_SET_DISABLE_THREAD to disable thread, cmd set must be
after mpp_create before mpp_init.
2. When thread disabled put_packet & get_frame MUST not be used.
3. Separate normal flow and no thread flow.

Change-Id: Icf189d312ff39aacf6ca0afe7f345ff4d1cbfb67
Signed-off-by: sayon.chen <sayon.chen@rock-chips.com>
This commit is contained in:
sayon.chen
2021-04-20 19:18:45 +08:00
committed by Herman Chen
parent 52bffbc7bd
commit 38fc8aada8
14 changed files with 2490 additions and 1266 deletions

View File

@@ -7,6 +7,8 @@ add_library(mpp_codec STATIC
mpp_enc_impl.cpp mpp_enc_impl.cpp
mpp_enc_v2.cpp mpp_enc_v2.cpp
enc_impl.cpp enc_impl.cpp
mpp_dec_no_thread.cpp
mpp_dec_normal.cpp
mpp_dec.cpp mpp_dec.cpp
mpp_parser.cpp mpp_parser.cpp
) )

View File

@@ -58,6 +58,8 @@ MPP_RET mpp_dec_callback(MppDec ctx, MppDecEvent event, void *arg);
MPP_RET mpp_dec_set_cfg_by_cmd(MppDecCfgSet *set, MpiCmd cmd, void *param); MPP_RET mpp_dec_set_cfg_by_cmd(MppDecCfgSet *set, MpiCmd cmd, void *param);
MPP_RET mpp_dec_set_cfg(MppDecCfgSet *dst, MppDecCfgSet *src); MPP_RET mpp_dec_set_cfg(MppDecCfgSet *dst, MppDecCfgSet *src);
MPP_RET mpp_dec_decode(MppDec ctx, MppPacket packet, MppFrame *frame);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -46,9 +46,30 @@ typedef enum MppDecTimingType_e {
DEC_TIMING_BUTT, DEC_TIMING_BUTT,
} MppDecTimingType; } MppDecTimingType;
typedef struct MppDecImpl_t {
typedef enum MppDecMode_e {
MPP_DEC_MODE_DEFAULT,
MPP_DEC_MODE_NO_THREAD,
MPP_DEC_MODE_BUTT,
} MppDecMode;
typedef struct MppDecImpl_t MppDecImpl;
typedef struct MppDecModeApi_t {
MPP_RET (*start)(MppDecImpl *dec);
MPP_RET (*stop)(MppDecImpl *dec);
MPP_RET (*reset)(MppDecImpl *dec);
MPP_RET (*notify)(MppDecImpl *dec, RK_U32 flag);
MPP_RET (*control)(MppDecImpl *dec, MpiCmd cmd, void *param);
} MppDecModeApi;
struct MppDecImpl_t {
MppCodingType coding; MppCodingType coding;
MppDecMode mode;
MppDecModeApi *api;
Parser parser; Parser parser;
MppHal hal; MppHal hal;
@@ -72,7 +93,7 @@ typedef struct MppDecImpl_t {
MppDecCfgSet cfg; MppDecCfgSet cfg;
/* control process */ /* control process */
Mutex *cmd_lock; MppMutexCond *cmd_lock;
RK_U32 cmd_send; RK_U32 cmd_send;
RK_U32 cmd_recv; RK_U32 cmd_recv;
MpiCmd cmd; MpiCmd cmd;
@@ -127,12 +148,98 @@ typedef struct MppDecImpl_t {
MppMemPool ts_pool; MppMemPool ts_pool;
struct list_head ts_link; struct list_head ts_link;
spinlock_t ts_lock; spinlock_t ts_lock;
} MppDecImpl; void *task_single;
};
/* external wait state */
#define MPP_DEC_WAIT_PKT_IN (0x00000001) /* input packet not ready */
#define MPP_DEC_WAIT_FRM_OUT (0x00000002) /* frame output queue full */
#define MPP_DEC_WAIT_INFO_CHG (0x00000020) /* wait info change ready */
#define MPP_DEC_WAIT_BUF_RDY (0x00000040) /* wait valid frame buffer */
#define MPP_DEC_WAIT_TSK_ALL_DONE (0x00000080) /* wait all task done */
#define MPP_DEC_WAIT_TSK_HND_RDY (0x00000100) /* wait task handle ready */
#define MPP_DEC_WAIT_TSK_PREV_DONE (0x00000200) /* wait previous task done */
#define MPP_DEC_WAIT_BUF_GRP_RDY (0x00000200) /* wait buffer group change ready */
/* internal wait state */
#define MPP_DEC_WAIT_BUF_SLOT_RDY (0x00001000) /* wait buffer slot ready */
#define MPP_DEC_WAIT_PKT_BUF_RDY (0x00002000) /* wait packet buffer ready */
#define MPP_DEC_WAIT_BUF_SLOT_KEEP (0x00004000) /* wait buffer slot reservation */
typedef union PaserTaskWait_u {
RK_U32 val;
struct {
RK_U32 dec_pkt_in : 1; // 0x0001 MPP_DEC_NOTIFY_PACKET_ENQUEUE
RK_U32 dis_que_full : 1; // 0x0002 MPP_DEC_NOTIFY_FRAME_DEQUEUE
RK_U32 reserv0004 : 1; // 0x0004
RK_U32 reserv0008 : 1; // 0x0008
RK_U32 ext_buf_grp : 1; // 0x0010 MPP_DEC_NOTIFY_EXT_BUF_GRP_READY
RK_U32 info_change : 1; // 0x0020 MPP_DEC_NOTIFY_INFO_CHG_DONE
RK_U32 dec_pic_unusd : 1; // 0x0040 MPP_DEC_NOTIFY_BUFFER_VALID
RK_U32 dec_all_done : 1; // 0x0080 MPP_DEC_NOTIFY_TASK_ALL_DONE
RK_U32 task_hnd : 1; // 0x0100 MPP_DEC_NOTIFY_TASK_HND_VALID
RK_U32 prev_task : 1; // 0x0200 MPP_DEC_NOTIFY_TASK_PREV_DONE
RK_U32 dec_pic_match : 1; // 0x0400 MPP_DEC_NOTIFY_BUFFER_MATCH
RK_U32 reserv0800 : 1; // 0x0800
RK_U32 dec_pkt_idx : 1; // 0x1000
RK_U32 dec_pkt_buf : 1; // 0x2000
RK_U32 dec_slot_idx : 1; // 0x4000
};
} PaserTaskWait;
typedef union DecTaskStatus_u {
RK_U32 val;
struct {
RK_U32 task_hnd_rdy : 1;
RK_U32 mpp_pkt_in_rdy : 1;
RK_U32 dec_pkt_idx_rdy : 1;
RK_U32 dec_pkt_buf_rdy : 1;
RK_U32 task_valid_rdy : 1;
RK_U32 dec_pkt_copy_rdy : 1;
RK_U32 prev_task_rdy : 1;
RK_U32 info_task_gen_rdy : 1;
RK_U32 curr_task_rdy : 1;
RK_U32 task_parsed_rdy : 1;
};
} DecTaskStatus;
typedef struct MppPktTimestamp_t {
struct list_head link;
RK_S64 pts;
RK_S64 dts;
} MppPktTs;
typedef struct DecTask_t {
HalTaskHnd hnd;
DecTaskStatus status;
PaserTaskWait wait;
HalTaskInfo info;
MppPktTs ts_cur;
MppBuffer hal_pkt_buf_in;
RK_S32 hal_pkt_idx_in;
MppBuffer hal_frm_buf_out;
} DecTask;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
MPP_RET dec_task_info_init(HalTaskInfo *task);
void dec_task_init(DecTask *task);
MPP_RET mpp_dec_proc_cfg(MppDecImpl *dec, MpiCmd cmd, void *param);
MPP_RET update_dec_hal_info(MppDecImpl *dec, MppFrame frame);
void mpp_dec_put_frame(Mpp *mpp, RK_S32 index, HalDecTaskFlag flags);
void mpp_dec_push_display(Mpp *mpp, HalDecTaskFlag flags);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2022 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.
*/
#ifndef __MPP_DEC_NO_THREAD_H__
#define __MPP_DEC_NO_THREAD_H__
#include "mpp_dec_impl.h"
#ifdef __cplusplus
extern "C" {
#endif
extern MppDecModeApi dec_api_no_thread;
#ifdef __cplusplus
}
#endif
#endif /*__MPP_DEC_NO_THREAD_H__*/

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2022 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.
*/
#ifndef __MPP_DEC_NORMAL_H__
#define __MPP_DEC_NORMAL_H__
#include "mpp_dec_impl.h"
#ifdef __cplusplus
extern "C" {
#endif
extern MppDecModeApi dec_api_normal;
#ifdef __cplusplus
}
#endif
#endif /*__MPP_DEC_NORMAL_H__*/

File diff suppressed because it is too large Load Diff

40
mpp/codec/mpp_dec_debug.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright 2022 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.
*/
#ifndef __MPP_DEC_DEBUG_H__
#define __MPP_DEC_DEBUG_H__
#include "mpp_debug.h"
#define MPP_DEC_DBG_FUNCTION (0x00000001)
#define MPP_DEC_DBG_TIMING (0x00000002)
#define MPP_DEC_DBG_STATUS (0x00000010)
#define MPP_DEC_DBG_DETAIL (0x00000020)
#define MPP_DEC_DBG_RESET (0x00000040)
#define MPP_DEC_DBG_NOTIFY (0x00000080)
#define mpp_dec_dbg(flag, fmt, ...) _mpp_dbg(mpp_dec_debug, flag, fmt, ## __VA_ARGS__)
#define mpp_dec_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_dec_debug, flag, fmt, ## __VA_ARGS__)
#define dec_dbg_func(fmt, ...) mpp_dec_dbg_f(MPP_DEC_DBG_FUNCTION, fmt, ## __VA_ARGS__)
#define dec_dbg_status(fmt, ...) mpp_dec_dbg_f(MPP_DEC_DBG_STATUS, fmt, ## __VA_ARGS__)
#define dec_dbg_detail(fmt, ...) mpp_dec_dbg(MPP_DEC_DBG_DETAIL, fmt, ## __VA_ARGS__)
#define dec_dbg_reset(fmt, ...) mpp_dec_dbg(MPP_DEC_DBG_RESET, fmt, ## __VA_ARGS__)
#define dec_dbg_notify(fmt, ...) mpp_dec_dbg_f(MPP_DEC_DBG_NOTIFY, fmt, ## __VA_ARGS__)
extern RK_U32 mpp_dec_debug;
#endif /* __MPP_DEC_DEBUG_H__ */

View File

@@ -0,0 +1,343 @@
/*
* Copyright 2022 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 "mpp_dec_nt"
#include <string.h>
#include "mpp_buffer_impl.h"
#include "mpp_dec_debug.h"
#include "mpp_dec_vproc.h"
#include "mpp_dec_no_thread.h"
MPP_RET mpp_dec_decode(MppDec ctx, MppPacket packet, MppFrame *frame)
{
MppDecImpl *dec = (MppDecImpl *)ctx;
Mpp *mpp = (Mpp *)dec->mpp;
DecTask *task = (DecTask *)dec->task_single;
MppBufSlots frame_slots = dec->frame_slots;
MppBufSlots packet_slots = dec->packet_slots;
HalDecTask *task_dec = &task->info.dec;
MppMutexCond *cmd_lock = dec->cmd_lock;
MppBuffer hal_buf_in = NULL;
MppBuffer hal_buf_out = NULL;
size_t stream_size = 0;
RK_S32 output = 0;
AutoMutex auto_lock(cmd_lock->mutex());
if (dec->mpp_pkt_in == NULL && !task->status.curr_task_rdy)
dec->mpp_pkt_in = packet;
if (!task->status.curr_task_rdy) {
if (dec->mpp_pkt_in == NULL)
return MPP_OK;
mpp_parser_prepare(dec->parser, dec->mpp_pkt_in, task_dec);
if (0 == mpp_packet_get_length(dec->mpp_pkt_in)) {
// mpp_packet_deinit(&dec->mpp_pkt_in);
dec->mpp_pkt_in = NULL;
}
if (!task_dec->valid) {
if (task_dec->flags.eos) {
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, task_dec->flags);
/*
* Use -1 as invalid buffer slot index.
* Reason: the last task maybe is a empty task with eos flag
* only but this task may go through vproc process also. We need
* create a buffer slot index for it.
*/
mpp_dec_put_frame(mpp, -1, task_dec->flags);
}
return MPP_OK;
}
}
task->status.curr_task_rdy = task_dec->valid;
// NOTE: packet in task should be ready now
mpp_assert(task_dec->input_packet);
/*
* 4. look for a unused packet slot index
*/
if (task_dec->input < 0) {
mpp_buf_slot_get_unused(packet_slots, &task_dec->input);
}
/*
* 5. malloc hardware buffer for the packet slot index
*/
task->hal_pkt_idx_in = task_dec->input;
stream_size = mpp_packet_get_size(task_dec->input_packet);
mpp_buf_slot_get_prop(packet_slots, task->hal_pkt_idx_in, SLOT_BUFFER, &hal_buf_in);
if (NULL == hal_buf_in) {
mpp_buffer_get(mpp->mPacketGroup, &hal_buf_in, stream_size);
if (hal_buf_in) {
mpp_buf_slot_set_prop(packet_slots, task->hal_pkt_idx_in, SLOT_BUFFER, hal_buf_in);
mpp_buffer_put(hal_buf_in);
}
} else {
MppBufferImpl *buf = (MppBufferImpl *)hal_buf_in;
mpp_assert(buf->info.size >= stream_size);
}
task->hal_pkt_buf_in = hal_buf_in;
if (!task->status.dec_pkt_copy_rdy) {
void *dst = mpp_buffer_get_ptr(task->hal_pkt_buf_in);
void *src = mpp_packet_get_data(task_dec->input_packet);
size_t length = mpp_packet_get_length(task_dec->input_packet);
memcpy(dst, src, length);
mpp_buf_slot_set_flag(packet_slots, task_dec->input, SLOT_CODEC_READY);
mpp_buf_slot_set_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
task->status.dec_pkt_copy_rdy = 1;
}
if (!task->status.task_parsed_rdy) {
mpp_clock_start(dec->clocks[DEC_PRS_PARSE]);
mpp_parser_parse(dec->parser, task_dec);
mpp_clock_pause(dec->clocks[DEC_PRS_PARSE]);
task->status.task_parsed_rdy = 1;
}
if (task_dec->output < 0 || !task_dec->valid) {
/*
* We may meet an eos in parser step and there will be no anymore vaild
* task generated. So here we try push eos task to hal, hal will push
* all frame(s) to display, a frame of them with a eos flag will be
* used to inform that all frame have decoded
*/
if (task_dec->flags.eos) {
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, task_dec->flags);
}
if (task->status.dec_pkt_copy_rdy) {
mpp_buf_slot_clr_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
task->status.dec_pkt_copy_rdy = 0;
}
task->status.curr_task_rdy = 0;
task->status.task_parsed_rdy = 0;
dec_task_info_init(&task->info);
return MPP_NOK;
}
dec_dbg_detail("detail: %p check output index pass\n", dec);
/*
* 9. parse local task and slot to check whether new buffer or info change is needed.
*
* detect info change from frame slot
*/
if (mpp_buf_slot_is_changed(frame_slots)) {
if (!task->status.info_task_gen_rdy) {
RK_U32 eos = task_dec->flags.eos;
// NOTE: info change should not go with eos flag
task_dec->flags.info_change = 1;
task_dec->flags.eos = 0;
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, task_dec->flags);
mpp_dec_put_frame(mpp, task_dec->output, task_dec->flags);
task_dec->flags.eos = eos;
task->status.info_task_gen_rdy = 1;
return MPP_OK;
}
dec->info_updated = 0;
}
task->wait.info_change = mpp_buf_slot_is_changed(frame_slots);
if (task->wait.info_change) {
return MPP_OK;
} else {
task->status.info_task_gen_rdy = 0;
task_dec->flags.info_change = 0;
// NOTE: check the task must be ready
// mpp_assert(task->hnd);
}
/* 10. whether the frame buffer group is internal or external */
if (NULL == mpp->mFrameGroup) {
mpp_log("mpp_dec use internal frame buffer group\n");
mpp_buffer_group_get_internal(&mpp->mFrameGroup, MPP_BUFFER_TYPE_ION);
}
/* 10.1 look for a unused hardware buffer for output */
if (mpp->mFrameGroup) {
RK_S32 unused = mpp_buffer_group_unused(mpp->mFrameGroup);
// NOTE: When dec post-process is enabled reserve 2 buffer for it.
task->wait.dec_pic_unusd = (dec->vproc) ? (unused < 3) : (unused < 1);
if (task->wait.dec_pic_unusd)
cmd_lock->wait();
}
dec_dbg_detail("detail: %p check frame group count pass\n", dec);
output = task_dec->output;
mpp_buf_slot_get_prop(frame_slots, output, SLOT_BUFFER, &hal_buf_out);
if (NULL == hal_buf_out) {
size_t size = mpp_buf_slot_get_size(frame_slots);
mpp_buffer_get(mpp->mFrameGroup, &hal_buf_out, size);
if (hal_buf_out)
mpp_buf_slot_set_prop(frame_slots, output, SLOT_BUFFER,
hal_buf_out);
}
if (!dec->info_updated && dec->dev) {
MppFrame slot_frm = NULL;
mpp_buf_slot_get_prop(frame_slots, output, SLOT_FRAME_PTR, &slot_frm);
update_dec_hal_info(dec, slot_frm);
dec->info_updated = 1;
}
task->hal_frm_buf_out = hal_buf_out;
task->wait.dec_pic_match = (NULL == hal_buf_out);
if (task->wait.dec_pic_match)
return MPP_NOK;
mpp_hal_reg_gen(dec->hal, &task->info);
mpp_hal_hw_start(dec->hal, &task->info);
mpp_hal_hw_wait(dec->hal, &task->info);
dec->dec_hw_run_count++;
/*
* when hardware decoding is done:
* 1. clear decoding flag (mark buffer is ready)
* 2. use get_display to get a new frame with buffer
* 3. add frame to output list
* repeat 2 and 3 until not frame can be output
*/
mpp_buf_slot_clr_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
if (task_dec->output >= 0)
mpp_buf_slot_clr_flag(frame_slots, task_dec->output, SLOT_HAL_OUTPUT);
for (RK_U32 i = 0; i < MPP_ARRAY_ELEMS(task_dec->refer); i++) {
RK_S32 index = task_dec->refer[i];
if (index >= 0)
mpp_buf_slot_clr_flag(frame_slots, index, SLOT_HAL_INPUT);
}
if (task_dec->flags.eos)
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, task_dec->flags);
(void)frame;
task->status.dec_pkt_copy_rdy = 0;
task->status.curr_task_rdy = 0;
task->status.task_parsed_rdy = 0;
task->status.prev_task_rdy = 0;
dec_task_info_init(&task->info);
return MPP_OK;
}
MPP_RET mpp_dec_reset_no_thread(MppDecImpl *dec)
{
DecTask *task = (DecTask *)dec->task_single;
MppBufSlots frame_slots = dec->frame_slots;
MppMutexCond *cmd_lock = dec->cmd_lock;
HalDecTask *task_dec = &task->info.dec;
RK_S32 index;
AutoMutex auto_lock(cmd_lock->mutex());
task->status.curr_task_rdy = 0;
task->status.prev_task_rdy = 1;
task_dec->valid = 0;
mpp_parser_reset(dec->parser);
mpp_hal_reset(dec->hal);
if (dec->vproc) {
dec_dbg_reset("reset: vproc reset start\n");
dec_vproc_reset(dec->vproc);
dec_dbg_reset("reset: vproc reset done\n");
}
// wait hal thread reset ready
if (task->wait.info_change) {
mpp_log("reset at info change status\n");
mpp_buf_slot_reset(frame_slots, task_dec->output);
}
if (task->status.task_parsed_rdy) {
mpp_log("task no send to hal que must clr current frame hal status\n");
mpp_buf_slot_clr_flag(frame_slots, task_dec->output, SLOT_HAL_OUTPUT);
for (RK_U32 i = 0; i < MPP_ARRAY_ELEMS(task_dec->refer); i++) {
index = task_dec->refer[i];
if (index >= 0)
mpp_buf_slot_clr_flag(frame_slots, index, SLOT_HAL_INPUT);
}
task->status.task_parsed_rdy = 0;
}
while (MPP_OK == mpp_buf_slot_dequeue(frame_slots, &index, QUEUE_DISPLAY)) {
/* release extra ref in slot's MppBuffer */
MppBuffer buffer = NULL;
mpp_buf_slot_get_prop(frame_slots, index, SLOT_BUFFER, &buffer);
if (buffer)
mpp_buffer_put(buffer);
mpp_buf_slot_clr_flag(frame_slots, index, SLOT_QUEUE_USE);
}
if (task->status.dec_pkt_copy_rdy) {
mpp_buf_slot_clr_flag(dec->packet_slots, task_dec->input, SLOT_HAL_INPUT);
task->status.dec_pkt_copy_rdy = 0;
task_dec->input = -1;
}
task->status.task_parsed_rdy = 0;
dec_task_init(task);
dec_dbg_reset("reset: parser reset all done\n");
dec->dec_in_pkt_count = 0;
dec->dec_hw_run_count = 0;
dec->dec_out_frame_count = 0;
dec->info_updated = 0;
cmd_lock->signal();
return MPP_OK;
}
MPP_RET mpp_dec_notify_no_thread(MppDecImpl *dec, RK_U32 flag)
{
// Only notify buffer group control
if (flag == (MPP_DEC_NOTIFY_BUFFER_VALID | MPP_DEC_NOTIFY_BUFFER_MATCH)) {
dec->cmd_lock->signal();
return MPP_OK;
}
return MPP_OK;
}
MPP_RET mpp_dec_control_no_thread(MppDecImpl *dec, MpiCmd cmd, void *param)
{
// cmd_lock is used to sync all async operations
AutoMutex auto_lock(dec->cmd_lock->mutex());
dec->cmd_send++;
return mpp_dec_proc_cfg(dec, cmd, param);
}
MppDecModeApi dec_api_no_thread = {
NULL,
NULL,
mpp_dec_reset_no_thread,
mpp_dec_notify_no_thread,
mpp_dec_control_no_thread,
};

1179
mpp/codec/mpp_dec_normal.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -115,6 +115,7 @@ public:
MPP_RET put_packet(MppPacket packet); MPP_RET put_packet(MppPacket packet);
MPP_RET get_frame(MppFrame *frame); MPP_RET get_frame(MppFrame *frame);
MPP_RET get_frame_noblock(MppFrame *frame);
MPP_RET put_frame(MppFrame frame); MPP_RET put_frame(MppFrame frame);
MPP_RET get_packet(MppPacket *packet); MPP_RET get_packet(MppPacket *packet);
@@ -123,6 +124,8 @@ public:
MPP_RET dequeue(MppPortType type, MppTask *task); MPP_RET dequeue(MppPortType type, MppTask *task);
MPP_RET enqueue(MppPortType type, MppTask task); MPP_RET enqueue(MppPortType type, MppTask task);
MPP_RET decode(MppPacket packet, MppFrame *frame);
MPP_RET reset(); MPP_RET reset();
MPP_RET control(MpiCmd cmd, MppParam param); MPP_RET control(MpiCmd cmd, MppParam param);
@@ -188,6 +191,7 @@ public:
RK_U32 mEncAyncIo; RK_U32 mEncAyncIo;
RK_U32 mEncAyncProc; RK_U32 mEncAyncProc;
MppIoMode mIoMode; MppIoMode mIoMode;
RK_U32 mDisableThread;
/* dump info for debug */ /* dump info for debug */
MppDump mDump; MppDump mDump;

View File

@@ -103,47 +103,23 @@ static MPP_RET mpi_decode(MppCtx ctx, MppPacket packet, MppFrame *frame)
MpiImpl *p = (MpiImpl *)ctx; MpiImpl *p = (MpiImpl *)ctx;
mpi_dbg_func("enter ctx %p packet %p frame %p\n", ctx, packet, frame); mpi_dbg_func("enter ctx %p packet %p frame %p\n", ctx, packet, frame);
do { do {
RK_U32 packet_done = 0;
Mpp *mpp = p->ctx;
ret = check_mpp_ctx(p); ret = check_mpp_ctx(p);
if (ret) if (ret)
break; break;
if (NULL == frame || NULL == packet) { /*
mpp_err_f("found NULL input packet %p frame %p\n", packet, frame); * NOTE: packet and frame could be NULL
ret = MPP_ERR_NULL_PTR; * If packet is NULL then it is equal to get_frame
break; * If frame is NULL then it is equal to put_packet
} */
if (frame)
*frame = NULL; *frame = NULL;
do { ret = p->ctx->decode(packet, frame);
/*
* If there is frame to return get the frame first
* But if the output mode is block then we need to send packet first
*/
if (!mpp->mOutputTimeout || packet_done) {
ret = mpp->get_frame(frame);
if (ret || *frame)
break;
}
/* when packet is send do one more get frame here */
if (packet_done)
break;
/*
* then send input stream with timeout mode
*/
ret = mpp->put_packet(packet);
if (MPP_OK == ret)
packet_done = 1;
} while (1);
} while (0); } while (0);
mpp_assert(0 == mpp_packet_get_length(packet));
mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret);
return ret; return ret;
} }

View File

@@ -41,8 +41,6 @@
#define MPP_TEST_FRAME_SIZE SZ_1M #define MPP_TEST_FRAME_SIZE SZ_1M
#define MPP_TEST_PACKET_SIZE SZ_512K #define MPP_TEST_PACKET_SIZE SZ_512K
typedef MPP_RET (*QueueFunc)(Mpp* mpp, MppPortType type, MppTask *task);
static void mpp_notify_by_buffer_group(void *arg, void *group) static void mpp_notify_by_buffer_group(void *arg, void *group)
{ {
Mpp *mpp = (Mpp *)arg; Mpp *mpp = (Mpp *)arg;
@@ -103,6 +101,7 @@ Mpp::Mpp(MppCtx ctx)
mEncAyncIo(0), mEncAyncIo(0),
mEncAyncProc(0), mEncAyncProc(0),
mIoMode(MPP_IO_MODE_DEFAULT), mIoMode(MPP_IO_MODE_DEFAULT),
mDisableThread(0),
mDump(NULL), mDump(NULL),
mType(MPP_CTX_BUTT), mType(MPP_CTX_BUTT),
mCoding(MPP_VIDEO_CodingUnused), mCoding(MPP_VIDEO_CodingUnused),
@@ -172,6 +171,9 @@ MPP_RET Mpp::init(MppCtxType type, MppCodingType coding)
mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT); mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT);
mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT); mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT);
mDecInitcfg.base.disable_thread = mDisableThread;
mDecInitcfg.base.change |= MPP_DEC_CFG_CHANGE_DISABLE_THREAD;
MppDecInitCfg cfg = { MppDecInitCfg cfg = {
coding, coding,
this, this,
@@ -316,6 +318,7 @@ void Mpp::clear()
mpp_buffer_group_put(mPacketGroup); mpp_buffer_group_put(mPacketGroup);
mPacketGroup = NULL; mPacketGroup = NULL;
} }
if (mFrameGroup && !mExternalFrameGroup) { if (mFrameGroup && !mExternalFrameGroup) {
mpp_buffer_group_put(mFrameGroup); mpp_buffer_group_put(mFrameGroup);
mFrameGroup = NULL; mFrameGroup = NULL;
@@ -354,6 +357,11 @@ MPP_RET Mpp::put_packet(MppPacket packet)
MppTask task_dequeue = NULL; MppTask task_dequeue = NULL;
RK_U32 pkt_copy = 0; RK_U32 pkt_copy = 0;
if (mDisableThread) {
mpp_err_f("no thread decoding case MUST use mpi_decode interface\n");
return ret;
}
if (mExtraPacket) { if (mExtraPacket) {
MppPacket extra = mExtraPacket; MppPacket extra = mExtraPacket;
@@ -504,6 +512,61 @@ MPP_RET Mpp::get_frame(MppFrame *frame)
return MPP_OK; return MPP_OK;
} }
MPP_RET Mpp::get_frame_noblock(MppFrame *frame)
{
MppFrame first = NULL;
if (!mInitDone)
return MPP_ERR_INIT;
mFrmOut->lock();
if (mFrmOut->list_size()) {
mFrmOut->del_at_head(&first, sizeof(frame));
mFrameGetCount++;
}
mFrmOut->unlock();
*frame = first;
return MPP_OK;
}
MPP_RET Mpp::decode(MppPacket packet, MppFrame *frame)
{
RK_U32 packet_done = 0;
MPP_RET ret = MPP_NOK;
if (!mDec)
return MPP_NOK;
do {
/*
* If there is frame to return get the frame first
* But if the output mode is block then we need to send packet first
*/
if (!mOutputTimeout || packet_done) {
ret = get_frame_noblock(frame);
if (ret || *frame)
break;
}
/* when packet is send do one more get frame here */
if (packet_done)
break;
ret = mpp_dec_decode(mDec, packet, frame);
if (!ret)
packet_done = 1;
if (!mOutputTimeout || packet_done) {
ret = get_frame_noblock(frame);
if (ret || *frame)
break;
}
} while (1);
return ret;
}
MPP_RET Mpp::put_frame(MppFrame frame) MPP_RET Mpp::put_frame(MppFrame frame)
{ {
if (!mInitDone) if (!mInitDone)
@@ -979,6 +1042,10 @@ MPP_RET Mpp::control_mpp(MpiCmd cmd, MppParam param)
mpp_log("deprecated block control, use timeout control instead\n"); mpp_log("deprecated block control, use timeout control instead\n");
} break; } break;
case MPP_SET_DISABLE_THREAD: {
mDisableThread = 1;
} break;
case MPP_SET_INPUT_TIMEOUT: case MPP_SET_INPUT_TIMEOUT:
case MPP_SET_OUTPUT_TIMEOUT: { case MPP_SET_OUTPUT_TIMEOUT: {
MppPollType timeout = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK; MppPollType timeout = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK;

View File

@@ -30,6 +30,9 @@ add_mpp_test(mpi_dec c)
# mpi decoder multi-thread input / output unit test # mpi decoder multi-thread input / output unit test
add_mpp_test(mpi_dec_mt c) add_mpp_test(mpi_dec_mt c)
# mpi decoder no-thread input / output unit test
add_mpp_test(mpi_dec_nt c)
# mpi encoder unit test # mpi encoder unit test
add_mpp_test(mpi_enc c) add_mpp_test(mpi_enc c)

602
test/mpi_dec_nt_test.c Normal file
View File

@@ -0,0 +1,602 @@
/*
* Copyright 2022 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.
*/
#if defined(_WIN32)
#include "vld.h"
#endif
#define MODULE_TAG "mpi_dec_nt_test"
#include <string.h>
#include "rk_mpi.h"
#include "mpp_mem.h"
#include "mpp_env.h"
#include "mpp_time.h"
#include "mpp_common.h"
#include "mpi_dec_utils.h"
typedef struct {
MpiDecTestCmd *cmd;
MppCtx ctx;
MppApi *mpi;
RK_U32 quiet;
/* end of stream flag when set quit the loop */
RK_U32 loop_end;
/* input and output */
MppBufferGroup frm_grp;
MppPacket packet;
MppFrame frame;
FILE *fp_output;
RK_S32 frame_count;
RK_S32 frame_num;
RK_S64 first_pkt;
RK_S64 first_frm;
size_t max_usage;
float frame_rate;
RK_S64 elapsed_time;
RK_S64 delay;
FILE *fp_verify;
FrmCrc checkcrc;
} MpiDecLoopData;
static int dec_loop(MpiDecLoopData *data)
{
RK_U32 pkt_done = 0;
RK_U32 pkt_eos = 0;
MPP_RET ret = MPP_OK;
MpiDecTestCmd *cmd = data->cmd;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
MppPacket packet = data->packet;
FileBufSlot *slot = NULL;
RK_U32 quiet = data->quiet;
FrmCrc *checkcrc = &data->checkcrc;
// when packet size is valid read the input binary file
ret = reader_read(cmd->reader, &slot);
mpp_assert(ret == MPP_OK);
mpp_assert(slot);
pkt_eos = slot->eos;
if (pkt_eos) {
if (data->frame_num < 0 || data->frame_num > data->frame_count) {
mpp_log_q(quiet, "%p loop again\n", ctx);
reader_rewind(cmd->reader);
pkt_eos = 0;
} else {
mpp_log_q(quiet, "%p found last packet\n", ctx);
data->loop_end = 1;
}
}
mpp_packet_set_data(packet, slot->data);
mpp_packet_set_size(packet, slot->size);
mpp_packet_set_pos(packet, slot->data);
mpp_packet_set_length(packet, slot->size);
// setup eos flag
if (pkt_eos)
mpp_packet_set_eos(packet);
do {
RK_U32 frm_eos = 0;
RK_S32 get_frm = 0;
MppFrame frame = NULL;
// send the packet first if packet is not done
ret = mpi->decode(ctx, packet, &frame);
if (ret)
mpp_err("decode failed ret %d\n", ret);
// then get all available frame and release
if (frame) {
if (mpp_frame_get_info_change(frame)) {
RK_U32 width = mpp_frame_get_width(frame);
RK_U32 height = mpp_frame_get_height(frame);
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(frame);
mpp_log_q(quiet, "%p decode_get_frame get info changed found\n", ctx);
mpp_log_q(quiet, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
ctx, width, height, hor_stride, ver_stride, buf_size);
/*
* NOTE: We can choose decoder's buffer mode here.
* There are three mode that decoder can support:
*
* Mode 1: Pure internal mode
* In the mode user will NOT call MPP_DEC_SET_EXT_BUF_GROUP
* control to decoder. Only call MPP_DEC_SET_INFO_CHANGE_READY
* to let decoder go on. Then decoder will use create buffer
* internally and user need to release each frame they get.
*
* Advantage:
* Easy to use and get a demo quickly
* Disadvantage:
* 1. The buffer from decoder may not be return before
* decoder is close. So memroy leak or crash may happen.
* 2. The decoder memory usage can not be control. Decoder
* is on a free-to-run status and consume all memory it can
* get.
* 3. Difficult to implement zero-copy display path.
*
* Mode 2: Half internal mode
* This is the mode current test code using. User need to
* create MppBufferGroup according to the returned info
* change MppFrame. User can use mpp_buffer_group_limit_config
* function to limit decoder memory usage.
*
* Advantage:
* 1. Easy to use
* 2. User can release MppBufferGroup after decoder is closed.
* So memory can stay longer safely.
* 3. Can limit the memory usage by mpp_buffer_group_limit_config
* Disadvantage:
* 1. The buffer limitation is still not accurate. Memory usage
* is 100% fixed.
* 2. Also difficult to implement zero-copy display path.
*
* Mode 3: Pure external mode
* In this mode use need to create empty MppBufferGroup and
* import memory from external allocator by file handle.
* On Android surfaceflinger will create buffer. Then
* mediaserver get the file handle from surfaceflinger and
* commit to decoder's MppBufferGroup.
*
* Advantage:
* 1. Most efficient way for zero-copy display
* Disadvantage:
* 1. Difficult to learn and use.
* 2. Player work flow may limit this usage.
* 3. May need a external parser to get the correct buffer
* size for the external allocator.
*
* The required buffer size caculation:
* hor_stride * ver_stride * 3 / 2 for pixel data
* hor_stride * ver_stride / 2 for extra info
* Total hor_stride * ver_stride * 2 will be enough.
*
* For H.264/H.265 20+ buffers will be enough.
* For other codec 10 buffers will be enough.
*/
if (NULL == data->frm_grp) {
/* If buffer group is not set create one and limit it */
ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
mpp_err("%p get mpp buffer group failed ret %d\n", ctx, ret);
break;
}
/* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
if (ret) {
mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
break;
}
} else {
/* If old buffer group exist clear it */
ret = mpp_buffer_group_clear(data->frm_grp);
if (ret) {
mpp_err("%p clear buffer group failed ret %d\n", ctx, ret);
break;
}
}
/* Use limit config to limit buffer count to 24 with buf_size */
ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
if (ret) {
mpp_err("%p limit buffer group failed ret %d\n", ctx, ret);
break;
}
/*
* All buffer group config done. Set info change ready to let
* decoder continue decoding
*/
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
if (ret) {
mpp_err("%p info change ready failed ret %d\n", ctx, ret);
break;
}
} else {
char log_buf[256];
RK_S32 log_size = sizeof(log_buf) - 1;
RK_S32 log_len = 0;
RK_U32 err_info = mpp_frame_get_errinfo(frame);
RK_U32 discard = mpp_frame_get_discard(frame);
if (!data->first_frm)
data->first_frm = mpp_time();
log_len += snprintf(log_buf + log_len, log_size - log_len,
"decode get frame %d", data->frame_count);
if (mpp_frame_has_meta(frame)) {
MppMeta meta = mpp_frame_get_meta(frame);
RK_S32 temporal_id = 0;
mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id);
log_len += snprintf(log_buf + log_len, log_size - log_len,
" tid %d", temporal_id);
}
if (err_info || discard) {
log_len += snprintf(log_buf + log_len, log_size - log_len,
" err %x discard %x", err_info, discard);
}
mpp_log_q(quiet, "%p %s\n", ctx, log_buf);
data->frame_count++;
if (data->fp_output && !err_info)
dump_mpp_frame_to_file(frame, data->fp_output);
if (data->fp_verify) {
calc_frm_crc(frame, checkcrc);
write_frm_crc(data->fp_verify, checkcrc);
}
fps_calc_inc(cmd->fps);
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
get_frm = 1;
}
// try get runtime frame memory usage
if (data->frm_grp) {
size_t usage = mpp_buffer_group_usage(data->frm_grp);
if (usage > data->max_usage)
data->max_usage = usage;
}
// when get one output frame check the output frame count limit
if (get_frm) {
if (data->frame_num > 0) {
// when get enough frame quit
if (data->frame_count >= data->frame_num) {
data->loop_end = 1;
break;
}
} else {
// when get last frame quit
if (frm_eos) {
mpp_log_q(quiet, "%p found last packet\n", ctx);
data->loop_end = 1;
break;
}
}
}
if (packet) {
if (mpp_packet_get_length(packet)) {
msleep(1);
continue;
}
if (!data->first_pkt)
data->first_pkt = mpp_time();
packet = NULL;
pkt_done = 1;
}
mpp_assert(pkt_done);
// if last packet is send but last frame is not found continue
if (pkt_eos && !frm_eos) {
msleep(1);
continue;
}
if (pkt_done)
break;
/*
* why sleep here:
* mpi->decode_put_packet will failed when packet in internal queue is
* full,waiting the package is consumed .Usually hardware decode one
* frame which resolution is 1080p needs 2 ms,so here we sleep 1ms
* * is enough.
*/
msleep(1);
} while (1);
return ret;
}
void *thread_decode(void *arg)
{
MpiDecLoopData *data = (MpiDecLoopData *)arg;
RK_S64 t_s, t_e;
memset(&data->checkcrc, 0, sizeof(data->checkcrc));
data->checkcrc.luma.sum = mpp_malloc(RK_ULONG, 512);
data->checkcrc.chroma.sum = mpp_malloc(RK_ULONG, 512);
t_s = mpp_time();
while (!data->loop_end)
dec_loop(data);
t_e = mpp_time();
data->elapsed_time = t_e - t_s;
data->frame_count = data->frame_count;
data->frame_rate = (float)data->frame_count * 1000000 / data->elapsed_time;
data->delay = data->first_frm - data->first_pkt;
mpp_log("decode %d frames time %lld ms delay %3d ms fps %3.2f\n",
data->frame_count, (RK_S64)(data->elapsed_time / 1000),
(RK_S32)(data->delay / 1000), data->frame_rate);
MPP_FREE(data->checkcrc.luma.sum);
MPP_FREE(data->checkcrc.chroma.sum);
return NULL;
}
int dec_nt_decode(MpiDecTestCmd *cmd)
{
// base flow context
MppCtx ctx = NULL;
MppApi *mpi = NULL;
// input / output
MppPacket packet = NULL;
MppFrame frame = NULL;
// paramter for resource malloc
RK_U32 width = cmd->width;
RK_U32 height = cmd->height;
MppCodingType type = cmd->type;
// config for runtime mode
MppDecCfg cfg = NULL;
RK_U32 need_split = 1;
// resources
MppBuffer frm_buf = NULL;
pthread_t thd;
pthread_attr_t attr;
MpiDecLoopData data;
MPP_RET ret = MPP_OK;
mpp_log("mpi_dec_test start\n");
memset(&data, 0, sizeof(data));
pthread_attr_init(&attr);
cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
if (cmd->have_output) {
data.fp_output = fopen(cmd->file_output, "w+b");
if (NULL == data.fp_output) {
mpp_err("failed to open output file %s\n", cmd->file_output);
goto MPP_TEST_OUT;
}
}
if (cmd->file_slt) {
data.fp_verify = fopen(cmd->file_slt, "wt");
if (!data.fp_verify)
mpp_err("failed to open verify file %s\n", cmd->file_slt);
}
if (cmd->simple) {
ret = mpp_packet_init(&packet, NULL, 0);
mpp_err_f("mpp_packet_init get %p\n", packet);
if (ret) {
mpp_err("mpp_packet_init failed\n");
goto MPP_TEST_OUT;
}
} else {
RK_U32 hor_stride = MPP_ALIGN(width, 16);
RK_U32 ver_stride = MPP_ALIGN(height, 16);
ret = mpp_buffer_group_get_internal(&data.frm_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
mpp_err("failed to get buffer group for input frame ret %d\n", ret);
goto MPP_TEST_OUT;
}
ret = mpp_frame_init(&frame); /* output frame */
if (ret) {
mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT;
}
/*
* NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16.
* YUV420 buffer is 3/2 times of w*h.
* YUV422 buffer is 2 times of w*h.
* So create larger buffer with 2 times w*h.
*/
ret = mpp_buffer_get(data.frm_grp, &frm_buf, hor_stride * ver_stride * 4);
if (ret) {
mpp_err("failed to get buffer for input frame ret %d\n", ret);
goto MPP_TEST_OUT;
}
mpp_frame_set_buffer(frame, frm_buf);
}
// decoder demo
ret = mpp_create(&ctx, &mpi);
if (ret) {
mpp_err("mpp_create failed\n");
goto MPP_TEST_OUT;
}
mpp_log("%p mpi_dec_test decoder test start w %d h %d type %d\n",
ctx, width, height, type);
ret = mpi->control(ctx, MPP_SET_DISABLE_THREAD, NULL);
ret = mpp_init(ctx, MPP_CTX_DEC, type);
if (ret) {
mpp_err("%p mpp_init failed\n", ctx);
goto MPP_TEST_OUT;
}
mpp_dec_cfg_init(&cfg);
/* get default config from decoder context */
ret = mpi->control(ctx, MPP_DEC_GET_CFG, cfg);
if (ret) {
mpp_err("%p failed to get decoder cfg ret %d\n", ctx, ret);
goto MPP_TEST_OUT;
}
/*
* split_parse is to enable mpp internal frame spliter when the input
* packet is not aplited into frames.
*/
ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", need_split);
if (ret) {
mpp_err("%p failed to set split_parse ret %d\n", ctx, ret);
goto MPP_TEST_OUT;
}
ret = mpi->control(ctx, MPP_DEC_SET_CFG, cfg);
if (ret) {
mpp_err("%p failed to set cfg %p ret %d\n", ctx, cfg, ret);
goto MPP_TEST_OUT;
}
data.cmd = cmd;
data.ctx = ctx;
data.mpi = mpi;
data.loop_end = 0;
data.packet = packet;
data.frame = frame;
data.frame_count = 0;
data.frame_num = cmd->frame_num;
data.quiet = cmd->quiet;
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
ret = pthread_create(&thd, &attr, thread_decode, &data);
if (ret) {
mpp_err("failed to create thread for input ret %d\n", ret);
goto MPP_TEST_OUT;
}
if (cmd->frame_num < 0) {
// wait for input then quit decoding
mpp_log("*******************************************\n");
mpp_log("**** Press Enter to stop loop decoding ****\n");
mpp_log("*******************************************\n");
getc(stdin);
data.loop_end = 1;
}
pthread_join(thd, NULL);
cmd->max_usage = data.max_usage;
ret = mpi->reset(ctx);
if (ret) {
mpp_err("%p mpi->reset failed\n", ctx);
goto MPP_TEST_OUT;
}
MPP_TEST_OUT:
if (data.packet) {
mpp_packet_deinit(&data.packet);
data.packet = NULL;
}
if (frame) {
mpp_frame_deinit(&frame);
frame = NULL;
}
if (ctx) {
mpp_destroy(ctx);
ctx = NULL;
}
if (!cmd->simple) {
if (frm_buf) {
mpp_buffer_put(frm_buf);
frm_buf = NULL;
}
}
if (data.frm_grp) {
mpp_buffer_group_put(data.frm_grp);
data.frm_grp = NULL;
}
if (data.fp_output) {
fclose(data.fp_output);
data.fp_output = NULL;
}
if (data.fp_verify) {
fclose(data.fp_verify);
data.fp_verify = NULL;
}
if (cfg) {
mpp_dec_cfg_deinit(cfg);
cfg = NULL;
}
pthread_attr_destroy(&attr);
return ret;
}
int main(int argc, char **argv)
{
RK_S32 ret = 0;
MpiDecTestCmd cmd_ctx;
MpiDecTestCmd* cmd = &cmd_ctx;
memset((void*)cmd, 0, sizeof(*cmd));
cmd->format = MPP_FMT_BUTT;
cmd->pkt_size = MPI_DEC_STREAM_SIZE;
// parse the cmd option
ret = mpi_dec_test_cmd_init(cmd, argc, argv);
if (ret)
goto RET;
mpi_dec_test_cmd_options(cmd);
ret = dec_nt_decode(cmd);
if (MPP_OK == ret)
mpp_log("test success max memory %.2f MB\n", cmd->max_usage / (float)(1 << 20));
else
mpp_err("test failed ret %d\n", ret);
RET:
mpi_dec_test_cmd_deinit(cmd);
return ret;
}