Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ 5fd002d4

History | View | Annotate | Download (18.9 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 2
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
    "\t[-p port]: player http port\n\n"
99
    "Other options:\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
#ifdef HTTPIO
145
        Port = -1;
146
#endif
147
#ifdef TCPIO
148
        Port = -1;
149
#endif
150
        struct MHD_Daemon *daemon = NULL;
151
        SDL_Event event;
152
        OverlayMutex = SDL_CreateMutex();
153
        int mandatories = 0;
154
        
155
        char c;
156
        while ((c = getopt (argc, argv, "q:c:p:A:V:s:t")) != -1)
157
        {
158
                switch (c) {
159
                        case 0: //for long options
160
                                break;
161
                        case 'q':
162
                                sscanf(optarg, "%d", &queue_filling_threshold);
163
                                break;
164
                        case 'c':
165
                                sprintf(firstChannelName, "%s", optarg);
166
                                mandatories++;
167
                                break;
168
                        case 'p':
169
#ifdef HTTPIO
170
                                sscanf(optarg, "%d", &Port);
171
#endif
172
#ifdef TCPIO
173
                                sscanf(optarg, "%d", &Port);
174
#endif
175
                                mandatories++;
176
                                break;
177
                        case 'A':
178
                                audio_codec = strdup(optarg);
179
                                break;
180
                        case 'V':
181
                                video_codec = strdup(optarg);
182
                                break;
183
                        case 's':
184
                                sscanf(optarg, "%d", &SilentMode);
185
                                break;
186
                        case 't':
187
                                DELETE_DIR("traces");
188
                                CREATE_DIR("traces");
189
                                LogTraces = 1;
190
                                break;
191
                        default:
192
                                print_usage(argc, argv);
193
                                return -1;
194
                }
195
        }
196
        if(mandatories < MANDATORY_PARAMS)
197
        {
198
                print_usage(argc, argv);
199
                return -1;
200
        }
201

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

    
253
#ifdef HTTPIO
254
        //this thread fetches chunks from the network by listening to the following path, port
255
        daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, Port);
256
        if(daemon == NULL)
257
        {
258
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
259
                exit(2);
260
        }
261
#endif
262
#ifdef TCPIO
263
        int fd = initChunkPuller(Port);
264
        if(! (fd > 0))
265
        {
266
                printf("CANNOT START TCP PULLER...\n");
267
                exit(2);
268
        }
269
#endif
270

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

    
324
        SwitchChannel(&(Channels[SelectedChannel]));
325

    
326
        // Wait for user input
327
        while(!quit) {
328
                if(QueueFillingMode) {
329
                        SDL_WM_SetCaption("Filling buffer...", NULL);
330

    
331
                        if(ChunkerPlayerCore_AudioEnded())
332
                                ChunkerPlayerCore_ResetAVQueues();
333

    
334
#ifdef DEBUG_QUEUE
335
                        //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);
336
#endif
337
                }
338
                else
339
                        SDL_WM_SetCaption("NAPA-Wine Player", NULL);
340
                
341
#ifdef PSNR_PUBLICATION
342
                event_base_loop(eventbase, EVLOOP_ONCE);
343
#endif
344

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

    
374
                                        //If something happened to the keyboard focus
375
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
376
                                        {
377
                                                //If the application gained keyboard focus
378
                                                if( event.active.gain != 0 )
379
                                                {
380
                                                        ChunkerPlayerGUI_HandleGetFocus();
381
                                                }
382
                                        }
383
                                        //If something happened to the mouse focus
384
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
385
                                        {
386
                                                //If the application gained mouse focus
387
                                                if( event.active.gain != 0 )
388
                                                {
389
                                                        ChunkerPlayerGUI_HandleGetFocus();
390
                                                }
391
                                        }
392
                                        break;
393
                                case SDL_MOUSEMOTION:
394
                                        if(SilentMode)
395
                                                break;
396
                                                
397
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
398
                                break;
399
                                case SDL_MOUSEBUTTONUP:
400
                                        if(SilentMode)
401
                                                break;
402
                                                
403
                                        if( event.button.button != SDL_BUTTON_LEFT )
404
                                                break;
405

    
406
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
407
                                break;
408
                        }
