~ubuntu-branches/ubuntu/gutsy/amsn/gutsy

« back to all changes in this revision

Viewing changes to utils/linux/capture/libng/grab-ng.c

  • Committer: Bazaar Package Importer
  • Author(s): Theodore Karkoulis
  • Date: 2006-01-04 15:26:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104152602-ipe1yg00rl3nlklv
Tags: 0.95-1
New Upstream Release (closes: #345052, #278575).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * next generation[tm] xawtv capture interfaces
 
3
 *
 
4
 * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
 
5
 *
 
6
 */
 
7
 
 
8
#define NG_PRIVATE
 
9
#include "config.h"
 
10
 
 
11
#include <stdio.h>
 
12
#include <stdlib.h>
 
13
#include <unistd.h>
 
14
#include <string.h>
 
15
#include <pthread.h>
 
16
#include <dirent.h>
 
17
#include <fnmatch.h>
 
18
#include <errno.h>
 
19
#include <ctype.h>
 
20
#include <inttypes.h>
 
21
#include <fcntl.h>
 
22
#include <sys/time.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
 
 
26
#include <dlfcn.h>
 
27
#ifndef RTLD_NOW
 
28
# define RTLD_NOW RTLD_LAZY
 
29
#endif
 
30
 
 
31
#include "grab-ng.h"
 
32
 
 
33
int  ng_debug          = 0;
 
34
int  ng_log_bad_stream = 0;
 
35
int  ng_log_resync     = 0;
 
36
 
 
37
int  ng_chromakey      = 0x00ff00ff;
 
38
int  ng_ratio_x        = 4;
 
39
int  ng_ratio_y        = 3;
 
40
int  ng_jpeg_quality   = 75;
 
41
 
 
42
char ng_v4l_conf[256]  = "v4l-conf";
 
43
 
 
44
/* --------------------------------------------------------------------- */
 
45
 
 
46
const unsigned int ng_vfmt_to_depth[VIDEO_FMT_COUNT] = {
 
47
    0,               /* unused   */
 
48
    8,               /* RGB8     */
 
49
    8,               /* GRAY8    */
 
50
    16,              /* RGB15 LE */
 
51
    16,              /* RGB16 LE */
 
52
    16,              /* RGB15 BE */
 
53
    16,              /* RGB16 BE */
 
54
    24,              /* BGR24    */
 
55
    32,              /* BGR32    */
 
56
    24,              /* RGB24    */
 
57
    32,              /* RGB32    */
 
58
    16,              /* LUT2     */
 
59
    32,              /* LUT4     */
 
60
    16,              /* YUYV     */
 
61
    16,              /* YUV422P  */
 
62
    12,              /* YUV420P  */
 
63
    0,               /* MJPEG    */
 
64
    0,               /* JPEG     */
 
65
    16,              /* UYVY     */
 
66
    0,               /* MPEG     */
 
67
};
 
68
 
 
69
const char* ng_vfmt_to_desc[VIDEO_FMT_COUNT] = {
 
70
    "none",
 
71
    "8 bit PseudoColor (dithering)",
 
72
    "8 bit StaticGray",
 
73
    "15 bit TrueColor (LE)",
 
74
    "16 bit TrueColor (LE)",
 
75
    "15 bit TrueColor (BE)",
 
76
    "16 bit TrueColor (BE)",
 
77
    "24 bit TrueColor (LE: bgr)",
 
78
    "32 bit TrueColor (LE: bgr-)",
 
79
    "24 bit TrueColor (BE: rgb)",
 
80
    "32 bit TrueColor (BE: -rgb)",
 
81
    "16 bit TrueColor (lut)",
 
82
    "32 bit TrueColor (lut)",
 
83
    "16 bit YUV 4:2:2 (packed, YUYV)",
 
84
    "16 bit YUV 4:2:2 (planar)",
 
85
    "12 bit YUV 4:2:0 (planar)",
 
86
    "MJPEG (AVI)",
 
87
    "JPEG (JFIF)",
 
88
    "16 bit YUV 4:2:2 (packed, UYVY)",
 
89
    "MPEG video",
 
90
};
 
91
 
 
92
/* --------------------------------------------------------------------- */
 
93
 
 
94
const unsigned int   ng_afmt_to_channels[AUDIO_FMT_COUNT] = {
 
95
    0,  1,  2,  1,  2,  1,  2, 0
 
96
};
 
97
const unsigned int   ng_afmt_to_bits[AUDIO_FMT_COUNT] = {
 
98
    0,  8,  8, 16, 16, 16, 16, 0
 
99
};
 
100
const char* ng_afmt_to_desc[AUDIO_FMT_COUNT] = {
 
101
    "none",
 
102
    "8bit mono",
 
103
    "8bit stereo",
 
104
    "16bit mono (LE)",
 
105
    "16bit stereo (LE)",
 
106
    "16bit mono (BE)",
 
107
    "16bit stereo (BE)",
 
108
    "MPEG audio",
 
109
};
 
110
 
 
111
/* --------------------------------------------------------------------- */
 
112
 
 
113
const char* ng_attr_to_desc[] = {
 
114
    "none",
 
115
    "norm",
 
116
    "input",
 
117
    "volume",
 
118
    "mute",
 
119
    "audio mode",
 
120
    "color",
 
121
    "bright",
 
122
    "hue",
 
123
    "contrast",
 
124
};
 
125
 
 
126
/* --------------------------------------------------------------------- */
 
127
 
 
128
void ng_init_video_buf(struct ng_video_buf *buf)
 
129
{
 
130
    memset(buf,0,sizeof(*buf));
 
131
    pthread_mutex_init(&buf->lock,NULL);    
 
132
    pthread_cond_init(&buf->cond,NULL);
 
133
}
 
134
 
 
135
void ng_release_video_buf(struct ng_video_buf *buf)
 
136
{
 
137
    int release;
 
138
 
 
139
    pthread_mutex_lock(&buf->lock);
 
140
    buf->refcount--;
 
141
    release = (buf->refcount == 0);
 
142
    pthread_mutex_unlock(&buf->lock);
 
143
    if (release && NULL != buf->release)
 
144
        buf->release(buf);
 
145
}
 
146
 
 
147
void ng_print_video_buf(char *tag, struct ng_video_buf *buf)
 
148
{
 
149
    fprintf(stderr,"buf %5s: %dx%d [%s]\n",
 
150
            tag, buf->fmt.width, buf->fmt.height,
 
151
            ng_vfmt_to_desc[buf->fmt.fmtid]);
 
152
}
 
153
 
 
154
void ng_copy_video_buf(struct ng_video_buf *dst, struct ng_video_buf *src)
 
155
{
 
156
    memcpy(dst->data, src->data, src->size);
 
157
    dst->size = src->size;
 
158
    dst->info = src->info;
 
159
}
 
160
 
 
161
void ng_wakeup_video_buf(struct ng_video_buf *buf)
 
162
{
 
163
    pthread_cond_signal(&buf->cond);
 
164
}
 
165
 
 
166
void ng_waiton_video_buf(struct ng_video_buf *buf)
 
167
{
 
168
    pthread_mutex_lock(&buf->lock);
 
169
    while (buf->refcount)
 
170
        pthread_cond_wait(&buf->cond, &buf->lock);
 
171
    pthread_mutex_unlock(&buf->lock);
 
172
}
 
173
 
 
174
static int malloc_video_bufs;
 
175
static int malloc_audio_bufs;
 
176
 
 
177
static void ng_free_video_buf(struct ng_video_buf *buf)
 
178
{
 
179
    free(buf->data);
 
180
    free(buf);
 
181
    malloc_video_bufs--;
 
182
}
 
183
 
 
184
struct ng_video_buf*
 
185
ng_malloc_video_buf(void *handle, struct ng_video_fmt *fmt)
 
186
{
 
187
    struct ng_video_buf *buf;
 
188
 
 
189
    buf = malloc(sizeof(*buf));
 
190
    if (NULL == buf)
 
191
        return NULL;
 
192
    ng_init_video_buf(buf);
 
193
    buf->fmt  = *fmt;
 
194
    buf->size = fmt->height * fmt->bytesperline;
 
195
    if (0 == buf->size)
 
196
        buf->size = fmt->width * fmt->height * 3;
 
197
    buf->data = malloc(buf->size);
 
198
    if (NULL == buf->data) {
 
199
        free(buf);
 
200
        return NULL;
 
201
    }
 
202
    buf->refcount = 1;
 
203
    buf->release  = ng_free_video_buf;
 
204
    malloc_video_bufs++;
 
205
    return buf;
 
206
}
 
207
 
 
208
struct ng_audio_buf*
 
209
ng_malloc_audio_buf(struct ng_audio_fmt *fmt, int size)
 
210
{
 
211
    struct ng_audio_buf *buf;
 
212
 
 
213
    buf = malloc(sizeof(*buf)+size);
 
214
    memset(buf,0,sizeof(*buf));
 
215
    buf->fmt  = *fmt;
 
216
    buf->size = size;
 
217
    buf->data = (char*)buf + sizeof(*buf);
 
218
    malloc_audio_bufs++;
 
219
    return buf;
 
220
}
 
221
 
 
222
void ng_free_audio_buf(struct ng_audio_buf *buf)
 
223
{
 
224
    malloc_audio_bufs--;
 
225
    free(buf);
 
226
}
 
227
 
 
228
static void __fini malloc_bufs_check(void)
 
229
{
 
230
    OOPS_ON(malloc_video_bufs > 0, "malloc_video_bufs is %d (expected 0)",
 
231
            malloc_video_bufs);
 
232
    OOPS_ON(malloc_audio_bufs > 0, "malloc_audio_bufs is %d (expected 0)",
 
233
            malloc_audio_bufs);
 
234
}
 
235
 
 
236
/* --------------------------------------------------------------------- */
 
237
 
 
238
struct ng_attribute*
 
239
ng_attr_byid(struct ng_devstate *dev, int id)
 
240
{
 
241
    struct list_head     *item;
 
242
    struct ng_attribute  *attr;
 
243
    
 
244
    list_for_each(item, &dev->attrs) {
 
245
        attr = list_entry(item, struct ng_attribute, device_list);
 
246
        if (attr->id == id)
 
247
            return attr;
 
248
    }
 
249
    return NULL;
 
250
}
 
251
 
 
252
struct ng_attribute*
 
253
ng_attr_byname(struct ng_devstate *dev, char *name)
 
254
{
 
255
    struct list_head     *item;
 
256
    struct ng_attribute  *attr;
 
257
    
 
258
    list_for_each(item, &dev->attrs) {
 
259
        attr = list_entry(item, struct ng_attribute, device_list);
 
260
        if (0 == strcasecmp(attr->name,name))
 
261
            return attr;
 
262
    }
 
263
    return NULL;
 
264
}
 
265
 
 
266
const char*
 
267
ng_attr_getstr(struct ng_attribute *attr, int value)
 
268
{
 
269
    int i;
 
270
    
 
271
    if (NULL == attr)
 
272
        return NULL;
 
273
    if (attr->type != ATTR_TYPE_CHOICE)
 
274
        return NULL;
 
275
 
 
276
    for (i = 0; attr->choices[i].str != NULL; i++)
 
277
        if (attr->choices[i].nr == value)
 
278
            return attr->choices[i].str;
 
279
    return NULL;
 
280
}
 
281
 
 
282
int
 
283
ng_attr_getint(struct ng_attribute *attr, char *value)
 
284
{
 
285
    int i,val;
 
286
    
 
287
    if (NULL == attr)
 
288
        return -1;
 
289
    if (attr->type != ATTR_TYPE_CHOICE)
 
290
        return -1;
 
291
 
 
292
    for (i = 0; attr->choices[i].str != NULL; i++) {
 
293
        if (0 == strcasecmp(attr->choices[i].str,value))
 
294
            return attr->choices[i].nr;
 
295
    }
 
296
 
 
297
    if (isdigit(value[0])) {
 
298
        /* Hmm.  String not found, but starts with a digit.
 
299
           Check if this is a valid number ... */
 
300
        val = atoi(value);
 
301
        for (i = 0; attr->choices[i].str != NULL; i++)
 
302
            if (val == attr->choices[i].nr)
 
303
                return attr->choices[i].nr;
 
304
        
 
305
    }
 
306
    return -1;
 
307
}
 
308
 
 
309
void
 
310
ng_attr_listchoices(struct ng_attribute *attr)
 
311
{
 
312
    int i;
 
313
    
 
314
    fprintf(stderr,"valid choices for \"%s\": ",attr->name);
 
315
    for (i = 0; attr->choices[i].str != NULL; i++)
 
316
        fprintf(stderr,"%s\"%s\"",
 
317
                i ? ", " : "",
 
318
                attr->choices[i].str);
 
319
    fprintf(stderr,"\n");
 
320
}
 
321
 
 
322
int
 
323
ng_attr_int2percent(struct ng_attribute *attr, int value)
 
324
{
 
325
    int range,percent;
 
326
 
 
327
    range   = attr->max - attr->min;
 
328
    percent = (value - attr->min) * 100 / range;
 
329
    if (percent < 0)
 
330
        percent = 0;
 
331
    if (percent > 100)
 
332
        percent = 100;
 
333
    return percent;
 
334
}
 
335
 
 
336
int
 
337
ng_attr_percent2int(struct ng_attribute *attr, int percent)
 
338
{
 
339
    int range,value;
 
340
 
 
341
    range = attr->max - attr->min;
 
342
    value = percent * range / 100 + attr->min;
 
343
    if (value < attr->min)
 
344
        value = attr->min;
 
345
    if (value > attr->max)
 
346
        value = attr->max;
 
347
    return value;
 
348
}
 
349
 
 
350
int
 
351
ng_attr_parse_int(struct ng_attribute *attr, char *str)
 
352
{
 
353
    int value,n;
 
354
 
 
355
    if (0 == sscanf(str,"%d%n",&value,&n))
 
356
        /* parse error */
 
357
        return attr->defval;
 
358
    if (str[n] == '%')
 
359
        value = ng_attr_percent2int(attr,value);
 
360
    if (value < attr->min)
 
361
        value = attr->min;
 
362
    if (value > attr->max)
 
363
        value = attr->max;
 
364
    return value;
 
365
}
 
366
 
 
367
/* --------------------------------------------------------------------- */
 
368
 
 
369
void
 
370
ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff)
 
