4 #include "core/advdumper.hpp"
5 #include "core/command.hpp"
6 #include "core/dispatch.hpp"
7 #include "core/lua.hpp"
8 #include "core/misc.hpp"
9 #include "core/settings.hpp"
20 uint32_t rates
[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000,
21 128000, 176400, 192000};
23 uint32_t get_rate(uint32_t n
, uint32_t d
, unsigned mode
)
27 double besterror
= 1e99
;
28 for(size_t i
= 0; i
< sizeof(rates
) / sizeof(rates
[0]); i
++) {
29 double error
= fabs(log(static_cast<double>(d
) * rates
[i
] / n
));
30 if(error
< besterror
) {
35 return rates
[bestidx
];
36 } else if(mode
== 1) {
37 return static_cast<uint32_t>(n
/ d
);
38 } else if(mode
== 2) {
39 return static_cast<uint32_t>((n
+ d
- 1) / d
);
45 unsigned compression_level
;
46 uint32_t audio_sampling_rate
;
47 uint32_t keyframe_interval
;
48 uint32_t max_frames_per_segment
;
51 boolean_setting
dump_large("avi-large", false);
52 numeric_setting
dtb("avi-top-border", 0, 8191, 0);
53 numeric_setting
dbb("avi-bottom-border", 0, 8191, 0);
54 numeric_setting
dlb("avi-left-border", 0, 8191, 0);
55 numeric_setting
drb("avi-right-border", 0, 8191, 0);
56 numeric_setting
clevel("avi-compression", 0, 18, 7);
57 numeric_setting
max_frames_per_segment("avi-maxframes", 0, 999999999, 0);
58 numeric_setting
soundrate_setting("avi-soundrate", 0, 2, 0);
60 class avi_avsnoop
: public information_dispatch
63 avi_avsnoop(const std::string
& prefix
, struct avi_info parameters
) throw(std::bad_alloc
)
64 : information_dispatch("dump-avi-cscd")
67 _parameters
= parameters
;
68 avi_cscd_dumper::global_parameters gp
;
69 avi_cscd_dumper::segment_parameters sp
;
70 soundrate
= get_sound_rate();
71 gp
.sampling_rate
= get_rate(soundrate
.first
, soundrate
.second
, soundrate_setting
);
73 gp
.audio_16bit
= true;
76 sp
.dataformat
= avi_cscd_dumper::PIXFMT_RGB15_NE
;
79 sp
.default_stride
= true;
81 sp
.keyframe_distance
= parameters
.keyframe_interval
;
82 sp
.deflate_level
= parameters
.compression_level
;
83 sp
.max_segment_frames
= parameters
.max_frames_per_segment
;
84 vid_dumper
= new avi_cscd_dumper(prefix
, gp
, sp
);
85 audio_record_rate
= parameters
.audio_sampling_rate
;
86 soxdumper
= new sox_dumper(prefix
+ ".sox", static_cast<double>(soundrate
.first
) /
89 have_dumped_frame
= false;
92 ~avi_avsnoop() throw()
98 void on_frame(struct lcscreen
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
102 if(dump_large
&& _frame
.width
< 400)
104 if(dump_large
&& _frame
.height
< 400)
107 struct lua_render_context lrc
;
111 lrc
.bottom_gap
= dbb
;
114 lrc
.width
= _frame
.width
* hscl
;
115 lrc
.height
= _frame
.height
* vscl
;
116 lua_callback_do_video(&lrc
);
118 vid_dumper
->wait_frame_processing();
119 avi_cscd_dumper::segment_parameters sp
;
122 uint32_t x
= 0x18100800;
123 if(*reinterpret_cast<const uint8_t*>(&x
) == 0x18)
124 sp
.dataformat
= avi_cscd_dumper::PIXFMT_XRGB
;
126 sp
.dataformat
= avi_cscd_dumper::PIXFMT_BGRX
;
127 sp
.width
= lrc
.left_gap
+ hscl
* _frame
.width
+ lrc
.right_gap
;
128 sp
.height
= lrc
.top_gap
+ vscl
* _frame
.height
+ lrc
.bottom_gap
;
129 sp
.default_stride
= true;
131 sp
.keyframe_distance
= _parameters
.keyframe_interval
;
132 sp
.deflate_level
= _parameters
.compression_level
;
133 sp
.max_segment_frames
= _parameters
.max_frames_per_segment
;
134 vid_dumper
->set_segment_parameters(sp
);
135 dscr
.reallocate(lrc
.left_gap
+ hscl
* _frame
.width
+ lrc
.right_gap
, lrc
.top_gap
+ vscl
*
136 _frame
.height
+ lrc
.bottom_gap
, false);
137 dscr
.set_origin(lrc
.left_gap
, lrc
.top_gap
);
138 dscr
.copy_from(_frame
, hscl
, vscl
);
140 vid_dumper
->video(dscr
.memory
);
141 have_dumped_frame
= true;
142 //vid_dumper->wait_frame_processing();
145 void on_sample(short l
, short r
)
147 dcounter
+= soundrate
.first
;
148 while(dcounter
< soundrate
.second
* audio_record_rate
+ soundrate
.first
) {
149 if(have_dumped_frame
)
150 vid_dumper
->audio(&l
, &r
, 1, avi_cscd_dumper::SNDFMT_SIGNED_16NE
);
151 dcounter
+= soundrate
.first
;
153 dcounter
-= (soundrate
.second
* audio_record_rate
+ soundrate
.first
);
154 if(have_dumped_frame
)
155 soxdumper
->sample(l
, r
);
160 vid_dumper
->wait_frame_processing();
165 bool get_dumper_flag() throw()
170 avi_cscd_dumper
* vid_dumper
;
171 sox_dumper
* soxdumper
;
174 struct avi_info _parameters
;
175 bool have_dumped_frame
;
176 std::pair
<uint32_t, uint32_t> soundrate
;
177 uint32_t audio_record_rate
;
180 avi_avsnoop
* vid_dumper
;
182 void startdump(const std::string
& prefix
)
185 throw std::runtime_error("Expected prefix");
187 throw std::runtime_error("AVI(CSCD) dumping already in progress");
188 unsigned long level2
= (unsigned long)clevel
;
189 struct avi_info parameters
;
190 parameters
.compression_level
= (level2
> 9) ? (level2
- 9) : level2
;
191 parameters
.audio_sampling_rate
= 32000;
192 parameters
.keyframe_interval
= (level2
> 9) ? 300 : 1;
193 parameters
.max_frames_per_segment
= max_frames_per_segment
;
195 vid_dumper
= new avi_avsnoop(prefix
, parameters
);
196 } catch(std::bad_alloc
& e
) {
198 } catch(std::exception
& e
) {
199 std::ostringstream x
;
200 x
<< "Error starting AVI(CSCD) dump: " << e
.what();
201 throw std::runtime_error(x
.str());
203 messages
<< "Dumping AVI(CSCD) to " << prefix
<< " at level " << level2
<< std::endl
;
204 information_dispatch::do_dumper_update();
210 throw std::runtime_error("No AVI(CSCD) video dump in progress");
212 vid_dumper
->on_dump_end();
213 messages
<< "AVI(CSCD) Dump finished" << std::endl
;
214 } catch(std::bad_alloc
& e
) {
216 } catch(std::exception
& e
) {
217 messages
<< "Error ending AVI(CSCD) dump: " << e
.what() << std::endl
;
221 information_dispatch::do_dumper_update();
224 function_ptr_command
<const std::string
&> avi_dump("dump-avi", "Start AVI capture",
225 "Syntax: dump-avi <prefix>\nStart AVI capture to <prefix>.\n",
226 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
227 tokensplitter
t(args
);
228 std::string prefix
= t
.tail();
232 function_ptr_command
<> end_avi("end-avi", "End AVI capture",
233 "Syntax: end-avi\nEnd a AVI capture.\n",
234 []() throw(std::bad_alloc
, std::runtime_error
) {
238 class adv_avi_dumper
: public adv_dumper
241 adv_avi_dumper() : adv_dumper("INTERNAL-AVI-CSCD") {information_dispatch::do_dumper_update(); }
242 ~adv_avi_dumper() throw();
243 std::set
<std::string
> list_submodes() throw(std::bad_alloc
)
245 std::set
<std::string
> x
;
249 bool wants_prefix(const std::string
& mode
) throw()
254 std::string
name() throw(std::bad_alloc
)
256 return "AVI (internal CSCD)";
259 std::string
modename(const std::string
& mode
) throw(std::bad_alloc
)
266 return (vid_dumper
!= NULL
);
269 void start(const std::string
& mode
, const std::string
& targetname
) throw(std::bad_alloc
,
272 startdump(targetname
);
281 adv_avi_dumper::~adv_avi_dumper() throw()