436b1d183d
These are deprecated in newer C++ versions.
454 lines
9.7 KiB
C++
454 lines
9.7 KiB
C++
#ifndef _library__ogg__hpp__included__
|
|
#define _library__ogg__hpp__included__
|
|
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
namespace ogg
|
|
{
|
|
/**
|
|
* A packet in Ogg bitstream.
|
|
*/
|
|
class packet
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
packet() {}
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
packet(uint64_t granule, bool first, bool last, bool spans, bool eos, bool bos,
|
|
const std::vector<uint8_t>& d);
|
|
/**
|
|
* Is the packet first within its page?
|
|
*/
|
|
bool get_first_page() const throw() { return first_page; }
|
|
/**
|
|
* Is the packet last within its page?
|
|
*/
|
|
bool get_last_page() const throw() { return last_page; }
|
|
/**
|
|
* Is the packet spanning multiple pages?
|
|
*/
|
|
bool get_spans_page() const throw() { return spans_page; }
|
|
/**
|
|
* Is atomic (first, last and on one page)?
|
|
*/
|
|
bool get_atomic() const throw() { return first_page && last_page && !spans_page; }
|
|
/**
|
|
* Get the granule position within page the packet finished at.
|
|
*/
|
|
uint64_t get_granulepos() const throw() { return granulepos; }
|
|
/**
|
|
* Does the page this ends on have EOS set?
|
|
*/
|
|
bool get_on_eos_page() const throw() { return eos_page; }
|
|
/**
|
|
* Does the page this starts on have BOS set?
|
|
*/
|
|
bool get_on_bos_page() const throw() { return bos_page; }
|
|
/**
|
|
* Get the packet data.
|
|
*/
|
|
const std::vector<uint8_t>& get_vector() const throw() { return data; }
|
|
/**
|
|
* Get length of packet data.
|
|
*/
|
|
size_t get_length() const throw() { return data.size(); }
|
|
/**
|
|
* Get packet data.
|
|
*/
|
|
const uint8_t* get_data() const throw() { return &data[0]; }
|
|
private:
|
|
bool first_page;
|
|
bool last_page;
|
|
bool spans_page;
|
|
bool eos_page;
|
|
bool bos_page;
|
|
uint64_t granulepos;
|
|
std::vector<uint8_t> data;
|
|
};
|
|
|
|
/**
|
|
* A page in Ogg bitstream.
|
|
*/
|
|
class page
|
|
{
|
|
public:
|
|
/**
|
|
* Create a new blank page.
|
|
*/
|
|
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.
|
|
*/
|
|
page(const char* buffer, size_t& advance);
|
|
/**
|
|
* 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; }
|
|
/**
|
|
* Get amount of data that can be written as a complete packet.
|
|
*/
|
|
size_t get_max_complete_packet() const throw();
|
|
/**
|
|
* 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();
|
|
/**
|
|
* Get debugging info for stream this page is from.
|
|
*/
|
|
std::string stream_debug_id() const;
|
|
/**
|
|
* Get debugging info for this page.
|
|
*/
|
|
std::string page_debug_id() const;
|
|
/**
|
|
* 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 demuxer.
|
|
*/
|
|
class demuxer
|
|
{
|
|
public:
|
|
/**
|
|
* Create a new demuxer.
|
|
*/
|
|
demuxer(std::ostream& _errors_to);
|
|
/**
|
|
* Demuxer wants a page in?
|
|
*/
|
|
bool wants_page_in() const throw() { return (dpacket == packets && !ended); }
|
|
/**
|
|
* Demuxer wants a packet out?
|
|
*/
|
|
bool wants_packet_out() const throw() { return (dpacket < packets); }
|
|
/**
|
|
* Input a page.
|
|
*/
|
|
bool page_in(const page& p);
|
|
/**
|
|
* Output a packet.
|
|
*/
|
|
void packet_out(packet& pkt);
|
|
/**
|
|
* Discard a packet.
|
|
*/
|
|
void discard_packet();
|
|
private:
|
|
uint32_t inc1(uint32_t x) { return x + 1; }
|
|
uint64_t page_fullseq(uint32_t seq);
|
|
void update_pageseq(uint32_t new_seq);
|
|
bool complain_lost_page(uint32_t new_seq, uint32_t stream);
|
|
void complain_continue_errors(unsigned flags, uint32_t seqno, uint32_t stream, uint32_t pkts,
|
|
uint64_t granule);
|
|
std::ostream& errors_to;
|
|
std::vector<uint8_t> partial;
|
|
bool started_bos;
|
|
bool seen_page;
|
|
bool damaged_packet;
|
|
uint32_t imprint_stream;
|
|
uint32_t page_seq;
|
|
uint32_t page_era;
|
|
page last_page;
|
|
uint32_t dpacket;
|
|
uint32_t packets;
|
|
uint64_t last_granulepos;
|
|
bool ended;
|
|
};
|
|
|
|
/**
|
|
* Ogg muxer.
|
|
*/
|
|
class muxer
|
|
{
|
|
public:
|
|
/**
|
|
* Create a muxer.
|
|
*/
|
|
muxer(uint32_t streamid, uint64_t _seq = 0);
|
|
/**
|
|
* Wants a packet?
|
|
*/
|
|
bool wants_packet_in() const throw();
|
|
/**
|
|
* Packet of this size fits on current page?
|
|
*/
|
|
bool packet_fits(size_t pktsize) const throw();
|
|
/**
|
|
* Has a page to output?
|
|
*/
|
|
bool has_page_out() const throw();
|
|
/**
|
|
* Input a packet.
|
|
*/
|
|
void packet_in(const std::vector<uint8_t>& data, uint64_t granule);
|
|
/**
|
|
* Signal end of stream.
|
|
*/
|
|
void signal_eos();
|
|
/**
|
|
* Output a page.
|
|
*/
|
|
void page_out(page& p);
|
|
private:
|
|
uint32_t strmid;
|
|
page buffer;
|
|
std::vector<uint8_t> buffered;
|
|
size_t written;
|
|
uint64_t seq;
|
|
bool eos_asserted;
|
|
uint64_t granulepos;
|
|
};
|
|
|
|
/**
|
|
* Ogg stream reader.
|
|
*/
|
|
class stream_reader
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
stream_reader() throw();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
virtual ~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) = 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(page& page);
|
|
/**
|
|
* Set stream to report errors to.
|
|
*
|
|
* Parameter strm: The stream.
|
|
*/
|
|
void set_errors_to(std::ostream& os);
|
|
/**
|
|
* Starting offset of last packet returned.
|
|
*/
|
|
uint64_t get_last_offset() { return last_offset; }
|
|
private:
|
|
stream_reader(const stream_reader&);
|
|
stream_reader& operator=(const stream_reader&);
|
|
void fill_buffer();
|
|
void discard_buffer(size_t amount);
|
|
bool eof;
|
|
char buffer[65536];
|
|
size_t left;
|
|
uint64_t last_offset;
|
|
uint64_t start_offset;
|
|
std::ostream* errors_to;
|
|
};
|
|
|
|
/**
|
|
* Ogg stream reader based on std::istream.
|
|
*/
|
|
class stream_reader_iostreams : public stream_reader
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* Parameter stream: The stream to read the data from.
|
|
*/
|
|
stream_reader_iostreams(std::istream& stream);
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~stream_reader_iostreams() throw();
|
|
|
|
size_t read(char* buffer, size_t size);
|
|
private:
|
|
std::istream& is;
|
|
};
|
|
|
|
/**
|
|
* Ogg stream writer.
|
|
*/
|
|
class stream_writer
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
stream_writer() throw();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
virtual ~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) = 0;
|
|
/**
|
|
* Write a page to stream.
|
|
*
|
|
* Parameter page: The page to write.
|
|
*/
|
|
void put_page(const page& page);
|
|
private:
|
|
stream_writer(const stream_writer&);
|
|
stream_writer& operator=(const stream_writer&);
|
|
};
|
|
|
|
/**
|
|
* Ogg stream writer based on std::istream.
|
|
*/
|
|
class stream_writer_iostreams : public stream_writer
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* Parameter stream: The stream to read the data from.
|
|
*/
|
|
stream_writer_iostreams(std::ostream& stream);
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~stream_writer_iostreams() throw();
|
|
|
|
void write(const char* buffer, size_t size);
|
|
private:
|
|
std::ostream& os;
|
|
};
|
|
}
|
|
|
|
#endif
|