371
{
 
372
    int h = *height;
 
373
    int w = *width;
 
374
 
 
375
    if (0 == ng_ratio_x || 0 == ng_ratio_y)
 
376
        return;
 
377
    if (w * ng_ratio_y < h * ng_ratio_x) {
 
378
        *height = *width * ng_ratio_y / ng_ratio_x;
 
379
        if (yoff)
 
380
            *yoff  += (h-*height)/2;
 
381
    } else if (w * ng_ratio_y > h * ng_ratio_x) {
 
382
        *width  = *height * ng_ratio_x / ng_ratio_y;
 
383
        if (yoff)
 
384
            *xoff  += (w-*width)/2;
 
385
    }
 
386
}
 
387
 
 
388
void
 
389
ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff,
 
390
                int ratio_x, int ratio_y, int up)
 
391
{
 
392
    int h = *height;
 
393
    int w = *width;
 
394
 
 
395
    if (0 == ratio_x || 0 == ratio_y)
 
396
        return;
 
397
    if ((!up  &&  w * ratio_y < h * ratio_x) ||
 
398
        (up   &&  w * ratio_y > h * ratio_x)) {
 
399
        *height = *width * ratio_y / ratio_x;
 
400
        if (yoff)
 
401
            *yoff  += (h-*height)/2;
 
402
    } else if ((!up  &&  w * ratio_y > h * ratio_x) ||
 
403
               (up   &&  w * ratio_y < h * ratio_x)) {
 
404
        *width  = *height * ratio_x / ratio_y;
 
405
        if (yoff)
 
406
            *xoff  += (w-*width)/2;
 
407
    }
 
408
}
 
