diff --git a/movie.c b/movie.c index 0f2cb7ca8f..a82bb8a72c 100644 --- a/movie.c +++ b/movie.c @@ -20,6 +20,7 @@ #include #include "general.h" #include "dynamic.h" +#include // CRC32 implementation taken from BSNES source :) @@ -88,7 +89,7 @@ struct bsv_movie FILE *file; uint8_t *state; - uint16_t *frame_state; // A ring buffer keeping track of many key presses were requested per frame. + long *frame_pos; // A ring buffer keeping track of many key presses were requested per frame. size_t frame_mask; uint16_t current_frame_count; size_t frame_ptr; @@ -221,25 +222,32 @@ void bsv_movie_free(bsv_movie_t *handle) if (handle->file) fclose(handle->file); free(handle->state); - free(handle->frame_state); + free(handle->frame_pos); free(handle); } } bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input) { - if (fread(input, sizeof(int16_t), 1, handle->file) != 1) - return false; + if (g_extern.frame_is_reverse) + { + *input = 0; + return true; + } + else + { + if (fread(input, sizeof(int16_t), 1, handle->file) != 1) + return false; - *input = swap_if_big16(*input); - handle->current_frame_count++; - return true; + *input = swap_if_big16(*input); + return true; + } } void bsv_movie_set_input(bsv_movie_t *handle, int16_t input) { - fwrite(&input, sizeof(int16_t), 1, handle->file); - handle->current_frame_count++; + if (!g_extern.frame_is_reverse) + fwrite(&input, sizeof(int16_t), 1, handle->file); } bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type) @@ -256,7 +264,7 @@ bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type) else if (!init_record(handle, path)) goto error; - if (!(handle->frame_state = malloc((1 << 20) * sizeof(uint16_t)))) // Just pick something really large :D + if (!(handle->frame_pos = calloc((1 << 20), sizeof(long)))) // Just pick something really large :D goto error; handle->frame_mask = (1 << 20) - 1; @@ -267,14 +275,16 @@ error: return NULL; } +void bsv_movie_set_frame_start(bsv_movie_t *handle) +{ + fprintf(stderr, "Starting frame: %u, Pos: %ld\n", (unsigned)handle->frame_ptr, ftell(handle->file)); + handle->frame_pos[handle->frame_ptr] = ftell(handle->file); +} + void bsv_movie_set_frame_end(bsv_movie_t *handle) { - fprintf(stderr, "Current frame count: %u\n", handle->current_frame_count); - handle->frame_state[handle->frame_ptr] = handle->current_frame_count; - handle->current_frame_count = 0; + fprintf(stderr, "Frame++\n"); handle->frame_ptr = (handle->frame_ptr + 1) & handle->frame_mask; - - fprintf(stderr, "Frame end: Current pos: %ld\n", ftell(handle->file) - handle->min_file_pos); } void bsv_movie_frame_rewind(bsv_movie_t *handle) @@ -284,14 +294,16 @@ void bsv_movie_frame_rewind(bsv_movie_t *handle) if (!handle->playback) { fseek(handle->file, 4 * sizeof(uint32_t), SEEK_SET); - psnes_serialize(handle->state, handle->min_file_pos - 4 * sizeof(uint32_t)); - fwrite(handle->state, 1, handle->min_file_pos - 4 * sizeof(uint32_t), handle->file); + psnes_serialize(handle->state, psnes_serialize_size()); + fwrite(handle->state, 1, psnes_serialize_size(), handle->file); } + else + fseek(handle->file, handle->min_file_pos, SEEK_SET); } else { + fprintf(stderr, "Frame--\n"); handle->frame_ptr = (handle->frame_ptr - 1) & handle->frame_mask; - fseek(handle->file, -((long)handle->frame_state[handle->frame_ptr] * sizeof(int16_t)), SEEK_CUR); + fseek(handle->file, handle->frame_pos[handle->frame_ptr], SEEK_SET); } - fprintf(stderr, "Rewind: Current pos: %ld\n", ftell(handle->file) - handle->min_file_pos); } diff --git a/movie.h b/movie.h index 13e6ace1db..ae0f73e3be 100644 --- a/movie.h +++ b/movie.h @@ -38,6 +38,7 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input); void bsv_movie_set_input(bsv_movie_t *handle, int16_t input); // Used for rewinding while playback/record. +void bsv_movie_set_frame_start(bsv_movie_t *handle); // Debugging purposes. void bsv_movie_set_frame_end(bsv_movie_t *handle); void bsv_movie_frame_rewind(bsv_movie_t *handle); diff --git a/rewind.c b/rewind.c index 486b43253c..0c23bbba54 100644 --- a/rewind.c +++ b/rewind.c @@ -33,6 +33,7 @@ struct state_manager size_t top_ptr; size_t bottom_ptr; size_t state_size; + bool first_pop; }; state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void *init_buffer) @@ -77,6 +78,11 @@ void state_manager_free(state_manager_t *state) bool state_manager_pop(state_manager_t *state, void **data) { *data = state->tmp_state; + if (state->first_pop) + { + state->first_pop = false; + return true; + } if (state->top_ptr == 0) state->top_ptr = state->buf_size - 1; @@ -126,7 +132,7 @@ static void generate_delta(state_manager_t *state, const void *data) const uint32_t *new_state = data; state->buffer[state->top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between. - if (state->top_ptr == state->bottom_ptr) // Check if top_ptr and bottom_ptr crossed eachother, which means we need to delete old cruft. + if (state->top_ptr == state->bottom_ptr) // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft. crossed = true; for (uint64_t i = 0; i < state->state_size; i++) @@ -156,6 +162,7 @@ bool state_manager_push(state_manager_t *state, const void *data) { generate_delta(state, data); memcpy(state->tmp_state, data, state->state_size * sizeof(uint32_t)); + state->first_pop = true; return true; } diff --git a/ssnes.c b/ssnes.c index c7a01c4502..9273e5105f 100644 --- a/ssnes.c +++ b/ssnes.c @@ -241,7 +241,7 @@ static void input_poll(void) static int16_t input_state(bool port, unsigned device, unsigned index, unsigned id) { - if (g_extern.bsv_movie && g_extern.bsv_movie_playback && !g_extern.frame_is_reverse) + if (g_extern.bsv_movie && g_extern.bsv_movie_playback) { int16_t ret; if (bsv_movie_get_input(g_extern.bsv_movie, &ret)) @@ -258,7 +258,7 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned binds[i] = g_settings.input.binds[i]; int16_t res = driver.input->input_state(driver.input_data, binds, port, device, index, id); - if (g_extern.bsv_movie && !g_extern.bsv_movie_playback && !g_extern.frame_is_reverse) + if (g_extern.bsv_movie && !g_extern.bsv_movie_playback) bsv_movie_set_input(g_extern.bsv_movie, res); return res; @@ -1037,19 +1037,26 @@ static void check_input_rate(void) static void check_rewind(void) { g_extern.frame_is_reverse = false; + static bool first = true; + if (first) + { + first = false; + return; + } + if (!g_extern.state_manager) return; if (driver.input->key_pressed(driver.input_data, SSNES_REWIND)) { - msg_queue_clear(g_extern.msg_queue); void *buf; if (state_manager_pop(g_extern.state_manager, &buf)) { + g_extern.frame_is_reverse = true; msg_queue_push(g_extern.msg_queue, "Rewinding!", 0, 30); psnes_unserialize(buf, psnes_serialize_size()); - g_extern.frame_is_reverse = true; + if (g_extern.bsv_movie) { for (unsigned i = 0; i < (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); i++) @@ -1254,6 +1261,8 @@ int main(int argc, char *argv[]) if (g_extern.netplay) netplay_pre_frame(g_extern.netplay); + if (g_extern.bsv_movie) + bsv_movie_set_frame_start(g_extern.bsv_movie); psnes_run();