plugin_LTLIBRARIES = libgstclosedcaption.la
+zvbi_sources = \
+ bit_slicer.c \
+ decoder.c \
+ raw_decoder.c \
+ sampling_par.c
+
+zvbi_headers = \
+ bcd.h \
+ bit_slicer.h \
+ decoder.h \
+ macros.h \
+ misc.h \
+ raw_decoder.h \
+ sampling_par.h \
+ sliced.h
+
libgstclosedcaption_la_SOURCES = \
+ $(zvbi_sources) \
+ $(zvbi_headers) \
gstccextractor.c \
gstccextractor.h \
gstclosedcaption.c
libgstclosedcaption_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = \
- gstccextractor.h
+ gstccextractor.h \
+ $(zvbi_headers)
--- /dev/null
+/*
+ * libzvbi -- BCD arithmetic for Teletext page numbers
+ *
+ * Copyright (C) 2001, 2002 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: bcd.h,v 1.19 2008-02-21 07:18:52 mschimek Exp $ */
+
+#ifndef BCD_H
+#define BCD_H
+
+#include "misc.h"
+
+/**
+ * @addtogroup BCD BCD arithmetic for Teletext page numbers
+ * @ingroup HiDec
+ *
+ * Teletext page numbers are expressed as packed binary coded decimal
+ * numbers in range 0x100 to 0x8FF. The bcd format encodes one decimal
+ * digit in every hex nibble (four bits) of the number. Page numbers
+ * containing digits 0xA to 0xF are reserved for various system purposes
+ * and not intended for display.
+ */
+
+/* Public */
+
+/**
+ * @ingroup HiDec
+ *
+ * Teletext or Closed Caption page number. For Teletext pages
+ * this is a packed bcd number in range 0x100 ... 0x8FF. Page
+ * numbers containing digits 0xA to 0xF are reserved for various
+ * system purposes, these pages are not intended for display.
+ *
+ * Closed Caption page numbers between 1 ... 8 correspond
+ * to the four Caption and Text channels:
+ * <table>
+ * <tr><td>1</td><td>Caption 1</td><td>
+ * "Primary synchronous caption service [English]"</td></tr>
+ * <tr><td>2</td><td>Caption 2</td><td>
+ * "Special non-synchronous data that is intended to
+ * augment information carried in the program"</td></tr>
+ * <tr><td>3</td><td>Caption 3</td><td>
+ * "Secondary synchronous caption service, usually
+ * second language [Spanish, French]"</td></tr>
+ * <tr><td>4</td><td>Caption 4</td><td>
+ * "Special non-synchronous data similar to Caption 2"</td></tr>
+ * <tr><td>5</td><td>Text 1</td><td>
+ * "First text service, data usually not program related"</td></tr>
+ * <tr><td>6</td><td>Text 2</td><td>
+ * "Second text service, additional data usually not program related
+ * [ITV data]"</td></tr>
+ * <tr><td>7</td><td>Text 3</td><td>
+ * "Additional text channel"</td></tr>
+ * <tr><td>8</td><td>Text 4</td><td>
+ * "Additional text channel"</td></tr>
+ * </table>
+ */
+/* XXX unsigned? */
+typedef int vbi_pgno;
+
+/**
+ * @ingroup HiDec
+ *
+ * This is the subpage number only applicable to Teletext pages,
+ * a packed bcd number in range 0x00 ... 0x99. On special 'clock' pages
+ * (for example listing the current time in different time zones)
+ * it can assume values between 0x0000 ... 0x2359 expressing
+ * local time. These are not actually subpages.
+ */
+typedef int vbi_subno;
+
+/**
+ * @ingroup HiDec
+ */
+#define VBI_ANY_SUBNO 0x3F7F
+/**
+ * @ingroup HiDec
+ */
+#define VBI_NO_SUBNO 0x3F7F
+
+/**
+ * @ingroup BCD
+ * @param dec Decimal number.
+ *
+ * Converts a two's complement binary between 0 ... 999 to a
+ * packed bcd number in range 0x000 ... 0x999. Extra digits in
+ * the input will be discarded.
+ *
+ * @return
+ * BCD number.
+ */
+_vbi_inline unsigned int
+vbi_dec2bcd(unsigned int dec)
+{
+ return (dec % 10) + ((dec / 10) % 10) * 16 + ((dec / 100) % 10) * 256;
+}
+
+/**
+ * @ingroup BCD
+ * @since 0.2.28
+ */
+#define vbi_bin2bcd(n) vbi_dec2bcd(n)
+
+/**
+ * @ingroup BCD
+ * @param bcd BCD number.
+ *
+ * Converts a packed bcd number between 0x000 ... 0xFFF to a two's
+ * complement binary in range 0 ... 999. Extra digits in the input
+ * will be discarded.
+ *
+ * @return
+ * Decimal number. The result is undefined when the bcd number contains
+ * hex digits 0xA ... 0xF.
+ **/
+_vbi_inline unsigned int
+vbi_bcd2dec(unsigned int bcd)
+{
+ return (bcd & 15) + ((bcd >> 4) & 15) * 10 + ((bcd >> 8) & 15) * 100;
+}
+
+/**
+ * @ingroup BCD
+ * @since 0.2.28
+ */
+#define vbi_bcd2bin(n) vbi_bcd2dec(n)
+
+/**
+ * @ingroup BCD
+ * @param a BCD number.
+ * @param b BCD number.
+ *
+ * Adds two packed bcd numbers, returning a packed bcd sum. Arguments
+ * and result are in range 0xF000 0000 ... 0x0999 9999, that
+ * is -10**7 ... +10**7 - 1 in decimal notation. To subtract you can
+ * add the 10's complement, e. g. -1 = 0xF999 9999.
+ *
+ * @return
+ * Packed bcd number. The result is undefined when any of the arguments
+ * contain hex digits 0xA ... 0xF.
+ */
+_vbi_inline unsigned int
+vbi_add_bcd(unsigned int a, unsigned int b)
+{
+ unsigned int t;
+
+ a += 0x06666666;
+ t = a + b;
+ b ^= a ^ t;
+ b = (~b & 0x11111110) >> 3;
+ b |= b * 2;
+
+ return t - b;
+}
+
+/**
+ * @ingroup BCD
+ * @param bcd BCD number.
+ *
+ * Tests if @a bcd forms a valid BCD number. The argument must be
+ * in range 0x0000 0000 ... 0x0999 9999.
+ *
+ * @return
+ * @c FALSE if @a bcd contains hex digits 0xA ... 0xF.
+ */
+_vbi_inline vbi_bool
+vbi_is_bcd(unsigned int bcd)
+{
+ static const unsigned int x = 0x06666666;
+
+ return (((bcd + x) ^ (bcd ^ x)) & 0x11111110) == 0;
+}
+
+/**
+ * @ingroup BCD
+ * @param bcd Unsigned BCD number.
+ * @param maximum Unsigned maximum value.
+ *
+ * Compares an unsigned packed bcd number digit-wise against a maximum
+ * value, for example 0x295959. @a maximum can contain digits 0x0
+ * ... 0xF.
+ *
+ * @return
+ * @c TRUE if any digit of @a bcd is greater than the
+ * corresponding digit of @a maximum.
+ *
+ * @since 0.2.28
+ */
+_vbi_inline vbi_bool
+vbi_bcd_digits_greater (unsigned int bcd,
+ unsigned int maximum)
+{
+ maximum ^= ~0;
+
+ return 0 != (((bcd + maximum) ^ bcd ^ maximum) & 0x11111110);
+}
+
+/* Private */
+
+#endif /* BCD_H */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi - Bit slicer
+ *
+ * Copyright (C) 2000-2007 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: bit_slicer.c,v 1.16 2008-02-19 00:35:14 mschimek Exp $ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "misc.h"
+#include "bit_slicer.h"
+
+# define VBI_PIXFMT_Y8 VBI_PIXFMT_YUV420
+# define VBI_PIXFMT_RGB24_LE VBI_PIXFMT_RGB24
+# define VBI_PIXFMT_BGR24_LE VBI_PIXFMT_BGR24
+# define VBI_PIXFMT_RGBA24_LE VBI_PIXFMT_RGBA32_LE
+# define VBI_PIXFMT_BGRA24_LE VBI_PIXFMT_BGRA32_LE
+# define VBI_PIXFMT_RGBA24_BE VBI_PIXFMT_RGBA32_BE
+# define VBI_PIXFMT_BGRA24_BE VBI_PIXFMT_BGRA32_BE
+# define VBI_PIXFMT_RGB8 101
+# define vbi_pixfmt_bytes_per_pixel VBI_PIXFMT_BPP
+
+/**
+ * $addtogroup BitSlicer Bit Slicer
+ * $ingroup Raw
+ * $brief Converting a single scan line of raw VBI
+ * data to sliced VBI data.
+ *
+ * These are low level functions most useful if you want to decode
+ * data services not covered by libzvbi. Usually you will want to
+ * use the raw VBI decoder, converting several lines of different
+ * data services at once.
+ */
+
+/* This is time critical, tinker with care.
+
+ What about all these macros? They are templates to avoid a
+ pixel format switch within time critical loops. Instead we
+ compile bit slicer functions for different pixel formats.
+
+ I would use inline functions for proper type checking, but
+ there's no guarantee the compiler really will inline. */
+
+/* Read a green sample, e.g. rrrrrggg gggbbbbb. endian is const. */
+#define GREEN2(raw, endian) \
+ (((raw)[0 + endian] + (raw)[1 - endian] * 256) & bs->green_mask)
+
+/* Read a sample with pixfmt conversion. pixfmt is const. */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GREEN(raw) \
+ ((VBI_PIXFMT_RGB8 == pixfmt) ? \
+ *(const uint8_t *)(raw) & bs->green_mask : \
+ ((VBI_PIXFMT_RGB16_LE == pixfmt) ? \
+ *(const uint16_t *)(raw) & bs->green_mask : \
+ ((VBI_PIXFMT_RGB16_BE == pixfmt) ? \
+ GREEN2 (raw, 1) : \
+ (raw)[0])))
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+#define GREEN(raw) \
+ ((VBI_PIXFMT_RGB8 == pixfmt) ? \
+ *(const uint8_t *)(raw) & bs->green_mask : \
+ ((VBI_PIXFMT_RGB16_LE == pixfmt) ? \
+ GREEN2 (raw, 0) : \
+ ((VBI_PIXFMT_RGB16_BE == pixfmt) ? \
+ *(const uint16_t *)(raw) & bs->green_mask : \
+ (raw)[0])))
+#else
+#define GREEN(raw) \
+ ((VBI_PIXFMT_RGB8 == pixfmt) ? \
+ *(const uint8_t *)(raw) & bs->green_mask : \
+ ((VBI_PIXFMT_RGB16_LE == pixfmt) ? \
+ GREEN2 (raw, 0) : \
+ ((VBI_PIXFMT_RGB16_BE == pixfmt) ? \
+ GREEN2 (raw, 1) : \
+ (raw)[0])))
+#endif
+
+/* raw0 = raw[index >> 8], linear interpolated. */
+#define SAMPLE(_kind) \
+do { \
+ const uint8_t *r; \
+ \
+ r = raw + (i >> 8) * bpp; \
+ raw0 = GREEN (r); \
+ raw1 = GREEN (r + bpp); \
+ raw0 = (int)(raw1 - raw0) * (i & 255) + (raw0 << 8); \
+ if (collect_points) { \
+ points->kind = _kind; \
+ points->index = (raw - raw_start) * 256 + i; \
+ points->level = raw0; \
+ points->thresh = tr; \
+ ++points; \
+ } \
+} while (0)
+
+#define PAYLOAD() \
+do { \
+ i = bs->phase_shift; /* current bit position << 8 */ \
+ tr *= 256; \
+ c = 0; \
+ \
+ for (j = bs->frc_bits; j > 0; --j) { \
+ SAMPLE (VBI3_FRC_BIT); \
+ c = c * 2 + (raw0 >= tr); \
+ i += bs->step; /* next bit */ \
+ } \
+ \
+ if (c != bs->frc) \
+ return FALSE; \
+ \
+ switch (bs->endian) { \
+ case 3: /* bitwise, lsb first */ \
+ for (j = 0; j < bs->payload; ++j) { \
+ SAMPLE (VBI3_PAYLOAD_BIT); \
+ c = (c >> 1) + ((raw0 >= tr) << 7); \
+ i += bs->step; \
+ if ((j & 7) == 7) \
+ *buffer++ = c; \
+ } \
+ *buffer = c >> ((8 - bs->payload) & 7); \
+ break; \
+ \
+ case 2: /* bitwise, msb first */ \
+ for (j = 0; j < bs->payload; ++j) { \
+ SAMPLE (VBI3_PAYLOAD_BIT); \
+ c = c * 2 + (raw0 >= tr); \
+ i += bs->step; \
+ if ((j & 7) == 7) \
+ *buffer++ = c; \
+ } \
+ *buffer = c & ((1 << (bs->payload & 7)) - 1); \
+ break; \
+ \
+ case 1: /* octets, lsb first */ \
+ for (j = bs->payload; j > 0; --j) { \
+ for (k = 0, c = 0; k < 8; ++k) { \
+ SAMPLE (VBI3_PAYLOAD_BIT); \
+ c += (raw0 >= tr) << k; \
+ i += bs->step; \
+ } \
+ *buffer++ = c; \
+ } \
+ break; \
+ \
+ default: /* octets, msb first */ \
+ for (j = bs->payload; j > 0; --j) { \
+ for (k = 0; k < 8; ++k) { \
+ SAMPLE (VBI3_PAYLOAD_BIT); \
+ c = c * 2 + (raw0 >= tr); \
+ i += bs->step; \
+ } \
+ *buffer++ = c; \
+ } \
+ break; \
+ } \
+} while (0)
+
+#define CRI() \
+do { \
+ unsigned int tavg; \
+ unsigned char b; /* current bit */ \
+ \
+ tavg = (t + (oversampling / 2)) / oversampling; \
+ b = (tavg >= tr); \
+ \
+ if (unlikely (b ^ b1)) { \
+ cl = bs->oversampling_rate >> 1; \
+ } else { \
+ cl += bs->cri_rate; \
+ \
+ if (cl >= bs->oversampling_rate) { \
+ if (collect_points) { \
+ points->kind = VBI3_CRI_BIT; \
+ points->index = (raw - raw_start) << 8; \
+ points->level = tavg << 8; \
+ points->thresh = tr << 8; \
+ ++points; \
+ } \
+ \
+ cl -= bs->oversampling_rate; \
+ c = c * 2 + b; \
+ if ((c & bs->cri_mask) == bs->cri) { \
+ PAYLOAD (); \
+ if (collect_points) { \
+ *n_points = points \
+ - points_start; \
+ } \
+ return TRUE; \
+ } \
+ } \
+ } \
+ \
+ b1 = b; \
+ \
+ if (oversampling > 1) \
+ t += raw1; \
+} while (0)
+
+#define CORE() \
+do { \
+ const uint8_t *raw_start; \
+ unsigned int i, j, k; \
+ unsigned int cl; /* clock */ \
+ unsigned int thresh0; /* old 0/1 threshold */ \
+ unsigned int tr; /* current threshold */ \
+ unsigned int c; /* current byte */ \
+ unsigned int t; /* t = raw[0] * j + raw[1] * (1 - j) */ \
+ unsigned int raw0; /* oversampling temporary */ \
+ unsigned int raw1; \
+ unsigned char b1; /* previous bit */ \
+ \
+ thresh0 = bs->thresh; \
+ raw_start = raw; \
+ raw += bs->skip; \
+ \
+ cl = 0; \
+ c = 0; \
+ b1 = 0; \
+ \
+ for (i = bs->cri_samples; i > 0; --i) { \
+ tr = bs->thresh >> thresh_frac; \
+ raw0 = GREEN (raw); \
+ raw1 = GREEN (raw + bpp); \
+ raw1 -= raw0; \
+ bs->thresh += (int)(raw0 - tr) * (int) ABS ((int) raw1); \
+ t = raw0 * oversampling; \
+ \
+ for (j = oversampling; j > 0; --j) \
+ CRI (); \
+ \
+ raw += bpp; \
+ } \
+ \
+ bs->thresh = thresh0; \
+ \
+ if (collect_points) \
+ *n_points = points - points_start; \
+ \
+ return FALSE; \
+} while (0)
+
+#define BIT_SLICER(fmt, os, tf) \
+static vbi_bool \
+bit_slicer_ ## fmt (vbi3_bit_slicer * bs, \
+ uint8_t * buffer, \
+ vbi3_bit_slicer_point *points, \
+ unsigned int * n_points, \
+ const uint8_t * raw) \
+{ \
+ static const vbi_pixfmt pixfmt = VBI_PIXFMT_ ## fmt; \
+ unsigned int bpp = \
+ vbi_pixfmt_bytes_per_pixel (VBI_PIXFMT_ ## fmt); \
+ static const unsigned int oversampling = os; \
+ static const vbi3_bit_slicer_point *points_start = NULL; \
+ static const vbi_bool collect_points = FALSE; \
+ unsigned int thresh_frac = tf; \
+ \
+ CORE (); \
+}
+
+#define DEF_THR_FRAC 9
+
+BIT_SLICER (Y8, 4, DEF_THR_FRAC) /* any format with 0 bytes between Y or G */
+ BIT_SLICER (YUYV, 4, DEF_THR_FRAC) /* 1 byte */
+ BIT_SLICER (RGB24_LE, 4, DEF_THR_FRAC) /* 2 bytes */
+ BIT_SLICER (RGBA24_LE, 4, DEF_THR_FRAC) /* 3 bytes */
+ BIT_SLICER (RGB16_LE, 4, bs->thresh_frac)
+ BIT_SLICER (RGB16_BE, 4, bs->thresh_frac)
+
+ static const unsigned int LP_AVG = 4;
+
+ static vbi_bool
+ low_pass_bit_slicer_Y8 (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ vbi3_bit_slicer_point * points, unsigned int *n_points, const uint8_t * raw)
+{
+ vbi3_bit_slicer_point *points_start;
+ const uint8_t *raw_start;
+ unsigned int i, j, k, m;
+ unsigned int cl; /* clock */
+ unsigned int thresh0; /* old 0/1 threshold */
+ unsigned int tr; /* current threshold */
+ unsigned int c; /* current byte */
+ unsigned int raw0; /* oversampling temporary */
+ unsigned char b1; /* previous bit */
+ unsigned int bps;
+ unsigned int raw0sum;
+
+ points_start = points;
+
+ raw_start = raw;
+ raw += bs->skip;
+
+ bps = bs->bytes_per_sample;
+
+ thresh0 = bs->thresh;
+
+ c = -1;
+ cl = 0;
+ b1 = 0;
+
+ raw0sum = raw[0];
+ for (m = bps; m < (bps << LP_AVG); m += bps) {
+ raw0sum += raw[m];
+ }
+
+ i = bs->cri_samples;
+
+ for (;;) {
+ unsigned char b; /* current bit */
+
+ tr = bs->thresh >> bs->thresh_frac;
+ raw0 = raw0sum;
+ raw0sum = raw0sum + raw[bps << LP_AVG]
+ - raw[0];
+ raw += bps;
+ bs->thresh += (int) (raw0 - tr)
+ * (int) ABS ((int) (raw0sum - raw0));
+
+ b = (raw0 >= tr);
+
+ if (unlikely (b ^ b1)) {
+ cl = bs->oversampling_rate >> 1;
+ } else {
+ cl += bs->cri_rate;
+
+ if (cl >= bs->oversampling_rate) {
+ if (unlikely (NULL != points)) {
+ points->kind = VBI3_CRI_BIT;
+ points->index = (raw - raw_start)
+ * 256 / bs->bytes_per_sample + (1 << LP_AVG) * 128;
+ points->level = raw0 << (8 - LP_AVG);
+ points->thresh = tr << (8 - LP_AVG);
+ ++points;
+ }
+
+ cl -= bs->oversampling_rate;
+ c = c * 2 + b;
+ if ((c & bs->cri_mask) == bs->cri) {
+ break;
+ }
+ }
+ }
+
+ b1 = b;
+
+ if (0 == --i) {
+ bs->thresh = thresh0;
+
+ if (unlikely (NULL != points))
+ *n_points = points - points_start;
+
+ return FALSE;
+ }
+ }
+
+#define LP_SAMPLE(_kind) \
+do { \
+ unsigned int ii = (i >> 8) * bps; \
+ \
+ raw0 = raw[ii]; \
+ for (m = bps; m < (bps << LP_AVG); m += bps) \
+ raw0 += raw[ii + m]; \
+ if (unlikely (NULL != points)) { \
+ points->kind = _kind; \
+ points->index = (raw - raw_start) \
+ * 256 / bs->bytes_per_sample \
+ + (1 << LP_AVG) * 128 \
+ + ii * 256; \
+ points->level = raw0 << (8 - LP_AVG); \
+ points->thresh = tr << (8 - LP_AVG); \
+ ++points; \
+ } \
+} while (0)
+
+ i = bs->phase_shift; /* current bit position << 8 */
+ c = 0;
+
+ for (j = bs->frc_bits; j > 0; --j) {
+ LP_SAMPLE (VBI3_FRC_BIT);
+ c = c * 2 + (raw0 >= tr);
+ i += bs->step; /* next bit */
+ }
+
+ if (c != bs->frc)
+ return FALSE;
+
+ c = 0;
+
+ switch (bs->endian) {
+ case 3: /* bitwise, lsb first */
+ for (j = 0; j < bs->payload; ++j) {
+ LP_SAMPLE (VBI3_PAYLOAD_BIT);
+ c = (c >> 1) + ((raw0 >= tr) << 7);
+ i += bs->step;
+ if ((j & 7) == 7)
+ *buffer++ = c;
+ }
+ *buffer = c >> ((8 - bs->payload) & 7);
+ break;
+
+ case 2: /* bitwise, msb first */
+ for (j = 0; j < bs->payload; ++j) {
+ LP_SAMPLE (VBI3_PAYLOAD_BIT);
+ c = c * 2 + (raw0 >= tr);
+ i += bs->step;
+ if ((j & 7) == 7)
+ *buffer++ = c;
+ }
+ *buffer = c & ((1 << (bs->payload & 7)) - 1);
+ break;
+
+ case 1: /* octets, lsb first */
+ j = bs->payload;
+ do {
+ for (k = 0; k < 8; ++k) {
+ LP_SAMPLE (VBI3_PAYLOAD_BIT);
+ c = (c >> 1) + ((raw0 >= tr) << 7);
+ i += bs->step;
+ }
+ *buffer++ = c;
+ } while (--j > 0);
+ break;
+
+ default: /* octets, msb first */
+ j = bs->payload;
+ do {
+ for (k = 0; k < 8; ++k) {
+ LP_SAMPLE (VBI3_PAYLOAD_BIT);
+ c = c * 2 + (raw0 >= tr);
+ i += bs->step;
+ }
+ *buffer++ = c;
+ } while (--j > 0);
+ break;
+ }
+
+ if (unlikely (NULL != points)) {
+ *n_points = points - points_start;
+ }
+
+ return TRUE;
+}
+
+static vbi_bool
+null_function (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ vbi3_bit_slicer_point * points, unsigned int *n_points, const uint8_t * raw)
+{
+ buffer = buffer; /* unused */
+ points = points;
+ n_points = n_points;
+ raw = raw;
+
+ warning (&bs->log, "vbi3_bit_slicer_set_params() not called.");
+
+ return FALSE;
+}
+
+/**
+ * @param bs Pointer to vbi3_bit_slicer object allocated with
+ * vbi3_bit_slicer_new().
+ * @param buffer Output data.
+ * @param buffer_size Size of the output buffer. The buffer must be
+ + large enough to store the number of bits given as @a payload_bits to
+ * vbi3_bit_slicer_new().
+ * @param points Information about the bits sampled by the bit slicer
+ * are stored here.
+ * @param n_points The number of sampling points stored in the
+ * @a points array will be stored here.
+ * @param max_points Size of the @a points array. The array must be
+ * large enough to store one sampling point for all @a crc_bits,
+ * @a frc_bits and @a payload_bits given to vbi3_bit_slicer_new().
+ * @param raw Input data. At least the number of pixels or samples
+ * given as @a samples_per_line to vbi3_bit_slicer_new().
+ *
+ * Like vbi3_bit_slicer_slice() but additionally provides information
+ * about where and how bits were sampled. This is mainly interesting
+ * for debugging.
+ *
+ * @returns
+ * @c FALSE if the @a buffer or @a points array is too small, if the
+ * pixel format is not supported or if the raw data does not contain
+ * the expected information, i. e. the CRI/FRC has not been found. In
+ * these cases the @a buffer remains unmodified but the @a points
+ * array may contain data.
+ *
+ * @bug
+ * Currently this function is only implemented for
+ * raw data in planar YUV formats and @c VBI3_PIXFMT_Y8.
+ */
+vbi_bool
+ vbi3_bit_slicer_slice_with_points
+ (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ unsigned int buffer_size,
+ vbi3_bit_slicer_point * points,
+ unsigned int *n_points, unsigned int max_points, const uint8_t * raw) {
+ static const vbi_pixfmt pixfmt = VBI_PIXFMT_Y8;
+ static const unsigned int bpp = 1;
+ static const unsigned int oversampling = 4; /* see above */
+ static const unsigned int thresh_frac = DEF_THR_FRAC;
+ static const vbi_bool collect_points = TRUE;
+ vbi3_bit_slicer_point *points_start;
+
+ assert (NULL != bs);
+ assert (NULL != buffer);
+ assert (NULL != points);
+ assert (NULL != n_points);
+ assert (NULL != raw);
+
+ points_start = points;
+ *n_points = 0;
+
+ if (bs->payload > buffer_size * 8) {
+ warning (&bs->log,
+ "buffer_size %u < %u bits of payload.", buffer_size * 8, bs->payload);
+ return FALSE;
+ }
+
+ if (bs->total_bits > max_points) {
+ warning (&bs->log,
+ "max_points %u < %u CRI, FRC and payload bits.",
+ max_points, bs->total_bits);
+ return FALSE;
+ }
+
+ if (low_pass_bit_slicer_Y8 == bs->func) {
+ return bs->func (bs, buffer, points, n_points, raw);
+ } else if (bit_slicer_Y8 != bs->func) {
+ warning (&bs->log,
+ "Function not implemented for pixfmt %u.", bs->sample_format);
+ return bs->func (bs, buffer,
+ /* points */ NULL,
+ /* n_points */ NULL,
+ raw);
+ }
+
+ CORE ();
+}
+
+/**
+ * @param bs Pointer to vbi3_bit_slicer object allocated with
+ * vbi3_bit_slicer_new(). You must also call
+ * vbi3_bit_slicer_set_params() before calling this function.
+ * @param buffer Output data.
+ * @param buffer_size Size of the output buffer. The buffer must be
+ + large enough to store the number of bits given as @a payload to
+ * vbi3_bit_slicer_new().
+ * @param raw Input data. At least the number of pixels or samples
+ * given as @a samples_per_line to vbi3_bit_slicer_new().
+ *
+ * Decodes one scan line of raw vbi data. Note the bit slicer tries
+ * to adapt to the average signal amplitude, you should avoid
+ * using the same vbi3_bit_slicer object for data from different
+ * devices.
+ *
+ * @return
+ * @c FALSE if the @a buffer is too small or if the raw data does not
+ * contain the expected information, i. e. the CRI/FRC has not been
+ * found. This may also result from a too weak or noisy signal. Error
+ * correction must be implemented at a higher layer. When the function
+ * fails, the @a buffer remains unmodified.
+ */
+vbi_bool
+vbi3_bit_slicer_slice (vbi3_bit_slicer * bs,
+ uint8_t * buffer, unsigned int buffer_size, const uint8_t * raw)
+{
+ assert (NULL != bs);
+ assert (NULL != buffer);
+ assert (NULL != raw);
+
+ if (bs->payload > buffer_size * 8) {
+ warning (&bs->log,
+ "buffer_size %u < %u bits of payload.", buffer_size * 8, bs->payload);
+ return FALSE;
+ }
+
+ return bs->func (bs, buffer,
+ /* points */ NULL,
+ /* n_points */ NULL,
+ raw);
+}
+
+/**
+ * @param bs Pointer to vbi3_bit_slicer object allocated with
+ * vbi3_bit_slicer_new().
+ * @param sample_format Format of the raw data, see vbi3_pixfmt.
+ * Note the bit slicer looks only at the green component of RGB
+ * pixels.
+ * @param sampling_rate Raw vbi sampling rate in Hz, that is the number
+ * of samples or pixels sampled per second by the hardware.
+ * @param sample_offset The bit slicer shall skip this number of samples at
+ * the start of the line.
+ * @param samples_per_line Number of samples or pixels in one raw vbi
+ * line later passed to vbi3_bit_slicer_slice(). This limits the number of
+ * bytes read from the raw data buffer. Do not to confuse the value
+ * with bytes per line.
+ * @param cri The Clock Run In is a NRZ modulated sequence of '1'
+ * and '0' bits prepending most data transmissions to synchronize data
+ * acquisition circuits. The bit slicer compares the bits in this
+ * word, lsb last transmitted, against the transmitted CRI. Decoding
+ * of FRC and payload starts with the next bit after a match, thus
+ * @a cri must contain a unique bit sequence. For example 0xAB to
+ * match '101010101011xxx'.
+ * @param cri_mask Of the CRI bits in @a cri, only these bits are
+ * significant for a match. For instance it is wise not to rely on
+ * the very first CRI bits transmitted.
+ * @param cri_bits Number of CRI bits, must not exceed 32.
+ * @param cri_rate CRI bit rate in Hz, the number of CRI bits
+ * transmitted per second.
+ * @param cri_end Number of samples between the start of the line and
+ * the latest possible end of the CRI. This is useful when
+ * the transmission is much shorter than samples_per_line, otherwise
+ * just pass @c ~0 and a limit will be calculated.
+ * @param frc The FRaming Code usually following the CRI is a bit
+ * sequence identifying the data service. There is no mask parameter,
+ * all bits must match. We assume FRC has the same @a modulation as
+ * the payload and is transmitted at @a payload_rate.
+ * @param frc_bits Number of FRC bits, must not exceed 32.
+ * @param payload_bits Number of payload bits. Only this data
+ * will be stored in the vbi3_bit_slicer_slice() output. If this number
+ * is no multiple of eight, the most significant bits of the
+ * last byte are undefined.
+ * @param payload_rate Payload bit rate in Hz, the number of payload
+ * bits transmitted per second.
+ * @param modulation Modulation of the payload, see vbi3_modulation.
+ *
+ * Initializes a vbi3_bit_slicer object for use with
+ * vbi3_bit_slicer_slice(). This is a low level function, see also
+ * vbi3_raw_decoder_new().
+ *
+ * @returns
+ * @c FALSE when the parameters are invalid (e. g.
+ * @a samples_per_line too small to contain CRI, FRC and payload).
+ */
+vbi_bool
+vbi3_bit_slicer_set_params (vbi3_bit_slicer * bs,
+ vbi_pixfmt sample_format,
+ unsigned int sampling_rate,
+ unsigned int sample_offset,
+ unsigned int samples_per_line,
+ unsigned int cri,
+ unsigned int cri_mask,
+ unsigned int cri_bits,
+ unsigned int cri_rate,
+ unsigned int cri_end,
+ unsigned int frc,
+ unsigned int frc_bits,
+ unsigned int payload_bits,
+ unsigned int payload_rate, vbi3_modulation modulation)
+{
+ unsigned int c_mask;
+ unsigned int f_mask;
+ unsigned int min_samples_per_bit;
+ unsigned int oversampling;
+ unsigned int data_bits;
+ unsigned int data_samples;
+ unsigned int cri_samples;
+ unsigned int skip;
+
+ assert (NULL != bs);
+ assert (cri_bits <= 32);
+ assert (frc_bits <= 32);
+ assert (payload_bits <= 32767);
+ assert (samples_per_line <= 32767);
+
+ if (cri_rate > sampling_rate) {
+ warning (&bs->log,
+ "cri_rate %u > sampling_rate %u.", cri_rate, sampling_rate);
+ goto failure;
+ }
+
+ if (payload_rate > sampling_rate) {
+ warning (&bs->log,
+ "payload_rate %u > sampling_rate %u.", payload_rate, sampling_rate);
+ goto failure;
+ }
+
+ min_samples_per_bit = sampling_rate / MAX (cri_rate, payload_rate);
+
+ bs->sample_format = sample_format;
+
+ c_mask = (cri_bits == 32) ? ~0U : (1U << cri_bits) - 1;
+ f_mask = (frc_bits == 32) ? ~0U : (1U << frc_bits) - 1;
+
+ oversampling = 4;
+ skip = 0;
+
+ /* 0-1 threshold, start value. */
+ bs->thresh = 105 << DEF_THR_FRAC;
+ bs->thresh_frac = DEF_THR_FRAC;
+
+ switch (sample_format) {
+ case VBI_PIXFMT_YUV420:
+ bs->bytes_per_sample = 1;
+ bs->func = bit_slicer_Y8;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+
+ case VBI_PIXFMT_YUYV:
+ case VBI_PIXFMT_YVYU:
+ bs->bytes_per_sample = 2;
+ bs->func = bit_slicer_YUYV;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+ case VBI_PIXFMT_UYVY:
+ case VBI_PIXFMT_VYUY:
+ skip = 1;
+ bs->bytes_per_sample = 2;
+ bs->func = bit_slicer_YUYV;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+ case VBI_PIXFMT_RGBA24_LE:
+ case VBI_PIXFMT_BGRA24_LE:
+ skip = 1;
+ bs->bytes_per_sample = 4;
+ bs->func = bit_slicer_RGBA24_LE;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+ case VBI_PIXFMT_RGBA24_BE:
+ case VBI_PIXFMT_BGRA24_BE:
+ skip = 2;
+ bs->bytes_per_sample = 4;
+ bs->func = bit_slicer_RGBA24_LE;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+ case VBI_PIXFMT_RGB24_LE:
+ case VBI_PIXFMT_BGR24_LE:
+ skip = 1;
+ bs->bytes_per_sample = 3;
+ bs->func = bit_slicer_RGB24_LE;
+ if (min_samples_per_bit > (3U << (LP_AVG - 1))) {
+ bs->func = low_pass_bit_slicer_Y8;
+ oversampling = 1;
+ bs->thresh <<= LP_AVG - 2;
+ bs->thresh_frac += LP_AVG - 2;
+ }
+ break;
+
+ case VBI_PIXFMT_RGB16_LE:
+ case VBI_PIXFMT_BGR16_LE:
+ bs->func = bit_slicer_RGB16_LE;
+ bs->green_mask = 0x07E0;
+ bs->thresh = 105 << (5 - 2 + 12);
+ bs->thresh_frac = 12;
+ bs->bytes_per_sample = 2;
+ break;
+
+ case VBI_PIXFMT_RGB16_BE:
+ case VBI_PIXFMT_BGR16_BE:
+ bs->func = bit_slicer_RGB16_BE;
+ bs->green_mask = 0x07E0;
+ bs->thresh = 105 << (5 - 2 + 12);
+ bs->thresh_frac = 12;
+ bs->bytes_per_sample = 2;
+ break;
+
+ case VBI_PIXFMT_RGBA15_LE:
+ case VBI_PIXFMT_BGRA15_LE:
+ bs->func = bit_slicer_RGB16_LE;
+ bs->green_mask = 0x03E0;
+ bs->thresh = 105 << (5 - 3 + 11);
+ bs->thresh_frac = 11;
+ bs->bytes_per_sample = 2;
+ break;
+
+ case VBI_PIXFMT_RGBA15_BE:
+ case VBI_PIXFMT_BGRA15_BE:
+ bs->func = bit_slicer_RGB16_BE;
+ bs->green_mask = 0x03E0;
+ bs->thresh = 105 << (5 - 3 + 11);
+ bs->thresh_frac = 11;
+ bs->bytes_per_sample = 2;
+ break;
+
+ case VBI_PIXFMT_ARGB15_LE:
+ case VBI_PIXFMT_ABGR15_LE:
+ bs->func = bit_slicer_RGB16_LE;
+ bs->green_mask = 0x07C0;
+ bs->thresh = 105 << (6 - 3 + 12);
+ bs->thresh_frac = 12;
+ bs->bytes_per_sample = 2;
+ break;
+
+ case VBI_PIXFMT_ARGB15_BE:
+ case VBI_PIXFMT_ABGR15_BE:
+ bs->func = bit_slicer_RGB16_BE;
+ bs->green_mask = 0x07C0;
+ bs->thresh = 105 << (6 - 3 + 12);
+ bs->thresh_frac = 12;
+ bs->bytes_per_sample = 2;
+ break;
+
+
+ default:
+ warning (&bs->log,
+ "Unknown sample_format 0x%x.", (unsigned int) sample_format);
+ return FALSE;
+ }
+
+ bs->skip = sample_offset * bs->bytes_per_sample + skip;
+
+ bs->cri_mask = cri_mask & c_mask;
+ bs->cri = cri & bs->cri_mask;
+
+ /* We stop searching for CRI when CRI, FRC and payload
+ cannot possibly fit anymore. Additionally this eliminates
+ a data end check in the payload loop. */
+ cri_samples = (sampling_rate * (int64_t) cri_bits) / cri_rate;
+
+ data_bits = payload_bits + frc_bits;
+ data_samples = (sampling_rate * (int64_t) data_bits) / payload_rate;
+
+ bs->total_bits = cri_bits + data_bits;
+
+ if ((sample_offset > samples_per_line)
+ || ((cri_samples + data_samples)
+ > (samples_per_line - sample_offset))) {
+ warning (&bs->log,
+ "%u samples_per_line too small for "
+ "sample_offset %u + %u cri_bits (%u samples) "
+ "+ %u frc_bits and %u payload_bits "
+ "(%u samples).",
+ samples_per_line, sample_offset,
+ cri_bits, cri_samples, frc_bits, payload_bits, data_samples);
+ goto failure;
+ }
+
+ cri_end = MIN (cri_end, samples_per_line - data_samples);
+
+ bs->cri_samples = cri_end - sample_offset;
+ bs->cri_rate = cri_rate;
+
+ bs->oversampling_rate = sampling_rate * oversampling;
+
+ bs->frc = frc & f_mask;
+ bs->frc_bits = frc_bits;
+
+ /* Payload bit distance in 1/256 raw samples. */
+ bs->step = (sampling_rate * (int64_t) 256) / payload_rate;
+
+ if (payload_bits & 7) {
+ /* Use bit routines. */
+ bs->payload = payload_bits;
+ bs->endian = 3;
+ } else {
+ /* Use faster octet routines. */
+ bs->payload = payload_bits >> 3;
+ bs->endian = 1;
+ }
+
+ switch (modulation) {
+ case VBI3_MODULATION_NRZ_MSB:
+ --bs->endian;
+
+ /* fall through */
+
+ case VBI3_MODULATION_NRZ_LSB:
+ bs->phase_shift = (int)
+ (sampling_rate * 256.0 / cri_rate * .5 + bs->step * .5 + 128);
+ break;
+
+ case VBI3_MODULATION_BIPHASE_MSB:
+ --bs->endian;
+
+ /* fall through */
+
+ case VBI3_MODULATION_BIPHASE_LSB:
+ /* Phase shift between the NRZ modulated CRI and the
+ biphase modulated rest. */
+ bs->phase_shift = (int)
+ (sampling_rate * 256.0 / cri_rate * .5 + bs->step * .25 + 128);
+ break;
+ }
+
+ return TRUE;
+
+failure:
+ bs->func = null_function;
+
+ return FALSE;
+}
+
+void
+vbi3_bit_slicer_set_log_fn (vbi3_bit_slicer * bs,
+ vbi_log_mask mask, vbi_log_fn * log_fn, void *user_data)
+{
+ assert (NULL != bs);
+
+ if (NULL == log_fn)
+ mask = 0;
+
+ bs->log.mask = mask;
+ bs->log.fn = log_fn;
+ bs->log.user_data = user_data;
+}
+
+/**
+ * @internal
+ */
+void
+_vbi3_bit_slicer_destroy (vbi3_bit_slicer * bs)
+{
+ assert (NULL != bs);
+
+ /* Make unusable. */
+ CLEAR (*bs);
+}
+
+/**
+ * @internal
+ */
+vbi_bool
+_vbi3_bit_slicer_init (vbi3_bit_slicer * bs)
+{
+ assert (NULL != bs);
+
+ CLEAR (*bs);
+
+ bs->func = null_function;
+
+ return TRUE;
+}
+
+/**
+ * @param bs Pointer to a vbi3_bit_slicer object allocated with
+ * vbi3_bit_slicer_new(), can be NULL.
+ *
+ * Deletes a vbi3_bit_slicer object.
+ */
+void
+vbi3_bit_slicer_delete (vbi3_bit_slicer * bs)
+{
+ if (NULL == bs)
+ return;
+
+ _vbi3_bit_slicer_destroy (bs);
+
+ vbi_free (bs);
+}
+
+/**
+ * Allocates a new vbi3_bit_slicer object.
+ *
+ * @returns
+ * @c NULL when out of memory.
+ */
+vbi3_bit_slicer *
+vbi3_bit_slicer_new (void)
+{
+ vbi3_bit_slicer *bs;
+
+ bs = vbi_malloc (sizeof (*bs));
+ if (NULL == bs) {
+ return NULL;
+ }
+
+ _vbi3_bit_slicer_init (bs);
+
+ return bs;
+}
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Bit slicer
+ *
+ * Copyright (C) 2000-2007 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: bit_slicer.h,v 1.11 2008-02-24 14:18:13 mschimek Exp $ */
+
+#ifndef __ZVBI_BIT_SLICER_H__
+#define __ZVBI_BIT_SLICER_H__
+
+#include "sampling_par.h"
+
+VBI_BEGIN_DECLS
+
+/**
+ * @addtogroup BitSlicer
+ * @{
+ */
+
+/**
+ * @brief Modulation used for VBI data transmission.
+ */
+typedef enum {
+ /**
+ * The data is 'non-return to zero' coded, logical '1' bits
+ * are described by high sample values, logical '0' bits by
+ * low values. The data is last significant bit first transmitted.
+ */
+ VBI3_MODULATION_NRZ_LSB,
+
+ /**
+ * 'Non-return to zero' coded, most significant bit first
+ * transmitted.
+ */
+ VBI3_MODULATION_NRZ_MSB,
+
+ /**
+ * The data is 'bi-phase' coded. Each data bit is described
+ * by two complementary signalling elements, a logical '1'
+ * by a sequence of '10' elements, a logical '0' by a '01'
+ * sequence. The data is last significant bit first transmitted.
+ */
+ VBI3_MODULATION_BIPHASE_LSB,
+
+ /** 'Bi-phase' coded, most significant bit first transmitted. */
+ VBI3_MODULATION_BIPHASE_MSB
+} vbi3_modulation;
+
+/**
+ * @brief Bit slicer context.
+ *
+ * The contents of this structure are private.
+ * Call vbi3_bit_slicer_new() to allocate a bit slicer context.
+ */
+typedef struct _vbi3_bit_slicer vbi3_bit_slicer;
+
+typedef enum {
+ VBI3_CRI_BIT = 1,
+ VBI3_FRC_BIT,
+ VBI3_PAYLOAD_BIT
+} vbi3_bit_slicer_bit;
+
+/**
+ * @brief Bit slicer sampling point.
+ *
+ * This structure contains information about
+ * a bit sampled by the bit slicer.
+ */
+typedef struct {
+ /** Whether this struct refers to a CRI, FRC or payload bit. */
+ vbi3_bit_slicer_bit kind;
+
+ /** Number of the sample times 256. */
+ unsigned int index;
+
+ /** Signal amplitude at this sample, in range 0 to 65535. */
+ unsigned int level;
+
+ /** 0/1 threshold at this sample, in range 0 to 65535. */
+ unsigned int thresh;
+} vbi3_bit_slicer_point;
+
+extern vbi_bool
+vbi3_bit_slicer_slice_with_points
+ (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ unsigned int buffer_size,
+ vbi3_bit_slicer_point *points,
+ unsigned int * n_points,
+ unsigned int max_points,
+ const uint8_t * raw)
+ _vbi_nonnull ((1, 2, 4, 5, 7));
+extern vbi_bool
+vbi3_bit_slicer_slice (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ unsigned int buffer_size,
+ const uint8_t * raw)
+ _vbi_nonnull ((1, 2, 4));
+extern vbi_bool
+vbi3_bit_slicer_set_params (vbi3_bit_slicer * bs,
+ vbi_pixfmt sample_format,
+ unsigned int sampling_rate,
+ unsigned int sample_offset,
+ unsigned int samples_per_line,
+ unsigned int cri,
+ unsigned int cri_mask,
+ unsigned int cri_bits,
+ unsigned int cri_rate,
+ unsigned int cri_end,
+ unsigned int frc,
+ unsigned int frc_bits,
+ unsigned int payload_bits,
+ unsigned int payload_rate,
+ vbi3_modulation modulation)
+ _vbi_nonnull ((1));
+extern void
+vbi3_bit_slicer_set_log_fn (vbi3_bit_slicer * bs,
+ vbi_log_mask mask,
+ vbi_log_fn * log_fn,
+ void * user_data)
+ _vbi_nonnull ((1));
+extern void
+vbi3_bit_slicer_delete (vbi3_bit_slicer * bs);
+extern vbi3_bit_slicer *
+vbi3_bit_slicer_new (void)
+ _vbi_alloc;
+
+/* Private */
+
+typedef vbi_bool
+_vbi3_bit_slicer_fn (vbi3_bit_slicer * bs,
+ uint8_t * buffer,
+ vbi3_bit_slicer_point *points,
+ unsigned int * n_points,
+ const uint8_t * raw);
+
+/** @internal */
+struct _vbi3_bit_slicer {
+ _vbi3_bit_slicer_fn * func;
+
+ vbi_pixfmt sample_format;
+ unsigned int cri;
+ unsigned int cri_mask;
+ unsigned int thresh;
+ unsigned int thresh_frac;
+ unsigned int cri_samples;
+ unsigned int cri_rate;
+ unsigned int oversampling_rate;
+ unsigned int phase_shift;
+ unsigned int step;
+ unsigned int frc;
+ unsigned int frc_bits;
+ unsigned int total_bits;
+ unsigned int payload;
+ unsigned int endian;
+ unsigned int bytes_per_sample;
+ unsigned int skip;
+ unsigned int green_mask;
+
+ _vbi_log_hook log;
+};
+
+extern void
+_vbi3_bit_slicer_destroy (vbi3_bit_slicer * bs)
+ _vbi_nonnull ((1));
+extern vbi_bool
+_vbi3_bit_slicer_init (vbi3_bit_slicer * bs)
+ _vbi_nonnull ((1));
+
+/** @} */
+
+VBI_END_DECLS
+
+#endif /* __ZVBI_BIT_SLICER_H__ */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Old raw VBI decoder
+ *
+ * Copyright (C) 2000, 2001, 2002 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: decoder.c,v 1.25 2008-02-19 00:35:15 mschimek Exp $ */
+
+/* Note this code is only retained for compatibility with older versions
+ of libzvbi. vbi_raw_decoder is now just a wrapper for the new raw
+ decoder (raw_decoder.c) and bit slicer (bit_slicer.c). We'll drop
+ the old API in libzvbi 0.3. Other modules (e.g. io-v4l2k.c) should
+ already use the new raw VBI decoder directly. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <pthread.h>
+
+#include "misc.h"
+#include "decoder.h"
+#include "raw_decoder.h"
+
+/**
+ * @addtogroup Rawdec Raw VBI decoder
+ * @ingroup Raw
+ * @brief Converting raw VBI samples to bits and bytes.
+ *
+ * The libzvbi already offers hardware interfaces to obtain sliced
+ * VBI data for further processing. However if you want to write your own
+ * interface or decode data services not covered by libzvbi you can use
+ * these lower level functions.
+ */
+
+/*
+ * Bit Slicer
+ */
+
+#define OVERSAMPLING 4 /* 1, 2, 4, 8 */
+#define THRESH_FRAC 9
+
+/*
+ * Note this is just a template. The code is inlined,
+ * with bpp and endian being const.
+ *
+ * This function translates from the image format to
+ * plain bytes, with linear interpolation of samples.
+ * Could be further improved with a lowpass filter.
+ */
+static inline unsigned int
+sample (uint8_t * raw, int offs, int bpp, int endian)
+{
+ unsigned char frac = offs;
+ int raw0, raw1;
+
+ switch (bpp) {
+ case 14: /* 1:5:5:5 LE/BE */
+ raw += (offs >> 8) * 2;
+ raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07C0;
+ raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07C0;
+ return (raw1 - raw0) * frac + (raw0 << 8);
+
+ case 15: /* 5:5:5:1 LE/BE */
+ raw += (offs >> 8) * 2;
+ raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x03E0;
+ raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x03E0;
+ return (raw1 - raw0) * frac + (raw0 << 8);
+
+ case 16: /* 5:6:5 LE/BE */
+ raw += (offs >> 8) * 2;
+ raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07E0;
+ raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07E0;
+ return (raw1 - raw0) * frac + (raw0 << 8);
+
+ default: /* 8 (intermediate bytes skipped by caller) */
+ raw += (offs >> 8) * bpp;
+ return (raw[bpp] - raw[0]) * frac + (raw[0] << 8);
+ }
+}
+
+/*
+ * Note this is just a template. The code is inlined,
+ * with bpp being const.
+ */
+static inline vbi_bool
+bit_slicer_tmpl (vbi_bit_slicer * d, uint8_t * raw,
+ uint8_t * buf, int bpp, int endian)
+{
+ unsigned int i, j, k;
+ unsigned int cl = 0, thresh0 = d->thresh, tr;
+ unsigned int c = 0, t;
+ unsigned char b, b1 = 0;
+ int raw0, raw1, mask;
+
+ raw += d->skip;
+
+ if (bpp == 14)
+ mask = 0x07C0;
+ else if (bpp == 15)
+ mask = 0x03E0;
+ else if (bpp == 16)
+ mask = 0x07E0;
+
+ for (i = d->cri_bytes; i > 0; raw += (bpp >= 14 && bpp <= 16) ? 2 : bpp, i--) {
+ if (bpp >= 14 && bpp <= 16) {
+ raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & mask;
+ raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & mask;
+ tr = d->thresh >> THRESH_FRAC;
+ d->thresh += ((raw0 - tr) * (int) ABS (raw1 - raw0)) >>
+ ((bpp == 15) ? 2 : 3);
+ t = raw0 * OVERSAMPLING;
+ } else {
+ tr = d->thresh >> THRESH_FRAC;
+ d->thresh += ((int) raw[0] - tr) * (int) ABS (raw[bpp] - raw[0]);
+ t = raw[0] * OVERSAMPLING;
+ }
+
+ for (j = OVERSAMPLING; j > 0; j--) {
+ b = ((t + (OVERSAMPLING / 2)) / OVERSAMPLING >= tr);
+
+ if (b ^ b1) {
+ cl = d->oversampling_rate >> 1;
+ } else {
+ cl += d->cri_rate;
+
+ if (cl >= (unsigned int) d->oversampling_rate) {
+ cl -= d->oversampling_rate;
+
+ c = c * 2 + b;
+
+ if ((c & d->cri_mask) == d->cri) {
+ i = d->phase_shift;
+ tr *= 256;
+ c = 0;
+
+ for (j = d->frc_bits; j > 0; j--) {
+ c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
+ i += d->step;
+ }
+
+ if (c ^= d->frc)
+ return FALSE;
+
+ /* CRI/FRC found, now get the
+ payload and exit */
+
+ switch (d->endian) {
+ case 3:
+ for (j = 0; j < (unsigned int) d->payload; j++) {
+ c >>= 1;
+ c += (sample (raw, i, bpp, endian) >= tr) << 7;
+ i += d->step;
+
+ if ((j & 7) == 7)
+ *buf++ = c;
+ }
+
+ *buf = c >> ((8 - d->payload) & 7);
+ break;
+
+ case 2:
+ for (j = 0; j < (unsigned int) d->payload; j++) {
+ c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
+ i += d->step;
+
+ if ((j & 7) == 7)
+ *buf++ = c;
+ }
+
+ *buf = c & ((1 << (d->payload & 7)) - 1);
+ break;
+
+ case 1:
+ for (j = d->payload; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ c >>= 1;
+ c += (sample (raw, i, bpp, endian) >= tr) << 7;
+ i += d->step;
+ }
+
+ *buf++ = c;
+ }
+
+ break;
+
+ case 0:
+ for (j = d->payload; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ c = c * 2 + (sample (raw, i, bpp, endian) >= tr);
+ i += d->step;
+ }
+
+ *buf++ = c;
+ }
+
+ break;
+ }
+
+ return TRUE;
+ }
+ }
+ }
+
+ b1 = b;
+
+ if (OVERSAMPLING > 1) {
+ if (bpp >= 14 && bpp <= 16) {
+ t += raw1;
+ t -= raw0;
+ } else {
+ t += raw[bpp];
+ t -= raw[0];
+ }
+ }
+ }
+ }
+
+ d->thresh = thresh0;
+
+ return FALSE;
+}
+
+static vbi_bool
+bit_slicer_1 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 1, 0);
+}
+
+static vbi_bool
+bit_slicer_2 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 2, 0);
+}
+
+static vbi_bool
+bit_slicer_3 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 3, 0);
+}
+
+static vbi_bool
+bit_slicer_4 (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 4, 0);
+}
+
+static vbi_bool
+bit_slicer_1555_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 14, 0);
+}
+
+static vbi_bool
+bit_slicer_5551_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 15, 0);
+}
+
+static vbi_bool
+bit_slicer_565_le (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 16, 0);
+}
+
+static vbi_bool
+bit_slicer_1555_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 14, 1);
+}
+
+static vbi_bool
+bit_slicer_5551_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 15, 1);
+}
+
+static vbi_bool
+bit_slicer_565_be (vbi_bit_slicer * d, uint8_t * raw, uint8_t * buf)
+{
+ return bit_slicer_tmpl (d, raw, buf, 16, 1);
+}
+
+/**
+ * @param slicer Pointer to vbi_bit_slicer object to be initialized.
+ * @param raw_samples Number of samples or pixels in one raw vbi line
+ * later passed to vbi_bit_slice(). This limits the number of
+ * bytes read from the sample buffer.
+ * @param sampling_rate Raw vbi sampling rate in Hz, that is the number of
+ * samples or pixels sampled per second by the hardware.
+ * @param cri_rate The Clock Run In is a NRZ modulated
+ * sequence of '0' and '1' bits prepending most data transmissions to
+ * synchronize data acquisition circuits. This parameter gives the CRI bit
+ * rate in Hz, that is the number of CRI bits transmitted per second.
+ * @param bit_rate The transmission bit rate of all data bits following the CRI
+ * in Hz.
+ * @param cri_frc The FRaming Code usually following the CRI is a bit sequence
+ * identifying the data service, and per libzvbi definition modulated
+ * and transmitted at the same bit rate as the payload (however nothing
+ * stops you from counting all nominal CRI and FRC bits as CRI).
+ * The bit slicer compares the bits in this word, lsb last transmitted,
+ * against the transmitted CRI and FRC. Decoding of payload starts
+ * with the next bit after a match.
+ * @param cri_mask Of the CRI bits in @c cri_frc, only these bits are
+ * actually significant for a match. For instance it is wise
+ * not to rely on the very first CRI bits transmitted. Note this
+ * mask is not shifted left by @a frc_bits.
+ * @param cri_bits
+ * @param frc_bits Number of CRI and FRC bits in @a cri_frc, respectively.
+ * Their sum is limited to 32.
+ * @param payload Number of payload <em>bits</em>. Only this data
+ * will be stored in the vbi_bit_slice() output. If this number
+ * is no multiple of eight, the most significant bits of the
+ * last byte are undefined.
+ * @param modulation Modulation of the vbi data, see vbi_modulation.
+ * @param fmt Format of the raw data, see vbi_pixfmt.
+ *
+ * Initializes vbi_bit_slicer object. Usually you will not use this
+ * function but vbi_raw_decode(), the vbi image decoder which handles
+ * all these details.
+ */
+void
+vbi_bit_slicer_init (vbi_bit_slicer * slicer,
+ int raw_samples, int sampling_rate,
+ int cri_rate, int bit_rate,
+ unsigned int cri_frc, unsigned int cri_mask,
+ int cri_bits, int frc_bits, int payload,
+ vbi_modulation modulation, vbi_pixfmt fmt)
+{
+ unsigned int c_mask = (unsigned int) (-(cri_bits > 0)) >> (32 - cri_bits);
+ unsigned int f_mask = (unsigned int) (-(frc_bits > 0)) >> (32 - frc_bits);
+ int gsh = 0;
+
+ slicer->func = bit_slicer_1;
+
+ switch (fmt) {
+ case VBI_PIXFMT_RGB24:
+ case VBI_PIXFMT_BGR24:
+ slicer->func = bit_slicer_3;
+ slicer->skip = 1;
+ break;
+
+ case VBI_PIXFMT_RGBA32_LE:
+ case VBI_PIXFMT_BGRA32_LE:
+ slicer->func = bit_slicer_4;
+ slicer->skip = 1;
+ break;
+
+ case VBI_PIXFMT_RGBA32_BE:
+ case VBI_PIXFMT_BGRA32_BE:
+ slicer->func = bit_slicer_4;
+ slicer->skip = 2;
+ break;
+
+ case VBI_PIXFMT_RGB16_LE:
+ case VBI_PIXFMT_BGR16_LE:
+ slicer->func = bit_slicer_565_le;
+ gsh = 3; /* (green << 3) & 0x07E0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_RGBA15_LE:
+ case VBI_PIXFMT_BGRA15_LE:
+ slicer->func = bit_slicer_5551_le;
+ gsh = 2; /* (green << 2) & 0x03E0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_ARGB15_LE:
+ case VBI_PIXFMT_ABGR15_LE:
+ slicer->func = bit_slicer_1555_le;
+ gsh = 3; /* (green << 2) & 0x07C0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_RGB16_BE:
+ case VBI_PIXFMT_BGR16_BE:
+ slicer->func = bit_slicer_565_be;
+ gsh = 3; /* (green << 3) & 0x07E0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_RGBA15_BE:
+ case VBI_PIXFMT_BGRA15_BE:
+ slicer->func = bit_slicer_5551_be;
+ gsh = 2; /* (green << 2) & 0x03E0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_ARGB15_BE:
+ case VBI_PIXFMT_ABGR15_BE:
+ slicer->func = bit_slicer_1555_be;
+ gsh = 3; /* (green << 2) & 0x07C0 */
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_YUV420:
+ slicer->func = bit_slicer_1;
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_YUYV:
+ case VBI_PIXFMT_YVYU:
+ slicer->func = bit_slicer_2;
+ slicer->skip = 0;
+ break;
+
+ case VBI_PIXFMT_UYVY:
+ case VBI_PIXFMT_VYUY:
+ slicer->func = bit_slicer_2;
+ slicer->skip = 1;
+ break;
+
+ default:
+ fprintf (stderr, "vbi_bit_slicer_init: unknown pixfmt %d\n", fmt);
+ exit (EXIT_FAILURE);
+ }
+
+ slicer->cri_mask = cri_mask & c_mask;
+ slicer->cri = (cri_frc >> frc_bits) & slicer->cri_mask;
+ /* We stop searching for CRI/FRC when the payload
+ cannot possibly fit anymore. */
+ slicer->cri_bytes = raw_samples
+ - ((long long) sampling_rate * (payload + frc_bits)) / bit_rate;
+ slicer->cri_rate = cri_rate;
+ /* Raw vbi data is oversampled to account for low sampling rates. */
+ slicer->oversampling_rate = sampling_rate * OVERSAMPLING;
+ /* 0/1 threshold */
+ slicer->thresh = 105 << (THRESH_FRAC + gsh);
+ slicer->frc = cri_frc & f_mask;
+ slicer->frc_bits = frc_bits;
+ /* Payload bit distance in 1/256 raw samples. */
+ slicer->step = (int) (sampling_rate * 256.0 / bit_rate);
+
+ if (payload & 7) {
+ slicer->payload = payload;
+ slicer->endian = 3;
+ } else {
+ slicer->payload = payload >> 3;
+ slicer->endian = 1;
+ }
+
+ switch (modulation) {
+ case VBI_MODULATION_NRZ_MSB:
+ slicer->endian--;
+ case VBI_MODULATION_NRZ_LSB:
+ slicer->phase_shift = (int)
+ (sampling_rate * 256.0 / cri_rate * .5
+ + sampling_rate * 256.0 / bit_rate * .5 + 128);
+ break;
+
+ case VBI_MODULATION_BIPHASE_MSB:
+ slicer->endian--;
+ case VBI_MODULATION_BIPHASE_LSB:
+ /* Phase shift between the NRZ modulated CRI and the rest */
+ slicer->phase_shift = (int)
+ (sampling_rate * 256.0 / cri_rate * .5
+ + sampling_rate * 256.0 / bit_rate * .25 + 128);
+ break;
+ }
+}
+
+/**
+ * @example examples/wss.c
+ * WSS capture example.
+ */
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param raw A raw vbi image as defined in the vbi_raw_decoder structure
+ * (rd->sampling_format, rd->bytes_per_line, rd->count[0] + rd->count[1]
+ * scan lines).
+ * @param out Buffer to store the decoded vbi_sliced data. Since every
+ * vbi scan line may contain data, this must be an array of vbi_sliced
+ * with the same number of entries as scan lines in the raw image
+ * (rd->count[0] + rd->count[1]).
+ *
+ * Decode a raw vbi image, consisting of several scan lines of raw vbi data,
+ * into sliced vbi data. The output is sorted by line number.
+ *
+ * Note this function attempts to learn which lines carry which data
+ * service, or none, to speed up decoding. You should avoid using the same
+ * vbi_raw_decoder structure for different sources.
+ *
+ * @return
+ * The number of lines decoded, i. e. the number of vbi_sliced records
+ * written.
+ */
+int
+vbi_raw_decode (vbi_raw_decoder * rd, uint8_t * raw, vbi_sliced * out)
+{
+ vbi3_raw_decoder *rd3;
+ unsigned int n_lines;
+
+ assert (NULL != rd);
+ assert (NULL != raw);
+ assert (NULL != out);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+ n_lines = rd->count[0] + rd->count[1];
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ n_lines = vbi3_raw_decoder_decode (rd3, out, n_lines, raw);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+
+ return n_lines;
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param start Array of start line indices for both fields
+ * @param count Array of line counts for both fields
+ *
+ * Grows or shrinks the internal state arrays for VBI geometry changes
+ */
+void
+vbi_raw_decoder_resize (vbi_raw_decoder * rd, int *start, unsigned int *count)
+{
+#if 0 /* Set but unused */
+ vbi_service_set service_set;
+#endif
+ vbi3_raw_decoder *rd3;
+
+ assert (NULL != rd);
+ assert (NULL != start);
+ assert (NULL != count);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ if ((rd->start[0] == start[0])
+ && (rd->start[1] == start[1])
+ && (rd->count[0] == (int) count[0])
+ && (rd->count[1] == (int) count[1])) {
+ pthread_mutex_unlock (&rd->mutex);
+ return;
+ }
+
+ rd->start[0] = start[0];
+ rd->start[1] = start[1];
+ rd->count[0] = count[0];
+ rd->count[1] = count[1];
+
+#if 0 /* Set but unused */
+ service_set = vbi3_raw_decoder_set_sampling_par
+ (rd3, (vbi_sampling_par *) rd, /* strict */ 0);
+#else
+ vbi3_raw_decoder_set_sampling_par
+ (rd3, (vbi_sampling_par *) rd, /* strict */ 0);
+#endif
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param services Set of @ref VBI_SLICED_ symbols.
+ *
+ * Removes one or more data services to be decoded from the
+ * vbi_raw_decoder structure. This function can be called at any
+ * time and does not touch sampling parameters.
+ *
+ * @return
+ * Set of @ref VBI_SLICED_ symbols describing the remaining data
+ * services that will be decoded.
+ */
+unsigned int
+vbi_raw_decoder_remove_services (vbi_raw_decoder * rd, unsigned int services)
+{
+ vbi_service_set service_set;
+ vbi3_raw_decoder *rd3;
+
+ assert (NULL != rd);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+ service_set = services;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ service_set = vbi3_raw_decoder_remove_services (rd3, service_set);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+
+ return service_set;
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param services Set of @ref VBI_SLICED_ symbols.
+ * @param strict See description of vbi_raw_decoder_add_services()
+ *
+ * Check which of the given services can be decoded with current capture
+ * parameters at a given strictness level.
+ *
+ * @return
+ * Subset of services actually decodable.
+ */
+unsigned int
+vbi_raw_decoder_check_services (vbi_raw_decoder * rd,
+ unsigned int services, int strict)
+{
+ vbi_service_set service_set;
+
+ assert (NULL != rd);
+
+ service_set = services;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ service_set = vbi_sampling_par_check_services
+ ((vbi_sampling_par *) rd, service_set, strict);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+
+ return (unsigned int) service_set;
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param services Set of @ref VBI_SLICED_ symbols.
+ * @param strict A value of 0, 1 or 2 requests loose, reliable or strict
+ * matching of sampling parameters. For example if the data service
+ * requires knowledge of line numbers while they are not known, @c 0
+ * will accept the service (which may work if the scan lines are
+ * populated in a non-confusing way) but @c 1 or @c 2 will not. If the
+ * data service <i>may</i> use more lines than are sampled, @c 1 will
+ * accept but @c 2 will not. If unsure, set to @c 1.
+ *
+ * After you initialized the sampling parameters in @a rd (according to
+ * the abilities of your raw vbi source), this function adds one or more
+ * data services to be decoded. The libzvbi raw vbi decoder can decode up
+ * to eight data services in parallel. You can call this function while
+ * already decoding, it does not change sampling parameters and you must
+ * not change them either after calling this.
+ *
+ * @return
+ * Set of @ref VBI_SLICED_ symbols describing the data services that actually
+ * will be decoded. This excludes those services not decodable given
+ * the sampling parameters in @a rd.
+ */
+unsigned int
+vbi_raw_decoder_add_services (vbi_raw_decoder * rd,
+ unsigned int services, int strict)
+{
+ vbi_service_set service_set;
+ vbi3_raw_decoder *rd3;
+
+ assert (NULL != rd);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+ service_set = services;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ vbi3_raw_decoder_set_sampling_par (rd3, (vbi_sampling_par *) rd, strict);
+
+ service_set = vbi3_raw_decoder_add_services (rd3, service_set, strict);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+
+ return service_set;
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
+ * can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
+ * vbi scan lines in the calculated sampling parameters.
+ * @param scanning When 525 accept only NTSC services, when 625
+ * only PAL/SECAM services. When scanning is 0, determine the scanning
+ * from the requested services, an ambiguous set will pick
+ * a 525 or 625 line system at random.
+ * @param max_rate If given, the highest data bit rate in Hz of all
+ * services requested is stored here. (The sampling rate
+ * should be at least twice as high; rd->sampling_rate will
+ * be set to a more reasonable value of 27 MHz derived
+ * from ITU-R Rec. 601.)
+ *
+ * Calculate the sampling parameters in @a rd required to receive and
+ * decode the requested data @a services. rd->sampling_format will be
+ * @c VBI_PIXFMT_YUV420, rd->bytes_per_line set accordingly to a
+ * reasonable minimum. This function can be used to initialize hardware
+ * prior to calling vbi_raw_decoder_add_service().
+ *
+ * @return
+ * Set of @ref VBI_SLICED_ symbols describing the data services covered
+ * by the calculated sampling parameters. This excludes services the libzvbi
+ * raw decoder cannot decode.
+ */
+unsigned int
+vbi_raw_decoder_parameters (vbi_raw_decoder * rd,
+ unsigned int services, int scanning, int *max_rate)
+{
+ vbi_videostd_set videostd_set;
+ vbi_service_set service_set;
+
+ switch (scanning) {
+ case 525:
+ videostd_set = VBI_VIDEOSTD_SET_525_60;
+ break;
+
+ case 625:
+ videostd_set = VBI_VIDEOSTD_SET_625_50;
+ break;
+
+ default:
+ videostd_set = 0;
+ break;
+ }
+
+ service_set = services;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ service_set = vbi_sampling_par_from_services
+ ((vbi_sampling_par *) rd,
+ (unsigned int *) max_rate, videostd_set, service_set);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+
+ return (unsigned int) service_set;
+}
+
+/**
+ * @param rd Initialized vbi_raw_decoder structure.
+ *
+ * Reset a vbi_raw_decoder structure. This removes
+ * all previously added services to be decoded (if any)
+ * but does not touch the sampling parameters. You are
+ * free to change the sampling parameters after calling this.
+ */
+void
+vbi_raw_decoder_reset (vbi_raw_decoder * rd)
+{
+ vbi3_raw_decoder *rd3;
+
+ if (!rd)
+ return; /* compatibility */
+
+ assert (NULL != rd);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+
+ pthread_mutex_lock (&rd->mutex);
+
+ {
+ vbi3_raw_decoder_reset (rd3);
+ }
+
+ pthread_mutex_unlock (&rd->mutex);
+}
+
+/**
+ * @param rd Pointer to initialized vbi_raw_decoder
+ * structure, can be @c NULL.
+ *
+ * Free all resources associated with @a rd.
+ */
+void
+vbi_raw_decoder_destroy (vbi_raw_decoder * rd)
+{
+ vbi3_raw_decoder *rd3;
+
+ assert (NULL != rd);
+
+ rd3 = (vbi3_raw_decoder *) rd->pattern;
+
+ vbi3_raw_decoder_delete (rd3);
+
+ pthread_mutex_destroy (&rd->mutex);
+
+ CLEAR (*rd);
+}
+
+/**
+ * @param rd Pointer to a vbi_raw_decoder structure.
+ *
+ * Initializes a vbi_raw_decoder structure.
+ */
+void
+vbi_raw_decoder_init (vbi_raw_decoder * rd)
+{
+ vbi3_raw_decoder *rd3;
+
+ assert (NULL != rd);
+
+ CLEAR (*rd);
+
+ pthread_mutex_init (&rd->mutex, NULL);
+
+ rd3 = vbi3_raw_decoder_new ( /* sampling_par */ NULL);
+ assert (NULL != rd3);
+
+ rd->pattern = (int8_t *) rd3;
+}
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Old raw VBI decoder
+ *
+ * Copyright (C) 2000, 2001, 2002 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: decoder.h,v 1.11 2008-02-19 00:35:15 mschimek Exp $ */
+
+#ifndef DECODER_H
+#define DECODER_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "bcd.h"
+#include "sliced.h"
+
+/* Public */
+
+#include <pthread.h>
+
+/* Bit slicer */
+
+/**
+ * @ingroup Rawdec
+ * @brief Image format used as source to vbi_bit_slice() and vbi_raw_decode().
+ *
+ * @htmlonly
+<table border=1>
+<tr><th>Symbol</th><th>Byte 0</th><th>Byte 1</th><th>Byte 2</th><th>Byte 3</th></tr>
+<tr><td colspan=5>Planar YUV 4:2:0 data.</td></tr>
+<tr><td>VBI_PIXFMT_YUV420</td><td colspan=4>
+ <table>
+ <tr><th>Y plane</th><th>U plane</th><th>V plane</th></tr>
+ <tr><td><table border=1>
+ <tr><td>Y00</td><td>Y01</td><td>Y02</td><td>Y03</td></tr>
+ <tr><td>Y10</td><td>Y11</td><td>Y12</td><td>Y13</td></tr>
+ <tr><td>Y20</td><td>Y21</td><td>Y22</td><td>Y23</td></tr>
+ <tr><td>Y30</td><td>Y31</td><td>Y32</td><td>Y33</td></tr>
+ </table></td>
+ <td><table border=1>
+ <tr><td>Cb00</td><td>Cb01</td></tr>
+ <tr><td>Cb10</td><td>Cb11</td></tr>
+ </table></td>
+ <td><table border=1>
+ <tr><td>Cr00</td><td>Cr01</td></tr>
+ <tr><td>Cr10</td><td>Cr11</td></tr>
+ </table></td>
+ </tr></table></td>
+</tr>
+<tr><td colspan=5>Packed YUV 4:2:2 data.</td></tr>
+<tr><td>VBI_PIXFMT_YUYV</td><td>Y0</td><td>Cb</td><td>Y1</td><td>Cr</td></tr>
+<tr><td>VBI_PIXFMT_YVYU</td><td>Y0</td><td>Cr</td><td>Y1</td><td>Cb</td></tr>
+<tr><td>VBI_PIXFMT_UYVY</td><td>Cb</td><td>Y0</td><td>Cr</td><td>Y1</td></tr>
+<tr><td>VBI_PIXFMT_VYUY</td><td>Cr</td><td>Y0</td><td>Cb</td><td>Y1</td></tr>
+<tr><td colspan=5>Packed 32 bit RGB data.</td></tr>
+<tr><td>VBI_PIXFMT_RGBA32_LE VBI_PIXFMT_ARGB32_BE</td>
+<td>r7 ... r0</td><td>g7 ... g0</td>
+<td>b7 ... b0</td><td>a7 ... a0</td></tr>
+<tr><td>VBI_PIXFMT_BGRA32_LE VBI_PIXFMT_ARGB32_BE</td>
+<td>b7 ... b0</td><td>g7 ... g0</td>
+<td>r7 ... r0</td><td>a7 ... a0</td></tr>
+<tr><td>VBI_PIXFMT_ARGB32_LE VBI_PIXFMT_BGRA32_BE</td>
+<td>a7 ... a0</td><td>r7 ... r0</td>
+<td>g7 ... g0</td><td>b7 ... b0</td></tr>
+<tr><td>VBI_PIXFMT_ABGR32_LE VBI_PIXFMT_RGBA32_BE</td>
+<td>a7 ... a0</td><td>b7 ... b0</td>
+<td>g7 ... g0</td><td>r7 ... r0</td></tr>
+<tr><td colspan=5>Packed 24 bit RGB data.</td></tr>
+<tr><td>VBI_PIXFMT_RGBA24</td>
+<td>r7 ... r0</td><td>g7 ... g0</td>
+<td>b7 ... b0</td><td> </td></tr>
+<tr><td>VBI_PIXFMT_BGRA24</td>
+<td>b7 ... b0</td><td>g7 ... g0</td>
+<td>r7 ... r0</td><td> </td></tr>
+<tr><td colspan=5>Packed 16 bit RGB data.</td></tr>
+<tr><td>VBI_PIXFMT_RGB16_LE</td>
+<td>g2 g1 g0 r4 r3 r2 r1 r0</td>
+<td>b4 b3 b2 b1 b0 g5 g4 g3</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_BGR16_LE</td>
+<td>g2 g1 g0 b4 b3 b2 b1 b0</td>
+<td>r4 r3 r2 r1 r0 g5 g4 g3</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_RGB16_BE</td>
+<td>b4 b3 b2 b1 b0 g5 g4 g3</td>
+<td>g2 g1 g0 r4 r3 r2 r1 r0</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_BGR16_BE</td>
+<td>r4 r3 r2 r1 r0 g5 g4 g3</td>
+<td>g2 g1 g0 b4 b3 b2 b1 b0</td>
+<td> </td><td> </td></tr>
+<tr><td colspan=5>Packed 15 bit RGB data.</td></tr>
+<tr><td>VBI_PIXFMT_RGBA15_LE</td>
+<td>g2 g1 g0 r4 r3 r2 r1 r0</td>
+<td>a0 b4 b3 b2 b1 b0 g4 g3</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_BGRA15_LE</td>
+<td>g2 g1 g0 b4 b3 b2 b1 b0</td>
+<td>a0 r4 r3 r2 r1 r0 g4 g3</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_ARGB15_LE</td>
+<td>g1 g0 r4 r3 r2 r1 r0 a0</td>
+<td>b4 b3 b2 b1 b0 g4 g3 g2</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_ABGR15_LE</td>
+<td>g1 g0 b4 b3 b2 b1 b0 a0</td>
+<td>r4 r3 r2 r1 r0 g4 g3 g2</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_RGBA15_BE</td>
+<td>a0 b4 b3 b2 b1 b0 g4 g3</td>
+<td>g2 g1 g0 r4 r3 r2 r1 r0</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_BGRA15_BE</td>
+<td>a0 r4 r3 r2 r1 r0 g4 g3</td>
+<td>g2 g1 g0 b4 b3 b2 b1 b0</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_ARGB15_BE</td>
+<td>b4 b3 b2 b1 b0 g4 g3 g2</td>
+<td>g1 g0 r4 r3 r2 r1 r0 a0</td>
+<td> </td><td> </td></tr><tr><td>VBI_PIXFMT_ABGR15_BE</td>
+<td>r4 r3 r2 r1 r0 g4 g3 g2</td>
+<td>g1 g0 b4 b3 b2 b1 b0 a0</td>
+<td> </td><td> </td></tr>
+</table>
+@endhtmlonly */
+/* Attn: keep this in sync with rte, don't change order */
+typedef enum {
+ VBI_PIXFMT_YUV420 = 1,
+ VBI_PIXFMT_YUYV,
+ VBI_PIXFMT_YVYU,
+ VBI_PIXFMT_UYVY,
+ VBI_PIXFMT_VYUY,
+ VBI_PIXFMT_PAL8,
+ VBI_PIXFMT_RGBA32_LE = 32,
+ VBI_PIXFMT_RGBA32_BE,
+ VBI_PIXFMT_BGRA32_LE,
+ VBI_PIXFMT_BGRA32_BE,
+ VBI_PIXFMT_ABGR32_BE = 32, /* synonyms */
+ VBI_PIXFMT_ABGR32_LE,
+ VBI_PIXFMT_ARGB32_BE,
+ VBI_PIXFMT_ARGB32_LE,
+ VBI_PIXFMT_RGB24,
+ VBI_PIXFMT_BGR24,
+ VBI_PIXFMT_RGB16_LE,
+ VBI_PIXFMT_RGB16_BE,
+ VBI_PIXFMT_BGR16_LE,
+ VBI_PIXFMT_BGR16_BE,
+ VBI_PIXFMT_RGBA15_LE,
+ VBI_PIXFMT_RGBA15_BE,
+ VBI_PIXFMT_BGRA15_LE,
+ VBI_PIXFMT_BGRA15_BE,
+ VBI_PIXFMT_ARGB15_LE,
+ VBI_PIXFMT_ARGB15_BE,
+ VBI_PIXFMT_ABGR15_LE,
+ VBI_PIXFMT_ABGR15_BE
+} vbi_pixfmt;
+
+/* Private */
+
+typedef uint64_t vbi_pixfmt_set;
+
+#define VBI_MAX_PIXFMTS 64
+#define VBI_PIXFMT_SET(pixfmt) (((vbi_pixfmt_set) 1) << (pixfmt))
+#define VBI_PIXFMT_SET_YUV (VBI_PIXFMT_SET (VBI_PIXFMT_YUV420) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_YUYV) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_YVYU) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_UYVY) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_VYUY))
+#define VBI_PIXFMT_SET_RGB (VBI_PIXFMT_SET (VBI_PIXFMT_RGBA32_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGBA32_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGRA32_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGRA32_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGB24) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGR24) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGB16_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGB16_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGR16_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGR16_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGBA15_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_RGBA15_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGRA15_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_BGRA15_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_ARGB15_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_ARGB15_BE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_ABGR15_LE) | \
+ VBI_PIXFMT_SET (VBI_PIXFMT_ABGR15_BE))
+#define VBI_PIXFMT_SET_ALL (VBI_PIXFMT_SET_YUV | \
+ VBI_PIXFMT_SET_RGB)
+
+#define VBI_PIXFMT_BPP(fmt) \
+ (((fmt) == VBI_PIXFMT_YUV420) ? 1 : \
+ (((fmt) >= VBI_PIXFMT_RGBA32_LE \
+ && (fmt) <= VBI_PIXFMT_BGRA32_BE) ? 4 : \
+ (((fmt) == VBI_PIXFMT_RGB24 \
+ || (fmt) == VBI_PIXFMT_BGR24) ? 3 : 2)))
+
+/* Public */
+
+/**
+ * @ingroup Rawdec
+ * @brief Modulation used for VBI data transmission.
+ */
+typedef enum {
+ /**
+ * The data is 'non-return to zero' coded, logical '1' bits
+ * are described by high sample values, logical '0' bits by
+ * low values. The data is last significant bit first transmitted.
+ */
+ VBI_MODULATION_NRZ_LSB,
+ /**
+ * 'Non-return to zero' coded, most significant bit first
+ * transmitted.
+ */
+ VBI_MODULATION_NRZ_MSB,
+ /**
+ * The data is 'bi-phase' coded. Each data bit is described
+ * by two complementary signalling elements, a logical '1'
+ * by a sequence of '10' elements, a logical '0' by a '01'
+ * sequence. The data is last significant bit first transmitted.
+ */
+ VBI_MODULATION_BIPHASE_LSB,
+ /**
+ * 'Bi-phase' coded, most significant bit first transmitted.
+ */
+ VBI_MODULATION_BIPHASE_MSB
+} vbi_modulation;
+
+/**
+ * @ingroup Rawdec
+ * @brief Bit slicer context.
+ *
+ * The contents of this structure are private,
+ * use vbi_bit_slicer_init() to initialize.
+ */
+typedef struct vbi_bit_slicer {
+ vbi_bool (* func)(struct vbi_bit_slicer *slicer,
+ uint8_t *raw, uint8_t *buf);
+ unsigned int cri;
+ unsigned int cri_mask;
+ int thresh;
+ int cri_bytes;
+ int cri_rate;
+ int oversampling_rate;
+ int phase_shift;
+ int step;
+ unsigned int frc;
+ int frc_bits;
+ int payload;
+ int endian;
+ int skip;
+} vbi_bit_slicer;
+
+/**
+ * @addtogroup Rawdec
+ * @{
+ */
+extern void vbi_bit_slicer_init(vbi_bit_slicer *slicer,
+ int raw_samples, int sampling_rate,
+ int cri_rate, int bit_rate,
+ unsigned int cri_frc, unsigned int cri_mask,
+ int cri_bits, int frc_bits, int payload,
+ vbi_modulation modulation, vbi_pixfmt fmt);
+/**
+ * @param slicer Pointer to initialized vbi_bit_slicer object.
+ * @param raw Input data. At least the number of pixels or samples
+ * given as @a raw_samples to vbi_bit_slicer_init().
+ * @param buf Output data. The buffer must be large enough to store
+ * the number of bits given as @a payload to vbi_bit_slicer_init().
+ *
+ * Decode one scan line of raw vbi data. Note the bit slicer tries
+ * to adapt to the average signal amplitude, you should avoid
+ * using the same vbi_bit_slicer object for data from different
+ * devices.
+ *
+ * @note As a matter of speed this function does not lock the
+ * @a slicer. When you want to share a vbi_bit_slicer object between
+ * multiple threads you must implement your own locking mechanism.
+ *
+ * @return
+ * @c FALSE if the raw data does not contain the expected
+ * information, i. e. the CRI/FRC has not been found. This may also
+ * result from a too weak or noisy signal. Error correction must be
+ * implemented at a higher layer.
+ */
+_vbi_inline vbi_bool
+vbi_bit_slice(vbi_bit_slicer *slicer, uint8_t *raw, uint8_t *buf)
+{
+ return slicer->func(slicer, raw, buf);
+}
+/** @} */
+
+/**
+ * @ingroup Rawdec
+ * @brief Raw vbi decoder context.
+ *
+ * Only the sampling parameters are public. See
+ * vbi_raw_decoder_parameters() and vbi_raw_decoder_add_services()
+ * for usage.
+ */
+typedef struct vbi_raw_decoder {
+ /* Sampling parameters */
+
+ /**
+ * Either 525 (M/NTSC, M/PAL) or 625 (PAL, SECAM), describing the
+ * scan line system all line numbers refer to.
+ */
+ int scanning;
+ /**
+ * Format of the raw vbi data.
+ */
+ vbi_pixfmt sampling_format;
+ /**
+ * Sampling rate in Hz, the number of samples or pixels
+ * captured per second.
+ */
+ int sampling_rate; /* Hz */
+ /**
+ * Number of samples or pixels captured per scan line,
+ * in bytes. This determines the raw vbi image width and you
+ * want it large enough to cover all data transmitted in the line (with
+ * headroom).
+ */
+ int bytes_per_line;
+ /**
+ * The distance from 0H (leading edge hsync, half amplitude point)
+ * to the first sample (pixel) captured, in samples (pixels). You want
+ * an offset small enough not to miss the start of the data
+ * transmitted.
+ */
+ int offset; /* 0H, samples */
+ /**
+ * First scan line to be captured, first and second field
+ * respectively, according to the ITU-R line numbering scheme
+ * (see vbi_sliced). Set to zero if the exact line number isn't
+ * known.
+ */
+ int start[2]; /* ITU-R numbering */
+ /**
+ * Number of scan lines captured, first and second
+ * field respectively. This can be zero if only data from one
+ * field is required. The sum @a count[0] + @a count[1] determines the
+ * raw vbi image height.
+ */
+ int count[2]; /* field lines */
+ /**
+ * In the raw vbi image, normally all lines of the second
+ * field are supposed to follow all lines of the first field. When
+ * this flag is set, the scan lines of first and second field
+ * will be interleaved in memory. This implies @a count[0] and @a count[1]
+ * are equal.
+ */
+ vbi_bool interlaced;
+ /**
+ * Fields must be stored in temporal order, i. e. as the
+ * lines have been captured. It is assumed that the first field is
+ * also stored first in memory, however if the hardware cannot reliable
+ * distinguish fields this flag shall be cleared, which disables
+ * decoding of data services depending on the field number.
+ */
+ vbi_bool synchronous;
+
+ /*< private >*/
+
+ pthread_mutex_t mutex;
+
+ unsigned int services;
+ int num_jobs;
+
+ int8_t * pattern;
+ struct _vbi_raw_decoder_job {
+ unsigned int id;
+ int offset;
+ vbi_bit_slicer slicer;
+ } jobs[8];
+} vbi_raw_decoder;
+
+/**
+ * @addtogroup Rawdec
+ * @{
+ */
+extern void vbi_raw_decoder_init(vbi_raw_decoder *rd);
+extern void vbi_raw_decoder_reset(vbi_raw_decoder *rd);
+extern void vbi_raw_decoder_destroy(vbi_raw_decoder *rd);
+extern unsigned int vbi_raw_decoder_add_services(vbi_raw_decoder *rd,
+ unsigned int services,
+ int strict);
+extern unsigned int vbi_raw_decoder_check_services(vbi_raw_decoder *rd,
+ unsigned int services, int strict);
+extern unsigned int vbi_raw_decoder_remove_services(vbi_raw_decoder *rd,
+ unsigned int services);
+extern void vbi_raw_decoder_resize( vbi_raw_decoder *rd,
+ int * start, unsigned int * count );
+extern unsigned int vbi_raw_decoder_parameters(vbi_raw_decoder *rd, unsigned int services,
+ int scanning, int *max_rate);
+extern int vbi_raw_decode(vbi_raw_decoder *rd, uint8_t *raw, vbi_sliced *out);
+/** @} */
+
+/* Private */
+
+#endif /* DECODER_H */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Useful macros
+ *
+ * Copyright (C) 2002, 2003, 2004, 2007 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: macros.h,v 1.12 2013-07-10 23:11:18 mschimek Exp $ */
+
+#ifndef __ZVBI_MACROS_H__
+#define __ZVBI_MACROS_H__
+
+#ifdef __cplusplus
+# define VBI_BEGIN_DECLS extern "C" {
+# define VBI_END_DECLS }
+#else
+# define VBI_BEGIN_DECLS
+# define VBI_END_DECLS
+#endif
+
+VBI_BEGIN_DECLS
+
+/* Public */
+
+#if __GNUC__ >= 4
+# define _vbi_sentinel __attribute__ ((__sentinel__(0)))
+# define _vbi_deprecated __attribute__ ((__deprecated__))
+#else
+# define _vbi_sentinel
+# define _vbi_deprecated
+# define __restrict__
+#endif
+
+#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4
+# define _vbi_nonnull(params) __attribute__ ((__nonnull__ params))
+# define _vbi_format(params) __attribute__ ((__format__ params))
+#else
+# define _vbi_nonnull(params)
+# define _vbi_format(params)
+#endif
+
+#if __GNUC__ >= 3
+# define _vbi_pure __attribute__ ((__pure__))
+# define _vbi_alloc __attribute__ ((__malloc__))
+#else
+# define _vbi_pure
+# define _vbi_alloc
+#endif
+
+#if __GNUC__ >= 2
+# define _vbi_unused __attribute__ ((__unused__))
+# define _vbi_const __attribute__ ((__const__))
+# define _vbi_inline static __inline__
+#else
+# define _vbi_unused
+# define _vbi_const
+# define _vbi_inline static
+#endif
+
+/**
+ * @ingroup Basic
+ * @name Boolean type
+ * @{
+ */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+typedef int vbi_bool;
+/** @} */
+
+#ifndef NULL
+# ifdef __cplusplus
+# define NULL (0L)
+# else
+# define NULL ((void *) 0)
+# endif
+#endif
+
+/* XXX Document me - for variadic funcs. */
+#define VBI_END ((void *) 0)
+
+#if 0
+typedef void
+vbi_lock_fn (void * user_data);
+typedef void
+vbi_unlock_fn (void * user_data);
+#endif
+
+/**
+ * @ingroup Basic
+ * @{
+ */
+typedef enum {
+ /** External error causes, for example lack of memory. */
+ VBI_LOG_ERROR = 1 << 3,
+
+ /**
+ * Invalid parameters and similar problems which suggest
+ * a bug in the application using the library.
+ */
+ VBI_LOG_WARNING = 1 << 4,
+
+ /**
+ * Causes of possibly undesired results, for example when a
+ * data service cannot be decoded with the current video
+ * standard setting.
+ */
+ VBI_LOG_NOTICE = 1 << 5,
+
+ /** Progress messages. */
+ VBI_LOG_INFO = 1 << 6,
+
+ /** Information useful to debug the library. */
+ VBI_LOG_DEBUG = 1 << 7,
+
+ /** Driver responses (strace). Not implemented yet. */
+ VBI_LOG_DRIVER = 1 << 8,
+
+ /** More detailed debugging information. */
+ VBI_LOG_DEBUG2 = 1 << 9,
+ VBI_LOG_DEBUG3 = 1 << 10
+} vbi_log_mask;
+
+typedef void
+vbi_log_fn (vbi_log_mask level,
+ const char * context,
+ const char * message,
+ void * user_data);
+
+extern vbi_log_fn vbi_log_on_stderr;
+/** @} */
+
+/* Private */
+
+typedef struct {
+ vbi_log_fn * fn;
+ void * user_data;
+ vbi_log_mask mask;
+} _vbi_log_hook;
+
+VBI_END_DECLS
+
+#endif /* __ZVBI_MACROS_H__ */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Miscellaneous cows and chickens
+ *
+ * Copyright (C) 2000-2003 Iñaki GarcÃa Etxebarria
+ * Copyright (C) 2002-2007 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: misc.h,v 1.24 2013-07-02 02:32:31 mschimek Exp $ */
+
+#ifndef MISC_H
+#define MISC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h> /* (u)intXX_t */
+#include <sys/types.h> /* (s)size_t */
+#include <float.h> /* DBL_MAX */
+#include <limits.h> /* (S)SIZE_MAX */
+#include <assert.h>
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "macros.h"
+
+#define N_ELEMENTS(array) (sizeof (array) / sizeof (*(array)))
+
+#ifdef __GNUC__
+
+#if __GNUC__ < 3
+/* Expect expression usually true/false, schedule accordingly. */
+# define likely(expr) (expr)
+# define unlikely(expr) (expr)
+#else
+# define likely(expr) __builtin_expect(expr, 1)
+# define unlikely(expr) __builtin_expect(expr, 0)
+#endif
+
+#undef __i386__
+#undef __i686__
+/* FIXME #cpu is deprecated
+#if #cpu (i386)
+# define __i386__ 1
+#endif
+#if #cpu (i686)
+# define __i686__ 1
+#endif
+*/
+
+/* &x == PARENT (&x.tm_min, struct tm, tm_min),
+ safer than &x == (struct tm *) &x.tm_min. A NULL _ptr is safe and
+ will return NULL, not -offsetof(_member). */
+#undef PARENT
+#define PARENT(_ptr, _type, _member) ({ \
+ __typeof__ (&((_type *) 0)->_member) _p = (_ptr); \
+ (_p != 0) ? (_type *)(((char *) _p) - offsetof (_type, \
+ _member)) : (_type *) 0; \
+})
+
+/* Like PARENT(), to be used with const _ptr. */
+#define CONST_PARENT(_ptr, _type, _member) ({ \
+ __typeof__ (&((const _type *) 0)->_member) _p = (_ptr); \
+ (_p != 0) ? (const _type *)(((const char *) _p) - offsetof \
+ (const _type, _member)) : (const _type *) 0; \
+})
+
+/* Note the following macros have no side effects only when you
+ compile with GCC, so don't expect this. */
+
+/* Absolute value of int, long or long long without a branch.
+ Note ABS (INT_MIN) -> INT_MAX + 1. */
+#undef ABS
+#define ABS(n) ({ \
+ register __typeof__ (n) _n = (n), _t = _n; \
+ if (-1 == (-1 >> 1)) { /* do we have signed shifts? */ \
+ _t >>= sizeof (_t) * 8 - 1; \
+ _n ^= _t; \
+ _n -= _t; \
+ } else if (_n < 0) { /* also warns if n is unsigned type */ \
+ _n = -_n; \
+ } \
+ /* return */ _n; \
+})
+
+#undef MIN
+#define MIN(x, y) ({ \
+ __typeof__ (x) _x = (x); \
+ __typeof__ (y) _y = (y); \
+ (void)(&_x == &_y); /* warn if types do not match */ \
+ /* return */ (_x < _y) ? _x : _y; \
+})
+
+#undef MAX
+#define MAX(x, y) ({ \
+ __typeof__ (x) _x = (x); \
+ __typeof__ (y) _y = (y); \
+ (void)(&_x == &_y); /* warn if types do not match */ \
+ /* return */ (_x > _y) ? _x : _y; \
+})
+
+/* Note other compilers may swap only int, long or pointer. */
+#undef SWAP
+#define SWAP(x, y) \
+do { \
+ __typeof__ (x) _x = x; \
+ x = y; \
+ y = _x; \
+} while (0)
+
+#undef SATURATE
+#ifdef __i686__ /* has conditional move */
+#define SATURATE(n, min, max) ({ \
+ __typeof__ (n) _n = (n); \
+ __typeof__ (n) _min = (min); \
+ __typeof__ (n) _max = (max); \
+ (void)(&_n == &_min); /* warn if types do not match */ \
+ (void)(&_n == &_max); \
+ if (_n < _min) \
+ _n = _min; \
+ if (_n > _max) \
+ _n = _max; \
+ /* return */ _n; \
+})
+#else
+#define SATURATE(n, min, max) ({ \
+ __typeof__ (n) _n = (n); \
+ __typeof__ (n) _min = (min); \
+ __typeof__ (n) _max = (max); \
+ (void)(&_n == &_min); /* warn if types do not match */ \
+ (void)(&_n == &_max); \
+ if (_n < _min) \
+ _n = _min; \
+ else if (_n > _max) \
+ _n = _max; \
+ /* return */ _n; \
+})
+#endif
+
+#else /* !__GNUC__ */
+
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#undef __i386__
+#undef __i686__
+
+static char *
+PARENT_HELPER (char *p, unsigned int offset)
+{ return (0 == p) ? ((char *) 0) : p - offset; }
+
+static const char *
+CONST_PARENT_HELPER (const char *p, unsigned int offset)
+{ return (0 == p) ? ((char *) 0) : p - offset; }
+
+#define PARENT(_ptr, _type, _member) \
+ ((0 == offsetof (_type, _member)) ? (_type *)(_ptr) \
+ : (_type *) PARENT_HELPER ((char *)(_ptr), offsetof (_type, _member)))
+#define CONST_PARENT(_ptr, _type, _member) \
+ ((0 == offsetof (const _type, _member)) ? (const _type *)(_ptr) \
+ : (const _type *) CONST_PARENT_HELPER ((const char *)(_ptr), \
+ offsetof (const _type, _member)))
+
+#undef ABS
+#define ABS(n) (((n) < 0) ? -(n) : (n))
+
+#undef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+#undef MAX
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#undef SWAP
+#define SWAP(x, y) \
+do { \
+ long _x = x; \
+ x = y; \
+ y = _x; \
+} while (0)
+
+#undef SATURATE
+#define SATURATE(n, min, max) MIN (MAX (min, n), max)
+
+#endif /* !__GNUC__ */
+
+/* 32 bit constant byte reverse, e.g. 0xAABBCCDD -> 0xDDCCBBAA. */
+#define SWAB32(m) \
+ (+ (((m) & 0xFF000000) >> 24) \
+ + (((m) & 0xFF0000) >> 8) \
+ + (((m) & 0xFF00) << 8) \
+ + (((m) & 0xFF) << 24))
+
+#ifdef HAVE_BUILTIN_POPCOUNT
+# define popcnt(x) __builtin_popcount ((uint32_t)(x))
+#else
+# define popcnt(x) _vbi_popcnt (x)
+#endif
+
+extern unsigned int
+_vbi_popcnt (uint32_t x);
+
+/* NB GCC inlines and optimizes these functions when size is const. */
+#define SET(var) memset (&(var), ~0, sizeof (var))
+
+#define CLEAR(var) memset (&(var), 0, sizeof (var))
+
+/* Useful to copy arrays, otherwise use assignment. */
+#define COPY(d, s) \
+ (assert (sizeof (d) == sizeof (s)), memcpy (d, s, sizeof (d)))
+
+/* Copy string const into char array. */
+#define STRACPY(array, s) \
+do { \
+ /* Complain if s is no string const or won't fit. */ \
+ const char t_[sizeof (array) - 1] _vbi_unused = s; \
+ \
+ memcpy (array, s, sizeof (s)); \
+} while (0)
+
+/* Copy bits through mask. */
+#define COPY_SET_MASK(dest, from, mask) \
+ (dest ^= (from) ^ (dest & (mask)))
+
+/* Set bits if cond is TRUE, clear if FALSE. */
+#define COPY_SET_COND(dest, bits, cond) \
+ ((cond) ? (dest |= (bits)) : (dest &= ~(bits)))
+
+/* Set and clear bits. */
+#define COPY_SET_CLEAR(dest, set, clear) \
+ (dest = (dest & ~(clear)) | (set))
+
+/* For applications, debugging and fault injection during unit tests. */
+
+#define vbi_malloc malloc
+#define vbi_realloc realloc
+#define vbi_strdup strdup
+#define vbi_free free
+
+#define vbi_cache_malloc vbi_malloc
+#define vbi_cache_free vbi_free
+
+/* Helper functions. */
+
+_vbi_inline int
+_vbi_to_ascii (int c)
+{
+ if (c < 0)
+ return '?';
+
+ c &= 0x7F;
+
+ if (c < 0x20 || c >= 0x7F)
+ return '.';
+
+ return c;
+}
+
+typedef struct {
+ const char * key;
+ int value;
+} _vbi_key_value_pair;
+
+extern vbi_bool
+_vbi_keyword_lookup (int * value,
+ const char ** inout_s,
+ const _vbi_key_value_pair * table,
+ unsigned int n_pairs)
+ _vbi_nonnull ((1, 2, 3));
+
+extern void
+_vbi_shrink_vector_capacity (void ** vector,
+ size_t * capacity,
+ size_t min_capacity,
+ size_t element_size)
+ _vbi_nonnull ((1, 2));
+extern vbi_bool
+_vbi_grow_vector_capacity (void ** vector,
+ size_t * capacity,
+ size_t min_capacity,
+ size_t element_size)
+ _vbi_nonnull ((1, 2));
+
+/* Logging stuff. */
+#ifdef G_HAVE_ISO_VARARGS
+#define VBI_CAT_LEVEL_LOG(cat,level,object,...) G_STMT_START{ \
+ if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) { \
+ gst_debug_log ((cat), (level), __FILE__, GST_FUNCTION, __LINE__, \
+ (GObject *) (object), __VA_ARGS__); \
+ } \
+}G_STMT_END
+#else /* G_HAVE_GNUC_VARARGS */
+#ifdef G_HAVE_GNUC_VARARGS
+#define VBI_CAT_LEVEL_LOG(cat,level,object,args...) G_STMT_START{ \
+ if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) { \
+ gst_debug_log ((cat), (level), __FILE__, GST_FUNCTION, __LINE__, \
+ (GObject *) (object), ##args ); \
+ } \
+}G_STMT_END
+#else /* no variadic macros, use inline */
+static inline void
+VBI_CAT_LEVEL_LOG_valist (GstDebugCategory * cat,
+ GstDebugLevel level, gpointer object, const char *format, va_list varargs)
+{
+ if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) {
+ gst_debug_log_valist (cat, level, "", "", 0, (GObject *) object, format,
+ varargs);
+ }
+}
+
+static inline void
+VBI_CAT_LEVEL_LOG (GstDebugCategory * cat, GstDebugLevel level,
+ gpointer object, const char *format, ...)
+{
+ va_list varargs;
+
+ va_start (varargs, format);
+ GST_CAT_LEVEL_LOG_valist (cat, level, object, format, varargs);
+ va_end (varargs);
+}
+#endif
+#endif /* G_HAVE_ISO_VARARGS */
+
+#define error(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_ERROR, NULL, templ , ##args)
+#define warning(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_WARNING, NULL, templ , ##args)
+#define notice(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_INFO, NULL, templ , ##args)
+#define info(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_INFO, NULL, templ , ##args)
+#define debug1(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, NULL, templ , ##args)
+#define debug2(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_LOG, NULL, templ , ##args)
+#define debug3(hook, templ, args...) \
+ VBI_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_TRACE, NULL, templ , ##args)
+
+#if 0 /* Replaced logging with GStreamer logging system */
+extern _vbi_log_hook _vbi_global_log;
+
+extern void
+_vbi_log_vprintf (vbi_log_fn * log_fn,
+ void * user_data,
+ vbi_log_mask level,
+ const char * source_file,
+ const char * context,
+ const char * templ,
+ va_list ap)
+ _vbi_nonnull ((1, 4, 5, 6));
+extern void
+_vbi_log_printf (vbi_log_fn * log_fn,
+ void * user_data,
+ vbi_log_mask level,
+ const char * source_file,
+ const char * context,
+ const char * templ,
+ ...)
+ _vbi_nonnull ((1, 4, 5, 6)) _vbi_format ((printf, 6, 7));
+
+#define _vbi_log(hook, level, templ, args...) \
+do { \
+ _vbi_log_hook *_h = hook; \
+ \
+ if ((NULL != _h && 0 != (_h->mask & level)) \
+ || (_h = &_vbi_global_log, 0 != (_h->mask & level))) \
+ _vbi_log_printf (_h->fn, _h->user_data, \
+ level, __FILE__, __FUNCTION__, \
+ templ , ##args); \
+} while (0)
+
+#define _vbi_vlog(hook, level, templ, ap) \
+do { \
+ _vbi_log_hook *_h = hook; \
+ \
+ if ((NULL != _h && 0 != (_h->mask & level)) \
+ || (_h = &_vbi_global_log, 0 != (_h->mask & level))) \
+ _vbi_log_vprintf (_h->fn, _h->user_data, \
+ level, __FILE__, __FUNCTION__, \
+ templ, ap); \
+} while (0)
+#define error(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_ERROR, templ , ##args)
+#define warning(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_ERROR, templ , ##args)
+#define notice(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_NOTICE, templ , ##args)
+#define info(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_INFO, templ , ##args)
+#define debug1(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_DEBUG, templ , ##args)
+#define debug2(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_DEBUG2, templ , ##args)
+#define debug3(hook, templ, args...) \
+ _vbi_log (hook, VBI_LOG_DEBUG3, templ , ##args)
+#endif
+
+/* Portability stuff. */
+
+/* These should be defined in inttypes.h. */
+#ifndef PRId64
+# define PRId64 "lld"
+#endif
+#ifndef PRIu64
+# define PRIu64 "llu"
+#endif
+#ifndef PRIx64
+# define PRIx64 "llx"
+#endif
+
+/* Should be defined in C99 limits.h? */
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#ifndef TIME_MIN
+# define TIME_MIN (_vbi_time_min ())
+_vbi_inline time_t
+_vbi_time_min (void)
+{
+ const time_t t = (time_t) -1.25;
+
+ if (t < -1) {
+ return (time_t)((sizeof (time_t) > 4) ? DBL_MIN : FLT_MIN);
+ } else if (t < 0) {
+ return ((uint64_t) 1) << (sizeof (time_t) * 8 - 1);
+ } else {
+ return 0;
+ }
+}
+#endif
+
+#ifndef TIME_MAX
+# define TIME_MAX (_vbi_time_max ())
+_vbi_inline time_t
+_vbi_time_max (void)
+{
+ const time_t t = (time_t) -1.25;
+
+ if (t < -1) {
+ return (time_t)((sizeof (time_t) > 4) ? DBL_MAX : FLT_MAX);
+ } else if (t < 0) {
+ /* Most likely signed 32 or 64 bit. */
+ return (((uint64_t) 1) << (sizeof (time_t) * 8 - 1)) - 1;
+ } else {
+ return -1;
+ }
+}
+#endif
+
+/* __va_copy is a GNU extension. */
+#ifndef __va_copy
+# define __va_copy(ap1, ap2) do { ap1 = ap2; } while (0)
+#endif
+
+/* Use this instead of strncpy(). strlcpy() is a BSD extension. */
+#ifndef HAVE_STRLCPY
+# define strlcpy _vbi_strlcpy
+#endif
+#undef strncpy
+#define strncpy use_strlcpy_instead
+
+extern size_t
+_vbi_strlcpy (char * dst,
+ const char * src,
+ size_t size)
+ _vbi_nonnull ((1, 2));
+
+/* strndup() is a BSD/GNU extension. */
+#ifndef HAVE_STRNDUP
+# define strndup _vbi_strndup
+#endif
+
+extern char *
+_vbi_strndup (const char * s,
+ size_t len)
+ _vbi_nonnull ((1));
+
+/* vasprintf() is a GNU extension. */
+#ifndef HAVE_VASPRINTF
+# define vasprintf _vbi_vasprintf
+#endif
+
+extern int
+_vbi_vasprintf (char ** dstp,
+ const char * templ,
+ va_list ap)
+ _vbi_nonnull ((1, 2));
+
+/* asprintf() is a GNU extension. */
+#ifndef HAVE_ASPRINTF
+# define asprintf _vbi_asprintf
+#endif
+
+extern int
+_vbi_asprintf (char ** dstp,
+ const char * templ,
+ ...)
+ _vbi_nonnull ((1, 2)) _vbi_format ((printf, 2, 3));
+
+#undef sprintf
+#define sprintf use_snprintf_or_asprintf_instead
+
+#endif /* MISC_H */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Raw VBI decoder
+ *
+ * Copyright (C) 2000-2004 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: raw_decoder.c,v 1.24 2008-08-19 10:04:46 mschimek Exp $ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "misc.h"
+#include "raw_decoder.h"
+
+#ifndef RAW_DECODER_PATTERN_DUMP
+# define RAW_DECODER_PATTERN_DUMP 0
+#endif
+
+# define sp_sample_format sampling_format
+
+/**
+ * $addtogroup RawDecoder Raw VBI decoder
+ * $ingroup Raw
+ * $brief Converting a raw VBI image to sliced VBI data.
+ */
+
+/* Missing:
+ VITC PAL 6-22 11.2us 1.8125 Mbit NRZ two start bits + CRC
+ VITC NTSC 10-21 ditto
+ CGMS NTSC 20 11us .450450 Mbit NRZ ?
+ MOJI
+*/
+const _vbi_service_par _vbi_service_table[] = {
+ {
+ VBI_SLICED_TELETEXT_A, /* UNTESTED */
+ "Teletext System A",
+ VBI_VIDEOSTD_SET_625_50,
+ {6, 318},
+ {22, 335},
+ 10500, 6203125, 6203125, /* 397 x FH */
+ 0x00AAAAE7, 0xFFFF, 18, 6, 37 * 8, VBI_MODULATION_NRZ_LSB,
+ 0, /* probably */
+ }, {
+ VBI_SLICED_TELETEXT_B_L10_625,
+ "Teletext System B 625 Level 1.5",
+ VBI_VIDEOSTD_SET_625_50,
+ {7, 320},
+ {22, 335},
+ 10300, 6937500, 6937500, /* 444 x FH */
+ 0x00AAAAE4, 0xFFFF, 18, 6, 42 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_B,
+ "Teletext System B, 625",
+ VBI_VIDEOSTD_SET_625_50,
+ {6, 318},
+ {22, 335},
+ 10300, 6937500, 6937500, /* 444 x FH */
+ 0x00AAAAE4, 0xFFFF, 18, 6, 42 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_C_625, /* UNTESTED */
+ "Teletext System C 625",
+ VBI_VIDEOSTD_SET_625_50,
+ {6, 318},
+ {22, 335},
+ 10480, 5734375, 5734375, /* 367 x FH */
+ 0x00AAAAE7, 0xFFFF, 18, 6, 33 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_D_625, /* UNTESTED */
+ "Teletext System D 625",
+ VBI_VIDEOSTD_SET_625_50,
+ {6, 318},
+ {22, 335},
+ 10500, /* or 10970 depending on field order */
+ 5642787, 5642787, /* 14/11 x FSC (color subcarrier) */
+ 0x00AAAAE5, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_VPS, "Video Program System",
+ VBI_VIDEOSTD_SET_PAL_BG,
+ {16, 0},
+ {16, 0},
+ 12500, 5000000, 2500000, /* 160 x FH */
+ 0xAAAA8A99, 0xFFFFFF, 32, 0, 13 * 8,
+ VBI_MODULATION_BIPHASE_MSB,
+ _VBI_SP_FIELD_NUM,
+ }, {
+ VBI_SLICED_VPS_F2, "Pseudo-VPS on field 2",
+ VBI_VIDEOSTD_SET_PAL_BG,
+ {0, 329},
+ {0, 329},
+ 12500, 5000000, 2500000, /* 160 x FH */
+ 0xAAAA8A99, 0xFFFFFF, 32, 0, 13 * 8,
+ VBI_MODULATION_BIPHASE_MSB,
+ _VBI_SP_FIELD_NUM,
+ }, {
+ VBI_SLICED_WSS_625, "Wide Screen Signalling 625",
+ VBI_VIDEOSTD_SET_625_50,
+ {23, 0},
+ {23, 0},
+ 11000, 5000000, 833333, /* 160/3 x FH */
+ /* ...1000 111 / 0 0011 1100 0111 1000 0011 111x */
+ /* ...0010 010 / 0 1001 1001 0011 0011 1001 110x */
+ 0x8E3C783E, 0x2499339C, 32, 0, 14 * 1,
+ VBI_MODULATION_BIPHASE_LSB,
+ /* Hm. Too easily confused with caption?? */
+ _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
+ }, {
+ VBI_SLICED_CAPTION_625_F1, "Closed Caption 625, field 1",
+ VBI_VIDEOSTD_SET_625_50,
+ {22, 0},
+ {22, 0},
+ 10500, 1000000, 500000, /* 32 x FH */
+ 0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
+ _VBI_SP_FIELD_NUM,
+ }, {
+ VBI_SLICED_CAPTION_625_F2, "Closed Caption 625, field 2",
+ VBI_VIDEOSTD_SET_625_50,
+ {0, 335},
+ {0, 335},
+ 10500, 1000000, 500000, /* 32 x FH */
+ 0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB,
+ _VBI_SP_FIELD_NUM,
+ }, {
+ VBI_SLICED_VBI_625, "VBI 625", /* Blank VBI */
+ VBI_VIDEOSTD_SET_625_50,
+ {6, 318},
+ {22, 335},
+ 10000, 1510000, 1510000,
+ 0, 0, 0, 0, 10 * 8, 0, /* 10.0-2 ... 62.9+1 us */
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_B_525, /* UNTESTED */
+ "Teletext System B 525",
+ VBI_VIDEOSTD_SET_525_60,
+ {10, 272},
+ {21, 284},
+ 10500, 5727272, 5727272, /* 364 x FH */
+ 0x00AAAAE4, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_C_525, /* UNTESTED */
+ "Teletext System C 525",
+ VBI_VIDEOSTD_SET_525_60,
+ {10, 272},
+ {21, 284},
+ 10480, 5727272, 5727272, /* 364 x FH */
+ 0x00AAAAE7, 0xFFFF, 18, 6, 33 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+ VBI_SLICED_TELETEXT_D_525, /* UNTESTED */
+ "Teletext System D 525",
+ VBI_VIDEOSTD_SET_525_60,
+ {10, 272},
+ {21, 284},
+ 9780, 5727272, 5727272, /* 364 x FH */
+ 0x00AAAAE5, 0xFFFF, 18, 6, 34 * 8, VBI_MODULATION_NRZ_LSB,
+ 0,
+ }, {
+#if 0 /* FIXME probably wrong */
+ VBI_SLICED_WSS_CPR1204, /* NOT CONFIRMED (EIA-J CPR-1204) */
+ "Wide Screen Signalling 525",
+ VBI_VIDEOSTD_SET_NTSC_M_JP,
+ {20, 283},
+ {20, 283},
+ 11200, 1789773, 447443, /* 1/8 x FSC */
+ 0x000000F0, 0xFF, 8, 0, 20 * 1, VBI_MODULATION_NRZ_MSB,
+ /* No useful FRC, but a six bit CRC */
+ 0,
+ }, {
+#endif
+ VBI_SLICED_CAPTION_525_F1,
+ "Closed Caption 525, field 1",
+ VBI_VIDEOSTD_SET_525_60,
+ {21, 0},
+ {21, 0},
+ 10500, 1006976, 503488, /* 32 x FH */
+ /* Test of CRI bits has been removed to handle the
+ incorrect signal observed by Rich Kandel (see
+ _VBI_RAW_SHIFT_CC_CRI). */
+ 0x03, 0x0F, 4, 0, 2 * 8, VBI_MODULATION_NRZ_LSB,
+ /* 0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB, */
+ /* I've seen CC signals on other lines and there's no
+ way to distinguish from the transmitted data. */
+ _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
+ }, {
+ VBI_SLICED_CAPTION_525_F2,
+ "Closed Caption 525, field 2",
+ VBI_VIDEOSTD_SET_525_60,
+ {0, 284},
+ {0, 284},
+ 10500, 1006976, 503488, /* 32 x FH */
+ 0x03, 0x0F, 4, 0, 2 * 8, VBI_MODULATION_NRZ_LSB,
+ /* 0x00005551, 0x7FF, 14, 2, 2 * 8, VBI_MODULATION_NRZ_LSB, */
+ _VBI_SP_FIELD_NUM | _VBI_SP_LINE_NUM,
+ }, {
+ VBI_SLICED_2xCAPTION_525, /* NOT CONFIRMED */
+ "2xCaption 525",
+ VBI_VIDEOSTD_SET_525_60,
+ {10, 0},
+ {21, 0},
+ 10500, 1006976, 1006976, /* 64 x FH */
+ 0x000554ED, 0xFFFF, 12, 8, 4 * 8,
+ VBI_MODULATION_NRZ_LSB, /* Tb. */
+ _VBI_SP_FIELD_NUM,
+ }, {
+ VBI_SLICED_VBI_525, "VBI 525", /* Blank VBI */
+ VBI_VIDEOSTD_SET_525_60,
+ {10, 272},
+ {21, 284},
+ 9500, 1510000, 1510000,
+ 0, 0, 0, 0, 10 * 8, 0, /* 9.5-1 ... 62.4+1 us */
+ 0,
+ }, {
+ 0, NULL,
+ VBI_VIDEOSTD_SET_EMPTY,
+ {0, 0},
+ {0, 0},
+ 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0,
+ }
+};
+
+_vbi_inline const _vbi_service_par *
+find_service_par (unsigned int service)
+{
+ unsigned int i;
+
+ for (i = 0; _vbi_service_table[i].id; ++i)
+ if (service == _vbi_service_table[i].id)
+ return _vbi_service_table + i;
+
+ return NULL;
+}
+
+/**
+ * $ingroup Sliced
+ * $param service A data service identifier, for example from a
+ * vbi_sliced structure.
+ *
+ * $return
+ * Name of the $a service, in ASCII, or $c NULL if unknown.
+ */
+const char *
+vbi_sliced_name (vbi_service_set service)
+{
+ const _vbi_service_par *par;
+
+ /* These are ambiguous */
+ if (service == VBI_SLICED_CAPTION_525)
+ return "Closed Caption 525";
+ if (service == VBI_SLICED_CAPTION_625)
+ return "Closed Caption 625";
+ if (service == (VBI_SLICED_VPS | VBI_SLICED_VPS_F2))
+ return "Video Program System";
+ if (service == VBI_SLICED_TELETEXT_B_L25_625)
+ return "Teletext System B 625 Level 2.5";
+
+ /* Incorrect, no longer in table */
+ if (service == VBI_SLICED_TELETEXT_BD_525)
+ return "Teletext System B/D";
+
+ if ((par = find_service_par (service)))
+ return par->label;
+
+ return NULL;
+}
+
+/**
+ * @ingroup Sliced
+ * @param service A data service identifier, for example from a
+ * vbi_sliced structure.
+ *
+ * @return
+ * Number of payload bits, @c 0 if the service is unknown.
+ */
+unsigned int
+vbi_sliced_payload_bits (unsigned int service)
+{
+ const _vbi_service_par *par;
+
+ /* These are ambiguous */
+ if (service == VBI_SLICED_CAPTION_525)
+ return 16;
+ if (service == VBI_SLICED_CAPTION_625)
+ return 16;
+ if (service == (VBI_SLICED_VPS | VBI_SLICED_VPS_F2))
+ return 13 * 8;
+ if (service == VBI_SLICED_TELETEXT_B_L25_625)
+ return 42 * 8;
+
+ /* Incorrect, no longer in table */
+ if (service == VBI_SLICED_TELETEXT_BD_525)
+ return 34 * 8;
+
+ if ((par = find_service_par (service)))
+ return par->payload;
+
+ return 0;
+}
+
+static void
+dump_pattern_line (const vbi3_raw_decoder * rd, unsigned int row, FILE * fp)
+{
+ const vbi_sampling_par *sp;
+ unsigned int line;
+ unsigned int i;
+
+ sp = &rd->sampling;
+
+ if (sp->interlaced) {
+ unsigned int field = row & 1;
+
+ if (0 == sp->start[field])
+ line = 0;
+ else
+ line = sp->start[field] + (row >> 1);
+ } else {
+ if (row >= (unsigned int) sp->count[0]) {
+ if (0 == sp->start[1])
+ line = 0;
+ else
+ line = sp->start[1] + row - sp->count[0];
+ } else {
+ if (0 == sp->start[0])
+ line = 0;
+ else
+ line = sp->start[0] + row;
+ }
+ }
+
+ fprintf (fp, "scan line %3u: ", line);
+
+ for (i = 0; i < _VBI3_RAW_DECODER_MAX_WAYS; ++i) {
+ unsigned int pos;
+
+ pos = row * _VBI3_RAW_DECODER_MAX_WAYS;
+ fprintf (fp, "%02x ", (uint8_t) rd->pattern[pos + i]);
+ }
+
+ fputc ('\n', fp);
+}
+
+void
+_vbi3_raw_decoder_dump (const vbi3_raw_decoder * rd, FILE * fp)
+{
+ const vbi_sampling_par *sp;
+ unsigned int i;
+
+ assert (NULL != fp);
+
+ fprintf (fp, "vbi3_raw_decoder %p\n", rd);
+
+ if (NULL == rd)
+ return;
+
+ fprintf (fp, " services 0x%08x\n", rd->services);
+
+ for (i = 0; i < rd->n_jobs; ++i)
+ fprintf (fp, " job %u: 0x%08x (%s)\n",
+ i + 1, rd->jobs[i].id, vbi_sliced_name (rd->jobs[i].id));
+
+ if (!rd->pattern) {
+ fprintf (fp, " no pattern\n");
+ return;
+ }
+
+ sp = &rd->sampling;
+
+ for (i = 0; i < ((unsigned int) sp->count[0]
+ + (unsigned int) sp->count[1]); ++i) {
+ fputs (" ", fp);
+ dump_pattern_line (rd, i, fp);
+ }
+}
+
+_vbi_inline int
+cpr1204_crc (const vbi_sliced * sliced)
+{
+ const int poly = (1 << 6) + (1 << 1) + 1;
+ int crc, i;
+
+ crc = (+(sliced->data[0] << 12)
+ + (sliced->data[1] << 4)
+ + (sliced->data[2]));
+
+ crc |= (((1 << 6) - 1) << (14 + 6));
+
+ for (i = 14 + 6 - 1; i >= 0; i--) {
+ if (crc & ((1 << 6) << i))
+ crc ^= poly << i;
+ }
+
+ return crc;
+}
+
+static vbi_bool
+slice (vbi3_raw_decoder * rd,
+ vbi_sliced * sliced,
+ _vbi3_raw_decoder_job * job, unsigned int i, const uint8_t * raw)
+{
+ if (rd->debug && NULL != rd->sp_lines) {
+ return vbi3_bit_slicer_slice_with_points
+ (&job->slicer,
+ sliced->data,
+ sizeof (sliced->data),
+ rd->sp_lines[i].points,
+ &rd->sp_lines[i].n_points, N_ELEMENTS (rd->sp_lines[i].points), raw);
+ } else {
+ return vbi3_bit_slicer_slice
+ (&job->slicer, sliced->data, sizeof (sliced->data), raw);
+ }
+}
+
+_vbi_inline vbi_sliced *
+decode_pattern (vbi3_raw_decoder * rd,
+ vbi_sliced * sliced, int8_t * pattern, unsigned int i, const uint8_t * raw)
+{
+ vbi_sampling_par *sp;
+ int8_t *pat;
+
+ sp = &rd->sampling;
+
+ for (pat = pattern;; ++pat) {
+ int j;
+
+ j = *pat; /* data service n, blank 0, or counter -n */
+
+ if (j > 0) {
+ _vbi3_raw_decoder_job *job;
+
+ job = rd->jobs + j - 1;
+
+ if (!slice (rd, sliced, job, i, raw)) {
+ continue; /* no match, try next data service */
+ }
+
+ /* FIXME probably wrong */
+ if (0 && VBI_SLICED_WSS_CPR1204 == job->id) {
+ const int poly = (1 << 6) + (1 << 1) + 1;
+ int crc, j;
+
+ crc = (sliced->data[0] << 12)
+ + (sliced->data[1] << 4)
+ + sliced->data[2];
+ crc |= (((1 << 6) - 1) << (14 + 6));
+
+ for (j = 14 + 6 - 1; j >= 0; j--) {
+ if (crc & ((1 << 6) << j))
+ crc ^= poly << j;
+ }
+
+ if (crc)
+ continue; /* no match */
+ }
+
+ /* Positive match, output decoded line. */
+
+ /* FIXME: if we have a field number we should
+ really only set the service id of one field. */
+ sliced->id = job->id;
+ sliced->line = 0;
+
+ if (i >= (unsigned int) sp->count[0]) {
+ if (sp->synchronous && 0 != sp->start[1])
+ sliced->line = sp->start[1]
+ + i - sp->count[0];
+ } else {
+ if (sp->synchronous && 0 != sp->start[0])
+ sliced->line = sp->start[0] + i;
+ }
+
+ if (0)
+ fprintf (stderr, "%2d %s\n",
+ sliced->line, vbi_sliced_name (sliced->id));
+
+ ++sliced;
+
+ /* Predict line as non-blank, force testing for
+ all data services in the next 128 frames. */
+ pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = -128;
+ } else if (pat == pattern) {
+ /* Line was predicted as blank, once in 16
+ frames look for data services. */
+ if (0 == rd->readjust) {
+ unsigned int size;
+
+ size = sizeof (*pattern)
+ * (_VBI3_RAW_DECODER_MAX_WAYS - 1);
+
+ j = pattern[0];
+ memmove (&pattern[0], &pattern[1], size);
+ pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = j;
+ }
+
+ break;
+ } else if ((j = pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1]) < 0) {
+ /* Increment counter, when zero predict line as
+ blank and stop looking for data services until
+ 0 == rd->readjust. */
+ /* Disabled because we may miss caption/subtitles
+ when the signal inserter is disabled during silent
+ periods for more than 4-5 seconds. */
+ /* pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = j + 1; */
+ break;
+ } else {
+ /* found nothing, j = 0 */
+ }
+
+ /* Try the found data service first next time. */
+ *pat = pattern[0];
+ pattern[0] = j;
+
+ break; /* line done */
+ }
+
+ return sliced;
+}
+
+/**
+ * $param rd Pointer to vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ * $param sliced Buffer to store the decoded vbi_sliced data. Since every
+ * vbi scan line may contain data, this should be an array of vbi_sliced
+ * with the same number of elements as scan lines in the raw image
+ * (vbi_sampling_parameters.count[0] + .count[1]).
+ * $param max_lines Size of $a sliced data array, in lines, not bytes.
+ * $param raw A raw vbi image as described by the vbi_sampling_par
+ * associated with $a rd.
+ *
+ * Decodes a raw vbi image, consisting of several scan lines of raw vbi data,
+ * to sliced vbi data. The output is sorted by ascending line number.
+ *
+ * Note this function attempts to learn which lines carry which data
+ * service, or if any, to speed up decoding. You should avoid using the same
+ * vbi3_raw_decoder object for different sources.
+ *
+ * $return
+ * The number of lines decoded, i. e. the number of vbi_sliced records
+ * written.
+ */
+unsigned int
+vbi3_raw_decoder_decode (vbi3_raw_decoder * rd,
+ vbi_sliced * sliced, unsigned int max_lines, const uint8_t * raw)
+{
+ vbi_sampling_par *sp;
+ unsigned int scan_lines;
+ unsigned int pitch;
+ int8_t *pattern;
+ const uint8_t *raw1;
+ vbi_sliced *sliced_begin;
+ vbi_sliced *sliced_end;
+ unsigned int i;
+
+ if (!rd->services)
+ return 0;
+
+ sp = &rd->sampling;
+
+ scan_lines = sp->count[0] + sp->count[1];
+ pitch = sp->bytes_per_line << sp->interlaced;
+
+ pattern = rd->pattern;
+
+ raw1 = raw;
+
+ sliced_begin = sliced;
+ sliced_end = sliced + max_lines;
+
+ if (RAW_DECODER_PATTERN_DUMP)
+ _vbi3_raw_decoder_dump (rd, stderr);
+
+ for (i = 0; i < scan_lines; ++i) {
+ if (sliced >= sliced_end)
+ break;
+
+ if (sp->interlaced && i == (unsigned int) sp->count[0])
+ raw = raw1 + sp->bytes_per_line;
+
+ sliced = decode_pattern (rd, sliced, pattern, i, raw);
+
+ pattern += _VBI3_RAW_DECODER_MAX_WAYS;
+ raw += pitch;
+ }
+
+ rd->readjust = (rd->readjust + 1) & 15;
+
+ return sliced - sliced_begin;
+}
+
+/**
+ * $param rd Pointer to vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ *
+ * Resets a vbi3_raw_decoder object, removing all services added
+ * with vbi3_raw_decoder_add_services().
+ */
+void
+vbi3_raw_decoder_reset (vbi3_raw_decoder * rd)
+{
+ assert (NULL != rd);
+
+ if (rd->pattern) {
+ vbi_free (rd->pattern);
+ rd->pattern = NULL;
+ }
+
+ rd->services = 0;
+ rd->n_jobs = 0;
+
+ rd->readjust = 1;
+
+ CLEAR (rd->jobs);
+}
+
+static void
+remove_job_from_pattern (vbi3_raw_decoder * rd, int job_num)
+{
+ int8_t *pattern;
+ unsigned int scan_lines;
+
+ job_num += 1; /* index into rd->jobs, 0 means no job */
+
+ pattern = rd->pattern;
+ scan_lines = rd->sampling.count[0] + rd->sampling.count[1];
+
+ /* For each scan line. */
+ while (scan_lines-- > 0) {
+ int8_t *dst;
+ int8_t *src;
+ int8_t *end;
+
+ dst = pattern;
+ end = pattern + _VBI3_RAW_DECODER_MAX_WAYS;
+
+ /* Remove jobs with job_num, fill up pattern with 0.
+ Jobs above job_num move down in rd->jobs. */
+ for (src = dst; src < end; ++src) {
+ int8_t num = *src;
+
+ if (num > job_num)
+ *dst++ = num - 1;
+ else if (num != job_num)
+ *dst++ = num;
+ }
+
+ while (dst < end)
+ *dst++ = 0;
+
+ pattern = end;
+ }
+}
+
+/**
+ * $param rd Pointer to vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ * $param services Set of data services.
+ *
+ * Removes one or more data services to be decoded from the
+ * vbi3_raw_decoder object.
+ *
+ * $return
+ * Set describing the remaining data services $a rd will decode.
+ */
+vbi_service_set
+ vbi3_raw_decoder_remove_services
+ (vbi3_raw_decoder * rd, vbi_service_set services) {
+ _vbi3_raw_decoder_job *job;
+ unsigned int job_num;
+
+ assert (NULL != rd);
+
+ job = rd->jobs;
+ job_num = 0;
+
+ while (job_num < rd->n_jobs) {
+ if (job->id & services) {
+ if (rd->pattern)
+ remove_job_from_pattern (rd, job_num);
+
+ memmove (job, job + 1, (rd->n_jobs - job_num - 1) * sizeof (*job));
+
+ --rd->n_jobs;
+
+ CLEAR (rd->jobs[rd->n_jobs]);
+ } else {
+ ++job_num;
+ }
+ }
+
+ rd->services &= ~services;
+
+ return rd->services;
+}
+
+static vbi_bool
+add_job_to_pattern (vbi3_raw_decoder * rd,
+ int job_num, unsigned int *start, unsigned int *count)
+{
+ int8_t *pattern_end;
+ unsigned int scan_lines;
+ unsigned int field;
+
+ job_num += 1; /* index into rd->jobs, 0 means no job */
+
+ scan_lines = rd->sampling.count[0]
+ + rd->sampling.count[1];
+
+ pattern_end = rd->pattern + scan_lines * _VBI3_RAW_DECODER_MAX_WAYS;
+
+ for (field = 0; field < 2; ++field) {
+ int8_t *pattern;
+ unsigned int i;
+
+ pattern = rd->pattern + start[field] * _VBI3_RAW_DECODER_MAX_WAYS;
+
+ /* For each line where we may find the data. */
+ for (i = 0; i < count[field]; ++i) {
+ unsigned int free;
+ int8_t *dst;
+ int8_t *src;
+ int8_t *end;
+
+ assert (pattern < pattern_end);
+
+ dst = pattern;
+ end = pattern + _VBI3_RAW_DECODER_MAX_WAYS;
+
+ free = 0;
+
+ for (src = dst; src < end; ++src) {
+ int8_t num = *src;
+
+ if (num <= 0) {
+ ++free;
+ continue;
+ } else {
+ free += (num == job_num);
+ *dst++ = num;
+ }
+ }
+
+ while (dst < end)
+ *dst++ = 0;
+
+ if (free <= 1) /* reserve a NULL way */
+ return FALSE;
+
+ pattern = end;
+ }
+ }
+
+ for (field = 0; field < 2; ++field) {
+ int8_t *pattern;
+ unsigned int i;
+
+ pattern = rd->pattern + start[field] * _VBI3_RAW_DECODER_MAX_WAYS;
+
+ /* For each line where we may find the data. */
+ for (i = 0; i < count[field]; ++i) {
+ unsigned int way;
+
+ for (way = 0; pattern[way] > 0; ++way)
+ if (pattern[way] == job_num)
+ break;
+
+ pattern[way] = job_num;
+ pattern[_VBI3_RAW_DECODER_MAX_WAYS - 1] = -128;
+
+ pattern += _VBI3_RAW_DECODER_MAX_WAYS;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+lines_containing_data (unsigned int start[2],
+ unsigned int count[2],
+ const vbi_sampling_par * sp, const _vbi_service_par * par)
+{
+ unsigned int field;
+
+ start[0] = 0;
+ start[1] = sp->count[0];
+
+ count[0] = sp->count[0];
+ count[1] = sp->count[1];
+
+ if (!sp->synchronous) {
+ /* XXX Scanning all lines isn't always necessary. */
+ return;
+ }
+
+ for (field = 0; field < 2; ++field) {
+ unsigned int first;
+ unsigned int last;
+
+ if (0 == par->first[field]
+ || 0 == par->last[field]) {
+ /* No data on this field. */
+ count[field] = 0;
+ continue;
+ }
+
+ first = sp->start[field];
+ last = first + sp->count[field] - 1;
+
+ if (first > 0 && sp->count[field] > 0) {
+ assert (par->first[field] <= par->last[field]);
+
+ if ((unsigned int) par->first[field] > last
+ || (unsigned int) par->last[field] < first)
+ continue;
+
+ first = MAX (first, (unsigned int) par->first[field]);
+ last = MIN ((unsigned int) par->last[field], last);
+
+ start[field] += first - sp->start[field];
+ count[field] = last + 1 - first;
+ }
+ }
+}
+
+/**
+ * $param rd Pointer to vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ * $param services Set of data services.
+ * $param strict A value of 0, 1 or 2 requests loose, reliable or strict
+ * matching of sampling parameters. For example if the data service
+ * requires knowledge of line numbers, $c 0 will always accept the
+ * service (which may work if the scan lines are populated in a
+ * non-confusing way) but $c 1 or $c 2 will not. If the data service
+ * might use more lines than are sampled, $c 1 will accept but $c 2
+ * will not. If unsure, set to $c 1.
+ *
+ * Adds one or more data services to be decoded. Currently the libzvbi
+ * raw vbi decoder can decode up to eight data services in parallel.
+ *
+ * $return
+ * Set describing the data services $a rd will decode. The function
+ * eliminates services which cannot be decoded with the current
+ * sampling parameters, or when they exceed the decoder capacity.
+ */
+/* Attn: strict must be int for compatibility with libzvbi 0.2 (-1 == 0) */
+vbi_service_set
+vbi3_raw_decoder_add_services (vbi3_raw_decoder * rd,
+ vbi_service_set services, int strict)
+{
+ const _vbi_service_par *par;
+ double min_offset;
+
+ assert (NULL != rd);
+
+ services &= ~(VBI_SLICED_VBI_525 | VBI_SLICED_VBI_625);
+
+ if (rd->services & services) {
+ info (&rd->log,
+ "Already decoding services 0x%08x.", rd->services & services);
+ services &= ~rd->services;
+ }
+
+ if (0 == services) {
+ info (&rd->log, "No services to add.");
+ return rd->services;
+ }
+
+ if (!rd->pattern) {
+ unsigned int scan_lines;
+ unsigned int scan_ways;
+ unsigned int size;
+
+ scan_lines = rd->sampling.count[0] + rd->sampling.count[1];
+ scan_ways = scan_lines * _VBI3_RAW_DECODER_MAX_WAYS;
+
+ size = scan_ways * sizeof (rd->pattern[0]);
+ rd->pattern = (int8_t *) vbi_malloc (size);
+ if (NULL == rd->pattern) {
+ error (&rd->log, "Out of memory.");
+ return rd->services;
+ }
+
+ memset (rd->pattern, 0, scan_ways * sizeof (rd->pattern[0]));
+ }
+
+ if (525 == rd->sampling.scanning) {
+ min_offset = 7.9e-6;
+ } else {
+ min_offset = 8.0e-6;
+ }
+
+ for (par = _vbi_service_table; par->id; ++par) {
+ vbi_sampling_par *sp;
+ _vbi3_raw_decoder_job *job;
+ unsigned int start[2];
+ unsigned int count[2];
+ unsigned int sample_offset;
+ unsigned int samples_per_line;
+ unsigned int cri_end;
+ unsigned int j;
+
+ if (0 == (par->id & services))
+ continue;
+
+ job = rd->jobs;
+
+ /* Some jobs can be merged, otherwise we add a new job. */
+ for (j = 0; j < rd->n_jobs; ++j) {
+ unsigned int id = job->id | par->id;
+
+ /* Level 1.0 and 2.5 */
+ if (0 == (id & ~VBI_SLICED_TELETEXT_B)
+ /* Field 1 and 2 */
+ || 0 == (id & ~VBI_SLICED_CAPTION_525)
+ || 0 == (id & ~VBI_SLICED_CAPTION_625)
+ || 0 == (id & ~(VBI_SLICED_VPS | VBI_SLICED_VPS_F2)))
+ break;
+
+ ++job;
+ }
+
+ if (j >= _VBI3_RAW_DECODER_MAX_JOBS) {
+ error (&rd->log,
+ "Set 0x%08x exceeds number of "
+ "simultaneously decodable "
+ "services (%u).", services, _VBI3_RAW_DECODER_MAX_WAYS);
+ break;
+ } else if (j >= rd->n_jobs) {
+ job->id = 0;
+ }
+
+
+ sp = &rd->sampling;
+
+ if (!_vbi_sampling_par_check_services_log (sp, par->id, strict, &rd->log))
+ continue;
+
+
+ sample_offset = 0;
+
+ /* Skip color burst. */
+ /* Offsets aren't that reliable, sigh. */
+ if (0 && sp->offset > 0 && strict > 0) {
+ double offset;
+
+ offset = sp->offset / (double) sp->sampling_rate;
+ if (offset < min_offset)
+ sample_offset = (int) (min_offset * sp->sampling_rate);
+ }
+
+ if (VBI_SLICED_WSS_625 & par->id) {
+ /* TODO: WSS 625 occupies only first half of line,
+ we can abort earlier. */
+ cri_end = ~0;
+ } else {
+ cri_end = ~0;
+ }
+
+ samples_per_line = sp->bytes_per_line
+ / VBI_PIXFMT_BPP (sp->sp_sample_format);
+
+ if (!_vbi3_bit_slicer_init (&job->slicer)) {
+ assert (!"bit_slicer_init");
+ }
+
+ if (!vbi3_bit_slicer_set_params
+ (&job->slicer,
+ sp->sp_sample_format,
+ sp->sampling_rate,
+ sample_offset,
+ samples_per_line,
+ par->cri_frc >> par->frc_bits,
+ par->cri_frc_mask >> par->frc_bits,
+ par->cri_bits,
+ par->cri_rate,
+ cri_end,
+ (par->cri_frc & ((1U << par->frc_bits) - 1)),
+ par->frc_bits, par->payload, par->bit_rate, par->modulation)) {
+ assert (!"bit_slicer_set_params");
+ }
+
+ vbi3_bit_slicer_set_log_fn (&job->slicer,
+ rd->log.mask, rd->log.fn, rd->log.user_data);
+
+ lines_containing_data (start, count, sp, par);
+
+ if (!add_job_to_pattern (rd, job - rd->jobs, start, count)) {
+ error (&rd->log,
+ "Out of decoder pattern space for "
+ "service 0x%08x (%s).", par->id, par->label);
+ continue;
+ }
+
+ job->id |= par->id;
+
+ if (job >= rd->jobs + rd->n_jobs)
+ ++rd->n_jobs;
+
+ rd->services |= par->id;
+ }
+
+ return rd->services;
+}
+
+vbi_bool
+vbi3_raw_decoder_sampling_point (vbi3_raw_decoder * rd,
+ vbi3_bit_slicer_point * point, unsigned int row, unsigned int nth_bit)
+{
+ assert (NULL != rd);
+ assert (NULL != point);
+
+ if (row >= rd->n_sp_lines)
+ return FALSE;
+
+ if (nth_bit >= rd->sp_lines[row].n_points)
+ return FALSE;
+
+ *point = rd->sp_lines[row].points[nth_bit];
+
+ return TRUE;
+}
+
+vbi_bool
+vbi3_raw_decoder_debug (vbi3_raw_decoder * rd, vbi_bool enable)
+{
+#if 0 /* Set but unused */
+ _vbi3_raw_decoder_sp_line *sp_lines;
+#endif
+ unsigned int n_lines;
+ vbi_bool r;
+
+ assert (NULL != rd);
+
+#if 0 /* Set but unused */
+ sp_lines = NULL;
+#endif
+ r = TRUE;
+
+ rd->debug = ! !enable;
+
+ n_lines = 0;
+ if (enable) {
+ n_lines = rd->sampling.count[0] + rd->sampling.count[1];
+ }
+
+ switch (rd->sampling.sp_sample_format) {
+ case VBI_PIXFMT_YUV420:
+ break;
+
+ default:
+ /* Not implemented. */
+ n_lines = 0;
+ r = FALSE;
+ break;
+ }
+
+ if (rd->n_sp_lines == n_lines)
+ return r;
+
+ vbi_free (rd->sp_lines);
+ rd->sp_lines = NULL;
+ rd->n_sp_lines = 0;
+
+ if (n_lines > 0) {
+ rd->sp_lines = calloc (n_lines, sizeof (*rd->sp_lines));
+ if (NULL == rd->sp_lines)
+ return FALSE;
+
+ rd->n_sp_lines = n_lines;
+ }
+
+ return r;
+}
+
+vbi_service_set
+vbi3_raw_decoder_services (vbi3_raw_decoder * rd)
+{
+ assert (NULL != rd);
+
+ return rd->services;
+}
+
+/**
+ * $param rd Pointer to a vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ * $param sp New sampling parameters.
+ * $param strict See vbi3_raw_decoder_add_services().
+ *
+ * Changes the sampling parameters used by $a rd. This will
+ * remove all services which have been added with
+ * vbi3_raw_decoder_add_services() but cannot be decoded with
+ * the new sampling parameters.
+ *
+ * $return
+ * Set of data services $rd will be decode after the change.
+ * Can be zero if the sampling parameters are invalid or some
+ * other error occured.
+ */
+/* Attn: strict must be int for compatibility with libzvbi 0.2 (-1 == 0) */
+vbi_service_set
+ vbi3_raw_decoder_set_sampling_par
+ (vbi3_raw_decoder * rd, const vbi_sampling_par * sp, int strict) {
+ unsigned int services;
+
+ assert (NULL != rd);
+ assert (NULL != sp);
+
+ services = rd->services;
+
+ vbi3_raw_decoder_reset (rd);
+
+ if (!_vbi_sampling_par_valid_log (sp, &rd->log)) {
+ CLEAR (rd->sampling);
+ return 0;
+ }
+
+ rd->sampling = *sp;
+
+ /* Error ignored. */
+ vbi3_raw_decoder_debug (rd, rd->debug);
+
+ return vbi3_raw_decoder_add_services (rd, services, strict);
+}
+
+/**
+ * $param rd Pointer to a vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new().
+ * $param sp Sampling parameters will be stored here.
+ *
+ * Returns sampling parameters used by $a rd.
+ */
+void vbi3_raw_decoder_get_sampling_par
+ (const vbi3_raw_decoder * rd, vbi_sampling_par * sp)
+{
+ assert (NULL != rd);
+ assert (NULL != sp);
+
+ *sp = rd->sampling;
+}
+
+void
+vbi3_raw_decoder_set_log_fn (vbi3_raw_decoder * rd,
+ vbi_log_fn * log_fn, void *user_data, vbi_log_mask mask)
+{
+ unsigned int i;
+
+ assert (NULL != rd);
+
+ if (NULL == log_fn)
+ mask = 0;
+
+ rd->log.mask = mask;
+ rd->log.fn = log_fn;
+ rd->log.user_data = user_data;
+
+ for (i = 0; i < _VBI3_RAW_DECODER_MAX_JOBS; ++i) {
+ vbi3_bit_slicer_set_log_fn (&rd->jobs[i].slicer, mask, log_fn, user_data);
+ }
+}
+
+/**
+ * @internal
+ *
+ * Free all resources associated with @a rd.
+ */
+void
+_vbi3_raw_decoder_destroy (vbi3_raw_decoder * rd)
+{
+ vbi3_raw_decoder_reset (rd);
+
+ vbi3_raw_decoder_debug (rd, FALSE);
+
+ /* Make unusable. */
+ CLEAR (*rd);
+}
+
+/**
+ * @internal
+ *
+ * See vbi3_raw_decoder_new().
+ */
+vbi_bool
+_vbi3_raw_decoder_init (vbi3_raw_decoder * rd, const vbi_sampling_par * sp)
+{
+ CLEAR (*rd);
+
+ vbi3_raw_decoder_reset (rd);
+
+ if (NULL != sp) {
+ if (!_vbi_sampling_par_valid_log (sp, &rd->log))
+ return FALSE;
+
+ rd->sampling = *sp;
+ }
+
+ return TRUE;
+}
+
+/**
+ * $param rd Pointer to a vbi3_raw_decoder object allocated with
+ * vbi3_raw_decoder_new(), can be NULL
+ *
+ * Deletes a vbi3_raw_decoder object.
+ */
+void
+vbi3_raw_decoder_delete (vbi3_raw_decoder * rd)
+{
+ if (NULL == rd)
+ return;
+
+ _vbi3_raw_decoder_destroy (rd);
+
+ vbi_free (rd);
+}
+
+/**
+ * $param sp VBI sampling parameters describing the raw VBI image
+ * to decode, can be $c NULL. If they are negotiatable you can determine
+ * suitable parameters with vbi_sampling_par_from_services(). You can
+ * change the sampling parameters later with
+ * vbi3_raw_decoder_set_sampling_par().
+ *
+ * Allocates a vbi3_raw_decoder object. To actually decode data
+ * services you must request the data with vbi3_raw_decoder_add_services().
+ *
+ * $returns
+ * NULL when out of memory or the sampling parameters are invalid,
+ * Otherwise a pointer to an opaque vbi3_raw_decoder object which must
+ * be deleted with vbi3_raw_decoder_delete() when done.
+ */
+vbi3_raw_decoder *
+vbi3_raw_decoder_new (const vbi_sampling_par * sp)
+{
+ vbi3_raw_decoder *rd;
+
+ rd = vbi_malloc (sizeof (*rd));
+ if (NULL == rd) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (!_vbi3_raw_decoder_init (rd, sp)) {
+ vbi_free (rd);
+ rd = NULL;
+ }
+
+ return rd;
+}
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Raw VBI decoder
+ *
+ * Copyright (C) 2000-2004 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: raw_decoder.h,v 1.12 2008-02-19 00:35:21 mschimek Exp $ */
+
+#ifndef __ZVBI_RAW_DECODER_H__
+#define __ZVBI_RAW_DECODER_H__
+
+#include <stdio.h>
+
+#include "decoder.h"
+#include "sampling_par.h"
+#include "bit_slicer.h"
+
+VBI_BEGIN_DECLS
+
+/*
+ * $ingroup RawDecoder
+ * $brief Raw VBI decoder.
+ *
+ * The contents of this structure are private.
+ * Call vbi3_raw_decoder_new() to allocate a raw VBI decoder.
+ */
+typedef struct _vbi3_raw_decoder vbi3_raw_decoder;
+
+/*
+ * $addtogroup RawDecoder
+ * ${
+ */
+extern vbi_bool
+vbi3_raw_decoder_sampling_point (vbi3_raw_decoder * rd,
+ vbi3_bit_slicer_point *point,
+ unsigned int row,
+ unsigned int nth_bit);
+extern unsigned int
+vbi3_raw_decoder_decode (vbi3_raw_decoder * rd,
+ vbi_sliced * sliced,
+ unsigned int sliced_lines,
+ const uint8_t * raw);
+extern void
+vbi3_raw_decoder_reset (vbi3_raw_decoder * rd);
+extern vbi_service_set
+vbi3_raw_decoder_services (vbi3_raw_decoder * rd);
+extern vbi_service_set
+vbi3_raw_decoder_remove_services
+ (vbi3_raw_decoder * rd,
+ vbi_service_set services);
+extern vbi_service_set
+vbi3_raw_decoder_add_services (vbi3_raw_decoder * rd,
+ vbi_service_set services,
+ int strict);
+extern vbi_bool
+vbi3_raw_decoder_debug (vbi3_raw_decoder * rd,
+ vbi_bool enable);
+extern vbi_service_set
+vbi3_raw_decoder_set_sampling_par
+ (vbi3_raw_decoder * rd,
+ const vbi_sampling_par *sp,
+ int strict);
+extern void
+vbi3_raw_decoder_get_sampling_par
+ (const vbi3_raw_decoder *rd,
+ vbi_sampling_par * sp);
+extern void
+vbi3_raw_decoder_set_log_fn (vbi3_raw_decoder * rd,
+ vbi_log_fn * log_fn,
+ void * user_data,
+ vbi_log_mask mask);
+extern void
+vbi3_raw_decoder_delete (vbi3_raw_decoder * rd);
+extern vbi3_raw_decoder *
+vbi3_raw_decoder_new (const vbi_sampling_par *sp);
+
+/* $} */
+
+/* Private */
+
+/** @internal */
+#define _VBI3_RAW_DECODER_MAX_JOBS 8
+/** @internal */
+#define _VBI3_RAW_DECODER_MAX_WAYS 8
+
+/** @internal */
+typedef struct {
+ vbi_service_set id;
+ vbi3_bit_slicer slicer;
+} _vbi3_raw_decoder_job;
+
+/** @internal */
+typedef struct {
+ vbi3_bit_slicer_point points[512];
+ unsigned int n_points;
+} _vbi3_raw_decoder_sp_line;
+
+/**
+ * @internal
+ * Don't dereference pointers to this structure.
+ * I guarantee it will change.
+ */
+struct _vbi3_raw_decoder {
+ vbi_sampling_par sampling;
+
+ vbi_service_set services;
+
+ _vbi_log_hook log;
+ vbi_bool debug;
+
+ unsigned int n_jobs;
+ unsigned int n_sp_lines;
+ int readjust;
+ int8_t * pattern; /* n scan lines * MAX_WAYS */
+ _vbi3_raw_decoder_job jobs[_VBI3_RAW_DECODER_MAX_JOBS];
+ _vbi3_raw_decoder_sp_line *sp_lines;
+};
+
+/** @internal */
+typedef enum {
+ /** Requires field line numbers. */
+ _VBI_SP_LINE_NUM = (1 << 0),
+ /** Requires field numbers. */
+ _VBI_SP_FIELD_NUM = (1 << 1),
+} _vbi_service_par_flag;
+
+typedef struct _vbi_service_par _vbi_service_par;
+
+/** @internal */
+struct _vbi_service_par {
+ vbi_service_set id;
+ const char * label;
+
+ /**
+ * Video standard
+ * - 525 lines, FV = 59.94 Hz, FH = 15734 Hz
+ * - 625 lines, FV = 50 Hz, FH = 15625 Hz
+ */
+ vbi_videostd_set videostd_set;
+
+ /**
+ * Most scan lines used by the data service, first and last
+ * line of first and second field. ITU-R numbering scheme.
+ * Zero if no data from this field, requires field sync.
+ */
+ unsigned int first[2];
+ unsigned int last[2];
+
+ /**
+ * Leading edge hsync to leading edge first CRI one bit,
+ * half amplitude points, in nanoseconds.
+ */
+ unsigned int offset;
+
+ unsigned int cri_rate; /**< Hz */
+ unsigned int bit_rate; /**< Hz */
+
+ /** Clock Run In and FRaming Code, LSB last txed bit of FRC. */
+ unsigned int cri_frc;
+
+ /** CRI and FRC bits significant for identification. */
+ unsigned int cri_frc_mask;
+
+ /**
+ * Number of significat cri_bits (at cri_rate),
+ * frc_bits (at bit_rate).
+ */
+ unsigned int cri_bits;
+ unsigned int frc_bits;
+
+ unsigned int payload; /**< bits */
+ vbi_modulation modulation;
+
+ _vbi_service_par_flag flags;
+};
+
+extern const _vbi_service_par _vbi_service_table [];
+
+extern void
+_vbi3_raw_decoder_dump (const vbi3_raw_decoder *rd,
+ FILE * fp);
+extern void
+_vbi3_raw_decoder_destroy (vbi3_raw_decoder * rd);
+extern vbi_bool
+_vbi3_raw_decoder_init (vbi3_raw_decoder * rd,
+ const vbi_sampling_par *sp);
+
+VBI_END_DECLS
+
+#endif /* __ZVBI_RAW_DECODER_H__ */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Raw VBI sampling parameters
+ *
+ * Copyright (C) 2000-2004 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: sampling_par.c,v 1.12 2013-08-28 14:45:00 mschimek Exp $ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+
+#include "misc.h"
+#include "raw_decoder.h"
+#include "sampling_par.h"
+#include "sliced.h"
+
+# define vbi_pixfmt_bytes_per_pixel VBI_PIXFMT_BPP
+# define sp_sample_format sampling_format
+
+/**
+ * @addtogroup Sampling Raw VBI sampling
+ * @ingroup Raw
+ * @brief Raw VBI data sampling interface.
+ */
+
+/**
+ * @internal
+ * Compatibility.
+ */
+vbi_videostd_set
+_vbi_videostd_set_from_scanning (int scanning)
+{
+ switch (scanning) {
+ case 525:
+ return VBI_VIDEOSTD_SET_525_60;
+
+ case 625:
+ return VBI_VIDEOSTD_SET_625_50;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+_vbi_inline vbi_bool
+range_check (unsigned int start,
+ unsigned int count, unsigned int min, unsigned int max)
+{
+ /* Check bounds and overflow. */
+ return (start >= min && (start + count) <= max && (start + count) >= start);
+}
+
+/**
+ * @internal
+ * @param sp Sampling parameters to verify.
+ *
+ * @return
+ * TRUE if the sampling parameters are valid (as far as we can tell).
+ */
+vbi_bool
+_vbi_sampling_par_valid_log (const vbi_sampling_par * sp, _vbi_log_hook * log)
+{
+ vbi_videostd_set videostd_set;
+ unsigned int bpp;
+
+ assert (NULL != sp);
+
+ switch (sp->sp_sample_format) {
+ case VBI_PIXFMT_YUV420:
+ /* This conflicts with the ivtv driver, which returns an
+ odd number of bytes per line. The driver format is
+ _GREY but libzvbi 0.2 has no VBI_PIXFMT_Y8. */
+ break;
+
+ default:
+ bpp = vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format);
+ if (0 != (sp->bytes_per_line % bpp))
+ goto bad_samples;
+ break;
+ }
+
+ if (0 == sp->bytes_per_line)
+ goto no_samples;
+
+ if (0 == sp->count[0]
+ && 0 == sp->count[1])
+ goto bad_range;
+
+ videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
+
+ if (VBI_VIDEOSTD_SET_525_60 & videostd_set) {
+ if (VBI_VIDEOSTD_SET_625_50 & videostd_set)
+ goto ambiguous;
+
+ if (0 != sp->start[0]
+ && !range_check (sp->start[0], sp->count[0], 1, 262))
+ goto bad_range;
+
+ if (0 != sp->start[1]
+ && !range_check (sp->start[1], sp->count[1], 263, 525))
+ goto bad_range;
+ } else if (VBI_VIDEOSTD_SET_625_50 & videostd_set) {
+ if (0 != sp->start[0]
+ && !range_check (sp->start[0], sp->count[0], 1, 311))
+ goto bad_range;
+
+ if (0 != sp->start[1]
+ && !range_check (sp->start[1], sp->count[1], 312, 625))
+ goto bad_range;
+ } else {
+ ambiguous:
+ info (log, "Ambiguous videostd_set 0x%lx.", (unsigned long) videostd_set);
+ return FALSE;
+ }
+
+ if (sp->interlaced && (sp->count[0] != sp->count[1]
+ || 0 == sp->count[0])) {
+ info (log,
+ "Line counts %u, %u must be equal and "
+ "non-zero when raw VBI data is interlaced.",
+ sp->count[0], sp->count[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+
+no_samples:
+ info (log, "samples_per_line is zero.");
+ return FALSE;
+
+
+bad_samples:
+ info (log,
+ "bytes_per_line value %u is no multiple of "
+ "the sample size %u.",
+ sp->bytes_per_line, vbi_pixfmt_bytes_per_pixel (sp->sp_sample_format));
+ return FALSE;
+
+bad_range:
+ info (log,
+ "Invalid VBI scan range %u-%u (%u lines), "
+ "%u-%u (%u lines).",
+ sp->start[0], sp->start[0] + sp->count[0] - 1,
+ sp->count[0],
+ sp->start[1], sp->start[1] + sp->count[1] - 1, sp->count[1]);
+ return FALSE;
+}
+
+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)
+{
+ const unsigned int unknown = 0;
+ double signal;
+ unsigned int field;
+ unsigned int samples_per_line;
+ vbi_videostd_set videostd_set;
+
+ assert (NULL != sp);
+ assert (NULL != par);
+
+ videostd_set = _vbi_videostd_set_from_scanning (sp->scanning);
+ if (0 == (par->videostd_set & videostd_set)) {
+ info (log,
+ "Service 0x%08x (%s) requires "
+ "videostd_set 0x%lx, "
+ "have 0x%lx.",
+ par->id, par->label,
+ (unsigned long) par->videostd_set, (unsigned long) videostd_set);
+ return FALSE;
+ }
+
+ if (par->flags & _VBI_SP_LINE_NUM) {
+ if ((par->first[0] > 0 && unknown == (unsigned int) sp->start[0])
+ || (par->first[1] > 0 && unknown == (unsigned int) sp->start[1])) {
+ info (log,
+ "Service 0x%08x (%s) requires known "
+ "line numbers.", par->id, par->label);
+ return FALSE;
+ }
+ }
+
+ {
+ unsigned int rate;
+
+ rate = MAX (par->cri_rate, par->bit_rate);
+
+ switch (par->id) {
+ case VBI_SLICED_WSS_625:
+ /* Effective bit rate is just 1/3 max_rate,
+ so 1 * max_rate should suffice. */
+ break;
+
+ default:
+ rate = (rate * 3) >> 1;
+ break;
+ }
+
+ if (rate > (unsigned int) sp->sampling_rate) {
+ info (log,
+ "Sampling rate %f MHz too low "
+ "for service 0x%08x (%s).",
+ sp->sampling_rate / 1e6, par->id, par->label);
+ return FALSE;
+ }
+ }
+
+ signal = par->cri_bits / (double) par->cri_rate
+ + (par->frc_bits + par->payload) / (double) par->bit_rate;
+
+ samples_per_line = sp->bytes_per_line / VBI_PIXFMT_BPP (sp->sampling_format);
+
+ if (0 && sp->offset > 0 && strict > 0) {
+ double sampling_rate;
+ double offset;
+ double end;
+
+ sampling_rate = (double) sp->sampling_rate;
+
+ offset = sp->offset / sampling_rate;
+ end = (sp->offset + samples_per_line) / sampling_rate;
+
+ if (offset > (par->offset / 1e3 - 0.5e-6)) {
+ info (log,
+ "Sampling starts at 0H + %f us, too "
+ "late for service 0x%08x (%s) at "
+ "%f us.", offset * 1e6, par->id, par->label, par->offset / 1e3);
+ return FALSE;
+ }
+
+ if (end < (par->offset / 1e9 + signal + 0.5e-6)) {
+ info (log,
+ "Sampling ends too early at 0H + "
+ "%f us for service 0x%08x (%s) "
+ "which ends at %f us",
+ end * 1e6,
+ par->id, par->label, par->offset / 1e3 + signal * 1e6 + 0.5);
+ return FALSE;
+ }
+ } else {
+ double samples;
+
+ samples = samples_per_line / (double) sp->sampling_rate;
+
+ if (strict > 0)
+ samples -= 1e-6; /* headroom */
+
+ if (samples < signal) {
+ info (log,
+ "Service 0x%08x (%s) signal length "
+ "%f us exceeds %f us sampling length.",
+ par->id, par->label, signal * 1e6, samples * 1e6);
+ return FALSE;
+ }
+ }
+
+ if ((par->flags & _VBI_SP_FIELD_NUM)
+ && !sp->synchronous) {
+ info (log,
+ "Service 0x%08x (%s) requires "
+ "synchronous field order.", par->id, par->label);
+ return FALSE;
+ }
+
+ for (field = 0; field < 2; ++field) {
+ unsigned int start;
+ unsigned int end;
+
+ start = sp->start[field];
+ end = start + sp->count[field] - 1;
+
+ if (0 == par->first[field]
+ || 0 == par->last[field]) {
+ /* No data on this field. */
+ continue;
+ }
+
+ if (0 == sp->count[field]) {
+ info (log,
+ "Service 0x%08x (%s) requires "
+ "data from field %u", par->id, par->label, field + 1);
+ return FALSE;
+ }
+
+ /* (int) <= 0 for compatibility with libzvbi 0.2.x */
+ if ((int) strict <= 0 || 0 == sp->start[field])
+ continue;
+
+ if (1 == strict && par->first[field] > par->last[field]) {
+ /* May succeed if not all scanning lines
+ available for the service are actually used. */
+ continue;
+ }
+
+ if (start > par->first[field]
+ || end < par->last[field]) {
+ info (log,
+ "Service 0x%08x (%s) requires "
+ "lines %u-%u, have %u-%u.",
+ par->id, par->label, par->first[field], par->last[field], start, end);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * @internal
+ */
+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) {
+ const _vbi_service_par *par;
+ vbi_service_set rservices;
+
+ assert (NULL != sp);
+
+ rservices = 0;
+
+ for (par = _vbi_service_table; par->id; ++par) {
+ if (0 == (par->id & services))
+ continue;
+
+ if (_vbi_sampling_par_permit_service (sp, par, strict, log))
+ rservices |= par->id;
+ }
+
+ return rservices;
+}
+
+/**
+ * @internal
+ */
+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) {
+ const _vbi_service_par *par;
+ vbi_service_set rservices;
+ vbi_videostd_set videostd_set;
+ unsigned int rate;
+ unsigned int samples_per_line;
+
+ assert (NULL != sp);
+
+ videostd_set = 0;
+
+ if (0 != videostd_set_req) {
+ if (0 == (VBI_VIDEOSTD_SET_ALL & videostd_set_req)
+ || ((VBI_VIDEOSTD_SET_525_60 & videostd_set_req)
+ && (VBI_VIDEOSTD_SET_625_50 & videostd_set_req))) {
+ warning (log,
+ "Ambiguous videostd_set 0x%lx.", (unsigned long) videostd_set_req);
+ CLEAR (*sp);
+ return 0;
+ }
+
+ videostd_set = videostd_set_req;
+ }
+
+ samples_per_line = 0;
+ sp->sampling_rate = 27000000; /* ITU-R BT.601 */
+ sp->offset = (int) (64e-6 * sp->sampling_rate);
+ sp->start[0] = 30000;
+ sp->count[0] = 0;
+ sp->start[1] = 30000;
+ sp->count[1] = 0;
+ sp->interlaced = FALSE;
+ sp->synchronous = TRUE;
+
+ rservices = 0;
+ rate = 0;
+
+ for (par = _vbi_service_table; par->id; ++par) {
+#if 0 /* Set but unused */
+ double margin;
+#endif
+ double signal;
+ int offset;
+ unsigned int samples;
+ unsigned int i;
+
+ if (0 == (par->id & services))
+ continue;
+
+ if (0 == videostd_set_req) {
+ vbi_videostd_set set;
+
+ set = par->videostd_set | videostd_set;
+
+ if (0 == (set & ~VBI_VIDEOSTD_SET_525_60)
+ || 0 == (set & ~VBI_VIDEOSTD_SET_625_50))
+ videostd_set |= par->videostd_set;
+ }
+#if 0 /* Set but unused */
+ if (VBI_VIDEOSTD_SET_525_60 & videostd_set)
+ margin = 1.0e-6;
+ else
+ margin = 2.0e-6;
+#endif
+
+ if (0 == (par->videostd_set & videostd_set)) {
+ info (log,
+ "Service 0x%08x (%s) requires "
+ "videostd_set 0x%lx, "
+ "have 0x%lx.",
+ par->id, par->label,
+ (unsigned long) par->videostd_set, (unsigned long) videostd_set);
+ continue;
+ }
+
+ rate = MAX (rate, par->cri_rate);
+ rate = MAX (rate, par->bit_rate);
+
+ signal = par->cri_bits / (double) par->cri_rate
+ + ((par->frc_bits + par->payload) / (double) par->bit_rate);
+
+ offset = (int) ((par->offset / 1e9) * sp->sampling_rate);
+ samples = (int) ((signal + 1.0e-6) * sp->sampling_rate);
+
+ sp->offset = MIN (sp->offset, offset);
+
+ samples_per_line = MAX (samples_per_line + sp->offset,
+ samples + offset) - sp->offset;
+
+ for (i = 0; i < 2; ++i)
+ if (par->first[i] > 0 && par->last[i] > 0) {
+ sp->start[i] = MIN
+ ((unsigned int) sp->start[i], (unsigned int) par->first[i]);
+ sp->count[i] = MAX ((unsigned int) sp->start[i]
+ + sp->count[i], (unsigned int) par->last[i] + 1)
+ - sp->start[i];
+ }
+
+ rservices |= par->id;
+ }
+
+ if (0 == rservices) {
+ CLEAR (*sp);
+ return 0;
+ }
+
+ if (0 == sp->count[1]) {
+ sp->start[1] = 0;
+
+ if (0 == sp->count[0]) {
+ sp->start[0] = 0;
+ sp->offset = 0;
+ }
+ } else if (0 == sp->count[0]) {
+ sp->start[0] = 0;
+ }
+
+ sp->scanning = (videostd_set & VBI_VIDEOSTD_SET_525_60)
+ ? 525 : 625;
+ sp->sp_sample_format = VBI_PIXFMT_YUV420;
+
+ /* Note bpp is 1. */
+ sp->bytes_per_line = MAX (1440U, samples_per_line);
+
+ if (max_rate)
+ *max_rate = rate;
+
+ return rservices;
+}
+
+/**
+ * @param sp Sampling parameters to check against.
+ * @param services Set of data services.
+ * @param strict See description of vbi_raw_decoder_add_services().
+ *
+ * Check which of the given services can be decoded with the given
+ * sampling parameters at the given strictness level.
+ *
+ * @return
+ * Subset of @a services decodable with the given sampling parameters.
+ */
+vbi_service_set
+ vbi_sampling_par_check_services
+ (const vbi_sampling_par * sp,
+ vbi_service_set services, unsigned int strict) {
+ return _vbi_sampling_par_check_services_log (sp, services, strict,
+ /* log_hook */ NULL);
+}
+
+/**
+ * @param sp Sampling parameters calculated by this function
+ * will be stored here.
+ * @param max_rate If not NULL, the highest data bit rate in Hz of
+ * all services requested will be stored here. The sampling rate
+ * should be at least twice as high; @sp sampling_rate will
+ * be set to a more reasonable value of 27 MHz, which is twice
+ * the video sampling rate defined by ITU-R Rec. BT.601.
+ * @param videostd_set Create sampling parameters matching these
+ * video standards. When 0 determine video standard from requested
+ * services.
+ * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
+ * can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
+ * vbi scan lines in the calculated sampling parameters.
+ *
+ * Calculate the sampling parameters required to receive and decode the
+ * requested data @a services. The @a sp sampling_format will be
+ * @c VBI_PIXFMT_Y8, offset and bytes_per_line will be set to
+ * reasonable minimums. This function can be used to initialize hardware
+ * prior to creating a vbi_raw_decoder object.
+ *
+ * @return
+ * Subset of @a services covered by the calculated sampling parameters.
+ */
+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)
+{
+ return _vbi_sampling_par_from_services_log (sp, max_rate,
+ videostd_set, services,
+ /* log_hook */ NULL);
+}
+
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Raw VBI sampling parameters
+ *
+ * Copyright (C) 2000-2004 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: sampling_par.h,v 1.9 2008-02-24 14:17:06 mschimek Exp $ */
+
+#ifndef __SAMPLING_PAR_H__
+#define __SAMPLING_PAR_H__
+
+#include "decoder.h"
+
+VBI_BEGIN_DECLS
+
+/* Public */
+
+typedef vbi_raw_decoder vbi_sampling_par;
+
+#define VBI_VIDEOSTD_SET_EMPTY 0
+#define VBI_VIDEOSTD_SET_PAL_BG 1
+#define VBI_VIDEOSTD_SET_625_50 1
+#define VBI_VIDEOSTD_SET_525_60 2
+#define VBI_VIDEOSTD_SET_ALL 3
+typedef uint64_t vbi_videostd_set;
+
+/* Private */
+
+extern 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);
+extern vbi_service_set
+vbi_sampling_par_check_services
+ (const vbi_sampling_par *sp,
+ vbi_service_set services,
+ unsigned int strict)
+ _vbi_pure;
+
+extern vbi_videostd_set
+_vbi_videostd_set_from_scanning (int scanning);
+
+extern vbi_service_set
+_vbi_sampling_par_from_services_log
+ (vbi_sampling_par * sp,
+ unsigned int * max_rate,
+ vbi_videostd_set videostd_set,
+ vbi_service_set services,
+ _vbi_log_hook * log);
+extern 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)
+ _vbi_pure;
+extern vbi_bool
+_vbi_sampling_par_valid_log (const vbi_sampling_par *sp,
+ _vbi_log_hook * log)
+ _vbi_pure;
+
+VBI_END_DECLS
+
+#endif /* __SAMPLING_PAR_H__ */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/
--- /dev/null
+/*
+ * libzvbi -- Sliced VBI data
+ *
+ * Copyright (C) 2000, 2001 Michael H. Schimek
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: sliced.h,v 1.11 2008-02-24 14:17:02 mschimek Exp $ */
+
+#ifndef SLICED_H
+#define SLICED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public */
+
+#include <inttypes.h>
+
+/**
+ * @addtogroup Sliced Sliced VBI data
+ * @ingroup Raw
+ * @brief Definition of sliced VBI data.
+ *
+ * The output of the libzvbi raw VBI decoder, and input to the data
+ * service decoder, is VBI data in binary format as defined in this
+ * section. It is similar to the output of hardware VBI decoders
+ * and VBI data transmitted in digital TV streams.
+ */
+
+/**
+ * @name Data service symbols
+ * @ingroup Sliced
+ * @{
+ */
+
+/**
+ * @anchor VBI_SLICED_
+ * No data service, blank vbi_sliced structure.
+ */
+#define VBI_SLICED_NONE 0
+
+/**
+ * Unknown data service (vbi_dvb_demux).
+ * @since 0.2.10
+ */
+#define VBI_SLICED_UNKNOWN 0
+
+/**
+ * Antiope a.k.a. Teletext System A
+ *
+ * Reference: <a href="http://www.itu.ch">ITU-R BT.653
+ * "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 37 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_ANTIOPE 0x00002000
+/**
+ * Synonym of VBI_SLICED_ANTIOPE.
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_A 0x00002000
+
+#define VBI_SLICED_TELETEXT_B_L10_625 0x00000001
+#define VBI_SLICED_TELETEXT_B_L25_625 0x00000002
+/**
+ * Teletext System B for 625 line systems
+ *
+ * Note this is separated into Level 1.0 and Level 2.5+ since the latter
+ * permits occupation of scan line 6 which is frequently out of
+ * range of raw VBI capture drivers. Clients should request decoding of both,
+ * may then verify Level 2.5 is covered. vbi_sliced id can be
+ * VBI_SLICED_TELETEXT_B, _B_L10_625 or _B_L25_625 regardless of line number.
+ *
+ * Reference: <a href="http://www.etsi.org">EN 300 706
+ * "Enhanced Teletext specification"</a>, <a href="http://www.itu.ch">
+ * ITU-R BT.653 "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 42 of the 45 byte Teletext packet, that is
+ * without clock run-in and framing code, lsb first transmitted.
+ */
+#define VBI_SLICED_TELETEXT_B (VBI_SLICED_TELETEXT_B_L10_625 | \
+ VBI_SLICED_TELETEXT_B_L25_625)
+/**
+ * Synonym of VBI_SLICED_TELETEXT_B.
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_B_625 VBI_SLICED_TELETEXT_B
+
+/**
+ * Teletext System C for 625 line systems
+ *
+ * Reference: <a href="http://www.itu.ch">ITU-R BT.653
+ * "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 33 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_C_625 0x00004000
+
+/**
+ * Teletext System D for 625 line systems
+ *
+ * Reference: <a href="http://www.itu.ch">ITU-R BT.653
+ * "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 34 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_D_625 0x00008000
+
+/**
+ * Video Program System
+ *
+ * Reference: <a href="http://www.etsi.org">ETS 300 231
+ * "Specification of the domestic video Programme
+ * Delivery Control system (PDC)"</a>, <a href="http://www.irt.de">
+ * IRT 8R2 "Video-Programm-System (VPS)"</a>.
+ *
+ * vbi_sliced payload: Byte number 3 to 15 according to ETS 300 231
+ * Figure 9, lsb first transmitted.
+ */
+#define VBI_SLICED_VPS 0x00000004
+
+/**
+ * Pseudo-VPS signal transmitted on field 2
+ *
+ * vbi_sliced payload: 13 bytes.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_VPS_F2 0x00001000
+
+#define VBI_SLICED_CAPTION_625_F1 0x00000008
+#define VBI_SLICED_CAPTION_625_F2 0x00000010
+/**
+ * Closed Caption for 625 line systems
+ *
+ * Note this is split into field one and two services since for basic
+ * caption decoding only field one is required. vbi_sliced id can be
+ * VBI_SLICED_CAPTION_625, _625_F1 or _625_F2 regardless of line number.
+ *
+ * Reference: <a href="http://global.ihs.com">EIA 608
+ * "Recommended Practice for Line 21 Data Service"</a>.
+ *
+ * vbi_sliced payload: First and second byte including parity,
+ * lsb first transmitted.
+ */
+#define VBI_SLICED_CAPTION_625 (VBI_SLICED_CAPTION_625_F1 | \
+ VBI_SLICED_CAPTION_625_F2)
+
+/**
+ * Wide Screen Signalling for 625 line systems
+ *
+ * Reference: <a href="http://www.etsi.org">EN 300 294
+ * "625-line television Wide Screen Signalling (WSS)"</a>.
+ *
+ * vbi_sliced payload:
+ * <pre>
+ * Byte 0 1
+ * msb lsb msb lsb
+ * bit 7 6 5 4 3 2 1 0 x x 13 12 11 10 9 8<br></pre>
+ * according to EN 300 294, Table 1, lsb first transmitted.
+ */
+#define VBI_SLICED_WSS_625 0x00000400
+
+#define VBI_SLICED_CAPTION_525_F1 0x00000020
+#define VBI_SLICED_CAPTION_525_F2 0x00000040
+/**
+ * Closed Caption for 525 line systems (NTSC).
+ *
+ * Note this is split into field one and two services since for basic
+ * caption decoding only field one is required. vbi_sliced id can be
+ * VBI_SLICED_CAPTION_525, _525_F1 or _525_F2 regardless of line number.
+ *
+ * VBI_SLICED_CAPTION_525 also covers XDS (Extended Data Service),
+ * V-Chip data and ITV / WebTV data.
+ *
+ * Reference: <a href="http://global.ihs.com">EIA 608
+ * "Recommended Practice for Line 21 Data Service"</a>.
+ *
+ * vbi_sliced payload: First and second byte including parity,
+ * lsb first transmitted.
+ */
+#define VBI_SLICED_CAPTION_525 (VBI_SLICED_CAPTION_525_F1 | \
+ VBI_SLICED_CAPTION_525_F2)
+/**
+ * Closed Caption at double bit rate for 525 line systems.
+ *
+ * Reference: ?
+ *
+ * vbi_sliced payload: First to fourth byte including parity bit,
+ * lsb first transmitted.
+ */
+#define VBI_SLICED_2xCAPTION_525 0x00000080
+
+/**
+ * Teletext System B for 525 line systems
+ *
+ * Reference: <a href="http://www.itu.ch">ITU-R BT.653
+ * "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 34 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_B_525 0x00010000
+
+/**
+ * North American Basic Teletext Specification
+ * a.k.a. Teletext System C for 525 line systems
+ *
+ * Reference: <a href="http://global.ihs.com">EIA-516
+ * "North American Basic Teletext Specification (NABTS)"</a>,
+ * <a href="http://www.itu.ch">ITU-R BT.653 "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 33 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_NABTS 0x00000100
+
+/**
+ * Synonym of VBI_SLICED_NABTS.
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_C_525 0x00000100
+
+/**
+ * Misdefined.
+ *
+ * vbi_sliced payload: 34 bytes.
+ *
+ * @deprecated
+ * This service was misdefined.
+ * Use VBI_SLICED_TELETEXT_B_525 or VBI_SLICED_TELETEXT_D_525 in new code.
+ */
+#define VBI_SLICED_TELETEXT_BD_525 0x00000200
+
+/**
+ * Teletext System D for 525 line systems
+ *
+ * Reference: <a href="http://www.itu.ch">ITU-R BT.653
+ * "Teletext Systems"</a>
+ *
+ * vbi_sliced payload: Last 34 bytes, without clock run-in and
+ * framing code, lsb first transmitted.
+ *
+ * @since 0.2.10
+ */
+#define VBI_SLICED_TELETEXT_D_525 0x00020000
+
+/**
+ * Wide Screen Signalling for NTSC Japan
+ *
+ * Reference: <a href="http://www.jeita.or.jp">EIA-J CPR-1204</a>
+ *
+ * vbi_sliced payload:
+ * <pre>
+ * Byte 0 1 2
+ * msb lsb msb lsb msb lsb
+ * bit 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 x x x x 19 18 17 16
+ * </pre>
+ */
+
+#define VBI_SLICED_WSS_CPR1204 0x00000800
+
+/**
+ * No actual data service. This symbol is used to request capturing
+ * of all PAL/SECAM VBI data lines from the libzvbi driver interface,
+ * as opposed to just those lines used to transmit the requested
+ * data services.
+ */
+#define VBI_SLICED_VBI_625 0x20000000
+
+/**
+ * No actual data service. This symbol is used to request capturing
+ * of all NTSC VBI data lines from the libzvbi driver interface,
+ * as opposed to just those lines used to transmit the requested
+ * data services.
+ */
+#define VBI_SLICED_VBI_525 0x40000000
+
+/** @} */
+
+typedef unsigned int vbi_service_set;
+
+/**
+ * @ingroup Sliced
+ * @brief This structure holds one scan line of sliced vbi data.
+ *
+ * For example the contents of NTSC line 21, two bytes of Closed Caption
+ * data. Usually an array of vbi_sliced is used, covering all
+ * VBI lines of the two fields of a video frame.
+ */
+typedef struct {
+ /**
+ * A @ref VBI_SLICED_ symbol identifying the data service. Under cirumstances
+ * (see VBI_SLICED_TELETEXT_B) this can be a set of VBI_SLICED_ symbols.
+ */
+ uint32_t id;
+ /**
+ * Source line number according to the ITU-R line numbering scheme,
+ * a value of @c 0 if the exact line number is unknown. Note that some
+ * data services cannot be reliable decoded without line number.
+ *
+ * @image html zvbi_625.gif "ITU-R PAL/SECAM line numbering scheme"
+ * @image html zvbi_525.gif "ITU-R NTSC line numbering scheme"
+ */
+ uint32_t line;
+ /**
+ * The actual payload. See the documentation of @ref VBI_SLICED_ symbols
+ * for details.
+ */
+ uint8_t data[56];
+} vbi_sliced;
+
+/**
+ * @addtogroup Sliced
+ * @{
+ */
+extern const char *
+vbi_sliced_name (vbi_service_set service)
+ _vbi_const;
+extern unsigned int
+vbi_sliced_payload_bits (vbi_service_set service)
+ _vbi_const;
+/** @} */
+
+/* Private */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SLICED_H */
+
+/*
+Local variables:
+c-set-style: K&R
+c-basic-offset: 8
+End:
+*/