Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ e8699fac

History | View | Annotate | Download (10 KB)

1
#include <stdio.h>
2
#include <unistd.h>
3
#include <SDL.h>
4
#include <SDL_mutex.h>
5
#include "player_defines.h"
6
#include <confuse.h>
7
#include "http_default_urls.h"
8
#include "player_defines.h"
9
#include "chunker_player.h"
10
#include "player_gui.h"
11

    
12
int main(int argc, char *argv[])
13
{
14
        // some initializations
15
        SilentMode = 0;
16
        queue_filling_threshold = 0;
17
        SaveYUV = 0;
18
        quit = 0;
19
        QueueFillingMode=1;
20
        P2PProcessID = -1;
21
        NChannels = 0;
22
        SelectedChannel = -1;
23
        char firstChannelName[255];
24
        int firstChannelIndex;
25
        
26
        memset((void*)Channels, 0, (MAX_CHANNELS_NUM*sizeof(SChannel)));
27

    
28
        HttpPort = -1;
29
        struct MHD_Daemon *daemon = NULL;
30
        SDL_Event event;
31
        OverlayMutex = SDL_CreateMutex();
32

    
33
        FILE *fp;
34
                
35
        if(argc<6) {
36
                printf("chunker_player queue_thresh httpd_port silentMode LossTracesFilenameSuffix ChannelName <YUVFilename>\n");
37
                exit(1);
38
        }
39
        sscanf(argv[1],"%d",&queue_filling_threshold);
40
        sscanf(argv[2],"%d",&HttpPort);
41
        sscanf(argv[3],"%d",&SilentMode);
42
        sscanf(argv[4],"%s",LossTracesFilename);
43
        sscanf(argv[5],"%s",firstChannelName);
44
        
45
        if(argc==7)
46
        {
47
                sscanf(argv[6],"%s",YUVFileName);
48
                printf("YUVFile: %s\n",YUVFileName);
49
                fp=fopen(YUVFileName, "wb");
50
                if(fp)
51
                {
52
                        SaveYUV=1;
53
                        fclose(fp);
54
                }
55
                else
56
                        printf("ERROR: Unable to create YUVFile\n");
57
        }
58
        
59
        char filename[255];
60
        sprintf(filename, "audio_%s", LossTracesFilename);
61
        fp=fopen(filename, "wb");
62
        if(fp)
63
        {
64
                fclose(fp);
65
                sprintf(filename, "video_%s", LossTracesFilename);
66
                fp=fopen(filename, "wb");
67
                if(fp)
68
                        fclose(fp);
69
                else
70
                {
71
                        printf("ERROR: Unable to create loss trace files\n");
72
                        exit(1);
73
                }
74
        }
75
        else
76
        {
77
                printf("ERROR: Unable to create loss trace files\n");
78
                exit(1);
79
        }
80

    
81
        //this thread fetches chunks from the network by listening to the following path, port
82
        daemon = (struct MHD_Daemon*)initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, HttpPort);
83
        if(daemon == NULL)
84
        {
85
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
86
//                KILLALL("offerstreamer");
87
                exit(2);
88
        }
89

    
90
        if(!SilentMode)
91
        {
92
                if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
93
                        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
94
                        return -1;
95
                }
96
        }
97
        else
98
        {
99
                if(SDL_Init(SDL_INIT_TIMER)) {
100
                        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
101
                        return -1;
102
                }
103
        }
104
        
105
        if(ParseConf())
106
        {
107
                printf("ERROR: Cannot parse configuration file, exit...\n");
108
                exit(1);
109
        }
110
        
111
        firstChannelIndex = -1;
112
        int it;
113
        for(it = 0; it < NChannels; it++)
114
        {
115
                if(!strcmp(Channels[it].Title, firstChannelName))
116
                {
117
                        firstChannelIndex = it;
118
                        break;
119
                }
120
        }
121
        
122
        if(firstChannelIndex < 0)
123
        {
124
                printf("Cannot find the specified channel (%s) into the configuration file (channels.conf), exiting\n");
125
                exit(0);
126
        }
127
        
128
        if(ChunkerPlayerGUI_Init())
129
        {
130
                printf("ERROR: Cannot init player gui, exit...\n");
131
                exit(1);
132
        }
133
        
134
        SelectedChannel = firstChannelIndex;
135

    
136
        SwitchChannel(&(Channels[SelectedChannel]));
137

    
138
        // Wait for user input
