1 #include "core/advdumper.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/moviefile.hpp"
5 #include "video/tcp.hpp"
6 #include "library/serialization.hpp"
17 #define IS_RGB(m) (((m) + ((m) >> 3)) & 2)
18 #define IS_64(m) (m % 5 < 2)
19 #define IS_TCP(m) (((m % 5) * (m % 5)) % 5 == 1)
26 unsigned strhash(const std::string
& str
)
29 for(size_t i
= 0; i
< str
.length(); i
++)
30 h
= (2 * h
+ static_cast<unsigned char>(str
[i
])) % 11;
34 void deleter_fn(void* f
)
36 delete reinterpret_cast<std::ofstream
*>(f
);
39 class raw_avsnoop
: public information_dispatch
42 raw_avsnoop(const std::string
& prefix
, bool _swap
, bool _bits64
, bool socket_mode
)
43 : information_dispatch("dump-raw")
47 socket_address videoaddr
= socket_address(prefix
);
48 socket_address audioaddr
= videoaddr
.next();
49 deleter
= socket_address::deleter();
52 video
= &videoaddr
.connect();
53 audio
= &audioaddr
.connect();
60 video
= new std::ofstream(prefix
+ ".video", std::ios::out
| std::ios::binary
);
61 audio
= new std::ofstream(prefix
+ ".audio", std::ios::out
| std::ios::binary
);
64 if(!*video
|| !*audio
)
65 throw std::runtime_error("Can't open output files");
66 have_dumped_frame
= false;
71 ~raw_avsnoop() throw()
79 void on_frame(struct framebuffer::raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
88 unsigned r
= (reinterpret_cast<unsigned char*>(&magic
))[swap
? 2 : 0];
89 unsigned g
= (reinterpret_cast<unsigned char*>(&magic
))[1];
90 unsigned b
= (reinterpret_cast<unsigned char*>(&magic
))[swap
? 0 : 2];
91 auto scl
= our_rom
.rtype
->get_scale_factors(_frame
.get_width(), _frame
.get_height());
92 uint32_t hscl
= scl
.first
;
93 uint32_t vscl
= scl
.second
;
95 size_t w
= dscr2
.get_width();
96 size_t h
= dscr2
.get_height();
97 if(!render_video_hud(dscr2
, _frame
, hscl
, vscl
, r
, g
, b
, 0, 0, 0, 0, NULL
)) {
98 akill
+= killed_audio_length(fps_n
, fps_d
, akillfrac
);
101 for(size_t i
= 0; i
< h
; i
++)
102 video
->write(reinterpret_cast<char*>(dscr2
.rowptr(i
)), 8 * w
);
104 size_t w
= dscr
.get_width();
105 size_t h
= dscr
.get_height();
106 if(!render_video_hud(dscr
, _frame
, hscl
, vscl
, r
, g
, b
, 0, 0, 0, 0, NULL
)) {
107 akill
+= killed_audio_length(fps_n
, fps_d
, akillfrac
);
110 for(size_t i
= 0; i
< h
; i
++)
111 video
->write(reinterpret_cast<char*>(dscr
.rowptr(i
)), 4 * w
);
114 messages
<< "Video write error" << std::endl
;
115 have_dumped_frame
= true;
118 void on_sample(short l
, short r
)
124 if(have_dumped_frame
&& audio
) {
126 serialization::s16b(buffer
+ 0, l
);
127 serialization::s16b(buffer
+ 2, r
);
128 audio
->write(buffer
, 4);
140 bool get_dumper_flag() throw()
147 void (*deleter
)(void* f
);
148 bool have_dumped_frame
;
149 struct framebuffer::fb
<false> dscr
;
150 struct framebuffer::fb
<true> dscr2
;
155 raw_avsnoop
* vid_dumper
;
157 class adv_raw_dumper
: public adv_dumper
160 adv_raw_dumper() : adv_dumper("INTERNAL-RAW") {information_dispatch::do_dumper_update(); }
161 ~adv_raw_dumper() throw();
162 std::set
<std::string
> list_submodes() throw(std::bad_alloc
)
164 std::set
<std::string
> x
;
165 for(size_t i
= 0; i
< (socket_address::supported() ? 2 : 1); i
++)
166 for(size_t j
= 0; j
< 2; j
++)
167 for(size_t k
= 0; k
< 2; k
++)
168 x
.insert(std::string("") + (i
? "tcp" : "") + (j
? "bgr" : "rgb")
169 + (k
? "64" : "32"));
173 unsigned mode_details(const std::string
& mode
) throw()
175 return IS_TCP(strhash(mode
)) ? target_type_special
: target_type_prefix
;
178 std::string
mode_extension(const std::string
& mode
) throw()
180 return ""; //Nothing interesting.
183 std::string
name() throw(std::bad_alloc
)
188 std::string
modename(const std::string
& mode
) throw(std::bad_alloc
)
190 unsigned _mode
= strhash(mode
);
191 std::string x
= std::string((IS_RGB(_mode
) ? "RGB" : "BGR")) +
192 (IS_64(_mode
) ? " 64-bit" : " 32-bit") + (IS_TCP(_mode
) ? " over TCP/IP" : "");
198 return (vid_dumper
!= NULL
);
201 void start(const std::string
& mode
, const std::string
& prefix
) throw(std::bad_alloc
,
204 unsigned _mode
= strhash(mode
);
205 bool bits64
= IS_64(_mode
);
206 bool swap
= !IS_RGB(_mode
);
207 bool sock
= IS_TCP(_mode
);
210 throw std::runtime_error("Expected prefix");
212 throw std::runtime_error("RAW dumping already in progress");
214 vid_dumper
= new raw_avsnoop(prefix
, swap
, bits64
, sock
);
215 } catch(std::bad_alloc
& e
) {
217 } catch(std::exception
& e
) {
218 std::ostringstream x
;
219 x
<< "Error starting RAW dump: " << e
.what();
220 throw std::runtime_error(x
.str());
222 messages
<< "Dumping to " << prefix
<< std::endl
;
223 information_dispatch::do_dumper_update();
231 throw std::runtime_error("No RAW video dump in progress");
233 vid_dumper
->on_dump_end();
234 messages
<< "RAW Dump finished" << std::endl
;
235 } catch(std::bad_alloc
& e
) {
237 } catch(std::exception
& e
) {
238 messages
<< "Error ending RAW dump: " << e
.what() << std::endl
;
242 information_dispatch::do_dumper_update();
246 adv_raw_dumper::~adv_raw_dumper() throw()