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;
175 dumper_base::~dumper_base() throw()
178 threads::arlock
h(mdumper
->lock
);
179 mdumper
->dumpers
.erase(fbase
);
180 mdumper
->statuschange();
183 master_dumper::notifier::~notifier() throw()
187 master_dumper::master_dumper(lua_state
& _lua2
)
190 current_rate_n
= 48000;
195 dumper_base
* master_dumper::get_instance(dumper_factory_base
* f
) throw()
197 threads::arlock
h(lock
);
198 return dumpers
.count(f
) ? dumpers
[f
] : NULL
;
201 dumper_base
* master_dumper::start(dumper_factory_base
& factory
, const std::string
& mode
,
202 const std::string
& targetname
) throw(std::bad_alloc
, std::runtime_error
)
204 threads::arlock
h(lock
);
205 auto f
= factory
.start(*this, mode
, targetname
);
210 void master_dumper::add_notifier(master_dumper::notifier
& n
)
212 threads::arlock
h(lock
);
213 notifications
.insert(&n
);
216 void master_dumper::drop_notifier(master_dumper::notifier
& n
)
218 threads::arlock
h(lock
);
219 notifications
.erase(&n
);
222 void master_dumper::add_dumper(dumper_base
& n
)
224 threads::arlock
h(lock
);
228 void master_dumper::drop_dumper(dumper_base
& n
)
230 threads::arlock
h(lock
);
234 void master_dumper::statuschange()
236 for(auto i
: notifications
)
237 i
->dump_status_change();
240 std::pair
<uint32_t, uint32_t> master_dumper::get_rate()
242 threads::arlock
h(lock
);
243 return std::make_pair(current_rate_n
, current_rate_d
);
246 const master_dumper::gameinfo
& master_dumper::get_gameinfo()
251 unsigned master_dumper::get_dumper_count() throw()
253 threads::arlock
h(lock
);
254 return sdumpers
.size();
257 void master_dumper::on_frame(struct framebuffer::raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
259 threads::arlock
h(lock
);
260 for(auto i
: sdumpers
)
262 i
->on_frame(_frame
, fps_n
, fps_d
);
263 } catch(std::exception
& e
) {
264 (*output
) << "Error in on_frame: " << e
.what() << std::endl
;
266 (*output
) << "Error in on_frame: <unknown error>" << std::endl
;
270 void master_dumper::on_sample(short l
, short r
)
272 threads::arlock
h(lock
);
273 for(auto i
: sdumpers
)
275 if(__builtin_expect(i
->samples_killed
, 0)) {
280 } catch(std::exception
& e
) {
281 (*output
) << "Error in on_sample: " << e
.what() << std::endl
;
283 (*output
) << "Error in on_sample: <unknown error>" << std::endl
;
287 void master_dumper::on_rate_change(uint32_t n
, uint32_t d
)
289 threads::arlock
h(lock
);
290 uint32_t ga
= gcd(n
, d
);
293 if(n
!= current_rate_n
|| d
!= current_rate_d
) {
299 for(auto i
: sdumpers
)
301 i
->on_rate_change(current_rate_n
, current_rate_d
);
302 } catch(std::exception
& e
) {
303 (*output
) << "Error in on_rate_change: " << e
.what() << std::endl
;
305 (*output
) << "Error in on_rate_change: <unknown error>" << std::endl
;
309 void master_dumper::on_gameinfo_change(const gameinfo
& gi
)
311 threads::arlock
h(lock
);
313 for(auto i
: sdumpers
)
315 i
->on_gameinfo_change(current_gi
);
316 } catch(std::exception
& e
) {
317 (*output
) << "Error in on_gameinfo_change: " << e
.what() << std::endl
;
319 (*output
) << "Error in on_gameinfo_change: <unknown error>" << std::endl
;
323 void master_dumper::end_dumps()
325 threads::arlock
h(lock
);
326 while(sdumpers
.size() > 0) {
327 auto d
= *sdumpers
.begin();
330 } catch(std::exception
& e
) {
331 (*output
) << "Error in on_end: " << e
.what() << std::endl
;
334 (*output
) << "Error in on_end: <unknown error>" << std::endl
;
340 void master_dumper::set_output(std::ostream
* _output
)
342 threads::arlock
h(lock
);
346 template<bool X
> bool master_dumper::render_video_hud(struct framebuffer::fb
<X
>& target
,
347 struct framebuffer::raw
& source
, uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
,
348 uint32_t bgap
, std::function
<void()> fn
)
350 bool lua_kill_video
= false;
351 struct lua::render_context lrc
;
352 framebuffer::queue rq
;
354 lrc
.right_gap
= rgap
;
355 lrc
.bottom_gap
= bgap
;
358 lrc
.width
= source
.get_width();
359 lrc
.height
= source
.get_height();
360 lua2
.callback_do_video(&lrc
, lua_kill_video
, hscl
, vscl
);
363 target
.reallocate(lrc
.left_gap
+ source
.get_width() * hscl
+ lrc
.right_gap
, lrc
.top_gap
+
364 source
.get_height() * vscl
+ lrc
.bottom_gap
, false);
365 target
.set_origin(lrc
.left_gap
, lrc
.top_gap
);
366 target
.copy_from(source
, hscl
, vscl
);
368 return !lua_kill_video
;
371 uint64_t master_dumper::killed_audio_length(uint32_t fps_n
, uint32_t fps_d
, double& fraction
)
374 double x
= 1.0 * fps_d
* r
.first
/ (fps_n
* r
.second
) + fraction
;
380 template bool master_dumper::render_video_hud(struct framebuffer::fb
<false>& target
, struct framebuffer::raw
& source
,
381 uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
, uint32_t bgap
,
382 std::function
<void()> fn
);
383 template bool master_dumper::render_video_hud(struct framebuffer::fb
<true>& target
, struct framebuffer::raw
& source
,
384 uint32_t hscl
, uint32_t vscl
, uint32_t lgap
, uint32_t tgap
, uint32_t rgap
, uint32_t bgap
,
385 std::function
<void()> fn
);