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