MNG is now written when -mngwrite is used together with -aviwrite [Oliver Stöneberg]

This commit is contained in:
Oliver Stöneberg 2014-04-07 09:27:43 +00:00
parent d63e60a4c8
commit 9a49c214e3
2 changed files with 112 additions and 70 deletions

View File

@ -101,10 +101,13 @@ video_manager::video_manager(running_machine &machine)
m_snap_native(true), m_snap_native(true),
m_snap_width(0), m_snap_width(0),
m_snap_height(0), m_snap_height(0),
m_avifile(NULL), m_mng_frame_period(attotime::zero),
m_movie_frame_period(attotime::zero), m_mng_next_frame_time(attotime::zero),
m_movie_next_frame_time(attotime::zero), m_mng_frame(0),
m_movie_frame(0) m_avi_file(NULL),
m_avi_frame_period(attotime::zero),
m_avi_next_frame_time(attotime::zero),
m_avi_frame(0)
{ {
// request a callback upon exiting // request a callback upon exiting
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(video_manager::exit), this)); machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(video_manager::exit), this));
@ -359,19 +362,19 @@ void video_manager::save_active_screen_snapshots()
void video_manager::begin_recording(const char *name, movie_format format) void video_manager::begin_recording(const char *name, movie_format format)
{ {
// stop any existign recording
end_recording();
// create a snapshot bitmap so we know what the target size is // create a snapshot bitmap so we know what the target size is
create_snapshot_bitmap(NULL); create_snapshot_bitmap(NULL);
// reset the state
m_movie_frame = 0;
m_movie_next_frame_time = machine().time();
// start up an AVI recording // start up an AVI recording
if (format == MF_AVI) if (format == MF_AVI)
{ {
// stop any existing recording
end_recording(format);
// reset the state
m_avi_frame = 0;
m_avi_next_frame_time = machine().time();
// build up information about this new movie // build up information about this new movie
avi_movie_info info; avi_movie_info info;
info.video_format = 0; info.video_format = 0;
@ -400,9 +403,6 @@ void video_manager::begin_recording(const char *name, movie_format format)
else else
filerr = open_next(tempfile, "avi"); filerr = open_next(tempfile, "avi");
// compute the frame time
m_movie_frame_period = attotime::from_seconds(1000) / info.video_timescale;
// if we succeeded, make a copy of the name and create the real file over top // if we succeeded, make a copy of the name and create the real file over top
if (filerr == FILERR_NONE) if (filerr == FILERR_NONE)
fullpath = tempfile.fullpath(); fullpath = tempfile.fullpath();
@ -410,39 +410,55 @@ void video_manager::begin_recording(const char *name, movie_format format)
if (filerr == FILERR_NONE) if (filerr == FILERR_NONE)
{ {
// compute the frame time
m_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
// create the file and free the string // create the file and free the string
avi_error avierr = avi_create(fullpath, &info, &m_avifile); avi_error avierr = avi_create(fullpath, &info, &m_avi_file);
if (avierr != AVIERR_NONE) if (avierr != AVIERR_NONE)
{
mame_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); mame_printf_error("Error creating AVI: %s\n", avi_error_string(avierr));
return end_recording(format);
}
} }
} }
// start up a MNG recording // start up a MNG recording
else if (format == MF_MNG) else if (format == MF_MNG)
{ {
// stop any existing recording
end_recording(format);
// reset the state
m_mng_frame = 0;
m_mng_next_frame_time = machine().time();
// create a new movie file and start recording // create a new movie file and start recording
m_mngfile.reset(global_alloc(emu_file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS))); m_mng_file.reset(global_alloc(emu_file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS)));
file_error filerr; file_error filerr;
if (name != NULL) if (name != NULL)
filerr = m_mngfile->open(name); filerr = m_mng_file->open(name);
else else
filerr = open_next(*m_mngfile, "mng"); filerr = open_next(*m_mng_file, "mng");
if (filerr == FILERR_NONE) if (filerr == FILERR_NONE)
{ {
// start the capture // start the capture
int rate = (machine().first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine().first_screen()->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE; int rate = (machine().first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine().first_screen()->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE;
png_error pngerr = mng_capture_start(*m_mngfile, m_snap_bitmap, rate); png_error pngerr = mng_capture_start(*m_mng_file, m_snap_bitmap, rate);
if (pngerr != PNGERR_NONE) if (pngerr != PNGERR_NONE)
return end_recording(); {
mame_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
return end_recording(format);
}
// compute the frame time // compute the frame time
m_movie_frame_period = attotime::from_hz(rate); m_mng_frame_period = attotime::from_hz(rate);
} }
else else
{ {
mame_printf_error("Error creating MNG\n"); mame_printf_error("Error creating MNG, file_error=%d\n", filerr);
m_mngfile.reset(); m_mng_file.reset();
} }
} }
} }
@ -452,24 +468,32 @@ void video_manager::begin_recording(const char *name, movie_format format)
// end_recording - stop recording of a movie // end_recording - stop recording of a movie
//------------------------------------------------- //-------------------------------------------------
void video_manager::end_recording() void video_manager::end_recording(movie_format format)
{ {
// close the file if it exists if (format == MF_AVI)
if (m_avifile != NULL)
{ {
avi_close(m_avifile); // close the file if it exists
m_avifile = NULL; if (m_avi_file != NULL)
{
avi_close(m_avi_file);
m_avi_file = NULL;
// reset the state
m_avi_frame = 0;
}
} }
else if (format == MF_MNG)
// close the file if it exists
if (m_mngfile != NULL)
{ {
mng_capture_stop(*m_mngfile); // close the file if it exists
m_mngfile.reset(); if (m_mng_file != NULL)
} {
mng_capture_stop(*m_mng_file);
m_mng_file.reset();
// reset the state // reset the state
m_movie_frame = 0; m_mng_frame = 0;
}
}
} }
@ -481,16 +505,16 @@ void video_manager::end_recording()
void video_manager::add_sound_to_recording(const INT16 *sound, int numsamples) void video_manager::add_sound_to_recording(const INT16 *sound, int numsamples)
{ {
// only record if we have a file // only record if we have a file
if (m_avifile != NULL) if (m_avi_file != NULL)
{ {
g_profiler.start(PROFILER_MOVIE_REC); g_profiler.start(PROFILER_MOVIE_REC);
// write the next frame // write the next frame
avi_error avierr = avi_append_sound_samples(m_avifile, 0, sound + 0, numsamples, 1); avi_error avierr = avi_append_sound_samples(m_avi_file, 0, sound + 0, numsamples, 1);
if (avierr == AVIERR_NONE) if (avierr == AVIERR_NONE)
avierr = avi_append_sound_samples(m_avifile, 1, sound + 1, numsamples, 1); avierr = avi_append_sound_samples(m_avi_file, 1, sound + 1, numsamples, 1);
if (avierr != AVIERR_NONE) if (avierr != AVIERR_NONE)
end_recording(); end_recording(MF_AVI);
g_profiler.stop(); g_profiler.stop();
} }
@ -505,7 +529,8 @@ void video_manager::add_sound_to_recording(const INT16 *sound, int numsamples)
void video_manager::exit() void video_manager::exit()
{ {
// stop recording any movie // stop recording any movie
end_recording(); end_recording(MF_AVI);
end_recording(MF_MNG);
// free the snapshot target // free the snapshot target
machine().render().target_free(m_snap_target); machine().render().target_free(m_snap_target);
@ -541,7 +566,8 @@ void video_manager::screenless_update_callback(void *ptr, int param)
void video_manager::postload() void video_manager::postload()
{ {
m_movie_next_frame_time = machine().time(); m_avi_next_frame_time = machine().time();
m_mng_next_frame_time = machine().time();
} }
@ -1189,7 +1215,7 @@ file_error video_manager::open_next(emu_file &file, const char *extension)
void video_manager::record_frame() void video_manager::record_frame()
{ {
// ignore if nothing to do // ignore if nothing to do
if (m_mngfile == NULL && m_avifile == NULL) if (m_mng_file == NULL && m_avi_file == NULL)
return; return;
// start the profiler and get the current time // start the profiler and get the current time
@ -1199,27 +1225,36 @@ void video_manager::record_frame()
// create the bitmap // create the bitmap
create_snapshot_bitmap(NULL); create_snapshot_bitmap(NULL);
// loop until we hit the right time // handle an AVI recording
while (m_movie_next_frame_time <= curtime) if (m_avi_file != NULL)
{ {
// handle an AVI recording // loop until we hit the right time
if (m_avifile != NULL) while (m_avi_next_frame_time <= curtime)
{ {
// write the next frame // write the next frame
avi_error avierr = avi_append_video_frame(m_avifile, m_snap_bitmap); avi_error avierr = avi_append_video_frame(m_avi_file, m_snap_bitmap);
if (avierr != AVIERR_NONE) if (avierr != AVIERR_NONE)
{ {
g_profiler.stop(); g_profiler.stop();
return end_recording(); end_recording(MF_AVI);
break;
} }
// advance time
m_avi_next_frame_time += m_avi_frame_period;
m_avi_frame++;
} }
}
// handle a MNG recording
if (m_mngfile != NULL) // handle a MNG recording
if (m_mng_file != NULL)
{
// loop until we hit the right time
while (m_mng_next_frame_time <= curtime)
{ {
// set up the text fields in the movie info // set up the text fields in the movie info
png_info pnginfo = { 0 }; png_info pnginfo = { 0 };
if (m_movie_frame == 0) if (m_mng_frame == 0)
{ {
astring text1(emulator_info::get_appname(), " ", build_version); astring text1(emulator_info::get_appname(), " ", build_version);
astring text2(machine().system().manufacturer, " ", machine().system().description); astring text2(machine().system().manufacturer, " ", machine().system().description);
@ -1230,19 +1265,21 @@ void video_manager::record_frame()
// write the next frame // write the next frame
const rgb_t *palette = (machine().first_screen() !=NULL && machine().first_screen()->palette() != NULL) ? machine().first_screen()->palette()->palette()->entry_list_adjusted() : NULL; const rgb_t *palette = (machine().first_screen() !=NULL && machine().first_screen()->palette() != NULL) ? machine().first_screen()->palette()->palette()->entry_list_adjusted() : NULL;
int entries = (machine().first_screen() !=NULL && machine().first_screen()->palette() != NULL) ? machine().first_screen()->palette()->entries() : 0; int entries = (machine().first_screen() !=NULL && machine().first_screen()->palette() != NULL) ? machine().first_screen()->palette()->entries() : 0;
png_error error = mng_capture_frame(*m_mngfile, &pnginfo, m_snap_bitmap, entries, palette); png_error error = mng_capture_frame(*m_mng_file, &pnginfo, m_snap_bitmap, entries, palette);
png_free(&pnginfo); png_free(&pnginfo);
if (error != PNGERR_NONE) if (error != PNGERR_NONE)
{ {
g_profiler.stop(); g_profiler.stop();
return end_recording(); end_recording(MF_MNG);
break;
} }
// advance time
m_mng_next_frame_time += m_mng_frame_period;
m_mng_frame++;
} }
// advance time
m_movie_next_frame_time += m_movie_frame_period;
m_movie_frame++;
} }
g_profiler.stop(); g_profiler.stop();
} }
@ -1264,12 +1301,12 @@ void video_manager::toggle_record_movie()
{ {
if (!is_recording()) if (!is_recording())
{ {
begin_recording(NULL, video_manager::MF_MNG); begin_recording(NULL, MF_MNG);
popmessage("REC START"); popmessage("REC START");
} }
else else
{ {
end_recording(); end_recording(MF_MNG);
popmessage("REC STOP"); popmessage("REC STOP");
} }
} }

View File

@ -64,7 +64,7 @@ public:
bool throttled() const { return m_throttled; } bool throttled() const { return m_throttled; }
float throttle_rate() const { return m_throttle_rate; } float throttle_rate() const { return m_throttle_rate; }
bool fastforward() const { return m_fastforward; } bool fastforward() const { return m_fastforward; }
bool is_recording() const { return (m_mngfile != NULL || m_avifile != NULL); } bool is_recording() const { return (m_mng_file != NULL || m_avi_file != NULL); }
// setters // setters
void set_frameskip(int frameskip); void set_frameskip(int frameskip);
@ -89,8 +89,8 @@ public:
void save_active_screen_snapshots(); void save_active_screen_snapshots();
// movies // movies
void begin_recording(const char *name, movie_format format = MF_AVI); void begin_recording(const char *name, movie_format format);
void end_recording(); void end_recording(movie_format format);
void add_sound_to_recording(const INT16 *sound, int numsamples); void add_sound_to_recording(const INT16 *sound, int numsamples);
private: private:
@ -165,12 +165,17 @@ private:
INT32 m_snap_width; // width of snapshots (0 == auto) INT32 m_snap_width; // width of snapshots (0 == auto)
INT32 m_snap_height; // height of snapshots (0 == auto) INT32 m_snap_height; // height of snapshots (0 == auto)
// movie recording // movie recording - MNG
auto_pointer<emu_file> m_mngfile; // handle to the open movie file auto_pointer<emu_file> m_mng_file; // handle to the open movie file
avi_file * m_avifile; // handle to the open movie file attotime m_mng_frame_period; // period of a single movie frame
attotime m_movie_frame_period; // period of a single movie frame attotime m_mng_next_frame_time; // time of next frame
attotime m_movie_next_frame_time; // time of next frame UINT32 m_mng_frame; // current movie frame number
UINT32 m_movie_frame; // current movie frame number
// movie recording - AVI
avi_file * m_avi_file; // handle to the open movie file
attotime m_avi_frame_period; // period of a single movie frame
attotime m_avi_next_frame_time; // time of next frame
UINT32 m_avi_frame; // current movie frame number
static const UINT8 s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS]; static const UINT8 s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS];