diff options
| author | 2008-08-05 16:30:35 +0000 | |
|---|---|---|
| committer | 2008-08-05 16:30:35 +0000 | |
| commit | 5e3764d0a09ec7e02f136cf33308135b9a1aa792 (patch) | |
| tree | 0082d5dbdafd19f3a30cd86bdce245f78fcfed0a /src/tools | |
| parent | 1f1fd39a44766718a5afa5023ce8e3f29561dc1c (diff) | |
Removed obsolete makemeta tool. Replaced it with new ldverify
tool which walks through either an AVI or CHD capture from a
laserdisc and ensures that there are no anomalies lurking in
the VBI data.
Added new option to chdman, where if you use -createav with
a special filename (either 2:2 or 3:2) it will create a fake
laserdisc files with the equivalent cadence. This can be used
for testing until full captures are available. Most games used
2:2 apart from Dragon's Lair and Space Ace, which were 3:2.
Note that even though these files are essentially blank, they
are Huffman-compressed, meaning that the maximum compression
ratio you will get is 8:1, so they still end up ~5GB.
Moved error strings from chdman.c to chd.c, where they can be
fetched from any caller via the new chd_error_string()
function.
Updated vbiparse to improve Manchester code decoding. It now
assigns a confidence level per bit based on how solid the
data is. Also added a new function vbi_parse_all which parses
the white flag and all three lines of metadata from a
laserdisc frame. It then compares line 17 and 18 against each
other and selects the most likely candidate based on per-bit
confidence and other factors.
Added frame number display to laserdsc.c. It is off by
default, though most players can be configured to turn it on
(not sure if any actually do). It can be manually toggled via
the backslash key during playback.
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/chdman.c | 384 | ||||
| -rw-r--r-- | src/tools/ldverify.c | 650 | ||||
| -rw-r--r-- | src/tools/makemeta.c | 506 | ||||
| -rw-r--r-- | src/tools/tools.mak | 10 |
4 files changed, 922 insertions, 628 deletions
diff --git a/src/tools/chdman.c b/src/tools/chdman.c index d81e74aac68..5c70b9823df 100644 --- a/src/tools/chdman.c +++ b/src/tools/chdman.c @@ -32,6 +32,21 @@ #define OPERATION_MERGE 1 #define OPERATION_CHOMP 2 +#ifdef PTR64 +#define IS_FAKE_AVI_FILE(a) ((UINT64)(a) <= 2) +#else +#define IS_FAKE_AVI_FILE(a) ((UINT32)(a) <= 2) +#endif +#define AVI_FAKE_FILE_22 ((avi_file *)1) +#define AVI_FAKE_FILE_32 ((avi_file *)2) + +#define AVI_FAKE_FRAMERATE 29970000 +#define AVI_FAKE_FRAMES 54004 +#define AVI_FAKE_WIDTH 720 +#define AVI_FAKE_HEIGHT 524 +#define AVI_FAKE_CHANNELS 2 +#define AVI_FAKE_SAMPLERATE 48000 + /*************************************************************************** @@ -59,33 +74,6 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot GLOBAL VARIABLES ***************************************************************************/ -static const char *const error_strings[] = -{ - "no error", - "no drive interface", - "out of memory", - "invalid file", - "invalid parameter", - "invalid data", - "file not found", - "requires parent", - "file not writeable", - "read error", - "write error", - "codec error", - "invalid parent", - "hunk out of range", - "decompression error", - "compression error", - "can't create file", - "can't verify file", - "operation not supported", - "can't find metadata", - "invalid metadata size", - "unsupported CHD version", - "incomplete verify" -}; - static clock_t lastprogress = 0; @@ -165,22 +153,6 @@ static void ATTR_PRINTF(2,3) progress(int forceit, const char *fmt, ...) /*------------------------------------------------- - error_string - return an error sting --------------------------------------------------*/ - -static const char *error_string(int err) -{ - static char temp_buffer[100]; - - if (err < sizeof(error_strings) / sizeof(error_strings[0])) - return error_strings[err]; - - sprintf(temp_buffer, "unknown error %d", err); - return temp_buffer; -} - - -/*------------------------------------------------- usage - generic usage error display -------------------------------------------------*/ @@ -332,7 +304,7 @@ static int do_createhd(int argc, char *argv[], int param) err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -340,7 +312,7 @@ static int do_createhd(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -349,14 +321,14 @@ static int do_createhd(int argc, char *argv[], int param) err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1); if (err != CHDERR_NONE) { - fprintf(stderr, "Error adding hard disk metadata: %s\n", error_string(err)); + fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err)); goto cleanup; } /* compress the hard drive */ err = chdman_compress_file(chd, inputfile, offset); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); cleanup: /* close everything down */ @@ -403,7 +375,7 @@ static int do_createraw(int argc, char *argv[], int param) err = chd_create(outputfile, logicalbytes, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -411,14 +383,14 @@ static int do_createraw(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } /* compress the CHD */ err = chdman_compress_file(chd, inputfile, offset); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); cleanup: /* close everything down */ @@ -474,7 +446,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chdcd_parse_toc(inputfile, &toc, &track_info); if (err != CHDERR_NONE) { - fprintf(stderr, "Error reading input file: %s\n", error_string(err)); + fprintf(stderr, "Error reading input file: %s\n", chd_error_string(err)); goto cleanup; } @@ -498,7 +470,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_ZLIB_PLUS, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -506,7 +478,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -520,7 +492,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chd_set_metadata(chd, CDROM_TRACK_METADATA_TAG, i, metadata, strlen(metadata) + 1); if (err != CHDERR_NONE) { - fprintf(stderr, "Error adding CD-ROM metadata: %s\n", error_string(err)); + fprintf(stderr, "Error adding CD-ROM metadata: %s\n", chd_error_string(err)); goto cleanup; } } @@ -529,7 +501,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chd_compress_begin(chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error compressing: %s\n", error_string(err)); + fprintf(stderr, "Error compressing: %s\n", chd_error_string(err)); goto cleanup; } @@ -595,7 +567,7 @@ static int do_createcd(int argc, char *argv[], int param) err = chd_compress_hunk(chd, cache, &ratio); if (err != CHDERR_NONE) { - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); goto cleanup; } } @@ -608,7 +580,7 @@ static int do_createcd(int argc, char *argv[], int param) /* cleanup */ err = chd_compress_finish(chd); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression finalization: %s\n", error_string(err)); + fprintf(stderr, "Error during compression finalization: %s\n", chd_error_string(err)); else progress(TRUE, "Compression complete ... final ratio = %d%% \n", (int)(100.0 * ratio)); @@ -691,7 +663,7 @@ static avi_error read_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 < info->video_height; y += interlace_factor) { - UINT16 *source = (UINT16 *)bitmap->base + y * bitmap->rowpixels; + UINT16 *source = BITMAP_ADDR16(bitmap, y, 0); for (x = 0; x < info->video_width; x++) { @@ -712,6 +684,161 @@ 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 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; + + /* 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; + } + } + + /* determine what metadata we should generate */ + whiteflag = line1718 = 0; + if (framenum < 2) + { + whiteflag = (framenum == 0); + line1718 = 0x88ffff; + } + else if (framenum >= AVI_FAKE_FRAMES * 2 - 2) + { + whiteflag = (framenum == AVI_FAKE_FRAMES * 2 - 2); + line1718 = 0x80eeee; + } + else + { + int effnum = framenum - 2; + if (avi == AVI_FAKE_FILE_22 && effnum % 2 == 0) + whiteflag = 1; + else if (avi == AVI_FAKE_FILE_32 && (effnum % 5 == 0 || effnum % 5 == 2)) + whiteflag = 1; + if (whiteflag) + { + line1718 = 0xf80000 | (((framecounter / 10000) % 10) << 16) | (((framecounter / 1000) % 10) << 12) | + (((framecounter / 100) % 10) << 8) | (((framecounter / 10) % 10) << 4) | (framecounter % 10); + framecounter++; + } + } + + /* loop over the data and copy it to the cache */ + for (y = framenum % interlace_factor; y < AVI_FAKE_HEIGHT; y += interlace_factor) + { + int effy = y / interlace_factor; + + /* white flag? */ + if (effy == 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; + } + } + + /* line 17/18 */ + else if ((effy == 17 || effy == 18) && line1718 != 0) + { + for (x = 0; x < AVI_FAKE_WIDTH; x++) + { + UINT16 pixel = 0x0080; + if (x >= 20) + { + int bitnum = (x - 20) / 28; + if (bitnum < 24) + { + int bithalf = (x - (bitnum * 28 + 20)) / 14; + if ((line1718 << bitnum) & 0x800000) bithalf ^= 1; + pixel = bithalf ? 0x0080 : 0xff80; + } + } + *dest++ = pixel; + *dest++ = pixel >> 8; + } + } + + /* anything else in VBI-land */ + else if (effy < 22) + { + for (x = 0; x < AVI_FAKE_WIDTH; x++) + { + UINT16 pixel = 0x0080; + *dest++ = pixel; + *dest++ = pixel >> 8; + } + } + + /* everything else */ + else + { + for (x = 0; x < AVI_FAKE_WIDTH; x++) + { + UINT16 pixel = framenum; + *dest++ = pixel; + *dest++ = pixel >> 8; + } + } + } + + /* fill the rest with 0 */ + while (dest < &cache[hunkbytes]) + *dest++ = 0; + + free(temp); + return AVIERR_NONE; +} + + +/*------------------------------------------------- do_createav - create a new A/V file from an input AVI file and metadata -------------------------------------------------*/ @@ -746,26 +873,44 @@ static int do_createav(int argc, char *argv[], int param) /* print some info */ printf("Input file: %s\n", inputfile); printf("Output file: %s\n", outputfile); - - /* open the source file */ - avierr = avi_open(inputfile, &avi); - if (avierr != AVIERR_NONE) - { - fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr)); - err = CHDERR_INVALID_FILE; - goto cleanup; + + /* special AVI files */ + if (strcmp(inputfile, "2:2") == 0 || strcmp(inputfile, "3:2") == 0) + { + /* create a fake handle */ + avi = (strcmp(inputfile, "2:2") == 0) ? AVI_FAKE_FILE_22 : AVI_FAKE_FILE_32; + + /* fake the movie information */ + fps_times_1million = AVI_FAKE_FRAMERATE; + width = AVI_FAKE_WIDTH; + height = AVI_FAKE_HEIGHT; + interlaced = TRUE; + channels = 2; + rate = AVI_FAKE_SAMPLERATE; + totalframes = AVI_FAKE_FRAMES; } + else + { + /* open the source file */ + avierr = avi_open(inputfile, &avi); + if (avierr != AVIERR_NONE) + { + fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr)); + err = CHDERR_INVALID_FILE; + goto cleanup; + } - /* get the movie information */ - info = avi_get_movie_info(avi); - fps_times_1million = (UINT64)info->video_timescale * 1000000 / info->video_sampletime; - width = info->video_width; - height = info->video_height; - interlaced = ((fps_times_1million / 1000000) <= 30) && (height % 2 == 0) && (height > 288); - channels = info->audio_channels; - rate = info->audio_samplerate; - totalframes = info->video_numsamples; - numframes = MIN(totalframes - firstframe, numframes); + /* get the movie information */ + info = avi_get_movie_info(avi); + fps_times_1million = (UINT64)info->video_timescale * 1000000 / info->video_sampletime; + width = info->video_width; + height = info->video_height; + interlaced = ((fps_times_1million / 1000000) <= 30) && (height % 2 == 0) && (height > 288); + channels = info->audio_channels; + rate = info->audio_samplerate; + totalframes = info->video_numsamples; + } + numframes = MIN(totalframes - firstframe, numframes); /* allocate a video buffer */ videobitmap.base = malloc(width * height * 2); @@ -809,7 +954,7 @@ static int do_createav(int argc, char *argv[], int param) err = chd_create(outputfile, (UINT64)numframes * (UINT64)bytes_per_frame, bytes_per_frame, CHDCOMPRESSION_AV, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -817,7 +962,7 @@ static int do_createav(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } header = chd_get_header(chd); @@ -827,7 +972,7 @@ static int do_createav(int argc, char *argv[], int param) err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1); if (err != CHDERR_NONE) { - fprintf(stderr, "Error adding AV metadata: %s\n", error_string(err)); + fprintf(stderr, "Error adding AV metadata: %s\n", chd_error_string(err)); goto cleanup; } @@ -866,7 +1011,10 @@ static int do_createav(int argc, char *argv[], int param) progress(framenum == 0, "Compressing hunk %d/%d... (ratio=%d%%) \r", framenum, header->totalhunks, (int)(100.0 * ratio)); /* read the frame into its proper format in the cache */ - avierr = read_avi_frame(avi, firstframe + framenum, cache, &videobitmap, interlaced, bytes_per_frame); + if (IS_FAKE_AVI_FILE(avi)) + avierr = fake_avi_frame(avi, firstframe + framenum, cache, &videobitmap, interlaced, bytes_per_frame); + else + avierr = read_avi_frame(avi, firstframe + framenum, cache, &videobitmap, interlaced, bytes_per_frame); if (avierr != AVIERR_NONE) { fprintf(stderr, "Error reading frame %d from AVI file: %s\n", firstframe + framenum, avi_error_string(avierr)); @@ -888,7 +1036,7 @@ static int do_createav(int argc, char *argv[], int param) cleanup: /* close everything down */ - if (avi != NULL) + if (avi != NULL && !IS_FAKE_AVI_FILE(avi)) avi_close(avi); if (chd != NULL) chd_close(chd); @@ -943,7 +1091,7 @@ static int do_createblankhd(int argc, char *argv[], int param) err = chd_create(outputfile, (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_NONE, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -951,7 +1099,7 @@ static int do_createblankhd(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -960,7 +1108,7 @@ static int do_createblankhd(int argc, char *argv[], int param) err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1); if (err != CHDERR_NONE) { - fprintf(stderr, "Error adding hard disk metadata: %s\n", error_string(err)); + fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err)); goto cleanup; } @@ -984,7 +1132,7 @@ static int do_createblankhd(int argc, char *argv[], int param) err = chd_write(chd, hunknum, cache); if (err != CHDERR_NONE) { - fprintf(stderr, "Error writing CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error writing CHD file: %s\n", chd_error_string(err)); goto cleanup; } } @@ -1033,7 +1181,7 @@ static int do_copydata(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening src CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening src CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -1041,14 +1189,14 @@ static int do_copydata(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &outputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening dest CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening dest CHD file: %s\n", chd_error_string(err)); goto cleanup; } /* compress the source into the dest */ err = chdman_compress_chd(outputchd, inputchd, 0); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); cleanup: /* close everything down */ @@ -1095,7 +1243,7 @@ static int do_extract(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &infile); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } header = chd_get_header(infile); @@ -1131,7 +1279,7 @@ static int do_extract(int argc, char *argv[], int param) err = chd_read(infile, hunknum, hunk); if (err != CHDERR_NONE) { - fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", hunknum, error_string(err)); + fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", hunknum, chd_error_string(err)); goto cleanup; } @@ -1141,7 +1289,7 @@ static int do_extract(int argc, char *argv[], int param) byteswritten = core_fwrite(outfile, hunk, bytes_to_write); if (byteswritten != bytes_to_write) { - fprintf(stderr, "Error writing hunk %d to output file: %s\n", hunknum, error_string(CHDERR_WRITE_ERROR)); + fprintf(stderr, "Error writing hunk %d to output file: %s\n", hunknum, chd_error_string(CHDERR_WRITE_ERROR)); err = CHDERR_WRITE_ERROR; goto cleanup; } @@ -1197,7 +1345,7 @@ static int do_extractcd(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } @@ -1299,7 +1447,7 @@ static int do_extractcd(int argc, char *argv[], int param) byteswritten = core_fwrite(outfile2, sector, toc->tracks[track].datasize); if (byteswritten != toc->tracks[track].datasize) { - fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, error_string(CHDERR_WRITE_ERROR)); + fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, chd_error_string(CHDERR_WRITE_ERROR)); err = CHDERR_WRITE_ERROR; goto cleanup; } @@ -1313,7 +1461,7 @@ static int do_extractcd(int argc, char *argv[], int param) byteswritten = core_fwrite(outfile2, sector, toc->tracks[track].subsize); if (byteswritten != toc->tracks[track].subsize) { - fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, error_string(CHDERR_WRITE_ERROR)); + fprintf(stderr, "Error writing frame %d to output file: %s\n", frame, chd_error_string(CHDERR_WRITE_ERROR)); err = CHDERR_WRITE_ERROR; goto cleanup; } @@ -1453,7 +1601,7 @@ static int do_extractav(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } header = chd_get_header(chd); @@ -1462,7 +1610,7 @@ static int do_extractav(int argc, char *argv[], int param) 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", error_string(err)); + fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(err)); goto cleanup; } @@ -1481,6 +1629,8 @@ static int do_extractav(int argc, char *argv[], int param) { fps_times_1million /= 2; height *= 2; + firstframe *= 2; + numframes *= 2; } numframes = MIN(totalframes - firstframe, numframes); @@ -1550,7 +1700,7 @@ static int do_extractav(int argc, char *argv[], int param) err = chd_read(chd, firstframe + framenum, hunk); if (err != CHDERR_NONE) { - fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", firstframe + framenum, error_string(err)); + fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", firstframe + framenum, chd_error_string(err)); goto cleanup; } @@ -1610,7 +1760,7 @@ static int do_verify(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening CHD file: %s\n", chd_error_string(err)); goto cleanup; } header = *chd_get_header(chd); @@ -1642,7 +1792,7 @@ static int do_verify(int argc, char *argv[], int param) if (err == CHDERR_CANT_VERIFY) fprintf(stderr, "Can't verify this type of image (probably writeable)\n"); else - fprintf(stderr, "\nError during verify: %s\n", error_string(err)); + fprintf(stderr, "\nError during verify: %s\n", chd_error_string(err)); goto cleanup; } @@ -1702,7 +1852,7 @@ static int do_verify(int argc, char *argv[], int param) { err = chd_set_header(inputfile, &header); if (err != CHDERR_NONE) - fprintf(stderr, "Error writing new header: %s\n", error_string(err)); + fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err)); else printf("Updated header successfully\n"); } @@ -1743,7 +1893,7 @@ static int do_info(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } header = *chd_get_header(chd); @@ -1996,7 +2146,7 @@ static int do_merge_update_chomp(int argc, char *argv[], int param) err = chd_open(parentfile, CHD_OPEN_READ, NULL, &parentchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, chd_error_string(err)); goto cleanup; } } @@ -2005,7 +2155,7 @@ static int do_merge_update_chomp(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, parentchd, &inputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } inputheader = chd_get_header(inputchd); @@ -2021,7 +2171,7 @@ static int do_merge_update_chomp(int argc, char *argv[], int param) err = chd_create(outputfile, inputheader->logicalbytes, inputheader->hunkbytes, inputheader->compression, NULL); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -2029,7 +2179,7 @@ static int do_merge_update_chomp(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, NULL, &outputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -2037,14 +2187,14 @@ static int do_merge_update_chomp(int argc, char *argv[], int param) err = chd_clone_metadata(inputchd, outputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error cloning metadata: %s\n", error_string(err)); + fprintf(stderr, "Error cloning metadata: %s\n", chd_error_string(err)); goto cleanup; } /* do the compression; our interface will route reads for us */ err = chdman_compress_chd(outputchd, inputchd, (param == OPERATION_CHOMP) ? (maxhunk + 1) : 0); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); cleanup: /* close everything down */ @@ -2091,7 +2241,7 @@ static int do_diff(int argc, char *argv[], int param) err = chd_open(parentfile, CHD_OPEN_READ, NULL, &parentchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", parentfile, chd_error_string(err)); goto cleanup; } @@ -2099,7 +2249,7 @@ static int do_diff(int argc, char *argv[], int param) err = chd_open(inputfile, CHD_OPEN_READ, NULL, &inputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err)); goto cleanup; } @@ -2107,7 +2257,7 @@ static int do_diff(int argc, char *argv[], int param) err = chd_create(outputfile, 0, 0, chd_get_header(parentchd)->compression, parentchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error creating CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error creating CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -2115,14 +2265,14 @@ static int do_diff(int argc, char *argv[], int param) err = chd_open(outputfile, CHD_OPEN_READWRITE, parentchd, &outputchd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening new CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error opening new CHD file: %s\n", chd_error_string(err)); goto cleanup; } /* do the compression; our interface will route reads for us */ err = chdman_compress_chd(outputchd, inputchd, 0); if (err != CHDERR_NONE) - fprintf(stderr, "Error during compression: %s\n", error_string(err)); + fprintf(stderr, "Error during compression: %s\n", chd_error_string(err)); cleanup: /* close everything down */ @@ -2175,7 +2325,7 @@ static int do_setchs(int argc, char *argv[], int param) err = chd_open(inoutfile, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, chd_error_string(err)); goto cleanup; } header = *chd_get_header(chd); @@ -2192,7 +2342,7 @@ static int do_setchs(int argc, char *argv[], int param) err = chd_set_header(inoutfile, &header); if (err != CHDERR_NONE) { - fprintf(stderr, "Error making CHD file writeable: %s\n", error_string(err)); + fprintf(stderr, "Error making CHD file writeable: %s\n", chd_error_string(err)); goto cleanup; } } @@ -2201,7 +2351,7 @@ static int do_setchs(int argc, char *argv[], int param) err = chd_open(inoutfile, CHD_OPEN_READWRITE, NULL, &chd); if (err != CHDERR_NONE) { - fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, error_string(err)); + fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, chd_error_string(err)); goto cleanup; } @@ -2219,7 +2369,7 @@ static int do_setchs(int argc, char *argv[], int param) err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1); if (err != CHDERR_NONE) { - fprintf(stderr, "Error writing new metadata to CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err)); goto cleanup; } @@ -2241,7 +2391,7 @@ static int do_setchs(int argc, char *argv[], int param) { err = chd_set_header(inoutfile, &header); if (err != CHDERR_NONE) - fprintf(stderr, "Error writing new header to CHD file: %s\n", error_string(err)); + fprintf(stderr, "Error writing new header to CHD file: %s\n", chd_error_string(err)); } /* print a warning if the size is different */ diff --git a/src/tools/ldverify.c b/src/tools/ldverify.c new file mode 100644 index 00000000000..a7a3d22be63 --- /dev/null +++ b/src/tools/ldverify.c @@ -0,0 +1,650 @@ +/*************************************************************************** + + ldverify.c + + Laserdisc AVI/CHD verifier. + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include <stdio.h> +#include <ctype.h> +#include "aviio.h" +#include "bitmap.h" +#include "chd.h" +#include "vbiparse.h" + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _movie_info movie_info; +struct _movie_info +{ + double framerate; + int numframes; + int width; + int height; + int samplerate; + int channels; +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static UINT8 *chdbuffer; +static UINT8 chdinterlaced; + +static int video_first_whitefield = -1; +static int video_saw_leadin = FALSE; +static int video_saw_leadout = FALSE; +static int video_last_frame = -1; +static int video_last_chapter = -1; +static int video_cadence = -1; +static UINT32 video_cadence_history = 0; +static int video_prev_whitefield = -1; + +static int audio_min_lsample = 32767; +static int audio_min_rsample = 32767; +static int audio_max_lsample = -32768; +static int audio_max_rsample = -32768; +static int audio_min_lsample_count = 0; +static int audio_min_rsample_count = 0; +static int audio_max_lsample_count = 0; +static int audio_max_rsample_count = 0; +static int audio_sample_count = 0; + + + +/*************************************************************************** + AVI HANDLING +***************************************************************************/ + +/*------------------------------------------------- + open_avi - open an AVI file and return + information about it +-------------------------------------------------*/ + +static void *open_avi(const char *filename, movie_info *info) +{ + const avi_movie_info *aviinfo; + avi_error avierr; + avi_file *avi; + + /* open the file */ + avierr = avi_open(filename, &avi); + if (avierr != AVIERR_NONE) + { + fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr)); + return NULL; + } + + /* extract movie info */ + aviinfo = avi_get_movie_info(avi); + info->framerate = (double)aviinfo->video_timescale / (double)aviinfo->video_sampletime; + info->numframes = aviinfo->video_numsamples; + info->width = aviinfo->video_width; + info->height = aviinfo->video_height; + info->samplerate = aviinfo->audio_samplerate; + info->channels = aviinfo->audio_channels; + + return avi; +} + + +/*------------------------------------------------- + read_avi - read a frame from an AVI file +-------------------------------------------------*/ + +static int read_avi(void *file, int frame, bitmap_t *bitmap, INT16 *lsound, INT16 *rsound, int *samples) +{ + const avi_movie_info *aviinfo = avi_get_movie_info(file); + UINT32 firstsample = ((UINT64)aviinfo->audio_samplerate * (UINT64)frame * (UINT64)aviinfo->video_sampletime + aviinfo->video_timescale - 1) / (UINT64)aviinfo->video_timescale; + UINT32 lastsample = ((UINT64)aviinfo->audio_samplerate * (UINT64)(frame + 1) * (UINT64)aviinfo->video_sampletime + aviinfo->video_timescale - 1) / (UINT64)aviinfo->video_timescale; + avi_error avierr; + + /* read the frame */ + avierr = avi_read_video_frame_yuy16(file, frame, bitmap); + if (avierr != AVIERR_NONE) + return FALSE; + + /* read the samples */ + avierr = avi_read_sound_samples(file, 0, firstsample, lastsample - firstsample, lsound); + avierr = avi_read_sound_samples(file, 1, firstsample, lastsample - firstsample, rsound); + if (avierr != AVIERR_NONE) + return FALSE; + *samples = lastsample - firstsample; + return TRUE; +} + + +/*------------------------------------------------- + close_avi - close an AVI file +-------------------------------------------------*/ + +static void close_avi(void *file) +{ + avi_close(file); +} + + + +/*************************************************************************** + CHD HANDLING +***************************************************************************/ + +/*------------------------------------------------- + open_chd - open a CHD file and return + information about it +-------------------------------------------------*/ + +static void *open_chd(const char *filename, movie_info *info) +{ + int fps, fpsfrac, width, height, interlaced, channels, rate; + char metadata[256]; + chd_error chderr; + chd_file *chd; + + /* open the file */ + chderr = chd_open(filename, CHD_OPEN_READ, NULL, &chd); + if (chderr != CHDERR_NONE) + { + fprintf(stderr, "Error opening CHD file: %s\n", chd_error_string(chderr)); + return NULL; + } + + /* get the metadata */ + chderr = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL); + if (chderr != CHDERR_NONE) + { + fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(chderr)); + chd_close(chd); + return NULL; + } + + /* extract the info */ + if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) + { + fprintf(stderr, "Improperly formatted metadata\n"); + chd_close(chd); + return NULL; + } + + /* extract movie info */ + info->framerate = (fps * 1000000 + fpsfrac) / 1000000.0; + info->numframes = chd_get_header(chd)->totalhunks; + info->width = width; + info->height = height; + info->samplerate = rate; + info->channels = channels; + + /* convert to an interlaced frame */ + chdinterlaced = interlaced; + if (interlaced) + { + info->framerate /= 2; + info->numframes = (info->numframes + 1) / 2; + info->height *= 2; + } + + /* allocate a buffer */ + chdbuffer = malloc(chd_get_header(chd)->hunkbytes); + if (chdbuffer == NULL) + { + fprintf(stderr, "Out of memory allocating chd buffer\n"); + chd_close(chd); + return NULL; + } + + return chd; +} + + +/*------------------------------------------------- + read_chd - read a frame from a CHD file +-------------------------------------------------*/ + +static int read_chd(void *file, int frame, bitmap_t *bitmap, INT16 *lsound, INT16 *rsound, int *samples) +{ + int interlace_factor = chdinterlaced ? 2 : 1; + int fieldnum, chnum, sampnum, x, y; + int channels, width, height; + chd_error chderr; + UINT8 *source; + + /* loop over fields */ + *samples = 0; + for (fieldnum = 0; fieldnum < interlace_factor; fieldnum++) + { + int startsamples = *samples; + + /* read the frame */ + chderr = chd_read(file, frame * interlace_factor + fieldnum, chdbuffer); + if (chderr != CHDERR_NONE) + return FALSE; + + /* parse out the info */ + channels = chdbuffer[5]; + *samples += (chdbuffer[6] << 8) | chdbuffer[7]; + width = (chdbuffer[8] << 8) | chdbuffer[9]; + height = ((chdbuffer[10] << 8) | chdbuffer[11]) & 0x7fff; + source = chdbuffer + 12 + chdbuffer[4]; + + /* make sure the data makes sense */ + if (width != bitmap->width || height != bitmap->height / interlace_factor) + { + fprintf(stderr, "Inconsistent frame width/height!\n"); + return FALSE; + } + + /* copy in sample data */ + for (chnum = 0; chnum < channels; chnum++) + { + INT16 *dest = (chnum == 0) ? lsound : rsound; + for (sampnum = startsamples; sampnum < *samples; sampnum++) + { + INT16 sample = *source++ << 8; + dest[sampnum] = sample | *source++; + } + } + + /* copy in the bitmap data */ + for (y = fieldnum; y < height * interlace_factor; y += interlace_factor) + { + UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0); + for (x = 0; x < width; x++) + { + UINT16 pixel = *source++; + *dest++ = pixel | (*source++ << 8); + } + } + } + return TRUE; +} + + +/*------------------------------------------------- + close_chd - close a CHD file +-------------------------------------------------*/ + +static void close_chd(void *file) +{ + if (chdbuffer != NULL) + free(chdbuffer); + chd_close(file); +} + + + +/*************************************************************************** + CORE IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + verify_video - verify video frame +-------------------------------------------------*/ + +static void verify_video(int frame, bitmap_t *bitmap) +{ + const int fields_per_frame = 2; + int fieldnum; + + /* loop over fields */ + for (fieldnum = 0; fieldnum < fields_per_frame; fieldnum++) + { + int field = frame * fields_per_frame + fieldnum; + vbi_metadata metadata; + + /* output status */ + if (frame % 10 == 0 && fieldnum == 0) + printf("%6d.%d...\r", frame, fieldnum); + + /* parse the VBI data */ + vbi_parse_all(BITMAP_ADDR16(bitmap, fieldnum, 0), bitmap->rowpixels * 2, bitmap->width, 8, &metadata); + + /* if we have data in both 17 and 18, it should match */ + if (metadata.line17 != 0 && metadata.line18 != 0 && metadata.line17 != metadata.line18) + { + printf("%6d.%d: line 17 and 18 data does not match (17=%06X 18=%06X) (WARNING)\n", frame, fieldnum, metadata.line17, metadata.line18); + printf("%6d.%d: selected %06X based on bit confidence\n", frame, fieldnum, metadata.line1718); + } + + /* is this a lead-in code? */ + if (metadata.line1718 == 0x88ffff) + { + /* if we haven't seen lead-in yet, detect it */ + if (!video_saw_leadin) + { + video_saw_leadin = TRUE; + printf("%6d.%d: lead-in code detected\n", frame, fieldnum); + } + + /* if we've previously seen chapters/frames, that's weird */ + if (video_last_frame != -1 || video_last_chapter != -1) + printf("%6d.%d: lead-in code detected after frame/chapter data (WARNING)\n", frame, fieldnum); + } + + /* is this a lead-out code? */ + if (metadata.line1718 == 0x80eeee) + { + /* if we haven't seen lead-in yet, detect it */ + if (!video_saw_leadout) + { + video_saw_leadout = TRUE; + printf("%6d.%d: lead-out code detected\n", frame, fieldnum); + if (video_last_frame != -1) + printf("%6d.%d: final frame number was %d\n", frame, fieldnum, video_last_frame); + else + printf("%6d.%d: never detected any frame numbers (ERROR)\n", frame, fieldnum); + } + + /* if we've previously seen chapters/frames, that's weird */ + if (video_last_frame == -1) + printf("%6d.%d: lead-out code detected with no frames detected beforehand (WARNING)\n", frame, fieldnum); + } + + /* is this a frame code? */ + if ((metadata.line1718 & 0xf80000) == 0xf80000) + { + int framenum = ((metadata.line1718 >> 0) & 15) * 1 + ((metadata.line1718 >> 4) & 15) * 10 + ((metadata.line1718 >> 8) & 15) * 100 + ((metadata.line1718 >> 12) & 15) * 1000 + ((metadata.line1718 >> 16) & 7) * 10000; + + /* did we see any leadin? */ + if (!video_saw_leadin) + { + printf("%6d.%d: detected frame number but never saw any lead-in (WARNING)\n", frame, fieldnum); + video_saw_leadin = TRUE; + } + + /* if this is the first frame, make sure it's 1 */ + if (video_last_frame == -1) + { + if (framenum == 1) + printf("%6d.%d: detected frame 1\n", frame, fieldnum); + else + printf("%6d.%d: first frame number is not 1 (%d) (ERROR)\n", frame, fieldnum, framenum); + } + + /* print an update every 1000 frames */ + if (framenum % 1000 == 0) + printf("%6d.%d: detected frame %d\n", frame, fieldnum, framenum); + + /* if this frame is not consecutive, it's an error */ + if (video_last_frame != -1 && framenum != video_last_frame + 1) + printf("%6d.%d: gap in frame number sequence (%d->%d) (ERROR)\n", frame, fieldnum, video_last_frame, framenum); + + /* remember the frame number */ + video_last_frame = framenum; + } + + /* is the whiteflag set? */ + if (metadata.white) + { + /* if this is the first white flag we see, count it */ + if (video_first_whitefield == -1) + { + video_first_whitefield = field; + printf("%6d.%d: first white flag seen\n", frame, fieldnum); + } + + /* if we've seen frames, but we're not yet to the lead-out, check the cadence */ + if (video_last_frame != -1 && !video_saw_leadout) + { + /* make sure we have a proper history */ + if (video_prev_whitefield != -1) + video_cadence_history = (video_cadence_history << 4) | ((field - video_prev_whitefield) & 0x0f); + video_prev_whitefield = field; + + /* if we don't know our cadence yet, determine it */ + if (video_cadence == -1 && (video_cadence_history & 0xf00) != 0) + { + if ((video_cadence_history & 0xfff) == 0x222) + { + printf("%6d.%d: detected 2:2 cadence\n", frame, fieldnum); + video_cadence = 4; + } + else if ((video_cadence_history & 0xfff) == 0x323) + { + printf("%6d.%d: detected 3:2 cadence\n", frame, fieldnum); + video_cadence = 5; + } + else if ((video_cadence_history & 0xfff) == 0x232) + { + printf("%6d.%d: detected 2:3 cadence\n", frame, fieldnum); + video_cadence = 5; + } + else + { + printf("%6d.%d: unknown cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, + (video_cadence_history >> 8) & 15, (video_cadence_history >> 4) & 15, video_cadence_history & 15); + } + } + + /* if we know our cadence, make sure we stick to it */ + if (video_cadence != -1) + { + if (video_cadence == 4 && (video_cadence_history & 0xfff) != 0x222) + { + printf("%6d.%d: missed cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, + (video_cadence_history >> 8) & 15, (video_cadence_history >> 4) & 15, video_cadence_history & 15); + video_cadence = -1; + video_cadence_history = 0; + } + else if (video_cadence == 5 && (video_cadence_history & 0xfff) != 0x323 && (video_cadence_history & 0xfff) != 0x232) + { + printf("%6d.%d: missed cadence (history %d:%d:%d) (WARNING)\n", frame, fieldnum, + (video_cadence_history >> 8) & 15, (video_cadence_history >> 4) & 15, video_cadence_history & 15); + video_cadence = -1; + video_cadence_history = 0; + } + } + } + } + } +} + + +/*------------------------------------------------- + verify_video_final - final verification +-------------------------------------------------*/ + +static void verify_video_final(int frame, bitmap_t *bitmap) +{ + int fields_per_frame = (bitmap->height >= 288) ? 2 : 1; + int field = frame * fields_per_frame; + + /* 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); +} + + +/*------------------------------------------------- + verify_audio - verify audio data +-------------------------------------------------*/ + +static void verify_audio(const INT16 *lsound, const INT16 *rsound, int samples) +{ + int sampnum; + + /* count the overall samples */ + audio_sample_count += samples; + + /* iterate over samples, tracking min/max */ + for (sampnum = 0; sampnum < samples; sampnum++) + { + /* did we hit a minimum on the left? */ + if (lsound[sampnum] < audio_min_lsample) + { + audio_min_lsample = lsound[sampnum]; + audio_min_lsample_count = 1; + } + else if (lsound[sampnum] == audio_min_lsample) + audio_min_lsample_count++; + + /* did we hit a maximum on the left? */ + if (lsound[sampnum] > audio_max_lsample) + { + audio_max_lsample = lsound[sampnum]; + audio_max_lsample_count = 1; + } + else if (lsound[sampnum] == audio_max_lsample) + audio_max_lsample_count++; + + /* did we hit a minimum on the right? */ + if (rsound[sampnum] < audio_min_rsample) + { + audio_min_rsample = rsound[sampnum]; + audio_min_rsample_count = 1; + } + else if (rsound[sampnum] == audio_min_rsample) + audio_min_rsample_count++; + + /* did we hit a maximum on the right? */ + if (rsound[sampnum] > audio_max_rsample) + { + audio_max_rsample = rsound[sampnum]; + audio_max_rsample_count = 1; + } + else if (rsound[sampnum] == audio_max_rsample) + audio_max_rsample_count++; + } +} + + +/*------------------------------------------------- + verify_audio_final - final verification +-------------------------------------------------*/ + +static void verify_audio_final(void) +{ + printf("Audio summary:\n"); + printf(" Channel 0 minimum: %6d (with %9d/%9d samples at minimum)\n", audio_min_lsample, audio_min_lsample_count, audio_sample_count); + printf(" Channel 0 maximum: %6d (with %9d/%9d samples at maximum)\n", audio_max_lsample, audio_max_lsample_count, audio_sample_count); + printf(" Channel 1 minimum: %6d (with %9d/%9d samples at minimum)\n", audio_min_rsample, audio_min_rsample_count, audio_sample_count); + printf(" Channel 1 maximum: %6d (with %9d/%9d samples at maximum)\n", audio_max_rsample, audio_max_rsample_count, audio_sample_count); +} + + +/*------------------------------------------------- + usage - display program usage +-------------------------------------------------*/ + +static int usage(void) +{ + fprintf(stderr, "Usage: \n"); + fprintf(stderr, " ldverify [avifile.avi|chdfile.chd]\n"); + return 1; +} + + +/*------------------------------------------------- + main - main entry point +-------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + movie_info info = { 0 }; + INT16 *lsound, *rsound; + const char *srcfile; + bitmap_t *bitmap; + int srcfilelen; + int samples = 0; + void *file; + int isavi; + int frame; + + /* verify arguments */ + if (argc < 2) + return usage(); + srcfile = argv[1]; + + /* check extension of file */ + srcfilelen = strlen(srcfile); + if (srcfilelen < 4) + return usage(); + if (tolower(srcfile[srcfilelen-3]) == 'a' && tolower(srcfile[srcfilelen-2]) == 'v' && tolower(srcfile[srcfilelen-1]) == 'i') + isavi = TRUE; + else if (tolower(srcfile[srcfilelen-3]) == 'c' && tolower(srcfile[srcfilelen-2]) == 'h' && tolower(srcfile[srcfilelen-1]) == 'd') + isavi = FALSE; + else + return usage(); + + /* open the file */ + printf("Processing file: %s\n", srcfile); + file = isavi ? open_avi(srcfile, &info) : open_chd(srcfile, &info); + if (file == NULL) + { + fprintf(stderr, "Unable to open file '%s'\n", srcfile); + return 1; + } + + /* comment on the video dimensions */ + printf("Video dimensions: %dx%d\n", info.width, info.height); + if (info.width != 720) + printf("WARNING: Unexpected video width (should be 720)\n"); + if (info.height != 524) + printf("WARNING: Unexpected video height (should be 262 or 524)\n"); + + /* comment on the video frame rate */ + printf("Video frame rate: %.2fHz\n", info.framerate); + if ((int)(info.framerate * 100.0 + 0.5) != 2997) + printf("WARNING: Unexpected frame rate (should be 29.97Hz)\n"); + + /* comment on the sample rate */ + printf("Sample rate: %dHz\n", info.samplerate); + if (info.samplerate != 48000) + printf("WARNING: Unexpected sampele rate (should be 48000Hz)\n"); + + /* allocate a bitmap */ + bitmap = bitmap_alloc(info.width, info.height, BITMAP_FORMAT_YUY16); + if (bitmap == NULL) + { + fprintf(stderr, "Out of memory creating %dx%d bitmap\n", info.width, info.height); + return 1; + } + + /* allocate sound buffers */ + lsound = malloc(info.samplerate * sizeof(*lsound)); + rsound = malloc(info.samplerate * sizeof(*rsound)); + if (lsound == NULL || rsound == NULL) + { + fprintf(stderr, "Out of memory allocating sound buffers of %d bytes\n", info.samplerate * sizeof(*rsound)); + return 1; + } + + /* loop over frames */ + frame = 0; + while (isavi ? read_avi(file, frame, bitmap, lsound, rsound, &samples) : read_chd(file, frame, bitmap, lsound, rsound, &samples)) + { + verify_video(frame, bitmap); + verify_audio(lsound, rsound, samples); + frame++; + } + + /* close the files */ + isavi ? close_avi(file) : close_chd(file); + + /* final output */ + verify_video_final(frame, bitmap); + verify_audio_final(); + + /* free memory */ + bitmap_free(bitmap); + free(lsound); + free(rsound); + + return 0; +} diff --git a/src/tools/makemeta.c b/src/tools/makemeta.c deleted file mode 100644 index 7cfb220f3f8..00000000000 --- a/src/tools/makemeta.c +++ /dev/null @@ -1,506 +0,0 @@ -/*************************************************************************** - - makemeta.c - - Laserdisc metadata generator. - - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - -**************************************************************************** - - Metadata format (12 bytes/field): - - Offset Description - ------ ------------------------------------------ - 0 = version (currently 2) - 1 = internal flags: - bit 0 = previous field is the same frame - bit 1 = next field is the same frame - 2 = white flag (from line 11) - 3-5 = line 16 Philips code - 6-8 = line 17 Philips code - 9-11 = line 18 Philips code - -***************************************************************************/ - -#include <stdio.h> -#include <ctype.h> -#include "aviio.h" -#include "bitmap.h" -#include "vbiparse.h" - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define INSERT_FRAME_CODE 0xff000000 -#define INSERT_FRAME_CODE_INC 0xff000001 -#define INVALID_CODE 0xffffffff - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -typedef struct _pattern_data pattern_data; -struct _pattern_data -{ - pattern_data *next; - UINT32 line16, line17, line18; - int white; -}; - - - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - output_meta - output a line of metadata --------------------------------------------------*/ - -static void output_meta(UINT8 flags, UINT8 white, UINT32 line16, UINT32 line17, UINT32 line18, UINT32 framenum, UINT32 chapternum) -{ - /* start with the raw metadata, followed by a comment */ - printf("02%02X%02X%06X%06X%06X ; ", - flags, white, line16, line17, line18); - - /* separate comments for leadin/leadout */ - if (line17 == 0x88ffff) - printf("leadin\n"); - else if (line17 == 0x80eeee) - printf("leadout\n"); - - /* otherwise, display the frame and chapter, and indicate white flag/stop code */ - else - { - printf("frame %05x ch %02x", framenum, chapternum); - if (white) - printf(" (white)"); - if (line16 == 0x82cfff) - printf(" (stop)"); - printf("\n"); - } -} - - -/*------------------------------------------------- - generate_from_avi - generate the data from - an AVI file --------------------------------------------------*/ - -static int generate_from_avi(const char *aviname) -{ - UINT32 line16 = 0, line17 = 0, line18 = 0, framenum = 0, chapternum = 0; - const avi_movie_info *info; - bitmap_t *bitmap; - avi_error avierr; - avi_file *avi; - int white = 0; - int frame; - - /* open the file */ - avierr = avi_open(aviname, &avi); - if (avierr != AVIERR_NONE) - { - fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr)); - return 1; - } - - /* extract movie info */ - info = avi_get_movie_info(avi); - fprintf(stderr, "%dx%d - %d frames total\n", info->video_width, info->video_height, info->video_numsamples); - if (info->video_height < 22*2) - { - fprintf(stderr, "Unknown VBI capture format: expected at least 44 rows\n"); - return 1; - } - - /* allocate a bitmap to hold it */ - bitmap = bitmap_alloc(info->video_width, info->video_height, BITMAP_FORMAT_YUY16); - if (bitmap == NULL) - { - fprintf(stderr, "Out of memory allocating %dx%d bitmap\n", info->video_width, info->video_height); - return 1; - } - - /* loop over frames */ - for (frame = 0; frame < info->video_numsamples; frame++) - { - int field; - UINT8 bits[24]; - - /* read the frame */ - avierr = avi_read_video_frame_yuy16(avi, frame, bitmap); - if (avierr != AVIERR_NONE) - { - fprintf(stderr, "Error reading AVI frame %d: %s\n", frame, avi_error_string(avierr)); - break; - } - - /* loop over two fields */ - for (field = 0; field < 2; field++) - { - int prevwhite = white; - int i; - - /* line 11 contains the white flag */ - white = vbi_parse_white_flag(BITMAP_ADDR16(bitmap, 11*2 + field, 0), bitmap->width, 8); - - /* output metadata for *previous* field */ - if (frame > 0 || field > 0) - { - int flags = 0; - - if (!prevwhite) flags |= 0x01; - if (!white) flags |= 0x02; - output_meta(flags, prevwhite, line16, line17, line18, framenum, chapternum); - } - - /* line 16 contains stop code and other interesting bits */ - line16 = 0; - if (vbi_parse_manchester_code(BITMAP_ADDR16(bitmap, 16*2 + field, 0), bitmap->width, 8, 24, bits) == 24) - for (i = 0; i < 24; i++) - line16 = (line16 << 1) | bits[i]; - - /* line 17 and 18 contain frame/chapter/lead in/out encodings */ - line17 = 0; - if (vbi_parse_manchester_code(BITMAP_ADDR16(bitmap, 17*2 + field, 0), bitmap->width, 8, 24, bits) == 24) - for (i = 0; i < 24; i++) - line17 = (line17 << 1) | bits[i]; - - line18 = 0; - if (vbi_parse_manchester_code(BITMAP_ADDR16(bitmap, 18*2 + field, 0), bitmap->width, 8, 24, bits) == 24) - for (i = 0; i < 24; i++) - line18 = (line18 << 1) | bits[i]; - - /* the two lines must match */ -// if (line17 != 0 && line18 != 0 && line17 != line18) -// line17 = line18 = 0; - - /* is this a frame number? */ - if ((line17 & 0xf00000) == 0xf00000) - framenum = line17 & 0x7ffff; - if ((line17 & 0xf00fff) == 0x800ddd) - chapternum = (line17 >> 12) & 0x7f; - } - } - - /* output metadata for *previous* field */ - { - int flags = 0; - - if (!white) flags |= 0x01; - output_meta(flags, white, line16, line17, line18, framenum, chapternum); - } - - bitmap_free(bitmap); - return 0; -} - - -/*------------------------------------------------- - parse_philips_code - parse a single Philips - code from a string, stopping at the given - end characters --------------------------------------------------*/ - -static UINT32 parse_philips_code(char **argptr, const char *endchars) -{ - char *arg = *argptr; - UINT32 value = 0; - - /* look for special chars first */ - if (*arg == '+') - { - *argptr = arg + 1; - return INSERT_FRAME_CODE_INC; - } - else if (*arg == '@') - { - *argptr = arg + 1; - return INSERT_FRAME_CODE; - } - - /* parse the rest as hex digits */ - for ( ; *arg != 0 && strchr(endchars, *arg) == NULL; arg++) - { - if (*arg >= '0' && *arg <= '9') - value = (value << 4) + (*arg - '0'); - else if (*arg >= 'a' && *arg <= 'f') - value = (value << 4) + 10 + (*arg - 'a'); - else if (*arg >= 'A' && *arg <= 'F') - value = (value << 4) + 10 + (*arg - 'A'); - else - return INVALID_CODE; - } - - /* if we're too big, we're invalid */ - if (value > 0xffffff) - return INVALID_CODE; - - *argptr = arg; - return value; -} - - -/*------------------------------------------------- - parse_pattern - parse a pattern into a series - of pattern_data structs --------------------------------------------------*/ - -static pattern_data *parse_pattern(char *arg, int *countptr) -{ - pattern_data *head = NULL; - pattern_data **tailptr = &head; - int count = 0; - - /* first parse the count */ - for ( ; *arg != 0 && *arg != '*'; arg++) - { - if (!isdigit(*arg)) - return NULL; - count = count * 10 + (*arg - '0'); - } - if (*arg == 0) - return NULL; - arg++; - *countptr = count; - - /* loop until we hit the end */ - while (*arg != 0) - { - pattern_data *pat; - - /* allocate a new structure */ - pat = malloc(sizeof(*pat)); - if (pat == NULL) - return NULL; - memset(pat, 0, sizeof(*pat)); - - /* bang at the beginning means white flag */ - if (*arg == '!') - { - arg++; - pat->white = 1; - } - - /* parse line16 until we hit a period or comma */ - pat->line16 = parse_philips_code(&arg, ".,"); - if (pat->line16 == INVALID_CODE) - return NULL; - if (*arg != '.' && *arg != ',' && *arg != 0) - return NULL; - if (*arg == '.') - arg++; - - /* parse line17 until we hit a period */ - pat->line17 = parse_philips_code(&arg, ".,"); - if (pat->line17 == INVALID_CODE) - return NULL; - if (*arg != '.' && *arg != ',' && *arg != 0) - return NULL; - if (*arg == '.') - arg++; - - /* parse line18 until we hit a comma */ - pat->line18 = parse_philips_code(&arg, ","); - if (pat->line18 == INVALID_CODE) - return NULL; - if (*arg != ',' && *arg != 0) - return NULL; - if (*arg == ',') - arg++; - - /* append to the end */ - *tailptr = pat; - tailptr = &pat->next; - } - - return head; -} - - -/*------------------------------------------------- - generate_from_pattern - generate metadata - from a pattern --------------------------------------------------*/ - -static int generate_from_pattern(pattern_data *pattern, int patcount) -{ - pattern_data *curpat = pattern; - int framenum = 0, bcdframenum = 0; - - /* loop until we exceed the pattern frame count */ - while (1) - { - UINT32 line16, line17, line18; - int flags = 0; - - /* handle special codes for line 16 */ - line16 = curpat->line16; - if (line16 == INSERT_FRAME_CODE_INC) - { - framenum++; - bcdframenum = (((framenum / 10000) % 10) << 16) | (((framenum / 1000) % 10) << 12) | (((framenum / 100) % 10) << 8) | (((framenum / 10) % 10) << 4) | (framenum % 10); - } - if (line16 == INSERT_FRAME_CODE || line16 == INSERT_FRAME_CODE_INC) - line16 = 0xf80000 | bcdframenum; - - /* handle special codes for line 17 */ - line17 = curpat->line17; - if (line17 == INSERT_FRAME_CODE_INC) - { - framenum++; - bcdframenum = (((framenum / 10000) % 10) << 16) | (((framenum / 1000) % 10) << 12) | (((framenum / 100) % 10) << 8) | (((framenum / 10) % 10) << 4) | (framenum % 10); - } - if (line17 == INSERT_FRAME_CODE || line17 == INSERT_FRAME_CODE_INC) - line17 = 0xf80000 | bcdframenum; - - /* handle special codes for line 18 */ - line18 = curpat->line18; - if (line18 == INSERT_FRAME_CODE_INC) - { - framenum++; - bcdframenum = (((framenum / 10000) % 10) << 16) | (((framenum / 1000) % 10) << 12) | (((framenum / 100) % 10) << 8) | (((framenum / 10) % 10) << 4) | (framenum % 10); - } - if (line18 == INSERT_FRAME_CODE || line18 == INSERT_FRAME_CODE_INC) - line18 = 0xf80000 | bcdframenum; - - /* bail if we passed the end */ - if (framenum > patcount) - break; - - /* if we don't have a white flag, the previous frame must match us */ - if (!curpat->white) flags |= 0x01; - - /* advance to the next pattern piece */ - curpat = curpat->next; - if (curpat == NULL) - curpat = pattern; - - /* if the new field doesn't have a white flag, it must match our current frame */ - if (!curpat->white) flags |= 0x02; - - /* output the result */ - output_meta(flags, curpat->white, line16, line17, line18, bcdframenum, 0); - } - return 0; -} - - -/*------------------------------------------------- - usage - display program usage --------------------------------------------------*/ - -static int usage(void) -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " makemeta [avifile.avi] [<option> [<option> [...]]]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, " -leadin <count> -- prepend <count> fields of leadin codes\n"); - fprintf(stderr, " -leadout <count> -- append <count> fields of leadout codes\n"); - fprintf(stderr, " -pattern <frames>*<pat0>[,<pat1>[,...]] -- repeat Philips code pattern\n"); - fprintf(stderr, " in place of AVI. <pat0>, <pat1>, etc. are of the form: \n"); - fprintf(stderr, " [!]A[.B[.C]][,<pattern>] where A,B,C are either hexadecimal\n"); - fprintf(stderr, " values one of these special codes:\n"); - fprintf(stderr, " ! -- at the start of a pattern sets the white flag\n"); - fprintf(stderr, " + -- increments frame number and inserts frame code\n"); - fprintf(stderr, " @ -- inserts repeat of most recent frame code\n"); - fprintf(stderr, " non-present values are assumed to be 0\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Examples:\n"); - fprintf(stderr, " makemeta -pattern 54000*!8da01e.+.@,8da01e,!8da01e.+.@,8da01e,8da01e\n"); - fprintf(stderr, " generates the following pattern of Philips codes:\n"); - fprintf(stderr, " 8da01e f80001 f80001 (white)\n"); - fprintf(stderr, " 8da01e 000000 000000\n"); - fprintf(stderr, " 8da01e f80002 f80002 (white)\n"); - fprintf(stderr, " 8da01e 000000 000000\n"); - fprintf(stderr, " 8da01e 000000 000000\n"); - fprintf(stderr, " <repeat until frame is 54000>\n"); - return 1; -} - - -/*------------------------------------------------- - main - main entry point --------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int leadin = 0, leadout = 0; - const char *avifile = NULL; - pattern_data *pattern = NULL; - int patcount = 0; - int arg; - int i; - - /* iterate over arguments */ - for (arg = 1; arg < argc; arg++) - { - /* assume anything without a - is a filename */ - if (argv[arg][0] != '-') - { - if (avifile != NULL || pattern != NULL) - return usage(); - avifile = argv[arg]; - } - - /* look for options */ - else if (strcmp(argv[arg], "-leadin") == 0) - { - if (++arg >= argc) - return usage(); - leadin = atoi(argv[arg]); - } - else if (strcmp(argv[arg], "-leadout") == 0) - { - if (++arg >= argc) - return usage(); - leadout = atoi(argv[arg]); - } - else if (strcmp(argv[arg], "-pattern") == 0) - { - if (avifile != NULL || pattern != NULL) - return usage(); - if (++arg >= argc) - return usage(); - pattern = parse_pattern(argv[arg], &patcount); - if (pattern == NULL) - return usage(); - } - } - - /* must have an AVI file or a pattern */ - if (avifile == NULL && pattern == NULL) - return usage(); - - /* output header and leadin */ - printf("chdmeta 12\n"); - for (i = 0; i < leadin; i++) - { - int flags = (i == 0) ? 0x02 : (i == leadin - 1) ? 0x01 : 0x03; - printf("02%02X%02X00000088FFFF88FFFF\n", flags, (i % 2)); - } - - /* if we got a file, output it */ - if (avifile != NULL) - generate_from_avi(avifile); - else if (pattern != NULL) - generate_from_pattern(pattern, patcount); - - /* output leadout */ - for (i = 0; i < leadout; i++) - { - int flags = (i == 0) ? 0x02 : (i == leadout - 1) ? 0x01 : 0x03; - printf("02%02X%02X00000080EEEE80EEEE\n", flags, (i % 2)); - } - - return 0; -} diff --git a/src/tools/tools.mak b/src/tools/tools.mak index 9e03fbfcbc7..c9f73eac95a 100644 --- a/src/tools/tools.mak +++ b/src/tools/tools.mak @@ -26,7 +26,7 @@ TOOLS += \ romcmp$(EXE) \ chdman$(EXE) \ jedutil$(EXE) \ - makemeta$(EXE) \ + ldverify$(EXE) \ regrep$(EXE) \ srcclean$(EXE) \ src2html$(EXE) \ @@ -74,13 +74,13 @@ jedutil$(EXE): $(JEDUTILOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) $(EXPAT) #------------------------------------------------- -# makemeta +# ldverify #------------------------------------------------- -MAKEMETAOBJS = \ - $(TOOLSOBJ)/makemeta.o \ +LDVERIFYOBJS = \ + $(TOOLSOBJ)/ldverify.o \ -makemeta$(EXE): $(MAKEMETAOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) $(EXPAT) +ldverify$(EXE): $(LDVERIFYOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) $(EXPAT) @echo Linking $@... $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ |
