Refactoring of AVI/MNG recording code (#6537)

* Initial refactor of AVI/MNG movie recording, consolidation of copy and paste
code, hiding of AVI/MNG behind interfaces

* Extracted recording specific code out of src/emu/video.cpp and put into
src/emu/recording.cpp

* Took the opportunity to move slightly more logic out of video.cpp into
recording.cpp

* Bug fix

* Consolidated frame counting logic
This commit is contained in:
npwoods 2020-04-22 19:00:30 -04:00 committed by GitHub
parent 5f8108b3ec
commit 7610231242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 460 additions and 419 deletions

View File

@ -177,6 +177,8 @@ files {
MAME_DIR .. "src/emu/profiler.h",
MAME_DIR .. "src/emu/output.cpp",
MAME_DIR .. "src/emu/output.h",
MAME_DIR .. "src/emu/recording.cpp",
MAME_DIR .. "src/emu/recording.h",
MAME_DIR .. "src/emu/render.cpp",
MAME_DIR .. "src/emu/render.h",
MAME_DIR .. "src/emu/rendfont.cpp",

View File

@ -273,11 +273,11 @@ void running_machine::start()
// start recording movie if specified
const char *filename = options().mng_write();
if (filename[0] != 0)
m_video->begin_recording(filename, video_manager::MF_MNG);
m_video->begin_recording(filename, movie_recording::format::MNG);
filename = options().avi_write();
if (filename[0] != 0)
m_video->begin_recording(filename, video_manager::MF_AVI);
m_video->begin_recording(filename, movie_recording::format::AVI);
// if we're coming in with a savegame request, process it now
const char *savegame = options().state();

292
src/emu/recording.cpp Normal file
View File

@ -0,0 +1,292 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
recording.cpp
Core MAME video routines.
***************************************************************************/
#include "emu.h"
#include "screen.h"
#include "aviio.h"
#include "png.h"
namespace
{
class avi_movie_recording : public movie_recording
{
public:
avi_movie_recording(screen_device *screen)
: movie_recording(screen)
{
}
bool initialize(running_machine &machine, std::unique_ptr<emu_file> &&file, int32_t width, int32_t height);
virtual bool add_sound_to_recording(const s16 *sound, int numsamples) override;
protected:
virtual bool append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries) override;
private:
avi_file::ptr m_avi_file; // handle to the open movie file
};
class mng_movie_recording : public movie_recording
{
public:
mng_movie_recording(screen_device *screen, std::map<std::string, std::string> &&info_fields);
~mng_movie_recording();
bool initialize(std::unique_ptr<emu_file> &&file, bitmap_t &snap_bitmap);
virtual bool add_sound_to_recording(const s16 *sound, int numsamples) override;
protected:
virtual bool append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries) override;
private:
std::unique_ptr<emu_file> m_mng_file; // handle to the open movie file
std::map<std::string, std::string> m_info_fields;
};
};
//**************************************************************************
// MOVIE RECORDING
//**************************************************************************
//-------------------------------------------------
// movie_recording - constructor
//-------------------------------------------------
movie_recording::movie_recording(screen_device *screen)
: m_screen(screen)
, m_frame(0)
{
m_frame_period = m_screen ? m_screen->frame_period() : attotime::from_hz(screen_device::DEFAULT_FRAME_RATE);
}
//-------------------------------------------------
// movie_recording - destructor
//-------------------------------------------------
movie_recording::~movie_recording()
{
}
//-------------------------------------------------
// movie_recording::append_video_frame
//-------------------------------------------------
bool movie_recording::append_video_frame(bitmap_rgb32 &bitmap, attotime curtime)
{
// identify the palette
bool has_palette = screen() && screen()->has_palette();
const rgb_t *palette = has_palette ? screen()->palette().palette()->entry_list_adjusted() : nullptr;
int palette_entries = has_palette ? screen()->palette().entries() : 0;
// keep appending frames until we're at curtime
while (next_frame_time() <= curtime)
{
// append this bitmap as a single frame
if (!append_single_video_frame(bitmap, palette, palette_entries))
return false;
m_frame++;
// advance time
set_next_frame_time(next_frame_time() + frame_period());
}
return true;
}
//-------------------------------------------------
// movie_recording::create - creates a new recording
// for the specified format
//-------------------------------------------------
movie_recording::ptr movie_recording::create(running_machine &machine, screen_device *screen, format fmt, std::unique_ptr<emu_file> &&file, bitmap_rgb32 &snap_bitmap)
{
movie_recording::ptr result;
switch (fmt)
{
case movie_recording::format::AVI:
{
auto avi_recording = std::make_unique<avi_movie_recording>(screen);
if (avi_recording->initialize(machine, std::move(file), snap_bitmap.width(), snap_bitmap.height()))
result = std::move(avi_recording);
}
break;
case movie_recording::format::MNG:
{
std::map<std::string, std::string> info_fields;
info_fields["Software"] = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
info_fields["System"] = std::string(machine.system().manufacturer).append(" ").append(machine.system().type.fullname());
auto mng_recording = std::make_unique<mng_movie_recording>(screen, std::move(info_fields));
if (mng_recording->initialize(std::move(file), snap_bitmap))
result = std::move(mng_recording);
}
break;
default:
throw false;
}
// if we successfully create a recording, set the current time and return it
if (result)
result->set_next_frame_time(machine.time());
return result;
}
//-------------------------------------------------
// movie_recording::format_file_extension
//-------------------------------------------------
const char *movie_recording::format_file_extension(movie_recording::format fmt)
{
switch (fmt)
{
case format::AVI: return "avi";
case format::MNG: return "mng";
default: throw false;
}
}
//-------------------------------------------------
// avi_movie_recording::initialize
//-------------------------------------------------
bool avi_movie_recording::initialize(running_machine &machine, std::unique_ptr<emu_file> &&file, int32_t width, int32_t height)
{
// we only use the file we're passed to get the full path
std::string fullpath = file->fullpath();
file.reset();
// build up information about this new movie
avi_file::movie_info info;
info.video_format = 0;
info.video_timescale = 1000 * frame_period().as_hz();
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = width;
info.video_height = height;
info.video_depth = 24;
info.audio_format = 0;
info.audio_timescale = machine.sample_rate();
info.audio_sampletime = 1;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
info.audio_samplerate = machine.sample_rate();
// create the file
avi_file::error avierr = avi_file::create(fullpath, info, m_avi_file);
if (avierr != avi_file::error::NONE)
osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr));
return avierr == avi_file::error::NONE;
}
//-------------------------------------------------
// avi_movie_recording::append_single_video_frame
//-------------------------------------------------
bool avi_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries)
{
avi_file::error avierr = m_avi_file->append_video_frame(bitmap);
return avierr == avi_file::error::NONE;
}
//-------------------------------------------------
// avi_movie_recording::append_video_frame
//-------------------------------------------------
bool avi_movie_recording::add_sound_to_recording(const s16 *sound, int numsamples)
{
g_profiler.start(PROFILER_MOVIE_REC);
// write the next frame
avi_file::error avierr = m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1);
if (avierr == avi_file::error::NONE)
avierr = m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1);
g_profiler.stop();
return avierr == avi_file::error::NONE;
}
//-------------------------------------------------
// mng_movie_recording - constructor
//-------------------------------------------------
mng_movie_recording::mng_movie_recording(screen_device *screen, std::map<std::string, std::string> &&info_fields)
: movie_recording(screen)
, m_info_fields(std::move(info_fields))
{
}
//-------------------------------------------------
// mng_movie_recording - destructor
//-------------------------------------------------
mng_movie_recording::~mng_movie_recording()
{
if (m_mng_file)
mng_capture_stop(*m_mng_file);
}
//-------------------------------------------------
// mng_movie_recording::initialize
//-------------------------------------------------
bool mng_movie_recording::initialize(std::unique_ptr<emu_file> &&file, bitmap_t &snap_bitmap)
{
m_mng_file = std::move(file);
png_error pngerr = mng_capture_start(*m_mng_file, snap_bitmap, frame_period().as_hz());
if (pngerr != PNGERR_NONE)
osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
return pngerr == PNGERR_NONE;
}
//-------------------------------------------------
// mng_movie_recording::append_single_video_frame
//-------------------------------------------------
bool mng_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries)
{
// set up the text fields in the movie info
png_info pnginfo;
if (current_frame() == 0)
{
for (auto &ent : m_info_fields)
pnginfo.add_text(ent.first.c_str(), ent.second.c_str());
}
png_error error = mng_capture_frame(*m_mng_file, pnginfo, bitmap, palette_entries, palette);
return error == png_error::PNGERR_NONE;
}
//-------------------------------------------------
// mng_movie_recording::add_sound_to_recording
//-------------------------------------------------
bool mng_movie_recording::add_sound_to_recording(const s16 *sound, int numsamples)
{
// not supported; do nothing
return true;
}

