Youtube Sonic TAS community

Impossible is possible

You are not logged in.

#1 2013-03-31 00:04:22

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Tutorial: working with gmv files

GMV is a very simple input file format. It consists of 2 parts:

1. GMV header — always 64 bytes long
2. Frame data — all what remains

GMV header contains all information about the input file: format version, number of controllers, number of rerecords and so on. The exact header structure is described on the corresponding wiki page of gens-rerecording. Using a HEX editor, it’s easy to notice a little mistype there: the first block is actually 15, not 16 bytes long. Other things seem to be OK. GMV header does not contain information about length of the movie — it’s calculated automatically from number of frames, which equals (length(file) - 64) / 3.

Let’s try to take some existing GMV file and read some information from it. For example, comment and number of rerecords. In my example I will use C coding language, because it makes it very easy to define such data structures.

gmv.h:

#include <stdint.h>

typedef struct {
	char signature[15];
	char gmv_version;
	uint32_t rerecords;
	char joypad_keys[2];
	uint16_t flags;
	char comment[40];
} MovieHeader;

gmv.c:

#include <stdio.h>
#include "gmv.h"

void readMovieHeader(FILE *handle, MovieHeader *header) {
	fread(header, sizeof(MovieHeader), 1, handle);
}

int main(int argc, char **argv) {
	MovieHeader header;
	FILE *handle = fopen("/home/wst/sega/tas/example-tas.gmv", "r");
	readMovieHeader(handle, &header);
	fclose(handle);
	printf("Rerecords: %d, comment: %s\n", header.rerecords, header.comment);
	return 0;
}

Put a valid path to some accessible gmv file into gmv.c and compile the example with the following command:

gcc -o gmv gmv.c

This requires availability of GNU C compiler on your computer. If you use Linux, you probably already have it installed. If you use Windows, consider installing MinGW if you want to try this example. A good MinGW distribution, which includes many other useful tools, can be found, for example, here. It also can be downloaded from YSTC’s file storage. Another good MinGW package is this, it’s easier to install/modify and more lightweight.

You will get an executable file called “gmv” in your current directory. Run it:

./gmv

It will show number of rerecords and comment from the specified GMV file.
In the next tutorial we’ll make a simple program allowing to edit those comment and number of rerecords (to cheat, in other words tongue)


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

#2 2013-03-31 21:39:05

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Re: Tutorial: working with gmv files

Time for the second tutorial. Now we’ll load entire gmv into the memory. I was wrong that we would make a program for editing comment and number of rerecords — for now it’s better to load the gmv completely, not only the header.

So, let’s see. Here is our new gmv.h:

typedef struct {
	char signature[15];
	char gmv_version;
	uint32_t rerecords;
	char joypad_keys[2];
	uint16_t flags;
	char comment[40];
} MovieHeader;

typedef struct {
	uint8_t first;
	uint8_t second;
	uint8_t mode;
} MovieFrame;

typedef struct {
	MovieHeader header;
	MovieFrame *frames;
} MovieFile;

Those new 2 structures represent the missing parts — movie frame data (see previous post) and entire GMV file. So, let’s see the source file, gmv.c.

#include <stdio.h>
#include <stdlib.h>
#include "gmv.h"

void readMovieHeader(FILE *handle, MovieHeader *header) {
	fseek(handle, 0, SEEK_SET);
	fread(header, sizeof(MovieHeader), 1, handle);
}

MovieFrame *loadInput(FILE *handle) {
	fseek(handle, 0, SEEK_END);
	uint32_t length = (ftell(handle) - 0x40) / 3;
	fseek(handle, 0x40, SEEK_SET);
	MovieFrame *buffer = (MovieFrame *) calloc(length, sizeof(MovieFrame));
	fread(buffer, sizeof(MovieHeader), length, handle);
	return buffer;
}

void disposeInput(MovieFrame *movie) {
	free(movie);
}

MovieFile *loadGMV(char *filename) {
	// Trying to open an input file, which may not exist. We assume it’s a valid gmv file.
	FILE *gmv = fopen(filename, "r");
	if(!gmv) return 0;

	// Allocating memory. Since input files are not large, we can store them in RAM entirely
	MovieFile *buffer = (MovieFile *) malloc(sizeof(MovieFile));

	// Loading the header (step 1)
	readMovieHeader(gmv, &(buffer->header));
	
	// Loading frame data (step 2)
	buffer->frames = loadInput(gmv);
	
	// Closing the opened input file
	fclose(gmv);
	
	// Return the resulting memory block
	return buffer;
}

