New enhanced movie encoding.

This commit is contained in:
n-a-c-h
2005-05-15 20:31:01 +00:00
parent 4a2b734b9b
commit 2f7351090d

View File

@@ -176,7 +176,7 @@ variable - Input
12 bits per regular controller, 18 per mouse where input changed padded to next full byte size 12 bits per regular controller, 18 per mouse where input changed padded to next full byte size
Minimum 2 bytes (12 controller bits + 4 padded bits) Minimum 2 bytes (12 controller bits + 4 padded bits)
Maximum 10 bytes (18 mouse controller bits + 48 regular controller bits [12*4] + 6 padded bits) Maximum 9 bytes (18 mouse controller bits + 48 regular controller bits [12*4] + 6 padded bits)
----------------------------------------------------------------- -----------------------------------------------------------------
@@ -546,6 +546,13 @@ Bit Encoder and Decoder
*/ */
/*
When working with bits, you have to find the bits in a byte.
Devide the amount of bits by 8 (bit_count >> 3) to find the proper byte.
The proper bit number in the byte is the amount of bits modulo 8 (bit_count & 7).
To get the most signifigant bit, you want the bit which is 7 minus the proper bit number.
*/
size_t bit_encoder(unsigned int data, unsigned int mask, unsigned char *buffer, size_t skip_bits) size_t bit_encoder(unsigned int data, unsigned int mask, unsigned char *buffer, size_t skip_bits)
{ {
unsigned char bit_loop; unsigned char bit_loop;
@@ -556,11 +563,11 @@ size_t bit_encoder(unsigned int data, unsigned int mask, unsigned char *buffer,
{ {
if (data & BIT(bit_loop)) if (data & BIT(bit_loop))
{ {
buffer[skip_bits/8] |= BIT(7-(skip_bits&7)); buffer[skip_bits>>3] |= BIT(7-(skip_bits&7));
} }
else else
{ {
buffer[skip_bits/8] &= ~BIT(7-(skip_bits&7)); buffer[skip_bits>>3] &= ~BIT(7-(skip_bits&7));
} }
skip_bits++; skip_bits++;
} }
@@ -580,7 +587,7 @@ size_t bit_decoder(unsigned int *data, unsigned int mask, unsigned char *buffer,
{ {
if (mask & BIT(bit_loop)) if (mask & BIT(bit_loop))
{ {
if (buffer[skip_bits/8] & BIT(7-(skip_bits&7))) if (buffer[skip_bits>>3] & BIT(7-(skip_bits&7)))
{ {
*data |= BIT(bit_loop); *data |= BIT(bit_loop);
} }
@@ -599,7 +606,7 @@ Shared var between record/replay functions
*/ */
#define WRITE_BUFFER_SIZE 512 #define WRITE_BUFFER_SIZE 1024
static struct static struct
{ {
struct zmv_header header; struct zmv_header header;
@@ -621,36 +628,137 @@ static struct
size_t rle_count; size_t rle_count;
} zmv_vars; } zmv_vars;
#define GAMEPAD_MASK 0xFFF00000
#define MOUSE_MASK 0x00C0FFFF
#define GAMEPAD_ENABLE 0x00008000
#define MOUSE_ENABLE 0x00010000
static size_t pad_bit_encoder(unsigned char pad, unsigned char *buffer, size_t skip_bits)
{
unsigned int last_state = 0;
switch (pad)
{
case 1:
last_state = zmv_vars.last_joy_state.A;
break;
case 2:
last_state = zmv_vars.last_joy_state.B;
break;
case 3:
last_state = zmv_vars.last_joy_state.C;
break;
case 4:
last_state = zmv_vars.last_joy_state.D;
break;
case 5:
last_state = zmv_vars.last_joy_state.E;
break;
}
switch (pad)
{
case 1:
if (zmv_vars.inputs_enabled & ((pad == 1) ? BIT(0xA) : BIT(0xB))) //Mouse ?
{
skip_bits = bit_encoder(last_state, MOUSE_MASK, buffer, skip_bits);
}
else
{
skip_bits = bit_encoder(last_state, GAMEPAD_MASK, buffer, skip_bits);
}
break;
case 3: case 4: case 5:
//No multitap if both ports use special devices
if (!(zmv_vars.inputs_enabled & BIT(0xA)) || (zmv_vars.inputs_enabled & BIT(0x09)))
{
skip_bits = bit_encoder(last_state, GAMEPAD_MASK, buffer, skip_bits);
}
break;
}
return(skip_bits);
}
static size_t pad_bit_decoder(unsigned char pad, unsigned char *buffer, size_t skip_bits)
{
unsigned int *last_state = 0;
unsigned short input_enable_mask = 0;
switch (pad)
{
case 1:
last_state = &zmv_vars.last_joy_state.A;
input_enable_mask = BIT(15);
break;
case 2:
last_state = &zmv_vars.last_joy_state.B;
input_enable_mask = BIT(14);
break;
case 3:
last_state = &zmv_vars.last_joy_state.C;
input_enable_mask = BIT(13);
break;
case 4:
last_state = &zmv_vars.last_joy_state.D;
input_enable_mask = BIT(12);
break;
case 5:
last_state = &zmv_vars.last_joy_state.E;
input_enable_mask = BIT(11);
break;
}
switch (pad)
{
case 1: case 2:
if (zmv_vars.inputs_enabled & ((pad == 1) ? BIT(0xA) : BIT(0xB))) //Mouse ?
{
skip_bits = bit_decoder(last_state, MOUSE_MASK, buffer, skip_bits);
*last_state |= (zmv_vars.inputs_enabled & input_enable_mask) ? MOUSE_ENABLE : 0;
}
else
{
skip_bits = bit_decoder(last_state, GAMEPAD_MASK, buffer, skip_bits);
*last_state |= (zmv_vars.inputs_enabled & input_enable_mask) ? GAMEPAD_ENABLE : 0;
}
break;
case 3:
//No multitap if both ports use special devices
if ((zmv_vars.inputs_enabled & BIT(0xA)) && (zmv_vars.inputs_enabled & BIT(0x09)))
{
*last_state = 0;
}
else
{
skip_bits = bit_decoder(last_state, GAMEPAD_MASK, buffer, skip_bits);
*last_state |= (zmv_vars.inputs_enabled & input_enable_mask) ? GAMEPAD_ENABLE : 0;
}
break;
}
return(skip_bits);
}
static void save_last_joy_state(unsigned char *buffer) static void save_last_joy_state(unsigned char *buffer)
{ {
size_t skip_bits = 16; size_t skip_bits = 16;
memcpy(buffer, uint16_to_bytes(zmv_vars.inputs_enabled), 2); memcpy(buffer, uint16_to_bytes(zmv_vars.inputs_enabled), 2);
if (zmv_vars.inputs_enabled & BIT(0xA)) //Mouse 1 skip_bits = pad_bit_encoder(1, buffer, skip_bits);
{ skip_bits = pad_bit_encoder(2, buffer, skip_bits);
skip_bits = bit_encoder(zmv_vars.last_joy_state.A, 0x00C0FFFF, buffer, skip_bits); skip_bits = pad_bit_encoder(3, buffer, skip_bits);
} skip_bits = pad_bit_encoder(4, buffer, skip_bits);
else skip_bits = pad_bit_encoder(5, buffer, skip_bits);
{
skip_bits = bit_encoder(zmv_vars.last_joy_state.A, 0xFFF00000, buffer, skip_bits);
}
if (zmv_vars.inputs_enabled & BIT(0x9)) //Mouse 2
{
skip_bits = bit_encoder(zmv_vars.last_joy_state.B, 0x00C0FFFF, buffer, skip_bits);
}
else
{
skip_bits = bit_encoder(zmv_vars.last_joy_state.B, 0xFFF00000, buffer, skip_bits);
}
//No multitap if both ports use special devices
if (!(zmv_vars.inputs_enabled & BIT(0xA)) || (zmv_vars.inputs_enabled & BIT(0x09)))
{
skip_bits = bit_encoder(zmv_vars.last_joy_state.C, 0xFFF00000, buffer, skip_bits);
skip_bits = bit_encoder(zmv_vars.last_joy_state.D, 0xFFF00000, buffer, skip_bits);
skip_bits = bit_encoder(zmv_vars.last_joy_state.E, 0xFFF00000, buffer, skip_bits);
}
} }
static void load_last_joy_state(unsigned char *buffer) static void load_last_joy_state(unsigned char *buffer)
@@ -658,47 +766,14 @@ static void load_last_joy_state(unsigned char *buffer)
size_t skip_bits = 16; size_t skip_bits = 16;
zmv_vars.inputs_enabled = bytes_to_uint16(buffer); zmv_vars.inputs_enabled = bytes_to_uint16(buffer);
if (zmv_vars.inputs_enabled & BIT(0xA)) //Mouse 1 skip_bits = pad_bit_decoder(1, buffer, skip_bits);
{ skip_bits = pad_bit_decoder(2, buffer, skip_bits);
skip_bits = bit_decoder(&zmv_vars.last_joy_state.A, 0x00C0FFFF, buffer, skip_bits); skip_bits = pad_bit_decoder(3, buffer, skip_bits);
zmv_vars.last_joy_state.A |= (zmv_vars.inputs_enabled & BIT(15)) ? 0x00010000 : 0; skip_bits = pad_bit_decoder(4, buffer, skip_bits);
} skip_bits = pad_bit_decoder(5, buffer, skip_bits);
else
{
skip_bits = bit_decoder(&zmv_vars.last_joy_state.A, 0xFFF00000, buffer, skip_bits);
zmv_vars.last_joy_state.A |= (zmv_vars.inputs_enabled & BIT(15)) ? 0x00008000 : 0;
}
if (zmv_vars.inputs_enabled & BIT(0x9)) //Mouse 2
{
skip_bits = bit_decoder(&zmv_vars.last_joy_state.B, 0x00C0FFFF, buffer, skip_bits);
zmv_vars.last_joy_state.B |= (zmv_vars.inputs_enabled & BIT(14)) ? 0x00010000 : 0;
}
else
{
skip_bits = bit_decoder(&zmv_vars.last_joy_state.A, 0xFFF00000, buffer, skip_bits);
zmv_vars.last_joy_state.B |= (zmv_vars.inputs_enabled & BIT(14)) ? 0x00008000 : 0;
}
//No multitap if both ports use special devices
if ((zmv_vars.inputs_enabled & BIT(0xA)) && (zmv_vars.inputs_enabled & BIT(0x09)))
{
zmv_vars.last_joy_state.C = 0;
zmv_vars.last_joy_state.D = 0;
zmv_vars.last_joy_state.E = 0;
}
else
{
skip_bits = bit_decoder(&zmv_vars.last_joy_state.C, 0xFFF00000, buffer, skip_bits);
skip_bits = bit_decoder(&zmv_vars.last_joy_state.D, 0xFFF00000, buffer, skip_bits);
skip_bits = bit_decoder(&zmv_vars.last_joy_state.E, 0xFFF00000, buffer, skip_bits);
zmv_vars.last_joy_state.C |= (zmv_vars.inputs_enabled & BIT(13)) ? 0x00008000 : 0;
zmv_vars.last_joy_state.D |= (zmv_vars.inputs_enabled & BIT(12)) ? 0x00008000 : 0;
zmv_vars.last_joy_state.E |= (zmv_vars.inputs_enabled & BIT(11)) ? 0x00008000 : 0;
}
} }
//These things are a total of 11 bytes (2 byte enable field, up to 9 bytes for input bits)
static void write_last_joy_state(FILE *fp) static void write_last_joy_state(FILE *fp)
{ {
save_last_joy_state(zmv_vars.write_buffer); save_last_joy_state(zmv_vars.write_buffer);
@@ -849,19 +924,57 @@ static void zmv_record_command(enum zmv_commands command)
flush_input_if_needed(); flush_input_if_needed();
} }
#define RECORD_PAD(prev, cur, bit) \ static void record_pad(unsigned char pad, unsigned char *flag, unsigned char *buffer, size_t *skip_bits)
if (cur != prev) \ {
{ \ unsigned int *last_state = 0, current_state = 0;
prev = cur; \ unsigned char bit_mask = 0;
flag |= BIT(bit); \
skip_bits = bit_encoder(prev, 0xFFF00000, press_buf, skip_bits); \ switch (pad)
{
case 1:
last_state = &zmv_vars.last_joy_state.A;
current_state = JoyAOrig;
bit_mask = BIT(7);
break;
case 2:
last_state = &zmv_vars.last_joy_state.B;
current_state = JoyBOrig;
bit_mask = BIT(6);
break;
case 3:
last_state = &zmv_vars.last_joy_state.C;
current_state = JoyCOrig;
bit_mask = BIT(5);
break;
case 4:
last_state = &zmv_vars.last_joy_state.D;
current_state = JoyDOrig;
bit_mask = BIT(4);
break;
case 5:
last_state = &zmv_vars.last_joy_state.E;
current_state = JoyEOrig;
bit_mask = BIT(3);
break;
}
if (current_state != *last_state)
{
*last_state = current_state;
*flag |= bit_mask;
*skip_bits = pad_bit_encoder(pad, buffer, *skip_bits);
}
} }
static void zmv_record(bool pause, unsigned char combos_used, unsigned char slow) static void zmv_record(bool pause, unsigned char combos_used, unsigned char slow)
{ {
unsigned char flag = 0; unsigned char flag = 0;
unsigned char press_buf[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char press_buf[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static double average = 1.0; static float average = 1.0f;
size_t skip_bits = 0; size_t skip_bits = 0;
if (pause) { zmv_vars.header.incr_frames++; } if (pause) { zmv_vars.header.incr_frames++; }
@@ -870,11 +983,11 @@ static void zmv_record(bool pause, unsigned char combos_used, unsigned char slow
debug_input; debug_input;
RECORD_PAD(zmv_vars.last_joy_state.A, JoyAOrig, 7); record_pad(1, &flag, press_buf, &skip_bits);
RECORD_PAD(zmv_vars.last_joy_state.B, JoyBOrig, 6); record_pad(2, &flag, press_buf, &skip_bits);
RECORD_PAD(zmv_vars.last_joy_state.C, JoyCOrig, 5); record_pad(3, &flag, press_buf, &skip_bits);
RECORD_PAD(zmv_vars.last_joy_state.D, JoyDOrig, 4); record_pad(4, &flag, press_buf, &skip_bits);
RECORD_PAD(zmv_vars.last_joy_state.E, JoyEOrig, 3); record_pad(5, &flag, press_buf, &skip_bits);
if (flag) if (flag)
{ {
@@ -894,7 +1007,8 @@ static void zmv_record(bool pause, unsigned char combos_used, unsigned char slow
} }
// it's the right formula, don't waste time busting your brain on it // it's the right formula, don't waste time busting your brain on it
average = (average * (zmv_vars.header.frames + zmv_vars.header.removed_frames) + 1.0/(slow+1))/(zmv_vars.header.frames + zmv_vars.header.removed_frames + 1); average = (average * (zmv_vars.header.frames + zmv_vars.header.removed_frames) + 1.0f/(float)(slow+1)) /
(float)(zmv_vars.header.frames + zmv_vars.header.removed_frames + 1);
// 1/4 precision for NTSC, 1/5 precision for PAL // 1/4 precision for NTSC, 1/5 precision for PAL
zmv_vars.header.average_fps = (unsigned char)(average * ((romispal) ? 250 : 240)); zmv_vars.header.average_fps = (unsigned char)(average * ((romispal) ? 250 : 240));
zmv_vars.header.frames++; zmv_vars.header.frames++;
@@ -1071,7 +1185,7 @@ static bool zmv_replay_command(enum zmv_commands command)
{ \ { \
fread(press_buf + skip_bits/8, 1, 2, zmv_vars.fp); \ fread(press_buf + skip_bits/8, 1, 2, zmv_vars.fp); \
} \ } \
skip_bits = bit_decoder(&prev, 0xFFF00000, press_buf, skip_bits); \ skip_bits = bit_decoder(&prev, GAMEPAD_MASK, press_buf, skip_bits); \
} \ } \
RESTORE_PAD(cur, prev, bit+8) RESTORE_PAD(cur, prev, bit+8)