1 #include "core/advdumper.hpp"
2 #include "core/instance.hpp"
3 #include "core/misc.hpp"
4 #include "library/globalwrap.hpp"
5 #include "library/string.hpp"
14 globalwrap
<std::map
<std::string
, dumper_factory_base
*>> S_dumpers
;
15 globalwrap
<std::set
<dumper_factory_base::notifier
*>> S_notifiers
;
18 master_dumper::gameinfo::gameinfo() throw(std::bad_alloc
)
24 std::string
master_dumper::gameinfo::get_readable_time(unsigned digits
) const throw(std::bad_alloc
)
26 double bias
= 0.5 * pow(10, -static_cast<int>(digits
));
27 double len
= length
+ bias
;
28 std::ostringstream str
;
30 double hours
= floor(len
/ 3600);
34 double minutes
= floor(len
/ 60);
36 double seconds
= floor(len
);
38 str
<< std::setw(2) << std::setfill('0') << minutes
<< ":" << seconds
;
43 str
<< '0' + static_cast<int>(len
);
50 size_t master_dumper::gameinfo::get_author_count() const throw()
52 return authors
.size();
55 std::string
master_dumper::gameinfo::get_author_short(size_t idx
) const throw(std::bad_alloc
)
57 if(idx
>= authors
.size())
59 const std::pair
<std::string
, std::string
>& x
= authors
[idx
];
66 std::string
master_dumper::gameinfo::get_author_long(size_t idx
) const throw(std::bad_alloc
)
68 if(idx
>= authors
.size())
70 const std::pair
<std::string
, std::string
>& x
= authors
[idx
];
73 return x
.first
+ " (" + x
.second
+ ")";
78 return "(" + x
.second
+ ")";
84 uint64_t master_dumper::gameinfo::get_rerecords() const throw()
87 uint64_t max
= 0xFFFFFFFFFFFFFFFFULL
;
88 for(size_t i
= 0; i
< rerecords
.length(); i
++) {
90 //No risk of overflow.
91 v
= v
* 10 + static_cast<unsigned>(rerecords
[i
] - '0');
92 else if(v
== max
/ 10) {
95 if(v
+ static_cast<unsigned>(rerecords
[i
] - '0') < v
)
97 v
= v
+ static_cast<unsigned>(rerecords
[i
] - '0');
105 dumper_factory_base::notifier::~notifier() throw()
109 const std::string
& dumper_factory_base::id() throw()
114 dumper_factory_base::~dumper_factory_base()
116 S_dumpers().erase(d_id
);
120 std::set
<dumper_factory_base
*> dumper_factory_base::get_dumper_set() throw(std::bad_alloc
)
122 std::set
<dumper_factory_base
*> d
;
123 for(auto i
: S_dumpers())
128 dumper_factory_base::dumper_factory_base(const std::string
& id
) throw(std::bad_alloc
)
131 S_dumpers()[d_id
] = this;
134 void dumper_factory_base::ctor_notify()
139 void dumper_factory_base::add_notifier(dumper_factory_base::notifier
& n
)
141 S_notifiers().insert(&n
);
144 void dumper_factory_base::drop_notifier(dumper_factory_base::notifier
& n
)
146 S_notifiers().erase(&n
);
149 void dumper_factory_base::run_notify()
151 for(auto i
: S_notifiers())
152 i
->dumpers_updated();
155 const unsigned dumper_factory_base::target_type_mask
= 3;
156 const unsigned dumper_factory_base::target_type_file
= 0;
157 const unsigned dumper_factory_base::target_type_prefix
= 1;
158 const unsigned dumper_factory_base::target_type_special
= 2;
160 dumper_base::dumper_base()
167 dumper_base::dumper_base(master_dumper
& _mdumper
, dumper_factory_base
& _fbase
)
168 : mdumper(&_mdumper
), fbase(&_fbase
)
170 threads::arlock
h(mdumper
->lock
);
171 mdumper
->dumpers
[fbase
] = this;
174 dumper_base::~dumper_base() throw()
177 threads::arlock
h(mdumper
->lock
);
178 mdumper
->dumpers
.erase(fbase
);
179 mdumper
->statuschange();
182 master_dumper::notifier::~notifier() throw()
186 master_dumper::master_dumper(lua_state
& _lua2
)
189 current_rate_n
= 48000;
194 dumper_base
* master_dumper::get_instance(dumper_factory_base
* f
) throw()
196 threads::arlock
h(lock
);
197 return dumpers
.count(f
) ? dumpers
[f
] : NULL
;
200 dumper_base
* master_dumper::start(dumper_factory_base
& factory
, const std::string
& mode
,
201 const std::string
& targetname
) throw(std::bad_alloc
, std::runtime_error
)
203 threads::arlock
h(lock
);
204 auto f
= factory
.start(*this, mode
, targetname
);
209 void master_dumper::add_notifier(master_dumper::notifier
& n
)
211 threads::arlock
h(lock
);
212 notifications
.insert(&n
);
215 void master_dumper::drop_notifier(master_dumper::notifier
& n
)
217 threads::arlock
h(lock
);
218 notifications
.erase(&n
);
221 void master_dumper::add_dumper(dumper_base
& n
)
223 threads::arlock
h(lock
);
227 void master_dumper::drop_dumper(dumper_base
& n
)
229 threads::arlock
h(lock
);
233 void master_dumper::statuschange()
235 for(auto i
: notifications
)
236 i
->dump_status_change();
239 std::pair
<uint32_t, uint32_t> master_dumper::get_rate()
241 threads::arlock
h(lock
);
242 return std::make_pair(current_rate_n
, current_rate_d
);
245 const master_dumper::gameinfo
& master_dumper::get_gameinfo()
250 unsigned master_dumper::get_dumper_count() throw()
252 threads::arlock
h(lock
);
253 return sdumpers
.size();
256 void master_dumper::on_frame(struct framebuffer::raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
258 threads::arlock
h(lock
);
259 for(auto i
: sdumpers
)
261 i
->on_frame(_frame
, fps_n
, fps_d
);
262 } catch(std::exception
& e
) {
263 (*output
) << "Error in on_frame: " << e
.what() << std::endl
;
265 (*output
) << "Error in on_frame: <unknown error>" << std::endl
;
269 void master_dumper::on_sample(short l
, short r
)
271 threads::arlock
h(lock
);
272 for(auto i
: sdumpers
)
274 if(__builtin_expect(i
->samples_killed
, 0)) {
279 } catch(std::exception
& e
) {
280 (*output
) << "Error in on_sample: " << e
.what() << std::endl
;
282 (*output
) << "Error in on_sample: <unknown error>" << std::endl
;
286 void master_dumper::on_rate_change(uint32_t n
, uint32_t d
)
288 threads::arlock
h(lock
);
289 uint32_t ga
= gcd(n
, d
);
292 if(n
!= current_rate_n
|| d
!= current_rate_d
) {
298 for(auto i
: sdumpers
)
300 i
->on_rate_change(current_rate_n
, current_rate_d
);
301 } catch(std::exception
& e
) {
302 (*output
) << "Error in on_rate_change: " << e
.what() << std::endl
;
304 (*output
) << "Error in on_rate_change: <unknown error>" << std::endl
;
308 void master_dumper::on_gameinfo_change(const gameinfo
& gi
)
310 threads::arlock
h(lock
);
312 for(auto i
: sdumpers
)
314 i
->on_gameinfo_change(current_gi
);
315 } catch(std::exception
& e
) {
316 (*output
) << "Error in on_gameinfo_change: " << e
.what() << std::endl
;
318 (*output
) << "Error in on_gameinfo_change: <unknown error>" << std::endl
;
322 void master_dumper::end_dumps()
324 threads::arlock
h(lock
);
325 while(sdumpers
.size() > 0) {
326 auto d
= *sdumpers
.begin();
329 } catch(std::exception
& e
) {
330 (*output
) << "Error in on_end: " << e
.what() << std::endl
;
333 (*output
) << "Error in on_end: <unknown error>" << std::endl
;
339 void master_dumper::set_output(std::ostream
* _output
)
341 threads::arlock
h(lock
);
345 template<bool X
> bool master_dumper::render_video_hud(struct framebuffer::fb
<X
>& target
,
346 struct framebuffer::raw
& source
, uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
,
347 uint32_t bgap
, std::function
<void()> fn
)
349 bool lua_kill_video
= false;
350 struct lua::render_context lrc
;
351 framebuffer::queue rq
;
353 lrc
.right_gap
= rgap
;
354 lrc
.bottom_gap
= bgap
;
357 lrc
.width
= source
.get_width();
358 lrc
.height
= source
.get_height();
359 lua2
.callback_do_video(&lrc
, lua_kill_video
, hscl
, vscl
);
362 target
.reallocate(lrc
.left_gap
+ source
.get_width() * hscl
+ lrc
.right_gap
, lrc
.top_gap
+
363 source
.get_height() * vscl
+ lrc
.bottom_gap
, false);
364 target
.set_origin(lrc
.left_gap
, lrc
.top_gap
);
365 target
.copy_from(source
, hscl
, vscl
);
367 return !lua_kill_video
;
370 uint64_t master_dumper::killed_audio_length(uint32_t fps_n
, uint32_t fps_d
, double& fraction
)
373 double x
= 1.0 * fps_d
* r
.first
/ (fps_n
* r
.second
) + fraction
;
379 template bool master_dumper::render_video_hud(struct framebuffer::fb
<false>& target
, struct framebuffer::raw
& source
,
380 uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
, uint32_t bgap
,
381 std::function
<void()> fn
);
382 template bool master_dumper::render_video_hud(struct framebuffer::fb
<true>& target
, struct framebuffer::raw
& source
,
383 uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
, uint32_t bgap
,
384 std::function
<void()> fn
);