#ifndef _advdumper__hpp__included__ #define _advdumper__hpp__included__ #include #include #include #include #include "library/framebuffer.hpp" #include "library/dispatch.hpp" #include "library/threads.hpp" class master_dumper; class dumper_factory_base; class dumper_base; class lua_state; class dumper_factory_base { public: /** * Notifier base. */ class notifier { public: virtual ~notifier() throw(); virtual void dumpers_updated() throw() = 0; }; /** * Detail flags. */ static const unsigned target_type_mask; static const unsigned target_type_file; static const unsigned target_type_prefix; static const unsigned target_type_special; /** * Register a dumper. * * Parameter id: The ID of dumper. * Throws std::bad_alloc: Not enough memory. */ dumper_factory_base(const std::string& id) throw(std::bad_alloc); /** * Unregister a dumper. */ ~dumper_factory_base(); /** * 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. */ static std::set get_dumper_set() throw(std::bad_alloc); /** * 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 list_submodes() throw(std::bad_alloc) = 0; /** * Get mode details * * parameter mode: The submode. * Returns: Mode details flags */ virtual unsigned mode_details(const std::string& mode) throw() = 0; /** * 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; /** * 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. * returns: The dumper object. * Throws std::bad_alloc: Not enough memory. * Throws std::runtime_error: Can't start dump. */ virtual dumper_base* start(master_dumper& _mdumper, const std::string& mode, const std::string& targetname) throw(std::bad_alloc, std::runtime_error) = 0; /** * Add dumper update notifier object. */ 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(); private: std::string d_id; }; 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> 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. */ master_dumper(lua_state& _lua2); /** * 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 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); /** * 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 render_video_hud(struct framebuffer::fb& 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 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); private: void statuschange(); friend class dumper_base; std::map dumpers; std::set notifications; std::set sdumpers; uint32_t current_rate_n; uint32_t current_rate_d; gameinfo current_gi; std::ostream* output; threads::rlock lock; lua_state& lua2; }; 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; /** * 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 render_video_hud(struct framebuffer::fb& 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 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; } private: friend class master_dumper; uint64_t samples_killed; master_dumper* mdumper; dumper_factory_base* fbase; double akillfrac; }; #endif