examples/sfexamples/oggvorbiscodec/src/VorbisDecoder/VorbisDecoder.cpp

00001 // VorbisDecoder.cpp
00002 //
00003 // Copyright (c) Symbian Software Ltd 2005-2008.  All rights reserved.
00004 //
00005 
00006 #include <e32base.h>
00007 #include <mmf/server/mmfdatabuffer.h>
00008 #include "ivorbiscodec.h" 
00009 #include <oggutil.h>
00010 #include <vorbisinfo.h>
00011 #include "VorbisDecoder.h"
00012 #include "../OggVorbisUtil/OggUtilBody.h"
00013 #include <e32debug.h>
00014 
00015 const TInt KMaxPcmOutFromPacket = 8000;//Maximum pcm data from a single packet.
00016 const TInt KEndOfStreamBytePos = 5;
00017 const TUint KEndOfStreamFlag = 0x0004;
00018 const TInt KInitDataPage = 3;
00019 _LIT8(KOggS, "OggS");
00020 
00021 CVorbisDecoder* CVorbisDecoder::NewL()
00022     {
00023     CVorbisDecoder* self = new(ELeave)CVorbisDecoder;
00024     CleanupStack::PushL(self);
00025     self->ConstructL();
00026     CleanupStack::Pop(self);
00027     return self;
00028     }
00029     
00030 CVorbisDecoder::CVorbisDecoder()
00031     {
00032     }
00033 
00034 void CVorbisDecoder::ConstructL()
00035     {
00036     vorbis_info_init(&iInfo);
00037     vorbis_comment_init(&iComment);
00038     
00039     iSyncState = ogg_sync_create();
00040     
00041     //stream with negative serial indicates it is not initialized. We do this during playing because we 
00042         //get the serial number from the clip.
00043         iStreamState = ogg_stream_create(-1);
00044     }
00045 
00046 CVorbisDecoder::~CVorbisDecoder()
00047     {
00048     if (iState==EReady)
00049         {
00050         vorbis_block_clear(&iBlock);
00051         vorbis_dsp_clear(&iDspState);
00052         }
00053     vorbis_comment_clear(&iComment);
00054     vorbis_info_clear(&iInfo);
00055     ogg_packet_release(&iPacket);
00056     ogg_page_release(&iPage);
00057         ogg_sync_destroy(iSyncState);
00058     ogg_stream_destroy(iStreamState);
00059     }
00060     
00071 void CVorbisDecoder::PacketInL(ogg_packet aPacket)
00072     {
00073     if (iState == EBadStream) 
00074         {
00075         User::Leave(KErrCorrupt);       
00076         }
00077     else if (iState == ENotVorbis) 
00078         {
00079         User::Leave(KErrNotSupported);  
00080         }       
00081         iPacket = aPacket;
00082     if (iState == EInitializing) // not finished reading header yet
00083         {
00084         TInt res = vorbis_synthesis_headerin(&iInfo, &iComment, &iPacket);
00085         if (res < KErrNone) // some error
00086             {
00087             if (res == OV_ENOTVORBIS)
00088                 {
00089                 iState = ENotVorbis;
00090                 User::Leave(KErrNotSupported);
00091                 }
00092             else
00093                 {
00094                 iState = EBadStream;
00095                 User::Leave(KErrCorrupt);
00096                 }
00097             }
00098         ++iPacketCount;
00099         // a vorbis header consists of 3 packets:
00100         if (iPacketCount == 3) 
00101             {
00102             vorbis_synthesis_init(&iDspState, &iInfo);
00103             vorbis_block_init(&iDspState, &iBlock);
00104             iState = EReady;
00105             }
00106         }
00107     else if (iState == EReady)
00108         {
00109         TInt res = vorbis_synthesis(&iBlock, &iPacket, 1);
00110         if (res == KErrNone) 
00111                 {
00112                 vorbis_synthesis_blockin(&iDspState, &iBlock);  
00113                 }
00114         else 
00115                 {
00116                 User::Leave(KErrCorrupt);       
00117                 }
00118         }
00119     else 
00120         {
00121         User::Leave(KErrGeneral);
00122         }
00123     }
00124     
00135 void CVorbisDecoder::PcmOutL(TDes8& aBuf)
00136     {
00137     if (iState == ENotVorbis) 
00138         {
00139         User::Leave(KErrNotSupported);
00140         }
00141     else if (iState == EBadStream) 
00142         {
00143         User::Leave(KErrCorrupt);       
00144         }
00145     else if (iState == EInitializing)
00146         {
00147         aBuf.SetLength(0);
00148         }
00149     else if (iState == EReady)
00150         {
00151             TInt** pcm;
00152         TInt samples = vorbis_synthesis_pcmout(&iDspState, &pcm);
00153         while ( samples > 0)
00154                 {
00155                 TInt bytesPerSample = 2*iInfo.channels; // 16-bit
00156                 if (bytesPerSample == 0)
00157                         {
00158                         User::Leave(KErrCorrupt);       
00159                         }
00160                 TInt data = aBuf.Length();
00161                 TInt newLength = 0;
00162                 if ( data == 0)
00163                         {
00164                         newLength = aBuf.MaxLength();   
00165                         }
00166                     else
00167                             {
00168                             newLength = aBuf.MaxLength() - data;        
00169                             }
00170                 TInt bufSamples = newLength/bytesPerSample; // max samples in aBuf
00171                 TInt toConv = (samples>bufSamples) ? bufSamples : samples;
00172                 TInt length = data + (toConv*bytesPerSample);
00173                 if(length <= aBuf.MaxLength())
00174                         {
00175                         aBuf.SetLength(length); 
00176                         }
00177                     else
00178                             {
00179                             User::Leave(KErrOverflow);  
00180                             }
00181                 TInt16* bufptr = reinterpret_cast<TInt16*>(&aBuf[data + 0]);
00182                 // clip samples to pcm16 and interleave
00183                 for (TInt c=0; c<iInfo.channels; ++c)
00184                     {
00185                     TInt* mono = pcm[c];
00186                     TInt16* dest = &bufptr[c];
00187                     for (TInt i=0; i<toConv; i++)
00188                         {
00189                         TInt s = mono[i]>>9; // pcm values from the decoder are from -1 to 1. Need to transform them
00190                         // to the integer range by multiplying or bitshifting
00191                         // clip just in case
00192                         if (s>KMaxTInt16) //see /libvorbis/examples/decoder_example.c
00193                             {
00194                             s = KMaxTInt16; 
00195                             }
00196                         else if (s<KMinTInt16)
00197                             {
00198                             s = KMinTInt16;
00199                             }
00200                         dest[i*iInfo.channels] = s;
00201                         }
00202                     }
00203                 vorbis_synthesis_read(&iDspState, toConv);
00204                 samples = vorbis_synthesis_pcmout(&iDspState, &pcm);
00205                 }
00206                 }
00207     else 
00208         {
00209         User::Leave(KErrGeneral);       
00210         }
00211     }
00212 
00213 void CVorbisDecoder::Reset()
00214     {
00215     if (iState==EReady)
00216         {
00217         vorbis_block_clear(&iBlock);
00218         vorbis_dsp_clear(&iDspState);
00219         }
00220     vorbis_comment_clear(&iComment);
00221     vorbis_info_clear(&iInfo);
00222     vorbis_info_init(&iInfo);
00223     vorbis_comment_init(&iComment);
00224     iPacketCount = 0;
00225     iPageNumber = 0;
00226     iState = EInitializing;
00227     }
00239 void CVorbisDecoder::DecoderL(const CMMFDataBuffer& aBuf, TDes8& aDstBuf)
00240     {
00241         CMMFDataBuffer& srcBuf = const_cast<CMMFDataBuffer&>(aBuf);//we need this because Status() is not a const function.
00242         if(srcBuf.Status()!= EUnAvailable)
00243                 {
00244                 unsigned char* buf = ogg_sync_bufferin(iSyncState, aBuf.BufferSize());
00245                 TPtr8 bufPtr(buf, 0, aBuf.BufferSize());
00246                 bufPtr.Copy(aBuf.Data());
00247                 ogg_sync_wrote(iSyncState, aBuf.BufferSize());
00248                 if(iPageNumber > KInitDataPage && IsLastPage(srcBuf))
00249                         {
00250                         srcBuf.SetStatus(EUnAvailable);
00251                         }
00252                 }
00253         TInt res = 0;
00254     while(ETrue)
00255             {
00256             res = ogg_stream_packetout(iStreamState, &iPacket);//Find packet
00257                 if (res > 0) //found one
00258                     {
00259                         PacketInL(iPacket);
00260                     if(iState != EInitializing)
00261                         {        
00262                                 PcmOutL(aDstBuf);
00263                                 //Check if destination buffer atleast has 8k space to add pcm data.
00264                         //If not destination buffer is full and send filled buffer.
00265                                 if (aDstBuf.MaxLength() - aDstBuf.Length() < KMaxPcmOutFromPacket) 
00266                                 {
00267                                 break;  
00268                                 }
00269                         }
00270                     }
00271                 else if(res == 0) //no packet in the stream
00272                     {
00273                     //Get the page
00274                     TInt length = ogg_sync_pageseek(iSyncState, &iPage);                    
00275                     if ( length < 0 )
00276                                 {
00277                             continue;   
00278                             }
00279                     else if ( length > 0 ) //we have one so submit into the stream
00280                         {
00281                         if(iPageNumber == 0)//First page should get serial number
00282                                     {
00283                                     ogg_stream_reset_serialno(iStreamState, ogg_page_serialno(&iPage)); 
00284                                     }
00285                         ++iPageNumber;
00286                         
00287                         ogg_stream_pagein(iStreamState, &iPage);
00288                         }
00289                      else
00290                                 {
00291                             break;
00292                                 }
00293                          }
00294             }
00295     }
00296 
00297 TBool CVorbisDecoder::IsLastPage(CMMFDataBuffer& aSrcBuf)
00298         {
00299         if(iPageNumber > KInitDataPage)
00300                 {
00301                 TInt pos = aSrcBuf.Data().Find(KOggS);
00302                 if(pos != KErrNotFound)
00303                         {
00304                         if(pos + KEndOfStreamBytePos < aSrcBuf.BufferSize())
00305                                 {
00306                                 TInt flag = aSrcBuf.Data()[pos + KEndOfStreamBytePos] & KEndOfStreamFlag;
00307                                 if(flag)
00308                                         {
00309                                         return ETrue;
00310                                         }
00311                                 }
00312                         }
00313                 }
00314         return EFalse;
00315         }
00316 //--------------------------------------------------------------------    
00317 //---------------------------- Processor -----------------------------    
00318 //--------------------------------------------------------------------    
00319 
00320 CVorbisDecoderProcessor* CVorbisDecoderProcessor::NewL()
00321     {
00322     CVorbisDecoderProcessor* self = new(ELeave)CVorbisDecoderProcessor;
00323     CleanupStack::PushL(self);
00324     self->ConstructL();
00325     CleanupStack::Pop(self);
00326     return self;
00327     }
00328     
00329 CVorbisDecoderProcessor::CVorbisDecoderProcessor()
00330     {
00331     }
00332     
00333 void CVorbisDecoderProcessor::ConstructL()
00334     {
00335 #ifdef SYMBIAN_SEP_HEAP
00336     User::LeaveIfError(iVorbisChunk.CreateLocal(KInitialChunkSize, KMaxChunkSize, EOwnerThread));
00337     iVorbisHeap = User::ChunkHeap(iVorbisChunk, KMinHeapLength);
00338     iDefaultHeap = &User::Heap();
00339 #endif
00340     VORBIS_TRAPD(leaveErr, iDecoder = CVorbisDecoder::NewL());
00341     User::LeaveIfError(leaveErr);
00342     }
00343     
00344 CVorbisDecoderProcessor::~CVorbisDecoderProcessor()
00345     {
00346 #ifdef SYMBIAN_SEP_HEAP
00347         if(iVorbisHeap)
00348                 {
00349                 User::SwitchHeap(iVorbisHeap);
00350                 }
00351 #endif
00352     delete iDecoder;
00353 #ifdef SYMBIAN_SEP_HEAP
00354         if(iVorbisHeap)
00355                 {
00356                 iVorbisChunk.Close();
00357         User::SwitchHeap(iDefaultHeap);
00358                 }
00359 #endif
00360     }
00361 
00379 void CVorbisDecoderProcessor::ProcessL(const CMMFBuffer& aSource, 
00380                                 CMMFBuffer& aDst,
00381                                 TProcessResult& aRes,
00382                                 TUint& aSourceUsed,
00383                                 TUint& aDestWritten)
00384     {
00385     // check that buffers are instances of CMMFDataBuffer
00386     if (!CMMFBuffer::IsSupportedDataBuffer(aSource.Type())) 
00387         {
00388         User::Leave(KErrNotSupported);
00389         }
00390     if (!CMMFBuffer::IsSupportedDataBuffer(aDst.Type())) 
00391         {
00392         User::Leave(KErrNotSupported);
00393         }
00394     const CMMFDataBuffer& src = static_cast<const CMMFDataBuffer&>(aSource);
00395     if((src.LastBuffer()) && (src.Data().Length() == 0 ))
00396         {
00397         //last buffer and is of length zero. just return
00398         aDestWritten = 0;
00399         aSourceUsed = 0;
00400         aRes = EComplete;
00401         return;
00402         }
00403     CMMFDataBuffer& dstBuf = static_cast<CMMFDataBuffer&>(aDst);
00404     if ((aSource.FrameNumber()<2) && (aSource.FrameNumber()<iLastFrame)) 
00405         {
00406         #ifdef SYMBIAN_SEP_HEAP
00407                         User::SwitchHeap(iVorbisHeap);
00408                 #endif
00409         iDecoder->Reset(); // process header again      
00410         #ifdef SYMBIAN_SEP_HEAP
00411                         iVorbisChunk.Close();
00412                 #endif
00413         }
00414     dstBuf.Data().SetLength(0);
00415     //Send the source buffer to decoder.
00416     VORBIS_TRAPD(leaveErr, iDecoder->DecoderL(src,dstBuf.Data()));
00417         User::LeaveIfError(leaveErr);
00418     aDestWritten = dstBuf.Data().Length();
00419     dstBuf.Data().SetLength(dstBuf.Data().Length());
00420     aSourceUsed = src.Data().Length()-aSource.Position();
00421     aRes = ( aDestWritten==0) ? EDestNotFilled : EComplete ;
00422     iLastFrame = aSource.FrameNumber();
00423         if( aDestWritten==0 && src.LastBuffer() )
00424             { //means end of play
00425             #ifdef SYMBIAN_SEP_HEAP
00426                         RHeap* oldHeap = User::SwitchHeap(iVorbisHeap);
00427                 #endif
00428                 iDecoder->Reset();
00429             #ifdef SYMBIAN_SEP_HEAP
00430                         User::SwitchHeap(oldHeap);
00431                 #endif
00432             }
00433     }
00434     

Generated by  doxygen 1.6.2