#ifndef _library__ogg__hpp__included__ #define _library__ogg__hpp__included__ #include #include #include #include /** * A page in Ogg bitstream. */ class ogg_page { public: /** * Create a new blank page. */ ogg_page() throw(); /** * Create a page, reading a buffer. * * Parameter buffer: The buffer to read. * Parameter advance: The number of bytes in packet is stored here. * Throws std::runtime_error: Bad packet. */ ogg_page(const char* buffer, size_t& advance) throw(std::runtime_error); /** * Scan a buffer for pages. * * Parameter buffer: The buffer to scan. * Parameter bufferlen: The length of buffer. Should be at least 65307, unless there's not that much available. * Parameter eof: If set, assume physical stream ends after this buffer. * Parameter advance: Amount to advance the pointer is stored here. * Returns: True if packet was found, false if not. */ static bool scan(const char* buffer, size_t bufferlen, bool eof, size_t& advance) throw(); /** * Get the continue flag of packet. */ bool get_continue() const throw() { return flag_continue; } /** * Set the continue flag of packet. */ void set_continue(bool c) throw() { flag_continue = c; } /** * Get the BOS flag of packet. */ bool get_bos() const throw() { return flag_bos; } /** * Set the BOS flag of packet. */ void set_bos(bool b) throw() { flag_bos = b; } /** * Get the EOS flag of packet. */ bool get_eos() const throw() { return flag_eos; } /** * Set the EOS flag of packet. */ void set_eos(bool e) throw() { flag_eos = e; } /** * Get the granulepos of packet. */ uint64_t get_granulepos() const throw() { return granulepos; } /** * Set the granulepos of packet. */ void set_granulepos(uint64_t g) throw() { granulepos = g; } /** * Get stream identifier. */ uint32_t get_stream() const throw() { return stream; } /** * Set stream identifier. */ void set_stream(uint32_t s) throw() { stream = s; } /** * Get stream identifier. */ uint32_t get_sequence() const throw() { return sequence; } /** * Set stream identifier. */ void set_sequence(uint32_t s) throw() { sequence = s; } /** * Get number of packets. */ uint8_t get_packet_count() const throw() { return packet_count; } /** * Get the packet. */ std::pair get_packet(size_t packetno) const throw() { if(packetno >= packet_count) return std::make_pair(reinterpret_cast(NULL), 0); else return std::make_pair(data + packets[packetno], packets[packetno + 1] - packets[packetno]); } /** * Get the last packet incomplete flag. */ bool get_last_packet_incomplete() const throw() { return last_incomplete; } /** * Append a complete packet to page. * * Parameter d: The data to append. * Parameter dlen: The length of data to append. * Returns: True on success, false on failure. */ bool append_packet(const uint8_t* d, size_t dlen) throw(); /** * Append a possibly incomplete packet to page. * * Parameter d: The data to append. Adjusted. * Parameter dlen: The length of data to append. Adjusted * Returns: True if write was complete, false if incomplete. */ bool append_packet_incomplete(const uint8_t*& d, size_t& dlen) throw(); /** * Get number of octets it takes to serialize this. */ size_t serialize_size() const throw() { return 27 + segment_count + data_count; } /** * Serialize this packet. * * Parameter buffer: Buffer to serialize to (use serialize_size() to find the size). */ void serialize(char* buffer) const throw(); /** * The special granule pos for nothing. */ const static uint64_t granulepos_none; private: uint8_t version; bool flag_continue; bool flag_bos; bool flag_eos; bool last_incomplete; uint64_t granulepos; uint32_t stream; uint32_t sequence; uint8_t segment_count; uint8_t packet_count; uint16_t data_count; uint8_t data[65025]; uint8_t segments[255]; uint16_t packets[256]; }; /** * Ogg stream reader. */ class ogg_stream_reader { public: /** * Constructor. */ ogg_stream_reader() throw(); /** * Destructor. */ virtual ~ogg_stream_reader() throw(); /** * Read some data. * * Parameter buffer: The buffer to store the data to. * Parameter size: The maximum size to read. * Returns: The number of bytes actually read. */ virtual size_t read(char* buffer, size_t size) throw(std::exception) = 0; /** * Read a page from stream. * * Parameter page: The page is assigned here if successful. * Returns: True if page was obtained, false if not. */ bool get_page(ogg_page& page) throw(std::exception); /** * Set stream to report errors to. * * Parameter strm: The stream. */ void set_errors_to(std::ostream& os); private: ogg_stream_reader(const ogg_stream_reader&); ogg_stream_reader& operator=(const ogg_stream_reader&); void fill_buffer(); void discard_buffer(size_t amount); bool eof; char buffer[65536]; size_t left; std::ostream* errors_to; }; /** * Ogg stream reader based on std::istream. */ class ogg_stream_reader_iostreams : public ogg_stream_reader { public: /** * Constructor. * * Parameter stream: The stream to read the data from. */ ogg_stream_reader_iostreams(std::istream& stream); /** * Destructor. */ ~ogg_stream_reader_iostreams() throw(); size_t read(char* buffer, size_t size) throw(std::exception); private: std::istream& is; }; /** * Ogg stream writer. */ class ogg_stream_writer { public: /** * Constructor. */ ogg_stream_writer() throw(); /** * Destructor. */ virtual ~ogg_stream_writer() throw(); /** * Write data. * * Parameter data: The data to write. * Parameter size: The size to write. */ virtual void write(const char* buffer, size_t size) throw(std::exception) = 0; /** * Write a page to stream. * * Parameter page: The page to write. */ void put_page(const ogg_page& page) throw(std::exception); private: ogg_stream_writer(const ogg_stream_writer&); ogg_stream_writer& operator=(const ogg_stream_writer&); }; /** * Ogg stream writer based on std::istream. */ class ogg_stream_writer_iostreams : public ogg_stream_writer { public: /** * Constructor. * * Parameter stream: The stream to read the data from. */ ogg_stream_writer_iostreams(std::ostream& stream); /** * Destructor. */ ~ogg_stream_writer_iostreams() throw(); void write(const char* buffer, size_t size) throw(std::exception); private: std::ostream& os; }; /** * OggOpus header structure. */ struct oggopus_header { uint8_t version; uint8_t channels; uint16_t preskip; uint32_t rate; int16_t gain; uint8_t map_family; uint8_t streams; uint8_t coupled; uint8_t chanmap[255]; }; /** * OggOpus tags structure */ struct oggopus_tags { std::string vendor; std::vector comments; }; /** * Parse Ogg page as OggOpus header. * * Parameter page: The page to parse. * Returns: Parsed data. * Throws std::runtime_error: Not valid OggOpus header page. */ struct oggopus_header parse_oggopus_header(struct ogg_page& page) throw(std::runtime_error); /** * Serialize OggOpus header as an Ogg page. * * Parameter header: The header. * Returns: The serialized page. * Throws std::runtime_error: Not valid OggOpus header. */ struct ogg_page serialize_oggopus_header(struct oggopus_header& header) throw(std::runtime_error); /** * Parse Ogg page as OggOpus comment. * * Parameter page: The page to parse. * Returns: Parsed data. * Throws std::runtime_error: Not valid OggOpus comment page. */ struct oggopus_tags parse_oggopus_tags(struct ogg_page& page) throw(std::bad_alloc, std::runtime_error); /** * Serialize OggOpus comments as an Ogg page. * * Parameter tags: The comments. * Returns: The serialized page. * Throws std::runtime_error: Not valid OggOpus comments. */ struct ogg_page serialize_oggopus_tags(struct oggopus_tags& tags) throw(std::runtime_error); #endif