/*
 *  libzvbi - Raw vbi decoder
 *
 *  Copyright (C) 2000, 2001, 2002 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: decoder.c,v 1.22 2006/05/31 03:55:52 mschimek Exp $ */

#include "site_def.h"

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <pthread.h>

#include "misc.h"
#include "decoder.h"
#include "raw_decoder.h"

/**
 * @addtogroup Rawdec Raw VBI decoder
 * @ingroup Raw
 * @brief Converting raw VBI samples to bits and bytes.
 *
 * The libzvbi already offers hardware interfaces to obtain sliced
 * VBI data for further processing. However if you want to write your own
 * interface or decode data services not covered by libzvbi you can use
 * these lower level functions.
 */

/*
 *  Bit Slicer
 */

#define OVERSAMPLING 4		/* 1, 2, 4, 8 */
#define THRESH_FRAC 9

/*
 * Note this is just a template. The code is inlined,
 * with bpp and endian being const.
 *
 * This function translates from the image format to
 * plain bytes, with linear interpolation of samples.
 * Could be further improved with a lowpass filter.
 */
static inline unsigned int
sample(uint8_t *raw, int offs, int bpp, int endian)
{
	unsigned char frac = offs;
	int raw0, raw1;

	switch (bpp) {
	case 14: /* 1:5:5:5 LE/BE */
		raw += (offs >> 8) * 2;
		raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07C0;
		raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07C0;
		return (raw1 - raw0) * frac + (raw0 << 8);

	case 15: /* 5:5:5:1 LE/BE */
		raw += (offs >> 8) * 2;
		raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x03E0;
		raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x03E0;
		return (raw1 - raw0) * frac + (raw0 << 8);

	case 16: /* 5:6:5 LE/BE */
		raw += (offs >> 8) * 2;
		raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & 0x07E0;
		raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & 0x07E0;
		return (raw1 - raw0) * frac + (raw0 << 8);

	default: /* 8 (intermediate bytes skipped by caller) */
		raw += (offs >> 8) * bpp;
		return (raw[bpp] - raw[0]) * frac + (raw[0] << 8);
	}
}

/*
 * Note this is just a template. The code is inlined,
 * with bpp being const.
 */
static inline vbi_bool
bit_slicer_tmpl(vbi_bit_slicer *d, uint8_t *raw,
		uint8_t *buf, int bpp, int endian)
{
	unsigned int i, j, k;
	unsigned int cl = 0, thresh0 = d->thresh, tr;
	unsigned int c = 0, t;
	unsigned char b, b1 = 0;
	int raw0, raw1, mask;

	raw += d->skip;

	if (bpp == 14)
		mask = 0x07C0;
	else if (bpp == 15)
		mask = 0x03E0;
	else if (bpp == 16)
		mask = 0x07E0;

	for (i = d->cri_bytes; i > 0; raw += (bpp >= 14 && bpp <= 16) ? 2 : bpp, i--) {
		if (bpp >= 14 && bpp <= 16) {
			raw0 = (raw[0 + endian] + raw[1 - endian] * 256) & mask;
			raw1 = (raw[2 + endian] + raw[3 - endian] * 256) & mask;
			tr = d->thresh >> THRESH_FRAC;
			d->thresh += ((raw0 - tr) * (int) ABS(raw1 - raw0)) >>
				((bpp == 15) ? 2 : 3);
			t = raw0 * OVERSAMPLING;
		} else {
			tr = d->thresh >> THRESH_FRAC;
			d->thresh += ((int) raw[0] - tr) * (int) ABS(raw[bpp] - raw[0]);
			t = raw[0] * OVERSAMPLING;
		}

		for (j = OVERSAMPLING; j > 0; j--) {
			b = ((t + (OVERSAMPLING / 2)) / OVERSAMPLING >= tr);

    			if (b ^ b1) {
				cl = d->oversampling_rate >> 1;
			} else {
				cl += d->cri_rate;

				if (cl >= (unsigned int) d->oversampling_rate) {
					cl -= d->oversampling_rate;

					c = c * 2 + b;

					if ((c & d->cri_mask) == d->cri) {
						i = d->phase_shift;
						tr *= 256;
						c = 0;

						for (j = d->frc_bits; j > 0; j--) {
							c = c * 2 + (sample(raw, i, bpp, endian) >= tr);
    							i += d->step;
						}

						if (c ^= d->frc)
							return FALSE;

						/* CRI/FRC found, now get the
						   payload and exit */
						
						switch (d->endian) {
						case 3:
							for (j = 0; j < (unsigned int) d->payload; j++) {
					    			c >>= 1;
								c += (sample(raw, i, bpp, endian) >= tr) << 7;
			    					i += d->step;

								if ((j & 7) == 7)
									*buf++ = c;
					    		}

							*buf = c >> ((8 - d->payload) & 7);
							break;

						case 2:
							for (j = 0; j < (unsigned int) d->payload; j++) {
								c = c * 2 + (sample(raw, i, bpp, endian) >= tr);
			    					i += d->step;

								if ((j & 7) == 7)
									*buf++ = c;
					    		}

							*buf = c & ((1 << (d->payload & 7)) - 1);
							break;

						case 1:
							for (j = d->payload; j > 0; j--) {
								for (k = 0; k < 8; k++) {
						    			c >>= 1;
									c += (sample(raw, i, bpp, endian) >= tr) << 7;
			    						i += d->step;
								}

								*buf++ = c;
					    		}

							break;

						case 0:
							for (j = d->payload; j > 0; j--) {
								for (k = 0; k < 8; k++) {
									c = c * 2 + (sample(raw, i, bpp, endian) >= tr);
			    						i += d->step;
								}

								*buf++ = c;
					    		}

							break;
						}

			    			return TRUE;
					}
				}
			}

			b1 = b;

			if (OVERSAMPLING > 1) {
				if (bpp >= 14 && bpp <= 16) {
					t += raw1;
					t -= raw0;
				} else {
					t += raw[bpp];
					t -= raw[0];
				}
			}
		}
	}

	d->thresh = thresh0;

	return FALSE;
}

static vbi_bool
bit_slicer_1(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 1, 0);
}

static vbi_bool
bit_slicer_2(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 2, 0);
}

static vbi_bool
bit_slicer_3(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 3, 0);
}

static vbi_bool
bit_slicer_4(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 4, 0);
}

static vbi_bool
bit_slicer_1555_le(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 14, 0);
}

static vbi_bool
bit_slicer_5551_le(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 15, 0);
}

static vbi_bool
bit_slicer_565_le(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 16, 0);
}

static vbi_bool
bit_slicer_1555_be(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 14, 1);
}

static vbi_bool
bit_slicer_5551_be(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 15, 1);
}

static vbi_bool
bit_slicer_565_be(vbi_bit_slicer *d, uint8_t *raw, uint8_t *buf)
{
	return bit_slicer_tmpl(d, raw, buf, 16, 1);
}

/**
 * @param slicer Pointer to vbi_bit_slicer object to be initialized. 
 * @param raw_samples Number of samples or pixels in one raw vbi line
 *   later passed to vbi_bit_slice(). This limits the number of
 *   bytes read from the sample buffer.
 * @param sampling_rate Raw vbi sampling rate in Hz, that is the number of
 *   samples or pixels sampled per second by the hardware. 
 * @param cri_rate The Clock Run In is a NRZ modulated
 *   sequence of '0' and '1' bits prepending most data transmissions to
 *   synchronize data acquisition circuits. This parameter gives the CRI bit
 *   rate in Hz, that is the number of CRI bits transmitted per second.
 * @param bit_rate The transmission bit rate of all data bits following the CRI
 *   in Hz.
 * @param cri_frc The FRaming Code usually following the CRI is a bit sequence
 *   identifying the data service, and per libzvbi definition modulated
 *   and transmitted at the same bit rate as the payload (however nothing
 *   stops you from counting all nominal CRI and FRC bits as CRI).
 *   The bit slicer compares the bits in this word, lsb last transmitted,
 *   against the transmitted CRI and FRC. Decoding of payload starts
 *   with the next bit after a match.
 * @param cri_mask Of the CRI bits in @c cri_frc, only these bits are
 *   actually significant for a match. For instance it is wise
 *   not to rely on the very first CRI bits transmitted. Note this
 *   mask is not shifted left by @a frc_bits.
 * @param cri_bits 
 * @param frc_bits Number of CRI and FRC bits in @a cri_frc, respectively.
 *   Their sum is limited to 32.
 * @param payload Number of payload <em>bits</em>. Only this data
 *   will be stored in the vbi_bit_slice() output. If this number
 *   is no multiple of eight, the most significant bits of the
 *   last byte are undefined.
 * @param modulation Modulation of the vbi data, see vbi_modulation.
 * @param fmt Format of the raw data, see vbi_pixfmt.
 * 
 * Initializes vbi_bit_slicer object. Usually you will not use this
 * function but vbi_raw_decode(), the vbi image decoder which handles
 * all these details.
 */
void
vbi_bit_slicer_init(vbi_bit_slicer *slicer,
		    int raw_samples, int sampling_rate,
		    int cri_rate, int bit_rate,
		    unsigned int cri_frc, unsigned int cri_mask,
		    int cri_bits, int frc_bits, int payload,
		    vbi_modulation modulation, vbi_pixfmt fmt)
{
	unsigned int c_mask = (unsigned int)(-(cri_bits > 0)) >> (32 - cri_bits);
	unsigned int f_mask = (unsigned int)(-(frc_bits > 0)) >> (32 - frc_bits);
	int gsh = 0;

	slicer->func = bit_slicer_1;

	switch (fmt) {
	case VBI_PIXFMT_RGB24:
	case VBI_PIXFMT_BGR24:
	        slicer->func = bit_slicer_3;
		slicer->skip = 1;
		break;

	case VBI_PIXFMT_RGBA32_LE:
	case VBI_PIXFMT_BGRA32_LE:
		slicer->func = bit_slicer_4;
		slicer->skip = 1;
		break;

	case VBI_PIXFMT_RGBA32_BE:
	case VBI_PIXFMT_BGRA32_BE:
		slicer->func = bit_slicer_4;
		slicer->skip = 2;
		break;

	case VBI_PIXFMT_RGB16_LE:
	case VBI_PIXFMT_BGR16_LE:
		slicer->func = bit_slicer_565_le;
		gsh = 3; /* (green << 3) & 0x07E0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_RGBA15_LE:
	case VBI_PIXFMT_BGRA15_LE:
		slicer->func = bit_slicer_5551_le;
		gsh = 2; /* (green << 2) & 0x03E0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_ARGB15_LE:
	case VBI_PIXFMT_ABGR15_LE:
		slicer->func = bit_slicer_1555_le;
		gsh = 3; /* (green << 2) & 0x07C0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_RGB16_BE:
	case VBI_PIXFMT_BGR16_BE:
		slicer->func = bit_slicer_565_be;
		gsh = 3; /* (green << 3) & 0x07E0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_RGBA15_BE:
	case VBI_PIXFMT_BGRA15_BE:
		slicer->func = bit_slicer_5551_be;
		gsh = 2; /* (green << 2) & 0x03E0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_ARGB15_BE:
	case VBI_PIXFMT_ABGR15_BE:
		slicer->func = bit_slicer_1555_be;
		gsh = 3; /* (green << 2) & 0x07C0 */
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_YUV420:
		slicer->func = bit_slicer_1;
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_YUYV:
	case VBI_PIXFMT_YVYU:
		slicer->func = bit_slicer_2;
		slicer->skip = 0;
		break;

	case VBI_PIXFMT_UYVY:
	case VBI_PIXFMT_VYUY:
		slicer->func = bit_slicer_2;
		slicer->skip = 1;
		break;

	default:
		fprintf(stderr, "vbi_bit_slicer_init: unknown pixfmt %d\n", fmt);
		exit(EXIT_FAILURE);
	}

	slicer->cri_mask		= cri_mask & c_mask;
	slicer->cri		 	= (cri_frc >> frc_bits) & slicer->cri_mask;
	/* We stop searching for CRI/FRC when the payload
	   cannot possibly fit anymore. */
	slicer->cri_bytes		= raw_samples
		- ((long long) sampling_rate * (payload + frc_bits)) / bit_rate;
	slicer->cri_rate		= cri_rate;
	/* Raw vbi data is oversampled to account for low sampling rates. */
	slicer->oversampling_rate	= sampling_rate * OVERSAMPLING;
	/* 0/1 threshold */
	slicer->thresh			= 105 << (THRESH_FRAC + gsh);
	slicer->frc			= cri_frc & f_mask;
	slicer->frc_bits		= frc_bits;
	/* Payload bit distance in 1/256 raw samples. */
	slicer->step			= (int)(sampling_rate * 256.0 / bit_rate);

	if (payload & 7) {
		slicer->payload	= payload;
		slicer->endian	= 3;
	} else {
		slicer->payload	= payload >> 3;
		slicer->endian	= 1;
	}

	switch (modulation) {
	case VBI_MODULATION_NRZ_MSB:
		slicer->endian--;
	case VBI_MODULATION_NRZ_LSB:
		slicer->phase_shift = (int)
			(sampling_rate * 256.0 / cri_rate * .5
			 + sampling_rate * 256.0 / bit_rate * .5 + 128);
		break;

	case VBI_MODULATION_BIPHASE_MSB:
		slicer->endian--;
	case VBI_MODULATION_BIPHASE_LSB:
		/* Phase shift between the NRZ modulated CRI and the rest */
		slicer->phase_shift = (int)
			(sampling_rate * 256.0 / cri_rate * .5
			 + sampling_rate * 256.0 / bit_rate * .25 + 128);
		break;
	}
}

