lsnes/include/library/ogg.hpp
2012-11-23 03:11:01 +02:00

333 lines
7.7 KiB
C++

#ifndef _library__ogg__hpp__included__
#define _library__ogg__hpp__included__
#include <cstdint>
#include <stdexcept>
#include <vector>
#include <map>
/**
* 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<const uint8_t*, size_t> get_packet(size_t packetno) const throw()
{
if(packetno >= packet_count)
return std::make_pair(reinterpret_cast<const uint8_t*>(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<std::string> 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