1 #include "core/advdumper.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/instance.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/moviefile.hpp"
6 #include "core/messages.hpp"
7 #include "core/rom.hpp"
8 #include "video/tcp.hpp"
9 #include "library/serialization.hpp"
10 #include "library/minmax.hpp"
21 #define IS_RGB(m) (((m) + ((m) >> 3)) & 2)
22 #define IS_64(m) (m % 5 < 2)
23 #define IS_TCP(m) (((m % 5) * (m % 5)) % 5 == 1)
27 unsigned strhash(const std::string
& str
)
30 for(size_t i
= 0; i
< str
.length(); i
++)
31 h
= (2 * h
+ static_cast<unsigned char>(str
[i
])) % 11;
35 void deleter_fn(void* f
)
37 delete reinterpret_cast<std::ofstream
*>(f
);
40 class raw_dump_obj
: public dumper_base
43 raw_dump_obj(master_dumper
& _mdumper
, dumper_factory_base
& _fbase
, const std::string
& mode
,
44 const std::string
& prefix
)
45 : dumper_base(_mdumper
, _fbase
), mdumper(_mdumper
)
47 unsigned _mode
= strhash(mode
);
48 bool _bits64
= IS_64(_mode
);
49 bool _swap
= !IS_RGB(_mode
);
50 bool socket_mode
= IS_TCP(_mode
);
53 throw std::runtime_error("Expected prefix");
56 socket_address videoaddr
= socket_address(prefix
);
57 socket_address audioaddr
= videoaddr
.next();
58 deleter
= socket_address::deleter();
61 video
= &videoaddr
.connect();
62 audio
= &audioaddr
.connect();
69 video
= new std::ofstream(prefix
+ ".video", std::ios::out
|
71 audio
= new std::ofstream(prefix
+ ".audio", std::ios::out
|
75 if(!*video
|| !*audio
)
76 throw std::runtime_error("Can't open output files");
77 have_dumped_frame
= false;
80 mdumper
.add_dumper(*this);
81 } catch(std::bad_alloc
& e
) {
83 } catch(std::exception
& e
) {
85 x
<< "Error starting RAW dump: " << e
.what();
86 throw std::runtime_error(x
.str());
88 messages
<< "Dumping to " << prefix
<< std::endl
;
90 ~raw_dump_obj() throw()
92 mdumper
.drop_dumper(*this);
97 messages
<< "RAW Dump finished" << std::endl
;
99 void on_frame(struct framebuffer::raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
105 rpair(hscl
, vscl
) = core
.rom
->get_scale_factors(_frame
.get_width(),
106 _frame
.get_height());
108 size_t w
= dscr2
.get_width();
109 size_t h
= dscr2
.get_height();
110 size_t s
= dscr2
.get_stride();
111 std::vector
<uint16_t> tmp
;
112 tmp
.resize(8 * s
+ 8);
113 uint32_t alignment
= (16 - reinterpret_cast<size_t>(&tmp
[0])) % 16 / 2;
114 if(!render_video_hud(dscr2
, _frame
, fps_n
, fps_d
, hscl
, vscl
, 0, 0, 0, 0, NULL
))
116 for(size_t i
= 0; i
< h
; i
++) {
118 framebuffer::copy_swap4(&tmp
[alignment
], dscr2
.rowptr(i
), s
);
120 memcpy(&tmp
[alignment
], dscr2
.rowptr(i
), 8 * w
);
121 video
->write(reinterpret_cast<char*>(&tmp
[alignment
]), 8 * w
);
124 size_t w
= dscr
.get_width();
125 size_t h
= dscr
.get_height();
126 size_t s
= dscr2
.get_stride();
127 std::vector
<uint8_t> tmp
;
128 tmp
.resize(4 * s
+ 16);
129 uint32_t alignment
= (16 - reinterpret_cast<size_t>(&tmp
[0])) % 16;
130 if(!render_video_hud(dscr
, _frame
, fps_n
, fps_d
, hscl
, vscl
, 0, 0, 0, 0, NULL
))
132 for(size_t i
= 0; i
< h
; i
++) {
134 framebuffer::copy_swap4(&tmp
[alignment
], dscr
.rowptr(i
), s
);
136 memcpy(&tmp
[alignment
], dscr
.rowptr(i
), 4 * w
);
137 video
->write(reinterpret_cast<char*>(&tmp
[alignment
]), 4 * w
);
141 messages
<< "Video write error" << std::endl
;
142 have_dumped_frame
= true;
145 void on_sample(short l
, short r
)
147 if(have_dumped_frame
&& audio
) {
149 serialization::s16b(buffer
+ 0, l
);
150 serialization::s16b(buffer
+ 2, r
);
151 audio
->write(buffer
, 4);
154 void on_rate_change(uint32_t n
, uint32_t d
)
158 void on_gameinfo_change(const master_dumper::gameinfo
& gi
)
169 void (*deleter
)(void* f
);
170 bool have_dumped_frame
;
171 struct framebuffer::fb
<false> dscr
;
172 struct framebuffer::fb
<true> dscr2
;
175 master_dumper
& mdumper
;
178 class adv_raw_dumper
: public dumper_factory_base
181 adv_raw_dumper() : dumper_factory_base("INTERNAL-RAW")
185 ~adv_raw_dumper() throw();
186 std::set
<std::string
> list_submodes() throw(std::bad_alloc
)
188 std::set
<std::string
> x
;
189 for(size_t i
= 0; i
< (socket_address::supported() ? 2 : 1); i
++)
190 for(size_t j
= 0; j
< 2; j
++)
191 for(size_t k
= 0; k
< 2; k
++)
192 x
.insert(std::string("") + (i
? "tcp" : "") + (j
? "bgr" : "rgb")
193 + (k
? "64" : "32"));
196 unsigned mode_details(const std::string
& mode
) throw()
198 return IS_TCP(strhash(mode
)) ? target_type_special
: target_type_prefix
;
200 std::string
mode_extension(const std::string
& mode
) throw()
202 return ""; //Nothing interesting.
204 std::string
name() throw(std::bad_alloc
)
208 std::string
modename(const std::string
& mode
) throw(std::bad_alloc
)
210 unsigned _mode
= strhash(mode
);
211 std::string x
= std::string((IS_RGB(_mode
) ? "RGB" : "BGR")) +
212 (IS_64(_mode
) ? " 64-bit" : " 32-bit") + (IS_TCP(_mode
) ? " over TCP/IP" : "");
215 raw_dump_obj
* start(master_dumper
& _mdumper
, const std::string
& mode
, const std::string
& prefix
)
216 throw(std::bad_alloc
, std::runtime_error
)
218 return new raw_dump_obj(_mdumper
, *this, mode
, prefix
);
222 adv_raw_dumper::~adv_raw_dumper() throw()