mirror of
https://github.com/holub/mame
synced 2025-07-02 16:49:22 +03:00
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.
This commit is contained in:
parent
d89508d201
commit
a85c4c754d
@ -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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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 decompression configuration, apply it now */
|
||||
if (param == AV_CODEC_DECOMPRESS_CONFIG)
|
||||
/* if we're getting the compression configuration, apply it now */
|
||||
if (param == AV_CODEC_COMPRESS_CONFIG)
|
||||
{
|
||||
data->decompconfig = *(av_codec_decompress_config *)config;
|
||||
data->compress = *(av_codec_compress_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_compress(data->compstate, &data->compress);
|
||||
return CHDERR_NONE;
|
||||
}
|
||||
|
||||
/* if we're getting the decompression configuration, apply it now */
|
||||
else if (param == AV_CODEC_DECOMPRESS_CONFIG)
|
||||
{
|
||||
data->decompress = *(av_codec_decompress_config *)config;
|
||||
if (data->compstate != NULL)
|
||||
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;
|
||||
}
|
||||
|
@ -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 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 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! */
|
||||
};
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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_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_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_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
|
||||
|
@ -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 =
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/* loop over the data and copy it to the cache */
|
||||
for (y = framenum % interlace_factor; y < AVI_FAKE_HEIGHT; y += interlace_factor)
|
||||
/* build the fake bitmap */
|
||||
*avconfig->video = *fullbitmap;
|
||||
if (interlaced)
|
||||
{
|
||||
int effy = y / interlace_factor;
|
||||
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 = 0; y < avconfig->video->height; y++)
|
||||
{
|
||||
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);
|
||||
@ -1487,80 +1404,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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user