source: titan/libeplayer3/main/exteplayer.c @ 42162

Last change on this file since 42162 was 42162, checked in by obi, 4 years ago

update libeplayer3 to v47

File size: 33.9 KB
Line 
1/*
2 * eplayer3: command line playback using libeplayer3
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <fcntl.h>
23#include <unistd.h>
24#include <sched.h>
25#include <signal.h>
26
27#include <sys/ioctl.h>
28#include <sys/prctl.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/time.h>
32#include <sys/resource.h>
33#include <sys/mman.h>
34#include <sys/socket.h>
35#include <sys/un.h>
36#include <errno.h>
37
38#include <pthread.h>
39
40#include "common.h"
41#include "misc.h"
42
43#define DUMP_BOOL(x) 0 == x ? "false"  : "true"
44#define IPTV_MAX_FILE_PATH 1024
45
46extern int ffmpeg_av_dict_set(const char *key, const char *value, int flags);
47extern void       aac_software_decoder_set(const int32_t val);
48extern void  aac_latm_software_decoder_set(const int32_t val);
49extern void       dts_software_decoder_set(const int32_t val);
50extern void       wma_software_decoder_set(const int32_t val);
51extern void       ac3_software_decoder_set(const int32_t val);
52extern void      eac3_software_decoder_set(const int32_t val);
53extern void       mp3_software_decoder_set(const int32_t val);
54extern void            rtmp_proto_impl_set(const int32_t val);
55extern void        flv2mpeg4_converter_set(const int32_t val);
56extern void        sel_program_id_set(const int32_t val);
57
58extern void pcm_resampling_set(int32_t val);
59extern void stereo_software_decoder_set(int32_t val);
60extern void insert_pcm_as_lpcm_set(int32_t val);
61extern void progressive_playback_set(int32_t val);
62
63extern OutputHandler_t         OutputHandler;
64extern PlaybackHandler_t       PlaybackHandler;
65extern ContainerHandler_t      ContainerHandler;
66extern ManagerHandler_t        ManagerHandler;
67
68static Context_t *g_player = NULL;
69
70static void TerminateAllSockets(void)
71{
72    int i;
73    for(i=0; i<1024; ++i)
74    {
75        if( 0 == shutdown(i, SHUT_RDWR) )
76        {
77            /* yes, I know that this is not good practice and I know what this could cause
78             * but in this use case it can be accepted.
79             * We must close socket because without closing it recv will return 0 (after shutdown)
80             * 0 is not correctly handled by external libraries
81             */
82            close(i);
83        }
84    }
85}
86
87static int g_pfd[2] = {-1, -1}; /* Used to wake terminate thread and kbhit */
88static int isPlaybackStarted = 0;
89static pthread_mutex_t playbackStartMtx;
90
91static void TerminateWakeUp()
92{
93    write(g_pfd[1], "x", 1);
94}
95
96static void *TermThreadFun(void *arg)
97{
98    const char *socket_path = "/tmp/iptvplayer_extplayer_term_fd";
99    struct sockaddr_un addr;
100    int fd = -1;
101    int cl = -1;
102    int nfds = 1;
103    fd_set readfds;
104   
105    unlink(socket_path);
106    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
107    {
108        perror("TermThreadFun socket error");
109        goto finish;
110    }
111
112    memset(&addr, 0, sizeof(addr));
113    addr.sun_family = AF_UNIX;
114    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
115
116    if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
117    {
118        perror("TermThreadFun bind error");
119        goto finish;
120    }
121
122    if (listen(fd, 1) == -1)
123    {
124        perror("TermThreadFun listen error");
125        goto finish;
126    }
127
128    FD_ZERO(&readfds);
129    FD_SET(g_pfd[0], &readfds);
130    FD_SET(fd, &readfds);
131   
132    nfds = fd > g_pfd[0] ? fd + 1 : g_pfd[0] + 1;
133   
134    while (select(nfds, &readfds, NULL, NULL, NULL) == -1
135           && errno == EINTR)
136    {
137        /* Restart if interrupted by signal */
138        continue;
139    }
140   
141    if (FD_ISSET(fd, &readfds))
142    {
143        pthread_mutex_lock(&playbackStartMtx);
144        PlaybackDieNow(1);
145        if (isPlaybackStarted)
146            TerminateAllSockets();
147        else
148            kill(getpid(), SIGINT);
149        pthread_mutex_unlock(&playbackStartMtx);
150    }
151
152finish:
153    close(cl);
154    close(fd);
155    pthread_exit(NULL);
156   
157}
158
159static void map_inter_file_path(char *filename)
160{
161    if (0 == strncmp(filename, "iptv://", 7))
162    {
163        FILE *f = fopen(filename + 7, "r");
164        if (NULL != f)
165        {
166            size_t num = fread(filename, 1, IPTV_MAX_FILE_PATH-1, f);
167            fclose(f);
168            if (num > 0 && filename[num-1] == '\n')
169            {
170                filename[num-1] = '\0';
171            }
172            else
173            {
174                filename[num] = '\0';
175            }
176        }
177    }
178}
179
180static int kbhit(void)
181{
182    struct timeval tv;
183    fd_set readfds;
184
185    tv.tv_sec = 1;
186    tv.tv_usec = 0;
187
188    FD_ZERO(&readfds);
189    FD_SET(0,&readfds);
190    FD_SET(g_pfd[0], &readfds);
191
192    if(-1 == select(g_pfd[0] + 1, &readfds, NULL, NULL, &tv))
193    {
194        return 0;
195    }
196
197    if(FD_ISSET(0, &readfds))
198    {
199        return 1;
200    }
201
202    return 0;
203}
204
205static void SetBuffering()
206{
207    static char buff[2048];
208    memset( buff, '\0', sizeof(buff));
209    if( setvbuf(stderr, buff, _IOLBF, sizeof(buff)) )
210    {
211        printf("SetBuffering: failed to change the buffer of stderr\n");
212    }
213   
214    // make fgets not blocking
215    int flags = fcntl(stdin->_fileno, F_GETFL, 0);
216    fcntl(stdin->_fileno, F_SETFL, flags | O_NONBLOCK);
217}
218
219static void SetNice(int prio)
220{
221#if 0
222    setpriority(PRIO_PROCESS, 0, -8);
223   
224    int prio = sched_get_priority_max(SCHED_RR) / 2;
225    struct sched_param param = {
226        .sched_priority = prio
227    };
228    sched_setscheduler(0, SCHED_RR, &param);
229#else
230    int prevPrio = getpriority(PRIO_PROCESS, 0);
231    if (-1 == setpriority(PRIO_PROCESS, 0, prio))
232    {
233        printf("setpriority - failed\n");
234    }
235#endif
236}
237
238static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbackSwitchCmd, const char *argvBuff)
239{
240    int commandRetVal = 0;
241   
242    if (NULL == ptrManager || NULL == argvBuff || 2 != strnlen(argvBuff, 2))
243    {
244        return -1;
245    }
246   
247    switch (argvBuff[1])
248    {
249        case 'l':
250        {
251            TrackDescription_t *TrackList = NULL;
252            ptrManager->Command(g_player, MANAGER_LIST, &TrackList);
253            if( NULL != TrackList)
254            {
255                int i = 0;
256                fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
257                for (i = 0; TrackList[i].Id >= 0; ++i)
258                {
259                    if(0 < i)
260                    {
261                        fprintf(stderr, ", ");
262                    }
263                    fprintf(stderr, "{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}", TrackList[i].Id , TrackList[i].Encoding, TrackList[i].Name);
264                    free(TrackList[i].Encoding);
265                    free(TrackList[i].Name);
266                }
267                fprintf(stderr, "]}\n");
268                free(TrackList);
269            }
270            else
271            {
272                // not tracks
273                fprintf(stderr, "{\"%c_%c\": []}\n", argvBuff[0], argvBuff[1]);
274            }
275            break;
276        }
277        case 'c':
278        {
279           
280            TrackDescription_t *track = NULL;
281            ptrManager->Command(g_player, MANAGER_GET_TRACK_DESC, &track);
282            if (NULL != track)
283            {
284                if ('a' == argvBuff[0] || 's' == argvBuff[0])
285                {
286                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name);
287                }
288                else // video
289                {
290                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d,\"an\":%d,\"ad\":%d}}\n", \
291                    argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name, track->width, track->height, track->frame_rate, track->progressive, track->aspect_ratio_num, track->aspect_ratio_den);
292                }
293                free(track->Encoding);
294                free(track->Name);
295                free(track);
296            }
297            else
298            {
299                // no tracks
300                if ('a' == argvBuff[0] || 's' == argvBuff[0])
301                {
302                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], -1, "", "");
303                }
304                else // video
305                {
306                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d}}\n", argvBuff[0], argvBuff[1], -1, "", "", -1, -1, 0, -1);
307                }
308            }
309            break;
310        }
311        default:
312        {
313            /* switch command available only for audio and subtitle tracks */
314            if ('a' == argvBuff[0] || 's' == argvBuff[0])
315            {
316                int ok = 0;
317                int id = -1;
318                if ('i' == argvBuff[1])
319                {
320                    int idx = -1;
321                    ok = sscanf(argvBuff+2, "%d", &idx);
322                    if (idx >= 0)
323                    {
324                        TrackDescription_t *TrackList = NULL;
325                        ptrManager->Command(g_player, MANAGER_LIST, &TrackList);
326                        if( NULL != TrackList)
327                        {
328                            int i = 0;
329                            for (i = 0; TrackList[i].Id >= 0; ++i)
330                            {
331                                if (idx == i)
332                                {
333                                    id = TrackList[i].Id;
334                                }
335                                free(TrackList[i].Encoding);
336                                free(TrackList[i].Name);
337                            }
338                            free(TrackList);
339                        }
340                    }
341                    else
342                    {
343                        id = idx;
344                    }
345                }
346                else
347                {
348                    ok = sscanf(argvBuff+1, "%d", &id);
349                }
350               
351                if(id >= 0 || (1 == ok && id == -1))
352                {
353                    commandRetVal = g_player->playback->Command(g_player, playbackSwitchCmd, (void*)&id);
354                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"sts\":%d}}\n", argvBuff[0], 's', id, commandRetVal);
355                }
356            }
357            break;
358        }
359    }
360   
361    return commandRetVal;
362}
363
364static void UpdateVideoTrack()
365{
366    HandleTracks(g_player->manager->video, (PlaybackCmd_t)-1, "vc");
367}
368
369static int ParseParams(int argc,char* argv[], PlayFiles_t *playbackFiles, int *pAudioTrackIdx, int *subtitleTrackIdx, uint32_t *linuxDvbBufferSizeMB)
370{   
371    int ret = 0;
372    int c;
373    int digit_optind = 0;
374    int aopt = 0, bopt = 0;
375    char *copt = 0, *dopt = 0;
376    while ( (c = getopt(argc, argv, "we3dlsrimva:n:x:u:c:h:o:p:P:t:9:0:1:4:f:b:F:S:O:")) != -1)
377    {
378        switch (c)
379        {
380        case 'a':
381        {
382            int flag = atoi(optarg);
383            printf("Software decoder will be used for AAC codec\n");
384            aac_software_decoder_set(flag & 0x01);
385            aac_latm_software_decoder_set(flag & 0x02);
386            break;
387        }
388        case 'e':
389            printf("Software decoder will be used for EAC3 codec\n");
390            eac3_software_decoder_set(1);
391            break;
392        case '3':
393            printf("Software decoder will be used for AC3 codec\n");
394            ac3_software_decoder_set(1);
395            break;
396        case 'd':
397            printf("Software decoder will be used for DTS codec\n");
398            dts_software_decoder_set(1);
399            break;
400        case 'm':
401            printf("Software decoder will be used for MP3 codec\n");
402            mp3_software_decoder_set(1);
403            break;
404        case 'w':
405            printf("Software decoder will be used for WMA codec\n");
406            wma_software_decoder_set(1);
407            break;
408        case 'l':
409            printf("Audio software decoding as LPCM\n");
410            insert_pcm_as_lpcm_set(1);
411            break;
412        case 's':
413            printf("Software decoder will decode to stereo\n");
414            stereo_software_decoder_set(1);
415            break;
416        case 'r':
417            printf("Software decoder do not use PCM resampling\n");
418            pcm_resampling_set(0);
419            break;
420        case 'o':
421            printf("Set progressive download to %d\n", atoi(optarg));
422            progressive_playback_set(atoi(optarg));
423            break;
424        case 'p':
425            SetNice(atoi(optarg));
426            break;
427        case 'P':
428            sel_program_id_set(atoi(optarg));
429            break;
430        case 't':
431            *pAudioTrackIdx = atoi(optarg);
432            break;
433        case '9':
434            *subtitleTrackIdx = atoi(optarg);
435            break;
436        case 'x':
437            if (optarg[0] != '\0')
438            {
439                playbackFiles->szSecondFile = malloc(IPTV_MAX_FILE_PATH);
440                playbackFiles->szSecondFile[0] = '\0';
441                strncpy(playbackFiles->szSecondFile, optarg, IPTV_MAX_FILE_PATH-1);
442                playbackFiles->szSecondFile[IPTV_MAX_FILE_PATH] = '\0';
443                map_inter_file_path(playbackFiles->szSecondFile);
444            }
445            break;
446        case 'h':
447            ffmpeg_av_dict_set("headers", optarg, 0);
448            break;
449        case 'u':
450            ffmpeg_av_dict_set("user-agent", optarg, 0);
451            break;
452        case 'c':
453            printf("For now cookies should be set via headers option!\n");
454            ffmpeg_av_dict_set("cookies", optarg, 0);
455            break;
456        case 'i':
457            printf("Play in (infinity) loop.\n");
458            PlaybackHandler.isLoopMode = 1;
459            break;
460        case 'v':
461            printf("Use live TS stream mode.\n");
462            PlaybackHandler.isTSLiveMode = 1;
463            break;
464        case 'n':
465            printf("Force rtmp protocol implementation\n");
466            rtmp_proto_impl_set(atoi(optarg));
467            break;
468        case '0':
469            ffmpeg_av_dict_set("video_rep_index", optarg, 0);
470            break;
471        case '1':
472            ffmpeg_av_dict_set("audio_rep_index", optarg, 0);
473            break;
474        case '4':
475#ifdef HAVE_FLV2MPEG4_CONVERTER
476            flv2mpeg4_converter_set(atoi(optarg));
477#endif
478            break;
479        case 'f':
480        {
481            char *ffopt = strdup(optarg);
482            char *ffval = strchr(ffopt, '=');
483            if (ffval)
484            {
485                *ffval = '\0';
486                ffval += 1;
487                ffmpeg_av_dict_set(ffopt, ffval, 0);
488            }
489            free(ffopt);
490            break;
491        }
492        case 'b':
493            *linuxDvbBufferSizeMB = 1024 * 1024 * atoi(optarg);
494            break;
495        case 'S':
496            playbackFiles->iFirstFileSize = (uint64_t) strtoull(optarg, (char **)NULL, 10);
497            break;
498        case 'O':
499            playbackFiles->iFirstMoovAtomOffset = (uint64_t) strtoull(optarg, (char **)NULL, 10);
500            break;
501        case 'F':
502            if (optarg[0] != '\0')
503            {
504                playbackFiles->szFirstMoovAtomFile = malloc(IPTV_MAX_FILE_PATH);
505                playbackFiles->szFirstMoovAtomFile[0] = '\0';
506                strncpy(playbackFiles->szFirstMoovAtomFile, optarg, IPTV_MAX_FILE_PATH-1);
507                playbackFiles->szFirstMoovAtomFile[IPTV_MAX_FILE_PATH] = '\0';
508                map_inter_file_path(playbackFiles->szFirstMoovAtomFile);
509            }
510            break;
511        default:
512            printf ("?? getopt returned character code 0%o ??\n", c);
513            ret = -1;
514        }
515    }
516   
517    if (0 == ret && optind < argc)
518    {
519        ret = 0;
520        playbackFiles->szFirstFile = malloc(IPTV_MAX_FILE_PATH);
521        playbackFiles->szFirstFile[0] = '\0';
522        if(NULL == strstr(argv[optind], "://"))
523        {
524            strcpy(playbackFiles->szFirstFile, "file://");
525        }
526        strcat(playbackFiles->szFirstFile, argv[optind]);
527        playbackFiles->szFirstFile[IPTV_MAX_FILE_PATH] = '\0';
528        map_inter_file_path(playbackFiles->szFirstFile);
529        printf("file: [%s]\n", playbackFiles->szFirstFile);
530        ++optind;
531    }
532    else
533    {
534        ret = -1;
535    }
536    return ret;
537}
538
539int main(int argc, char* argv[])
540{
541    pthread_t termThread;
542    int isTermThreadStarted = 0;
543   
544    int audioTrackIdx = -1;
545    int subtitleTrackIdx = -1;
546   
547    uint32_t linuxDvbBufferSizeMB = 0;
548   
549    char argvBuff[256];
550    memset(argvBuff, '\0', sizeof(argvBuff));
551    int commandRetVal = -1;
552    /* inform client that we can handle additional commands */
553    fprintf(stderr, "{\"EPLAYER3_EXTENDED\":{\"version\":%d}}\n", 47);
554
555    PlayFiles_t playbackFiles;
556    memset(&playbackFiles, 0x00, sizeof(playbackFiles));
557    if (0 != ParseParams(argc, argv, &playbackFiles, &audioTrackIdx, &subtitleTrackIdx, &linuxDvbBufferSizeMB))
558    {
559        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");
560        printf("[-b size] Linux DVB output buffer size in MB\n");
561        printf("[-a 0|1|2|3] AAC software decoding - 1 bit - AAC ADTS, 2 - bit AAC LATM\n");
562        printf("[-e] EAC3 software decoding\n");
563        printf("[-3] AC3 software decoding\n");
564        printf("[-d] DTS software decoding\n");
565        printf("[-m] MP3 software decoding\n");
566        printf("[-w] WMA1, WMA2, WMA/PRO software decoding\n");
567        printf("[-l] software decoder use LPCM for injection (otherwise wav PCM will be used)\n");
568        printf("[-s] software decoding as stereo [downmix]\n");
569#ifdef HAVE_FLV2MPEG4_CONVERTER
570        printf("[-4 0|1] - disable/enable flv2mpeg4 converter\n");
571#endif
572        printf("[-i] play in infinity loop\n");
573        printf("[-v] switch to live TS stream mode\n");
574        printf("[-n 0|1|2] rtmp force protocol implementation auto(0) native/ffmpeg(1) or librtmp(2)\n");       
575        printf("[-o 0|1] set progressive download\n");
576        printf("[-p value] nice value\n");
577        printf("[-P value] select Program ID from multi-service stream\n");
578        printf("[-t id] audio track ID switched on at start\n");
579        printf("[-9 id] subtitle track ID switched on at start\n");
580        printf("[-h headers] set custom HTTP headers \"Name: value\\r\\nName: value\\r\\n\"\n");
581        printf("[-u user-agent] set custom http User-Agent header\n");
582        printf("[-c cookies] set cookies - not working at now, please use -h instead\n");
583        printf("[-x separateAudioUri]\n");
584        printf("[-0 idx] video MPEG-DASH representation index\n");
585        printf("[-1 idx] audio MPEG-DASH representation index\n");
586        printf("[-f ffopt=ffval] any other ffmpeg option\n");
587        printf("[-F path to additional file with moov atom data (used for mp4 playback in progressive download mode)\n");
588        printf("[-O moov atom offset in the original file (used for mp4 playback in progressive download mode)\n");
589        printf("[-S remote file size (used for mp4 playback in progressive download mode)\n");
590        exit(1);
591    }
592   
593    g_player = malloc(sizeof(Context_t));
594    if(NULL == g_player)
595    {
596        printf("g_player allocate error\n");
597        exit(1);
598    }
599   
600    pthread_mutex_init(&playbackStartMtx, NULL);
601    do
602    {
603        int flags = 0;
604       
605        if (pipe(g_pfd) == -1)
606            break;
607       
608        /* Make read and write ends of pipe nonblocking */
609        if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1)
610            break;
611       
612        /* Make read end nonblocking */
613        flags |= O_NONBLOCK;
614        if (fcntl(g_pfd[0], F_SETFL, flags) == -1)
615            break;
616       
617        if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1)
618            break;
619       
620        /* Make write end nonblocking */
621        flags |= O_NONBLOCK;
622        if (fcntl(g_pfd[1], F_SETFL, flags) == -1)
623            break;
624       
625        if(0 == pthread_create(&termThread, NULL, TermThreadFun, NULL))
626            isTermThreadStarted = 1;
627    } while(0);
628   
629    g_player->playback    = &PlaybackHandler;
630    g_player->output      = &OutputHandler;
631    g_player->container   = &ContainerHandler;
632    g_player->manager     = &ManagerHandler;
633
634    // make sure to kill myself when parent dies
635    prctl(PR_SET_PDEATHSIG, SIGKILL);
636
637    SetBuffering();
638   
639    //Registrating output devices
640    g_player->output->Command(g_player, OUTPUT_ADD, "audio");
641    g_player->output->Command(g_player, OUTPUT_ADD, "video");
642    g_player->output->Command(g_player, OUTPUT_ADD, "subtitle");
643   
644    //Set LINUX DVB additional write buffer size
645    if (linuxDvbBufferSizeMB)
646        g_player->output->Command(g_player, OUTPUT_SET_BUFFER_SIZE, &linuxDvbBufferSizeMB);
647   
648
649    g_player->manager->video->Command(g_player, MANAGER_REGISTER_UPDATED_TRACK_INFO, UpdateVideoTrack);
650    if (strncmp(playbackFiles.szFirstFile, "rtmp", 4) && strncmp(playbackFiles.szFirstFile, "ffrtmp", 4))
651    {
652        g_player->playback->noprobe = 1;
653    }
654
655    commandRetVal = g_player->playback->Command(g_player, PLAYBACK_OPEN, &playbackFiles);
656    fprintf(stderr, "{\"PLAYBACK_OPEN\":{\"OutputName\":\"%s\", \"file\":\"%s\", \"sts\":%d}}\n", g_player->output->Name, playbackFiles.szFirstFile, commandRetVal);
657    if(commandRetVal < 0)
658    {
659        if(NULL != g_player)
660        {
661            free(g_player);
662        }
663        return 10;
664    }
665   
666    {
667        pthread_mutex_lock(&playbackStartMtx);
668        isPlaybackStarted = 1;
669        pthread_mutex_unlock(&playbackStartMtx);
670       
671        commandRetVal = g_player->output->Command(g_player, OUTPUT_OPEN, NULL);
672        fprintf(stderr, "{\"OUTPUT_OPEN\":{\"sts\":%d}}\n", commandRetVal);
673        commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PLAY, NULL);
674        fprintf(stderr, "{\"PLAYBACK_PLAY\":{\"sts\":%d}}\n", commandRetVal);
675       
676        if (g_player->playback->isPlaying)
677        {
678            PlaybackDieNowRegisterCallback(TerminateWakeUp);
679           
680            HandleTracks(g_player->manager->video, (PlaybackCmd_t)-1, "vc");
681            HandleTracks(g_player->manager->audio, (PlaybackCmd_t)-1, "al");
682            if (audioTrackIdx >= 0)
683            {
684                static char cmd[128] = ""; // static to not allocate on stack
685                sprintf(cmd, "ai%d\n", audioTrackIdx);
686                commandRetVal = HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, cmd);
687            }
688            HandleTracks(g_player->manager->audio, (PlaybackCmd_t)-1, "ac");
689           
690            HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t)-1, "sl");
691            if (subtitleTrackIdx >= 0)
692            {
693                static char cmd[128] = ""; // static to not allocate on stack
694                sprintf(cmd, "si%d\n", subtitleTrackIdx);
695                commandRetVal = HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, cmd);
696            }
697            HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t)-1, "sc");
698        }
699
700        while(g_player->playback->isPlaying && 0 == PlaybackDieNow(0))
701        {
702            /* we made fgets non blocking */
703            if( NULL == fgets(argvBuff, sizeof(argvBuff)-1 , stdin) )
704            {
705                /* wait for data - max 1s */
706                kbhit();
707                continue;
708            }
709
710            if(0 == argvBuff[0])
711            {
712                continue;
713            }
714           
715            switch(argvBuff[0])
716            {
717            case 'v':
718            {
719                HandleTracks(g_player->manager->video, (PlaybackCmd_t)-1, argvBuff);
720            break;
721            }
722            case 'a':
723            {
724                HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, argvBuff);
725            break;
726            }
727            case 's':
728            {
729                HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, argvBuff);
730            break;
731            }
732            case 'q':
733            {
734                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_STOP, NULL);
735                fprintf(stderr, "{\"PLAYBACK_STOP\":{\"sts\":%d}}\n", commandRetVal);
736                break;
737            }
738            case 'c':
739            {
740                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_CONTINUE, NULL);
741                fprintf(stderr, "{\"PLAYBACK_CONTINUE\":{\"sts\":%d}}\n", commandRetVal);
742                break;
743            }
744            case 'p':
745            {
746                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PAUSE, NULL);
747                fprintf(stderr, "{\"PLAYBACK_PAUSE\":{\"sts\":%d}}\n", commandRetVal);
748                break;
749            }
750            case 'm':
751            {
752                int speed = 0;
753                sscanf(argvBuff+1, "%d", &speed);
754
755                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SLOWMOTION, &speed);
756                fprintf(stderr, "{\"PLAYBACK_SLOWMOTION\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
757                break;
758            }
759            case 'o':
760            {
761                int flags = 0;
762                if( 1 == sscanf(argvBuff+1, "%d", &flags) )
763                {
764                    progressive_playback_set(flags);
765                    fprintf(stderr, "{\"PROGRESSIVE_DOWNLOAD\":{\"flags\":%d, \"sts\":0}}\n", flags);
766                }
767                break;
768            }
769            case 'f':
770            {
771                int speed = 0;
772                sscanf(argvBuff+1, "%d", &speed);
773
774                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTFORWARD, &speed);
775                fprintf(stderr, "{\"PLAYBACK_FASTFORWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
776                break;
777            }
778            case 'b':
779            {
780                int speed = 0;
781                sscanf(argvBuff+1, "%d", &speed);
782
783                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTBACKWARD, &speed);
784                fprintf(stderr, "{\"PLAYBACK_FASTBACKWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
785                break;
786            }
787            case 'g':
788            {
789                int32_t gotoPos = 0;
790                int64_t length = 0;
791                int32_t lengthInt = 0;
792                int64_t sec = 0;
793                int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check
794               
795                sscanf(argvBuff+2, "%d", &gotoPos);
796                if(0 <= gotoPos || force)
797                {
798                    commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length);
799                    fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
800
801                    lengthInt = (int32_t)length;
802                    if(10 <= lengthInt || force)
803                    {
804                        sec = gotoPos;
805                        if(!force && gotoPos >= lengthInt)
806                        {
807                            sec = lengthInt - 10;
808                        }
809                       
810                        commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK_ABS, (void*)&sec);
811                        fprintf(stderr, "{\"PLAYBACK_SEEK_ABS\":{\"sec\":%lld, \"sts\":%d}}\n", sec, commandRetVal);
812                    }
813                }
814                break;
815            }
816            case 'k':
817            {
818                int32_t seek = 0;
819                int64_t length = 0;
820                int32_t lengthInt = 0;
821                int64_t sec = 0;
822                int64_t pts = 0;
823                int32_t CurrentSec = 0;
824                int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check
825               
826                sscanf(argvBuff+2, "%d", &seek);
827               
828                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts);
829                CurrentSec = (int32_t)(pts / 90000);
830                if (0 == commandRetVal)
831                {
832                    fprintf(stderr, "{\"J\":{\"ms\":%lld}}\n", pts / 90, commandRetVal);
833                }
834                if(0 == commandRetVal || force)
835                {                   
836                    commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length);
837                    fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
838                   
839                    lengthInt = (int32_t)length;
840                    if(10 <= lengthInt || force )
841                    {
842                        int32_t ergSec = CurrentSec + seek;
843                        if(!force && 0 > ergSec)
844                        {
845                            sec = CurrentSec * -1; // jump to start position
846                        }
847                        else if(!force && ergSec >= lengthInt)
848                        {
849                            sec = (lengthInt - CurrentSec) - 5;
850                            if(0 < sec)
851                            {
852                                sec = 0; // no jump we are at the end
853                            }
854                        }
855                        else
856                        {
857                            sec = seek;
858                        }
859                    }
860                    commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK, (void*)&sec);
861                    fprintf(stderr, "{\"PLAYBACK_SEEK\":{\"sec\":%lld, \"sts\":%d}}\n", sec, commandRetVal);
862                }
863                break;
864            }
865            case 'l':
866            {
867                int64_t length = 0;
868                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void*)&length);
869                fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
870                break;
871            }
872            case 'j':
873            {
874                int64_t pts = 0;
875                commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts);
876                if (0 == commandRetVal)
877                {
878                    int64_t lastPts = 0;
879                    commandRetVal = 1;
880                    if (g_player->container && g_player->container->selectedContainer)
881                    {
882                        commandRetVal = g_player->container->selectedContainer->Command(g_player->container, CONTAINER_LAST_PTS, &lastPts);
883                    }
884                   
885                    if (0 == commandRetVal && lastPts != INVALID_PTS_VALUE)
886                    {
887                        fprintf(stderr, "{\"J\":{\"ms\":%lld,\"lms\":%lld}}\n", pts / 90, lastPts / 90);
888                    }
889                    else
890                    {
891                        fprintf(stderr, "{\"J\":{\"ms\":%lld}}\n", pts / 90);
892                    }
893                }
894                break;
895            }
896            case 'i':
897            {
898                PlaybackHandler_t *ptrP = g_player->playback;
899                if(ptrP)
900                {
901                    fprintf(stderr, "{\"PLAYBACK_INFO\":{ \"isPlaying\":%s, \"isPaused\":%s, \"isForwarding\":%s, \"isSeeking\":%s, \"isCreationPhase\":%s,", \
902                    DUMP_BOOL(ptrP->isPlaying), DUMP_BOOL(ptrP->isPaused), DUMP_BOOL(ptrP->isForwarding), DUMP_BOOL(ptrP->isSeeking), DUMP_BOOL(ptrP->isCreationPhase) );
903                    fprintf(stderr, "\"BackWard\":%d, \"SlowMotion\":%d, \"Speed\":%d, \"AVSync\":%d,", ptrP->BackWard, ptrP->SlowMotion, ptrP->Speed, ptrP->AVSync);
904                    fprintf(stderr, " \"isVideo\":%s, \"isAudio\":%s, \"isSubtitle\":%s, \"isDvbSubtitle\":%s, \"isTeletext\":%s, \"mayWriteToFramebuffer\":%s, \"abortRequested\":%s }}\n", \
905                    DUMP_BOOL(ptrP->isVideo), DUMP_BOOL(ptrP->isAudio), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(ptrP->abortRequested) );
906                }
907               
908                break;
909            }
910            case 'n':
911            {
912                uint8_t loop = 0;
913                if( '1' == argvBuff[1] || '0' == argvBuff[1] )
914                {
915                    PlaybackHandler_t *ptrP = g_player->playback;
916                    if(ptrP)
917                    {
918                        ptrP->isLoopMode = '1' == argvBuff[1] ? 1 : 0;
919                        fprintf(stderr, "{\"N\":{ \"isLoop\":%s }}\n", DUMP_BOOL(ptrP->isLoopMode));
920                    }
921                }
922                break;
923            }
924           
925            default:
926            {
927                break;
928            }
929            }
930        }
931
932        g_player->output->Command(g_player, OUTPUT_CLOSE, NULL);
933    }
934   
935    if(NULL != g_player)
936    {
937        free(g_player);
938    }
939   
940    if (isTermThreadStarted && 1 == write(g_pfd[1], "x", 1))
941    {
942        pthread_join(termThread, NULL);
943    }
944   
945    pthread_mutex_destroy(&playbackStartMtx);
946   
947    close(g_pfd[0]);
948    close(g_pfd[1]);
949   
950    exit(0);
951}
Note: See TracBrowser for help on using the repository browser.