summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-08-12 09:24:22 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-08-12 09:24:22 +0000
commita85c4c754d9d7512310f9fb9cd8196d0a6568997 (patch)
tree20393dcc7233a51e3a551bd69109f3790dd24d9d
parentd89508d2010709affb21ed8b0d33757d3ead6ea7 (diff)
Rejiggered huffman.c to support multiple interleaving
streams and a delta-RLE pre-encoding. Added optimized case for the Y/Cb/Y/Cr video encoding case. Cleaned up the code. Updated avcomp.c to use the new huffman.c functions. Reworked configuration options to allow for both input and output of naturally aligned data streams. Updated chdman and laserdsc to use the new interfaces. New compression gives an additional 3-7% over previous attempt and compresses the dummy CHDs down significantly.
-rw-r--r--src/emu/machine/laserdsc.c151
-rw-r--r--src/lib/util/avcomp.c762
-rw-r--r--src/lib/util/avcomp.h50
-rw-r--r--src/lib/util/chd.c54
-rw-r--r--src/lib/util/chd.h52
-rw-r--r--src/lib/util/huffman.c1321
-rw-r--r--src/lib/util/huffman.h27
-rw-r--r--src/mame/audio/madalien.c2
-rw-r--r--src/mame/drivers/dlair.c5
-rw-r--r--src/tools/chdman.c413
-rw-r--r--src/tools/ldverify.c4
11 files changed, 1751 insertions, 1090 deletions
diff --git a/src/emu/machine/laserdsc.c b/src/emu/machine/laserdsc.c
index 61398379243..234d17a9844 100644
--- a/src/emu/machine/laserdsc.c
+++ b/src/emu/machine/laserdsc.c
@@ -205,7 +205,6 @@ struct _laserdisc_state
chd_file * disc; /* handle to the disc itself */
av_codec_decompress_config avconfig; /* decompression configuration */
UINT8 readpending; /* true if a read is pending */
- UINT8 * framebuffer; /* buffer to hold one frame */
UINT32 maxfractrack; /* maximum track number */
UINT32 fieldnum; /* field number (0 or 1) */
@@ -216,6 +215,7 @@ struct _laserdisc_state
UINT32 videoframenum[3]; /* frame number contained in each frame */
UINT8 videoindex; /* index of the current video buffer */
bitmap_t * emptyframe; /* blank frame */
+ bitmap_t videotarget; /* fake target bitmap for decompression */
/* audio data */
laserdisc_audio_func audiocallback; /* callback function for audio processing */
@@ -223,6 +223,8 @@ struct _laserdisc_state
UINT32 audiobufsize; /* size of buffer */
UINT32 audiobufin; /* input index */
UINT32 audiobufout; /* output index */
+ UINT32 audiocursamples; /* current samples this track */
+ UINT32 audiomaxsamples; /* maximum samples per track */
int audiocustom; /* custom sound index */
int samplerate; /* playback samplerate */
@@ -1261,11 +1263,6 @@ static void read_track_data(laserdisc_state *ld)
UINT32 chdhunk = (tracknum - 1) * 2 + fieldnum;
chd_error err;
- /* initialize the decompression structure */
- ld->avconfig.decode_mask = AVCOMP_DECODE_VIDEO;
- ld->avconfig.video_xor = BYTE_XOR_LE(0);
- ld->avconfig.audio_xor = BYTE_XOR_BE(0);
-
/* if the previous field had the white flag, force the new field to pair with it */
if (ld->metadata[fieldnum ^ 1].white)
ld->videofields[ld->videoindex] = 1;
@@ -1277,15 +1274,35 @@ static void read_track_data(laserdisc_state *ld)
ld->videofields[ld->videoindex] = 0;
}
- /* set the video buffer information */
- ld->avconfig.video_buffer = (UINT8 *)BITMAP_ADDR16(ld->videoframe[ld->videoindex], fieldnum, 0);
- ld->avconfig.video_stride = 4 * ld->videoframe[ld->videoindex]->rowpixels;
-
- /* if audio is active, enable audio decoding */
- if (audio_channel_active(ld, 0))
- ld->avconfig.decode_mask |= AVCOMP_DECODE_AUDIO(0);
- if (audio_channel_active(ld, 1))
- ld->avconfig.decode_mask |= AVCOMP_DECODE_AUDIO(1);
+ /* set the video target information */
+ ld->videotarget = *ld->videoframe[ld->videoindex];
+ ld->videotarget.base = BITMAP_ADDR16(&ld->videotarget, fieldnum, 0);
+ ld->videotarget.height /= 2;
+ ld->videotarget.rowpixels *= 2;
+ ld->avconfig.video = &ld->videotarget;
+
+ /* set the audio target information */
+ if (ld->audiobufin + ld->audiomaxsamples <= ld->audiobufsize)
+ {
+ /* if we can fit without wrapping, just read the data directly */
+ ld->avconfig.audio[0] = &ld->audiobuffer[0][ld->audiobufin];
+ ld->avconfig.audio[1] = &ld->audiobuffer[1][ld->audiobufin];
+ }
+ else
+ {
+ /* otherwise, read to the beginning of the buffer */
+ ld->avconfig.audio[0] = &ld->audiobuffer[0][0];
+ ld->avconfig.audio[1] = &ld->audiobuffer[1][0];
+ }
+
+ /* override if we're not decoding */
+ ld->avconfig.maxsamples = ld->audiomaxsamples;
+ ld->avconfig.actsamples = &ld->audiocursamples;
+ ld->audiocursamples = 0;
+ if (!audio_channel_active(ld, 0))
+ ld->avconfig.audio[0] = NULL;
+ if (!audio_channel_active(ld, 1))
+ ld->avconfig.audio[1] = NULL;
/* configure the codec and then read */
if (ld->disc != NULL)
@@ -1293,7 +1310,7 @@ static void read_track_data(laserdisc_state *ld)
err = chd_codec_config(ld->disc, AV_CODEC_DECOMPRESS_CONFIG, &ld->avconfig);
if (err == CHDERR_NONE)
{
- err = chd_read_async(ld->disc, chdhunk, ld->framebuffer);
+ err = chd_read_async(ld->disc, chdhunk, NULL);
ld->readpending = TRUE;
}
}
@@ -1310,25 +1327,22 @@ static void process_track_data(const device_config *device)
laserdisc_state *ld = get_safe_token(device);
UINT32 tracknum = FRAC_TO_INT(ld->curfractrack);
UINT32 fieldnum = ld->fieldnum & 1;
- const UINT8 *rawdata = NULL;
- const INT16 *sampsource[2];
int frame, chapter;
chd_error chderr;
- int samples;
/* wait for the async operation to complete */
if (ld->disc != NULL && ld->readpending)
{
/* complete the async operation */
chderr = chd_async_complete(ld->disc);
- if (chderr == CHDERR_NONE || chderr == CHDERR_NO_ASYNC_OPERATION)
- rawdata = ld->framebuffer;
+ if (chderr != CHDERR_NONE && chderr != CHDERR_NO_ASYNC_OPERATION)
+ ld->avconfig.video = NULL;
}
ld->readpending = FALSE;
/* parse the metadata */
- if (ld->disc != NULL && ld->avconfig.video_buffer != NULL)
- vbi_parse_all((const UINT16 *)ld->avconfig.video_buffer, ld->avconfig.video_stride / 2, ld->videoframe[0]->width, 8, &ld->metadata[fieldnum]);
+ if (ld->disc != NULL && ld->avconfig.video != NULL)
+ vbi_parse_all((const UINT16 *)ld->avconfig.video->base, ld->avconfig.video->rowpixels, ld->avconfig.video->width, 8, &ld->metadata[fieldnum]);
else
fake_metadata(tracknum, fieldnum, &ld->metadata[fieldnum]);
// printf("Track %5d: Metadata = %d %08X %08X %08X %08X\n", tracknum, ld->metadata[fieldnum].white, ld->metadata[fieldnum].line16, ld->metadata[fieldnum].line17, ld->metadata[fieldnum].line18, ld->metadata[fieldnum].line1718);
@@ -1343,59 +1357,39 @@ static void process_track_data(const device_config *device)
/* render the display if present */
if (ld->display)
- render_display((UINT16 *)ld->avconfig.video_buffer, ld->avconfig.video_stride / 2, ld->videoframe[0]->width, ld->last_frame);
+ render_display((UINT16 *)ld->avconfig.video->base, ld->avconfig.video->rowpixels, ld->avconfig.video->width, ld->last_frame);
- /* update video ld */
- if (rawdata != NULL && (ld->avconfig.decode_mask & AVCOMP_DECODE_VIDEO))
+ /* update video field */
+ if (ld->avconfig.video != NULL)
{
ld->videofields[ld->videoindex]++;
ld->videoframenum[ld->videoindex] = ld->last_frame;
}
- /* stream the audio into our ring buffers */
- if (rawdata != NULL)
+ /* shift audio data if we read it into the beginning of the buffer */
+ if (ld->audiocursamples != 0 && ld->audiobufin != 0)
{
- samples = (rawdata[6] << 8) + rawdata[7];
- sampsource[0] = (const INT16 *)(rawdata + 12 + rawdata[4]) + 0 * samples;
- sampsource[1] = sampsource[0] + samples;
-
- /* let the audio callback at it first */
- if (ld->audiocallback != NULL)
- (*ld->audiocallback)(device, ld->samplerate, samples, sampsource[0], sampsource[1]);
-
- /* loop until all samples are copied */
- while (samples != 0)
- {
- int samples_to_copy = MIN(ld->audiobufsize - ld->audiobufin, samples);
- int channum;
-
- /* don't overrun the output pointer */
- if (ld->audiobufout > ld->audiobufin)
+ int chnum;
+
+ /* iterate over channels */
+ for (chnum = 0; chnum < 2; chnum++)
+ if (ld->avconfig.audio[chnum] == &ld->audiobuffer[chnum][0])
{
- samples_to_copy = MIN(samples_to_copy, ld->audiobufout - ld->audiobufin);
- if (samples_to_copy == 0)
- break;
+ int samplesleft;
+
+ /* move data to the end */
+ samplesleft = ld->audiobufsize - ld->audiobufin;
+ samplesleft = MIN(samplesleft, ld->audiocursamples);
+ memmove(&ld->audiobuffer[chnum][ld->audiobufin], &ld->audiobuffer[chnum][0], samplesleft * 2);
+
+ /* shift data at the beginning */
+ if (samplesleft < ld->audiocursamples)
+ memmove(&ld->audiobuffer[chnum][0], &ld->audiobuffer[chnum][samplesleft], (ld->audiocursamples - samplesleft) * 2);
}
-
- /* for reach channel, copy the data or clear to 0 */
- for (channum = 0; channum < 2; channum++)
- {
- if (audio_channel_active(ld, channum))
- {
- memcpy(&ld->audiobuffer[channum][ld->audiobufin], sampsource[channum], samples_to_copy * 2);
- sampsource[channum] += samples_to_copy;
- }
- else
- memset(&ld->audiobuffer[channum][ld->audiobufin], 0, samples_to_copy * 2);
- }
- samples -= samples_to_copy;
-
- /* point past the data */
- ld->audiobufin += samples_to_copy;
- if (ld->audiobufin >= ld->audiobufsize)
- ld->audiobufin = 0;
- }
}
+
+ /* update the input buffer pointer */
+ ld->audiobufin = (ld->audiobufin + ld->audiocursamples) % ld->audiobufsize;
}
@@ -1524,15 +1518,17 @@ static void custom_stream_callback(void *param, stream_sample_t **inputs, stream
/* otherwise, stream from our buffer */
else
{
- const INT16 *buffer0 = ld->audiobuffer[0];
- const INT16 *buffer1 = ld->audiobuffer[1];
+ INT16 *buffer0 = ld->audiobuffer[0];
+ INT16 *buffer1 = ld->audiobuffer[1];
int sampout = ld->audiobufout;
- /* copy samples */
+ /* copy samples, clearing behind us as we go */
while (sampout != ld->audiobufin && samples-- > 0)
{
*dst0++ = buffer0[sampout];
*dst1++ = buffer1[sampout];
+ buffer0[sampout] = 0;
+ buffer1[sampout] = 0;
sampout++;
if (sampout >= ld->audiobufsize)
sampout = 0;
@@ -1565,15 +1561,15 @@ static void custom_stream_callback(void *param, stream_sample_t **inputs, stream
device start callback
-------------------------------------------------*/
-static DEVICE_START(laserdisc)
+static DEVICE_START( laserdisc )
{
int fps = 30, fpsfrac = 0, width = 720, height = 240, interlaced = 1, channels = 2, rate = 44100;
const laserdisc_config *config = device->inline_config;
- UINT32 fps_times_1million, max_samples_per_track;
laserdisc_state *ld = get_safe_token(device);
+ UINT32 fps_times_1million;
char metadata[256];
- chd_error err;
int sndnum, index;
+ chd_error err;
/* copy config data to the live state */
ld->type = config->type;
@@ -1605,7 +1601,6 @@ static DEVICE_START(laserdisc)
/* determine the maximum track and allocate a frame buffer */
ld->maxfractrack = INT_TO_FRAC(chd_get_header(ld->disc)->totalhunks / (interlaced + 1));
- ld->framebuffer = auto_malloc(chd_get_header(ld->disc)->hunkbytes);
}
else
ld->maxfractrack = INT_TO_FRAC(54000);
@@ -1625,8 +1620,8 @@ static DEVICE_START(laserdisc)
/* allocate audio buffers */
fps_times_1million = fps * 1000000 + fpsfrac;
- max_samples_per_track = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
- ld->audiobufsize = max_samples_per_track * 4;
+ ld->audiomaxsamples = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
+ ld->audiobufsize = ld->audiomaxsamples * 4;
ld->audiobuffer[0] = auto_malloc(ld->audiobufsize * sizeof(ld->audiobuffer[0][0]));
ld->audiobuffer[1] = auto_malloc(ld->audiobufsize * sizeof(ld->audiobuffer[1][0]));
ld->samplerate = rate;
@@ -1637,7 +1632,7 @@ static DEVICE_START(laserdisc)
device exit callback
-------------------------------------------------*/
-static DEVICE_STOP(laserdisc)
+static DEVICE_STOP( laserdisc )
{
laserdisc_state *ld = get_safe_token(device);
@@ -1722,7 +1717,7 @@ static DEVICE_RESET( laserdisc )
device set info callback
-------------------------------------------------*/
-static DEVICE_SET_INFO(laserdisc)
+static DEVICE_SET_INFO( laserdisc )
{
laserdisc_state *ld = get_safe_token(device);
switch (state)
@@ -1743,7 +1738,7 @@ static DEVICE_SET_INFO(laserdisc)
device get info callback
-------------------------------------------------*/
-DEVICE_GET_INFO(laserdisc)
+DEVICE_GET_INFO( laserdisc )
{
const laserdisc_config *config = (device != NULL) ? device->inline_config : NULL;
switch (state)
diff --git a/src/lib/util/avcomp.c b/src/lib/util/avcomp.c
index c9f7b6b4173..a45867e7f7e 100644
--- a/src/lib/util/avcomp.c
+++ b/src/lib/util/avcomp.c
@@ -1,9 +1,3 @@
-/*
-To do:
-* verify Cb,Y,Cr,Y ordering
-* swap the ordering(?)
-* add backchannel support for samples as well?
-*/
/***************************************************************************
avcomp.c
@@ -18,37 +12,37 @@ To do:
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
+ +00 = 'chav' (4 bytes) - fixed header data to identify the format
+ +04 = metasize (1 byte) - size of metadata in bytes (max=255 bytes)
+ +05 = channels (1 byte) - number of audio channels
+ +06 = samples (2 bytes) - number of samples per audio stream
+ +08 = width (2 bytes) - width of video data
+ +0A = height (2 bytes) - height of video data
+ +0C = <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
+ +00 = metasize (1 byte) - size of metadata in bytes
+ +01 = channels (1 byte) - number of audio channels
+ +02 = samples (2 bytes) - number of samples per audio stream
+ +04 = width (2 bytes) - width of video data
+ +06 = height (2 bytes) - height of video data
+ +08 = audio huffman size (2 bytes) - size of audio huffman tables
+ +0A = str0size (2 bytes) - compressed size of stream 0
+ +0C = 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 tables> - Huffman tables for video decoding
+ <video data> - compressed data
****************************************************************************
@@ -73,18 +67,19 @@ To do:
/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_CHANNELS 4
+
+
+
+/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
struct _avcomp_state
{
- /* decompression parameters */
- UINT32 decodemask;
- UINT8 * videobuffer;
- UINT32 videostride;
- UINT32 videoxor;
- UINT32 audioxor;
-
/* video parameters */
UINT32 maxwidth, maxheight;
@@ -92,13 +87,18 @@ struct _avcomp_state
UINT32 maxchannels;
/* intermediate data */
- UINT8 * deltadata;
UINT8 * audiodata;
/* huffman contexts */
huffman_context * ycontext;
- huffman_context * ccontext;
- huffman_context * audiocontext;
+ huffman_context * cbcontext;
+ huffman_context * crcontext;
+ huffman_context * audiohicontext;
+ huffman_context * audiolocontext;
+
+ /* configuration data */
+ av_codec_compress_config compress;
+ av_codec_decompress_config decompress;
};
@@ -108,14 +108,14 @@ struct _avcomp_state
***************************************************************************/
/* 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);
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 **source, int sourcexor, UINT8 *dest, UINT8 *sizes);
+static avcomp_error encode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength);
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, 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);
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes);
+static avcomp_error decode_video(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor);
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor);
@@ -133,6 +133,10 @@ avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels)
{
huffman_error hufferr;
avcomp_state *state;
+
+ /* error if out of range */
+ if (maxchannels > MAX_CHANNELS)
+ return NULL;
/* allocate memory for state block */
state = malloc(sizeof(*state));
@@ -142,28 +146,30 @@ avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels)
/* 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)
+ if (state->audiodata == NULL)
goto cleanup;
/* create huffman contexts */
- hufferr = huffman_create_context(&state->ycontext, 12);
+ hufferr = huffman_create_context(&state->ycontext, 16);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->cbcontext, 16);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->crcontext, 16);
if (hufferr != HUFFERR_NONE)
goto cleanup;
- hufferr = huffman_create_context(&state->ccontext, 12);
+ hufferr = huffman_create_context(&state->audiohicontext, 16);
if (hufferr != HUFFERR_NONE)
goto cleanup;
- hufferr = huffman_create_context(&state->audiocontext, 12);
+ hufferr = huffman_create_context(&state->audiolocontext, 16);
if (hufferr != HUFFERR_NONE)
goto cleanup;
@@ -182,35 +188,44 @@ cleanup:
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);
+ if (state->cbcontext != NULL)
+ huffman_free_context(state->cbcontext);
+ if (state->crcontext != NULL)
+ huffman_free_context(state->crcontext);
+ if (state->audiohicontext != NULL)
+ huffman_free_context(state->audiohicontext);
+ if (state->audiolocontext != NULL)
+ huffman_free_context(state->audiolocontext);
free(state);
}
/*-------------------------------------------------
- avcomp_decompress_config - configure compression
+ avcomp_config_compress - configure compression
parameters
-------------------------------------------------*/
-void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *videobuffer, UINT32 videostride, UINT32 videoxor, UINT32 audioxor)
+void avcomp_config_compress(avcomp_state *state, const av_codec_compress_config *config)
{
- state->decodemask = decodemask;
- state->videobuffer = videobuffer;
- state->videostride = videostride;
- state->videoxor = videoxor;
- state->audioxor = audioxor;
+ state->compress = *config;
+}
+
+
+/*-------------------------------------------------
+ avcomp_config_decompress - configure
+ decompression parameters
+-------------------------------------------------*/
+
+void avcomp_config_decompress(avcomp_state *state, const av_codec_decompress_config *config)
+{
+ state->decompress = *config;
}
@@ -226,23 +241,75 @@ void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *vid
avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength)
{
+ const UINT8 *metastart, *videostart, *audiostart[MAX_CHANNELS];
UINT32 metasize, channels, samples, width, height;
- UINT32 srcoffs, dstoffs;
+ UINT32 audioxor, videoxor, videostride;
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;
+ UINT32 dstoffs;
+ int chnum;
+
+ /* extract data from source if present */
+ if (source != NULL)
+ {
+ /* 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];
+
+ /* determine the start of each piece of data */
+ source += 12;
+ metastart = source;
+ source += metasize;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ audiostart[chnum] = source;
+ source += 2 * samples;
+ }
+ videostart = source;
+
+ /* data is assumed to be big-endian already */
+ audioxor = videoxor = 0;
+ videostride = 2 * width;
+ }
+
+ /* otherwise, extract from the state */
+ else
+ {
+ UINT16 betest = 0;
+
+ /* extract metadata information */
+ metastart = state->compress.metadata;
+ metasize = state->compress.metalength;
+ if ((metastart == NULL && metasize != 0) || (metastart != NULL && metasize == 0))
+ return AVCERR_INVALID_CONFIGURATION;
+
+ /* extract audio information */
+ channels = state->compress.channels;
+ samples = state->compress.samples;
+ for (chnum = 0; chnum < channels; chnum++)
+ audiostart[chnum] = (const UINT8 *)state->compress.audio[chnum];
- /* 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;
+ /* extract video information */
+ videostart = NULL;
+ videostride = width = height = 0;
+ if (state->compress.video != NULL)
+ {
+ videostart = state->compress.video->base;
+ videostride = state->compress.video->rowpixels * 2;
+ width = state->compress.video->width;
+ height = state->compress.video->height;
+ }
+
+ /* data is assumed to be native-endian */
+ *(UINT8 *)&betest = 1;
+ audioxor = videoxor = (betest == 1) ? 1 : 0;
+ }
/* validate the info from the header */
if (width > state->maxwidth || height > state->maxheight)
@@ -257,36 +324,31 @@ avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8
dest[3] = samples;
dest[4] = width >> 8;
dest[5] = width;
- dest[6] = (interlaced << 7) | (height >> 8);
+ dest[6] = height >> 8;
dest[7] = height;
/* starting offsets */
- srcoffs = 12;
- dstoffs = 9 + 2 * channels;
+ dstoffs = 10 + 2 * channels;
/* copy the metadata first */
if (metasize > 0)
{
- memcpy(dest + dstoffs, source + srcoffs, metasize);
- srcoffs += metasize;
+ memcpy(dest + dstoffs, metastart, 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]);
+ err = encode_audio(state, channels, samples, audiostart, audioxor, dest + dstoffs, &dest[8]);
if (err != AVCERR_NONE)
return err;
/* advance the pointers past the data */
- srcoffs += channels * samples * 2;
- dstoffs += dest[8];
+ dstoffs += (dest[8] << 8) + dest[9];
for (chnum = 0; chnum < channels; chnum++)
- dstoffs += (dest[9 + 2 * chnum] << 8) + dest[10 + 2 * chnum];
+ dstoffs += (dest[10 + 2 * chnum] << 8) + dest[11 + 2 * chnum];
}
/* encode the video data */
@@ -295,12 +357,11 @@ avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8
UINT32 vidlength;
/* encode the video */
- err = encode_video(state, width, height, interlaced, source + srcoffs, dest + dstoffs, &vidlength);
+ err = encode_video(state, width, height, videostart, videostride, videoxor, dest + dstoffs, &vidlength);
if (err != AVCERR_NONE)
return err;
/* advance the pointers past the data */
- srcoffs += width * height * 2;
dstoffs += vidlength;
}
@@ -317,10 +378,11 @@ avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8
avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest)
{
+ UINT8 *metastart, *videostart, *audiostart[MAX_CHANNELS];
UINT32 metasize, channels, samples, width, height;
- UINT32 srcoffs, dstoffs, totalsize;
+ UINT32 audioxor, videoxor, videostride;
+ UINT32 srcoffs, totalsize;
avcomp_error err;
- int interlaced;
int chnum;
/* extract info from the header */
@@ -331,8 +393,6 @@ avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32
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)
@@ -341,61 +401,110 @@ avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32
return AVCERR_AUDIO_TOO_LARGE;
/* validate that the sizes make sense */
- if (complength < 9 + 2 * channels)
+ if (complength < 10 + 2 * channels)
return AVCERR_INVALID_DATA;
- totalsize = 9 + 2 * channels + source[8];
+ totalsize = 10 + 2 * channels;
+ totalsize += (source[8] << 8) | source[9];
for (chnum = 0; chnum < channels; chnum++)
- totalsize += (source[9 + 2 * chnum] << 8) | source[10 + 2 * chnum];
+ totalsize += (source[10 + 2 * chnum] << 8) | source[11 + 2 * chnum];
if (totalsize >= complength)
return AVCERR_INVALID_DATA;
-
+
/* starting offsets */
- srcoffs = 9 + 2 * channels;
- dstoffs = 12;
+ srcoffs = 10 + 2 * channels;
- /* 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;
+ /* if we are decoding raw, set up the output parameters */
+ if (dest != NULL)
+ {
+ /* create a 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] = height >> 8;
+ dest[11] = height;
+
+ /* determine the start of each piece of data */
+ dest += 12;
+ metastart = dest;
+ dest += metasize;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ audiostart[chnum] = dest;
+ dest += 2 * samples;
+ }
+ videostart = dest;
+
+ /* data is assumed to be big-endian already */
+ audioxor = videoxor = 0;
+ videostride = 2 * width;
+ }
+
+ /* otherwise, extract from the state */
+ else
+ {
+ UINT16 betest = 0;
+
+ /* determine the start of each piece of data */
+ metastart = state->decompress.metadata;
+ for (chnum = 0; chnum < channels; chnum++)
+ audiostart[chnum] = (UINT8 *)state->decompress.audio[chnum];
+ videostart = (state->decompress.video != NULL) ? state->decompress.video->base : NULL;
+ videostride = (state->decompress.video != NULL) ? state->decompress.video->rowpixels * 2 : 0;
+
+ /* data is assumed to be native-endian */
+ *(UINT8 *)&betest = 1;
+ audioxor = videoxor = (betest == 1) ? 1 : 0;
+
+ /* verify against sizes */
+ if (state->decompress.video != NULL && (state->decompress.video->width < width || state->decompress.video->height < height))
+ return AVCERR_VIDEO_TOO_LARGE;
+ for (chnum = 0; chnum < channels; chnum++)
+ if (state->decompress.audio[chnum] != NULL && state->decompress.maxsamples < samples)
+ return AVCERR_AUDIO_TOO_LARGE;
+ if (state->decompress.metadata != NULL && state->decompress.maxmetalength < metasize)
+ return AVCERR_METADATA_TOO_LARGE;
+
+ /* set the output values */
+ if (state->decompress.actsamples != NULL)
+ *state->decompress.actsamples = samples;
+ if (state->decompress.actmetalength != NULL)
+ *state->decompress.actmetalength = metasize;
+ }
/* copy the metadata first */
if (metasize > 0)
{
- if ((state->decodemask & AVCOMP_DECODE_META) != 0)
- memcpy(dest + dstoffs, source + srcoffs, metasize);
+ if (metastart != NULL)
+ memcpy(metastart, 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);
+ err = decode_audio(state, channels, samples, source + srcoffs, audiostart, audioxor, &source[8]);
if (err != AVCERR_NONE)
return err;
/* advance the pointers past the data */
- srcoffs += source[8];
+ srcoffs += (source[8] << 8) + source[9];
for (chnum = 0; chnum < channels; chnum++)
- srcoffs += (source[9 + 2 * chnum] << 8) + source[10 + 2 * chnum];
- dstoffs += channels * samples * 2;
+ srcoffs += (source[10 + 2 * chnum] << 8) + source[11 + 2 * chnum];
}
/* decode the video data */
- if (width > 0 && height > 0 && (state->decodemask & AVCOMP_DECODE_VIDEO) != 0)
+ if (width > 0 && height > 0 && videostart != NULL)
{
/* decode the video */
- err = decode_video(state, width, height, interlaced, source + srcoffs, complength - srcoffs, dest + dstoffs);
+ err = decode_video(state, width, height, source + srcoffs, complength - srcoffs, videostart, videostride, videoxor);
if (err != AVCERR_NONE)
return err;
}
@@ -413,96 +522,93 @@ avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32
to the destination
-------------------------------------------------*/
-static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, UINT8 *sizes)
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 **source, int sourcexor, UINT8 *dest, UINT8 *sizes)
{
- UINT32 size, bytesleft;
+ UINT32 size, huffsize, totalsize;
+ huffman_context *contexts[2];
huffman_error hufferr;
+ UINT8 *output = dest;
int chnum, sampnum;
- const UINT8 *input;
- UINT8 *output;
-
- /* get input/output pointers */
- input = source;
- output = state->audiodata;
-
- /* extract audio deltas */
+ UINT8 *deltabuf;
+
+ /* iterate over channels to compute deltas */
+ deltabuf = state->audiodata;
for (chnum = 0; chnum < channels; chnum++)
{
- INT16 prev = 0;
-
+ const UINT8 *srcdata = source[chnum];
+ INT16 prevsample = 0;
+
+ /* extract audio data into hi and lo deltas stored in big-endian order */
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;
+ INT16 newsample = (srcdata[0 ^ sourcexor] << 8) | srcdata[1 ^ sourcexor];
+ INT16 delta = newsample - prevsample;
+ prevsample = newsample;
+ *deltabuf++ = delta >> 8;
+ *deltabuf++ = delta;
+ srcdata += 2;
}
}
- /* reset our output pointer and huffman encode */
- input = state->audiodata;
- output = dest;
- bytesleft = channels * samples * 2;
+ /* compute the trees */
+ contexts[0] = state->audiohicontext;
+ contexts[1] = state->audiolocontext;
+ hufferr = huffman_compute_tree_interleaved(2, contexts, state->audiodata, samples * 2, channels, samples * 2, 0);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
- /* compute a single huffman tree for all the audio data */
- hufferr = huffman_compute_tree(state->audiocontext, input, bytesleft, 1);
+ /* export them to the output */
+ hufferr = huffman_export_tree(state->audiohicontext, output, 256, &size);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
- hufferr = huffman_export_tree(state->audiocontext, output, bytesleft, &size);
+ output += size;
+ hufferr = huffman_export_tree(state->audiolocontext, output, 256, &size);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
output += size;
- *sizes++ = size;
- bytesleft -= size;
-
- /* encode each stream separately */
+
+ /* note the size of the two trees */
+ huffsize = output - dest;
+ sizes[0] = huffsize >> 8;
+ sizes[1] = huffsize;
+
+ /* iterate over channels */
+ totalsize = huffsize;
for (chnum = 0; chnum < channels; chnum++)
{
+ const UINT8 *input = state->audiodata + chnum * samples * 2;
+
/* encode the data */
- hufferr = huffman_encode_data(state->audiocontext, input, samples * 2, output, bytesleft, &size);
+ hufferr = huffman_encode_data_interleaved(2, contexts, input, samples * 2, 1, 0, 0, output, samples * 2, &size);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
- input += samples * 2;
output += size;
- bytesleft = (bytesleft > size) ? (bytesleft - size) : 0;
+
+ /* if we didn't compress enough, set the huffman table size to 0 and memcpy the data */
+ if (size >= samples * 2)
+ {
+ memcpy(output, input, samples * 2);
+ size = samples * 2;
+ }
/* store the size of this stream */
- *sizes++ = size >> 8;
- *sizes++ = size;
+ totalsize += size;
+ if (totalsize >= channels * samples * 2)
+ break;
+ sizes[chnum * 2 + 2] = size >> 8;
+ sizes[chnum * 2 + 3] = size;
}
-
- /* if we didn't compress enough, set the huffman table size to 0 and memcpy the data */
- if (bytesleft == 0)
+
+ /* if we ran out of room, throw it all away and just store raw */
+ if (chnum < channels)
{
- /* 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 */
+ memcpy(dest, state->audiodata, channels * samples * 2);
size = samples * 2;
+ sizes[0] = sizes[1] = 0;
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;
+ sizes[chnum * 2 + 2] = size >> 8;
+ sizes[chnum * 2 + 3] = size;
}
}
@@ -515,10 +621,10 @@ static avcomp_error encode_audio(avcomp_state *state, int channels, int samples,
to the destination
-------------------------------------------------*/
-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(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength)
{
/* only lossless supported at this time */
- return encode_video_lossless(state, width, height, interlaced, source, dest, complength);
+ return encode_video_lossless(state, width, height, source, sstride, sxor, dest, complength);
}
@@ -527,64 +633,45 @@ static avcomp_error encode_video(avcomp_state *state, int width, int height, int
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)
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 *complength)
{
UINT32 srcbytes = width * height * 2;
- int rowbytes = width * 2;
+ huffman_context *contexts[4];
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 */
+ contexts[0] = state->ycontext;
+ contexts[1] = state->cbcontext;
+ contexts[2] = state->ycontext;
+ contexts[3] = state->crcontext;
/* compute the histograms for the data */
- hufferr = huffman_compute_tree(state->ycontext, state->deltadata + 0, srcbytes, 2);
+ hufferr = huffman_deltarle_compute_tree_interleaved(4, contexts, source, width * 2, height, sstride, sxor);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
- hufferr = huffman_compute_tree(state->ccontext, state->deltadata + 1, srcbytes, 2);
+
+ /* export the trees to the data stream */
+ hufferr = huffman_deltarle_export_tree(state->ycontext, output, 256, &outbytes);
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);
+ output += outbytes;
+ hufferr = huffman_deltarle_export_tree(state->cbcontext, output, 256, &outbytes);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
output += outbytes;
- hufferr = huffman_export_tree(state->ccontext, output, 256, &outbytes);
+ hufferr = huffman_deltarle_export_tree(state->crcontext, 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);
+ /* encode the data using the trees */
+ hufferr = huffman_deltarle_encode_data_interleaved(4, contexts, source, width * 2, height, sstride, sxor, output, srcbytes, &outbytes);
if (hufferr != HUFFERR_NONE)
return AVCERR_COMPRESSION_ERROR;
output += outbytes;
@@ -605,108 +692,107 @@ static avcomp_error encode_video_lossless(avcomp_state *state, int width, int he
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)
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 **dest, UINT32 dxor, const UINT8 *sizes)
{
+ huffman_context *contexts[2];
+ UINT32 actsize, huffsize;
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++;
+ size = (sizes[0] << 8) | sizes[1];
if (size == 0)
{
/* loop over channels */
for (chnum = 0; chnum < channels; chnum++)
{
+ UINT8 *curdest = dest[chnum];
+
/* extract the size of this channel */
- size = *sizes++ << 8;
- size |= *sizes++;
+ size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
- /* copy the data */
- if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ /* extract data from the deltas */
+ if (dest[chnum] != NULL)
{
+ INT16 prevsample = 0;
for (sampnum = 0; sampnum < samples; sampnum++)
{
- output[0 ^ destxor] = input[0];
- output[1 ^ destxor] = input[1];
- output += 2;
- input += 2;
+ INT16 delta = (source[0] << 8) | source[1];
+ INT16 newsample = prevsample + delta;
+ prevsample = newsample;
+
+ curdest[0 ^ dxor] = newsample >> 8;
+ curdest[1 ^ dxor] = newsample;
+ source += 2;
+ curdest += 2;
}
}
else
- {
- input += size;
- output += size;
- }
+ source += 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)
+ /* extract the huffman trees */
+ hufferr = huffman_import_tree(state->audiohicontext, source, size, &actsize);
+ if (hufferr != HUFFERR_NONE)
return AVCERR_INVALID_DATA;
- input += actsize;
+ source += actsize;
+ huffsize = actsize;
+
+ hufferr = huffman_import_tree(state->audiolocontext, source, size, &actsize);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+ huffsize += actsize;
+ if (huffsize != size)
+ return AVCERR_INVALID_DATA;
+
+ /* set up the contexts */
+ contexts[0] = state->audiohicontext;
+ contexts[1] = state->audiolocontext;
/* 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++;
+ size = (sizes[chnum * 2 + 2] << 8) | sizes[chnum * 2 + 3];
/* decode the data */
- if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ if (dest[chnum] != NULL)
{
- hufferr = huffman_decode_data(state->audiocontext, input, size, output, samples * 2, &actsize);
+ UINT8 *deltabuf = state->audiodata + chnum * samples * 2;
+ hufferr = huffman_decode_data_interleaved(2, contexts, source, size, deltabuf, samples * 2, 1, 0, 0, &actsize);
if (hufferr != HUFFERR_NONE || actsize != size)
return AVCERR_INVALID_DATA;
}
/* advance */
- input += size;
- output += samples * 2;
+ source += size;
}
- /* 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)
+ if (dest[chnum] != NULL)
{
+ UINT8 *deltabuf = state->audiodata + chnum * samples * 2;
+ UINT8 *curdest = dest[chnum];
+ INT16 prevsample = 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;
+ INT16 delta = (deltabuf[0] << 8) | deltabuf[1];
+ INT16 newsample = prevsample + delta;
+ prevsample = newsample;
+
+ curdest[0 ^ dxor] = newsample >> 8;
+ curdest[1 ^ dxor] = newsample;
+ deltabuf += 2;
+ curdest += 2;
}
}
- else
- output += samples * 2;
- }
+
return AVCERR_NONE;
}
@@ -716,28 +802,11 @@ static avcomp_error decode_audio(avcomp_state *state, int channels, int samples,
compressed data stream
-------------------------------------------------*/
-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(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 dstride, UINT32 dxor)
{
- 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);
+ return decode_video_lossless(state, width, height, source, complength, dest, dstride, dxor);
else
return AVCERR_INVALID_DATA;
}
@@ -748,93 +817,42 @@ static avcomp_error decode_video(avcomp_state *state, int width, int height, int
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)
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor)
{
const UINT8 *sourceend = source + complength;
- const huffman_lookup_value *table1, *table2;
+ huffman_context *contexts[4];
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);
+ /* import the tables */
+ hufferr = huffman_deltarle_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);
+ hufferr = huffman_deltarle_import_tree(state->cbcontext, 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);
+ hufferr = huffman_deltarle_import_tree(state->crcontext, source, sourceend - source, &actsize);
if (hufferr != HUFFERR_NONE)
- return AVCERR_OUT_OF_MEMORY;
- hufferr = huffman_get_lookup_table(state->ccontext, &table2);
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+
+ /* set up the decoding contexts */
+ contexts[0] = state->ycontext;
+ contexts[1] = state->cbcontext;
+ contexts[2] = state->ycontext;
+ contexts[3] = state->crcontext;
+
+ /* decode to the destination */
+ hufferr = huffman_deltarle_decode_data_interleaved(4, contexts, source, sourceend - source, dest, width * 2, height, deststride, destxor, &actsize);
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_INVALID_DATA;
+ if (actsize != sourceend - source)
+ return AVCERR_INVALID_DATA;
return AVCERR_NONE;
}
diff --git a/src/lib/util/avcomp.h b/src/lib/util/avcomp.h
index 1571f644fb0..2223ae0e9b2 100644
--- a/src/lib/util/avcomp.h
+++ b/src/lib/util/avcomp.h
@@ -10,8 +10,10 @@
***************************************************************************/
#ifndef __AVCOMP_H__
+#define __AVCOMP_H__
#include "osdcore.h"
+#include "bitmap.h"
/***************************************************************************
@@ -19,22 +21,25 @@
***************************************************************************/
/* errors */
-enum _avcomp_error
+enum _avcomp_error
{
AVCERR_NONE = 0,
AVCERR_INVALID_DATA,
AVCERR_VIDEO_TOO_LARGE,
AVCERR_AUDIO_TOO_LARGE,
+ AVCERR_METADATA_TOO_LARGE,
AVCERR_OUT_OF_MEMORY,
- AVCERR_COMPRESSION_ERROR
+ AVCERR_COMPRESSION_ERROR,
+ AVCERR_TOO_MANY_CHANNELS,
+ AVCERR_INVALID_CONFIGURATION
};
typedef enum _avcomp_error avcomp_error;
/* default decompression parameters */
-#define AVCOMP_DECODE_META (1 << 0)
-#define AVCOMP_DECODE_VIDEO (1 << 1)
-#define AVCOMP_DECODE_AUDIO(x) (1 << (2 + (x)))
-#define AVCOMP_DECODE_DEFAULT (~0)
+#define AVCOMP_ENABLE_META (1 << 0)
+#define AVCOMP_ENABLE_VIDEO (1 << 1)
+#define AVCOMP_ENABLE_AUDIO(x) (1 << (2 + (x)))
+#define AVCOMP_ENABLE_DEFAULT (~0)
@@ -42,6 +47,35 @@ typedef enum _avcomp_error avcomp_error;
TYPE DEFINITIONS
***************************************************************************/
+/* compression configuration */
+typedef struct _av_codec_compress_config av_codec_compress_config;
+struct _av_codec_compress_config
+{
+ bitmap_t * video; /* pointer to video bitmap */
+ UINT32 channels; /* number of channels */
+ UINT32 samples; /* number of samples per channel */
+ INT16 * audio[16]; /* pointer to individual audio channels */
+ UINT32 metalength; /* length of metadata */
+ UINT8 * metadata; /* pointer to metadata buffer */
+};
+
+
+/* decompression configuration */
+typedef struct _av_codec_decompress_config av_codec_decompress_config;
+struct _av_codec_decompress_config
+{
+ bitmap_t * video; /* pointer to video bitmap */
+ UINT32 channels; /* number of channels */
+ UINT32 maxsamples; /* maximum number of samples per channel */
+ UINT32 * actsamples; /* actual number of samples per channel */
+ INT16 * audio[16]; /* pointer to individual audio channels */
+ UINT32 maxmetalength; /* maximum length of metadata */
+ UINT32 * actmetalength; /* actual length of metadata */
+ UINT8 * metadata; /* pointer to metadata buffer */
+};
+
+
+/* opaque state */
typedef struct _avcomp_state avcomp_state;
@@ -52,7 +86,9 @@ typedef struct _avcomp_state avcomp_state;
avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels);
void avcomp_free(avcomp_state *state);
-void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *videobuffer, UINT32 videostride, UINT32 videoxor, UINT32 audioxor);
+
+void avcomp_config_compress(avcomp_state *state, const av_codec_compress_config *config);
+void avcomp_config_decompress(avcomp_state *state, const av_codec_decompress_config *config);
avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength);
avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest);
diff --git a/src/lib/util/chd.c b/src/lib/util/chd.c
index 8f3aca2f66c..aa21bb8a1ae 100644
--- a/src/lib/util/chd.c
+++ b/src/lib/util/chd.c
@@ -177,7 +177,8 @@ typedef struct _av_codec_data av_codec_data;
struct _av_codec_data
{
avcomp_state * compstate;
- av_codec_decompress_config decompconfig;
+ av_codec_compress_config compress;
+ av_codec_decompress_config decompress;
};
@@ -1382,7 +1383,7 @@ chd_error chd_compress_hunk(chd_file *chd, const void *data, double *curratio)
/* if we are lossy, then we need to use the decompressed version in */
/* the cache as our MD5/SHA1 source */
- crcdata = chd->codecintf->lossy ? chd->cache : data;
+ crcdata = (chd->codecintf->lossy || data == NULL) ? chd->cache : data;
/* update the MD5/SHA1 */
bytestochecksum = chd->header.hunkbytes;
@@ -1933,10 +1934,12 @@ static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UIN
chd->maxhunk = hunknum;
/* first compute the CRC of the original data */
- newentry.crc = crc32(0, &src[0], chd->header.hunkbytes);
+ newentry.crc = 0;
+ if (src != NULL)
+ newentry.crc = crc32(0, &src[0], chd->header.hunkbytes);
/* if we're not a lossy codec, compute the CRC and look for matches */
- if (!chd->codecintf->lossy)
+ if (!chd->codecintf->lossy && src != NULL)
{
/* some extra stuff for zlib+ compression */
if (chd->header.compression >= CHDCOMPRESSION_ZLIB_PLUS)
@@ -1986,7 +1989,7 @@ static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UIN
err = (*chd->codecintf->compress)(chd, src, &bytes);
/* if that worked, and we're lossy, decompress and CRC the result */
- if (err == CHDERR_NONE && chd->codecintf->lossy)
+ if (err == CHDERR_NONE && (chd->codecintf->lossy || src == NULL))
{
err = (*chd->codecintf->decompress)(chd, bytes, chd->cache);
if (err == CHDERR_NONE)
@@ -2710,9 +2713,6 @@ static chd_error av_codec_init(chd_file *chd)
memset(data, 0, sizeof(*data));
chd->codecdata = data;
- /* set up the default decompression configuration */
- data->decompconfig.decode_mask = AVCOMP_DECODE_DEFAULT;
-
/* attempt to do a post-init now; if we're creating a new CHD, this won't work */
/* but that's ok */
av_codec_postinit(chd);
@@ -2759,10 +2759,13 @@ static chd_error av_codec_compress(chd_file *chd, const void *src, UINT32 *lengt
}
/* make sure short frames are padded with 0 */
- size = av_raw_data_size(src);
- while (size < chd->header.hunkbytes)
- if (((const UINT8 *)src)[size++] != 0)
- return CHDERR_INVALID_DATA;
+ if (src != NULL)
+ {
+ size = av_raw_data_size(src);
+ while (size < chd->header.hunkbytes)
+ if (((const UINT8 *)src)[size++] != 0)
+ return CHDERR_INVALID_DATA;
+ }
/* encode the audio and video */
averr = avcomp_encode_data(data->compstate, src, chd->compressed, length);
@@ -2800,9 +2803,12 @@ static chd_error av_codec_decompress(chd_file *chd, UINT32 srclength, void *dest
return CHDERR_DECOMPRESSION_ERROR;
/* pad short frames with 0 */
- size = av_raw_data_size(dest);
- while (size < chd->header.hunkbytes)
- ((UINT8 *)dest)[size++] = 0;
+ if (dest != NULL)
+ {
+ size = av_raw_data_size(dest);
+ while (size < chd->header.hunkbytes)
+ ((UINT8 *)dest)[size++] = 0;
+ }
return CHDERR_NONE;
}
@@ -2817,12 +2823,21 @@ static chd_error av_codec_config(chd_file *chd, int param, void *config)
{
av_codec_data *data = chd->codecdata;
+ /* if we're getting the compression configuration, apply it now */
+ if (param == AV_CODEC_COMPRESS_CONFIG)
+ {
+ data->compress = *(av_codec_compress_config *)config;
+ if (data->compstate != NULL)
+ avcomp_config_compress(data->compstate, &data->compress);
+ return CHDERR_NONE;
+ }
+
/* if we're getting the decompression configuration, apply it now */
- if (param == AV_CODEC_DECOMPRESS_CONFIG)
+ else if (param == AV_CODEC_DECOMPRESS_CONFIG)
{
- data->decompconfig = *(av_codec_decompress_config *)config;
+ data->decompress = *(av_codec_decompress_config *)config;
if (data->compstate != NULL)
- avcomp_decompress_config(data->compstate, data->decompconfig.decode_mask, data->decompconfig.video_buffer, data->decompconfig.video_stride, data->decompconfig.video_xor, data->decompconfig.audio_xor);
+ avcomp_config_decompress(data->compstate, &data->decompress);
return CHDERR_NONE;
}
@@ -2869,6 +2884,7 @@ static chd_error av_codec_postinit(chd_file *chd)
data->compstate = avcomp_init(width, height, channels);
/* configure the codec */
- avcomp_decompress_config(data->compstate, data->decompconfig.decode_mask, data->decompconfig.video_buffer, data->decompconfig.video_stride, data->decompconfig.video_xor, data->decompconfig.audio_xor);
+ avcomp_config_compress(data->compstate, &data->compress);
+ avcomp_config_decompress(data->compstate, &data->decompress);
return CHDERR_NONE;
}
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
index 6e70e3e18f8..7914a9161f9 100644
--- a/src/lib/util/chd.h
+++ b/src/lib/util/chd.h
@@ -15,7 +15,9 @@
#define __CHD_H__
#include "osdcore.h"
+#include "bitmap.h"
#include "corefile.h"
+#include "avcomp.h"
/***************************************************************************
@@ -108,8 +110,8 @@
#define CHDCOMPRESSION_AV 3
/* A/V codec configuration parameters */
-#define AV_CODEC_COMPRESS_CONFIG 0
-#define AV_CODEC_DECOMPRESS_CONFIG 1
+#define AV_CODEC_COMPRESS_CONFIG 1
+#define AV_CODEC_DECOMPRESS_CONFIG 2
/* metadata parameters */
#define CHDMETATAG_WILDCARD 0
@@ -180,35 +182,23 @@ typedef struct _chd_file chd_file;
typedef struct _chd_header chd_header;
struct _chd_header
{
- UINT32 length; /* length of header data */
- UINT32 version; /* drive format version */
- UINT32 flags; /* flags field */
- UINT32 compression; /* compression type */
- UINT32 hunkbytes; /* number of bytes per hunk */
- UINT32 totalhunks; /* total # of hunks represented */
- UINT64 logicalbytes; /* logical size of the data */
- UINT64 metaoffset; /* offset in file of first metadata */
- UINT8 md5[CHD_MD5_BYTES]; /* MD5 checksum of raw data */
- UINT8 parentmd5[CHD_MD5_BYTES]; /* MD5 checksum of parent file */
- UINT8 sha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
- UINT8 parentsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of parent file */
-
- UINT32 obsolete_cylinders; /* obsolete field -- do not use! */
- UINT32 obsolete_sectors; /* obsolete field -- do not use! */
- UINT32 obsolete_heads; /* obsolete field -- do not use! */
- UINT32 obsolete_hunksize; /* obsolete field -- do not use! */
-};
-
-
-/* A/V codec decompression configuration */
-typedef struct _av_codec_decompress_config av_codec_decompress_config;
-struct _av_codec_decompress_config
-{
- UINT32 decode_mask; /* decoding mask */
- UINT8 * video_buffer; /* pointer to alternate video buffer */
- UINT32 video_stride; /* bytes between rows in video buffer */
- UINT32 video_xor; /* XOR to apply to bytes in video buffer */
- UINT32 audio_xor; /* XOR to apply to bytes in audio buffer */
+ UINT32 length; /* length of header data */
+ UINT32 version; /* drive format version */
+ UINT32 flags; /* flags field */
+ UINT32 compression; /* compression type */
+ UINT32 hunkbytes; /* number of bytes per hunk */
+ UINT32 totalhunks; /* total # of hunks represented */
+ UINT64 logicalbytes; /* logical size of the data */
+ UINT64 metaoffset; /* offset in file of first metadata */
+ UINT8 md5[CHD_MD5_BYTES]; /* MD5 checksum of raw data */
+ UINT8 parentmd5[CHD_MD5_BYTES]; /* MD5 checksum of parent file */
+ UINT8 sha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
+ UINT8 parentsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of parent file */
+
+ UINT32 obsolete_cylinders; /* obsolete field -- do not use! */
+ UINT32 obsolete_sectors; /* obsolete field -- do not use! */
+ UINT32 obsolete_heads; /* obsolete field -- do not use! */
+ UINT32 obsolete_hunksize; /* obsolete field -- do not use! */
};
diff --git a/src/lib/util/huffman.c b/src/lib/util/huffman.c
index de6a269c54a..7bbd3ae0baf 100644
--- a/src/lib/util/huffman.c
+++ b/src/lib/util/huffman.c
@@ -64,6 +64,37 @@
4M samples -> 31 bits max
8M samples -> 32 bits max
+****************************************************************************
+
+ Delta-RLE encoding works as follows:
+
+ Starting value is assumed to be 0. All data is encoded as a delta
+ from the previous value, such that final[i] = final[i - 1] + delta.
+ Long runs of 0s are RLE-encoded as follows:
+
+ 0x100 = repeat count of 8
+ 0x101 = repeat count of 9
+ 0x102 = repeat count of 10
+ 0x103 = repeat count of 11
+ 0x104 = repeat count of 12
+ 0x105 = repeat count of 13
+ 0x106 = repeat count of 14
+ 0x107 = repeat count of 15
+ 0x108 = repeat count of 16
+ 0x109 = repeat count of 32
+ 0x10a = repeat count of 64
+ 0x10b = repeat count of 128
+ 0x10c = repeat count of 256
+ 0x10d = repeat count of 512
+ 0x10e = repeat count of 1024
+ 0x10f = repeat count of 2048
+
+ Note that repeat counts are reset at the end of a row, so if a 0 run
+ extends to the end of a row, a large repeat count may be used.
+
+ The reason for starting the run counts at 8 is that 0 is expected to
+ be the most common symbol, and is typically encoded in 1 or 2 bits.
+
***************************************************************************/
#include "huffman.h"
@@ -74,7 +105,21 @@
CONSTANTS
***************************************************************************/
-#define MAX_HUFFMAN_NODES (256 + 256)
+#define HUFFMAN_CODES 256
+#define HUFFMAN_DELTARLE_CODES (HUFFMAN_CODES + 16)
+
+#define MAX_HUFFMAN_CODES (HUFFMAN_DELTARLE_CODES)
+#define MAX_HUFFMAN_NODES (MAX_HUFFMAN_CODES + MAX_HUFFMAN_CODES)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define MAKE_LOOKUP(code,bits) (((code) << 6) | ((bits) & 0x1f))
+#define LOOKUP_CODE(val) ((val) >> 6)
+#define LOOKUP_BITS(val) ((val) & 0x1f)
@@ -85,37 +130,39 @@
typedef struct _bit_buffer bit_buffer;
struct _bit_buffer
{
- UINT32 buffer;
- int bits;
+ UINT32 buffer; /* current bit accumulator */
+ int bits; /* number of bits in the accumulator */
union
{
- const UINT8 *read;
- UINT8 * write;
+ const UINT8 * read; /* read pointer */
+ UINT8 * write; /* write pointer */
} data;
- UINT32 doffset;
- UINT32 dlength;
- int overflow;
+ UINT32 doffset; /* byte offset within the data */
+ UINT32 dlength; /* length of the data */
+ int overflow; /* flag: true if we read/wrote past the end */
};
typedef struct _huffman_node huffman_node;
struct _huffman_node
{
- huffman_node * parent;
- UINT32 count;
- UINT32 weight;
- UINT32 bits;
- UINT8 numbits;
+ huffman_node * parent; /* pointer to parent node */
+ UINT32 count; /* number of hits on this node */
+ UINT32 weight; /* assigned weight of this node */
+ UINT32 bits; /* bits used to encode the node */
+ UINT8 numbits; /* number of bits needed for this node */
};
struct _huffman_context
{
- UINT8 maxbits;
- UINT8 lookupdirty;
- huffman_node huffnode[MAX_HUFFMAN_NODES];
- UINT32 lookupmask;
- huffman_lookup_value *lookup;
+ UINT8 maxbits; /* maximum bits per code */
+ UINT8 lookupdirty; /* TRUE if the lookup table is dirty */
+ UINT8 prevdata; /* value of the previous data (for delta-RLE encoding) */
+ UINT32 datahisto[MAX_HUFFMAN_CODES]; /* histogram of data values */
+ int rleremaining; /* number of RLE bytes remaining (for delta-RLE encoding) */
+ huffman_node huffnode[MAX_HUFFMAN_NODES]; /* array of nodes */
+ huffman_lookup_value * lookup; /* pointer to the lookup table */
};
@@ -124,11 +171,16 @@ struct _huffman_context
PROTOTYPES
***************************************************************************/
-static void huffman_write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits);
-static int CLIB_DECL huffman_tree_node_compare(const void *item1, const void *item2);
-static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight);
-static huffman_error huffman_assign_canonical_codes(huffman_context *context);
-static huffman_error huffman_build_lookup_table(huffman_context *context);
+static huffman_error huffman_deltarle_decode_data_interleaved_0102(huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
+
+static huffman_error import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength, UINT32 numcodes);
+static huffman_error export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength, UINT32 numcodes);
+static void write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits);
+static int CLIB_DECL tree_node_compare(const void *item1, const void *item2);
+static huffman_error compute_optimal_tree(huffman_context *context, const UINT32 *datahisto, UINT32 numcodes);
+static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight, UINT32 numcodes);
+static huffman_error assign_canonical_codes(huffman_context *context, UINT32 numcodes);
+static huffman_error build_lookup_table(huffman_context *context, UINT32 numcodes);
@@ -223,7 +275,7 @@ INLINE void bit_buffer_read_init(bit_buffer *bitbuf, const UINT8 *data, UINT32 d
/*-------------------------------------------------
bit_buffer_read - read 'numbits' bits from
- the buffer, returning the right-justified
+ the buffer, returning them right-justified
-------------------------------------------------*/
INLINE UINT32 bit_buffer_read(bit_buffer *bitbuf, int numbits)
@@ -253,6 +305,46 @@ INLINE UINT32 bit_buffer_read(bit_buffer *bitbuf, int numbits)
/*-------------------------------------------------
+ bit_buffer_peek - peek ahead and return
+ 'numbits' bits from the buffer, returning
+ them right-justified
+-------------------------------------------------*/
+
+INLINE UINT32 bit_buffer_peek(bit_buffer *bitbuf, int numbits)
+{
+ /* fetch data if we need more */
+ if (numbits > bitbuf->bits)
+ {
+ while (bitbuf->bits <= 24)
+ {
+ if (bitbuf->doffset < bitbuf->dlength)
+ bitbuf->buffer |= bitbuf->data.read[bitbuf->doffset] << (24 - bitbuf->bits);
+ bitbuf->doffset++;
+ bitbuf->bits += 8;
+ }
+ if (numbits > bitbuf->bits)
+ bitbuf->overflow = TRUE;
+ }
+
+ /* return the data */
+ return bitbuf->buffer >> (32 - numbits);
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_remove - remove 'numbits' bits
+ from the bit buffer; this presupposes that
+ at least 'numbits' are present
+-------------------------------------------------*/
+
+INLINE void bit_buffer_remove(bit_buffer *bitbuf, int numbits)
+{
+ bitbuf->buffer <<= numbits;
+ bitbuf->bits -= numbits;
+}
+
+
+/*-------------------------------------------------
bit_buffer_read_offset - return the current
rounded byte reading offset
-------------------------------------------------*/
@@ -270,6 +362,51 @@ INLINE UINT32 bit_buffer_read_offset(bit_buffer *bitbuf)
}
+/*-------------------------------------------------
+ code_to_rlecount - number of RLE repetitions
+ encoded in a given byte
+-------------------------------------------------*/
+
+INLINE int code_to_rlecount(int code)
+{
+ if (code == 0x00)
+ return 1;
+ if (code <= 0x107)
+ return 8 + (code - 0x100);
+ return 16 << (code - 0x108);
+}
+
+
+/*-------------------------------------------------
+ rlecount_to_byte - return a byte encoding
+ the maximum RLE count less than or equal to
+ the provided amount
+-------------------------------------------------*/
+
+INLINE int rlecount_to_code(int rlecount)
+{
+ if (rlecount >= 2048)
+ return 0x10f;
+ if (rlecount >= 1024)
+ return 0x10e;
+ if (rlecount >= 512)
+ return 0x10d;
+ if (rlecount >= 256)
+ return 0x10c;
+ if (rlecount >= 128)
+ return 0x10b;
+ if (rlecount >= 64)
+ return 0x10a;
+ if (rlecount >= 32)
+ return 0x109;
+ if (rlecount >= 16)
+ return 0x108;
+ if (rlecount >= 8)
+ return 0x100 + (rlecount - 8);
+ return 0x00;
+}
+
+
/***************************************************************************
IMPLEMENTATION
@@ -294,7 +431,6 @@ huffman_error huffman_create_context(huffman_context **context, int maxbits)
/* set the info */
memset(*context, 0, sizeof(**context));
(*context)->maxbits = maxbits;
- (*context)->lookupmask = (1 << maxbits) - 1;
(*context)->lookupdirty = TRUE;
return HUFFERR_NONE;
@@ -315,401 +451,951 @@ void huffman_free_context(huffman_context *context)
/*-------------------------------------------------
- huffman_compute_tree - compute an optimal
- huffman tree for the given source data
+ huffman_import_tree - import a huffman tree
+ from a source data stream
-------------------------------------------------*/
-huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 sstride)
+huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
{
- UINT32 lowerweight, upperweight;
- UINT32 datahisto[256];
- int i;
+ return import_tree(context, source, slength, actlength, HUFFMAN_CODES);
+}
- /* build the data histogram */
- memset(datahisto, 0, sizeof(datahisto));
- for (i = 0; i < slength; i += sstride)
- datahisto[source[i]]++;
- /* binary search to achieve the optimum encoding */
- lowerweight = 0;
- upperweight = slength * 2;
- while (TRUE)
- {
- UINT32 curweight = (upperweight + lowerweight) / 2;
- int curmaxbits;
+/*-------------------------------------------------
+ huffman_export_tree - export a huffman tree
+ to a target data stream
+-------------------------------------------------*/
- /* build a tree using the current weight */
- curmaxbits = huffman_build_tree(context, datahisto, slength, curweight);
+huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ return export_tree(context, dest, dlength, actlength, HUFFMAN_CODES);
+}
- /* apply binary search here */
- if (curmaxbits <= context->maxbits)
- {
- lowerweight = curweight;
- /* early out if it worked with the raw weights, or if we're done searching */
- if (curweight == slength || (upperweight - lowerweight) <= 1)
- break;
- }
- else
- upperweight = curweight;
- }
+/*-------------------------------------------------
+ huffman_deltarle_import_tree - import a
+ huffman tree from a source data stream for
+ delta-RLE encoded data
+-------------------------------------------------*/
- /* assign canonical codes for all nodes based on their code lengths */
- return huffman_assign_canonical_codes(context);
+huffman_error huffman_deltarle_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
+{
+ return import_tree(context, source, slength, actlength, HUFFMAN_DELTARLE_CODES);
}
/*-------------------------------------------------
- huffman_import_tree - import a huffman tree
- from a source data stream
+ huffman__deltarle_export_tree - export a
+ huffman tree to a target data stream for
+ delta-RLE encoded data
-------------------------------------------------*/
-huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
+huffman_error huffman_deltarle_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
{
- huffman_error error;
- bit_buffer bitbuf;
- int curnode;
- int numbits;
+ return export_tree(context, dest, dlength, actlength, HUFFMAN_DELTARLE_CODES);
+}
- /* initialize the input buffer */
- bit_buffer_read_init(&bitbuf, source, slength);
- /* bits per entry depends on the maxbits */
- if (context->maxbits >= 16)
- numbits = 5;
- else if (context->maxbits >= 8)
- numbits = 4;
- else
- numbits = 3;
+/*-------------------------------------------------
+ huffman_compute_tree - compute an optimal
+ huffman tree for the given source data
+-------------------------------------------------*/
- /* loop until we read all the nodes */
- for (curnode = 0; curnode < 256; )
- {
- int nodebits = bit_buffer_read(&bitbuf, numbits);
+huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
+{
+ return huffman_compute_tree_interleaved(1, &context, source, swidth, sheight, sstride, sxor);
+}
- /* a non-one value is just raw */
- if (nodebits != 1)
- context->huffnode[curnode++].numbits = nodebits;
+huffman_error huffman_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
+{
+ UINT32 sx, sy, ctxnum;
+ huffman_error error;
+
+ /* initialize all nodes */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ memset(context->datahisto, 0, sizeof(context->datahisto));
+ }
- /* a one value is an escape code */
- else
+ /* iterate over "height" */
+ for (sy = 0; sy < sheight; sy++)
+ {
+ /* iterate over "width" */
+ for (sx = 0; sx < swidth; )
{
- nodebits = bit_buffer_read(&bitbuf, numbits);
-
- /* a double 1 is just a single 1 */
- if (nodebits == 1)
- context->huffnode[curnode++].numbits = nodebits;
-
- /* otherwise, we need one for value for the repeat count */
- else
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
{
- int repcount = bit_buffer_read(&bitbuf, numbits) + 3;
- while (repcount--)
- context->huffnode[curnode++].numbits = nodebits;
+ huffman_context *context = contexts[ctxnum];
+ context->datahisto[source[sx ^ sxor]]++;
}
}
+
+ /* advance to the next row */
+ source += sstride;
+ }
+
+ /* compute optimal trees for each */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ error = compute_optimal_tree(context, context->datahisto, HUFFMAN_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
}
+ return HUFFERR_NONE;
+}
- /* assign canonical codes for all nodes based on their code lengths */
- error = huffman_assign_canonical_codes(context);
- if (error != HUFFERR_NONE)
- return error;
- /* make sure we ended up with the right number */
- if (curnode != 256)
- return HUFFERR_INVALID_DATA;
+/*-------------------------------------------------
+ huffman_deltarle_compute_tree - compute an
+ optimal huffman tree for the given source
+ data, with pre-encoding as delta-RLE
+-------------------------------------------------*/
- *actlength = bit_buffer_read_offset(&bitbuf);
- return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+huffman_error huffman_deltarle_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
+{
+ return huffman_deltarle_compute_tree_interleaved(1, &context, source, swidth, sheight, sstride, sxor);
+}
+
+huffman_error huffman_deltarle_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor)
+{
+ UINT32 sx, sy, ctxnum;
+ huffman_error error;
+
+ /* initialize all nodes */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ memset(context->datahisto, 0, sizeof(context->datahisto));
+ context->prevdata = 0;
+ }
+
+ /* iterate over "height" */
+ for (sy = 0; sy < sheight; sy++)
+ {
+ /* reset RLE counts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ context->rleremaining = 0;
+ }
+
+ /* iterate over "width" */
+ for (sx = 0; sx < swidth; )
+ {
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ UINT8 newdata, delta;
+
+ /* if still counting RLE, do nothing */
+ if (context->rleremaining != 0)
+ {
+ context->rleremaining--;
+ continue;
+ }
+
+ /* fetch new data and compute the delta */
+ newdata = source[sx ^ sxor];
+ delta = newdata - context->prevdata;
+ context->prevdata = newdata;
+
+ /* 0 deltas scan forward for a count */
+ if (delta == 0)
+ {
+ int zerocount = 1;
+ int rlecode;
+ UINT32 scan;
+
+ /* count the number of consecutive values */
+ for (scan = sx + 1; scan < swidth; scan++)
+ if (contexts[scan % numcontexts] == context)
+ {
+ if (newdata == source[scan ^ sxor])
+ zerocount++;
+ else
+ break;
+ }
+
+ /* if we hit the end of row, maximize the count */
+ if (scan >= swidth && zerocount >= 8)
+ zerocount = 100000;
+
+ /* encode the maximal count we can */
+ rlecode = rlecount_to_code(zerocount);
+ context->datahisto[rlecode]++;
+
+ /* set up the remaining count */
+ context->rleremaining = code_to_rlecount(rlecode) - 1;
+ }
+ else
+ {
+ /* encode the actual delta */
+ context->datahisto[delta]++;
+ }
+ }
+ }
+
+ /* advance to the next row */
+ source += sstride;
+ }
+
+ /* compute optimal trees for each */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ error = compute_optimal_tree(context, context->datahisto, HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ return HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_export_tree - export a huffman tree
- to a target data stream
+ huffman_encode_data - encode data using the
+ given tree
-------------------------------------------------*/
-huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
{
+ return huffman_encode_data_interleaved(1, &context, source, swidth, sheight, sstride, sxor, dest, dlength, actlength);
+}
+
+huffman_error huffman_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ UINT32 sx, sy, ctxnum;
bit_buffer bitbuf;
- int repcount;
- int lastval;
- int numbits;
- int i;
/* initialize the output buffer */
bit_buffer_write_init(&bitbuf, dest, dlength);
+
+ /* iterate over "height" */
+ for (sy = 0; sy < sheight; sy++)
+ {
+ /* iterate over "width" */
+ for (sx = 0; sx < swidth; )
+ {
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ huffman_node *node = &context->huffnode[source[sx ^ sxor]];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ }
+ }
+
+ /* advance to the next row */
+ source += sstride;
+ }
- /* bits per entry depends on the maxbits */
- if (context->maxbits >= 16)
- numbits = 5;
- else if (context->maxbits >= 8)
- numbits = 4;
- else
- numbits = 3;
+ /* flush and return a status */
+ *actlength = bit_buffer_flush(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
- /* RLE encode the lengths */
- lastval = ~0;
- repcount = 0;
- for (i = 0; i < 256; i++)
- {
- int newval = context->huffnode[i].numbits;
- /* if we match the previous value, just bump the repcount */
- if (newval == lastval)
- repcount++;
+/*-------------------------------------------------
+ huffman_deltarle_encode_data - encode data
+ using the given tree with delta-RLE
+ pre-encoding
+-------------------------------------------------*/
- /* otherwise, we need to flush the previous repeats */
- else
+huffman_error huffman_deltarle_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ return huffman_deltarle_encode_data_interleaved(1, &context, source, swidth, sheight, sstride, sxor, dest, dlength, actlength);
+}
+
+huffman_error huffman_deltarle_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ UINT32 sx, sy, ctxnum;
+ bit_buffer bitbuf;
+
+ /* initialize the output buffer */
+ bit_buffer_write_init(&bitbuf, dest, dlength);
+
+ /* initialize the contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ context->prevdata = 0;
+ }
+
+ /* iterate over "height" */
+ for (sy = 0; sy < sheight; sy++)
+ {
+ /* reset RLE counts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
{
- if (repcount != 0)
- huffman_write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
- lastval = newval;
- repcount = 1;
+ huffman_context *context = contexts[ctxnum];
+ context->rleremaining = 0;
+ }
+
+ /* iterate over "width" */
+ for (sx = 0; sx < swidth; )
+ {
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, sx++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ UINT8 newdata, delta;
+ huffman_node *node;
+
+ /* if still counting RLE, do nothing */
+ if (context->rleremaining != 0)
+ {
+ context->rleremaining--;
+ continue;
+ }
+
+ /* fetch new data and compute the delta */
+ newdata = source[sx ^ sxor];
+ delta = newdata - context->prevdata;
+ context->prevdata = newdata;
+
+ /* 0 deltas scan forward for a count */
+ if (delta == 0)
+ {
+ int zerocount = 1;
+ int rlecode;
+ UINT32 scan;
+
+ /* count the number of consecutive values */
+ for (scan = sx + 1; scan < swidth; scan++)
+ if (contexts[scan % numcontexts] == context)
+ {
+ if (newdata == source[scan ^ sxor])
+ zerocount++;
+ else
+ break;
+ }
+
+ /* if we hit the end of row, maximize the count */
+ if (scan >= swidth && zerocount >= 8)
+ zerocount = 100000;
+
+ /* encode the maximal count we can */
+ rlecode = rlecount_to_code(zerocount);
+ node = &context->huffnode[rlecode];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+
+ /* set up the remaining count */
+ context->rleremaining = code_to_rlecount(rlecode) - 1;
+ }
+ else
+ {
+ /* encode the actual delta */
+ node = &context->huffnode[delta];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ }
+ }
}
+
+ /* advance to the next row */
+ source += sstride;
}
- /* flush the last value */
- huffman_write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
+ /* flush and return a status */
*actlength = bit_buffer_flush(&bitbuf);
return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_get_lookup_table - return a pointer to
- the lookup table
+ huffman_decode_data - decode data using the
+ given tree
-------------------------------------------------*/
-huffman_error huffman_get_lookup_table(huffman_context *context, const huffman_lookup_value **table)
+huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
{
+ const huffman_lookup_value *table;
+ int maxbits = context->maxbits;
+ huffman_error error;
+ bit_buffer bitbuf;
+ UINT32 dx, dy;
+
+ /* regenerate the lookup table if necessary */
if (context->lookupdirty)
{
- huffman_error error = huffman_build_lookup_table(context);
+ error = build_lookup_table(context, HUFFMAN_CODES);
if (error != HUFFERR_NONE)
return error;
}
- *table = context->lookup;
- return HUFFERR_NONE;
+ table = context->lookup;
+
+ /* initialize our bit buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
+
+ /* iterate over "height" */
+ for (dy = 0; dy < dheight; dy++)
+ {
+ /* iterate over "width" */
+ for (dx = 0; dx < dwidth; dx++)
+ {
+ huffman_lookup_value lookup;
+ UINT32 bits;
+
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* store the upper byte */
+ dest[dx ^ dxor] = LOOKUP_CODE(lookup);
+ }
+
+ /* advance to the next row */
+ dest += dstride;
+ }
+
+ /* determine the actual length and indicate overflow */
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_encode_data - encode data using the
- current tree
+ huffman_decode_data_interleaved - decode
+ interleaved data using multiple contexts
-------------------------------------------------*/
-huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+huffman_error huffman_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
{
+ UINT32 dx, dy, ctxnum;
+ huffman_error error;
bit_buffer bitbuf;
- UINT32 soffset;
- /* initialize the output buffer */
- bit_buffer_write_init(&bitbuf, dest, dlength);
+ /* regenerate the lookup tables if necessary */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ if (context->lookupdirty)
+ {
+ error = build_lookup_table(context, HUFFMAN_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ }
+
+ /* initialize our bit buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
- /* loop over source data and encode */
- for (soffset = 0; soffset < slength; soffset++)
+ /* iterate over "height" */
+ for (dy = 0; dy < dheight; dy++)
{
- huffman_node *node = &context->huffnode[source[soffset]];
- bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ /* iterate over "width" */
+ for (dx = 0; dx < dwidth; )
+ {
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, dx++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ huffman_lookup_value lookup;
+ UINT32 bits;
+
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, context->maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = context->lookup[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* store the upper byte */
+ dest[dx ^ dxor] = LOOKUP_CODE(lookup);
+ }
+ }
+
+ /* advance to the next row */
+ dest += dstride;
}
- *actlength = bit_buffer_flush(&bitbuf);
- return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+
+ /* determine the actual length and indicate overflow */
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_encode_data_interleaved_2 - encode
- alternating data with two contexts
+ huffman_deltarle_decode_data - decode data
+ using the given tree with delta-RLE
+ post-decoding
-------------------------------------------------*/
-huffman_error huffman_encode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+huffman_error huffman_deltarle_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
{
+ const huffman_lookup_value *table;
+ int maxbits = context->maxbits;
+ UINT32 rleremaining = 0;
+ huffman_error error;
+ UINT8 prevdata = 0;
bit_buffer bitbuf;
- UINT32 soffset;
+ UINT32 dx, dy;
- /* initialize the output buffer */
- bit_buffer_write_init(&bitbuf, dest, dlength);
+ /* regenerate the lookup table if necessary */
+ if (context->lookupdirty)
+ {
+ error = build_lookup_table(context, HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ table = context->lookup;
+
+ /* initialize our bit buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
- /* loop over source data and encode */
- for (soffset = 0; soffset < slength; soffset += 2)
+ /* iterate over "height" */
+ for (dy = 0; dy < dheight; dy++)
{
- huffman_node *node;
+ /* reset RLE counts */
+ rleremaining = 0;
- node = &context1->huffnode[source[soffset + 0]];
- bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ /* iterate over "width" */
+ for (dx = 0; dx < dwidth; dx++)
+ {
+ huffman_lookup_value lookup;
+ UINT32 bits;
+ int data;
+
+ /* if we have RLE remaining, just store that */
+ if (rleremaining != 0)
+ {
+ rleremaining--;
+ dest[dx ^ dxor] = prevdata;
+ continue;
+ }
+
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ prevdata += (UINT8)data;
+ else
+ rleremaining = code_to_rlecount(data) - 1;
- node = &context2->huffnode[source[soffset + 1]];
- bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ /* store the updated data value */
+ dest[dx ^ dxor] = prevdata;
+ }
+
+ /* advance to the next row */
+ dest += dstride;
}
- *actlength = bit_buffer_flush(&bitbuf);
- return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+
+ /* determine the actual length and indicate overflow */
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_decode_data - decode data using the
- current tree
+ huffman_deltarle_decode_data_interleaved -
+ decode data using multiple contexts and
+ delta-RLE post-decoding
-------------------------------------------------*/
-huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+huffman_error huffman_deltarle_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
{
- int maxbits = context->maxbits;
- int shiftbits = 32 - maxbits;
- const huffman_lookup_value *table;
- int overflow = FALSE;
+ UINT32 dx, dy, ctxnum;
huffman_error error;
- UINT32 doffset = 0;
- UINT32 soffset = 0;
- UINT32 bitbuf = 0;
- int sbits = 0;
+ bit_buffer bitbuf;
+
+ /* fast case the A/V Y/Cb/Y/Cr case */
+ if (numcontexts == 4 && contexts[0] == contexts[2] && contexts[0] != contexts[1] && contexts[1] != contexts[3] &&
+ contexts[0]->maxbits == contexts[1]->maxbits && contexts[0]->maxbits == contexts[3]->maxbits)
+ return huffman_deltarle_decode_data_interleaved_0102(contexts, source, slength, dest, dwidth, dheight, dstride, dxor, actlength);
+
+ /* regenerate the lookup tables if necessary */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ if (context->lookupdirty)
+ {
+ error = build_lookup_table(context, HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ context->prevdata = 0;
+ }
- /* regenerate the lookup table if necessary */
- error = huffman_get_lookup_table(context, &table);
- if (error != HUFFERR_NONE)
- return error;
+ /* initialize our bit buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
- /* decode until we process all of the destination data */
- for (doffset = 0; doffset < dlength; doffset++)
+ /* iterate over "height" */
+ for (dy = 0; dy < dheight; dy++)
{
- huffman_lookup_value lookup;
+ /* reset RLE counts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++)
+ {
+ huffman_context *context = contexts[ctxnum];
+ context->rleremaining = 0;
+ }
- /* if we don't have enough bits, load up the buffer */
- if (sbits < maxbits)
+ /* iterate over "width" */
+ for (dx = 0; dx < dwidth; )
{
- while (sbits <= 24)
+ /* iterate over contexts */
+ for (ctxnum = 0; ctxnum < numcontexts; ctxnum++, dx++)
{
- if (soffset < slength)
- bitbuf |= source[soffset] << (24 - sbits);
- soffset++;
- sbits += 8;
+ huffman_context *context = contexts[ctxnum];
+ huffman_lookup_value lookup;
+ UINT32 bits;
+ int data;
+
+ /* if we have RLE remaining, just store that */
+ if (context->rleremaining != 0)
+ {
+ context->rleremaining--;
+ dest[dx ^ dxor] = context->prevdata;
+ continue;
+ }
+
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, context->maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = context->lookup[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ context->prevdata += (UINT8)data;
+ else
+ context->rleremaining = code_to_rlecount(data) - 1;
+
+ /* store the updated data value */
+ dest[dx ^ dxor] = context->prevdata;
}
- if (sbits < maxbits)
- overflow = TRUE;
}
+
+ /* advance to the next row */
+ dest += dstride;
+ }
- /* lookup the data */
- lookup = table[bitbuf >> shiftbits];
+ /* determine the actual length and indicate overflow */
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
- /* store the upper byte */
- dest[doffset] = lookup >> 8;
- /* count the bits */
- lookup &= 0x1f;
- bitbuf <<= lookup;
- sbits -= lookup;
+/*-------------------------------------------------
+ huffman_deltarle_decode_data_interleaved_0102 -
+ decode data using 3 unique contexts in
+ 0/1/0/2 order (used for Y/Cb/Y/Cr encoding)
+-------------------------------------------------*/
+
+static huffman_error huffman_deltarle_decode_data_interleaved_0102(huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength)
+{
+ const huffman_lookup_value *table02, *table1, *table3;
+ int rleremaining02, rleremaining1, rleremaining3;
+ UINT8 prevdata02 = 0, prevdata1 = 0, prevdata3 = 0;
+ int maxbits = contexts[0]->maxbits;
+ huffman_error error;
+ bit_buffer bitbuf;
+ UINT32 dx, dy;
+
+ /* regenerate the lookup tables if necessary */
+ if (contexts[0]->lookupdirty)
+ {
+ error = build_lookup_table(contexts[0], HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ if (contexts[1]->lookupdirty)
+ {
+ error = build_lookup_table(contexts[1], HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
}
+ if (contexts[3]->lookupdirty)
+ {
+ error = build_lookup_table(contexts[3], HUFFMAN_DELTARLE_CODES);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+
+ /* cache the tables locally */
+ table02 = contexts[0]->lookup;
+ table1 = contexts[1]->lookup;
+ table3 = contexts[3]->lookup;
- /* back off soffset while we have whole bytes */
- while (sbits >= 8)
+ /* initialize our bit buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
+
+ /* iterate over "height" */
+ for (dy = 0; dy < dheight; dy++)
{
- sbits -= 8;
- soffset--;
+ /* reset RLE counts */
+ rleremaining02 = rleremaining1 = rleremaining3 = 0;
+
+ /* iterate over "width" */
+ for (dx = 0; dx < dwidth; dx += 4)
+ {
+ huffman_lookup_value lookup;
+ UINT32 bits;
+ int data;
+
+ /* ----- offset 0 ----- */
+
+ /* if we have RLE remaining, just store that */
+ if (rleremaining02 != 0)
+ rleremaining02--;
+ else
+ {
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table02[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ prevdata02 += (UINT8)data;
+ else
+ rleremaining02 = code_to_rlecount(data) - 1;
+ }
+
+ /* store the updated data value */
+ dest[(dx + 0) ^ dxor] = prevdata02;
+
+ /* ----- offset 1 ----- */
+
+ /* if we have RLE remaining, just store that */
+ if (rleremaining1 != 0)
+ rleremaining1--;
+ else
+ {
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table1[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ prevdata1 += (UINT8)data;
+ else
+ rleremaining1 = code_to_rlecount(data) - 1;
+ }
+
+ /* store the updated data value */
+ dest[(dx + 1) ^ dxor] = prevdata1;
+
+ /* ----- offset 2 (same as 0) ----- */
+
+ /* if we have RLE remaining, just store that */
+ if (rleremaining02 != 0)
+ rleremaining02--;
+ else
+ {
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table02[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ prevdata02 += (UINT8)data;
+ else
+ rleremaining02 = code_to_rlecount(data) - 1;
+ }
+
+ /* store the updated data value */
+ dest[(dx + 2) ^ dxor] = prevdata02;
+
+ /* ----- offset 3 ----- */
+
+ /* if we have RLE remaining, just store that */
+ if (rleremaining3 != 0)
+ rleremaining3--;
+ else
+ {
+ /* peek ahead to get maxbits worth of data */
+ bits = bit_buffer_peek(&bitbuf, maxbits);
+
+ /* look it up, then remove the actual number of bits for this code */
+ lookup = table3[bits];
+ bit_buffer_remove(&bitbuf, LOOKUP_BITS(lookup));
+
+ /* compute the data and handle RLE decoding */
+ data = LOOKUP_CODE(lookup);
+
+ /* if not an RLE special, just add to the previous; otherwise, start counting RLE */
+ if (data < 0x100)
+ prevdata3 += (UINT8)data;
+ else
+ rleremaining3 = code_to_rlecount(data) - 1;
+ }
+
+ /* store the updated data value */
+ dest[(dx + 3) ^ dxor] = prevdata3;
+ }
+
+ /* advance to the next row */
+ dest += dstride;
}
- *actlength = soffset;
- return overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+
+ /* determine the actual length and indicate overflow */
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
/*-------------------------------------------------
- huffman_decode_data_interleaved_2 - decode
- interleaved data using two contexts
+ import_tree - import a huffman tree from a
+ source data stream
-------------------------------------------------*/
-huffman_error huffman_decode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+static huffman_error import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength, UINT32 numcodes)
{
- int maxbits1 = context1->maxbits, maxbits2 = context2->maxbits;
- const huffman_lookup_value *table1, *table2;
- int shiftbits1 = 32 - maxbits1;
- int shiftbits2 = 32 - maxbits2;
- int overflow = FALSE;
huffman_error error;
- UINT32 doffset = 0;
- UINT32 soffset = 0;
- UINT32 bitbuf = 0;
- int sbits = 0;
+ bit_buffer bitbuf;
+ int curnode;
+ int numbits;
- /* regenerate the lookup table if necessary */
- error = huffman_get_lookup_table(context1, &table1);
- if (error != HUFFERR_NONE)
- return error;
- error = huffman_get_lookup_table(context2, &table2);
- if (error != HUFFERR_NONE)
- return error;
+ /* initialize the input buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
+
+ /* bits per entry depends on the maxbits */
+ if (context->maxbits >= 16)
+ numbits = 5;
+ else if (context->maxbits >= 8)
+ numbits = 4;
+ else
+ numbits = 3;
- /* decode until we process all of the destination data */
- for (doffset = 0; doffset < dlength; doffset += 2)
+ /* loop until we read all the nodes */
+ for (curnode = 0; curnode < numcodes; )
{
- huffman_lookup_value lookup;
+ int nodebits = bit_buffer_read(&bitbuf, numbits);
+
+ /* a non-one value is just raw */
+ if (nodebits != 1)
+ context->huffnode[curnode++].numbits = nodebits;
- /* if we don't have enough bits, load up the buffer */
- if (sbits < maxbits1)
+ /* a one value is an escape code */
+ else
{
- while (sbits <= 24)
+ nodebits = bit_buffer_read(&bitbuf, numbits);
+
+ /* a double 1 is just a single 1 */
+ if (nodebits == 1)
+ context->huffnode[curnode++].numbits = nodebits;
+
+ /* otherwise, we need one for value for the repeat count */
+ else
{
- if (soffset < slength)
- bitbuf |= source[soffset] << (24 - sbits);
- soffset++;
- sbits += 8;
+ int repcount = bit_buffer_read(&bitbuf, numbits) + 3;
+ while (repcount--)
+ context->huffnode[curnode++].numbits = nodebits;
}
- if (sbits < maxbits1)
- overflow = TRUE;
}
+ }
- /* lookup the data */
- lookup = table1[bitbuf >> shiftbits1];
+ /* assign canonical codes for all nodes based on their code lengths */
+ error = assign_canonical_codes(context, numcodes);
+ if (error != HUFFERR_NONE)
+ return error;
- /* store the upper byte */
- dest[doffset + 0] = lookup >> 8;
+ /* make sure we ended up with the right number */
+ if (curnode != numcodes)
+ return HUFFERR_INVALID_DATA;
- /* count the bits */
- lookup &= 0x1f;
- bitbuf <<= lookup;
- sbits -= lookup;
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
- /* if we don't have enough bits, load up the buffer */
- if (sbits < maxbits2)
- {
- while (sbits <= 24)
- {
- if (soffset < slength)
- bitbuf |= source[soffset] << (24 - sbits);
- soffset++;
- sbits += 8;
- }
- if (sbits < maxbits2)
- overflow = TRUE;
- }
- /* lookup the data */
- lookup = table2[bitbuf >> shiftbits2];
+/*-------------------------------------------------
+ export_tree - export a huffman tree to a
+ target data stream
+-------------------------------------------------*/
- /* store the upper byte */
- dest[doffset + 1] = lookup >> 8;
+static huffman_error export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength, UINT32 numcodes)
+{
+ bit_buffer bitbuf;
+ int repcount;
+ int lastval;
+ int numbits;
+ int i;
- /* count the bits */
- lookup &= 0x1f;
- bitbuf <<= lookup;
- sbits -= lookup;
- }
+ /* initialize the output buffer */
+ bit_buffer_write_init(&bitbuf, dest, dlength);
- /* back off soffset while we have whole bytes */
- while (sbits >= 8)
+ /* bits per entry depends on the maxbits */
+ if (context->maxbits >= 16)
+ numbits = 5;
+ else if (context->maxbits >= 8)
+ numbits = 4;
+ else
+ numbits = 3;
+
+ /* RLE encode the lengths */
+ lastval = ~0;
+ repcount = 0;
+ for (i = 0; i < numcodes; i++)
{
- sbits -= 8;
- soffset--;
+ int newval = context->huffnode[i].numbits;
+
+ /* if we match the previous value, just bump the repcount */
+ if (newval == lastval)
+ repcount++;
+
+ /* otherwise, we need to flush the previous repeats */
+ else
+ {
+ if (repcount != 0)
+ write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
+ lastval = newval;
+ repcount = 1;
+ }
}
- *actlength = soffset;
- return overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+
+ /* flush the last value */
+ write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
+ *actlength = bit_buffer_flush(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}
/*-------------------------------------------------
- huffman_write_rle_tree_bits - write an RLE
- encoded set of data to a target stream
+ write_rle_tree_bits - write an RLE encoded
+ set of data to a target stream
-------------------------------------------------*/
-static void huffman_write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits)
+static void write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits)
{
/* loop until we have output all of the repeats */
while (repcount > 0)
@@ -743,11 +1429,11 @@ static void huffman_write_rle_tree_bits(bit_buffer *bitbuf, int value, int repco
/*-------------------------------------------------
- huffman_tree_node_compare - compare two
- tree nodes by weight
+ tree_node_compare - compare two tree nodes
+ by weight
-------------------------------------------------*/
-static int CLIB_DECL huffman_tree_node_compare(const void *item1, const void *item2)
+static int CLIB_DECL tree_node_compare(const void *item1, const void *item2)
{
const huffman_node *node1 = *(const huffman_node **)item1;
const huffman_node *node2 = *(const huffman_node **)item2;
@@ -756,13 +1442,58 @@ static int CLIB_DECL huffman_tree_node_compare(const void *item1, const void *it
/*-------------------------------------------------
+ compute_optimal_tree - common backend for
+ computing a tree based on the data histogram
+-------------------------------------------------*/
+
+static huffman_error compute_optimal_tree(huffman_context *context, const UINT32 *datahisto, UINT32 numcodes)
+{
+ UINT32 lowerweight, upperweight;
+ UINT32 sdatacount;
+ int i;
+
+ /* compute the number of data items in the histogram */
+ sdatacount = 0;
+ for (i = 0; i < numcodes; i++)
+ sdatacount += datahisto[i];
+
+ /* binary search to achieve the optimum encoding */
+ lowerweight = 0;
+ upperweight = sdatacount * 2;
+ while (TRUE)
+ {
+ UINT32 curweight = (upperweight + lowerweight) / 2;
+ int curmaxbits;
+
+ /* build a tree using the current weight */
+ curmaxbits = huffman_build_tree(context, datahisto, sdatacount, curweight, numcodes);
+
+ /* apply binary search here */
+ if (curmaxbits <= context->maxbits)
+ {
+ lowerweight = curweight;
+
+ /* early out if it worked with the raw weights, or if we're done searching */
+ if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
+ break;
+ }
+ else
+ upperweight = curweight;
+ }
+
+ /* assign canonical codes for all nodes based on their code lengths */
+ return assign_canonical_codes(context, numcodes);
+}
+
+
+/*-------------------------------------------------
huffman_build_tree - build a huffman tree
based on the data distribution
-------------------------------------------------*/
-static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight)
+static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight, UINT32 numcodes)
{
- huffman_node *list[256];
+ huffman_node *list[MAX_HUFFMAN_CODES];
int listitems;
int nextalloc;
int maxbits;
@@ -770,8 +1501,8 @@ static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto,
/* make a list of all non-zero nodes */
listitems = 0;
- memset(context->huffnode, 0, 256 * sizeof(context->huffnode[0]));
- for (i = 0; i < 256; i++)
+ memset(context->huffnode, 0, numcodes * sizeof(context->huffnode[0]));
+ for (i = 0; i < numcodes; i++)
if (datahisto[i] != 0)
{
list[listitems++] = &context->huffnode[i];
@@ -784,10 +1515,10 @@ static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto,
}
/* sort the list by weight, largest weight first */
- qsort(list, listitems, sizeof(list[0]), huffman_tree_node_compare);
+ qsort(list, listitems, sizeof(list[0]), tree_node_compare);
/* now build the tree */
- nextalloc = 256;
+ nextalloc = MAX_HUFFMAN_CODES;
while (listitems > 1)
{
huffman_node *node0, *node1, *newnode;
@@ -815,7 +1546,7 @@ static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto,
/* compute the number of bits in each code, and fill in another histogram */
maxbits = 0;
- for (i = 0; i < 256; i++)
+ for (i = 0; i < numcodes; i++)
{
huffman_node *node = &context->huffnode[i];
node->numbits = 0;
@@ -841,12 +1572,12 @@ static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto,
/*-------------------------------------------------
- huffman_assign_canonical_codes - assign
+ assign_canonical_codes - assign
canonical codes to all the nodes based on the
number of bits in each
-------------------------------------------------*/
-static huffman_error huffman_assign_canonical_codes(huffman_context *context)
+static huffman_error assign_canonical_codes(huffman_context *context, UINT32 numcodes)
{
UINT32 bithisto[33];
int curstart;
@@ -854,7 +1585,7 @@ static huffman_error huffman_assign_canonical_codes(huffman_context *context)
/* build up a histogram of bit lengths */
memset(bithisto, 0, sizeof(bithisto));
- for (i = 0; i < 256; i++)
+ for (i = 0; i < numcodes; i++)
{
huffman_node *node = &context->huffnode[i];
if (node->numbits > context->maxbits)
@@ -875,7 +1606,7 @@ static huffman_error huffman_assign_canonical_codes(huffman_context *context)
}
/* now assign canonical codes */
- for (i = 0; i < 256; i++)
+ for (i = 0; i < numcodes; i++)
{
huffman_node *node = &context->huffnode[i];
if (node->numbits > 0)
@@ -889,11 +1620,11 @@ static huffman_error huffman_assign_canonical_codes(huffman_context *context)
/*-------------------------------------------------
- huffman_build_lookup_table - build a lookup
+ build_lookup_table - build a lookup
table for fast decoding
-------------------------------------------------*/
-static huffman_error huffman_build_lookup_table(huffman_context *context)
+static huffman_error build_lookup_table(huffman_context *context, UINT32 numcodes)
{
int i;
@@ -904,7 +1635,7 @@ static huffman_error huffman_build_lookup_table(huffman_context *context)
return HUFFERR_OUT_OF_MEMORY;
/* now build */
- for (i = 0; i < 256; i++)
+ for (i = 0; i < numcodes; i++)
{
huffman_node *node = &context->huffnode[i];
if (node->numbits > 0)
@@ -918,7 +1649,7 @@ static huffman_error huffman_build_lookup_table(huffman_context *context)
huffman_lookup_value value;
/* set up the entry */
- value = (i << 8) | node->numbits;
+ value = (i << 6) | node->numbits;
/* fill all matching entries */
dest = &context->lookup[start];
diff --git a/src/lib/util/huffman.h b/src/lib/util/huffman.h
index e705b8b9621..b2ef2701955 100644
--- a/src/lib/util/huffman.h
+++ b/src/lib/util/huffman.h
@@ -26,7 +26,8 @@ enum _huffman_error
HUFFERR_INVALID_DATA,
HUFFERR_INPUT_BUFFER_TOO_SMALL,
HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
- HUFFERR_INTERNAL_INCONSISTENCY
+ HUFFERR_INTERNAL_INCONSISTENCY,
+ HUFFERR_TOO_MANY_CONTEXTS
};
typedef enum _huffman_error huffman_error;
@@ -49,14 +50,24 @@ typedef struct _huffman_context huffman_context;
huffman_error huffman_create_context(huffman_context **context, int maxbits);
void huffman_free_context(huffman_context *context);
-huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 sstride);
huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength);
huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
-huffman_error huffman_get_lookup_table(huffman_context *context, const huffman_lookup_value **table);
-
-huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
-huffman_error huffman_encode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
-huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
-huffman_error huffman_decode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_deltarle_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength);
+huffman_error huffman_deltarle_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+
+huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
+huffman_error huffman_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
+huffman_error huffman_deltarle_compute_tree(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
+huffman_error huffman_deltarle_compute_tree_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor);
+
+huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_deltarle_encode_data(huffman_context *context, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_deltarle_encode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 swidth, UINT32 sheight, UINT32 sstride, UINT32 sxor, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+
+huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
+huffman_error huffman_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
+huffman_error huffman_deltarle_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
+huffman_error huffman_deltarle_decode_data_interleaved(int numcontexts, huffman_context **contexts, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dwidth, UINT32 dheight, UINT32 dstride, UINT32 dxor, UINT32 *actlength);
#endif
diff --git a/src/mame/audio/madalien.c b/src/mame/audio/madalien.c
index 16c8f5edd4e..8b6d71acf30 100644
--- a/src/mame/audio/madalien.c
+++ b/src/mame/audio/madalien.c
@@ -107,7 +107,7 @@ static const discrete_mixer_desc madalien_555_1c_cv =
{
DISC_MIXER_IS_RESISTOR,
{RES_K(1.5), RES_K(5)},
- {}, {}, 0, RES_K(10), 0, 0, 0, 1
+ {0}, {0}, 0, RES_K(10), 0, 0, 0, 1
};
static const discrete_mixer_desc madalien_final_mix =
diff --git a/src/mame/drivers/dlair.c b/src/mame/drivers/dlair.c
index 560527e1137..70ed50fb66e 100644
--- a/src/mame/drivers/dlair.c
+++ b/src/mame/drivers/dlair.c
@@ -803,10 +803,7 @@ static MACHINE_DRIVER_START( dlair_base )
MDRV_SCREEN_ADD("main", RASTER)
MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
- MDRV_SCREEN_REFRESH_RATE(59.94)
- MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
- MDRV_SCREEN_SIZE(32*8, 32*8)
- MDRV_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 32*8-1)
+ MDRV_SCREEN_RAW_PARAMS(XTAL_14_31818MHz, 910, 0, 720, 525.0/2, 0, 480/2)
MDRV_VIDEO_START(dlair)
MDRV_VIDEO_UPDATE(dlair)
diff --git a/src/tools/chdman.c b/src/tools/chdman.c
index b8dc7c9d5cb..ac47b9f04fc 100644
--- a/src/tools/chdman.c
+++ b/src/tools/chdman.c
@@ -11,6 +11,7 @@
#include "corefile.h"
#include "chdcd.h"
#include "aviio.h"
+#include "avcomp.h"
#include "bitmap.h"
#include "md5.h"
#include "sha1.h"
@@ -601,84 +602,40 @@ cleanup:
read_avi_frame - read an AVI frame
-------------------------------------------------*/
-static avi_error read_avi_frame(avi_file *avi, UINT32 framenum, UINT8 *cache, bitmap_t *bitmap, int interlaced, UINT32 hunkbytes)
+static avi_error read_avi_frame(avi_file *avi, UINT32 framenum, UINT32 first_sample, bitmap_t *fullbitmap, int interlaced, av_codec_compress_config *avconfig)
{
const avi_movie_info *info = avi_get_movie_info(avi);
int interlace_factor = interlaced ? 2 : 1;
- UINT32 first_sample, num_samples;
avi_error avierr = AVIERR_NONE;
- int chnum, sampnum, x, y;
- UINT8 *dest = cache;
- INT16 *temp;
-
- /* compute the number of samples in this frame */
- first_sample = avi_first_sample_in_frame(avi, framenum / interlace_factor);
- num_samples = avi_first_sample_in_frame(avi, framenum / interlace_factor + 1) - first_sample;
- if (interlaced)
- {
- if (framenum % 2 == 0)
- num_samples = (num_samples + 1) / 2;
- else
- {
- first_sample += (num_samples + 1) / 2;
- num_samples -= (num_samples + 1) / 2;
- }
- }
-
- /* allocate a temporary buffer */
- temp = malloc(num_samples * 2);
- if (temp == NULL)
- return AVIERR_NO_MEMORY;
-
- /* update the header with the actual number of samples in the frame */
- dest[6] = num_samples >> 8;
- dest[7] = num_samples;
- dest += 12 + dest[4];
+ int chnum;
/* loop over channels and read the samples */
for (chnum = 0; chnum < info->audio_channels; chnum++)
{
/* read the sound samples */
- avierr = avi_read_sound_samples(avi, chnum, first_sample, num_samples, temp);
+ avierr = avi_read_sound_samples(avi, chnum, first_sample, avconfig->samples, avconfig->audio[chnum]);
if (avierr != AVIERR_NONE)
goto cleanup;
-
- /* store them big endian at the destination */
- for (sampnum = 0; sampnum < num_samples; sampnum++)
- {
- INT16 sample = temp[sampnum];
- *dest++ = sample >> 8;
- *dest++ = sample;
- }
}
/* read the video data when we hit a new frame */
if (framenum % interlace_factor == 0)
{
- avierr = avi_read_video_frame_yuy16(avi, framenum / interlace_factor, bitmap);
+ avierr = avi_read_video_frame_yuy16(avi, framenum / interlace_factor, fullbitmap);
if (avierr != AVIERR_NONE)
goto cleanup;
}
-
- /* loop over the data and copy it to the cache */
- for (y = framenum % interlace_factor; y < info->video_height; y += interlace_factor)
+
+ /* build the fake bitmap */
+ *avconfig->video = *fullbitmap;
+ if (interlaced)
{
- UINT16 *source = BITMAP_ADDR16(bitmap, y, 0);
-
- for (x = 0; x < info->video_width; x++)
- {
- UINT16 pixel = *source++;
- *dest++ = pixel;
- *dest++ = pixel >> 8;
- }
+ avconfig->video->base = BITMAP_ADDR16(avconfig->video, framenum % interlace_factor, 0);
+ avconfig->video->rowpixels *= 2;
+ avconfig->video->height /= 2;
}
- /* fill the rest with 0 */
- while (dest < &cache[hunkbytes])
- *dest++ = 0;
-
cleanup:
- free(temp);
return avierr;
}
@@ -687,59 +644,29 @@ cleanup:
fake_avi_frame - fake an AVI frame
-------------------------------------------------*/
-static avi_error fake_avi_frame(avi_file *avi, UINT32 framenum, UINT8 *cache, bitmap_t *bitmap, int interlaced, UINT32 hunkbytes)
+static avi_error fake_avi_frame(avi_file *avi, UINT32 framenum, UINT32 first_sample, bitmap_t *fullbitmap, int interlaced, av_codec_compress_config *avconfig)
{
static int framecounter = 0;
int leftsamp = (framenum % 200 < 10) ? 10000 : 0;
int rightsamp = (framenum % 200 >= 100 && framenum % 200 < 110) ? 10000 : 0;
int interlace_factor = interlaced ? 2 : 1;
- UINT32 first_sample, num_samples;
int chnum, sampnum, x, y;
int whiteflag, line1718;
- UINT8 *dest = cache;
- INT16 *temp;
/* reset framecounter to 1 on frame 0 */
if (framenum == 0)
framecounter = 1;
- /* compute the number of samples in this frame */
- first_sample = ((UINT64)AVI_FAKE_SAMPLERATE * (UINT64)framenum * (UINT64)1000000 + AVI_FAKE_FRAMERATE - 1) / AVI_FAKE_FRAMERATE;
- num_samples = ((UINT64)AVI_FAKE_SAMPLERATE * (UINT64)(framenum + 1) * (UINT64)1000000 + AVI_FAKE_FRAMERATE - 1) / AVI_FAKE_FRAMERATE - first_sample;
- if (interlaced)
- {
- if (framenum % 2 == 0)
- num_samples = (num_samples + 1) / 2;
- else
- {
- first_sample += (num_samples + 1) / 2;
- num_samples -= (num_samples + 1) / 2;
- }
- }
-
- /* allocate a temporary buffer */
- temp = malloc(num_samples * 2);
- if (temp == NULL)
- return AVIERR_NO_MEMORY;
-
- /* update the header with the actual number of samples in the frame */
- dest[6] = num_samples >> 8;
- dest[7] = num_samples;
- dest += 12 + dest[4];
-
/* loop over channels and read the samples */
for (chnum = 0; chnum < AVI_FAKE_CHANNELS; chnum++)
{
int modcheck = AVI_FAKE_SAMPLERATE / ((chnum == 0) ? 110 : 220);
int samp = (chnum == 0) ? leftsamp : rightsamp;
+ INT16 *dest = avconfig->audio[chnum];
- /* store them big endian at the destination */
- for (sampnum = 0; sampnum < num_samples; sampnum++)
- {
- INT16 sample = ((first_sample + sampnum) % modcheck < modcheck / 2) ? samp : -samp;
- *dest++ = sample >> 8;
- *dest++ = sample;
- }
+ /* store them to the audio buffer */
+ for (sampnum = 0; sampnum < avconfig->samples; sampnum++)
+ *dest++ = ((first_sample + sampnum) % modcheck < modcheck / 2) ? samp : -samp;
}
/* determine what metadata we should generate */
@@ -769,26 +696,31 @@ static avi_error fake_avi_frame(avi_file *avi, UINT32 framenum, UINT8 *cache, bi
}
}
+ /* build the fake bitmap */
+ *avconfig->video = *fullbitmap;
+ if (interlaced)
+ {
+ avconfig->video->base = BITMAP_ADDR16(avconfig->video, framenum % interlace_factor, 0);
+ avconfig->video->rowpixels *= 2;
+ avconfig->video->height /= 2;
+ }
+
/* loop over the data and copy it to the cache */
- for (y = framenum % interlace_factor; y < AVI_FAKE_HEIGHT; y += interlace_factor)
+ for (y = 0; y < avconfig->video->height; y++)
{
- int effy = y / interlace_factor;
+ UINT16 *dest = BITMAP_ADDR16(avconfig->video, y, 0);
/* white flag? */
- if (effy == 11 && whiteflag)
+ if (y == 11 && whiteflag)
{
for (x = 0; x < AVI_FAKE_WIDTH; x++)
- {
- UINT16 pixel = (x > 10 && x < AVI_FAKE_WIDTH - 10) ? 0xff80 : 0x0080;
- *dest++ = pixel;
- *dest++ = pixel >> 8;
- }
+ *dest++ = (x > 10 && x < avconfig->video->width - 10) ? 0xff80 : 0x0080;
}
/* line 17/18 */
- else if ((effy == 17 || effy == 18) && line1718 != 0)
+ else if ((y == 17 || y == 18) && line1718 != 0)
{
- for (x = 0; x < AVI_FAKE_WIDTH; x++)
+ for (x = 0; x < avconfig->video->width; x++)
{
UINT16 pixel = 0x0080;
if (x >= 20)
@@ -802,38 +734,24 @@ static avi_error fake_avi_frame(avi_file *avi, UINT32 framenum, UINT8 *cache, bi
}
}
*dest++ = pixel;
- *dest++ = pixel >> 8;
}
}
/* anything else in VBI-land */
- else if (effy < 22)
+ else if (y < 22)
{
- for (x = 0; x < AVI_FAKE_WIDTH; x++)
- {
- UINT16 pixel = 0x0080;
- *dest++ = pixel;
- *dest++ = pixel >> 8;
- }
+ for (x = 0; x < avconfig->video->width; x++)
+ *dest++ = 0x0080;
}
/* everything else */
else
{
- for (x = 0; x < AVI_FAKE_WIDTH; x++)
- {
- UINT16 pixel = framenum;
- *dest++ = pixel;
- *dest++ = pixel >> 8;
- }
+ for (x = 0; x < avconfig->video->width; x++)
+ *dest++ = framenum;
}
}
- /* fill the rest with 0 */
- while (dest < &cache[hunkbytes])
- *dest++ = 0;
-
- free(temp);
return AVIERR_NONE;
}
@@ -847,18 +765,20 @@ static int do_createav(int argc, char *argv[], int param)
{
UINT32 fps_times_1million, width, height, interlaced, channels, rate, totalframes;
UINT32 max_samples_per_frame, bytes_per_frame, firstframe, numframes;
+ av_codec_compress_config avconfig = { 0 };
const char *inputfile, *outputfile;
- bitmap_t videobitmap = { 0 };
+ bitmap_t *fullbitmap = NULL;
const avi_movie_info *info;
const chd_header *header;
chd_file *chd = NULL;
avi_file *avi = NULL;
- UINT8 *cache = NULL;
+ bitmap_t fakebitmap;
double ratio = 1.0;
char metadata[256];
avi_error avierr;
- chd_error err;
UINT32 framenum;
+ chd_error err;
+ int chnum;
/* require 4-6 args total */
if (argc < 4 || argc > 6)
@@ -912,20 +832,6 @@ static int do_createav(int argc, char *argv[], int param)
}
numframes = MIN(totalframes - firstframe, numframes);
- /* allocate a video buffer */
- videobitmap.base = malloc(width * height * 2);
- if (videobitmap.base == NULL)
- {
- fprintf(stderr, "Out of memory allocating temporary bitmap\n");
- err = CHDERR_OUT_OF_MEMORY;
- goto cleanup;
- }
- videobitmap.format = BITMAP_FORMAT_YUY16;
- videobitmap.width = width;
- videobitmap.height = height;
- videobitmap.bpp = 16;
- videobitmap.rowpixels = width;
-
/* print some of it */
printf("Use frames: %d-%d\n", firstframe, firstframe + numframes - 1);
printf("Frame rate: %d.%06d\n", fps_times_1million / 1000000, fps_times_1million % 1000000);
@@ -950,6 +856,29 @@ static int do_createav(int argc, char *argv[], int param)
max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2;
+ /* allocate a video buffer */
+ fullbitmap = bitmap_alloc(width, height * (interlaced ? 2 : 1), BITMAP_FORMAT_YUY16);
+ if (fullbitmap == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating temporary bitmap\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ avconfig.video = &fakebitmap;
+
+ /* allocate audio buffers */
+ avconfig.channels = channels;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ avconfig.audio[chnum] = malloc(max_samples_per_frame * 2);
+ if (avconfig.audio[chnum] == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating temporary audio buffer\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ }
+
/* create the new CHD */
err = chd_create(outputfile, (UINT64)numframes * (UINT64)bytes_per_frame, bytes_per_frame, CHDCOMPRESSION_AV, NULL);
if (err != CHDERR_NONE)
@@ -976,29 +905,6 @@ static int do_createav(int argc, char *argv[], int param)
goto cleanup;
}
- /* allocate a cache */
- cache = malloc(bytes_per_frame);
- if (cache == NULL)
- {
- fprintf(stderr, "Out of memory allocating temporary buffer\n");
- err = CHDERR_OUT_OF_MEMORY;
- goto cleanup;
- }
-
- /* fill in the basic values */
- cache[0] = 'c';
- cache[1] = 'h';
- cache[2] = 'a';
- cache[3] = 'v';
- cache[4] = 0;
- cache[5] = channels;
- cache[6] = max_samples_per_frame >> 8;
- cache[7] = max_samples_per_frame;
- cache[8] = width >> 8;
- cache[9] = width;
- cache[10] = (interlaced << 7) | (height >> 8);
- cache[11] = height;
-
/* begin compressing */
err = chd_compress_begin(chd);
if (err != CHDERR_NONE)
@@ -1007,22 +913,32 @@ static int do_createav(int argc, char *argv[], int param)
/* loop over source hunks until we run out */
for (framenum = 0; framenum < numframes; framenum++)
{
+ int effframe = firstframe + framenum;
+ UINT32 first_sample;
+
/* progress */
progress(framenum == 0, "Compressing hunk %d/%d... (ratio=%d%%) \r", framenum, header->totalhunks, (int)(100.0 * ratio));
+ /* compute the number of samples in this frame */
+ first_sample = ((UINT64)rate * (UINT64)effframe * (UINT64)1000000 + fps_times_1million - 1) / (UINT64)fps_times_1million;
+ avconfig.samples = ((UINT64)rate * (UINT64)(effframe + 1) * (UINT64)1000000 + fps_times_1million - 1) / (UINT64)fps_times_1million - first_sample;
+
/* read the frame into its proper format in the cache */
if (IS_FAKE_AVI_FILE(avi))
- avierr = fake_avi_frame(avi, firstframe + framenum, cache, &videobitmap, interlaced, bytes_per_frame);
+ avierr = fake_avi_frame(avi, effframe, first_sample, fullbitmap, interlaced, &avconfig);
else
- avierr = read_avi_frame(avi, firstframe + framenum, cache, &videobitmap, interlaced, bytes_per_frame);
+ avierr = read_avi_frame(avi, effframe, first_sample, fullbitmap, interlaced, &avconfig);
if (avierr != AVIERR_NONE)
{
- fprintf(stderr, "Error reading frame %d from AVI file: %s\n", firstframe + framenum, avi_error_string(avierr));
+ fprintf(stderr, "Error reading frame %d from AVI file: %s\n", effframe, avi_error_string(avierr));
err = CHDERR_COMPRESSION_ERROR;
}
+ /* configure the compressor for this frame */
+ chd_codec_config(chd, AV_CODEC_COMPRESS_CONFIG, &avconfig);
+
/* append the data */
- err = chd_compress_hunk(chd, cache, &ratio);
+ err = chd_compress_hunk(chd, NULL, &ratio);
if (err != CHDERR_NONE)
goto cleanup;
}
@@ -1040,10 +956,11 @@ cleanup:
avi_close(avi);
if (chd != NULL)
chd_close(chd);
- if (cache != NULL)
- free(cache);
- if (videobitmap.base != NULL)
- free(videobitmap.base);
+ for (chnum = 0; chnum < ARRAY_LENGTH(avconfig.audio); chnum++)
+ if (avconfig.audio[chnum] != NULL)
+ free(avconfig.audio[chnum]);
+ if (fullbitmap != NULL)
+ bitmap_free(fullbitmap);
if (err != CHDERR_NONE)
osd_rmfile(outputfile);
return (err != CHDERR_NONE);
@@ -1488,80 +1405,6 @@ cleanup:
/*-------------------------------------------------
- write_avi_frame - write an AVI frame
--------------------------------------------------*/
-
-static avi_error write_avi_frame(avi_file *avi, UINT32 framenum, const UINT8 *buffer, bitmap_t *bitmap)
-{
- const avi_movie_info *info = avi_get_movie_info(avi);
- UINT32 channels, samples, width, height;
- avi_error avierr = AVIERR_NONE;
- int chnum, sampnum, x, y;
- int interlace_factor;
- INT16 *temp;
-
- /* extract core data */
- channels = buffer[5];
- samples = (buffer[6] << 8) | buffer[7];
- width = (buffer[8] << 8) | buffer[9];
- height = (buffer[10] << 8) | buffer[11];
- interlace_factor = (height & 0x8000) ? 2 : 1;
- height &= 0x7fff;
- height *= interlace_factor;
- buffer += 12 + buffer[4];
-
- /* make sure it makes sense */
- if (width != info->video_width || height != info->video_height)
- return AVIERR_INVALID_DATA;
-
- /* allocate a temporary buffer */
- temp = malloc(samples * 2);
- if (temp == NULL)
- return AVIERR_NO_MEMORY;
-
- /* loop over audio channels */
- for (chnum = 0; chnum < channels; chnum++)
- {
- /* extract samples */
- for (sampnum = 0; sampnum < samples; sampnum++)
- {
- INT16 sample = *buffer++ << 8;
- temp[sampnum] = sample | *buffer++;
- }
-
- /* write the samples */
- avierr = avi_append_sound_samples(avi, chnum, temp, samples, 0);
- if (avierr != AVIERR_NONE)
- goto cleanup;
- }
-
- /* loop over the data and copy it to the bitmap */
- for (y = framenum % interlace_factor; y < height; y += interlace_factor)
- {
- UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
-
- for (x = 0; x < width; x++)
- {
- UINT16 pixel = *buffer++;
- *dest++ = pixel | *buffer++ << 8;
- }
- }
-
- /* write the video data */
- if (interlace_factor == 1 || framenum % 2 == 1)
- {
- avierr = avi_append_video_frame_yuy16(avi, bitmap);
- if (avierr != AVIERR_NONE)
- goto cleanup;
- }
-
-cleanup:
- free(temp);
- return avierr;
-}
-
-
-/*-------------------------------------------------
do_extractav - extract an AVI file from a
CHD image
-------------------------------------------------*/
@@ -1569,19 +1412,21 @@ cleanup:
static int do_extractav(int argc, char *argv[], int param)
{
int fps, fpsfrac, width, height, interlaced, channels, rate, totalframes;
+ av_codec_decompress_config avconfig = { 0 };
const char *inputfile, *outputfile;
- int firstframe, numframes;
- bitmap_t videobitmap = { 0 };
+ UINT32 firstframe, numframes;
+ bitmap_t *fullbitmap = NULL;
+ UINT32 framenum, numsamples;
UINT32 fps_times_1million;
const chd_header *header;
chd_file *chd = NULL;
avi_file *avi = NULL;
+ bitmap_t fakebitmap;
avi_movie_info info;
char metadata[256];
- void *hunk = NULL;
avi_error avierr;
chd_error err;
- int framenum;
+ int chnum;
/* require 4-6 args total */
if (argc < 4 || argc > 6)
@@ -1635,18 +1480,29 @@ static int do_extractav(int argc, char *argv[], int param)
numframes = MIN(totalframes - firstframe, numframes);
/* allocate a video buffer */
- videobitmap.base = malloc(width * height * 2);
- if (videobitmap.base == NULL)
+ fullbitmap = bitmap_alloc(width, height * (interlaced ? 2 : 1), BITMAP_FORMAT_YUY16);
+ if (fullbitmap == NULL)
{
fprintf(stderr, "Out of memory allocating temporary bitmap\n");
err = CHDERR_OUT_OF_MEMORY;
goto cleanup;
}
- videobitmap.format = BITMAP_FORMAT_YUY16;
- videobitmap.width = width;
- videobitmap.height = height;
- videobitmap.bpp = 16;
- videobitmap.rowpixels = width;
+ avconfig.video = &fakebitmap;
+
+ /* allocate audio buffers */
+ avconfig.channels = channels;
+ avconfig.maxsamples = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
+ avconfig.actsamples = &numsamples;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ avconfig.audio[chnum] = malloc(avconfig.maxsamples * 2);
+ if (avconfig.audio[chnum] == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating temporary audio buffer\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ }
/* print some of it */
printf("Use frames: %d-%d\n", firstframe, firstframe + numframes - 1);
@@ -1658,15 +1514,6 @@ static int do_extractav(int argc, char *argv[], int param)
(UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million / 60) % 60),
(UINT32)(((UINT64)totalframes * 1000000 / fps_times_1million) % 60));
- /* allocate memory to hold a hunk */
- hunk = malloc(header->hunkbytes);
- if (hunk == NULL)
- {
- fprintf(stderr, "Out of memory allocating hunk buffer!\n");
- err = CHDERR_OUT_OF_MEMORY;
- goto cleanup;
- }
-
/* build up the movie info */
info.video_format = FORMAT_YUY2;
info.video_timescale = fps_times_1million;
@@ -1695,22 +1542,41 @@ static int do_extractav(int argc, char *argv[], int param)
{
/* progress */
progress(framenum == 0, "Extracting hunk %d/%d... \r", framenum, numframes);
+
+ /* set up the fake bitmap for this frame */
+ *avconfig.video = *fullbitmap;
+ if (interlaced)
+ {
+ avconfig.video->base = BITMAP_ADDR16(avconfig.video, framenum % 2, 0);
+ avconfig.video->rowpixels *= 2;
+ avconfig.video->height /= 2;
+ }
+
+ /* configure the decompressor for this frame */
+ chd_codec_config(chd, AV_CODEC_DECOMPRESS_CONFIG, &avconfig);
- /* read the hunk into a buffer */
- err = chd_read(chd, firstframe + framenum, hunk);
+ /* read the hunk into the buffers */
+ err = chd_read(chd, firstframe + framenum, NULL);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", firstframe + framenum, chd_error_string(err));
goto cleanup;
}
- /* write the hunk to the file */
- avierr = write_avi_frame(avi, framenum, hunk, &videobitmap);
- if (avierr != AVIERR_NONE)
+ /* write audio */
+ for (chnum = 0; chnum < channels; chnum++)
{
- fprintf(stderr, "Error writing AVI frame: %s\n", avi_error_string(avierr));
- err = CHDERR_DECOMPRESSION_ERROR;
- goto cleanup;
+ avierr = avi_append_sound_samples(avi, chnum, avconfig.audio[chnum], numsamples, 0);
+ if (avierr != AVIERR_NONE)
+ goto cleanup;
+ }
+
+ /* write video */
+ if (!interlaced || (firstframe + framenum) % 2 == 1)
+ {
+ avierr = avi_append_video_frame_yuy16(avi, fullbitmap);
+ if (avierr != AVIERR_NONE)
+ goto cleanup;
}
}
progress(TRUE, "Extraction complete! \n");
@@ -1719,10 +1585,11 @@ cleanup:
/* clean up our mess */
if (avi != NULL)
avi_close(avi);
- if (hunk != NULL)
- free(hunk);
- if (videobitmap.base != NULL)
- free(videobitmap.base);
+ for (chnum = 0; chnum < ARRAY_LENGTH(avconfig.audio); chnum++)
+ if (avconfig.audio[chnum] != NULL)
+ free(avconfig.audio[chnum]);
+ if (fullbitmap != NULL)
+ bitmap_free(fullbitmap);
if (chd != NULL)
chd_close(chd);
if (err != CHDERR_NONE)
diff --git a/src/tools/ldverify.c b/src/tools/ldverify.c
index 9f66dd61dd5..01037d921cf 100644
--- a/src/tools/ldverify.c
+++ b/src/tools/ldverify.c
@@ -472,8 +472,8 @@ static void verify_video_final(int frame, bitmap_t *bitmap)
printf("Track %6d.%d: never saw any white flags; no cadence detection done (WARNING)\n", field / fields_per_frame, 0);
/* did we ever see any lead-out? */
- if (video_saw_leadin && !video_saw_leadout)
- printf("Track %6d.%d: detected lead-in but never saw any lead-out (WARNING)\n", field / fields_per_frame, 0);
+ if (!video_saw_leadout)
+ printf("Track %6d.%d: never saw any lead-out (WARNING)\n", field / fields_per_frame, 0);
}