[xiph-commits] r11273 - in trunk/xiph-qt/CAVorbis: . src
arek at svn.xiph.org
arek at svn.xiph.org
Mon Apr 24 15:28:54 PDT 2006
Author: arek
Date: 2006-04-24 15:28:46 -0700 (Mon, 24 Apr 2006)
New Revision: 11273
Modified:
trunk/xiph-qt/CAVorbis/Info.plist
trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.cpp
trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.h
trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.cpp
trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.h
trunk/xiph-qt/CAVorbis/src/vorbis_versions.h
Log:
Added support for non-zero sample offset on the first ogg page.
Also, applied some small changes suggested by Apple engineers (received
through Steve Nicolai!) regarding problems QT has with VBR codecs :P
Well, we'll see how it works...
Modified: trunk/xiph-qt/CAVorbis/Info.plist
===================================================================
--- trunk/xiph-qt/CAVorbis/Info.plist 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/Info.plist 2006-04-24 22:28:46 UTC (rev 11273)
@@ -6,6 +6,8 @@
<string>English</string>
<key>CFBundleExecutable</key>
<string>CAVorbis</string>
+ <key>CFBundleGetInfoString</key>
+ <string>CoreAudio Vorbis Decoder Component 0.1.5, Copyright © 2005-2006 Arek Korbik</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
@@ -15,11 +17,13 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
- <string>0.1.1</string>
+ <string>0.1.5</string>
<key>CFBundleSignature</key>
<string>adec</string>
<key>CFBundleVersion</key>
- <string>0.1.1</string>
+ <string>0.1.5</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>CoreAudio Vorbis Decoder Component 0.1.5, Copyright © 2005-2006 Arek Korbik</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
Modified: trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.cpp
===================================================================
--- trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.cpp 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.cpp 2006-04-24 22:28:46 UTC (rev 11273)
@@ -6,7 +6,7 @@
* for the actual decoding.
*
*
- * Copyright (c) 2005 Arek Korbik
+ * Copyright (c) 2005-2006 Arek Korbik
*
* This file is part of XiphQT, the Xiph QuickTime Components.
*
@@ -42,7 +42,12 @@
CAOggVorbisDecoder::CAOggVorbisDecoder() :
CAVorbisDecoder(true),
- mFramesBufferedList()
+ mFramesBufferedList(),
+ mSOBuffer(NULL),
+ mSOBufferSize(0), mSOBufferUsed(0),
+ mSOBufferWrapped(0), mSOBufferPackets(0),
+ mSOBufferPages(0), mSOReturned(0),
+ mFirstPageNo(2)
{
CAStreamBasicDescription theInputFormat(kAudioStreamAnyRate, kAudioFormatXiphOggFramedVorbis,
kVorbisBytesPerPacket, kVorbisFramesPerPacket,
@@ -50,7 +55,7 @@
kVorbisBitsPerChannel, kVorbisFormatFlags);
AddInputFormat(theInputFormat);
- mInputFormat.mSampleRate = 44100;
+ mInputFormat.mSampleRate = 44100.0;
mInputFormat.mFormatID = kAudioFormatXiphOggFramedVorbis;
mInputFormat.mFormatFlags = kVorbisFormatFlags;
mInputFormat.mBytesPerPacket = kVorbisBytesPerPacket;
@@ -67,7 +72,7 @@
kAudioFormatFlagsNativeFloatPacked);
AddOutputFormat(theOutputFormat2);
- mOutputFormat.mSampleRate = 44100;
+ mOutputFormat.mSampleRate = 44100.0;
mOutputFormat.mFormatID = kAudioFormatLinearPCM;
mOutputFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
mOutputFormat.mBytesPerPacket = 8;
@@ -81,6 +86,9 @@
{
if (mCompressionInitialized)
ogg_stream_clear(&mO_st);
+
+ if (mSOBuffer)
+ delete[] mSOBuffer;
}
void CAOggVorbisDecoder::SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat)
@@ -99,7 +107,8 @@
UInt32 CAOggVorbisDecoder::ProduceOutputPackets(void* outOutputData, UInt32& ioOutputDataByteSize, UInt32& ioNumberPackets,
AudioStreamPacketDescription* outPacketDescription)
{
- dbg_printf(" >> [%08lx] CAOggVorbisDecoder :: ProduceOutputPackets(%ld [%ld])\n", (UInt32) this, ioNumberPackets, ioOutputDataByteSize);
+ dbg_printf(" >> [%08lx] CAOggVorbisDecoder :: ProduceOutputPackets(%ld [%ld]) (%ld, %ld, %ld; %ld[%ld])\n",
+ (UInt32) this, ioNumberPackets, ioOutputDataByteSize, mSOBufferSize, mSOBufferUsed, mSOReturned, mSOBufferPages, mSOBufferPackets);
UInt32 ret = kAudioCodecProduceOutputPacketSuccess;
if (mFramesBufferedList.empty()) {
@@ -117,40 +126,133 @@
UInt32 vorbis_total_returned_data = 0;
Byte *the_data = static_cast<Byte*> (outOutputData);
- while (true) {
- UInt32 vorbis_return = CAVorbisDecoder::ProduceOutputPackets(the_data, vorbis_returned_data, vorbis_packets, NULL);
- if (vorbis_return == kAudioCodecProduceOutputPacketSuccess || vorbis_return == kAudioCodecProduceOutputPacketSuccessHasMore) {
- if (vorbis_packets > 0)
- mFramesBufferedList.front() -= vorbis_packets;
+ if (mSOBuffer != NULL) {
+ dbg_printf(" + SOBuffering output\n");
+ /* stream/sample offset buffer not empty - must be beginning of the stream */
+ if (mSOBufferUsed == 0) {
+ /* fill the buffer first */
+ the_data = mSOBuffer;
+ vorbis_packets = mSOBufferPackets;
+ vorbis_returned_data = mSOBufferSize;
- if (mFramesBufferedList.front() <= 0) {
- ogg_packets++;
+ while (true) {
+ UInt32 vorbis_return = CAVorbisDecoder::ProduceOutputPackets(the_data, vorbis_returned_data, vorbis_packets, NULL);
+ if (vorbis_return == kAudioCodecProduceOutputPacketSuccess ||
+ vorbis_return == kAudioCodecProduceOutputPacketSuccessHasMore ||
+ vorbis_return == kAudioCodecProduceOutputPacketNeedsMoreInputData) {
+ vorbis_total_returned_data += vorbis_returned_data;
+
+ if (vorbis_return == kAudioCodecProduceOutputPacketSuccess || vorbis_return == kAudioCodecProduceOutputPacketNeedsMoreInputData)
+ {
+ /* ok, all data decoded */
+ mSOBufferUsed = vorbis_total_returned_data;
+ if (vorbis_total_returned_data > mSOBufferSize) {
+ mSOBufferWrapped = vorbis_total_returned_data % mSOBufferSize;
+ mSOBufferUsed = mSOBufferSize;
+ } else if (vorbis_total_returned_data < mSOBufferSize) {
+ BlockZero(mSOBuffer + mSOBufferUsed, mSOBufferSize - mSOBufferUsed);
+ mSOBufferWrapped = mSOBufferUsed;
+ }
+ the_data = static_cast<Byte*> (outOutputData);
+ break;
+ } else {
+ if (vorbis_total_returned_data < mSOBufferSize) {
+ the_data += vorbis_returned_data;
+ mSOBufferUsed = vorbis_total_returned_data;
+ vorbis_returned_data = mSOBufferSize - mSOBufferUsed;
+ } else {
+ /* buffer filled, but the underlying decoder still has more... */
+ the_data = mSOBuffer;
+ mSOBufferUsed = mSOBufferSize;
+ vorbis_returned_data = mSOBufferSize;
+ }
+ mSOBufferPackets -= vorbis_packets;
+ vorbis_packets = mSOBufferPackets;
+ }
+ } else {
+ ret = kAudioCodecProduceOutputPacketFailure;
+ ioOutputDataByteSize = 0;
+ ioNumberPackets = mSOBufferPackets;
+ break;
+ }
+ }
+ }
+
+ /* buffer filled, return chunk by chunk */
+ if (ret != kAudioCodecProduceOutputPacketFailure) {
+ vorbis_returned_data = mSOBufferSize - mSOReturned;
+ if (vorbis_returned_data > ioOutputDataByteSize)
+ vorbis_returned_data = ioOutputDataByteSize;
+ UInt32 offset = (mSOBufferWrapped + mSOReturned) % mSOBufferSize;
+ Byte *src_data = mSOBuffer + offset;
+ if (offset + vorbis_returned_data > mSOBufferSize) {
+ /* copy in two takes */
+ UInt32 first_chunk_size = mSOBufferSize - offset;
+ BlockMoveData(src_data, the_data, first_chunk_size);
+ BlockMoveData(mSOBuffer, the_data + first_chunk_size, vorbis_returned_data - first_chunk_size);
+ } else {
+ BlockMoveData(src_data, the_data, vorbis_returned_data);
+ }
+ mSOReturned += vorbis_returned_data;
+ ioOutputDataByteSize = vorbis_returned_data;
+ // ioNumberPackets = ioNumberPackets;
+ if (mSOReturned == mSOBufferSize) {
+ /* all data flushed */
+ ret = kAudioCodecProduceOutputPacketSuccess;
+ ioNumberPackets = mSOBufferPages;
mFramesBufferedList.erase(mFramesBufferedList.begin());
+ delete[] mSOBuffer;
+ mSOBufferSize = mSOBufferUsed = mSOBufferWrapped = mSOBufferPackets = mSOBufferPages = mSOReturned = 0;
+ mSOBuffer = NULL;
+ } else {
+ ret = kAudioCodecProduceOutputPacketSuccessHasMore;
+ ogg_packets = ioNumberPackets;
+ if (ogg_packets >= mSOBufferPages) {
+ ogg_packets = 1;
+ }
+ if (mSOBufferPages == 1)
+ ogg_packets = 0;
+ mSOBufferPages -= ogg_packets;
+ ioNumberPackets = ogg_packets;
}
+ }
+ } else {
+ /* normal output without additional buffering */
+ while (true) {
+ UInt32 vorbis_return = CAVorbisDecoder::ProduceOutputPackets(the_data, vorbis_returned_data, vorbis_packets, NULL);
+ if (vorbis_return == kAudioCodecProduceOutputPacketSuccess || vorbis_return == kAudioCodecProduceOutputPacketSuccessHasMore) {
+ if (vorbis_packets > 0)
+ mFramesBufferedList.front() -= vorbis_packets;
- vorbis_total_returned_data += vorbis_returned_data;
+ if (mFramesBufferedList.front() <= 0) {
+ ogg_packets++;
+ mFramesBufferedList.erase(mFramesBufferedList.begin());
+ }
- if (vorbis_total_returned_data == ioOutputDataByteSize || vorbis_return == kAudioCodecProduceOutputPacketSuccess)
- {
- ioNumberPackets = ogg_packets;
- ioOutputDataByteSize = vorbis_total_returned_data;
+ vorbis_total_returned_data += vorbis_returned_data;
- if (!mFramesBufferedList.empty())
- ret = kAudioCodecProduceOutputPacketSuccessHasMore;
- else
- ret = kAudioCodecProduceOutputPacketSuccess;
+ if (vorbis_total_returned_data == ioOutputDataByteSize || vorbis_return == kAudioCodecProduceOutputPacketSuccess)
+ {
+ ioNumberPackets = ogg_packets;
+ ioOutputDataByteSize = vorbis_total_returned_data;
+ if (!mFramesBufferedList.empty())
+ ret = kAudioCodecProduceOutputPacketSuccessHasMore;
+ else
+ ret = kAudioCodecProduceOutputPacketSuccess;
+
+ break;
+ } else {
+ the_data += vorbis_returned_data;
+ vorbis_returned_data = ioOutputDataByteSize - vorbis_total_returned_data;
+ vorbis_packets = mFramesBufferedList.front();
+ }
+ } else {
+ ret = kAudioCodecProduceOutputPacketFailure;
+ ioOutputDataByteSize = vorbis_total_returned_data;
+ ioNumberPackets = ogg_packets;
break;
- } else {
- the_data += vorbis_returned_data;
- vorbis_returned_data = ioOutputDataByteSize - vorbis_total_returned_data;
- vorbis_packets = mFramesBufferedList.front();
}
- } else {
- ret = kAudioCodecProduceOutputPacketFailure;
- ioOutputDataByteSize = vorbis_total_returned_data;
- ioNumberPackets = ogg_packets;
- break;
}
}
@@ -168,12 +270,22 @@
void CAOggVorbisDecoder::BDCUninitialize()
{
mFramesBufferedList.clear();
+
+ delete[] mSOBuffer;
+ mSOBufferSize = mSOBufferUsed = mSOBufferWrapped = mSOBufferPackets = mSOBufferPages = mSOReturned = 0;
+ mSOBuffer = NULL;
+
CAVorbisDecoder::BDCUninitialize();
}
void CAOggVorbisDecoder::BDCReset()
{
mFramesBufferedList.clear();
+
+ delete[] mSOBuffer;
+ mSOBufferSize = mSOBufferUsed = mSOBufferWrapped = mSOBufferPackets = mSOBufferPages = mSOReturned = 0;
+ mSOBuffer = NULL;
+
if (mCompressionInitialized)
ogg_stream_reset(&mO_st);
CAVorbisDecoder::BDCReset();
@@ -188,6 +300,7 @@
void CAOggVorbisDecoder::InPacket(const void* inInputData, const AudioStreamPacketDescription* inPacketDescription)
{
+ dbg_printf(" >> [%08lx] CAOggVorbisDecoder :: InPacket({%ld, %ld})\n", (UInt32) this, inPacketDescription->mDataByteSize, inPacketDescription->mVariableFramesInPacket);
if (!mCompressionInitialized)
CODEC_THROW(kAudioCodecUnspecifiedError);
@@ -217,6 +330,26 @@
}
mFramesBufferedList.push_back(packet_count);
+
+ /* if pageno == FPN from the cookie then this is the first audio page
+ - we need to buffer the audio data from the first page, to be able
+ to apply the stream offset described in Vorbis spec, section A.2 */
+ /* the expected number of audio samples(frames) should be less than
+ some reasonable value, like 255 * 8192:
+ (max packets per ogg page * max size of a vorbis block) */
+ if (ogg_page_pageno(&op) == mFirstPageNo && inPacketDescription->mVariableFramesInPacket > 0 && inPacketDescription->mVariableFramesInPacket < (255 * 8192)) {
+ mSOBufferSize = inPacketDescription->mVariableFramesInPacket * mOutputFormat.mBytesPerFrame;
+ if (mSOBuffer)
+ delete[] mSOBuffer;
+ mSOBuffer = new Byte[mSOBufferSize];
+ mSOBufferUsed = 0;
+ mSOBufferWrapped = 0;
+ mSOBufferPackets = packet_count;
+ mSOBufferPages = 1; // ?! :/
+ mSOReturned = 0;
+ }
+
+ dbg_printf("<.. [%08lx] CAOggVorbisDecoder :: InPacket(pn: %ld)\n", (UInt32) this, ogg_page_pageno (&op));
}
@@ -227,10 +360,24 @@
ogg_stream_clear(&mO_st);
OggSerialNoAtom *atom = reinterpret_cast<OggSerialNoAtom*> (mCookie);
+ Byte *ptrheader = mCookie + EndianU32_BtoN(atom->size);
+ Byte *cend = mCookie + mCookieSize;
+ CookieAtomHeader *aheader = reinterpret_cast<CookieAtomHeader*> (ptrheader);
if (EndianS32_BtoN(atom->type) == kCookieTypeOggSerialNo && EndianS32_BtoN(atom->size) <= mCookieSize) {
ogg_stream_init(&mO_st, EndianS32_BtoN(atom->serialno));
}
+
+ while (ptrheader < cend) {
+ aheader = reinterpret_cast<CookieAtomHeader*> (ptrheader);
+ ptrheader += EndianU32_BtoN(aheader->size);
+
+ if (EndianS32_BtoN(aheader->type) == kCookieTypeVorbisFirstPageNo && ptrheader <= cend) {
+ mFirstPageNo = EndianU32_BtoN((reinterpret_cast<OggSerialNoAtom*> (aheader))->serialno);
+ dbg_printf(" = [%08lx] CAOggVorbisDecoder :: InitializeCompressionSettings(fpn: %ld)\n", (UInt32) this, mFirstPageNo);
+ break;
+ }
+ }
}
ogg_stream_reset(&mO_st);
Modified: trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.h
===================================================================
--- trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.h 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/src/CAOggVorbisDecoder.h 2006-04-24 22:28:46 UTC (rev 11273)
@@ -4,7 +4,7 @@
* CAOggVorbisDecoder class definition.
*
*
- * Copyright (c) 2005 Arek Korbik
+ * Copyright (c) 2005-2006 Arek Korbik
*
* This file is part of XiphQT, the Xiph QuickTime Components.
*
@@ -62,6 +62,17 @@
ogg_stream_state mO_st;
std::vector<SInt32> mFramesBufferedList;
+
+ /* SampleOffsetBuffer */
+ Byte *mSOBuffer;
+ UInt32 mSOBufferSize;
+ UInt32 mSOBufferUsed;
+ UInt32 mSOBufferWrapped;
+ UInt32 mSOBufferPackets;
+ UInt32 mSOBufferPages;
+ UInt32 mSOReturned;
+
+ UInt32 mFirstPageNo;
};
Modified: trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.cpp
===================================================================
--- trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.cpp 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.cpp 2006-04-24 22:28:46 UTC (rev 11273)
@@ -5,7 +5,7 @@
* codec functionality.
*
*
- * Copyright (c) 2005 Arek Korbik
+ * Copyright (c) 2005-2006 Arek Korbik
*
* This file is part of XiphQT, the Xiph QuickTime Components.
*
@@ -57,7 +57,7 @@
kVorbisBitsPerChannel, kVorbisFormatFlags);
AddInputFormat(theInputFormat);
- mInputFormat.mSampleRate = 44100;
+ mInputFormat.mSampleRate = 44100.0;
mInputFormat.mFormatID = kAudioFormatXiphVorbis;
mInputFormat.mFormatFlags = kVorbisFormatFlags;
mInputFormat.mBytesPerPacket = kVorbisBytesPerPacket;
@@ -74,7 +74,7 @@
kAudioFormatFlagsNativeFloatPacked);
AddOutputFormat(theOutputFormat2);
- mOutputFormat.mSampleRate = 44100;
+ mOutputFormat.mSampleRate = 44100.0;
mOutputFormat.mFormatID = kAudioFormatLinearPCM;
mOutputFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
mOutputFormat.mBytesPerPacket = 8;
@@ -169,7 +169,15 @@
case kAudioCodecPropertyPacketFrameSize:
if(ioPropertyDataSize == sizeof(UInt32))
{
- *reinterpret_cast<UInt32*>(outPropertyData) = kVorbisFramesPerPacket;
+ /* The following line has been changed according to Apple engineers' suggestion
+ I received via Steve Nicolai (in response to *my* bugreport, I think...).
+ (Why don't they just implement the VBR-VFPP properly? *sigh*)
+
+ The original line is left here as I still believe that's how it should be
+ implemented according to the QT docs. (And in case this workaround stops
+ working again one wonderful morning!) */
+ // *reinterpret_cast<UInt32*>(outPropertyData) = kVorbisFramesPerPacket;
+ *reinterpret_cast<UInt32*>(outPropertyData) = kVorbisFramesPerPacketReported;
}
else
{
@@ -177,6 +185,14 @@
}
break;
+ case kAudioCodecPropertyMaximumPacketByteSize:
+ if(ioPropertyDataSize == sizeof(UInt32)) {
+ *reinterpret_cast<UInt32*>(outPropertyData) = kVorbisFormatMaxBytesPerPacket;
+ } else {
+ CODEC_THROW(kAudioCodecBadPropertySizeError);
+ }
+ break;
+
//case kAudioCodecPropertyQualitySetting: ???
#if TARGET_OS_MAC
case kAudioCodecPropertyNameCFString:
@@ -217,6 +233,11 @@
outWritable = false;
break;
+ case kAudioCodecPropertyMaximumPacketByteSize:
+ outPropertyDataSize = sizeof(UInt32);
+ outWritable = false;
+ break;
+
default:
ACBaseCodec::GetPropertyInfo(inPropertyID, outPropertyDataSize, outWritable);
break;
Modified: trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.h
===================================================================
--- trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.h 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/src/CAVorbisDecoder.h 2006-04-24 22:28:46 UTC (rev 11273)
@@ -120,11 +120,15 @@
enum {
kVorbisBytesPerPacket = 0,
kVorbisFramesPerPacket = _SHOULD_BE_ZERO_HERE,
+ kVorbisFramesPerPacketReported = 8192,
kVorbisBytesPerFrame = 0,
kVorbisChannelsPerFrame = 0,
kVorbisBitsPerChannel = 16,
kVorbisFormatFlags = 0,
+ /* Just a funny number, and only roughly valid for the 'Xiph (Ogg-Framed) Vorbis'. */
+ kVorbisFormatMaxBytesPerPacket = 255 * 255,
+
kVorbisDecoderBufferSize = 64 * 1024
};
};
Modified: trunk/xiph-qt/CAVorbis/src/vorbis_versions.h
===================================================================
--- trunk/xiph-qt/CAVorbis/src/vorbis_versions.h 2006-04-24 22:22:14 UTC (rev 11272)
+++ trunk/xiph-qt/CAVorbis/src/vorbis_versions.h 2006-04-24 22:28:46 UTC (rev 11273)
@@ -4,7 +4,7 @@
* The current version of the Vorbis component.
*
*
- * Copyright (c) 2005 Arek Korbik
+ * Copyright (c) 2005-2006 Arek Korbik
*
* This file is part of XiphQT, the Xiph QuickTime Components.
*
@@ -33,9 +33,9 @@
#ifdef DEBUG
-#define kCAVorbis_adec_Version (0x00FF0101)
+#define kCAVorbis_adec_Version (0x00FF0105)
#else
-#define kCAVorbis_adec_Version (0x00000101)
+#define kCAVorbis_adec_Version (0x00000105)
#endif /* DEBUG */
More information about the commits
mailing list