Statistics
| Branch: | Revision:

chunker-player / chunker_player / chunker_player.c @ 10c75ef7

History | View | Annotate | Download (8.88 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 "codec_definitions.h"
9
#include "player_defines.h"
10
#include "chunker_player.h"
11
#include "player_gui.h"
12

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

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

    
32
        FILE *fp;
33
                
34
        if(argc<4) {
35
                printf("chunker_player queue_thresh httpd_port silentMode <YUVFilename>\n");
36
                exit(1);
37
        }
38
        sscanf(argv[1],"%d",&queue_filling_threshold);
39
        sscanf(argv[2],"%d",&HttpPort);
40
        sscanf(argv[3],"%d",&SilentMode);
41
        
42
        if(argc==5)
43
        {
44
                sscanf(argv[4],"%s",YUVFileName);
45
                printf("YUVFile: %s\n",YUVFileName);
46
                fp=fopen(YUVFileName, "wb");
47
                if(fp)
48
                {
49
                        SaveYUV=1;
50
                        fclose(fp);
51
                }
52
                else
53
                        printf("ERROR: Unable to create YUVFile\n");
54
        }
55
        
56
        if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
57
                fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
58
                return -1;
59
        }
60
        
61
        if(ParseConf())
62
        {
63
                printf("ERROR: Cannot parse configuration file, exit...\n");
64
                exit(1);
65
        }
66
        
67
        if(ChunkerPlayerGUI_Init())
68
        {
69
                printf("ERROR: Cannot init player gui, exit...\n");
70
                exit(1);
71
        }
72
        
73
        SelectedChannel = 0;
74
        // KILLALL("offerstreamer-ml-monl-http-debug");
75
        SwitchChannel(&(Channels[SelectedChannel]));
76
        
77
        //this thread fetches chunks from the network by listening to the following path, port
78
        daemon = initChunkPuller(UL_DEFAULT_EXTERNALPLAYER_PATH, HttpPort);
79
        if(daemon == NULL)
80
        {
81
                printf("CANNOT START MICROHTTPD SERVICE, EXITING...\n");
82
                exit(2);
83
        }
84

    
85
        // Wait for user input
86
        while(!quit) {
87
                if(QueueFillingMode) {
88
                        SDL_WM_SetCaption("Filling buffer...", NULL);
89

    
90
                        if(ChunkerPlayerCore_VideoEnded())
91
                                ChunkerPlayerCore_ResetAVQueues();
92

    
93
#ifdef DEBUG_QUEUE
94
                        //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);
95
#endif
96
                }
97
                else
98
                        SDL_WM_SetCaption("NAPA-Wine Player", NULL);
99

    
100
                //listen for key and mouse
101
                while(SDL_PollEvent(&event)) {
102
                        switch(event.type) {
103
                                case SDL_QUIT:
104
                                        quit=1;
105
                                break;
106
                                case SDL_VIDEORESIZE:
107
                                        // printf("\tSDL_VIDEORESIZE event received!! \n");
108
                                        if(!FullscreenMode)
109
                                                ChunkerPlayerGUI_HandleResize(event.resize.w, event.resize.h);
110
                                        else
111
                                                ChunkerPlayerGUI_HandleResize(FullscreenWidth, FullscreenHeight);
112
                                break;
113
                                case SDL_ACTIVEEVENT:
114
                                        // if the window was iconified or restored
115
                                        if(event.active.state & SDL_APPACTIVE)
116
                                        {
117
                                                //If the application is being reactivated
118
                                                if( event.active.gain != 0 )
119
                                                {
120
                                                        ChunkerPlayerGUI_HandleGetFocus();
121
                                                }
122
                                        }
123

    
124
                                        //If something happened to the keyboard focus
125
                                        else if( event.active.state & SDL_APPINPUTFOCUS )
126
                                        {
127
                                                //If the application gained keyboard focus
128
                                                if( event.active.gain != 0 )
129
                                                {
130
                                                        ChunkerPlayerGUI_HandleGetFocus();
131
                                                }
132
                                        }
133
                                        //If something happened to the mouse focus
134
                                        else if( event.active.state & SDL_APPMOUSEFOCUS )
135
                                        {
136
                                                //If the application gained mouse focus
137
                                                if( event.active.gain != 0 )
138
                                                {
139
                                                        ChunkerPlayerGUI_HandleGetFocus();
140
                                                }
141
                                        }
142
                                        break;
143
                                case SDL_MOUSEMOTION:
144
                                        ChunkerPlayerGUI_HandleMouseMotion(event.motion.x, event.motion.y);
145
                                break;
146
                                case SDL_MOUSEBUTTONUP:
147
                                        if( event.button.button != SDL_BUTTON_LEFT )
148
                                                break;
149

    
150
                                        ChunkerPlayerGUI_HandleLButton(event.motion.x, event.motion.y);
151
                                break;
152
                        }
153
                        ChunkerPlayerGUI_HandleKey();
154
                }
155
                usleep(120000);
156
        }
