#include "videodumper.hpp" #include "settings.hpp" #include "videodumper2.hpp" #include #include #include #include #include #include "misc.hpp" #include "fieldsplit.hpp" #include "command.hpp" avidumper* vid_dumper = NULL; void update_movie_state(); namespace { screen dscr; boolean_setting dump_large("large-video", false); class dump_video_command : public command { public: dump_video_command() throw(std::bad_alloc) : command("dump-video") {} void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error) { tokensplitter t(args); std::string level = t; std::string prefix = t.tail(); if(prefix == "") throw std::runtime_error("Expected prefix"); if(vid_dumper) throw std::runtime_error("Video dumping already in progress"); unsigned long level2; try { level2 = parse_value(level); if(level2 > 18) throw std::runtime_error("Level must be 0-18"); } catch(std::bad_alloc& e) { OOM_panic(win); } catch(std::runtime_error& e) { throw std::runtime_error("Bad video compression level '" + level + "': " + e.what()); } struct avi_info parameters; parameters.compression_level = (level2 > 9) ? (level2 - 9) : level2; parameters.audio_drop_counter_inc = 81; parameters.audio_drop_counter_max = 64081; parameters.audio_sampling_rate = 32000; parameters.audio_native_sampling_rate = 32040.5; parameters.keyframe_interval = (level2 > 9) ? 300 : 1; try { vid_dumper = new avidumper(prefix, parameters); } catch(std::bad_alloc& e) { OOM_panic(win); } catch(std::exception& e) { std::ostringstream x; x << "Error starting dump: " << e.what(); throw std::runtime_error(x.str()); } out(win) << "Dumping to " << prefix << " at level " << level2 << std::endl; update_movie_state(); } std::string get_short_help() throw(std::bad_alloc) { return "Start video capture"; } std::string get_long_help() throw(std::bad_alloc) { return "Syntax: dump-video \n" "Start video capture to using compression\n" "level (0-18).\n"; } } dump_video; class end_video_command : public command { public: end_video_command() throw(std::bad_alloc) : command("end-video") {} void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error) { if(args != "") throw std::runtime_error("This command does not take parameters"); if(!vid_dumper) throw std::runtime_error("No video dump in progress"); try { vid_dumper->on_end(); out(win) << "Dump finished" << std::endl; } catch(std::bad_alloc& e) { OOM_panic(win); } catch(std::exception& e) { out(win) << "Error ending dump: " << e.what() << std::endl; } delete vid_dumper; vid_dumper = NULL; update_movie_state(); } std::string get_short_help() throw(std::bad_alloc) { return "End video capture"; } std::string get_long_help() throw(std::bad_alloc) { return "Syntax: end-video\n" "End a video capture.\n"; } } end_vieo; } void end_vid_dump() throw(std::bad_alloc, std::runtime_error) { if(vid_dumper) try { vid_dumper->on_end(); } catch(std::bad_alloc& e) { throw; } catch(std::exception& e) { std::cerr << "Error ending dump: " << e.what() << std::endl; } } void dump_frame(lcscreen& ls, render_queue* rq, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom, bool region, window* win) throw(std::bad_alloc, std::runtime_error) { if(vid_dumper) try { vid_dumper->wait_idle(); uint32_t hscl = 1; uint32_t vscl = 1; if(dump_large && ls.width < 400) hscl = 2; if(dump_large && ls.height < 400) vscl = 2; uint32_t _magic = 403703808; uint8_t* magic = reinterpret_cast(&_magic); dscr.reallocate(left + hscl * ls.width + right, top + vscl * ls.height + bottom, left, top, true); dscr.set_palette(magic[2], magic[1], magic[0]); dscr.copy_from(ls, hscl, vscl); if(rq) rq->run(dscr); assert(dscr.memory); assert(dscr.width); assert(dscr.height); uint32_t fps_n = 10738636; uint32_t fps_d = 178683; if(region) { fps_n = 322445; fps_d = 6448; } vid_dumper->on_frame(dscr.memory, dscr.width, dscr.height, fps_n, fps_d); } catch(std::bad_alloc& e) { OOM_panic(win); } catch(std::exception& e) { out(win) << "Error sending video frame: " << e.what() << std::endl; } if(rq) rq->clear(); } void dump_audio_sample(int16_t l_sample, int16_t r_sample, window* win) throw(std::bad_alloc, std::runtime_error) { if(vid_dumper) try { vid_dumper->on_sample(l_sample, r_sample); } catch(std::bad_alloc& e) { OOM_panic(win); } catch(std::exception& e) { out(win) << "Error sending audio sample: " << e.what() << std::endl; } } bool dump_in_progress() throw() { return (vid_dumper != NULL); } void video_fill_shifts(uint32_t& r, uint32_t& g, uint32_t& b) { r = dscr.active_rshift; g = dscr.active_gshift; b = dscr.active_bshift; }