409
 
 
410
/* --------------------------------------------------------------------- */
 
411
 
 
412
LIST_HEAD(ng_conv);
 
413
LIST_HEAD(ng_aconv);
 
414
LIST_HEAD(ng_filters);
 
415
LIST_HEAD(ng_writers);
 
416
LIST_HEAD(ng_readers);
 
417
LIST_HEAD(ng_vid_drivers);
 
418
LIST_HEAD(ng_dsp_drivers);
 
419
LIST_HEAD(ng_mix_drivers);
 
420
 
 
421
static int ng_check_magic(int magic, char *plugname, char *type)
 
422
{
 
423
    char *h;
 
424
 
 
425
    h=strrchr(plugname,'/');
 
426
    if (h)
 
427
        h++;
 
428
    else
 
429
        h=plugname;
 
430
    
 
431
    if (magic != NG_PLUGIN_MAGIC) {
 
432
        fprintf(stderr, "ERROR: plugin magic mismatch [me=%x,%s=%x]\n",
 
433
                NG_PLUGIN_MAGIC,h,magic);
 
434
        return -1;
 
435
    }
 
436
#if 0
 
437
    if (ng_debug)
 
438
        fprintf(stderr,"plugins: %s registered by %s\n",type,plugname);
 
439
#endif
 
440
    return 0;
 
441
}
 
442
 
 
443
int
 
444
ng_conv_register(int magic, char *plugname,
 
445
                 struct ng_video_conv *list, int count)
 
