/* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in the * file 'LICENSE' which is part of this source code package. * * Description: */ #define LOG_TAG "SubtitleTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SubtitleLog.h" #include "SubtitleNativeAPI.h" #define DEBUG_DUMP 1 #define CC_MODE_ATV 1 #define CC_MODE_DTV 2 #define MEDIA_SYNC_DEFAULT_ID 1 std::shared_ptr mReceiver; AmlSubtitleHnd mSubtitleHandle = nullptr; /** Close caption's input.*/ typedef enum { CLOSED_CAPTION_INPUT_USERDATA, /**< Input from MPEG userdata.*/ CLOSED_CAPTION_INPUT_VBI /**< Input from VBI.*/ } ClosedCaptionInput; /** caption mode*/ typedef enum { CLOSED_CAPTION_NONE = -1, CLOSED_CAPTION_DEFAULT, /*NTSC CC channels*/ CLOSED_CAPTION_CC1, CLOSED_CAPTION_CC2, CLOSED_CAPTION_CC3, CLOSED_CAPTION_CC4, CLOSED_CAPTION_TEXT1, CLOSED_CAPTION_TEXT2, CLOSED_CAPTION_TEXT3, CLOSED_CAPTION_TEXT4, /*DTVCC services*/ CLOSED_CAPTION_SERVICE1, CLOSED_CAPTION_SERVICE2, CLOSED_CAPTION_SERVICE3, CLOSED_CAPTION_SERVICE4, CLOSED_CAPTION_SERVICE5, CLOSED_CAPTION_SERVICE6, CLOSED_CAPTION_XDS, CLOSED_CAPTION_DATA, CLOSED_CAPTION_MAX } ClosedCaptionMode; void initSocketTestReceiver() { if (mReceiver == nullptr) { mReceiver = std::make_shared(false); mReceiver->start(6666, nullptr); } if (!mReceiver->isvalid()) { SUBTITLE_LOGE("Client: initRemoteLocked failed \n"); mReceiver->stop(); mReceiver->join(); mReceiver = nullptr; return; } mReceiver->setEventListener([](int fd, void* self) -> int { printf("initReceiver \n"); auto reply = [](int fd) { std::string retStr = "1"; bool send = IpcSocket::send(fd, retStr.c_str(), retStr.size()); printf("Reply %s", (send ? "OK" : "NG")); }; char retBuf[sizeof(RemoteData)]; if (!IpcSocket::receive(fd, retBuf, sizeof(retBuf))) { printf("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; } // CC metadata info printf( "Client received: RemoteData_ {\n" " int type= %d;\n" " int width= %d;\n" " int height = %d;\n" " int size = %d;\n" " bool isShow= %d;\n" " bool isText= %d;\n" " int x= %d;\n" " int y= %d;\n" " int videoWidth= %d;\n" " int videoHeight= %d;\n" " int objectSegmentId= %d;\n" " int shimId= %d;\n" " int event= %d;\n" " int channelId= %d;\n" " int callbackType= %x;\n" " int available= %d;\n" " int afd= %d;\n" " int playerid= %d;\n" " string lang= %s;\n" " int what= %d;\n" " int extra= %d;\n" "}", remoteData->type, remoteData->width, remoteData->height, remoteData->size, remoteData->isShow, remoteData->isText, remoteData->x, remoteData->y, remoteData->videoWidth, remoteData->videoHeight, remoteData->objectSegmentId, remoteData->shimId, remoteData->event, remoteData->channelId, remoteData->callbackType, remoteData->available, remoteData->afd, remoteData->playerid, remoteData->lang, remoteData->what, remoteData->extra); if (remoteData->callbackType == EVENT_ON_SUBTITLEDATA_CALLBACK || remoteData->callbackType == EVENT_ON_SUBTITLEAVAILABLE_CALLBACK || remoteData->callbackType == EVENT_ON_VIDEOAFDCHANGE_CALLBACK || remoteData->callbackType == EVENT_ON_MIXVIDEOEVENT_CALLBACK || remoteData->callbackType == EVENT_ON_SUBTITLE_DIMENSION_CALLBACK || remoteData->callbackType == EVENT_ON_SUBTITLE_LANGUAGE_CALLBACK || remoteData->callbackType == EVENT_ON_SUBTITLE_INFO_CALLBACK) { printf("SubtitleTest No cc data. \n"); reply(fd); return EventsTracker::RET_CONTINUE; } // CC json data by shared mem int shmId = shmget(remoteData->shimId, remoteData->size, 0); if (shmId == -1) { printf("Error get shm ipc_id error shmid=%d, error=%s \n", shmId, strerror(errno)); return EventsTracker::RET_CONTINUE; } char* data = (char*)shmat(shmId, NULL, 0); #if DEBUG_DUMP if (remoteData->isText) { printf("cc json data: %s \n", data); } #endif printf("initReceiver shmdt shmctl \n"); shmdt(data); reply(fd); return EventsTracker::RET_CONTINUE; }); std::string retStr = "recv-ready"; retStr = mReceiver->sendForResult(mReceiver->fd(), retStr.c_str(), retStr.size()); printf("recv-ready result: %s \n", retStr.c_str()); if (retStr == "1") { printf("recv-ready register OK \n"); } } static void startAtvCc(int channel) { if (channel > CLOSED_CAPTION_TEXT4 || channel < CLOSED_CAPTION_CC1) { printf("invalid cc channel:%d", channel); } printf("startAtvCc channel:%d", channel); int ch = channel | CLOSED_CAPTION_INPUT_VBI << 8; if (mSubtitleHandle == nullptr) { mSubtitleHandle = amlsub_Create(); } if (mSubtitleHandle == nullptr) { printf("mSubtitleHandle is NULL"); return; } AmlSubtitleParam subParam{}; subParam.subtitleType = TYPE_SUBTITLE_CLOSED_CAPTION; subParam.channelId = ch; amlsub_Open(mSubtitleHandle, &subParam); // amlsub_SetPip(mSubtitleHandle, MODE_SUBTITLE_PIP_MEDIASYNC, 1); printf("amlsub_Open ok"); } static void startDtvCc(int channel) { int mediaSyncId = MEDIA_SYNC_DEFAULT_ID; printf("startDtvCc ch:%x", channel); if (mSubtitleHandle == nullptr) { mSubtitleHandle = amlsub_Create(); } if (mSubtitleHandle == nullptr) { printf("mSubtitleHandle is NULL"); return; } AmlSubtitleParam subParam{}; subParam.subtitleType = TYPE_SUBTITLE_CLOSED_CAPTION; subParam.channelId = channel; amlsub_Open(mSubtitleHandle, &subParam); amlsub_SetPip(mSubtitleHandle, MODE_SUBTITLE_PIP_MEDIASYNC, mediaSyncId); printf("amlsub_Open ok"); } static const char* kShortOption = "hsm:c:"; static const struct option kLongOption[] = {{"help", no_argument, 0, 'h'}, {"socktest", no_argument, 0, 's'}, {"ccMode", required_argument, NULL, 'm'}, {"channel", required_argument, NULL, 'c'}, {0, 0, 0, 0}}; static void print_usage() { printf( "Usage: subtitle test\n" "Options:\n" " -h \t list all cmd\n" " -s \t socket test\n" " -m \t cc mode\n" " \t 1: CC_MODE_ATV \n" " \t 2: CC_MODE_DTV \n" " -c \t cc channel\n" " \t 1: CLOSED_CAPTION_CC1 \n" " \t 2: CLOSED_CAPTION_CC2 \n" " \t 3: CLOSED_CAPTION_CC3 \n" " \t 4: CLOSED_CAPTION_CC4 \n" " \t 9: CLOSED_CAPTION_CS1 \n" " \t10: CLOSED_CAPTION_CS2 \n" " \t11: CLOSED_CAPTION_CS3 \n" " \t12: CLOSED_CAPTION_CS4 \n" " \t13: CLOSED_CAPTION_CS5 \n" " \t14: CLOSED_CAPTION_CS6 \n" ); } int main(int argc, char** argv) { if (argc == 1) { print_usage(); return 0; } int opt; int ccMode; int ccChannel; while ((opt = getopt_long_only(argc, argv, kShortOption, kLongOption, NULL)) != -1) { switch (opt) { case 'h': print_usage(); break; case 's': /*test socket cc json data*/ initSocketTestReceiver(); break; case 'm': { char* endptr; ccMode = strtol(optarg, &endptr, 10); } break; case 'c': { char* endptr; ccChannel = strtol(optarg, &endptr, 10); printf("ccMode:%d, ccChannel:%d\n", ccMode, ccChannel); if (ccMode == CC_MODE_ATV) { startAtvCc(ccChannel); } else if (ccMode == CC_MODE_DTV) { startDtvCc(ccChannel); } else { printf("please input ccMode first!\n"); } } break; default: print_usage(); break; } } while (1) continue; printf("Process exit!"); return 0; }