85
src/emu/recording.h Normal file
View File

@ -0,0 +1,85 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
recording.h
MAME AVI/MNG video recording routines.
***************************************************************************/
#pragma once
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
#ifndef MAME_EMU_RECORDING_H
#define MAME_EMU_RECORDING_H
#include <memory>
#include "attotime.h"
#include "palette.h"
class screen_device;
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> movie_recording
class movie_recording
{
public:
// movie format options
enum class format
{
MNG,
AVI
};
typedef std::unique_ptr<movie_recording> ptr;
// dtor
virtual ~movie_recording();
// accessors
screen_device *screen() { return m_screen; }
attotime frame_period() { return m_frame_period; }
void set_next_frame_time(attotime time) { m_next_frame_time = time; }
attotime next_frame_time() const { return m_next_frame_time; }
// methods
bool append_video_frame(bitmap_rgb32 &bitmap, attotime curtime);
// virtuals
virtual bool add_sound_to_recording(const s16 *sound, int numsamples) = 0;
// statics
static movie_recording::ptr create(running_machine &machine, screen_device *screen, format fmt, std::unique_ptr<emu_file> &&file, bitmap_rgb32 &snap_bitmap);
static const char *format_file_extension(format fmt);
protected:
// ctor
movie_recording(screen_device *screen);
movie_recording(const movie_recording &) = delete;
movie_recording(movie_recording &&) = delete;
// virtuals
virtual bool append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries) = 0;
// accessors
int current_frame() const { return m_frame; }
private:
screen_device * m_screen; // screen associated with this movie (can be nullptr)
attotime m_frame_period; // time of frame period
attotime m_next_frame_time; // time of next frame
int m_frame; // current movie frame number
};
#endif // MAME_EMU_RECORDING_H

