blob: 687a02f4208e494c6b68b5e4dbd7e86e4588320b
1 | /* |
2 | * libzvbi -- VBI decoding library |
3 | * |
4 | * Copyright (C) 2000-2008 Michael H. Schimek |
5 | * Copyright (C) 2000, 2001 Iñaki García Etxebarria |
6 | * Copyright (C) 2003, 2004 Tom Zoerner |
7 | * |
8 | * Originally based on AleVT 1.5.1 by Edgar Toernig |
9 | * |
10 | * This library is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Library General Public |
12 | * License as published by the Free Software Foundation; either |
13 | * version 2 of the License, or (at your option) any later version. |
14 | * |
15 | * This library is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Library General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU Library General Public |
21 | * License along with this library; if not, write to the |
22 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
23 | * Boston, MA 02110-1301 USA. |
24 | */ |
25 | |
26 | /* $Id: vbi.c,v 1.24 2008/03/05 13:33:04 mschimek Exp $ */ |
27 | |
28 | #include "site_def.h" |
29 | |
30 | #ifdef HAVE_CONFIG_H |
31 | # include "config.h" |
32 | #endif |
33 | |
34 | #include <stdio.h> |
35 | #include <stdlib.h> |
36 | #include <string.h> |
37 | #include <stdarg.h> |
38 | #include <unistd.h> |
39 | #include <fcntl.h> |
40 | #include <time.h> |
41 | #include <errno.h> |
42 | #include <sys/ioctl.h> |
43 | #include <sys/time.h> |
44 | #include <pthread.h> |
45 | |
46 | #include "misc.h" |
47 | #include "version.h" |
48 | #include "vbi.h" |
49 | #include "hamm.h" |
50 | #include "lang.h" |
51 | #include "export.h" |
52 | #include "tables.h" |
53 | #include "format.h" |
54 | #include "wss.h" |
55 | |
56 | /** |
57 | * @mainpage ZVBI - VBI Decoding Library |
58 | * |
59 | * @author Iñaki García Etxebarria<br> |
60 | * Michael H. Schimek<br> |
61 | * Tom Zoerner<br> |
62 | * based on AleVT by Edgar Toernig |
63 | * |
64 | * @section intro Introduction |
65 | * |
66 | * The ZVBI library provides routines to access raw VBI sampling devices |
67 | * (currently the Linux <a href="http://linux.bytesex.org/v4l2/">V4L and |
68 | * and V4L2</a> API and the FreeBSD |
69 | * <a href="http://telepresence.dmem.strath.ac.uk/bt848/">bktr driver</a> API |
70 | * are supported), a versatile raw VBI bit slicer, |
71 | * decoders for various data services and basic search, |
72 | * render and export functions for text pages. The library was written for |
73 | * the <a href="http://zapping.sourceforge.net">Zapping TV viewer and |
74 | * Zapzilla Teletext browser</a>. |
75 | * |
76 | * @section feedback Feedback |
77 | * |
78 | * If you have any ideas, questions, patches or bug reports please see |
79 | * the README file included with the source code or visit our home page at |
80 | * <a href="http://zapping.sourceforge.net">http://zapping.sourceforge.net</a>. |
81 | */ |
82 | |
83 | /** @defgroup Basic Basic types */ |
84 | /** @defgroup Raw Raw VBI */ |
85 | /** @defgroup LowDec Low Level Decoding */ |
86 | /** @defgroup HiDec High Level Decoding */ |
87 | /** |
88 | * @defgroup Service Data Service Decoder |
89 | * @ingroup HiDec |
90 | */ |
91 | |
92 | pthread_once_t vbi_init_once = PTHREAD_ONCE_INIT; |
93 | |
94 | void |
95 | vbi_init (void) |
96 | { |
97 | #ifdef ENABLE_NLS |
98 | bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR); |
99 | #endif |
100 | } |
101 | |
102 | /** |
103 | * @ingroup Basic |
104 | * @param mask Which kind of information to log. Can be @c 0. |
105 | * @param log_fn This function is called with log messages. Consider |
106 | * vbi_log_on_stderr(). Can be @c NULL to disable logging. |
107 | * @param user_data User pointer passed through to the @a log_fn function. |
108 | * |
109 | * Various functions can print warnings, errors and information useful to |
110 | * debug the library. With this function you can enable these messages |
111 | * and determine a function to print them. |
112 | * |
113 | * @note |
114 | * The kind and contents of messages logged by particular functions |
115 | * may change in the future. |
116 | * |
117 | * @since 0.2.22 |
118 | */ |
119 | void |
120 | vbi_set_log_fn (vbi_log_mask mask, |
121 | vbi_log_fn * log_fn, |
122 | void * user_data) |
123 | { |
124 | if (NULL == log_fn) |
125 | mask = 0; |
126 | |
127 | _vbi_global_log.mask = mask; |
128 | _vbi_global_log.fn = log_fn; |
129 | _vbi_global_log.user_data = user_data; |
130 | } |
131 | |
132 | /* |
133 | * Events |
134 | */ |
135 | |
136 | /* Should this be public? */ |
137 | static void |
138 | vbi_event_enable(vbi_decoder *vbi, int mask) |
139 | { |
140 | int activate; |
141 | |
142 | activate = mask & ~vbi->event_mask; |
143 | |
144 | if (activate & VBI_EVENT_TTX_PAGE) |
145 | vbi_teletext_channel_switched(vbi); |
146 | if (activate & VBI_EVENT_CAPTION) |
147 | vbi_caption_channel_switched(vbi); |
148 | if (activate & (VBI_EVENT_NETWORK | VBI_EVENT_NETWORK_ID)) |
149 | memset(&vbi->network, 0, sizeof(vbi->network)); |
150 | if (activate & VBI_EVENT_TRIGGER) |
151 | vbi_trigger_flush(vbi); |
152 | if (activate & (VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO)) { |
153 | if (!(vbi->event_mask & (VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO))) { |
154 | vbi_reset_prog_info(&vbi->prog_info[0]); |
155 | vbi_reset_prog_info(&vbi->prog_info[1]); |
156 | |
157 | vbi->prog_info[1].future = TRUE; |
158 | vbi->prog_info[0].future = FALSE; |
159 | |
160 | vbi->aspect_source = 0; |
161 | } |
162 | } |
163 | |
164 | vbi->event_mask = mask; |
165 | } |
166 | |
167 | /** |
168 | * @param vbi Initialized vbi decoding context. |
169 | * @param event_mask Events the handler is waiting for. |
170 | * @param handler Event handler function. |
171 | * @param user_data Pointer passed to the handler. |
172 | * |
173 | * @deprecated |
174 | * Replaces all existing handlers with this @a handler function, |
175 | * ignoring @a user_data. Use vbi_event_handler_register() in new code. |
176 | * |
177 | * @return |
178 | * FALSE on failure. |
179 | */ |
180 | vbi_bool |
181 | vbi_event_handler_add(vbi_decoder *vbi, int event_mask, |
182 | vbi_event_handler handler, void *user_data) |
183 | { |
184 | struct event_handler *eh, **ehp; |
185 | int found = 0, mask = 0, was_locked; |
186 | |
187 | /* If was_locked we're a handler, no recursion. */ |
188 | was_locked = pthread_mutex_trylock(&vbi->event_mutex); |
189 | |
190 | ehp = &vbi->handlers; |
191 | |
192 | while ((eh = *ehp)) { |
193 | if (eh->handler == handler) { |
194 | found = 1; |
195 | |
196 | if (!event_mask) { |
197 | *ehp = eh->next; |
198 | |
199 | if (vbi->next_handler == eh) |
200 | vbi->next_handler = eh->next; |
201 | /* in event send loop */ |
202 | free(eh); |
203 | |
204 | continue; |
205 | } else |
206 | eh->event_mask = event_mask; |
207 | } |
208 | |
209 | mask |= eh->event_mask; |
210 | ehp = &eh->next; |
211 | } |
212 | |
213 | if (!found && event_mask) { |
214 | if (!(eh = (struct event_handler *) calloc(1, sizeof(*eh)))) |
215 | return FALSE; |
216 | |
217 | eh->event_mask = event_mask; |
218 | mask |= event_mask; |
219 | |
220 | eh->handler = handler; |
221 | eh->user_data = user_data; |
222 | |
223 | *ehp = eh; |
224 | } |
225 | |
226 | vbi_event_enable(vbi, mask); |
227 | |
228 | if (!was_locked) |
229 | pthread_mutex_unlock(&vbi->event_mutex); |
230 | |
231 | return TRUE; |
232 | } |
233 | |
234 | /** |
235 | * @param vbi Initialized vbi decoding context. |
236 | * @param handler Event handler function. |
237 | * |
238 | * @deprecated |
239 | * This functions lacks a user_data parameter. |
240 | * Use vbi_event_handler_register() in new code. |
241 | */ |
242 | void |
243 | vbi_event_handler_remove(vbi_decoder *vbi, vbi_event_handler handler) |
244 | { |
245 | vbi_event_handler_add(vbi, 0, handler, NULL); |
246 | } |
247 | |
248 | /** |
249 | * @param vbi Initialized vbi decoding context. |
250 | * @param event_mask Events the handler is waiting for. |
251 | * @param handler Event handler function. |
252 | * @param user_data Pointer passed to the handler. |
253 | * |
254 | * Registers a new event handler. @a event_mask can be any 'or' of VBI_EVENT_ |
255 | * symbols, -1 for all events and 0 for none. When the @a handler with |
256 | * @a user_data is already registered, its event_mask will be changed. Any |
257 | * number of handlers can be registered, also different handlers for the same |
258 | * event which will be called in registration order. |
259 | * |
260 | * Apart of adding handlers this function also enables and disables decoding |
261 | * of data services depending on the presence of at least one handler for the |
262 | * respective data. A @c VBI_EVENT_TTX_PAGE handler for example enables Teletext |
263 | * decoding. |
264 | * |
265 | * This function can be safely called at any time, even from a handler. |
266 | * |
267 | * @return |
268 | * @c FALSE on failure. |
269 | */ |
270 | vbi_bool |
271 | vbi_event_handler_register(vbi_decoder *vbi, int event_mask, |
272 | vbi_event_handler handler, void *user_data) |
273 | { |
274 | struct event_handler *eh, **ehp; |
275 | int found = 0, mask = 0, was_locked; |
276 | |
277 | /* If was_locked we're a handler, no recursion. */ |
278 | was_locked = pthread_mutex_trylock(&vbi->event_mutex); |
279 | |
280 | ehp = &vbi->handlers; |
281 | |
282 | while ((eh = *ehp)) { |
283 | if (eh->handler == handler |
284 | && eh->user_data == user_data) { |
285 | found = 1; |
286 | |
287 | if (!event_mask) { |
288 | *ehp = eh->next; |
289 | |
290 | if (vbi->next_handler == eh) |
291 | vbi->next_handler = eh->next; |
292 | /* in event send loop */ |
293 | free(eh); |
294 | |
295 | continue; |
296 | } else |
297 | eh->event_mask = event_mask; |
298 | } |
299 | |
300 | mask |= eh->event_mask; |
301 | ehp = &eh->next; |
302 | } |
303 | |
304 | if (!found && event_mask) { |
305 | if (!(eh = (struct event_handler *) calloc(1, sizeof(*eh)))) |
306 | return FALSE; |
307 | |
308 | eh->event_mask = event_mask; |
309 | mask |= event_mask; |
310 | |
311 | eh->handler = handler; |
312 | eh->user_data = user_data; |
313 | |
314 | *ehp = eh; |
315 | } |
316 | |
317 | vbi_event_enable(vbi, mask); |
318 | |
319 | if (!was_locked) |
320 | pthread_mutex_unlock(&vbi->event_mutex); |
321 | |
322 | return TRUE; |
323 | } |
324 | |
325 | /** |
326 | * @param vbi Initialized vbi decoding context. |
327 | * @param handler Event handler function. |
328 | * @param user_data Pointer passed to the handler. |
329 | * |
330 | * Unregisters an event handler. |
331 | * |
332 | * Apart of removing a handler this function also disables decoding |
333 | * of data services when no handler is registered to consume the |
334 | * respective data. Removing the last @c VBI_EVENT_TTX_PAGE handler for |
335 | * example disables Teletext decoding. |
336 | * |
337 | * This function can be safely called at any time, even from a handler |
338 | * removing itself or another handler, and regardless if the @a handler |
339 | * has been successfully registered. |
340 | **/ |
341 | void |
342 | vbi_event_handler_unregister(vbi_decoder *vbi, |
343 | vbi_event_handler handler, void *user_data) |
344 | { |
345 | vbi_event_handler_register(vbi, 0, handler, user_data); |
346 | } |
347 | |
348 | /** |
349 | * @internal |
350 | * @param vbi Initialized vbi decoding context. |
351 | * @param ev The event to send. |
352 | * |
353 | * Traverses the list of event handlers and calls each handler waiting |
354 | * * for this @a ev->type of event, passing @a ev as parameter. |
355 | * |
356 | * This function is reentrant, but not supposed to be called from |
357 | * different threads to ensure correct event order. |
358 | */ |
359 | void |
360 | vbi_send_event(vbi_decoder *vbi, vbi_event *ev) |
361 | { |
362 | struct event_handler *eh; |
363 | |
364 | pthread_mutex_lock(&vbi->event_mutex); |
365 | |
366 | for (eh = vbi->handlers; eh; eh = vbi->next_handler) { |
367 | vbi->next_handler = eh->next; |
368 | |
369 | if (eh->event_mask & ev->type) |
370 | eh->handler(ev, eh->user_data); |
371 | } |
372 | |
373 | pthread_mutex_unlock(&vbi->event_mutex); |
374 | } |
375 | |
376 | /* |
377 | * VBI Decoder |
378 | */ |
379 | |
380 | static inline double |
381 | current_time(void) |
382 | { |
383 | struct timeval tv; |
384 | |
385 | gettimeofday(&tv, NULL); |
386 | |
387 | return tv.tv_sec + tv.tv_usec * (1 / 1e6); |
388 | } |
389 | |
390 | /** |
391 | * @param vbi Initialized vbi decoding context as returned by vbi_decoder_new(). |
392 | * @param sliced Array of vbi_sliced data packets to be decoded. |
393 | * @param lines Number of vbi_sliced data packets, i. e. VBI lines. |
394 | * @param time Timestamp associated with <em>all</em> sliced data packets. |
395 | * This is the time in seconds and fractions since 1970-01-01 00:00, |
396 | * for example from function gettimeofday(). @a time should only |
397 | * increment, the latest time entered is considered the current time |
398 | * for activity calculation. |
399 | * |
400 | * @brief Main function of the data service decoder. |
401 | * |
402 | * Decodes zero or more lines of sliced VBI data from the same video |
403 | * frame, updates the decoder state and calls event handlers. |
404 | * |
405 | * @a timestamp shall advance by 1/30 to 1/25 seconds whenever calling this |
406 | * function. Failure to do so will be interpreted as frame dropping, which |
407 | * starts a resynchronization cycle, eventually a channel switch may be assumed |
408 | * which resets even more decoder state. So even if a frame did not contain |
409 | * any useful data this function must be called, with @a lines set to zero. |
410 | * |
411 | * @note This is one of the few not reentrant libzvbi functions. If multiple |
412 | * threads call this with the same @a vbi context you must implement your |
413 | * own locking mechanism. Never call this function from an event handler. |
414 | */ |
415 | void |
416 | vbi_decode(vbi_decoder *vbi, vbi_sliced *sliced, int lines, double time) |
417 | { |
418 | double d; |
419 | |
420 | d = time - vbi->time; |
421 | |
422 | if (vbi->time > 0 && (d < 0.025 || d > 0.050)) { |
423 | /* |
424 | * Since (dropped >= channel switch) we give |
425 | * ~1.5 s, then assume a switch. |
426 | */ |
427 | pthread_mutex_lock(&vbi->chswcd_mutex); |
428 | |
429 | if (vbi->chswcd == 0) |
430 | vbi->chswcd = 40; |
431 | |
432 | pthread_mutex_unlock(&vbi->chswcd_mutex); |
433 | |
434 | if (0) |
435 | fprintf(stderr, "vbi frame/s dropped at %f, D=%f\n", |
436 | time, time - vbi->time); |
437 | |
438 | /*Disable desync by GK*/ |
439 | #if 0 |
440 | if (vbi->event_mask & (VBI_EVENT_TTX_PAGE | |
441 | VBI_EVENT_NETWORK | |
442 | VBI_EVENT_NETWORK_ID)) |
443 | vbi_teletext_desync(vbi); |
444 | if (vbi->event_mask & (VBI_EVENT_CAPTION | |
445 | VBI_EVENT_NETWORK | |
446 | VBI_EVENT_NETWORK_ID)) |
447 | vbi_caption_desync(vbi); |
448 | #endif |
449 | } else { |
450 | pthread_mutex_lock(&vbi->chswcd_mutex); |
451 | |
452 | if (vbi->chswcd > 0 && --vbi->chswcd == 0) { |
453 | pthread_mutex_unlock(&vbi->chswcd_mutex); |
454 | vbi_chsw_reset(vbi, 0); |
455 | } else |
456 | pthread_mutex_unlock(&vbi->chswcd_mutex); |
457 | } |
458 | |
459 | if (time > vbi->time) |
460 | vbi->time = time; |
461 | |
462 | while (lines) { |
463 | if (sliced->id & VBI_SLICED_TELETEXT_B) |
464 | vbi_decode_teletext(vbi, sliced->data); |
465 | else if (sliced->id & (VBI_SLICED_CAPTION_525 | VBI_SLICED_CAPTION_625)) |
466 | vbi_decode_caption(vbi, sliced->line, sliced->data); |
467 | else if (sliced->id & VBI_SLICED_VPS) |
468 | vbi_decode_vps(vbi, sliced->data); |
469 | else if (sliced->id & VBI_SLICED_WSS_625) |
470 | vbi_decode_wss_625(vbi, sliced->data, time); |
471 | else if (sliced->id & VBI_SLICED_WSS_CPR1204) |
472 | vbi_decode_wss_cpr1204(vbi, sliced->data); |
473 | |
474 | sliced++; |
475 | lines--; |
476 | } |
477 | |
478 | if (vbi->event_mask & VBI_EVENT_TRIGGER) |
479 | vbi_deferred_trigger(vbi); |
480 | |
481 | if (0 && (rand() % 511) == 0) |
482 | vbi_eacem_trigger(vbi, (unsigned char *) /* Latin-1 */ |
483 | "<http://zapping.sourceforge.net>[n:Zapping][5450]"); |
484 | } |
485 | |
486 | void |
487 | vbi_chsw_reset(vbi_decoder *vbi, vbi_nuid identified) |
488 | { |
489 | vbi_nuid old_nuid; |
490 | |
491 | old_nuid = vbi->network.ev.network.nuid; |
492 | |
493 | if (0) |
494 | fprintf(stderr, "*** chsw identified=%d old nuid=%d\n", |
495 | identified, old_nuid); |
496 | |
497 | cache_network_unref (vbi->cn); |
498 | vbi->cn = _vbi_cache_add_network (vbi->ca, /* nk */ NULL, |
499 | VBI_VIDEOSTD_SET_625_50); |
500 | assert (NULL != vbi->cn); |
501 | |
502 | vbi_teletext_channel_switched(vbi); |
503 | vbi_caption_channel_switched(vbi); |
504 | |
505 | if (identified == 0) { |
506 | memset(&vbi->network, 0, sizeof(vbi->network)); |
507 | |
508 | if (old_nuid != 0) { |
509 | vbi->network.type = VBI_EVENT_NETWORK; |
510 | vbi_send_event(vbi, &vbi->network); |
511 | } |
512 | } /* else already identified */ |
513 | |
514 | vbi_trigger_flush(vbi); /* sic? */ |
515 | |
516 | if (vbi->aspect_source > 0) { |
517 | vbi_event e; |
518 | |
519 | e.ev.aspect.first_line = (vbi->aspect_source == 1) ? 23 : 22; |
520 | e.ev.aspect.last_line = (vbi->aspect_source == 1) ? 310 : 262; |
521 | e.ev.aspect.ratio = 1.0; |
522 | e.ev.aspect.film_mode = 0; |
523 | e.ev.aspect.open_subtitles = VBI_SUBT_UNKNOWN; |
524 | |
525 | e.type = VBI_EVENT_ASPECT; |
526 | vbi_send_event(vbi, &e); |
527 | } |
528 | |
529 | vbi_reset_prog_info(&vbi->prog_info[0]); |
530 | vbi_reset_prog_info(&vbi->prog_info[1]); |
531 | /* XXX event? */ |
532 | |
533 | vbi->prog_info[1].future = TRUE; |
534 | vbi->prog_info[0].future = FALSE; |
535 | |
536 | vbi->aspect_source = 0; |
537 | |
538 | vbi->wss_last[0] = 0; |
539 | vbi->wss_last[1] = 0; |
540 | vbi->wss_rep_ct = 0; |
541 | vbi->wss_time = 0.0; |
542 | |
543 | vbi->vt.header_page.pgno = 0; |
544 | |
545 | pthread_mutex_lock(&vbi->chswcd_mutex); |
546 | |
547 | vbi->chswcd = 0; |
548 | |
549 | pthread_mutex_unlock(&vbi->chswcd_mutex); |
550 | } |
551 | |
552 | /** |
553 | * @param vbi VBI decoding context. |
554 | * @param nuid Set to zero for now. |
555 | * |
556 | * Call this after switching away from the channel (RF channel, |
557 | * video input line, precisely: the network) from which this context |
558 | * used to receive vbi data, to reset the decoding context accordingly. |
559 | * This includes deletion of all cached Teletext and Closed Caption pages. |
560 | * |
561 | * The decoder attempts to detect channel switches automatically, but this |
562 | * is not 100 % reliable, especially without receiving and decoding Teletext |
563 | * or VPS which frequently transmit network identifiers. |
564 | * |
565 | * Note the reset is not executed until the next frame is about to be |
566 | * decoded, so you may still receive "old" events after calling this. You |
567 | * may also receive blank events (e. g. unknown network, unknown aspect |
568 | * ratio) revoking a previously sent event, until new information becomes |
569 | * available. |
570 | */ |
571 | void |
572 | vbi_channel_switched(vbi_decoder *vbi, vbi_nuid nuid) |
573 | { |
574 | /* XXX nuid */ |
575 | |
576 | nuid = nuid; |
577 | |
578 | pthread_mutex_lock(&vbi->chswcd_mutex); |
579 | |
580 | vbi->chswcd = 1; |
581 | |
582 | pthread_mutex_unlock(&vbi->chswcd_mutex); |
583 | } |
584 | |
585 | static inline int |
586 | transp(int val, int brig, int cont) |
587 | { |
588 | int r = (((val - 128) * cont) / 64) + brig; |
589 | |
590 | return SATURATE(r, 0, 255); |
591 | } |
592 | |
593 | /** |
594 | * @internal |
595 | * @param vbi Initialized vbi decoding context. |
596 | * @param d Destination palette. |
597 | * @param s Source palette. |
598 | * @param entries Size of source and destination palette. |
599 | * |
600 | * Transposes the source palette by @a vbi->brightness and @a vbi->contrast. |
601 | */ |
602 | void |
603 | vbi_transp_colormap(vbi_decoder *vbi, vbi_rgba *d, vbi_rgba *s, int entries) |
604 | { |
605 | int brig, cont; |
606 | |
607 | brig = SATURATE(vbi->brightness, 0, 255); |
608 | cont = SATURATE(vbi->contrast, -128, +127); |
609 | |
610 | while (entries--) { |
611 | *d++ = VBI_RGBA(transp(VBI_R(*s), brig, cont), |
612 | transp(VBI_G(*s), brig, cont), |
613 | transp(VBI_B(*s), brig, cont)); |
614 | s++; |
615 | } |
616 | } |
617 | |
618 | /** |
619 | * @param vbi Initialized vbi decoding context. |
620 | * @param brightness 0 dark ... 255 bright, default 128. |
621 | * |
622 | * Change brightness of text pages, this affects the |
623 | * color palette of pages fetched with vbi_fetch_vt_page() and |
624 | * vbi_fetch_cc_page(). |
625 | */ |
626 | void |
627 | vbi_set_brightness(vbi_decoder *vbi, int brightness) |
628 | { |
629 | vbi->brightness = brightness; |
630 | |
631 | vbi_caption_color_level(vbi); |
632 | } |
633 | |
634 | /** |
635 | * @param vbi Initialized vbi decoding context. |
636 | * @param contrast -128 inverse ... 0 none ... 127 maximum, default 64. |
637 | * |
638 | * Change contrast of text pages, this affects the |
639 | * color palette of pages fetched with vbi_fetch_vt_page() and |
640 | * vbi_fetch_cc_page(). |
641 | */ |
642 | void |
643 | vbi_set_contrast(vbi_decoder *vbi, int contrast) |
644 | { |
645 | vbi->contrast = contrast; |
646 | |
647 | vbi_caption_color_level(vbi); |
648 | } |
649 | |
650 | /** |
651 | * @param vbi Initialized vbi decoding context. |
652 | * @param pgno Teletext or Closed Caption page to examine, see vbi_pgno. |
653 | * @param subno The highest subpage number of this page will be |
654 | * stored here. @a subno can be @c NULL. |
655 | * @param language If it is possible to determine the language a page |
656 | * is written in, a pointer to the language name (Latin-1) will |
657 | * be stored here, @c NULL if the language is unknown. @a language |
658 | * can be @c NULL if this information is not needed. |
659 | * |
660 | * Returns information about the page. |
661 | * |
662 | * For Closed Caption pages (@a pgno 1 ... 8) @a subno will always |
663 | * be zero, @a language set or @c NULL. The return value will be |
664 | * @c VBI_SUBTITLE_PAGE for page 1 ... 4 (Closed Caption |
665 | * channel 1 ... 4), @c VBI_NORMAL_PAGE for page 5 ... 8 (Text channel |
666 | * 1 ... 4), or @c VBI_NO_PAGE if no data is currently transmitted on |
667 | * the channel. |
668 | * |
669 | * For Teletext pages (@a pgno 0x100 ... 0x8FF) @a subno returns |
670 | * the highest subpage number used. Note this number can be larger |
671 | * (but not smaller) than the number of subpages actually received |
672 | * and cached. Still there is no guarantee the advertised subpages |
673 | * will ever appear or stay in cache. |
674 | * |
675 | * <table> |
676 | * <tr><td><b>subno</b></td><td><b>meaning</b></td></tr> |
677 | * <tr><td>0</td><td>single page, no subpages</td></tr> |
678 | * <tr><td>1</td><td>never</td></tr> |
679 | * <tr><td>2 ... 0x3F7F</td><td>has subpages 1 ... @a subno </td></tr> |
680 | * <tr><td>0xFFFE</td><td>has unknown number (two or more) of subpages</td></tr> |
681 | * <tr><td>0xFFFF</td><td>presence of subpages unknown</td></tr> |
682 | * </table> |
683 | * |
684 | * @a language currently returns the language of subtitle pages, @c NULL |
685 | * if unknown or the page is not classified as @c VBI_SUBTITLE_PAGE. |
686 | * |
687 | * Other page types are: |
688 | * |
689 | * <table> |
690 | * <tr><td>VBI_NO_PAGE</td><td>Page is not in transmission</td></tr> |
691 | * <tr><td>VBI_NORMAL_PAGE</td><td> </td></tr> |
692 | * <tr><td>VBI_SUBTITLE_PAGE</td><td> </td></tr> |
693 | * <tr><td>VBI_SUBTITLE_INDEX</td><td>List of subtitle pages</td></tr> |
694 | * <tr><td>VBI_NONSTD_SUBPAGES</td><td>For example a world time page</td></tr> |
695 | * <tr><td>VBI_PROGR_WARNING</td><td>Program related warning (perhaps |
696 | * schedule change anouncements, the Teletext specification does not |
697 | * elaborate on this)</td></tr> |
698 | * <tr><td>VBI_CURRENT_PROGR</td><td>Information about the |
699 | * current program</td></tr> |
700 | * <tr><td>VBI_NOW_AND_NEXT</td><td>Brief information about the |
701 | * current and next program</td></tr> |
702 | * <tr><td>VBI_PROGR_INDEX</td><td>Program index page (perhaps the front |
703 | * page of all program related pages)</td></tr> |
704 | * <tr><td>VBI_PROGR_SCHEDULE</td><td>Program schedule page</td></tr> |
705 | * <tr><td>VBI_UNKNOWN_PAGE</td><td> </td></tr> |
706 | * </table> |
707 | * |
708 | * @note The results of this function are volatile: As more information |
709 | * becomes available and pages are edited (e. g. activation of subtitles, |
710 | * news updates, program related pages) subpage numbers can grow, page |
711 | * types, subno 0xFFFE and 0xFFFF and languages can change. |
712 | * |
713 | * @return |
714 | * Page type. |
715 | */ |
716 | vbi_page_type |
717 | vbi_classify_page(vbi_decoder *vbi, vbi_pgno pgno, |
718 | vbi_subno *subno, char **language) |
719 | { |
720 | struct ttx_page_stat *ps; |
721 | int code, subc; |
722 | char *lang; |
723 | |
724 | if (!subno) |
725 | subno = &subc; |
726 | if (!language) |
727 | language = ⟨ |
728 | |
729 | *subno = 0; |
730 | *language = NULL; |
731 | |
732 | if (pgno < 1) { |
733 | return VBI_UNKNOWN_PAGE; |
734 | } else if (pgno <= 8) { |
735 | if ((current_time() - vbi->cc.channel[pgno - 1].time) > 20) |
736 | return VBI_NO_PAGE; |
737 | |
738 | *language = vbi->cc.channel[pgno - 1].language; |
739 | |
740 | return (pgno <= 4) ? VBI_SUBTITLE_PAGE : VBI_NORMAL_PAGE; |
741 | } else if (pgno < 0x100 || pgno > 0x8FF) { |
742 | return VBI_UNKNOWN_PAGE; |
743 | } |
744 | |
745 | ps = cache_network_page_stat (vbi->cn, pgno); |
746 | code = ps->page_type; |
747 | |
748 | if (code != VBI_UNKNOWN_PAGE) { |
749 | if (code == VBI_SUBTITLE_PAGE) { |
750 | if (ps->charset_code != 0xFF) |
751 | *language = vbi_font_descriptors[ps->charset_code].label; |
752 | } else if (code == VBI_TOP_BLOCK || code == VBI_TOP_GROUP) |
753 | code = VBI_NORMAL_PAGE; |
754 | else if (code == VBI_NOT_PUBLIC || code > 0xE0) |
755 | return VBI_UNKNOWN_PAGE; |
756 | |
757 | *subno = ps->subcode; |
758 | |
759 | return code; |
760 | } |
761 | |
762 | if ((pgno & 0xFF) <= 0x99) { |
763 | *subno = 0xFFFF; |
764 | return VBI_NORMAL_PAGE; /* wild guess */ |
765 | } |
766 | |
767 | return VBI_UNKNOWN_PAGE; |
768 | } |
769 | |
770 | /** |
771 | * @param pi |
772 | * |
773 | * Convenience function to set a vbi_program_info |
774 | * structure to defaults. |
775 | */ |
776 | void |
777 | vbi_reset_prog_info(vbi_program_info *pi) |
778 | { |
779 | int i; |
780 | |
781 | /* PID */ |
782 | pi->month = -1; |
783 | pi->day = -1; |
784 | pi->hour = -1; |
785 | pi->min = -1; |
786 | pi->tape_delayed = 0; |
787 | /* PL */ |
788 | pi->length_hour = -1; |
789 | pi->length_min = -1; |
790 | pi->elapsed_hour = -1; |
791 | pi->elapsed_min = -1; |
792 | pi->elapsed_sec = -1; |
793 | /* PN */ |
794 | pi->title[0] = 0; |
795 | /* PT */ |
796 | pi->type_classf = VBI_PROG_CLASSF_NONE; |
797 | /* PR */ |
798 | pi->rating_auth = VBI_RATING_AUTH_NONE; |
799 | /* PAS */ |
800 | pi->audio[0].mode = VBI_AUDIO_MODE_UNKNOWN; |
801 | pi->audio[0].language = NULL; |
802 | pi->audio[1].mode = VBI_AUDIO_MODE_UNKNOWN; |
803 | pi->audio[1].language = NULL; |
804 | /* PCS */ |
805 | pi->caption_services = -1; |
806 | for (i = 0; i < 8; i++) |
807 | pi->caption_language[i] = NULL; |
808 | /* CGMS */ |
809 | pi->cgms_a = -1; |
810 | /* AR */ |
811 | pi->aspect.first_line = -1; |
812 | pi->aspect.last_line = -1; |
813 | pi->aspect.ratio = 0.0; |
814 | pi->aspect.film_mode = 0; |
815 | pi->aspect.open_subtitles = VBI_SUBT_UNKNOWN; |
816 | /* PD */ |
817 | for (i = 0; i < 8; i++) |
818 | pi->description[i][0] = 0; |
819 | } |
820 | |
821 | /** |
822 | * @param vbi Decoder structure allocated with vbi_decoder_new(). |
823 | * @brief Delete a data service decoder instance. |
824 | */ |
825 | void |
826 | vbi_decoder_delete(vbi_decoder *vbi) |
827 | { |
828 | struct event_handler *eh; |
829 | |
830 | if (NULL == vbi) |
831 | return; |
832 | |
833 | vbi_trigger_flush(vbi); |
834 | |
835 | vbi_caption_destroy(vbi); |
836 | |
837 | while (NULL != (eh = vbi->handlers)) { |
838 | vbi_event_handler_unregister (vbi, |
839 | eh->handler, |
840 | eh->user_data); |
841 | } |
842 | |
843 | pthread_mutex_destroy(&vbi->prog_info_mutex); |
844 | pthread_mutex_destroy(&vbi->event_mutex); |
845 | pthread_mutex_destroy(&vbi->chswcd_mutex); |
846 | |
847 | cache_network_unref (vbi->cn); |
848 | |
849 | vbi_cache_delete (vbi->ca); |
850 | |
851 | CLEAR (*vbi); |
852 | |
853 | free (vbi); |
854 | } |
855 | |
856 | /** |
857 | * @brief Allocate a new data service decoder instance. |
858 | * |
859 | * @return |
860 | * vbi_decoder pointer or @c NULL on failure, probably due to lack |
861 | * of memory. |
862 | */ |
863 | vbi_decoder * |
864 | vbi_decoder_new(void) |
865 | { |
866 | vbi_decoder *vbi; |
867 | |
868 | pthread_once (&vbi_init_once, vbi_init); |
869 | |
870 | vbi = (vbi_decoder *) calloc (1, sizeof (*vbi)); |
871 | if (NULL == vbi) |
872 | goto failed; |
873 | |
874 | vbi->ca = vbi_cache_new (); |
875 | if (NULL == vbi->ca) |
876 | goto failed; |
877 | |
878 | vbi->cn = _vbi_cache_add_network (vbi->ca, |
879 | /* nk */ NULL, |
880 | VBI_VIDEOSTD_SET_625_50); |
881 | if (NULL == vbi->cn) |
882 | goto failed; |
883 | |
884 | pthread_mutex_init(&vbi->chswcd_mutex, NULL); |
885 | pthread_mutex_init(&vbi->event_mutex, NULL); |
886 | pthread_mutex_init(&vbi->prog_info_mutex, NULL); |
887 | |
888 | vbi->time = 0.0; |
889 | |
890 | vbi->brightness = 128; |
891 | vbi->contrast = 64; |
892 | |
893 | vbi_teletext_init(vbi); |
894 | |
895 | vbi_teletext_set_level(vbi, VBI_WST_LEVEL_2p5); |
896 | |
897 | vbi_caption_init(vbi); |
898 | |
899 | return vbi; |
900 | |
901 | failed: |
902 | if (NULL != vbi) { |
903 | cache_network_unref (vbi->cn); |
904 | |
905 | vbi_cache_delete (vbi->ca); |
906 | |
907 | CLEAR (*vbi); |
908 | |
909 | free (vbi); |
910 | } |
911 | |
912 | return NULL; |
913 | } |
914 | |
915 | /** |
916 | * @ingroup Basic |
917 | * |
918 | * @param major Store major number here, can be NULL. |
919 | * @param minor Store minor number here, can be NULL. |
920 | * @param micro Store micro number here, can be NULL. |
921 | * |
922 | * Returns the library version defined in the libzvbi.h header file |
923 | * when the library was compiled. |
924 | * |
925 | * @since 0.2.5 |
926 | */ |
927 | void |
928 | vbi_version (unsigned int * major, |
929 | unsigned int * minor, |
930 | unsigned int * micro) |
931 | { |
932 | if (major) *major = VBI_VERSION_MAJOR; |
933 | if (minor) *minor = VBI_VERSION_MINOR; |
934 | if (micro) *micro = VBI_VERSION_MICRO; |
935 | } |
936 | |
937 | /** |
938 | * @param vbi |
939 | * @param pgno |
940 | * @param subno |
941 | * |
942 | * @deprecated At the moment pages can only be added to the |
943 | * cache but not removed unless the decoder is reset. That |
944 | * will change, making the result volatile in a multithreaded |
945 | * environment. |
946 | * |
947 | * @returns |
948 | * @c TRUE if the given page is cached. |
949 | */ |
950 | int |
951 | vbi_is_cached (vbi_decoder * vbi, |
952 | int pgno, |
953 | int subno) |
954 | { |
955 | cache_page *cp; |
956 | |
957 | cp = _vbi_cache_get_page (vbi->ca, vbi->cn, |
958 | pgno, subno, |
959 | /* subno_mask */ -1); |
960 | cache_page_unref (cp); |
961 | |
962 | return NULL != cp; |
963 | } |
964 | |
965 | /** |
966 | * @param vbi |
967 | * @param pgno |
968 | * |
969 | * @deprecated Rationale same as vbi_is_cached(). |
970 | * |
971 | * @returns |
972 | * Highest cached subpage of this page. |
973 | */ |
974 | int |
975 | vbi_cache_hi_subno (vbi_decoder * vbi, |
976 | int pgno) |
977 | { |
978 | const struct ttx_page_stat *ps; |
979 | |
980 | ps = cache_network_const_page_stat (vbi->cn, pgno); |
981 | |
982 | return ps->subno_max; |
983 | } |
984 | |
985 | /* |
986 | Local variables: |
987 | c-set-style: K&R |
988 | c-basic-offset: 8 |
989 | End: |
990 | */ |
991 |