139
        while(!quit) {
140
                if(QueueFillingMode) {
141
                        SDL_WM_SetCaption("Filling buffer...", NULL);
142

    
143
                        if(ChunkerPlayerCore_AudioEnded())
144
                                ChunkerPlayerCore_ResetAVQueues();
145

    
146
#ifdef DEBUG_QUEUE
147
                        //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);
148
#endif
149
                }
150
                else
151
                        SDL_WM_SetCaption("NAPA-Wine Player", NULL);
152

    
153
                //listen for key and mouse
154
                while(SDL_PollEvent(&event)) {
155
                        switch(event.type) {
156
                                case SDL_QUIT:
157
                                        quit=1;
158
                                break;
159
                                case SDL_VIDEORESIZE:
160
                                        if(SilentMode)
161
                                                break;
162
                                        // printf("\tSDL_VIDEORESIZE event received!! \n");
163
                                        if(!FullscreenMode)
164
                                                ChunkerPlayerGUI_HandleResize(event.resize.w, event.resize.h);
165
                                        else
166
                                                ChunkerPlayerGUI_HandleResize(FullscreenWidth, FullscreenHeight);
167
                                break;
168
                                case SDL_ACTIVEEVENT:
169
                                        if(SilentMode)
170
                                                break;
171
                                                
172
                                        // if the window was iconified or restored
173
                                        if(event.active.state & SDL_APPACTIVE)
174
                                        {
175
                                                //If the application is being reactivated
176
                                                if( event.active.gain != 0 )
177
                                                {
178
                                                        ChunkerPlayerGUI_HandleGetFocus();
179
                                                }
180
                                        }
181

    
182
                                        //If something happened to the keyboard focus
183
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
184
                                        {
185
                                                //If the application gained keyboard focus
186
                                                if( event.active.gain != 0 )
187
                                                {
188
                                                        ChunkerPlayerGUI_HandleGetFocus();
189
                                                }
190
                                        }
191
                                        //If something happened to the mouse focus
192
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
193
                                        {
194
                                                //If the application gained mouse focus
195
                                                if( event.active.gain != 0 )
196
                                                {
197
                                                        ChunkerPlayerGUI_HandleGetFocus();
198
                                                }
199
                                        }
200
                                        break;
201
                                case SDL_MOUSEMOTION:
202
                                        if(SilentMode)
203
                                                break;
204
                                                
205
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
206
                                break;
207
                                case SDL_MOUSEBUTTONUP:
208
                                        if(SilentMode)
209
                                                break;
210
                                                
211
                                        if( event.button.button != SDL_BUTTON_LEFT )
212
                                                break;
213

    
214
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
215
                                break;
216
                        }
217
                        ChunkerPlayerGUI_HandleKey();
218
                }
219
                usleep(120000);
220
        }
221
        
222
        if(P2PProcessID > 0)
223
                KILL_PROCESS(P2PProcessID);
224

    
225
        //TERMINATE
226
        ChunkerPlayerCore_Stop();
227
        if(YUVOverlay != NULL)
228
                SDL_FreeYUVOverlay(YUVOverlay);
229
        
230
        ChunkerPlayerGUI_Close();
231
        SDL_DestroyMutex(OverlayMutex);
232
        SDL_Quit();
233
        finalizeChunkPuller(daemon);
234
        return 0;
235
}
236

    
237
int ParseConf()
238
{
239
        int j;
240
        
241
        // PARSING CONF FILE
242
        cfg_opt_t channel_opts[] =
243
        {
244
                CFG_STR("Title", "", CFGF_NONE),
245
                CFG_STR("LaunchString", "", CFGF_NONE),
246
                CFG_INT("AudioChannels", 2, CFGF_NONE),
247
                CFG_INT("SampleRate", 48000, CFGF_NONE),
248
                CFG_INT("Width", 176, CFGF_NONE),
249
                CFG_INT("Height", 144, CFGF_NONE),
250
                CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
251
                CFG_END()
252
        };
253
        cfg_opt_t opts[] =
254
        {
255
                CFG_STR("PeerExecName", DEFAULT_CHANNEL_EXEC_NAME, CFGF_NONE),
256
                CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
257
                CFG_END()
258
        };
259
        cfg_t *cfg, *cfg_channel;
260
        cfg = cfg_init(opts, CFGF_NONE);
261
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_PARSE_ERROR)
262
        {
263
                printf("Error while parsing configuration file, exiting...\n");
264
                return 1;
265
        }
266
        
267
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_FILE_ERROR)
268
        {
269
                printf("Error trying parsing configuration file. '%s' file couldn't be opened for reading\n", DEFAULT_CONF_FILENAME);
270
                return 1;
271
        }
272
        
273
        sprintf(OfferStreamerFilename, "%s", cfg_getstr(cfg, "PeerExecName"));
274
        
275
        FILE * tmp_file;
276
        if(tmp_file = fopen(OfferStreamerFilename, "r"))
277
    {
278
        fclose(tmp_file);
279
    }
280
    else
281
        {
282
                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", OfferStreamerFilename);
283
                exit(1);
284
        }
285
        
