summaryrefslogtreecommitdiff
path: root/ext/closedcaption/decoder.c
blob: b74e72956d81d0b58ea8ffd7f0875e07130f0034 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
/*
 *  libzvbi -- Old raw VBI decoder
 *
 *  Copyright (C) 2000, 2001, 2002 Michael H. Schimek
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the 
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 *  Boston, MA  02110-1301  USA.
 */

/* $Id: decoder.c,v 1.25 2008-02-19 00:35:15 mschimek Exp $ */

/* Note this code is only retained for compatibility with older versions
   of libzvbi. vbi_raw_decoder is now just a wrapper for the new raw
   decoder (raw_decoder.c) and bit slicer (bit_slicer.c). We'll drop
   the old API in libzvbi 0.3. Other modules (e.g. io-v4l2k.c) should
   already use the new raw VBI decoder directly. */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <pthread.h>

#include "misc.h"
#include "decoder.h"
#include "raw_decoder.h"

/**
 * @addtogroup Rawdec Raw VBI decoder
 * @ingroup Raw
 * @brief Converting raw VBI samples to bits and bytes.
 *
 * The libzvbi already offers hardware interfaces to obtain sliced
 * VBI data for further processing. However if you want to write your own
 * interface or decode data services not covered by libzvbi you can use
 * these lower level functions.
 */

#if 0                           /* LEGACY BIT SLICER */
/*
 *  Bit Slicer
 */

#define OVERSAMPLING 4          /* 1, 2, 4, 8 */
#define THRESH_FRAC 9

/*
 * Note this is just a template. The code is inlined,
 * with bpp and endian being const.
 *
 * This function translates from the image format to
 * plain bytes, with linear interpolation of samples.
 * Could be further improved with a lowpass filter.
 */
static inline unsigned int
sample (uint8_t * raw, int offs, int bpp, int endian)
{
  unsigned char frac = offs;
  int raw0, raw1;

  switch (bpp) {
    case 14:                   /* 1:5:5:5 LE/BE */
      raw += (offs >> 8) * 2;
      raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07C0;
      raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07C0;
      return (raw1 - raw0) * frac + (raw0 << 8);

    case 15:                   /* 5:5:5:1 LE/BE */
      raw += (offs >> 8) * 2;
      raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x03E0;
      raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x03E0;
      return (raw1 - raw0) * frac + (raw0 << 8);

    case 16:                   /* 5:6:5 LE/BE */
      raw += (offs >> 8) * 2;
      raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07E0;
      raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07E0;
      return (raw1 - raw0) * frac + (raw0 << 8);

    default:                   /* 8 (intermediate bytes skipped by caller) */
      raw += (offs >> 8) * bpp;
      return (raw[bpp] - raw[0]) * frac + (raw[0] << 8);
  }
}

/*
 * Note this is just a template. The code is inlined,
 * with bpp being const.
 */
