11 #define AVI_CUTOFF_SIZE 2100000000
15 struct dumper_thread_obj
17 int operator()(avi_cscd_dumper
* d
)
20 return d
->encode_thread();
21 } catch(std::exception
& e
) {
22 std::cerr
<< "Encode thread threw: " << e
.what() << std::endl
;
23 d
->set_capture_error(e
.what());
29 void write8(char* out
, unsigned char x
)
34 void write16(char* out
, unsigned x
)
40 void write32(char* out
, unsigned long x
)
48 struct stream_format_base
50 virtual ~stream_format_base();
51 virtual unsigned long type() = 0;
52 virtual unsigned long scale() = 0;
53 virtual unsigned long rate() = 0;
54 virtual unsigned long sample_size() = 0;
55 virtual unsigned long rect_left() = 0;
56 virtual unsigned long rect_top() = 0;
57 virtual unsigned long rect_right() = 0;
58 virtual unsigned long rect_bottom() = 0;
59 virtual size_t size() = 0;
60 virtual void serialize(std::ostream
& out
) = 0;
63 struct stream_format_video
: public stream_format_base
65 ~stream_format_video();
66 unsigned long type() { return 0x73646976UL
; }
67 unsigned long scale() { return fps_d
; }
68 unsigned long rate() { return fps_n
; }
69 unsigned long rect_left() { return 0; }
70 unsigned long rect_top() { return 0; }
71 unsigned long rect_right() { return width
; }
72 unsigned long rect_bottom() { return height
; }
73 unsigned long sample_size() { return (bit_count
+ 7) / 8; }
74 size_t size() { return 48; }
79 unsigned long compression
;
80 unsigned long size_image
;
81 unsigned long resolution_x
;
82 unsigned long resolution_y
;
83 unsigned long clr_used
;
84 unsigned long clr_important
;
87 void serialize(std::ostream
& out
)
89 std::vector
<char> buf
;
91 write32(&buf
[0], 0x66727473UL
); //Type
92 write32(&buf
[4], size() - 8); //Size.
93 write32(&buf
[8], 40); //BITMAPINFOHEADER size.
94 write32(&buf
[12], width
);
95 write32(&buf
[16], height
);
96 write16(&buf
[20], planes
);
97 write16(&buf
[22], bit_count
);
98 write32(&buf
[24], compression
);
99 write32(&buf
[28], size_image
);
100 write32(&buf
[32], resolution_x
);
101 write32(&buf
[36], resolution_y
);
102 write32(&buf
[40], clr_used
);
103 write32(&buf
[44], clr_important
);
104 out
.write(&buf
[0], buf
.size());
106 throw std::runtime_error("Can't write strf (video)");
111 struct stream_format_audio
: public stream_format_base
113 ~stream_format_audio();
114 unsigned long type() { return 0x73647561; }
115 unsigned long scale() { return 1; }
116 unsigned long rate() { return samples_per_second
; }
117 unsigned long rect_left() { return 0; }
118 unsigned long rect_top() { return 0; }
119 unsigned long rect_right() { return 0; }
120 unsigned long rect_bottom() { return 0; }
121 unsigned long sample_size() { return blocksize
; }
122 size_t size() { return 28; }
125 unsigned long samples_per_second
;
126 unsigned long average_bytes_per_second
;
127 unsigned block_align
;
128 unsigned bits_per_sample
;
129 unsigned long blocksize
;
130 void serialize(std::ostream
& out
)
132 std::vector
<char> buf
;
134 write32(&buf
[0], 0x66727473UL
); //Type
135 write32(&buf
[4], size() - 8); //Size.
136 write16(&buf
[8], format_tag
);
137 write16(&buf
[10], channels
);
138 write32(&buf
[12], samples_per_second
);
139 write32(&buf
[16], average_bytes_per_second
);
140 write16(&buf
[20], block_align
);
141 write16(&buf
[22], bits_per_sample
);
142 write16(&buf
[24], 0); //No extension data.
143 write16(&buf
[26], 0); //Pad
144 out
.write(&buf
[0], buf
.size());
146 throw std::runtime_error("Can't write strf (audio)");
150 stream_format_base::~stream_format_base() {}
151 stream_format_video::~stream_format_video() {}
152 stream_format_audio::~stream_format_audio() {}
156 size_t size() { return 72; }
157 unsigned long handler
;
161 unsigned long initial_frames
;
163 unsigned long length
;
164 unsigned long suggested_buffer_size
;
165 unsigned long quality
;
171 void add_frames(size_t count
)
173 length
= length
+ count
;
176 void serialize(std::ostream
& out
, struct stream_format_base
& format
)
178 std::vector
<char> buf
;
180 write32(&buf
[0], 0x68727473UL
); //Type
181 write32(&buf
[4], size() - 8); //Size.
182 write32(&buf
[8], format
.type());
183 write32(&buf
[12], handler
);
184 write32(&buf
[16], flags
);
185 write16(&buf
[20], priority
);
186 write16(&buf
[22], language
);
187 write32(&buf
[24], initial_frames
);
188 write32(&buf
[28], format
.scale());
189 write32(&buf
[32], format
.rate());
190 write32(&buf
[36], start
);
191 write32(&buf
[40], length
);
192 write32(&buf
[44], suggested_buffer_size
);
193 write32(&buf
[48], quality
);
194 write32(&buf
[52], format
.sample_size());
195 write32(&buf
[56], format
.rect_left());
196 write32(&buf
[60], format
.rect_top());
197 write32(&buf
[64], format
.rect_right());
198 write32(&buf
[68], format
.rect_bottom());
199 out
.write(&buf
[0], buf
.size());
201 throw std::runtime_error("Can't write strh");
205 template<class format
>
206 struct stream_header_list
208 size_t size() { return 12 + strh
.size() + strf
.size(); }
211 void serialize(std::ostream
& out
)
213 std::vector
<char> buf
;
215 write32(&buf
[0], 0x5453494CUL
); //List.
216 write32(&buf
[4], size() - 8);
217 write32(&buf
[8], 0x6c727473UL
); //Type.
218 out
.write(&buf
[0], buf
.size());
220 throw std::runtime_error("Can't write strl");
221 strh
.serialize(out
, strf
);
228 size_t size() { return 64; }
229 unsigned long microsec_per_frame
;
230 unsigned long max_bytes_per_sec
;
231 unsigned long padding_granularity
;
233 unsigned long initial_frames
;
234 unsigned long suggested_buffer_size
;
235 void serialize(std::ostream
& out
, stream_header_list
<stream_format_video
>& videotrack
,
236 unsigned long tracks
)
238 std::vector
<char> buf
;
240 write32(&buf
[0], 0x68697661); //Type.
241 write32(&buf
[4], size() - 8);
242 write32(&buf
[8], microsec_per_frame
);
243 write32(&buf
[12], max_bytes_per_sec
);
244 write32(&buf
[16], padding_granularity
);
245 write32(&buf
[20], flags
);
246 write32(&buf
[24], videotrack
.strh
.length
);
247 write32(&buf
[28], initial_frames
);
248 write32(&buf
[32], tracks
);
249 write32(&buf
[36], suggested_buffer_size
);
250 write32(&buf
[40], videotrack
.strf
.width
);
251 write32(&buf
[44], videotrack
.strf
.height
);
252 write32(&buf
[48], 0);
253 write32(&buf
[52], 0);
254 write32(&buf
[56], 0);
255 write32(&buf
[60], 0);
256 out
.write(&buf
[0], buf
.size());
258 throw std::runtime_error("Can't write avih");
264 size_t size() { return 12 + avih
.size() + videotrack
.size() + audiotrack
.size(); }
266 stream_header_list
<stream_format_video
> videotrack
;
267 stream_header_list
<stream_format_audio
> audiotrack
;
268 void serialize(std::ostream
& out
)
270 std::vector
<char> buf
;
272 write32(&buf
[0], 0x5453494CUL
); //List.
273 write32(&buf
[4], size() - 8);
274 write32(&buf
[8], 0x6c726468UL
); //Type.
275 out
.write(&buf
[0], buf
.size());
277 throw std::runtime_error("Can't write hdrl");
278 avih
.serialize(out
, videotrack
, 2);
279 videotrack
.serialize(out
);
280 audiotrack
.serialize(out
);
286 unsigned long payload_size
;
287 size_t write_offset() { return 12; }
288 size_t size() { return 12 + payload_size
; }
295 void add_payload(size_t s
)
297 payload_size
= payload_size
+ s
;
300 void serialize(std::ostream
& out
)
302 std::vector
<char> buf
;
304 write32(&buf
[0], 0x5453494CUL
); //List.
305 write32(&buf
[4], size() - 8);
306 write32(&buf
[8], 0x69766f6d); //Type.
307 out
.write(&buf
[0], buf
.size());
308 out
.seekp(payload_size
, std::ios_base::cur
);
310 throw std::runtime_error("Can't write movi");
316 size_t size() { return 16; }
317 unsigned long chunk_type
;
319 unsigned long offset
;
320 unsigned long length
;
321 index_entry(unsigned long _chunk_type
, unsigned long _flags
, unsigned long _offset
,
322 unsigned long _length
)
324 chunk_type
= _chunk_type
;
330 void serialize(std::ostream
& out
)
332 std::vector
<char> buf
;
334 write32(&buf
[0], chunk_type
);
335 write32(&buf
[4], flags
);
336 write32(&buf
[8], offset
);
337 write32(&buf
[12], length
);
338 out
.write(&buf
[0], buf
.size());
340 throw std::runtime_error("Can't write index entry");
346 void add_entry(const index_entry
& entry
) { entries
.push_back(entry
); }
347 std::list
<index_entry
> entries
;
351 //Not exactly right, but much faster than the proper way.
354 s
= s
+ entries
.begin()->size() * entries
.size();
358 void serialize(std::ostream
& out
)
360 std::vector
<char> buf
;
362 write32(&buf
[0], 0x31786469UL
); //Type.
363 write32(&buf
[4], size() - 8);
364 out
.write(&buf
[0], buf
.size());
366 throw std::runtime_error("Can't write idx1");
367 for(std::list
<index_entry
>::iterator i
= entries
.begin(); i
!= entries
.end(); i
++)
372 size_t bpp_for_pixtype(enum avi_cscd_dumper::pixelformat pf
)
375 case avi_cscd_dumper::PIXFMT_RGB15_BE
:
376 case avi_cscd_dumper::PIXFMT_RGB15_LE
:
377 case avi_cscd_dumper::PIXFMT_RGB15_NE
:
379 case avi_cscd_dumper::PIXFMT_RGB24
:
380 case avi_cscd_dumper::PIXFMT_BGR24
:
382 case avi_cscd_dumper::PIXFMT_RGBX
:
383 case avi_cscd_dumper::PIXFMT_BGRX
:
384 case avi_cscd_dumper::PIXFMT_XRGB
:
385 case avi_cscd_dumper::PIXFMT_XBGR
:
392 size_t bps_for_sndtype(enum avi_cscd_dumper::soundformat sf
)
395 case avi_cscd_dumper::SNDFMT_SILENCE
:
397 case avi_cscd_dumper::SNDFMT_SIGNED_8
:
398 case avi_cscd_dumper::SNDFMT_UNSIGNED_8
:
400 case avi_cscd_dumper::SNDFMT_SIGNED_16BE
:
401 case avi_cscd_dumper::SNDFMT_SIGNED_16NE
:
402 case avi_cscd_dumper::SNDFMT_SIGNED_16LE
:
403 case avi_cscd_dumper::SNDFMT_UNSIGNED_16BE
:
404 case avi_cscd_dumper::SNDFMT_UNSIGNED_16NE
:
405 case avi_cscd_dumper::SNDFMT_UNSIGNED_16LE
:
411 inline unsigned short convert_audio_sample(const char* addr
, enum avi_cscd_dumper::soundformat sf
)
415 unsigned short magic
= 258;
416 bool little_endian
= (*reinterpret_cast<char*>(&magic
) == 2);
418 case avi_cscd_dumper::SNDFMT_SILENCE
:
420 case avi_cscd_dumper::SNDFMT_SIGNED_8
:
421 return static_cast<unsigned short>((static_cast<short>(*addr
) << 8)) + 32768;
422 case avi_cscd_dumper::SNDFMT_UNSIGNED_8
:
423 return static_cast<unsigned short>(static_cast<unsigned char>(*addr
)) << 8;
424 case avi_cscd_dumper::SNDFMT_SIGNED_16BE
:
425 a
= static_cast<unsigned char>(addr
[0]);
426 b
= static_cast<unsigned char>(addr
[1]);
427 return a
* 256 + b
+ 32768;
428 case avi_cscd_dumper::SNDFMT_SIGNED_16NE
:
429 a
= static_cast<unsigned char>(addr
[0]);
430 b
= static_cast<unsigned char>(addr
[1]);
432 return b
* 256 + a
+ 32768;
434 return a
* 256 + b
+ 32768;
435 case avi_cscd_dumper::SNDFMT_SIGNED_16LE
:
436 a
= static_cast<unsigned char>(addr
[0]);
437 b
= static_cast<unsigned char>(addr
[1]);
438 return b
* 256 + a
+ 32768;
439 case avi_cscd_dumper::SNDFMT_UNSIGNED_16BE
:
440 a
= static_cast<unsigned char>(addr
[0]);
441 b
= static_cast<unsigned char>(addr
[1]);
443 case avi_cscd_dumper::SNDFMT_UNSIGNED_16NE
:
444 a
= static_cast<unsigned char>(addr
[0]);
445 b
= static_cast<unsigned char>(addr
[1]);
450 case avi_cscd_dumper::SNDFMT_UNSIGNED_16LE
:
451 a
= static_cast<unsigned char>(addr
[0]);
452 b
= static_cast<unsigned char>(addr
[1]);
458 void copy_row(unsigned char* target
, const unsigned char* src
, unsigned width
,
459 enum avi_cscd_dumper::pixelformat pf
)
461 unsigned ewidth
= (width
+ 3) >> 2 << 2;
462 size_t sbpp
= bpp_for_pixtype(pf
);
463 size_t dbpp
= (sbpp
== 2) ? 2 : 3;
464 unsigned short magic
= 258;
465 bool little_endian
= (*reinterpret_cast<char*>(&magic
) == 2);
466 for(unsigned i
= 0; i
< width
; i
++) {
468 case avi_cscd_dumper::PIXFMT_RGB15_BE
:
469 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 1];
470 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 0];
472 case avi_cscd_dumper::PIXFMT_RGB15_NE
:
473 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ (little_endian
? 0 : 1)];
474 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ (little_endian
? 1 : 0)];
476 case avi_cscd_dumper::PIXFMT_RGB15_LE
:
477 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 0];
478 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 1];
480 case avi_cscd_dumper::PIXFMT_BGR24
:
481 case avi_cscd_dumper::PIXFMT_BGRX
:
482 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 0];
483 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 1];
484 target
[dbpp
* i
+ 2] = src
[sbpp
* i
+ 2];
486 case avi_cscd_dumper::PIXFMT_RGB24
:
487 case avi_cscd_dumper::PIXFMT_RGBX
:
488 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 2];
489 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 1];
490 target
[dbpp
* i
+ 2] = src
[sbpp
* i
+ 0];
492 case avi_cscd_dumper::PIXFMT_XRGB
:
493 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 3];
494 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 2];
495 target
[dbpp
* i
+ 2] = src
[sbpp
* i
+ 1];
497 case avi_cscd_dumper::PIXFMT_XBGR
:
498 target
[dbpp
* i
+ 0] = src
[sbpp
* i
+ 1];
499 target
[dbpp
* i
+ 1] = src
[sbpp
* i
+ 2];
500 target
[dbpp
* i
+ 2] = src
[sbpp
* i
+ 3];
504 memset(target
+ dbpp
* width
, 0, dbpp
* (ewidth
- width
));
508 struct avi_file_structure
510 size_t write_offset() { return 12 + hdrl
.size() + movi
.write_offset(); }
511 size_t size() { return 12 + hdrl
.size() + movi
.size() + idx1
.size(); }
515 void serialize(std::ostream
& out
)
517 std::vector
<char> buf
;
519 write32(&buf
[0], 0x46464952UL
); //RIFF.
520 write32(&buf
[4], size() - 8);
521 write32(&buf
[8], 0x20495641UL
); //Type.
522 out
.write(&buf
[0], buf
.size());
524 throw std::runtime_error("Can't write AVI header");
530 void start_data(std::ostream
& out
)
532 out
.seekp(0, std::ios_base::beg
);
533 size_t reserved_for_header
= write_offset();
534 std::vector
<char> tmp
;
535 tmp
.resize(reserved_for_header
);
536 out
.write(&tmp
[0], tmp
.size());
538 throw std::runtime_error("Can't write dummy header");
541 void finish_avi(std::ostream
& out
)
543 out
.seekp(0, std::ios_base::beg
);
546 throw std::runtime_error("Can't finish AVI");
552 void fill_avi_structure(struct avi_file_structure
* avis
, unsigned width
, unsigned height
, unsigned long fps_n
,
553 unsigned long fps_d
, int mode
, unsigned channels
, unsigned long sampling_rate
, bool bits16
)
555 avis
->hdrl
.avih
.microsec_per_frame
= (Uint64
)1000000 * fps_d
/ fps_n
;
556 avis
->hdrl
.avih
.max_bytes_per_sec
= 1000000;
557 avis
->hdrl
.avih
.padding_granularity
= 0;
558 avis
->hdrl
.avih
.flags
= 2064;
559 avis
->hdrl
.avih
.initial_frames
= 0;
560 avis
->hdrl
.avih
.suggested_buffer_size
= 1000000;
561 avis
->hdrl
.videotrack
.strh
.handler
= 0;
562 avis
->hdrl
.videotrack
.strh
.flags
= 0;
563 avis
->hdrl
.videotrack
.strh
.priority
= 0;
564 avis
->hdrl
.videotrack
.strh
.language
= 0;
565 avis
->hdrl
.videotrack
.strh
.initial_frames
= 0;
566 avis
->hdrl
.videotrack
.strh
.start
= 0;
567 avis
->hdrl
.videotrack
.strh
.suggested_buffer_size
= 1000000;
568 avis
->hdrl
.videotrack
.strh
.quality
= 9999;
569 avis
->hdrl
.videotrack
.strf
.width
= width
;
570 avis
->hdrl
.videotrack
.strf
.height
= height
;
571 avis
->hdrl
.videotrack
.strf
.planes
= 1;
572 avis
->hdrl
.videotrack
.strf
.bit_count
= (mode
+ 1) << 3;
573 avis
->hdrl
.videotrack
.strf
.compression
= 0x44435343;
574 avis
->hdrl
.videotrack
.strf
.size_image
= (1UL * (mode
+ 1) * width
* height
);
575 avis
->hdrl
.videotrack
.strf
.resolution_x
= 4000;
576 avis
->hdrl
.videotrack
.strf
.resolution_y
= 4000;
577 avis
->hdrl
.videotrack
.strf
.clr_used
= 0;
578 avis
->hdrl
.videotrack
.strf
.clr_important
= 0;
579 avis
->hdrl
.videotrack
.strf
.fps_n
= fps_n
;
580 avis
->hdrl
.videotrack
.strf
.fps_d
= fps_d
;
581 avis
->hdrl
.audiotrack
.strh
.handler
= 0;
582 avis
->hdrl
.audiotrack
.strh
.flags
= 0;
583 avis
->hdrl
.audiotrack
.strh
.priority
= 0;
584 avis
->hdrl
.audiotrack
.strh
.language
= 0;
585 avis
->hdrl
.audiotrack
.strh
.initial_frames
= 0;
586 avis
->hdrl
.audiotrack
.strh
.start
= 0;
587 avis
->hdrl
.audiotrack
.strh
.suggested_buffer_size
= 1000000;
588 avis
->hdrl
.audiotrack
.strh
.quality
= 9999;
589 avis
->hdrl
.audiotrack
.strf
.format_tag
= 1;
590 avis
->hdrl
.audiotrack
.strf
.channels
= channels
;
591 avis
->hdrl
.audiotrack
.strf
.samples_per_second
= sampling_rate
;
592 avis
->hdrl
.audiotrack
.strf
.average_bytes_per_second
= sampling_rate
* channels
* (bits16
? 2 : 1);
593 avis
->hdrl
.audiotrack
.strf
.block_align
= channels
* (bits16
? 2 : 1);
594 avis
->hdrl
.audiotrack
.strf
.bits_per_sample
= (bits16
? 16 : 8);
595 avis
->hdrl
.audiotrack
.strf
.blocksize
= channels
* (bits16
? 2 : 1);
599 avi_cscd_dumper::avi_cscd_dumper(const std::string
& prefix
, const avi_cscd_dumper::global_parameters
& global
,
600 const avi_cscd_dumper::segment_parameters
& segment
) throw(std::bad_alloc
, std::runtime_error
)
602 dump_prefix
= prefix
;
603 if(!global
.sampling_rate
|| global
.sampling_rate
>= 0xFFFFFFFFUL
)
604 throw std::runtime_error("Sound sampling rate invalid");
605 if(!global
.channel_count
|| global
.channel_count
>= 0xFFFFU
)
606 throw std::runtime_error("Sound channel count invalid");
607 if(!segment
.fps_n
|| segment
.fps_n
>= 0xFFFFFFFFUL
)
608 throw std::runtime_error("FPS numerator invalid");
609 if(!segment
.fps_d
|| segment
.fps_d
>= 0xFFFFFFFFUL
)
610 throw std::runtime_error("FPS denominator invalid");
611 if(!bpp_for_pixtype(segment
.dataformat
))
612 throw std::runtime_error("Pixel format invalid");
613 if(!segment
.width
|| segment
.width
> 0xFFFCU
)
614 throw std::runtime_error("Width invalid");
615 if(!segment
.height
|| segment
.height
> 0xFFFCU
)
616 throw std::runtime_error("Height invalid");
617 if(segment
.deflate_level
> 9)
618 throw std::runtime_error("Invalid deflate level");
619 gp_sampling_rate
= global
.sampling_rate
;
620 gp_channel_count
= global
.channel_count
;
621 gp_audio_16bit
= global
.audio_16bit
;
622 sp_fps_n
= segment
.fps_n
;
623 sp_fps_d
= segment
.fps_d
;
624 sp_dataformat
= segment
.dataformat
;
625 sp_width
= segment
.width
;
626 sp_height
= segment
.height
;
627 sp_max_segment_frames
= segment
.max_segment_frames
;
628 if(segment
.default_stride
)
629 sp_stride
= bpp_for_pixtype(segment
.dataformat
) * segment
.width
;
631 sp_stride
= segment
.stride
;
632 sp_keyframe_distance
= segment
.keyframe_distance
;
633 sp_deflate_level
= segment
.deflate_level
;
635 current_major_segment
= 0;
636 next_minor_segment
= 0;
637 current_major_segment_frames
= 0;
638 frames_since_last_keyframe
= 0;
639 avifile_structure
= NULL
;
641 buffered_sound_samples
= 0;
642 switch_segments_on_next_frame
= false;
643 frame_period_counter
= 0;
645 quit_requested
= false;
646 flush_requested
= false;
647 flush_requested_forced
= false;
648 frame_processing
= false;
649 frame_pointer
= NULL
;
650 exception_error_present
= false;
651 //std::cerr << "A" << std::endl;
652 dumper_thread_obj dto
;
653 //std::cerr << "B" << std::endl;
654 frame_thread
= new thread_class(dto
, this);
655 //std::cerr << "C" << std::endl;
658 avi_cscd_dumper::~avi_cscd_dumper() throw()
667 avi_cscd_dumper::segment_parameters
avi_cscd_dumper::get_segment_parameters() throw()
669 segment_parameters sp
;
670 sp
.dataformat
= sp_dataformat
;
671 sp
.default_stride
= false;
672 sp
.deflate_level
= sp_deflate_level
;
675 sp
.height
= sp_height
;
676 sp
.keyframe_distance
= sp_keyframe_distance
;
677 sp
.stride
= sp_stride
;
682 void avi_cscd_dumper::set_segment_parameters(const avi_cscd_dumper::segment_parameters
& segment
) throw(std::bad_alloc
,
685 wait_frame_processing();
686 if(!segment
.fps_n
|| segment
.fps_n
>= 0xFFFFFFFFUL
)
687 throw std::runtime_error("FPS numerator invalid");
688 if(!segment
.fps_d
|| segment
.fps_d
>= 0xFFFFFFFFUL
)
689 throw std::runtime_error("FPS denominator invalid");
690 if(segment
.dataformat
< PIXFMT_RGB15_LE
|| segment
.dataformat
> PIXFMT_XBGR
)
691 throw std::runtime_error("Pixel format invalid");
692 if(!segment
.width
|| segment
.width
> 0xFFFCU
)
693 throw std::runtime_error("Width invalid");
694 if(!segment
.height
|| segment
.height
> 0xFFFCU
)
695 throw std::runtime_error("Height invalid");
696 if(segment
.deflate_level
> 9)
697 throw std::runtime_error("Invalid deflate level");
698 //Switch all parameters that can't be incompatible.
699 if(segment
.default_stride
)
700 sp_stride
= bpp_for_pixtype(segment
.dataformat
) * segment
.width
;
702 sp_stride
= segment
.stride
;
703 sp_keyframe_distance
= segment
.keyframe_distance
;
704 sp_deflate_level
= segment
.deflate_level
;
705 sp_max_segment_frames
= segment
.max_segment_frames
;
707 bool incompatible
= false;
708 if(sp_fps_n
!= segment
.fps_n
)
710 if(sp_fps_d
!= segment
.fps_d
)
712 if(((sp_width
+ 3) >> 2) != ((segment
.width
+ 3) >> 2))
714 if(((sp_height
+ 3) >> 2) != ((segment
.height
+ 3) >> 2))
716 if(bpp_for_pixtype(sp_dataformat
) == 2 && bpp_for_pixtype(segment
.dataformat
) != 2)
718 if(bpp_for_pixtype(sp_dataformat
) != 2 && bpp_for_pixtype(segment
.dataformat
) == 2)
722 spn_dataformat
= segment
.dataformat
;
723 spn_fps_d
= segment
.fps_d
;
724 spn_fps_n
= segment
.fps_n
;
725 spn_height
= segment
.height
;
726 spn_width
= segment
.width
;
727 switch_segments_on_next_frame
= true;
729 sp_dataformat
= segment
.dataformat
;
730 sp_fps_d
= segment
.fps_d
;
731 sp_fps_n
= segment
.fps_n
;
732 sp_height
= segment
.height
;
733 sp_width
= segment
.width
;
734 switch_segments_on_next_frame
= false;
738 void avi_cscd_dumper::audio(const void* audio
, size_t samples
, enum avi_cscd_dumper::soundformat format
)
739 throw(std::bad_alloc
, std::runtime_error
)
741 if(exception_error_present
)
742 throw std::runtime_error(exception_error
);
743 const char* s
= reinterpret_cast<const char*>(audio
);
744 size_t stride
= bps_for_sndtype(format
);
745 size_t mstride
= gp_channel_count
* stride
;
746 //std::cerr << "Locking lock." << std::endl;
748 //std::cerr << "Locked lock." << std::endl;
749 for(size_t i
= 0; i
< samples
; i
++) {
750 for(size_t j
= 0; j
< gp_channel_count
; j
++) {
751 unsigned short as
= convert_audio_sample(s
+ mstride
* i
+ stride
* j
, format
);
752 while(buffered_sound_samples
* gp_channel_count
+ j
>= sound_buffer
.size())
753 sound_buffer
.resize(sound_buffer
.size() + 128);
754 sound_buffer
[buffered_sound_samples
* gp_channel_count
+ j
] = as
;
756 buffered_sound_samples
++;
758 frame_mutex
.unlock();
759 request_flush_buffers(false);
762 void avi_cscd_dumper::audio(const void* laudio
, const void* raudio
, size_t samples
,
763 enum avi_cscd_dumper::soundformat format
) throw(std::bad_alloc
, std::runtime_error
)
765 if(exception_error_present
)
766 throw std::runtime_error(exception_error
);
767 if(gp_channel_count
!= 2)
768 throw std::runtime_error("Split-stereo audio only allowed for stereo output");
769 const char* l
= reinterpret_cast<const char*>(laudio
);
770 const char* r
= reinterpret_cast<const char*>(raudio
);
771 size_t stride
= bps_for_sndtype(format
);
772 //std::cerr << "Locking lock." << std::endl;
774 //std::cerr << "Locked lock." << std::endl;
775 for(size_t i
= 0; i
< samples
; i
++) {
776 unsigned short ls
= convert_audio_sample(l
+ stride
* i
, format
);
777 unsigned short rs
= convert_audio_sample(r
+ stride
* i
, format
);
778 while(buffered_sound_samples
* gp_channel_count
>= sound_buffer
.size())
779 sound_buffer
.resize(sound_buffer
.size() + 128);
780 sound_buffer
[buffered_sound_samples
* 2 + 0] = ls
;
781 sound_buffer
[buffered_sound_samples
* 2 + 1] = rs
;
782 buffered_sound_samples
++;
784 frame_mutex
.unlock();
785 request_flush_buffers(false);
788 void avi_cscd_dumper::video(const void* framedata
) throw(std::bad_alloc
, std::runtime_error
)
790 if(exception_error_present
)
791 throw std::runtime_error(exception_error
);
792 wait_frame_processing();
793 //std::cerr << "Locking lock." << std::endl;
795 //std::cerr << "Locked lock." << std::endl;
796 frame_processing
= true;
797 frame_pointer
= framedata
;
798 frame_cond
.notify_all();
799 //std::cerr << "Requesting processing of frame" << std::endl;
800 frame_mutex
.unlock();
801 #ifndef ACTUALLY_USE_THREADS
806 void avi_cscd_dumper::_video(const void* framedata
)
808 buffered_frame frame
;
809 frame
.forcebreak
= switch_segments_on_next_frame
;
810 //Switch parameters if needed.
811 if(switch_segments_on_next_frame
) {
812 sp_dataformat
= spn_dataformat
;
813 sp_fps_d
= spn_fps_d
;
814 sp_fps_n
= spn_fps_n
;
815 sp_height
= spn_height
;
816 sp_width
= spn_width
;
817 switch_segments_on_next_frame
= false;
819 frame
.compression_level
= sp_deflate_level
;
820 frame
.mode
= (bpp_for_pixtype(sp_dataformat
) == 2) ? 1 : 2;
821 frame
.fps_d
= sp_fps_d
;
822 frame
.fps_n
= sp_fps_n
;
823 frame
.width
= sp_width
;
824 frame
.height
= sp_height
;
825 frame
.keyframe
= (++frames_since_last_keyframe
>= sp_keyframe_distance
);
827 frames_since_last_keyframe
= 0;
828 size_t stride
= ((bpp_for_pixtype(sp_dataformat
) == 2) ? 2 : 3) * ((sp_width
+ 3) >> 2 << 2);
829 size_t srcstride
= (bpp_for_pixtype(sp_dataformat
)) * sp_width
;
830 frame
.data
.resize(stride
* ((sp_height
+ 3) >> 2 << 2));
831 if(framedata
== NULL
)
832 memset(&frame
.data
[0], 0, frame
.data
.size());
834 const unsigned char* _framedata
= reinterpret_cast<const unsigned char*>(framedata
);
835 unsigned extheight
= (sp_height
+ 3) >> 2 << 2;
836 for(unsigned i
= 0; i
< sp_height
; i
++)
837 copy_row(&frame
.data
[(extheight
- i
- 1) * stride
], _framedata
+ srcstride
* i
, sp_width
,
839 for(unsigned i
= sp_height
; i
< extheight
; i
++)
840 memset(&frame
.data
[(extheight
- i
- 1) * stride
], 0, stride
);
843 frame_processing
= false;
844 frame_pointer
= NULL
;
845 frame_cond
.notify_all();
846 frame_mutex
.unlock();
847 frame_buffer
.push_back(frame
);
848 flush_buffers(false);
851 void avi_cscd_dumper::end() throw(std::bad_alloc
, std::runtime_error
)
853 request_flush_buffers(true);
854 //std::cerr << "Locking lock." << std::endl;
856 //std::cerr << "Locked lock." << std::endl;
857 quit_requested
= true;
858 frame_cond
.notify_all();
859 //std::cerr << "Requesting quit" << std::endl;
860 frame_mutex
.unlock();
861 frame_thread
->join();
862 if(avifile_structure
)
866 size_t avi_cscd_dumper::emit_frame(const std::vector
<unsigned char>& data
, bool keyframe
, unsigned level
,
869 size_t nsize
= data
.size();
870 if(previous_frame
.size() != nsize
) {
871 previous_frame
.resize(nsize
);
872 compression_input
.resize(nsize
);
873 //8 bytes for AVI chunk header, 2 bytes for CSCD frame header. 3 bytes for padding.
874 size_t pmaxsize
= compressBound(nsize
) + 13;
875 if(pmaxsize
> compression_output
.size())
876 compression_output
.resize(pmaxsize
);
879 for(size_t i
= 0; i
< nsize
; i
++)
880 compression_input
[i
] = data
[i
] - previous_frame
[i
];
882 memcpy(&compression_input
[0], &data
[0], data
.size());
883 memcpy(&previous_frame
[0], &data
[0], nsize
);
884 uLongf l
= compression_output
.size();
885 compress2(&compression_output
[10], &l
, &compression_input
[0], compression_input
.size(), level
);
889 compression_output
[0] = '0';
890 compression_output
[1] = '0';
891 compression_output
[2] = 'd';
892 compression_output
[3] = 'b'; //strictly speaking, this is wrong, but FCEUX does this when dumping.
893 compression_output
[4] = (l
+ 2);
894 compression_output
[5] = (l
+ 2) >> 8;
895 compression_output
[6] = (l
+ 2) >> 16;
896 compression_output
[7] = (l
+ 2) >> 24;
897 compression_output
[8] = (keyframe
? 0x3 : 0x2) | (level
<< 4);
898 compression_output
[9] = mode
<< 2;
902 size_t avi_cscd_dumper::emit_sound(size_t samples
)
904 size_t packetsize
= 8 + samples
* gp_channel_count
* (gp_audio_16bit
? 2 : 1);
905 size_t towrite
= samples
* gp_channel_count
;
906 if(packetsize
+ 3 > compression_output
.size())
907 compression_output
.resize(packetsize
+ 3);
908 compression_output
[0] = '0';
909 compression_output
[1] = '1';
910 compression_output
[2] = 'w';
911 compression_output
[3] = 'b';
912 compression_output
[4] = (packetsize
- 8);
913 compression_output
[5] = (packetsize
- 8) >> 8;
914 compression_output
[6] = (packetsize
- 8) >> 16;
915 compression_output
[7] = (packetsize
- 8) >> 24;
917 umutex_class
_frame_mutex(frame_mutex
);
918 for(size_t i
= 0; i
< towrite
; i
++) {
919 unsigned short sample
= 0;
920 if(itr
< buffered_sound_samples
* gp_channel_count
)
921 sample
= sound_buffer
[itr
++];
923 compression_output
[8 + 2 * i
+ 1] = (sample
+ 32768) >> 8;
924 compression_output
[8 + 2 * i
+ 0] = (sample
+ 32768);
926 compression_output
[8 + i
] = (sample
+ 32768) >> 8;
928 if(itr
< buffered_sound_samples
* gp_channel_count
) {
929 memmove(&sound_buffer
[0], &sound_buffer
[itr
], sizeof(unsigned short) * (buffered_sound_samples
*
930 gp_channel_count
- itr
));
931 buffered_sound_samples
-= itr
/ gp_channel_count
;
933 buffered_sound_samples
= 0;
934 while(packetsize
& 3)
939 void avi_cscd_dumper::start_segment(unsigned major_seg
, unsigned minor_seg
)
941 struct buffered_frame
& f
= *frame_buffer
.begin();
942 std::ostringstream name
;
943 name
<< dump_prefix
<< "_" << std::setfill('0') << std::setw(4) << major_seg
<< "_" << std::setfill('0')
944 << std::setw(4) << minor_seg
<< ".avi";
945 avifile
.open(name
.str().c_str(), std::ios::out
| std::ios::binary
);
947 throw std::runtime_error("Can't open AVI file");
948 avifile_structure
= new avi_file_structure
;
949 fill_avi_structure(avifile_structure
, (f
.width
+ 3) >> 2 << 2, (f
.height
+ 3) >> 2 << 2, f
.fps_n
,
950 f
.fps_d
, f
.mode
, gp_channel_count
, gp_sampling_rate
, gp_audio_16bit
);
951 avifile_structure
->start_data(avifile
);
952 frame_period_counter
= 0;
955 void avi_cscd_dumper::end_segment()
957 if(!avifile_structure
)
959 avifile_structure
->finish_avi(avifile
);
962 throw std::runtime_error("Can't finish AVI");
964 delete avifile_structure
;
965 avifile_structure
= NULL
;
968 bool avi_cscd_dumper::restart_segment_if_needed(bool force_break
)
970 if(!avifile_structure
) {
971 start_segment(current_major_segment
, next_minor_segment
++);
974 if(sp_max_segment_frames
&& current_major_segment_frames
>= sp_max_segment_frames
) {
976 current_major_segment
++;
977 next_minor_segment
= 0;
978 start_segment(current_major_segment
, next_minor_segment
++);
979 current_major_segment_frames
= 0;
984 start_segment(current_major_segment
, next_minor_segment
++);
987 if(avifile_structure
->size() > AVI_CUTOFF_SIZE
) {
989 start_segment(current_major_segment
, next_minor_segment
++);
995 void avi_cscd_dumper::write_frame_av(size_t samples
)
997 struct buffered_frame
& f
= *frame_buffer
.begin();
998 std::vector
<unsigned char>& data
= f
.data
;
999 bool keyframe
= f
.keyframe
;
1000 unsigned level
= f
.compression_level
;
1001 unsigned mode
= f
.mode
;
1002 bool force_break
= f
.forcebreak
;
1005 bool tmp
= restart_segment_if_needed(force_break
);
1006 keyframe
= keyframe
|| tmp
;
1007 size
= emit_frame(data
, keyframe
, level
, mode
);
1008 emit_frame_stream(size
, keyframe
);
1009 size
= emit_sound(samples
);
1010 emit_sound_stream(size
, samples
);
1011 current_major_segment_frames
++;
1012 frame_buffer
.erase(frame_buffer
.begin());
1015 void avi_cscd_dumper::emit_frame_stream(size_t size
, bool keyframe
)
1017 avifile_structure
->idx1
.add_entry(index_entry(0x62643030UL
, keyframe
? 0x10 : 0,
1018 avifile_structure
->movi
.payload_size
+ 4, size
- 8));
1019 avifile
.write(reinterpret_cast<const char*>(&compression_output
[0]), size
);
1020 avifile_structure
->hdrl
.videotrack
.strh
.add_frames(1);
1021 avifile_structure
->movi
.add_payload(size
);
1024 void avi_cscd_dumper::emit_sound_stream(size_t size
, size_t samples
)
1026 avifile_structure
->idx1
.add_entry(index_entry(0x62773130UL
, 0x10,
1027 avifile_structure
->movi
.payload_size
+ 4, size
- 8));
1028 avifile
.write(reinterpret_cast<const char*>(&compression_output
[0]), size
);
1029 avifile_structure
->hdrl
.audiotrack
.strh
.add_frames(samples
);
1030 avifile_structure
->movi
.add_payload(size
);
1033 size_t avi_cscd_dumper::samples_for_next_frame()
1035 //The average number of samples per frame needs to be:
1036 //samplerate * fps_d / fps_n.
1037 struct buffered_frame
& f
= *frame_buffer
.begin();
1038 unsigned long critical
= static_cast<Uint64
>(gp_sampling_rate
) * f
.fps_d
% f
.fps_n
;
1039 unsigned long ret
= static_cast<Uint64
>(gp_sampling_rate
) * f
.fps_d
/ f
.fps_n
;
1040 if(static_cast<Uint64
>(frame_period_counter
) * critical
% f
.fps_n
< critical
)
1045 void avi_cscd_dumper::flush_buffers(bool forced
)
1047 while(!frame_buffer
.empty()) {
1048 unsigned long s_fps_n
= frame_buffer
.begin()->fps_n
;
1049 size_t samples
= samples_for_next_frame();
1051 size_t asamples
= buffered_sound_samples
;
1052 frame_mutex
.unlock();
1053 if(!forced
&& asamples
< samples
)
1055 write_frame_av(samples
);
1056 frame_period_counter
++;
1057 frame_period_counter
%= s_fps_n
;
1061 void avi_cscd_dumper::request_flush_buffers(bool forced
)
1063 //std::cerr << "Locking lock." << std::endl;
1065 //std::cerr << "Locked lock." << std::endl;
1066 flush_requested
= true;
1067 flush_requested_forced
= forced
;
1068 frame_cond
.notify_all();
1069 //std::cerr << "Requesting buffer flush (" << flush_requested_forced << ")" << std::endl;
1070 frame_mutex
.unlock();
1071 #ifndef ACTUALLY_USE_THREADS
1072 flush_buffers(forced
);
1076 bool avi_cscd_dumper::is_frame_processing() throw()
1078 return frame_processing
;
1081 void avi_cscd_dumper::wait_frame_processing() throw()
1083 umutex_class
_frame_mutex(frame_mutex
);
1084 while(frame_processing
) {
1085 //std::cerr << "Waiting for frame to process." << std::endl;
1086 frame_cond
.wait(_frame_mutex
);
1088 //std::cerr << "Ok, frame processed, returning" << std::endl;
1091 int avi_cscd_dumper::encode_thread()
1094 //std::cerr << "Encoder thread ready." << std::endl;
1097 if(quit_requested
&& !frame_pointer
&& !flush_requested
) {
1098 //std::cerr << "OK, quitting on request." << std::endl;
1101 if(frame_pointer
|| frame_processing
) {
1102 //std::cerr << "Servicing video frame" << std::endl;
1103 frame_mutex
.unlock();
1104 const void* f
= (const void*)frame_pointer
;
1108 if(flush_requested
) {
1109 //std::cerr << "Servicing flush" << std::endl;
1110 frame_mutex
.unlock();
1111 flush_buffers(flush_requested_forced
);
1113 flush_requested
= false;
1115 frame_mutex
.unlock();
1117 umutex_class
_frame_mutex(frame_mutex
);
1118 while(!quit_requested
&& !frame_pointer
&& !flush_requested
&& !frame_processing
) {
1119 //std::cerr << "Waiting for work." << std::endl;
1120 frame_cond
.wait(_frame_mutex
);
1125 frame_mutex
.unlock();
1127 } catch(std::exception
& e
) {
1128 set_capture_error(e
.what());
1133 void avi_cscd_dumper::set_capture_error(const std::string
& err
)
1136 exception_error
= err
;
1137 frame_mutex
.unlock();
1138 exception_error_present
= true;