2012-01-11 01:21:13 +02:00
|
|
|
#ifndef _advdumper__hpp__included__
|
|
|
|
#define _advdumper__hpp__included__
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <set>
|
|
|
|
#include <stdexcept>
|
2014-05-28 13:51:24 +03:00
|
|
|
#include <iostream>
|
2012-01-11 01:21:13 +02:00
|
|
|
|
2012-06-20 17:40:27 +03:00
|
|
|
#include "library/framebuffer.hpp"
|
2014-05-28 13:51:24 +03:00
|
|
|
#include "library/dispatch.hpp"
|
|
|
|
#include "library/threads.hpp"
|
2012-02-04 16:57:41 +02:00
|
|
|
|
2014-05-28 13:51:24 +03:00
|
|
|
class master_dumper;
|
|
|
|
class dumper_factory_base;
|
|
|
|
class dumper_base;
|
2014-06-06 15:03:16 +03:00
|
|
|
class lua_state;
|
2014-05-28 13:51:24 +03:00
|
|
|
|
|
|
|
class dumper_factory_base
|
2012-01-11 01:21:13 +02:00
|
|
|
{
|
|
|
|
public:
|
2014-05-28 13:51:24 +03:00
|
|
|
/**
|
|
|
|
* Notifier base.
|
|
|
|
*/
|
|
|
|
class notifier
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~notifier() throw();
|
|
|
|
virtual void dumpers_updated() throw() = 0;
|
|
|
|
};
|
2012-04-06 14:35:56 +03:00
|
|
|
/**
|
|
|
|
* Detail flags.
|
|
|
|
*/
|
2014-06-03 03:52:13 +03:00
|
|
|
static const unsigned target_type_mask;
|
|
|
|
static const unsigned target_type_file;
|
|
|
|
static const unsigned target_type_prefix;
|
|
|
|
static const unsigned target_type_special;
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
|
|
|
* Register a dumper.
|
|
|
|
*
|
|
|
|
* Parameter id: The ID of dumper.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2014-05-28 13:51:24 +03:00
|
|
|
dumper_factory_base(const std::string& id) throw(std::bad_alloc);
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
|
|
|
* Unregister a dumper.
|
|
|
|
*/
|
2014-05-28 13:51:24 +03:00
|
|
|
~dumper_factory_base();
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
|
|
|
* Get ID of dumper.
|
|
|
|
*
|
|
|
|
* Returns: The id.
|
|
|
|
*/
|
|
|
|
const std::string& id() throw();
|
|
|
|
/**
|
|
|
|
* Get set of all dumpers.
|
|
|
|
*
|
|
|
|
* Returns: The set.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2014-05-28 13:51:24 +03:00
|
|
|
static std::set<dumper_factory_base*> get_dumper_set() throw(std::bad_alloc);
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
|
|
|
* List all valid submodes.
|
|
|
|
*
|
|
|
|
* Returns: List of all valid submodes. Empty list means this dumper has no submodes.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
virtual std::set<std::string> list_submodes() throw(std::bad_alloc) = 0;
|
|
|
|
/**
|
2012-04-06 14:35:56 +03:00
|
|
|
* Get mode details
|
2012-01-11 01:21:13 +02:00
|
|
|
*
|
|
|
|
* parameter mode: The submode.
|
2012-04-06 14:35:56 +03:00
|
|
|
* Returns: Mode details flags
|
2012-01-11 01:21:13 +02:00
|
|
|
*/
|
2012-04-06 14:35:56 +03:00
|
|
|
virtual unsigned mode_details(const std::string& mode) throw() = 0;
|
2012-09-05 20:13:26 +03:00
|
|
|
/**
|
|
|
|
* Get mode extensions. Only called if mode details specifies that output is a single file.
|
|
|
|
*
|
|
|
|
* parameter mode: The submode.
|
|
|
|
* Returns: Mode extension
|
|
|
|
*/
|
|
|
|
virtual std::string mode_extension(const std::string& mode) throw() = 0;
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
|
|
|
* Get human-readable name for this dumper.
|
|
|
|
*
|
|
|
|
* Returns: The name.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
virtual std::string name() throw(std::bad_alloc) = 0;
|
|
|
|
/**
|
|
|
|
* Get human-readable name for submode.
|
|
|
|
*
|
|
|
|
* Parameter mode: The submode.
|
|
|
|
* Returns: The name.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
virtual std::string modename(const std::string& mode) throw(std::bad_alloc) = 0;
|
|
|
|
/**
|
|
|
|
* Start dump.
|
|
|
|
*
|
|
|
|
* parameter mode: The mode to dump using.
|
|
|
|
* parameter targetname: The target filename or prefix.
|
2014-05-28 13:51:24 +03:00
|
|
|
* returns: The dumper object.
|
2012-01-11 01:21:13 +02:00
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
* Throws std::runtime_error: Can't start dump.
|
|
|
|
*/
|
2014-05-28 13:51:24 +03:00
|
|
|
virtual dumper_base* start(master_dumper& _mdumper, const std::string& mode, const std::string& targetname)
|
|
|
|
throw(std::bad_alloc, std::runtime_error) = 0;
|
2012-01-11 01:21:13 +02:00
|
|
|
/**
|
2014-05-28 13:51:24 +03:00
|
|
|
* Add dumper update notifier object.
|
2012-01-11 01:21:13 +02:00
|
|
|
*/
|
2014-05-28 13:51:24 +03:00
|
|
|
static void add_notifier(notifier& n);
|
|
|
|
/**
|
|
|
|
* Remove dumper update notifier object.
|
|
|
|
*/
|
|
|
|
static void drop_notifier(notifier& n);
|
|
|
|
/**
|
|
|
|
* Notify ctor finished.
|
|
|
|
*/
|
|
|
|
void ctor_notify();
|
|
|
|
/**
|
|
|
|
* Notify dumper change.
|
|
|
|
*/
|
|
|
|
static void run_notify();
|
2012-01-11 01:21:13 +02:00
|
|
|
private:
|
|
|
|
std::string d_id;
|
|
|
|
};
|
|
|
|
|
2014-05-28 13:51:24 +03:00
|
|
|
class master_dumper
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Information about run.
|
|
|
|
*/
|
|
|
|
struct gameinfo
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Construct game info.
|
|
|
|
*/
|
|
|
|
gameinfo() throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Game name.
|
|
|
|
*/
|
|
|
|
std::string gamename;
|
|
|
|
/**
|
|
|
|
* Run length in seconds.
|
|
|
|
*/
|
|
|
|
double length;
|
|
|
|
/**
|
|
|
|
* Rerecord count (base 10 ASCII)
|
|
|
|
*/
|
|
|
|
std::string rerecords;
|
|
|
|
/**
|
|
|
|
* Authors. The first components are real names, the second components are nicknames. Either (but not both) may be
|
|
|
|
* blank.
|
|
|
|
*/
|
|
|
|
std::vector<std::pair<std::string, std::string>> authors;
|
|
|
|
/**
|
|
|
|
* Format human-redable representation of the length.
|
|
|
|
*
|
|
|
|
* Parameter digits: Number of sub-second digits to use.
|
|
|
|
* Returns: The time formated.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
std::string get_readable_time(unsigned digits) const throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Get number of authors.
|
|
|
|
*
|
|
|
|
* Returns: Number of authors.
|
|
|
|
*/
|
|
|
|
size_t get_author_count() const throw();
|
|
|
|
/**
|
|
|
|
* Get short name of author (nickname if present, otherwise full name).
|
|
|
|
*
|
|
|
|
* Parameter idx: Index of author (0-based).
|
|
|
|
* Returns: The short name.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
std::string get_author_short(size_t idx) const throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Get long name of author (full name and nickname if present).
|
|
|
|
*
|
|
|
|
* Parameter idx: Index of author (0-based).
|
|
|
|
* Returns: The long name.
|
|
|
|
* Throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
|
|
|
std::string get_author_long(size_t idx) const throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Get rerecord count as a number. If rerecord count is too high, returns the maximum representatible count.
|
|
|
|
*
|
|
|
|
* Returns: The rerecord count.
|
|
|
|
*/
|
|
|
|
uint64_t get_rerecords() const throw();
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Notifier.
|
|
|
|
*/
|
|
|
|
class notifier
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~notifier() throw();
|
|
|
|
virtual void dump_status_change() = 0;
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Ctor.
|
|
|
|
*/
|
2014-06-06 15:03:16 +03:00
|
|
|
master_dumper(lua_state& _lua2);
|
2014-05-28 13:51:24 +03:00
|
|
|
/**
|
|
|
|
* Get instance for specified dumper.
|
|
|
|
*/
|
|
|
|
dumper_base* get_instance(dumper_factory_base* dumper) throw();
|
|
|
|
/**
|
|
|
|
* Is dumper busy in this instance?
|
|
|
|
*/
|
|
|
|
bool busy(dumper_factory_base* dumper) throw()
|
|
|
|
{
|
|
|
|
return get_instance(dumper) != NULL;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Call start on dumper.
|
|
|
|
*/
|
|
|
|
dumper_base* start(dumper_factory_base& factory, const std::string& mode, const std::string& targetname)
|
|
|
|
throw(std::bad_alloc, std::runtime_error);
|
|
|
|
/**
|
|
|
|
* Add dumper update notifier object.
|
|
|
|
*/
|
|
|
|
void add_notifier(notifier& n);
|
|
|
|
/**
|
|
|
|
* Remove dumper update notifier object.
|
|
|
|
*/
|
|
|
|
void drop_notifier(notifier& n);
|
|
|
|
/**
|
|
|
|
* Add dumper update notifier object.
|
|
|
|
*/
|
|
|
|
void add_dumper(dumper_base& n);
|
|
|
|
/**
|
|
|
|
* Remove dumper update notifier object.
|
|
|
|
*/
|
|
|
|
void drop_dumper(dumper_base& n);
|
|
|
|
/**
|
|
|
|
* Get number of active dumpers.
|
|
|
|
*/
|
|
|
|
unsigned get_dumper_count() throw();
|
|
|
|
/**
|
|
|
|
* Call all notifiers (on_frame).
|
|
|
|
*/
|
|
|
|
void on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d);
|
|
|
|
/**
|
|
|
|
* Call all notifiers (on_sample).
|
|
|
|
*/
|
|
|
|
void on_sample(short l, short r);
|
|
|
|
/**
|
|
|
|
* Call all notifiers (on_rate_change)
|
|
|
|
*
|
|
|
|
* Also changes builtin rate variables.
|
|
|
|
*/
|
|
|
|
void on_rate_change(uint32_t n, uint32_t d);
|
|
|
|
/**
|
|
|
|
* Call all notifiers (on_gameinfo_change)
|
|
|
|
*
|
|
|
|
* Also changes builtin gameinfo structure.
|
|
|
|
*/
|
|
|
|
void on_gameinfo_change(const gameinfo& gi);
|
|
|
|
/**
|
|
|
|
* Get current sound rate in effect.
|
|
|
|
*/
|
|
|
|
std::pair<uint32_t, uint32_t> get_rate();
|
|
|
|
/**
|
|
|
|
* Get current gameinfo in effect.
|
|
|
|
*/
|
|
|
|
const gameinfo& get_gameinfo();
|
|
|
|
/**
|
|
|
|
* End all dumps.
|
|
|
|
*/
|
|
|
|
void end_dumps();
|
|
|
|
/**
|
|
|
|
* Set output stream.
|
|
|
|
*/
|
|
|
|
void set_output(std::ostream* _output);
|
2014-05-31 09:10:04 +03:00
|
|
|
/**
|
|
|
|
* Render Lua HUD on video.
|
|
|
|
*
|
|
|
|
* Parameter target: The target screen to render on.
|
|
|
|
* Parameter source: The source screen to read.
|
|
|
|
* Parameter hscl: The horizontal scale factor.
|
|
|
|
* Parameter vscl: The vertical scale factor.
|
|
|
|
* Parameter lgap: Left gap.
|
|
|
|
* Parameter tgap: Top gap.
|
|
|
|
* Parameter rgap: Right gap
|
|
|
|
* Parameter bgap: Bottom gap.
|
|
|
|
* Parameter fn: Function to call between running lua hooks and actually rendering.
|
|
|
|
* Returns: True if frame should be dumped, false if not.
|
|
|
|
*/
|
|
|
|
template<bool X> bool render_video_hud(struct framebuffer::fb<X>& target, struct framebuffer::raw& source,
|
|
|
|
uint32_t hscl, uint32_t vscl, uint32_t lgap, uint32_t tgap, uint32_t rgap, uint32_t bgap,
|
|
|
|
std::function<void()> fn);
|
|
|
|
/**
|
|
|
|
* Calculate number of sound samples to drop due to dropped frame.
|
|
|
|
*/
|
|
|
|
uint64_t killed_audio_length(uint32_t fps_n, uint32_t fps_d, double& fraction);
|
2014-05-28 13:51:24 +03:00
|
|
|
private:
|
|
|
|
void statuschange();
|
|
|
|
friend class dumper_base;
|
|
|
|
std::map<dumper_factory_base*, dumper_base*> dumpers;
|
|
|
|
std::set<notifier*> notifications;
|
|
|
|
std::set<dumper_base*> sdumpers;
|
|
|
|
uint32_t current_rate_n;
|
|
|
|
uint32_t current_rate_d;
|
|
|
|
gameinfo current_gi;
|
|
|
|
std::ostream* output;
|
|
|
|
threads::rlock lock;
|
2014-06-06 15:03:16 +03:00
|
|
|
lua_state& lua2;
|
2014-05-28 13:51:24 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
class dumper_base
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
dumper_base();
|
|
|
|
dumper_base(master_dumper& _mdumper, dumper_factory_base& _fbase);
|
|
|
|
virtual ~dumper_base() throw();
|
|
|
|
/**
|
|
|
|
* New frame available.
|
|
|
|
*/
|
|
|
|
virtual void on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d) = 0;
|
|
|
|
/**
|
|
|
|
* New sample available.
|
|
|
|
*/
|
|
|
|
virtual void on_sample(short l, short r) = 0;
|
|
|
|
/**
|
|
|
|
* Sample rate is changing.
|
|
|
|
*/
|
|
|
|
virtual void on_rate_change(uint32_t n, uint32_t d) = 0;
|
|
|
|
/**
|
|
|
|
* Gameinfo is changing.
|
|
|
|
*/
|
|
|
|
virtual void on_gameinfo_change(const master_dumper::gameinfo& gi) = 0;
|
|
|
|
/**
|
|
|
|
* Dump is being forcibly ended.
|
|
|
|
*/
|
|
|
|
virtual void on_end() = 0;
|
2014-05-31 09:23:47 +03:00
|
|
|
/**
|
|
|
|
* Render Lua HUD on video. samples_killed is incremented if needed.
|
|
|
|
*
|
|
|
|
* Parameter target: The target screen to render on.
|
|
|
|
* Parameter source: The source screen to read.
|
|
|
|
* Parameter fps_n: Fps numerator.
|
|
|
|
* Parameter fps_d: Fps denominator.
|
|
|
|
* Parameter hscl: The horizontal scale factor.
|
|
|
|
* Parameter vscl: The vertical scale factor.
|
|
|
|
* Parameter lgap: Left gap.
|
|
|
|
* Parameter tgap: Top gap.
|
|
|
|
* Parameter rgap: Right gap
|
|
|
|
* Parameter bgap: Bottom gap.
|
|
|
|
* Parameter fn: Function to call between running lua hooks and actually rendering.
|
|
|
|
* Returns: True if frame should be dumped, false if not.
|
|
|
|
*/
|
|
|
|
template<bool X> bool render_video_hud(struct framebuffer::fb<X>& target, struct framebuffer::raw& source,
|
|
|
|
uint32_t fps_n, uint32_t fps_d, uint32_t hscl, uint32_t vscl, uint32_t lgap, uint32_t tgap,
|
|
|
|
uint32_t rgap, uint32_t bgap, std::function<void()> fn)
|
|
|
|
{
|
|
|
|
bool r = mdumper->render_video_hud(target, source, hscl, vscl, lgap, tgap, rgap, bgap, fn);
|
|
|
|
if(!r)
|
|
|
|
samples_killed += mdumper->killed_audio_length(fps_n, fps_d, akillfrac);
|
|
|
|
return r;
|
|
|
|
}
|
2014-05-28 13:51:24 +03:00
|
|
|
private:
|
2014-05-31 09:23:47 +03:00
|
|
|
friend class master_dumper;
|
|
|
|
uint64_t samples_killed;
|
2014-05-28 13:51:24 +03:00
|
|
|
master_dumper* mdumper;
|
|
|
|
dumper_factory_base* fbase;
|
2014-05-31 09:23:47 +03:00
|
|
|
double akillfrac;
|
2014-05-28 13:51:24 +03:00
|
|
|
};
|
|
|
|
|
2012-01-11 01:21:13 +02:00
|
|
|
#endif
|