void MythDVDPlayer::DisplayLastFrame(void) { // clear the buffering state SetBuffering(false); DisplayDVDButton(); videofiltersLock.lock(); videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players, kScan_Progressive); videofiltersLock.unlock(); AVSync(NULL, true); }
int main(int argc, char* argv[]) { pthread_t termThread; int isTermThreadStarted = 0; int audioTrackIdx = -1; int subtitleTrackIdx = -1; uint32_t linuxDvbBufferSizeMB = 0; char argvBuff[256]; memset(argvBuff, '\0', sizeof(argvBuff)); int commandRetVal = -1; /* inform client that we can handle additional commands */ fprintf(stderr, "{\"EPLAYER3_EXTENDED\":{\"version\":%d}}\n", 51); PlayFiles_t playbackFiles; memset(&playbackFiles, 0x00, sizeof(playbackFiles)); if (0 != ParseParams(argc, argv, &playbackFiles, &audioTrackIdx, &subtitleTrackIdx, &linuxDvbBufferSizeMB)) { printf("Usage: exteplayer3 filePath [-u user-agent] [-c cookies] [-h headers] [-p prio] [-a] [-d] [-w] [-l] [-s] [-i] [-t audioTrackId] [-9 subtitleTrackId] [-x separateAudioUri] plabackUri\n"); printf("[-b size] Linux DVB output buffer size in MB\n"); printf("[-a 0|1|2|3] AAC software decoding - 1 bit - AAC ADTS, 2 - bit AAC LATM\n"); printf("[-e] EAC3 software decoding\n"); printf("[-3] AC3 software decoding\n"); printf("[-d] DTS software decoding\n"); printf("[-m] MP3 software decoding\n"); printf("[-w] WMA1, WMA2, WMA/PRO software decoding\n"); printf("[-l] software decoder use LPCM for injection (otherwise wav PCM will be used)\n"); printf("[-s] software decoding as stereo [downmix]\n"); #ifdef HAVE_FLV2MPEG4_CONVERTER printf("[-4 0|1] - disable/enable flv2mpeg4 converter\n"); #endif printf("[-i] play in infinity loop\n"); printf("[-v] switch to live TS stream mode\n"); printf("[-n 0|1|2] rtmp force protocol implementation auto(0) native/ffmpeg(1) or librtmp(2)\n"); printf("[-o 0|1] set progressive download\n"); printf("[-p value] nice value\n"); printf("[-P value] select Program ID from multi-service stream\n"); printf("[-t id] audio track ID switched on at start\n"); printf("[-9 id] subtitle track ID switched on at start\n"); printf("[-h headers] set custom HTTP headers \"Name: value\\r\\nName: value\\r\\n\"\n"); printf("[-u user-agent] set custom http User-Agent header\n"); printf("[-c cookies] set cookies - not working at now, please use -h instead\n"); printf("[-x separateAudioUri]\n"); printf("[-0 idx] video MPEG-DASH representation index\n"); printf("[-1 idx] audio MPEG-DASH representation index\n"); printf("[-f ffopt=ffval] any other ffmpeg option\n"); printf("[-F path to additional file with moov atom data (used for mp4 playback in progressive download mode)\n"); printf("[-O moov atom offset in the original file (used for mp4 playback in progressive download mode)\n"); printf("[-S remote file size (used for mp4 playback in progressive download mode)\n"); exit(1); } g_player = malloc(sizeof(Context_t)); if(NULL == g_player) { printf("g_player allocate error\n"); exit(1); } pthread_mutex_init(&playbackStartMtx, NULL); do { int flags = 0; if (pipe(g_pfd) == -1) break; /* Make read and write ends of pipe nonblocking */ if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1) break; /* Make read end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[0], F_SETFL, flags) == -1) break; if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1) break; /* Make write end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[1], F_SETFL, flags) == -1) break; if(0 == pthread_create(&termThread, NULL, TermThreadFun, NULL)) isTermThreadStarted = 1; } while(0); g_player->playback = &PlaybackHandler; g_player->output = &OutputHandler; g_player->container = &ContainerHandler; g_player->manager = &ManagerHandler; // make sure to kill myself when parent dies prctl(PR_SET_PDEATHSIG, SIGKILL); SetBuffering(); //Registrating output devices g_player->output->Command(g_player, OUTPUT_ADD, "audio"); g_player->output->Command(g_player, OUTPUT_ADD, "video"); g_player->output->Command(g_player, OUTPUT_ADD, "subtitle"); //Set LINUX DVB additional write buffer size if (linuxDvbBufferSizeMB) g_player->output->Command(g_player, OUTPUT_SET_BUFFER_SIZE, &linuxDvbBufferSizeMB); g_player->manager->video->Command(g_player, MANAGER_REGISTER_UPDATED_TRACK_INFO, UpdateVideoTrack); if (strncmp(playbackFiles.szFirstFile, "rtmp", 4) && strncmp(playbackFiles.szFirstFile, "ffrtmp", 4)) { g_player->playback->noprobe = 1; } commandRetVal = g_player->playback->Command(g_player, PLAYBACK_OPEN, &playbackFiles); fprintf(stderr, "{\"PLAYBACK_OPEN\":{\"OutputName\":\"%s\", \"file\":\"%s\", \"sts\":%d}}\n", g_player->output->Name, playbackFiles.szFirstFile, commandRetVal); if(commandRetVal < 0) { if(NULL != g_player) { free(g_player); } return 10; } { pthread_mutex_lock(&playbackStartMtx); isPlaybackStarted = 1; pthread_mutex_unlock(&playbackStartMtx); commandRetVal = g_player->output->Command(g_player, OUTPUT_OPEN, NULL); fprintf(stderr, "{\"OUTPUT_OPEN\":{\"sts\":%d}}\n", commandRetVal); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PLAY, NULL); fprintf(stderr, "{\"PLAYBACK_PLAY\":{\"sts\":%d}}\n", commandRetVal); if (g_player->playback->isPlaying) { PlaybackDieNowRegisterCallback(TerminateWakeUp); HandleTracks(g_player->manager->video, (PlaybackCmd_t)-1, "vc"); HandleTracks(g_player->manager->audio, (PlaybackCmd_t)-1, "al"); if (audioTrackIdx >= 0) { static char cmd[128] = ""; // static to not allocate on stack sprintf(cmd, "ai%d\n", audioTrackIdx); commandRetVal = HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, cmd); } HandleTracks(g_player->manager->audio, (PlaybackCmd_t)-1, "ac"); HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t)-1, "sl"); if (subtitleTrackIdx >= 0) { static char cmd[128] = ""; // static to not allocate on stack sprintf(cmd, "si%d\n", subtitleTrackIdx); commandRetVal = HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, cmd); } HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t)-1, "sc"); } while(g_player->playback->isPlaying && 0 == PlaybackDieNow(0)) { /* we made fgets non blocking */ if( NULL == fgets(argvBuff, sizeof(argvBuff)-1 , stdin) ) { /* wait for data - max 1s */ kbhit(); continue; } if(0 == argvBuff[0]) { continue; } switch(argvBuff[0]) { case 'v': { HandleTracks(g_player->manager->video, (PlaybackCmd_t)-1, argvBuff); break; } case 'a': { HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, argvBuff); break; } case 's': { HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, argvBuff); break; } case 'q': { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_STOP, NULL); fprintf(stderr, "{\"PLAYBACK_STOP\":{\"sts\":%d}}\n", commandRetVal); break; } case 'c': { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_CONTINUE, NULL); fprintf(stderr, "{\"PLAYBACK_CONTINUE\":{\"sts\":%d}}\n", commandRetVal); break; } case 'p': { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PAUSE, NULL); fprintf(stderr, "{\"PLAYBACK_PAUSE\":{\"sts\":%d}}\n", commandRetVal); break; } case 'm': { int speed = 0; sscanf(argvBuff+1, "%d", &speed); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SLOWMOTION, &speed); fprintf(stderr, "{\"PLAYBACK_SLOWMOTION\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; } case 'o': { int flags = 0; if( 1 == sscanf(argvBuff+1, "%d", &flags) ) { progressive_playback_set(flags); fprintf(stderr, "{\"PROGRESSIVE_DOWNLOAD\":{\"flags\":%d, \"sts\":0}}\n", flags); } break; } case 'f': { int speed = 0; sscanf(argvBuff+1, "%d", &speed); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTFORWARD, &speed); fprintf(stderr, "{\"PLAYBACK_FASTFORWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; } case 'b': { int speed = 0; sscanf(argvBuff+1, "%d", &speed); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTBACKWARD, &speed); fprintf(stderr, "{\"PLAYBACK_FASTBACKWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; } case 'g': { int32_t gotoPos = 0; int64_t length = 0; int32_t lengthInt = 0; int64_t sec = 0; int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check sscanf(argvBuff+2, "%d", &gotoPos); if(0 <= gotoPos || force) { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length); fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%"PRId64", \"sts\":%d}}\n", length, commandRetVal); lengthInt = (int32_t)length; if(10 <= lengthInt || force) { sec = gotoPos; if(!force && gotoPos >= lengthInt) { sec = lengthInt - 10; } commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK_ABS, (void*)&sec); fprintf(stderr, "{\"PLAYBACK_SEEK_ABS\":{\"sec\":%"PRId64", \"sts\":%d}}\n", sec, commandRetVal); } } break; } case 'k': { int32_t seek = 0; int64_t length = 0; int32_t lengthInt = 0; int64_t sec = 0; int64_t pts = 0; int32_t CurrentSec = 0; int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check sscanf(argvBuff+2, "%d", &seek); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts); CurrentSec = (int32_t)(pts / 90000); if (0 == commandRetVal) { fprintf(stderr, "{\"J\":{\"ms\":%"PRId64"}}\n", pts / 90); } if(0 == commandRetVal || force) { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length); fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%"PRId64", \"sts\":%d}}\n", length, commandRetVal); lengthInt = (int32_t)length; if(10 <= lengthInt || force ) { int32_t ergSec = CurrentSec + seek; if(!force && 0 > ergSec) { sec = CurrentSec * -1; // jump to start position } else if(!force && ergSec >= lengthInt) { sec = (lengthInt - CurrentSec) - 5; if(0 < sec) { sec = 0; // no jump we are at the end } } else { sec = seek; } } commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK, (void*)&sec); fprintf(stderr, "{\"PLAYBACK_SEEK\":{\"sec\":%"PRId64", \"sts\":%d}}\n", sec, commandRetVal); } break; } case 'l': { int64_t length = 0; commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length); fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%"PRId64", \"sts\":%d}}\n", length, commandRetVal); break; } case 'j': { int64_t pts = 0; commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts); if (0 == commandRetVal) { int64_t lastPts = 0; commandRetVal = 1; if (g_player->container && g_player->container->selectedContainer) { commandRetVal = g_player->container->selectedContainer->Command(g_player->container, CONTAINER_LAST_PTS, &lastPts); } if (0 == commandRetVal && lastPts != INVALID_PTS_VALUE) { fprintf(stderr, "{\"J\":{\"ms\":%"PRId64",\"lms\":%"PRId64"}}\n", pts / 90, lastPts / 90); } else { fprintf(stderr, "{\"J\":{\"ms\":%"PRId64"}}\n", pts / 90); } } break; } case 'i': { PlaybackHandler_t *ptrP = g_player->playback; if(ptrP) { fprintf(stderr, "{\"PLAYBACK_INFO\":{ \"isPlaying\":%s, \"isPaused\":%s, \"isForwarding\":%s, \"isSeeking\":%s, \"isCreationPhase\":%s,", \ DUMP_BOOL(ptrP->isPlaying), DUMP_BOOL(ptrP->isPaused), DUMP_BOOL(ptrP->isForwarding), DUMP_BOOL(ptrP->isSeeking), DUMP_BOOL(ptrP->isCreationPhase) ); fprintf(stderr, "\"BackWard\":%d, \"SlowMotion\":%d, \"Speed\":%d, \"AVSync\":%d,", ptrP->BackWard, ptrP->SlowMotion, ptrP->Speed, ptrP->AVSync); fprintf(stderr, " \"isVideo\":%s, \"isAudio\":%s, \"isSubtitle\":%s, \"isDvbSubtitle\":%s, \"isTeletext\":%s, \"mayWriteToFramebuffer\":%s, \"abortRequested\":%s }}\n", \ DUMP_BOOL(ptrP->isVideo), DUMP_BOOL(ptrP->isAudio), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(ptrP->abortRequested) ); } break; } case 'n': { uint8_t loop = 0; if( '1' == argvBuff[1] || '0' == argvBuff[1] ) { PlaybackHandler_t *ptrP = g_player->playback; if(ptrP) { ptrP->isLoopMode = '1' == argvBuff[1] ? 1 : 0; fprintf(stderr, "{\"N\":{ \"isLoop\":%s }}\n", DUMP_BOOL(ptrP->isLoopMode)); } } break; } default: { break; } } } g_player->output->Command(g_player, OUTPUT_CLOSE, NULL); } if(NULL != g_player) { free(g_player); } if (isTermThreadStarted && 1 == write(g_pfd[1], "x", 1)) { pthread_join(termThread, NULL); } pthread_mutex_destroy(&playbackStartMtx); close(g_pfd[0]); close(g_pfd[1]); exit(0); }