446
{
 
447
    int n;
 
448
 
 
449
    if (0 != ng_check_magic(magic,plugname,"video converters"))
 
450
        return -1;
 
451
    for (n = 0; n < count; n++)
 
452
        list_add_tail(&(list[n].list),&ng_conv);
 
453
    return 0;
 
454
}
 
455
 
 
456
int
 
457
ng_aconv_register(int magic, char *plugname,
 
458
                  struct ng_audio_conv *list, int count)
 
459
{
 
460
    int n;
 
461
    
 
462
    if (0 != ng_check_magic(magic,plugname,"audio converters"))
 
463
        return -1;
 
464
    for (n = 0; n < count; n++)
 
465
        list_add_tail(&(list[n].list),&ng_aconv);
 
466
    return 0;
 
467
}
 
468
 
 
469
int
 
470
ng_filter_register(int magic, char *plugname, struct ng_video_filter *filter)
 
471
{
 
472
    if (0 != ng_check_magic(magic,plugname,"filter"))
 
473
        return -1;
 
474
    list_add_tail(&filter->list,&ng_filters);
 
475
    return 0;
 
476
}
 
477
 
 
478
int
 
479
ng_writer_register(int magic, char *plugname, struct ng_writer *writer)
 
480
{
 
481
    if (0 != ng_check_magic(magic,plugname,"writer"))
 
482
        return -1;
 
483
    list_add_tail(&writer->list,&ng_writers);
 
484
    return 0;
 
485
}
 
486
 
 
487
int
 
488
ng_reader_register(int magic, char *plugname, struct ng_reader *reader)
 
489
{
 
490
    if (0 != ng_check_magic(magic,plugname,"reader"))
 
491
        return -1;
 
492
    list_add_tail(&reader->list,&ng_readers);
 
493
    return 0;
 
494
}
 
495
 
 
496
int
 
497
ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver)
 
498
{
 
499
    struct list_head *item;
 
500
    struct ng_vid_driver *drv;
 
501
 
 
502
    if (0 != ng_check_magic(magic,plugname,"video drv"))
 
503
        return -1;
 
504
 
 
505
    list_for_each(item,&ng_vid_drivers) {
 
506
        drv = list_entry(item, struct ng_vid_driver, list);
 
507
        if (drv->priority > driver->priority) {
 
508
            list_add_tail(&driver->list,&drv->list);
 
509
            return 0;
 
510
        }
 
511
    }
 
512
    list_add_tail(&driver->list,&ng_vid_drivers);
 
513
    return 0;
 
514
}
 
515
 
 
516
int
 
517
ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver)
 
518
{
 
519
    struct list_head *item;
 
520
    struct ng_dsp_driver *drv;
 
521
 
 
522
    if (0 != ng_check_magic(magic,plugname,"dsp drv"))
 
523
        return -1;
 
524
 
 
525
    list_for_each(item,&ng_dsp_drivers) {
 
526
        drv = list_entry(item, struct ng_dsp_driver, list);
 
527
        if (drv->priority > driver->priority) {
 
528
            list_add_tail(&driver->list,&drv->list);
 
529
            return 0;
 
530
        }
 
531
    }
 
532
    list_add_tail(&driver->list,&ng_dsp_drivers);
 
533
    return 0;
 
534
}
 
535
 
 
536
int
 
537
ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver)
 
538
{
 
539
    struct list_head *item;
 
540
    struct ng_mix_driver *drv;
 
541
 
 
542
    if (0 != ng_check_magic(magic,plugname,"mixer drv"))
 
543
        return -1;
 
544
 
 
545
    list_for_each(item,&ng_mix_drivers) {
 
546
        drv = list_entry(item, struct ng_mix_driver, list);
 
547
        if (drv->priority > driver->priority) {
 
548
            list_add_tail(&driver->list,&drv->list);
 
549
            return 0;
 
550
        }
 
551
    }
 
552
    list_add_tail(&driver->list,&ng_mix_drivers);
 
553
    return 0;
 
554
}
 
555
 
 
556
struct ng_video_conv*
 
557
ng_conv_find_to(unsigned int out, int *i)
 
558
{
 
559
    struct list_head *item;
 
560
    struct ng_video_conv *ret;
 
561
    int j = 0;
 
562
 
 
563
    list_for_each(item,&ng_conv) {
 
564
        if (j < *i) {
 
565
            j++;
 
566
            continue;
 
567
        }
 
568
        ret = list_entry(item, struct ng_video_conv, list);
 
569
#if 0
 
570
        fprintf(stderr,"\tconv to:  %-28s =>  %s\n",
 
571
                ng_vfmt_to_desc[ret->fmtid_in],
 
572
                ng_vfmt_to_desc[ret->fmtid_out]);
 
573
#endif
 
574
        if (ret->fmtid_out == out) {
 
575
            (*i)++;
 
576
            return ret;
 
577
        }
 
578
        (*i)++;
 
579
        j++;
 
580
    }
 
581
    return NULL;
 
582
}
 
583
 
 
584
struct ng_video_conv*
 
585
ng_conv_find_from(unsigned int in, int *i)
 
586
{
 
587
    struct list_head *item;
 
588
    struct ng_video_conv *ret;
 
589
    
 
590
    int j = 0;
 
591
 
 
592
    list_for_each(item,&ng_conv) {
 
593
        if (j < *i) {
 
594
            j++;
 
595
            continue;
 
596
        }
 
597
        ret = list_entry(item, struct ng_video_conv, list);
 
598
#if 0
 
599
        fprintf(stderr,"\tconv from:  %-28s =>  %s\n",
 
600
                ng_vfmt_to_desc[ret->fmtid_in],
 
601
                ng_vfmt_to_desc[ret->fmtid_out]);
 
602
#endif
 
603
        if (ret->fmtid_in == in) {
 
604
            (*i)++;
 
605
            return ret;
 
606
        }
 
607
    }
 
608
    return NULL;
 
609
}
 
610
 
 
611
struct ng_video_conv*
 
612
ng_conv_find_match(unsigned int in, unsigned int out)
 
