Post subject: What do virtua nes movies save?
Joined: 3/19/2004
Posts: 710
Location: USA
If it also just saves keypresses, and is 60 fps, I could probably make a program that can convert the two. I just need to figure out how each stores key presses. Or is this impossible?
Joined: 3/30/2004
Posts: 1354
Location: Heather's imagination
You can't. The emulators are different, so the way they generate random numbers is different, so they're not compatible. The inputs would be the same but the video would 'break' in many games.
someone is out there who will like you. take off your mask so they can find you faster. I support the new Nekketsu Kouha Kunio-kun.
Joined: 3/19/2004
Posts: 710
Location: USA
Oh. Darn. Oh well.
Active player, Editor (296)
Joined: 3/8/2004
Posts: 7468
Location: Arzareth
I don't actually know how different they are. I know that timings are unique to each emulator, but does it matter so much or not, is a question to me...
Joined: 3/30/2004
Posts: 1354
Location: Heather's imagination
They probably store in very similar formats after the headers are stripped. So it'd be easy to test with a game that doesn't have much randomness (Rockman).
someone is out there who will like you. take off your mask so they can find you faster. I support the new Nekketsu Kouha Kunio-kun.
Joined: 4/11/2004
Posts: 155
Location: Fairfax, VA, USA
VirtuaNES movies contain a savestate where the movie was started from. This would be impossible to duplicate in Famtasia unless Famtasia was hacked into loading a savestate before playing. A Nesticle->VirtuaNES transcoder would probably be more feasible, since Nesticle movies also contain a savestate. I had a look at it, and IIRC the Nesticle header was like 3000 bytes larger than the VirtuaNES header. I dont know enough about the NES hardware to know what those 3000 bytes were for. That said, I would be very very surprised if the movies could be converted without problems. There would be differences in the emulation which would cause desync (even minor updates to an emulator, like Nesticle 0.42->0.43, cause desync).
Joined: 3/30/2004
Posts: 1354
Location: Heather's imagination
If the VirtuaNES movie started from system reset, though?
someone is out there who will like you. take off your mask so they can find you faster. I support the new Nekketsu Kouha Kunio-kun.
Joined: 4/11/2004
Posts: 155
Location: Fairfax, VA, USA
Well, I am amazed. For the heck of it I converted genisto's smb2 run into a VirtuaNES .vmv file, and it played back perfectly. This means that a .vmv to .fmv converter is also likely possible.
Boco wrote:
If the VirtuaNES movie started from system reset, though?
Let me try converting one of Lezard's videos to .fmv and we'll see how that goes. I'm really worried that if the movie doesn't start on the *exact* right frame, then the random number generators will start with different values. But we'll see. Edit: Lezard's Batman movie desyncs after about a minute of playing in Famtasia. I can't be sure, but it appears that at the desync point VirtuaNES emulates some slowdown in the game and Famtasia does not. So this desync appears to be due to a difference in the emulation. I'll happily post my converter code if people want to play around with it. My guess is that some .vmv files can be successfully converted.
Joined: 4/11/2004
Posts: 155
Location: Fairfax, VA, USA
I'll just post the code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//static const char* input_vmv="C:\\GAMES\\VirtuaNes\\Bat_Lezard.vmv";
//static const char* output_fmv="C:\\GAMES\\fam510\\lezard-batman.fmv";
static const char* famtasia_string="Family Emulator \"Famtasia\" Ver5.1";

int main(int argc, char** argv)
{
	if(argc<3)
	{
		printf("usage: convert <input_vmv_file> <output_fmv_file>\n");
		exit(0);
	}

	FILE* f_in=fopen(argv[1], "rb");
	if(!f_in)
	{
		perror("fopen\n");
		exit(0);
	}

	FILE* f_out=fopen(argv[2], "wb");
	if(!f_out)
	{
		perror("fopen\n");
		exit(0);
	}

	long rerecord_count;
	long ctr_data_offset;
	long num_samples;
	unsigned char ctr_flags;
	fseek(f_in, 0x10, SEEK_SET);
	fread(&ctr_flags, 1, 1, f_in);
	fseek(f_in, 0x1c, SEEK_SET);
	fread(&rerecord_count, 1, 4, f_in);
	fseek(f_in, 0x34, SEEK_SET);
	fread(&ctr_data_offset, 1, 4, f_in);
	fread(&num_samples, 1, 4, f_in);

	fwrite("FMV\x1a\x00", 1, 5, f_out);
	if(ctr_flags&0x02)
	{
		fwrite("\xc0", 1, 1, f_out);
		num_samples<<=1;
	}
	else
	{
		fwrite("\x80", 1, 1, f_out);
	}
	fwrite("\x00\x00\x00\x00", 1, 4, f_out);
	fwrite(&rerecord_count, 1, 4, f_out);
	fwrite("\x00\x00", 1, 2, f_out);

	unsigned char buf[0x1000];
	memset(buf, 0, 0x1000);
	strcpy((char*)buf, famtasia_string);
	fwrite(buf, 1, 0x80, f_out);

	fseek(f_in, ctr_data_offset, SEEK_SET);
	long i;
	for(i=0; i<num_samples; )
	{
		long n=(num_samples-i)>0x1000 ? 0x1000 : (num_samples-i);
		fread(buf, 1, n, f_in);
		long x;
		for(x=0; x<n; ++x)
		{
			unsigned char c=0;
			if(buf[x]&0x80)	c|=0x01;
			if(buf[x]&0x40)	c|=0x02;
			if(buf[x]&0x10)	c|=0x04;
			if(buf[x]&0x20)	c|=0x08;
			if(buf[x]&0x02)	c|=0x10;
			if(buf[x]&0x01)	c|=0x20;
			if(buf[x]&0x04)	c|=0x40;
			if(buf[x]&0x08)	c|=0x80;
			buf[x]=c;
		}
		fwrite(buf, 1, n, f_out);
		i+=n;
	}

	fclose(f_out);
	fclose(f_in);

	return 0;
}