View File

@ -16,7 +16,6 @@
#include "rendersw.hxx"
#include "output.h"
#include "aviio.h"
#include "png.h"
#include "xmlfile.h"
@ -412,144 +411,47 @@ std::string &video_manager::timecode_total_text(std::string &str)
return str;
}
//-------------------------------------------------
// begin_recording_mng - begin recording a MNG
// begin_recording_screen - begin recording a
// movie for a specific screen
//-------------------------------------------------
void video_manager::begin_recording_mng(const char *name, uint32_t index, screen_device *screen)
void video_manager::begin_recording_screen(const std::string &filename, uint32_t index, screen_device *screen, movie_recording::format format)
{
// stop any existing recording
end_recording_mng(index);
// determine the file extension
const char *extension = movie_recording::format_file_extension(format);
mng_info_t &info = m_mngs[index];
// create the emu_file
bool is_absolute_path = !filename.empty() && osd_is_absolute_path(filename);
std::unique_ptr<emu_file> movie_file = std::make_unique<emu_file>(
is_absolute_path ? "" : machine().options().snapshot_directory(),
OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
// reset the state
info.m_mng_frame = 0;
info.m_mng_next_frame_time = machine().time();
// create a new movie file and start recording
info.m_mng_file = std::make_unique<emu_file>(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
osd_file::error filerr;
if (name != nullptr)
// and open the actual file
osd_file::error filerr = filename.empty()
? open_next(*movie_file, extension)
: movie_file->open(filename);
if (filerr != osd_file::error::NONE)
{
std::string full_name(name);
if (index > 0)
{
char name_buf[256] = { 0 };
snprintf(name_buf, 256, "%s%d", name, index);
full_name = name_buf;
}
filerr = info.m_mng_file->open(full_name);
}
else
{
filerr = open_next(*info.m_mng_file, "mng");
osd_printf_error("Error creating movie, osd_file::error=%d\n", int(filerr));
return;
}
if (filerr == osd_file::error::NONE)
{
// start the capture
int rate = int(screen ? screen->frame_period().as_hz() : screen_device::DEFAULT_FRAME_RATE);
png_error pngerr = mng_capture_start(*info.m_mng_file, m_snap_bitmap, rate);
if (pngerr != PNGERR_NONE)
{
osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
return end_recording_mng(index);
}
// we have a file; try to create the recording
std::unique_ptr<movie_recording> recording = movie_recording::create(machine(), screen, format, std::move(movie_file), m_snap_bitmap);
// compute the frame time
info.m_mng_frame_period = attotime::from_hz(rate);
}
else
{
osd_printf_error("Error creating MNG, osd_file::error=%d\n", int(filerr));
info.m_mng_file.reset();
}
// if successful push it onto the list
if (recording)
m_movie_recordings.push_back(std::move(recording));
}
//-------------------------------------------------
// begin_recording_avi - begin recording an AVI
//-------------------------------------------------
void video_manager::begin_recording_avi(const char *name, uint32_t index, screen_device *screen)
{
// stop any existing recording
end_recording_avi(index);
avi_info_t &avi_info = m_avis[index];
// reset the state
avi_info.m_avi_frame = 0;
avi_info.m_avi_next_frame_time = machine().time();
// build up information about this new movie
avi_file::movie_info info;
info.video_format = 0;
info.video_timescale = 1000 * (screen ? screen->frame_period().as_hz() : screen_device::DEFAULT_FRAME_RATE);
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = m_snap_bitmap.width();
info.video_height = m_snap_bitmap.height();
info.video_depth = 24;
info.audio_format = 0;
info.audio_timescale = machine().sample_rate();
info.audio_sampletime = 1;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
info.audio_samplerate = machine().sample_rate();
// create a new temporary movie file
osd_file::error filerr;
std::string fullpath;
{
emu_file tempfile(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (name != nullptr)
{
std::string full_name(name);
if (index > 0)
{
char name_buf[256] = { 0 };
snprintf(name_buf, 256, "%s%d", name, index);
full_name = name_buf;
}
filerr = tempfile.open(full_name);
}
else
{
filerr = open_next(tempfile, "avi");
}
// if we succeeded, make a copy of the name and create the real file over top
if (filerr == osd_file::error::NONE)
fullpath = tempfile.fullpath();
}
if (filerr == osd_file::error::NONE)
{
// compute the frame time
avi_info.m_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
// create the file and free the string
avi_file::error avierr = avi_file::create(fullpath, info, avi_info.m_avi_file);
if (avierr != avi_file::error::NONE)
{
osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr));
return end_recording_avi(index);
}
}
}
//-------------------------------------------------
// begin_recording - begin recording of a movie
//-------------------------------------------------
void video_manager::begin_recording(const char *name, movie_format format)
void video_manager::begin_recording(const char *name, movie_recording::format format)
{
// create a snapshot bitmap so we know what the target size is
screen_device_iterator iterator = screen_device_iterator(machine().root_device());
@ -563,84 +465,33 @@ void video_manager::begin_recording(const char *name, movie_format format)
count = 1;
}
switch (format)
// clear out existing recordings
m_movie_recordings.clear();
if (m_snap_native)
{
case MF_AVI:
if (m_avis.empty())
m_avis.resize(count);
if (m_snap_native)
{
for (uint32_t index = 0; index < count; index++, iter++)
{
create_snapshot_bitmap(iter.current());
begin_recording_avi(name, index, iter.current());
}
}
else
{
create_snapshot_bitmap(nullptr);
begin_recording_avi(name, 0, iter.current());
}
break;
for (uint32_t index = 0; index < count; index++, iter++)
{
create_snapshot_bitmap(iter.current());
case MF_MNG:
if (m_mngs.empty())
m_mngs.resize(count);
if (m_snap_native)
{
for (uint32_t index = 0; index < count; index++, iter++)
{
create_snapshot_bitmap(iter.current());
begin_recording_mng(name, index, iter.current());
}
}
else
{
create_snapshot_bitmap(nullptr);
begin_recording_mng(name, 0, iter.current());
}
break;
default:
osd_printf_error("Unknown movie format: %d\n", format);
break;
std::string tempname;
if (name)
tempname = index > 0 ? name : util::string_format("%s%d", name, index);
begin_recording_screen(
tempname,
index,
iter.current(),
format);
}
}
else
{
create_snapshot_bitmap(nullptr);
begin_recording_screen(name ? name : "", 0, iter.current(), format);
}
}
//--------------------------------------------------
// end_recording_avi - stop recording an AVI movie
//--------------------------------------------------
void video_manager::end_recording_avi(uint32_t index)
{
avi_info_t &info = m_avis[index];
if (info.m_avi_file)
{
info.m_avi_file.reset();
// reset the state
info.m_avi_frame = 0;
}
}
//--------------------------------------------------
// end_recording_mng - stop recording a MNG movie
//--------------------------------------------------
void video_manager::end_recording_mng(uint32_t index)
{
mng_info_t &info = m_mngs[index];
if (info.m_mng_file != nullptr)
{
mng_capture_stop(*info.m_mng_file);
info.m_mng_file.reset();
// reset the state
info.m_mng_frame = 0;
}
}
//-------------------------------------------------
// add_sound_to_recording - add sound to a movie
// recording
@ -648,37 +499,10 @@ void video_manager::end_recording_mng(uint32_t index)
void video_manager::add_sound_to_recording(const s16 *sound, int numsamples)
{
for (uint32_t index = 0; index < m_avis.size(); index++)
{
add_sound_to_avi_recording(sound, numsamples, index);
if (!m_snap_native)
break;
}
for (auto &recording : m_movie_recordings)
recording->add_sound_to_recording(sound, numsamples);
}
//-------------------------------------------------
// add_sound_to_avi_recording - add sound to an
// AVI recording for a given screen
//-------------------------------------------------
void video_manager::add_sound_to_avi_recording(const s16 *sound, int numsamples, uint32_t index)
{
avi_info_t &info = m_avis[index];
// only record if we have a file
if (info.m_avi_file != nullptr)
{
g_profiler.start(PROFILER_MOVIE_REC);
// write the next frame
avi_file::error avierr = info.m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1);
if (avierr == avi_file::error::NONE)
avierr = info.m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1);
if (avierr != avi_file::error::NONE)
end_recording_avi(index);
g_profiler.stop();
}
}
//-------------------------------------------------
// video_exit - close down the video system
@ -687,17 +511,7 @@ void video_manager::add_sound_to_avi_recording(const s16 *sound, int numsamples,
void video_manager::exit()
{
// stop recording any movie
for (uint32_t index = 0; index < (std::max)(m_mngs.size(), m_avis.size()); index++)
{
if (index < m_avis.size())
end_recording_avi(index);
if (index < m_mngs.size())
end_recording_mng(index);
if (!m_snap_native)
break;
}
m_movie_recordings.clear();
// free the snapshot target
machine().render().target_free(m_snap_target);
@ -733,17 +547,8 @@ void video_manager::screenless_update_callback(void *ptr, int param)
void video_manager::postload()
{
for (uint32_t index = 0; index < (std::max)(m_mngs.size(), m_avis.size()); index++)
{
if (index < m_avis.size())
m_avis[index].m_avi_next_frame_time = machine().time();
if (index < m_mngs.size())
m_mngs[index].m_mng_next_frame_time = machine().time();
if (!m_snap_native)
break;
}
for (const auto &x : m_movie_recordings)
x->set_next_frame_time(machine().time());
}
@ -754,21 +559,7 @@ void video_manager::postload()
bool video_manager::is_recording() const
{
for (mng_info_t const &mng : m_mngs)
{
if (mng.m_mng_file)
return true;
else if (!m_snap_native)
break;
}
for (avi_info_t const &avi : m_avis)
{
if (avi.m_avi_file)
return true;
else if (!m_snap_native)
break;
}
return false;
return !m_movie_recordings.empty();
}
//-------------------------------------------------
@ -1464,79 +1255,22 @@ void video_manager::record_frame()
g_profiler.start(PROFILER_MOVIE_REC);
attotime curtime = machine().time();
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
for (uint32_t index = 0; index < (std::max)(m_mngs.size(), m_avis.size()); index++, iter++)
bool error = false;
for (auto &recording : m_movie_recordings)
{
// create the bitmap
create_snapshot_bitmap(iter.current());
create_snapshot_bitmap(recording->screen());
// handle an AVI recording
if ((index < m_avis.size()) && m_avis[index].m_avi_file)
{
avi_info_t &avi_info = m_avis[index];
// loop until we hit the right time
while (avi_info.m_avi_next_frame_time <= curtime)
{
// write the next frame
avi_file::error avierr = avi_info.m_avi_file->append_video_frame(m_snap_bitmap);
if (avierr != avi_file::error::NONE)
{
g_profiler.stop(); // FIXME: double exit if this happens?
end_recording_avi(index);
break;
}
// advance time
avi_info.m_avi_next_frame_time += avi_info.m_avi_frame_period;
avi_info.m_avi_frame++;
}
}
// handle a MNG recording
if ((index < m_mngs.size()) && m_mngs[index].m_mng_file)
{
mng_info_t &mng_info = m_mngs[index];
// loop until we hit the right time
while (mng_info.m_mng_next_frame_time <= curtime)
{
// set up the text fields in the movie info
png_info pnginfo;
if (mng_info.m_mng_frame == 0)
{
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname());
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
}
// write the next frame
screen_device *screen = iter.current();
const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr;
int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0;
png_error error = mng_capture_frame(*mng_info.m_mng_file, pnginfo, m_snap_bitmap, entries, palette);
if (error != PNGERR_NONE)
{
g_profiler.stop(); // FIXME: double exit if this happens?
end_recording_mng(index);
break;
}
// advance time
mng_info.m_mng_next_frame_time += mng_info.m_mng_frame_period;
mng_info.m_mng_frame++;
}
}
if (!m_snap_native)
// and append the frame
if (!recording->append_video_frame(m_snap_bitmap, curtime))
{
error = true;
break;
}
}
if (error)
end_recording();
g_profiler.stop();
}
@ -1554,52 +1288,21 @@ void video_manager::toggle_throttle()
// toggle_record_movie
//-------------------------------------------------
void video_manager::toggle_record_movie(movie_format format)
void video_manager::toggle_record_movie(movie_recording::format format)
{
if (!is_recording())
{
begin_recording(nullptr, format);
machine().popmessage("REC START (%s)", format == MF_MNG ? "MNG" : "AVI");
machine().popmessage("REC START (%s)", format == movie_recording::format::MNG ? "MNG" : "AVI");
}
else
{
end_recording(format);
machine().popmessage("REC STOP (%s)", format == MF_MNG ? "MNG" : "AVI");
end_recording();
machine().popmessage("REC STOP");
}
}
void video_manager::end_recording(movie_format format)
void video_manager::end_recording()
{
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
switch (format)
{
case MF_AVI:
for (uint32_t index = 0; index < count; index++, iter++)
{
end_recording_avi(index);
if (!m_snap_native)
{
break;
}
}
break;
case MF_MNG:
for (uint32_t index = 0; index < count; index++, iter++)
{
end_recording_mng(index);
if (!m_snap_native)
{
break;
}
}
break;
default:
osd_printf_error("Unknown movie format: %d\n", format);
break;
}
m_movie_recordings.clear();
}