286
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
287
        {
288
                cfg_channel = cfg_getnsec(cfg, "Channel", j);
289
                sprintf(Channels[j].Title, "%s", cfg_title(cfg_channel));
290
                strcpy(Channels[j].LaunchString, cfg_getstr(cfg_channel, "LaunchString"));
291
                Channels[j].Width = cfg_getint(cfg_channel, "Width");
292
                Channels[j].Height = cfg_getint(cfg_channel, "Height");
293
                Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
294
                Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
295
                Channels[j].Ratio = cfg_getfloat(cfg_channel, "Ratio");
296
                Channels[j].Index = j+1;
297
                NChannels++;
298
        }
299
        cfg_free(cfg);
300

    
301
        return 0;
302
}
303

    
304
int SwitchChannel(SChannel* channel)
305
{
306
        int i=0;
307
#ifdef RESTORE_SCREEN_ON_ZAPPING
308
        int was_fullscreen = FullscreenMode;
309
        int old_width = window_width, old_height = window_height;
310
#endif
311
        
312
        if(ChunkerPlayerCore_IsRunning())
313
                ChunkerPlayerCore_Stop();
314

    
315
        if(P2PProcessID > 0)
316
                KILL_PROCESS(P2PProcessID);
317
        
318
        ratio = channel->Ratio;
319
        ChunkerPlayerGUI_SetChannelTitle(channel->Title);
320
        ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
321
        
322
        ChunkerPlayerCore_SetupOverlay(channel->Width, channel->Height);
323
        //ChunkerPlayerGUI_SetupOverlayRect(channel);
324
        
325
        ChunkerPlayerCore_InitCodecs(channel->Width, channel->Height, channel->SampleRate, channel->AudioChannels);
326
                
327
        char* parameters_vector[255];
328
        char argv0[255], parameters_string[511];
329
        sprintf(argv0, "%s", OfferStreamerFilename);
330
        
331
        sprintf(parameters_string, "%s %s %s %s %s %d %s %d", argv0, channel->LaunchString, "-C", channel->Title, "-P", (HttpPort+channel->Index), "-F", HttpPort);
332
        
333
        printf("EXECUTING %s\n", parameters_string);
334
        
335
        int par_count=0;
336
        
337
        // split parameters and count them
338
        char* pch = strtok (parameters_string, " ");
339
        
340
        while (pch != NULL)
341
        {
342
                if(par_count > 255) break;
343
                // printf ("\tpch=%s\n",pch);
344
                parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
345
                strcpy(parameters_vector[par_count], pch);
346
                pch = strtok (NULL, " ");
347
                par_count++;
348
        }
349
        parameters_vector[par_count] = NULL;
350

    
351
        //reset quality info
352
        channel->startTime = time(NULL);
353
        channel->instant_score = 0.0;
354
        channel->average_score = 0.0;
355
        channel->history_index = 0;
356
        for(i=0; i<CHANNEL_SCORE_HISTORY_SIZE; i++)
357
                channel->score_history[i] = -1;
358
        sprintf(channel->quality, "EVALUATING...");
359

    
360
#ifdef __LINUX__
361

    
362
        int d;
363
        int stdoutS, stderrS;
364
        FILE* stream;
365
        stream = fopen("/dev/null", "a+");
366
        d = fileno(stream);
367

    
368
        // create backup descriptors for the current stdout and stderr devices
369
        stdoutS = dup(STDOUT_FILENO);
370
        stderrS = dup(STDERR_FILENO);
371
        
372
        // redirect child output to /dev/null
373
        dup2(d, STDOUT_FILENO);
374
        dup2(d, STDERR_FILENO);
375

    
376
        int pid = fork();
377
        if(pid == 0)
378
        {
379
                execv(argv0, parameters_vector);
380
                printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
381
                exit(2);
382
        }
383
        else
384
                P2PProcessID = pid;
385
        
386
        // restore backup descriptors in the parent process
387
        dup2(stdoutS, STDOUT_FILENO);
388
        dup2(stderrS, STDERR_FILENO);
389
        
390
        for(i=0; i<par_count; i++)
391
                free(parameters_vector[i]);
392
                
393
        fclose(stream);
394

    
395
#ifdef RESTORE_SCREEN_ON_ZAPPING
396
        if(was_fullscreen)
397
                ChunkerPlayerGUI_ToggleFullscreen();
398
        else
399
        {
400
                ChunkerPlayerGUI_HandleResize(old_width, old_height);
401
        }
402
#endif
403
        
404
        ChunkerPlayerCore_Play();
405
        
406
        return 0;
407
#endif
408

    
409
        return 1;
410
}
411

    
412
void ZapDown()
413
{
414
        SelectedChannel = ((SelectedChannel+1) %NChannels);
415
        SwitchChannel(&(Channels[SelectedChannel]));
416
}
417

    
418
void ZapUp()
419
{
420
        SelectedChannel--;
421
        if(SelectedChannel < 0)
422
                SelectedChannel = NChannels-1;
423

    
424
        SwitchChannel(&(Channels[SelectedChannel]));
425
}
426

    
427
int enqueueBlock(const uint8_t *block, const int block_size)
428
{
429
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
430
}