Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ 2f5ae7bb

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 3
27
#define OPTIONAL_PARAMS 1
28

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

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

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

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

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

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

    
83
        return result;
84
}
85

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

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

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

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

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

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

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

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

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

    
326
        SwitchChannel(&(Channels[SelectedChannel]));
327

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

    
333
                        if(ChunkerPlayerCore_AudioEnded())
334
                                ChunkerPlayerCore_ResetAVQueues();
335

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

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

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

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

    
416
        KILL_PROCESS(P2PProcessHandle);
417

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

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

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

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

    
558
        return 0;
559
}
560

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

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

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

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

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

    
787
        SwitchChannel(&(Channels[SelectedChannel]));
788
}
789

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