mirror of
https://github.com/libretro/RetroArch
synced 2025-03-28 19:20:35 +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;
|
FILE *file;
|
||||||
uint8_t *state;
|
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
|
#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)
|
static bool init_playback(bsv_movie_t *handle, const char *path)
|
||||||
{
|
{
|
||||||
|
handle->playback = true;
|
||||||
handle->file = fopen(path, "rb");
|
handle->file = fopen(path, "rb");
|
||||||
if (!handle->file)
|
if (!handle->file)
|
||||||
{
|
{
|
||||||
@ -158,6 +167,8 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
|
|||||||
if (!handle->state)
|
if (!handle->state)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
handle->min_file_pos = sizeof(header) + state_size;
|
||||||
|
|
||||||
if (fread(handle->state, 1, state_size, handle->file) != state_size)
|
if (fread(handle->state, 1, state_size, handle->file) != state_size)
|
||||||
{
|
{
|
||||||
SSNES_ERR("Couldn't read state from movie.\n");
|
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)
|
if (!handle->state)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
handle->min_file_pos = sizeof(header) + state_size;
|
||||||
|
|
||||||
psnes_serialize(handle->state, state_size);
|
psnes_serialize(handle->state, state_size);
|
||||||
fwrite(handle->state, 1, state_size, handle->file);
|
fwrite(handle->state, 1, state_size, handle->file);
|
||||||
return true;
|
return true;
|
||||||
@ -208,6 +221,7 @@ void bsv_movie_free(bsv_movie_t *handle)
|
|||||||
if (handle->file)
|
if (handle->file)
|
||||||
fclose(handle->file);
|
fclose(handle->file);
|
||||||
free(handle->state);
|
free(handle->state);
|
||||||
|
free(handle->frame_state);
|
||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,12 +232,14 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
*input = swap_if_big16(*input);
|
*input = swap_if_big16(*input);
|
||||||
|
handle->current_frame_count++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bsv_movie_set_input(bsv_movie_t *handle, int16_t input)
|
void bsv_movie_set_input(bsv_movie_t *handle, int16_t input)
|
||||||
{
|
{
|
||||||
fwrite(&input, sizeof(int16_t), 1, handle->file);
|
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)
|
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))
|
else if (!init_record(handle, path))
|
||||||
goto error;
|
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;
|
return handle;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
bsv_movie_free(handle);
|
bsv_movie_free(handle);
|
||||||
return NULL;
|
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
|
// Recording
|
||||||
void bsv_movie_set_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_end(bsv_movie_t *handle);
|
||||||
|
void bsv_movie_frame_rewind(bsv_movie_t *handle);
|
||||||
|
|
||||||
void bsv_movie_free(bsv_movie_t *handle);
|
void bsv_movie_free(bsv_movie_t *handle);
|
||||||
|
|
||||||
uint32_t crc32_calculate(const uint8_t *data, unsigned length);
|
uint32_t crc32_calculate(const uint8_t *data, unsigned length);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#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)
|
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;
|
int16_t ret;
|
||||||
if (bsv_movie_get_input(g_extern.bsv_movie, &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];
|
binds[i] = g_settings.input.binds[i];
|
||||||
|
|
||||||
int16_t res = driver.input->input_state(driver.input_data, binds, port, device, index, id);
|
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);
|
bsv_movie_set_input(g_extern.bsv_movie, res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -1042,6 +1042,9 @@ static void check_rewind(void)
|
|||||||
|
|
||||||
if (driver.input->key_pressed(driver.input_data, SSNES_REWIND))
|
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);
|
msg_queue_clear(g_extern.msg_queue);
|
||||||
void *buf;
|
void *buf;
|
||||||
if (state_manager_pop(g_extern.state_manager, &buf))
|
if (state_manager_pop(g_extern.state_manager, &buf))
|
||||||
@ -1174,8 +1177,8 @@ static void do_state_checks(void)
|
|||||||
{
|
{
|
||||||
check_stateslots();
|
check_stateslots();
|
||||||
check_savestates();
|
check_savestates();
|
||||||
check_rewind();
|
|
||||||
}
|
}
|
||||||
|
check_rewind();
|
||||||
|
|
||||||
if (!g_extern.bsv_movie_playback)
|
if (!g_extern.bsv_movie_playback)
|
||||||
check_movie_record();
|
check_movie_record();
|
||||||
@ -1207,14 +1210,15 @@ int main(int argc, char *argv[])
|
|||||||
init_movie();
|
init_movie();
|
||||||
|
|
||||||
if (!g_extern.bsv_movie)
|
if (!g_extern.bsv_movie)
|
||||||
{
|
|
||||||
load_save_files();
|
load_save_files();
|
||||||
init_rewind();
|
|
||||||
}
|
|
||||||
|
|
||||||
init_netplay();
|
init_netplay();
|
||||||
init_drivers();
|
init_drivers();
|
||||||
|
|
||||||
|
if (!g_extern.netplay)
|
||||||
|
init_rewind();
|
||||||
|
|
||||||
psnes_set_video_refresh(g_extern.netplay ? video_frame_net : video_frame);
|
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_audio_sample(g_extern.netplay ? audio_sample_net : audio_sample);
|
||||||
psnes_set_input_poll(g_extern.netplay ? input_poll_net : input_poll);
|
psnes_set_input_poll(g_extern.netplay ? input_poll_net : input_poll);
|
||||||
@ -1250,6 +1254,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
psnes_run();
|
psnes_run();
|
||||||
|
|
||||||
|
if (g_extern.bsv_movie)
|
||||||
|
bsv_movie_set_frame_end(g_extern.bsv_movie);
|
||||||
if (g_extern.netplay)
|
if (g_extern.netplay)
|
||||||
netplay_post_frame(g_extern.netplay);
|
netplay_post_frame(g_extern.netplay);
|
||||||
|
|
||||||
@ -1280,10 +1286,10 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!g_extern.bsv_movie_playback && !g_extern.netplay_is_client)
|
if (!g_extern.bsv_movie_playback && !g_extern.netplay_is_client)
|
||||||
{
|
|
||||||
deinit_rewind();
|
|
||||||
save_files();
|
save_files();
|
||||||
}
|
|
||||||
|
if (!g_extern.netplay)
|
||||||
|
deinit_rewind();
|
||||||
|
|
||||||
deinit_movie();
|
deinit_movie();
|
||||||
deinit_msg_queue();
|
deinit_msg_queue();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user