mpp-nyanmisaka/mpp/vproc/mpp_dec_vproc.cpp
Herman Chen 9431bbc980 fix[vproc]: Fix deadlock in vproc thread
BUG is reported from https://redmine.rock-chips.com/issues/464206

Thread 18 (LWP 2440):
#0  __lll_lock_wait (futex=0x7f34000d48, private=0) at lowlevellock.c:52
#1  0x0000007fab5b1540 in __GI___pthread_mutex_lock (mutex=0x7f34000d48) at pthread_mutex_lock.c:115
#2  0x0000007fa9e0299c in dec_vproc_signal (ctx=0x7f34001260) at ../git/mpp/vproc/mpp_dec_vproc.cpp:929
#3  0x0000007fa9df5bdc in mpp_dec_notify (ctx=0x7f602be600, flag=1088) at ../git/mpp/codec/mpp_dec.cpp:956
#4  0x0000007fa9e0ef30 in mpp_buffer_ref_dec (buffer=0x7f6403f6c8, caller=caller@entry=0x7fa9ee300c "mpp_frame_deinit") at ../git/mpp/base/mpp_buffer_impl.cpp:509
#5  0x0000007fa9e0fb84 in mpp_buffer_put_with_caller (buffer=<optimized out>, caller=caller@entry=0x7fa9ee300c "mpp_frame_deinit") at ../git/mpp/base/mpp_buffer.cpp:105
#6  0x0000007fa9e11820 in mpp_frame_deinit (frame=frame@entry=0x7f602ec340) at ../git/mpp/base/mpp_frame.cpp:85
#7  0x0000007fabd6bf4c in rkmpp_release_frame (opaque=<optimized out>, data=0x7f602ba600 <error: Cannot access memory at address 0x7f602ba600>) at src/libavcodec/rkmppdec.c:339
#8  0x0000007fab9547dc in buffer_replace (src=0x0, dst=<optimized out>) at src/libavutil/buffer.c:133
#9  av_buffer_unref (buf=<optimized out>) at src/libavutil/buffer.c:144
#10 0x0000007fac714bb8 in mp_image_destructor (ptr=0x7f60252c80) at ../../../../../../sources/mpv/video/mp_image.c:209
#11 0x0000007fac748d40 in ta_free (ptr=0x7f60252c80) at ../../../../../../sources/mpv/ta/ta.c:244
#12 0x0000007fac715178 in mp_image_unrefp (p_img=p_img@entry=0x7f4c00bfc0) at ../../../../../../sources/mpv/video/mp_image.c:472
#13 0x0000007fac73396c in wlbuf_pool_entry_release (data=0x7f4c00bfa0, wl_buffer=<optimized out>) at ../../../../../../sources/mpv/video/out/wlbuf_pool.c:132
#14 0x0000007fb4cfe328 in ffi_call_SYSV () at ../libffi-3.3/src/aarch64/sysv.S:114
#15 0x0000007fb4cfdb44 in ffi_call_int (cif=cif@entry=0x7f70fdec80, fn=0x7f70fdeca0, orig_rvalue=orig_rvalue@entry=0x0, avalue=0x10, avalue@entry=0x7f70fded50, closure=0x200000001, closure@entry=0x0) at ../libffi-3.3/src/aarch64/ffi.c:747
#16 0x0000007fb4cfdf24 in ffi_call (cif=cif@entry=0x7f70fdec80, fn=<optimized out>, rvalue=rvalue@entry=0x0, avalue=avalue@entry=0x7f70fded50) at ../libffi-3.3/src/aarch64/ffi.c:756
#17 0x0000007faa49c7c0 in wl_closure_invoke (closure=0x7f4c00bff0, flags=<optimized out>, target=<optimized out>, opcode=0, data=<optimized out>) at ../wayland-1.22.0/src/connection.c:1025
#18 0x0000007faa499df0 in dispatch_event (display=display@entry=0x7f4c001d40, queue=<optimized out>) at ../wayland-1.22.0/src/wayland-client.c:1644
#19 0x0000007faa49b2c8 in dispatch_queue (queue=0x7f4c001e30, display=0x7f4c001d40) at ../wayland-1.22.0/src/wayland-client.c:1790
#20 wl_display_dispatch_queue_pending (display=0x7f4c001d40, queue=0x7f4c001e30) at ../wayland-1.22.0/src/wayland-client.c:2032
#21 0x0000007faa49b2f4 in wl_display_dispatch_pending (display=<optimized out>) at ../wayland-1.22.0/src/wayland-client.c:2095
#22 0x0000007fac73e2cc in vo_wayland_dispatch_events (wl=0x7f4c000e40, nfds=nfds@entry=2, timeout=timeout@entry=100) at ../../../../../../sources/mpv/video/out/wayland_common.c:1933
#23 0x0000007fac741d7c in vo_wayland_wait_events_timeout (vo=vo@entry=0x7f600abed0, timeout_ms=timeout_ms@entry=100) at ../../../../../../sources/mpv/video/out/wayland_common.c:2594
#24 0x0000007fac73baf4 in draw_frame (vo=0x7f600abed0, frame=0x7f302063b0) at ../../../../../../sources/mpv/video/out/vo_dmabuf_wayland.c:1113
#25 0x0000007fac7360c4 in render_frame (vo=0x7f600abed0) at ../../../../../../sources/mpv/video/out/vo.c:984
#26 vo_thread (ptr=0x7f600abed0) at ../../../../../../sources/mpv/video/out/vo.c:1123
#27 0x0000007fab5af370 in start_thread (arg=0x7f72ffbe06) at pthread_create.c:477
#28 0x0000007fab51bedc in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78

