From a84aeaea96a5e659b2a8ebe041cdd45c9f283c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano?= Date: Tue, 23 Feb 2016 14:23:27 +0100 Subject: [PATCH] implement most of ogg::Encoder --- src/actions.cc | 4 +-- src/ogg.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- src/ogg.h | 11 +++++--- 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/actions.cc b/src/actions.cc index fa3c6a8..b5b365f 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -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: diff --git a/src/ogg.cc b/src/ogg.cc index 83ef006..f9b8198 100644 --- a/src/ogg.cc +++ b/src/ogg.cc @@ -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); +} diff --git a/src/ogg.h b/src/ogg.h index d3125d8..21302ac 100644 --- a/src/ogg.h +++ b/src/ogg.h @@ -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 streams; + std::map streams; + + private: + Stream& get_stream(int streamno); + void forward_stream(Stream &in, Stream &out); + void flush_stream(Stream &out); }; } }