summaryrefslogtreecommitdiff
path: root/src/vbi.c (plain)
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
92pthread_once_t vbi_init_once = PTHREAD_ONCE_INIT;
93
94void
95vbi_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 */
119void
120vbi_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? */
137static void
138vbi_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 */
180vbi_bool
181vbi_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 */
242void
243vbi_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 */
270vbi_bool
271vbi_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 **/
341void
342vbi_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 */
359void
360vbi_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
380static inline double
381current_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 */
415void
416vbi_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
486void
487vbi_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 */
571void
572vbi_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
585static inline int
586transp(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 */
602void
603vbi_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 */
626void
627vbi_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 */
642void
643vbi_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>&nbsp;</td></tr>
692 * <tr><td>VBI_SUBTITLE_PAGE</td><td>&nbsp;</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>&nbsp;</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 */
716vbi_page_type
717vbi_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 = &lang;
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 */
776void
777vbi_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 */
825void
826vbi_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 */
863vbi_decoder *
864vbi_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 */
927void
928vbi_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 */
950int
951vbi_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 */
974int
975vbi_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/*
986Local variables:
987c-set-style: K&R
988c-basic-offset: 8
989End:
990*/
991