~ubuntu-branches/ubuntu/oneiric/gmerlin/oneiric

« back to all changes in this revision

Viewing changes to .pc/function_param_type.patch/lib/visualize_slave.c

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2011-02-08 00:38:27 UTC
  • mfrom: (3.2.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20110208003827-0q94ml0vrwryr8fb
Tags: 1.0.0~dfsg-4
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 * gmerlin - a general purpose multimedia framework and applications
 
3
 *
 
4
 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
 
5
 * gmerlin-general@lists.sourceforge.net
 
6
 * http://gmerlin.sourceforge.net
 
7
 *
 
8
 * This program is free software: you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation, either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 * *****************************************************************/
 
21
 
 
22
#include <string.h>
 
23
#include <dlfcn.h>
 
24
#include <unistd.h>
 
25
 
 
26
#include <gavl/gavl.h>
 
27
 
 
28
#include <config.h>
 
29
#include <gmerlin/translation.h>
 
30
 
 
31
#include <gmerlin/pluginregistry.h>
 
32
#include <gmerlin/visualize.h>
 
33
#include <visualize_priv.h>
 
34
#include <gmerlin/utils.h>
 
35
 
 
36
 
 
37
 
 
38
#include <gmerlin/log.h>
 
39
 
 
40
#define LOG_DOMAIN "visualizer_slave"
 
41
 
 
42
#ifdef HAVE_LV
 
43
#include <bglv.h>
 
44
#endif
 
45
 
 
46
/* Messages from the application to the visualizer */
 
47
 
 
48
typedef struct
 
49
  {
 
50
  gavl_audio_converter_t * cnv;
 
51
  gavl_audio_frame_t     * in_frame_1;
 
52
  gavl_audio_frame_t     * in_frame_2;
 
53
  pthread_mutex_t in_mutex;
 
54
  
 
55
  int do_convert;
 
56
  
 
57
  gavl_audio_frame_t * out_frame;
 
58
  
 
59
  gavl_audio_format_t in_format;
 
60
  gavl_audio_format_t out_format;
 
61
  
 
62
  int last_samples_read;
 
63
  int frame_done;
 
64
  
 
65
  gavl_volume_control_t * gain_control;
 
66
  pthread_mutex_t gain_mutex;
 
67
  
 
68
  } audio_buffer_t;
 
69
 
 
70
static audio_buffer_t * audio_buffer_create()
 
71
  {
 
72
  audio_buffer_t * ret;
 
73
  ret = calloc(1, sizeof(*ret));
 
74
  ret->cnv = gavl_audio_converter_create();
 
75
  pthread_mutex_init(&ret->in_mutex,(pthread_mutexattr_t *)0);
 
76
  pthread_mutex_init(&ret->gain_mutex,(pthread_mutexattr_t *)0);
 
77
  
 
78
  ret->gain_control = gavl_volume_control_create();
 
79
  
 
80
  return ret;
 
81
  }
 
82
 
 
83
static void audio_buffer_cleanup(audio_buffer_t * b)
 
84
  {
 
85
  if(b->in_frame_1)
 
86
    {
 
87
    gavl_audio_frame_destroy(b->in_frame_1);
 
88
    b->in_frame_1 = (gavl_audio_frame_t*)0;
 
89
    }
 
90
  if(b->in_frame_2)
 
91
    {
 
92
    gavl_audio_frame_destroy(b->in_frame_2);
 
93
    b->in_frame_2 = (gavl_audio_frame_t*)0;
 
94
    }
 
95
  if(b->out_frame)
 
96
    {
 
97
    gavl_audio_frame_destroy(b->out_frame);
 
98
    b->out_frame = (gavl_audio_frame_t*)0;
 
99
    }
 
100
  b->last_samples_read = 0;
 
101
  b->frame_done = 0;
 
102
  }
 
103
 
 
104
 
 
105
static void audio_buffer_destroy(audio_buffer_t * b)
 
106
  {
 
107
  audio_buffer_cleanup(b);
 
108
  gavl_audio_converter_destroy(b->cnv);
 
109
  gavl_volume_control_destroy(b->gain_control);
 
110
  pthread_mutex_destroy(&b->in_mutex);
 
111
  pthread_mutex_destroy(&b->gain_mutex);
 
112
  free(b);
 
113
  }
 
114
 
 
115
static void audio_buffer_init(audio_buffer_t * b,
 
116
                              const gavl_audio_format_t * in_format,
 
117
                              const gavl_audio_format_t * out_format)
 
118
  {
 
119
  gavl_audio_format_t frame_format;
 
120
  /* Cleanup */
 
121
  audio_buffer_cleanup(b);
 
122
  gavl_audio_format_copy(&b->in_format, in_format);
 
123
  gavl_audio_format_copy(&b->out_format, out_format);
 
124
 
 
125
  /* For visualizations, we ignore the samplerate completely.
 
126
     Perfect synchronization is mathematically impossible anyway. */
 
127
  
 
128
  b->out_format.samplerate = b->in_format.samplerate;
 
129
  
 
130
  b->do_convert = gavl_audio_converter_init(b->cnv,
 
131
                                            &b->in_format,
 
132
                                            &b->out_format);
 
133
 
 
134
  b->in_frame_1 = gavl_audio_frame_create(&b->in_format);
 
135
 
 
136
  gavl_audio_format_copy(&frame_format, out_format);
 
137
  frame_format.samples_per_frame = b->in_format.samples_per_frame;
 
138
  
 
139
  b->in_frame_2 = gavl_audio_frame_create(&frame_format);
 
140
  
 
141
  b->out_frame = gavl_audio_frame_create(&b->out_format);
 
142
  
 
143
  gavl_volume_control_set_format(b->gain_control, &frame_format);
 
144
  }
 
145
 
 
146
static void audio_buffer_put(audio_buffer_t * b,
 
147
                             const gavl_audio_frame_t * f)
 
148
  {
 
149
  pthread_mutex_lock(&b->in_mutex);
 
150
  
 
151
  b->in_frame_1->valid_samples =
 
152
    gavl_audio_frame_copy(&b->in_format,
 
153
                          b->in_frame_1,
 
154
                          f,
 
155
                          0, /* dst_pos */
 
156
                          0, /* src_pos */
 
157
                          b->in_format.samples_per_frame, /* dst_size */
 
158
                          f->valid_samples /* src_size */ ); 
 
159
  pthread_mutex_unlock(&b->in_mutex);
 
160
  }
 
161
 
 
162
static void audio_buffer_set_gain(audio_buffer_t * b, float gain)
 
163
  {
 
164
  pthread_mutex_lock(&b->gain_mutex);
 
165
  gavl_volume_control_set_volume(b->gain_control, gain);
 
166
  pthread_mutex_unlock(&b->gain_mutex);
 
167
  }
 
168
 
 
169
static gavl_audio_frame_t * audio_buffer_get(audio_buffer_t * b)
 
170
  {
 
171
  int samples_copied;
 
172
  /* Check if there is new audio */
 
173
  pthread_mutex_lock(&b->in_mutex);
 
174
 
 
175
  if(b->in_frame_1->valid_samples)
 
176
    {
 
177
    if(b->do_convert)
 
178
      {
 
179
      gavl_audio_convert(b->cnv, b->in_frame_1, b->in_frame_2);
 
180
      samples_copied = b->in_frame_1->valid_samples;
 
181
      }
 
182
    else
 
183
      samples_copied =
 
184
        gavl_audio_frame_copy(&b->in_format,
 
185
                              b->in_frame_2,
 
186
                              b->in_frame_1,
 
187
                              0, /* dst_pos */
 
188
                              0, /* src_pos */
 
189
                              b->in_format.samples_per_frame, /* dst_size */
 
190
                              b->in_frame_1->valid_samples    /* src_size */ ); 
 
191
    b->in_frame_2->valid_samples = samples_copied;
 
192
    b->last_samples_read         = samples_copied;
 
193
    b->in_frame_1->valid_samples = 0;
 
194
    
 
195
    pthread_mutex_lock(&b->gain_mutex);
 
196
    gavl_volume_control_apply(b->gain_control, b->in_frame_2);
 
197
    pthread_mutex_unlock(&b->gain_mutex);
 
198
    }
 
199
  pthread_mutex_unlock(&b->in_mutex);
 
200
  
 
201
  /* If the frame was output the last time, set valid_samples to 0 */
 
202
  if(b->frame_done)
 
203
    {
 
204
    b->out_frame->valid_samples = 0;
 
205
    b->frame_done = 0;
 
206
    }
 
207
  
 
208
  /* Copy to output frame and check if there are enough samples */
 
209
  
 
210
  samples_copied =
 
211
    gavl_audio_frame_copy(&b->out_format,
 
212
                          b->out_frame,
 
213
                          b->in_frame_2,
 
214
                          b->out_frame->valid_samples, /* dst_pos */
 
215
                          b->last_samples_read - b->in_frame_2->valid_samples, /* src_pos */
 
216
                          b->out_format.samples_per_frame - b->out_frame->valid_samples, /* dst_size */
 
217
                          b->in_frame_2->valid_samples /* src_size */ ); 
 
218
  
 
219
  b->out_frame->valid_samples += samples_copied;
 
220
  b->in_frame_2->valid_samples -= samples_copied;
 
221
    
 
222
  if(b->out_frame->valid_samples == b->out_format.samples_per_frame)
 
223
    {
 
224
    b->frame_done = 1;
 
225
    return b->out_frame;
 
226
    }
 
227
  return (gavl_audio_frame_t*)0;
 
228
  }
 
229
 
 
230
typedef struct
 
231
  {
 
232
  bg_plugin_handle_t * vis_handle;
 
233
  bg_plugin_handle_t * ov_handle;
 
234
  bg_plugin_api_t vis_api;
 
235
  
 
236
  audio_buffer_t * audio_buffer;
 
237
  
 
238
  gavl_video_converter_t * video_cnv;
 
239
 
 
240
  int do_convert_video;
 
241
    
 
242
  bg_ov_plugin_t * ov_plugin;
 
243
  bg_ov_callbacks_t ov_callbacks;
 
244
 
 
245
  bg_visualization_plugin_t * vis_plugin;
 
246
 
 
247
  gavl_video_format_t video_format_in;
 
248
  gavl_video_format_t video_format_in_real;
 
249
  gavl_video_format_t video_format_out;
 
250
  
 
251
  pthread_t video_thread;
 
252
  
 
253
  pthread_mutex_t running_mutex;
 
254
  pthread_mutex_t stop_mutex;
 
255
  pthread_mutex_t vis_mutex;
 
256
  pthread_mutex_t ov_mutex;
 
257
  
 
258
  int do_stop;
 
259
 
 
260
  gavl_video_frame_t * video_frame_in;
 
261
  gavl_video_frame_t * video_frame_out;
 
262
 
 
263
  gavl_timer_t * timer;
 
264
  
 
265
  gavl_time_t last_frame_time;
 
266
 
 
267
  gavl_audio_format_t audio_format_in;
 
268
  gavl_audio_format_t audio_format_out;
 
269
  
 
270
  int do_ov;
 
271
  
 
272
  char * window_id;
 
273
  
 
274
  gavl_audio_frame_t * read_frame;
 
275
  
 
276
  pthread_mutex_t fps_mutex;
 
277
  float fps;
 
278
 
 
279
  bg_msg_queue_t * cb_queue; /* Pass events */
 
280
 
 
281
  bg_ov_callbacks_t   cb;
 
282
  
 
283
  } bg_visualizer_slave_t;
 
284
 
 
285
static int init_plugin(bg_visualizer_slave_t * v);
 
286
 
 
287
static bg_plugin_handle_t *
 
288
load_plugin_gmerlin(const char * filename)
 
289
  {
 
290
  int (*get_plugin_api_version)();
 
291
  bg_plugin_handle_t * ret;
 
292
  ret = calloc(1, sizeof(*ret));
 
293
  
 
294
  ret->dll_handle = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
 
295
  if(!(ret->dll_handle))
 
296
    {
 
297
    bg_log(BG_LOG_ERROR, LOG_DOMAIN,
 
298
           "Cannot dlopen plugin module %s: %s", filename,
 
299
           dlerror());
 
300
    goto fail;
 
301
    }
 
302
  
 
303
  get_plugin_api_version = dlsym(ret->dll_handle, "get_plugin_api_version");
 
304
  if(!get_plugin_api_version)
 
305
    {
 
306
    bg_log(BG_LOG_ERROR, LOG_DOMAIN,
 
307
           "cannot get API version: %s", dlerror());
 
308
    goto fail;
 
309
    }
 
310
  if(get_plugin_api_version() != BG_PLUGIN_API_VERSION)
 
311
    {
 
312
    bg_log(BG_LOG_ERROR, LOG_DOMAIN,
 
313
           "Wrong API version: Got %d expected %d",
 
314
           get_plugin_api_version(), BG_PLUGIN_API_VERSION);
 
315
    goto fail;
 
316
    }
 
317
  ret->plugin = dlsym(ret->dll_handle, "the_plugin");
 
318
  if(!ret)
 
319
    {
 
320
    bg_log(BG_LOG_ERROR, LOG_DOMAIN,
 
321
           "No symbol the_plugin: %s",
 
322
           dlerror());
 
323
    goto fail;
 
324
    }
 
325
  ret->priv = ret->plugin->create();
 
326
  return ret;
 
327
  fail:
 
328
  return (bg_plugin_handle_t *)0;
 
329
  }
 
330
 
 
331
#ifdef HAVE_LV
 
332
static bg_plugin_handle_t *
 
333
load_plugin_lv(const char * name, int plugin_flags, const char * window_id)
 
334
  {
 
335
  bg_plugin_handle_t * ret;
 
336
  ret = calloc(1, sizeof(*ret));
 
337
  if(!bg_lv_load(ret, name, plugin_flags, window_id))
 
338
    {
 
339
    free(ret);
 
340
    return (bg_plugin_handle_t*)0;
 
341
    }
 
342
  return ret;
 
343
  }
 
344
#endif
 
345
 
 
346
// #define BG_VIS_MSG_CB_MOTION // x, y, mask
 
347
// #define // x, y, button, mask
 
348
// #define BG_VIS_MSG_CB_BUTTON_REL // x, y, button, mask
 
349
 
 
350
 
 
351
static int ov_button_callback(void * data, int x, int y,
 
352
                              int button, int mask)
 
353
  {
 
354
  bg_msg_t * msg;
 
355
  bg_visualizer_slave_t * s = data;
 
356
  
 
357
  msg = bg_msg_queue_lock_write(s->cb_queue);
 
358
  bg_msg_set_id(msg, BG_VIS_MSG_CB_BUTTON);
 
359
  bg_msg_set_arg_int(msg, 0, x);
 
360
  bg_msg_set_arg_int(msg, 1, y);
 
361
  bg_msg_set_arg_int(msg, 2, button);
 
362
  bg_msg_set_arg_int(msg, 3, mask);
 
363
  bg_msg_queue_unlock_write(s->cb_queue);
 
364
  return 1;
 
365
  }
 
366
 
 
367
static int ov_button_release_callback(void * data, int x, int y,
 
368
                                      int button, int mask)
 
369
  {
 
370
  bg_msg_t * msg;
 
371
  bg_visualizer_slave_t * s = data;
 
372
 
 
373
  msg = bg_msg_queue_lock_write(s->cb_queue);
 
374
  bg_msg_set_id(msg, BG_VIS_MSG_CB_BUTTON_REL);
 
375
  bg_msg_set_arg_int(msg, 0, x);
 
376
  bg_msg_set_arg_int(msg, 1, y);
 
377
  bg_msg_set_arg_int(msg, 2, button);
 
378
  bg_msg_set_arg_int(msg, 3, mask);
 
379
  bg_msg_queue_unlock_write(s->cb_queue);
 
380
  return 1;
 
381
  }
 
382
 
 
383
static int ov_motion_callback(void * data, int x, int y,
 
384
                              int mask)
 
385
  {
 
386
  bg_msg_t * msg;
 
387
  bg_visualizer_slave_t * s = data;
 
388
 
 
389
  msg = bg_msg_queue_lock_write(s->cb_queue);
 
390
  bg_msg_set_id(msg, BG_VIS_MSG_CB_MOTION);
 
391
  bg_msg_set_arg_int(msg, 0, x);
 
392
  bg_msg_set_arg_int(msg, 1, y);
 
393
  bg_msg_set_arg_int(msg, 2, mask);
 
394
  bg_msg_queue_unlock_write(s->cb_queue);
 
395
  return 1;
 
396
  }
 
397
 
 
398
static bg_visualizer_slave_t *
 
399
bg_visualizer_slave_create(int argc, char ** argv)
 
400
  {
 
401
  int i;
 
402
  bg_visualizer_slave_t * ret;
 
403
  char * window_id = (char*)0;
 
404
  char * plugin_module = (char*)0;
 
405
  char * ov_module = (char*)0;
 
406
  
 
407
  /* Handle arguments and load plugins */
 
408
  i = 1;
 
409
  while(i < argc)
 
410
    {
 
411
    if(!strcmp(argv[i], "-w"))
 
412
      {
 
413
      window_id = argv[i+1];
 
414
      i += 2;
 
415
      }
 
416
    else if(!strcmp(argv[i], "-p"))
 
417
      {
 
418
      plugin_module = argv[i+1];
 
419
      i += 2;
 
420
      }
 
421
    else if(!strcmp(argv[i], "-o"))
 
422
      {
 
423
      ov_module = argv[i+1];
 
424
      i += 2;
 
425
      }
 
426
    }
 
427
  
 
428
  /* Sanity checks */
 
429
  if(!window_id)
 
430
    {
 
431
    bg_log(BG_LOG_ERROR, LOG_DOMAIN, "No window ID given");
 
432
    return (bg_visualizer_slave_t *)0;
 
433
    }
 
434
  if(!plugin_module)
 
435
    {
 
436
    bg_log(BG_LOG_ERROR, LOG_DOMAIN, "No plugin given");
 
437
    return (bg_visualizer_slave_t *)0;
 
438
    }
 
439
  
 
440
  ret = calloc(1, sizeof(*ret));
 
441
  ret->audio_buffer = audio_buffer_create();
 
442
  ret->window_id = window_id;
 
443
 
 
444
  /* Create callbacks */
 
445
  ret->cb.button_release_callback = ov_button_release_callback;
 
446
  ret->cb.button_callback = ov_button_callback;
 
447
  ret->cb.motion_callback = ov_motion_callback;
 
448
  ret->cb.data = ret;
 
449
  
 
450
  ret->cb_queue = bg_msg_queue_create();
 
451
  
 
452
  pthread_mutex_init(&ret->stop_mutex,(pthread_mutexattr_t *)0);
 
453
  pthread_mutex_init(&ret->running_mutex,(pthread_mutexattr_t *)0);
 
454
  pthread_mutex_init(&ret->vis_mutex,(pthread_mutexattr_t *)0);
 
455
  pthread_mutex_init(&ret->ov_mutex,(pthread_mutexattr_t *)0);
 
456
  pthread_mutex_init(&ret->fps_mutex,(pthread_mutexattr_t *)0);
 
457
  
 
458
  ret->timer = gavl_timer_create();
 
459
 
 
460
  /* Load ov module */
 
461
  if(ov_module)
 
462
    {
 
463
    ret->do_ov = 1;
 
464
    ret->video_cnv = gavl_video_converter_create();
 
465
    
 
466
    ret->ov_handle = load_plugin_gmerlin(ov_module);
 
467
    if(!ret->ov_handle)
 
468
      return (bg_visualizer_slave_t*)0;
 
469
    
 
470
    ret->ov_plugin = (bg_ov_plugin_t*)ret->ov_handle->plugin;
 
471
    
 
472
    if(ret->ov_plugin->set_callbacks)
 
473
      ret->ov_plugin->set_callbacks(ret->ov_handle->priv,
 
474
                                    &ret->cb);
 
475
    
 
476
    ret->ov_plugin->set_window(ret->ov_handle->priv, ret->window_id);
 
477
 
 
478
    }
 
479
  ret->vis_api = BG_PLUGIN_API_GMERLIN;
 
480
  
 
481
#ifdef HAVE_LV
 
482
  if(!strncmp(plugin_module, "vis_lv_", 7))
 
483
    {
 
484
    if(ret->ov_handle)
 
485
      ret->vis_handle = load_plugin_lv(plugin_module, BG_PLUGIN_VISUALIZE_FRAME, ret->window_id);
 
486
    else
 
487
      ret->vis_handle = load_plugin_lv(plugin_module, BG_PLUGIN_VISUALIZE_GL, ret->window_id);
 
488
    ret->vis_api = BG_PLUGIN_API_LV;
 
489
    }
 
490
  else
 
491
#endif
 
492
    ret->vis_handle =
 
493
      load_plugin_gmerlin(plugin_module);
 
494
 
 
495
  if(!ret->vis_handle)
 
496
    return (bg_visualizer_slave_t*)0;
 
497
  
 
498
  ret->vis_plugin = (bg_visualization_plugin_t*)(ret->vis_handle->plugin);
 
499
  
 
500
  if(ret->vis_plugin->set_callbacks)
 
501
    ret->vis_plugin->set_callbacks(ret->vis_handle->priv, &ret->cb);
 
502
  
 
503
  return ret;
 
504
  }
 
505
 
 
506
static void uload_plugin(bg_plugin_handle_t * h, bg_plugin_api_t api)
 
507
  {
 
508
#ifdef HAVE_LV
 
509
  if(api == BG_PLUGIN_API_LV)
 
510
    {
 
511
    bg_lv_unload(h);
 
512
    free(h);
 
513
    return;
 
514
    }
 
515
#endif
 
516
  h->plugin->destroy(h->priv);
 
517
  dlclose(h->dll_handle);
 
518
  free(h);
 
519
  }
 
520
 
 
521
static void bg_visualizer_slave_destroy(bg_visualizer_slave_t * v)
 
522
  {
 
523
  pthread_mutex_destroy(&v->stop_mutex);
 
524
 
 
525
  if(v->video_cnv)
 
526
    gavl_video_converter_destroy(v->video_cnv);
 
527
 
 
528
  audio_buffer_destroy(v->audio_buffer);
 
529
  gavl_timer_destroy(v->timer);
 
530
 
 
531
  bg_msg_queue_destroy(v->cb_queue);
 
532
  
 
533
  pthread_mutex_destroy(&v->running_mutex);
 
534
  pthread_mutex_destroy(&v->fps_mutex);
 
535
  pthread_mutex_destroy(&v->stop_mutex);
 
536
  pthread_mutex_destroy(&v->ov_mutex);
 
537
  pthread_mutex_destroy(&v->vis_mutex);
 
538
 
 
539
  /* Close vis plugin */
 
540
  v->vis_plugin->close(v->vis_handle->priv);
 
541
  uload_plugin(v->vis_handle, v->vis_api);
 
542
  
 
543
  /* Close OV Plugin */
 
544
  if(v->do_ov)
 
545
    {
 
546
    if(v->video_frame_out)
 
547
      {
 
548
      if(v->ov_plugin->destroy_frame)
 
549
        v->ov_plugin->destroy_frame(v->ov_handle->priv,
 
550
                                 v->video_frame_out);
 
551
      else
 
552
        gavl_video_frame_destroy(v->video_frame_out);
 
553
      v->video_frame_out = (gavl_video_frame_t*)0;
 
554
      }
 
555
    if(v->video_frame_in)
 
556
      {
 
557
      gavl_video_frame_destroy(v->video_frame_in);
 
558
      v->video_frame_in = (gavl_video_frame_t*)0;
 
559
      }
 
560
    v->ov_plugin->close(v->ov_handle->priv);
 
561
    uload_plugin(v->ov_handle, BG_PLUGIN_API_GMERLIN);
 
562
    }
 
563
  
 
564
  free(v);
 
565
  }
 
566
 
 
567
static void * video_thread_func(void * data)
 
568
  {
 
569
  int do_stop;
 
570
  bg_visualizer_slave_t * v;
 
571
  gavl_audio_frame_t * audio_frame;
 
572
  gavl_time_t diff_time, current_time;
 
573
  float last_fps = -1.0;
 
574
  int64_t frame_time;
 
575
  
 
576
  v = (bg_visualizer_slave_t*)data;
 
577
  
 
578
  pthread_mutex_lock(&v->running_mutex);
 
579
  while(1)
 
580
    {
 
581
    /* Check if we should stop */
 
582
    pthread_mutex_lock(&v->stop_mutex);
 
583
    do_stop = v->do_stop;
 
584
    pthread_mutex_unlock(&v->stop_mutex);
 
585
    if(do_stop)
 
586
      break;
 
587
    
 
588
    /* Draw frame */
 
589
    pthread_mutex_lock(&v->vis_mutex);
 
590
    
 
591
    /* Check if we should update audio */
 
592
 
 
593
    audio_frame = audio_buffer_get(v->audio_buffer);
 
594
    if(audio_frame)
 
595
      v->vis_plugin->update(v->vis_handle->priv, audio_frame);
 
596
    
 
597
    /* Draw frame */
 
598
    
 
599
    if(!(v->do_ov))
 
600
      v->vis_plugin->draw_frame(v->vis_handle->priv,
 
601
                                (gavl_video_frame_t*)0);
 
602
    else if(v->do_convert_video)
 
603
      {
 
604
      v->vis_plugin->draw_frame(v->vis_handle->priv, v->video_frame_in);
 
605
      gavl_video_convert(v->video_cnv, v->video_frame_in, v->video_frame_out);
 
606
      }
 
607
    else
 
608
      v->vis_plugin->draw_frame(v->vis_handle->priv, v->video_frame_out);
 
609
    
 
610
    pthread_mutex_unlock(&v->vis_mutex);
 
611
    
 
612
    /* Wait until we can show the frame */
 
613
    current_time = gavl_timer_get(v->timer);
 
614
    
 
615
    diff_time = v->last_frame_time +
 
616
      v->video_format_in.frame_duration - current_time;
 
617
    
 
618
    if(diff_time > GAVL_TIME_SCALE / 1000)
 
619
      gavl_time_delay(&diff_time);
 
620
    
 
621
    /* Show frame */
 
622
    
 
623
    if(v->do_ov)
 
624
      {
 
625
      pthread_mutex_lock(&v->ov_mutex);
 
626
      v->ov_plugin->put_video(v->ov_handle->priv, v->video_frame_out);
 
627
      frame_time = gavl_timer_get(v->timer);
 
628
      
 
629
      v->ov_plugin->handle_events(v->ov_handle->priv);
 
630
      pthread_mutex_unlock(&v->ov_mutex);
 
631
      }
 
632
    else
 
633
      {
 
634
      pthread_mutex_lock(&v->vis_mutex);
 
635
      v->vis_plugin->show_frame(v->vis_handle->priv);
 
636
      frame_time = gavl_timer_get(v->timer);
 
637
      pthread_mutex_unlock(&v->vis_mutex);
 
638
      }
 
639
    if(v->last_frame_time < frame_time)
 
640
      {
 
641
      if(last_fps < 0.0)
 
642
        {
 
643
        pthread_mutex_lock(&v->fps_mutex);
 
644
        v->fps = (double)(GAVL_TIME_SCALE) /
 
645
          (double)(frame_time - v->last_frame_time);
 
646
        last_fps = v->fps;
 
647
        pthread_mutex_unlock(&v->fps_mutex);
 
648
        }
 
649
      else
 
650
        {
 
651
        pthread_mutex_lock(&v->fps_mutex);
 
652
        v->fps = 0.95 * last_fps +
 
653
          0.05 * (double)(GAVL_TIME_SCALE) /
 
654
          (double)(frame_time - v->last_frame_time);
 
655
        last_fps = v->fps;
 
656
        pthread_mutex_unlock(&v->fps_mutex);
 
657
        }
 
658
      }
 
659
    v->last_frame_time = frame_time;
 
660
    }
 
661
  pthread_mutex_unlock(&v->running_mutex);
 
662
  return (void*)0;
 
663
  }
 
664
 
 
665
static int bg_visualizer_slave_stop(bg_visualizer_slave_t * v)
 
666
  {
 
667
  if(!pthread_mutex_trylock(&v->running_mutex))
 
668
    {
 
669
    pthread_mutex_unlock(&v->running_mutex);
 
670
    return 0;
 
671
    }
 
672
  
 
673
  /* Join threads */
 
674
  
 
675
  pthread_mutex_lock(&v->stop_mutex);
 
676
  v->do_stop = 1;
 
677
  pthread_mutex_unlock(&v->stop_mutex);
 
678
  
 
679
  pthread_join(v->video_thread, (void**)0);
 
680
  bg_log(BG_LOG_INFO, LOG_DOMAIN, "Joined thread");
 
681
  gavl_timer_stop(v->timer);
 
682
  return 1;
 
683
  }
 
684
 
 
685
static int bg_visualizer_slave_start(bg_visualizer_slave_t * v)
 
686
  {
 
687
  if(pthread_mutex_trylock(&v->running_mutex))
 
688
    return 0;
 
689
  
 
690
  pthread_mutex_unlock(&v->running_mutex);
 
691
  
 
692
  v->fps = -1.0;
 
693
  v->do_stop = 0;
 
694
  v->last_frame_time = 0; 
 
695
  gavl_timer_set(v->timer, 0);
 
696
  gavl_timer_start(v->timer);
 
697
  
 
698
  pthread_create(&v->video_thread, (pthread_attr_t*)0, video_thread_func, v);
 
699
  bg_log(BG_LOG_INFO, LOG_DOMAIN, "Started thread");
 
700
  return 1;
 
701
  }
 
702
 
 
703
static void
 
704
bg_visualizer_slave_set_audio_format(bg_visualizer_slave_t * v,
 
705
                                     const gavl_audio_format_t * format)
 
706
  {
 
707
  int was_running;
 
708
  was_running = bg_visualizer_slave_stop(v);
 
709
  pthread_mutex_lock(&v->audio_buffer->in_mutex);
 
710
  
 
711
  gavl_audio_format_copy(&v->audio_format_in, format);
 
712
 
 
713
  if(was_running)
 
714
    audio_buffer_init(v->audio_buffer, &v->audio_format_in, &v->audio_format_out);
 
715
  pthread_mutex_unlock(&v->audio_buffer->in_mutex);
 
716
  if(was_running)
 
717
    bg_visualizer_slave_start(v);
 
718
  }
 
719
 
 
720
static void cleanup_plugin(bg_visualizer_slave_t * v)
 
721
  {
 
722
  }
 
723
 
 
724
static int init_plugin(bg_visualizer_slave_t * v)
 
725
  {
 
726
  gavl_audio_format_copy(&v->audio_format_out, &v->audio_format_in);
 
727
 
 
728
  /* Set members, which might be missing */
 
729
  v->video_format_in.pixel_width  = 1;
 
730
  v->video_format_in.pixel_height = 1;
 
731
  
 
732
  /* Set video format */
 
733
  gavl_video_format_copy(&v->video_format_in_real, &v->video_format_in);
 
734
  
 
735
  /* Open visualizer plugin */
 
736
  
 
737
  if(v->do_ov)
 
738
    {
 
739
    v->vis_plugin->open_ov(v->vis_handle->priv, &v->audio_format_out,
 
740
                           &v->video_format_in_real);
 
741
    
 
742
    gavl_video_format_copy(&v->video_format_out, &v->video_format_in_real);
 
743
    
 
744
    /* Open OV Plugin */
 
745
    if(!v->ov_plugin->open(v->ov_handle->priv, &v->video_format_out, 0))
 
746
      return 0;
 
747
    
 
748
    /* Initialize video converter */
 
749
    
 
750
    v->do_convert_video =
 
751
      gavl_video_converter_init(v->video_cnv, &v->video_format_in_real,
 
752
                                &v->video_format_out);
 
753
    
 
754
    if(v->ov_plugin->create_frame)
 
755
      v->video_frame_out = v->ov_plugin->create_frame(v->ov_handle->priv);
 
756
    else
 
757
      v->video_frame_out = gavl_video_frame_create(&v->video_format_out);
 
758
    
 
759
    if(v->do_convert_video)
 
760
      v->video_frame_in = gavl_video_frame_create(&v->video_format_in_real);
 
761
    }
 
762
  else
 
763
    {
 
764
    if(!v->vis_plugin->open_win(v->vis_handle->priv, &v->audio_format_out,
 
765
                                v->window_id))
 
766
      return 0;
 
767
    gavl_video_format_copy(&v->video_format_out, &v->video_format_in);
 
768
    }
 
769
  
 
770
  audio_buffer_init(v->audio_buffer, &v->audio_format_in, &v->audio_format_out);
 
771
  return 1;
 
772
  }
 
773
 
 
774
 
 
775
static int msg_read_callback(void * priv, uint8_t * data, int len)
 
776
  {
 
777
  return read(STDIN_FILENO, data, len);
 
778
  }
 
779
 
 
780
static int msg_write_callback(void * priv, const uint8_t * data, int len)
 
781
  {
 
782
  return write(STDOUT_FILENO, data, len);
 
783
  }
 
784
 
 
785
static int write_message(msg)
 
786
  {
 
787
  int result;
 
788
//  fprintf(stderr, "Write message slave...\n");
 
789
  result = bg_msg_write(msg, msg_write_callback, NULL);
 
790
//  fprintf(stderr, "Write message slave done %d\n", result);
 
791
  return result;
 
792
  }
 
793
 
 
794
static void flush_queue(bg_msg_queue_t * queue)
 
795
  {
 
796
  bg_msg_t * msg;
 
797
  while((msg = bg_msg_queue_try_lock_read(queue)))
 
798
    {
 
799
    write_message(msg);
 
800
    bg_msg_queue_unlock_read(queue);
 
801
    }
 
802
  }
 
803
 
 
804
 
 
805
int main(int argc, char ** argv)
 
806
  {
 
807
  gavl_audio_format_t audio_format;
 
808
  gavl_audio_frame_t * audio_frame = (gavl_audio_frame_t *)0;
 
809
  float arg_f;
 
810
  
 
811
  int keep_going;
 
812
  bg_visualizer_slave_t * s;
 
813
  bg_msg_t * msg;
 
814
 
 
815
  char * parameter_name = (char*)0;
 
816
  bg_parameter_value_t parameter_value;
 
817
  bg_msg_queue_t * log_queue;
 
818
  int counter = 0.0;
 
819
  bg_parameter_type_t parameter_type;
 
820
  gavl_dsp_context_t * ctx;
 
821
  int big_endian;
 
822
  int result;
 
823
 
 
824
  ctx = gavl_dsp_context_create();
 
825
  
 
826
  memset(&parameter_value, 0, sizeof(parameter_value));
 
827
  
 
828
  if(isatty(fileno(stdin)))
 
829
    {
 
830
    printf("This program is not meant to be started from the commandline.\nThe official frontend API for visualizatons is in " PREFIX "/include/gmerlin/visualize.h\n");
 
831
    return -1;
 
832
    }
 
833
 
 
834
  log_queue = bg_msg_queue_create();
 
835
  bg_log_set_dest(log_queue);
 
836
    
 
837
  s = bg_visualizer_slave_create(argc, argv);
 
838
 
 
839
  msg = bg_msg_create();
 
840
 
 
841
  keep_going = 1;
 
842
  
 
843
  while(keep_going)
 
844
    {
 
845
//    fprintf(stderr, "Read message slave...\n"); 
 
846
    result = bg_msg_read(msg, msg_read_callback, (void*)0);
 
847
//    fprintf(stderr, "Read message slave done %d\n", result);
 
848
    if(!result)
 
849
      break;
 
850
    
 
851
    switch(bg_msg_get_id(msg))
 
852
      {
 
853
      case BG_VIS_MSG_AUDIO_FORMAT:
 
854
        bg_msg_get_arg_audio_format(msg, 0, &audio_format, &big_endian);
 
855
 
 
856
        bg_visualizer_slave_set_audio_format(s, &audio_format);
 
857
        if(audio_frame)
 
858
          gavl_audio_frame_destroy(audio_frame);
 
859
        audio_frame = gavl_audio_frame_create(&audio_format);
 
860
        break;
 
861
      case BG_VIS_MSG_AUDIO_DATA:
 
862
        bg_msg_read_audio_frame(ctx,
 
863
                                msg,
 
864
                                &audio_format,
 
865
                                audio_frame,
 
866
                                msg_read_callback,
 
867
                                (void*)0, big_endian);
 
868
        
 
869
        if(!pthread_mutex_trylock(&s->running_mutex))
 
870
          {
 
871
          pthread_mutex_unlock(&s->running_mutex);
 
872
          break;
 
873
          }
 
874
        else
 
875
          audio_buffer_put(s->audio_buffer,
 
876
                           audio_frame);
 
877
        break;
 
878
      case BG_VIS_MSG_VIS_PARAM:
 
879
        bg_msg_get_parameter(msg,
 
880
                             &parameter_name,
 
881
                             &parameter_type,
 
882
                             &parameter_value);
 
883
       
 
884
        pthread_mutex_lock(&s->vis_mutex);
 
885
        s->vis_plugin->common.set_parameter(s->vis_handle->priv,
 
886
                                            parameter_name,
 
887
                                            &parameter_value);
 
888
        pthread_mutex_unlock(&s->vis_mutex);
 
889
        if(parameter_name)
 
890
          {
 
891
          free(parameter_name);
 
892
          parameter_name = (char*)0;
 
893
          bg_parameter_value_free(&parameter_value,
 
894
                                  parameter_type);
 
895
          }
 
896
        
 
897
        break;
 
898
      case BG_VIS_MSG_OV_PARAM:
 
899
        bg_msg_get_parameter(msg,
 
900
                             &parameter_name,
 
901
                             &parameter_type,
 
902
                             &parameter_value);
 
903
        pthread_mutex_lock(&s->ov_mutex);
 
904
 
 
905
 
 
906
        s->ov_plugin->common.set_parameter(s->ov_handle->priv,
 
907
                                           parameter_name,
 
908
                                           &parameter_value);
 
909
        pthread_mutex_unlock(&s->ov_mutex);
 
910
        if(parameter_name)
 
911
          {
 
912
          free(parameter_name);
 
913
          parameter_name = (char*)0;
 
914
          bg_parameter_value_free(&parameter_value,
 
915
                                  parameter_type);
 
916
          }
 
917
        break;
 
918
      case BG_VIS_MSG_GAIN:
 
919
        arg_f = bg_msg_get_arg_float(msg, 0);
 
920
        audio_buffer_set_gain(s->audio_buffer, arg_f);
 
921
        break;
 
922
      case BG_VIS_MSG_FPS:
 
923
        s->video_format_in.timescale = GAVL_TIME_SCALE;
 
924
        s->video_format_in.frame_duration =
 
925
          (int)(GAVL_TIME_SCALE / bg_msg_get_arg_float(msg, 0));
 
926
        break;
 
927
      case BG_VIS_MSG_IMAGE_SIZE:
 
928
        s->video_format_in.image_width =
 
929
          bg_msg_get_arg_int(msg, 0);
 
930
        s->video_format_in.image_height =
 
931
          bg_msg_get_arg_int(msg, 1);
 
932
 
 
933
        s->video_format_in.frame_width =
 
934
          s->video_format_in.image_width;
 
935
        s->video_format_in.frame_height =
 
936
          s->video_format_in.image_height;
 
937
        break;
 
938
      case BG_VIS_MSG_START:
 
939
        if(!init_plugin(s))
 
940
          bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Starting visualization failed");
 
941
        else
 
942
          bg_visualizer_slave_start(s);
 
943
        break;
 
944
      case BG_VIS_MSG_QUIT:
 
945
        keep_going = 0;
 
946
        break;
 
947
      case BG_VIS_MSG_TELL:
 
948
        flush_queue(log_queue);
 
949
        flush_queue(s->cb_queue);
 
950
        if(counter > 10)
 
951
          {
 
952
          counter = 0;
 
953
 
 
954
          bg_msg_set_id(msg, BG_VIS_SLAVE_MSG_FPS);
 
955
          pthread_mutex_lock(&s->fps_mutex);
 
956
          bg_msg_set_arg_float(msg, 0, s->fps);
 
957
          pthread_mutex_unlock(&s->fps_mutex);
 
958
          write_message(msg);
 
959
          bg_msg_free(msg);
 
960
          
 
961
          }
 
962
        counter++;
 
963
        bg_msg_set_id(msg, BG_VIS_SLAVE_MSG_END);
 
964
        write_message(msg);
 
965
        bg_msg_free(msg);
 
966
        break;
 
967
      }
 
968
    }
 
969
  bg_visualizer_slave_stop(s);
 
970
  cleanup_plugin(s);
 
971
  
 
972
  bg_visualizer_slave_destroy(s);
 
973
  bg_msg_free(msg);
 
974
 
 
975
  gavl_dsp_context_destroy(ctx);
 
976
 
 
977
  return 0;
 
978
  }