795 lines
25 KiB
C
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;
|
|
}
|