You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1282 lines
39 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2009-2019. All rights reserved.
* Description: Defines avplay export function
* Author: Hisilicon
* Create: 2009-12-21
* History:
*/
#include "drv_avplay.h"
#include "drv_module_ext.h"
#include "drv_demux_struct.h"
#include "drv_sync_ext.h"
#include "drv_vdec_ext.h"
#include "drv_policy_ext.h"
#define big_endian_write(a, b) (((a) << 32) | (b))
#define DRV_AVPLAY_MAX_VIR_WIN_CNT 1
typedef enum {
AVPLAY_PARAM_INC = 0, /* 递增 */
AVPLAY_PARAM_ADD, /* 累加 */
AVPLAY_PARAM_RES /* 覆盖 */
} avplay_param_type;
typedef struct {
demux_func_export *dmx_func;
drv_vdec_export_func *vdec_func;
void *win_func;
} avplay_import_func;
typedef struct {
td_bool update;
td_u64 param;
avplay_param_type param_type;
} avplay_event_info;
typedef struct {
td_handle self;
td_handle vdec;
td_handle vid_dmx;
td_handle aud_dmx;
td_handle pcr_dmx;
td_handle win;
td_handle virtual_win[DRV_AVPLAY_MAX_VIR_WIN_CNT];
td_u8 virtual_win_cnt;
td_handle sync;
td_bool vid_enable;
td_bool aud_enable;
avplay_resolution_param res;
td_u64 event_mask; /* 一个bit对应一种事件, 用于控制是否立即上报事件, 0: disable; 1: enable */
avplay_event_info events[AVPLAY_EVENT_TYPE_MAX]; /* protected by instance->spin */
} avplay_drv_ctx;
typedef struct {
td_handle handle;
avplay_drv_ctx *ctx;
const void *unique;
td_bool wait_cond;
osal_wait wq;
avplay_drv_spin_t spin; /* used in the context of interruption */
avplay_drv_mutex_t mutex;
} avplay_drv_instance;
static td_bool g_avplay_inited = TD_FALSE;
static td_u32 g_avplay_instance_cnt = 0;
static td_u32 g_avplay_play_cnt = 0;
static avplay_drv_instance g_avplay_instance[AVPLAY_MAX_CNT];
static avplay_drv_spin_t g_avplay_spinlock;
static avplay_import_func g_avplay_import_func = {TD_NULL};
static avplay_param_type g_avplay_param_types[AVPLAY_EVENT_TYPE_MAX] = {
[AVPLAY_EVENT_VID_RENDER_UNDERLOAD] = AVPLAY_PARAM_ADD,
[AVPLAY_EVENT_VID_ERR_FRAME] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_TYPE_ERR] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_DECODE_FORMAT_CHANGE] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_DECODE_PACKING_CHANGE] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_FIRST_PTS] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_SECOND_PTS] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_DECODE_EOS] = AVPLAY_PARAM_RES,
[AVPLAY_EVENT_VID_NEW_DMX_IDX] = AVPLAY_PARAM_RES
};
static td_s32 drv_wakeup(avplay_drv_instance *instance);
static void ctx_init(avplay_drv_ctx *ctx, td_handle avplay)
{
td_u32 i;
ctx->self = avplay;
ctx->vdec = TD_INVALID_HANDLE;
ctx->vid_dmx = TD_INVALID_HANDLE;
ctx->aud_dmx = TD_INVALID_HANDLE;
ctx->win = TD_INVALID_HANDLE;
ctx->virtual_win_cnt = 0;
for (i = 0; i < DRV_AVPLAY_MAX_VIR_WIN_CNT; i++) {
ctx->virtual_win[i] = TD_INVALID_HANDLE;
}
ctx->sync = TD_INVALID_HANDLE;
ctx->vid_enable = TD_FALSE;
ctx->aud_enable = TD_FALSE;
ctx->res.width = 0;
ctx->res.height = 0;
ctx->res.stride = 0;
ctx->res.bit_depth = 0;
ctx->res.frm_num = 0;
ctx->res.frm_size = 0;
ctx->res.meta_size = 0;
ctx->event_mask = 0LL;
for (i = 0; i < AVPLAY_EVENT_TYPE_MAX; i++) {
ctx->events[i].update = TD_FALSE;
ctx->events[i].param = 0LL;
ctx->events[i].param_type = g_avplay_param_types[i];
}
}
static void delete_win_attach(avplay_drv_ctx *ctx)
{
td_s32 ret;
td_u8 i = 0;
ext_sys_policy_win_attach_info info;
info.source_handle = ctx->self;
if (ctx->win != TD_INVALID_HANDLE) {
info.window_handle = ctx->win;
ret = ext_drv_sys_policy_del_win_attach_info(&info);
log_when_error(ret, ext_drv_sys_del_window_attach_info);
if (ret == TD_SUCCESS) {
ctx->win = TD_INVALID_HANDLE;
}
}
for (; i < DRV_AVPLAY_MAX_VIR_WIN_CNT; i++) {
if (ctx->virtual_win[i] != TD_INVALID_HANDLE) {
info.window_handle = ctx->virtual_win[i];
ret = ext_drv_sys_policy_del_win_attach_info(&info);
log_when_error(ret, ext_drv_sys_del_window_attach_info);
if (ret == TD_SUCCESS) {
ctx->virtual_win[i] = TD_INVALID_HANDLE;
}
}
}
}
static void ctx_deinit(avplay_drv_instance *instance, avplay_drv_ctx **free_ctx)
{
td_ulong flags = 0;
avplay_mutex_lock(&instance->mutex);
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx != TD_NULL) {
drv_wakeup(instance);
delete_win_attach(instance->ctx);
*free_ctx = instance->ctx;
instance->ctx = TD_NULL; /* ctx is freed outside spinlock by caller */
}
avplay_spin_unlock(&instance->spin, flags);
avplay_mutex_unlock(&instance->mutex);
}
static void instance_init(void)
{
td_u32 i = 0;
if (g_avplay_inited) {
return;
}
for (; i < AVPLAY_MAX_CNT; i++) {
g_avplay_instance[i].handle = TD_INVALID_HANDLE;
g_avplay_instance[i].ctx = TD_NULL;
g_avplay_instance[i].unique = TD_NULL;
avplay_mutex_init(&g_avplay_instance[i].mutex);
}
g_avplay_instance_cnt = 0;
g_avplay_play_cnt = 0;
g_avplay_inited = TD_TRUE;
}
static avplay_drv_instance *instance_get(td_handle handle)
{
avplay_drv_instance *instance = TD_NULL;
td_u32 index = avplay_get_id(handle);
if (index >= AVPLAY_MAX_CNT || avplay_get_modid(handle) != SOC_ID_AVPLAY) {
ext_err_avplay("Invalid avplay handle[0x%x]\n", handle);
return TD_NULL;
}
if (!g_avplay_inited) {
ext_err_avplay("AVPLAY not inited\n");
return TD_NULL;
}
if (g_avplay_instance[index].ctx == TD_NULL) {
ext_warn_avplay("Invalid avplay handle[0x%x], instance context is NULL\n", handle);
} else if (g_avplay_instance[index].handle != handle) {
ext_err_avplay("Invalid avplay handle[0x%x], instance handle[0x%x] check failed\n",
handle, g_avplay_instance[index].handle);
} else {
instance = &g_avplay_instance[index];
}
return instance;
}
static td_s32 instance_alloc(td_handle *handle, const void *unique, avplay_drv_ctx **external_ctx)
{
td_u32 i = 0;
if (!g_avplay_inited) {
ext_err_avplay("AVPLAY not inited\n");
return SOC_ERR_AVPLAY_DEV_NO_INIT;
}
for (; i < AVPLAY_MAX_CNT; i++) {
if (g_avplay_instance[i].handle == TD_INVALID_HANDLE) {
break;
}
}
if (i >= AVPLAY_MAX_CNT) {
ext_err_avplay("Too many avplays are created, instance cnt = %u\n", g_avplay_instance_cnt);
return SOC_ERR_AVPLAY_CREATE_ERR;
}
if (g_avplay_instance[i].ctx == TD_NULL) {
g_avplay_instance[i].ctx = *external_ctx;
*external_ctx = TD_NULL;
}
ctx_init(g_avplay_instance[i].ctx, avplay_get_handle(i));
g_avplay_instance[i].wait_cond = TD_FALSE;
g_avplay_instance_cnt++;
g_avplay_instance[i].handle = avplay_get_handle(i);
g_avplay_instance[i].unique = unique;
*handle = g_avplay_instance[i].handle;
ext_dbg_avplay("Alloc drv avplay, index = 0x%x, instance_cnt = %u\n", i, g_avplay_instance_cnt);
return TD_SUCCESS;
}
static td_s32 instance_del(td_handle handle, avplay_drv_ctx **free_ctx)
{
td_u32 index = avplay_get_id(handle);
if (index >= AVPLAY_MAX_CNT) {
ext_err_avplay("Invalid handle, index = %u\n", index);
return TD_FAILURE;
}
ctx_deinit(&g_avplay_instance[index], free_ctx);
g_avplay_instance[index].handle = TD_INVALID_HANDLE;
g_avplay_instance[index].unique = TD_NULL;
g_avplay_instance_cnt--;
ext_dbg_avplay("Delete drv avplay, index = 0x%x\n", index);
return TD_SUCCESS;
}
static td_s32 instance_clear(const void *unique, avplay_drv_ctx *free_ctx[], td_u32 num)
{
td_u32 i = 0;
TD_UNUSED(num);
for (; i < AVPLAY_MAX_CNT; i++) {
if (g_avplay_instance[i].unique == unique) {
ctx_deinit(&g_avplay_instance[i], &free_ctx[i]);
g_avplay_instance[i].handle = TD_INVALID_HANDLE;
g_avplay_instance[i].unique = TD_NULL;
ext_dbg_avplay("Clear drv avplay, index = 0x%x\n", i);
}
}
return TD_SUCCESS;
}
static void instance_deinit(avplay_drv_ctx *free_ctx[], td_u32 num)
{
td_u32 i = 0;
TD_UNUSED(num);
for (; i < AVPLAY_MAX_CNT; i++) {
ctx_deinit(&g_avplay_instance[i], &free_ctx[i]);
osal_wait_destroy(&g_avplay_instance[i].wq);
avplay_spin_deinit(&g_avplay_instance[i].spin);
avplay_mutex_deinit(&g_avplay_instance[i].mutex);
g_avplay_instance[i].handle = TD_INVALID_HANDLE;
g_avplay_instance[i].unique = TD_NULL;
}
}
static void drv_instance_init(void)
{
td_u32 i = 0;
td_ulong flags = 0;
avplay_spin_lock(&g_avplay_spinlock, flags);
instance_init();
avplay_spin_unlock(&g_avplay_spinlock, flags);
for (; i < AVPLAY_MAX_CNT; i++) {
avplay_spin_init(&g_avplay_instance[i].spin);
osal_wait_init(&g_avplay_instance[i].wq);
}
}
static avplay_drv_instance *drv_instance_get(td_handle handle)
{
td_ulong flags = 0;
avplay_drv_instance *instance = TD_NULL;
avplay_spin_lock(&g_avplay_spinlock, flags);
instance = instance_get(handle);
avplay_spin_unlock(&g_avplay_spinlock, flags);
return instance;
}
static td_s32 drv_instance_alloc(td_handle *handle, const void *unique)
{
td_s32 ret;
td_ulong flags = 0;
avplay_drv_ctx *ctx = TD_NULL;
ctx = (avplay_drv_ctx*)avplay_malloc(sizeof(avplay_drv_ctx));
check_null(ctx);
avplay_spin_lock(&g_avplay_spinlock, flags);
ret = instance_alloc(handle, unique, &ctx);
avplay_spin_unlock(&g_avplay_spinlock, flags);
if (ret != TD_SUCCESS || ctx != TD_NULL) {
avplay_free(ctx);
}
return ret;
}
static td_s32 drv_instance_del(td_handle handle)
{
td_s32 ret;
td_ulong flags = 0;
avplay_drv_ctx *free_ctx = TD_NULL;
avplay_spin_lock(&g_avplay_spinlock, flags);
ret = instance_del(handle, &free_ctx);
avplay_spin_unlock(&g_avplay_spinlock, flags);
if (free_ctx != TD_NULL) {
avplay_free(free_ctx);
}
return ret;
}
static td_s32 drv_instance_clear(const void *unique)
{
td_s32 ret;
td_ulong flags = 0;
td_u32 i = 0;
avplay_drv_ctx *free_ctx[AVPLAY_MAX_CNT] = {TD_NULL};
avplay_spin_lock(&g_avplay_spinlock, flags);
ret = instance_clear(unique, free_ctx, AVPLAY_MAX_CNT);
avplay_spin_unlock(&g_avplay_spinlock, flags);
for (; i < AVPLAY_MAX_CNT; i++) {
if (free_ctx[i] != TD_NULL) {
avplay_free(free_ctx[i]);
}
}
return ret;
}
static void drv_instance_deinit(void)
{
td_ulong flags = 0;
td_u32 i = 0;
avplay_drv_ctx *free_ctx[AVPLAY_MAX_CNT] = {TD_NULL};
avplay_spin_lock(&g_avplay_spinlock, flags);
instance_deinit(free_ctx, AVPLAY_MAX_CNT);
avplay_spin_unlock(&g_avplay_spinlock, flags);
for (; i < AVPLAY_MAX_CNT; i++) {
if (free_ctx[i] != TD_NULL) {
avplay_free(free_ctx[i]);
}
}
}
#define AVPLAY_INSTANCE (instance)
#define AVPLAY_DRV_CTX (AVPLAY_INSTANCE->ctx)
#define avplay_drv_do_func(avplay, func) do { \
td_s32 ret = TD_SUCCESS; \
td_ulong flags = 0; \
avplay_drv_instance *AVPLAY_INSTANCE = drv_instance_get(avplay); \
check_null(AVPLAY_INSTANCE); \
avplay_spin_lock(&AVPLAY_INSTANCE->spin, flags); \
\
if (AVPLAY_DRV_CTX != TD_NULL) { \
ret = func; \
} else { \
ret = SOC_ERR_AVPLAY_NULL_PTR; \
ext_err_avplay("Instance ctx is NULL\n"); \
} \
\
avplay_spin_unlock(&AVPLAY_INSTANCE->spin, flags); \
return ret; \
} while (0)
#define avplay_drv_do_func_without_spin(avplay, func) do { \
td_s32 ret = TD_SUCCESS; \
avplay_drv_instance *AVPLAY_INSTANCE = drv_instance_get(avplay); \
check_null(AVPLAY_INSTANCE); \
\
if (AVPLAY_DRV_CTX != TD_NULL) { \
ret = func; \
} else { \
ret = SOC_ERR_AVPLAY_NULL_PTR; \
ext_err_avplay("Instance ctx is NULL\n"); \
} \
\
return ret; \
} while (0)
static td_void set_resolution_param(const ext_vdec_size_change *vdec_param, avplay_resolution_param *param)
{
if (vdec_param == TD_NULL || param == TD_NULL) {
return;
}
param->width = vdec_param->new_width;
param->height = vdec_param->new_height;
param->stride = vdec_param->new_stride;
param->bit_depth = vdec_param->new_bit_depth;
param->frm_num = vdec_param->new_frm_num;
param->frm_size = vdec_param->new_frm_size;
param->meta_size = vdec_param->new_meta_size;
}
static td_s32 event_process(avplay_drv_instance *instance, avplay_event_type event, td_u64 param)
{
avplay_drv_ctx *ctx = instance->ctx;
check_null(ctx);
check_param(event < AVPLAY_EVENT_TYPE_MAX);
if (event == AVPLAY_EVENT_VID_DECODE_RESOLUTION_CHANGE) {
const ext_vdec_size_change *res = (ext_vdec_size_change *)(uintptr_t)param;
set_resolution_param(res, &ctx->res);
}
if (ctx->events[event].param_type == AVPLAY_PARAM_ADD) {
ctx->events[event].param += param;
} else if (ctx->events[event].param_type == AVPLAY_PARAM_RES) {
ctx->events[event].param = param;
} else {
ctx->events[event].param++;
}
ctx->events[event].update = TD_TRUE;
if (is_bit_enable(ctx->event_mask, event)) {
return drv_wakeup(instance);
}
return TD_SUCCESS;
}
static td_s32 process_callback_event(td_handle avplay, avplay_event_type event_type, td_u64 event_param)
{
td_s32 ret;
td_ulong flags = 0;
avplay_drv_instance *instance = TD_NULL;
instance = drv_instance_get(avplay);
if (instance == TD_NULL) {
ext_warn_avplay("Instance is not exist.\n");
return SOC_ERR_AVPLAY_NULL_PTR;
}
avplay_spin_lock(&instance->spin, flags);
ret = event_process(instance, event_type, event_param);
avplay_spin_unlock(&instance->spin, flags);
return ret;
}
static td_s32 vid_dmx_callback(td_handle avplay, ext_dmx_evt_id evt_id, const void *param, td_u32 param_size)
{
td_u64 event_param = 0LL;
avplay_event_type event_type = AVPLAY_EVENT_TYPE_MAX;
switch (evt_id) {
case EXT_DMX_EVT_ERR:
event_type = AVPLAY_EVENT_VID_DMX_ERR;
break;
case EXT_DMX_EVT_NEW_PES:
event_type = AVPLAY_EVENT_VID_NEW_PES;
break;
case EXT_DMX_EVT_EOS:
event_type = AVPLAY_EVENT_VID_DMX_EOS;
break;
case EXT_DMX_EVT_OVFL:
ext_warn_avplay("video demux event id[0x%x].\n", evt_id);
return TD_SUCCESS;
default:
ext_err_avplay("Unsupport video demux event id[0x%x].\n", evt_id);
return SOC_ERR_AVPLAY_NOT_SUPPORT;
}
soc_trace_avplay("Receive video demux event id[0x%x], avplay event id = 0x%x\n", evt_id, event_type);
return process_callback_event(avplay, event_type, event_param);
}
static td_s32 aud_dmx_callback(td_handle avplay, ext_dmx_evt_id evt_id, const void *param, td_u32 param_size)
{
td_u64 event_param = 0LL;
avplay_event_type event_type = AVPLAY_EVENT_TYPE_MAX;
switch (evt_id) {
case EXT_DMX_EVT_ERR:
event_type = AVPLAY_EVENT_AUD_DMX_ERR;
break;
case EXT_DMX_EVT_NEW_PES:
event_type = AVPLAY_EVENT_AUD_NEW_PES;
break;
case EXT_DMX_EVT_EOS:
event_type = AVPLAY_EVENT_AUD_DMX_EOS;
break;
case EXT_DMX_EVT_OVFL:
ext_warn_avplay("audio demux event id[0x%x].\n", evt_id);
return TD_SUCCESS;
default:
ext_err_avplay("Unsupport audio demux event id[0x%x].\n", evt_id);
return SOC_ERR_AVPLAY_NOT_SUPPORT;
}
soc_trace_avplay("Receive audio demux event id[0x%x], avplay event id = 0x%x\n", evt_id, event_type);
return process_callback_event(avplay, event_type, event_param);
}
static td_s32 pcr_dmx_callback(td_handle avplay, ext_dmx_evt_id evt_id, const void *param, td_u32 param_size)
{
td_s32 ret = TD_SUCCESS;
const dmx_sync_pcr *info = TD_NULL;
check_null(param);
if (evt_id == EXT_DMX_EVT_PCR) {
info = (const dmx_sync_pcr *)param;
ret = ext_drv_sync_pcr_proc(info->handle, info->pcr_value, info->scr_value);
}
return ret;
}
static td_s32 dmx_index_callback(td_handle avplay, ext_dmx_opt_type opt_type, const dmx_index_data *data)
{
check_null(data);
if (opt_type != EXT_DMX_OPT_ADD) {
return TD_SUCCESS;
} else if (data->frame_type != DMX_FRAME_TYPE_I && data->frame_type != DMX_FRAME_TYPE_IDR) {
return TD_SUCCESS;
}
ext_dbg_avplay("Receive demux index event: type[%d] size[%u] offset[%llu] pts[%lld] \n",
data->frame_type, data->frame_size, data->global_offset, data->pts_us);
return process_callback_event(avplay, AVPLAY_EVENT_VID_NEW_DMX_IDX, data->global_offset);
}
static void err_frame_info_to_u64(const void *param, td_u32 param_size, td_u64 *event_param)
{
const ext_vdec_err_frm *err_frame = (const ext_vdec_err_frm*)param;
td_u64 a = err_frame->err_frm_type;
td_u64 b = err_frame->err_ratio;
*event_param = big_endian_write(a, b);
}
static td_s32 vdec_evt_map_with_param(ext_vdec_evt_id evt_id, const void *param, td_u32 param_size,
avplay_event_type *avplay_evt, td_u64 *event_param)
{
check_null(param);
switch (evt_id) {
case EXT_VDEC_EVT_FIRST_PTS: {
*avplay_evt = AVPLAY_EVENT_VID_FIRST_PTS;
*event_param = *(const td_s64*)param;
break;
}
case EXT_VDEC_EVT_SECOND_PTS: {
*avplay_evt = AVPLAY_EVENT_VID_SECOND_PTS;
*event_param = *(const td_s64*)param;
break;
}
case EXT_VDEC_EVT_EOS: {
const ext_vdec_eos_param *eos = param;
*avplay_evt = AVPLAY_EVENT_VID_DECODE_EOS;
*event_param = eos->last_frame_flag;
break;
}
case EXT_VDEC_EVT_ERR_STANDARD: {
*avplay_evt = AVPLAY_EVENT_VID_TYPE_ERR;
*event_param = *(const td_u32*)param;
break;
}
case EXT_VDEC_EVT_NORM_CHG: {
const ext_vdec_norm_param *norm = param;
*avplay_evt = AVPLAY_EVENT_VID_DECODE_FORMAT_CHANGE;
*event_param = norm->norm_type;
break;
}
case EXT_VDEC_EVT_SIZE_CHG: {
const ext_vdec_size_change *res = param;
*avplay_evt = AVPLAY_EVENT_VID_DECODE_RESOLUTION_CHANGE;
*event_param = (td_u64)(uintptr_t)res;
break;
}
case EXT_VDEC_EVT_FRM_PCK_CHG: {
*avplay_evt = AVPLAY_EVENT_VID_DECODE_PACKING_CHANGE;
*event_param = *(const td_u32*)param;
break;
}
case EXT_VDEC_EVT_ERR_FRAME: {
*avplay_evt = AVPLAY_EVENT_VID_ERR_FRAME;
err_frame_info_to_u64(param, param_size, event_param);
break;
}
default:
ext_err_avplay("Unsupport vdec event id[0x%x]\n", evt_id);
return SOC_ERR_AVPLAY_NOT_SUPPORT;
}
return TD_SUCCESS;
}
static td_s32 vdec_callback(td_handle avplay, ext_vdec_evt_id evt_id, const void *param, td_u32 param_size)
{
td_s32 ret;
td_u64 event_param = 0LL;
avplay_event_type event_type = AVPLAY_EVENT_TYPE_MAX;
switch (evt_id) {
case EXT_VDEC_EVT_NEW_FRAME:
event_type = AVPLAY_EVENT_VID_NEW_FRAME;
break;
case EXT_VDEC_EVT_NEW_STREAM:
event_type = AVPLAY_EVENT_VID_RLS_PES;
break;
case EXT_VDEC_EVT_NEW_USER_DATA:
event_type = AVPLAY_EVENT_VID_NEW_USER_DATA;
break;
case EXT_VDEC_EVT_UNSUPPORT:
event_type = AVPLAY_EVENT_VID_UNSUPPORT;
break;
default:
ret = vdec_evt_map_with_param(evt_id, param, param_size, &event_type, &event_param);
return_when_error(ret, vdec_evt_map_with_param);
}
soc_trace_avplay("Receive vdec event id[0x%x], avplay event id = 0x%x\n", evt_id, event_type);
return process_callback_event(avplay, event_type, event_param);
}
static td_bool pop_event(avplay_drv_ctx *ctx, avplay_event_type *event, td_u64 *param)
{
td_s32 i;
avplay_event_info *event_info = TD_NULL;
if (ctx == TD_NULL) {
return TD_FALSE;
}
for (i = 0; i < AVPLAY_EVENT_TYPE_MAX; i++) {
event_info = &ctx->events[i];
if (event_info->update) {
*event = i;
*param = event_info->param;
event_info->update = TD_FALSE;
event_info->param = 0LL;
return TD_TRUE;
}
}
return TD_FALSE;
}
static td_bool drv_pop_event(avplay_drv_instance *instance, avplay_event_type *event, td_u64 *param)
{
td_bool ret;
td_ulong flags = 0;
avplay_spin_lock(&instance->spin, flags);
ret = pop_event(instance->ctx, event, param);
avplay_spin_unlock(&instance->spin, flags);
return ret;
}
static td_s32 drv_reset(avplay_drv_ctx *ctx, avplay_channel_type chn)
{
td_u32 i;
(void)chn;
for (i = 0; i < AVPLAY_EVENT_TYPE_MAX; i++) {
ctx->events[i].update = TD_FALSE;
ctx->events[i].param = 0LL;
}
return TD_SUCCESS;
}
static td_s32 drv_set_channel_state(avplay_drv_ctx *ctx, avplay_channel_type chn, avplay_channel_state state)
{
if (chn == AVPLAY_CHANNEL_AUD || chn == AVPLAY_CHANNEL_MAX) {
if (state == AVPLAY_CHANNEL_START) {
ctx->aud_enable = TD_TRUE;
} else if (state == AVPLAY_CHANNEL_STOP) {
ctx->aud_enable = TD_FALSE;
}
}
if (chn == AVPLAY_CHANNEL_VID || chn == AVPLAY_CHANNEL_MAX) {
if (state == AVPLAY_CHANNEL_START) {
ctx->vid_enable = TD_TRUE;
} else if (state == AVPLAY_CHANNEL_STOP) {
ctx->vid_enable = TD_FALSE;
}
}
return TD_SUCCESS;
}
static void drv_set_dmx_index_callback(td_handle dmx, avplay_drv_instance *instance,
drv_dmx_play_index_callback callback)
{
td_s32 ret;
td_handle avplay;
td_ulong flags = 0;
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx == TD_NULL) {
avplay_spin_unlock(&instance->spin, flags);
return;
}
avplay = instance->ctx->self;
avplay_spin_unlock(&instance->spin, flags);
if (dmx == TD_INVALID_HANDLE ||
g_avplay_import_func.dmx_func == TD_NULL ||
g_avplay_import_func.dmx_func->dmx_set_play_index_callback == TD_NULL) {
ext_err_avplay("dmx_set_play_index_callback is NULL, cannot set callback\n");
return;
}
ret = g_avplay_import_func.dmx_func->dmx_set_play_index_callback(dmx, avplay, callback);
log_when_error(ret, dmx_set_play_index_callback);
return;
}
static td_s32 drv_set_dmx_callback(avplay_drv_instance *instance, td_handle handle,
avplay_resource_type type, drv_dmx_callback callback)
{
td_s32 ret = TD_SUCCESS;
td_handle avplay;
td_handle dmx_handle = TD_INVALID_HANDLE;
td_ulong flags = 0;
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx == TD_NULL) {
avplay_spin_unlock(&instance->spin, flags);
return TD_FAILURE;
}
avplay = instance->ctx->self;
switch (type) {
case AVPLAY_RESOURCE_TYPE_VID_DEMUX: {
dmx_handle = instance->ctx->vid_dmx;
instance->ctx->vid_dmx = handle;
break;
}
case AVPLAY_RESOURCE_TYPE_AUD_DEMUX: {
dmx_handle = instance->ctx->aud_dmx;
instance->ctx->aud_dmx = handle;
break;
}
case AVPLAY_RESOURCE_TYPE_PCR_DEMUX: {
dmx_handle = instance->ctx->pcr_dmx;
instance->ctx->pcr_dmx = handle;
break;
}
default: {
avplay_spin_unlock(&instance->spin, flags);
return TD_FAILURE;
}
}
avplay_spin_unlock(&instance->spin, flags);
if (g_avplay_import_func.dmx_func == TD_NULL ||
g_avplay_import_func.dmx_func->dmx_set_callback == TD_NULL) {
ext_err_avplay("drv_dmx_set_callback is NULL, cannot set resrouce\n");
return SOC_ERR_AVPLAY_INVALID_OPT;
}
if (handle != TD_INVALID_HANDLE) {
ret = g_avplay_import_func.dmx_func->dmx_set_callback(handle, avplay, callback);
} else if (dmx_handle != TD_INVALID_HANDLE) {
ret = g_avplay_import_func.dmx_func->dmx_set_callback(dmx_handle, avplay, TD_NULL);
}
return ret;
}
static td_s32 drv_set_vdec_callback(avplay_drv_instance *instance, td_handle handle,
fn_drv_vdec_callback callback)
{
td_s32 ret = TD_SUCCESS;
td_ulong flags = 0;
td_handle avplay;
td_handle vdec_handle;
fn_drv_vdec_set_callback vdec_set_cb = TD_NULL;
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx == TD_NULL) {
avplay_spin_unlock(&instance->spin, flags);
return TD_FAILURE;
}
avplay = instance->ctx->self;
vdec_handle = instance->ctx->vdec;
instance->ctx->vdec = handle;
avplay_spin_unlock(&instance->spin, flags);
if (g_avplay_import_func.vdec_func != TD_NULL &&
g_avplay_import_func.vdec_func->pfn_drv_vdec_set_callback != TD_NULL) {
vdec_set_cb = g_avplay_import_func.vdec_func->pfn_drv_vdec_set_callback;
} else {
ext_err_avplay("drv_vdec_set_callback is NULL, cannot set resrouce\n");
return SOC_ERR_AVPLAY_INVALID_OPT;
}
if (handle != TD_INVALID_HANDLE) {
ret = vdec_set_cb(handle, avplay, vdec_callback);
} else if (vdec_handle != TD_INVALID_HANDLE) {
ret = vdec_set_cb(vdec_handle, avplay, TD_NULL);
}
return ret;
}
static td_bool find_virtual_win(const avplay_drv_instance *instance, td_handle handle, td_u32 *index)
{
td_u32 i;
for (i = 0; i < DRV_AVPLAY_MAX_VIR_WIN_CNT; i++) {
if (instance->ctx->virtual_win[i] == handle) {
*index = i;
return TD_TRUE;
}
}
for (i = 0; i < DRV_AVPLAY_MAX_VIR_WIN_CNT; i++) {
if (instance->ctx->virtual_win[i] == TD_INVALID_HANDLE) {
*index = i;
return TD_FALSE;
}
}
return TD_FALSE;
}
static td_s32 set_win_resource(avplay_drv_instance *instance, td_handle handle, td_u32 param)
{
td_s32 ret = TD_SUCCESS;
td_ulong flags = 0;
td_u32 index = 0;
td_bool is_win_valid;
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx == TD_NULL) {
avplay_spin_unlock(&instance->spin, flags);
return TD_FAILURE;
}
if (param == TD_FALSE) {
if (instance->ctx->win == TD_INVALID_HANDLE) {
ext_dbg_avplay("attach master window[0x%x] to avplay[0x%x]\n", handle, instance->ctx->self);
instance->ctx->win = handle;
} else if (instance->ctx->win == handle) {
ext_dbg_avplay("detach master window[0x%x] to avplay[0x%x]\n", handle, instance->ctx->self);
instance->ctx->win = TD_INVALID_HANDLE;
} else {
ext_err_avplay("Only one master window is suppurted\n");
ret = TD_FAILURE;
}
} else {
is_win_valid = find_virtual_win(instance, handle, &index);
if (is_win_valid == TD_TRUE) {
ext_dbg_avplay("detach virtual window[0x%x] to avplay[0x%x]\n", handle, instance->ctx->self);
instance->ctx->virtual_win[index] = TD_INVALID_HANDLE;
instance->ctx->virtual_win_cnt--;
} else if (index < DRV_AVPLAY_MAX_VIR_WIN_CNT) {
ext_dbg_avplay("attach virturl window[0x%x] to avplay[0x%x]\n", handle, instance->ctx->self);
instance->ctx->virtual_win[index] = handle;
instance->ctx->virtual_win_cnt++;
} else {
ext_err_avplay("Too many windwos[%zu] attached\n", instance->ctx->virtual_win_cnt);
ret = TD_FAILURE;
}
}
avplay_spin_unlock(&instance->spin, flags);
return ret;
}
static td_s32 drv_set_resource(avplay_drv_instance *instance, td_handle handle, avplay_resource_type type, td_u32 param)
{
td_s32 ret = TD_SUCCESS;
td_ulong flags = 0;
switch (type) {
case AVPLAY_RESOURCE_TYPE_VID_DEMUX: {
ret = drv_set_dmx_callback(instance, handle, type, vid_dmx_callback);
drv_set_dmx_index_callback(handle, instance, dmx_index_callback);
break;
}
case AVPLAY_RESOURCE_TYPE_AUD_DEMUX: {
ret = drv_set_dmx_callback(instance, handle, type, aud_dmx_callback);
break;
}
case AVPLAY_RESOURCE_TYPE_PCR_DEMUX: {
ret = drv_set_dmx_callback(instance, handle, type, pcr_dmx_callback);
break;
}
case AVPLAY_RESOURCE_TYPE_VDEC: {
ret = drv_set_vdec_callback(instance, handle, vdec_callback);
break;
}
case AVPLAY_RESOURCE_TYPE_WINDOW: {
ret = set_win_resource(instance, handle, param);
break;
}
case AVPLAY_RESOURCE_TYPE_SYNC: {
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx != TD_NULL) {
instance->ctx->sync = handle;
}
avplay_spin_unlock(&instance->spin, flags);
break;
}
default: {
ext_err_avplay("Unsupport resource type[%d]\n", type);
ret = SOC_ERR_AVPLAY_NOT_SUPPORT;
break;
}
}
return_when_error(ret, set_resource);
return TD_SUCCESS;
}
static td_s32 drv_get_avplay_handle_by_window(td_handle win, td_handle *avplay)
{
td_u32 i = 0;
td_ulong flags = 0;
*avplay = TD_INVALID_HANDLE;
avplay_spin_lock(&g_avplay_spinlock, flags);
for (; i < AVPLAY_MAX_CNT; i++) {
if (g_avplay_instance[i].ctx != TD_NULL && g_avplay_instance[i].ctx->win == win) {
*avplay = g_avplay_instance[i].ctx->self;
break;
}
}
avplay_spin_unlock(&g_avplay_spinlock, flags);
return (*avplay == TD_INVALID_HANDLE) ? SOC_ERR_AVPLAY_NO_DATA : TD_SUCCESS;
}
static td_s32 drv_get_resource(const avplay_drv_ctx *ctx, avplay_resource_type type, td_u32 param, td_handle *dst)
{
td_s32 ret = TD_SUCCESS;
*dst = TD_INVALID_HANDLE;
switch (type) {
case AVPLAY_RESOURCE_TYPE_VID_DEMUX: {
*dst = ctx->vid_dmx;
break;
}
case AVPLAY_RESOURCE_TYPE_AUD_DEMUX: {
*dst = ctx->aud_dmx;
break;
}
case AVPLAY_RESOURCE_TYPE_PCR_DEMUX: {
*dst = ctx->pcr_dmx;
break;
}
case AVPLAY_RESOURCE_TYPE_VDEC: {
*dst = ctx->vdec;
break;
}
case AVPLAY_RESOURCE_TYPE_WINDOW: {
*dst = ctx->win;
break;
}
case AVPLAY_RESOURCE_TYPE_SYNC: {
*dst = ctx->sync;
break;
}
default: {
ext_err_avplay("Unsupport resource type[%d]\n", type);
ret = SOC_ERR_AVPLAY_NOT_SUPPORT;
break;
}
}
return_when_error(ret, get_resource);
return TD_SUCCESS;
}
static td_s32 drv_get_global_play_info(const avplay_drv_ctx *ctx, avplay_global_play_info *info)
{
info->audio_enable = ctx->aud_enable;
info->video_enable = ctx->vid_enable;
return TD_SUCCESS;
}
static td_s32 drv_wakeup(avplay_drv_instance *instance)
{
instance->wait_cond = TD_TRUE;
osal_wait_wakeup(&instance->wq);
return TD_SUCCESS;
}
static int drv_wait_cond(const void *param)
{
if (*(const td_bool*)param) {
return 1;
}
return 0;
}
static td_s32 drv_wait_event(avplay_drv_instance *instance, td_u64 event_mask,
avplay_event_type *event, td_u64 *param, td_s64 timeout)
{
td_s32 ret = TD_FAILURE;
td_ulong flags = 0;
avplay_spin_lock(&instance->spin, flags);
if (instance->ctx != TD_NULL) {
instance->ctx->event_mask = event_mask;
}
avplay_spin_unlock(&instance->spin, flags);
*event = AVPLAY_EVENT_TYPE_MAX;
if (!drv_pop_event(instance, event, param)) {
avplay_mutex_unlock(&instance->mutex);
ret = osal_wait_timeout_interruptible(&instance->wq, drv_wait_cond, &instance->wait_cond, (td_ulong)timeout);
avplay_mutex_lock(&instance->mutex);
(void)drv_pop_event(instance, event, param);
instance->wait_cond = TD_FALSE;
}
if (*event != AVPLAY_EVENT_TYPE_MAX) {
ret = TD_SUCCESS;
} else if (ret == 0) {
ret = SOC_ERR_AVPLAY_TIMEOUT;
}
return ret;
}
static td_s32 drv_get_video_info(avplay_drv_instance *instance, avplay_video_info *info)
{
td_s32 ret;
ext_vdec_feature feature = {0};
fn_drv_vdec_get_param vdec_get_param = TD_NULL;
td_handle vdec;
td_ulong flags = 0;
if (instance == TD_NULL || instance->ctx == TD_NULL) {
return TD_FAILURE;
}
avplay_spin_lock(&instance->spin, flags);
vdec = instance->ctx->vdec;
avplay_spin_unlock(&instance->spin, flags);
if (g_avplay_import_func.vdec_func != TD_NULL &&
g_avplay_import_func.vdec_func->pfn_drv_vdec_get_param != TD_NULL) {
vdec_get_param = g_avplay_import_func.vdec_func->pfn_drv_vdec_get_param;
}
if (vdec_get_param == TD_NULL || vdec == TD_INVALID_HANDLE) {
return TD_SUCCESS; /* return success if vdec not exist */
}
ret = vdec_get_param(vdec, EXT_VDEC_PARAM_FEATURE, &feature, sizeof(ext_vdec_feature));
if (ret != TD_SUCCESS) {
return TD_FAILURE;
}
info->width = feature.dec_width;
info->height = feature.dec_height;
info->aspect_width = feature.aspect_width;
info->aspect_height = feature.aspect_height;
info->fps = feature.frame_rate;
info->sampling_type = feature.sampling_type;
return TD_SUCCESS;
}
static td_s32 drv_get_event_param(const avplay_drv_instance *instance, avplay_event_param *param)
{
const avplay_drv_ctx *ctx = instance->ctx;
param->res_param.width = ctx->res.width;
param->res_param.height = ctx->res.height;
param->res_param.stride = ctx->res.stride;
param->res_param.bit_depth = ctx->res.bit_depth;
param->res_param.frm_num = ctx->res.frm_num;
param->res_param.frm_size = ctx->res.frm_size;
param->res_param.meta_size = ctx->res.meta_size;
return TD_SUCCESS;
}
static td_s32 drv_avplay_import_function(void)
{
td_s32 ret;
td_ulong flags = 0;
demux_func_export *dmx_func = TD_NULL;
drv_vdec_export_func *vdec_func = TD_NULL;
ret = ext_drv_module_get_func(SOC_ID_DEMUX, (void **)&dmx_func);
log_when_error(ret, ext_drv_module_get_func);
ret = ext_drv_module_get_func(SOC_ID_VDEC, (void **)&vdec_func);
log_when_error(ret, ext_drv_module_get_func);
avplay_spin_lock(&g_avplay_spinlock, flags);
g_avplay_import_func.dmx_func = dmx_func;
g_avplay_import_func.vdec_func = vdec_func;
avplay_spin_unlock(&g_avplay_spinlock, flags);
return TD_SUCCESS;
}
static td_s32 drv_avplay_set_channel_state(td_handle avplay, avplay_channel_type chn, avplay_channel_state state)
{
avplay_drv_do_func(avplay, drv_set_channel_state(AVPLAY_DRV_CTX, chn, state));
}
static td_s32 drv_avplay_get_resource(td_handle avplay, avplay_resource_type type, td_u32 param, td_handle *dst)
{
avplay_drv_do_func(avplay, drv_get_resource(AVPLAY_DRV_CTX, type, param, dst));
}
static td_s32 drv_avplay_get_global_play_info(td_handle avplay, avplay_global_play_info *info)
{
avplay_drv_do_func(avplay, drv_get_global_play_info(AVPLAY_DRV_CTX, info));
}
td_s32 ext_drv_avplay_create(td_handle *avplay, const void *unique)
{
check_null(avplay);
return drv_instance_alloc(avplay, unique);
}
td_s32 ext_drv_avplay_destroy(td_handle avplay)
{
return drv_instance_del(avplay);
}
td_s32 ext_drv_avplay_reset(td_handle avplay, avplay_channel_type chn)
{
avplay_drv_do_func(avplay, drv_reset(AVPLAY_DRV_CTX, chn));
}
td_s32 ext_drv_avplay_set_channel_state(td_handle avplay, avplay_channel_type chn, avplay_channel_state state)
{
td_ulong flags = 0;
avplay_spin_lock(&g_avplay_spinlock, flags);
if (state == AVPLAY_CHANNEL_START) {
g_avplay_play_cnt++;
}
avplay_spin_unlock(&g_avplay_spinlock, flags);
return drv_avplay_set_channel_state(avplay, chn, state);
}
td_s32 ext_drv_avplay_set_resource(td_handle avplay, td_handle handle, avplay_resource_type type, td_u32 param)
{
avplay_drv_do_func_without_spin(avplay, drv_set_resource(AVPLAY_INSTANCE, handle, type, param));
}
td_s32 ext_drv_avplay_get_resource(td_handle src, avplay_resource_type type, td_u32 param, td_handle *dst)
{
check_null(dst);
if (type == AVPLAY_RESOURCE_TYPE_AVPLAY) {
return drv_get_avplay_handle_by_window(src, dst);
} else {
return drv_avplay_get_resource(src, type, param, dst);
}
}
td_s32 ext_drv_avplay_wakeup(td_handle avplay)
{
avplay_drv_do_func_without_spin(avplay, drv_wakeup(AVPLAY_INSTANCE));
}
td_s32 ext_drv_avplay_wait_event(td_handle avplay, td_u64 event_mask,
avplay_event_type *event, td_u64 *param, td_s64 timeout)
{
check_null(event);
check_null(param);
avplay_drv_do_func_without_spin(avplay, drv_wait_event(AVPLAY_INSTANCE, event_mask, event, param, timeout));
}
td_s32 ext_drv_avplay_get_video_info(td_handle avplay, avplay_video_info *info)
{
check_null(info);
avplay_drv_do_func_without_spin(avplay, drv_get_video_info(AVPLAY_INSTANCE, info));
}
td_s32 ext_drv_avplay_get_global_play_info(td_handle avplay, avplay_global_play_info *info)
{
check_null(info);
info->content_count = g_avplay_play_cnt;
return drv_avplay_get_global_play_info(avplay, info);
}
td_s32 ext_drv_avplay_get_event_param(td_handle avplay, avplay_event_param *param)
{
check_null(param);
avplay_drv_do_func(avplay, drv_get_event_param(AVPLAY_INSTANCE, param));
}
td_s32 avplay_init(void)
{
avplay_spin_init(&g_avplay_spinlock);
drv_instance_init();
return TD_SUCCESS;
}
td_s32 avplay_deinit(void)
{
drv_instance_deinit();
avplay_spin_deinit(&g_avplay_spinlock);
return TD_SUCCESS;
}
td_s32 avplay_open(void *private_data)
{
return drv_avplay_import_function();
}
td_s32 avplay_release(void *private_data)
{
return drv_instance_clear(private_data);
}