diff --git a/ext/closedcaption/Makefile.am b/ext/closedcaption/Makefile.am index 13185e7342..2941e857ca 100644 --- a/ext/closedcaption/Makefile.am +++ b/ext/closedcaption/Makefile.am @@ -1,6 +1,24 @@ 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 @@ -18,4 +36,5 @@ libgstclosedcaption_la_LIBADD = \ libgstclosedcaption_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) noinst_HEADERS = \ - gstccextractor.h + gstccextractor.h \ + $(zvbi_headers) diff --git a/ext/closedcaption/bcd.h b/ext/closedcaption/bcd.h new file mode 100644 index 0000000000..ad63bf430a --- /dev/null +++ b/ext/closedcaption/bcd.h @@ -0,0 +1,223 @@ +/* + * 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: + * + * + * + * + * + * + * + * + * + *
1Caption 1 + * "Primary synchronous caption service [English]"
2Caption 2 + * "Special non-synchronous data that is intended to + * augment information carried in the program"
3Caption 3 + * "Secondary synchronous caption service, usually + * second language [Spanish, French]"
4Caption 4 + * "Special non-synchronous data similar to Caption 2"
5Text 1 + * "First text service, data usually not program related"
6Text 2 + * "Second text service, additional data usually not program related + * [ITV data]"
7Text 3 + * "Additional text channel"
8Text 4 + * "Additional text channel"
+ */ +/* 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: +*/ diff --git a/ext/closedcaption/bit_slicer.c b/ext/closedcaption/bit_slicer.c new file mode 100644 index 0000000000..3bb870241b --- /dev/null +++ b/ext/closedcaption/bit_slicer.c @@ -0,0 +1,1017 @@ +/* + * 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: +*/ diff --git a/ext/closedcaption/bit_slicer.h b/ext/closedcaption/bit_slicer.h new file mode 100644 index 0000000000..a537f4f802 --- /dev/null +++ b/ext/closedcaption/bit_slicer.h @@ -0,0 +1,197 @@ +/* + * 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: +*/ diff --git a/ext/closedcaption/decoder.c b/ext/closedcaption/decoder.c new file mode 100644 index 0000000000..98933b1c85 --- /dev/null +++ b/ext/closedcaption/decoder.c @@ -0,0 +1,832 @@ +/* + * 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 + +#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 bits. 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 may 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: +*/ diff --git a/ext/closedcaption/decoder.h b/ext/closedcaption/decoder.h new file mode 100644 index 0000000000..f12147ded8 --- /dev/null +++ b/ext/closedcaption/decoder.h @@ -0,0 +1,415 @@ +/* + * 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 + +/* Bit slicer */ + +/** + * @ingroup Rawdec + * @brief Image format used as source to vbi_bit_slice() and vbi_raw_decode(). + * + * @htmlonly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SymbolByte 0Byte 1Byte 2Byte 3
Planar YUV 4:2:0 data.
VBI_PIXFMT_YUV420 + + + + + +
Y planeU planeV plane
+ + + + +
Y00Y01Y02Y03
Y10Y11Y12Y13
Y20Y21Y22Y23
Y30Y31Y32Y33
+ + +
Cb00Cb01
Cb10Cb11
+ + +
Cr00Cr01
Cr10Cr11
Packed YUV 4:2:2 data.
VBI_PIXFMT_YUYVY0CbY1Cr
VBI_PIXFMT_YVYUY0CrY1Cb
VBI_PIXFMT_UYVYCbY0CrY1
VBI_PIXFMT_VYUYCrY0CbY1
Packed 32 bit RGB data.
VBI_PIXFMT_RGBA32_LE VBI_PIXFMT_ARGB32_BEr7 ... r0g7 ... g0b7 ... b0a7 ... a0
VBI_PIXFMT_BGRA32_LE VBI_PIXFMT_ARGB32_BEb7 ... b0g7 ... g0r7 ... r0a7 ... a0
VBI_PIXFMT_ARGB32_LE VBI_PIXFMT_BGRA32_BEa7 ... a0r7 ... r0g7 ... g0b7 ... b0
VBI_PIXFMT_ABGR32_LE VBI_PIXFMT_RGBA32_BEa7 ... a0b7 ... b0g7 ... g0r7 ... r0
Packed 24 bit RGB data.
VBI_PIXFMT_RGBA24r7 ... r0g7 ... g0b7 ... b0 
VBI_PIXFMT_BGRA24b7 ... b0g7 ... g0r7 ... r0 
Packed 16 bit RGB data.
VBI_PIXFMT_RGB16_LEg2 g1 g0 r4 r3 r2 r1 r0b4 b3 b2 b1 b0 g5 g4 g3  
VBI_PIXFMT_BGR16_LEg2 g1 g0 b4 b3 b2 b1 b0r4 r3 r2 r1 r0 g5 g4 g3  
VBI_PIXFMT_RGB16_BEb4 b3 b2 b1 b0 g5 g4 g3g2 g1 g0 r4 r3 r2 r1 r0  
VBI_PIXFMT_BGR16_BEr4 r3 r2 r1 r0 g5 g4 g3g2 g1 g0 b4 b3 b2 b1 b0  
Packed 15 bit RGB data.
VBI_PIXFMT_RGBA15_LEg2 g1 g0 r4 r3 r2 r1 r0a0 b4 b3 b2 b1 b0 g4 g3  
VBI_PIXFMT_BGRA15_LEg2 g1 g0 b4 b3 b2 b1 b0a0 r4 r3 r2 r1 r0 g4 g3  
VBI_PIXFMT_ARGB15_LEg1 g0 r4 r3 r2 r1 r0 a0b4 b3 b2 b1 b0 g4 g3 g2  
VBI_PIXFMT_ABGR15_LEg1 g0 b4 b3 b2 b1 b0 a0r4 r3 r2 r1 r0 g4 g3 g2  
VBI_PIXFMT_RGBA15_BEa0 b4 b3 b2 b1 b0 g4 g3g2 g1 g0 r4 r3 r2 r1 r0  
VBI_PIXFMT_BGRA15_BEa0 r4 r3 r2 r1 r0 g4 g3g2 g1 g0 b4 b3 b2 b1 b0  
VBI_PIXFMT_ARGB15_BEb4 b3 b2 b1 b0 g4 g3 g2g1 g0 r4 r3 r2 r1 r0 a0  
VBI_PIXFMT_ABGR15_BEr4 r3 r2 r1 r0 g4 g3 g2g1 g0 b4 b3 b2 b1 b0 a0  
+@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: +*/ diff --git a/ext/closedcaption/macros.h b/ext/closedcaption/macros.h new file mode 100644 index 0000000000..2e9bdfb4f3 --- /dev/null +++ b/ext/closedcaption/macros.h @@ -0,0 +1,168 @@ +/* + * 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: +*/ diff --git a/ext/closedcaption/misc.h b/ext/closedcaption/misc.h new file mode 100644 index 0000000000..f978a51d76 --- /dev/null +++ b/ext/closedcaption/misc.h @@ -0,0 +1,525 @@ +/* + * 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 +#include +#include +#include +#include +#include /* (u)intXX_t */ +#include /* (s)size_t */ +#include /* DBL_MAX */ +#include /* (S)SIZE_MAX */ +#include +#include +#include + +#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: +*/ diff --git a/ext/closedcaption/raw_decoder.c b/ext/closedcaption/raw_decoder.c new file mode 100644 index 0000000000..0ff956a22f --- /dev/null +++ b/ext/closedcaption/raw_decoder.c @@ -0,0 +1,1279 @@ +/* + * 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 +#include +#include +#include + +#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: +*/ diff --git a/ext/closedcaption/raw_decoder.h b/ext/closedcaption/raw_decoder.h new file mode 100644 index 0000000000..8f7382c29e --- /dev/null +++ b/ext/closedcaption/raw_decoder.h @@ -0,0 +1,212 @@ +/* + * 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 + +#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: +*/ diff --git a/ext/closedcaption/sampling_par.c b/ext/closedcaption/sampling_par.c new file mode 100644 index 0000000000..b08c63a945 --- /dev/null +++ b/ext/closedcaption/sampling_par.c @@ -0,0 +1,551 @@ +/* + * 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 + +#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: +*/ diff --git a/ext/closedcaption/sampling_par.h b/ext/closedcaption/sampling_par.h new file mode 100644 index 0000000000..50c01b8e00 --- /dev/null +++ b/ext/closedcaption/sampling_par.h @@ -0,0 +1,87 @@ +/* + * 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: +*/ diff --git a/ext/closedcaption/sliced.h b/ext/closedcaption/sliced.h new file mode 100644 index 0000000000..1b209d4ca5 --- /dev/null +++ b/ext/closedcaption/sliced.h @@ -0,0 +1,367 @@ +/* + * 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 + +/** + * @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: ITU-R BT.653 + * "Teletext Systems" + * + * 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: EN 300 706 + * "Enhanced Teletext specification", + * ITU-R BT.653 "Teletext Systems" + * + * 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: ITU-R BT.653 + * "Teletext Systems" + * + * 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: ITU-R BT.653 + * "Teletext Systems" + * + * 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: ETS 300 231 + * "Specification of the domestic video Programme + * Delivery Control system (PDC)", + * IRT 8R2 "Video-Programm-System (VPS)". + * + * 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: EIA 608 + * "Recommended Practice for Line 21 Data Service". + * + * 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: EN 300 294 + * "625-line television Wide Screen Signalling (WSS)". + * + * vbi_sliced payload: + *
+ * Byte         0                  1
+ *       msb         lsb  msb             lsb
+ * bit   7 6 5 4 3 2 1 0  x x 13 12 11 10 9 8
+ * 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: EIA 608 + * "Recommended Practice for Line 21 Data Service". + * + * 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: ITU-R BT.653 + * "Teletext Systems" + * + * 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: EIA-516 + * "North American Basic Teletext Specification (NABTS)", + * ITU-R BT.653 "Teletext Systems" + * + * 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: ITU-R BT.653 + * "Teletext Systems" + * + * 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: EIA-J CPR-1204 + * + * vbi_sliced payload: + *
+ * 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
+ * 
+ */ + +#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: +*/