summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-09-18 15:17:42 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-09-18 15:17:42 +0000
commit1eb3c2d964342aef09a08d854bdab6716a6792bd (patch)
treeac364ed9466a0556e178770d87855ed21ce113ea /src/tools
parent8e4ed692473ee31f5fdeee460526357ee4440392 (diff)
Changed requirements for laserdisc CHDs to require a new chunk of
metadata with pre-decoded frame information. Modified chdman to automatically produce this for CHDs that are of the appropriate parameters. To fix up existing CHDs, use chdman -fixavdata on the CHD. Modified the laserdisc core to leverage the pre-decoded frame metadata, which is now required. This improves seek times when searching and allows the player-specific emulation access to the VBI data as soon as it would really be available. Changed update callback timing to fire just before the first line of VBI data would be read; at that point, the frame selection is assumed to be committed. Converted PR-8210 emulation over to using the actual MCU from the laserdisc player. This MCU controls low-level functions such as slider position and laser on/off, and receives decoded vertical blanking data in order to make decisions. Removed old HLE behavior. Note that the overlay text is displayed via the UI; this is temporary and will be fixed shortly. Converted Simutrek-hacked laserdisc emulation to using the actual MCU from the game, which in turn hands off commands to the PR-8210 MCU. This is still not 100% but is pretty close at this point and achieves the correct behaviors in most cases. Fixed Cube Quest overlay scaling to cover the whole screen. Changed laserdisc video parameters to position the screen area at the bottom rather than the top, since this corresponds more closely to standard line numbering. Extended the vbiparse code to support pack/unpack, and to more fully document all the meanings of the VBI codes. Updated ldplayer to support slow/fast forward movement, frame/chapter display, and separate controls for scanning/stepping. Added new built-in variable "frame" to the debugger. Fixed device-based ROM loading to support loading ROMs from the game's ZIP as well.
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/chdman.c279
1 files changed, 275 insertions, 4 deletions
diff --git a/src/tools/chdman.c b/src/tools/chdman.c
index f5af8f22b40..06765cb910a 100644
--- a/src/tools/chdman.c
+++ b/src/tools/chdman.c
@@ -15,6 +15,7 @@
#include "bitmap.h"
#include "md5.h"
#include "sha1.h"
+#include "vbiparse.h"
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
@@ -84,7 +85,8 @@ static clock_t lastprogress = 0;
***************************************************************************/
/*-------------------------------------------------
- print_big_int - 64-bit int printing with commas
+ print_big_int - 64-bit int printing with
+ commas
-------------------------------------------------*/
static void print_big_int(UINT64 intvalue, char *output)
@@ -105,7 +107,8 @@ static void print_big_int(UINT64 intvalue, char *output)
/*-------------------------------------------------
- big_int_string - return a string for a big int
+ big_int_string - return a string for a big
+ integer
-------------------------------------------------*/
static char *big_int_string(UINT64 intvalue)
@@ -162,6 +165,7 @@ static int usage(void)
printf(" or: chdman -merge parent.chd diff.chd output.chd\n");
printf(" or: chdman -diff parent.chd compare.chd diff.chd\n");
printf(" or: chdman -setchs inout.chd cylinders heads sectors\n");
+ printf(" or: chdman -fixavdata inout.chd\n");
return 1;
}
@@ -755,6 +759,7 @@ static int do_createav(int argc, char *argv[], int param)
const char *inputfile, *outputfile;
bitmap_t *fullbitmap = NULL;
const avi_movie_info *info;
+ UINT8 *ldframedata = NULL;
const chd_header *header;
chd_file *chd = NULL;
avi_file *avi = NULL;
@@ -837,6 +842,19 @@ static int do_createav(int argc, char *argv[], int param)
firstframe *= 2;
numframes *= 2;
}
+
+ /* allocate space for the frame data */
+ if (height == 524/2 || height == 624/2)
+ {
+ ldframedata = malloc(numframes * VBI_PACKED_BYTES);
+ if (ldframedata == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating frame metadata\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ memset(ldframedata, 0, numframes * VBI_PACKED_BYTES);
+ }
/* determine the number of bytes per frame */
max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
@@ -919,6 +937,15 @@ static int do_createav(int argc, char *argv[], int param)
fprintf(stderr, "Error reading frame %d from AVI file: %s\n", effframe, avi_error_string(avierr));
err = CHDERR_COMPRESSION_ERROR;
}
+
+ /* update metadata for this frame */
+ if (ldframedata != NULL)
+ {
+ /* parse the data and pack it */
+ vbi_metadata vbi;
+ vbi_parse_all((const UINT16 *)avconfig.video->base, avconfig.video->rowpixels, avconfig.video->width, 8, &vbi);
+ vbi_metadata_pack(&ldframedata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
+ }
/* configure the compressor for this frame */
chd_codec_config(chd, AV_CODEC_COMPRESS_CONFIG, &avconfig);
@@ -929,6 +956,17 @@ static int do_createav(int argc, char *argv[], int param)
goto cleanup;
}
+ /* write the final metadata */
+ if (ldframedata != NULL)
+ {
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ }
+
/* finish compression */
err = chd_compress_finish(chd);
if (err != CHDERR_NONE)
@@ -947,6 +985,8 @@ cleanup:
free(avconfig.audio[chnum]);
if (fullbitmap != NULL)
bitmap_free(fullbitmap);
+ if (ldframedata != NULL)
+ free(ldframedata);
if (err != CHDERR_NONE)
osd_rmfile(outputfile);
return (err != CHDERR_NONE);
@@ -1466,7 +1506,7 @@ static int do_extractav(int argc, char *argv[], int param)
numframes = MIN(totalframes - firstframe, numframes);
/* allocate a video buffer */
- fullbitmap = bitmap_alloc(width, height * (interlaced ? 2 : 1), BITMAP_FORMAT_YUY16);
+ fullbitmap = bitmap_alloc(width, height, BITMAP_FORMAT_YUY16);
if (fullbitmap == NULL)
{
fprintf(stderr, "Out of memory allocating temporary bitmap\n");
@@ -1724,6 +1764,236 @@ cleanup:
/*-------------------------------------------------
+ do_fixavdata - fix the AV metadata for an
+ A/V file
+-------------------------------------------------*/
+
+static int do_fixavdata(int argc, char *argv[], int param)
+{
+ int fps, fpsfrac, width, height, interlaced, channels, rate;
+ av_codec_decompress_config avconfig = { 0 };
+ bitmap_t *fullbitmap = NULL;
+ const char *inputfile;
+ UINT8 *vbidata = NULL;
+ int writeable = FALSE;
+ chd_file *chd = NULL;
+ bitmap_t fakebitmap;
+ char metadata[256];
+ chd_header header;
+ UINT32 actlength;
+ UINT32 framenum;
+ chd_error err;
+ int fixframes = 0;
+ int fixes = 0;
+
+ /* require 3 args total */
+ if (argc != 3)
+ return usage();
+
+ /* extract the data */
+ inputfile = argv[2];
+
+ /* print some info */
+ printf("Input file: %s\n", inputfile);
+
+ /* get the header */
+ err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
+ goto cleanup;
+ }
+ header = *chd_get_header(chd);
+
+ /* get the metadata */
+ err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* extract the info */
+ if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
+ {
+ fprintf(stderr, "Improperly formatted metadata\n");
+ err = CHDERR_INVALID_METADATA;
+ goto cleanup;
+ }
+
+ /* allocate space for the frame data */
+ if ((height != 524/2 && height != 624/2) || !interlaced)
+ {
+ fprintf(stderr, "This file does not need VBI metadata\n");
+ err = CHDERR_INVALID_METADATA;
+ goto cleanup;
+ }
+
+ /* allocate a video buffer */
+ fullbitmap = bitmap_alloc(width, height, 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 memory for VBI data */
+ vbidata = malloc(header.totalhunks * VBI_PACKED_BYTES);
+ if (vbidata == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating VBI data\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ /* read the metadata */
+ err = chd_get_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, &actlength, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error getting VBI metadata: %s\n", chd_error_string(err));
+ memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
+ fixes++;
+ }
+ if (actlength != header.totalhunks * VBI_PACKED_BYTES)
+ {
+ fprintf(stderr, "VBI metadata incorrect size\n");
+ memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
+ fixes++;
+ }
+
+ /* loop over hunks, reading */
+ for (framenum = 0; framenum < header.totalhunks; framenum++)
+ {
+ vbi_metadata origvbi;
+ vbi_metadata vbi;
+ UINT32 vbiframe;
+
+ /* progress */
+ progress(framenum == 0, "Processing hunk %d/%d... \r", framenum, header.totalhunks);
+
+ /* set up the fake bitmap for this frame */
+ *avconfig.video = *fullbitmap;
+
+ /* configure the decompressor for this frame */
+ chd_codec_config(chd, AV_CODEC_DECOMPRESS_CONFIG, &avconfig);
+
+ /* read the hunk into the buffers */
+ err = chd_read(chd, framenum, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", framenum, chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* unpack the current data for this frame */
+ vbi_metadata_unpack(&origvbi, &vbiframe, &vbidata[framenum * VBI_PACKED_BYTES]);
+
+ /* parse the video data */
+ vbi_parse_all((const UINT16 *)avconfig.video->base, avconfig.video->rowpixels, avconfig.video->width, 8, &vbi);
+
+ /* verify the data */
+ if (vbiframe != 0 || origvbi.white != 0 || origvbi.line16 != 0 || origvbi.line17 != 0 || origvbi.line18 != 0 || origvbi.line1718 != 0)
+ {
+ int errors = 0;
+
+ if (vbiframe != framenum)
+ {
+ fprintf(stderr, "%d:Frame mismatch in VBI data (%d, should be %d)\n", framenum, vbiframe, framenum);
+ errors++;
+ }
+ if (vbi.white != origvbi.white)
+ {
+ fprintf(stderr, "%d:White flag mismatch in VBI data (%d, should be %d)\n", framenum, origvbi.white, vbi.white);
+ errors++;
+ }
+ if (vbi.line16 != origvbi.line16)
+ {
+ fprintf(stderr, "%d:Line 16 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line16, vbi.line16);
+ errors++;
+ }
+ if (vbi.line17 != origvbi.line17)
+ {
+ fprintf(stderr, "%d:Line 17 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line17, vbi.line17);
+ errors++;
+ }
+ if (vbi.line18 != origvbi.line18)
+ {
+ fprintf(stderr, "%d:Line 18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line18, vbi.line18);
+ errors++;
+ }
+ if (vbi.line1718 != origvbi.line1718)
+ {
+ fprintf(stderr, "%d:Line 17/18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line1718, vbi.line1718);
+ errors++;
+ }
+ fixes += errors;
+ fixframes += (errors != 0);
+ }
+
+ /* pack the new data */
+ vbi_metadata_pack(&vbidata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
+ }
+ progress(TRUE, "Processing complete! \n");
+
+ /* print final results */
+ if (fixes == 0)
+ printf("\nNo fixes required\n");
+ else
+ printf("\nFound %d errors on %d frames\n", fixes, fixframes);
+
+ /* close the drive */
+ chd_close(chd);
+ chd = NULL;
+
+ /* apply fixes */
+ if (fixes > 0)
+ {
+ /* mark the CHD writeable */
+ header.flags |= CHDFLAGS_IS_WRITEABLE;
+ err = chd_set_header(inputfile, &header);
+ if (err != CHDERR_NONE)
+ fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err));
+ header.flags &= ~CHDFLAGS_IS_WRITEABLE;
+ writeable = TRUE;
+
+ /* open the file */
+ err = chd_open(inputfile, CHD_OPEN_READWRITE, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* write new metadata */
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ else
+ printf("Updated metadata written successfully\n");
+
+ /* allow cleanup code to close the file and revert the header */
+ }
+
+cleanup:
+ /* clean up our mess */
+ if (fullbitmap != NULL)
+ bitmap_free(fullbitmap);
+ if (vbidata != NULL)
+ free(vbidata);
+ if (chd != NULL)
+ chd_close(chd);
+ if (writeable)
+ chd_set_header(inputfile, &header);
+ return (err != CHDERR_NONE);
+}
+
+
+/*-------------------------------------------------
do_info - dump the header information from
a drive image
-------------------------------------------------*/
@@ -2535,7 +2805,8 @@ int CLIB_DECL main(int argc, char **argv)
{ "-info", do_info, 0 },
{ "-merge", do_merge_update_chomp, OPERATION_MERGE },
{ "-diff", do_diff, 0 },
- { "-setchs", do_setchs, 0 }
+ { "-setchs", do_setchs, 0 },
+ { "-fixavdata", do_fixavdata, 0 }
};
extern char build_version[];
int i;