| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <sys/eventfd.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <poll.h> |
| #include <dlfcn.h> |
| |
| #include <dmx.h> |
| /*add for config define for linux dvb *.h*/ |
| #include "record_device.h" |
| #include "dvr_types.h" |
| #include "dvr_utils.h" |
| #include "dvb_utils.h" |
| |
| #define MAX_RECORD_DEVICE_COUNT 8 |
| #define MAX_DEMUX_DEVICE_COUNT 8 |
| #define MAX_FEND_DEVICE_COUNT 2 |
| |
| /**\brief DVR record device state*/ |
| typedef enum { |
| RECORD_DEVICE_STATE_OPENED, /**< Record open state*/ |
| RECORD_DEVICE_STATE_STARTED, /**< Record start state*/ |
| RECORD_DEVICE_STATE_STOPPED, /**< Record stop state*/ |
| RECORD_DEVICE_STATE_CLOSED, /**< Record close state*/ |
| } Record_DeviceState_t; |
| |
| /**\brief Record stream information*/ |
| typedef struct { |
| int fid; /**< DMX Filter ID*/ |
| uint16_t pid; /**< Stream PID*/ |
| DVR_Bool_t is_start; /**< Flag indicate the stream is start or not*/ |
| } Record_Stream_t; |
| |
| /**\brief Record device context information*/ |
| typedef struct { |
| int fd; /**< DVR device file descriptor*/ |
| int stream_cnt; /**< Stream counts*/ |
| Record_Stream_t streams[DVR_MAX_RECORD_PIDS_COUNT]; /**< Record stream list*/ |
| Record_DeviceState_t state; /**< Record device state*/ |
| int fend_dev_id; /**< Frontend device id*/ |
| uint32_t dmx_dev_id; /**< Record source*/ |
| size_t dvr_buf; |
| size_t output_handle; /**< Secure demux output*/ |
| pthread_mutex_t lock; /**< Record device lock*/ |
| int evtfd; /**< eventfd for poll's exit*/ |
| } Record_DeviceContext_t; |
| |
| /* each sid need one mutex */ |
| static pthread_mutex_t secdmx_lock[MAX_FEND_DEVICE_COUNT] = PTHREAD_MUTEX_INITIALIZER; |
| |
| static Record_DeviceContext_t record_ctx[MAX_RECORD_DEVICE_COUNT] = { |
| { |
| .state = RECORD_DEVICE_STATE_CLOSED, |
| .fend_dev_id = -1, |
| .lock = PTHREAD_MUTEX_INITIALIZER |
| }, |
| { |
| .state = RECORD_DEVICE_STATE_CLOSED, |
| .fend_dev_id = -1, |
| .lock = PTHREAD_MUTEX_INITIALIZER |
| } |
| }; |
| /*define sec dmx function api ptr*/ |
| static void* secdmx_handle = NULL; |
| int (*SECDMX_Init_Ptr)(void); |
| int (*SECDMX_Deinit_Ptr)(void); |
| int (*SECDMX_AllocateDVRBuffer_Ptr)(int sid, size_t size, size_t *addr); |
| int (*SECDMX_FreeDVRBuffer_Ptr)(int sid); |
| int (*SECDMX_AddOutputBuffer_Ptr)(int sid, size_t addr, size_t size, size_t *handle); |
| int (*SECDMX_AddDVRPids_Ptr)(size_t handle, uint16_t *pids, int pid_num); |
| int (*SECDMX_RemoveOutputBuffer_Ptr)(size_t handle); |
| int (*SECDMX_GetOutputBufferStatus_Ptr)(size_t handle, size_t *start_addr, size_t *len); |
| int (*SECDMX_ProcessData_Ptr)(int sid, size_t wp); |
| |
| static void* load_secdmx_api(void) |
| { |
| if (secdmx_handle != NULL) { |
| return secdmx_handle; |
| } |
| void* handle = NULL; |
| handle = dlopen("libdmx_client_sys.so", RTLD_NOW);//RTLD_NOW RTLD_LAZY |
| |
| if (handle == NULL) { |
| DVR_ERROR("load_secdmx_api load libdmx_client_sys error[%s] no:%d", strerror(errno), errno); |
| handle = dlopen("libdmx_client.so", RTLD_NOW);//RTLD_NOW RTLD_LAZY |
| } |
| |
| if (handle == NULL) { |
| DVR_ERROR("load_secdmx_api load libdmx_client error[%s] no:%d", strerror(errno), errno); |
| return NULL; |
| } |
| secdmx_handle = handle; |
| |
| SECDMX_Init_Ptr = dlsym(handle, "SECDMX_Init"); |
| SECDMX_Deinit_Ptr = dlsym(handle, "SECDMX_Deinit"); |
| SECDMX_AllocateDVRBuffer_Ptr = dlsym(handle, "SECDMX_AllocateDVRBuffer"); |
| SECDMX_FreeDVRBuffer_Ptr = dlsym(handle, "SECDMX_FreeDVRBuffer"); |
| SECDMX_AddOutputBuffer_Ptr = dlsym(handle, "SECDMX_AddOutputBuffer"); |
| SECDMX_AddDVRPids_Ptr = dlsym(handle, "SECDMX_AddDVRPids"); |
| SECDMX_RemoveOutputBuffer_Ptr = dlsym(handle, "SECDMX_RemoveOutputBuffer"); |
| SECDMX_GetOutputBufferStatus_Ptr = dlsym(handle, "SECDMX_GetOutputBufferStatus"); |
| SECDMX_ProcessData_Ptr = dlsym(handle, "SECDMX_ProcessData"); |
| |
| return handle; |
| } |
| |
| static int unload_secdmx_api(void) |
| { |
| int ret=0; |
| if (secdmx_handle == NULL) { |
| return 0; |
| } |
| ret = dlclose(secdmx_handle); |
| secdmx_handle = NULL; |
| return ret; |
| } |
| |
| int add_dvr_pids(Record_DeviceContext_t *p_ctx) |
| { |
| int i; |
| int result = DVR_SUCCESS; |
| int cnt = 0; |
| uint16_t pids[DVR_MAX_RECORD_PIDS_COUNT]; |
| |
| if (dvr_check_dmx_isNew() == 1) { |
| memset(pids, 0, sizeof(pids)); |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| if (p_ctx->streams[i].pid != DVR_INVALID_PID) { |
| pids[cnt++] = p_ctx->streams[i].pid; |
| DVR_DEBUG("dvr pid:%x, cnt:%x", pids[cnt-1], cnt); |
| } |
| } |
| if (SECDMX_AddDVRPids_Ptr != NULL && p_ctx->output_handle) |
| result = SECDMX_AddDVRPids_Ptr(p_ctx->output_handle, pids, cnt); |
| DVR_RETURN_IF_FALSE(result == DVR_SUCCESS); |
| } |
| |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_open(Record_DeviceHandle_t *p_handle, Record_DeviceOpenParams_t *params) |
| { |
| int i; |
| int dev_no; |
| char dev_name[32]; |
| int ret; |
| char buf[64]; |
| char cmd[32]; |
| Record_DeviceContext_t *p_ctx; |
| |
| DVR_RETURN_IF_FALSE(p_handle); |
| DVR_RETURN_IF_FALSE(params); |
| DVR_RETURN_IF_FALSE(params->dmx_dev_id < MAX_DEMUX_DEVICE_COUNT); |
| |
| for (dev_no = 0; dev_no < MAX_RECORD_DEVICE_COUNT; dev_no++) { |
| if (record_ctx[dev_no].state == RECORD_DEVICE_STATE_CLOSED) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(dev_no < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(record_ctx[dev_no].state == RECORD_DEVICE_STATE_CLOSED); |
| p_ctx = &record_ctx[dev_no]; |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| p_ctx->streams[i].is_start = DVR_FALSE; |
| p_ctx->streams[i].pid = DVR_INVALID_PID; |
| p_ctx->streams[i].fid = -1; |
| } |
| /*Open dvr device*/ |
| memset(dev_name, 0, sizeof(dev_name)); |
| snprintf(dev_name, sizeof(dev_name), "/dev/dvb0.dvr%d", params->dmx_dev_id); |
| p_ctx->fd = open(dev_name, O_RDONLY); |
| if (p_ctx->fd == -1) |
| { |
| DVR_INFO("%s cannot open \"%s\" (%s)", __func__, dev_name, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| if (fcntl(p_ctx->fd, F_SETFL, fcntl(p_ctx->fd, F_GETFL, 0) | O_NONBLOCK, 0) < 0) { |
| DVR_ERROR("%s setting non-block flag fails with errno:%d(%s)", |
| __func__,errno,strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| |
| p_ctx->evtfd = eventfd(0, 0); |
| DVR_INFO("%s, %d fd: %d %p %d %p", __func__, __LINE__, p_ctx->fd, &(p_ctx->fd), p_ctx->evtfd, &(p_ctx->evtfd)); |
| load_secdmx_api(); |
| /*Configure flush size*/ |
| if (dvr_check_dmx_isNew() == 1) { |
| /* initialize secure demux client */ |
| if (SECDMX_Init_Ptr != NULL) { |
| ret = SECDMX_Init_Ptr(); |
| if (ret != DVR_SUCCESS) { |
| DVR_INFO("%s secure demux init failed:%d", __func__, ret); |
| } |
| } |
| } |
| //set dvbcore ringbuf size |
| { |
| //set del buf size is 10 * 188 *1024 |
| int buf_size = params->ringbuf_size; |
| if (buf_size > 0) { |
| ret = ioctl(p_ctx->fd, DMX_SET_BUFFER_SIZE, buf_size); |
| if (ret == -1) { |
| DVR_INFO("%s set dvr ringbuf size failed\"%s\" (%s) buf_size:%d", __func__, dev_name, strerror(errno), buf_size); |
| } else { |
| DVR_INFO("%s set dvr ringbuf size success \"%s\" buf_size:%d", __func__, dev_name, buf_size); |
| } |
| } |
| } |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_flush_size", dev_no); |
| memset(cmd, 0, sizeof(cmd)); |
| |
| snprintf(cmd, sizeof(cmd), "%d", params->buf_size); |
| dvr_file_echo(buf, cmd); |
| |
| /*Configure source*/ |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_source", dev_no); |
| memset(cmd, 0, sizeof(cmd)); |
| snprintf(cmd, sizeof(cmd), "dmx%d", params->dmx_dev_id); |
| p_ctx->dmx_dev_id = params->dmx_dev_id; |
| dvr_file_echo(buf, cmd); |
| |
| /*Configure Non secure mode*/ |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_enable", dev_no); |
| dvr_file_echo(buf, "0"); |
| |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_addr", dev_no); |
| dvr_file_echo(buf, "0"); |
| |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_addr_size", dev_no); |
| dvr_file_echo(buf, "0"); |
| |
| if (params->fend_dev_id > MAX_FEND_DEVICE_COUNT -1) { |
| DVR_ERROR("invalid frontend device id:%d, will use default.\n", |
| params->fend_dev_id); |
| p_ctx->fend_dev_id = 0; |
| } else { |
| p_ctx->fend_dev_id = params->fend_dev_id; |
| } |
| p_ctx->output_handle = (size_t)NULL; |
| p_ctx->dvr_buf = (size_t)NULL; |
| p_ctx->state = RECORD_DEVICE_STATE_OPENED; |
| *p_handle = p_ctx; |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_close(Record_DeviceHandle_t handle) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int i; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock); |
| close(p_ctx->fd); |
| close(p_ctx->evtfd); |
| if (dvr_check_dmx_isNew()) { |
| if (p_ctx->output_handle) { |
| if (SECDMX_RemoveOutputBuffer_Ptr != NULL) |
| SECDMX_RemoveOutputBuffer_Ptr(p_ctx->output_handle); |
| p_ctx->output_handle = (size_t)NULL; |
| } |
| if (p_ctx->dvr_buf) { |
| if (SECDMX_FreeDVRBuffer_Ptr != NULL) { |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (&record_ctx[i] != p_ctx && |
| record_ctx[i].fend_dev_id == p_ctx->fend_dev_id && |
| record_ctx[i].dvr_buf == p_ctx->dvr_buf) { |
| break; |
| } |
| } |
| if (i >= MAX_RECORD_DEVICE_COUNT) { |
| SECDMX_FreeDVRBuffer_Ptr(p_ctx->fend_dev_id); |
| } |
| p_ctx->dvr_buf = (size_t)NULL; |
| } |
| } |
| } |
| p_ctx->fend_dev_id = -1; |
| p_ctx->state = RECORD_DEVICE_STATE_CLOSED; |
| pthread_mutex_unlock(&p_ctx->lock); |
| |
| unload_secdmx_api(); |
| |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_add_pid(Record_DeviceHandle_t handle, int pid) |
| { |
| int i; |
| int fd; |
| int ret; |
| Record_DeviceContext_t *p_ctx; |
| char dev_name[32]; |
| struct dmx_pes_filter_params params; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID); |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock); |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| if (p_ctx->streams[i].pid == DVR_INVALID_PID) |
| break; |
| } |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(i < DVR_MAX_RECORD_PIDS_COUNT, &p_ctx->lock); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->streams[i].pid == DVR_INVALID_PID, &p_ctx->lock); |
| |
| p_ctx->streams[i].pid = pid; |
| DVR_INFO("%s add pid:%#x", __func__, pid); |
| snprintf(dev_name, sizeof(dev_name), "/dev/dvb0.demux%d", p_ctx->dmx_dev_id); |
| fd = open(dev_name, O_RDWR); |
| if (fd == -1) { |
| DVR_INFO("%s cannot open \"%s\" (%s)", __func__, dev_name, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| //DVR_INFO("%s libdvrFilterTrace open1 \"%s\" p_ctx->dmx_dev_id: 0x%x, fd: 0x%x ", __func__,dev_name,p_ctx->dmx_dev_id, fd); |
| p_ctx->streams[i].fid = fd; |
| |
| //DVR_RETURN_IF_FALSE_WITH_UNLOCK(DVR_SUCCESS == add_dvr_pids(p_ctx), &p_ctx->lock); |
| add_dvr_pids(p_ctx); |
| if (p_ctx->state == RECORD_DEVICE_STATE_STARTED) { |
| //need start pid filter |
| if (fcntl(fd, F_SETFL, O_NONBLOCK)<0) { |
| DVR_ERROR("%s setting non-block flag fails with errno:%d(%s)", |
| __func__,errno,strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| memset(¶ms, 0, sizeof(params)); |
| params.pid = p_ctx->streams[i].pid; |
| params.input = DMX_IN_FRONTEND; |
| params.output = DMX_OUT_TS_TAP; |
| params.pes_type = DMX_PES_OTHER; |
| ret = ioctl(fd, DMX_SET_PES_FILTER, ¶ms); |
| if (ret == -1) { |
| DVR_INFO("%s set pes filter failed\"%s\" (%s)", __func__, dev_name, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| ret = ioctl(fd, DMX_START, 0); |
| if (ret == -1) { |
| DVR_INFO("%s start pes filter failed:\"%s\" (%s)", __func__, dev_name, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| p_ctx->streams[i].is_start = DVR_TRUE; |
| } |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_remove_pid(Record_DeviceHandle_t handle, int pid) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int fd; |
| int ret; |
| int i; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID); |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock); |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| if (p_ctx->streams[i].pid == pid) |
| break; |
| } |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(i < DVR_MAX_RECORD_PIDS_COUNT, &p_ctx->lock); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->streams[i].pid == pid, &p_ctx->lock); |
| |
| fd = p_ctx->streams[i].fid; |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(fd != -1, &p_ctx->lock); |
| |
| if (p_ctx->streams[i].is_start == DVR_TRUE) { |
| ret = ioctl(fd, DMX_STOP, 0); |
| if (ret == -1) { |
| DVR_INFO("%s stop pes filter failed (%s)", __func__, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| } |
| |
| p_ctx->streams[i].pid = DVR_INVALID_PID; |
| //DVR_RETURN_IF_FALSE_WITH_UNLOCK(DVR_SUCCESS == add_dvr_pids(p_ctx), &p_ctx->lock); |
| add_dvr_pids(p_ctx); |
| //DVR_INFO("%s libdvrFilterTrace close1-1. pid: 0x%x, fd: 0x%x ", __func__,pid, fd); |
| close(fd); |
| p_ctx->streams[i].fid = -1; |
| p_ctx->streams[i].is_start = DVR_FALSE; |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_start(Record_DeviceHandle_t handle) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int fd; |
| int ret; |
| int i; |
| struct dmx_pes_filter_params params; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| if (p_ctx->state != RECORD_DEVICE_STATE_OPENED && |
| p_ctx->state != RECORD_DEVICE_STATE_STOPPED) { |
| pthread_mutex_unlock(&p_ctx->lock); |
| DVR_ERROR("%s, %d, wrong state:%d", __func__, __LINE__,p_ctx->state); |
| return DVR_FAILURE; |
| } |
| |
| //DVR_RETURN_IF_FALSE_WITH_UNLOCK(DVR_SUCCESS == add_dvr_pids(p_ctx), &p_ctx->lock); |
| add_dvr_pids(p_ctx); |
| |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| if (p_ctx->streams[i].fid != -1 && |
| p_ctx->streams[i].pid != DVR_INVALID_PID && |
| p_ctx->streams[i].is_start == DVR_FALSE) { |
| //need start pid filter |
| fd = p_ctx->streams[i].fid; |
| if (fcntl(fd, F_SETFL, O_NONBLOCK)<0) { |
| DVR_ERROR("%s setting non-block flag fails with errno:%d(%s)", |
| __func__,errno,strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| memset(¶ms, 0, sizeof(params)); |
| params.pid = p_ctx->streams[i].pid; |
| params.input = DMX_IN_FRONTEND; |
| params.output = DMX_OUT_TS_TAP; |
| params.pes_type = DMX_PES_OTHER; |
| ret = ioctl(fd, DMX_SET_PES_FILTER, ¶ms); |
| if (ret == -1) { |
| DVR_ERROR("%s set pes filter failed (%s)", __func__, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| ret = ioctl(fd, DMX_START, 0); |
| if (ret == -1) { |
| DVR_ERROR("%s start pes filter failed (%s)", __func__, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| p_ctx->streams[i].is_start = DVR_TRUE; |
| } |
| } |
| p_ctx->state = RECORD_DEVICE_STATE_STARTED; |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_stop(Record_DeviceHandle_t handle) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int fd; |
| int ret; |
| int i; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| if (p_ctx->state != RECORD_DEVICE_STATE_STARTED) { |
| DVR_INFO("%s, %d, wrong state:%d", __func__, __LINE__,p_ctx->state); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| |
| for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) { |
| if (p_ctx->streams[i].fid != -1 && |
| p_ctx->streams[i].pid != DVR_INVALID_PID && |
| p_ctx->streams[i].is_start == DVR_TRUE) { |
| /*Stop the filter*/ |
| fd = p_ctx->streams[i].fid; |
| ret = ioctl(fd, DMX_STOP, 0); |
| if (ret == -1) { |
| DVR_INFO("%s stop pes filter failed (%s)", __func__, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| /*Close the filter*/ |
| p_ctx->streams[i].pid = DVR_INVALID_PID; |
| //DVR_INFO("%s libdvrFilterTrace close1-2. fd: 0x%x ", __func__, fd); |
| close(fd); |
| p_ctx->streams[i].fid = -1; |
| p_ctx->streams[i].is_start = DVR_FALSE; |
| } |
| } |
| p_ctx->state = RECORD_DEVICE_STATE_STOPPED; |
| { |
| /*wakeup the poll*/ |
| int64_t pad = 1; |
| write(p_ctx->evtfd, &pad, sizeof(pad)); |
| } |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| int record_device_read(Record_DeviceHandle_t handle, void *buf, size_t len, int timeout) |
| { |
| Record_DeviceContext_t *p_ctx; |
| struct pollfd fds[2]; |
| int ret; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->fd != -1); |
| DVR_RETURN_IF_FALSE(buf); |
| DVR_RETURN_IF_FALSE(len); |
| |
| memset(fds, 0, sizeof(fds)); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| fds[0].fd = p_ctx->fd; |
| fds[1].fd = p_ctx->evtfd; |
| pthread_mutex_unlock(&p_ctx->lock); |
| |
| fds[0].events = fds[1].events = POLLIN | POLLERR; |
| ret = poll(fds, 2, timeout); |
| if (ret <= 0) { |
| if (ret < 0) |
| DVR_INFO("%s, %d failed: %s fd %d event fd %d", __func__, __LINE__, strerror(errno), p_ctx->fd, p_ctx->evtfd); |
| else |
| DVR_INFO("%s, %d timeout", __func__, __LINE__); |
| return DVR_FAILURE; |
| } |
| |
| if (!(fds[0].revents & POLLIN)) |
| return DVR_FAILURE; |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| if (p_ctx->state == RECORD_DEVICE_STATE_STARTED) { |
| ret = read(fds[0].fd, buf, len); |
| if (ret <= 0) { |
| DVR_INFO("%s, %d failed: %s", __func__, __LINE__, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| } else { |
| ret = DVR_FAILURE; |
| } |
| pthread_mutex_unlock(&p_ctx->lock); |
| return ret; |
| } |
| |
| ssize_t record_device_read_ext(Record_DeviceHandle_t handle, size_t *buf, size_t *len) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int result; |
| int sid; |
| struct dvr_mem_info info; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(buf); |
| DVR_RETURN_IF_FALSE(len); |
| DVR_RETURN_IF_FALSE(p_ctx->dvr_buf); |
| DVR_RETURN_IF_FALSE(p_ctx->output_handle); |
| |
| sid = p_ctx->fend_dev_id; |
| pthread_mutex_lock(&p_ctx->lock); |
| |
| /* wp_offset is hw write pointer shared by multiple recordings under one sid, |
| * must use mutex for thread safe |
| */ |
| pthread_mutex_lock(&secdmx_lock[sid]); |
| memset(&info, 0, sizeof(info)); |
| result = ioctl(p_ctx->fd, DMX_GET_DVR_MEM, &info); |
| //DVR_INFO("sid[%d] fd[%d] wp:%#x\n", sid, p_ctx->fd, info.wp_offset); |
| if (result == DVR_SUCCESS) { |
| if (SECDMX_ProcessData_Ptr != NULL) |
| result = SECDMX_ProcessData_Ptr(sid, info.wp_offset); |
| } |
| if (result) { |
| DVR_INFO("result:%#x\n", result); |
| } |
| pthread_mutex_unlock(&secdmx_lock[sid]); |
| |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(result == DVR_SUCCESS, &p_ctx->lock); |
| if (SECDMX_GetOutputBufferStatus_Ptr != NULL) |
| result = SECDMX_GetOutputBufferStatus_Ptr(p_ctx->output_handle, buf, len); |
| //DVR_INFO("addr:%#x, len:%#x\n", *buf, *len); |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(result == DVR_SUCCESS, &p_ctx->lock); |
| |
| pthread_mutex_unlock(&p_ctx->lock); |
| return *len; |
| } |
| |
| int record_device_set_secure_buffer(Record_DeviceHandle_t handle, uint8_t *sec_buf, uint32_t len) |
| { |
| Record_DeviceContext_t *p_ctx; |
| int i; |
| char buf[64]; |
| char cmd[32]; |
| |
| p_ctx = (Record_DeviceContext_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(sec_buf); |
| DVR_RETURN_IF_FALSE(len); |
| |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (p_ctx == &record_ctx[i]) |
| break; |
| } |
| DVR_RETURN_IF_FALSE(i < MAX_RECORD_DEVICE_COUNT); |
| DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]); |
| |
| pthread_mutex_lock(&p_ctx->lock); |
| if (p_ctx->state != RECORD_DEVICE_STATE_OPENED && |
| p_ctx->state != RECORD_DEVICE_STATE_STOPPED) { |
| DVR_INFO("%s, %d, wrong state:%d", __func__, __LINE__,p_ctx->state); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| |
| if (dvr_check_dmx_isNew() == 1) { |
| //new dmx drive,used io to set sec buf. |
| int result = DVR_SUCCESS; |
| size_t dvr_buf = 0; |
| size_t op_handle = 0; |
| int sid = p_ctx->fend_dev_id; |
| int fd; |
| char node[32] = {0}; |
| memset(node, 0, sizeof(node)); |
| snprintf(node, sizeof(node), "/dev/dvb0.demux%d", p_ctx->dmx_dev_id); |
| fd = open(node, O_RDONLY); |
| if (fd<0) { |
| DVR_ERROR("opening %d returns failure. errno:%d, %s", fd, errno, strerror(errno)); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_FAILURE; |
| } |
| //DVR_INFO("%s libdvrFilterTrace open2 \"%s\",p_ctx->dmx_dev_id: 0x%x, fd: 0x%x ", __func__,node, p_ctx->dmx_dev_id, fd); |
| if (SECDMX_AllocateDVRBuffer_Ptr != NULL) { |
| for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) { |
| if (record_ctx[i].state != RECORD_DEVICE_STATE_CLOSED && |
| &record_ctx[i] != p_ctx && |
| record_ctx[i].fend_dev_id == p_ctx->fend_dev_id && |
| record_ctx[i].dvr_buf != 0) { |
| break; |
| } |
| } |
| if (i >= MAX_RECORD_DEVICE_COUNT) { |
| result = SECDMX_AllocateDVRBuffer_Ptr(sid, len, &dvr_buf); |
| if (result != DVR_SUCCESS) { |
| //DVR_INFO("%s libdvrFilterTrace close2-1. fd: 0x%x ", __func__, fd); |
| close(fd); |
| } |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(result == DVR_SUCCESS, &p_ctx->lock); |
| } else { |
| dvr_buf = record_ctx[i].dvr_buf; |
| } |
| |
| p_ctx->dvr_buf = dvr_buf; |
| } else { |
| p_ctx->dvr_buf = (size_t)sec_buf; |
| } |
| |
| struct dmx_sec_mem sec_mem; |
| sec_mem.buff = p_ctx->dvr_buf; |
| sec_mem.size = len; |
| if (ioctl(fd, DMX_SET_SEC_MEM, &sec_mem) == -1) { |
| DVR_INFO("record_device_set_secure_buffer ioctl DMX_SET_SEC_MEM error:%d", errno); |
| } |
| else |
| { |
| DVR_INFO("record_device_set_secure_buffer ioctl succeeded DMX_SET_SEC_MEM: fd:%d, buf:%#x\n", fd, p_ctx->dvr_buf); |
| } |
| if (SECDMX_AddOutputBuffer_Ptr != NULL) |
| result = SECDMX_AddOutputBuffer_Ptr(sid, (size_t)sec_buf, len, &op_handle); |
| if (result != DVR_SUCCESS) { |
| //DVR_INFO("%s libdvrFilterTrace close2-2. fd: 0x%x ", __func__, fd); |
| close(fd); |
| } |
| DVR_RETURN_IF_FALSE_WITH_UNLOCK(result == DVR_SUCCESS, &p_ctx->lock); |
| p_ctx->output_handle = op_handle; |
| |
| //DVR_INFO("%s libdvrFilterTrace close2-3. fd: 0x%x ", __func__, fd); |
| close(fd); |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_enable", i); |
| dvr_file_echo(buf, "1"); |
| |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_addr", i); |
| snprintf(cmd, sizeof(cmd), "%llu", (uint64_t)sec_buf); |
| dvr_file_echo(buf, cmd); |
| |
| memset(buf, 0, sizeof(buf)); |
| snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_secure_addr_size", i); |
| snprintf(cmd, sizeof(cmd), "%d", len); |
| dvr_file_echo(buf, cmd); |
| |
| pthread_mutex_unlock(&p_ctx->lock); |
| return DVR_SUCCESS; |
| } |
| |