View File

@ -17,7 +17,7 @@
#ifndef MAME_EMU_VIDEO_H
#define MAME_EMU_VIDEO_H
#include "aviio.h"
#include "recording.h"
//**************************************************************************
@ -40,13 +40,6 @@ class video_manager
friend class screen_device;
public:
// movie format options
enum movie_format
{
MF_MNG,
MF_AVI
};
// construction/destruction
video_manager(running_machine &machine);
@ -69,9 +62,7 @@ public:
// misc
void toggle_throttle();
void toggle_record_movie(movie_format format);
void toggle_record_mng() { toggle_record_movie(MF_MNG); }
void toggle_record_avi() { toggle_record_movie(MF_AVI); }
void toggle_record_movie(movie_recording::format format);
osd_file::error open_next(emu_file &file, const char *extension, uint32_t index = 0);
void compute_snapshot_size(s32 &width, s32 &height);
void pixels(u32 *buffer);
@ -90,14 +81,9 @@ public:
void save_input_timecode();
// movies
void begin_recording(const char *name, movie_format format);
void begin_recording_mng(const char *name, uint32_t index, screen_device *screen);
void begin_recording_avi(const char *name, uint32_t index, screen_device *screen);
void end_recording(movie_format format);
void end_recording_mng(uint32_t index);
void end_recording_avi(uint32_t index);
void begin_recording(const char *name, movie_recording::format format);
void end_recording();
void add_sound_to_recording(const s16 *sound, int numsamples);
void add_sound_to_avi_recording(const s16 *sound, int numsamples, uint32_t index);
void set_timecode_enabled(bool value) { m_timecode_enabled = value; }
bool get_timecode_enabled() { return m_timecode_enabled; }
@ -132,6 +118,9 @@ private:
void create_snapshot_bitmap(screen_device *screen);
void record_frame();
// movies
void begin_recording_screen(const std::string &filename, uint32_t index, screen_device *screen, movie_recording::format format);
// internal state
running_machine & m_machine; // reference to our machine
@ -180,38 +169,8 @@ private:
s32 m_snap_width; // width of snapshots (0 == auto)
s32 m_snap_height; // height of snapshots (0 == auto)
// movie recording - MNG
class mng_info_t
{
public:
mng_info_t()
: m_mng_frame_period(attotime::zero)
, m_mng_next_frame_time(attotime::zero)
, m_mng_frame(0) { }
std::unique_ptr<emu_file> m_mng_file; // handle to the open movie file
attotime m_mng_frame_period; // period of a single movie frame
attotime m_mng_next_frame_time; // time of next frame
u32 m_mng_frame; // current movie frame number
};
std::vector<mng_info_t> m_mngs;
// movie recording - AVI
class avi_info_t
{
public:
avi_info_t()
: m_avi_file(nullptr)
, m_avi_frame_period(attotime::zero)
, m_avi_next_frame_time(attotime::zero)
, m_avi_frame(0) { }
avi_file::ptr 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
u32 m_avi_frame; // current movie frame number
};
std::vector<avi_info_t> m_avis;
// movie recordings
std::vector<movie_recording::ptr> m_movie_recordings;
static const bool s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS];

