implement most of ogg::Encoder

This commit is contained in:
Frédéric Mangano
2016-02-23 14:23:27 +01:00
parent 8d1ea8d32d
commit a84aeaea96
3 changed files with 80 additions and 6 deletions

View File

@ -38,7 +38,7 @@ void opustags::edit_tags(ogg::Decoder &in, ogg::Encoder &out, TagsHandler &handl
s->downgrade();
out.write_raw_page(in.current_page);
} else {
out.write_page(in.current_page);
out.forward(*s);
}
break;
@ -48,7 +48,7 @@ void opustags::edit_tags(ogg::Decoder &in, ogg::Encoder &out, TagsHandler &handl
break;
case ogg::DATA_READY:
out.write_page(in.current_page);
out.forward(*s);
break;
case ogg::RAW_READY:

View File

@ -42,7 +42,7 @@ bool ogg::Stream::page_in(ogg_page &og)
bool ogg::Stream::handle_page()
{
ogg_packet op;
int rc = ogg_stream_packetout(&stream, &op);
int rc = ogg_stream_packetpeek(&stream, &op);
if (rc < 0)
throw std::runtime_error("ogg_stream_packetout failed");
else if (rc == 0) // insufficient data
@ -143,3 +143,72 @@ bool ogg::Decoder::buff()
ogg_sync_wrote(&sync, input->gcount());
return true;
}
////////////////////////////////////////////////////////////////////////////////
// ogg::Encoder
ogg::Encoder::Encoder(std::ostream *out)
: output(out)
{
output->exceptions(std::ifstream::badbit);
}
ogg::Stream& ogg::Encoder::get_stream(int streamno)
{
auto i = streams.find(streamno);
if (i == streams.end())
i = streams.emplace(streamno, Stream(streamno)).first;
return i->second;
}
void ogg::Encoder::forward(ogg::Stream &in)
{
ogg::Stream *out = &get_stream(in.stream.serialno);
forward_stream(in, *out);
flush_stream(*out);
}
void ogg::Encoder::forward_stream(ogg::Stream &in, ogg::Stream &out)
{
int rc;
ogg_packet op;
for (;;) {
rc = ogg_stream_packetout(&in.stream, &op);
if (rc < 0) {
throw std::runtime_error("ogg_stream_packetout failed");
} else if (rc == 0) {
break;
} else {
if (ogg_stream_packetin(&out.stream, &op) != 0)
throw std::runtime_error("ogg_stream_packetin failed");
}
}
}
void ogg::Encoder::flush_stream(ogg::Stream &out)
{
ogg_page og;
if (ogg_stream_flush(&out.stream, &og))
write_raw_page(og);
}
void ogg::Encoder::write_raw_page(const ogg_page &og)
{
output->write((const char*) og.header, og.header_len);
output->write((const char*) og.body, og.body_len);
}
void ogg::Encoder::write_tags(int streamno, const Tags&)
{
ogg_packet op;
op.b_o_s = 0;
op.e_o_s = 0;
op.granulepos = 0;
op.packetno = 1; // TODO ensure it's not 2
// craft the tags
op.bytes = 0;
ogg::Stream *s = &streams.at(streamno); // assume it exists
if (ogg_stream_packetin(&s->stream, &op) != 0)
throw std::runtime_error("ogg_stream_packetin failed");
flush_stream(*s);
}

View File

@ -93,9 +93,9 @@ namespace ogg
struct Encoder
{
Encoder(std::ostream*);
~Encoder();
void write_page(const ogg_page&);
// Copy the input stream's current page.
void forward(Stream &in);
// Write the page without even ensuring its page number is correct.
// It would be an efficient way to copy a stream identically, and also
@ -108,7 +108,12 @@ namespace ogg
// We're gonna need some ogg_stream_state for adjusting the page
// numbers and splitting large packets as it's gotta be done.
std::map<int, ogg_stream_state> streams;
std::map<int, Stream> streams;
private:
Stream& get_stream(int streamno);
void forward_stream(Stream &in, Stream &out);
void flush_stream(Stream &out);
};
}
}