#include #include #include #include #include #include #include "dataserver_reader_inner.h" #ifdef LOG_LOGCAT #define LOG_TAG "ccdataserver" #include #define ds_inf(_fmt_,...) ALOGI("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__) #define ds_err(_fmt_,...) ALOGE("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__) #else #define ds_inf(_fmt_,...) printf("I %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__) #define ds_err(_fmt_,...) printf("E %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__) #endif struct userdata_meta_info_t { uint32_t poc_number; /************ flags bit definition *********** bit 0: //used for mpeg2 1, group start 0, not group start bit 1-2: //used for mpeg2 0, extension_and_user_data( 0 ) 1, extension_and_user_data( 1 ) 2, extension_and_user_data( 2 ) bit 3-6: //video format 0, VFORMAT_MPEG12 1, VFORMAT_MPEG4 2, VFORMAT_H264 3, VFORMAT_MJPEG 4, VFORMAT_REAL 5, VFORMAT_JPEG 6, VFORMAT_VC1 7, VFORMAT_AVS 8, VFORMAT_SW 9, VFORMAT_H264MVC 10, VFORMAT_H264_4K2K 11, VFORMAT_HEVC 12, VFORMAT_H264_ENC 13, VFORMAT_JPEG_ENC 14, VFORMAT_VP9 bit 7-9: //frame type 0, Unknown Frame Type 1, I Frame 2, B Frame 3, P Frame 4, D_Type_MPEG2 bit 10: //top_field_first_flag valid 0: top_field_first_flag is not valid 1: top_field_first_flag is valid bit 11: //top_field_first bit val bit 12-13: //picture_struct, used for H264 0: Invalid 1: TOP_FIELD_PICTURE 2: BOT_FIELD_PICTURE 3: FRAME_PICTURE **********************************************/ uint32_t flags; uint32_t vpts; /*video frame pts*/ /****************************************** 0: pts is invalid, please use duration to calculate 1: pts is valid ******************************************/ uint32_t vpts_valid; /*duration for frame*/ uint32_t duration; /* how many records left in queue waiting to be read*/ uint32_t records_in_que; unsigned long long priv_data; uint64_t vpts_64; /*valid only if version == 2*/ uint32_t padding_data[2]; }; struct userdata_param_t { uint32_t version; uint32_t instance_id; /*input, 0~9*/ uint32_t buf_len; /*input*/ uint32_t data_size; /*output*/ void* pbuf_addr; /*input*/ struct userdata_meta_info_t meta_info; /*output*/ }; #define AMSTREAM_IOC_MAGIC 'S' #define AMSTREAM_IOC_UD_FLUSH_USERDATA _IOR(AMSTREAM_IOC_MAGIC, 0x56, int) #define AMSTREAM_IOC_UD_BUF_READ _IOR(AMSTREAM_IOC_MAGIC, 0x57, int) #define AMSTREAM_IOC_UD_AVAILABLE_VDEC _IOR(AMSTREAM_IOC_MAGIC, 0x5c, unsigned int) #define USERDATA_POLL_TIMEOUT 100 static void *ds_userdata_read_task(void *args) { reader_inst_t *inst = (reader_inst_t *)args; ds_inf("userdata read task started"); uint8_t buf[5 * 1024 + 4]; int flush = 1; while (inst->running) { struct pollfd pfd[2]; int ret; pfd[0].fd = inst->fd; pfd[1].fd = inst->evtfd; pfd[0].events = pfd[1].events = POLLIN | POLLERR; ret = poll(pfd, 2, USERDATA_POLL_TIMEOUT); if (!inst->running || ret <= 0 || !(pfd[0].events & POLLIN)) continue; int vdec_ids = 0; ret = ioctl(inst->fd, AMSTREAM_IOC_UD_AVAILABLE_VDEC, &vdec_ids); if (ret == -1) { ds_err("ioctl AVAILABLE_VDECS fail, err(%d/%s)", errno, strerror(errno)); } int vdec_id = vdec_ids; /*drop the data not current vid*/ if (vdec_id != inst->priv) continue; if (flush) { ret = ioctl(inst->fd, AMSTREAM_IOC_UD_FLUSH_USERDATA, &vdec_id); if (ret == -1) { ds_inf("ioctl FLUSH_USERDATA %d, err(%d/%s)", vdec_id, errno, strerror(errno)); } flush = 0; } struct userdata_param_t user_para_info; do { memset(&user_para_info, 0, sizeof(struct userdata_param_t)); user_para_info.pbuf_addr = (void*)(size_t)buf; user_para_info.buf_len = sizeof(buf); user_para_info.instance_id = vdec_id; ret = ioctl(inst->fd, AMSTREAM_IOC_UD_BUF_READ, &user_para_info); if (ret == -1) { ds_err("ioctl READ fail, err(%d/%s)", errno, strerror(errno)); continue; } if (user_para_info.data_size <= 0) continue; #define MAX_CC_DATA_LEN (1024*5 + 4) if (user_para_info.data_size > MAX_CC_DATA_LEN) user_para_info.data_size = MAX_CC_DATA_LEN; /*callback the data*/ { ds_data_callback_t *cb; pthread_mutex_lock(&inst->callback_list_lock); /*move the waiting callbacks to main list*/ if (!list_empty(&inst->callback_wait_list)) { struct list_head *pos, *tmp; list_for_each_safe(pos, tmp, &inst->callback_wait_list) { list_del(pos); list_add_tail(pos, &inst->callback_list); } } list_for_each_entry(cb, &inst->callback_list, head) { cb->fn.data_cb((uint8_t *)&user_para_info, sizeof(user_para_info), cb->priv); cb->fn.data_cb(buf, user_para_info.data_size, cb->priv); cb->fn.ready_cb(1/*blk mode*/, sizeof(user_para_info) + user_para_info.data_size, cb->priv); ds_inf("userdata: %zd+%d", sizeof(user_para_info), user_para_info.data_size); } pthread_mutex_unlock(&inst->callback_list_lock); } } while (user_para_info.meta_info.records_in_que > 1); } ds_inf("userdata read task exit"); return 0; } static int ds_userdata_set(reader_inst_t *inst, const char *settings) { (void)inst; int ret = 0; char *set = "src_para_userdata_vid"; int len = strlen(set); if (!settings) return ret; if (strncmp(settings, set, len) == 0) { int vid = 1; if (sscanf(settings, "%*s %d", &vid) == 1) { ds_inf("userdata vid set:%d", vid); inst->priv = vid; } else { ds_err("userdata vid set fail"); ret = -1; } } return ret; } static ds_reader_t userdata_reader = { .task = ds_userdata_read_task, .set = ds_userdata_set, }; static ds_reader_t* ds_userdata_reader_check(const char *devname) { if (strcmp(devname, "/dev/amstream_userdata") == 0) return &userdata_reader; return NULL; } REG_DS_READER(ds_userdata_reader_check);