409
                        ChunkerPlayerGUI_HandleKey();
410
                }
411
                usleep(120000);
412
        }
413

    
414
        KILL_PROCESS(P2PProcessHandle);
415

    
416
        //TERMINATE
417
        ChunkerPlayerCore_Stop();
418
        if(YUVOverlay != NULL)
419
                SDL_FreeYUVOverlay(YUVOverlay);
420
        
421
        ChunkerPlayerGUI_Close();
422
        SDL_DestroyMutex(OverlayMutex);
423
        SDL_Quit();
424
        
425
#ifdef HTTPIO
426
        finalizeChunkPuller(daemon);
427
#endif
428
#ifdef TCPIO
429
        finalizeChunkPuller();
430
#endif
431
        
432
#ifdef EMULATE_CHUNK_LOSS
433
        if(ScheduledChunkLosses)
434
                free(ScheduledChunkLosses);
435
#endif
436

    
437
#ifdef PSNR_PUBLICATION
438
        if(repoclient) repClose(repoclient);
439
        event_base_free(eventbase);
440
#endif
441
        return 0;
442
}
443

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

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

    
556
        return 0;
557
}
558

    
559
int ReTune(SChannel* channel)
560
{        
561
        if(ChunkerPlayerCore_IsRunning())
562
                ChunkerPlayerCore_Pause();
563
        
564
        //reset quality info
565
        channel->startTime = time(NULL);
566
        
567
        ChunkerPlayerCore_Play();
568
        
569
        return 0;
570
}
571

    
572
int SwitchChannel(SChannel* channel)
573
{
574
        int i=0;
575
#ifdef RESTORE_SCREEN_ON_ZAPPING
576
        int was_fullscreen = FullscreenMode;
577
        int old_width = window_width, old_height = window_height;
578
#endif
579
        
580
        if(ChunkerPlayerCore_IsRunning())
581
                ChunkerPlayerCore_Stop();
582

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

    
615
#ifdef HTTPIO
616
        sprintf(parameters_string, "%s %s %s %d %s %s %d", "-C", channel->Title, "-P", (Port+channel->Index), channel->LaunchString, "-F", Port);
617
#endif
618

    
619
#ifdef TCPIO
620
        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);
621
#endif
622

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

    
625
        char* parameters_vector[255];
626
        parameters_vector[0] = argv0;
627
        
628
        RepoAddress[0]='\0';
629
        
630
        // split parameters and count them
631
        int par_count=1;
632
        char* pch = strtok (parameters_string, " ");
633
        while (pch != NULL)
634
        {
635
                if(par_count > 255) break;
636
                // printf ("\tpch=%s\n",pch);
637
                parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
638
                strcpy(parameters_vector[par_count], pch);
639
                // Find repo_address
640
            CheckForRepoAddress(parameters_vector[par_count]);
641
                pch = strtok (NULL, " ");
642
                par_count++;
643
        }
644
        parameters_vector[par_count] = NULL;
645

    
646
        if(SilentMode != 3) //mode 3 is without P2P peer process
