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:
parent
81b05b60f1
commit
e2b605b45c
@ -15,6 +15,24 @@
|
||||
#define TRACE(a...) ((void)0)
|
||||
#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()
|
||||
{
|
||||
TRACE("oggReader::oggReader\n");
|
||||
@ -164,14 +182,38 @@ oggReader::Sniff(int32 *streamCount)
|
||||
return B_ERROR;
|
||||
#endif STRICT_OGG
|
||||
}
|
||||
// save a copy of the packet information
|
||||
unsigned char * buffer = new unsigned char[packet.bytes];
|
||||
fInitialHeaderPackets[serialno] = packet;
|
||||
memcpy(buffer,packet.packet,packet.bytes);
|
||||
fInitialHeaderPackets[serialno].packet = buffer;
|
||||
if (GetPage(&page,4096,short_page) != B_OK) {
|
||||
memcpy(buffer, packet.packet, packet.bytes);
|
||||
packet.packet = buffer;
|
||||
fHeaderPackets[serialno].push_back(packet);
|
||||
fHeaderPacketsLeft[serialno] = getPacketsLeft(&packet);
|
||||
if (GetPage(&page) != B_OK) {
|
||||
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();
|
||||
if (fSeekable) {
|
||||
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 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);
|
||||
}
|
||||
*frameCount = filePositionToFrame(input_length);
|
||||
@ -268,8 +310,13 @@ oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
|
||||
*frameCount = INT64_MAX;
|
||||
*duration = INT64_MAX;
|
||||
}
|
||||
ogg_packet * packet = &fInitialHeaderPackets[stream->serialno];
|
||||
format->SetMetaData((void*)packet,sizeof(ogg_packet));
|
||||
std::vector<ogg_packet> * ogg_packets = &fHeaderPackets[stream->serialno];
|
||||
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;
|
||||
*infoSize = 0;
|
||||
return B_OK;
|
||||
@ -289,9 +336,9 @@ oggReader::Seek(void *cookie,
|
||||
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
|
||||
int position;
|
||||
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
|
||||
position = frameToFilePosition(*frame);
|
||||
position = fPostSniffPosition+frameToFilePosition(*frame);
|
||||
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
|
||||
position = timeToFilePosition(*time);
|
||||
position = fPostSniffPosition+timeToFilePosition(*time);
|
||||
} else {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
@ -4,11 +4,14 @@
|
||||
#include "ReaderPlugin.h"
|
||||
#include "ogg/ogg.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace BPrivate { namespace media {
|
||||
|
||||
typedef std::map<int,ogg_stream_state*> ogg_stream_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
|
||||
{
|
||||
@ -44,7 +47,8 @@ private:
|
||||
off_t fPostSniffPosition;
|
||||
|
||||
ogg_sync_state fSync;
|
||||
ogg_packet_map fInitialHeaderPackets;
|
||||
ogg_packets_map fHeaderPackets;
|
||||
packet_count_map fHeaderPacketsLeft;
|
||||
ogg_stream_map fStreams;
|
||||
ogg_packet_map fPackets;
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <Locker.h>
|
||||
#include <MediaFormats.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <vector>
|
||||
#include "vorbisCodecPlugin.h"
|
||||
|
||||
#define TRACE_THIS 1
|
||||
@ -27,10 +28,6 @@ vorbisDecoder::vorbisDecoder()
|
||||
vorbis_info_init(&fInfo);
|
||||
vorbis_comment_init(&fComment);
|
||||
|
||||
fHeaderPacketParsed = false;
|
||||
fCommentPacketParsed = false;
|
||||
fCodebookPacketParsed = false;
|
||||
|
||||
fStartTime = 0;
|
||||
fFrameSize = 0;
|
||||
fOutputBufferSize = 0;
|
||||
@ -47,79 +44,43 @@ status_t
|
||||
vorbisDecoder::Setup(media_format *inputFormat,
|
||||
const void *infoBuffer, int32 infoSize)
|
||||
{
|
||||
if ((inputFormat->type != B_MEDIA_UNKNOWN_TYPE)
|
||||
&& (inputFormat->type != B_MEDIA_ENCODED_AUDIO)) {
|
||||
TRACE("vorbisDecoder::Setup not called with audio/unknown stream: not vorbis\n");
|
||||
if (inputFormat->type != B_MEDIA_ENCODED_AUDIO) {
|
||||
TRACE("vorbisDecoder::Setup not called with audio stream: not vorbis\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
if (inputFormat->MetaDataSize() == sizeof(ogg_packet)) {
|
||||
if (!fHeaderPacketParsed) {
|
||||
// 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
|
||||
if (inputFormat->u.encoded_audio.encoding != 'vorb') {
|
||||
TRACE("vorbisDecoder::Setup not called with 'vorb' stream: not vorbis\n");
|
||||
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) {
|
||||
// get comment packet
|
||||
if (GetNextChunk((void**)&packet, &size, &mh) != B_OK) {
|
||||
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 (inputFormat->MetaDataSize() != sizeof(std::vector<ogg_packet> *)) {
|
||||
TRACE("vorbisDecoder::Setup not called with ogg_packet<vector> meta data: not vorbis\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
if (!fCodebookPacketParsed) {
|
||||
// get codebook packet
|
||||
if (GetNextChunk((void**)&packet, &size, &mh) != B_OK) {
|
||||
TRACE("vorbisDecoder::Setup: GetNextChunk failed to get codebook\n");
|
||||
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);
|
||||
std::vector<ogg_packet> * packets = (std::vector<ogg_packet> *)inputFormat->MetaData();
|
||||
if (packets->size() != 3) {
|
||||
TRACE("vorbisDecoder::Setup not called with three ogg_packets: not vorbis\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
// 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
|
||||
CopyInfoToEncodedFormat(ioEncodedFormat);
|
||||
|
||||
CopyInfoToEncodedFormat(inputFormat);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -263,7 +224,6 @@ vorbisDecoderPlugin::NewDecoder()
|
||||
status_t
|
||||
vorbisDecoderPlugin::RegisterPlugin()
|
||||
{
|
||||
PublishDecoder("unknown", "vorbis", "vorbis decoder, based on libvorbis");
|
||||
PublishDecoder("audiocodec/vorbis", "vorbis", "vorbis decoder, based on libvorbis");
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ public:
|
||||
status_t Setup(media_format *inputFormat,
|
||||
const void *infoBuffer, int32 infoSize);
|
||||
|
||||
status_t InitializeInput(media_format * ioEncodedFormat);
|
||||
|
||||
status_t NegotiateOutputFormat(media_format *ioDecodedFormat);
|
||||
|
||||
status_t Seek(uint32 seekTo,
|
||||
@ -27,9 +25,6 @@ private:
|
||||
void CopyInfoToEncodedFormat(media_format * format);
|
||||
void CopyInfoToDecodedFormat(media_raw_audio_format * raf);
|
||||
|
||||
bool fHeaderPacketParsed;
|
||||
bool fCommentPacketParsed;
|
||||
bool fCodebookPacketParsed;
|
||||
vorbis_info fInfo;
|
||||
vorbis_comment fComment;
|
||||
vorbis_dsp_state fDspState;
|
||||
|
Loading…
Reference in New Issue
Block a user