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"
20 unsigned compression_level
;
21 uint32_t audio_sampling_rate
;
22 uint32_t keyframe_interval
;
23 uint32_t max_frames_per_segment
;
26 boolean_setting
dump_large("avi-large", false);
27 numeric_setting
dtb("avi-top-border", 0, 8191, 0);
28 numeric_setting
dbb("avi-bottom-border", 0, 8191, 0);
29 numeric_setting
dlb("avi-left-border", 0, 8191, 0);
30 numeric_setting
drb("avi-right-border", 0, 8191, 0);
31 numeric_setting
max_frames_per_segment("avi-maxframes", 0, 999999999, 0);
33 class avi_avsnoop
: public information_dispatch
36 avi_avsnoop(const std::string
& prefix
, struct avi_info parameters
) throw(std::bad_alloc
)
37 : information_dispatch("dump-avi-cscd")
39 _parameters
= parameters
;
40 avi_cscd_dumper::global_parameters gp
;
41 avi_cscd_dumper::segment_parameters sp
;
42 gp
.sampling_rate
= parameters
.audio_sampling_rate
;
44 gp
.audio_16bit
= true;
47 sp
.dataformat
= avi_cscd_dumper::PIXFMT_RGB15_NE
;
50 sp
.default_stride
= true;
52 sp
.keyframe_distance
= parameters
.keyframe_interval
;
53 sp
.deflate_level
= parameters
.compression_level
;
54 sp
.max_segment_frames
= parameters
.max_frames_per_segment
;
55 vid_dumper
= new avi_cscd_dumper(prefix
, gp
, sp
);
56 soundrate
= get_sound_rate();
57 audio_record_rate
= parameters
.audio_sampling_rate
;
58 soxdumper
= new sox_dumper(prefix
+ ".sox", static_cast<double>(soundrate
.first
) /
61 have_dumped_frame
= false;
64 ~avi_avsnoop() throw()
70 void on_frame(struct lcscreen
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
74 if(dump_large
&& _frame
.width
< 400)
76 if(dump_large
&& _frame
.height
< 400)
79 struct lua_render_context lrc
;
86 lrc
.width
= _frame
.width
* hscl
;
87 lrc
.height
= _frame
.height
* vscl
;
88 lua_callback_do_video(&lrc
);
90 vid_dumper
->wait_frame_processing();
91 avi_cscd_dumper::segment_parameters sp
;
94 uint32_t x
= 0x18100800;
95 if(*reinterpret_cast<const uint8_t*>(&x
) == 0x18)
96 sp
.dataformat
= avi_cscd_dumper::PIXFMT_XRGB
;
98 sp
.dataformat
= avi_cscd_dumper::PIXFMT_BGRX
;
99 sp
.width
= lrc
.left_gap
+ hscl
* _frame
.width
+ lrc
.right_gap
;
100 sp
.height
= lrc
.top_gap
+ vscl
* _frame
.height
+ lrc
.bottom_gap
;
101 sp
.default_stride
= true;
103 sp
.keyframe_distance
= _parameters
.keyframe_interval
;
104 sp
.deflate_level
= _parameters
.compression_level
;
105 sp
.max_segment_frames
= _parameters
.max_frames_per_segment
;
106 vid_dumper
->set_segment_parameters(sp
);
107 dscr
.reallocate(lrc
.left_gap
+ hscl
* _frame
.width
+ lrc
.right_gap
, lrc
.top_gap
+ vscl
*
108 _frame
.height
+ lrc
.bottom_gap
, false);
109 dscr
.set_origin(lrc
.left_gap
, lrc
.top_gap
);
110 dscr
.copy_from(_frame
, hscl
, vscl
);
112 vid_dumper
->video(dscr
.memory
);
113 have_dumped_frame
= true;
114 vid_dumper
->wait_frame_processing();
117 void on_sample(short l
, short r
)
119 dcounter
+= soundrate
.first
;
120 while(dcounter
< soundrate
.second
* audio_record_rate
+ soundrate
.first
) {
121 if(have_dumped_frame
)
122 vid_dumper
->audio(&l
, &r
, 1, avi_cscd_dumper::SNDFMT_SIGNED_16NE
);
123 dcounter
+= soundrate
.first
;
125 dcounter
-= (soundrate
.second
* audio_record_rate
+ soundrate
.first
);
126 if(have_dumped_frame
)
127 soxdumper
->sample(l
, r
);
136 bool get_dumper_flag() throw()
141 avi_cscd_dumper
* vid_dumper
;
142 sox_dumper
* soxdumper
;
145 struct avi_info _parameters
;
146 bool have_dumped_frame
;
147 std::pair
<uint32_t, uint32_t> soundrate
;
148 uint32_t audio_record_rate
;
151 avi_avsnoop
* vid_dumper
;
153 function_ptr_command
<const std::string
&> avi_dump("dump-avi", "Start AVI capture",
154 "Syntax: dump-avi <level> <prefix>\nStart AVI capture to <prefix> using compression\n"
155 "level <level> (0-18).\n",
156 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
157 tokensplitter
t(args
);
158 std::string level
= t
;
159 std::string prefix
= t
.tail();
161 throw std::runtime_error("Expected prefix");
163 throw std::runtime_error("AVI(CSCD) dumping already in progress");
164 unsigned long level2
;
166 level2
= parse_value
<unsigned long>(level
);
168 throw std::runtime_error("AVI(CSCD) level must be 0-18");
169 } catch(std::bad_alloc
& e
) {
171 } catch(std::runtime_error
& e
) {
172 throw std::runtime_error("Bad AVI(CSCD) compression level '" + level
+ "': " +
175 struct avi_info parameters
;
176 parameters
.compression_level
= (level2
> 9) ? (level2
- 9) : level2
;
177 parameters
.audio_sampling_rate
= 32000;
178 parameters
.keyframe_interval
= (level2
> 9) ? 300 : 1;
179 parameters
.max_frames_per_segment
= max_frames_per_segment
;
181 vid_dumper
= new avi_avsnoop(prefix
, parameters
);
182 } catch(std::bad_alloc
& e
) {
184 } catch(std::exception
& e
) {
185 std::ostringstream x
;
186 x
<< "Error starting AVI(CSCD) dump: " << e
.what();
187 throw std::runtime_error(x
.str());
189 messages
<< "Dumping AVI(CSCD) to " << prefix
<< " at level " << level2
<< std::endl
;
192 function_ptr_command
<> end_avi("end-avi", "End AVI capture",
193 "Syntax: end-avi\nEnd a AVI capture.\n",
194 []() throw(std::bad_alloc
, std::runtime_error
) {
196 throw std::runtime_error("No AVI(CSCD) video dump in progress");
198 vid_dumper
->on_dump_end();
199 messages
<< "AVI(CSCD) Dump finished" << std::endl
;
200 } catch(std::bad_alloc
& e
) {
202 } catch(std::exception
& e
) {
203 messages
<< "Error ending AVI(CSCD) dump: " << e
.what() << std::endl
;