ogg/vorbis update to MetaData. ogg update to do codec identification for vorbis, and to meta-data all header packets for each stream

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6169 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty 2004-01-20 00:29:53 +00:00
parent 81b05b60f1
commit e2b605b45c
4 changed files with 92 additions and 86 deletions

View File

@ -15,6 +15,24 @@
#define TRACE(a...) ((void)0) #define TRACE(a...) ((void)0)
#endif #endif
// codec identification
static bool isVorbisPacket(ogg_packet * packet) {
static const char * vorbis = "vorbis";
if ((unsigned)packet->bytes < (sizeof(vorbis)+1)) {
return false;
}
return !memcmp(&packet->packet[1], vorbis, sizeof(vorbis));
}
// codec-dependent packet gobbling for extra header packets
static int getPacketsLeft(ogg_packet * packet) {
if (isVorbisPacket(packet)) {
return 2;
}
return 0;
}
oggReader::oggReader() oggReader::oggReader()
{ {
TRACE("oggReader::oggReader\n"); TRACE("oggReader::oggReader\n");
@ -164,14 +182,38 @@ oggReader::Sniff(int32 *streamCount)
return B_ERROR; return B_ERROR;
#endif STRICT_OGG #endif STRICT_OGG
} }
// save a copy of the packet information
unsigned char * buffer = new unsigned char[packet.bytes]; unsigned char * buffer = new unsigned char[packet.bytes];
fInitialHeaderPackets[serialno] = packet; memcpy(buffer, packet.packet, packet.bytes);
memcpy(buffer,packet.packet,packet.bytes); packet.packet = buffer;
fInitialHeaderPackets[serialno].packet = buffer; fHeaderPackets[serialno].push_back(packet);
if (GetPage(&page,4096,short_page) != B_OK) { fHeaderPacketsLeft[serialno] = getPacketsLeft(&packet);
if (GetPage(&page) != B_OK) {
return B_ERROR; return B_ERROR;
} }
} }
packet_count_map::iterator iter = fHeaderPacketsLeft.begin();
while (iter != fHeaderPacketsLeft.end()) {
int current_serial = iter->first;
while (fHeaderPacketsLeft[current_serial] > 0) {
int serialno = ogg_page_serialno(&page);
if (fHeaderPacketsLeft[serialno] > 0) {
ogg_stream_state * stream = fStreams[serialno];
ogg_packet packet;
ogg_stream_packetout(stream,&packet);
// save a copy of the packet information
unsigned char * buffer = new unsigned char[packet.bytes];
memcpy(buffer, packet.packet, packet.bytes);
packet.packet = buffer;
fHeaderPackets[serialno].push_back(packet);
fHeaderPacketsLeft[serialno]--;
}
if (GetPage(&page) != B_OK) {
return B_ERROR;
}
}
iter++;
}
*streamCount = fStreams.size(); *streamCount = fStreams.size();
if (fSeekable) { if (fSeekable) {
fPostSniffPosition = fSeekable->Seek(0,SEEK_CUR); fPostSniffPosition = fSeekable->Seek(0,SEEK_CUR);
@ -257,7 +299,7 @@ oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
off_t input_length; off_t input_length;
{ {
off_t current_position = fSeekable->Seek(0,SEEK_CUR); off_t current_position = fSeekable->Seek(0,SEEK_CUR);
input_length = fSeekable->Seek(0,SEEK_END); input_length = fSeekable->Seek(0,SEEK_END)-fPostSniffPosition;
fSeekable->Seek(current_position,SEEK_SET); fSeekable->Seek(current_position,SEEK_SET);
} }
*frameCount = filePositionToFrame(input_length); *frameCount = filePositionToFrame(input_length);
@ -268,8 +310,13 @@ oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
*frameCount = INT64_MAX; *frameCount = INT64_MAX;
*duration = INT64_MAX; *duration = INT64_MAX;
} }
ogg_packet * packet = &fInitialHeaderPackets[stream->serialno]; std::vector<ogg_packet> * ogg_packets = &fHeaderPackets[stream->serialno];
format->SetMetaData((void*)packet,sizeof(ogg_packet)); format->SetMetaData((void*)ogg_packets,sizeof(ogg_packets));
if (isVorbisPacket(&(*ogg_packets)[0])) {
format->type = B_MEDIA_ENCODED_AUDIO;
format->u.encoded_audio.encoding
= (media_encoded_audio_format::audio_encoding)'vorb';
}
*infoBuffer = 0; *infoBuffer = 0;
*infoSize = 0; *infoSize = 0;
return B_OK; return B_OK;
@ -289,9 +336,9 @@ oggReader::Seek(void *cookie,
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie); ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
int position; int position;
if (seekTo & B_MEDIA_SEEK_TO_FRAME) { if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
position = frameToFilePosition(*frame); position = fPostSniffPosition+frameToFilePosition(*frame);
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) { } else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
position = timeToFilePosition(*time); position = fPostSniffPosition+timeToFilePosition(*time);
} else { } else {
return B_ERROR; return B_ERROR;
} }