static inline vbi_bool
bit_slicer_tmpl (vbi_bit_slicer * d, uint8_t * raw,
    uint8_t * buf, int bpp, int endian)
{
  unsigned int i, j, k;
  unsigned int cl = 0, thresh0 = d->thresh, tr;
  unsigned int c = 0, t;
  unsigned char b, b1 = 0;
  int raw0, raw1, mask;

  raw += d->skip;

  if (bpp == 14)
    mask = 0x07C0;
  else if (bpp == 15)
    mask = 0x03E0;
  else if (bpp == 16)
    mask = 0x07E0;

  for (i = d->cri_bytes; i > 0; raw += (bpp >= 14 && bpp <= 16) ? 2 : bpp, i--) {
    if (bpp >= 14 && bpp <= 16) {
      raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & mask;
      raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & mask;
      tr = d->thresh >> THRESH_FRAC;
      d->thresh += ((raw0 - tr) * (int) ABS (raw1 - raw0)) >>
          ((bpp == 15) ? 2 : 3);
      t = raw0 * OVERSAMPLING;
    } else {
      tr = d->thresh >> THRESH_FRAC;
      d->thresh += ((int) raw[0] - tr) * (int) ABS (raw[bpp] - raw[0]);
      t = raw[0] * OVERSAMPLING;
    }

    for (j = OVERSAMPLING; j > 0; j--) {
      b = ((t + (OVERSAMPLING / 2)) / OVERSAMPLING >= tr);

      if (b ^ b1) {
        cl = d->oversampling_rate >> 1;
      } else {
        cl += d->cri_rate;

        if (cl >= (unsigned int) d->oversampling_rate) {
          cl -= d->oversampling_rate;

          c = c * 2 + b;

          if ((c & d->cri_mask) == d->cri) {
            i = d->phase_shift;
            tr *= 256;
            c = 0;

            for (j = d->frc_bits; j > 0; j--) {
              c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
              i += d->step;
            }

            if (c ^= d->frc)
              return FALSE;

            /* CRI/FRC found, now get the
               payload and exit */

            switch (d->endian) {
              case 3:
                for (j = 0; j < (unsigned int) d->payload; j++) {
                  c >>= 1;
                  c += (sample (raw, i, bpp, endian) >= tr) << 7;
                  i += d->step;

                  if ((j & 7) == 7)
                    *buf++ = c;
                }

                *buf = c >> ((8 - d->payload) & 7);
                break;

              case 2:
                for (j = 0; j < (unsigned int) d->payload; j++) {
                  c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
                  i += d->step;

                  if ((j & 7) == 7)
                    *buf++ = c;
                }

                *buf = c & ((1 << (d->payload & 7)) - 1);
                break;

              case 1:
                for (j = d->payload; j > 0; j--) {
                  for (k = 0; k < 8; k++) {
                    c >>= 1;
                    c += (sample (raw, i, bpp, endian) >= tr) << 7;
                    i += d->step;
                  }

                  *buf++ = c;
                }

                break;

              case 0:
                for (j = d->payload; j > 0; j--) {
                  for (k = 0; k < 8; k++) {
                    c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
                    i += d->step;
                  }

                  *buf++ = c;
                }

                break;
            }

            return TRUE;
          }
        }
      }

      b1 = b;

      if (OVERSAMPLING > 1) {
        if (bpp >= 14 && bpp <= 16) {
          t += raw1;
          t -= raw0;
        } else {
          t += raw[bpp];
          t -= raw[0];
        }
      }
    }
  }

  d->thresh = thresh0;

  return FALSE;
}

static vbi_bool
bit_slicer_1 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 1, 0);
}

static vbi_bool
bit_slicer_2 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 2, 0);
}

static vbi_bool
bit_slicer_3 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 3, 0);
}

static vbi_bool
bit_slicer_4 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 4, 0);
}

static vbi_bool
bit_slicer_1555_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 14, 0);
}

static vbi_bool
bit_slicer_5551_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 15, 0);
}

static vbi_bool
bit_slicer_565_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 16, 0);
}

static vbi_bool
bit_slicer_1555_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 14, 1);
}

static vbi_bool
bit_slicer_5551_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 15, 1);
}

static vbi_bool
bit_slicer_565_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
{
  return bit_slicer_tmpl (d, raw, buf, 16, 1);
}

