Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ 157c26b4

History | View | Annotate | Download (18.8 KB)

1
/*
2
 *  Copyright (c) 2009-2011 Carmelo Daniele, Dario Marchese, Diego Reforgiato, Giuseppe Tropea
3
 *  developed for the Napa-Wine EU project. See www.napa-wine.eu
4
 *
5
 *  This is free software; see lgpl-2.1.txt
6
 */
7

    
8
#include <stdio.h>
9
#include <unistd.h>
10
#include <SDL.h>
11
#include <SDL_mutex.h>
12
#include "player_defines.h"
13
#include <confuse.h>
14
#include "http_default_urls.h"
15
#include "player_defines.h"
16
#include "chunker_player.h"
17
#include "player_gui.h"
18
#include <time.h>
19
#include <getopt.h>
20

    
21
#ifdef PSNR_PUBLICATION
22
#include <event2/event.h>
23
#include <napa_log.h>
24
#endif
25

    
26
#define MANDATORY_PARAMS 1
27

    
28
#ifdef _WIN32
29
#include <windows.h>
30
#endif
31

    
32
static char *audio_codec = "mp2";
33
static char *video_codec = "mpeg4";
34

    
35
int ReadALine(FILE* fp, char* Output, int MaxOutputSize)
36
{
37
    int i=0;
38
    int c;
39
    do
40
    {
41
        c=getc(fp);
42
        if(c=='\r' || c=='\n' || c==EOF)
43
        {
44
            Output[i]=0;
45
            return i;
46
        }
47
        Output[i++]=c;
48
    }
49
    while(c!=EOF);
50
    
51
    return -1;
52
}
53

    
54
int CheckForRepoAddress(char* Param)
55
{
56
        int result = 0;
57
    int i, Found=0;
58

    
59
    if(strncasecmp(Param,"repo_address=",13)==0)
60
    {
61
        result=1;
62
        //find ',' in Param (if exist)
63
        int len=strlen(Param);
64
        char* tmp=(char*)calloc(1,len);
65
        if(tmp)
66
        {
67
            for(i=13;i<len;i++)
68
            {
69
                if(Param[i]==',')
70
                {
71
                    Found=1;
72
                    break;
73
                }
74
                tmp[i-13]=Param[i];
75
            }
76

    
77
            if(i==len || Found) strncpy(RepoAddress,tmp,2048);
78
            free(tmp);
79
        }
80
    }
81

    
82
        return result;
83
}
84

    
85
void sigproc()
86
{
87
        printf("you have pressed ctrl-c, terminating...\n");
88
        quit = 1;
89
}
90

    
91
static void print_usage(int argc, char *argv[])
92
{
93
  fprintf (stderr,
94
    "\nUsage:%s [options]\n"
95
    "\n"
96
    "Mandatory options:\n"
97
    "\t[-c ChannelName]: channel name (from channels.conf)\n"
98
    "Other options:\n"
99
    "\t[-p port]: player http port\n\n"
100
    "\t[-q q_thresh]: playout queue size\n"
101
    "\t[-A audiocodec]\n"
102
    "\t[-V videocodec]\n"
103
    "\t[-t]: log traces (WARNING: old traces will be deleted).\n"
104
    "\t[-s mode]: silent mode (no GUI) (mode=1 audio ON, mode=2 audio OFF, mode=3 audio OFF; P2P OFF).\n\n"
105
    "=======================================================\n", argv[0]
106
    );
107
}
108

    
109
int main(int argc, char *argv[])
110
{
111
        srand ( time(NULL) );
112
        // some initializations
113
        SilentMode = 0;
114
        queue_filling_threshold = 50;
115
        quit = 0;
116
        QueueFillingMode=1;
117
        LogTraces = 0;
118

    
119
#ifdef PSNR_PUBLICATION
120
        repoclient=NULL;
121
        LastTimeRepoPublish.tv_sec=0;
122
        LastTimeRepoPublish.tv_usec=0;
123
        eventbase = event_base_new();
124
        napaInitLog(LOG_DEBUG, NULL, NULL);
125
        repInit("");
126
#endif
127
        
128
#ifndef __WIN32__
129
        static pid_t fork_pid = -1;
130
        P2PProcessHandle=&fork_pid;
131
#else
132
        static PROCESS_INFORMATION ProcessInfo;
133
        ZeroMemory( &ProcessInfo, sizeof(ProcessInfo) );
134
        P2PProcessHandle=&ProcessInfo;
135
#endif
136

    
137
        NChannels = 0;
138
        SelectedChannel = -1;
139
        char firstChannelName[255];
140
        int firstChannelIndex;
141
        
142
        memset((void*)Channels, 0, (MAX_CHANNELS_NUM*sizeof(SChannel)));
143

    
144
        Port = 9876;
145

    
146
        struct MHD_Daemon *daemon = NULL;
147
        SDL_Event event;
148
        OverlayMutex = SDL_CreateMutex();
149
        int mandatories = 0;
150
        
151
        char c;
152
        while ((c = getopt (argc, argv, "q:c:p:A:V:s:t")) != -1)
153
        {
154
                switch (c) {
155
                        case 0: //for long options
156
                                break;
157
                        case 'q':
158
                                sscanf(optarg, "%d", &queue_filling_threshold);
159
                                break;
160
                        case 'c':
161
                                sprintf(firstChannelName, "%s", optarg);
162
                                mandatories++;
163
                                break;
164
                        case 'p':
165
                                sscanf(optarg, "%d", &Port);
166
                                break;
167
                        case 'A':
168
                                audio_codec = strdup(optarg);
169
                                break;
170
                        case 'V':
171
                                video_codec = strdup(optarg);
172
                                break;
173
                        case 's':
174
                                sscanf(optarg, "%d", &SilentMode);
175
                                break;
176
                        case 't':
177
                                DELETE_DIR("traces");
178
                                CREATE_DIR("traces");
179
                                LogTraces = 1;
180
                                break;
181
                        default:
182
                                print_usage(argc, argv);
183
                                return -1;
184
                }
185
        }
186
        if(mandatories < MANDATORY_PARAMS)
187
        {
188
                print_usage(argc, argv);
189
                return -1;
190
        }
191

    
192
#ifdef EMULATE_CHUNK_LOSS
193
        ScheduledChunkLosses = NULL;
194
        cfg_opt_t scheduled_chunk_loss_opts[] =
195
        {
196
                CFG_INT("Time", 0, CFGF_NONE),
197
                CFG_INT("Value", 0, CFGF_NONE),
198
                CFG_INT("MinValue", 0, CFGF_NONE),
199
                CFG_INT("MaxValue", 0, CFGF_NONE),
200
                CFG_INT("Burstiness", 0, CFGF_NONE),
201
                CFG_END()
202
        };
203
        cfg_opt_t opts[] =
204
        {
205
                CFG_SEC("ScheduledChunkLoss", scheduled_chunk_loss_opts, CFGF_MULTI),
206
                CFG_END()
207
        };
208
        cfg_t *cfg, *cfg_sched;
209
        cfg = cfg_init(opts, CFGF_NONE);
210
        if(!cfg_parse(cfg, "_chunklossrate.conf") == CFG_PARSE_ERROR)
211
        {
212
                NScheduledChunkLosses = cfg_size(cfg, "ScheduledChunkLoss");
213
                if(NScheduledChunkLosses > 0)
214
                        ScheduledChunkLosses = (SChunkLoss*)malloc((NScheduledChunkLosses)*sizeof(SChunkLoss));
215
                
216
                int j;
217
                for(j = 0; j < cfg_size(cfg, "ScheduledChunkLoss"); j++)
218
                {
219
                        cfg_sched = cfg_getnsec(cfg, "ScheduledChunkLoss", j);
220
                        ScheduledChunkLosses[j].Time = cfg_getint(cfg_sched, "Time");
221
                        ScheduledChunkLosses[j].Value = cfg_getint(cfg_sched, "Value");
222
                        ScheduledChunkLosses[j].Burstiness = cfg_getint(cfg_sched, "Burstiness");
223
                        
224
                        // -1 means random value between min and max
225
                        if(ScheduledChunkLosses[j].Value == -1)
226
                        {
227
                                ScheduledChunkLosses[j].MinValue = cfg_getint(cfg_sched, "MinValue");
228
                                ScheduledChunkLosses[j].MaxValue = cfg_getint(cfg_sched, "MaxValue");
229
                        }
230
                }
231
                cfg_free(cfg);
232
                CurrChunkLossIndex = -1;
233
                
234
                for(j=0; j < NScheduledChunkLosses; j++)
235
                {
236
                        printf("ScheduledChunkLosses[%d].Time = %ld\n", j, ScheduledChunkLosses[j].Time);
237
                        printf("ScheduledChunkLosses[%d].Value = %d\n", j, ScheduledChunkLosses[j].Value);
238
                        printf("ScheduledChunkLosses[%d].Burstiness = %d\n", j, ScheduledChunkLosses[j].Burstiness);
239
                }
240
        }
241
#endif
242

    
243
#ifdef HTTPIO
244
        //this thread fetches chunks from the network by listening to the following path, port
245
        daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, Port);
