From ff17d3553111e15ab49765f2b2e24ceb58d4da20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano?= Date: Tue, 23 Feb 2016 11:21:00 +0100 Subject: [PATCH] partial implementation of ogg::Stream --- src/actions.cc | 1 + src/ogg.cc | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/ogg.h | 17 +++++++---- 3 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 src/ogg.cc diff --git a/src/actions.cc b/src/actions.cc index cc1efd4..fa3c6a8 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -16,6 +16,7 @@ void opustags::list_tags(ogg::Decoder &dec, TagsHandler &handler) break; case ogg::TAGS_READY: handler.list(s->stream.serialno, s->tags); + s->downgrade(); // no more use for it break; default: ; diff --git a/src/ogg.cc b/src/ogg.cc new file mode 100644 index 0000000..9ffff5d --- /dev/null +++ b/src/ogg.cc @@ -0,0 +1,76 @@ +#include "ogg.h" + +#include + +using namespace opustags; + +ogg::Stream::Stream(int streamno) +{ + state = ogg::BEGIN_OF_STREAM; + type = ogg::UNKNOWN_STREAM; + if (ogg_stream_init(&stream, streamno) != 0) + throw std::runtime_error("ogg_stream_init failed"); +} + +ogg::Stream::~Stream() +{ + ogg_stream_clear(&stream); +} + +bool ogg::Stream::page_in(ogg_page &og) +{ + if (state == ogg::RAW_READY) + return true; + if (ogg_stream_pagein(&stream, &og) != 0) + throw std::runtime_error("ogg_stream_pagein failed"); + + if (state == ogg::BEGIN_OF_STREAM || state == ogg::HEADER_READY) { + // We're expecting a header, so we parse it. + return handle_page(); + } else { + // We're past the first two headers. + state = ogg::DATA_READY; + return true; + } +} + +// Read the first packet of the page and parses it. +bool ogg::Stream::handle_page() +{ + ogg_packet op; + int rc = ogg_stream_packetout(&stream, &op); + if (rc < 0) + throw std::runtime_error("ogg_stream_packetout failed"); + else if (rc == 0) // insufficient data + return false; // asking for a new page + // We've read the first packet successfully. + // The headers are supposed to contain only one packet, so this is enough + // for us. Still, we could ensure there are no other packets. + handle_packet(op); + return true; +} + +void ogg::Stream::handle_packet(const ogg_packet &op) +{ + if (state == ogg::BEGIN_OF_STREAM) + parse_header(op); + else if (state == ogg::HEADER_READY) + parse_tags(op); + // else shrug +} +void ogg::Stream::parse_header(const ogg_packet &op) +{ + // TODO +} + +void ogg::Stream::parse_tags(const ogg_packet &op) +{ + // TODO +} + +void ogg::Stream::downgrade() +{ + type = ogg::UNKNOWN_STREAM; + if (state != ogg::BEGIN_OF_STREAM && state != ogg::END_OF_STREAM) + state = RAW_READY; +} diff --git a/src/ogg.h b/src/ogg.h index 740dff0..b301c5c 100644 --- a/src/ogg.h +++ b/src/ogg.h @@ -1,12 +1,11 @@ #pragma once -#include +#include "tags.h" + #include #include #include -#include "tags.h" - namespace opustags { namespace ogg { @@ -30,13 +29,13 @@ namespace ogg // not. struct Stream { - Stream(int serialno); + Stream(int streamno); ~Stream(); // Called by Decoder once a page was read. // Returns true if it's ready, false if it expects more data. // In the latter case, Decoder::read_page will keep reading. - bool page_in(const ogg_page&); + bool page_in(ogg_page&); // Make the stream behave as if it were unknown. // As a consequence, no more effort would be made in extracting data. @@ -61,6 +60,12 @@ namespace ogg // need a new sequence number. ogg_stream_state stream; + + private: + bool handle_page(); + void handle_packet(const ogg_packet&); + void parse_header(const ogg_packet&); + void parse_tags(const ogg_packet&); }; struct Decoder @@ -93,7 +98,7 @@ namespace ogg // needed for write_page. void write_raw_page(const ogg_page&); - void write_tags(int serialno, const Tags&); + void write_tags(int streamno, const Tags&); std::ostream output;