diff options
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 |
commit | 1eb3c2d964342aef09a08d854bdab6716a6792bd (patch) | |
tree | ac364ed9466a0556e178770d87855ed21ce113ea /src/tools | |
parent | 8e4ed692473ee31f5fdeee460526357ee4440392 (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.c | 279 |
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; |