618 lines
22 KiB
C++
618 lines
22 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 "DemuxSource"
|
|
|
|
#include "DemuxSource.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <utils/CallStack.h>
|
|
|
|
#include <string>
|
|
|
|
#include "ParserFactory.h"
|
|
#include "SubtitleLog.h"
|
|
|
|
extern "C" {
|
|
#include "MediaSyncInterface.h"
|
|
mediasync_result MediaSync_bindInstance(void *handle, uint32_t SyncInsId,
|
|
sync_stream_type streamtype);
|
|
mediasync_result MediaSync_getTrackMediaTime(void *handle, int64_t *outMediaUs);
|
|
mediasync_result MediaSync_getFirstVideoFrameInfo(void *handle, mediasync_frameinfo *arg);
|
|
}
|
|
|
|
// Lagecy tsync is only used in:
|
|
// - Old MM demux architecture before Android T
|
|
// - New MM demux architecture before Android R
|
|
// tsync/pts_video returns 32bit 90kHz Pts.
|
|
// tsync/pts_video_u64 returns 33bit 90kHz Pts.
|
|
static const std::string SYSFS_VIDEO_PTS = "/sys/class/tsync/pts_video_u64";
|
|
|
|
static const std::string SYSFS_VIDEO_FIRSTRRAME =
|
|
"/sys/module/amvideo/parameters/first_frame_toggled";
|
|
static const std::string SYSFS_SUBTITLE_TYPE = "/sys/class/subtitle/subtype";
|
|
static const std::string SYSFS_SUBTITLE_SIZE = "/sys/class/subtitle/size";
|
|
static const std::string SYSFS_SUBTITLE_TOTAL = "/sys/class/subtitle/total";
|
|
static const std::string SUBTITLE_READ_DEVICE = "/dev/amstream_sub_read";
|
|
|
|
#define AMSTREAM_IOC_MAGIC 'S'
|
|
#define AMSTREAM_IOC_SUB_LENGTH _IOR(AMSTREAM_IOC_MAGIC, 0x1b, int)
|
|
#define AMSTREAM_IOC_SUB_RESET _IOW(AMSTREAM_IOC_MAGIC, 0x1a, int)
|
|
#define SECTION_DEMUX_INDEX 2
|
|
#define DMX_SUBTITLE_NO_SEC 0
|
|
#define DMX_SUBTITLE_SEC (2 << 10)
|
|
#ifdef USE_FB
|
|
#define DMX_SUBTITLE_BUFFER_SIZE 0x20000
|
|
#else
|
|
#define DMX_SUBTITLE_BUFFER_SIZE 0x80000
|
|
#endif
|
|
|
|
DemuxSource *DemuxSource::sInstance = nullptr;
|
|
DemuxSource *DemuxSource::getCurrentInstance() {
|
|
return DemuxSource::sInstance;
|
|
}
|
|
|
|
namespace {
|
|
static inline int64_t sysfsReadInt(const char *path, int base) {
|
|
int fd;
|
|
int64_t val = 0;
|
|
char bcmd[64] = {0};
|
|
fd = ::open(path, O_RDONLY);
|
|
if (fd >= 0) {
|
|
int c = read(fd, bcmd, sizeof(bcmd));
|
|
if (c > 0) {
|
|
val = strtoll(bcmd, NULL, base);
|
|
}
|
|
::close(fd);
|
|
} else {
|
|
SUBTITLE_LOGE("unable to open file %s,err: %s", path, strerror(errno));
|
|
}
|
|
return val;
|
|
}
|
|
|
|
static void pes_data_cb(int dev_no, int fhandle, const uint8_t *data, int len, void *user_data) {
|
|
(void)dev_no;
|
|
(void)fhandle;
|
|
(void)user_data;
|
|
|
|
std::shared_ptr<char> spBuf(new char[len], [](char *buf) { delete[] buf; });
|
|
memcpy(spBuf.get(), data, len);
|
|
DemuxSource::getCurrentInstance()->mSegment->push(std::move(spBuf), len);
|
|
DemuxSource::getCurrentInstance()->onPesCallback();
|
|
|
|
// coverity[RESOURCE_LEAK]
|
|
if (isSubtitleDumpAvailable()) {
|
|
if (DemuxSource::getCurrentInstance()->mDumpFd == -1) {
|
|
DemuxSource::getCurrentInstance()->mDumpFd =
|
|
::open(DUMP_DATA_FILE_PATH, O_RDWR | O_CREAT, 0666);
|
|
if (DemuxSource::getCurrentInstance()->mDumpFd < 0) {
|
|
SUBTITLE_LOGI("mDumpFd=%d %m", DemuxSource::getCurrentInstance()->mDumpFd);
|
|
return;
|
|
}
|
|
}
|
|
auto ret = write(DemuxSource::getCurrentInstance()->mDumpFd, data, len);
|
|
if (ret != len) {
|
|
SUBTITLE_LOGE("Failed to write data: ret=%zd, %m", ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int open_dvb_dmx(TVSubtitleData *data, int dmx_id, int pid, int flag) {
|
|
SUBTITLE_LOGI_FUNC_IN();
|
|
int ret;
|
|
AmlogicDemuxOpenParameterType op;
|
|
struct dmx_pes_filter_params pesp;
|
|
struct dmx_sct_filter_params param;
|
|
int subtype = DemuxSource::getCurrentInstance()->mSubType;
|
|
SUBTITLE_LOGI("dmx_id=%d, pid=%d, flag=%d, subtype=%d", dmx_id, pid, flag, subtype);
|
|
|
|
data->dmx_id = -1;
|
|
data->filter_handle = -1;
|
|
memset(&op, 0, sizeof(op));
|
|
data->dmx_id = dmx_id;
|
|
if (data->dmx_id == -1) {
|
|
SUBTITLE_LOGE("invalid argument, data->dmx_id is -1");
|
|
return -1;
|
|
}
|
|
ret = DemuxOpen(dmx_id, &op);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
|
|
ret = DemuxAllocateFilter(dmx_id, &data->filter_handle);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
SUBTITLE_LOGI("data->filter_handle:%d", data->filter_handle);
|
|
|
|
ret = DemuxSetBufferSize(dmx_id, data->filter_handle, DMX_SUBTITLE_BUFFER_SIZE);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
memset(&pesp, 0, sizeof(pesp));
|
|
pesp.pid = pid;
|
|
pesp.output = DMX_OUT_TAP;
|
|
if (flag) {
|
|
pesp.flags = DMX_SUBTITLE_SEC;
|
|
} else {
|
|
pesp.flags = DMX_SUBTITLE_NO_SEC;
|
|
}
|
|
if (TYPE_SUBTITLE_DVB == subtype) {
|
|
SUBTITLE_LOGI("use PES filter subtype=%d", subtype);
|
|
pesp.pes_type = DMX_PES_SUBTITLE;
|
|
pesp.input = DMX_IN_FRONTEND;
|
|
ret = DemuxSetPesFilter(dmx_id, data->filter_handle, &pesp);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
} else if (TYPE_SUBTITLE_DVB_TELETEXT == subtype) {
|
|
SUBTITLE_LOGI("use PES filter subtype=%d", subtype);
|
|
pesp.pes_type = DMX_PES_SUBTITLE; // DMX_PES_TELETEXT;
|
|
pesp.input = DMX_IN_FRONTEND;
|
|
ret = DemuxSetPesFilter(dmx_id, data->filter_handle, &pesp);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
} else if (TYPE_SUBTITLE_SCTE27 == subtype) {
|
|
// the scte27 data is section
|
|
SUBTITLE_LOGI("use section filter subtype=%d", subtype);
|
|
memset(¶m, 0, sizeof(param));
|
|
param.pid = pid;
|
|
param.filter.filter[0] = SCTE27_TID;
|
|
param.filter.mask[0] = 0xff;
|
|
param.flags = DMX_CHECK_CRC;
|
|
ret = DemuxSetSecFilter(dmx_id, data->filter_handle, ¶m);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
} else if (TYPE_SUBTITLE_ARIB_B24 == subtype) {
|
|
// the arib data is section
|
|
SUBTITLE_LOGI("use PES filter subtype=%d", subtype);
|
|
pesp.pes_type = DMX_PES_SUBTITLE;
|
|
pesp.input = DMX_IN_FRONTEND;
|
|
ret = DemuxSetPesFilter(dmx_id, data->filter_handle, &pesp);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
} else if (TYPE_SUBTITLE_DVB_TTML == subtype) {
|
|
// the ttml data is section
|
|
SUBTITLE_LOGI("use PES filter subtype=%d", subtype);
|
|
pesp.pes_type = DMX_PES_SUBTITLE;
|
|
pesp.input = DMX_IN_FRONTEND;
|
|
ret = DemuxSetPesFilter(dmx_id, data->filter_handle, &pesp);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
}
|
|
|
|
ret = DemuxSetCallback(dmx_id, data->filter_handle, pes_data_cb, data);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
|
|
ret = DemuxStartFilter(dmx_id, data->filter_handle);
|
|
if (ret != AM_SUCCESS) goto error;
|
|
SUBTITLE_LOGI_FUNC_OUT();
|
|
return 0;
|
|
error:
|
|
SUBTITLE_LOGE("ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
if (data->filter_handle != -1) {
|
|
DemuxFreeFilter(dmx_id, data->filter_handle);
|
|
}
|
|
if (data->dmx_id != -1) {
|
|
DemuxClose(dmx_id);
|
|
}
|
|
SUBTITLE_LOGI_FUNC_OUT();
|
|
return -1;
|
|
}
|
|
|
|
static void close_dvb_dmx(TVSubtitleData *data, int dmx_id) {
|
|
SUBTITLE_LOGI_FUNC_IN();
|
|
if (data == nullptr) {
|
|
SUBTITLE_LOGE("data is nullptr");
|
|
return;
|
|
}
|
|
|
|
if (data->filter_handle != -1) {
|
|
DemuxStopFilter(dmx_id, data->filter_handle);
|
|
DemuxSetCallback(dmx_id, data->filter_handle, NULL, NULL);
|
|
DemuxFreeFilter(dmx_id, data->filter_handle);
|
|
data->filter_handle = -1;
|
|
}
|
|
|
|
if (dmx_id != -1) {
|
|
DemuxClose(dmx_id);
|
|
}
|
|
|
|
data->dmx_id = -1;
|
|
SUBTITLE_LOGI_FUNC_OUT();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DemuxSource::DemuxSource() {
|
|
sInstance = this;
|
|
mMediaSync = MediaSync_create();
|
|
SUBTITLE_LOGI("subtitle mediasync created");
|
|
}
|
|
|
|
DemuxSource::~DemuxSource() {
|
|
SUBTITLE_LOGI_FUNC_IN();
|
|
mExitRequested = true;
|
|
if (mRenderTimeThread != nullptr) {
|
|
mRenderTimeThread->join();
|
|
mRenderTimeThread = nullptr;
|
|
}
|
|
|
|
if (mMediaSync != nullptr) {
|
|
MediaSync_destroy(mMediaSync);
|
|
mMediaSync = nullptr;
|
|
}
|
|
mPlayerId = -1;
|
|
mMediaSyncId = -1;
|
|
mMediaSyncDestroyFlag = false;
|
|
|
|
if (mDemuxContext != nullptr) {
|
|
close_dvb_dmx(mDemuxContext, mDemuxId);
|
|
delete mDemuxContext;
|
|
mDemuxContext = nullptr;
|
|
}
|
|
|
|
if (mDumpFd > 0) {
|
|
::close(mDumpFd);
|
|
mDumpFd = -1;
|
|
}
|
|
|
|
mSegment = nullptr;
|
|
SUBTITLE_LOGI_FUNC_OUT();
|
|
}
|
|
|
|
bool DemuxSource::notifyInfoChange() {
|
|
std::unique_lock<std::mutex> autolock(mLock);
|
|
for (auto it = mInfoListeners.begin(); it != mInfoListeners.end(); it++) {
|
|
auto wk_listener = (*it);
|
|
if (auto lstn = wk_listener.lock()) {
|
|
lstn->onTypeChanged(mSubType);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DemuxSource::loopRenderTime() {
|
|
while (!mExitRequested) {
|
|
mLock.lock();
|
|
for (auto it = mInfoListeners.begin(); it != mInfoListeners.end();) {
|
|
// Using weak_ Ptr. lock() to obtain shared_ Ptr, ensuring that null pointer exceptions
|
|
// are not caused by expired listeners during processing
|
|
auto wk_listener = it->lock();
|
|
|
|
if (!wk_listener) {
|
|
SUBTITLE_LOGI("Listener is null or expired.");
|
|
// Use erase to remove expired weeks_ PTR
|
|
it = mInfoListeners.erase(it);
|
|
continue;
|
|
}
|
|
|
|
int64_t value = 0;
|
|
if (-1 == mMediaSyncId) {
|
|
mSyncPts = sysfsReadInt(SYSFS_VIDEO_PTS.c_str(), 16);
|
|
} else if (mMediaSync != nullptr && !mMediaSyncDestroyFlag) {
|
|
MediaSync_getTrackMediaTime(mMediaSync, &value);
|
|
mSyncPts = us2Pts(value);
|
|
}
|
|
|
|
static int i = 0;
|
|
if (i++ % 300 == 0) {
|
|
SUBTITLE_LOGE("read pts: %" PRId64 ", mMediaSyncId: %d", mSyncPts, mMediaSyncId);
|
|
}
|
|
|
|
if (!mExitRequested && mSyncPts > 0) {
|
|
wk_listener->onRenderTimeChanged(mSyncPts);
|
|
}
|
|
++it;
|
|
}
|
|
mLock.unlock();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
|
}
|
|
}
|
|
|
|
SubtitleIOType DemuxSource::type() {
|
|
return E_SUBTITLE_DEMUX;
|
|
}
|
|
|
|
bool DemuxSource::start() {
|
|
if (E_SOURCE_STARTED == mState) {
|
|
SUBTITLE_LOGE("already stated");
|
|
return false;
|
|
}
|
|
SUBTITLE_LOGI("DemuxSource start mPid:%d mSecureLevelFlag:%d", mPid, mSecureLevelFlag);
|
|
mState = E_SOURCE_STARTED;
|
|
mSegment = std::shared_ptr<BufferSegment>(new BufferSegment());
|
|
mDemuxContext = new TVSubtitleData();
|
|
mRenderTimeThread =
|
|
std::shared_ptr<std::thread>(new std::thread(&DemuxSource::loopRenderTime, this));
|
|
int ret = open_dvb_dmx(mDemuxContext, mDemuxId, mPid, mSecureLevelFlag);
|
|
if (ret == -1) {
|
|
return false;
|
|
}
|
|
|
|
notifyInfoChange();
|
|
return true;
|
|
}
|
|
|
|
void DemuxSource::updateParameter(int type, void *data) {
|
|
SUBTITLE_LOGI("type = %d ", type);
|
|
bool restartDemux = false;
|
|
if (TYPE_SUBTITLE_DVB == type) {
|
|
DvbParam *pDvbParam = (DvbParam *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pDvbParam->pid)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pDvbParam->demuxId;
|
|
mPid = pDvbParam->pid;
|
|
mSecureLevelFlag = pDvbParam->flag;
|
|
mParam1 = pDvbParam->compositionId;
|
|
mParam2 = pDvbParam->ancillaryId;
|
|
} else if (TYPE_SUBTITLE_DVB_TELETEXT == type) {
|
|
TeletextParam *pTeletextParam = (TeletextParam *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pTeletextParam->pid)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pTeletextParam->demuxId;
|
|
mPid = pTeletextParam->pid;
|
|
mSecureLevelFlag = pTeletextParam->flag;
|
|
mParam1 = pTeletextParam->magazine;
|
|
mParam2 = pTeletextParam->pageNo;
|
|
} else if (TYPE_SUBTITLE_SCTE27 == type) {
|
|
Scte27Param *pScte27Param = (Scte27Param *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pScte27Param->SCTE27_PID)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pScte27Param->demuxId;
|
|
mPid = pScte27Param->SCTE27_PID;
|
|
mSecureLevelFlag = pScte27Param->flag;
|
|
} else if (TYPE_SUBTITLE_ARIB_B24 == type) {
|
|
Arib24Param *pArib24Param = (Arib24Param *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pArib24Param->pid)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pArib24Param->demuxId;
|
|
mPid = pArib24Param->pid;
|
|
mSecureLevelFlag = pArib24Param->flag;
|
|
mParam1 = pArib24Param->languageCodeId;
|
|
} else if (TYPE_SUBTITLE_DVB_TTML == type) {
|
|
TtmlParam *pTtmlParam = (TtmlParam *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pTtmlParam->pid)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pTtmlParam->demuxId;
|
|
mPid = pTtmlParam->pid;
|
|
mSecureLevelFlag = pTtmlParam->flag;
|
|
} else if (TYPE_SUBTITLE_SMPTE_TTML == type) {
|
|
SmpteTtmlParam *pSmpteTtmlParam = (SmpteTtmlParam *)data;
|
|
if ((mState == E_SOURCE_STARTED) && (mPid != pSmpteTtmlParam->pid)) {
|
|
restartDemux = true;
|
|
}
|
|
mDemuxId = pSmpteTtmlParam->demuxId;
|
|
mPid = pSmpteTtmlParam->pid;
|
|
mSecureLevelFlag = pSmpteTtmlParam->flag;
|
|
}
|
|
SUBTITLE_LOGI("restartDemux=%d ", restartDemux);
|
|
mSubType = type;
|
|
if (restartDemux) {
|
|
mExitRequested = true;
|
|
if (mRenderTimeThread != nullptr) {
|
|
mRenderTimeThread->join();
|
|
mRenderTimeThread = nullptr;
|
|
}
|
|
|
|
if (mDemuxContext != nullptr) {
|
|
close_dvb_dmx(mDemuxContext, mDemuxId);
|
|
delete mDemuxContext;
|
|
mDemuxContext = nullptr;
|
|
}
|
|
|
|
mDemuxContext = new TVSubtitleData();
|
|
int ret = open_dvb_dmx(mDemuxContext, mDemuxId, mPid, mSecureLevelFlag);
|
|
if (ret == 0) {
|
|
mExitRequested = false;
|
|
mRenderTimeThread =
|
|
std::shared_ptr<std::thread>(new std::thread(&DemuxSource::loopRenderTime, this));
|
|
notifyInfoChange();
|
|
} else {
|
|
delete mDemuxContext;
|
|
mDemuxContext = nullptr;
|
|
}
|
|
}
|
|
SUBTITLE_LOGI("mPid:%d, demuxId = %d, mSecureLevelFlag = %d", mPid, mDemuxId, mSecureLevelFlag);
|
|
return;
|
|
}
|
|
|
|
void DemuxSource::setPipId(int mode, int id) {
|
|
SUBTITLE_LOGI("mode:%d, id = %d", mode, id);
|
|
if (PIP_PLAYER_ID == mode) {
|
|
mPlayerId = id;
|
|
} else if (PIP_MEDIASYNC_ID == mode) {
|
|
if ((-1 != mMediaSyncId) || (mMediaSyncId != id)) {
|
|
mMediaSyncId = id;
|
|
mMediaSyncDestroyFlag = true;
|
|
if (mMediaSync != nullptr) {
|
|
MediaSync_destroy(mMediaSync);
|
|
mMediaSync = MediaSync_create();
|
|
}
|
|
MediaSync_bindInstance(mMediaSync, mMediaSyncId, MEDIA_SUBTITLE);
|
|
mMediaSyncDestroyFlag = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DemuxSource::stop() {
|
|
SUBTITLE_LOGI_FUNC_IN();
|
|
mState = E_SOURCE_STOPPED;
|
|
mExitRequested = true;
|
|
|
|
if (mRenderTimeThread != nullptr) {
|
|
mRenderTimeThread->join();
|
|
mRenderTimeThread = nullptr;
|
|
}
|
|
|
|
// If parser has problem, it read more data than provided
|
|
// then stop cannot stopped. need notify exit here.
|
|
if (mSegment != nullptr) {
|
|
mSegment->notifyExit();
|
|
}
|
|
|
|
if (mDemuxContext != nullptr) {
|
|
close_dvb_dmx(mDemuxContext, mDemuxId);
|
|
delete mDemuxContext;
|
|
mDemuxContext = nullptr;
|
|
}
|
|
|
|
mDemuxId = -1;
|
|
SUBTITLE_LOGI_FUNC_OUT();
|
|
return false;
|
|
}
|
|
|
|
bool DemuxSource::isFileAvailable() {
|
|
auto firstFrameToggle = sysfsReadInt(SYSFS_VIDEO_FIRSTRRAME.c_str(), 10);
|
|
mediasync_frameinfo tempInfo;
|
|
tempInfo.framePts = -1;
|
|
|
|
SUBTITLE_LOGI("mMediaSyncId:%d, mMediaSync:%p", mMediaSyncId, mMediaSync);
|
|
if (mMediaSyncId != -1 && mMediaSync != nullptr) {
|
|
MediaSync_getFirstVideoFrameInfo(mMediaSync, &tempInfo);
|
|
}
|
|
SUBTITLE_LOGI("firstFrameToggle:%" PRId64 ",tempInfo.framePts:%" PRId64, firstFrameToggle,
|
|
tempInfo.framePts);
|
|
return (firstFrameToggle == 1 || tempInfo.framePts > 0);
|
|
}
|
|
|
|
size_t DemuxSource::availableDataSize() {
|
|
if (mSegment == nullptr) return 0;
|
|
|
|
return mSegment->availableDataSize();
|
|
}
|
|
|
|
size_t DemuxSource::read(void *buffer, size_t size) {
|
|
size_t read = 0;
|
|
int isReadItemEnd = 0;
|
|
// Current design of Parser Read, do not need add lock protection.
|
|
// because all the read, is in Parser's parser thread.
|
|
// We only need add lock here, is for protect access the mCurrentItem's
|
|
// member function multi-thread.
|
|
// Current Impl do not need lock, if required, then redesign the SegmentBuffer.
|
|
|
|
// in case of applied size more than 1024*2, such as dvb subtitle,
|
|
// and data process error for two reads.
|
|
// so add until read applied data then exit.
|
|
while (read != size && mState == E_SOURCE_STARTED) {
|
|
if (mSegment == nullptr) {
|
|
return 0;
|
|
}
|
|
if (mCurrentItem != nullptr && !mCurrentItem->isEmpty()) {
|
|
if (size == 0xffff) {
|
|
// if size is 0xffff, it means to get all the data of the current item
|
|
size = mCurrentItem->getSize();
|
|
}
|
|
read += mCurrentItem->read_check(((char *)buffer + read), size - read, &isReadItemEnd,
|
|
E_SUBTITLE_DEMUX);
|
|
// SUBTITLE_LOGV("read:%d,size:%d isReadItemEnd:%d SourceType:%d", read, size,
|
|
// isReadItemEnd, E_SUBTITLE_DEMUX);
|
|
if (read == size || isReadItemEnd == -1) return read;
|
|
} else {
|
|
// SUBTITLE_LOGV("mCurrentItem null, pop next buffer item");
|
|
mCurrentItem = mSegment->pop();
|
|
}
|
|
}
|
|
return read;
|
|
}
|
|
|
|
void DemuxSource::dump(int fd, const char *prefix) {
|
|
dprintf(fd, "%s nDemuxSource:\n", prefix);
|
|
{
|
|
std::unique_lock<std::mutex> autolock(mLock);
|
|
for (auto it = mInfoListeners.begin(); it != mInfoListeners.end(); it++) {
|
|
auto wk_listener = (*it);
|
|
if (auto lstn = wk_listener.lock())
|
|
dprintf(fd, "%s InfoListener: %p\n", prefix, lstn.get());
|
|
}
|
|
}
|
|
dprintf(fd, "%s state:%d\n\n", prefix, mState);
|
|
|
|
dprintf(fd, "%s Total Subtitle Tracks: (%s)%" PRId64 "\n", prefix,
|
|
SYSFS_SUBTITLE_TOTAL.c_str(), sysfsReadInt(SYSFS_SUBTITLE_TOTAL.c_str(), 10));
|
|
dprintf(fd, "%s Current Subtitle type: (%s)%" PRId64 "\n", prefix,
|
|
SYSFS_SUBTITLE_TYPE.c_str(), sysfsReadInt(SYSFS_SUBTITLE_TYPE.c_str(), 10));
|
|
|
|
dprintf(fd, "\n%s Current Unconsumed Data Size: %zu\n", prefix, availableDataSize());
|
|
}
|
|
|
|
void DemuxSource::onPesCallback() {
|
|
// See DataSource::checkParsedPts(), mNewestDemuxAVPts is updated within some conditions.
|
|
if (mNewestDemuxAVPts != 0) {
|
|
return;
|
|
}
|
|
updateNewestAVPts(0, 0);
|
|
}
|
|
|
|
void DemuxSource::updateNewestAVPts(int64_t subtitlePts, int64_t syncedPts) {
|
|
amdmx_filter_mem_info demuxFilterMemInfo;
|
|
memset(&demuxFilterMemInfo, 0, sizeof(demuxFilterMemInfo));
|
|
auto ret = DemuxGetNewestPts(mDemuxId, &demuxFilterMemInfo);
|
|
if (ret != AM_SUCCESS) {
|
|
SUBTITLE_LOGE("[newest_avpts_tag] fail to DemuxGetNewestPts");
|
|
return;
|
|
}
|
|
|
|
int64_t audioPts = 0;
|
|
int64_t videoPts = 0;
|
|
int64_t subtitleDemuxPts = 0;
|
|
int64_t teletextPts = 0;
|
|
for (__u32 i = 0; i < demuxFilterMemInfo.filter_num; ++i) {
|
|
auto info = demuxFilterMemInfo.info[i];
|
|
if (info.type == AMDMX_AUDIO_TYPE) {
|
|
audioPts = info.filter_info.newest_pts;
|
|
} else if (info.type == AMDMX_VIDEO_TYPE) {
|
|
videoPts = info.filter_info.newest_pts;
|
|
} else if (info.type == AMDMX_SUBTITLE_TYPE) {
|
|
subtitleDemuxPts = info.filter_info.newest_pts;
|
|
} else if (info.type == AMDMX_TELETEXT_TYPE) {
|
|
teletextPts = info.filter_info.newest_pts;
|
|
}
|
|
}
|
|
|
|
if (subtitlePts != 0 && syncedPts != 0) {
|
|
SUBTITLE_LOGI("[newest_avpts_tag_check] PES's PTS difference: video-audio = %" PRId64
|
|
" ms, video-subtitle = %" PRId64 " ms, audio-subtitle = %" PRId64
|
|
" ms, video-syncedPts = %" PRId64 " ms",
|
|
pts2Ms(videoPts - audioPts), pts2Ms(videoPts - subtitlePts),
|
|
pts2Ms(audioPts - subtitlePts), pts2Ms(videoPts - syncedPts));
|
|
}
|
|
|
|
if (audioPts == 0 || videoPts == 0) {
|
|
if (subtitlePts != 0 && syncedPts != 0) {
|
|
SUBTITLE_LOGE("[newest_avpts_tag] audioPts = %" PRId64 " ms, videoPts = %" PRId64
|
|
" ms, teletextPts = %" PRId64 " ms, subtitlePts = %" PRId64 " ms",
|
|
pts2Ms(audioPts), pts2Ms(videoPts), pts2Ms(teletextPts),
|
|
pts2Ms(subtitleDemuxPts));
|
|
}
|
|
mNewestDemuxAVPts = std::max(audioPts, videoPts);
|
|
} else {
|
|
mNewestDemuxAVPts = std::min(audioPts, videoPts);
|
|
}
|
|
}
|