Files
2026-08-24 10:03:24 +08:00

795 lines
25 KiB
C

/***************************************************************************
* Copyright (C) 2014-2026 Amlogic, Inc. All rights reserved.
*
* All information contained herein is Amlogic confidential.
*
* This software is provided to you pursuant to Software License Agreement
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
* only in accordance with the terms of this agreement.
*
* Redistribution and use in source and binary forms, with or without
* modification is strictly prohibited without prior written permission from
* Amlogic.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#define LOG_TAG "DemuxDriver"
#ifdef _FORTIFY_SOURCE
#undef _FORTIFY_SOURCE
#endif
#include "DemuxDriver.h"
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "AmlogicUtil.h"
#include "SubtitleLog.h"
#define DMX_SYNC
#define DMX_BUF_SIZE (4096)
#define DMX_POLL_TIMEOUT (200)
#ifdef CHIP_8226H
#define DMX_DEV_COUNT (16)
#elif defined(CHIP_8226M) || defined(CHIP_8626X)
#define DMX_DEV_COUNT (16)
#else
#define DMX_DEV_COUNT (16)
#endif
#define DMX_CHAN_ISSET_FILTER(chan, fid) ((chan)->filter_mask[(fid) >> 3] & (1 << ((fid)&3)))
#define DMX_CHAN_SET_FILTER(chan, fid) ((chan)->filter_mask[(fid) >> 3] |= (1 << ((fid)&3)))
#define DMX_CHAN_CLR_FILTER(chan, fid) ((chan)->filter_mask[(fid) >> 3] &= ~(1 << ((fid)&3)))
/****************************************************************************
* Static data
***************************************************************************/
#ifdef EMU_DEMUX
extern const DemuxDriverType emu_dmx_drv;
#define HW_DMX_DRV emu_dmx_drv
#else
extern const DemuxDriverType linux_dvb_dmx_drv;
#define HW_DMX_DRV linux_dvb_dmx_drv
#endif
// extern const DemuxDriverType dvr_dmx_drv;
// #define SW_DMX_DRV dvr_dmx_drv
static DemuxDeviceType dmx_devices[DMX_DEV_COUNT] = {
#ifdef EMU_DEMUX
{.drv = &emu_dmx_drv, .src = DEMUX_SRC_TS0}, {.drv = &emu_dmx_drv, .src = DEMUX_SRC_TS0}
#else
{.drv = &linux_dvb_dmx_drv, .src = DEMUX_SRC_TS0},
{.drv = &linux_dvb_dmx_drv, .src = DEMUX_SRC_TS0}
// #if defined(CHIP_8226M) || defined(CHIP_8626X)
,
{.drv = &linux_dvb_dmx_drv, .src = DEMUX_SRC_TS0}
// #endif
#endif
};
/****************************************************************************
* Static functions
***************************************************************************/
/** Get the device structure pointer based on the device number*/
static inline int dmx_get_dev(int dev_no, DemuxDeviceType **dev) {
if ((dev_no < 0) || (dev_no >= DMX_DEV_COUNT)) {
SUBTITLE_LOGI("invalid demux device number %d, must in(%d~%d)", dev_no, 0,
DMX_DEV_COUNT - 1);
return DEMUX_ERROR_INVALID_DEV_NO;
}
*dev = &dmx_devices[dev_no];
return AM_SUCCESS;
}
/** Get the device structure based on the device number and check whether the device is open*/
static inline int dmx_get_opened_dev(int dev_no, DemuxDeviceType **dev) {
AM_TRY(dmx_get_dev(dev_no, dev));
pthread_mutex_lock(&am_gAdpLock);
if ((*dev)->open_count <= 0) {
pthread_mutex_unlock(&am_gAdpLock);
return DEMUX_ERROR_INVALID_DEV_NO;
}
pthread_mutex_unlock(&am_gAdpLock);
return AM_SUCCESS;
}
/** Get the corresponding filter structure based on the ID and check whether the device is in use*/
static inline int dmx_get_used_filter(DemuxDeviceType *dev, int filter_id, DemuxFilterType **pf) {
DemuxFilterType *filter;
if ((filter_id < 0) || (filter_id >= DEMUX_FILTER_COUNT)) {
SUBTITLE_LOGI("invalid filter id, must in %d~%d", 0, DEMUX_FILTER_COUNT - 1);
return DEMUX_ERROR_INVALID_ID;
}
filter = &dev->filters[filter_id];
if (!filter->used) {
SUBTITLE_LOGI("filter %d has not been allocated", filter_id);
return DEMUX_ERROR_NOT_ALLOCATED;
}
*pf = filter;
return AM_SUCCESS;
}
/** Data detection thread*/
static void *dmx_data_thread(void *arg) {
DemuxDeviceType *dev = (DemuxDeviceType *)arg;
uint8_t *sec_buf;
uint8_t *sec;
int sec_len;
Demux_FilterMaskType mask;
int ret;
SUBTITLE_LOGI_FUNC_IN();
#define BUF_SIZE (4096)
sec_buf = (uint8_t *)malloc(BUF_SIZE);
// for coverity
if (sec_buf) {
memset(sec_buf, 0, BUF_SIZE);
}
while (true) {
// Check if thread should stop before processing
pthread_mutex_lock(&dev->lock);
if (!dev->enable_thread) {
pthread_mutex_unlock(&dev->lock);
SUBTITLE_LOGI("stop before poll");
break;
}
pthread_mutex_unlock(&dev->lock);
DEMUX_FILTER_MASK_CLEAR(&mask);
uint32_t id;
ret = dev->drv->poll(dev, &mask, DMX_POLL_TIMEOUT);
// Check if thread should stop immediately after poll
pthread_mutex_lock(&dev->lock);
if (!dev->enable_thread) {
pthread_mutex_unlock(&dev->lock);
SUBTITLE_LOGI("stop after poll");
break;
}
pthread_mutex_unlock(&dev->lock);
if (ret == AM_SUCCESS) {
if (DEMUX_FILTER_MASK_ISEMPTY(&mask)) continue;
#if defined(DMX_WAIT_CB) || defined(DMX_SYNC)
pthread_mutex_lock(&dev->lock);
dev->flags |= DMX_FL_RUN_CB;
pthread_mutex_unlock(&dev->lock);
#endif
for (id = 0; id < DEMUX_FILTER_COUNT; id++) {
DemuxFilterType *filter = &dev->filters[id];
DemuxDataCb cb = NULL;
void *data = NULL;
if (!DEMUX_FILTER_MASK_ISSET(&mask, id)) continue;
if (!filter->enable || !filter->used) continue;
sec_len = BUF_SIZE;
#ifndef DMX_WAIT_CB
pthread_mutex_lock(&dev->lock);
#endif
if (!filter->enable || !filter->used) {
ret = AM_FAILURE;
} else {
cb = filter->cb;
data = filter->user_data;
ret = dev->drv->read(dev, filter, sec_buf, &sec_len);
}
#ifndef DMX_WAIT_CB
pthread_mutex_unlock(&dev->lock);
#endif
if (ret == DEMUX_ERROR_TIMEOUT) {
sec = NULL;
sec_len = 0;
} else if (ret != AM_SUCCESS) {
continue;
} else {
sec = sec_buf;
}
if (cb) {
if (id && sec) {
SUBTITLE_LOGI(
"filter %d data callback len fd:%ld len:%d, %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x",
id, (long)filter->drv_data, sec_len, sec[0], sec[1], sec[2], sec[3],
sec[4], sec[5], sec[6], sec[7], sec[8], sec[9]);
}
cb(dev->dev_no, id, sec, sec_len, data);
if (id && sec) {
SUBTITLE_LOGI("filter %d data callback ok", id);
}
}
}
#if defined(DMX_WAIT_CB) || defined(DMX_SYNC)
pthread_mutex_lock(&dev->lock);
dev->flags &= ~DMX_FL_RUN_CB;
pthread_mutex_unlock(&dev->lock);
pthread_cond_broadcast(&dev->cond);
#endif
} else {
usleep(10000);
}
}
if (sec_buf) {
free(sec_buf);
}
SUBTITLE_LOGI_FUNC_OUT();
return NULL;
}
/** Wait for the callback function to stop running*/
static inline int dmx_wait_cb(DemuxDeviceType *dev) {
#ifdef DMX_WAIT_CB
if (dev->thread != pthread_self()) {
while (dev->flags & DMX_FL_RUN_CB) pthread_cond_wait(&dev->cond, &dev->lock);
}
#else
UNUSED(dev);
#endif
return AM_SUCCESS;
}
/** Stop Section filter*/
static int dmx_stop_filter(DemuxDeviceType *dev, DemuxFilterType *filter) {
int ret = AM_SUCCESS;
if (!filter->used || !filter->enable) return ret;
if (dev->drv->enable_filter) ret = dev->drv->enable_filter(dev, filter, 0);
if (ret >= 0) filter->enable = 0;
return ret;
}
/** release filter*/
static int dmx_free_filter(DemuxDeviceType *dev, DemuxFilterType *filter) {
int ret = AM_SUCCESS;
if (!filter->used) return ret;
ret = dmx_stop_filter(dev, filter);
if (ret == AM_SUCCESS) {
if (dev->drv->free_filter) {
ret = dev->drv->free_filter(dev, filter);
}
}
if (ret == AM_SUCCESS) {
filter->used = 0;
}
return ret;
}
/****************************************************************************
* API functions
***************************************************************************/
/** Open the demultiplexing device
* dev_no demultiplexing device number
* \param[in] para Demultiplexing device opening parameters
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxOpen(int dev_no, const AmlogicDemuxOpenParameterType *para) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
int ret = AM_SUCCESS;
assert(para);
AM_TRY(dmx_get_dev(dev_no, &dev));
pthread_mutex_lock(&am_gAdpLock);
if (dev->open_count > 0) {
SUBTITLE_LOGI("demux device %d was already opened", dev_no);
dev->open_count++;
ret = AM_SUCCESS;
goto final;
}
dev->dev_no = dev_no;
/*if(para->use_sw_filter){
dev->drv = &SW_DMX_DRV;
}else{
dev->drv = &HW_DMX_DRV;
}*/
// Use hw dmx default
dev->drv = &HW_DMX_DRV;
if (dev->drv->open) {
ret = dev->drv->open(dev, para);
}
if (ret == AM_SUCCESS) {
pthread_mutex_init(&dev->lock, NULL);
pthread_cond_init(&dev->cond, NULL);
pthread_mutex_lock(&dev->lock);
dev->flags = 0;
dev->enable_thread = true;
int result = pthread_create(&dev->thread, NULL, dmx_data_thread, dev);
if (result != 0) {
dev->enable_thread = false;
SUBTITLE_LOGE("fail to create demux data thread: %s", strerror(result));
pthread_mutex_unlock(&dev->lock);
pthread_mutex_destroy(&dev->lock);
pthread_cond_destroy(&dev->cond);
ret = DEMUX_ERROR_CANNOT_CREATE_THREAD;
} else {
pthread_mutex_unlock(&dev->lock);
}
dev->open_count = 1;
} else {
SUBTITLE_LOGE("fail to open device: %d", ret);
}
final:
pthread_mutex_unlock(&am_gAdpLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Close demultiplexing device
* dev_no demultiplexing device number
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxClose(int dev_no) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
int ret = AM_SUCCESS;
int i = 0;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gAdpLock);
if (dev->open_count == 1) {
// First signal thread to stop before destroying
// synchronization primitives
pthread_mutex_lock(&dev->lock);
dev->enable_thread = false;
pthread_cond_broadcast(&dev->cond); // Wake up any waiting threads
pthread_mutex_unlock(&dev->lock);
/** Stop timing sequence:
* dev->drv->poll_exit(dev); // Exit the poll
* pthread_join(...); // Wait demux data thread to exit
* dmx_free_filter // Free filter resources
* dev->drv->close(dev); // Free demux resources
*/
// Wake up the thread from poll to avoid 200ms delay
if (dev->drv->poll_exit) {
dev->drv->poll_exit(dev);
}
// Wait for thread to complete before destroying resources
if (dev->thread != 0) {
pthread_join(dev->thread, NULL);
dev->thread = 0;
SUBTITLE_LOGI("dmx thread exit end");
}
// Free filter resources, including fd, event_fd.
for (i = 0; i < DEMUX_FILTER_COUNT; i++) {
dmx_free_filter(dev, &dev->filters[i]);
}
// Free dmx resources.
if (dev->drv->close) {
dev->drv->close(dev);
}
// Now it's safe to destroy the synchronization primitives
pthread_mutex_destroy(&dev->lock);
pthread_cond_destroy(&dev->cond);
}
dev->open_count--;
pthread_mutex_unlock(&am_gAdpLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** assigns a filter
* dev_no demultiplexing device number
* \param[out] fhandle returns the filter handle
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxAllocateFilter(int dev_no, int *fhandle) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
int ret = AM_SUCCESS;
int fid;
assert(fhandle);
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
for (fid = 0; fid < DEMUX_FILTER_COUNT; fid++) {
if (!dev->filters[fid].used) break;
}
if (fid >= DEMUX_FILTER_COUNT) {
SUBTITLE_LOGI("no free section filter");
ret = DEMUX_ERROR_NO_FREE_FILTER;
}
if (ret == AM_SUCCESS) {
dmx_wait_cb(dev);
dev->filters[fid].id = fid;
if (dev->drv->alloc_filter) {
ret = dev->drv->alloc_filter(dev, &dev->filters[fid]);
}
}
if (ret == AM_SUCCESS) {
dev->filters[fid].used = true;
*fhandle = fid;
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Set Section filter
* dev_no demultiplexing device number
* fhandle filter handle
* \param[in] params Section filter parameters
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSetSecFilter(int dev_no, int fhandle, const struct dmx_sct_filter_params *params) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
assert(params);
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
if (!dev->drv->set_sec_filter) {
SUBTITLE_LOGI("demux do not support set_sec_filter");
return DEMUX_ERROR_NOT_SUPPORTED;
}
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
dmx_wait_cb(dev);
ret = dmx_stop_filter(dev, filter);
}
if (ret == AM_SUCCESS) {
ret = dev->drv->set_sec_filter(dev, filter, params);
SUBTITLE_LOGI(
"set sec filter %d PID: %d filter: %02x:%02x %02x:%02x %02x:%02x %02x:%02x %02x:%02x "
"%02x:%02x %02x:%02x %02x:%02x",
fhandle, params->pid, params->filter.filter[0], params->filter.mask[0],
params->filter.filter[1], params->filter.mask[1], params->filter.filter[2],
params->filter.mask[2], params->filter.filter[3], params->filter.mask[3],
params->filter.filter[4], params->filter.mask[4], params->filter.filter[5],
params->filter.mask[5], params->filter.filter[6], params->filter.mask[6],
params->filter.filter[7], params->filter.mask[7]);
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Set PES filter
* dev_no demultiplexing device number
* fhandle filter handle
* \param[in] params PES filter parameters
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSetPesFilter(int dev_no, int fhandle, const struct dmx_pes_filter_params *params) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
assert(params);
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
if (!dev->drv->set_pes_filter) {
SUBTITLE_LOGI("demux do not support set_pes_filter");
return DEMUX_ERROR_NOT_SUPPORTED;
}
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
dmx_wait_cb(dev);
ret = dmx_stop_filter(dev, filter);
}
if (ret == AM_SUCCESS) {
ret = dev->drv->set_pes_filter(dev, filter, params);
SUBTITLE_LOGI("set pes filter %d PID %d flags %d", fhandle, params->pid, params->flags);
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** releases a filter
* dev_no demultiplexing device number
* fhandle filter handle
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxFreeFilter(int dev_no, int fhandle) {
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
dmx_wait_cb(dev);
ret = dmx_free_filter(dev, filter);
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
return ret;
}
/** starts a filter
* dev_no demultiplexing device number
* fhandle filter handle
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxStartFilter(int dev_no, int fhandle) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
DemuxFilterType *filter = NULL;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (!filter->enable) {
if (ret == AM_SUCCESS) {
if (dev->drv->enable_filter) {
ret = dev->drv->enable_filter(dev, filter, true);
}
}
if (ret == AM_SUCCESS) {
filter->enable = true;
ret = dev->drv->poll_exit(dev);
}
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Stop a filter
* dev_no demultiplexing device number
* fhandle filter handle
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxStopFilter(int dev_no, int fhandle) {
DemuxDeviceType *dev;
DemuxFilterType *filter = NULL;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
if (filter->enable) {
dmx_wait_cb(dev);
ret = dmx_stop_filter(dev, filter);
}
}
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
return ret;
}
/** Set the buffer size of a filter
* dev_no demultiplexing device number
* fhandle filter handle
* size buffer size
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSetBufferSize(int dev_no, int fhandle, int size) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
if (!dev->drv->set_buf_size) {
SUBTITLE_LOGI("do not support set_buf_size");
ret = DEMUX_ERROR_NOT_SUPPORTED;
}
if (ret == AM_SUCCESS) ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) ret = dev->drv->set_buf_size(dev, filter, size);
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Get the callback function and user parameters corresponding to a filter
* dev_no demultiplexing device number
* fhandle filter handle
* \param[out] cb returns the callback function corresponding to the filter
* \param[out] data returns user parameters
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxGetCallback(int dev_no, int fhandle, DemuxDataCb *cb, void **data) {
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
if (cb) *cb = filter->cb;
if (data) *data = filter->user_data;
}
pthread_mutex_unlock(&dev->lock);
return ret;
}
/** Set the callback function and user parameters corresponding to a filter
* dev_no demultiplexing device number
* fhandle filter handle
* \param[in] cb callback function
* \param[in] data user parameters of the callback function
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSetCallback(int dev_no, int fhandle, DemuxDataCb cb, void *data) {
SUBTITLE_LOGI_FUNC_IN();
DemuxDeviceType *dev;
DemuxFilterType *filter;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = dmx_get_used_filter(dev, fhandle, &filter);
if (ret == AM_SUCCESS) {
dmx_wait_cb(dev);
filter->cb = cb;
filter->user_data = data;
}
pthread_mutex_unlock(&dev->lock);
SUBTITLE_LOGI_FUNC_OUT();
return ret;
}
/** Set the input source of the demultiplexing device
* dev_no demultiplexing device number
* src input source
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSetSource(int dev_no, AmlogicDemuxSourceType src) {
DemuxDeviceType *dev;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
if (!dev->drv->set_source) {
SUBTITLE_LOGI("do not support set_source");
ret = DEMUX_ERROR_NOT_SUPPORTED;
}
if (ret == AM_SUCCESS) {
ret = dev->drv->set_source(dev, src);
}
pthread_mutex_unlock(&dev->lock);
if (ret == AM_SUCCESS) {
pthread_mutex_lock(&am_gAdpLock);
dev->src = src;
pthread_mutex_unlock(&am_gAdpLock);
}
return ret;
}
/** DMX synchronization, which can be used to wait for the callback function to complete execution
* dev_no demultiplexing device number
* - AM_SUCCESS Success
* - other values error code (see DemuxDriver.h)
*/
int DemuxSync(int dev_no) {
DemuxDeviceType *dev;
int ret = AM_SUCCESS;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
if (dev->thread != pthread_self()) {
while (dev->flags & DMX_FL_RUN_CB) pthread_cond_wait(&dev->cond, &dev->lock);
}
pthread_mutex_unlock(&dev->lock);
return ret;
}
int DemuxGetScrambleStatus(int dev_no, bool dev_status[2]) {
char buf[32];
char class_file[64];
int vflag, aflag;
int i;
dev_status[0] = dev_status[1] = 0;
snprintf(class_file, sizeof(class_file), "/sys/class/dmx/demux%d_scramble", dev_no);
for (i = 0; i < 5; i++) {
if (AmlogicFileRead(class_file, buf, sizeof(buf)) == AM_SUCCESS) {
sscanf(buf, "%d %d", &vflag, &aflag);
if (!dev_status[0]) dev_status[0] = vflag ? true : 0;
if (!dev_status[1]) dev_status[1] = aflag ? true : 0;
// SUBTITLE_LOGI("DemuxGetScrambleStatus video scramble %d, audio scramble %d\n", vflag,
// aflag);
if (dev_status[0] && dev_status[1]) {
return AM_SUCCESS;
}
usleep(10 * 1000);
} else {
SUBTITLE_LOGI("DemuxGetScrambleStatus read scramble status failed\n");
return AM_FAILURE;
}
}
return AM_SUCCESS;
}
int DemuxGetNewestPts(int dev_no, amdmx_filter_mem_info *demuxFilterMemInfo) {
assert(demuxFilterMemInfo);
DemuxDeviceType *dev = NULL;
AM_TRY(dmx_get_opened_dev(dev_no, &dev));
if (!dev || !dev->drv->get_newest_pts) {
SUBTITLE_LOGE("[newest_avpts_tag] dev is null or get_newest_pts is unavailable");
return AM_FAILURE;
}
pthread_mutex_lock(&am_gHwDmxLock);
pthread_mutex_lock(&dev->lock);
int ret = dev->drv->get_newest_pts(dev, demuxFilterMemInfo);
pthread_mutex_unlock(&dev->lock);
pthread_mutex_unlock(&am_gHwDmxLock);
return ret;
}