Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ 59e008ed

History | View | Annotate | Download (18.2 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 <napa_log.h>
23
#endif
24

    
25
#define MANDATORY_PARAMS 3
26
#define OPTIONAL_PARAMS 1
27

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

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

    
51
int CheckForRepoAddress(char* Param)
52
{
53
        int result = 0;
54
/*
55
    char* pch;
56
    if(strncasecmp(Param,"repo_address=",13)==0)
57
    {
58
        pch=strtok(Param+13,",");
59
        strncpy(RepoAddress,pch,2048);
60
    }
61
*/
62
//strcpy(RepoAddress,"repo-wut.napa-wine.eu:9832");
63
strcpy(RepoAddress,"repository.disi.unitn.it:9832");
64
result = 1;
65

    
66
        return result;
67
}
68

    
69
void sigproc()
70
{
71
        printf("you have pressed ctrl-c, terminating...\n");
72
        quit = 1;
73
}
74

    
75
static void print_usage(int argc, char *argv[])
76
{
77
  fprintf (stderr,
78
    "\nUsage:%s [options]\n"
79
    "\n"
80
    "Mandatory options:\n"
81
    "\t[-q q_thresh]: playout queue size\n"
82
    "\t[-c ChannelName]: channel name (from channels.conf)\n"
83
    "\t[-p port]: player http port\n\n"
84
    "Other options:\n"
85
    "\t[-t]: log traces (WARNING: old traces will be deleted).\n"
86
    "\t[-s mode]: silent mode (no GUI) (mode=1 audio ON, mode=2 audio OFF, mode=3 audio OFF; P2P OFF).\n\n"
87
    "=======================================================\n", argv[0]
88
    );
89
}
90

    
91
int main(int argc, char *argv[])
92
{
93
        srand ( time(NULL) );
94
        // some initializations
95
        SilentMode = 0;
96
        queue_filling_threshold = 0;
97
        quit = 0;
98
        QueueFillingMode=1;
99
        LogTraces = 0;
100

    
101
#ifdef PSNR_PUBLICATION
102
        repoclient=NULL;
103
        LastTimeRepoPublish.tv_sec=0;
104
        LastTimeRepoPublish.tv_usec=0;
105
        eventbase = event_base_new();
106
        napaInitLog(LOG_DEBUG, NULL, NULL);
107
        repInit("");
108
#endif
109
        
110
#ifndef __WIN32__
111
        static pid_t fork_pid = -1;
112
        P2PProcessHandle=&fork_pid;
113
#else
114
        static PROCESS_INFORMATION ProcessInfo;
115
        ZeroMemory( &ProcessInfo, sizeof(ProcessInfo) );
116
        P2PProcessHandle=&ProcessInfo;
117
#endif
118

    
119
        NChannels = 0;
120
        SelectedChannel = -1;
121
        char firstChannelName[255];
122
        int firstChannelIndex;
123
        
124
        memset((void*)Channels, 0, (MAX_CHANNELS_NUM*sizeof(SChannel)));
125

    
126
#ifdef HTTPIO
127
        HttpPort = -1;
128
#endif
129
#ifdef TCPIO
130
        TcpPort = -1;
131
#endif
132
        struct MHD_Daemon *daemon = NULL;
133
        SDL_Event event;
134
        OverlayMutex = SDL_CreateMutex();
135
        int mandatories = 0;
136
        
137
        char c;
138
        while ((c = getopt (argc, argv, "q:c:p:s:t")) != -1)
139
        {
140
                switch (c) {
141
                        case 0: //for long options
142
                                break;
143
                        case 'q':
144
                                sscanf(optarg, "%d", &queue_filling_threshold);
145
                                mandatories++;
146
                                break;
147
                        case 'c':
148
                                sprintf(firstChannelName, "%s", optarg);
149
                                mandatories++;
150
                                break;
151
                        case 'p':
152
#ifdef HTTPIO
153
                                sscanf(optarg, "%d", &HttpPort);
154
#endif
155
#ifdef TCPIO
156
                                sscanf(optarg, "%d", &TcpPort);
157
#endif
158
                                mandatories++;
159
                                break;
160
                        case 's':
161
                                sscanf(optarg, "%d", &SilentMode);
162
                                break;
163
                        case 't':
164
                                DELETE_DIR("traces");
165
                                CREATE_DIR("traces");
166
                                LogTraces = 1;
167
                                break;
168
                        default:
169
                                print_usage(argc, argv);
170
                                return -1;
171
                }
172
        }
173
        if(mandatories < MANDATORY_PARAMS)
174
        {
175
                print_usage(argc, argv);
176
                return -1;
177
        }
178

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

    
230
#ifdef HTTPIO
231
        //this thread fetches chunks from the network by listening to the following path, port
232
        daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, HttpPort);
233
        if(daemon == NULL)
234
        {
235
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
236
                exit(2);
237
        }
238
#endif
239
#ifdef TCPIO
240
        int fd = initChunkPuller(TcpPort);
241
        if(! (fd > 0))
242
        {
243
                printf("CANNOT START TCP PULLER...\n");
244
                exit(2);
245
        }
246
#endif
247

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

    
301
        SwitchChannel(&(Channels[SelectedChannel]));
302

    
303
        // Wait for user input
304
        while(!quit) {
305
                if(QueueFillingMode) {
306
                        SDL_WM_SetCaption("Filling buffer...", NULL);
307

    
308
                        if(ChunkerPlayerCore_AudioEnded())
309
                                ChunkerPlayerCore_ResetAVQueues();
310

    
311
#ifdef DEBUG_QUEUE
312
                        //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);
313
#endif
314
                }
315
                else
316
                        SDL_WM_SetCaption("NAPA-Wine Player", NULL);
317

    
318
                //listen for key and mouse
319
                while(SDL_PollEvent(&event)) {
320
                        switch(event.type) {
321
                                case SDL_QUIT:
322
                                        quit=1;
323
                                break;
324
                                case SDL_VIDEORESIZE:
325
                                        if(SilentMode)
326
                                                break;
327
                                        // printf("\tSDL_VIDEORESIZE event received!! \n");
328
                                        if(!FullscreenMode)
329
                                                ChunkerPlayerGUI_HandleResize(event.resize.w, event.resize.h);
330
                                        else
331
                                                ChunkerPlayerGUI_HandleResize(FullscreenWidth, FullscreenHeight);
332
                                break;
333
                                case SDL_ACTIVEEVENT:
334
                                        if(SilentMode)
335
                                                break;
336
                                                
337
                                        // if the window was iconified or restored
338
                                        if(event.active.state & SDL_APPACTIVE)
339
                                        {
340
                                                //If the application is being reactivated
341
                                                if( event.active.gain != 0 )
342
                                                {
343
                                                        ChunkerPlayerGUI_HandleGetFocus();
344
                                                }
345
                                        }
346

    
347
                                        //If something happened to the keyboard focus
348
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
349
                                        {
350
                                                //If the application gained keyboard focus
351
                                                if( event.active.gain != 0 )
352
                                                {
353
                                                        ChunkerPlayerGUI_HandleGetFocus();
354
                                                }
355
                                        }
356
                                        //If something happened to the mouse focus
357
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
358
                                        {
359
                                                //If the application gained mouse focus
360
                                                if( event.active.gain != 0 )
361
                                                {
362
                                                        ChunkerPlayerGUI_HandleGetFocus();
363
                                                }
364
                                        }
365
                                        break;
366
                                case SDL_MOUSEMOTION:
367
                                        if(SilentMode)
368
                                                break;
369
                                                
370
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
371
                                break;
372
                                case SDL_MOUSEBUTTONUP:
373
                                        if(SilentMode)
374
                                                break;
375
                                                
376
                                        if( event.button.button != SDL_BUTTON_LEFT )
377
                                                break;
378

    
379
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
380
                                break;
381
                        }
382
                        ChunkerPlayerGUI_HandleKey();
383
                }
384
                usleep(120000);
385
        }
386

    
387
        KILL_PROCESS(P2PProcessHandle);
388

    
389
        //TERMINATE
390
        ChunkerPlayerCore_Stop();
391
        if(YUVOverlay != NULL)
392
                SDL_FreeYUVOverlay(YUVOverlay);
393
        
394
        ChunkerPlayerGUI_Close();
395
        SDL_DestroyMutex(OverlayMutex);
396
        SDL_Quit();
397
        
398
#ifdef HTTPIO
399
        finalizeChunkPuller(daemon);
400
#endif
401
#ifdef TCPIO
402
        finalizeChunkPuller();
403
#endif
404
        
405
#ifdef EMULATE_CHUNK_LOSS
406
        if(ScheduledChunkLosses)
407
                free(ScheduledChunkLosses);
408
#endif
409

    
410
#ifdef PSNR_PUBLICATION
411
        repClose(repoclient);
412
        event_base_free(eventbase);
413
#endif
414
        return 0;
415
}
416

    
417
int cb_validate_conffile(cfg_t *cfg)
418
{
419
        char LaunchString[255];
420
        cfg_t *cfg_greet;
421
        
422
        if(cfg_size(cfg, "Channel") == 0)
423
        {
424
                cfg_error(cfg, "no \"Channel\" section found");
425
                return -1;
426
        }
427
        
428
        printf("\t%d Channel setions found\n", cfg_size(cfg, "Channel"));
429
        
430
        int j;
431
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
432
        {
433
                cfg_greet = cfg_getnsec(cfg, "Channel", j);
434
                sprintf(LaunchString, "%s", cfg_getstr(cfg_greet, "LaunchString"));
435
                if(!(strlen(LaunchString) > 0))
436
                {
437
                        cfg_error(cfg, "invalid LaunchString for Channel[%d]", j);
438
                        return -1;
439
                }
440
                printf("\tChannel[%d].LaunchString = %s\n", j, LaunchString);
441
                printf("\tChannel[%d].AudioChannels = %ld\n", j, cfg_getint(cfg_greet, "AudioChannels"));
442
                printf("\tChannel[%d].SampleRate = %ld\n", j, cfg_getint(cfg_greet, "SampleRate"));
443
                printf("\tChannel[%d].Width = %ld\n", j, cfg_getint(cfg_greet, "Width"));
444
                printf("\tChannel[%d].Height = %ld\n", j, cfg_getint(cfg_greet, "Height"));
445
                printf("\tChannel[%d].Bitrate = %ld\n", j, cfg_getint(cfg_greet, "Bitrate"));
446
                printf("\tChannel[%d].Ratio = %s\n", j, cfg_getstr(cfg_greet, "Ratio"));
447
        }
448
    return 0;
449
}
450

    
451
int ParseConf()
452
{
453
        int j;
454
        
455
        // PARSING CONF FILE
456
        cfg_opt_t channel_opts[] =
457
        {
458
                CFG_STR("Title", "", CFGF_NONE),
459
                CFG_STR("LaunchString", "", CFGF_NONE),
460
                CFG_INT("AudioChannels", 2, CFGF_NONE),
461
                CFG_INT("SampleRate", 48000, CFGF_NONE),
462
                CFG_INT("Width", 176, CFGF_NONE),
463
                CFG_INT("Height", 144, CFGF_NONE),
464
                CFG_INT("Bitrate", 0, CFGF_NONE),
465
                
466
                // for some reason libconfuse parsing for floating point does not work in windows
467
                //~ CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
468
                CFG_STR("Ratio", "1.22", CFGF_NONE),
469
                CFG_END()
470
        };
471
        cfg_opt_t opts[] =
472
        {
473
                CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
474
                CFG_END()
475
        };
476
        cfg_t *cfg, *cfg_channel;
477
        cfg = cfg_init(opts, CFGF_NONE);
478
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_PARSE_ERROR)
479
        {
480
                printf("Error while parsing configuration file, exiting...\n");
481
                cb_validate_conffile(cfg);
482
                return 1;
483
        }
484
        
485
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_FILE_ERROR)
486
        {
487
                printf("Error trying parsing configuration file. '%s' file couldn't be opened for reading\n", DEFAULT_CONF_FILENAME);
488
                return 1;
489
        }
490
        
491
        FILE * tmp_file;
492
        if(tmp_file = fopen(DEFAULT_PEEREXECNAME_FILENAME, "r")) {
493
                if(fscanf(tmp_file, "%s", StreamerFilename) != 1) {
494
                        printf("Wrong format of conf file %s containing peer application exec name. Assuming default: %s.\n\n", DEFAULT_PEEREXECNAME_FILENAME, DEFAULT_PEER_EXEC_NAME);
495
                }
496
                fclose(tmp_file);
497
        }
498
        else {
499
                printf("Could not find conf file %s containing peer application exec name. Exiting.\n\n", DEFAULT_PEEREXECNAME_FILENAME);
500
                exit(1);
501
        }
502
        if(tmp_file = fopen(StreamerFilename, "r"))
503
    {
504
        fclose(tmp_file);
505
    }
506
    else
507
        {
508
                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);
509
                exit(1);
510
        }
511
        
512
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
513
        {
514
                cfg_channel = cfg_getnsec(cfg, "Channel", j);
515
                sprintf(Channels[j].Title, "%s", cfg_title(cfg_channel));
516
                strcpy(Channels[j].LaunchString, cfg_getstr(cfg_channel, "LaunchString"));
517
                Channels[j].Width = cfg_getint(cfg_channel, "Width");
518
                Channels[j].Height = cfg_getint(cfg_channel, "Height");
519
                Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
520
                Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
521
                Channels[j].Ratio = strtof(cfg_getstr(cfg_channel, "Ratio"), 0);
522
                Channels[j].Bitrate = cfg_getint(cfg_channel, "Bitrate");
523
                
524
                Channels[j].Index = j+1;
525
                NChannels++;
526
        }
527
        cfg_free(cfg);
528

    
529
        return 0;
530
}
531

    
532
int ReTune(SChannel* channel)
533
{        
534
        if(ChunkerPlayerCore_IsRunning())
535
                ChunkerPlayerCore_Pause();
536
        
537
        //reset quality info
538
        channel->startTime = time(NULL);
539
        
540
        ChunkerPlayerCore_Play();
541
        
542
        return 0;
543
}
544

    
545
int SwitchChannel(SChannel* channel)
546
{
547
        int i=0;
548
#ifdef RESTORE_SCREEN_ON_ZAPPING
549
        int was_fullscreen = FullscreenMode;
550
        int old_width = window_width, old_height = window_height;
551
#endif
552
        
553
        if(ChunkerPlayerCore_IsRunning())
554
                ChunkerPlayerCore_Stop();
555

    
556
    KILL_PROCESS(P2PProcessHandle);
557
        remove("NetworkID");
558
        
559
        ratio = channel->Ratio;
560
        ChunkerPlayerGUI_SetChannelTitle(channel->Title);
561
        ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
562
        
563
        int w=0, h=0;
564
        ChunkerPlayerGUI_AspectRatioResize((float)channel->Ratio, channel->Width, channel->Height, &w, &h);
565
        ChunkerPlayerCore_SetupOverlay(w, h);
566
        //ChunkerPlayerGUI_SetupOverlayRect(channel);
567
        
568
        if(ChunkerPlayerCore_InitCodecs(channel->Width, channel->Height, channel->SampleRate, channel->AudioChannels) < 0)
569
        {
570
                printf("ERROR, COULD NOT INITIALIZE CODECS\n");
571
                exit(2);
572
        }
573
        
574
        //reset quality info
575
        channel->startTime = time(NULL);
576
        channel->instant_score = 0.0;
577
        channel->average_score = 0.0;
578
        channel->history_index = 0;
579
        for(i=0; i<CHANNEL_SCORE_HISTORY_SIZE; i++)
580
                channel->score_history[i] = -1;
581
        sprintf(channel->quality, "EVALUATING...");
582
        
583
        char argv0[255], parameters_string[511];
584
        sprintf(argv0, "%s", StreamerFilename);
585

    
586
#ifdef HTTPIO
587
        sprintf(parameters_string, "%s %s %s %d %s %s %d", "-C", channel->Title, "-P", (HttpPort+channel->Index), channel->LaunchString, "-F", HttpPort);
588
#endif
589

    
590
#ifdef TCPIO
591
        sprintf(parameters_string, "%s %s %s %d %s %s 127.0.0.1:%d", "-C", channel->Title, "-P", (TcpPort+channel->Index), channel->LaunchString, "-F", TcpPort);
592
#endif
593

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

    
596
        char* parameters_vector[255];
597
        parameters_vector[0] = argv0;
598
        
599
        // split parameters and count them
600
        int par_count=1;
601
        char* pch = strtok (parameters_string, " ");
602
        while (pch != NULL)
603
        {
604
                if(par_count > 255) break;
605
                // printf ("\tpch=%s\n",pch);
606
                parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
607
                strcpy(parameters_vector[par_count], pch);
608
                pch = strtok (NULL, " ");
609
                par_count++;
610
        }
611
        parameters_vector[par_count] = NULL;
612

    
613
        if(SilentMode != 3) //mode 3 is without P2P peer process
614
        {
615

    
616
#ifndef __WIN32__
617
                int d;
618
                int stdoutS, stderrS;
619
                FILE* stream;
620
                stream = fopen("/dev/null", "a+");
621
                d = fileno(stream);
622

    
623
                // create backup descriptors for the current stdout and stderr devices
624
                stdoutS = dup(STDOUT_FILENO);
625
                stderrS = dup(STDERR_FILENO);
626
                
627
                // redirect child output to /dev/null
628
                dup2(d, STDOUT_FILENO);
629
                dup2(d, STDERR_FILENO);
630

    
631
                int pid = fork();
632
                if(pid == 0)
633
                {
634
                        execv(argv0, parameters_vector);
635
                        printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
636
                        exit(2);
637
                }
638
                else
639
                        *((pid_t*)P2PProcessHandle) = pid;
640
                
641
                // restore backup descriptors in the parent process
642
                dup2(stdoutS, STDOUT_FILENO);
643
                dup2(stderrS, STDERR_FILENO);
644

    
645
                fclose(stream);
646
#else
647
                STARTUPINFO sti;
648
                SECURITY_ATTRIBUTES sats = { 0 };
649
                DWORD writ, excode, read, available;
650
                int ret = 0;
651

    
652
                //set SECURITY_ATTRIBUTES struct fields
653
                sats.nLength = sizeof(sats);
654
                sats.bInheritHandle = TRUE;
655
                sats.lpSecurityDescriptor = NULL;
656

    
657
                ZeroMemory( &sti, sizeof(sti) );
658
                sti.cb = sizeof(sti);
659
                ZeroMemory( P2PProcessHandle, sizeof(PROCESS_INFORMATION) );
660

    
661
                char buffer[512];
662
                sprintf(buffer, "%s %s", argv0, parameters_string);
663

    
664
                if(!CreateProcess(NULL,
665
                  buffer,
666
                  &sats,
667
                  &sats,
668
                  TRUE,
669
                  0,
670
                  NULL,
671
                  NULL,
672
                  &sti,
673
                  P2PProcessHandle))
674
                {
675
                        printf("Unable to generate process \n");
676
                        return -1;
677
                }
678
#endif
679

    
680
        }
681

    
682
#ifdef RESTORE_SCREEN_ON_ZAPPING
683
        if(SilentMode == 0) {
684
                if(was_fullscreen)
685
                        ChunkerPlayerGUI_ToggleFullscreen();
686
                else
687
                {
688
                        ChunkerPlayerGUI_HandleResize(old_width, old_height);
689
                }
690
        }
691
#endif
692

    
693
#ifdef PSNR_PUBLICATION
694
        // Find repo_address
695
        if(CheckForRepoAddress(parameters_vector[par_count])) {
696

    
697
        // Open Repository
698
        if(repoclient)
699
                repClose(repoclient);
700
        repoclient=NULL;
701

    
702
        repoclient = repOpen(RepoAddress,0);
703
        if (repoclient == NULL)
704
                printf("Unable to initialize PSNR publication in repoclient %s\n", RepoAddress);
705
        }
706
        else {
707
                printf("Repository address not present in streames launch string. Publication disabled\n");
708
        }
709
#endif
710

    
711
        for(i=1; i<par_count; i++)
712
                free(parameters_vector[i]);
713

    
714
        // Read the Network ID
715
        int Error=true;
716
        char Line1[255], Line2[255];
717
        while(Error)
718
        {
719
            FILE* fp=fopen("NetworkID","r");
720
            if(fp)
721
            {
722
                if(ReadALine(fp,Line1,255)!=-1)
723
                    if(ReadALine(fp,Line2,255)!=-1)
724
                    {
725
                        if(strcmp(Line2,"IDEnd")==0)
726
                        {
727
                            strcpy(NetworkID,Line1);
728
                            Error=false;
729
                        }
730
                    }
731
                fclose(fp);
732
            }
733
            if(Error) usleep(100000);
734
        }
735
        
736
        printf("NetworkID = %s\n",NetworkID);
737
        
738
        ChunkerPlayerCore_Play();
739
        ChunkerPlayerGUI_ChannelSwitched();
740
        return 0;
741
}
742

    
743
void ZapDown()
744
{
745
        SelectedChannel = ((SelectedChannel+1) %NChannels);
746
        SwitchChannel(&(Channels[SelectedChannel]));
747
}
748

    
749
void ZapUp()
750
{
751
        SelectedChannel--;
752
        if(SelectedChannel < 0)
753
                SelectedChannel = NChannels-1;
754

    
755
        SwitchChannel(&(Channels[SelectedChannel]));
756
}
757

    
758
int enqueueBlock(const uint8_t *block, const int block_size)
759
{
760
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
761
}