mmserv/thumbnailengine/TneProcessorSrc/mp4demux.cpp
changeset 0 71ca22bcf22a
equal deleted inserted replaced
-1:000000000000 0:71ca22bcf22a
       
     1 /*
       
     2 * Copyright (c) 2001 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 #include "videoprocessorimpl.h"
       
    22 #include "statusmonitor.h"
       
    23 #include "activequeue.h"
       
    24 #include "dataprocessor.h"
       
    25 #include "mp4demux.h"
       
    26 #include "mp4parser.h"
       
    27 
       
    28 // ASSERTIONS
       
    29 #define DASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CVideoPlayer"), EInternalAssertionFailure))
       
    30 
       
    31 //  LOCAL HELPER MACROS
       
    32 // Debug printing, define DEBUGPRINT to get output
       
    33 //#define DEBUGPRINT
       
    34 #ifdef _DEBUG
       
    35 #include <e32svr.h>
       
    36 #define PRINT(x) RDebug::Print x;
       
    37 #else
       
    38 #define PRINT(x)
       
    39 #endif
       
    40 
       
    41 //  LOCAL CONSTANTS
       
    42 const TUint KAudioReadAheadTimeMs = 100;
       
    43 //const TUint KMaxMsInQueue = 600;
       
    44 const TUint KMaxMsInQueue = 300;
       
    45 const TUint KMaxBytesPerRun = 4096;
       
    46 const TUint KMaxBlocksInQueue = 16;
       
    47 
       
    48 
       
    49 //  MEMBER FUNCTIONS
       
    50 
       
    51 
       
    52 //=============================================================================
       
    53 
       
    54 // MODULE DATA STRUCTURES
       
    55 //enum ?declaration
       
    56 //typedef ?declaration
       
    57 
       
    58 // LOCAL FUNCTION PROTOTYPES
       
    59 // ?type ?function_name( ?arg_type, ?arg_type );
       
    60 
       
    61 // ==================== LOCAL FUNCTIONS ====================
       
    62 
       
    63 // ================= MEMBER FUNCTIONS =======================
       
    64 
       
    65 
       
    66 // ---------------------------------------------------------
       
    67 // CMP4Demux::NewL
       
    68 // Symbian two-phased constructor.
       
    69 // ---------------------------------------------------------
       
    70 //
       
    71 CMP4Demux* CMP4Demux::NewL(CActiveQueue *anInputQueue,              
       
    72                            TUint aNumChannels, TOutputChannel *aOutputChannels,
       
    73                            TStreamParameters *aParameters,
       
    74                            CStatusMonitor *aStatusMonitor,
       
    75                            CMP4Parser *aParser,                  
       
    76                            TInt aPriority)
       
    77 {
       
    78 
       
    79     CMP4Demux *self = new (ELeave) CMP4Demux(anInputQueue,              
       
    80                                              aNumChannels, 
       
    81                                              aOutputChannels,
       
    82                                              aParameters,
       
    83                                              aStatusMonitor,
       
    84                                              aParser,
       
    85                                              aPriority);
       
    86 
       
    87     CleanupStack::PushL(self);
       
    88     self->ConstructL();
       
    89     CleanupStack::Pop();
       
    90 
       
    91     return self;
       
    92 
       
    93 
       
    94 }
       
    95 
       
    96 // ---------------------------------------------------------
       
    97 // C++ default constructor can NOT contain any code, that
       
    98 // might leave.
       
    99 // ---------------------------------------------------------
       
   100 //
       
   101 CMP4Demux::CMP4Demux(CActiveQueue *anInputQueue,
       
   102                      TUint aNumChannels, TOutputChannel *aOutputChannels,
       
   103                      TStreamParameters *aParameters,
       
   104                      CStatusMonitor *aStatusMonitor,
       
   105                      CMP4Parser *aParser,                     
       
   106                      TInt aPriority)
       
   107                      : CDemultiplexer(aPriority)
       
   108     {
       
   109     // Remember the objects
       
   110     iInputQueue = anInputQueue;
       
   111     iMonitor = aStatusMonitor;
       
   112     iParser = aParser;    
       
   113 
       
   114     iPicturePeriodMs = aParameters->iPicturePeriodMs;
       
   115     iAudioFramesInSample = aParameters->iAudioFramesInSample;    
       
   116 
       
   117     // Remember the channels and mux table
       
   118     iNumOutputChannels = aNumChannels;
       
   119     iOutputChannels = aOutputChannels;
       
   120     }
       
   121 
       
   122 // EPOC default constructor can leave.
       
   123 void CMP4Demux::ConstructL()
       
   124     {
       
   125     TUint i;
       
   126     
       
   127     // Set as a reader to the input queue
       
   128     if ( iInputQueue )
       
   129         {
       
   130         iInputQueue->SetReader(this, NULL);
       
   131         iReaderSet = ETrue;
       
   132         }
       
   133     
       
   134     // Set as writer to the output queues
       
   135     for ( i = 0; i < iNumOutputChannels; i++ )
       
   136         iOutputChannels[i].iTargetQueue->SetWriter(this, NULL);
       
   137     iWriterSet = ETrue;
       
   138     
       
   139     // Add us to active scheduler
       
   140     CActiveScheduler::Add(this);
       
   141 
       
   142     iBytesDemuxed = 0;
       
   143     iAudioEnd = iVideoEnd = 0;
       
   144     
       
   145     // Open all channels
       
   146     iAudioChannel = 0;
       
   147     iVideoChannel = 0;
       
   148     for ( i = 0; i < iNumOutputChannels; i++ )
       
   149         {
       
   150         TOutputChannel *chan = &iOutputChannels[i];
       
   151         
       
   152         // Check the channel type
       
   153         switch ( chan->iDataType )
       
   154             {
       
   155             case EDataAudio:                
       
   156                 
       
   157                 if ( !iAudioChannel )
       
   158                     iAudioChannel = chan;
       
   159                 break;
       
   160                 
       
   161             case EDataVideo:
       
   162                 
       
   163                 if ( !iVideoChannel )
       
   164                     iVideoChannel = chan;
       
   165                 break;
       
   166 
       
   167             case EDataNone:
       
   168             default:
       
   169                 User::Leave(CVideoProcessorImpl::EUnsupportedFormat);
       
   170             }
       
   171         }     
       
   172 
       
   173     // Make us active
       
   174     SetActive();
       
   175     iStatus = KRequestPending;
       
   176     }
       
   177 
       
   178 // Destructor
       
   179 CMP4Demux::~CMP4Demux()
       
   180     {
       
   181     // If we are demultiplexing, stop
       
   182     if ( iDemultiplexing )
       
   183         Stop();
       
   184 
       
   185     // return input block
       
   186     if ( iInputBlock )
       
   187         {
       
   188         iInputQueue->ReturnBlock(iInputBlock);
       
   189         iInputBlock = 0;
       
   190         }
       
   191     
       
   192     // Remove from being a reader or a writer
       
   193     if ( iReaderSet )
       
   194         iInputQueue->RemoveReader();
       
   195     if ( iWriterSet )
       
   196         {
       
   197         for ( TUint i = 0; i < iNumOutputChannels; i++ )
       
   198             iOutputChannels[i].iTargetQueue->RemoveWriter();
       
   199         }
       
   200     
       
   201     iMonitor = 0;
       
   202     iInputQueue = 0;
       
   203     iParser = 0;
       
   204     iOutputChannels = 0;
       
   205     iVideoChannel = 0;
       
   206     iAudioChannel = 0;
       
   207         
       
   208     Cancel();
       
   209     
       
   210     }
       
   211 
       
   212 // ---------------------------------------------------------
       
   213 // CMP4Demux::Start
       
   214 // Starts demuxing
       
   215 // (other items were commented in a header).
       
   216 // ---------------------------------------------------------
       
   217 //
       
   218 
       
   219 void CMP4Demux::Start()
       
   220     {
       
   221     if ( iDemultiplexing )
       
   222         return;
       
   223     
       
   224     // Activate the object if we have data
       
   225     if ( (iStatus == KRequestPending) && (!iInputQueue || iInputQueue->NumDataBlocks()) )
       
   226         {
       
   227         TRequestStatus *status = &iStatus;
       
   228         User::RequestComplete(status, KErrNone);
       
   229         }
       
   230     
       
   231     iDemultiplexing = ETrue;
       
   232     iAudioEnd = iVideoEnd = iStreamEnd = 0;
       
   233     iStreamEndDemuxed = 0;
       
   234     }
       
   235 
       
   236 // ---------------------------------------------------------
       
   237 // CMP4Demux::Stop
       
   238 // Stops demuxing
       
   239 // (other items were commented in a header).
       
   240 // ---------------------------------------------------------
       
   241 //
       
   242 
       
   243 void CMP4Demux::Stop()
       
   244     {
       
   245     iDemultiplexing = EFalse;
       
   246     }
       
   247 
       
   248 // ---------------------------------------------------------
       
   249 // CMP4Demux::RunL
       
   250 // Standard active object running method, called when new input data 
       
   251 // or free output space has been signaled to be available 
       
   252 // (other items were commented in a header).
       
   253 // ---------------------------------------------------------
       
   254 //
       
   255 
       
   256 void CMP4Demux::RunL()
       
   257     {
       
   258     PRINT((_L("MP4Demux::RunL() in") ));
       
   259 
       
   260     // If we have demuxed everything up to stream end, theres is nothing for
       
   261     // us to do
       
   262     if ( iStreamEndDemuxed )
       
   263         return;
       
   264     
       
   265     // Don't do anything if we are not demuxing
       
   266     if ( !iDemultiplexing )
       
   267         {
       
   268         SetActive();
       
   269         iStatus = KRequestPending;
       
   270         return;
       
   271         }
       
   272     
       
   273     // If we don't have a primary channel, we have no open channels and may as
       
   274     // well quit
       
   275     if ( !iAudioChannel && !iVideoChannel )
       
   276         {
       
   277         iMonitor->StreamEndReached();
       
   278         return;
       
   279         }    
       
   280 
       
   281     // streaming case:
       
   282     // Try to demux as long as we have a free block in the primary output queue
       
   283     // and we can find more frames 
       
   284     // If we have both video and audio, we'll check the available space only
       
   285     // in the primary audio queue, and the video queue will allocate more
       
   286     // blocks as needed. This way the audio decoder will get more data as
       
   287     // needed, no matter what the video bitrate is.            
       
   288 
       
   289     // in file-reading case, GetFrameInfo() checks if there's available space
       
   290     // in queues, and this info is contained in variable iGotFrame       
       
   291 
       
   292     // send frame(s) if:
       
   293     // a frame is available AND
       
   294     // there are free blocks in output queue AND
       
   295     // we have not demuxed too much during this run so other objects get CPU AND
       
   296     // the stream end has not been demuxed    
       
   297 
       
   298     iBytesDemuxed = 0;
       
   299 
       
   300     // NOTE: only video queue fullness checked for now
       
   301     CActiveQueue *queue = iVideoChannel->iTargetQueue;
       
   302 
       
   303     GetFrameInfo();
       
   304 
       
   305     while ( iGotFrame && ( (iInputQueue && NumFreeBlocks() > 0) || 
       
   306           ( (queue->NumDataBlocks() < KMaxBlocksInQueue) && (iBytesDemuxed < KMaxBytesPerRun) ) ) && 
       
   307           (!iStreamEndDemuxed) )
       
   308         {
       
   309         // Read & send frame(s)        
       
   310         TInt error = ReadAndSendFrames();
       
   311         
       
   312         if ( error != KErrNone )
       
   313             {
       
   314             iMonitor->Error(error);
       
   315             return;        
       
   316             }
       
   317         
       
   318         // And to try get info for new frame
       
   319         GetFrameInfo();
       
   320         }
       
   321     
       
   322     // If we have demultiplexed everything up to stream end, signal the queues
       
   323     // and don't demux any more. If we have no output channels, notify the
       
   324     // status monitor.
       
   325     if ( iStreamEnd && (!iGotFrame) )
       
   326         {
       
   327         // report stream end in streaming case
       
   328         // in file-reading case, its reported in GetFrameInfo
       
   329         if ( iNumOutputChannels )
       
   330             {
       
   331             if ( iInputQueue )
       
   332                 {
       
   333                 TUint i;
       
   334                 for ( i = 0; i < iNumOutputChannels; i++ )
       
   335                     iOutputChannels[i].iTargetQueue->WriteStreamEnd();
       
   336                 }
       
   337             }
       
   338         else
       
   339             {
       
   340             iMonitor->StreamEndReached();
       
   341             }
       
   342         iStreamEndDemuxed = ETrue;
       
   343         return;
       
   344         }
       
   345     
       
   346     // Re-activate to get signals about new blocks
       
   347     SetActive();
       
   348     iStatus = KRequestPending;
       
   349 
       
   350     PRINT((_L("MP4Demux::RunL() out") ));
       
   351     }
       
   352 
       
   353 
       
   354 // ---------------------------------------------------------
       
   355 // CMP4Demux::StreamEndReached
       
   356 // Informs the object that stream end has been reached
       
   357 // (when we have an input queue, not used in file-reading case)
       
   358 // (other items were commented in a header).
       
   359 // ---------------------------------------------------------
       
   360 //
       
   361 
       
   362 void CMP4Demux::StreamEndReached(TAny* /*aUserPointer*/)
       
   363     {
       
   364     iStreamEnd = ETrue;
       
   365     
       
   366     // Signal ourselves if we are demultiplexing
       
   367     if ( iDemultiplexing && (iStatus == KRequestPending) )
       
   368         {
       
   369         TRequestStatus *status = &iStatus;
       
   370         User::RequestComplete(status, KErrNone);
       
   371         }
       
   372     }
       
   373 
       
   374 // ---------------------------------------------------------
       
   375 // CMP4Demux::DoCancel
       
   376 // Standard active object cancellation method
       
   377 // (other items were commented in a header).
       
   378 // ---------------------------------------------------------
       
   379 //
       
   380 
       
   381 void CMP4Demux::DoCancel()
       
   382     {
       
   383     // Cancel our internal request
       
   384     if ( iStatus == KRequestPending )
       
   385         {
       
   386         TRequestStatus *status = &iStatus;
       
   387         User::RequestComplete(status, KErrCancel);
       
   388         }
       
   389     }
       
   390 
       
   391 // ---------------------------------------------------------
       
   392 // CMP4Demux::GetFrameInfo
       
   393 // Gets information regarding the next frame. In file-reading
       
   394 // case, also sets the type of next frame to be read. 
       
   395 // (other items were commented in a header).
       
   396 // ---------------------------------------------------------
       
   397 //
       
   398 
       
   399 void CMP4Demux::GetFrameInfo()
       
   400     {     
       
   401     
       
   402     if ( iGotFrame )
       
   403         return;    
       
   404     
       
   405     if ( !iInputQueue )
       
   406         {
       
   407         // file-reading case: set frame type according to 
       
   408         // queue fullness 
       
   409         
       
   410         SetFrameType();
       
   411         if ( iFrameType == EDataNone )            
       
   412             return;
       
   413 
       
   414         }
       
   415     
       
   416     TBool frameAvailable = EFalse;
       
   417     // check if parser has info & data for next frame available
       
   418     TInt error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
       
   419         iFrameLen, frameAvailable);
       
   420     
       
   421     if ( error != KErrNone )
       
   422         {
       
   423         if ( error != CParser::EParserEndOfStream )
       
   424         {            
       
   425             iMonitor->Error(error);
       
   426         }
       
   427 #ifdef _DEBUG
       
   428         else
       
   429             DASSERT( iStreamEnd );
       
   430 #endif
       
   431         return;
       
   432         }                
       
   433     
       
   434     if ( iInputQueue ) 
       
   435         {                             
       
   436         
       
   437         // Read data from input queue until we know the frame type and length
       
   438         // and have data for it available        
       
   439         while ( !frameAvailable )
       
   440             {
       
   441             // Get a new input block with data
       
   442             while ( !iInputBlock )
       
   443                 {
       
   444                 if ( (iInputBlock = iInputQueue->ReadBlock()) == NULL )
       
   445                     return;                    
       
   446                 
       
   447                 // Return empty blocks immediately
       
   448                 if ( iInputBlock->Length() == 0 ) 
       
   449                     {
       
   450                     iInputQueue->ReturnBlock(iInputBlock);
       
   451                     iInputBlock = 0;
       
   452                     }
       
   453                 }      
       
   454             
       
   455             // give input block to parser
       
   456             error = iParser->WriteDataBlock(*iInputBlock);
       
   457             if ( error != KErrNone )
       
   458                 {
       
   459                 iMonitor->Error(error);
       
   460                 return;
       
   461                 }
       
   462             
       
   463             // Return our current input block 
       
   464             iInputQueue->ReturnBlock(iInputBlock);
       
   465             iInputBlock = 0;                                             
       
   466             
       
   467             // check if parser has info & data for next frame available
       
   468             error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
       
   469                 iFrameLen, frameAvailable);
       
   470             
       
   471             if ( error != KErrNone ) 
       
   472                 {
       
   473                 iMonitor->Error(error);                
       
   474                 return;
       
   475                 }
       
   476             }
       
   477         }
       
   478     else {
       
   479         while ( !frameAvailable )
       
   480         {
       
   481             if ( iFrameType == EDataAudio )
       
   482             {
       
   483                 iAudioEnd = ETrue;
       
   484                 iAudioChannel->iTargetQueue->WriteStreamEnd();
       
   485                 PRINT((_L("MP4Demux, audio ended\n") ));
       
   486             }
       
   487             else
       
   488             {
       
   489                 iVideoEnd = ETrue;
       
   490                 iVideoChannel->iTargetQueue->WriteStreamEnd();
       
   491                 PRINT((_L("MP4Demux, video ended\n") ));
       
   492             }
       
   493             if ( iVideoEnd && (iAudioChannel == 0 || iAudioEnd) )
       
   494             {
       
   495                 iStreamEnd = ETrue;
       
   496                 return;
       
   497             }
       
   498             iFrameType = EDataNone;
       
   499             SetFrameType();
       
   500             if ( iFrameType == EDataNone )
       
   501                 return;
       
   502             error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
       
   503                 iFrameLen, frameAvailable);
       
   504             if ( error != KErrNone ) 
       
   505             {
       
   506                 iMonitor->Error(error);                
       
   507                 return;
       
   508             }
       
   509         }
       
   510     }
       
   511            
       
   512     // at least one frame available
       
   513     iGotFrame = ETrue;    
       
   514     }
       
   515 
       
   516 // ---------------------------------------------------------
       
   517 // CMP4Demux::NumFreeBlocks
       
   518 // Gets the number of free blocks in target queue
       
   519 // Relevant in streaming -case
       
   520 // (other items were commented in a header).
       
   521 // ---------------------------------------------------------
       
   522 //
       
   523 
       
   524 TUint CMP4Demux::NumFreeBlocks()
       
   525     {
       
   526     // check if there's space available for next frame    
       
   527     
       
   528     CActiveQueue *queue = 0;
       
   529     
       
   530     // streaming case: use audio queue value for both so
       
   531     // that enough audio is always available regardless of 
       
   532     // video bitrate.
       
   533 
       
   534     if ( iAudioChannel )    
       
   535         queue = iAudioChannel->iTargetQueue;    
       
   536     else     
       
   537         queue = iVideoChannel->iTargetQueue;
       
   538     
       
   539     DASSERT(queue);
       
   540 
       
   541     return queue->NumFreeBlocks();
       
   542     
       
   543     }
       
   544 
       
   545 // ---------------------------------------------------------
       
   546 // CMP4Demux::SetFrameType
       
   547 // Sets the type of next frame to be read
       
   548 // Relevant in file-reading case
       
   549 // (other items were commented in a header).
       
   550 // ---------------------------------------------------------
       
   551 //
       
   552 void CMP4Demux::SetFrameType()
       
   553     {   
       
   554     
       
   555     TUint audioDataBlocks = 0;
       
   556     TUint audioInQueue = 0;
       
   557     TUint videoDataBlocks = iVideoChannel->iTargetQueue->NumDataBlocks();    
       
   558     TUint videoInQueue = videoDataBlocks * iPicturePeriodMs;    
       
   559 
       
   560     DASSERT( iFrameType == EDataNone );
       
   561 
       
   562     if ( iAudioChannel )
       
   563     {
       
   564         audioDataBlocks = iAudioChannel->iTargetQueue->NumDataBlocks();
       
   565         audioInQueue = audioDataBlocks * 20 * iAudioFramesInSample;
       
   566     }
       
   567 
       
   568     if ( iAudioChannel == 0 || iAudioEnd )
       
   569     {
       
   570         iFrameType = EDataVideo;
       
   571     }        
       
   572 
       
   573     else if ( iVideoEnd )
       
   574     {    
       
   575         iFrameType = EDataAudio;        
       
   576     }
       
   577 
       
   578     else 
       
   579     {
       
   580         if ( audioInQueue > videoInQueue + KAudioReadAheadTimeMs )
       
   581             iFrameType = EDataVideo;
       
   582         else 
       
   583             iFrameType = EDataAudio;            
       
   584     }
       
   585     
       
   586     //if ( ( iFrameType == EDataVideo && videoInQueue >= KMaxMsInQueue ) || 
       
   587     //     ( iFrameType == EDataAudio && audioInQueue >= KMaxMsInQueue + KAudioReadAheadTimeMs ) )
       
   588     //    iFrameType = EDataNone;          
       
   589     
       
   590     }
       
   591 
       
   592 // ---------------------------------------------------------
       
   593 // CMP4Demux::ReadVideoFrames
       
   594 // Read video frames to video queue
       
   595 // (other items were commented in a header).
       
   596 // ---------------------------------------------------------
       
   597 //
       
   598 TInt CMP4Demux::ReadVideoFrames(TInt aCount)
       
   599 {
       
   600     
       
   601     while (aCount--)
       
   602     {
       
   603         iFrameType = EDataVideo;
       
   604 
       
   605         TBool frameAvailable = 0;
       
   606         TInt error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
       
   607             iFrameLen, frameAvailable);
       
   608 
       
   609         if (error !=KErrNone)
       
   610             return error;
       
   611 
       
   612         DASSERT(frameAvailable);
       
   613 
       
   614         iGotFrame = ETrue;
       
   615         error = ReadAndSendFrames();
       
   616         if (error !=KErrNone)
       
   617             return error;
       
   618     }
       
   619     return KErrNone;
       
   620 
       
   621 }
       
   622 
       
   623 // ---------------------------------------------------------
       
   624 // CMP4Demux::StreamEndReached
       
   625 // Reads the next frame(s) from parser and writes
       
   626 // them to the target queue
       
   627 // (other items were commented in a header).
       
   628 // ---------------------------------------------------------
       
   629 //
       
   630 
       
   631 TInt CMP4Demux::ReadAndSendFrames()
       
   632     {    
       
   633 
       
   634     DASSERT( iGotFrame );
       
   635 
       
   636     // Find the correct channel. If there is no channel open for this
       
   637     // type of frames, we'll simply ignore it
       
   638     TOutputChannel *chan = 0;
       
   639     TUint i;
       
   640     for ( i = 0; i < iNumOutputChannels; i++ )
       
   641         {
       
   642         if ( iOutputChannels[i].iDataType == iFrameType )
       
   643             chan = &iOutputChannels[i];
       
   644         }    
       
   645     
       
   646     if ( chan )
       
   647         {
       
   648         // OK, we have a target channel. Get a block from its queue
       
   649         
       
   650         TPtr8 *block = 0;                       
       
   651         
       
   652         // NOTE: if output block does not need to be saved in any case, make it a local variable
       
   653 
       
   654         //PRINT((_L("framelen = %d, bytesdemuxed = %d\n"), iFrameLen, iBytesDemuxed));
       
   655 
       
   656         TUint blockLen = iFrameLen;
       
   657         TPtr8 readDes(0,0);        
       
   658         TInt error;
       
   659 
       
   660         if ( iFrameType == EDataVideo ) 
       
   661         {
       
   662             // make room for timestamp
       
   663             blockLen += 4;
       
   664         }              
       
   665         
       
   666 
       
   667 
       
   668         TRAP( error, (block = chan->iTargetQueue->GetFreeBlockL(blockLen)) );
       
   669         if ( error != KErrNone )
       
   670             return error;        
       
   671 
       
   672         if ( iFrameType == EDataVideo ) 
       
   673         {
       
   674             TUint8 *p = (TUint8 *)(block->Ptr()) + 4;
       
   675             readDes.Set( p, 0, TInt(iFrameLen) );
       
   676         }
       
   677         else
       
   678         {
       
   679             readDes.Set( *block );
       
   680         }
       
   681                 
       
   682         TUint32 numReadFrames = 0;
       
   683         TUint32 timeStamp;
       
   684 
       
   685         // read frame(s) from parser
       
   686         error = iParser->ReadFrames(readDes, CMP4Parser::TFrameType(iFrameType), 
       
   687             numReadFrames, timeStamp);
       
   688    
       
   689         if ( error != KErrNone )
       
   690             return error;
       
   691 
       
   692         DASSERT( numReadFrames > 0 );   
       
   693         
       
   694         if ( iFrameType == EDataAudio )
       
   695         {
       
   696             block->SetLength(readDes.Length());            
       
   697         }
       
   698         else
       
   699         {            
       
   700             block->SetLength(readDes.Length() + 4);
       
   701 
       
   702             // put timestamp in the output block before the actual frame data                       
       
   703             TUint* d = (TUint *)(block->Ptr());            
       
   704             Mem::Copy(d, &timeStamp, 4);
       
   705         }
       
   706 
       
   707         iBytesDemuxed += TUint( readDes.Length() );
       
   708         
       
   709         // Send the block
       
   710         chan->iTargetQueue->WriteBlock(block);        
       
   711         iFrameLen = 0;
       
   712         iFrameType = EDataNone;
       
   713         iGotFrame = EFalse;
       
   714         }
       
   715     else
       
   716         {     
       
   717         PRINT((_L("Unknown channel\n")));
       
   718         }    
       
   719     
       
   720     return KErrNone;
       
   721     }
       
   722