summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/avcomp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/avcomp.c')
-rw-r--r--src/lib/util/avcomp.c840
1 files changed, 840 insertions, 0 deletions
diff --git a/src/lib/util/avcomp.c b/src/lib/util/avcomp.c
new file mode 100644
index 00000000000..d3144e01175
--- /dev/null
+++ b/src/lib/util/avcomp.c
@@ -0,0 +1,840 @@
+/*
+To do:
+* verify Cb,Y,Cr,Y ordering
+* swap the ordering(?)
+* add backchannel support for samples as well?
+*/
+/***************************************************************************
+
+ avcomp.c
+
+ Audio/video compression and decompression helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Each frame is compressed as a unit. The raw data is of the form:
+ (all multibyte values are stored in big-endian format)
+
+ 'chav' (4 bytes) - fixed header data to identify the format
+ metasize (1 byte) - size of metadata in bytes (max=255 bytes)
+ channels (1 byte) - number of audio channels
+ samples (2 bytes) - number of samples per audio stream
+ width (2 bytes) - width of video data
+ height (2 bytes) - height of video data (high bit set means interlaced)
+ <metadata> - as raw bytes
+ <audio stream 0> - as signed 16-bit samples
+ <audio stream 1> - as signed 16-bit samples
+ ...
+ <video data> - as a raw array of 8-bit YUY data in (Cb,Y,Cr,Y) order
+
+ When compressed, the data is stored as follows:
+ (all multibyte values are stored in big-endian format)
+
+ metasize (1 byte) - size of metadata in bytes
+ channels (1 byte) - number of audio channels
+ samples (2 bytes) - number of samples per audio stream
+ width (2 bytes) - width of video data
+ height (2 bytes) - height of video data (high bit set means interlaced)
+ audhuffsize (1 byte) - size of the audio Huffman table
+ str0size (2 bytes) - compressed size of stream 0
+ str1size (2 bytes) - compressed size of stream 1
+ ...
+ <metadata> - as raw data
+ <audio huffman table> - Huffman table for audio decoding
+ <audio stream 0 data> - Huffman-compressed deltas
+ <audio stream 1 data> - Huffman-compressed deltas
+ <...>
+ <video huffman table> - Huffman table for video decoding
+ <video data> - compressed data
+
+****************************************************************************
+
+ Attempted techniques that have not been worthwhile:
+
+ * Attempted to use integer DCTs from the IJG code; even the "slow"
+ variants produce a lot of error and thus kill our compression ratio,
+ since our compression is based on error not bitrate.
+
+ * Tried various other predictors for the lossless video encoding, but
+ none tended to give any significant gain over predicting the
+ previous pixel.
+
+***************************************************************************/
+
+#include "avcomp.h"
+#include "huffman.h"
+#include "chd.h"
+
+#include <math.h>
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _avcomp_state
+{
+ /* decompression parameters */
+ UINT32 decodemask;
+ UINT8 * videobuffer;
+ UINT32 videostride;
+ UINT32 videoxor;
+ UINT32 audioxor;
+
+ /* video parameters */
+ UINT32 maxwidth, maxheight;
+
+ /* audio parameters */
+ UINT32 maxchannels;
+
+ /* intermediate data */
+ UINT8 * deltadata;
+ UINT8 * audiodata;
+
+ /* huffman contexts */
+ huffman_context * ycontext;
+ huffman_context * ccontext;
+ huffman_context * audiocontext;
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* encoding helpers */
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, UINT8 *sizes);
+static avcomp_error encode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength);
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength);
+
+/* decoding helpers */
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, const UINT8 *sizes, UINT32 destxor);
+static avcomp_error decode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest);
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor);
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ avcomp_init - allocate and initialize a
+ new state block for compression or
+ decompression
+-------------------------------------------------*/
+
+avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels)
+{
+ huffman_error hufferr;
+ avcomp_state *state;
+
+ /* allocate memory for state block */
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return NULL;
+
+ /* clear the buffers */
+ memset(state, 0, sizeof(*state));
+
+ /* fill in sensible decompression defaults */
+ state->decodemask = AVCOMP_DECODE_DEFAULT;
+
+ /* compute the core info */
+ state->maxwidth = maxwidth;
+ state->maxheight = maxheight;
+ state->maxchannels = maxchannels;
+
+ /* now allocate data buffers */
+ state->deltadata = malloc(state->maxwidth * state->maxheight * 2);
+ state->audiodata = malloc(65536 * state->maxchannels * 2);
+ if (state->deltadata == NULL || state->audiodata == NULL)
+ goto cleanup;
+
+ /* create huffman contexts */
+ hufferr = huffman_create_context(&state->ycontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->ccontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->audiocontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+
+ return state;
+
+cleanup:
+ avcomp_free(state);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ avcomp_free - free a state block
+-------------------------------------------------*/
+
+void avcomp_free(avcomp_state *state)
+{
+ /* free the data buffers */
+ if (state->deltadata != NULL)
+ free(state->deltadata);
+ if (state->audiodata != NULL)
+ free(state->audiodata);
+
+ /* free the contexts */
+ if (state->ycontext != NULL)
+ huffman_free_context(state->ycontext);
+ if (state->ccontext != NULL)
+ huffman_free_context(state->ccontext);
+ if (state->audiocontext != NULL)
+ huffman_free_context(state->audiocontext);
+
+ free(state);
+}
+
+
+/*-------------------------------------------------
+ avcomp_decompress_config - configure compression
+ parameters
+-------------------------------------------------*/
+
+void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *videobuffer, UINT32 videostride, UINT32 videoxor, UINT32 audioxor)
+{
+ state->decodemask = decodemask;
+ state->videobuffer = videobuffer;
+ state->videostride = videostride;
+ state->videoxor = videoxor;
+ state->audioxor = audioxor;
+}
+
+
+
+/***************************************************************************
+ ENCODING/DECODING FRONTENDS
+***************************************************************************/
+
+/*-------------------------------------------------
+ avcomp_encode_data - encode a block of data
+ into a compressed data stream
+-------------------------------------------------*/
+
+avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ UINT32 metasize, channels, samples, width, height;
+ UINT32 srcoffs, dstoffs;
+ avcomp_error err;
+ int interlaced;
+
+ /* validate the header */
+ if (source[0] != 'c' || source[1] != 'h' || source[2] != 'a' || source[3] != 'v')
+ return AVCERR_INVALID_DATA;
+
+ /* extract info from the header */
+ metasize = source[4];
+ channels = source[5];
+ samples = (source[6] << 8) + source[7];
+ width = (source[8] << 8) + source[9];
+ height = (source[10] << 8) + source[11];
+ interlaced = (height >> 15) & 1;
+ height &= 0x7fff;
+
+ /* validate the info from the header */
+ if (width > state->maxwidth || height > state->maxheight)
+ return AVCERR_VIDEO_TOO_LARGE;
+ if (channels > state->maxchannels)
+ return AVCERR_AUDIO_TOO_LARGE;
+
+ /* write the basics to the new header */
+ dest[0] = metasize;
+ dest[1] = channels;
+ dest[2] = samples >> 8;
+ dest[3] = samples;
+ dest[4] = width >> 8;
+ dest[5] = width;
+ dest[6] = (interlaced << 7) | (height >> 8);
+ dest[7] = height;
+
+ /* starting offsets */
+ srcoffs = 12;
+ dstoffs = 9 + 2 * channels;
+
+ /* copy the metadata first */
+ if (metasize > 0)
+ {
+ memcpy(dest + dstoffs, source + srcoffs, metasize);
+ srcoffs += metasize;
+ dstoffs += metasize;
+ }
+
+ /* encode the audio channels */
+ if (channels > 0)
+ {
+ int chnum;
+
+ /* encode the audio */
+ err = encode_audio(state, channels, samples, source + srcoffs, dest + dstoffs, &dest[8]);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += channels * samples * 2;
+ dstoffs += dest[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ dstoffs += (dest[9 + 2 * chnum] << 8) + dest[10 + 2 * chnum];
+ }
+
+ /* encode the video data */
+ if (width > 0 && height > 0)
+ {
+ UINT32 vidlength;
+
+ /* encode the video */
+ err = encode_video(state, width, height, interlaced, source + srcoffs, dest + dstoffs, &vidlength);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += width * height * 2;
+ dstoffs += vidlength;
+ }
+
+ /* set the total compression */
+ *complength = dstoffs;
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ avcomp_decode_data - decode both
+ audio and video from a raw data stream
+-------------------------------------------------*/
+
+avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest)
+{
+ UINT32 metasize, channels, samples, width, height;
+ UINT32 srcoffs, dstoffs, totalsize;
+ avcomp_error err;
+ int interlaced;
+ int chnum;
+
+ /* extract info from the header */
+ if (complength < 8)
+ return AVCERR_INVALID_DATA;
+ metasize = source[0];
+ channels = source[1];
+ samples = (source[2] << 8) + source[3];
+ width = (source[4] << 8) + source[5];
+ height = (source[6] << 8) + source[7];
+ interlaced = height >> 15;
+ height &= 0x7fff;
+
+ /* validate the info from the header */
+ if (width > state->maxwidth || height > state->maxheight)
+ return AVCERR_VIDEO_TOO_LARGE;
+ if (channels > state->maxchannels)
+ return AVCERR_AUDIO_TOO_LARGE;
+
+ /* validate that the sizes make sense */
+ if (complength < 9 + 2 * channels)
+ return AVCERR_INVALID_DATA;
+ totalsize = 9 + 2 * channels + source[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ totalsize += (source[9 + 2 * chnum] << 8) | source[10 + 2 * chnum];
+ if (totalsize >= complength)
+ return AVCERR_INVALID_DATA;
+
+ /* starting offsets */
+ srcoffs = 9 + 2 * channels;
+ dstoffs = 12;
+
+ /* write the basics to the new header */
+ dest[0] = 'c';
+ dest[1] = 'h';
+ dest[2] = 'a';
+ dest[3] = 'v';
+ dest[4] = metasize;
+ dest[5] = channels;
+ dest[6] = samples >> 8;
+ dest[7] = samples;
+ dest[8] = width >> 8;
+ dest[9] = width;
+ dest[10] = (interlaced << 7) | (height >> 8);
+ dest[11] = height;
+
+ /* copy the metadata first */
+ if (metasize > 0)
+ {
+ if ((state->decodemask & AVCOMP_DECODE_META) != 0)
+ memcpy(dest + dstoffs, source + srcoffs, metasize);
+ srcoffs += metasize;
+ dstoffs += metasize;
+ }
+
+ /* decode the audio channels */
+ if (channels > 0)
+ {
+ /* decode the audio */
+ err = decode_audio(state, channels, samples, source + srcoffs, dest + dstoffs, &source[8], state->audioxor);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += source[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ srcoffs += (source[9 + 2 * chnum] << 8) + source[10 + 2 * chnum];
+ dstoffs += channels * samples * 2;
+ }
+
+ /* decode the video data */
+ if (width > 0 && height > 0 && (state->decodemask & AVCOMP_DECODE_VIDEO) != 0)
+ {
+ /* decode the video */
+ err = decode_video(state, width, height, interlaced, source + srcoffs, complength - srcoffs, dest + dstoffs);
+ if (err != AVCERR_NONE)
+ return err;
+ }
+ return AVCERR_NONE;
+}
+
+
+
+/***************************************************************************
+ ENCODING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ encode_audio - encode raw audio data
+ to the destination
+-------------------------------------------------*/
+
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, UINT8 *sizes)
+{
+ UINT32 size, bytesleft;
+ huffman_error hufferr;
+ int chnum, sampnum;
+ const UINT8 *input;
+ UINT8 *output;
+
+ /* get input/output pointers */
+ input = source;
+ output = state->audiodata;
+
+ /* extract audio deltas */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ INT16 prev = 0;
+
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ INT16 cursample, delta;
+
+ /* read current sample (big endian) */
+ cursample = *input++ << 8;
+ cursample |= *input++;
+
+ /* compute delta against previous sample in this channel */
+ delta = cursample - prev;
+ prev = cursample;
+
+ /* store the delta (big endian) */
+ *output++ = delta >> 8;
+ *output++ = delta & 0xff;
+ }
+ }
+
+ /* reset our output pointer and huffman encode */
+ input = state->audiodata;
+ output = dest;
+ bytesleft = channels * samples * 2;
+
+ /* compute a single huffman tree for all the audio data */
+ hufferr = huffman_compute_tree(state->audiocontext, input, bytesleft, 1);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ hufferr = huffman_export_tree(state->audiocontext, output, bytesleft, &size);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += size;
+ *sizes++ = size;
+ bytesleft -= size;
+
+ /* encode each stream separately */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* encode the data */
+ hufferr = huffman_encode_data(state->audiocontext, input, samples * 2, output, bytesleft, &size);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ input += samples * 2;
+ output += size;
+ bytesleft = (bytesleft > size) ? (bytesleft - size) : 0;
+
+ /* store the size of this stream */
+ *sizes++ = size >> 8;
+ *sizes++ = size;
+ }
+
+ /* if we didn't compress enough, set the huffman table size to 0 and memcpy the data */
+ if (bytesleft == 0)
+ {
+ /* back up to the beginning */
+ input = source;
+ output = dest;
+ sizes -= 1 + 2 * channels;
+
+ /* huffman table size of 0 */
+ *sizes++ = 0;
+
+ /* write the full size of each stream and then copy it */
+ size = samples * 2;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* copy the data */
+ memcpy(output, input, size);
+ input += size;
+ output += size;
+
+ /* store the size of this stream */
+ *sizes++ = size >> 8;
+ *sizes++ = size;
+ }
+ }
+
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ encode_video - encode raw video data
+ to the destination
+-------------------------------------------------*/
+
+static avcomp_error encode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ /* only lossless supported at this time */
+ return encode_video_lossless(state, width, height, interlaced, source, dest, complength);
+}
+
+
+/*-------------------------------------------------
+ encode_video_lossless - do a lossless video
+ encoding using deltas and huffman encoding
+-------------------------------------------------*/
+
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ UINT32 srcbytes = width * height * 2;
+ int rowbytes = width * 2;
+ huffman_error hufferr;
+ UINT32 outbytes;
+ UINT8 *output;
+ int x, y;
+
+ /* loop over rows */
+ output = state->deltadata;
+ for (y = 0; y < height; y++)
+ {
+ const UINT8 *src = &source[rowbytes * y];
+ UINT8 lasty = (y == 0) ? 0x80 : src[-rowbytes + 1];
+ UINT8 lastcb = (y == 0) ? 0x80 : src[-rowbytes + 0];
+ UINT8 lastcr = (y == 0) ? 0x80 : src[-rowbytes + 2];
+
+ /* loop over columns */
+ for (x = 0; x < rowbytes; x += 4)
+ {
+ *output++ = *src - lastcb;
+ lastcb = *src++;
+ *output++ = *src - lasty;
+ lasty = *src++;
+ *output++ = *src - lastcr;
+ lastcr = *src++;
+ *output++ = *src - lasty;
+ lasty = *src++;
+ }
+ }
+
+ /* set up the output; first byte is 0x80 to indicate lossless encoding */
+ output = dest;
+ *output++ = 0x80;
+
+ /* now encode to the destination using two trees, one for the Y and one for the Cr/Cb */
+
+ /* compute the histograms for the data */
+ hufferr = huffman_compute_tree(state->ycontext, state->deltadata + 0, srcbytes, 2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ hufferr = huffman_compute_tree(state->ccontext, state->deltadata + 1, srcbytes, 2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+
+ /* export the two trees to the data stream */
+ hufferr = huffman_export_tree(state->ycontext, output, 256, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+ hufferr = huffman_export_tree(state->ccontext, output, 256, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+
+ /* encode the data using the two trees */
+ hufferr = huffman_encode_data_interleaved_2(state->ycontext, state->ccontext, state->deltadata, srcbytes, output, srcbytes, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+
+ /* set the final length */
+ *complength = output - dest;
+ return AVCERR_NONE;
+}
+
+
+
+/***************************************************************************
+ DECODING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ decode_audio - decode audio from a
+ compressed data stream
+-------------------------------------------------*/
+
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, const UINT8 *sizes, UINT32 destxor)
+{
+ huffman_error hufferr;
+ int chnum, sampnum;
+ const UINT8 *input;
+ UINT32 actsize;
+ UINT8 *output;
+ UINT16 size;
+
+ /* set up input/output pointers */
+ input = source;
+ output = dest;
+
+ /* if no huffman length, just copy the data */
+ size = *sizes++;
+ if (size == 0)
+ {
+ /* loop over channels */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* extract the size of this channel */
+ size = *sizes++ << 8;
+ size |= *sizes++;
+
+ /* copy the data */
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ output[0 ^ destxor] = input[0];
+ output[1 ^ destxor] = input[1];
+ output += 2;
+ input += 2;
+ }
+ }
+ else
+ {
+ input += size;
+ output += size;
+ }
+ }
+ return AVCERR_NONE;
+ }
+
+ /* extract the huffman tree */
+ input = source;
+ hufferr = huffman_import_tree(state->audiocontext, input, size, &actsize);
+ if (hufferr != HUFFERR_NONE || actsize != size)
+ return AVCERR_INVALID_DATA;
+ input += actsize;
+
+ /* now loop over channels and decode their data */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* extract the size of this channel */
+ size = *sizes++ << 8;
+ size |= *sizes++;
+
+ /* decode the data */
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ hufferr = huffman_decode_data(state->audiocontext, input, size, output, samples * 2, &actsize);
+ if (hufferr != HUFFERR_NONE || actsize != size)
+ return AVCERR_INVALID_DATA;
+ }
+
+ /* advance */
+ input += size;
+ output += samples * 2;
+ }
+
+ /* reset input/output pointers */
+ output = dest;
+
+ /* reassemble audio from the deltas */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ INT16 prev = 0;
+
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ INT16 cursample;
+
+ /* read current sample (big endian) */
+ cursample = output[0] << 8;
+ cursample |= output[1];
+
+ /* compute delta against previous sample in this channel */
+ cursample += prev;
+ prev = cursample;
+
+ /* store the delta (big endian) */
+ output[0 ^ destxor] = cursample >> 8;
+ output[1 ^ destxor] = cursample;
+ output += 2;
+ }
+ }
+ else
+ output += samples * 2;
+ }
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ decode_video - decode video from a
+ compressed data stream
+-------------------------------------------------*/
+
+static avcomp_error decode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest)
+{
+ UINT32 targetstride, targetxor;
+ UINT8 *target;
+
+ /* if we have a target buffer, use that instead */
+ if (state->videobuffer != NULL)
+ {
+ target = state->videobuffer;
+ targetstride = state->videostride;
+ targetxor = state->videoxor;
+ }
+ else
+ {
+ target = dest;
+ targetstride = width * 2;
+ targetxor = 0;
+ }
+
+ /* if the high bit of the first byte is set, we decode losslessly */
+ if (source[0] & 0x80)
+ return decode_video_lossless(state, width, height, interlaced, source, complength, target, targetstride, targetxor);
+ else
+ return AVCERR_INVALID_DATA;
+}
+
+
+/*-------------------------------------------------
+ decode_video_lossless - do a lossless video
+ decoding using deltas and huffman encoding
+-------------------------------------------------*/
+
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor)
+{
+ const UINT8 *sourceend = source + complength;
+ const huffman_lookup_value *table1, *table2;
+ huffman_error hufferr;
+ UINT32 bitbuf = 0;
+ UINT32 actsize;
+ int sbits = 0;
+ int x, y;
+
+ /* skip the first byte */
+ source++;
+
+ /* decode the table and data */
+ hufferr = huffman_import_tree(state->ycontext, source, sourceend - source, &actsize);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+ hufferr = huffman_import_tree(state->ccontext, source, sourceend - source, &actsize);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+
+ /* get the lookup tables */
+ hufferr = huffman_get_lookup_table(state->ycontext, &table1);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_OUT_OF_MEMORY;
+ hufferr = huffman_get_lookup_table(state->ccontext, &table2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_OUT_OF_MEMORY;
+
+ /* loop over rows */
+ for (y = 0; y < height; y++)
+ {
+ UINT8 *dst = &dest[y * deststride];
+ UINT8 lasty = (y == 0) ? 0x80 : (dst - deststride)[1 ^ destxor];
+ UINT8 lastcb = (y == 0) ? 0x80 : (dst - deststride)[0 ^ destxor];
+ UINT8 lastcr = (y == 0) ? 0x80 : (dst - deststride)[2 ^ destxor];
+
+ /* loop over columns */
+ for (x = 0; x < width * 2; x += 4)
+ {
+ huffman_lookup_value lookup;
+
+ /* keep the buffer full */
+ while (sbits <= 24)
+ {
+ bitbuf |= *source++ << (24 - sbits);
+ sbits += 8;
+ }
+
+ /* do the Cb component */
+ lookup = table1[bitbuf >> 20];
+ dst[(x + 0) ^ destxor] = lastcb += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* do the Y component */
+ lookup = table2[bitbuf >> 20];
+ dst[(x + 1) ^ destxor] = lasty += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* keep the buffer full */
+ while (sbits <= 24)
+ {
+ bitbuf |= *source++ << (24 - sbits);
+ sbits += 8;
+ }
+
+ /* do the Cr component */
+ lookup = table1[bitbuf >> 20];
+ dst[(x + 2) ^ destxor] = lastcr += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* do the Y component */
+ lookup = table2[bitbuf >> 20];
+ dst[(x + 3) ^ destxor] = lasty += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+ }
+ }
+
+ return AVCERR_NONE;
+}