/* * 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 #include #include #include #include #include #include #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 ¶ms) {} // 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(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(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 mReceiver; }; class SubtitleContext : public android::RefBase { public: SubtitleContext() { SUBTITLE_LOGI("call>> [%p]", this); mClient = nullptr; } ~SubtitleContext() { SUBTITLE_LOGI("call>> [%p]", this); } sp mClient; sp mAdaptorListener; }; std::vector> gAvailContextMap; std::mutex gContextMapLock; static bool __pushContext(sp ctx) { std::unique_lock 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 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 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 ctx = new SubtitleContext(); sp 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; }