647
        {
648

    
649
#ifndef __WIN32__
650
                int d;
651
                int stdoutS, stderrS;
652
                FILE* stream;
653
                stream = fopen("/dev/null", "a+");
654
                d = fileno(stream);
655

    
656
                // create backup descriptors for the current stdout and stderr devices
657
                stdoutS = dup(STDOUT_FILENO);
658
                stderrS = dup(STDERR_FILENO);
659
                
660
                // redirect child output to /dev/null
661
                dup2(d, STDOUT_FILENO);
662
                dup2(d, STDERR_FILENO);
663

    
664
                int pid = fork();
665
                if(pid == 0)
666
                {
667
                        execv(argv0, parameters_vector);
668
                        printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
669
                        exit(2);
670
                }
671
                else
672
                        *((pid_t*)P2PProcessHandle) = pid;
673
                
674
                // restore backup descriptors in the parent process
675
                dup2(stdoutS, STDOUT_FILENO);
676
                dup2(stderrS, STDERR_FILENO);
677

    
678
                fclose(stream);
679
#else
680
                STARTUPINFO sti;
681
                SECURITY_ATTRIBUTES sats = { 0 };
682
                DWORD writ, excode, read, available;
683
                int ret = 0;
684

    
685
                //set SECURITY_ATTRIBUTES struct fields
686
                sats.nLength = sizeof(sats);
687
                sats.bInheritHandle = TRUE;
688
                sats.lpSecurityDescriptor = NULL;
689

    
690
                ZeroMemory( &sti, sizeof(sti) );
691
                sti.cb = sizeof(sti);
692
                ZeroMemory( P2PProcessHandle, sizeof(PROCESS_INFORMATION) );
693

    
694
                char buffer[512];
695
                sprintf(buffer, "%s %s", argv0, parameters_string);
696

    
697
                if(!CreateProcess(NULL,
698
                  buffer,
699
                  &sats,
700
                  &sats,
701
                  TRUE,
702
                  0,
703
                  NULL,
704
                  NULL,
705
                  &sti,
706
                  P2PProcessHandle))
707
                {
708
                        printf("Unable to generate process \n");
709
                        return -1;
710
                }
711
#endif
712

    
713
        }
714

    
715
#ifdef RESTORE_SCREEN_ON_ZAPPING
716
        if(SilentMode == 0) {
717
                if(was_fullscreen)
718
                        ChunkerPlayerGUI_ToggleFullscreen();
719
                else
720
                {
721
                        ChunkerPlayerGUI_HandleResize(old_width, old_height);
722
                }
723
        }
724
#endif
725

    
726
#ifdef PSNR_PUBLICATION
727
        if(RepoAddress[0]!='\0')
728
        {
729
            // Open Repository
730
            if(repoclient)
731
                    repClose(repoclient);
732
            repoclient=NULL;
733

    
734
            repoclient = repOpen(RepoAddress,0);
735
            if (repoclient == NULL)
736
                    printf("Unable to initialize PSNR publication in repoclient %s\n", RepoAddress);
737
    }
738
    else {
739
            printf("Repository address not present in streames launch string. Publication disabled\n");
740
    }
741
#endif
742

    
743
        for(i=1; i<par_count; i++)
744
                free(parameters_vector[i]);
745

    
746
#ifdef PSNR_PUBLICATION
747
        // Read the Network ID
748
        int Error=true;
749
        char Line1[255], Line2[255];
750
        while(Error)
751
        {
752
            FILE* fp=fopen("NetworkID","r");
753
            if(fp)
754
            {
755
                if(ReadALine(fp,Line1,255)!=-1)
756
                    if(ReadALine(fp,Line2,255)!=-1)
757
                    {
758
                        if(strcmp(Line2,"IDEnd")==0)
759
                        {
760
                            strcpy(NetworkID,Line1);
761
                            Error=false;
762
                        }
763
                    }
764
                fclose(fp);
765
            }
766
            if(Error) usleep(100000);
767
        }
768
        
769
        printf("NetworkID = %s\n",NetworkID);
770
#endif
771
        
772
        ChunkerPlayerCore_Play();
773
        ChunkerPlayerGUI_ChannelSwitched();
774
        return 0;
775
}
776

    
777
void ZapDown()
778
{
779
        SelectedChannel = ((SelectedChannel+1) %NChannels);
780
        SwitchChannel(&(Channels[SelectedChannel]));
781
}
782

    
783
void ZapUp()
784
{
785
        SelectedChannel--;
786
        if(SelectedChannel < 0)
787
                SelectedChannel = NChannels-1;
788

    
789
        SwitchChannel(&(Channels[SelectedChannel]));
790
}
791

    
792
int enqueueBlock(const uint8_t *block, const int block_size)
793
{
794
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
795
}