246
        if(daemon == NULL)
247
        {
248
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
249
                exit(2);
250
        }
251
#endif
252
#ifdef TCPIO
253
        int fd = initChunkPuller(Port);
254
        if(! (fd > 0))
255
        {
256
                printf("CANNOT START TCP PULLER...\n");
257
                exit(2);
258
        }
259
#endif
260

    
261
        if(SilentMode == 0)
262
        {
263
                if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
264
                        fprintf(stderr, "Could not initialize SDL audio/video or timer - %s\n", SDL_GetError());
265
                        return -1;
266
                }
267
        }
268
        else if(SilentMode == 1)
269
        {
270
                if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
271
                        fprintf(stderr, "Could not initialize SDL audio or timer - %s\n", SDL_GetError());
272
                        return -1;
273
                }
274
        }
275
        else
276
        {
277
                if(SDL_Init(SDL_INIT_TIMER)) {
278
                        fprintf(stderr, "Could not initialize SDL timer - %s\n", SDL_GetError());
279
                        return -1;
280
                }
281
        }
282
        
283
        if(ParseConf())
284
        {
285
                printf("ERROR: Cannot parse configuration file, exit...\n");
286
                exit(1);
287
        }
288
        
289
        firstChannelIndex = -1;
290
        int it;
291
        for(it = 0; it < NChannels; it++)
