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

970 lines
33 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 "SubtitleNativeAPI"
#include "SubtitleNativeAPI.h"
#include <IpcSocket.h>
#include <RemoteData.h>
#include <inttypes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <utils/CallStack.h>
#include <mutex>
#include "SubtitleClientLinux.h"
#include "SubtitleLog.h"
#define INVALID_PIP_ID -1
using ::android::CallStack;
enum RenderType {
CALLBACK_RENDER = 0,
DIRECT_RENDER = 1,
};
static AmlSubDataType __mapServerType2ApiType(int type) {
switch (type) {
case TYPE_SUBTITLE_DVB:
case TYPE_SUBTITLE_PGS:
case TYPE_SUBTITLE_SMPTE_TTML:
return SUB_DATA_TYPE_POSITION_BITMAP;
case TYPE_SUBTITLE_EXTERNAL:
case TYPE_SUBTITLE_MKV_STR:
case TYPE_SUBTITLE_SSA:
case TYPE_SUBTITLE_ARIB_B24:
case TYPE_SUBTITLE_TTML:
return SUB_DATA_TYPE_STRING;
case TYPE_SUBTITLE_CLOSED_CAPTION:
return SUB_DATA_TYPE_CC_JSON;
case 0xAAAA:
return SUB_DATA_TYPE_QTONE;
}
return SUB_DATA_TYPE_BITMAP;
}
/* deprecated, use Struct AmlSubtitleType directly */
static int __mapApiType2SubtitleType(int type) {
SUBTITLE_LOGI("call>> [stype:%d]", type);
switch (type) {
case TYPE_SUBTITLE_DVB:
return DTV_SUB_DVB;
case TYPE_SUBTITLE_DVB_TELETEXT:
return DTV_SUB_DVB_TELETEXT;
case TYPE_SUBTITLE_SCTE27:
return DTV_SUB_SCTE27;
case TYPE_SUBTITLE_CLOSED_CAPTION:
return DTV_SUB_CC;
case TYPE_SUBTITLE_ARIB_B24:
return DTV_SUB_ARIB24;
case TYPE_SUBTITLE_TTML:
return DTV_SUB_DVB_TTML;
case TYPE_SUBTITLE_SMPTE_TTML:
return DTV_SUB_SMPTE_TTML;
default:
return DTV_SUB_INVALID;
}
}
class MyAdaptorListener : public SubtitleListener {
public:
MyAdaptorListener() {
mDataCb = nullptr;
mChannelUpdateCb = nullptr;
mSubtitleAvailCb = nullptr;
mAfdEventCb = nullptr;
mDimensionCb = nullptr;
mLanguageCb = nullptr;
mSubtitleInfoCb = nullptr;
mMixVideoEventCb = nullptr;
checkDebug();
initReceiver();
}
virtual ~MyAdaptorListener() {
mDataCb = nullptr;
mChannelUpdateCb = nullptr;
mSubtitleAvailCb = nullptr;
mAfdEventCb = nullptr;
mDimensionCb = nullptr;
mLanguageCb = nullptr;
mSubtitleInfoCb = nullptr;
mMixVideoEventCb = nullptr;
deInitReceiver();
}
virtual void onSubtitleEvent(const char *data, int size, int parserType, int x, int y,
int width, int height, int videoWidth, int videoHeight,
int showing, int objectSegmentId) {
if (mDataCb != nullptr) {
mDataCb(data, size, __mapServerType2ApiType((AmlSubtitletype)parserType), x, y, width,
height, videoWidth, videoHeight, showing);
}
}
virtual void onSubtitleDataEvent(int event, int id) {
if (mChannelUpdateCb != nullptr) mChannelUpdateCb(event, id);
}
virtual void onSubtitleAvail(int avail) {
if (mSubtitleAvailCb != nullptr) mSubtitleAvailCb(avail);
}
virtual void onSubtitleAfdEvent(int event, int playerid) {
if (mAfdEventCb != nullptr) mAfdEventCb(event);
}
virtual void onSubtitleDimension(int width, int height) {
if (mDimensionCb != nullptr) mDimensionCb(width, height);
}
virtual void onSubtitleLanguage(std::string lang) {
if (mLanguageCb != nullptr) mLanguageCb(lang);
}
virtual void onSubtitleInfo(int what, int extra) {
if (mSubtitleInfoCb != nullptr) mSubtitleInfoCb(what, extra);
}
// middleware api do not need this
virtual void onMixVideoEvent(int val) {
if (mMixVideoEventCb != nullptr) mMixVideoEventCb(val);
}
virtual void onSubtitleUIEvent(int uiCmd, const std::vector<int> &params) {}
// sometime, server may crash, we need clean up in server side.
virtual void onServerDied() {}
void setupDataCb(AmlSubtitleDataCb cb) {
mDataCb = cb;
sendReadyMessage();
}
void setupChannelUpdateCb(AmlChannelUpdateCb cb) {
mChannelUpdateCb = cb;
sendReadyMessage();
}
void setupSubtitleAvailCb(AmlSubtitleAvailCb cb) {
mSubtitleAvailCb = cb;
sendReadyMessage();
}
void setupAfdEventCb(AmlAfdEventCb cb) {
mAfdEventCb = cb;
sendReadyMessage();
}
void setupDimensionCb(AmlSubtitleDimensionCb cb) {
mDimensionCb = cb;
sendReadyMessage();
}
void setupLanguageCb(AmlSubtitleLanguageCb cb) {
mLanguageCb = cb;
sendReadyMessage();
}
void setupSubtitleInfoCb(AmlSubtitleInfoCb cb) {
mSubtitleInfoCb = cb;
sendReadyMessage();
}
void setupMixVideoEventCb(AmlMixVideoEventCb cb) {
mMixVideoEventCb = cb;
sendReadyMessage();
}
private:
void checkDebug() { updateSubtitleLogLevel(); }
static void save2BitmapFile(const char *filename, uint32_t *bitmap, int w, int h) {
SUBTITLE_LOGI("png_save2:%s\n", filename);
FILE *f;
char fname[128] = {0};
snprintf(fname, sizeof(fname), "%s.ppm", filename);
f = fopen(fname, "w");
if (!f) {
perror(fname);
return;
}
fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int v = bitmap[y * w + x];
putc((v >> 16) & 0xff, f);
putc((v >> 8) & 0xff, f);
putc((v >> 0) & 0xff, f);
}
}
fclose(f);
}
void deInitReceiver() {
if (mReceiver) {
mReceiver->stop();
mReceiver->join();
mReceiver = nullptr;
}
}
void initReceiver() {
if (mReceiver == nullptr) {
mReceiver = std::make_shared<IpcSocket>(false);
mReceiver->start(6666, this);
}
if (!mReceiver->isvalid()) {
SUBTITLE_LOGE("Client: initRemoteLocked failed");
deInitReceiver();
return;
}
mReceiver->setEventListener(
[this](int fd, void *self) -> int { return handleRemoteDataEvent(fd, self); });
}
int handleRemoteDataEvent(int fd, void *self) {
auto reply = [](int fd) {
std::string retStr = "1";
bool success = IpcSocket::send(fd, retStr.c_str(), retStr.size());
SUBTITLE_LOGE("Reply %s", success ? "OK" : "NG");
};
if (self == nullptr) {
reply(fd);
return EventsTracker::RET_REMOVE;
}
char retBuf[sizeof(RemoteData)];
if (!IpcSocket::receive(fd, retBuf, sizeof(retBuf))) {
SUBTITLE_LOGE("Server broken, fd=%d, remove.", fd);
return EventsTracker::RET_REMOVE;
}
RemoteData *remoteData = (RemoteData *)(retBuf);
if (remoteData == nullptr) {
SUBTITLE_LOGE("Failed to allocate memory for RemoteData");
reply(fd);
return EventsTracker::RET_CONTINUE;
}
SUBTITLE_LOGI("Client received successfully, callbackType = %x", remoteData->callbackType);
auto *listener = (MyAdaptorListener *)(self);
if (listener) {
handleRemoteData(listener, remoteData);
}
reply(fd);
return EventsTracker::RET_CONTINUE;
}
void handleRemoteData(MyAdaptorListener *listener, const RemoteData *remoteData) {
switch (remoteData->callbackType) {
case EVENT_ON_SUBTITLEDATA_CALLBACK:
SUBTITLE_LOGI("EVENT_ON_SUBTITLEDATA_CALLBACK:event = %d, channelId = %d",
remoteData->event, remoteData->channelId);
listener->onSubtitleDataEvent(remoteData->event, remoteData->channelId);
break;
case EVENT_ON_SUBTITLEAVAILABLE_CALLBACK:
SUBTITLE_LOGI("EVENT_ON_SUBTITLEAVAILABLE_CALLBACK:available = %d",
remoteData->available);
listener->onSubtitleAvail(remoteData->available);
break;
case EVENT_ON_VIDEOAFDCHANGE_CALLBACK:
SUBTITLE_LOGI("EVENT_ON_VIDEOAFDCHANGE_CALLBACK:afd= %d, playerid= %d",
remoteData->afd, remoteData->playerid);
listener->onSubtitleAfdEvent(remoteData->afd, remoteData->playerid);
break;
case EVENT_ON_MIXVIDEOEVENT_CALLBACK:
// Middleware API does not need this event
break;
case EVENT_ON_SUBTITLE_DIMENSION_CALLBACK:
SUBTITLE_LOGI("EVENT_ON_SUBTITLE_DIMENSION_CALLBACK:width= %d, height= %d",
remoteData->width, remoteData->height);
listener->onSubtitleDimension(remoteData->width, remoteData->height);
break;
case EVENT_ON_SUBTITLE_LANGUAGE_CALLBACK:
if (remoteData->lang[0] != '\0') {
SUBTITLE_LOGI("EVENT_ON_SUBTITLE_LANGUAGE_CALLBACK:lang= %s", remoteData->lang);
listener->onSubtitleLanguage(std::string(remoteData->lang));
}
break;
case EVENT_ON_SUBTITLE_INFO_CALLBACK:
SUBTITLE_LOGI("EVENT_ON_SUBTITLE_INFO_CALLBACK:what= %d,extra= %d",
remoteData->what, remoteData->extra);
listener->onSubtitleInfo(remoteData->what, remoteData->extra);
break;
default:
SUBTITLE_LOGI(
"Default RemoteData:"
"type=%d, width=%d, height=%d, size=%d,"
"isShow=%d, isText=%d, x=%d, y=%d,"
"videoWidth=%d, videoHeight=%d, objectSegmentId=%d, shimId=%d;",
remoteData->type, remoteData->width, remoteData->height, remoteData->size,
remoteData->isShow, remoteData->isText, remoteData->x, remoteData->y,
remoteData->videoWidth, remoteData->videoHeight, remoteData->objectSegmentId,
remoteData->shimId);
handleDefaultEvent(listener, remoteData);
break;
}
}
void handleDefaultEvent(MyAdaptorListener *listener, const RemoteData *remoteData) {
if (listener->mDataCb == nullptr) {
SUBTITLE_LOGE("No data cb, do nothing on shard memory!");
return;
}
int shmId = shmget(remoteData->shimId, remoteData->size, 0);
if (shmId == -1) {
SUBTITLE_LOGI("Error getting shared memory, shmId=%d, error=%s", shmId,
strerror(errno));
return;
}
char *data = (char *)shmat(shmId, NULL, 0);
if (data == (char *)-1) {
SUBTITLE_LOGI("Error attaching shared memory, shmId=%d, error=%m", shmId);
return;
}
if (isSubtitleDumpAvailable()) {
if (remoteData->isText) {
SUBTITLE_LOGI("Text data: %s", data);
} else {
static int count = 0;
char filename[50];
snprintf(filename, sizeof(filename), "%s/callback_dvb(%d)", DUMP_DATA_DIRECTORY,
count++);
save2BitmapFile(filename, reinterpret_cast<uint32_t *>(data), remoteData->width,
remoteData->height);
}
}
listener->onSubtitleEvent(data, remoteData->size, remoteData->type, remoteData->x,
remoteData->y, remoteData->width, remoteData->height,
remoteData->videoWidth, remoteData->videoHeight,
remoteData->isShow, remoteData->objectSegmentId);
SUBTITLE_LOGI("Detaching and cleaning up shared memory");
shmdt(data);
}
void sendReadyMessage() {
if (mReceiver == nullptr) {
SUBTITLE_LOGE("Receiver is not ready, init it first!");
initReceiver();
if (mReceiver == nullptr) return;
}
std::string retStr = "recv-ready";
retStr = mReceiver->sendForResult(mReceiver->fd(), retStr.c_str(), retStr.size());
SUBTITLE_LOGI("recv-ready result: %s", retStr.c_str());
if (retStr == "1") {
SUBTITLE_LOGI("recv-ready register OK");
}
}
private:
AmlSubtitleDataCb mDataCb;
AmlChannelUpdateCb mChannelUpdateCb;
AmlSubtitleAvailCb mSubtitleAvailCb;
AmlAfdEventCb mAfdEventCb;
AmlSubtitleDimensionCb mDimensionCb;
AmlSubtitleLanguageCb mLanguageCb;
AmlSubtitleInfoCb mSubtitleInfoCb;
AmlMixVideoEventCb mMixVideoEventCb;
std::shared_ptr<IpcSocket> mReceiver;
};
class SubtitleContext : public android::RefBase {
public:
SubtitleContext() {
SUBTITLE_LOGI("call>> [%p]", this);
mClient = nullptr;
}
~SubtitleContext() { SUBTITLE_LOGI("call>> [%p]", this); }
sp<SubtitleClientLinux> mClient;
sp<MyAdaptorListener> mAdaptorListener;
};
std::vector<sp<SubtitleContext>> gAvailContextMap;
std::mutex gContextMapLock;
static bool __pushContext(sp<SubtitleContext> ctx) {
std::unique_lock<std::mutex> autolock(gContextMapLock);
auto it = gAvailContextMap.begin();
it = gAvailContextMap.insert(it, ctx);
SUBTITLE_LOGI(">> ctx:%p MapSize=%d", ctx.get(), gAvailContextMap.size());
return *it != nullptr;
}
static bool __checkInContextMap(SubtitleContext *ctx) {
std::unique_lock<std::mutex> autolock(gContextMapLock);
for (auto it = gAvailContextMap.begin(); it < gAvailContextMap.end(); it++) {
SUBTITLE_LOGI(">> search ctx:%p current:%p MapSize=%d", ctx, (*it).get(),
gAvailContextMap.size());
if (ctx == (*it).get()) {
return true;
}
}
SUBTITLE_LOGE("Error Invalid context handle!");
return false;
}
static bool __eraseFromContext(SubtitleContext *ctx) {
std::unique_lock<std::mutex> autolock(gContextMapLock);
for (auto it = gAvailContextMap.begin(); it < gAvailContextMap.end(); it++) {
SUBTITLE_LOGI(">> search ctx:%p current:%p MapSize=%d", ctx, (*it).get(),
gAvailContextMap.size());
if (ctx == (*it).get()) {
gAvailContextMap.erase(it);
return true;
}
}
SUBTITLE_LOGE("Error Invalid context handle!");
return false;
}
AmlSubtitleHnd amlsub_Create() {
SUBTITLE_LOGI("call>>");
sp<SubtitleContext> ctx = new SubtitleContext();
sp<MyAdaptorListener> listener = new MyAdaptorListener();
ctx->mClient = new SubtitleClientLinux(false, listener, OpenType::TYPE_MIDDLEWARE);
ctx->mAdaptorListener = listener;
__pushContext(ctx);
SUBTITLE_LOGI_FUNC_OUT();
return ctx.get();
}
AmlSubtitleStatus amlsub_Destroy(AmlSubtitleHnd handle) {
SubtitleContext *ctx = (SubtitleContext *)handle;
SUBTITLE_LOGI("call>> handle[%p]", handle);
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mClient = nullptr;
ctx->mAdaptorListener = nullptr;
__eraseFromContext(ctx);
SUBTITLE_LOGI_FUNC_OUT();
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_GetSessionId(AmlSubtitleHnd handle, int *sId) {
SubtitleContext *ctx = (SubtitleContext *)handle;
SUBTITLE_LOGI("call>> handle[%p]", handle);
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
auto client = ctx->mClient;
if (client == nullptr) {
return SUB_STAT_INV;
} else {
*sId = client->getSessionId();
}
return SUB_STAT_OK;
}
////////////////////////////////////////////////////////////
///////////////////// generic control //////////////////////
////////////////////////////////////////////////////////////
/**
* open, start to play subtitle.
* Param:
* handle: current subtitle handle.
* path: the subtitle external file path.
*/
AmlSubtitleStatus amlsub_Open(AmlSubtitleHnd handle, AmlSubtitleParam *param) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
SUBTITLE_LOGE("Error! invalid handle, uninitialized?");
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
if (param == nullptr) {
SUBTITLE_LOGE("Error! invalid input param, param=%p", param);
return SUB_STAT_INV;
}
ctx->mClient->userDataOpen();
// Here, we support all the parametes from client to server
// server will filter the parameter, select to use according from the type.
ctx->mClient->setSubType(param->subtitleType);
ctx->mClient->setSubPid(param->pid);
ctx->mClient->setSecureLevel(param->flag);
ctx->mClient->setChannelId(param->channelId);
ctx->mClient->setClosedCaptionVfmt(param->videoFormat);
// ctx->mClient->setCompositionPageId(param->ancillaryPageId);
ctx->mClient->doRegisterOnDataCB();
// TODO: CTC always use amstream. later we may all change to hwdemux
// From middleware, the extSubPath should always null.
SUBTITLE_LOGI("call>> demuxId[%d] ioSource[%d] subtitleType[%d] pid[%d]", param->dmxId,
param->ioSource, param->subtitleType, param->pid);
int ioType = -1;
if (param->dmxId >= 0) {
ioType = (param->dmxId << 16 | param->ioSource);
} else {
ioType = param->ioSource;
}
bool r = ctx->mClient->open(param->fd, ioType);
ctx->mClient->setPageId(param->compositionPageId);
ctx->mClient->setAncPageId(param->ancillaryPageId); // setAncPageId
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_Close(AmlSubtitleHnd handle) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool ret1 = ctx->mClient->userDataClose();
if (!ret1) {
SUBTITLE_LOGE("userDataClose failed");
}
bool ret2 = ctx->mClient->close();
if (!ret2) {
SUBTITLE_LOGE("close failed");
}
SUBTITLE_LOGI_FUNC_OUT();
return (ret1 && ret2) ? SUB_STAT_OK : SUB_STAT_FAIL;
}
/**
* reset current play, most used for seek.
*/
AmlSubtitleStatus amlsub_Reset(AmlSubtitleHnd handle) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
return ctx->mClient->resetForSeek() ? SUB_STAT_OK : SUB_STAT_FAIL;
}
////////////////////////////////////////////////////////////
//////////////// DTV operation/param related ///////////////
////////////////////////////////////////////////////////////
AmlSubtitleStatus amlsub_SetParameter(AmlSubtitleHnd handle, AmlSubtitleParamCmd cmd, void *value,
int paramSize) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
if (cmd == SUBCMD_TTX_COUNTRY_CODE) {
uint32_t countryCode = *(uint32_t *)value;
// Only support passing integer in Linux by now
ctx->mClient->setDvbCountryCode(countryCode);
}
return SUB_STAT_OK;
}
int amlsub_GetParameter(AmlSubtitleHnd handle, AmlSubtitleParamCmd cmd, void *value) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
return 0;
}
AmlSubtitleStatus amlsub_SetPip(AmlSubtitleHnd handle, AmlSubtitlePipMode mode, int value) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
if (value == INVALID_PIP_ID) return SUB_STAT_INV;
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mClient->setPipId(mode, value);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_TeletextControl(AmlSubtitleHnd handle, AmlTeletextCtrlParam *param) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr || param == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
if (param->event == TT_EVENT_SET_PAGE_NUMBER || param->event == TT_EVENT_SET_SUBPAGE_NUMBER) {
ctx->mClient->ttControl(param->event, param->magazine, param->page, param->regionid,
param->subPageNo);
} else {
ctx->mClient->ttControl(param->event, param->magazine, param->page, param->regionid, -1);
}
return SUB_STAT_OK;
}
int amlsub_getSubtitleStatus(AmlSubtitleHnd handle, int type, int event) {
SUBTITLE_LOGI("call>> handle[%p] type:%d event:%d", handle, type, event);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
int ret = SUB_STAT_INV;
ret = ctx->mClient->getSubtitleStatus(type, event);
return ret;
}
AmlSubtitleStatus amlsub_SelectCcChannel(AmlSubtitleHnd handle, int ch) {
SUBTITLE_LOGI("call>> handle[%p] ch:%d", handle, ch);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr || ch < 0) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mClient->resetForSeek();
ctx->mClient->close();
ctx->mClient->setChannelId(ch);
ctx->mClient->setSubType(TYPE_SUBTITLE_CLOSED_CAPTION);
ctx->mClient->open(0, 0); // CC do not care io type
return SUB_STAT_OK;
}
////////////////////////////////////////////////////////////
////// Regist callbacks for subtitle Event and data ////////
////// Will be directed display when listener is ////////
////// null or not called this. ////////
////////////////////////////////////////////////////////////
AmlSubtitleStatus amlsub_RegistOnDataCB(AmlSubtitleHnd handle, AmlSubtitleDataCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupDataCb(listener);
ctx->mClient->registerOnDataCB();
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistOnChannelUpdateCb(AmlSubtitleHnd handle,
AmlChannelUpdateCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupChannelUpdateCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistOnSubtitleAvailCb(AmlSubtitleHnd handle,
AmlSubtitleAvailCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupSubtitleAvailCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistAfdEventCB(AmlSubtitleHnd handle, AmlAfdEventCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupAfdEventCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistGetDimensionCb(AmlSubtitleHnd handle,
AmlSubtitleDimensionCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupDimensionCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistOnSubtitleLanguageCb(AmlSubtitleHnd handle,
AmlSubtitleLanguageCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupLanguageCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistOnSubtitleInfoCB(AmlSubtitleHnd handle, AmlSubtitleInfoCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupSubtitleInfoCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_RegistOnMixVideoEventCB(AmlSubtitleHnd handle,
AmlMixVideoEventCb listener) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
ctx->mAdaptorListener->setupMixVideoEventCb(listener);
return SUB_STAT_OK;
}
AmlSubtitleStatus amlsub_UiShow(AmlSubtitleHnd handle) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiShow();
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiHide(AmlSubtitleHnd handle) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiHide();
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
/* Only available for text subtitle */
AmlSubtitleStatus amlsub_UiSetTextColor(AmlSubtitleHnd handle, int color) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetTextColor(color);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiSetTextSize(AmlSubtitleHnd handle, int sp) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetTextSize(sp);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiSetGravity(AmlSubtitleHnd handle, int gravity) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetGravity(gravity);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiSetPosHeight(AmlSubtitleHnd handle, int yOffset) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetYOffset(yOffset);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiSetImgRatio(AmlSubtitleHnd handle, float ratioW, float ratioH, int maxW,
int maxH) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetImageRatio(ratioW, ratioH, maxW, maxH);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UiSetSurfaceViewRect(AmlSubtitleHnd handle, int x, int y, int width,
int height) {
SUBTITLE_LOGI("call>> handle[%p]", handle);
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->uiSetSurfaceViewRect(x, y, width, height);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}
AmlSubtitleStatus amlsub_UpdateVideoPos(AmlSubtitleHnd handle, int64_t pos) {
static int logCnt = 0;
if (++logCnt % 100 == 0) {
SUBTITLE_LOGI("call>> handle[%p] UpdateVideoPos: %" PRId64, handle, pos);
}
SubtitleContext *ctx = (SubtitleContext *)handle;
if (ctx == nullptr || ctx->mClient == nullptr) {
return SUB_STAT_INV;
}
if (!__checkInContextMap(ctx)) {
SUBTITLE_LOGE("Error! Bad handle! mis-using API?");
return SUB_STAT_INV;
}
bool r = ctx->mClient->updateVideoPos(pos);
return r ? SUB_STAT_OK : SUB_STAT_FAIL;
}