/**
 * @param slicer Pointer to vbi_bit_slicer object to be initialized. 
 * @param raw_samples Number of samples or pixels in one raw vbi line
 *   later passed to vbi_bit_slice(). This limits the number of
 *   bytes read from the sample buffer.
 * @param sampling_rate Raw vbi sampling rate in Hz, that is the number of
 *   samples or pixels sampled per second by the hardware. 
 * @param cri_rate The Clock Run In is a NRZ modulated
 *   sequence of '0' and '1' bits prepending most data transmissions to
 *   synchronize data acquisition circuits. This parameter gives the CRI bit
 *   rate in Hz, that is the number of CRI bits transmitted per second.
 * @param bit_rate The transmission bit rate of all data bits following the CRI
 *   in Hz.
 * @param cri_frc The FRaming Code usually following the CRI is a bit sequence
 *   identifying the data service, and per libzvbi definition modulated
 *   and transmitted at the same bit rate as the payload (however nothing
 *   stops you from counting all nominal CRI and FRC bits as CRI).
 *   The bit slicer compares the bits in this word, lsb last transmitted,
 *   against the transmitted CRI and FRC. Decoding of payload starts
 *   with the next bit after a match.
 * @param cri_mask Of the CRI bits in @c cri_frc, only these bits are
 *   actually significant for a match. For instance it is wise
 *   not to rely on the very first CRI bits transmitted. Note this
 *   mask is not shifted left by @a frc_bits.
 * @param cri_bits 
 * @param frc_bits Number of CRI and FRC bits in @a cri_frc, respectively.
 *   Their sum is limited to 32.
 * @param payload Number of payload <em>bits</em>. Only this data
 *   will be stored in the vbi_bit_slice() output. If this number
 *   is no multiple of eight, the most significant bits of the
 *   last byte are undefined.
 * @param modulation Modulation of the vbi data, see vbi_modulation.
 * @param fmt Format of the raw data, see vbi_pixfmt.
 * 
 * Initializes vbi_bit_slicer object. Usually you will not use this
 * function but vbi_raw_decode(), the vbi image decoder which handles
 * all these details.
 */
void
vbi_bit_slicer_init (vbi_bit_slicer * slicer,
    int raw_samples, int sampling_rate,
    int cri_rate, int bit_rate,
    unsigned int cri_frc, unsigned int cri_mask,
    int cri_bits, int frc_bits, int payload,
    vbi_modulation modulation, vbi_pixfmt fmt)
{
  unsigned int c_mask = (unsigned int) (-(cri_bits > 0)) >> (32 - cri_bits);
  unsigned int f_mask = (unsigned int) (-(frc_bits > 0)) >> (32 - frc_bits);
  int gsh = 0;

  slicer->func = bit_slicer_1;

  switch (fmt) {
    case VBI_PIXFMT_RGB24:
    case VBI_PIXFMT_BGR24:
      slicer->func = bit_slicer_3;
      slicer->skip = 1;
      break;

    case VBI_PIXFMT_RGBA32_LE:
    case VBI_PIXFMT_BGRA32_LE:
      slicer->func = bit_slicer_4;
      slicer->skip = 1;
      break;

    case VBI_PIXFMT_RGBA32_BE:
    case VBI_PIXFMT_BGRA32_BE:
      slicer->func = bit_slicer_4;
      slicer->skip = 2;
      break;

    case VBI_PIXFMT_RGB16_LE:
    case VBI_PIXFMT_BGR16_LE:
      slicer->func = bit_slicer_565_le;
      gsh = 3;                  /* (green << 3) & 0x07E0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_RGBA15_LE:
    case VBI_PIXFMT_BGRA15_LE:
      slicer->func = bit_slicer_5551_le;
      gsh = 2;                  /* (green << 2) & 0x03E0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_ARGB15_LE:
    case VBI_PIXFMT_ABGR15_LE:
      slicer->func = bit_slicer_1555_le;
      gsh = 3;                  /* (green << 2) & 0x07C0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_RGB16_BE:
    case VBI_PIXFMT_BGR16_BE:
      slicer->func = bit_slicer_565_be;
      gsh = 3;                  /* (green << 3) & 0x07E0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_RGBA15_BE:
    case VBI_PIXFMT_BGRA15_BE:
      slicer->func = bit_slicer_5551_be;
      gsh = 2;                  /* (green << 2) & 0x03E0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_ARGB15_BE:
    case VBI_PIXFMT_ABGR15_BE:
      slicer->func = bit_slicer_1555_be;
      gsh = 3;                  /* (green << 2) & 0x07C0 */
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_YUV420:
      slicer->func = bit_slicer_1;
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_YUYV:
    case VBI_PIXFMT_YVYU:
      slicer->func = bit_slicer_2;
      slicer->skip = 0;
      break;

    case VBI_PIXFMT_UYVY:
    case VBI_PIXFMT_VYUY:
      slicer->func = bit_slicer_2;
      slicer->skip = 1;
      break;

    default:
      fprintf (stderr, "vbi_bit_slicer_init: unknown pixfmt %d\n", fmt);
      exit (EXIT_FAILURE);
  }

  slicer->cri_mask = cri_mask & c_mask;
  slicer->cri = (cri_frc >> frc_bits) & slicer->cri_mask;
  /* We stop searching for CRI/FRC when the payload
     cannot possibly fit anymore. */
  slicer->cri_bytes = raw_samples
      - ((long long) sampling_rate * (payload + frc_bits)) / bit_rate;
  slicer->cri_rate = cri_rate;
  /* Raw vbi data is oversampled to account for low sampling rates. */
  slicer->oversampling_rate = sampling_rate * OVERSAMPLING;
  /* 0/1 threshold */
  slicer->thresh = 105 << (THRESH_FRAC + gsh);
  slicer->frc = cri_frc & f_mask;
  slicer->frc_bits = frc_bits;
  /* Payload bit distance in 1/256 raw samples. */
  slicer->step = (int) (sampling_rate * 256.0 / bit_rate);

  if (payload & 7) {
    slicer->payload = payload;
    slicer->endian = 3;
  } else {
    slicer->payload = payload >> 3;
    slicer->endian = 1;
  }

  switch (modulation) {
    case VBI_MODULATION_NRZ_MSB:
      slicer->endian--;
    case VBI_MODULATION_NRZ_LSB:
      slicer->phase_shift = (int)
          (sampling_rate * 256.0 / cri_rate * .5
          + sampling_rate * 256.0 / bit_rate * .5 + 128);
      break;

    case VBI_MODULATION_BIPHASE_MSB:
      slicer->endian--;
    case VBI_MODULATION_BIPHASE_LSB:
      /* Phase shift between the NRZ modulated CRI and the rest */
      slicer->phase_shift = (int)
          (sampling_rate * 256.0 / cri_rate * .5
          + sampling_rate * 256.0 / bit_rate * .25 + 128);
      break;
  }
}