Thread 14 (LWP 3455):
#0  __lll_lock_wait (futex=0x7f60208040, private=0) at lowlevellock.c:52
#1  0x0000007fab5b1540 in __GI___pthread_mutex_lock (mutex=mutex@entry=0x7f60208040) at pthread_mutex_lock.c:115
#2  0x0000007fa9e0ef48 in mpp_buffer_ref_dec (buffer=0x7f6406fee8, caller=caller@entry=0x7fa9ee1ae7 "check_entry_unused") at ../git/mpp/base/mpp_buffer_impl.cpp:503
#3  0x0000007fa9e0fb84 in mpp_buffer_put_with_caller (buffer=<optimized out>, caller=caller@entry=0x7fa9ee1ae7 "check_entry_unused") at ../git/mpp/base/mpp_buffer.cpp:105
#4  0x0000007fa9e0bf1c in check_entry_unused (entry=0x7f601ef530, impl=0x7f60263ec0) at ../git/mpp/base/mpp_buf_slot.cpp:627
#5  mpp_buf_slot_clr_flag (slots=0x7f60263ec0, index=<optimized out>, type=type@entry=SLOT_QUEUE_USE) at ../git/mpp/base/mpp_buf_slot.cpp:919
#6  0x0000007fa9e00eb0 in dec_vproc_clr_prev0 (ctx=ctx@entry=0x7f34001260) at ../git/mpp/vproc/mpp_dec_vproc.cpp:149
#7  0x0000007fa9e00fd0 in dec_vproc_clr_prev (ctx=ctx@entry=0x7f34001260) at ../git/mpp/vproc/mpp_dec_vproc.cpp:180
#8  0x0000007fa9e012b8 in dec_vproc_thread (data=0x7f34001260) at ../git/mpp/vproc/mpp_dec_vproc.cpp:631
#9  0x0000007fab5af370 in start_thread (arg=0x7f47ffdf16) at pthread_create.c:477
#10 0x0000007fab51bedc in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I742e55e745c46a4adb229e2f6f0e2a2c3498e369
2024-02-05 10:33:35 +08:00

971 lines
29 KiB
C++

