VideoSnaps patch

http://adb.arcadeitalia.net/videosnaps.php
This commit is contained in:
Michele Fochi aka motoschifo 2016-02-07 11:05:55 +01:00
parent 44f98845f7
commit 34bc216ef9
6 changed files with 308 additions and 3 deletions

View File

@ -2454,6 +2454,9 @@ ioport_manager::ioport_manager(running_machine &machine)
m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ),
m_playback_accumulated_speed(0),
m_playback_accumulated_frames(0),
m_timecode_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS),
m_timecode_count(0),
m_timecode_last_time(attotime::zero),
m_has_configs(false),
m_has_analog(false),
m_has_dips(false),
@ -2564,6 +2567,7 @@ time_t ioport_manager::initialize()
// open playback and record files if specified
time_t basetime = playback_init();
record_init();
timecode_init();
return basetime;
}
@ -2657,6 +2661,7 @@ void ioport_manager::exit()
// close any playback or recording files
playback_end();
record_end();
timecode_end();
}
@ -3428,6 +3433,12 @@ void ioport_manager::playback_end(const char *message)
m_playback_accumulated_speed /= m_playback_accumulated_frames;
osd_printf_info("Total playback frames: %d\n", UINT32(m_playback_accumulated_frames));
osd_printf_info("Average recorded speed: %d%%\n", UINT32((m_playback_accumulated_speed * 200 + 1) >> 21));
// Close the Mame at the end of inp file playback
//if (strcmp(message, "End of file")) {
osd_printf_info("Exiting MAME now...\n");
machine().schedule_exit();
//}
}
}
@ -3510,6 +3521,29 @@ void ioport_manager::record_write<bool>(bool value)
record_write(byte);
}
template<typename _Type>
void ioport_manager::timecode_write(_Type value)
{
// protect against NULL handles if previous reads fail
if (!m_timecode_file.is_open())
return;
// read the value; if we fail, end playback
if (m_timecode_file.write(&value, sizeof(value)) != sizeof(value))
timecode_end("Out of space");
}
/*template<>
void ioport_manager::timecode_write<bool>(bool value)
{
UINT8 byte = UINT8(value);
timecode_write(byte);
}*/
template<>
void ioport_manager::timecode_write<std::string>(std::string value) {
timecode_write(value.c_str());
}
//-------------------------------------------------
// record_init - initialize INP recording
@ -3554,6 +3588,41 @@ void ioport_manager::record_init()
}
void ioport_manager::timecode_init() {
// if no file, nothing to do
const char *record_filename = machine().options().record();
if (record_filename[0] == 0) {
machine().video().set_timecode_enabled(false);
return;
}
//osd_printf_error("DEBUG FILENAME-1: %s\n", record_filename);
machine().video().set_timecode_enabled(true);
// open the record file
std::string filename;
filename.append(record_filename).append(".timecode");
//sprintf(filename, "%s.timecode", record_filename);
//osd_printf_error("DEBUG FILENAME-2: %s\n", filename.c_str());
file_error filerr = m_timecode_file.open(filename.c_str());
assert_always(filerr == FILERR_NONE, "Failed to open file for timecode recording");
m_timecode_file.puts(std::string("# ==========================================\n").c_str());
m_timecode_file.puts(std::string("# TIMECODE FILE FOR VIDEO PREVIEW GENERATION\n").c_str());
m_timecode_file.puts(std::string("# ==========================================\n").c_str());
m_timecode_file.puts(std::string("#\n").c_str());
m_timecode_file.puts(std::string("# VIDEO_PART: code of video timecode\n").c_str());
m_timecode_file.puts(std::string("# START: start time (hh:mm:ss.mmm)\n").c_str());
m_timecode_file.puts(std::string("# ELAPSED: elapsed time (hh:mm:ss.mmm)\n").c_str());
m_timecode_file.puts(std::string("# MSEC_START: start time (milliseconds)\n").c_str());
m_timecode_file.puts(std::string("# MSEC_ELAPSED: elapsed time (milliseconds)\n").c_str());
m_timecode_file.puts(std::string("# FRAME_START: start time (frames)\n").c_str());
m_timecode_file.puts(std::string("# FRAME_ELAPSED: elapsed time (frames)\n").c_str());
m_timecode_file.puts(std::string("#\n").c_str());
m_timecode_file.puts(std::string("# VIDEO_PART======= START======= ELAPSED===== MSEC_START===== MSEC_ELAPSED=== FRAME_START==== FRAME_ELAPSED==\n").c_str());
}
//-------------------------------------------------
// record_end - end INP recording
//-------------------------------------------------
@ -3573,6 +3642,19 @@ void ioport_manager::record_end(const char *message)
}
void ioport_manager::timecode_end(const char *message)
{
// only applies if we have a live file
if (m_timecode_file.is_open()) {
// close the file
m_timecode_file.close();
// pop a message
if (message != nullptr)
machine().popmessage("Recording Timecode Ended\nReason: %s", message);
}
}
//-------------------------------------------------
// record_frame - start of frame callback for
// recording
@ -3584,12 +3666,123 @@ void ioport_manager::record_frame(const attotime &curtime)
if (m_record_file.is_open())
{
// first the absolute time
record_write(curtime.seconds());
record_write(curtime.attoseconds());
record_write(curtime.m_seconds);
record_write(curtime.m_attoseconds);
// then the current speed
record_write(UINT32(machine().video().speed_percent() * double(1 << 20)));
}
if (m_timecode_file.is_open() && machine().video().get_timecode_write()) {
// Display the timecode
std::string current_time_str;
m_timecode_count++;
strcatprintf(current_time_str, "%02d:%02d:%02d.%03d",
(int)curtime.m_seconds / (60 * 60),
(curtime.m_seconds / 60) % 60,
curtime.m_seconds % 60,
(int)(curtime.m_attoseconds/ATTOSECONDS_PER_MILLISECOND));
// Elapsed from previous timecode
attotime elapsed_time = curtime - m_timecode_last_time;
m_timecode_last_time = curtime;
std::string elapsed_time_str;
strcatprintf(elapsed_time_str, "%02d:%02d:%02d.%03d",
elapsed_time.m_seconds / (60 * 60),
(elapsed_time.m_seconds / 60) % 60,
elapsed_time.m_seconds % 60,
int(elapsed_time.m_attoseconds/ATTOSECONDS_PER_MILLISECOND));
// Number of ms from beginning of playback
int mseconds_start = curtime.m_seconds*1000 + curtime.m_attoseconds/ATTOSECONDS_PER_MILLISECOND;
std::string mseconds_start_str;
strcatprintf(mseconds_start_str, "%015d", mseconds_start);
// Number of ms from previous timecode
int mseconds_elapsed = elapsed_time.m_seconds*1000 + elapsed_time.m_attoseconds/ATTOSECONDS_PER_MILLISECOND;
std::string mseconds_elapsed_str;
strcatprintf(mseconds_elapsed_str, "%015d", mseconds_elapsed);
// Number of frames from beginning of playback
int frame_start = mseconds_start * 60 / 1000;
std::string frame_start_str;
strcatprintf(frame_start_str, "%015d", frame_start);
// Number of frames from previous timecode
int frame_elapsed = mseconds_elapsed * 60 / 1000;
std::string frame_elapsed_str;
strcatprintf(frame_elapsed_str, "%015d", frame_elapsed);
std::string messaggio;
std::string timecode_text;
std::string timecode_key;
bool show_timecode_counter = false;
if (m_timecode_count==1) {
messaggio += "INTRO STARTED AT " + current_time_str;
timecode_key = "INTRO_START";
timecode_text = "INTRO";
show_timecode_counter = true;
}
else if (m_timecode_count==2) {
messaggio += "INTRO DURATION " + elapsed_time_str;
timecode_key = "INTRO_STOP";
machine().video().add_to_total_time(elapsed_time);
//timecode_text += "INTRO";
}
else if (m_timecode_count==3) {
messaggio += "GAMEPLAY STARTED AT " + current_time_str;
timecode_key = "GAMEPLAY_START";
timecode_text += "GAMEPLAY";
show_timecode_counter = true;
}
else if (m_timecode_count==4) {
messaggio += "GAMEPLAY DURATION " + elapsed_time_str;
timecode_key = "GAMEPLAY_STOP";
machine().video().add_to_total_time(elapsed_time);
//timecode_text += "GAMEPLAY";
}
else if (m_timecode_count % 2 == 1) {
std::string timecode_count_str;
strcatprintf(timecode_count_str, "%03d", (m_timecode_count-3)/2);
timecode_key = "EXTRA_START_" + timecode_count_str;
timecode_count_str.clear();
strcatprintf(timecode_count_str, "%d", (m_timecode_count-3)/2);
messaggio += "EXTRA " + timecode_count_str + " STARTED AT " + current_time_str;
timecode_text += "EXTRA " + timecode_count_str;
show_timecode_counter = true;
}
else {
machine().video().add_to_total_time(elapsed_time);
std::string timecode_count_str;
strcatprintf(timecode_count_str, "%d", (m_timecode_count-4)/2);
messaggio += "EXTRA " + timecode_count_str + " DURATION " + elapsed_time_str;
//std::string timecode_count_str;
timecode_count_str.clear();
strcatprintf(timecode_count_str, "%03d", (m_timecode_count-4)/2);
timecode_key = "EXTRA_STOP_" + timecode_count_str;
}
osd_printf_info("%s \n", messaggio.c_str());
machine().popmessage("%s \n", messaggio.c_str());
std::string riga_file;
riga_file.append(timecode_key).append(19-timecode_key.length(), ' ');
//riga_file += "INTRO_START " +
riga_file +=
" " + current_time_str + " " + elapsed_time_str +
" " + mseconds_start_str + " " + mseconds_elapsed_str +
" " + frame_start_str + " " + frame_elapsed_str +
"\n";
m_timecode_file.puts(riga_file.c_str());
machine().video().set_timecode_write(false);
//machine().video().set_timecode_text(timecode_text);
machine().video().set_timecode_text(timecode_text);
machine().video().set_timecode_start(m_timecode_last_time);
machine().ui().set_show_timecode_counter(show_timecode_counter);
}
}