View File

@ -2129,16 +2129,16 @@ void lua_engine::initialize()
std::string fn = filename;
strreplace(fn, "/", PATH_SEPARATOR);
strreplace(fn, "%g", machine().basename());
vm.begin_recording(fn.c_str(), video_manager::MF_AVI);
vm.begin_recording(fn.c_str(), movie_recording::format::AVI);
},
[](video_manager &vm) { vm.begin_recording(nullptr, video_manager::MF_AVI); }));
[](video_manager &vm) { vm.begin_recording(nullptr, movie_recording::format::AVI); }));
video_type.set("end_recording", [this](video_manager &vm) {
if(!vm.is_recording())
{
machine().logerror("[luaengine] No active recording to stop\n");
return;
}
vm.end_recording(video_manager::MF_AVI);
vm.end_recording();
});
video_type.set("snapshot", &video_manager::save_active_screen_snapshots);
video_type.set("is_recording", &video_manager::is_recording);

View File

@ -1208,11 +1208,11 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
// toggle MNG recording
if (machine().ui_input().pressed(IPT_UI_RECORD_MNG))
machine().video().toggle_record_mng();
machine().video().toggle_record_movie(movie_recording::format::MNG);
// toggle MNG recording
if (machine().ui_input().pressed(IPT_UI_RECORD_AVI))
machine().video().toggle_record_avi();
machine().video().toggle_record_movie(movie_recording::format::AVI);
// toggle profiler display
if (machine().ui_input().pressed(IPT_UI_SHOW_PROFILER))