mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-29 15:32:01 +00:00
A start on movie rewind.
This commit is contained in:
parent
b07827a856
commit
e8865060ca
45
movie.c
45
movie.c
@ -87,6 +87,14 @@ 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.
|
||||
size_t frame_mask;
|
||||
uint16_t current_frame_count;
|
||||
size_t frame_ptr;
|
||||
|
||||
bool playback;
|
||||
unsigned min_file_pos;
|
||||
};
|
||||
|
||||
#define BSV_MAGIC 0x42535631
|
||||
@ -127,6 +135,7 @@ static inline uint16_t swap_if_big16(uint16_t val)
|
||||
|
||||
static bool init_playback(bsv_movie_t *handle, const char *path)
|
||||
{
|
||||
handle->playback = true;
|
||||
handle->file = fopen(path, "rb");
|
||||
if (!handle->file)
|
||||
{
|
||||
@ -158,6 +167,8 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
|
||||
if (!handle->state)
|
||||
return false;
|
||||
|
||||
handle->min_file_pos = sizeof(header) + state_size;
|
||||
|
||||
if (fread(handle->state, 1, state_size, handle->file) != state_size)
|
||||
{
|
||||
SSNES_ERR("Couldn't read state from movie.\n");
|
||||
@ -196,6 +207,8 @@ static bool init_record(bsv_movie_t *handle, const char *path)
|
||||
if (!handle->state)
|
||||
return false;
|
||||
|
||||
handle->min_file_pos = sizeof(header) + state_size;
|
||||
|
||||
psnes_serialize(handle->state, state_size);
|
||||
fwrite(handle->state, 1, state_size, handle->file);
|
||||
return true;
|
||||
@ -208,6 +221,7 @@ void bsv_movie_free(bsv_movie_t *handle)
|
||||
if (handle->file)
|
||||
fclose(handle->file);
|
||||
free(handle->state);
|
||||
free(handle->frame_state);
|
||||
free(handle);
|
||||
}
|
||||
}
|
||||
@ -218,12 +232,14 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input)
|
||||
return false;
|
||||
|
||||
*input = swap_if_big16(*input);
|
||||
handle->current_frame_count++;
|
||||
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++;
|
||||
}
|
||||
|
||||
bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type)
|
||||
@ -240,9 +256,38 @@ 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
|
||||
goto error;
|
||||
handle->frame_mask = (1 << 20) - 1;
|
||||
|
||||
return handle;
|
||||
|
||||
error:
|
||||
bsv_movie_free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bsv_movie_set_frame_end(bsv_movie_t *handle)
|
||||
{
|
||||
handle->frame_state[handle->frame_ptr] = handle->current_frame_count;
|
||||
handle->current_frame_count = 0;
|
||||
handle->frame_ptr = (handle->frame_ptr + 1) & handle->frame_mask;
|
||||
}
|
||||
|
||||
void bsv_movie_frame_rewind(bsv_movie_t *handle)
|
||||
{
|
||||
if (ftell(handle->file) <= (long)handle->min_file_pos)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
7
movie.h
7
movie.h
@ -37,12 +37,13 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input);
|
||||
// Recording
|
||||
void bsv_movie_set_input(bsv_movie_t *handle, int16_t input);
|
||||
|
||||
// Used for rewinding while playback/record.
|
||||
void bsv_movie_set_frame_end(bsv_movie_t *handle);
|
||||
void bsv_movie_frame_rewind(bsv_movie_t *handle);
|
||||
|
||||
void bsv_movie_free(bsv_movie_t *handle);
|
||||
|
||||
uint32_t crc32_calculate(const uint8_t *data, unsigned length);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
24
ssnes.c
24
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)
|
||||
if (g_extern.bsv_movie && g_extern.bsv_movie_playback && !g_extern.frame_is_reverse)
|
||||
{
|
||||
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)
|
||||
if (g_extern.bsv_movie && !g_extern.bsv_movie_playback && !g_extern.frame_is_reverse)
|
||||
bsv_movie_set_input(g_extern.bsv_movie, res);
|
||||
|
||||
return res;
|
||||
@ -1042,6 +1042,9 @@ static void check_rewind(void)
|
||||
|
||||
if (driver.input->key_pressed(driver.input_data, SSNES_REWIND))
|
||||
{
|
||||
if (g_extern.bsv_movie)
|
||||
bsv_movie_frame_rewind(g_extern.bsv_movie);
|
||||
|
||||
msg_queue_clear(g_extern.msg_queue);
|
||||
void *buf;
|
||||
if (state_manager_pop(g_extern.state_manager, &buf))
|
||||
@ -1174,8 +1177,8 @@ static void do_state_checks(void)
|
||||
{
|
||||
check_stateslots();
|
||||
check_savestates();
|
||||
check_rewind();
|
||||
}
|
||||
check_rewind();
|
||||
|
||||
if (!g_extern.bsv_movie_playback)
|
||||
check_movie_record();
|
||||
@ -1207,14 +1210,15 @@ int main(int argc, char *argv[])
|
||||
init_movie();
|
||||
|
||||
if (!g_extern.bsv_movie)
|
||||
{
|
||||
load_save_files();
|
||||
init_rewind();
|
||||
}
|
||||
|
||||
|
||||
init_netplay();
|
||||
init_drivers();
|
||||
|
||||
if (!g_extern.netplay)
|
||||
init_rewind();
|
||||
|
||||
psnes_set_video_refresh(g_extern.netplay ? video_frame_net : video_frame);
|
||||
psnes_set_audio_sample(g_extern.netplay ? audio_sample_net : audio_sample);
|
||||
psnes_set_input_poll(g_extern.netplay ? input_poll_net : input_poll);
|
||||
@ -1250,6 +1254,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
psnes_run();
|
||||
|
||||
if (g_extern.bsv_movie)
|
||||
bsv_movie_set_frame_end(g_extern.bsv_movie);
|
||||
if (g_extern.netplay)
|
||||
netplay_post_frame(g_extern.netplay);
|
||||
|
||||
@ -1280,10 +1286,10 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
if (!g_extern.bsv_movie_playback && !g_extern.netplay_is_client)
|
||||
{
|
||||
deinit_rewind();
|
||||
save_files();
|
||||
}
|
||||
|
||||
if (!g_extern.netplay)
|
||||
deinit_rewind();
|
||||
|
||||
deinit_movie();
|
||||
deinit_msg_queue();
|
||||
|
Loading…
x
Reference in New Issue
Block a user