/*
* Copyright 2020 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_vproc"
#include <string.h>
#include "mpp_env.h"
#include "mpp_mem.h"
#include "mpp_common.h"
#include "mpp_dec_impl.h"
#include "mpp_frame_impl.h"
#include "mpp_dec_vproc.h"
#include "iep_api.h"
#include "iep2_api.h"
#define DUMP_FILE 1
#define dec_vproc_dbg(flag, fmt, ...) \
do { \
_mpp_dbg(vproc_debug, flag, fmt, ## __VA_ARGS__); \
} while (0)
#define vproc_dbg_f(flag, fmt, ...) \
do { \
_mpp_dbg_f(vproc_debug, flag, fmt, ## __VA_ARGS__); \
} while (0)
#define VPROC_DBG_FUNCTION (0x00000001)
#define VPROC_DBG_STATUS (0x00000002)
#define VPROC_DBG_RESET (0x00000004)
#define VPROC_DBG_DUMP_IN (0x00000010)
#define VPROC_DBG_DUMP_OUT (0x00000020)
#define vproc_dbg_func(fmt, ...) \
vproc_dbg_f(VPROC_DBG_FUNCTION, fmt, ## __VA_ARGS__);
#define vproc_dbg_status(fmt, ...) \
vproc_dbg_f(VPROC_DBG_STATUS, fmt, ## __VA_ARGS__);
#define vproc_dbg_reset(fmt, ...) \
vproc_dbg_f(VPROC_DBG_RESET, fmt, ## __VA_ARGS__);
RK_U32 vproc_debug = 0;
typedef union VprocTaskStatus_u {
RK_U32 val;
struct {
RK_U32 task_rdy : 1;
RK_U32 buf_rdy : 1;
};
} VprocTaskStatus;
typedef union VprocTaskWait_u {
RK_U32 val;
struct {
RK_U32 task_in : 1;
RK_U32 task_buf_in : 1;
};
} VprocTaskWait;
typedef struct MppDecVprocCtxImpl_t {
Mpp *mpp;
HalTaskGroup task_group;
MppBufSlots slots;
MppThread *thd;
RK_U32 reset;
sem_t reset_sem;
IepCtx iep_ctx;
iep_com_ctx *com_ctx;
IepCmdParamDeiCfg dei_cfg;
iep2_api_info dei_info;
VprocTaskStatus task_status;
VprocTaskWait task_wait;
// slot index for previous frame and current frame
RK_S32 prev_idx0;
MppFrame prev_frm0;
RK_S32 prev_idx1;
MppFrame prev_frm1;
RK_U32 detection;
RK_U32 pd_mode;
MppBuffer out_buf0;
MppBuffer out_buf1;
} MppDecVprocCtxImpl;
static void dec_vproc_put_frame(Mpp *mpp, MppFrame frame, MppBuffer buf, RK_S64 pts, RK_U32 err)
{
mpp_list *list = mpp->mFrmOut;
MppFrame out = NULL;
MppFrameImpl *impl = NULL;
mpp_frame_init(&out);
mpp_frame_copy(out, frame);
mpp_frame_set_errinfo(out, err);
impl = (MppFrameImpl *)out;
if (pts >= 0)
impl->pts = pts;
if (buf)
impl->buffer = buf;
list->lock();
list->add_at_tail(&out, sizeof(out));
mpp_dbg_pts("output frame pts %lld\n", mpp_frame_get_pts(out));
mpp->mFramePutCount++;
list->signal();
list->unlock();
if (mpp->mDec)
mpp_dec_callback(mpp->mDec, MPP_DEC_EVENT_ON_FRM_READY, out);
}
static void dec_vproc_clr_prev0(MppDecVprocCtxImpl *ctx)
{
if (vproc_debug & VPROC_DBG_STATUS) {
if (ctx->prev_frm0) {
MppBuffer buf = mpp_frame_get_buffer(ctx->prev_frm0);
RK_S32 fd = (buf) ? (mpp_buffer_get_fd(buf)) : (-1);
mpp_log("clearing prev index %d frm %p fd %d\n", ctx->prev_idx0,
ctx->prev_frm0, fd);
} else
mpp_log("clearing nothing\n");
}
if (ctx->prev_frm0) {
MppBuffer buf = mpp_frame_get_buffer(ctx->prev_frm0);
if (buf)
mpp_buffer_put(buf);
}
if (ctx->prev_idx0 >= 0)
mpp_buf_slot_clr_flag(ctx->slots, ctx->prev_idx0, SLOT_QUEUE_USE);
ctx->prev_idx0 = -1;
ctx->prev_frm0 = NULL;
}
static void dec_vproc_clr_prev1(MppDecVprocCtxImpl *ctx)
{
if (vproc_debug & VPROC_DBG_STATUS) {
if (ctx->prev_frm1) {
MppBuffer buf = mpp_frame_get_buffer(ctx->prev_frm1);
RK_S32 fd = (buf) ? (mpp_buffer_get_fd(buf)) : (-1);
mpp_log("clearing prev index %d frm %p fd %d\n", ctx->prev_idx1,
ctx->prev_frm1, fd);
} else
mpp_log("clearing nothing\n");
}
if (ctx->prev_frm1) {
MppBuffer buf = mpp_frame_get_buffer(ctx->prev_frm1);
if (buf)
mpp_buffer_put(buf);
}
if (ctx->prev_idx1 >= 0)
mpp_buf_slot_clr_flag(ctx->slots, ctx->prev_idx1, SLOT_QUEUE_USE);
ctx->prev_idx1 = -1;
ctx->prev_frm1 = NULL;
}
static void dec_vproc_clr_prev(MppDecVprocCtxImpl *ctx)
{
dec_vproc_clr_prev0(ctx);
dec_vproc_clr_prev1(ctx);
if (ctx->out_buf0) {
mpp_buffer_put(ctx->out_buf0);
ctx->out_buf0 = NULL;
}
if (ctx->out_buf1) {
mpp_buffer_put(ctx->out_buf1);
ctx->out_buf1 = NULL;
}
}
static void dec_vproc_set_img_fmt(IepImg *img, MppFrame frm)
{
memset(img, 0, sizeof(*img));
img->act_w = mpp_frame_get_width(frm);
img->act_h = mpp_frame_get_height(frm);
img->vir_w = mpp_frame_get_hor_stride(frm);
img->vir_h = mpp_frame_get_ver_stride(frm);
img->format = IEP_FORMAT_YCbCr_420_SP;
}
static void dec_vproc_set_img(MppDecVprocCtxImpl *ctx, IepImg *img, RK_S32 fd, IepCmd cmd)
{
RK_S32 y_size = img->vir_w * img->vir_h;
img->mem_addr = fd;
img->uv_addr = fd + (y_size << 10);
img->v_addr = fd + ((y_size + y_size / 4) << 10);
MPP_RET ret = ctx->com_ctx->ops->control(ctx->iep_ctx, cmd, img);
if (ret)
mpp_log_f("control %08x failed %d\n", cmd, ret);
}
// start deinterlace hardware
static void dec_vproc_start_dei(MppDecVprocCtxImpl *ctx, RK_U32 mode)
{
MPP_RET ret;
if (ctx->com_ctx->ver == 1) {
ctx->dei_cfg.dei_field_order =
(mode & MPP_FRAME_FLAG_TOP_FIRST) ?
(IEP_DEI_FLD_ORDER_TOP_FIRST) :
(IEP_DEI_FLD_ORDER_BOT_FIRST);
ret = ctx->com_ctx->ops->control(ctx->iep_ctx,
IEP_CMD_SET_DEI_CFG, &ctx->dei_cfg);
if (ret)
mpp_log_f("IEP_CMD_SET_DEI_CFG failed %d\n", ret);
}
ret = ctx->com_ctx->ops->control(ctx->iep_ctx, IEP_CMD_RUN_SYNC, &ctx->dei_info);
if (ret)
mpp_log_f("IEP_CMD_RUN_SYNC failed %d\n", ret);
}
static void dec_vproc_set_dei_v1(MppDecVprocCtxImpl *ctx, MppFrame frm)
{
MPP_RET ret = MPP_OK;
IepImg img;
Mpp *mpp = ctx->mpp;
RK_U32 mode = mpp_frame_get_mode(frm);
MppBuffer buf = mpp_frame_get_buffer(frm);
MppBuffer dst0 = ctx->out_buf0;
MppBuffer dst1 = ctx->out_buf1;
int fd = -1;
RK_U32 frame_err = 0;
// setup source IepImg
dec_vproc_set_img_fmt(&img, frm);
ret = ctx->com_ctx->ops->control(ctx->iep_ctx, IEP_CMD_INIT, NULL);
if (ret)
mpp_log_f("IEP_CMD_INIT failed %d\n", ret);
IepCap_t *cap = NULL;
ret = ctx->com_ctx->ops->control(ctx->iep_ctx, IEP_CMD_QUERY_CAP, &cap);
if (ret)
mpp_log_f("IEP_CMD_QUERY_CAP failed %d\n", ret);
// setup destination IepImg with new buffer
// NOTE: when deinterlace is enabled parser thread will reserve
// more buffer than normal case
if (ctx->prev_frm0 && cap && cap->i4_deinterlace_supported) {
// 4 in 2 out case
vproc_dbg_status("4 field in and 2 frame out\n");
RK_S64 prev_pts = mpp_frame_get_pts(ctx->prev_frm0);
RK_S64 curr_pts = mpp_frame_get_pts(frm);
RK_S64 first_pts = (prev_pts + curr_pts) / 2;
buf = mpp_frame_get_buffer(ctx->prev_frm0);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_SRC);
frame_err = mpp_frame_get_errinfo(ctx->prev_frm0) ||
mpp_frame_get_discard(ctx->prev_frm0);
// setup dst 0
mpp_assert(dst0);
fd = mpp_buffer_get_fd(dst0);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DST);
buf = mpp_frame_get_buffer(frm);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_SRC1);
frame_err |= mpp_frame_get_errinfo(frm) ||
mpp_frame_get_discard(frm);
// setup dst 1
mpp_assert(dst1);
fd = mpp_buffer_get_fd(dst1);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_DST1);
ctx->dei_cfg.dei_mode = IEP_DEI_MODE_I4O2;
mode = mode | MPP_FRAME_FLAG_IEP_DEI_I4O2;
mpp_frame_set_mode(frm, mode);
// start hardware
dec_vproc_start_dei(ctx, mode);
// NOTE: we need to process pts here
if (mode & MPP_FRAME_FLAG_TOP_FIRST) {
dec_vproc_put_frame(mpp, frm, dst0, first_pts, frame_err);
dec_vproc_put_frame(mpp, frm, dst1, curr_pts, frame_err);
} else {
dec_vproc_put_frame(mpp, frm, dst1, first_pts, frame_err);
dec_vproc_put_frame(mpp, frm, dst0, curr_pts, frame_err);
}
ctx->out_buf0 = NULL;
ctx->out_buf1 = NULL;
} else {
// 2 in 1 out case
vproc_dbg_status("2 field in and 1 frame out\n");
buf = mpp_frame_get_buffer(frm);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_SRC);
frame_err = mpp_frame_get_errinfo(frm) ||
mpp_frame_get_discard(frm);
// setup dst 0
mpp_assert(dst0);
fd = mpp_buffer_get_fd(dst0);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DST);
ctx->dei_cfg.dei_mode = IEP_DEI_MODE_I2O1;
mode = mode | MPP_FRAME_FLAG_IEP_DEI_I2O1;
mpp_frame_set_mode(frm, mode);
// start hardware
dec_vproc_start_dei(ctx, mode);
dec_vproc_put_frame(mpp, frm, dst0, -1, frame_err);
ctx->out_buf0 = NULL;
}
}
#if DUMP_FILE
static void dump_mppbuffer(MppBuffer buf, const char *fname, int stride, int height)
{
char title[256];
void *ptr = mpp_buffer_get_ptr(buf);
sprintf(title, "%s.%dx%d.yuv", fname, stride, height);
FILE *dump = fopen(title, "ab+");
if (dump) {
fwrite(ptr, 1, stride * height * 3 / 2, dump);
fclose(dump);
}
}
#else
#define dump_mppbuffer(...)
#endif
static void dec_vproc_set_dei_v2(MppDecVprocCtxImpl *ctx, MppFrame frm)
{
IepImg img;
Mpp *mpp = ctx->mpp;
RK_U32 mode = mpp_frame_get_mode(frm);
MppBuffer buf = mpp_frame_get_buffer(frm);
MppBuffer dst0 = ctx->out_buf0;
MppBuffer dst1 = ctx->out_buf1;
RK_U32 hor_stride = mpp_frame_get_hor_stride(frm);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frm);
int fd = -1;
iep_com_ops *ops = ctx->com_ctx->ops;
RK_U32 frame_err = 0;
// setup source IepImg
dec_vproc_set_img_fmt(&img, frm);
if (vproc_debug & VPROC_DBG_DUMP_IN)
dump_mppbuffer(buf, "/data/dump/dump_in.yuv", hor_stride, ver_stride);
if (ctx->prev_frm1 && ctx->prev_frm0) {
struct iep2_api_params params;
// 5 in 2 out case
vproc_dbg_status("5 field in and 2 frame out\n");
RK_S64 prev_pts = mpp_frame_get_pts(ctx->prev_frm1);
RK_S64 curr_pts = mpp_frame_get_pts(ctx->prev_frm0);
RK_S64 first_pts = (prev_pts + curr_pts) / 2;
// setup source frames
buf = mpp_frame_get_buffer(ctx->prev_frm0);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_SRC);
frame_err = mpp_frame_get_errinfo(ctx->prev_frm0) ||
mpp_frame_get_discard(ctx->prev_frm0);
buf = mpp_frame_get_buffer(frm);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_SRC1);
frame_err |= mpp_frame_get_errinfo(frm) ||
mpp_frame_get_discard(frm);
buf = mpp_frame_get_buffer(ctx->prev_frm1);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_SRC2);
frame_err |= mpp_frame_get_errinfo(ctx->prev_frm1) ||
mpp_frame_get_discard(ctx->prev_frm0);
mpp_assert(dst0);
fd = mpp_buffer_get_fd(dst0);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DST);
mpp_assert(dst1);
fd = mpp_buffer_get_fd(dst1);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_DST1);
params.ptype = IEP2_PARAM_TYPE_MODE;
if (ctx->detection) {
params.param.mode.dil_mode = IEP2_DIL_MODE_DECT;
} else if (!ctx->pd_mode) {
params.param.mode.dil_mode = IEP2_DIL_MODE_I5O2;
} else {
params.param.mode.dil_mode = IEP2_DIL_MODE_PD;
}
params.param.mode.out_mode = IEP2_OUT_MODE_LINE;
if ((mode & MPP_FRAME_FLAG_TOP_FIRST) && (mode & MPP_FRAME_FLAG_BOT_FIRST))
params.param.mode.dil_order = IEP2_FIELD_ORDER_UND;
else if (mode & MPP_FRAME_FLAG_BOT_FIRST)
params.param.mode.dil_order = IEP2_FIELD_ORDER_BFF;
else
params.param.mode.dil_order = IEP2_FIELD_ORDER_TFF;
ops->control(ctx->iep_ctx, IEP_CMD_SET_DEI_CFG, &params);
params.ptype = IEP2_PARAM_TYPE_COM;
params.param.com.sfmt = IEP2_FMT_YUV420;
params.param.com.dfmt = IEP2_FMT_YUV420;
params.param.com.sswap = IEP2_YUV_SWAP_SP_UV;
params.param.com.dswap = IEP2_YUV_SWAP_SP_UV;
params.param.com.width = mpp_frame_get_width(frm);//img.act_w;
params.param.com.hor_stride = hor_stride;//img.act_w;
params.param.com.height = ver_stride;
ops->control(ctx->iep_ctx, IEP_CMD_SET_DEI_CFG, &params);
if (!ctx->detection) {
mode = mode | MPP_FRAME_FLAG_IEP_DEI_I4O2;
mpp_frame_set_mode(frm, mode);
}
// start hardware
dec_vproc_start_dei(ctx, mode);
// NOTE: we need to process pts here
if (!ctx->detection) {
if (ctx->pd_mode) {
if (ctx->dei_info.pd_flag != PD_COMP_FLAG_NON && ctx->dei_info.pd_types != PD_TYPES_UNKNOWN) {
dec_vproc_put_frame(mpp, frm, dst0, first_pts, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst0, "/data/dump/dump_output.yuv", hor_stride, ver_stride);
ctx->out_buf0 = NULL;
}
} else {
RK_U32 fo_from_syntax = (mode & MPP_FRAME_FLAG_TOP_FIRST) ? 1 : 0;
RK_U32 fo_from_iep = (ctx->dei_info.dil_order == IEP2_FIELD_ORDER_TFF);
RK_U32 is_tff = 0;
if (fo_from_iep != fo_from_syntax) {
if (ctx->dei_info.dil_order_confidence_ratio > 30)
is_tff = fo_from_iep;
else
is_tff = fo_from_iep;
} else {
is_tff = fo_from_syntax;
}
if (is_tff) {
dec_vproc_put_frame(mpp, frm, dst0, first_pts, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst0, "/data/dump/dump_output.yuv", hor_stride, ver_stride);
dec_vproc_put_frame(mpp, frm, dst1, curr_pts, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst1, "/data/dump/dump_output.yuv", hor_stride, ver_stride);
} else {
dec_vproc_put_frame(mpp, frm, dst1, first_pts, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst1, "/data/dump/dump_output.yuv", hor_stride, mpp_frame_get_height(frm));
dec_vproc_put_frame(mpp, frm, dst0, curr_pts, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst0, "/data/dump/dump_output.yuv", hor_stride, mpp_frame_get_height(frm));
}
ctx->out_buf0 = NULL;
ctx->out_buf1 = NULL;
}
}
if (ctx->dei_info.frm_mode) {
ctx->detection = 1;
} else if (ctx->dei_info.pd_types == PD_TYPES_UNKNOWN) {
ctx->pd_mode = 0;
ctx->detection = 0;
} else {
ctx->pd_mode = 1;
ctx->detection = 0;
}
} else if (ctx->prev_frm0 && ! ctx->prev_frm1) {
vproc_dbg_status("Wait for next frame to turn into I5O2");
if (ctx->out_buf0) {
mpp_buffer_put(ctx->out_buf0);
ctx->out_buf0 = NULL;
}
if (ctx->out_buf1) {
mpp_buffer_put(ctx->out_buf1);
ctx->out_buf1 = NULL;
}
} else {
struct iep2_api_params params;
// 2 in 1 out case
vproc_dbg_status("2 field in and 1 frame out\n");
buf = mpp_frame_get_buffer(frm);
fd = mpp_buffer_get_fd(buf);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_SRC);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_SRC1);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_SRC2);
frame_err = mpp_frame_get_errinfo(frm) ||
mpp_frame_get_discard(frm);
// setup dst 0
fd = mpp_buffer_get_fd(dst0);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DST);
dec_vproc_set_img(ctx, &img, fd, IEP_CMD_SET_DEI_DST1);
params.ptype = IEP2_PARAM_TYPE_MODE;
params.param.mode.dil_mode = IEP2_DIL_MODE_I1O1T;
params.param.mode.out_mode = IEP2_OUT_MODE_LINE;
ops->control(ctx->iep_ctx, IEP_CMD_SET_DEI_CFG, &params);
params.ptype = IEP2_PARAM_TYPE_COM;
params.param.com.sfmt = IEP2_FMT_YUV420;
params.param.com.dfmt = IEP2_FMT_YUV420;
params.param.com.sswap = IEP2_YUV_SWAP_SP_UV;
params.param.com.dswap = IEP2_YUV_SWAP_SP_UV;
params.param.com.width = hor_stride;
params.param.com.height = ver_stride;
params.param.com.hor_stride = hor_stride;//img.act_w;
ops->control(ctx->iep_ctx, IEP_CMD_SET_DEI_CFG, &params);
mode = mode | MPP_FRAME_FLAG_IEP_DEI_I2O1;
mpp_frame_set_mode(frm, mode);
// start hardware
dec_vproc_start_dei(ctx, mode);
if (!ctx->detection) {
dec_vproc_put_frame(mpp, frm, dst0, -1, frame_err);
if (vproc_debug & VPROC_DBG_DUMP_OUT)
dump_mppbuffer(dst0, "/data/dump/dump_output.yuv", hor_stride, mpp_frame_get_height(frm));
ctx->out_buf0 = NULL;
}
}
}
static void dec_vproc_update_ref(MppDecVprocCtxImpl *ctx, MppFrame frm, RK_U32 index, RK_U32 eos)
{
Mpp *mpp = ctx->mpp;
if (ctx->com_ctx->ver == 1) {
dec_vproc_clr_prev0(ctx);
ctx->prev_idx0 = index;
ctx->prev_frm0 = frm;
} else {
if (ctx->detection) {
if (ctx->prev_frm1) {
dec_vproc_put_frame(mpp, ctx->prev_frm1, NULL, -1, 0);
if (ctx->prev_idx1 >= 0)
mpp_buf_slot_clr_flag(ctx->slots, ctx->prev_idx1, SLOT_QUEUE_USE);
ctx->prev_idx1 = -1;
ctx->prev_frm1 = NULL;
}
} else {
dec_vproc_clr_prev1(ctx);
}
ctx->prev_idx1 = ctx->prev_idx0;
ctx->prev_idx0 = index;
ctx->prev_frm1 = ctx->prev_frm0;
ctx->prev_frm0 = frm;
}
if (eos) {
mpp_frame_init(&frm);
mpp_frame_set_eos(frm, eos);
dec_vproc_put_frame(mpp, frm, NULL, -1, 0);
dec_vproc_clr_prev(ctx);
mpp_frame_deinit(&frm);
}
return;
}
static void *dec_vproc_thread(void *data)
{
MppDecVprocCtxImpl *ctx = (MppDecVprocCtxImpl *)data;
HalTaskGroup tasks = ctx->task_group;
MppThread *thd = ctx->thd;
Mpp *mpp = ctx->mpp;
MppDecImpl *dec = (MppDecImpl *)mpp->mDec;
MppBufSlots slots = dec->frame_slots;
HalTaskHnd task = NULL;
HalTaskInfo task_info;
HalDecVprocTask *task_vproc = &task_info.dec_vproc;
mpp_dbg_info("mpp_dec_post_proc_thread started\n");
while (1) {
MPP_RET ret = MPP_OK;
{
AutoMutex autolock(thd->mutex());
if (MPP_THREAD_RUNNING != thd->get_status())
break;
if (ctx->task_wait.val && !ctx->reset) {
vproc_dbg_status("vproc thread wait %d", ctx->task_wait.val);
thd->wait();
}
}
if (!ctx->task_status.task_rdy) {
if (hal_task_get_hnd(tasks, TASK_PROCESSING, &task)) {
if (ctx->reset) {
/* reset only on all task finished */
vproc_dbg_reset("reset start\n");
dec_vproc_clr_prev(ctx);
thd->lock(THREAD_CONTROL);
ctx->reset = 0;
thd->unlock(THREAD_CONTROL);
sem_post(&ctx->reset_sem);
ctx->task_wait.val = 0;
vproc_dbg_reset("reset done\n");
continue;
}
ctx->task_wait.task_in = 1;
continue;
}
ctx->task_status.task_rdy = 1;
ctx->task_wait.task_in = 0;
}
if (task) {
ret = hal_task_hnd_get_info(task, &task_info);
mpp_assert(ret == MPP_OK);
RK_S32 index = task_vproc->input;
RK_U32 eos = task_vproc->flags.eos;
RK_U32 change = task_vproc->flags.info_change;
MppFrame frm = NULL;
if (eos && index < 0) {
vproc_dbg_status("eos signal\n");
mpp_frame_init(&frm);
mpp_frame_set_eos(frm, eos);
dec_vproc_put_frame(mpp, frm, NULL, -1, 0);
dec_vproc_clr_prev(ctx);
mpp_frame_deinit(&frm);
hal_task_hnd_set_status(task, TASK_IDLE);
ctx->task_status.task_rdy = 0;
continue;
}
mpp_buf_slot_get_prop(slots, index, SLOT_FRAME_PTR, &frm);
if (change) {
vproc_dbg_status("info change\n");
dec_vproc_put_frame(mpp, frm, NULL, -1, 0);
dec_vproc_clr_prev(ctx);
hal_task_hnd_set_status(task, TASK_IDLE);
ctx->task_status.task_rdy = 0;
continue;
}
vproc_dbg_status("vproc get buf in");
if (!ctx->task_status.buf_rdy && !ctx->reset) {
MppBuffer buf = mpp_frame_get_buffer(frm);
size_t buf_size = mpp_buffer_get_size(buf);
if (!ctx->out_buf0) {
mpp_buffer_get(mpp->mFrameGroup, &ctx->out_buf0, buf_size);
if (NULL == ctx->out_buf0) {
ctx->task_wait.task_buf_in = 1;
continue;
}
}
if (!ctx->out_buf1) {
mpp_buffer_get(mpp->mFrameGroup, &ctx->out_buf1, buf_size);
if (NULL == ctx->out_buf1) {
ctx->task_wait.task_buf_in = 1;
continue;
}
}
ctx->task_status.buf_rdy = 1;
}
RK_S32 tmp = -1;
mpp_buf_slot_dequeue(slots, &tmp, QUEUE_DEINTERLACE);
mpp_assert(tmp == index);
vproc_dbg_status("vproc get buf ready & start process ");
if (!ctx->reset && ctx->iep_ctx) {
if (ctx->com_ctx->ver == 1) {
dec_vproc_set_dei_v1(ctx, frm);
} else {
dec_vproc_set_dei_v2(ctx, frm);
}
}
dec_vproc_update_ref(ctx, frm, index, eos);
hal_task_hnd_set_status(task, TASK_IDLE);
ctx->task_status.val = 0;
ctx->task_wait.val = 0;
vproc_dbg_status("vproc task done");
}
}
mpp_dbg_info("mpp_dec_post_proc_thread exited\n");
return NULL;
}
MPP_RET dec_vproc_init(MppDecVprocCtx *ctx, MppDecVprocCfg *cfg)
{
MPP_RET ret = MPP_OK;
if (NULL == ctx || NULL == cfg || NULL == cfg->mpp) {
mpp_err_f("found NULL input ctx %p mpp %p\n", ctx, cfg->mpp);
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
mpp_env_get_u32("vproc_debug", &vproc_debug, 0);
*ctx = NULL;
MppDecVprocCtxImpl *p = mpp_calloc(MppDecVprocCtxImpl, 1);
if (NULL == p) {
mpp_err_f("malloc failed\n");
return MPP_ERR_MALLOC;
}
p->mpp = (Mpp *)cfg->mpp;
p->slots = ((MppDecImpl *)p->mpp->mDec)->frame_slots;
p->thd = new MppThread(dec_vproc_thread, p, "mpp_dec_vproc");
sem_init(&p->reset_sem, 0, 0);
ret = hal_task_group_init(&p->task_group, TASK_BUTT, 4, sizeof(HalDecVprocTask));
if (ret) {
mpp_err_f("create task group failed\n");
delete p->thd;
MPP_FREE(p);
return MPP_ERR_MALLOC;
}
cfg->task_group = p->task_group;
/// TODO, seperate iep1/2 api
p->com_ctx = get_iep_ctx();
if (!p->com_ctx) {
mpp_err("failed to require context\n");
delete p->thd;
if (p->task_group) {
hal_task_group_deinit(p->task_group);
p->task_group = NULL;
}
MPP_FREE(p);
return MPP_ERR_MALLOC;
}
ret = p->com_ctx->ops->init(&p->com_ctx->priv);
p->iep_ctx = p->com_ctx->priv;
if (!p->thd || ret) {
mpp_err("failed to create context\n");
if (p->thd) {
delete p->thd;
p->thd = NULL;
}
if (p->iep_ctx)
p->com_ctx->ops->deinit(p->iep_ctx);
if (p->task_group) {
hal_task_group_deinit(p->task_group);
p->task_group = NULL;
}
put_iep_ctx(p->com_ctx);
MPP_FREE(p);
} else {
p->dei_cfg.dei_mode = IEP_DEI_MODE_I2O1;
p->dei_cfg.dei_field_order = IEP_DEI_FLD_ORDER_BOT_FIRST;
/*
* We need to turn off this switch to prevent some areas
* of the video from flickering.
*/
p->dei_cfg.dei_high_freq_en = 0;
p->dei_cfg.dei_high_freq_fct = 64;
p->dei_cfg.dei_ei_mode = 0;
p->dei_cfg.dei_ei_smooth = 1;
p->dei_cfg.dei_ei_sel = 0;
p->dei_cfg.dei_ei_radius = 2;
p->prev_idx0 = -1;
p->prev_frm0 = NULL;
p->prev_idx1 = -1;
p->prev_frm1 = NULL;
}
*ctx = p;
vproc_dbg_func("out\n");
return ret;
}
RK_U32 dec_vproc_get_version(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return 0;
}
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
return p->com_ctx->ver;
}
void dec_vproc_enable_detect(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return;
}
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
p->detection = 1;
return;
}
MPP_RET dec_vproc_deinit(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd) {
p->thd->stop();
delete p->thd;
p->thd = NULL;
}
if (p->iep_ctx)
p->com_ctx->ops->deinit(p->iep_ctx);
if (p->task_group) {
hal_task_group_deinit(p->task_group);
p->task_group = NULL;
}
if (p->com_ctx) {
put_iep_ctx(p->com_ctx);
p->com_ctx = NULL;
}
sem_destroy(&p->reset_sem);
mpp_free(p);
vproc_dbg_func("out\n");
return MPP_OK;
}
MPP_RET dec_vproc_start(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd)
p->thd->start();
else
mpp_err("failed to start dec vproc thread\n");
vproc_dbg_func("out\n");
return MPP_OK;
}
MPP_RET dec_vproc_stop(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd)
p->thd->stop();
else
mpp_err("failed to stop dec vproc thread\n");
vproc_dbg_func("out\n");
return MPP_OK;
}
MPP_RET dec_vproc_signal(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd) {
p->thd->lock();
p->thd->signal();
p->thd->unlock();
}
vproc_dbg_func("out\n");
return MPP_OK;
}
MPP_RET dec_vproc_reset(MppDecVprocCtx ctx)
{
if (NULL == ctx) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
vproc_dbg_func("in\n");
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd) {
MppThread *thd = p->thd;
vproc_dbg_reset("reset contorl start\n");
// wait reset finished
thd->lock();
thd->lock(THREAD_CONTROL);
p->reset = 1;
thd->signal();
thd->unlock(THREAD_CONTROL);
thd->unlock();
vproc_dbg_reset("reset contorl wait\n");
sem_wait(&p->reset_sem);
vproc_dbg_reset("reset contorl done\n");
mpp_assert(p->reset == 0);
}
vproc_dbg_func("out\n");
return MPP_OK;
}