2 #include <snes/snes.hpp>
3 #include "core/advdumper.hpp"
4 #include "core/dispatch.hpp"
5 #include "library/serialization.hpp"
6 #include "video/tcp.hpp"
17 #define CUTOFF 2100000000
18 #define SDUMP_FLAG_HIRES 1
19 #define SDUMP_FLAG_INTERLACED 2
20 #define SDUMP_FLAG_OVERSCAN 4
21 #define SDUMP_FLAG_PAL 8
25 void deleter_fn(void* f
)
27 delete reinterpret_cast<std::ofstream
*>(f
);
30 class sdmp_avsnoop
: public information_dispatch
33 sdmp_avsnoop(const std::string
& prefix
, const std::string
& mode
) throw(std::bad_alloc
,
35 : information_dispatch("dump-sdmp")
39 sdump_ss
= (mode
!= "ms");
44 out
= &(socket_address(prefix
).connect());
45 deleter
= socket_address::deleter();
52 ~sdmp_avsnoop() throw()
61 void on_raw_frame(const uint32_t* raw
, bool hires
, bool interlaced
, bool overscan
, unsigned region
)
64 flags
|= (hires
? SDUMP_FLAG_HIRES
: 0);
65 flags
|= (interlaced
? SDUMP_FLAG_INTERLACED
: 0);
66 flags
|= (overscan
? SDUMP_FLAG_OVERSCAN
: 0);
67 flags
|= (region
== VIDEO_REGION_PAL
? SDUMP_FLAG_PAL
: 0);
68 unsigned char tbuffer
[2049];
69 if(!out
|| (ssize
> CUTOFF
&& !sdump_ss
)) {
70 std::cerr
<< "Starting new segment" << std::endl
;
73 std::ostringstream str
;
77 str
<< oprefix
<< "_" << std::setw(4) << std::setfill('0') << (next_seq
++)
79 std::string str2
= str
.str();
80 out
= new std::ofstream(str2
.c_str(), std::ios::out
| std::ios::binary
);
82 throw std::runtime_error("Failed to open '" + str2
+ "'");
83 write32ube(tbuffer
, 0x53444D50U
);
84 write32ube(tbuffer
+ 4, SNES::system
.cpu_frequency());
85 write32ube(tbuffer
+ 8, SNES::system
.apu_frequency());
86 out
->write(reinterpret_cast<char*>(tbuffer
), 12);
88 throw std::runtime_error("Failed to write header to '" + str2
+ "'");
93 for(unsigned i
= 0; i
< 512; i
++) {
94 for(unsigned j
= 0; j
< 512; j
++)
95 write32ube(tbuffer
+ (4 * j
+ 1), raw
[512 * i
+ j
]);
96 out
->write(reinterpret_cast<char*>(tbuffer
+ (i
? 1 : 0)), i
? 2048 : 2049);
99 throw std::runtime_error("Failed to write frame");
103 void on_sample(short l
, short r
)
105 if(!out
|| !dumped_pic
)
107 unsigned char pkt
[5];
109 write16sbe(pkt
+ 1, l
);
110 write16sbe(pkt
+ 3, r
);
111 out
->write(reinterpret_cast<char*>(pkt
), 5);
113 throw std::runtime_error("Failed to write sample");
123 bool get_dumper_flag() throw()
133 void (*deleter
)(void* f
);
137 sdmp_avsnoop
* vid_dumper
;
139 class adv_sdmp_dumper
: public adv_dumper
142 adv_sdmp_dumper() : adv_dumper("INTERNAL-SDMP") { information_dispatch::do_dumper_update(); }
143 ~adv_sdmp_dumper() throw();
144 std::set
<std::string
> list_submodes() throw(std::bad_alloc
)
146 std::set
<std::string
> x
;
153 unsigned mode_details(const std::string
& mode
) throw()
156 return target_type_file
;
158 return target_type_prefix
;
160 return target_type_special
;
161 return target_type_mask
;
164 std::string
name() throw(std::bad_alloc
)
169 std::string
modename(const std::string
& mode
) throw(std::bad_alloc
)
172 return "Single-Segment";
174 return "Multi-Segment";
176 return "over TCP/IP";
182 return (vid_dumper
!= NULL
);
185 void start(const std::string
& mode
, const std::string
& prefix
) throw(std::bad_alloc
,
189 throw std::runtime_error("Expected target");
191 throw std::runtime_error("SDMP Dump already in progress");
193 vid_dumper
= new sdmp_avsnoop(prefix
, mode
);
194 } catch(std::bad_alloc
& e
) {
196 } catch(std::exception
& e
) {
197 std::ostringstream x
;
198 x
<< "Error starting SDMP dump: " << e
.what();
199 throw std::runtime_error(x
.str());
201 messages
<< "Dumping SDMP (" << mode
<< ") to " << prefix
<< std::endl
;
202 information_dispatch::do_dumper_update();
208 throw std::runtime_error("No SDMP video dump in progress");
210 vid_dumper
->on_dump_end();
211 messages
<< "SDMP Dump finished" << std::endl
;
212 } catch(std::bad_alloc
& e
) {
214 } catch(std::exception
& e
) {
215 messages
<< "Error ending SDMP dump: " << e
.what() << std::endl
;
219 information_dispatch::do_dumper_update();
223 adv_sdmp_dumper::~adv_sdmp_dumper() throw()