/**
 * @example examples/wss.c
 * WSS capture example.
 */

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param raw A raw vbi image as defined in the vbi_raw_decoder structure
 *   (rd->sampling_format, rd->bytes_per_line, rd->count[0] + rd->count[1]
 *    scan lines).
 * @param out Buffer to store the decoded vbi_sliced data. Since every
 *   vbi scan line may contain data, this must be an array of vbi_sliced
 *   with the same number of entries as scan lines in the raw image
 *   (rd->count[0] + rd->count[1]).
 * 
 * Decode a raw vbi image, consisting of several scan lines of raw vbi data,
 * into sliced vbi data. The output is sorted by line number.
 * 
 * Note this function attempts to learn which lines carry which data
 * service, or none, to speed up decoding. You should avoid using the same
 * vbi_raw_decoder structure for different sources.
 *
 * @return
 * The number of lines decoded, i. e. the number of vbi_sliced records
 * written.
 */
int
vbi_raw_decode			(vbi_raw_decoder *	rd,
				 uint8_t *		raw,
				 vbi_sliced *		out)
{
	vbi3_raw_decoder *rd3;
	unsigned int n_lines;

	assert (NULL != rd);
	assert (NULL != raw);
	assert (NULL != out);

	rd3 = (vbi3_raw_decoder *) rd->pattern;
	n_lines = rd->count[0] + rd->count[1];

	pthread_mutex_lock (&rd->mutex);

	{
		n_lines = vbi3_raw_decoder_decode (rd3, out, n_lines, raw);
	}

	pthread_mutex_unlock (&rd->mutex);

	return n_lines;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param start Array of start line indices for both fields
 * @param count Array of line counts for both fields
 * 
 * Grows or shrinks the internal state arrays for VBI geometry changes
 */
void
vbi_raw_decoder_resize		(vbi_raw_decoder *	rd,
				 int *			start,
				 unsigned int *		count)
{
	vbi_service_set service_set;
	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];

		service_set = vbi3_raw_decoder_set_sampling_par
			(rd3, (vbi_sampling_par *) rd, /* strict */ 0);
	}

	pthread_mutex_unlock (&rd->mutex);
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * 
 * Removes one or more data services to be decoded from the
 * vbi_raw_decoder structure. This function can be called at any
 * time and does not touch sampling parameters. 
 * 
 * @return 
 * Set of @ref VBI_SLICED_ symbols describing the remaining data
 * services that will be decoded.
 */
