Raw dumping support
[lsnes.git] / src / core / raw-control.cpp
blob75cba8820ba03ac14e3b6c459c07935c343af82b
1 #include "core/advdumper.hpp"
2 #include "core/command.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/lua.hpp"
5 #include "core/misc.hpp"
6 #include "core/settings.hpp"
8 #include <iomanip>
9 #include <cassert>
10 #include <cstring>
11 #include <sstream>
12 #include <fstream>
13 #include <zlib.h>
15 namespace
17 class raw_avsnoop : public information_dispatch
19 public:
20 raw_avsnoop(const std::string& prefix) throw(std::bad_alloc)
21 : information_dispatch("dump-raw")
23 enable_send_sound();
24 video = new std::ofstream(prefix + ".video", std::ios::out | std::ios::binary);
25 audio = new std::ofstream(prefix + ".audio", std::ios::out | std::ios::binary);
26 if(!*video || !*audio)
27 throw std::runtime_error("Can't open output files");
28 have_dumped_frame = false;
31 ~raw_avsnoop() throw()
33 delete video;
34 delete audio;
37 void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d)
39 if(!video)
40 return;
41 struct lua_render_context lrc;
42 render_queue rq;
43 lrc.left_gap = 0;
44 lrc.right_gap = 0;
45 lrc.bottom_gap = 0;
46 lrc.top_gap = 0;
47 lrc.queue = &rq;
48 lrc.width = _frame.width;
49 lrc.height = _frame.height;
50 lua_callback_do_video(&lrc);
51 dscr.set_palette(16, 8, 0);
52 uint32_t hscl = (_frame.width < 400) ? 2 : 1;
53 uint32_t vscl = (_frame.height < 400) ? 2 : 1;
54 dscr.reallocate(lrc.left_gap + _frame.width * hscl + lrc.right_gap, lrc.top_gap +
55 _frame.height * vscl + lrc.bottom_gap, false);
56 dscr.set_origin(lrc.left_gap, lrc.top_gap);
57 dscr.copy_from(_frame, hscl, vscl);
58 rq.run(dscr);
59 for(size_t i = 0; i < dscr.height; i++)
60 video->write(reinterpret_cast<char*>(dscr.rowptr(i)), 4 * dscr.width);
61 have_dumped_frame = true;
64 void on_sample(short l, short r)
66 if(have_dumped_frame && audio) {
67 char buffer[4];
68 buffer[0] = static_cast<unsigned short>(l);
69 buffer[1] = static_cast<unsigned short>(l) >> 8;
70 buffer[2] = static_cast<unsigned short>(r);
71 buffer[3] = static_cast<unsigned short>(r) >> 8;
72 audio->write(buffer, 4);
76 void on_dump_end()
78 delete video;
79 delete audio;
80 video = NULL;
81 audio = NULL;
84 bool get_dumper_flag() throw()
86 return true;
88 private:
89 std::ofstream* audio;
90 std::ofstream* video;
91 bool have_dumped_frame;
92 struct screen dscr;
95 raw_avsnoop* vid_dumper;
97 void startdump(std::string prefix)
99 if(prefix == "")
100 throw std::runtime_error("Expected prefix");
101 if(vid_dumper)
102 throw std::runtime_error("RAW dumping already in progress");
103 try {
104 vid_dumper = new raw_avsnoop(prefix);
105 } catch(std::bad_alloc& e) {
106 throw;
107 } catch(std::exception& e) {
108 std::ostringstream x;
109 x << "Error starting RAW dump: " << e.what();
110 throw std::runtime_error(x.str());
112 messages << "Dumping to " << prefix << std::endl;
113 information_dispatch::do_dumper_update();
116 void enddump()
118 if(!vid_dumper)
119 throw std::runtime_error("No RAW video dump in progress");
120 try {
121 vid_dumper->on_dump_end();
122 messages << "RAW Dump finished" << std::endl;
123 } catch(std::bad_alloc& e) {
124 throw;
125 } catch(std::exception& e) {
126 messages << "Error ending RAW dump: " << e.what() << std::endl;
128 delete vid_dumper;
129 vid_dumper = NULL;
130 information_dispatch::do_dumper_update();
133 function_ptr_command<const std::string&> raw_dump("dump-raw", "Start RAW capture",
134 "Syntax: dump-raw <prefix>\nStart RAW capture to <prefix>.video and <prefix>.audio.\n",
135 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
136 tokensplitter t(args);
137 std::string prefix = t.tail();
138 startdump(prefix);
141 function_ptr_command<> end_raw("end-raw", "End RAW capture",
142 "Syntax: end-raw\nEnd a RAW capture.\n",
143 []() throw(std::bad_alloc, std::runtime_error) {
144 enddump();
147 class adv_raw_dumper : public adv_dumper
149 public:
150 adv_raw_dumper() : adv_dumper("INTERNAL-RAW") {information_dispatch::do_dumper_update(); }
151 ~adv_raw_dumper() throw();
152 std::set<std::string> list_submodes() throw(std::bad_alloc)
154 std::set<std::string> x;
155 return x;
158 bool wants_prefix(const std::string& mode) throw()
160 return true;
163 std::string name() throw(std::bad_alloc)
165 return "RAW";
168 std::string modename(const std::string& mode) throw(std::bad_alloc)
170 return "";
173 bool busy()
175 return (vid_dumper != NULL);
178 void start(const std::string& mode, const std::string& targetname) throw(std::bad_alloc,
179 std::runtime_error)
181 startdump(targetname);
184 void end() throw()
186 enddump();
188 } adv;
190 adv_raw_dumper::~adv_raw_dumper() throw()