292
        {
293
                if(!strcmp(Channels[it].Title, firstChannelName))
294
                {
295
                        firstChannelIndex = it;
296
                        break;
297
                }
298
        }
299
        
300
        if(firstChannelIndex < 0)
301
        {
302
                printf("Cannot find the specified channel (%s) into the configuration file (channels.conf), exiting\n", firstChannelName);
303
                exit(0);
304
        }
305
        
306
        if(ChunkerPlayerGUI_Init())
307
        {
308
                printf("ERROR: Cannot init player gui, exit...\n");
309
                exit(1);
310
        }
311
        
312
        SelectedChannel = firstChannelIndex;
313

    
314
        SwitchChannel(&(Channels[SelectedChannel]));
315

    
316
        // Wait for user input
317
        while(!quit) {
318
                if(QueueFillingMode) {
319
                        SDL_WM_SetCaption("Filling buffer...", NULL);
320

    
321
                        if(ChunkerPlayerCore_AudioEnded())
322
                                ChunkerPlayerCore_ResetAVQueues();
323

    
324
#ifdef DEBUG_QUEUE
325
                        //printf("QUEUE: MAIN audio:%d video:%d audiolastframe:%d videolastframe:%d\n", audioq.nb_packets, videoq.nb_packets, audioq.last_frame_extracted, videoq.last_frame_extracted);
326
#endif
327
                }
328
                else
329
                        SDL_WM_SetCaption("NAPA-Wine Player", NULL);
330
                
331
#ifdef PSNR_PUBLICATION
332
                event_base_loop(eventbase, EVLOOP_ONCE);
333
#endif
334

    
335
                //listen for key and mouse
336
                while(SDL_PollEvent(&event)) {
337
                        switch(event.type) {
338
                                case SDL_QUIT:
339
                                        quit=1;
340
                                break;
341
                                case SDL_VIDEORESIZE:
342
                                        if(SilentMode)
343
                                                break;
344
                                        // printf("\tSDL_VIDEORESIZE event received!! \n");
345
                                        if(!FullscreenMode)
346
                                                ChunkerPlayerGUI_HandleResize(event.resize.w, event.resize.h);
347
                                        else
348
                                                ChunkerPlayerGUI_HandleResize(FullscreenWidth, FullscreenHeight);
349
                                break;
350
                                case SDL_ACTIVEEVENT:
351
                                        if(SilentMode)
352
                                                break;
353
                                                
354
                                        // if the window was iconified or restored
355
                                        if(event.active.state & SDL_APPACTIVE)
356
                                        {
357
                                                //If the application is being reactivated
358
                                                if( event.active.gain != 0 )
359
                                                {
360
                                                        ChunkerPlayerGUI_HandleGetFocus();
361
                                                }
362
                                        }
363

    
364
                                        //If something happened to the keyboard focus
365
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
366
                                        {
367
                                                //If the application gained keyboard focus
368
                                                if( event.active.gain != 0 )
369
                                                {
370
                                                        ChunkerPlayerGUI_HandleGetFocus();
371
                                                }
372
                                        }
373
                                        //If something happened to the mouse focus
374
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
375
                                        {
376
                                                //If the application gained mouse focus
377
                                                if( event.active.gain != 0 )
378
                                                {
379
                                                        ChunkerPlayerGUI_HandleGetFocus();
380
                                                }
381
                                        }
382
                                        break;
383
                                case SDL_MOUSEMOTION:
384
                                        if(SilentMode)
385
                                                break;
386
                                                
387
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
388
                                break;
389
                                case SDL_MOUSEBUTTONUP:
390
                                        if(SilentMode)
391
                                                break;
392
                                                
393
                                        if( event.button.button != SDL_BUTTON_LEFT )
394
                                                break;
395

    
396
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
397
                                break;
398
                        }
399
                        ChunkerPlayerGUI_HandleKey();
400
                }
401
                usleep(120000);
402
        }