unsigned int
vbi_raw_decoder_remove_services	(vbi_raw_decoder *	rd,
				 unsigned int		services)
{
	vbi_service_set service_set;
	vbi3_raw_decoder *rd3;

	assert (NULL != rd);

	rd3 = (vbi3_raw_decoder *) rd->pattern;
	service_set = services;

	pthread_mutex_lock (&rd->mutex);

	{
		service_set = vbi3_raw_decoder_remove_services
			(rd3, service_set);
	}

	pthread_mutex_unlock (&rd->mutex);

	return service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * @param strict See description of vbi_raw_decoder_add_services()
 *
 * Check which of the given services can be decoded with current capture
 * parameters at a given strictness level.
 *
 * @return
 * Subset of services actually decodable.
 */
unsigned int
vbi_raw_decoder_check_services	(vbi_raw_decoder *	rd,
				 unsigned int		services,
				 int			strict)
{
	vbi_service_set service_set;

	assert (NULL != rd);

	service_set = services;

	pthread_mutex_lock (&rd->mutex);

	{
		service_set = vbi_sampling_par_check_services
			((vbi_sampling_par *) rd, service_set, strict);
	}

	pthread_mutex_unlock (&rd->mutex);

	return (unsigned int) service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of @ref VBI_SLICED_ symbols.
 * @param strict A value of 0, 1 or 2 requests loose, reliable or strict
 *  matching of sampling parameters. For example if the data service
 *  requires knowledge of line numbers while they are not known, @c 0
 *  will accept the service (which may work if the scan lines are
 *  populated in a non-confusing way) but @c 1 or @c 2 will not. If the
 *  data service <i>may</i> use more lines than are sampled, @c 1 will
 *  accept but @c 2 will not. If unsure, set to @c 1.
 * 
 * After you initialized the sampling parameters in @a rd (according to
 * the abilities of your raw vbi source), this function adds one or more
 * data services to be decoded. The libzvbi raw vbi decoder can decode up
 * to eight data services in parallel. You can call this function while
 * already decoding, it does not change sampling parameters and you must
 * not change them either after calling this.
 * 
 * @return
 * Set of @ref VBI_SLICED_ symbols describing the data services that actually
 * will be decoded. This excludes those services not decodable given
 * the sampling parameters in @a rd.
 */
unsigned int
vbi_raw_decoder_add_services	(vbi_raw_decoder *	rd,
				 unsigned int		services,
				 int			strict)
{
	vbi_service_set service_set;
	vbi3_raw_decoder *rd3;

	assert (NULL != rd);

	rd3 = (vbi3_raw_decoder *) rd->pattern;
	service_set = services;

	pthread_mutex_lock (&rd->mutex);

	{
		vbi3_raw_decoder_set_sampling_par
			(rd3, (vbi_sampling_par *) rd, strict);

		service_set = vbi3_raw_decoder_add_services
			(rd3, service_set, strict);
	}

	pthread_mutex_unlock (&rd->mutex);

	return service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * @param services Set of VBI_SLICED_ symbols. Here (and only here) you
 *   can add @c VBI_SLICED_VBI_625 or @c VBI_SLICED_VBI_525 to include all
 *   vbi scan lines in the calculated sampling parameters.
 * @param scanning When 525 accept only NTSC services, when 625
 *   only PAL/SECAM services. When scanning is 0, determine the scanning
 *   from the requested services, an ambiguous set will pick
 *   a 525 or 625 line system at random.
 * @param max_rate If given, the highest data bit rate in Hz of all
 *   services requested is stored here. (The sampling rate
 *   should be at least twice as high; rd->sampling_rate will
 *   be set to a more reasonable value of 27 MHz derived
 *   from ITU-R Rec. 601.)
 * 
 * Calculate the sampling parameters in @a rd required to receive and
 * decode the requested data @a services. rd->sampling_format will be
 * @c VBI_PIXFMT_YUV420, rd->bytes_per_line set accordingly to a
 * reasonable minimum. This function can be used to initialize hardware
 * prior to calling vbi_raw_decoder_add_service().
 * 
 * @return
 * Set of @ref VBI_SLICED_ symbols describing the data services covered
 * by the calculated sampling parameters. This excludes services the libzvbi
 * raw decoder cannot decode.
 */
unsigned int
vbi_raw_decoder_parameters	(vbi_raw_decoder *	rd,
				 unsigned int		services,
				 int			scanning,
				 int *			max_rate)
{
	vbi_videostd_set videostd_set;
	vbi_service_set service_set;

	switch (scanning) {
	case 525:
		videostd_set = VBI_VIDEOSTD_SET_525_60;
		break;

	case 625:
		videostd_set = VBI_VIDEOSTD_SET_625_50;
		break;

	default:
		videostd_set = 0;
		break;
	}

	service_set = services;
 
	pthread_mutex_lock (&rd->mutex);

	{
		service_set = vbi_sampling_par_from_services
			((vbi_sampling_par *) rd,
			 (unsigned int *) max_rate,
			 videostd_set, service_set);
	}

	pthread_mutex_unlock(&rd->mutex);

	return (unsigned int) service_set;
}

/**
 * @param rd Initialized vbi_raw_decoder structure.
 * 
 * Reset a vbi_raw_decoder structure. This removes
 * all previously added services to be decoded (if any)
 * but does not touch the sampling parameters. You are
 * free to change the sampling parameters after calling this.
 */
void
vbi_raw_decoder_reset		(vbi_raw_decoder *	rd)
{
	vbi3_raw_decoder *rd3;

	if (!rd)
		return; /* compatibility */

	assert (NULL != rd);

	rd3 = (vbi3_raw_decoder *) rd->pattern;

	pthread_mutex_lock (&rd->mutex);

	{
		vbi3_raw_decoder_reset (rd3);
	}

	pthread_mutex_unlock (&rd->mutex);
}

/**
 * @param rd Pointer to initialized vbi_raw_decoder
 *  structure, can be @c NULL.
 * 
 * Free all resources associated with @a rd.
 */
void
vbi_raw_decoder_destroy		(vbi_raw_decoder *	rd)
{
	vbi3_raw_decoder *rd3;

	assert (NULL != rd);

	rd3 = (vbi3_raw_decoder *) rd->pattern;

	vbi3_raw_decoder_delete (rd3);

	pthread_mutex_destroy (&rd->mutex);

	CLEAR (*rd);
}

/**
 * @param rd Pointer to a vbi_raw_decoder structure.
 * 
 * Initializes a vbi_raw_decoder structure.
 */
void
vbi_raw_decoder_init		(vbi_raw_decoder *	rd)
{
	vbi3_raw_decoder *rd3;

	assert (NULL != rd);

	CLEAR (*rd);

	pthread_mutex_init (&rd->mutex, NULL);

	rd3 = vbi3_raw_decoder_new (/* sampling_par */ NULL);
	assert (NULL != rd3);

	rd->pattern = (int8_t *) rd3;
}


syntax highlighted by Code2HTML, v. 0.9.1