970 lines
33 KiB
C++
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> ¶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<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;
|
|
}
|