403

    
404
        KILL_PROCESS(P2PProcessHandle);
405

    
406
        //TERMINATE
407
        ChunkerPlayerCore_Stop();
408
        if(YUVOverlay != NULL)
409
                SDL_FreeYUVOverlay(YUVOverlay);
410
        
411
        ChunkerPlayerGUI_Close();
412
        SDL_DestroyMutex(OverlayMutex);
413
        SDL_Quit();
414
        
415
#ifdef HTTPIO
416
        finalizeChunkPuller(daemon);
417
#endif
418
#ifdef TCPIO
419
        finalizeChunkPuller();
420
#endif
421
        
422
#ifdef EMULATE_CHUNK_LOSS
423
        if(ScheduledChunkLosses)
424
                free(ScheduledChunkLosses);
425
#endif
426

    
427
#ifdef PSNR_PUBLICATION
428
        if(repoclient) repClose(repoclient);
429
        event_base_free(eventbase);
430
#endif
431
        return 0;
432
}
433

    
434
int cb_validate_conffile(cfg_t *cfg)
435
{
436
        char LaunchString[255];
437
        cfg_t *cfg_greet;
438
        
439
        if(cfg_size(cfg, "Channel") == 0)
440
        {
441
                cfg_error(cfg, "no \"Channel\" section found");
442
                return -1;
443
        }
444
        
445
        printf("\t%d Channel setions found\n", cfg_size(cfg, "Channel"));
446
        
447
        int j;
448
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
449
        {
450
                cfg_greet = cfg_getnsec(cfg, "Channel", j);
451
                sprintf(LaunchString, "%s", cfg_getstr(cfg_greet, "LaunchString"));
452
                if(!(strlen(LaunchString) > 0))
453
                {
454
                        cfg_error(cfg, "invalid LaunchString for Channel[%d]", j);
455
                        return -1;
456
                }
457
                printf("\tChannel[%d].LaunchString = %s\n", j, LaunchString);
458
                printf("\tChannel[%d].AudioChannels = %ld\n", j, cfg_getint(cfg_greet, "AudioChannels"));
459
                printf("\tChannel[%d].SampleRate = %ld\n", j, cfg_getint(cfg_greet, "SampleRate"));
460
                printf("\tChannel[%d].Width = %ld\n", j, cfg_getint(cfg_greet, "Width"));
461
                printf("\tChannel[%d].Height = %ld\n", j, cfg_getint(cfg_greet, "Height"));
462
                printf("\tChannel[%d].Bitrate = %ld\n", j, cfg_getint(cfg_greet, "Bitrate"));
463
                printf("\tChannel[%d].Ratio = %s\n", j, cfg_getstr(cfg_greet, "Ratio"));
464
        }
465
    return 0;
466
}
467

    
468
int ParseConf()
469
{
470
        int j;
471
        
472
        // PARSING CONF FILE
473
        cfg_opt_t channel_opts[] =
474
        {
475
                CFG_STR("Title", "", CFGF_NONE),
476
                CFG_STR("LaunchString", "", CFGF_NONE),
477
                CFG_INT("AudioChannels", 2, CFGF_NONE),
478
                CFG_INT("SampleRate", 48000, CFGF_NONE),
479
                CFG_INT("Width", 176, CFGF_NONE),
480
                CFG_INT("Height", 144, CFGF_NONE),
481
                CFG_INT("Bitrate", 0, CFGF_NONE),
482
                
483
                // for some reason libconfuse parsing for floating point does not work in windows
484
                //~ CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
485
                CFG_STR("Ratio", "1.22", CFGF_NONE),
486
                CFG_END()
487
        };
488
        cfg_opt_t opts[] =
489
        {
490
                CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
491
                CFG_END()
492
        };
493
        cfg_t *cfg, *cfg_channel;
494
        cfg = cfg_init(opts, CFGF_NONE);
495
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_PARSE_ERROR)
496
        {
497
                printf("Error while parsing configuration file, exiting...\n");
498
                cb_validate_conffile(cfg);
499
                return 1;
500
        }
