lsnes rr1-β10
[lsnes.git] / avi / cscd.cpp
blobd1f0cb49342e89ee2c817d7325652c7452fd4c1c
1 #include "cscd.hpp"
2 #include <zlib.h>
3 #include <cstring>
4 #include <iomanip>
5 #include <sstream>
6 #include <stdexcept>
7 #include <vector>
8 #include <iostream>
9 #include <list>
11 #define AVI_CUTOFF_SIZE 2100000000
13 namespace
15 struct dumper_thread_obj
17 int operator()(avi_cscd_dumper* d)
19 try {
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());
25 return 1;
29 void write8(char* out, unsigned char x)
31 out[0] = x;
34 void write16(char* out, unsigned x)
36 out[0] = x;
37 out[1] = x >> 8;
40 void write32(char* out, unsigned long x)
42 out[0] = x;
43 out[1] = x >> 8;
44 out[2] = x >> 16;
45 out[3] = x >> 24;
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; }
75 unsigned long width;
76 unsigned long height;
77 unsigned planes;
78 unsigned bit_count;
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;
85 unsigned long fps_n;
86 unsigned long fps_d;
87 void serialize(std::ostream& out)
89 std::vector<char> buf;
90 buf.resize(size());
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());
105 if(!out)
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; }
123 unsigned format_tag;
124 unsigned channels;
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;
133 buf.resize(size());
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());
145 if(!out)
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() {}
154 struct stream_header
156 size_t size() { return 72; }
157 unsigned long handler;
158 unsigned long flags;
159 unsigned priority;
160 unsigned language;
161 unsigned long initial_frames;
162 unsigned long start;
163 unsigned long length;
164 unsigned long suggested_buffer_size;
165 unsigned long quality;
166 stream_header()
168 length = 0;
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;
179 buf.resize(size());
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());
200 if(!out)
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(); }
209 stream_header strh;
210 format strf;
211 void serialize(std::ostream& out)
213 std::vector<char> buf;
214 buf.resize(12);
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());
219 if(!out)
220 throw std::runtime_error("Can't write strl");
221 strh.serialize(out, strf);
222 strf.serialize(out);
226 struct avi_header
228 size_t size() { return 64; }
229 unsigned long microsec_per_frame;
230 unsigned long max_bytes_per_sec;
231 unsigned long padding_granularity;
232 unsigned long flags;
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;
239 buf.resize(size());
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());
257 if(!out)
258 throw std::runtime_error("Can't write avih");
262 struct header_list
264 size_t size() { return 12 + avih.size() + videotrack.size() + audiotrack.size(); }
265 avi_header avih;
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;
271 buf.resize(12);
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());
276 if(!out)
277 throw std::runtime_error("Can't write hdrl");
278 avih.serialize(out, videotrack, 2);
279 videotrack.serialize(out);
280 audiotrack.serialize(out);
284 struct movi_chunk
286 unsigned long payload_size;
287 size_t write_offset() { return 12; }
288 size_t size() { return 12 + payload_size; }
290 movi_chunk()
292 payload_size = 0;
295 void add_payload(size_t s)
297 payload_size = payload_size + s;
300 void serialize(std::ostream& out)
302 std::vector<char> buf;
303 buf.resize(12);
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);
309 if(!out)
310 throw std::runtime_error("Can't write movi");
314 struct index_entry
316 size_t size() { return 16; }
317 unsigned long chunk_type;
318 unsigned long flags;
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;
325 flags = _flags;
326 offset = _offset;
327 length = _length;
330 void serialize(std::ostream& out)
332 std::vector<char> buf;
333 buf.resize(16);
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());
339 if(!out)
340 throw std::runtime_error("Can't write index entry");
344 struct idx1_chunk
346 void add_entry(const index_entry& entry) { entries.push_back(entry); }
347 std::list<index_entry> entries;
348 size_t size()
350 size_t s = 8;
351 //Not exactly right, but much faster than the proper way.
352 if(entries.empty())
353 return s;
354 s = s + entries.begin()->size() * entries.size();
355 return s;
358 void serialize(std::ostream& out)
360 std::vector<char> buf;
361 buf.resize(8);
362 write32(&buf[0], 0x31786469UL); //Type.
363 write32(&buf[4], size() - 8);
364 out.write(&buf[0], buf.size());
365 if(!out)
366 throw std::runtime_error("Can't write idx1");
367 for(std::list<index_entry>::iterator i = entries.begin(); i != entries.end(); i++)
368 i->serialize(out);
372 size_t bpp_for_pixtype(enum avi_cscd_dumper::pixelformat pf)
374 switch(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:
378 return 2;
379 case avi_cscd_dumper::PIXFMT_RGB24:
380 case avi_cscd_dumper::PIXFMT_BGR24:
381 return 3;
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:
386 return 4;
387 default:
388 return 0;
392 size_t bps_for_sndtype(enum avi_cscd_dumper::soundformat sf)
394 switch(sf) {
395 case avi_cscd_dumper::SNDFMT_SILENCE:
396 return 0;
397 case avi_cscd_dumper::SNDFMT_SIGNED_8:
398 case avi_cscd_dumper::SNDFMT_UNSIGNED_8:
399 return 1;
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:
406 return 2;
408 return 0;
411 inline unsigned short convert_audio_sample(const char* addr, enum avi_cscd_dumper::soundformat sf)
413 unsigned short a;
414 unsigned short b;
415 unsigned short magic = 258;
416 bool little_endian = (*reinterpret_cast<char*>(&magic) == 2);
417 switch(sf) {
418 case avi_cscd_dumper::SNDFMT_SILENCE:
419 return 32768;
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]);
431 if(little_endian)
432 return b * 256 + a + 32768;
433 else
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]);
442 return a * 256 + b;
443 case avi_cscd_dumper::SNDFMT_UNSIGNED_16NE:
444 a = static_cast<unsigned char>(addr[0]);
445 b = static_cast<unsigned char>(addr[1]);
446 if(little_endian)
447 return b * 256 + a;
448 else
449 return a * 256 + b;
450 case avi_cscd_dumper::SNDFMT_UNSIGNED_16LE:
451 a = static_cast<unsigned char>(addr[0]);
452 b = static_cast<unsigned char>(addr[1]);
453 return a * 256 + b;
455 return 32768;
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++) {
467 switch(pf) {
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];
471 break;
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)];
475 break;
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];
479 break;
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];
485 break;
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];
491 break;
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];
496 break;
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];
501 break;
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(); }
512 header_list hdrl;
513 movi_chunk movi;
514 idx1_chunk idx1;
515 void serialize(std::ostream& out)
517 std::vector<char> buf;
518 buf.resize(12);
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());
523 if(!out)
524 throw std::runtime_error("Can't write AVI header");
525 hdrl.serialize(out);
526 movi.serialize(out);
527 idx1.serialize(out);
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());
537 if(!out)
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);
544 serialize(out);
545 if(!out)
546 throw std::runtime_error("Can't finish AVI");
550 namespace
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;
630 else
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()
660 try {
661 end();
662 } catch(...) {
664 delete frame_thread;
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;
673 sp.fps_d = sp_fps_d;
674 sp.fps_n = sp_fps_n;
675 sp.height = sp_height;
676 sp.keyframe_distance = sp_keyframe_distance;
677 sp.stride = sp_stride;
678 sp.width = sp_width;
679 return sp;
682 void avi_cscd_dumper::set_segment_parameters(const avi_cscd_dumper::segment_parameters& segment) throw(std::bad_alloc,
683 std::runtime_error)
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;
701 else
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)
709 incompatible = true;
710 if(sp_fps_d != segment.fps_d)
711 incompatible = true;
712 if(((sp_width + 3) >> 2) != ((segment.width + 3) >> 2))
713 incompatible = true;
714 if(((sp_height + 3) >> 2) != ((segment.height + 3) >> 2))
715 incompatible = true;
716 if(bpp_for_pixtype(sp_dataformat) == 2 && bpp_for_pixtype(segment.dataformat) != 2)
717 incompatible = true;
718 if(bpp_for_pixtype(sp_dataformat) != 2 && bpp_for_pixtype(segment.dataformat) == 2)
719 incompatible = true;
721 if(incompatible) {
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;
728 } else {
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;
747 frame_mutex.lock();
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;
773 frame_mutex.lock();
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;
794 frame_mutex.lock();
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 REALLY_USE_THREADS
802 _video(framedata);
803 #endif
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);
826 if(frame.keyframe)
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());
833 else {
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,
838 sp_dataformat);
839 for(unsigned i = sp_height; i < extheight; i++)
840 memset(&frame.data[(extheight - i - 1) * stride], 0, stride);
842 frame_mutex.lock();
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;
855 frame_mutex.lock();
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)
863 end_segment();
866 size_t avi_cscd_dumper::emit_frame(const std::vector<unsigned char>& data, bool keyframe, unsigned level,
867 unsigned mode)
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);
878 if(!keyframe)
879 for(size_t i = 0; i < nsize; i++)
880 compression_input[i] = data[i] - previous_frame[i];
881 else
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);
886 //Pad the frame.
887 while((l % 4) != 2)
888 l++;
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;
899 return l + 10;
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;
916 size_t itr = 0;
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++];
922 if(gp_audio_16bit) {
923 compression_output[8 + 2 * i + 1] = (sample + 32768) >> 8;
924 compression_output[8 + 2 * i + 0] = (sample + 32768);
925 } else
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;
932 } else
933 buffered_sound_samples = 0;
934 while(packetsize & 3)
935 packetsize++;
936 return packetsize;
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);
946 if(!avifile)
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)
958 return;
959 avifile_structure->finish_avi(avifile);
960 avifile.flush();
961 if(!avifile)
962 throw std::runtime_error("Can't finish AVI");
963 avifile.close();
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++);
972 return true;
974 if(sp_max_segment_frames && current_major_segment_frames >= sp_max_segment_frames) {
975 end_segment();
976 current_major_segment++;
977 next_minor_segment = 0;
978 start_segment(current_major_segment, next_minor_segment++);
979 current_major_segment_frames = 0;
980 return true;
982 if(force_break) {
983 end_segment();
984 start_segment(current_major_segment, next_minor_segment++);
985 return true;
987 if(avifile_structure->size() > AVI_CUTOFF_SIZE) {
988 end_segment();
989 start_segment(current_major_segment, next_minor_segment++);
990 return true;
992 return false;
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;
1004 size_t size;
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)
1041 ret++;
1042 return ret;
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();
1050 frame_mutex.lock();
1051 size_t asamples = buffered_sound_samples;
1052 frame_mutex.unlock();
1053 if(!forced && asamples < samples)
1054 break;
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;
1064 frame_mutex.lock();
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 REALLY_USE_THREADS
1072 flush_buffers(forced);
1073 #endif
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()
1093 try {
1094 //std::cerr << "Encoder thread ready." << std::endl;
1095 start:
1096 frame_mutex.lock();
1097 if(quit_requested && !frame_pointer && !flush_requested) {
1098 //std::cerr << "OK, quitting on request." << std::endl;
1099 goto end;
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;
1105 _video(f);
1106 frame_mutex.lock();
1108 if(flush_requested) {
1109 //std::cerr << "Servicing flush" << std::endl;
1110 frame_mutex.unlock();
1111 flush_buffers(flush_requested_forced);
1112 frame_mutex.lock();
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);
1123 goto start;
1124 end:
1125 frame_mutex.unlock();
1126 return 0;
1127 } catch(std::exception& e) {
1128 set_capture_error(e.what());
1129 return 1;
1133 void avi_cscd_dumper::set_capture_error(const std::string& err)
1135 frame_mutex.lock();
1136 exception_error = err;
1137 frame_mutex.unlock();
1138 exception_error_present = true;