gstreamer/subprojects/gst-plugins-bad/ext/closedcaption/bit_slicer.c

1010 lines
28 KiB
C
Raw Normal View History

/*
* 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_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_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_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_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; */
warn (&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) {
warn (&bs->log,
"buffer_size %u < %u bits of payload.", buffer_size * 8, bs->payload);
return FALSE;
}
if (bs->total_bits > max_points) {
warn (&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) {
warn (&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) {
warn (&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) {
warn (&bs->log, "cri_rate %u > sampling_rate %u.", cri_rate, sampling_rate);
goto failure;
}
if (payload_rate > sampling_rate) {
warn (&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:
warn (&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))) {
warn (&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:
*/