Since window is singleton anyway, get rid of window* parameters
[lsnes.git] / avidump / avidump-control.cpp
blob25c2d613fd001ba263e02f913aada499a683e3e6
1 #include "lua.hpp"
2 #include "avidump.hpp"
3 #include "sox.hpp"
4 #include "settings.hpp"
5 #include "window.hpp"
6 #include <iomanip>
7 #include <cassert>
8 #include <cstring>
9 #include <sstream>
10 #include <zlib.h>
11 #include "misc.hpp"
12 #include "avsnoop.hpp"
13 #include "command.hpp"
15 namespace
17 boolean_setting dump_large("large-video", false);
18 numeric_setting dtb("default-top-border", 0, 8191, 0);
19 numeric_setting dbb("default-bottom-border", 0, 8191, 0);
20 numeric_setting dlb("default-left-border", 0, 8191, 0);
21 numeric_setting drb("default-right-border", 0, 8191, 0);
22 numeric_setting max_frames_per_segment("max-frames-per-segment", 0, 999999999, 0);
24 class avi_avsnoop : public av_snooper
26 public:
27 avi_avsnoop(const std::string& prefix, struct avi_info parameters) throw(std::bad_alloc)
29 vid_dumper = new avidumper(prefix, parameters);
30 soxdumper = new sox_dumper(prefix + ".sox", 32040.5, 2);
31 dcounter = 0;
34 ~avi_avsnoop() throw()
36 delete vid_dumper;
37 delete soxdumper;
40 void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d)
41 throw(std::bad_alloc, std::runtime_error)
43 vid_dumper->wait_idle();
44 uint32_t hscl = 1;
45 uint32_t vscl = 1;
46 if(dump_large && _frame.width < 400)
47 hscl = 2;
48 if(dump_large && _frame.height < 400)
49 vscl = 2;
50 uint32_t _magic = 403703808;
51 uint8_t* magic = reinterpret_cast<uint8_t*>(&_magic);
52 dscr.set_palette(magic[2], magic[1], magic[0]);
54 struct lua_render_context lrc;
55 render_queue rq;
56 lrc.left_gap = dlb;
57 lrc.right_gap = drb;
58 lrc.bottom_gap = dbb;
59 lrc.top_gap = dtb;
60 lrc.queue = &rq;
61 lrc.width = _frame.width * hscl;
62 lrc.height = _frame.height * vscl;
63 lrc.rshift = magic[2];
64 lrc.gshift = magic[1];
65 lrc.bshift = magic[0];
66 lua_callback_do_video(&lrc);
68 dscr.reallocate(lrc.left_gap + hscl * _frame.width + lrc.right_gap, lrc.top_gap + vscl *
69 _frame.height + lrc.bottom_gap, lrc.left_gap, lrc.top_gap, true);
70 dscr.copy_from(_frame, hscl, vscl);
71 rq.run(dscr);
72 vid_dumper->on_frame(dscr.memory, dscr.width, dscr.height, fps_n, fps_d);
75 void sample(short l, short r) throw(std::bad_alloc, std::runtime_error)
77 dcounter += 81;
78 if(dcounter < 64081)
79 vid_dumper->on_sample(l, r);
80 else
81 dcounter -= 64081;
82 soxdumper->sample(l, r);
85 void end() throw(std::bad_alloc, std::runtime_error)
87 vid_dumper->on_end();
88 soxdumper->close();
91 void gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
92 authors, double gametime, const std::string& rerecords) throw(std::bad_alloc,
93 std::runtime_error)
95 //We don't have place for this info and thus ignore it.
97 private:
98 avidumper* vid_dumper;
99 sox_dumper* soxdumper;
100 screen dscr;
101 unsigned dcounter;
104 avi_avsnoop* vid_dumper;
106 class dump_video_command : public command
108 public:
109 dump_video_command() throw(std::bad_alloc) : command("dump-avi") {}
110 void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
112 tokensplitter t(args);
113 std::string level = t;
114 std::string prefix = t.tail();
115 if(prefix == "")
116 throw std::runtime_error("Expected prefix");
117 if(vid_dumper)
118 throw std::runtime_error("AVI dumping already in progress");
119 unsigned long level2;
120 try {
121 level2 = parse_value<unsigned long>(level);
122 if(level2 > 18)
123 throw std::runtime_error("Level must be 0-18");
124 } catch(std::bad_alloc& e) {
125 throw;
126 } catch(std::runtime_error& e) {
127 throw std::runtime_error("Bad AVI compression level '" + level + "': " + e.what());
129 struct avi_info parameters;
130 parameters.compression_level = (level2 > 9) ? (level2 - 9) : level2;
131 parameters.audio_sampling_rate = 32000;
132 parameters.keyframe_interval = (level2 > 9) ? 300 : 1;
133 parameters.max_frames_per_segment = max_frames_per_segment;
134 try {
135 vid_dumper = new avi_avsnoop(prefix, parameters);
136 } catch(std::bad_alloc& e) {
137 throw;
138 } catch(std::exception& e) {
139 std::ostringstream x;
140 x << "Error starting dump: " << e.what();
141 throw std::runtime_error(x.str());
143 window::out() << "Dumping to " << prefix << " at level " << level2 << std::endl;
145 std::string get_short_help() throw(std::bad_alloc) { return "Start AVI capture"; }
146 std::string get_long_help() throw(std::bad_alloc)
148 return "Syntax: dump-avi <level> <prefix>\n"
149 "Start AVI capture to <prefix> using compression\n"
150 "level <level> (0-18).\n";
152 } dump_video;
154 class end_video_command : public command
156 public:
157 end_video_command() throw(std::bad_alloc) : command("end-avi") {}
158 void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
160 if(args != "")
161 throw std::runtime_error("This command does not take parameters");
162 if(!vid_dumper)
163 throw std::runtime_error("No video dump in progress");
164 try {
165 vid_dumper->end();
166 window::out() << "Dump finished" << std::endl;
167 } catch(std::bad_alloc& e) {
168 throw;
169 } catch(std::exception& e) {
170 window::out() << "Error ending dump: " << e.what() << std::endl;
172 delete vid_dumper;
173 vid_dumper = NULL;
175 std::string get_short_help() throw(std::bad_alloc) { return "End AVI capture"; }
176 std::string get_long_help() throw(std::bad_alloc)
178 return "Syntax: end-avi\n"
179 "End a AVI capture.\n";
181 } end_vieo;