View File

@ -1452,6 +1452,10 @@ private:
void record_frame(const attotime &curtime);
void record_port(ioport_port &port);
template<typename _Type> void timecode_write(_Type value);
void timecode_init();
void timecode_end(const char *message = NULL);
// internal state
running_machine & m_machine; // reference to owning machine
bool m_safe_to_read; // clear at start; set after state is loaded
@ -1474,6 +1478,9 @@ private:
emu_file m_playback_file; // playback file (NULL if not recording)
UINT64 m_playback_accumulated_speed; // accumulated speed during playback
UINT32 m_playback_accumulated_frames; // accumulated frames during playback
emu_file m_timecode_file; // timecode/frames playback file (NULL if not recording)
int m_timecode_count;
attotime m_timecode_last_time;
// has...
bool m_has_configs;

View File

@ -286,6 +286,8 @@ void ui_manager::init()
m_popup_text_end = 0;
m_use_natural_keyboard = false;
m_mouse_arrow_texture = nullptr;
m_show_timecode_counter = false;
m_show_timecode_total = false;
m_load_save_hold = false;
get_font_rows(&machine());
@ -1035,6 +1037,16 @@ bool ui_manager::is_menu_active(void)
}
bool ui_manager::show_timecode_counter()
{
return m_show_timecode_counter;
}
bool ui_manager::show_timecode_total()
{
return m_show_timecode_total;
}
/***************************************************************************
TEXT GENERATORS
@ -1559,6 +1571,20 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co
JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, nullptr, nullptr);
}
// Show the duration of current part (intro or gameplay or extra)
if (machine.ui().show_timecode_counter()) {
std::string tempstring;
machine.ui().draw_text_full(container, machine.video().timecode_text(tempstring).c_str(), 0.0f, 0.0f, 1.0f,
JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, rgb_t(0xf0,0xf0,0x10,0x10), ARGB_BLACK, NULL, NULL);
}
// Show the total time elapsed for the video preview (all parts intro, gameplay, extras)
if (machine.ui().show_timecode_total()) {
std::string tempstring;
machine.ui().draw_text_full(container, machine.video().timecode_total_text(tempstring).c_str(), 0.0f, 0.0f, 1.0f,
JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, rgb_t(0xf0,0x10,0xf0,0x10), ARGB_BLACK, NULL, NULL);
}
// draw the profiler if visible
if (machine.ui().show_profiler())
{

View File

@ -171,6 +171,10 @@ public:
// other
void process_natural_keyboard();
void set_show_timecode_counter(bool value) { m_show_timecode_counter = value; m_show_timecode_total = true; }
bool show_timecode_counter();
bool show_timecode_total();
// word wrap
void wrap_text(render_container *container, const char *origs, float x, float y, float origwrapwidth, int &totallines, std::vector<int> &xstart, std::vector<int> &xend, float text_size = 1.0f);
@ -195,6 +199,8 @@ private:
std::unique_ptr<UINT8[]> m_non_char_keys_down;
render_texture * m_mouse_arrow_texture;
bool m_mouse_show;
bool m_show_timecode_counter;
bool m_show_timecode_total;
bool m_load_save_hold;
ui_options m_ui_options;

View File

@ -108,7 +108,13 @@ video_manager::video_manager(running_machine &machine)
m_avi_frame_period(attotime::zero),
m_avi_next_frame_time(attotime::zero),
m_avi_frame(0),
m_dummy_recording(false)
m_dummy_recording(false),
m_timecode_enabled(false),
m_timecode_write(false),
m_timecode_text(""),
m_timecode_start(attotime::zero),
m_timecode_total(attotime::zero)
{
// request a callback upon exiting
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(video_manager::exit), this));
@ -335,6 +341,13 @@ void video_manager::save_snapshot(screen_device *screen, emu_file &file)
void video_manager::save_active_screen_snapshots()
{
// If record inp is acrive, no snapshot will be created
if (m_timecode_enabled) {
// This flag will write the line on file inp.timecode (see function ioport_manager::record_frame)
m_timecode_write = true;
return;
}
// if we're native, then write one snapshot per visible screen
if (m_snap_native)
{
@ -360,6 +373,48 @@ void video_manager::save_active_screen_snapshots()
}
}
std::string &video_manager::timecode_text(std::string &str) {
str.clear();
str += " ";
if (!m_timecode_text.empty()) {
str += m_timecode_text + " ";
}
attotime elapsed_time = machine().time() - m_timecode_start;
std::string elapsed_time_str;
strcatprintf(elapsed_time_str, "%02d:%02d",
(elapsed_time.m_seconds / 60) % 60,
elapsed_time.m_seconds % 60);
str += elapsed_time_str;
bool paused = machine().paused();
if (paused) {
str.append(" [paused]");
}
str += " ";
return str;
}
std::string &video_manager::timecode_total_text(std::string &str) {
str.clear();
str += " TOTAL ";
attotime elapsed_time = m_timecode_total;
if (machine().ui().show_timecode_counter()) {
elapsed_time += machine().time() - m_timecode_start;
}
std::string elapsed_time_str;
strcatprintf(elapsed_time_str, "%02d:%02d",
(elapsed_time.m_seconds / 60) % 60,
elapsed_time.m_seconds % 60);
str += elapsed_time_str + " ";
return str;
}
//-------------------------------------------------
// begin_recording - begin recording of a movie

View File

@ -92,6 +92,17 @@ public:
void begin_recording(const char *name, movie_format format);
void end_recording(movie_format format);
void add_sound_to_recording(const INT16 *sound, int numsamples);
void set_timecode_enabled(bool value) { m_timecode_enabled = value; }
bool get_timecode_enabled() { return m_timecode_enabled; }
bool get_timecode_write() { return m_timecode_write; }
void set_timecode_write(bool value) { m_timecode_write = value; }
void set_timecode_text(std::string &str) { m_timecode_text = str; }
void set_timecode_start(attotime time) { m_timecode_start = time; }
void add_to_total_time(attotime time) { m_timecode_total += time; }
std::string &timecode_text(std::string &str);
std::string &timecode_total_text(std::string &str);
private:
// internal helpers
@ -184,6 +195,13 @@ private:
static const attoseconds_t ATTOSECONDS_PER_SPEED_UPDATE = ATTOSECONDS_PER_SECOND / 4;
static const int PAUSED_REFRESH_RATE = 30;
bool m_timecode_enabled; // inp.timecode record enabled
bool m_timecode_write; // Show/hide timer at right (partial time)
std::string m_timecode_text; // Message for that video part (intro, gameplay, extra)
attotime m_timecode_start; // Starting timer for that video part (intro, gameplay, extra)
attotime m_timecode_total; // Show/hide timer at left (total elapsed on resulting video preview)
};
#endif /* __VIDEO_H__ */