#endif

/**
 * @example examples/wss.c
 * WSS capture example.
 */

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param raw A raw vbi image as defined in the vbi_raw_decoder structure
 *   (rd->sampling_format, rd->bytes_per_line, rd->count[0] + rd->count[1]
 *    scan lines).
 * @param out Buffer to store the decoded vbi_sliced data. Since every
 *   vbi scan line may contain data, this must be an array of vbi_sliced
 *   with the same number of entries as scan lines in the raw image
 *   (rd->count[0] + rd->count[1]).
 * 
 * Decode a raw vbi image, consisting of several scan lines of raw vbi data,
 * into sliced vbi data. The output is sorted by line number.
 * 
 * Note this function attempts to learn which lines carry which data
 * service, or none, to speed up decoding. You should avoid using the same
 * vbi_raw_decoder structure for different sources.
 *
 * @return
 * The number of lines decoded, i. e. the number of vbi_sliced records
 * written.
 */
int
vbi_raw_decode (vbi_raw_decoder * rd, uint8_t * raw, vbi_sliced * out)
{
  vbi3_raw_decoder *rd3;
  unsigned int n_lines;

  assert (NULL != rd);
  assert (NULL != raw);
  assert (NULL != out);

  rd3 = (vbi3_raw_decoder *) rd->pattern;
  n_lines = rd->count[0] + rd->count[1];

  pthread_mutex_lock (&rd->mutex);

  {
    n_lines = vbi3_raw_decoder_decode (rd3, out, n_lines, raw);
  }

  pthread_mutex_unlock (&rd->mutex);

  return n_lines;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param start Array of start line indices for both fields
 * @param count Array of line counts for both fields
 * 
 * Grows or shrinks the internal state arrays for VBI geometry changes
 */
void
vbi_raw_decoder_resize (vbi_raw_decoder * rd, int *start, unsigned int *count)
{
#if 0                           /* Set but unused */
  vbi_service_set service_set;
#endif
  vbi3_raw_decoder *rd3;

  assert (NULL != rd);
  assert (NULL != start);
  assert (NULL != count);

  rd3 = (vbi3_raw_decoder *) rd->pattern;

  pthread_mutex_lock (&rd->mutex);

  {
    if ((rd->start[0] == start[0])
        && (rd->start[1] == start[1])
        && (rd->count[0] == (int) count[0])
        && (rd->count[1] == (int) count[1])) {
      pthread_mutex_unlock (&rd->mutex);
      return;
    }

    rd->start[0] = start[0];
    rd->start[1] = start[1];
    rd->count[0] = count[0];
    rd->count[1] = count[1];

#if 0                           /* Set but unused */
    service_set = vbi3_raw_decoder_set_sampling_par
        (rd3, (vbi_sampling_par *) rd, /* strict */ 0);
#else
    vbi3_raw_decoder_set_sampling_par
        (rd3, (vbi_sampling_par *) rd, /* strict */ 0);
#endif
  }

  pthread_mutex_unlock (&rd->mutex);
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * 
 * Removes one or more data services to be decoded from the
 * vbi_raw_decoder structure. This function can be called at any
 * time and does not touch sampling parameters. 
 * 
 * @return 
 * Set of @ref VBI_SLICED_ symbols describing the remaining data
 * services that will be decoded.
 */
unsigned int
vbi_raw_decoder_remove_services (vbi_raw_decoder * rd, unsigned int services)
{
  vbi_service_set service_set;
  vbi3_raw_decoder *rd3;

  assert (NULL != rd);

  rd3 = (vbi3_raw_decoder *) rd->pattern;
  service_set = services;

  pthread_mutex_lock (&rd->mutex);

  {
    service_set = vbi3_raw_decoder_remove_services (rd3, service_set);
  }

  pthread_mutex_unlock (&rd->mutex);

  return service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * @param strict See description of vbi_raw_decoder_add_services()
 *
 * Check which of the given services can be decoded with current capture
 * parameters at a given strictness level.
 *
 * @return
 * Subset of services actually decodable.
 */
unsigned int
vbi_raw_decoder_check_services (vbi_raw_decoder * rd,
    unsigned int services, int strict)
{
  vbi_service_set service_set;

  assert (NULL != rd);

  service_set = services;

  pthread_mutex_lock (&rd->mutex);

  {
    service_set = vbi_sampling_par_check_services
        ((vbi_sampling_par *) rd, service_set, strict);
  }

  pthread_mutex_unlock (&rd->mutex);

  return (unsigned int) service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * @param strict A value of 0, 1 or 2 requests loose, reliable or strict
 *  matching of sampling parameters. For example if the data service
 *  requires knowledge of line numbers while they are not known, @c 0
 *  will accept the service (which may work if the scan lines are
 *  populated in a non-confusing way) but @c 1 or @c 2 will not. If the
 *  data service <i>may</i> use more lines than are sampled, @c 1 will
 *  accept but @c 2 will not. If unsure, set to @c 1.
 * 
 * After you initialized the sampling parameters in @a rd (according to
 * the abilities of your raw vbi source), this function adds one or more
 * data services to be decoded. The libzvbi raw vbi decoder can decode up
 * to eight data services in parallel. You can call this function while
 * already decoding, it does not change sampling parameters and you must
 * not change them either after calling this.
 * 
 * @return
 * Set of @ref VBI_SLICED_ symbols describing the data services that actually
 * will be decoded. This excludes those services not decodable given
 * the sampling parameters in @a rd.
 */
unsigned int
vbi_raw_decoder_add_services (vbi_raw_decoder * rd,
    unsigned int services, int strict)
{
  vbi_service_set service_set;
  vbi3_raw_decoder *rd3;

  assert (NULL != rd);

  rd3 = (vbi3_raw_decoder *) rd->pattern;
  service_set = services;

  pthread_mutex_lock (&rd->mutex);

  {
    vbi3_raw_decoder_set_sampling_par (rd3, (vbi_sampling_par *) rd, strict);

    service_set = vbi3_raw_decoder_add_services (rd3, service_set, strict);
  }

  pthread_mutex_unlock (&rd->mutex);

  return service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
 *   can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
 *   vbi scan lines in the calculated sampling parameters.
 * @param scanning When 525 accept only NTSC services, when 625
 *   only PAL/SECAM services. When scanning is 0, determine the scanning
 *   from the requested services, an ambiguous set will pick
 *   a 525 or 625 line system at random.
 * @param max_rate If given, the highest data bit rate in Hz of all
 *   services requested is stored here. (The sampling rate
 *   should be at least twice as high; rd->sampling_rate will
 *   be set to a more reasonable value of 27 MHz derived
 *   from ITU-R Rec. 601.)
 * 
 * Calculate the sampling parameters in @a rd required to receive and
 * decode the requested data @a services. rd->sampling_format will be
 * @c VBI_PIXFMT_YUV420, rd->bytes_per_line set accordingly to a
 * reasonable minimum. This function can be used to initialize hardware
 * prior to calling vbi_raw_decoder_add_service().
 * 
 * @return
 * Set of @ref VBI_SLICED_ symbols describing the data services covered
 * by the calculated sampling parameters. This excludes services the libzvbi
 * raw decoder cannot decode.
 */
unsigned int
vbi_raw_decoder_parameters (vbi_raw_decoder * rd,
    unsigned int services, int scanning, int *max_rate)
{
  vbi_videostd_set videostd_set;
  vbi_service_set service_set;

  switch (scanning) {
    case 525:
      videostd_set = VBI_VIDEOSTD_SET_525_60;
      break;

    case 625:
      videostd_set = VBI_VIDEOSTD_SET_625_50;
      break;

    default:
      videostd_set = 0;
      break;
  }

  service_set = services;

  pthread_mutex_lock (&rd->mutex);

  {
    service_set = vbi_sampling_par_from_services
        ((vbi_sampling_par *) rd,
        (unsigned int *) max_rate, videostd_set, service_set);
  }

  pthread_mutex_unlock (&rd->mutex);

  return (unsigned int) service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * 
 * Reset a vbi_raw_decoder structure. This removes
 * all previously added services to be decoded (if any)
 * but does not touch the sampling parameters. You are
 * free to change the sampling parameters after calling this.
 */
void
vbi_raw_decoder_reset (vbi_raw_decoder * rd)
{
  vbi3_raw_decoder *rd3;

  if (!rd)
    return;                     /* compatibility */

  assert (NULL != rd);

  rd3 = (vbi3_raw_decoder *) rd->pattern;

  pthread_mutex_lock (&rd->mutex);

  {
    vbi3_raw_decoder_reset (rd3);
  }

  pthread_mutex_unlock (&rd->mutex);
}

/**
 * @param rd Pointer to initialized vbi_raw_decoder
 *  structure, can be @c NULL.
 * 
 * Free all resources associated with @a rd.
 */
void
vbi_raw_decoder_destroy (vbi_raw_decoder * rd)
{
  vbi3_raw_decoder *rd3;

  assert (NULL != rd);

  rd3 = (vbi3_raw_decoder *) rd->pattern;

  vbi3_raw_decoder_delete (rd3);

  pthread_mutex_destroy (&rd->mutex);

  CLEAR (*rd);
}

/**
 * @param rd Pointer to a vbi_raw_decoder structure.
 * 
 * Initializes a vbi_raw_decoder structure.
 */
void
vbi_raw_decoder_init (vbi_raw_decoder * rd)
{
  vbi3_raw_decoder *rd3;

  assert (NULL != rd);

  CLEAR (*rd);

  pthread_mutex_init (&rd->mutex, NULL);

  rd3 = vbi3_raw_decoder_new ( /* sampling_par */ NULL);
  assert (NULL != rd3);

  rd->pattern = (int8_t *) rd3;
}

GST_DEBUG_CATEGORY (libzvbi_debug);
void
vbi_initialize_gst_debug (void)
{
  GST_DEBUG_CATEGORY_INIT (libzvbi_debug, "libzvbi", 0, "libzvbi");
}

/*
Local variables:
c-set-style: K&R
c-basic-offset: 8
End:
*/