• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  libzvbi -- Raw VBI decoder
3  *
4  *  Copyright (C) 2000-2004 Michael H. Schimek
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public
17  *  License along with this library; if not, write to the
18  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA  02110-1301  USA.
20  */
21 
22 /* $Id: raw_decoder.c,v 1.24 2008-08-19 10:04:46 mschimek Exp $ */
23 
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 
33 #include "misc.h"
34 #include "raw_decoder.h"
35 
36 #ifndef RAW_DECODER_PATTERN_DUMP
37 #  define RAW_DECODER_PATTERN_DUMP 0
38 #endif
39 
40 #  define sp_sample_format sampling_format
41 
42 /**
43  * $addtogroup RawDecoder Raw VBI decoder
44  * $ingroup Raw
45  * $brief Converting a raw VBI image to sliced VBI data.
46  */
47 
48 /* Missing:
49    VITC PAL 6-22 11.2us 1.8125 Mbit NRZ two start bits + CRC
50    VITC NTSC 10-21 ditto
51    CGMS NTSC 20 11us .450450 Mbit NRZ ?
52    MOJI
53 */
54 const _vbi_service_par _vbi_service_table[] = {
55   {
56         VBI_SLICED_TELETEXT_A,  /* UNTESTED */
57         "Teletext System A",
58         VBI_VIDEOSTD_SET_625_50,
59         {6, 318},
60         {22, 335},
61         10500, 6203125, 6203125,        /* 397 x FH */
62         0x00AAAAE7, 0xFFFF, 18, 6, 37 * 8, VBI_MODULATION_NRZ_LSB,
63         0,                      /* probably */
64       }, {
65         VBI_SLICED_TELETEXT_B_L10_625,
66         "Teletext System B 625 Level 1.5",
67         VBI_VIDEOSTD_SET_625_50,
68         {7, 320},
69         {22, 335},
70         10300, 6937500, 6937500,        /* 444 x FH */
71         0x00AAAAE4, 0xFFFF, 18, 6, 42 * 8, VBI_MODULATION_NRZ_LSB,
72         0,
73       }, {
74         VBI_SLICED_TELETEXT_B,
75         "Teletext System B, 625",
76         VBI_VIDEOSTD_SET_625_50,
77         {6, 318},
78         {22, 335},
79         10300, 6937500, 6937500,        /* 444 x FH */
80         0x00AAAAE4, 0xFFFF, 18, 6, 42 * 8, VBI_MODULATION_NRZ_LSB,
81         0,
82       }, {
83         VBI_SLICED_TELETEXT_C_625,      /* UNTESTED */
84         "Teletext System C 625",
85         VBI_VIDEOSTD_SET_625_50,
86         {6, 318},
87         {22, 335},
88         10480, 5734375, 5734375,        /* 367 x FH */
89         0x00AAAAE7, 0xFFFF, 18, 6, 33 * 8, VBI_MODULATION_NRZ_LSB,
90         0,
91       }, {
92         VBI_SLICED_TELETEXT_D_625,      /* UNTESTED */
93         "Teletext System D 625",
94         VBI_VIDEOSTD_SET_625_50,
95         {6, 318},
96         {22, 335},
97         10500,                  /* or 10970 depending on field order */
98         5642787, 5642787,       /* 14/11 x FSC (color subcarrier) */
99         0x00AAAAE5, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
100         0,
101       }, {
102         VBI_SLICED_VPS, "Video Program System",
103         VBI_VIDEOSTD_SET_PAL_BG,
104         {16, 0},
105         {16, 0},
106         12500, 5000000, 2500000,        /* 160 x FH */
107         0xAAAA8A99, 0xFFFFFF, 32, 0, 13 * 8,
108         VBI_MODULATION_BIPHASE_MSB,
109         _VBI_SP_FIELD_NUM,
110       }, {
111         VBI_SLICED_VPS_F2, "Pseudo-VPS on field 2",
112         VBI_VIDEOSTD_SET_PAL_BG,
113         {0, 329},
114         {0, 329},
115         12500, 5000000, 2500000,        /* 160 x FH */
116         0xAAAA8A99, 0xFFFFFF, 32, 0, 13 * 8,
117         VBI_MODULATION_BIPHASE_MSB,
118         _VBI_SP_FIELD_NUM,
119       }, {
120         VBI_SLICED_WSS_625, "Wide Screen Signalling 625",
121         VBI_VIDEOSTD_SET_625_50,
122         {23, 0},
123         {23, 0},
124         11000, 5000000, 833333, /* 160/3 x FH */
125         /* ...1000 111 / 0 0011 1100 0111 1000 0011 111x */
126         /* ...0010 010 / 0 1001 1001 0011 0011 1001 110x */
127         0x8E3C783E, 0x2499339C, 32, 0, 14 * 1,
128         VBI_MODULATION_BIPHASE_LSB,
129         /* Hm. Too easily confused with caption?? */
130         _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
131       }, {
132         VBI_SLICED_CAPTION_625_F1, "Closed Caption 625, field 1",
133         VBI_VIDEOSTD_SET_625_50,
134         {22, 0},
135         {22, 0},
136         10500, 1000000, 500000, /* 32 x FH */
137         0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
138         _VBI_SP_FIELD_NUM,
139       }, {
140         VBI_SLICED_CAPTION_625_F2, "Closed Caption 625, field 2",
141         VBI_VIDEOSTD_SET_625_50,
142         {0, 335},
143         {0, 335},
144         10500, 1000000, 500000, /* 32 x FH */
145         0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
146         _VBI_SP_FIELD_NUM,
147       }, {
148         VBI_SLICED_VBI_625, "VBI 625",  /* Blank VBI */
149         VBI_VIDEOSTD_SET_625_50,
150         {6, 318},
151         {22, 335},
152         10000, 1510000, 1510000,
153         0, 0, 0, 0, 10 * 8, 0,  /* 10.0-2 ... 62.9+1 us */
154         0,
155       }, {
156         VBI_SLICED_TELETEXT_B_525,      /* UNTESTED */
157         "Teletext System B 525",
158         VBI_VIDEOSTD_SET_525_60,
159         {10, 272},
160         {21, 284},
161         10500, 5727272, 5727272,        /* 364 x FH */
162         0x00AAAAE4, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
163         0,
164       }, {
165         VBI_SLICED_TELETEXT_C_525,      /* UNTESTED */
166         "Teletext System C 525",
167         VBI_VIDEOSTD_SET_525_60,
168         {10, 272},
169         {21, 284},
170         10480, 5727272, 5727272,        /* 364 x FH */
171         0x00AAAAE7, 0xFFFF, 18, 6, 33 * 8, VBI_MODULATION_NRZ_LSB,
172         0,
173       }, {
174         VBI_SLICED_TELETEXT_D_525,      /* UNTESTED */
175         "Teletext System D 525",
176         VBI_VIDEOSTD_SET_525_60,
177         {10, 272},
178         {21, 284},
179         9780, 5727272, 5727272, /* 364 x FH */
180         0x00AAAAE5, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
181         0,
182       }, {
183 #if 0                           /* FIXME probably wrong */
184         VBI_SLICED_WSS_CPR1204, /* NOT CONFIRMED (EIA-J CPR-1204) */
185         "Wide Screen Signalling 525",
186         VBI_VIDEOSTD_SET_NTSC_M_JP,
187         {20, 283},
188         {20, 283},
189         11200, 1789773, 447443, /* 1/8 x FSC */
190         0x000000F0, 0xFF, 8, 0, 20 * 1, VBI_MODULATION_NRZ_MSB,
191         /* No useful FRC, but a six bit CRC */
192         0,
193       }, {
194 #endif
195         VBI_SLICED_CAPTION_525_F1,
196         "Closed Caption 525, field 1",
197         VBI_VIDEOSTD_SET_525_60,
198         {21, 0},
199         {21, 0},
200         10500, 1006976, 503488, /* 32 x FH */
201 #if 0
202         /* Test of CRI bits has been removed to handle the
203            incorrect signal observed by Rich Kandel (see
204            _VBI_RAW_SHIFT_CC_CRI). */
205         0x03, 0x0F, 4, 0, 2 * 8, VBI_MODULATION_NRZ_LSB,
206 #else
207         0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
208         /* I've seen CC signals on other lines and there's no
209            way to distinguish from the transmitted data. */
210 #endif
211         _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
212       }, {
213         VBI_SLICED_CAPTION_525_F2,
214         "Closed Caption 525, field 2",
215         VBI_VIDEOSTD_SET_525_60,
216         {0, 284},
217         {0, 284},
218         10500, 1006976, 503488, /* 32 x FH */
219 #if 0
220         /* Test of CRI bits has been removed to handle the
221            incorrect signal observed by Rich Kandel (see
222            _VBI_RAW_SHIFT_CC_CRI). */
223         0x03, 0x0F, 4, 0, 2 * 8, VBI_MODULATION_NRZ_LSB,
224 #else
225         0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
226 #endif
227         _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
228       }, {
229         VBI_SLICED_2xCAPTION_525,       /* NOT CONFIRMED */
230         "2xCaption 525",
231         VBI_VIDEOSTD_SET_525_60,
232         {10, 0},
233         {21, 0},
234         10500, 1006976, 1006976,        /* 64 x FH */
235         0x000554ED, 0xFFFF, 12, 8, 4 * 8,
236         VBI_MODULATION_NRZ_LSB, /* Tb. */
237         _VBI_SP_FIELD_NUM,
238       }, {
239         VBI_SLICED_VBI_525, "VBI 525",  /* Blank VBI */
240         VBI_VIDEOSTD_SET_525_60,
241         {10, 272},
242         {21, 284},
243         9500, 1510000, 1510000,
244         0, 0, 0, 0, 10 * 8, 0,  /* 9.5-1 ... 62.4+1 us */
245         0,
246       }, {
247         0, NULL,
248         VBI_VIDEOSTD_SET_EMPTY,
249         {0, 0},
250         {0, 0},
251         0, 0, 0,
252         0, 0, 0, 0, 0, 0,
253         0,
254       }
255 };
256 
257 _vbi_inline const _vbi_service_par *
find_service_par(unsigned int service)258 find_service_par (unsigned int service)
259 {
260   unsigned int i;
261 
262   for (i = 0; _vbi_service_table[i].id; ++i)
263     if (service == _vbi_service_table[i].id)
264       return _vbi_service_table + i;
265 
266   return NULL;
267 }
268 
269 /**
270  * $ingroup Sliced
271  * $param service A data service identifier, for example from a
272  *   vbi_sliced structure.
273  *
274  * $return
275  * Name of the $a service, in ASCII, or $c NULL if unknown.
276  */
277 const char *
vbi_sliced_name(vbi_service_set service)278 vbi_sliced_name (vbi_service_set service)
279 {
280   const _vbi_service_par *par;
281 
282   /* These are ambiguous */
283   if (service == VBI_SLICED_CAPTION_525)
284     return "Closed Caption 525";
285   if (service == VBI_SLICED_CAPTION_625)
286     return "Closed Caption 625";
287   if (service == (VBI_SLICED_VPS | VBI_SLICED_VPS_F2))
288     return "Video Program System";
289   if (service == VBI_SLICED_TELETEXT_B_L25_625)
290     return "Teletext System B 625 Level 2.5";
291 
292   /* Incorrect, no longer in table */
293   if (service == VBI_SLICED_TELETEXT_BD_525)
294     return "Teletext System B/D";
295 
296   if ((par = find_service_par (service)))
297     return par->label;
298 
299   return NULL;
300 }
301 
302 /**
303  * @ingroup Sliced
304  * @param service A data service identifier, for example from a
305  *   vbi_sliced structure.
306  *
307  * @return
308  * Number of payload bits, @c 0 if the service is unknown.
309  */
310 unsigned int
vbi_sliced_payload_bits(unsigned int service)311 vbi_sliced_payload_bits (unsigned int service)
312 {
313   const _vbi_service_par *par;
314 
315   /* These are ambiguous */
316   if (service == VBI_SLICED_CAPTION_525)
317     return 16;
318   if (service == VBI_SLICED_CAPTION_625)
319     return 16;
320   if (service == (VBI_SLICED_VPS | VBI_SLICED_VPS_F2))
321     return 13 * 8;
322   if (service == VBI_SLICED_TELETEXT_B_L25_625)
323     return 42 * 8;
324 
325   /* Incorrect, no longer in table */
326   if (service == VBI_SLICED_TELETEXT_BD_525)
327     return 34 * 8;
328 
329   if ((par = find_service_par (service)))
330     return par->payload;
331 
332   return 0;
333 }
334 
335 static void
dump_pattern_line(const vbi3_raw_decoder * rd,unsigned int row,FILE * fp)336 dump_pattern_line (const vbi3_raw_decoder * rd, unsigned int row, FILE * fp)
337 {
338   const vbi_sampling_par *sp;
339   unsigned int line;
340   unsigned int i;
341 
342   sp = &rd->sampling;
343 
344   if (sp->interlaced) {
345     unsigned int field = row & 1;
346 
347     if (0 == sp->start[field])
348       line = 0;
349     else
350       line = sp->start[field] + (row >> 1);
351   } else {
352     if (row >= (unsigned int) sp->count[0]) {
353       if (0 == sp->start[1])
354         line = 0;
355       else
356         line = sp->start[1] + row - sp->count[0];
357     } else {
358       if (0 == sp->start[0])
359         line = 0;
360       else
361         line = sp->start[0] + row;
362     }
363   }
364 
365   fprintf (fp, "scan line %3u: ", line);
366 
367   for (i = 0; i < _VBI3_RAW_DECODER_MAX_WAYS; ++i) {
368     unsigned int pos;
369 
370     pos = row * _VBI3_RAW_DECODER_MAX_WAYS;
371     fprintf (fp, "%02x ", (uint8_t) rd->pattern[pos + i]);
372   }
373 
374   fputc ('\n', fp);
375 }
376 
377 void
_vbi3_raw_decoder_dump(const vbi3_raw_decoder * rd,FILE * fp)378 _vbi3_raw_decoder_dump (const vbi3_raw_decoder * rd, FILE * fp)
379 {
380   const vbi_sampling_par *sp;
381   unsigned int i;
382 
383   assert (NULL != fp);
384 
385   fprintf (fp, "vbi3_raw_decoder %p\n", rd);
386 
387   if (NULL == rd)
388     return;
389 
390   fprintf (fp, "  services 0x%08x\n", rd->services);
391 
392   for (i = 0; i < rd->n_jobs; ++i)
393     fprintf (fp, "  job %u: 0x%08x (%s)\n",
394         i + 1, rd->jobs[i].id, vbi_sliced_name (rd->jobs[i].id));
395 
396   if (!rd->pattern) {
397     fprintf (fp, "  no pattern\n");
398     return;
399   }
400 
401   sp = &rd->sampling;
402 
403   for (i = 0; i < ((unsigned int) sp->count[0]
404           + (unsigned int) sp->count[1]); ++i) {
405     fputs ("  ", fp);
406     dump_pattern_line (rd, i, fp);
407   }
408 }
409 
410 #if 0                           /* @UNUSED */
411 _vbi_inline int
412 cpr1204_crc (const vbi_sliced * sliced)
413 {
414   const int poly = (1 << 6) + (1 << 1) + 1;
415   int crc, i;
416 
417   crc = (+(sliced->data[0] << 12)
418       + (sliced->data[1] << 4)
419       + (sliced->data[2]));
420 
421   crc |= (((1 << 6) - 1) << (14 + 6));
422 
423   for (i = 14 + 6 - 1; i >= 0; i--) {
424     if (crc & ((1 << 6) << i))
425       crc ^= poly << i;
426   }
427 
428   return crc;
429 }
430 #endif
431 
432 static vbi_bool
slice(vbi3_raw_decoder * rd,vbi_sliced * sliced,_vbi3_raw_decoder_job * job,unsigned int i,const uint8_t * raw)433 slice (vbi3_raw_decoder * rd,
434     vbi_sliced * sliced,
435     _vbi3_raw_decoder_job * job, unsigned int i, const uint8_t * raw)
436 {
437   if (rd->debug && NULL != rd->sp_lines) {
438     return vbi3_bit_slicer_slice_with_points
439         (&job->slicer,
440         sliced->data,
441         sizeof (sliced->data),
442         rd->sp_lines[i].points,
443         &rd->sp_lines[i].n_points, N_ELEMENTS (rd->sp_lines[i].points), raw);
444   } else {
445     return vbi3_bit_slicer_slice
446         (&job->slicer, sliced->data, sizeof (sliced->data), raw);
447   }
448 }
449 
450 _vbi_inline vbi_sliced *
decode_pattern(vbi3_raw_decoder * rd,vbi_sliced * sliced,int8_t * pattern,unsigned int i,const uint8_t * raw)451 decode_pattern (vbi3_raw_decoder * rd,
452     vbi_sliced * sliced, int8_t * pattern, unsigned int i, const uint8_t * raw)
453 {
454   vbi_sampling_par *sp;
455   int8_t *pat;
456 
457   sp = &rd->sampling;
458 
459   for (pat = pattern;; ++pat) {
460     int j;
461 
462     j = *pat;                   /* data service n, blank 0, or counter -n */
463 
464     if (j > 0) {
465       _vbi3_raw_decoder_job *job;
466 
467       job = rd->jobs + j - 1;
468 
469       if (!slice (rd, sliced, job, i, raw)) {
470         continue;               /* no match, try next data service */
471       }
472 
473       /* FIXME probably wrong */
474       if (0 && VBI_SLICED_WSS_CPR1204 == job->id) {
475         const int poly = (1 << 6) + (1 << 1) + 1;
476         int crc, j;
477 
478         crc = (sliced->data[0] << 12)
479             + (sliced->data[1] << 4)
480             + sliced->data[2];
481         crc |= (((1 << 6) - 1) << (14 + 6));
482 
483         for (j = 14 + 6 - 1; j >= 0; j--) {
484           if (crc & ((1 << 6) << j))
485             crc ^= poly << j;
486         }
487 
488         if (crc)
489           continue;             /* no match */
490       }
491 
492       /* Positive match, output decoded line. */
493 
494       /* FIXME: if we have a field number we should
495          really only set the service id of one field. */
496       sliced->id = job->id;
497       sliced->line = 0;
498 
499       if (i >= (unsigned int) sp->count[0]) {
500         if (sp->synchronous && 0 != sp->start[1])
501           sliced->line = sp->start[1]
502               + i - sp->count[0];
503       } else {
504         if (sp->synchronous && 0 != sp->start[0])
505           sliced->line = sp->start[0] + i;
506       }
507 
508       if (0)
509         fprintf (stderr, "%2d %s\n",
510             sliced->line, vbi_sliced_name (sliced->id));
511 
512       ++sliced;
513 
514       /* Predict line as non-blank, force testing for
515          all data services in the next 128 frames. */
516       pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = -128;
517     } else if (pat == pattern) {
518       /* Line was predicted as blank, once in 16
519          frames look for data services. */
520       if (0 == rd->readjust) {
521         unsigned int size;
522 
523         size = sizeof (*pattern)
524             * (_VBI3_RAW_DECODER_MAX_WAYS - 1);
525 
526         j = pattern[0];
527         memmove (&pattern[0], &pattern[1], size);
528         pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = j;
529       }
530 
531       break;
532     } else if ((j = pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1]) < 0) {
533       /* Increment counter, when zero predict line as
534          blank and stop looking for data services until
535          0 == rd->readjust. */
536       /* Disabled because we may miss caption/subtitles
537          when the signal inserter is disabled during silent
538          periods for more than 4-5 seconds. */
539       /* pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = j + 1; */
540       break;
541     } else {
542       /* found nothing, j = 0 */
543     }
544 
545     /* Try the found data service first next time. */
546     *pat = pattern[0];
547     pattern[0] = j;
548 
549     break;                      /* line done */
550   }
551 
552   return sliced;
553 }
554 
555 /**
556  * $param rd Pointer to vbi3_raw_decoder object allocated with
557  *   vbi3_raw_decoder_new().
558  * $param sliced Buffer to store the decoded vbi_sliced data. Since every
559  *   vbi scan line may contain data, this should be an array of vbi_sliced
560  *   with the same number of elements as scan lines in the raw image
561  *   (vbi_sampling_parameters.count[0] + .count[1]).
562  * $param max_lines Size of $a sliced data array, in lines, not bytes.
563  * $param raw A raw vbi image as described by the vbi_sampling_par
564  *   associated with $a rd.
565  *
566  * Decodes a raw vbi image, consisting of several scan lines of raw vbi data,
567  * to sliced vbi data. The output is sorted by ascending line number.
568  *
569  * Note this function attempts to learn which lines carry which data
570  * service, or if any, to speed up decoding. You should avoid using the same
571  * vbi3_raw_decoder object for different sources.
572  *
573  * $return
574  * The number of lines decoded, i. e. the number of vbi_sliced records
575  * written.
576  */
577 unsigned int
vbi3_raw_decoder_decode(vbi3_raw_decoder * rd,vbi_sliced * sliced,unsigned int max_lines,const uint8_t * raw)578 vbi3_raw_decoder_decode (vbi3_raw_decoder * rd,
579     vbi_sliced * sliced, unsigned int max_lines, const uint8_t * raw)
580 {
581   vbi_sampling_par *sp;
582   unsigned int scan_lines;
583   unsigned int pitch;
584   int8_t *pattern;
585   const uint8_t *raw1;
586   vbi_sliced *sliced_begin;
587   vbi_sliced *sliced_end;
588   unsigned int i;
589 
590   if (!rd->services)
591     return 0;
592 
593   sp = &rd->sampling;
594 
595   scan_lines = sp->count[0] + sp->count[1];
596   pitch = sp->bytes_per_line << sp->interlaced;
597 
598   pattern = rd->pattern;
599 
600   raw1 = raw;
601 
602   sliced_begin = sliced;
603   sliced_end = sliced + max_lines;
604 
605   if (RAW_DECODER_PATTERN_DUMP)
606     _vbi3_raw_decoder_dump (rd, stderr);
607 
608   for (i = 0; i < scan_lines; ++i) {
609     if (sliced >= sliced_end)
610       break;
611 
612     if (sp->interlaced && i == (unsigned int) sp->count[0])
613       raw = raw1 + sp->bytes_per_line;
614 
615     sliced = decode_pattern (rd, sliced, pattern, i, raw);
616 
617     pattern += _VBI3_RAW_DECODER_MAX_WAYS;
618     raw += pitch;
619   }
620 
621   rd->readjust = (rd->readjust + 1) & 15;
622 
623   return sliced - sliced_begin;
624 }
625 
626 /**
627  * $param rd Pointer to vbi3_raw_decoder object allocated with
628  *   vbi3_raw_decoder_new().
629  *
630  * Resets a vbi3_raw_decoder object, removing all services added
631  * with vbi3_raw_decoder_add_services().
632  */
633 void
vbi3_raw_decoder_reset(vbi3_raw_decoder * rd)634 vbi3_raw_decoder_reset (vbi3_raw_decoder * rd)
635 {
636   assert (NULL != rd);
637 
638   if (rd->pattern) {
639     vbi_free (rd->pattern);
640     rd->pattern = NULL;
641   }
642 
643   rd->services = 0;
644   rd->n_jobs = 0;
645 
646   rd->readjust = 1;
647 
648   CLEAR (rd->jobs);
649 }
650 
651 static void
remove_job_from_pattern(vbi3_raw_decoder * rd,int job_num)652 remove_job_from_pattern (vbi3_raw_decoder * rd, int job_num)
653 {
654   int8_t *pattern;
655   unsigned int scan_lines;
656 
657   job_num += 1;                 /* index into rd->jobs, 0 means no job */
658 
659   pattern = rd->pattern;
660   scan_lines = rd->sampling.count[0] + rd->sampling.count[1];
661 
662   /* For each scan line. */
663   while (scan_lines-- > 0) {
664     int8_t *dst;
665     int8_t *src;
666     int8_t *end;
667 
668     dst = pattern;
669     end = pattern + _VBI3_RAW_DECODER_MAX_WAYS;
670 
671     /* Remove jobs with job_num, fill up pattern with 0.
672        Jobs above job_num move down in rd->jobs. */
673     for (src = dst; src < end; ++src) {
674       int8_t num = *src;
675 
676       if (num > job_num)
677         *dst++ = num - 1;
678       else if (num != job_num)
679         *dst++ = num;
680     }
681 
682     while (dst < end)
683       *dst++ = 0;
684 
685     pattern = end;
686   }
687 }
688 
689 /**
690  * $param rd Pointer to vbi3_raw_decoder object allocated with
691  *   vbi3_raw_decoder_new().
692  * $param services Set of data services.
693  *
694  * Removes one or more data services to be decoded from the
695  * vbi3_raw_decoder object.
696  *
697  * $return
698  * Set describing the remaining data services $a rd will decode.
699  */
700 vbi_service_set
vbi3_raw_decoder_remove_services(vbi3_raw_decoder * rd,vbi_service_set services)701     vbi3_raw_decoder_remove_services
702     (vbi3_raw_decoder * rd, vbi_service_set services) {
703   _vbi3_raw_decoder_job *job;
704   unsigned int job_num;
705 
706   assert (NULL != rd);
707 
708   job = rd->jobs;
709   job_num = 0;
710 
711   while (job_num < rd->n_jobs) {
712     if (job->id & services) {
713       if (rd->pattern)
714         remove_job_from_pattern (rd, job_num);
715 
716       memmove (job, job + 1, (rd->n_jobs - job_num - 1) * sizeof (*job));
717 
718       --rd->n_jobs;
719 
720       CLEAR (rd->jobs[rd->n_jobs]);
721     } else {
722       ++job_num;
723     }
724   }
725 
726   rd->services &= ~services;
727 
728   return rd->services;
729 }
730 
731 static vbi_bool
add_job_to_pattern(vbi3_raw_decoder * rd,int job_num,unsigned int * start,unsigned int * count)732 add_job_to_pattern (vbi3_raw_decoder * rd,
733     int job_num, unsigned int *start, unsigned int *count)
734 {
735   int8_t *pattern_end;
736   unsigned int scan_lines;
737   unsigned int field;
738 
739   job_num += 1;                 /* index into rd->jobs, 0 means no job */
740 
741   scan_lines = rd->sampling.count[0]
742       + rd->sampling.count[1];
743 
744   pattern_end = rd->pattern + scan_lines * _VBI3_RAW_DECODER_MAX_WAYS;
745 
746   for (field = 0; field < 2; ++field) {
747     int8_t *pattern;
748     unsigned int i;
749 
750     pattern = rd->pattern + start[field] * _VBI3_RAW_DECODER_MAX_WAYS;
751 
752     /* For each line where we may find the data. */
753     for (i = 0; i < count[field]; ++i) {
754       unsigned int free;
755       int8_t *dst;
756       int8_t *src;
757       int8_t *end;
758 
759       assert (pattern < pattern_end);
760 
761       dst = pattern;
762       end = pattern + _VBI3_RAW_DECODER_MAX_WAYS;
763 
764       free = 0;
765 
766       for (src = dst; src < end; ++src) {
767         int8_t num = *src;
768 
769         if (num <= 0) {
770           ++free;
771           continue;
772         } else {
773           free += (num == job_num);
774           *dst++ = num;
775         }
776       }
777 
778       while (dst < end)
779         *dst++ = 0;
780 
781       if (free <= 1)            /* reserve a NULL way */
782         return FALSE;
783 
784       pattern = end;
785     }
786   }
787 
788   for (field = 0; field < 2; ++field) {
789     int8_t *pattern;
790     unsigned int i;
791 
792     pattern = rd->pattern + start[field] * _VBI3_RAW_DECODER_MAX_WAYS;
793 
794     /* For each line where we may find the data. */
795     for (i = 0; i < count[field]; ++i) {
796       unsigned int way;
797 
798       for (way = 0; pattern[way] > 0; ++way)
799         if (pattern[way] == job_num)
800           break;
801 
802       pattern[way] = job_num;
803       pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = -128;
804 
805       pattern += _VBI3_RAW_DECODER_MAX_WAYS;
806     }
807   }
808 
809   return TRUE;
810 }
811 
812 static void
lines_containing_data(unsigned int start[2],unsigned int count[2],const vbi_sampling_par * sp,const _vbi_service_par * par)813 lines_containing_data (unsigned int start[2],
814     unsigned int count[2],
815     const vbi_sampling_par * sp, const _vbi_service_par * par)
816 {
817   unsigned int field;
818 
819   start[0] = 0;
820   start[1] = sp->count[0];
821 
822   count[0] = sp->count[0];
823   count[1] = sp->count[1];
824 
825   if (!sp->synchronous) {
826     /* XXX Scanning all lines isn't always necessary. */
827     return;
828   }
829 
830   for (field = 0; field < 2; ++field) {
831     unsigned int first;
832     unsigned int last;
833 
834     if (0 == par->first[field]
835         || 0 == par->last[field]) {
836       /* No data on this field. */
837       count[field] = 0;
838       continue;
839     }
840 
841     first = sp->start[field];
842     last = first + sp->count[field] - 1;
843 
844     if (first > 0 && sp->count[field] > 0) {
845       assert (par->first[field] <= par->last[field]);
846 
847       if ((unsigned int) par->first[field] > last
848           || (unsigned int) par->last[field] < first)
849         continue;
850 
851       first = MAX (first, (unsigned int) par->first[field]);
852       last = MIN ((unsigned int) par->last[field], last);
853 
854       start[field] += first - sp->start[field];
855       count[field] = last + 1 - first;
856     }
857   }
858 }
859 
860 /**
861  * $param rd Pointer to vbi3_raw_decoder object allocated with
862  *   vbi3_raw_decoder_new().
863  * $param services Set of data services.
864  * $param strict A value of 0, 1 or 2 requests loose, reliable or strict
865  *  matching of sampling parameters. For example if the data service
866  *  requires knowledge of line numbers, $c 0 will always accept the
867  *  service (which may work if the scan lines are populated in a
868  *  non-confusing way) but $c 1 or $c 2 will not. If the data service
869  *  might use more lines than are sampled, $c 1 will accept but $c 2
870  *  will not. If unsure, set to $c 1.
871  *
872  * Adds one or more data services to be decoded. Currently the libzvbi
873  * raw vbi decoder can decode up to eight data services in parallel.
874  *
875  * $return
876  * Set describing the data services $a rd will decode. The function
877  * eliminates services which cannot be decoded with the current
878  * sampling parameters, or when they exceed the decoder capacity.
879  */
880 /* Attn: strict must be int for compatibility with libzvbi 0.2 (-1 == 0) */
881 vbi_service_set
vbi3_raw_decoder_add_services(vbi3_raw_decoder * rd,vbi_service_set services,int strict)882 vbi3_raw_decoder_add_services (vbi3_raw_decoder * rd,
883     vbi_service_set services, int strict)
884 {
885   const _vbi_service_par *par;
886   double min_offset;
887 
888   assert (NULL != rd);
889 
890   services &= ~(VBI_SLICED_VBI_525 | VBI_SLICED_VBI_625);
891 
892   if (rd->services & services) {
893     info (&rd->log,
894         "Already decoding services 0x%08x.", rd->services & services);
895     services &= ~rd->services;
896   }
897 
898   if (0 == services) {
899     info (&rd->log, "No services to add.");
900     return rd->services;
901   }
902 
903   if (!rd->pattern) {
904     unsigned int scan_lines;
905     unsigned int scan_ways;
906     unsigned int size;
907 
908     scan_lines = rd->sampling.count[0] + rd->sampling.count[1];
909     scan_ways = scan_lines * _VBI3_RAW_DECODER_MAX_WAYS;
910 
911     size = scan_ways * sizeof (rd->pattern[0]);
912     rd->pattern = (int8_t *) vbi_malloc (size);
913     if (NULL == rd->pattern) {
914       error (&rd->log, "Out of memory.");
915       return rd->services;
916     }
917 
918     memset (rd->pattern, 0, scan_ways * sizeof (rd->pattern[0]));
919   }
920 
921   if (525 == rd->sampling.scanning) {
922     min_offset = 7.9e-6;
923   } else {
924     min_offset = 8.0e-6;
925   }
926 
927   for (par = _vbi_service_table; par->id; ++par) {
928     vbi_sampling_par *sp;
929     _vbi3_raw_decoder_job *job;
930     unsigned int start[2];
931     unsigned int count[2];
932     unsigned int sample_offset;
933     unsigned int samples_per_line;
934     unsigned int cri_end;
935     unsigned int j;
936 
937     if (0 == (par->id & services))
938       continue;
939 
940     job = rd->jobs;
941 
942     /* Some jobs can be merged, otherwise we add a new job. */
943     for (j = 0; j < rd->n_jobs; ++j) {
944       unsigned int id = job->id | par->id;
945 
946       /* Level 1.0 and 2.5 */
947       if (0 == (id & ~VBI_SLICED_TELETEXT_B)
948           /* Field 1 and 2 */
949           || 0 == (id & ~VBI_SLICED_CAPTION_525)
950           || 0 == (id & ~VBI_SLICED_CAPTION_625)
951           || 0 == (id & ~(VBI_SLICED_VPS | VBI_SLICED_VPS_F2)))
952         break;
953 
954       ++job;
955     }
956 
957     if (j >= _VBI3_RAW_DECODER_MAX_JOBS) {
958       error (&rd->log,
959           "Set 0x%08x exceeds number of "
960           "simultaneously decodable "
961           "services (%u).", services, _VBI3_RAW_DECODER_MAX_WAYS);
962       break;
963     } else if (j >= rd->n_jobs) {
964       job->id = 0;
965     }
966 
967 
968     sp = &rd->sampling;
969 
970     if (!_vbi_sampling_par_check_services_log (sp, par->id, strict, &rd->log))
971       continue;
972 
973 
974     sample_offset = 0;
975 
976     /* Skip color burst. */
977     /* Offsets aren't that reliable, sigh. */
978     if (0 && sp->offset > 0 && strict > 0) {
979       double offset;
980 
981       offset = sp->offset / (double) sp->sampling_rate;
982       if (offset < min_offset)
983         sample_offset = (int) (min_offset * sp->sampling_rate);
984     }
985 
986     if (VBI_SLICED_WSS_625 & par->id) {
987       /* TODO: WSS 625 occupies only first half of line,
988          we can abort earlier. */
989       cri_end = ~0;
990     } else {
991       cri_end = ~0;
992     }
993 
994     samples_per_line = sp->bytes_per_line
995         / VBI_PIXFMT_BPP (sp->sp_sample_format);
996 
997     if (!_vbi3_bit_slicer_init (&job->slicer)) {
998       assert (!"bit_slicer_init");
999     }
1000 
1001     if (!vbi3_bit_slicer_set_params
1002         (&job->slicer,
1003             sp->sp_sample_format,
1004             sp->sampling_rate,
1005             sample_offset,
1006             samples_per_line,
1007             par->cri_frc >> par->frc_bits,
1008             par->cri_frc_mask >> par->frc_bits,
1009             par->cri_bits,
1010             par->cri_rate,
1011             cri_end,
1012             (par->cri_frc & ((1U << par->frc_bits) - 1)),
1013             par->frc_bits, par->payload, par->bit_rate,
1014             (vbi3_modulation) par->modulation)) {
1015       assert (!"bit_slicer_set_params");
1016     }
1017 
1018     vbi3_bit_slicer_set_log_fn (&job->slicer,
1019         rd->log.mask, rd->log.fn, rd->log.user_data);
1020 
1021     lines_containing_data (start, count, sp, par);
1022 
1023     if (!add_job_to_pattern (rd, job - rd->jobs, start, count)) {
1024       error (&rd->log,
1025           "Out of decoder pattern space for "
1026           "service 0x%08x (%s).", par->id, par->label);
1027       continue;
1028     }
1029 
1030     job->id |= par->id;
1031 
1032     if (job >= rd->jobs + rd->n_jobs)
1033       ++rd->n_jobs;
1034 
1035     rd->services |= par->id;
1036   }
1037 
1038   return rd->services;
1039 }
1040 
1041 vbi_bool
vbi3_raw_decoder_sampling_point(vbi3_raw_decoder * rd,vbi3_bit_slicer_point * point,unsigned int row,unsigned int nth_bit)1042 vbi3_raw_decoder_sampling_point (vbi3_raw_decoder * rd,
1043     vbi3_bit_slicer_point * point, unsigned int row, unsigned int nth_bit)
1044 {
1045   assert (NULL != rd);
1046   assert (NULL != point);
1047 
1048   if (row >= rd->n_sp_lines)
1049     return FALSE;
1050 
1051   if (nth_bit >= rd->sp_lines[row].n_points)
1052     return FALSE;
1053 
1054   *point = rd->sp_lines[row].points[nth_bit];
1055 
1056   return TRUE;
1057 }
1058 
1059 vbi_bool
vbi3_raw_decoder_debug(vbi3_raw_decoder * rd,vbi_bool enable)1060 vbi3_raw_decoder_debug (vbi3_raw_decoder * rd, vbi_bool enable)
1061 {
1062 #if 0                           /* Set but unused */
1063   _vbi3_raw_decoder_sp_line *sp_lines;
1064 #endif
1065   unsigned int n_lines;
1066   vbi_bool r;
1067 
1068   assert (NULL != rd);
1069 
1070 #if 0                           /* Set but unused */
1071   sp_lines = NULL;
1072 #endif
1073   r = TRUE;
1074 
1075   rd->debug = ! !enable;
1076 
1077   n_lines = 0;
1078   if (enable) {
1079     n_lines = rd->sampling.count[0] + rd->sampling.count[1];
1080   }
1081 
1082   switch (rd->sampling.sp_sample_format) {
1083     case VBI_PIXFMT_YUV420:
1084       break;
1085 
1086     default:
1087       /* Not implemented. */
1088       n_lines = 0;
1089       r = FALSE;
1090       break;
1091   }
1092 
1093   if (rd->n_sp_lines == n_lines)
1094     return r;
1095 
1096   vbi_free (rd->sp_lines);
1097   rd->sp_lines = NULL;
1098   rd->n_sp_lines = 0;
1099 
1100   if (n_lines > 0) {
1101     rd->sp_lines = calloc (n_lines, sizeof (*rd->sp_lines));
1102     if (NULL == rd->sp_lines)
1103       return FALSE;
1104 
1105     rd->n_sp_lines = n_lines;
1106   }
1107 
1108   return r;
1109 }
1110 
1111 vbi_service_set
vbi3_raw_decoder_services(vbi3_raw_decoder * rd)1112 vbi3_raw_decoder_services (vbi3_raw_decoder * rd)
1113 {
1114   assert (NULL != rd);
1115 
1116   return rd->services;
1117 }
1118 
1119 /**
1120  * $param rd Pointer to a vbi3_raw_decoder object allocated with
1121  *   vbi3_raw_decoder_new().
1122  * $param sp New sampling parameters.
1123  * $param strict See vbi3_raw_decoder_add_services().
1124  *
1125  * Changes the sampling parameters used by $a rd. This will
1126  * remove all services which have been added with
1127  * vbi3_raw_decoder_add_services() but cannot be decoded with
1128  * the new sampling parameters.
1129  *
1130  * $return
1131  * Set of data services $rd will be decode after the change.
1132  * Can be zero if the sampling parameters are invalid or some
1133  * other error occurred.
1134  */
1135 /* Attn: strict must be int for compatibility with libzvbi 0.2 (-1 == 0) */
1136 vbi_service_set
vbi3_raw_decoder_set_sampling_par(vbi3_raw_decoder * rd,const vbi_sampling_par * sp,int strict)1137     vbi3_raw_decoder_set_sampling_par
1138     (vbi3_raw_decoder * rd, const vbi_sampling_par * sp, int strict) {
1139   unsigned int services;
1140 
1141   assert (NULL != rd);
1142   assert (NULL != sp);
1143 
1144   services = rd->services;
1145 
1146   vbi3_raw_decoder_reset (rd);
1147 
1148   if (!_vbi_sampling_par_valid_log (sp, &rd->log)) {
1149     CLEAR (rd->sampling);
1150     return 0;
1151   }
1152 
1153   rd->sampling = *sp;
1154 
1155   /* Error ignored. */
1156   vbi3_raw_decoder_debug (rd, rd->debug);
1157 
1158   return vbi3_raw_decoder_add_services (rd, services, strict);
1159 }
1160 
1161 /**
1162  * $param rd Pointer to a vbi3_raw_decoder object allocated with
1163  *   vbi3_raw_decoder_new().
1164  * $param sp Sampling parameters will be stored here.
1165  *
1166  * Returns sampling parameters used by $a rd.
1167  */
vbi3_raw_decoder_get_sampling_par(const vbi3_raw_decoder * rd,vbi_sampling_par * sp)1168 void vbi3_raw_decoder_get_sampling_par
1169     (const vbi3_raw_decoder * rd, vbi_sampling_par * sp)
1170 {
1171   assert (NULL != rd);
1172   assert (NULL != sp);
1173 
1174   *sp = rd->sampling;
1175 }
1176 
1177 void
vbi3_raw_decoder_set_log_fn(vbi3_raw_decoder * rd,vbi_log_fn * log_fn,void * user_data,vbi_log_mask mask)1178 vbi3_raw_decoder_set_log_fn (vbi3_raw_decoder * rd,
1179     vbi_log_fn * log_fn, void *user_data, vbi_log_mask mask)
1180 {
1181   unsigned int i;
1182 
1183   assert (NULL != rd);
1184 
1185   if (NULL == log_fn)
1186     mask = 0;
1187 
1188   rd->log.mask = mask;
1189   rd->log.fn = log_fn;
1190   rd->log.user_data = user_data;
1191 
1192   for (i = 0; i < _VBI3_RAW_DECODER_MAX_JOBS; ++i) {
1193     vbi3_bit_slicer_set_log_fn (&rd->jobs[i].slicer, mask, log_fn, user_data);
1194   }
1195 }
1196 
1197 /**
1198  * @internal
1199  *
1200  * Free all resources associated with @a rd.
1201  */
1202 void
_vbi3_raw_decoder_destroy(vbi3_raw_decoder * rd)1203 _vbi3_raw_decoder_destroy (vbi3_raw_decoder * rd)
1204 {
1205   vbi3_raw_decoder_reset (rd);
1206 
1207   vbi3_raw_decoder_debug (rd, FALSE);
1208 
1209   /* Make unusable. */
1210   CLEAR (*rd);
1211 }
1212 
1213 /**
1214  * @internal
1215  *
1216  * See vbi3_raw_decoder_new().
1217  */
1218 vbi_bool
_vbi3_raw_decoder_init(vbi3_raw_decoder * rd,const vbi_sampling_par * sp)1219 _vbi3_raw_decoder_init (vbi3_raw_decoder * rd, const vbi_sampling_par * sp)
1220 {
1221   CLEAR (*rd);
1222 
1223   vbi3_raw_decoder_reset (rd);
1224 
1225   if (NULL != sp) {
1226     if (!_vbi_sampling_par_valid_log (sp, &rd->log))
1227       return FALSE;
1228 
1229     rd->sampling = *sp;
1230   }
1231 
1232   return TRUE;
1233 }
1234 
1235 /**
1236  * $param rd Pointer to a vbi3_raw_decoder object allocated with
1237  *   vbi3_raw_decoder_new(), can be NULL
1238  *
1239  * Deletes a vbi3_raw_decoder object.
1240  */
1241 void
vbi3_raw_decoder_delete(vbi3_raw_decoder * rd)1242 vbi3_raw_decoder_delete (vbi3_raw_decoder * rd)
1243 {
1244   if (NULL == rd)
1245     return;
1246 
1247   _vbi3_raw_decoder_destroy (rd);
1248 
1249   vbi_free (rd);
1250 }
1251 
1252 /**
1253  * $param sp VBI sampling parameters describing the raw VBI image
1254  *   to decode, can be $c NULL. If they are negotiatable you can determine
1255  *   suitable parameters with vbi_sampling_par_from_services(). You can
1256  *   change the sampling parameters later with
1257  *   vbi3_raw_decoder_set_sampling_par().
1258  *
1259  * Allocates a vbi3_raw_decoder object. To actually decode data
1260  * services you must request the data with vbi3_raw_decoder_add_services().
1261  *
1262  * $returns
1263  * NULL when out of memory or the sampling parameters are invalid,
1264  * Otherwise a pointer to an opaque vbi3_raw_decoder object which must
1265  * be deleted with vbi3_raw_decoder_delete() when done.
1266  */
1267 vbi3_raw_decoder *
vbi3_raw_decoder_new(const vbi_sampling_par * sp)1268 vbi3_raw_decoder_new (const vbi_sampling_par * sp)
1269 {
1270   vbi3_raw_decoder *rd;
1271 
1272   rd = vbi_malloc (sizeof (*rd));
1273   if (NULL == rd) {
1274     errno = ENOMEM;
1275     return NULL;
1276   }
1277 
1278   if (!_vbi3_raw_decoder_init (rd, sp)) {
1279     vbi_free (rd);
1280     rd = NULL;
1281   }
1282 
1283   return rd;
1284 }
1285 
1286 /*
1287 Local variables:
1288 c-set-style: K&R
1289 c-basic-offset: 8
1290 End:
1291 */
1292