.smv is the movie capture format of Snes9x emulators.
SMV 1.43
SMV file consists of a 32-byte header and various blocks that depend on settings.
Header format
000 4-byte signature: 53 4D 56 1A "SMV\x1A" 004 4-byte little-endian unsigned int: version number, must be 1 008 4-byte little-endian integer: movie "uid" - identifies the movie-savestate relationship, also used as the recording time in Unix epoch format 00C 4-byte little-endian unsigned int: rerecord count 010 4-byte little-endian unsigned int: number of frames 014 1-byte flags "controller mask": bit 0: controller 1 in use bit 1: controller 2 in use bit 2: controller 3 in use bit 3: controller 4 in use bit 4: controller 5 in use other: reserved, set to 0 015 1-byte flags "movie options": bit 0: if "0", movie begins from an embedded "quicksave" snapshot if "1", a SRAM is included instead of a quicksave; movie begins from reset bit 1: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps) other: reserved, set to 0 016 1-byte flags "sync options": bit 0: MOVIE_SYNC2_INIT_FASTROM other: reserved, set to 0 017 1-byte flags "sync options": bit 0: MOVIE_SYNC_DATA_EXISTS if "1", all sync options flags are defined. if "0", all sync options flags have no meaning. bit 1: MOVIE_SYNC_WIP1TIMING bit 2: MOVIE_SYNC_LEFTRIGHT bit 3: MOVIE_SYNC_VOLUMEENVX bit 4: MOVIE_SYNC_FAKEMUTE bit 5: MOVIE_SYNC_SYNCSOUND bit 6: MOVIE_SYNC_HASROMINFO if "1", there is extra ROM info located right in between of the metadata and the savestate. bit 7: set to 0. 018 4-byte little-endian unsigned int: offset to the savestate inside file 01C 4-byte little-endian unsigned int: offset to the controller data inside file
Metadata
After the header comes "metadata", which is UTF16-coded movie title string (author info). The metadata begins from position 32 (0x20) and ends at <savestate_offset - length_of_extra_rom_info_in_bytes>.
Extra ROM info
Extra ROM info is an optional 30-byte record which contains the following structure:
000 3 bytes of zero padding: 00 00 00 003 4-byte integer: CRC32 of the ROM 007 23-byte ascii string: the game name copied from the ROM, truncated to 23 bytes (the game name in the ROM is 21 bytes)
Extra ROM info is always positioned right before the savestate.
Its size is 30 bytes if MOVIE_SYNC_HASROMINFO is used (and MOVIE_SYNC_DATA_EXISTS is set), 0 bytes otherwise.
Savestates
The savestate offset is <32 + length_of_metadata_in_bytes + length_of_extra_rom_info_in_bytes>.
At the savestate offset there is a gzip-compressed file.
* If the movie is snapshot-anchored, it is a structured Snes9x savestate. * If the movie is reset-anchored, it is a SRAM snapshot (which should decompress into 0x20000 bytes in length).
Controller data
The controller data offset is <savestate_offset + length_of_compressed_savestate>.
The controller data contains <number_of_frames + 1> frames. Each frame consists of 2 bytes per controller. So if there are 3 controllers, a frame is 6 bytes and if there is only 1 controller, a frame is 2 bytes.
Note that the savestate data must come before controller data - Snes9x uses the savestate offset to calculate the length of the metadata.
A gap between the savestate data and the controller data is allowed.
Each value is determined by OR-ing together values for whichever of the following are pressed:
01 00 (reserved) 02 00 (reserved) 04 00 (reserved) 08 00 (reserved) 10 00 R 20 00 L 40 00 X 80 00 A 00 01 Right 00 02 Left 00 04 Down 00 08 Up 00 10 Start 00 20 Select 00 40 Y 00 80 B
In the reset-recording patch, a frame that contains the value FF FF for every controller denotes a reset. The reset is done through the S9xSoftReset routine.
Smv 151
The format is very similar to the SMV 1.43 format with only the following changes:
The version byte at 004 must be 4 instead of 1
The byte 016 bit 0 (MOVIE_SYNC2_INIT_FASTROM) has no meaning and should be 0.
The byte 017 bit 1 (MOVIE_SYNC_WIP1TIMING) now has no meaning and should be 0.
The byte 017 bit 7 is now MOVIE_SYNC_NOCPUSHUTDOWN. 0 means the "SpeedHacks" config option is on, 1 means it is off. (This option is off (=1) by default, and turning it on means a different (usually laggier) timing.)
The header has an additional 32 bytes at the end:
020 4-byte little-endian unsigned int: number of input samples, primarily for peripheral-using games 024 2 1-byte unsigned ints: what type of controller is plugged into ports 1 and 2 respectively: 0=NONE, 1=JOYPAD, 2=MOUSE, 3=SUPERSCOPE, 4=JUSTIFIER, 5=MULTITAP 026 4 1-byte signed ints: controller IDs of port 1, or -1 for unplugged 02A 4 1-byte signed ints: controller IDs of port 2, or -1 for unplugged 02E 18 bytes: reserved for future use
The header size is thus 64 bytes as opposed to 32 bytes. The only difference this makes for existing programs that deal with v1.43 SMV files is that, if they need to look at the metadata (author info), they must look for it at 0x40 instead of 0x20. The first 32 bytes in the header were not rearranged, and locating the controller and save data is unaffected because those are not stored at absolute file positions.
Controller data format
Also, while the meaning of controller data for a single standard SNES controller pad remains the same, each frame of controller data can contain additional bytes if input for peripherals is being recorded.
Here is how to calculate the size in bytes of a frame or sample of controller data in a v1.51 SMV:
- sizeof(InputSample) == 2*number_of_controllers + 5*num_mouse_ports + 6*num_superscope_ports + 11*num_justifier_ports
where
- number_of_controllers == the sum of the bits in byte 0x014 in the header.
- num_mouse_ports == the number of bytes 0x024 - 0x025 inclusive that are 2=MOUSE
- num_superscope_ports == the number of bytes 0x024 - 0x025 inclusive that are 3=SUPERSCOPE
- num_justifier_ports == the number of bytes 0x024 - 0x025 inclusive that are 4=JUSTIFIER
The total number of these samples stored in the movie is given by the number at 0x020 in the header. This should be the number of movie frames if no peripherals were used, or higher if peripherals were used. There is considerable redundancy in the controller data stored in a peripheral-using movie, but presumably it compresses well, and the length in bytes of an input sample continues to be uniform for a given movie.