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)
|
#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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user