examples/sfexamples/oggvorbiscodec/src/omx/decoder/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 
00017 CVorbisDecoder* CVorbisDecoder::NewL()
00018     {
00019     CVorbisDecoder* self = new(ELeave)CVorbisDecoder;
00020     CleanupStack::PushL(self);
00021     self->ConstructL();
00022     CleanupStack::Pop(self);
00023     return self;
00024     }
00025     
00026 CVorbisDecoder::CVorbisDecoder()
00027     {
00028     }
00029 
00030 void CVorbisDecoder::ConstructL()
00031     {
00032     vorbis_info_init(&iInfo);
00033     vorbis_comment_init(&iComment);
00034     
00035     iSyncState = ogg_sync_create();
00036     
00037     //stream with negative serial indicates it is not initialized. We do this during playing because we 
00038         //get the serial number from the clip.
00039         iStreamState = ogg_stream_create(-1);
00040     }
00041 
00042 CVorbisDecoder::~CVorbisDecoder()
00043     {
00044     if (iState==EReady)
00045         {
00046         vorbis_block_clear(&iBlock);
00047         vorbis_dsp_clear(&iDspState);
00048         }
00049     vorbis_comment_clear(&iComment);
00050     vorbis_info_clear(&iInfo);
00051     ogg_packet_release(&iPacket);
00052     ogg_page_release(&iPage);
00053     ogg_sync_destroy(iSyncState);
00054     ogg_stream_destroy(iStreamState);
00055     }
00056     
00067 void CVorbisDecoder::PacketInL(ogg_packet aPacket)
00068     {
00069     if (iState == EBadStream) 
00070         {
00071         User::Leave(KErrCorrupt);       
00072         }
00073     else if (iState == ENotVorbis) 
00074         {
00075         User::Leave(KErrNotSupported);  
00076         }       
00077         iPacket = aPacket;
00078     if (iState == EInitializing) // not finished reading header yet
00079         {
00080         TInt res = vorbis_synthesis_headerin(&iInfo, &iComment, &iPacket);
00081         if (res < KErrNone) // some error
00082             {
00083             if (res == OV_ENOTVORBIS)
00084                 {
00085                 iState = ENotVorbis;
00086                 User::Leave(KErrNotSupported);
00087                 }
00088             else
00089                 {
00090                 iState = EBadStream;
00091                 User::Leave(KErrCorrupt);
00092                 }
00093             }
00094         ++iPacketCount;
00095         // a vorbis header consists of 3 packets:
00096         if (iPacketCount == 3) 
00097             {
00098             vorbis_synthesis_init(&iDspState, &iInfo);
00099             vorbis_block_init(&iDspState, &iBlock);
00100             iState = EReady;
00101             }
00102         }
00103     else if (iState == EReady)
00104         {
00105         TInt res = vorbis_synthesis(&iBlock, &iPacket, 1);
00106         if (res == KErrNone) 
00107                 {
00108                 vorbis_synthesis_blockin(&iDspState, &iBlock);  
00109                 }
00110         else 
00111                 {
00112                 User::Leave(KErrCorrupt);       
00113                 }
00114         }
00115     else 
00116         {
00117         User::Leave(KErrGeneral);
00118         }
00119     }
00120     
00131 void CVorbisDecoder::PcmOutL(TDes8& aBuf)
00132     {
00133     if (iState == ENotVorbis) 
00134         {
00135         User::Leave(KErrNotSupported);
00136         }
00137     else if (iState == EBadStream) 
00138         {
00139         User::Leave(KErrCorrupt);       
00140         }
00141     else if (iState == EInitializing)
00142         {
00143         aBuf.SetLength(0);
00144         }
00145     else if (iState == EReady)
00146         {
00147             TInt** pcm;
00148         TInt samples = vorbis_synthesis_pcmout(&iDspState, &pcm);
00149         while ( samples > 0)
00150                 {
00151                 TInt bytesPerSample = 2*iInfo.channels; // 16-bit
00152                 if (bytesPerSample == 0)
00153                         {
00154                         User::Leave(KErrCorrupt);       
00155                         }
00156                 TInt data = aBuf.Length();
00157                 TInt newLength = 0;
00158                 if ( data == 0)
00159                         {
00160                         newLength = aBuf.MaxLength();   
00161                         }
00162                     else
00163                             {
00164                             newLength = aBuf.MaxLength() - data;        
00165                             }
00166                 TInt bufSamples = newLength/bytesPerSample; // max samples in aBuf
00167                 TInt toConv = (samples>bufSamples) ? bufSamples : samples;
00168                 TInt length = data + (toConv*bytesPerSample);
00169                 if(length <= aBuf.MaxLength())
00170                         {
00171                         aBuf.SetLength(length); 
00172                         }
00173                     else
00174                             {
00175                             User::Leave(KErrOverflow);  
00176                             }
00177                 TInt16* bufptr = reinterpret_cast<TInt16*>(&aBuf[data + 0]);
00178                 // clip samples to pcm16 and interleave
00179                 for (TInt c=0; c<iInfo.channels; ++c)
00180                     {
00181                     TInt* mono = pcm[c];
00182                     TInt16* dest = &bufptr[c];
00183                     for (TInt i=0; i<toConv; i++)
00184                         {
00185                         TInt s = mono[i]>>9; // pcm values from the decoder are from -1 to 1. Need to transform them
00186                         // to the integer range by multiplying or bitshifting
00187                         // clip just in case
00188                         if (s>KMaxTInt16) //see /libvorbis/examples/decoder_example.c
00189                             {
00190                             s = KMaxTInt16; 
00191                             }
00192                         else if (s<KMinTInt16)
00193                             {
00194                             s = KMinTInt16;
00195                             }
00196                         dest[i*iInfo.channels] = s;
00197                         }
00198                     }
00199                 vorbis_synthesis_read(&iDspState, toConv);
00200                 samples = vorbis_synthesis_pcmout(&iDspState, &pcm);
00201                 }
00202                 }
00203     else 
00204         {
00205         User::Leave(KErrGeneral);       
00206         }
00207     }
00208 
00209 void CVorbisDecoder::Reset()
00210     {
00211     if (iState==EReady)
00212         {
00213         vorbis_block_clear(&iBlock);
00214         vorbis_dsp_clear(&iDspState);
00215         }
00216     vorbis_comment_clear(&iComment);
00217     vorbis_info_clear(&iInfo);
00218     vorbis_info_init(&iInfo);
00219     vorbis_comment_init(&iComment);
00220     iPacketCount = 0;
00221     iState = EInitializing;
00222     }
00234 void CVorbisDecoder::DecoderL(const CMMFDataBuffer& aBuf, TDes8& aDstBuf)
00235     {
00236         CMMFDataBuffer& srcBuf = const_cast<CMMFDataBuffer&>(aBuf);//we need this because Status() is not a const function.
00237         if(srcBuf.Status()!= EUnAvailable)
00238                 {
00239                 unsigned char* buf = ogg_sync_bufferin(iSyncState, aBuf.BufferSize());
00240                 TPtr8 bufPtr(buf, 0, aBuf.BufferSize());
00241                 bufPtr.Copy(aBuf.Data());
00242                 ogg_sync_wrote(iSyncState, aBuf.BufferSize());
00243                 }
00244         TInt res = 0;
00245     while(ETrue)
00246             {
00247             res = ogg_stream_packetout(iStreamState, &iPacket);//Find packet
00248                 if (res > 0) //found one
00249                     {
00250                         PacketInL(iPacket);
00251                     if(iState != EInitializing)
00252                         {        
00253                                 PcmOutL(aDstBuf);
00254                                 //Check if destination buffer atleast has 8k space to add pcm data.
00255                         //If not destination buffer is full and send filled buffer.
00256                                 if (aDstBuf.MaxLength() - aDstBuf.Length() < KMaxPcmOutFromPacket) 
00257                                 {
00258                                 break;  
00259                                 }
00260                         }
00261                     }
00262                 else if(res == 0) //no packet in the stream
00263                     {
00264                     //Get the page
00265                     TInt length = ogg_sync_pageseek(iSyncState, &iPage);                    
00266                     if ( length < 0 )
00267                                 {
00268                             continue;   
00269                             }
00270                     else if ( length > 0 ) //we have one so submit into the stream
00271                         {
00272                         if(iPageNumber == 0)//First page should get serial number
00273                                     {
00274                                     ogg_stream_reset_serialno(iStreamState, ogg_page_serialno(&iPage)); 
00275                                     }
00276                         ++iPageNumber;
00277                         
00278                         ogg_stream_pagein(iStreamState, &iPage);
00279                         }
00280                      else
00281                                 {
00282                             break;
00283                                 }
00284                          }
00285             }
00286     }
00287 
00288 //--------------------------------------------------------------------    
00289 //---------------------------- Processor -----------------------------    
00290 //--------------------------------------------------------------------    
00291 
00292 CVorbisDecoderProcessor* CVorbisDecoderProcessor::NewL()
00293     {
00294     CVorbisDecoderProcessor* self = new(ELeave)CVorbisDecoderProcessor;
00295     CleanupStack::PushL(self);
00296     self->ConstructL();
00297     CleanupStack::Pop(self);
00298     return self;
00299     }
00300     
00301 CVorbisDecoderProcessor::CVorbisDecoderProcessor()
00302     {
00303     }
00304     
00305 void CVorbisDecoderProcessor::ConstructL()
00306     {
00307 #ifdef SYMBIAN_SEP_HEAP
00308     User::LeaveIfError(iVorbisChunk.CreateLocal(KInitialChunkSize, KMaxChunkSize, EOwnerThread));
00309     iVorbisHeap = User::ChunkHeap(iVorbisChunk, KMinHeapLength);
00310     iDefaultHeap = &User::Heap();
00311 #endif
00312     VORBIS_TRAPD(leaveErr, iDecoder = CVorbisDecoder::NewL());
00313     User::LeaveIfError(leaveErr);
00314     }
00315     
00316 CVorbisDecoderProcessor::~CVorbisDecoderProcessor()
00317     {
00318 #ifdef SYMBIAN_SEP_HEAP
00319         if(iVorbisHeap)
00320                 {
00321                 User::SwitchHeap(iVorbisHeap);
00322                 }
00323 #endif
00324     delete iDecoder;
00325 #ifdef SYMBIAN_SEP_HEAP
00326         if(iVorbisHeap)
00327                 {
00328                 iVorbisChunk.Close();
00329         User::SwitchHeap(iDefaultHeap);
00330                 }
00331 #endif
00332     }
00333 
00351 void CVorbisDecoderProcessor::ProcessL(const CMMFBuffer& aSource, 
00352                                 CMMFBuffer& aDst,
00353                                 TProcessResult& aRes,
00354                                 TUint& aSourceUsed,
00355                                 TUint& aDestWritten)
00356     {
00357     // check that buffers are instances of CMMFDataBuffer
00358     if (!CMMFBuffer::IsSupportedDataBuffer(aSource.Type())) 
00359         {
00360         User::Leave(KErrNotSupported);
00361         }
00362     if (!CMMFBuffer::IsSupportedDataBuffer(aDst.Type())) 
00363         {
00364         User::Leave(KErrNotSupported);
00365         }
00366     const CMMFDataBuffer& src = static_cast<const CMMFDataBuffer&>(aSource);
00367     if((src.LastBuffer()) && (src.Data().Length() == 0 ))
00368         {
00369         //last buffer and is of length zero. just return
00370         aDestWritten = 0;
00371         aSourceUsed = 0;
00372         aRes = EComplete;
00373         return;
00374         }
00375     CMMFDataBuffer& dstBuf = static_cast<CMMFDataBuffer&>(aDst);
00376     if ((aSource.FrameNumber()<2) && (aSource.FrameNumber()<iLastFrame)) 
00377         {
00378         #ifdef SYMBIAN_SEP_HEAP
00379                         User::SwitchHeap(iVorbisHeap);
00380                 #endif
00381         iDecoder->Reset(); // process header again      
00382         #ifdef SYMBIAN_SEP_HEAP
00383                         iVorbisChunk.Close();
00384                 #endif
00385         }
00386     dstBuf.Data().SetLength(0);
00387     //Send the source buffer to decoder.
00388     VORBIS_TRAPD(leaveErr, iDecoder->DecoderL(src,dstBuf.Data()));
00389         User::LeaveIfError(leaveErr);
00390     aDestWritten = dstBuf.Data().Length();
00391     dstBuf.Data().SetLength(dstBuf.Data().Length());
00392     aSourceUsed = src.Data().Length()-aSource.Position();
00393     aRes = ( aDestWritten==0) ? EDestNotFilled : EComplete ;
00394         iLastFrame = aSource.FrameNumber();
00395     }
00396     

Generated by  doxygen 1.6.2