Changeset 408

Show
Ignore:
Timestamp:
04/12/07 01:59:38 (2 years ago)
Author:
dconrad
Message:

Rework the audio decoder to store the input data in our own ringbuffer and do packet-based decoding. Makes it much easier to support new formats.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/FFissionCodec/FFissionDecoder.cpp

    r407 r408  
    4848 
    4949 
    50 FFissionDecoder::FFissionDecoder(UInt32 inInputBufferByteSize) : FFissionCodec(inInputBufferByteSize
     50FFissionDecoder::FFissionDecoder(UInt32 inInputBufferByteSize) : FFissionCodec(0
    5151{ 
    5252        kIntPCMOutFormatFlag = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; 
     
    6262        CAStreamBasicDescription theOutputFormat(kAudioStreamAnyRate, kAudioFormatLinearPCM, 0, 1, 0, 0, 16, kIntPCMOutFormatFlag); 
    6363        AddOutputFormat(theOutputFormat); 
     64         
     65        inputBuffer.Initialize(inInputBufferByteSize); 
     66        outBufUsed = 0; 
     67        outBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; 
     68        outputBuffer = new Byte[outBufSize]; 
    6469} 
    6570 
     
    6873        if (magicCookie) 
    6974                delete[] magicCookie; 
     75         
     76        delete[] outputBuffer; 
    7077} 
    7178 
     
    7683         
    7784        FFissionCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize); 
     85} 
     86 
     87void FFissionDecoder::Uninitialize() 
     88{ 
     89        outBufUsed = 0; 
     90        inputBuffer.Zap(inputBuffer.GetDataAvailable()); 
     91         
     92        FFissionCodec::Uninitialize(); 
     93} 
     94 
     95void FFissionDecoder::Reset() 
     96{ 
     97        outBufUsed = 0; 
     98        inputBuffer.Zap(inputBuffer.GetDataAvailable()); 
     99         
     100        FFissionCodec::Reset(); 
    78101} 
    79102 
     
    122145                                CODEC_THROW(kAudioCodecBadPropertySizeError); 
    123146                        break; 
    124         } 
     147                         
     148                case kAudioCodecPropertyInputBufferSize: 
     149                case kAudioCodecPropertyUsedInputBufferSize: 
     150                        if (ioPropertyDataSize != sizeof(UInt32)) 
     151                                CODEC_THROW(kAudioCodecBadPropertySizeError); 
     152                        break; 
     153        } 
     154         
    125155        switch (inPropertyID) { 
    126156                case kAudioCodecPropertyNameCFString: 
     
    128158                        *(CFStringRef*)outPropertyData = name; 
    129159                        break;  
     160                         
     161                case kAudioCodecPropertyInputBufferSize: 
     162                        *reinterpret_cast<UInt32*>(outPropertyData) = inputBuffer.GetBufferByteSize(); 
     163                        break; 
     164                         
     165                case kAudioCodecPropertyUsedInputBufferSize: 
     166                        *reinterpret_cast<UInt32*>(outPropertyData) = inputBuffer.GetDataAvailable(); 
     167                        break; 
    130168                         
    131169                default: 
     
    203241} 
    204242 
     243void FFissionDecoder::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize,  
     244                                                                          UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription) 
     245{ 
     246        const Byte *inData = (const Byte *)inInputData; 
     247         
     248        if (inPacketDescription && ioNumberPackets) { 
     249                for (int i = 0; i < ioNumberPackets; i++) { 
     250                        UInt32 packetSize = inPacketDescription[i].mDataByteSize; 
     251                        inputBuffer.In(inData + inPacketDescription[i].mStartOffset, packetSize); 
     252                } 
     253        } else { 
     254                // no packet description, assume cbr 
     255                UInt32 amountToCopy = FFMIN(mInputFormat.mBytesPerPacket * ioNumberPackets, ioInputDataByteSize); 
     256                UInt32 numPackets = amountToCopy / mInputFormat.mBytesPerPacket; 
     257                 
     258                ioInputDataByteSize = amountToCopy; 
     259                ioNumberPackets = numPackets; 
     260                 
     261                for (int i = 0; i < numPackets; i++) { 
     262                        UInt32 packetSize = mInputFormat.mBytesPerPacket; 
     263                        inputBuffer.In(inData, packetSize); 
     264                        inData += mInputFormat.mBytesPerPacket; 
     265                } 
     266        } 
     267} 
     268 
    205269UInt32 FFissionDecoder::ProduceOutputPackets(void* outOutputData, 
    206                                                                                           UInt32& ioOutputDataByteSize, // number of bytes written to outOutputData 
    207                                                                                           UInt32& ioNumberPackets,  
    208                                                                                           AudioStreamPacketDescription* outPacketDescription) 
    209 
    210         // setup the return value, by assuming that everything is going to work 
    211         UInt32 theAnswer = kAudioCodecProduceOutputPacketSuccess; 
     270                                                                                         UInt32& ioOutputDataByteSize,  // number of bytes written to outOutputData 
     271                                                                                         UInt32& ioNumberPackets,  
     272                                                                                         AudioStreamPacketDescription* outPacketDescription) 
     273
     274        UInt32 ans = kAudioCodecProduceOutputPacketSuccess; 
    212275         
    213276        if (!mIsInitialized) 
    214277                CODEC_THROW(kAudioCodecStateError); 
    215278         
    216         // clamp the number of packets to produce based on what is available in the input buffer 
    217         UInt32 inputPacketSize = avContext->channels * avContext->block_align; 
    218         UInt32 numberOfInputPackets = GetUsedInputBufferByteSize() / inputPacketSize; 
    219          
    220         if (ioNumberPackets < numberOfInputPackets) 
    221         { 
    222                 numberOfInputPackets = ioNumberPackets; 
    223         } 
    224         else if (ioNumberPackets > numberOfInputPackets) 
    225         { 
    226                 ioNumberPackets = numberOfInputPackets; 
    227                  
    228                 //      this also means we need more input to satisfy the request so set the return value 
    229                 theAnswer = kAudioCodecProduceOutputPacketNeedsMoreInputData; 
    230         } 
    231          
    232         UInt32 inputByteSize = numberOfInputPackets * inputPacketSize; 
    233          
    234         if(ioNumberPackets > 0) 
    235         { 
    236                 // make sure that there is enough space in the output buffer for the encoded data 
    237                 // it is an error to ask for more output than you pass in buffer space for 
    238                 UInt32 theOutputByteSize = ioNumberPackets * avContext->frame_size * mOutputFormat.mBytesPerFrame; 
    239                 ThrowIf(ioOutputDataByteSize < theOutputByteSize, static_cast<ComponentResult>(kAudioCodecNotEnoughBufferSpaceError), "ACAppleIMA4Decoder::ProduceOutputPackets: not enough space in the output buffer"); 
    240                  
    241                 // set the return value 
    242                 ioOutputDataByteSize = theOutputByteSize; 
    243                  
    244                 // decode the input data for each channel 
    245                 Byte* theInputData = GetBytes(inputByteSize); 
    246                  
    247                 int out_size = 0; 
    248                 SInt16* theOutputData = reinterpret_cast<SInt16*>(outOutputData); 
    249                  
    250                 int len = avcodec_decode_audio(avContext, theOutputData, &out_size, theInputData, inputByteSize); 
    251                 ioOutputDataByteSize = out_size; 
    252                  
    253                 ConsumeInputData(len); 
    254         } 
    255         else 
    256         { 
    257                 // set the return value since we're not actually doing any work 
    258                 ioOutputDataByteSize = 0; 
    259         } 
    260          
    261         if((theAnswer == kAudioCodecProduceOutputPacketSuccess) && (GetUsedInputBufferByteSize() >= inputPacketSize)) 
    262         { 
    263                 // we satisfied the request, and there's at least one more full packet of data we can decode 
    264                 // so set the return value 
    265                 theAnswer = kAudioCodecProduceOutputPacketSuccessHasMore; 
    266         } 
    267          
    268         return theAnswer; 
     279        UInt32 written = 0; 
     280        ioNumberPackets = 0; 
     281        Byte *outData = (Byte *) outOutputData; 
     282         
     283        // we have leftovers from the last packet, use that first 
     284        if (outBufUsed > 0) { 
     285                int amountToCopy = FFMIN(outBufUsed, ioOutputDataByteSize); 
     286                memcpy(outData, outputBuffer, amountToCopy); 
     287                outBufUsed -= amountToCopy; 
     288                written += amountToCopy; 
     289                 
     290                if (outBufUsed > 0) 
     291                        memmove(outputBuffer, outputBuffer + amountToCopy, outBufUsed); 
     292        } 
     293         
     294        // loop until we satisfy the request or run out of input data 
     295        while (written < ioOutputDataByteSize && inputBuffer.GetNumPackets() > 0) { 
     296                int packetSize = inputBuffer.GetCurrentPacketSize(); 
     297                uint8_t *packet = inputBuffer.GetData(); 
     298                 
     299                // decode one packet to our buffer 
     300                outBufUsed = outBufSize; 
     301                int len = avcodec_decode_audio2(avContext, (int16_t *)outputBuffer, &outBufUsed, packet, packetSize); 
     302                inputBuffer.Zap(len); 
     303                 
     304                if (len < 0) { 
     305                        Codecprintf(NULL, "Error decoding audio frame\n"); 
     306                        inputBuffer.Zap(packetSize); 
     307                        outBufUsed = 0; 
     308                        ioOutputDataByteSize = written; 
     309                        return kAudioCodecProduceOutputPacketFailure; 
     310                } 
     311                 
     312                // copy up to the amount requested 
     313                int amountToCopy = FFMIN(outBufUsed, ioOutputDataByteSize - written); 
     314                memcpy(outData + written, outputBuffer, amountToCopy); 
     315                outBufUsed -= amountToCopy; 
     316                written += amountToCopy; 
     317                ioNumberPackets++; 
     318                 
     319                // and save what's left over 
     320                if (outBufUsed > 0) 
     321                        memmove(outputBuffer, outputBuffer + amountToCopy, outBufUsed); 
     322        } 
     323         
     324        if (written < ioOutputDataByteSize) 
     325                ans = kAudioCodecProduceOutputPacketNeedsMoreInputData; 
     326        else if (outBufUsed > written || inputBuffer.GetNumPackets() > 0) 
     327                // we have more left than what we wrote, or an entire other packet 
     328                ans = kAudioCodecProduceOutputPacketSuccessHasMore; 
     329         
     330        ioOutputDataByteSize = written; 
     331         
     332        return ans; 
    269333} 
    270334 
  • trunk/FFissionCodec/FFissionDecoder.h

    r219 r408  
    2525#include "FFissionCodec.h" 
    2626#include "avcodec.h" 
     27#include "RingBuffer.h" 
    2728 
    2829class FFissionDecoder : public FFissionCodec 
     
    3334         
    3435        virtual void Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize); 
     36        virtual void Uninitialize(); 
     37        virtual void Reset(); 
    3538         
    3639        virtual void GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData); 
     
    4144        virtual UInt32 GetVersion() const; 
    4245 
     46        virtual void AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription); 
    4347        virtual UInt32 ProduceOutputPackets(void* outOutputData, UInt32& ioOutputDataByteSize, UInt32& ioNumberPackets, AudioStreamPacketDescription* outPacketDescription); 
    4448         
     
    4953        Byte *magicCookie; 
    5054        UInt32 magicCookieSize; 
     55         
     56        RingBuffer inputBuffer; 
     57        Byte *outputBuffer; 
     58        int outBufSize; 
     59        int outBufUsed; 
    5160}; 
    5261 
  • trunk/Perian.xcodeproj/project.pbxproj

    r406 r408  
    124124                613CD51E0AD1FB650098A825 /* TextSubCodec.c in Sources */ = {isa = PBXBuildFile; fileRef = 613CD51A0AD1FB650098A825 /* TextSubCodec.c */; }; 
    125125                613CD51F0AD1FB650098A825 /* TextSubCodec.r in Rez */ = {isa = PBXBuildFile; fileRef = 613CD51C0AD1FB650098A825 /* TextSubCodec.r */; }; 
     126                6156986F0BCDA87700E17ADE /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6156986D0BCDA87700E17ADE /* ringbuffer.cpp */; }; 
    126127                61CB11200ACDF3A2007994BD /* Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CB11070ACDF3A2007994BD /* Debug.h */; }; 
    127128                61CB11210ACDF3A2007994BD /* EbmlBinary.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CB11080ACDF3A2007994BD /* EbmlBinary.h */; }; 
     
    514515                613CD51C0AD1FB650098A825 /* TextSubCodec.r */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.rez; path = TextSubCodec.r; sourceTree = "<group>"; }; 
    515516                613CD51D0AD1FB650098A825 /* TextSubCodecDispatch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TextSubCodecDispatch.h; sourceTree = "<group>"; }; 
     517                6156986D0BCDA87700E17ADE /* ringbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ringbuffer.cpp; sourceTree = "<group>"; }; 
     518                6156986E0BCDA87700E17ADE /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; }; 
    516519                61CB10FF0ACDF350007994BD /* libebml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libebml.a; sourceTree = BUILT_PRODUCTS_DIR; }; 
    517520                61CB11070ACDF3A2007994BD /* Debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Debug.h; path = libebml/ebml/Debug.h; sourceTree = "<group>"; }; 
     
    901904                        isa = PBXGroup; 
    902905                        children = ( 
     906                                6156986D0BCDA87700E17ADE /* ringbuffer.cpp */, 
     907                                6156986E0BCDA87700E17ADE /* ringbuffer.h */, 
    903908                                6116E54C0B43C27B0020F1CE /* FFissionCodec.cpp */, 
    904909                                6116E54D0B43C27B0020F1CE /* FFissionCodec.h */, 
     
    15931598                                3DB2BB290B6C92F000416863 /* SSARenderCodec.m in Sources */, 
    15941599                                3DAD32DA0B6DB26100DA0A72 /* StdIOCallback.cpp in Sources */, 
     1600                                6156986F0BCDA87700E17ADE /* ringbuffer.cpp in Sources */, 
    15951601                        ); 
    15961602                        runOnlyForDeploymentPostprocessing = 0;