implement ogg::Decoder

This commit is contained in:
Frédéric Mangano
2016-02-23 13:26:22 +01:00
parent ff17d35531
commit 8d1ea8d32d
3 changed files with 83 additions and 7 deletions

View File

@ -37,7 +37,8 @@ namespace opustags {
// header is read.
//
// Use:
// ogg::Decoder dec(std::ifstream("in.ogg"));
// std::ifstream in("in.ogg");
// ogg::Decoder dec(&in);
// TagsLister lister(options);
// list_tags(dec, lister);
//
@ -47,8 +48,10 @@ namespace opustags {
// with the handler's edit method.
//
// Use:
// ogg::Decoder dec(std::ifstream("in.ogg"));
// ogg::Encoder enc(std::ofstream("out.ogg"));
// std::ifstream in("in.ogg");
// ogg::Decoder dec(&in);
// std::ofstream out("out.ogg");
// std::Encoder enc(&out);
// TagsEditor editor(options);
// edit_tags(dec, enc, editor);
//

View File

@ -1,9 +1,13 @@
#include "ogg.h"
#include <stdexcept>
#include <fstream>
using namespace opustags;
////////////////////////////////////////////////////////////////////////////////
// ogg::Stream
ogg::Stream::Stream(int streamno)
{
state = ogg::BEGIN_OF_STREAM;
@ -61,11 +65,14 @@ void ogg::Stream::handle_packet(const ogg_packet &op)
void ogg::Stream::parse_header(const ogg_packet &op)
{
// TODO
// set type
// set state
}
void ogg::Stream::parse_tags(const ogg_packet &op)
{
// TODO
state = TAGS_READY;
}
void ogg::Stream::downgrade()
@ -74,3 +81,65 @@ void ogg::Stream::downgrade()
if (state != ogg::BEGIN_OF_STREAM && state != ogg::END_OF_STREAM)
state = RAW_READY;
}
////////////////////////////////////////////////////////////////////////////////
// ogg::Decoder
ogg::Decoder::Decoder(std::istream *in)
: input(in)
{
input->exceptions(std::ifstream::badbit);
ogg_sync_init(&sync);
}
ogg::Decoder::~Decoder()
{
ogg_sync_clear(&sync);
}
ogg::Stream* ogg::Decoder::read_page()
{
while (page_out()) {
int streamno = ogg_page_serialno(&current_page);
auto i = streams.find(streamno);
if (i == streams.end()) {
// we could check the page number to detect new streams (pageno = 0)
i = streams.emplace(streamno, Stream(streamno)).first;
}
if (i->second.page_in(current_page))
return &(i->second);
}
return NULL; // end of stream
}
// Read the next page and return true on success, false on end of stream.
bool ogg::Decoder::page_out()
{
int rc;
for (;;) {
rc = ogg_sync_pageout(&sync, &current_page);
if (rc < 0) {
throw std::runtime_error("ogg_sync_pageout failed");
} else if (rc == 1) {
break; // page complete
} else if (!buff()) {
// more data required but end of file reached
// TODO check sync.unsynced flag in case we've got an incomplete page
return false;
}
}
return true;
}
// Read data from the stream into the sync's buffer.
bool ogg::Decoder::buff()
{
if (input->eof())
return false;
char *buf = ogg_sync_buffer(&sync, 65536);
if (buf == NULL)
throw std::runtime_error("ogg_sync_buffer failed");
input->read(buf, 65536);
ogg_sync_wrote(&sync, input->gcount());
return true;
}

View File

@ -70,7 +70,7 @@ namespace ogg
struct Decoder
{
Decoder(std::istream&&);
Decoder(std::istream*);
~Decoder();
// Read a page, dispatch it, and return the stream it belongs to.
@ -79,16 +79,20 @@ namespace ogg
// After the end of the file is reached, it returns NULL.
Stream* read_page();
std::istream input;
std::istream *input;
ogg_sync_state sync;
ogg_page current_page;
std::map<int, Stream> streams;
private:
bool page_out();
bool buff();
};
struct Encoder
{
Encoder(std::ostream&&);
Encoder(std::ostream*);
~Encoder();
void write_page(const ogg_page&);
@ -100,7 +104,7 @@ namespace ogg
void write_tags(int streamno, const Tags&);
std::ostream output;
std::ostream *output;
// We're gonna need some ogg_stream_state for adjusting the page
// numbers and splitting large packets as it's gotta be done.