613
{
 
614
    struct list_head *item;
 
615
    struct ng_video_conv *ret = NULL;
 
616
    
 
617
    list_for_each(item,&ng_conv) {
 
618
        ret = list_entry(item, struct ng_video_conv, list);
 
619
        if (ret->fmtid_in  == in && ret->fmtid_out == out)
 
620
            return ret;
 
621
    }
 
622
    return NULL;
 
623
}
 
624
 
 
625
/* --------------------------------------------------------------------- */
 
626
 
 
627
int ng_vid_init(struct ng_devstate *dev, char *device)
 
628
{
 
629
    struct list_head *item;
 
630
    struct ng_vid_driver *drv;
 
631
    struct ng_attribute *attr;
 
632
    void *handle;
 
633
    int i, err = ENODEV;
 
634
 
 
635
    /* check all grabber drivers */
 
636
    memset(dev,0,sizeof(*dev));
 
637
    list_for_each(item,&ng_vid_drivers) {
 
638
        drv = list_entry(item, struct ng_vid_driver, list);
 
639
        if (ng_debug)
 
640
            fprintf(stderr,"vid-open: trying: %s... \n", drv->name);
 
641
        if (NULL != (handle = drv->init(device)))
 
642
            break;
 
643
        if (errno)
 
644
            err = errno;
 
645
        if (ng_debug)
 
646
            fprintf(stderr,"vid-open: failed: %s\n",drv->name);
 
647
    }
 
648
    if (item == &ng_vid_drivers)
 
649
        return err;
 
650
    if (ng_debug)
 
651
        fprintf(stderr,"vid-open: ok: %s\n", drv->name);
 
652
 
 
653
    dev->type   = NG_DEV_VIDEO;
 
654
    dev->v      = drv;
 
655
    dev->handle = handle;
 
656
    dev->device = dev->v->devname(dev->handle);
 
657
    dev->flags  = dev->v->capabilities(dev->handle);
 
658
    if (ng_debug)
 
659
        fprintf(stderr,"vid-open: flags: %x\n", dev->flags);
 
660
        
 
661
    INIT_LIST_HEAD(&dev->attrs);
 
662
    attr = dev->v->list_attrs(dev->handle);
 
663
    for (i = 0; attr && attr[i].name; i++) {
 
664
        attr[i].dev   = dev;
 
665
        attr[i].group = dev->device;
 
666
        list_add_tail(&attr[i].device_list,&dev->attrs);
 
667
    }
 
668
    return 0;
 
669
}
 
670
 
 
671
struct ng_devinfo* ng_vid_probe(char *driver)
 
672
{
 
673
    struct list_head *item;
 
674
    struct ng_vid_driver *drv;
 
675
 
 
676
    /* check all grabber drivers */
 
677
    list_for_each(item,&ng_vid_drivers) {
 
678
        drv = list_entry(item, struct ng_vid_driver, list);
 
679
        if (ng_debug)
 
680
            fprintf(stderr,"vid-probe: trying: %s... \n", drv->name);
 
681
        if (strcmp(driver, drv->name))
 
682
            continue;
 
683
 
 
684
        return drv->probe(ng_debug);
 
685
    }
 
686
 
 
687
    return NULL;
 
688
}
 
689
 
 
690
int ng_dsp_init(struct ng_devstate *dev, char *device, int record)
 
691
{
 
692
    struct list_head *item;
 
693
    struct ng_dsp_driver *drv;
 
694
    void *handle;
 
695
    int err = ENODEV;
 
696
 
 
697
    /* check all dsp drivers */
 
698
    list_for_each(item,&ng_dsp_drivers) {
 
699
        drv = list_entry(item, struct ng_dsp_driver, list);
 
700
        if (record && NULL == drv->read)
 
701
            continue;
 
702
        if (!record && NULL == drv->write)
 
703
            continue;
 
704
        if (ng_debug)
 
705
            fprintf(stderr, "dsp-open: trying: %s... \n", drv->name);
 
706
        if (NULL != (handle = drv->init(device, record)))
 
707
            break;
 
708
        if (errno)
 
709
            err = errno;
 
710
        if (ng_debug)
 
711
            fprintf(stderr,"dsp-open: failed: %s\n", drv->name);
 
712
    }
 
713
    if (item == &ng_dsp_drivers)
 
714
        return err;
 
715
    if (ng_debug)
 
716
        fprintf(stderr,"dsp-open: ok: %s\n",drv->name);
 
717
 
 
718
    memset(dev,0,sizeof(*dev));
 
719
    dev->type   = NG_DEV_DSP;
 
720
    dev->a      = drv;
 
721
    dev->handle = handle;
 
722
    dev->device = dev->a->devname(dev->handle);
 
723
    //dev->flags  = dev->a->capabilities(dev->handle);
 
724
    INIT_LIST_HEAD(&dev->attrs);
 
725
 
 
726
    return 0;
 
727
}
 
728
 
 
729
int ng_mix_init(struct ng_devstate *dev, char *device, char *control)
 
730
{
 
731
    struct list_head *item;
 
732
    struct ng_mix_driver *drv;
 
733
    struct ng_attribute *attr;
 
734
    void *handle;
 
735
    int i, err = ENODEV;
 
736
 
 
737
    /* check all dsp drivers */
 
738
    list_for_each(item,&ng_mix_drivers) {
 
739
        drv = list_entry(item, struct ng_mix_driver, list);
 
740
        if (ng_debug)
 
741
            fprintf(stderr, "mix-open: trying: %s... \n", drv->name);
 
742
        if (NULL != (handle = drv->init(device, control)))
 
743
            break;
 
744
        if (errno)
 
745
            err = errno;
 
746
        if (ng_debug)
 
747
            fprintf(stderr,"mix-open: failed: %s\n", drv->name);
 
748
    }
 
749
    if (item == &ng_mix_drivers)
 
750
        return err;
 
751
    if (ng_debug)
 
752
        fprintf(stderr,"mix-open: ok: %s\n",drv->name);
 
753
 
 
754
    memset(dev,0,sizeof(*dev));
 
755
    dev->type   = NG_DEV_MIX;
 
756
    dev->m      = drv;
 
757
    dev->handle = handle;
 
758
    dev->device = dev->m->devname(dev->handle);
 
759
 
 
760
    INIT_LIST_HEAD(&dev->attrs);
 
761
    attr = dev->m->list_attrs(dev->handle);
 
762
    for (i = 0; attr && attr[i].name; i++) {
 
763
        attr[i].dev   = dev;
 
764
        attr[i].group = dev->device;
 
765
        list_add_tail(&attr[i].device_list,&dev->attrs);
 
766
    }
 
767
 
 
768
    return 0;
 
769
}
 