157
        
158
        if(P2PProcessID > 0)
159
                KILL_PROCESS(P2PProcessID);
160

    
161
        //TERMINATE
162
        ChunkerPlayerCore_Stop();
163
        if(YUVOverlay != NULL)
164
                SDL_FreeYUVOverlay(YUVOverlay);
165
        
166
        ChunkerPlayerGUI_Close();
167
        SDL_DestroyMutex(OverlayMutex);
168
        SDL_Quit();
169
        finalizeChunkPuller(daemon);
170
        return 0;
171
}
172

    
173
int ParseConf()
174
{
175
        int j;
176
        
177
        // PARSING CONF FILE
178
        cfg_opt_t channel_opts[] =
179
        {
180
                CFG_STR("Title", "", CFGF_NONE),
181
                CFG_STR("LaunchString", "", CFGF_NONE),
182
                CFG_INT("AudioChannels", 2, CFGF_NONE),
183
                CFG_INT("SampleRate", 48000, CFGF_NONE),
184
                CFG_INT("Width", 176, CFGF_NONE),
185
                CFG_INT("Height", 144, CFGF_NONE),
186
                CFG_FLOAT("Ratio", 1.22, CFGF_NONE),
187
                CFG_END()
188
        };
189
        cfg_opt_t opts[] =
190
        {
191
                CFG_STR("ExecPath", DEFAULT_CHANNEL_EXEC_PATH, CFGF_NONE),
192
                CFG_STR("ExecName", DEFAULT_CHANNEL_EXEC_NAME, CFGF_NONE),
193
                CFG_SEC("Channel", channel_opts, CFGF_TITLE | CFGF_MULTI),
194
                CFG_END()
195
        };
196
        cfg_t *cfg, *cfg_channel;
197
        cfg = cfg_init(opts, CFGF_NONE);
198
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_PARSE_ERROR)
199
        {
200
                printf("Error while parsing configuration file, exiting...\n");
201
                return 1;
202
        }
203
        
204
        if(cfg_parse(cfg, DEFAULT_CONF_FILENAME) == CFG_FILE_ERROR)
205
        {
206
                printf("Error trying parsing configuration file. '%s' file couldn't be opened for reading\n", DEFAULT_CONF_FILENAME);
207
                return 1;
208
        }
209
        
210
        sprintf(OfferStreamerPath, "%s", cfg_getstr(cfg, "ExecPath"));
211
        sprintf(OfferStreamerFilename, "%s", cfg_getstr(cfg, "ExecName"));
212
        for(j = 0; j < cfg_size(cfg, "Channel"); j++)
213
        {
214
                cfg_channel = cfg_getnsec(cfg, "Channel", j);
215
                sprintf(Channels[j].Title, "%s", cfg_title(cfg_channel));
216
                strcpy(Channels[j].LaunchString, cfg_getstr(cfg_channel, "LaunchString"));
217
                Channels[j].Width = cfg_getint(cfg_channel, "Width");
218
                Channels[j].Height = cfg_getint(cfg_channel, "Height");
219
                Channels[j].AudioChannels = cfg_getint(cfg_channel, "AudioChannels");
220
                Channels[j].SampleRate = cfg_getint(cfg_channel, "SampleRate");
221
                Channels[j].Ratio = cfg_getfloat(cfg_channel, "Ratio");
222
                Channels[j].Index = j+1;
223
                NChannels++;
224
        }
225
        cfg_free(cfg);
226

    
227
        return 0;
