#ifndef _avidump__hpp__included__ #define _avidump__hpp__included__ #include #include #include #include #include #include #ifndef NO_THREADS #include #include #include /** * Class of thread. */ typedef std::thread thread_class; /** * Class of condition variables. */ typedef std::condition_variable cv_class; /** * Class of mutexes. */ typedef std::mutex mutex_class; /** * Class of unique mutexes (for condition variable waiting). */ typedef std::unique_lock umutex_class; #else /** * Class of thread. */ struct thread_class { /** * Does nothing. */ template thread_class(T obj, args... a) {} /** * Does nothing. */ void join() {} }; /** * Class of mutexes. */ typedef struct mutex_class { /** * Does nothing. */ void lock() {} /** * Does nothing. */ void unlock() {} } umutex_class; /** * Class of condition variables. */ struct cv_class { /** * Does nothing. */ void wait(umutex_class& m) {} /** * Does nothing. */ void notify_all() {} }; #endif /** * Size of audio buffer (enough to buffer 3 frames). */ #define AVIDUMPER_AUDIO_BUFFER 4096 /** * Information about frame in AVI. */ struct avi_frame { /** * Constructor. * * parameter _flags: Flags for frame. * parameter _type: AVI type for frame (big-endian!). * parameter _offset: Offset of frame from start of MOVI. * parameter _size: Size of frame data. */ avi_frame(uint32_t _flags, uint32_t _type, uint32_t _offset, uint32_t _size); /** * Write the index entry for frame. * * parameter buf: Buffer to write to. */ void write(uint8_t* buf); /** * Flags. */ uint32_t flags; /** * Chunk type. */ uint32_t type; /** * Chunk offset. */ uint32_t offset; /** * Chunk size. */ uint32_t size; }; /** * Parameters for AVI dumping. */ struct avi_info { /** * Zlib compression level (0-9). */ unsigned compression_level; /** * Audio sampling rate to write to AVI. */ uint32_t audio_sampling_rate; /** * Interval of keyframes (WARNING: >1 gives non-keyframes which AVISource() doesn't like). */ uint32_t keyframe_interval; /** * Maximum number of frames per segement (0 => infinite) */ uint32_t max_frames_per_segment; }; /** * The actual AVI dumper. */ class avidumper { public: avidumper(const std::string& _prefix, struct avi_info parameters); ~avidumper() throw(); /** * Waits for the encode thread. Not needed: Operations that need to synchronize synchronize themselves. */ void wait_idle() throw(); /** * Dump a frame (new segment starts if needed). Pixel byte order is BGRx. * * parameter data: The frame data. * parameter width: Width of frame. * parameter height: Height of frame. * parameter fps_n: Numerator of fps value. * parameter fps_d: Denomerator of fps value. * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Error dumping frame. */ void on_frame(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error); /** * Dump an audio sample * * parameter left: Signed sample for left channel (-32768 - 327678). * parameter right: Signed sample for right channel (-32768 - 327678). * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Error dumping sample. */ void on_sample(short left, short right) throw(std::bad_alloc, std::runtime_error); /** * Notify end of dump. * * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Error closing dump. */ void on_end() throw(std::bad_alloc, std::runtime_error); /** * Causes current thread to become encode thread. Do not call this, the code internally uses it. * * returns: Return status for the thread. */ int encode_thread(); /** * Set capture errored flag. * * parameter err: The error message. */ void set_capture_error(const char* err) throw(); private: void print_summary(std::ostream& str); void on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error); void flush_audio_to(unsigned commit_ptr); void open_and_write_avi_header(uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d); void fixup_avi_header_and_close(); std::ofstream avi_stream; bool capture_error; std::string capture_error_str; bool avi_open; //Global settings. unsigned compression_level; uint32_t audio_sampling_rate; uint32_t keyframe_interval; uint32_t maxframes; //Previous frame. uint16_t pwidth; uint16_t pheight; uint32_t pfps_n; uint32_t pfps_d; //Current segment. uint32_t segment_movi_ptr; uint32_t segment_frames; uint32_t segment_samples; uint32_t segment_last_keyframe; uint32_t current_segment; uint32_t fixup_avi_size; uint32_t fixup_avi_frames; uint32_t fixup_avi_length; uint32_t fixup_avi_a_length; uint32_t fixup_movi_size; std::list segment_chunks; //Global info. std::string prefix; uint64_t total_data; uint64_t total_frames; uint64_t total_samples; //Temporary buffers. std::vector pframe; std::vector tframe; std::vector cframe; short audio_buffer[AVIDUMPER_AUDIO_BUFFER]; unsigned audio_put_ptr; unsigned audio_get_ptr; volatile unsigned audio_commit_ptr; //Protected by frame_mutex. //Multithreading stuff. thread_class* frame_thread; cv_class frame_cond; mutex_class frame_mutex; const uint32_t* mt_data; volatile uint16_t mt_width; volatile uint16_t mt_height; volatile uint32_t mt_fps_n; volatile uint32_t mt_fps_d; volatile bool sigquit; }; #endif