void disposeGMV(MovieFile *gmv) {
	disposeInput(gmv->frames);
	free(gmv);
}

int main(int argc, char **argv) {
	// Checking whether the application is started properly
	if(argc != 2) {
		printf("Usage: %s <path-to-your-gmv>\n", argv[0]);
		return -1;
	}
	
	// Making an attempt to load the specified GMV file
	MovieFile *tas = loadGMV(argv[1]);
	if(!tas) {
		printf("Failed to load GMV file\n");
		return -2;
	}
	
	// Showing the GMV metadata
	printf("Rerecords: %d, comment: %s\n", tas->header.rerecords, tas->header.comment);
	
	// Closing the GMV gile and exitting
	disposeGMV(tas);
	return 0;
}

The code would look much nicer in object-oriented style (C++), but I chose pure C, because it can be used in C++ programs without any problem.
Since now we store in our memory all information about the selected GMV file. If you are familiar with programming well, you may notice that we could make it even simplier — read entire file into memory in one single fread iteration, but I think such a minor optimization does not make much sense. So we read the header and frame data separately. Well, time to compile and run our program.

[wst@localhost Desktop]$ ./gmv /home/wst/feeuzz-tas.gmv
Rerecords: 443, comment: 
[wst@localhost Desktop]$

This program does exactly the same as previous one — the most significant change is not visible — now we read GMV completely. Other changes are: ability to specify custom path to GMV file, checking it’s existence. We still assume that we got a valid GMV file, but this will be fixed in further turorials. In one of those tutorials we can try to make a shared library (libgmv.so on Linux or gmv.dll on Windows), if someone of you want to see how to do it tongue

Thanks for your attention smile


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

#3 2013-08-17 22:11:12

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Re: Tutorial: working with gmv files

I’ve wrote a simple GUI program which uses the code blocks from above.
It uses Qt framework and it’s available in my github.

git clone https://github.com/WST/gmvprop.git

Compiling it under Linux is simple:

cd gmvprop
qmake
make
./bin/gmvprop

   gmvprop.png

For those of you who are unfamiliar with all that programming stuff, here is a Windows build: http://ystc.ru/files/utilities/gmvprop.rar

In case you are wondering why so simple application is so huge, the answer is: because it’s using a huge Qt framework. The size can be slightly reduced by recompiling Qt libraries with size optimizations, but it is boring to do.

Editing frame data will be hard to implement, and I am not sure I will make it. But this little piece of crap still can be used for cheating with number of rerecords setting the correct number of rerecords after editions made in TAS movie editor. So… If you have any suggestions or can make contributions, don’t stay silent… smile

P.S.: maybe next time I will make a shared library for working with gmv files


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

#4 2013-08-19 22:00:52

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Re: Tutorial: working with gmv files

Made some improvements; the Windows build is also updated. You may want to redownload-it (or recompile the source, if you are feeuzz a Linux user).

Had some serious troubles with the flags — as it happened, the 16-bit flag variable is encoded as big-endian number (while some others in the header are little-endian encoded). Anyway, this binary hell is over, I am happy smile

gmvprop-2.png

Some other little minor features coming soon


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

#5 2013-08-20 23:20:09

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Re: Tutorial: working with gmv files

New features… Zzzzzzzzz… Coming soon… Hey, guys, seriously, anyone interested in the project? smile

gmvprop-3.png


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

#6 2014-10-18 11:06:41

WST
administrator
From: Maykop, RU · Jakarta, ID
Registered: 2012-10-06
Posts: 287
Website

Re: Tutorial: working with gmv files

Just correcting myself: as there is no guarantee by the standard that sizeof(char) is always 1 byte, it makes sense to use uint8_t instead. However, I beleive, you will not find any place where sizeof(char) ≠ 1 byte.


Sonic the EDGEhog has been obsoleted by Amy the LTEhog ©

Offline

Board footer

Powered by FluxBB

Яндекс.Метрика