/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: encoder * Author: sdk * Create: 2019-08-13 */ #include #include #include #include #include #include #include #include #include #include #include #include "uapi_ssm.h" #include "mpi_venc_ext.h" #include "soc_errno.h" #include "td_type.h" #include "mpi_memory_ext.h" #include "drv_ioctl_venc.h" #include "securec.h" #include "soc_module.h" #include "mpi_venc.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* end of #ifdef __cplusplus */ #define RC_LIB_NAME "libuapi_rc.so" static td_void *g_handle = TD_NULL; static td_s32 g_venc_dev_fd = -1; static const td_char g_venc_dev_name[] = VENC_DEV; static pthread_mutex_t g_venc_mutex = PTHREAD_MUTEX_INITIALIZER; static ext_ioctl_strm_buf_info g_asr_ve_chn_info[VENC_MAX_CHN_NUM]; static ext_ioctl_chan_virt_addr g_asr_ve_chn_vir_addr[VENC_MAX_CHN_NUM]; td_s32 g_dev_open_cnt; #define ext_venc_lock() (void)pthread_mutex_lock(&g_venc_mutex) #define ext_venc_unlock() (void)pthread_mutex_unlock(&g_venc_mutex) #define check_venc_init_ret() \ do { \ ext_venc_lock(); \ if (g_venc_dev_fd < 0) { \ ext_err_venc("venc not init\n"); \ ext_venc_unlock(); \ return SOC_ERR_VENC_NO_INIT; \ } \ ext_venc_unlock(); \ } while (0) #define check_channel_exist_ret(i, max, chn_handle) do { \ for ((i) = 0; (i) < (max); (i)++) { \ if (g_asr_ve_chn_info[(i)].handle == (chn_handle)) \ break; \ } \ if ((max) == (i)) { \ ext_err_venc("venc channel not exit\n"); \ return SOC_ERR_VENC_CHN_NOT_EXIST; \ } \ } while (0) #define venc_handle_invalid(handle) ((((handle) & 0xff000000) >> 24) != SOC_ID_VENC) /* 24 bit of handle */ static td_s32 init_function(td_void) { td_s32 (*rc_init_function)(td_void) = TD_NULL; td_s32 ret; g_handle = dlopen(RC_LIB_NAME, RTLD_LAZY); if (g_handle == TD_NULL) { close(g_venc_dev_fd); g_venc_dev_fd = -1; ext_fatal_venc("dynamic load the RC lib failed because %s!\n", dlerror()); return TD_FAILURE; } rc_init_function = dlsym(g_handle, "venc_rc_init"); if (rc_init_function == TD_NULL) { dlclose(g_handle); g_handle = TD_NULL; close(g_venc_dev_fd); g_venc_dev_fd = -1; ext_fatal_venc("can't find the RC initial function becasuse %s!\n", dlerror()); return TD_FAILURE; } ret = rc_init_function(); if (ret != TD_SUCCESS && ret != SOC_ERR_VENC_DEV_OPENED) { dlclose(g_handle); g_handle = TD_NULL; close(g_venc_dev_fd); g_venc_dev_fd = -1; ext_fatal_venc("RC initial failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } td_s32 ext_mpi_venc_init(td_void) { struct stat st; td_s32 i; ext_venc_lock(); /* already opened in the process */ if (g_venc_dev_fd > 0) { ext_venc_unlock(); return TD_SUCCESS; } g_venc_dev_fd = open(g_venc_dev_name, O_RDWR | O_NONBLOCK, 0); if (g_venc_dev_fd < 0) { ext_fatal_venc("open VEDU err.\n"); ext_venc_unlock(); return SOC_ERR_VENC_NOT_SUPPORT; } if (fstat(g_venc_dev_fd, &st) == TD_FAILURE) { ext_fatal_venc("VEDU is not exist.\n"); ext_venc_unlock(); return SOC_ERR_VENC_DEV_NOT_EXIST; } if (!S_ISCHR(st.st_mode)) { ext_fatal_venc("VEDU is not device.\n"); ext_venc_unlock(); return SOC_ERR_VENC_NOT_DEV_FILE; } for (i = 0; i < VENC_MAX_CHN_NUM; i++) { g_asr_ve_chn_vir_addr[i].strm_buf_virt_addr = TD_NULL; g_asr_ve_chn_info[i].handle = TD_INVALID_HANDLE; g_asr_ve_chn_info[i].strm_buf_phy_addr = TD_NULL; g_asr_ve_chn_info[i].buf_size = 0; g_asr_ve_chn_info[i].secure = TD_FALSE; } if (init_function() != TD_SUCCESS) { ext_venc_unlock(); return TD_FAILURE; } if (g_dev_open_cnt < 0x7FFFFFFF) { g_dev_open_cnt++; ext_warn_venc("init count:g_dev_open_cnt = %d\n", g_dev_open_cnt); } else { ext_fatal_venc("init count:%d is overflow\n", g_dev_open_cnt); } ext_info_venc(" open librc success\n"); ext_venc_unlock(); return TD_SUCCESS; } static void unmap_phy_addr_base(td_s32 i) { td_s32 ret; td_u64 addr_temp; td_void *virt_addr = TD_NULL; td_mem_size_t buf_size; addr_temp = ptr_u64(g_asr_ve_chn_vir_addr[i].strm_buf_virt_addr); virt_addr = u64_ptr(addr_temp); buf_size = g_asr_ve_chn_vir_addr[i].strm_buf_size; ret = ext_mpi_mem_unmap(virt_addr, buf_size); if (ret != TD_SUCCESS) { ext_err_venc("venc unmap failed!\n"); } g_asr_ve_chn_vir_addr[i].strm_buf_virt_addr = NULL; } td_s32 ext_mpi_venc_deinit(td_void) { td_s32 i; td_s32 (*rc_deinit_function)(td_void) = TD_NULL; ext_venc_lock(); if (g_venc_dev_fd < 0) { ext_venc_unlock(); return TD_SUCCESS; } g_dev_open_cnt = (g_dev_open_cnt - 1) > 0 ? g_dev_open_cnt - 1 : 0; if (g_dev_open_cnt > 0) { ext_warn_venc("g_dev_open_cnt = %d venc is working in another channel, don't close!\n", g_dev_open_cnt); ext_venc_unlock(); return TD_SUCCESS; } for (i = 0; i < VENC_MAX_CHN_NUM; i++) { if (g_asr_ve_chn_info[i].handle != TD_INVALID_HANDLE && g_asr_ve_chn_info[i].secure == TD_FALSE) { unmap_phy_addr_base(i); } } rc_deinit_function = dlsym(g_handle, "venc_rc_deinit"); if (rc_deinit_function == TD_NULL) { ext_err_venc("can't find the RC de_init function becasuse %s!\n", dlerror()); } else { td_s32 ret = rc_deinit_function(); if (ret != TD_SUCCESS && ret != SOC_ERR_VENC_DEV_OPENED) { ext_err_venc("RC user deinit failed!\n"); } } dlclose(g_handle); g_handle = TD_NULL; close(g_venc_dev_fd); g_venc_dev_fd = -1; ext_venc_unlock(); return TD_SUCCESS; } td_s32 ext_mpi_venc_set_config(td_handle venc_chan, venc_ioctl_chan_info *chan_info) { td_s32 ret; td_s32 i; if (chan_info == NULL) { ext_err_venc("Channel config parameters is NULL\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); chan_info->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_SET_CHN_CFG, chan_info); if (ret != TD_SUCCESS) { ext_err_venc("Set channel config failed(0x%x).\n", ret); } return ret; } td_s32 ext_mpi_venc_get_config(td_handle venc_chan, venc_ioctl_chan_info *chan_info) { td_s32 ret; td_s32 i; if (chan_info == NULL) { ext_err_venc("Channel config parameters is NULL\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); chan_info->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_GET_CHN_CFG, chan_info); if (ret != TD_SUCCESS) { ext_err_venc("Set channel config failed(0x%x).\n", ret); return ret; } return ret; } static td_s32 get_venc_stream_addr_user(td_u32 chan_id) { td_u64 fd; td_u32 buf_size; td_void *start_vir_addr = TD_NULL; td_void *strm_vir_addr = TD_NULL; fd = g_asr_ve_chn_info[chan_id].strm_buf_fd; buf_size = g_asr_ve_chn_info[chan_id].buf_size; if (g_asr_ve_chn_info[chan_id].secure == TD_FALSE) { start_vir_addr = ext_mpi_mem_map((td_mem_handle_t)fd, (td_mem_size_t)buf_size); if (start_vir_addr == TD_NULL) { ext_err_venc("memmap VENC's stream buffer failed.fd = %d\n", fd); return SOC_ERR_VENC_CREATE_ERR; } strm_vir_addr = start_vir_addr; } g_asr_ve_chn_vir_addr[chan_id].strm_buf_virt_addr = strm_vir_addr; g_asr_ve_chn_vir_addr[chan_id].strm_buf_size = buf_size; return TD_SUCCESS; } static td_s32 tee_support_init(td_handle *ssm_handle) { uapi_ssm_attr ssm_attr = {0}; if (uapi_ssm_init() != TD_SUCCESS) { ext_err_venc("uapi_ssm_init() fail\n"); return TD_FAILURE; } ssm_attr.intent = UAPI_SSM_INTENT_WATCH; if (uapi_ssm_create(&ssm_attr, ssm_handle) != TD_SUCCESS) { ext_err_venc("uapi_ssm_create() fail\n"); (td_void)uapi_ssm_deinit(); return TD_FAILURE; } return TD_SUCCESS; } td_s32 ext_mpi_venc_create(td_handle *venc_chan, venc_ioctl_create *venc_chn_create) { td_s32 ret; td_u32 i; if (venc_chn_create == TD_NULL || venc_chan == TD_NULL) { ext_err_venc("NULL para\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); if (venc_chn_create->attr.secure) { if (tee_support_init(&venc_chn_create->strm_buf_info.ssm_handle) != TD_SUCCESS) { ext_err_venc("tee_support_init failed\n"); return SOC_ERR_VENC_CREATE_ERR; } } else { venc_chn_create->strm_buf_info.ssm_handle = TD_INVALID_HANDLE; } ext_venc_lock(); for (i = 0; i < VENC_MAX_CHN_NUM; i++) { if (g_asr_ve_chn_info[i].handle == TD_INVALID_HANDLE) { break; } } if (i == VENC_MAX_CHN_NUM) { ext_err_venc("mpi create err, \n"); ext_venc_unlock(); return SOC_ERR_VENC_CREATE_ERR; } ret = ioctl(g_venc_dev_fd, CMD_VENC_CREATE_CHN, venc_chn_create); if (ret != TD_SUCCESS) { ext_venc_unlock(); return ret; } (td_void)memcpy_s(&g_asr_ve_chn_info[i], sizeof(ext_ioctl_strm_buf_info), &venc_chn_create->strm_buf_info, sizeof(venc_chn_create->strm_buf_info)); ret = get_venc_stream_addr_user(i); if (ret != TD_SUCCESS) { (void)ioctl(g_venc_dev_fd, CMD_VENC_DESTROY_CHN, &(venc_chn_create->chan_id)); ext_venc_unlock(); return ret; } *venc_chan = venc_chn_create->chan_id; g_asr_ve_chn_info[i].handle = venc_chn_create->chan_id; ext_info_venc("create_ok, chn%d, buf fd: %#x, len:%#x.\n", i, g_asr_ve_chn_info[i].strm_buf_fd, g_asr_ve_chn_info[i].buf_size); ext_venc_unlock(); return TD_SUCCESS; } static td_s32 destroy_venc_stream_addr(td_u32 chan_id) { td_s32 ret; td_void *user_virt_addr = NULL; td_u64 addr_temp; if (g_asr_ve_chn_vir_addr[chan_id].strm_buf_virt_addr == TD_NULL) { return TD_SUCCESS; } if (g_asr_ve_chn_info[chan_id].protocol == EXT_VENC_STD_JPEG) { user_virt_addr = g_asr_ve_chn_vir_addr[chan_id].strm_buf_virt_addr; } else { addr_temp = ptr_u64(g_asr_ve_chn_vir_addr[chan_id].strm_buf_virt_addr); user_virt_addr = u64_ptr(addr_temp); } ret = ext_mpi_mem_unmap(user_virt_addr, g_asr_ve_chn_info[chan_id].buf_size); if (ret != TD_SUCCESS) { ext_err_venc("venc ext_mpi_media_mem_unmap failed!\n"); return ret; } g_asr_ve_chn_vir_addr[chan_id].strm_buf_virt_addr = TD_NULL; return TD_SUCCESS; } static td_void tee_support_deinit(td_handle *ssm_handle) { if (*ssm_handle != TD_INVALID_HANDLE) { (td_void)uapi_ssm_destroy(*ssm_handle); (td_void)uapi_ssm_deinit(); *ssm_handle = TD_INVALID_HANDLE; } } td_s32 ext_mpi_venc_destroy(td_handle venc_chan) { td_s32 ret; td_u32 i; if (venc_chan == TD_INVALID_HANDLE) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_CHN_NOT_EXIST; } check_venc_init_ret(); ext_venc_lock(); for (i = 0; i < VENC_MAX_CHN_NUM; i++) { if (g_asr_ve_chn_info[i].handle == venc_chan) { break; } } if (i == VENC_MAX_CHN_NUM) { ext_venc_unlock(); return SOC_ERR_VENC_CHN_NOT_EXIST; } ret = destroy_venc_stream_addr(i); if (ret != TD_SUCCESS) { ext_venc_unlock(); return ret; } ret = ioctl(g_venc_dev_fd, CMD_VENC_DESTROY_CHN, &venc_chan); if (ret != TD_SUCCESS) { ext_venc_unlock(); return ret; } tee_support_deinit(&g_asr_ve_chn_info[i].ssm_handle); g_asr_ve_chn_info[i].handle = TD_INVALID_HANDLE; ext_venc_unlock(); return ret; } static td_u8 *get_video_stream_addr(td_u32 handle_id, venc_ioctl_buf_offset *buf_offset) { td_u8 *user_stream_addr = TD_NULL; if (g_asr_ve_chn_info[handle_id].secure == TD_FALSE) { user_stream_addr = (td_u8 *)(g_asr_ve_chn_vir_addr[handle_id].strm_buf_virt_addr) + buf_offset->strm_buf_offset[0]; } return user_stream_addr; } td_s32 ext_mpi_venc_acquire_stream(const td_handle venc_chan, venc_ioctl_acquire_stream *drv_stream, const td_u32 timeout_ms) { td_s32 ret; td_u32 i = 0; venc_ioctl_buf_offset *buf_off_set = TD_NULL; if (venc_chan == TD_INVALID_HANDLE) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_CHN_NOT_EXIST; } if (drv_stream == TD_NULL) { ext_err_venc("para stream is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); drv_stream->chan_id = venc_chan; drv_stream->block_flag = timeout_ms; ret = ioctl(g_venc_dev_fd, CMD_VENC_ACQUIRE_STREAM, drv_stream); if (ret != TD_SUCCESS) { return ret; } buf_off_set = &drv_stream->buf_offset; if (drv_stream->stream.slc_len > 0) { drv_stream->stream.virt_addr = ptr_u64(get_video_stream_addr(i, buf_off_set)); if ((drv_stream->stream.virt_addr == TD_NULL) && (g_asr_ve_chn_info[i].secure == TD_FALSE)) { ext_err_venc("get_stream_addr failed\n"); return TD_FAILURE; } } drv_stream->buf_handle.addr_offset = drv_stream->buf_offset.strm_buf_offset[0]; drv_stream->buf_handle.mem_handle = (td_mem_handle_t)g_asr_ve_chn_info[i].strm_buf_fd; drv_stream->protocol = g_asr_ve_chn_info[i].protocol; return TD_SUCCESS; } td_s32 ext_mpi_venc_release_stream(td_handle venc_chan, venc_ioctl_acquire_stream *acquire_stream) { td_s32 ret; if (venc_chan == TD_INVALID_HANDLE) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_CHN_NOT_EXIST; } if (acquire_stream == TD_NULL) { ext_err_venc("para stream is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); acquire_stream->chan_id = venc_chan; acquire_stream->h264_stream_off = (td_u32)acquire_stream->buf_handle.addr_offset; ret = ioctl(g_venc_dev_fd, CMD_VENC_RELEASE_STREAM, acquire_stream); return ret; } td_s32 ext_mpi_venc_start(td_handle venc_chan) { td_s32 ret; td_s32 i; if (venc_handle_invalid(venc_chan)) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_INVALID_PARA; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); ret = ioctl(g_venc_dev_fd, CMD_VENC_START_RECV_PIC, &venc_chan); return ret; } td_s32 ext_mpi_venc_stop(td_handle venc_chan) { td_s32 ret; td_s32 i; if (venc_handle_invalid(venc_chan)) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_INVALID_PARA; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); ret = ioctl(g_venc_dev_fd, CMD_VENC_STOP_RECV_PIC, &venc_chan); return ret; } td_s32 ext_mpi_venc_request_i_frame(td_handle venc_chan) { td_s32 ret; td_s32 i; if (venc_handle_invalid(venc_chan)) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_INVALID_PARA; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); ret = ioctl(g_venc_dev_fd, CMD_VENC_REQUEST_I_FRAME, &venc_chan); return ret; } td_s32 ext_mpi_venc_queue_frame(td_handle venc_chan, venc_ioctl_queue_frame *venc_queue_frame) { td_s32 ret; td_s32 i; if (venc_chan == TD_INVALID_HANDLE) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_CHN_NOT_EXIST; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); if (venc_queue_frame == TD_NULL) { ext_err_venc("para _stream is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } venc_queue_frame->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_QUEUE_FRAME, venc_queue_frame); return ret; } td_s32 ext_mpi_venc_dequeue_frame(td_handle venc_chan, venc_ioctl_queue_frame *venc_queue_frame) { td_s32 ret; td_s32 i; if (venc_chan == TD_INVALID_HANDLE) { ext_err_venc("para venc_chan is invalid.\n"); return SOC_ERR_VENC_CHN_NOT_EXIST; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); if (venc_queue_frame == TD_NULL) { ext_err_venc("para _stream is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } venc_queue_frame->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_DEQUEUE_FRAME, venc_queue_frame); return ret; } td_s32 ext_mpi_venc_get_cap_ability(venc_ioctl_cap *drv_cap) { td_s32 ret; if (drv_cap == TD_NULL) { ext_err_venc("para capability is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); venc_check_neq_ret(memset_s(drv_cap, sizeof(venc_ioctl_cap), 0, sizeof(venc_ioctl_cap)), TD_SUCCESS, TD_FAILURE); ret = ioctl(g_venc_dev_fd, CMD_VENC_GET_CAP, drv_cap); return ret; } td_s32 ext_mpi_venc_set_frame_drop_strategy(td_handle venc_id, venc_ioctl_drop_frame_strategy *venc_frm_drop_strategy) { td_s32 ret; td_s32 i; check_venc_ptr_ret(venc_frm_drop_strategy); check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_id); venc_frm_drop_strategy->chan_id = venc_id; ret = ioctl(g_venc_dev_fd, CMD_VENC_SET_DROP_FRM_STRATEGY, venc_frm_drop_strategy); if (ret != TD_SUCCESS) { ext_err_venc("set_frame_drop_strategy failed! ret = %x\n", ret); } return ret; } td_s32 ext_mpi_venc_get_frame_drop_strategy(td_handle venc_id, venc_ioctl_drop_frame_strategy *venc_frm_drop_strategy) { td_s32 ret; td_s32 i; check_venc_ptr_ret(venc_frm_drop_strategy); check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_id); venc_frm_drop_strategy->chan_id = venc_id; ret = ioctl(g_venc_dev_fd, CMD_VENC_GET_DROP_FRM_STRATEGY, venc_frm_drop_strategy); if (ret != TD_SUCCESS) { ext_err_venc("get_frame_drop_strategy failed! ret = %x\n", ret); return ret; } return ret; } td_s32 ext_mpi_venc_reset(td_handle venc_id) { td_s32 ret; td_s32 i; check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_id); ret = ioctl(g_venc_dev_fd, CMD_VENC_RESET_CHN, &venc_id); if (ret != TD_SUCCESS) { ext_err_venc("venc_reset chn %d failed! ret = %x\n", venc_id, ret); } return ret; } td_s32 ext_mpi_venc_query_status(td_handle venc_id, venc_ioctl_status *query_status) { td_s32 ret; td_s32 i; check_venc_ptr_ret(query_status); check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_id); query_status->chan_id = venc_id; ret = ioctl(g_venc_dev_fd, CMD_VENC_QUERY_STATUS, query_status); if (ret != TD_SUCCESS) { ext_err_venc("venc_reset failed! ret = %x\n", ret); return ret; } return ret; } td_s32 ext_mpi_venc_get_attr(td_handle venc_chan, venc_ioctl_create *venc_chn_create) { td_s32 ret; td_s32 i; if (venc_chn_create == TD_NULL) { ext_err_venc("para attr is NULL.\n"); return SOC_ERR_VENC_NULL_PTR; } check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); venc_chn_create->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_GET_CHN_ATTR, venc_chn_create); return ret; } td_s32 ext_mpi_venc_set_rc_param(td_handle venc_chan, venc_ioctl_rc_param *ioctl_rc_param) { td_s32 ret; td_s32 i; check_venc_ptr_ret(ioctl_rc_param); check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); ioctl_rc_param->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_SET_RC_PARAM, ioctl_rc_param); return ret; } td_s32 ext_mpi_venc_get_rc_param(td_handle venc_chan, venc_ioctl_rc_param *ioctl_rc_param) { td_s32 ret; td_s32 i; check_venc_ptr_ret(ioctl_rc_param); check_venc_init_ret(); check_channel_exist_ret(i, VENC_MAX_CHN_NUM, venc_chan); ioctl_rc_param->chan_id = venc_chan; ret = ioctl(g_venc_dev_fd, CMD_VENC_GET_RC_PARAM, ioctl_rc_param); return ret; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* end of #ifdef __cplusplus */