770
 
 
771
int ng_dev_fini(struct ng_devstate *dev)
 
772
{
 
773
    switch (dev->type) {
 
774
    case NG_DEV_NONE:
 
775
        /* nothing */
 
776
        break;
 
777
    case NG_DEV_VIDEO:
 
778
        dev->v->fini(dev->handle);
 
779
        break;
 
780
    case NG_DEV_DSP:
 
781
        dev->a->fini(dev->handle);
 
782
        break;
 
783
    case NG_DEV_MIX:
 
784
        dev->m->fini(dev->handle);
 
785
        break;
 
786
    }
 
787
    memset(dev,0,sizeof(*dev));
 
788
    return 0;
 
789
}
 
790
 
 
791
int ng_dev_open(struct ng_devstate *dev)
 
792
{
 
793
    int rc = 0;
 
794
 
 
795
    if (0 == dev->refcount) {
 
796
        switch (dev->type) {
 
797
        case NG_DEV_NONE:
 
798
            BUG_ON(1,"dev type NONE");
 
799
            break;
 
800
        case NG_DEV_VIDEO:
 
801
            rc = dev->v->open(dev->handle);
 
802
            break;
 
803
        case NG_DEV_DSP:
 
804
            rc = dev->a->open(dev->handle);
 
805
            break;
 
806
        case NG_DEV_MIX:
 
807
            rc = dev->m->open(dev->handle);
 
808
            break;
 
809
        }
 
810
    }
 
811
    if (0 == rc) {
 
812
        dev->refcount++;
 
813
        if (ng_debug)
 
814
            fprintf(stderr,"%s: opened %s [refcount %d]\n",
 
815
                    __FUNCTION__, dev->device, dev->refcount);
 
816
    }
 
817
    return rc;
 
818
}
 
819
 
 
820
int ng_dev_close(struct ng_devstate *dev)
 
821
{
 
822
    dev->refcount--;
 
823
    BUG_ON(dev->refcount < 0, "refcount below 0");
 
824
    
 
825
    if (0 == dev->refcount) {
 
826
        switch (dev->type) {
 
827
        case NG_DEV_NONE:
 
828
            BUG_ON(1,"dev type NONE");
 
829
            break;
 
830
        case NG_DEV_VIDEO:
 
831
            dev->v->close(dev->handle);
 
832
            break;
 
833
        case NG_DEV_DSP:
 
834
            dev->a->close(dev->handle);
 
835
            break;
 
836
        case NG_DEV_MIX:
 
837
            dev->m->close(dev->handle);
 
838
            break;
 
839
        }
 
840
    }
 
841
    if (ng_debug)
 
842
        fprintf(stderr,"%s: closed %s [refcount %d]\n",
 
843
                __FUNCTION__, dev->device, dev->refcount);
 
844
    return 0;
 
845
}
 
846
 
 
847
int ng_dev_users(struct ng_devstate *dev)
 
848
{
 
849
    return dev->refcount;
 
850
}
 
851
 
 
852
int ng_chardev_open(char *device, int flags, int major, int complain)
 
853
{
 
854
    struct stat st;
 
855
    int fd = -1;
 
856
 
 
857
    if (strncmp(device, "/dev/", 5)) {
 
858
        if (complain)
 
859
            fprintf(stderr,"%s: not below /dev\n",device);
 
860
        goto err;
 
861
    }
 
862
    if (-1 == (fd = open(device, flags))) {
 
863
        if (complain)
 
864
            fprintf(stderr,"open(%s): %s\n",device,strerror(errno));
 
865
        goto err;
 
866
    }
 
867
    if (-1 == fstat(fd,&st)) {
 
868
        if (complain)
 
869
            fprintf(stderr,"fstat(%s): %s\n",device,strerror(errno));
 
870
        goto err;
 
871
    }
 
872
    if (!S_ISCHR(st.st_mode)) {
 
873
        if (complain)
 
874
            fprintf(stderr,"%s: not a charcter device\n",device);
 
875
        goto err;
 
876
    }
 
877
    if (major(st.st_rdev) != major) {
 
878
        if (complain)
 
879
            fprintf(stderr,"%s: wrong major number (expected %d, got %d)\n",
 
880
                    device, major, major(st.st_rdev));
 
881
        goto err;
 
882
    }
 
883
    fcntl(fd,F_SETFD,FD_CLOEXEC);
 
884
    return fd;
 
885
 
 
886
 err:
 
887
    if (-1 != fd)
 
888
        close(fd);
 
889
    return -1;
 
890
}
 
891
 
 
892
/* --------------------------------------------------------------------- */
 
893
 
 
894
struct ng_reader* ng_find_reader_magic(char *filename)
 
895
{
 
896
    struct list_head *item;
 
897
    struct ng_reader *reader;
 
898
    char blk[512];
 
899
    FILE *fp;
 
900
    int m;
 
901
 
 
902
    if (NULL == (fp = fopen(filename, "r"))) {
 
903
        fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
 
904
        return NULL;
 
905
    }
 
906
    memset(blk,0,sizeof(blk));
 
907
    fread(blk,1,sizeof(blk),fp);
 
908
    fclose(fp);
 
909
 
 
910
    list_for_each(item,&ng_readers) {
 
911
        reader = list_entry(item, struct ng_reader, list);
 
912
        for (m = 0; m < 8 && reader->mlen[m] > 0; m++) {
 
913
            if (0 == memcmp(blk+reader->moff[m],reader->magic[m],
 
914
                            reader->mlen[m]))
 
915
                return reader;
 
916
        }
 
917
    }
 
918
    if (ng_debug)
 
919
        fprintf(stderr,"%s: no reader found [magic]\n",filename);
 
920
    return NULL;
 
921
}
 