View File

@ -4,11 +4,14 @@
#include "ReaderPlugin.h" #include "ReaderPlugin.h"
#include "ogg/ogg.h" #include "ogg/ogg.h"
#include <map> #include <map>
#include <vector>
namespace BPrivate { namespace media { namespace BPrivate { namespace media {
typedef std::map<int,ogg_stream_state*> ogg_stream_map; typedef std::map<int,ogg_stream_state*> ogg_stream_map;
typedef std::map<int,ogg_packet> ogg_packet_map; typedef std::map<int,ogg_packet> ogg_packet_map;
typedef std::map<int,std::vector<ogg_packet> > ogg_packets_map;
typedef std::map<int,int> packet_count_map;
class oggReader : public Reader class oggReader : public Reader
{ {
@ -44,7 +47,8 @@ private:
off_t fPostSniffPosition; off_t fPostSniffPosition;
ogg_sync_state fSync; ogg_sync_state fSync;
ogg_packet_map fInitialHeaderPackets; ogg_packets_map fHeaderPackets;
packet_count_map fHeaderPacketsLeft;
ogg_stream_map fStreams; ogg_stream_map fStreams;
ogg_packet_map fPackets; ogg_packet_map fPackets;
}; };

View File

@ -4,6 +4,7 @@
#include <Locker.h> #include <Locker.h>
#include <MediaFormats.h> #include <MediaFormats.h>
#include <MediaRoster.h> #include <MediaRoster.h>
#include <vector>
#include "vorbisCodecPlugin.h" #include "vorbisCodecPlugin.h"
#define TRACE_THIS 1 #define TRACE_THIS 1
@ -27,10 +28,6 @@ vorbisDecoder::vorbisDecoder()
vorbis_info_init(&fInfo); vorbis_info_init(&fInfo);
vorbis_comment_init(&fComment); vorbis_comment_init(&fComment);
fHeaderPacketParsed = false;
fCommentPacketParsed = false;
fCodebookPacketParsed = false;
fStartTime = 0; fStartTime = 0;
fFrameSize = 0; fFrameSize = 0;
fOutputBufferSize = 0; fOutputBufferSize = 0;
@ -47,79 +44,43 @@ status_t
vorbisDecoder::Setup(media_format *inputFormat, vorbisDecoder::Setup(media_format *inputFormat,
const void *infoBuffer, int32 infoSize) const void *infoBuffer, int32 infoSize)
{ {
if ((inputFormat->type != B_MEDIA_UNKNOWN_TYPE) if (inputFormat->type != B_MEDIA_ENCODED_AUDIO) {
&& (inputFormat->type != B_MEDIA_ENCODED_AUDIO)) { TRACE("vorbisDecoder::Setup not called with audio stream: not vorbis\n");
TRACE("vorbisDecoder::Setup not called with audio/unknown stream: not vorbis\n");
return B_ERROR; return B_ERROR;
} }
if (inputFormat->MetaDataSize() == sizeof(ogg_packet)) { if (inputFormat->u.encoded_audio.encoding != 'vorb') {
if (!fHeaderPacketParsed) { TRACE("vorbisDecoder::Setup not called with 'vorb' stream: not vorbis\n");
// header packet passed in meta data
ogg_packet * packet = (ogg_packet*)inputFormat->MetaData();
// parse header packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,packet) != 0) {
TRACE("vorbisDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis header\n");
return B_ERROR;
}
fHeaderPacketParsed = true;
}
} else if (inputFormat->MetaDataSize() != 0) {
// unexpected meta data
return B_ERROR; return B_ERROR;
}
return InitializeInput(inputFormat);
}
status_t
vorbisDecoder::InitializeInput(media_format *ioEncodedFormat)
{
ogg_packet * packet;
int32 size;
media_header mh;
if (!fHeaderPacketParsed) {
// get header packet
if (GetNextChunk((void**)&packet, &size, &mh) != B_OK) {
TRACE("vorbisDecoder::Setup: GetNextChunk failed to get comment\n");
return B_ERROR;
}
// parse header packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,packet) != 0) {
TRACE("vorbisDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis header\n");
return B_ERROR;
}
fHeaderPacketParsed = true;
} }
if (!fCommentPacketParsed) { if (inputFormat->MetaDataSize() != sizeof(std::vector<ogg_packet> *)) {
// get comment packet TRACE("vorbisDecoder::Setup not called with ogg_packet<vector> meta data: not vorbis\n");
if (GetNextChunk((void**)&packet, &size, &mh) != B_OK) { return B_ERROR;
TRACE("vorbisDecoder::Setup: GetNextChunk failed to get comment\n");
return B_ERROR;
}
// parse comment packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,packet) != 0) {
TRACE("vorbiseDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis comment\n");
return B_ERROR;
}
fCommentPacketParsed = true;
} }
if (!fCodebookPacketParsed) { std::vector<ogg_packet> * packets = (std::vector<ogg_packet> *)inputFormat->MetaData();
// get codebook packet if (packets->size() != 3) {
if (GetNextChunk((void**)&packet, &size, &mh) != B_OK) { TRACE("vorbisDecoder::Setup not called with three ogg_packets: not vorbis\n");
TRACE("vorbisDecoder::Setup: GetNextChunk failed to get codebook\n"); return B_ERROR;
return B_ERROR;
}
// parse codebook packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,packet) != 0) {
TRACE("vorbiseDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis codebook\n");
return B_ERROR;
}
// initialize decoder
vorbis_synthesis_init(&fDspState,&fInfo);
vorbis_block_init(&fDspState,&fBlock);
} }
// parse header packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,&(*packets)[0]) != 0) {
TRACE("vorbisDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis header\n");
return B_ERROR;
}
// parse comment packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,&(*packets)[1]) != 0) {
TRACE("vorbiseDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis comment\n");
return B_ERROR;
}
// parse codebook packet
if (vorbis_synthesis_headerin(&fInfo,&fComment,&(*packets)[2]) != 0) {
TRACE("vorbiseDecoder::Setup: vorbis_synthesis_headerin failed: not vorbis codebook\n");
return B_ERROR;
}
// initialize decoder
vorbis_synthesis_init(&fDspState,&fInfo);
vorbis_block_init(&fDspState,&fBlock);
// fill out the encoding format // fill out the encoding format
CopyInfoToEncodedFormat(ioEncodedFormat); CopyInfoToEncodedFormat(inputFormat);
return B_OK; return B_OK;
} }
@ -263,7 +224,6 @@ vorbisDecoderPlugin::NewDecoder()
status_t status_t
vorbisDecoderPlugin::RegisterPlugin() vorbisDecoderPlugin::RegisterPlugin()
{ {
PublishDecoder("unknown", "vorbis", "vorbis decoder, based on libvorbis");
PublishDecoder("audiocodec/vorbis", "vorbis", "vorbis decoder, based on libvorbis"); PublishDecoder("audiocodec/vorbis", "vorbis", "vorbis decoder, based on libvorbis");
return B_OK; return B_OK;
} }

View File

@ -11,8 +11,6 @@ public:
status_t Setup(media_format *inputFormat, status_t Setup(media_format *inputFormat,
const void *infoBuffer, int32 infoSize); const void *infoBuffer, int32 infoSize);
status_t InitializeInput(media_format * ioEncodedFormat);
status_t NegotiateOutputFormat(media_format *ioDecodedFormat); status_t NegotiateOutputFormat(media_format *ioDecodedFormat);
status_t Seek(uint32 seekTo, status_t Seek(uint32 seekTo,
@ -27,9 +25,6 @@ private:
void CopyInfoToEncodedFormat(media_format * format); void CopyInfoToEncodedFormat(media_format * format);
void CopyInfoToDecodedFormat(media_raw_audio_format * raf); void CopyInfoToDecodedFormat(media_raw_audio_format * raf);
bool fHeaderPacketParsed;
bool fCommentPacketParsed;
bool fCodebookPacketParsed;
vorbis_info fInfo; vorbis_info fInfo;
vorbis_comment fComment; vorbis_comment fComment;
vorbis_dsp_state fDspState; vorbis_dsp_state fDspState;