3 #include "core/advdumper.hpp"
4 #include "core/command.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/lua.hpp"
7 #include "core/misc.hpp"
8 #include "core/settings.hpp"
18 numeric_setting
clevel("jmd-compression", 0, 9, 7);
20 class jmd_avsnoop
: public information_dispatch
23 jmd_avsnoop(const std::string
& filename
, unsigned level
) throw(std::bad_alloc
)
24 : information_dispatch("dump-jmd")
27 vid_dumper
= new jmd_dumper(filename
, level
);
28 have_dumped_frame
= false;
34 soundrate
= get_sound_rate();
36 on_gameinfo(get_gameinfo());
37 } catch(std::exception
& e
) {
38 messages
<< "Can't write gameinfo: " << e
.what() << std::endl
;
42 ~jmd_avsnoop() throw()
47 void on_frame(struct lcscreen
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
49 struct lua_render_context lrc
;
56 lrc
.width
= _frame
.width
;
57 lrc
.height
= _frame
.height
;
58 lua_callback_do_video(&lrc
);
59 dscr
.set_palette(0, 8, 16);
60 dscr
.reallocate(lrc
.left_gap
+ _frame
.width
+ lrc
.right_gap
, lrc
.top_gap
+ _frame
.height
+
61 lrc
.bottom_gap
, false);
62 dscr
.set_origin(lrc
.left_gap
, lrc
.top_gap
);
63 dscr
.copy_from(_frame
, 1, 1);
66 vid_dumper
->video(get_next_video_ts(fps_n
, fps_d
), dscr
.memory
, dscr
.width
, dscr
.height
);
67 have_dumped_frame
= true;
70 void on_sample(short l
, short r
)
72 uint64_t ts
= get_next_audio_ts();
74 vid_dumper
->audio(ts
, l
, r
);
79 vid_dumper
->end(maxtc
);
82 void on_gameinfo(const struct gameinfo_struct
& gi
)
85 for(size_t i
= 0; i
< gi
.get_author_count(); i
++) {
87 authstr
= authstr
+ ", ";
88 authstr
= authstr
+ gi
.get_author_short(i
);
90 vid_dumper
->gameinfo(gi
.gamename
, authstr
, 1000000000ULL * gi
.length
, gi
.get_rerecords());
93 bool get_dumper_flag() throw()
98 uint64_t get_next_video_ts(uint32_t fps_n
, uint32_t fps_d
)
100 uint64_t ret
= video_w
;
101 video_w
+= (1000000000ULL * fps_d
) / fps_n
;
102 video_n
+= (1000000000ULL * fps_d
) % fps_n
;
103 if(video_n
>= fps_n
) {
107 maxtc
= (ret
> maxtc
) ? ret
: maxtc
;
111 uint64_t get_next_audio_ts()
113 uint64_t ret
= audio_w
;
114 audio_w
+= (1000000000ULL * soundrate
.second
) / soundrate
.first
;
115 audio_n
+= (1000000000ULL * soundrate
.second
) % soundrate
.first
;
116 if(audio_n
>= soundrate
.first
) {
117 audio_n
-= soundrate
.first
;
120 maxtc
= (ret
> maxtc
) ? ret
: maxtc
;
124 jmd_dumper
* vid_dumper
;
127 bool have_dumped_frame
;
133 std::pair
<uint32_t, uint32_t> soundrate
;
136 jmd_avsnoop
* vid_dumper
;
138 void startdump(std::string prefix
)
141 throw std::runtime_error("Expected filename");
143 throw std::runtime_error("JMD dumping already in progress");
144 unsigned long level2
= (unsigned long)clevel
;
146 vid_dumper
= new jmd_avsnoop(prefix
, level2
);
147 } catch(std::bad_alloc
& e
) {
149 } catch(std::exception
& e
) {
150 std::ostringstream x
;
151 x
<< "Error starting JMD dump: " << e
.what();
152 throw std::runtime_error(x
.str());
154 messages
<< "Dumping to " << prefix
<< " at level " << level2
<< std::endl
;
155 information_dispatch::do_dumper_update();
161 throw std::runtime_error("No JMD video dump in progress");
163 vid_dumper
->on_dump_end();
164 messages
<< "JMD Dump finished" << std::endl
;
165 } catch(std::bad_alloc
& e
) {
167 } catch(std::exception
& e
) {
168 messages
<< "Error ending JMD dump: " << e
.what() << std::endl
;
172 information_dispatch::do_dumper_update();
175 function_ptr_command
<const std::string
&> jmd_dump("dump-jmd", "Start JMD capture",
176 "Syntax: dump-jmd <file>\nStart JMD capture to <file>.\n",
177 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
178 tokensplitter
t(args
);
179 std::string prefix
= t
.tail();
183 function_ptr_command
<> end_avi("end-jmd", "End JMD capture",
184 "Syntax: end-jmd\nEnd a JMD capture.\n",
185 []() throw(std::bad_alloc
, std::runtime_error
) {
189 class adv_jmd_dumper
: public adv_dumper
192 adv_jmd_dumper() : adv_dumper("INTERNAL-JMD") {information_dispatch::do_dumper_update(); }
193 ~adv_jmd_dumper() throw();
194 std::set
<std::string
> list_submodes() throw(std::bad_alloc
)
196 std::set
<std::string
> x
;
200 bool wants_prefix(const std::string
& mode
) throw()
205 std::string
name() throw(std::bad_alloc
)
210 std::string
modename(const std::string
& mode
) throw(std::bad_alloc
)
217 return (vid_dumper
!= NULL
);
220 void start(const std::string
& mode
, const std::string
& targetname
) throw(std::bad_alloc
,
223 startdump(targetname
);
232 adv_jmd_dumper::~adv_jmd_dumper() throw()