228
}
229

    
230
int SwitchChannel(SChannel* channel)
231
{
232
        // int k =0;
233
        // for(; k<NChannels; k++)
234
        // {
235
                // printf("\tChannels[%d].LaunchString = %s\n", k, Channels[k].LaunchString);
236
                // printf("\tChannels[%d].Title = %s\n", k, Channels[k].Title);
237
                // printf("\tChannels[%d].Width = %d\n", k, Channels[k].Width);
238
                // printf("\tChannels[%d].Height = %d\n", k, Channels[k].Height);
239
                // printf("\tChannels[%d].Ratio = %f\n", k, Channels[k].Ratio);
240
                // printf("\tChannels[%d].SampleRate = %d\n", k, Channels[k].SampleRate);
241
                // printf("\tChannels[%d].AudioChannels = %d\n", k, Channels[k].AudioChannels);
242
        // }
243
        
244
#ifdef RESTORE_SCREEN_ON_ZAPPING
245
        int was_fullscreen = FullscreenMode;
246
        int old_width = window_width, old_height = window_height;
247
#endif
248
        
249
        if(ChunkerPlayerCore_IsRunning())
250
                ChunkerPlayerCore_Stop();
251

    
252
        if(P2PProcessID > 0)
253
                KILL_PROCESS(P2PProcessID);
254
        
255
        ChunkerPlayerGUI_SetChannelTitle(channel->Title);
256
        ChunkerPlayerGUI_ForceResize(channel->Width, channel->Height);
257
        
258
        ChunkerPlayerCore_SetupOverlay(channel->Width, channel->Height);
259
        
260
        ChunkerPlayerCore_InitCodecs(channel->Width, channel->Height, channel->SampleRate, channel->AudioChannels);
261
                
262
        char* parameters_vector[255];
263
        char argv0[255], parameters_string[511];
264
        sprintf(argv0, "%s%s", OfferStreamerPath, OfferStreamerFilename);
265
        
266
        sprintf(parameters_string, "%s %s %s %d %s %d", argv0, channel->LaunchString, "-P", (HttpPort+channel->Index), "-F", HttpPort);
267
        
268
        printf("EXECUTING %s\n", parameters_string);
269
        
270
        int par_count=0;
271
        
272
        // split parameters and count them
273
        char* pch = strtok (parameters_string, " ");
274
        
275
        while (pch != NULL)
276
        {
277
                if(par_count > 255) break;
278
                // printf ("\tpch=%s\n",pch);
279
                parameters_vector[par_count] = (char*) malloc(sizeof(char)*(strlen(pch)+1));
280
                strcpy(parameters_vector[par_count], pch);
281
                pch = strtok (NULL, " ");
282
                par_count++;
283
        }
284
        parameters_vector[par_count] = NULL;
285

    
286
#ifdef __LINUX__
287

    
288
        int d;
289
        int stdoutS, stderrS;
290
        FILE* stream;
291
        stream = fopen("/dev/null", "a+");
292
        d = fileno(stream);
293

    
294
        // create backup descriptors for the current stdout and stderr devices
295
        stdoutS = dup(STDOUT_FILENO);
296
        stderrS = dup(STDERR_FILENO);
297
        
298
        // redirect child output to /dev/null
299
        dup2(d, STDOUT_FILENO);
300
        dup2(d, STDERR_FILENO);
301

    
302
        int pid = fork();
303
        if(pid == 0)
304
        {
305
                execv(argv0, parameters_vector);
306
                printf("ERROR, COULD NOT LAUNCH OFFERSTREAMER\n");
307
                exit(2);
308
        }
309
        else
310
                P2PProcessID = pid;
311
        
312
        // restore backup descriptors in the parent process
313
        dup2(stdoutS, STDOUT_FILENO);
314
        dup2(stderrS, STDERR_FILENO);
315
        
316
        int i;
317
        for(i=0; i<par_count; i++)
318
                free(parameters_vector[i]);
319
                
320
        fclose(stream);
321

    
322
#ifdef RESTORE_SCREEN_ON_ZAPPING
323
        if(was_fullscreen)
324
                ChunkerPlayerGUI_ToggleFullscreen();
325
        else
326
        {
327
                ChunkerPlayerGUI_HandleResize(old_width, old_height);
328
        }
329
#endif
330
        
331
        ChunkerPlayerCore_Play();
332
        
333
        return 0;
334
#endif
335

    
336
        return 1;
337
}
338

    
339
void ZapDown()
340
{
341
        SelectedChannel = ((SelectedChannel+1) %NChannels);
342
        SwitchChannel(&(Channels[SelectedChannel]));
343
}
344

    
345
void ZapUp()
346
{
347
        SelectedChannel--;
348
        if(SelectedChannel < 0)
349
                SelectedChannel = NChannels-1;
350

    
351
        SwitchChannel(&(Channels[SelectedChannel]));
352
}
353

    
354
int enqueueBlock(const uint8_t *block, const int block_size)
355
{
356
        return ChunkerPlayerCore_EnqueueBlocks(block, block_size);
357
}