922
 
 
923
struct ng_reader* ng_find_reader_name(char *name)
 
924
{
 
925
    struct list_head *item;
 
926
    struct ng_reader *reader;
 
927
 
 
928
    list_for_each(item,&ng_readers) {
 
929
        reader = list_entry(item, struct ng_reader, list);
 
930
        if (0 == strcasecmp(reader->name,name))
 
931
            return reader;
 
932
    }
 
933
    if (ng_debug)
 
934
        fprintf(stderr,"%s: no reader found [name]\n",name);
 
935
    return NULL;
 
936
}
 
937
 
 
938
struct ng_writer* ng_find_writer_name(char *name)
 
939
{
 
940
    struct list_head *item;
 
941
    struct ng_writer *writer;
 
942
 
 
943
    list_for_each(item,&ng_writers) {
 
944
        writer = list_entry(item, struct ng_writer, list);
 
945
        if (0 == strcasecmp(writer->name,name))
 
946
            return writer;
 
947
    }
 
948
    if (ng_debug)
 
949
        fprintf(stderr,"%s: no writer found [name]\n",name);
 
950
    return NULL;
 
951
}
 
952
 
 
953
int64_t
 
954
ng_tofday_to_timestamp(struct timeval *tv)
 
955
{
 
956
    long long ts;
 
957
 
 
958
    ts  = tv->tv_sec;
 
959
    ts *= 1000000;
 
960
    ts += tv->tv_usec;
 
961
    ts *= 1000;
 
962
    return ts;
 
963
}
 
964
 
 
965
int64_t
 
966
ng_get_timestamp()
 
967
{
 
968
    struct timeval tv;
 
969
 
 
970
    gettimeofday(&tv,NULL);
 
971
    return ng_tofday_to_timestamp(&tv);
 
972
}
 
973
 
 
974
struct ng_video_buf*
 
975
ng_filter_single(struct ng_video_filter *filter, struct ng_video_buf *in)
 
976
{
 
977
    struct ng_video_buf *out = in;
 
978
    void *handle;
 
979
 
 
980
    if (NULL != filter  &&  filter->fmts & (1 << in->fmt.fmtid)) {
 
981
        handle = filter->init(&in->fmt);
 
982
#if 0
 
983
        BUG_ON(1,"not fixed yet");
 
984
        out = filter->frame(handle,in);
 
985
        filter->fini(handle);
 
986
#endif
 
987
    }
 
988
    return out;
 
989
}
 
990
 
 
991
/* --------------------------------------------------------------------- */
 
992
 
 
993
static void clip_dump(char *state, struct OVERLAY_CLIP *oc, int count)
 
994
{
 
995
    int i;
 
996
 
 
997
    fprintf(stderr,"clip: %s - %d clips\n",state,count);
 
998
    for (i = 0; i < count; i++)
 
999
        fprintf(stderr,"clip:   %d: %dx%d+%d+%d\n",i,
 
1000
                oc[i].x2 - oc[i].x1,
 
1001
                oc[i].y2 - oc[i].y1,
 
1002
                oc[i].x1, oc[i].y1);
 
1003
}
 
1004
 
 
1005
static void clip_drop(struct OVERLAY_CLIP *oc, int n, int *count)
 
1006
{
 
1007
    (*count)--;
 
1008
    memmove(oc+n, oc+n+1, sizeof(struct OVERLAY_CLIP) * (*count-n));
 
1009
}
 
1010
 
 
1011
void ng_check_clipping(int width, int height, int xadjust, int yadjust,
 
1012
                       struct OVERLAY_CLIP *oc, int *count)
 
