diff --git a/src/add-ons/media/plugins/ogg/Jamfile b/src/add-ons/media/plugins/ogg/Jamfile index 6ce3aee2fe..e1cc3977b4 100644 --- a/src/add-ons/media/plugins/ogg/Jamfile +++ b/src/add-ons/media/plugins/ogg/Jamfile @@ -2,7 +2,7 @@ SubDir OBOS_TOP src add-ons media plugins ogg ; UsePrivateHeaders media ; -SubDirHdrs $(SUBDIR) libogg ogg ; +SubDirHdrs [ FDirName $(SUBDIR) libogg ] ; Addon ogg : media plugins : OggReaderPlugin.cpp diff --git a/src/add-ons/media/plugins/ogg/OggReaderPlugin.cpp b/src/add-ons/media/plugins/ogg/OggReaderPlugin.cpp index deced43185..e4a0f3a942 100644 --- a/src/add-ons/media/plugins/ogg/OggReaderPlugin.cpp +++ b/src/add-ons/media/plugins/ogg/OggReaderPlugin.cpp @@ -19,15 +19,13 @@ oggReader::oggReader() { TRACE("oggReader::oggReader\n"); - ogg_stream_init(&fOggStreamState,(int)this); - ogg_sync_init(&fOggSyncState); + ogg_sync_init(&fSync); } oggReader::~oggReader() { - ogg_stream_destroy(&fOggStreamState); - ogg_sync_destroy(&fOggSyncState); + ogg_sync_destroy(&fSync); } @@ -42,47 +40,116 @@ status_t oggReader::Sniff(int32 *streamCount) { TRACE("oggReader::Sniff\n"); - - fSeekableSource = dynamic_cast(Reader::Source()); - if (!fSeekableSource) { - TRACE("oggReader::Sniff: not a BPositionIO\n"); - return B_ERROR; - } - fSeekableSource->Seek(0,SEEK_SET); - ogg_sync_state sync; - ogg_sync_init(&sync); - char * buffer = 0; - ssize_t bytes = 0; ogg_page page; - buffer = ogg_sync_buffer(&sync,4096); - bytes = fSeekableSource->Read(buffer,4096); + ogg_sync_pageout(&fSync,&page); // clear the buffer + + char * buffer = ogg_sync_buffer(&fSync,4096); + ssize_t bytes = Source()->Read(buffer,4096); if (bytes < 4096) { TRACE("oggReader::Sniff: Read: not enough: not ogg\n"); - ogg_sync_destroy(&sync); + return B_ERROR; + } + if (ogg_sync_wrote(&fSync,bytes) != 0) { + TRACE("oggReader::Sniff: ogg_sync_wrote failed?: bail\n"); return B_ERROR; } - ogg_sync_wrote(&sync,bytes); - if (bytesogg_sync_pageout(&sync,&page) != 1) { - TRACE("oggReader::Sniff: ogg_sync_pageout error: not ogg\n"); - ogg_sync_destroy(&sync); + switch ((int)ogg_sync_pageout(&fSync,&page)) { + case -1: + TRACE("oggReader::Sniff: ogg_sync_pageout: not synced: not ogg\n"); + return B_ERROR; + case 0: + TRACE("oggReader::Sniff: ogg_sync_pageout: need more data: not ogg\n"); + return B_ERROR; + case 1: + TRACE("oggReader::Sniff: looks like a valid ogg page\n"); + break; + default: + TRACE("oggReader::Sniff: ogg_sync_pageout: unexpected result: bail\n"); return B_ERROR; } + // page sanity checks + if (ogg_page_version(&page) != 0) { + TRACE("oggReader::Sniff: ogg_sync_version: error in page encoding: not ogg\n"); + return B_ERROR; + } + if (ogg_page_continued(&page) != 0) { + TRACE("oggReader::Sniff: ogg_page_continued: continued page: not ogg\n"); + return B_ERROR; + } + if (ogg_page_bos(&page) == 0) { + TRACE("oggReader::Sniff: ogg_page_bos: not beginning of a bitstream: not ogg\n"); + return B_ERROR; + } + // seems like ogg - // TODO: count the streams - *streamCount = 1; - -/* ogg_stream_state stream; - ogg_stream_init(&stream,ogg_page_serial_no(&page); - - ogg_stream_pagein(&stream,&page); - ogg_packet packet; - ogg_stream_packetout(&stream,&packet);*/ - + ogg_stream_state stream; + if (ogg_stream_init(&stream,ogg_page_serialno(&page)) != 0) { + TRACE("oggReader::Sniff: ogg_stream_init: failed: bail\n"); + return B_ERROR; + } + if (ogg_stream_pagein(&stream,&page) != 0) { + TRACE("oggReader::Sniff: ogg_stream_pagein: failed: bail\n"); + return B_ERROR; + } + fStreams[ogg_page_serialno(&page)] = stream; + while (true) { + buffer = ogg_sync_buffer(&fSync,4096); + bytes = Source()->Read(buffer,4096); + if (bytes < 4096) { + TRACE("oggReader::Sniff: Read: not enough: not ogg\n"); + return B_ERROR; + } + if (ogg_sync_wrote(&fSync,bytes) != 0) { + TRACE("oggReader::Sniff: ogg_sync_wrote failed?: bail\n"); + return B_ERROR; + } + int result = ogg_sync_pageout(&fSync,&page); + if (result == -1) { + TRACE("oggReader::Sniff: ogg_sync_pageout: not synced: not ogg\n"); + return B_ERROR; + } else if (result == 0) { + // need more data to complete an ogg page + } else if (result == 1) { + // valid ogg page + if (ogg_page_version(&page) != 0) { + TRACE("oggReader::Sniff: ogg_sync_version: error in page encoding: not ogg\n"); + return B_ERROR; + } + if (ogg_page_bos(&page) == 0) { + // not start of stream + break; + } + // new stream + if (ogg_stream_init(&stream,ogg_page_serialno(&page)) != 0) { + TRACE("oggReader::Sniff: ogg_stream_init: failed: bail\n"); + return B_ERROR; + } + if (ogg_stream_pagein(&stream,&page) != 0) { + TRACE("oggReader::Sniff: ogg_stream_pagein: failed: bail\n"); + return B_ERROR; + } + // we don't check for unique-ness of start pages. we accept duplication. + fStreams[ogg_page_serialno(&page)] = stream; + } else { + TRACE("oggReader::Sniff: ogg_sync_pageout: unexpected result: bail\n"); + return B_ERROR; + } + } + // last page needs to be put into the right stream + ogg_stream_map::iterator i = fStreams.find(ogg_page_serialno(&page)); + if (i == fStreams.end()) { + // the next page doesn't belong to any existing stream? + return B_ERROR; + } + if (ogg_stream_pagein(&i->second,&page) != 0) { + TRACE("oggReader::Sniff: ogg_stream_pagein: failed: bail\n"); + return B_ERROR; + } + *streamCount = fStreams.size(); return B_OK; } - void oggReader::GetFileFormatInfo(media_file_format *mff) { @@ -90,14 +157,11 @@ oggReader::GetFileFormatInfo(media_file_format *mff) | media_file_format::B_KNOWS_ENCODED_VIDEO | media_file_format::B_KNOWS_ENCODED_AUDIO | media_file_format::B_IMPERFECTLY_SEEKABLE; - mff->family = B_OGG_FORMAT_FAMILY; + mff->family = B_MISC_FORMAT_FAMILY; mff->version = 100; strcpy(mff->mime_type, "application/ogg"); strcpy(mff->file_extension, "ogg"); - -// uint8 header[4]; -// Source()->ReadAt(fDataStart, header, sizeof(header)); - strcpy(mff->short_name, "Ogg"); + strcpy(mff->short_name, "Ogg"); strcpy(mff->pretty_name, "Ogg bitstream"); } @@ -106,9 +170,17 @@ status_t oggReader::AllocateCookie(int32 streamNumber, void **cookie) { TRACE("oggReader::AllocateCookie\n"); - + ogg_stream_map::iterator i = fStreams.begin(); + while (streamNumber > 0) { + if (i == fStreams.end()) { + TRACE("oggReader::AllocateCookie: invalid streamNumber: bail\n"); + return B_ERROR; + } + i++; + streamNumber--; + } // store the cookie - *cookie = data; + *cookie = (void*)(&i->second); return B_OK; } @@ -125,6 +197,13 @@ status_t oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration, media_format *format, void **infoBuffer, int32 *infoSize) { + TRACE("oggReader::GetStreamInfo\n"); + ogg_stream_state * stream = static_cast(cookie); + *frameCount = -1; // don't know + *duration = -1; // don't know + // no info + *infoBuffer = 0; + *infoSize = 0; return B_OK; } @@ -134,10 +213,15 @@ oggReader::Seek(void *cookie, uint32 seekTo, int64 *frame, bigtime_t *time) { - if (!fSeekableSource) + TRACE("oggReader::Seek\n"); + BPositionIO * input = dynamic_cast(Source()); + if (input == 0) { + TRACE("oggReader::Seek: not a PositionIO: not seekable\n"); return B_ERROR; + } + ogg_stream_state * stream = static_cast(cookie); + - ogg_sync_reset return B_OK; } @@ -147,6 +231,9 @@ oggReader::GetNextChunk(void *cookie, void **chunkBuffer, int32 *chunkSize, media_header *mediaHeader) { + ogg_stream_state * stream = static_cast(cookie); + + return B_OK; } diff --git a/src/add-ons/media/plugins/ogg/OggReaderPlugin.h b/src/add-ons/media/plugins/ogg/OggReaderPlugin.h index fb57ff6eb8..206a62c5a9 100644 --- a/src/add-ons/media/plugins/ogg/OggReaderPlugin.h +++ b/src/add-ons/media/plugins/ogg/OggReaderPlugin.h @@ -3,9 +3,12 @@ #include "ReaderPlugin.h" #include "ogg/ogg.h" +#include namespace BPrivate { namespace media { +typedef std::map ogg_stream_map; + class oggReader : public Reader { public: @@ -32,12 +35,9 @@ public: void **chunkBuffer, int32 *chunkSize, media_header *mediaHeader); - BPositionIO *Source() { return fSeekableSource; } - private: - BPositionIO * fSeekableSource; - ogg_stream_state fOggStreamState; - ogg_sync_state fOggSyncState; + ogg_sync_state fSync; + ogg_stream_map fStreams; };