getnextchunk

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5758 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2003-12-26 08:15:36 +00:00
parent 8267371e90
commit 439271f084
2 changed files with 111 additions and 94 deletions
+106 -94
View File
@@ -35,116 +35,110 @@ oggReader::Copyright()
return "ogg reader, " B_UTF8_COPYRIGHT " by Andrew Bachmann";
}
status_t
oggReader::GetPage(ogg_page * page, int read_size, bool short_page)
{
ogg_sync_pageout(&fSync,page); // clear the buffer
int result = 0;
while (result == 0) {
char * buffer = ogg_sync_buffer(&fSync,read_size);
ssize_t bytes = Source()->Read(buffer,read_size);
if (bytes < 0) {
TRACE("oggReader::GetPage: Read: error\n");
return B_ERROR;
}
if (ogg_sync_wrote(&fSync,bytes) != 0) {
TRACE("oggReader::GetPage: ogg_sync_wrote failed?: error\n");
return B_ERROR;
}
result = ogg_sync_pageout(&fSync,page);
if (short_page && (result != 0)) {
TRACE("oggReader::GetPage: short page not found: error\n");
return B_ERROR;
}
}
if (result == -1) {
TRACE("oggReader::GetPage: ogg_sync_pageout: not synced: error\n");
return B_ERROR;
}
#ifdef STRICT_OGG
if (ogg_page_version(page) != 0) {
TRACE("oggReader::GetPage: ogg_page_version: error in page encoding: error\n");
return B_ERROR;
}
#endif
long serialno = ogg_page_serialno(page);
if (fStreams.find(serialno) == fStreams.end()) {
// this is an unknown serialno
if (ogg_page_bos(page) == 0) {
TRACE("oggReader::GetPage: non-bos packet with unknown serialno\n");
#ifdef STRICT_OGG
return B_ERROR;
#endif
}
ogg_stream_state stream;
fStreams[serialno] = stream;
if (ogg_stream_init(&fStreams[serialno],serialno) != 0) {
TRACE("oggReader::GetPage: ogg_stream_init failed?: error\n");
return B_ERROR;
}
} else if (ogg_page_bos(page) > 0) {
TRACE("oggReader::GetPage: bos packet with duplicate serialno\n");
#ifdef STRICT_OGG
return B_ERROR;
#else
if (ogg_stream_destroy(&fStreams[serialno]) != 0) {
TRACE("oggReader::GetPage: ogg_stream_destroy failed?: error\n");
return B_ERROR;
}
if (ogg_stream_init(&fStreams[serialno],serialno) != 0) {
TRACE("oggReader::GetPage: ogg_stream_init failed?: error\n");
return B_ERROR;
}
#endif
}
if (ogg_stream_pagein(&fStreams[serialno],page) != 0) {
TRACE("oggReader::Sniff: ogg_stream_pagein: failed: error\n");
return B_ERROR;
}
return B_OK;
}
status_t
oggReader::Sniff(int32 *streamCount)
{
TRACE("oggReader::Sniff\n");
#ifdef STRICT_OGG
bool short_page = true;
#else
bool short_page = false;
#endif
ogg_page page;
ogg_sync_pageout(&fSync,&page); // clear the buffer
if (GetPage(&page,4096,short_page) != B_OK) {
return B_ERROR;
}
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");
return B_ERROR;
}
if (ogg_sync_wrote(&fSync,bytes) != 0) {
TRACE("oggReader::Sniff: ogg_sync_wrote failed?: bail\n");
return B_ERROR;
}
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");
TRACE("oggReader::Sniff: ogg_page_version: error in page encoding: not ogg\n");
return B_ERROR;
}
#ifdef STRICT_OGG
if (ogg_page_bos(&page) == 0) {
TRACE("oggReader::Sniff: ogg_page_bos: not beginning of a bitstream: 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;
}
#endif STRICT_OGG
// seems like ogg
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");
while (ogg_page_bos(&page) > 0) {
if (GetPage(&page,4096,short_page) != B_OK) {
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;
@@ -198,7 +192,8 @@ 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<ogg_stream_state *>(cookie);
// ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
memset(format, 0, sizeof(*format));
*frameCount = -1; // don't know
*duration = -1; // don't know
// no info
@@ -219,7 +214,7 @@ oggReader::Seek(void *cookie,
TRACE("oggReader::Seek: not a PositionIO: not seekable\n");
return B_ERROR;
}
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
// ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
return B_OK;
@@ -232,11 +227,28 @@ oggReader::GetNextChunk(void *cookie,
media_header *mediaHeader)
{
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
while (ogg_stream_packetpeek(stream,NULL) != 1) {
ogg_page page;
do {
if (GetPage(&page) != B_OK) {
return B_ERROR;
}
} while (ogg_page_serialno(&page) != stream->serialno);
}
if (fPackets.find(stream->serialno) == fPackets.end()) {
ogg_packet packet;
fPackets[stream->serialno] = packet;
}
if (ogg_stream_packetout(stream,&fPackets[stream->serialno]) != 1) {
return B_ERROR;
}
*chunkBuffer = (void*)&fPackets[stream->serialno];
*chunkSize = sizeof(ogg_packet);
return B_OK;
}
Reader *
oggReaderPlugin::NewReader()
{
@@ -8,6 +8,7 @@
namespace BPrivate { namespace media {
typedef std::map<int,ogg_stream_state> ogg_stream_map;
typedef std::map<int,ogg_packet> ogg_packet_map;
class oggReader : public Reader
{
@@ -36,8 +37,12 @@ public:
media_header *mediaHeader);
private:
status_t GetPage(ogg_page * page, int read_size = 4*B_PAGE_SIZE,
bool short_page = false);
ogg_sync_state fSync;
ogg_stream_map fStreams;
ogg_packet_map fPackets;
};