1013
{
 
1014
    int i,j;
 
1015
 
 
1016
    if (ng_debug > 1) {
 
1017
        fprintf(stderr,"clip: win=%dx%d xa=%d ya=%d\n",
 
1018
                width,height,xadjust,yadjust);
 
1019
        clip_dump("init",oc,*count);
 
1020
    }
 
1021
    for (i = 0; i < *count; i++) {
 
1022
        /* fixup coordinates */
 
1023
        oc[i].x1 += xadjust;
 
1024
        oc[i].x2 += xadjust;
 
1025
        oc[i].y1 += yadjust;
 
1026
        oc[i].y2 += yadjust;
 
1027
    }
 
1028
    if (ng_debug > 1)
 
1029
        clip_dump("fixup adjust",oc,*count);
 
1030
 
 
1031
    for (i = 0; i < *count; i++) {
 
1032
        /* fixup borders */
 
1033
        if (oc[i].x1 < 0)
 
1034
            oc[i].x1 = 0;
 
1035
        if (oc[i].x2 < 0)
 
1036
            oc[i].x2 = 0;
 
1037
        if (oc[i].x1 > width)
 
1038
            oc[i].x1 = width;
 
1039
        if (oc[i].x2 > width)
 
1040
            oc[i].x2 = width;
 
1041
        if (oc[i].y1 < 0)
 
1042
            oc[i].y1 = 0;
 
1043
        if (oc[i].y2 < 0)
 
1044
            oc[i].y2 = 0;
 
1045
        if (oc[i].y1 > height)
 
1046
            oc[i].y1 = height;
 
1047
        if (oc[i].y2 > height)
 
1048
            oc[i].y2 = height;
 
1049
    }
 
1050
    if (ng_debug > 1)
 
1051
        clip_dump("fixup range",oc,*count);
 
1052
 
 
1053
    /* drop zero-sized clips */
 
1054
    for (i = 0; i < *count;) {
 
1055
        if (oc[i].x1 == oc[i].x2 || oc[i].y1 == oc[i].y2) {
 
1056
            clip_drop(oc,i,count);
 
1057
            continue;
 
1058
        }
 
1059
        i++;
 
1060
    }
 
1061
    if (ng_debug > 1)
 
1062
        clip_dump("zerosize done",oc,*count);
 
1063
 
 
1064
    /* try to merge clips */
 
1065
 restart_merge:
 
1066
    for (j = *count - 1; j >= 0; j--) {
 
1067
        for (i = 0; i < *count; i++) {
 
1068
            if (i == j)
 
1069
                continue;
 
1070
            if (oc[i].x1 == oc[j].x1 &&
 
1071
                oc[i].x2 == oc[j].x2 &&
 
1072
                oc[i].y1 <= oc[j].y1 &&
 
1073
                oc[i].y2 >= oc[j].y1) {
 
1074
                if (ng_debug > 1)
 
1075
                    fprintf(stderr,"clip: merge y %d,%d\n",i,j);
 
1076
                if (oc[i].y2 < oc[j].y2)
 
1077
                    oc[i].y2 = oc[j].y2;
 
1078
                clip_drop(oc,j,count);
 
1079
                if (ng_debug > 1)
 
1080
                    clip_dump("merge y done",oc,*count);
 
1081
                goto restart_merge;
 
1082
            }
 
1083
            if (oc[i].y1 == oc[j].y1 &&
 
1084
                oc[i].y2 == oc[j].y2 &&
 
1085
                oc[i].x1 <= oc[j].x1 &&
 
1086
                oc[i].x2 >= oc[j].x1) {
 
1087
                if (ng_debug > 1)
 
1088
                    fprintf(stderr,"clip: merge x %d,%d\n",i,j);
 
1089
                if (oc[i].x2 < oc[j].x2)
 
1090
                    oc[i].x2 = oc[j].x2;
 
1091
                clip_drop(oc,j,count);
 
1092
                if (ng_debug > 1)
 
1093
                    clip_dump("merge x done",oc,*count);
 
1094
                goto restart_merge;
 
1095
            }
 
1096
        }
 
1097
    }
 
1098
    if (ng_debug)
 
1099
        clip_dump("final",oc,*count);
 
1100
}
 
1101
 
 
1102
/* --------------------------------------------------------------------- */
 
1103
 
 
1104
#if 0
 
1105
void ng_print_stacktrace(void)
 
1106
{
 
1107
    void *array[16];
 
1108
    size_t size;
 
1109
    char **strings;
 
1110
    size_t i;
 
1111
    
 
1112
    size = backtrace(array, DIMOF(array));
 
1113
    strings = backtrace_symbols(array, size);
 
1114
    
 
1115
    for (i = 0; i < size; i++)
 
1116
        fprintf(stderr, "\t%s\n", strings[i]);
 
1117
    free(strings);
 
1118
}
 
1119
#endif
 
1120
 
 
1121
static int ng_plugins(char *dirname)
 
1122
{
 
1123
    struct dirent **list;
 
1124
    char filename[1024];
 
1125
    void *plugin;
 
1126
#if 1
 
1127
    void (*initcall)(void);
 
1128
#endif
 
1129
    int i,n = 0,l = 0;
 
1130
 
 
1131
    n = scandir(dirname,&list,NULL,alphasort);
 
1132
    if (n <= 0)
 
1133
        return 0;
 
1134
    for (i = 0; i < n; i++) {
 
1135
        if (0 != fnmatch("*.so",list[i]->d_name,0))
 
1136
            continue;
 
1137
        sprintf(filename,"%s/%s",dirname,list[i]->d_name);
 
1138
        if (NULL == (plugin = dlopen(filename,RTLD_NOW))) {
 
1139
            fprintf(stderr,"dlopen: %s\n",dlerror());
 
1140
            continue;
 
1141
        }
 
1142
 
 
1143
        if (NULL == (initcall = dlsym(plugin,"ng_plugin_init"))) {
 
1144
            if (NULL == (initcall = dlsym(plugin,"_ng_plugin_init"))) {
 
1145
                fprintf(stderr,"dlsym[%s]: %s\n",filename,dlerror());
 
1146
                continue;
 
1147
            }
 
1148
        }
 
1149
#if 0
 
1150
        initcall();
 
1151
#endif
 
1152
        l++;
 
1153
    }
 
1154
    for (i = 0; i < n; i++)
 
1155
        free(list[i]);
 
1156
    free(list);
 
1157
    return l;
 
1158
}
 
1159
 
 
1160
void
 
1161
ng_init(void)
 
1162
{
 
1163
    static int once=0;
 
1164
    int count=0;
 
1165
 
 
1166
    if (once++) {
 
1167
        fprintf(stderr,"panic: ng_init called twice\n");
 
1168
        return;
 
1169
    }
 
1170
 
 
1171
 
 
1172
    yuv2rgb_init();
 
1173
    packed_init();
 
1174
 
 
1175
    /* dirty hack: touch ng_dev to make ld _not_ drop devices.o, it is
 
1176
     *             needed by various plugins */
 
1177
    if (!ng_dev.video[0])
 
1178
        return;
 
1179
 
 
1180
    count += ng_plugins(LIBDIR);
 
1181
    count += ng_plugins("./libng/plugins");
 
1182
    count += ng_plugins("./libng/contrib-plugins"); 
 
1183
    count += ng_plugins("../libng/plugins");
 
1184
    count += ng_plugins("../libng/contrib-plugins");
 
1185
    count += ng_plugins("./utils/linux/capture/libng/plugins");
 
1186
    count += ng_plugins("./utils/linux/capture/libng/contrib-plugins");
 
1187
 
 
1188
 
 
1189
    if (0 == count)
 
1190
        fprintf(stderr,"WARNING: no plugins found [%s]\n",LIBDIR);
 
1191
}