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