/*
 *  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; */

  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:
*/
