examples/sfexamples/oggvorbiscodec/src/VorbisEncoder/VorbisEncoder.cpp

00001 // VorbisEncoder.cpp
00002 //
00003 // Copyright (c) Symbian Software Ltd 2005-2008.  All rights reserved.
00004 //
00005 
00006 #include <e32base.h>
00007 #include <e32debug.h>
00008 #include <e32math.h>
00009 #include "VorbisEncoder.h"
00010 
00011 const TInt KDefaultBitRate = 64000;
00012 const TInt KDefaultQuality = 0.0;
00013 
00014 //--------------------------------------------------------------------
00015 //----------------------------- Encoder ------------------------------
00016 //--------------------------------------------------------------------
00017 
00018  CVorbisEncoder* CVorbisEncoder::NewL()
00019     {
00020     CVorbisEncoder* self = new(ELeave)CVorbisEncoder;
00021     CleanupStack::PushL(self);
00022     self->ConstructL();
00023     CleanupStack::Pop(self);
00024     return self;
00025     }
00026     
00027 CVorbisEncoder::CVorbisEncoder(): iState(ENotReady), iBitRate(KDefaultBitRate), iQuality(KDefaultQuality)
00028     {
00029     }
00030 
00031 void CVorbisEncoder::ConstructL()
00032     {
00033     vorbis_info_init(&iInfo);
00034     ogg_stream_init(&iStream,10);
00035     }
00036 
00037 CVorbisEncoder::~CVorbisEncoder()
00038     {
00039         if (iState != ENotReady)
00040         {
00041         vorbis_block_clear(&iBlock);
00042         vorbis_dsp_clear(&iDspState);
00043         }
00044     ogg_stream_clear(&iStream);
00045     vorbis_comment_clear(&iComment);
00046     vorbis_info_clear(&iInfo);
00047     }
00048 
00056 void CVorbisEncoder::PcmInL(const CMMFDataBuffer& aBuf)
00057     {
00058     TPtrC8 data = aBuf.Data();
00059     TInt bytes = data.Length();
00060     TInt ret = KErrNone;
00061     if (iState == ENotReady)
00062         {
00063         User::Leave(KErrNotReady);
00064         }
00065     
00066     iLastBuffer = aBuf.LastBuffer();
00067     
00068     if(bytes==0)
00069         {
00070         ret = vorbis_analysis_wrote(&iDspState,0);
00071         DEBUG1("Called vorbis_analysis_wrote zero bytes = %d",bytes);
00072         if (ret != KErrNone)
00073                 {
00074                 User::Leave(TranslateOggVorbisError(ret));
00075                 }
00076         }
00077     else
00078         {
00079         TReal32** buffer;
00080         TInt bytesPerSample = 2*iInfo.channels; // 16-bit assumed (most likely 2 channels)
00081         TInt bufSamples = bytes/bytesPerSample;
00082         buffer = vorbis_analysis_buffer(&iDspState,bufSamples);
00083         TInt i = 0;
00084         if(iInfo.channels == 1)
00085                 {
00086                 for(i = 0 ; i < bufSamples ; i++)
00087                         {
00088                         buffer[0][i]=((static_cast<TInt8>(data[i*2+1])<<8)|(0x00ff&static_cast<TInt16>(data[i*2])))/32768.f;
00089                         }
00090                 }
00091         else
00092                 {
00093                 for(i=0;i<bufSamples;i++)
00094                         {
00095                         //16 bits either side of the | 
00096                         buffer[0][i]=((static_cast<TInt8>(data[i*4+1])<<8)|(0x00ff&static_cast<TInt16>(data[i*4])))/32768.f;
00097                                 buffer[1][i]=((static_cast<TInt8>(data[i*4+3])<<8)|(0x00ff&static_cast<TInt16>(data[i*4+2])))/32768.f;
00098                         }       
00099         }
00100 
00101         ret = vorbis_analysis_wrote(&iDspState,i);
00102         if (ret != KErrNone)
00103                 {
00104                 User::Leave(TranslateOggVorbisError(ret));
00105                 }
00106         DEBUG1("Called vorbis_analysis_wrote with vals = %d",i);
00107         }
00108      }
00109 
00120 TInt CVorbisEncoder::PageOutL(CMMFDataBuffer& aDst)
00121     {
00122     TDes8* dst = &aDst.Data();
00123     dst->SetLength(0);
00124     ogg_packet  op; // one raw packet of data to output 
00125     ogg_page og;
00126     TInt pageCount = 0;
00127     if(iState == EInitialized)
00128         {
00129         while(ogg_stream_flush(&iStream,&og))
00130                         {
00131                         dst->Append(og.header, og.header_len);
00132                         dst->Append(og.body, og.body_len);
00133                         DEBUG1("HeaderPageLength %d",og.header_len + og.body_len);
00134                         iState = EReady;
00135                         }
00136         }
00137     DEBUG("about to call vorbis_analysis_blockout");
00138         if(iLastBuffer)
00139                 {
00140                 while (vorbis_analysis_blockout(&iDspState,&iBlock) == 1)
00141                         {
00142                         vorbis_analysis(&iBlock,NULL);
00143                         vorbis_bitrate_addblock(&iBlock);
00144 
00145                         while (vorbis_bitrate_flushpacket(&iDspState,&op))
00146                                 {
00147                                 ogg_stream_packetin(&iStream,&op);
00148                                 }
00149                         }
00150                 while(ogg_stream_flush(&iStream,&og))
00151                 {
00152                 dst->Append(og.header, og.header_len);
00153                 dst->Append(og.body, og.body_len);
00154                 DEBUG("Last Buffer flag is set");
00155                 DEBUG1("PageLength %d",og.header_len + og.body_len);
00156                 DEBUG1("PageCount %d",++iPageCount);
00157                 }
00158                 aDst.SetLastBuffer(ETrue);
00159         }
00160         else 
00161                 {
00162                 while (vorbis_analysis_blockout(&iDspState,&iBlock) == 1)
00163                         {
00164                         // got a block of vorbis data, analyse it
00165                         DEBUG("called vorbis_analysis_blockout with return of 1");
00166                         vorbis_analysis(&iBlock,NULL);
00167                         vorbis_bitrate_addblock(&iBlock);
00168                         DEBUG1("called  packet vorbis_bitrate_flushpacket",(*dst).Length());
00169                         while (vorbis_bitrate_flushpacket(&iDspState,&op))
00170                                 {
00171                                 ogg_stream_packetin(&iStream,&op);
00172                                 DEBUG1("CVorbisEncoder::PacketOut packet of length %d added to cache",op.bytes);
00173                                 while(ogg_stream_pageout(&iStream, &og))
00174                                         {
00175                                         dst->Append(og.header, og.header_len);
00176                                         dst->Append(og.body, og.body_len);
00177                                 
00178                                         DEBUG1("PageLength %d",og.header_len + og.body_len);
00179                                         DEBUG1("PageCount %d",++iPageCount);
00180                                         pageCount++;
00181                                         if(ogg_page_eos(&og))
00182                                                 {
00183                                                 aDst.SetLastBuffer(ETrue);
00184                                                 DEBUG1("LastPageLength %d",og.header_len + og.body_len);
00185                                                 return dst->Length();
00186                                                 }
00187                                         }
00188                                 }
00189                         }
00190                 }
00191         return dst->Length();
00192     }
00193 
00197 void CVorbisEncoder::PrepareHeadersL()
00198         {
00199         ogg_packet op1,op2,op3;
00200         TInt ret = KErrNone;
00201         ret = vorbis_analysis_headerout(&iDspState,&iComment,&op1,&op2,&op3);
00202         if (ret != KErrNone)
00203                 {
00204                 User::Leave(TranslateOggVorbisError(ret));      
00205                 }
00206         ogg_stream_packetin(&iStream,&op1);
00207         ogg_stream_packetin(&iStream,&op2);     
00208         ogg_stream_packetin(&iStream,&op3);
00209         }
00210 
00211 void CVorbisEncoder::Reset()
00212     {
00213     if (iState==EReady)
00214         {
00215         vorbis_block_clear(&iBlock);
00216         vorbis_dsp_clear(&iDspState);
00217         }
00218     vorbis_comment_clear(&iComment);
00219     vorbis_info_clear(&iInfo);
00220     vorbis_info_init(&iInfo);
00221     vorbis_comment_init(&iComment);
00222     iLastBuffer = EFalse;
00223     iState = ENotReady;
00224     }
00225 
00226 TInt CVorbisEncoder::BitRateL()
00227         {
00228         return iBitRate;
00229         }
00230         
00231 void CVorbisEncoder::SetBitRateL(TInt aBitRate)
00232         {
00233         if (aBitRate < KOggVorbisMinBitrate)
00234                 {
00235                 aBitRate = KOggVorbisMinBitrate;
00236                 }
00237         iBitRate = aBitRate;
00238         ConvertBitRateToQuality(iBitRate, iQuality);
00239         }
00246 void CVorbisEncoder::InitializeVorbisStreamL()
00247         {
00248         TInt ret = KErrNone;
00249         ret = vorbis_encode_init_vbr(&iInfo,iChannels,iSampleRate,iQuality);
00250         if(ret == KErrNone)
00251                 {
00252                 vorbis_comment_init(&iComment);
00253                 //Custom interface could allow user to set up iComments in future
00254         vorbis_comment_add_tag(&iComment,"ENCODER","Reference Vorbis Encoder");
00255                 vorbis_analysis_init(&iDspState,&iInfo);        
00256                 vorbis_block_init(&iDspState,&iBlock);
00257                 PrepareHeadersL();
00258                 iState = EInitialized;  
00259                 }
00260         if(ret)
00261                 {
00262                 User::Leave(TranslateOggVorbisError(ret));      
00263                 }
00264         }
00270 void CVorbisEncoder::ConfigureL(TInt aSampleRate, TInt aChannels)
00271         {
00272         iSampleRate = aSampleRate;
00273         iChannels = aChannels;
00274         InitializeVorbisStreamL();
00275         }
00276         
00277 TInt CVorbisEncoder::TranslateOggVorbisError(TInt aError)
00278         {
00279         //reference libvorbis\doc\vorbis-errors.txt
00280         switch (aError)
00281                 {
00282                 case OV_EIMPL:
00283                         return KErrNotSupported;
00284                 case OV_EINVAL:
00285                         return KErrArgument;
00286                 default:
00287                 return KErrUnknown;
00288                 }       
00289         }
00290 
00299 void CVorbisEncoder::ConvertBitRateToQuality(TInt aBitRate, TReal32& aQuality)
00300         {
00301         switch (aBitRate)
00302                 {
00303                 case KVorbisQuality0:
00304                         aQuality = 0.0;
00305                         break;
00306                 case KVorbisQuality1:
00307                         aQuality = 0.1;
00308                         break;
00309                 case KVorbisQuality2:
00310                         aQuality = 0.2;
00311                         break;
00312                 case KVorbisQuality3:
00313                         aQuality = 0.3;
00314                         break;
00315                 case KVorbisQuality4:
00316                         aQuality = 0.4;
00317                         break;
00318                 case KVorbisQuality5:
00319                         aQuality = 0.5;
00320                         break;
00321                 case KVorbisQuality6:
00322                         aQuality = 0.6;
00323                         break;
00324                 case KVorbisQuality7:
00325                         aQuality = 0.7;
00326                         break;
00327                 case KVorbisQuality8:
00328                         aQuality = 0.8;
00329                         break;
00330                 case KVorbisQuality9:
00331                         aQuality = 0.9;
00332                         break;
00333                 case KVorbisQuality10:
00334                         aQuality = 1.0;
00335                         break;  
00336                 default:
00337                 aQuality = -0.1;
00338                 break;
00339                 }       
00340         }
00341 //--------------------------------------------------------------------
00342 //---------------------------- Processor -----------------------------
00343 //--------------------------------------------------------------------
00344 
00345 CVorbisProcessor* CVorbisProcessor::NewL()
00346     {
00347     CVorbisProcessor* self = new(ELeave)CVorbisProcessor;
00348     CleanupStack::PushL(self);
00349     self->ConstructL();
00350     CleanupStack::Pop(self);
00351     return self;
00352     }
00353 
00354 CVorbisProcessor::CVorbisProcessor()
00355     {
00356     }
00357 
00358 void CVorbisProcessor::ConstructL()
00359     {
00360 #ifdef SYMBIAN_SEP_HEAP    
00361     User::LeaveIfError(iVorbisChunk.CreateLocal(KInitialChunkSize, KMaxChunkSize, EOwnerThread));
00362     iVorbisHeap = User::ChunkHeap(iVorbisChunk, KMinHeapLength);
00363     iDefaultHeap = &User::Heap();
00364 #endif
00365     VORBIS_TRAPD(leaveErr, iEncoder = CVorbisEncoder::NewL());
00366     User::LeaveIfError(leaveErr);
00367     }
00368     
00369 CVorbisProcessor::~CVorbisProcessor()
00370     {
00371 #ifdef SYMBIAN_SEP_HEAP
00372         if(iVorbisHeap)
00373                 {
00374                 User::SwitchHeap(iVorbisHeap);
00375                 }
00376 #endif
00377     delete iEncoder;
00378 #ifdef SYMBIAN_SEP_HEAP
00379     if(iVorbisHeap)
00380         {
00381         iVorbisChunk.Close();
00382         User::SwitchHeap(iDefaultHeap);
00383         }
00384 #endif
00385     }
00386 
00387 void CVorbisProcessor::ProcessL(const CMMFBuffer& aSource,
00388                                 CMMFBuffer& aDst,
00389                                 TProcessResult& aRes,
00390                                 TUint& aSourceUsed,
00391                                 TUint& aDestWritten)
00392     {
00393     // check that buffers are instances of CMMFDataBuffer
00394     if (!CMMFBuffer::IsSupportedDataBuffer(aSource.Type())) 
00395         {
00396         User::Leave(KErrNotSupported);
00397         }
00398     if (!CMMFBuffer::IsSupportedDataBuffer(aDst.Type())) 
00399         {
00400         User::Leave(KErrNotSupported);
00401         }
00402         const CMMFDataBuffer& src = static_cast<const CMMFDataBuffer&>(aSource);
00403     CMMFDataBuffer& dstBuf = static_cast<CMMFDataBuffer&>(aDst);
00404     VORBIS_TRAPD(leaveErr, iEncoder->PcmInL(src));
00405     User::LeaveIfError(leaveErr);
00406     VORBIS_TRAP(leaveErr, iEncoder->PageOutL(dstBuf));
00407     User::LeaveIfError(leaveErr);
00408     aDestWritten = dstBuf.Data().Length();
00409     aSourceUsed = src.Data().Length();
00410     aRes = ( aDestWritten > 0 ? EComplete : EDestNotFilled);
00411     }
00412     
00413 TInt CVorbisProcessor::BitRateL()
00414         {
00415         return iEncoder->BitRateL();
00416         }
00417         
00418 void CVorbisProcessor::SetBitRateL(TInt aBitRate)
00419         {
00420         iEncoder->SetBitRateL(aBitRate);
00421         }
00422 
00423 void CVorbisProcessor::ConfigureL(TInt aSampleRate, TInt aChannels)
00424         {
00425         VORBIS_TRAPD(leaveErr, iEncoder->ConfigureL(aSampleRate, aChannels));
00426         User::LeaveIfError(leaveErr);
00427         }

Generated by  doxygen 1.6.2