501
        
502
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_FILE_ERROR)
503
        {
504
                printf("Error trying parsing configuration file. '%s' file couldn't be opened for reading\n", DEFAULT_CONF_FILENAME);
505
                return 1;
506
        }
507
        
508
        FILE * tmp_file;
509
        if(tmp_file = fopen(DEFAULT_PEEREXECNAME_FILENAME, "r")) {
510
                if(fscanf(tmp_file, "%s", StreamerFilename) != 1) {
511
                        printf("Wrong format of conf file %s containing peer application exec name. Assuming default: %s.\n\n", DEFAULT_PEEREXECNAME_FILENAME, DEFAULT_PEER_EXEC_NAME);
512
                }
513
                fclose(tmp_file);
514
        }
515
        else {
516
                printf("Could not find conf file %s containing peer application exec name. Exiting.\n\n", DEFAULT_PEEREXECNAME_FILENAME);
517
                exit(1);
518
        }
519
        if(tmp_file = fopen(StreamerFilename, "r"))
520
    {
521
        fclose(tmp_file);
522
    }
523
    else
524
        {
525
                printf("Could not find peer application (named '%s') into the current folder, please copy or link it into the player folder, then retry\n\n", StreamerFilename);
526
                exit(1);
527
        }
528
        
529
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
530
        {
531
                cfg_channel = cfg_getnsec(cfg, "Channel", j);
532
                sprintf(Channels[j].Title, "%s", cfg_title(cfg_channel));
533
                strcpy(Channels[j].LaunchString, cfg_getstr(cfg_channel, "LaunchString"));
534
                Channels[j].Width = cfg_getint(cfg_channel, "Width");
535
                Channels[j].Height = cfg_getint(cfg_channel, "Height");
536
                Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
537
                Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
538
                Channels[j].Ratio = strtof(cfg_getstr(cfg_channel, "Ratio"), 0);
539
                Channels[j].Bitrate = cfg_getint(cfg_channel, "Bitrate");
540
                
541
                Channels[j].Index = j+1;
542
                NChannels++;
543
        }
544
        cfg_free(cfg);
545

    
546
        return 0;
