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.12 2013-08-28 14:45:00 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
35 # define vbi_pixfmt_bytes_per_pixel VBI_PIXFMT_BPP
36 # define sp_sample_format sampling_format
37
38 /**
39 * @addtogroup Sampling Raw VBI sampling
40 * @ingroup Raw
41 * @brief Raw VBI data sampling interface.
42 */
43
44 /**
45 * @internal
46 * Compatibility.
47 */
48 vbi_videostd_set
_vbi_videostd_set_from_scanning(int scanning)49 _vbi_videostd_set_from_scanning (int scanning)
50 {
51 switch (scanning) {
52 case 525:
53 return VBI_VIDEOSTD_SET_525_60;
54
55 case 625:
56 return VBI_VIDEOSTD_SET_625_50;
57
58 default:
59 break;
60 }
61
62 return 0;
63 }
64
65 _vbi_inline vbi_bool
range_check(unsigned int start,unsigned int count,unsigned int min,unsigned int max)66 range_check (unsigned int start,
67 unsigned int count, unsigned int min, unsigned int max)
68 {
69 /* Check bounds and overflow. */
70 return (start >= min && (start + count) <= max && (start + count) >= start);
71 }
72
73 /**
74 * @internal
75 * @param sp Sampling parameters to verify.
76 *
77 * @return
78 * TRUE if the sampling parameters are valid (as far as we can tell).
79 */
80 vbi_bool
_vbi_sampling_par_valid_log(const vbi_sampling_par * sp,_vbi_log_hook * log)81 _vbi_sampling_par_valid_log (const vbi_sampling_par * sp, _vbi_log_hook * log)
82 {
83 vbi_videostd_set videostd_set;
84 unsigned int bpp;
85
86 assert (NULL != sp);
87
88 switch (sp->sp_sample_format) {
89 case VBI_PIXFMT_YUV420:
90 /* This conflicts with the ivtv driver, which returns an
91 odd number of bytes per line. The driver format is
92 _GREY but libzvbi 0.2 has no VBI_PIXFMT_Y8. */
93 break;
94
95 default:
96 bpp = vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format);
97 if (0 != (sp->bytes_per_line % bpp))
98 goto bad_samples;
99 break;
100 }
101
102 if (0 == sp->bytes_per_line)
103 goto no_samples;
104
105 if (0 == sp->count[0]
106 && 0 == sp->count[1])
107 goto bad_range;
108
109 videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
110
111 if (VBI_VIDEOSTD_SET_525_60 & videostd_set) {
112 if (VBI_VIDEOSTD_SET_625_50 & videostd_set)
113 goto ambiguous;
114
115 if (0 != sp->start[0]
116 && !range_check (sp->start[0], sp->count[0], 1, 262))
117 goto bad_range;
118
119 if (0 != sp->start[1]
120 && !range_check (sp->start[1], sp->count[1], 263, 525))
121 goto bad_range;
122 } else if (VBI_VIDEOSTD_SET_625_50 & videostd_set) {
123 if (0 != sp->start[0]
124 && !range_check (sp->start[0], sp->count[0], 1, 311))
125 goto bad_range;
126
127 if (0 != sp->start[1]
128 && !range_check (sp->start[1], sp->count[1], 312, 625))
129 goto bad_range;
130 } else {
131 ambiguous:
132 info (log, "Ambiguous videostd_set 0x%lx.", (unsigned long) videostd_set);
133 return FALSE;
134 }
135
136 if (sp->interlaced && (sp->count[0] != sp->count[1]
137 || 0 == sp->count[0])) {
138 info (log,
139 "Line counts %u, %u must be equal and "
140 "non-zero when raw VBI data is interlaced.",
141 sp->count[0], sp->count[1]);
142 return FALSE;
143 }
144
145 return TRUE;
146
147 no_samples:
148 info (log, "samples_per_line is zero.");
149 return FALSE;
150
151
152 bad_samples:
153 info (log,
154 "bytes_per_line value %u is no multiple of "
155 "the sample size %u.",
156 sp->bytes_per_line, vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format));
157 return FALSE;
158
159 bad_range:
160 info (log,
161 "Invalid VBI scan range %u-%u (%u lines), "
162 "%u-%u (%u lines).",
163 sp->start[0], sp->start[0] + sp->count[0] - 1,
164 sp->count[0],
165 sp->start[1], sp->start[1] + sp->count[1] - 1, sp->count[1]);
166 return FALSE;
167 }
168
169 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)170 _vbi_sampling_par_permit_service
171 (const vbi_sampling_par * sp,
172 const _vbi_service_par * par, unsigned int strict, _vbi_log_hook * log)
173 {
174 const unsigned int unknown = 0;
175 double signal;
176 unsigned int field;
177 unsigned int samples_per_line;
178 vbi_videostd_set videostd_set;
179
180 assert (NULL != sp);
181 assert (NULL != par);
182
183 videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
184 if (0 == (par->videostd_set & videostd_set)) {
185 info (log,
186 "Service 0x%08x (%s) requires "
187 "videostd_set 0x%lx, "
188 "have 0x%lx.",
189 par->id, par->label,
190 (unsigned long) par->videostd_set, (unsigned long) videostd_set);
191 return FALSE;
192 }
193
194 if (par->flags & _VBI_SP_LINE_NUM) {
195 if ((par->first[0] > 0 && unknown == (unsigned int) sp->start[0])
196 || (par->first[1] > 0 && unknown == (unsigned int) sp->start[1])) {
197 info (log,
198 "Service 0x%08x (%s) requires known "
199 "line numbers.", par->id, par->label);
200 return FALSE;
201 }
202 }
203
204 {
205 unsigned int rate;
206
207 rate = MAX (par->cri_rate, par->bit_rate);
208
209 switch (par->id) {
210 case VBI_SLICED_WSS_625:
211 /* Effective bit rate is just 1/3 max_rate,
212 so 1 * max_rate should suffice. */
213 break;
214
215 default:
216 rate = (rate * 3) >> 1;
217 break;
218 }
219
220 if (rate > (unsigned int) sp->sampling_rate) {
221 info (log,
222 "Sampling rate %f MHz too low "
223 "for service 0x%08x (%s).",
224 sp->sampling_rate / 1e6, par->id, par->label);
225 return FALSE;
226 }
227 }
228
229 signal = par->cri_bits / (double) par->cri_rate
230 + (par->frc_bits + par->payload) / (double) par->bit_rate;
231
232 samples_per_line = sp->bytes_per_line / VBI_PIXFMT_BPP (sp->sampling_format);
233
234 if (0 && sp->offset > 0 && strict > 0) {
235 double sampling_rate;
236 double offset;
237 double end;
238
239 sampling_rate = (double) sp->sampling_rate;
240
241 offset = sp->offset / sampling_rate;
242 end = (sp->offset + samples_per_line) / sampling_rate;
243
244 if (offset > (par->offset / 1e3 - 0.5e-6)) {
245 info (log,
246 "Sampling starts at 0H + %f us, too "
247 "late for service 0x%08x (%s) at "
248 "%f us.", offset * 1e6, par->id, par->label, par->offset / 1e3);
249 return FALSE;
250 }
251
252 if (end < (par->offset / 1e9 + signal + 0.5e-6)) {
253 info (log,
254 "Sampling ends too early at 0H + "
255 "%f us for service 0x%08x (%s) "
256 "which ends at %f us",
257 end * 1e6,
258 par->id, par->label, par->offset / 1e3 + signal * 1e6 + 0.5);
259 return FALSE;
260 }
261 } else {
262 double samples;
263
264 samples = samples_per_line / (double) sp->sampling_rate;
265
266 if (strict > 0)
267 samples -= 1e-6; /* headroom */
268
269 if (samples < signal) {
270 info (log,
271 "Service 0x%08x (%s) signal length "
272 "%f us exceeds %f us sampling length.",
273 par->id, par->label, signal * 1e6, samples * 1e6);
274 return FALSE;
275 }
276 }
277
278 if ((par->flags & _VBI_SP_FIELD_NUM)
279 && !sp->synchronous) {
280 info (log,
281 "Service 0x%08x (%s) requires "
282 "synchronous field order.", par->id, par->label);
283 return FALSE;
284 }
285
286 for (field = 0; field < 2; ++field) {
287 unsigned int start;
288 unsigned int end;
289
290 start = sp->start[field];
291 end = start + sp->count[field] - 1;
292
293 if (0 == par->first[field]
294 || 0 == par->last[field]) {
295 /* No data on this field. */
296 continue;
297 }
298
299 if (0 == sp->count[field]) {
300 info (log,
301 "Service 0x%08x (%s) requires "
302 "data from field %u", par->id, par->label, field + 1);
303 return FALSE;
304 }
305
306 /* (int) <= 0 for compatibility with libzvbi 0.2.x */
307 if ((int) strict <= 0 || 0 == sp->start[field])
308 continue;
309
310 if (1 == strict && par->first[field] > par->last[field]) {
311 /* May succeed if not all scanning lines
312 available for the service are actually used. */
313 continue;
314 }
315
316 if (start > par->first[field]
317 || end < par->last[field]) {
318 info (log,
319 "Service 0x%08x (%s) requires "
320 "lines %u-%u, have %u-%u.",
321 par->id, par->label, par->first[field], par->last[field], start, end);
322 return FALSE;
323 }
324 }
325
326 return TRUE;
327 }
328
329 /**
330 * @internal
331 */
332 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)333 _vbi_sampling_par_check_services_log
334 (const vbi_sampling_par * sp,
335 vbi_service_set services, unsigned int strict, _vbi_log_hook * log) {
336 const _vbi_service_par *par;
337 vbi_service_set rservices;
338
339 assert (NULL != sp);
340
341 rservices = 0;
342
343 for (par = _vbi_service_table; par->id; ++par) {
344 if (0 == (par->id & services))
345 continue;
346
347 if (_vbi_sampling_par_permit_service (sp, par, strict, log))
348 rservices |= par->id;
349 }
350
351 return rservices;
352 }
353
354 /**
355 * @internal
356 */
357 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)358 _vbi_sampling_par_from_services_log
359 (vbi_sampling_par * sp,
360 unsigned int *max_rate,
361 vbi_videostd_set videostd_set_req,
362 vbi_service_set services, _vbi_log_hook * log) {
363 const _vbi_service_par *par;
364 vbi_service_set rservices;
365 vbi_videostd_set videostd_set;
366 unsigned int rate;
367 unsigned int samples_per_line;
368
369 assert (NULL != sp);
370
371 videostd_set = 0;
372
373 if (0 != videostd_set_req) {
374 if (0 == (VBI_VIDEOSTD_SET_ALL & videostd_set_req)
375 || ((VBI_VIDEOSTD_SET_525_60 & videostd_set_req)
376 && (VBI_VIDEOSTD_SET_625_50 & videostd_set_req))) {
377 warn (log,
378 "Ambiguous videostd_set 0x%lx.", (unsigned long) videostd_set_req);
379 CLEAR (*sp);
380 return 0;
381 }
382
383 videostd_set = videostd_set_req;
384 }
385
386 samples_per_line = 0;
387 sp->sampling_rate = 27000000; /* ITU-R BT.601 */
388 sp->offset = (int) (64e-6 * sp->sampling_rate);
389 sp->start[0] = 30000;
390 sp->count[0] = 0;
391 sp->start[1] = 30000;
392 sp->count[1] = 0;
393 sp->interlaced = FALSE;
394 sp->synchronous = TRUE;
395
396 rservices = 0;
397 rate = 0;
398
399 for (par = _vbi_service_table; par->id; ++par) {
400 #if 0 /* Set but unused */
401 double margin;
402 #endif
403 double signal;
404 int offset;
405 unsigned int samples;
406 unsigned int i;
407
408 if (0 == (par->id & services))
409 continue;
410
411 if (0 == videostd_set_req) {
412 vbi_videostd_set set;
413
414 set = par->videostd_set | videostd_set;
415
416 if (0 == (set & ~VBI_VIDEOSTD_SET_525_60)
417 || 0 == (set & ~VBI_VIDEOSTD_SET_625_50))
418 videostd_set |= par->videostd_set;
419 }
420 #if 0 /* Set but unused */
421 if (VBI_VIDEOSTD_SET_525_60 & videostd_set)
422 margin = 1.0e-6;
423 else
424 margin = 2.0e-6;
425 #endif
426
427 if (0 == (par->videostd_set & videostd_set)) {
428 info (log,
429 "Service 0x%08x (%s) requires "
430 "videostd_set 0x%lx, "
431 "have 0x%lx.",
432 par->id, par->label,
433 (unsigned long) par->videostd_set, (unsigned long) videostd_set);
434 continue;
435 }
436
437 rate = MAX (rate, par->cri_rate);
438 rate = MAX (rate, par->bit_rate);
439
440 signal = par->cri_bits / (double) par->cri_rate
441 + ((par->frc_bits + par->payload) / (double) par->bit_rate);
442
443 offset = (int) ((par->offset / 1e9) * sp->sampling_rate);
444 samples = (int) ((signal + 1.0e-6) * sp->sampling_rate);
445
446 sp->offset = MIN (sp->offset, offset);
447
448 samples_per_line = MAX (samples_per_line + sp->offset,
449 samples + offset) - sp->offset;
450
451 for (i = 0; i < 2; ++i)
452 if (par->first[i] > 0 && par->last[i] > 0) {
453 sp->start[i] = MIN
454 ((unsigned int) sp->start[i], (unsigned int) par->first[i]);
455 sp->count[i] = MAX ((unsigned int) sp->start[i]
456 + sp->count[i], (unsigned int) par->last[i] + 1)
457 - sp->start[i];
458 }
459
460 rservices |= par->id;
461 }
462
463 if (0 == rservices) {
464 CLEAR (*sp);
465 return 0;
466 }
467
468 if (0 == sp->count[1]) {
469 sp->start[1] = 0;
470
471 if (0 == sp->count[0]) {
472 sp->start[0] = 0;
473 sp->offset = 0;
474 }
475 } else if (0 == sp->count[0]) {
476 sp->start[0] = 0;
477 }
478
479 sp->scanning = (videostd_set & VBI_VIDEOSTD_SET_525_60)
480 ? 525 : 625;
481 sp->sp_sample_format = VBI_PIXFMT_YUV420;
482
483 /* Note bpp is 1. */
484 sp->bytes_per_line = MAX (1440U, samples_per_line);
485
486 if (max_rate)
487 *max_rate = rate;
488
489 return rservices;
490 }
491
492 /**
493 * @param sp Sampling parameters to check against.
494 * @param services Set of data services.
495 * @param strict See description of vbi_raw_decoder_add_services().
496 *
497 * Check which of the given services can be decoded with the given
498 * sampling parameters at the given strictness level.
499 *
500 * @return
501 * Subset of @a services decodable with the given sampling parameters.
502 */
503 vbi_service_set
vbi_sampling_par_check_services(const vbi_sampling_par * sp,vbi_service_set services,unsigned int strict)504 vbi_sampling_par_check_services
505 (const vbi_sampling_par * sp,
506 vbi_service_set services, unsigned int strict) {
507 return _vbi_sampling_par_check_services_log (sp, services, strict,
508 /* log_hook */ NULL);
509 }
510
511 /**
512 * @param sp Sampling parameters calculated by this function
513 * will be stored here.
514 * @param max_rate If not NULL, the highest data bit rate in Hz of
515 * all services requested will be stored here. The sampling rate
516 * should be at least twice as high; @sp sampling_rate will
517 * be set to a more reasonable value of 27 MHz, which is twice
518 * the video sampling rate defined by ITU-R Rec. BT.601.
519 * @param videostd_set Create sampling parameters matching these
520 * video standards. When 0 determine video standard from requested
521 * services.
522 * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
523 * can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
524 * vbi scan lines in the calculated sampling parameters.
525 *
526 * Calculate the sampling parameters required to receive and decode the
527 * requested data @a services. The @a sp sampling_format will be
528 * @c VBI_PIXFMT_Y8, offset and bytes_per_line will be set to
529 * reasonable minimums. This function can be used to initialize hardware
530 * prior to creating a vbi_raw_decoder object.
531 *
532 * @return
533 * Subset of @a services covered by the calculated sampling parameters.
534 */
535 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)536 vbi_sampling_par_from_services (vbi_sampling_par * sp,
537 unsigned int *max_rate,
538 vbi_videostd_set videostd_set, vbi_service_set services)
539 {
540 return _vbi_sampling_par_from_services_log (sp, max_rate,
541 videostd_set, services,
542 /* log_hook */ NULL);
543 }
544
545
546 /*
547 Local variables:
548 c-set-style: K&R
549 c-basic-offset: 8
550 End:
551 */
552