1 /*
2 * libzvbi -- Raw VBI sampling parameters
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: sampling_par.c,v 1.11 2009/02/18 15:37:11 mschimek Exp $ */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <errno.h>
29
30 #include "misc.h"
31 #include "raw_decoder.h"
32 #include "sampling_par.h"
33 #include "sliced.h"
34 #include "version.h"
35
36 #if 2 == VBI_VERSION_MINOR
37 # define vbi_pixfmt_bytes_per_pixel VBI_PIXFMT_BPP
38 # define sp_sample_format sampling_format
39 #else
40 # define sp_sample_format sample_format
41 #endif
42
43 /**
44 * @addtogroup Sampling Raw VBI sampling
45 * @ingroup Raw
46 * @brief Raw VBI data sampling interface.
47 */
48
49 /**
50 * @internal
51 * Compatibility.
52 */
53 vbi_videostd_set
_vbi_videostd_set_from_scanning(int scanning)54 _vbi_videostd_set_from_scanning
55 (int scanning)
56 {
57 switch (scanning) {
58 case 525:
59 return VBI_VIDEOSTD_SET_525_60;
60
61 case 625:
62 return VBI_VIDEOSTD_SET_625_50;
63
64 default:
65 break;
66 }
67
68 return 0;
69 }
70
71 _vbi_inline vbi_bool
range_check(unsigned int start,unsigned int count,unsigned int min,unsigned int max)72 range_check (unsigned int start,
73 unsigned int count,
74 unsigned int min,
75 unsigned int max)
76 {
77 /* Check bounds and overflow. */
78 return (start >= min
79 && (start + count) <= max
80 && (start + count) >= start);
81 }
82
83 /**
84 * @internal
85 * @param sp Sampling parameters to verify.
86 *
87 * @return
88 * TRUE if the sampling parameters are valid (as far as we can tell).
89 */
90 vbi_bool
_vbi_sampling_par_valid_log(const vbi_sampling_par * sp,_vbi_log_hook * log)91 _vbi_sampling_par_valid_log (const vbi_sampling_par *sp,
92 _vbi_log_hook * log)
93 {
94 vbi_videostd_set videostd_set;
95 unsigned int bpp;
96
97 assert (NULL != sp);
98
99 switch (sp->sp_sample_format) {
100 case VBI_PIXFMT_YUV420:
101 #if 2 == VBI_VERSION_MINOR
102 /* This conflicts with the ivtv driver, which returns an
103 odd number of bytes per line. The driver format is
104 _GREY but libzvbi 0.2 has no VBI_PIXFMT_Y8. */
105 #else
106 if (sp->samples_per_line & 1)
107 goto bad_samples;
108
109 /* fall through */
110
111 case VBI3_PIXFMT_Y8: /* very common */
112 if (sp->samples_per_line > sp->bytes_per_line)
113 goto too_many_samples;
114 #endif
115 break;
116
117 default:
118 bpp = vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format);
119 #if 2 == VBI_VERSION_MINOR
120 if (0 != (sp->bytes_per_line % bpp))
121 goto bad_samples;
122 #else
123 if (sp->samples_per_line * bpp > sp->bytes_per_line)
124 goto too_many_samples;
125 #endif
126 break;
127 }
128
129 #if 2 == VBI_VERSION_MINOR
130 if (0 == sp->bytes_per_line)
131 goto no_samples;
132 #else
133 if (0 == sp->samples_per_line)
134 goto no_samples;
135 #endif
136
137 if (0 == sp->count[0]
138 && 0 == sp->count[1])
139 goto bad_range;
140
141 #if 2 == VBI_VERSION_MINOR
142 videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
143 #else
144 videostd_set = sp->videostd_set;
145 #endif
146
147 if (VBI_VIDEOSTD_SET_525_60 & videostd_set) {
148 if (VBI_VIDEOSTD_SET_625_50 & videostd_set)
149 goto ambiguous;
150
151 if (0 != sp->start[0]
152 && !range_check (sp->start[0], sp->count[0], 1, 262))
153 goto bad_range;
154
155 if (0 != sp->start[1]
156 && !range_check (sp->start[1], sp->count[1], 263, 525))
157 goto bad_range;
158 } else if (VBI_VIDEOSTD_SET_625_50 & videostd_set) {
159 if (0 != sp->start[0]
160 && !range_check (sp->start[0], sp->count[0], 1, 311))
161 goto bad_range;
162
163 if (0 != sp->start[1]
164 && !range_check (sp->start[1], sp->count[1], 312, 625))
165 goto bad_range;
166 } else {
167 ambiguous:
168 info (log,
169 "Ambiguous videostd_set 0x%lx.",
170 (unsigned long) videostd_set);
171 return FALSE;
172 }
173
174 if (sp->interlaced
175 && (sp->count[0] != sp->count[1]
176 || 0 == sp->count[0])) {
177 info (log,
178 "Line counts %u, %u must be equal and "
179 "non-zero when raw VBI data is interlaced.",
180 sp->count[0], sp->count[1]);
181 return FALSE;
182 }
183
184 return TRUE;
185
186 no_samples:
187 info (log, "samples_per_line is zero.");
188 return FALSE;
189
190 #if 3 == VBI_VERSION_MINOR
191 too_many_samples:
192 info (log,
193 "samples_per_line %u times bytes per samples %u is "
194 "greater than bytes_per_line %u.",
195 sp->samples_per_line,
196 vbi3_pixfmt_bytes_per_pixel (sp->sp_sample_format),
197 sp->bytes_per_line);
198 return FALSE;
199 #endif
200
201 bad_samples:
202 info (log,
203 "bytes_per_line value %u is no multiple of "
204 "the sample size %u.",
205 sp->bytes_per_line,
206 vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format));
207 return FALSE;
208
209 bad_range:
210 info (log,
211 "Invalid VBI scan range %u-%u (%u lines), "
212 "%u-%u (%u lines).",
213 sp->start[0], sp->start[0] + sp->count[0] - 1,
214 sp->count[0],
215 sp->start[1], sp->start[1] + sp->count[1] - 1,
216 sp->count[1]);
217 return FALSE;
218 }
219
220 static vbi_bool
_vbi_sampling_par_permit_service(const vbi_sampling_par * sp,const _vbi_service_par * par,unsigned int strict,_vbi_log_hook * log)221 _vbi_sampling_par_permit_service
222 (const vbi_sampling_par *sp,
223 const _vbi_service_par *par,
224 unsigned int strict,
225 _vbi_log_hook * log)
226 {
227 const unsigned int unknown = 0;
228 double signal;
229 unsigned int field;
230 unsigned int samples_per_line;
231 vbi_videostd_set videostd_set;
232
233 assert (NULL != sp);
234 assert (NULL != par);
235
236 #if 2 == VBI_VERSION_MINOR
237 videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
238 #else
239 videostd_set = sp->videostd_set;
240 #endif
241 if (0 == (par->videostd_set & videostd_set)) {
242 info (log,
243 "Service 0x%08x (%s) requires "
244 "videostd_set 0x%lx, "
245 "have 0x%lx.",
246 par->id, par->label,
247 (unsigned long) par->videostd_set,
248 (unsigned long) videostd_set);
249 return FALSE;
250 }
251
252 if (par->flags & _VBI_SP_LINE_NUM) {
253 if ((par->first[0] > 0
254 && unknown == (unsigned int) sp->start[0])
255 || (par->first[1] > 0
256 && unknown == (unsigned int) sp->start[1])) {
257 info (log,
258 "Service 0x%08x (%s) requires known "
259 "line numbers.",
260 par->id, par->label);
261 return FALSE;
262 }
263 }
264
265 {
266 unsigned int rate;
267
268 rate = MAX (par->cri_rate, par->bit_rate);
269
270 switch (par->id) {
271 case VBI_SLICED_WSS_625:
272 /* Effective bit rate is just 1/3 max_rate,
273 so 1 * max_rate should suffice. */
274 break;
275
276 default:
277 rate = (rate * 3) >> 1;
278 break;
279 }
280
281 if (rate > (unsigned int) sp->sampling_rate) {
282 info (log,
283 "Sampling rate %f MHz too low "
284 "for service 0x%08x (%s).",
285 sp->sampling_rate / 1e6,
286 par->id, par->label);
287 return FALSE;
288 }
289 }
290
291 signal = par->cri_bits / (double) par->cri_rate
292 + (par->frc_bits + par->payload) / (double) par->bit_rate;
293
294 #if 2 == VBI_VERSION_MINOR
295 samples_per_line = sp->bytes_per_line
296 / VBI_PIXFMT_BPP (sp->sampling_format);
297 #else
298 samples_per_line = sp->samples_per_line;
299 #endif
300
301 if (0 && sp->offset > 0 && strict > 0) {
302 double sampling_rate;
303 double offset;
304 double end;
305
306 sampling_rate = (double) sp->sampling_rate;
307
308 offset = sp->offset / sampling_rate;
309 end = (sp->offset + samples_per_line) / sampling_rate;
310
311 if (offset > (par->offset / 1e3 - 0.5e-6)) {
312 info (log,
313 "Sampling starts at 0H + %f us, too "
314 "late for service 0x%08x (%s) at "
315 "%f us.",
316 offset * 1e6,
317 par->id, par->label,
318 par->offset / 1e3);
319 return FALSE;
320 }
321
322 if (end < (par->offset / 1e9 + signal + 0.5e-6)) {
323 info (log,
324 "Sampling ends too early at 0H + "
325 "%f us for service 0x%08x (%s) "
326 "which ends at %f us",
327 end * 1e6,
328 par->id, par->label,
329 par->offset / 1e3
330 + signal * 1e6 + 0.5);
331 return FALSE;
332 }
333 } else {
334 double samples;
335
336 samples = samples_per_line / (double) sp->sampling_rate;
337
338 if (strict > 0)
339 samples -= 1e-6; /* headroom */
340
341 if (samples < signal) {
342 info (log,
343 "Service 0x%08x (%s) signal length "
344 "%f us exceeds %f us sampling length.",
345 par->id, par->label,
346 signal * 1e6, samples * 1e6);
347 return FALSE;
348 }
349 }
350
351 if ((par->flags & _VBI_SP_FIELD_NUM)
352 && !sp->synchronous) {
353 info (log,
354 "Service 0x%08x (%s) requires "
355 "synchronous field order.",
356 par->id, par->label);
357 return FALSE;
358 }
359
360 for (field = 0; field < 2; ++field) {
361 unsigned int start;
362 unsigned int end;
363
364 start = sp->start[field];
365 end = start + sp->count[field] - 1;
366
367 if (0 == par->first[field]
368 || 0 == par->last[field]) {
369 /* No data on this field. */
370 continue;
371 }
372
373 if (0 == sp->count[field]) {
374 info (log,
375 "Service 0x%08x (%s) requires "
376 "data from field %u",
377 par->id, par->label, field + 1);
378 return FALSE;
379 }
380
381 /* (int) <= 0 for compatibility with libzvbi 0.2.x */
382 if ((int) strict <= 0 || 0 == sp->start[field])
383 continue;
384
385 if (1 == strict && par->first[field] > par->last[field]) {
386 /* May succeed if not all scanning lines
387 available for the service are actually used. */
388 continue;
389 }
390
391 if (start > par->first[field]
392 || end < par->last[field]) {
393 info (log,
394 "Service 0x%08x (%s) requires "
395 "lines %u-%u, have %u-%u.",
396 par->id, par->label,
397 par->first[field],
398 par->last[field],
399 start, end);
400 return FALSE;
401 }
402 }
403
404 return TRUE;
405 }
406
407 /**
408 * @internal
409 */
410 vbi_service_set
_vbi_sampling_par_check_services_log(const vbi_sampling_par * sp,vbi_service_set services,unsigned int strict,_vbi_log_hook * log)411 _vbi_sampling_par_check_services_log
412 (const vbi_sampling_par *sp,
413 vbi_service_set services,
414 unsigned int strict,
415 _vbi_log_hook * log)
416 {
417 const _vbi_service_par *par;
418 vbi_service_set rservices;
419
420 assert (NULL != sp);
421
422 rservices = 0;
423
424 for (par = _vbi_service_table; par->id; ++par) {
425 if (0 == (par->id & services))
426 continue;
427
428 if (_vbi_sampling_par_permit_service (sp, par, strict, log))
429 rservices |= par->id;
430 }
431
432 return rservices;
433 }
434
435 /**
436 * @internal
437 */
438 vbi_service_set
_vbi_sampling_par_from_services_log(vbi_sampling_par * sp,unsigned int * max_rate,vbi_videostd_set videostd_set_req,vbi_service_set services,_vbi_log_hook * log)439 _vbi_sampling_par_from_services_log
440 (vbi_sampling_par * sp,
441 unsigned int * max_rate,
442 vbi_videostd_set videostd_set_req,
443 vbi_service_set services,
444 _vbi_log_hook * log)
445 {
446 const _vbi_service_par *par;
447 vbi_service_set rservices;
448 vbi_videostd_set videostd_set;
449 unsigned int rate;
450 unsigned int samples_per_line;
451
452 assert (NULL != sp);
453
454 videostd_set = 0;
455
456 if (0 != videostd_set_req) {
457 if (0 == (VBI_VIDEOSTD_SET_ALL & videostd_set_req)
458 || ((VBI_VIDEOSTD_SET_525_60 & videostd_set_req)
459 && (VBI_VIDEOSTD_SET_625_50 & videostd_set_req))) {
460 warning (log,
461 "Ambiguous videostd_set 0x%lx.",
462 (unsigned long) videostd_set_req);
463 CLEAR (*sp);
464 return 0;
465 }
466
467 videostd_set = videostd_set_req;
468 }
469
470 samples_per_line = 0;
471 sp->sampling_rate = 27000000; /* ITU-R BT.601 */
472 sp->offset = (int)(64e-6 * sp->sampling_rate);
473 sp->start[0] = 30000;
474 sp->count[0] = 0;
475 sp->start[1] = 30000;
476 sp->count[1] = 0;
477 sp->interlaced = FALSE;
478 sp->synchronous = TRUE;
479
480 rservices = 0;
481 rate = 0;
482
483 for (par = _vbi_service_table; par->id; ++par) {
484 double margin;
485 double signal;
486 int offset;
487 unsigned int samples;
488 unsigned int i;
489
490 if (0 == (par->id & services))
491 continue;
492
493 if (0 == videostd_set_req) {
494 vbi_videostd_set set;
495
496 set = par->videostd_set | videostd_set;
497
498 if (0 == (set & ~VBI_VIDEOSTD_SET_525_60)
499 || 0 == (set & ~VBI_VIDEOSTD_SET_625_50))
500 videostd_set |= par->videostd_set;
501 }
502
503 if (VBI_VIDEOSTD_SET_525_60 & videostd_set)
504 margin = 1.0e-6;
505 else
506 margin = 2.0e-6;
507
508 if (0 == (par->videostd_set & videostd_set)) {
509 info (log,
510 "Service 0x%08x (%s) requires "
511 "videostd_set 0x%lx, "
512 "have 0x%lx.",
513 par->id, par->label,
514 (unsigned long) par->videostd_set,
515 (unsigned long) videostd_set);
516 continue;
517 }
518
519 rate = MAX (rate, par->cri_rate);
520 rate = MAX (rate, par->bit_rate);
521
522 signal = par->cri_bits / (double) par->cri_rate
523 + ((par->frc_bits + par->payload) / (double) par->bit_rate);
524
525 offset = (int)((par->offset / 1e9) * sp->sampling_rate);
526 samples = (int)((signal + 1.0e-6) * sp->sampling_rate);
527
528 sp->offset = MIN (sp->offset, offset);
529
530 samples_per_line = MAX (samples_per_line + sp->offset,
531 samples + offset) - sp->offset;
532
533 for (i = 0; i < 2; ++i)
534 if (par->first[i] > 0
535 && par->last[i] > 0) {
536 sp->start[i] = MIN
537 ((unsigned int) sp->start[i],
538 (unsigned int) par->first[i]);
539 sp->count[i] = MAX
540 ((unsigned int) sp->start[i]
541 + sp->count[i],
542 (unsigned int) par->last[i] + 1)
543 - sp->start[i];
544 }
545
546 rservices |= par->id;
547 }
548
549 if (0 == rservices) {
550 CLEAR (*sp);
551 return 0;
552 }
553
554 if (0 == sp->count[1]) {
555 sp->start[1] = 0;
556
557 if (0 == sp->count[0]) {
558 sp->start[0] = 0;
559 sp->offset = 0;
560 }
561 } else if (0 == sp->count[0]) {
562 sp->start[0] = 0;
563 }
564
565 #if 3 == VBI_VERSION_MINOR
566 sp->videostd_set = videostd_set;
567 sp->sp_sample_format = VBI_PIXFMT_Y8;
568 sp->samples_per_line = samples_per_line;
569 #else
570 sp->scanning = (videostd_set & VBI_VIDEOSTD_SET_525_60)
571 ? 525 : 625;
572 sp->sp_sample_format = VBI_PIXFMT_YUV420;
573 #endif
574
575 /* Note bpp is 1. */
576 sp->bytes_per_line = MAX (1440U, samples_per_line);
577
578 if (max_rate)
579 *max_rate = rate;
580
581 return rservices;
582 }
583
584 /**
585 * @param sp Sampling parameters to check against.
586 * @param services Set of data services.
587 * @param strict See description of vbi_raw_decoder_add_services().
588 *
589 * Check which of the given services can be decoded with the given
590 * sampling parameters at the given strictness level.
591 *
592 * @return
593 * Subset of @a services decodable with the given sampling parameters.
594 */
595 vbi_service_set
vbi_sampling_par_check_services(const vbi_sampling_par * sp,vbi_service_set services,unsigned int strict)596 vbi_sampling_par_check_services
597 (const vbi_sampling_par *sp,
598 vbi_service_set services,
599 unsigned int strict)
600 {
601 return _vbi_sampling_par_check_services_log (sp, services, strict,
602 /* log_hook */ NULL);
603 }
604
605 /**
606 * @param sp Sampling parameters calculated by this function
607 * will be stored here.
608 * @param max_rate If not NULL, the highest data bit rate in Hz of
609 * all services requested will be stored here. The sampling rate
610 * should be at least twice as high; @sp sampling_rate will
611 * be set to a more reasonable value of 27 MHz, which is twice
612 * the video sampling rate defined by ITU-R Rec. BT.601.
613 * @param videostd_set Create sampling parameters matching these
614 * video standards. When 0 determine video standard from requested
615 * services.
616 * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
617 * can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
618 * vbi scan lines in the calculated sampling parameters.
619 *
620 * Calculate the sampling parameters required to receive and decode the
621 * requested data @a services. The @a sp sampling_format will be
622 * @c VBI_PIXFMT_Y8, offset and bytes_per_line will be set to
623 * reasonable minimums. This function can be used to initialize hardware
624 * prior to creating a vbi_raw_decoder object.
625 *
626 * @return
627 * Subset of @a services covered by the calculated sampling parameters.
628 */
629 vbi_service_set
vbi_sampling_par_from_services(vbi_sampling_par * sp,unsigned int * max_rate,vbi_videostd_set videostd_set,vbi_service_set services)630 vbi_sampling_par_from_services (vbi_sampling_par * sp,
631 unsigned int * max_rate,
632 vbi_videostd_set videostd_set,
633 vbi_service_set services)
634 {
635 return _vbi_sampling_par_from_services_log (sp, max_rate,
636 videostd_set,
637 services,
638 /* log_hook */ NULL);
639 }
640
641 #if 3 == VBI_VERSION_MINOR
642
643 /**
644 * @param videostd A video standard number.
645 *
646 * Returns the name of a video standard like VBI_VIDEOSTD_PAL_B ->
647 * "PAL_B". This is mainly intended for debugging.
648 *
649 * @return
650 * Static ASCII string, NULL if @a videostd is a custom standard
651 * or invalid.
652 */
653 const char *
_vbi_videostd_name(vbi_videostd videostd)654 _vbi_videostd_name (vbi_videostd videostd)
655 {
656 switch (videostd) {
657
658 #undef CASE
659 #define CASE(std) case VBI_VIDEOSTD_##std : return #std ;
660
661 CASE (NONE)
662 CASE (PAL_B)
663 CASE (PAL_B1)
664 CASE (PAL_G)
665 CASE (PAL_H)
666 CASE (PAL_I)
667 CASE (PAL_D)
668 CASE (PAL_D1)
669 CASE (PAL_K)
670 CASE (PAL_M)
671 CASE (PAL_N)
672 CASE (PAL_NC)
673 CASE (PAL_60)
674 CASE (NTSC_M)
675 CASE (NTSC_M_JP)
676 CASE (NTSC_M_KR)
677 CASE (NTSC_443)
678 CASE (SECAM_B)
679 CASE (SECAM_D)
680 CASE (SECAM_G)
681 CASE (SECAM_H)
682 CASE (SECAM_K)
683 CASE (SECAM_K1)
684 CASE (SECAM_L)
685 CASE (SECAM_LC)
686
687 }
688
689 return NULL;
690 }
691
692 #endif /* 3 == VBI_VERSION_MINOR */
693
694 /*
695 Local variables:
696 c-set-style: K&R
697 c-basic-offset: 8
698 End:
699 */
700