547
}
548

    
549
int ReTune(SChannel* channel)
550
{        
551
        if(ChunkerPlayerCore_IsRunning())
552
                ChunkerPlayerCore_Pause();
553
        
554
        //reset quality info
555
        channel->startTime = time(NULL);
556
        
557
        ChunkerPlayerCore_Play();
558
        
559
        return 0;
560
}
561

    
562
int SwitchChannel(SChannel* channel)
563
{
564
        int i=0;
565
#ifdef RESTORE_SCREEN_ON_ZAPPING
566
        int was_fullscreen = FullscreenMode;
567
        int old_width = window_width, old_height = window_height;
568
#endif
569
        
570
        if(ChunkerPlayerCore_IsRunning())
571
                ChunkerPlayerCore_Stop();
572

    
573
    KILL_PROCESS(P2PProcessHandle);
574
#ifdef PSNR_PUBLICATION
575
        remove("NetworkID");
576
#endif
577
        
578
        ratio = channel->Ratio;
579
        ChunkerPlayerGUI_SetChannelTitle(channel->Title);
580
        ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
581
        
582
        int w=0, h=0;
583
        ChunkerPlayerGUI_AspectRatioResize((float)channel->Ratio, channel->Width, channel->Height, &w, &h);
584
        ChunkerPlayerCore_SetupOverlay(w, h);
585
        //ChunkerPlayerGUI_SetupOverlayRect(channel);
586
        
587
        if(ChunkerPlayerCore_InitCodecs(video_codec, channel->Width, channel->Height, audio_codec, channel->SampleRate, channel->AudioChannels) < 0)
588
        {
589
                printf("ERROR, COULD NOT INITIALIZE CODECS\n");
590
                exit(2);
591
        }
592
        
593
        //reset quality info
594
        channel->startTime = time(NULL);
595
        channel->instant_score = 0.0;
596
        channel->average_score = 0.0;
597
        channel->history_index = 0;
598
        for(i=0; i<CHANNEL_SCORE_HISTORY_SIZE; i++)
599
                channel->score_history[i] = -1;
600
        sprintf(channel->quality, "EVALUATING...");
601
        
602
        char argv0[255], parameters_string[511];
603
        sprintf(argv0, "%s", StreamerFilename);
604

    
605
#ifdef HTTPIO
606
        sprintf(parameters_string, "%s %s %s %d %s %s %d", "-C", channel->Title, "-P", (Port+channel->Index), channel->LaunchString, "-F", Port);
607
#endif
608

    
609
#ifdef TCPIO
610
        sprintf(parameters_string, "%s %s %s %d %s %s tcp://127.0.0.1:%d", "-C", channel->Title, "-P", (Port+channel->Index), channel->LaunchString, "-F", Port);
611
#endif
612

    
613
        printf("OFFERSTREAMER LAUNCH STRING: %s %s\n", argv0, parameters_string);
614

    
615
        char* parameters_vector[255];
616
        parameters_vector[0] = argv0;
617
        
618
        RepoAddress[0]='\0';
619
        
620
        // split parameters and count them
621
        int par_count=1;
622
        char* pch = strtok (parameters_string, " ");
623
        while (pch != NULL)
624
        {
625
                if(par_count > 255) break;
626
                // printf ("\tpch=%s\n",pch);
627
                parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
628
                strcpy(parameters_vector[par_count], pch);
629
                // Find repo_address
630
            CheckForRepoAddress(parameters_vector[par_count]);
631
                pch = strtok (NULL, " ");
632
                par_count++;
633
        }
634
        parameters_vector[par_count] = NULL;
635

    
636
        if(SilentMode != 3) //mode 3 is without P2P peer process
637
        {
638

    
639
#ifndef __WIN32__
640
                int d;
641
                int stdoutS, stderrS;
642
                FILE* stream;
643
                stream = fopen("/dev/null", "a+");
644
                d = fileno(stream);
645

    
646
                // create backup descriptors for the current stdout and stderr devices
647
                stdoutS = dup(STDOUT_FILENO);
648
                stderrS = dup(STDERR_FILENO);
649
                
650
                // redirect child output to /dev/null
651
                dup2(d, STDOUT_FILENO);
652
                dup2(d, STDERR_FILENO);
653

    
654
                int pid = fork();
655
                if(pid == 0)
656
                {
657
                        execv(argv0, parameters_vector);
658
                        printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
659
                        exit(2);
660
                }
661
                else
662
                        *((pid_t*)P2PProcessHandle) = pid;
663
                
664
                // restore backup descriptors in the parent process
665
                dup2(stdoutS, STDOUT_FILENO);
666
                dup2(stderrS, STDERR_FILENO);
667

    
668
                fclose(stream);
669
#else
670
                STARTUPINFO sti;
671
                SECURITY_ATTRIBUTES sats = { 0 };
672
                DWORD writ, excode, read, available;
673
                int ret = 0;
674

    
675
                //set SECURITY_ATTRIBUTES struct fields
676
                sats.nLength = sizeof(sats);
677
                sats.bInheritHandle = TRUE;
678
                sats.lpSecurityDescriptor = NULL;
679

    
680
                ZeroMemory( &sti, sizeof(sti) );
681
                sti.cb = sizeof(sti);
682
                ZeroMemory( P2PProcessHandle, sizeof(PROCESS_INFORMATION) );
683

    
684
                char buffer[512];
685
                sprintf(buffer, "%s %s", argv0, parameters_string);
686

    
687
                if(!CreateProcess(NULL,
688
                  buffer,
689
                  &sats,
690
                  &sats,
691
                  TRUE,
692
                  0,
693
                  NULL,
694
                  NULL,
695
                  &sti,
696
                  P2PProcessHandle))
697
                {
698
                        printf("Unable to generate process \n");
699
                        return -1;
700
                }
701
#endif
702

    
703
        }
704

    
705
#ifdef RESTORE_SCREEN_ON_ZAPPING
706
        if(SilentMode == 0) {
707
                if(was_fullscreen)
708
                        ChunkerPlayerGUI_ToggleFullscreen();
709
                else
710
                {
711
                        ChunkerPlayerGUI_HandleResize(old_width, old_height);
712
                }
713
        }
714
#endif
715

    
716
#ifdef PSNR_PUBLICATION
717
        if(RepoAddress[0]!='\0')
718
        {
719
            // Open Repository
720
            if(repoclient)
721
                    repClose(repoclient);
722
            repoclient=NULL;
723

    
724
            repoclient = repOpen(RepoAddress,0);
725
            if (repoclient == NULL)
726
                    printf("Unable to initialize PSNR publication in repoclient %s\n", RepoAddress);
727
    }
728
    else {
729
            printf("Repository address not present in streames launch string. Publication disabled\n");
730
    }
731
#endif
732

    
733
        for(i=1; i<par_count; i++)
734
                free(parameters_vector[i]);
735

    
736
#ifdef PSNR_PUBLICATION
737
        // Read the Network ID
738
        int Error=true;
739
        char Line1[255], Line2[255];
740
        while(Error)
741
        {
742
            FILE* fp=fopen("NetworkID","r");
743
            if(fp)
744
            {
745
                if(ReadALine(fp,Line1,255)!=-1)
746
                    if(ReadALine(fp,Line2,255)!=-1)
747
                    {
748
                        if(strcmp(Line2,"IDEnd")==0)
749
                        {
750
                            strcpy(NetworkID,Line1);
751
                            Error=false;
752
                        }
753
                    }
754
                fclose(fp);
755
            }
756
            if(Error) usleep(100000);
757
        }
758
        
759
        printf("NetworkID = %s\n",NetworkID);
760
#endif
761
        
762
        ChunkerPlayerCore_Play();
763
        ChunkerPlayerGUI_ChannelSwitched();
764
        return 0;
765
}
766

    
767
void ZapDown()
768
{
769
        SelectedChannel = ((SelectedChannel+1) %NChannels);
770
        SwitchChannel(&(Channels[SelectedChannel]));
771
}
772

    
773
void ZapUp()
774
{
775
        SelectedChannel--;
776
        if(SelectedChannel < 0)
777
                SelectedChannel = NChannels-1;
778

    
779
        SwitchChannel(&(Channels[SelectedChannel]));
780
}
781

    
782
int enqueueBlock(const uint8_t *block, const int block_size)
783
{
784
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
785
}