videoeditorengine/vedengine/videoprocessor/src/mp4demux.cpp
branchRCL_3
changeset 3 e0b5df5c0969
parent 0 951a5db380a0
child 7 4c409de21d23
--- a/videoeditorengine/vedengine/videoprocessor/src/mp4demux.cpp	Fri Jan 29 14:08:33 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,748 +0,0 @@
-/*
-* Copyright (c) 2010 Ixonos Plc.
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of the "Eclipse Public License v1.0"
-* which accompanies this distribution, and is available
-* at the URL "http://www.eclipse.org/legal/epl-v10.html".
-*
-* Initial Contributors:
-* Nokia Corporation - Initial contribution
-*
-* Contributors:
-* Ixonos Plc
-*
-* Description:  
-* Implementation of mp4 demux class.
-*
-*/
-
-
-// INCLUDE FILES
-#include "movieprocessorimpl.h"
-#include "statusmonitor.h"
-#include "activequeue.h"
-#include "dataprocessor.h"
-#include "mp4demux.h"
-#include "mp4parser.h"
-
-// ASSERTIONS
-#define DASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CVideoPlayer"), EInternalAssertionFailure))
-
-//  LOCAL HELPER MACROS
-// Debug printing, define DEBUGPRINT to get output
-//#define DEBUGPRINT
-#ifdef _DEBUG
-#include <e32svr.h>
-#define PRINT(x) RDebug::Print x;
-#else
-#define PRINT(x)
-#endif
-
-//  LOCAL CONSTANTS
-const TUint KAudioReadAheadTimeMs = 100;
-//const TUint KMaxMsInQueue = 600;
-//const TUint KMaxMsInQueue = 300;
-const TUint KMaxBytesPerRun = 4096;
-const TUint KMaxBlocksInQueue = 16;
-
-
-//  MEMBER FUNCTIONS
-
-
-//=============================================================================
-
-// MODULE DATA STRUCTURES
-//enum ?declaration
-//typedef ?declaration
-
-// LOCAL FUNCTION PROTOTYPES
-// ?type ?function_name( ?arg_type, ?arg_type );
-
-// ==================== LOCAL FUNCTIONS ====================
-
-// ================= MEMBER FUNCTIONS =======================
-
-
-// ---------------------------------------------------------
-// CMP4Demux::NewL
-// Symbian two-phased constructor.
-// ---------------------------------------------------------
-//
-CMP4Demux* CMP4Demux::NewL(CActiveQueue *anInputQueue,              
-                           TUint aNumChannels, TOutputChannel *aOutputChannels,
-                           TStreamParameters *aParameters,
-                           CStatusMonitor *aStatusMonitor,
-                           CMP4Parser *aParser,                  
-                           TInt aPriority)
-{
-
-    CMP4Demux *self = new (ELeave) CMP4Demux(anInputQueue,              
-                                             aNumChannels, 
-                                             aOutputChannels,
-                                             aParameters,
-                                             aStatusMonitor,
-                                             aParser,
-                                             aPriority);
-
-    CleanupStack::PushL(self);
-    self->ConstructL();
-    CleanupStack::Pop();
-
-    return self;
-
-
-}
-
-// ---------------------------------------------------------
-// C++ default constructor can NOT contain any code, that
-// might leave.
-// ---------------------------------------------------------
-//
-CMP4Demux::CMP4Demux(CActiveQueue *anInputQueue,
-                     TUint aNumChannels, TOutputChannel *aOutputChannels,
-                     TStreamParameters *aParameters,
-                     CStatusMonitor *aStatusMonitor,
-                     CMP4Parser *aParser,                     
-                     TInt aPriority)
-                     : CDemultiplexer(aPriority)
-    {
-    // Remember the objects
-    iInputQueue = anInputQueue;
-    iMonitor = aStatusMonitor;
-    iParser = aParser;    
-
-    iPicturePeriodMs = aParameters->iPicturePeriodMs;
-    iAudioFramesInSample = aParameters->iAudioFramesInSample;    
-
-    // Remember the channels and mux table
-    iNumOutputChannels = aNumChannels;
-    iOutputChannels = aOutputChannels;
-    }
-
-// EPOC default constructor can leave.
-void CMP4Demux::ConstructL()
-    {
-    TUint i;
-    
-    // Set as a reader to the input queue
-    if ( iInputQueue )
-        {
-        iInputQueue->SetReader(this, NULL);
-        iReaderSet = ETrue;
-        }
-    
-    // Set as writer to the output queues
-    for ( i = 0; i < iNumOutputChannels; i++ )
-        iOutputChannels[i].iTargetQueue->SetWriter(this, NULL);
-    iWriterSet = ETrue;
-    
-    // Add us to active scheduler
-    CActiveScheduler::Add(this);
-
-    iBytesDemuxed = 0;
-    iAudioEnd = iVideoEnd = 0;
-    
-    // Open all channels
-    iAudioChannel = 0;
-    iVideoChannel = 0;
-    for ( i = 0; i < iNumOutputChannels; i++ )
-        {
-        TOutputChannel *chan = &iOutputChannels[i];
-        
-        // Check the channel type
-        switch ( chan->iDataType )
-            {
-            case EDataAudio:                
-                
-                if ( !iAudioChannel )
-                    iAudioChannel = chan;
-                break;
-                
-            case EDataVideo:
-                
-                if ( !iVideoChannel )
-                    iVideoChannel = chan;
-                break;
-
-            case EDataNone:
-            default:
-                User::Leave(CMovieProcessorImpl::EUnsupportedFormat);
-            }
-        }     
-
-    // Make us active
-    SetActive();
-    iStatus = KRequestPending;
-    }
-
-// Destructor
-CMP4Demux::~CMP4Demux()
-    {
-
-    // If we are demultiplexing, stop
-    if ( iDemultiplexing )
-        Stop();
-
-    // return input block
-    if ( iInputBlock )
-        {
-        if (iInputQueue)
-            iInputQueue->ReturnBlock(iInputBlock);
-        iInputBlock = 0;
-        }
-     
-    // Remove from being a reader or a writer
-    if ( iReaderSet )
-        {
-        if (iInputQueue)
-            iInputQueue->RemoveReader();
-        }
-
-    if ( iWriterSet )
-        {
-        for ( TUint i = 0; i < iNumOutputChannels; i++ )
-            {
-            if (iOutputChannels[i].iTargetQueue)
-                iOutputChannels[i].iTargetQueue->RemoveWriter();
-            }
-        }
-
-    iMonitor = 0;
-    iInputQueue = 0;
-    iParser = 0;
-    iOutputChannels = 0;
-    iVideoChannel = 0;
-    iAudioChannel = 0;
-        
-    Cancel();
-    
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::Start
-// Starts demuxing
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-void CMP4Demux::Start()
-    {
-    if ( iDemultiplexing )
-        return;
-    
-    if (!IsActive())
-    {
-        // Make us active
-        SetActive();
-        iStatus = KRequestPending;
-    }
-    
-    // Activate the object if we have data
-    if ( (iStatus == KRequestPending) && (!iInputQueue || iInputQueue->NumDataBlocks()) )
-        {
-        TRequestStatus *status = &iStatus;
-        User::RequestComplete(status, KErrNone);
-        }
-    
-    iDemultiplexing = ETrue;
-    iAudioEnd = iVideoEnd = iStreamEnd = 0;
-    iStreamEndDemuxed = 0;
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::Stop
-// Stops demuxing
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-void CMP4Demux::Stop()
-    {
-    iDemultiplexing = EFalse;
-    iGotFrame = EFalse;
-    iFrameType = EDataNone;
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::RunL
-// Standard active object running method, called when new input data 
-// or free output space has been signaled to be available 
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-void CMP4Demux::RunL()
-    {
-    PRINT((_L("MP4Demux::RunL() in") ));
-
-    // If we have demuxed everything up to stream end, theres is nothing for
-    // us to do
-    if ( iStreamEndDemuxed )
-        return;
-    
-    // Don't do anything if we are not demuxing
-    if ( !iDemultiplexing )
-        {
-        SetActive();
-        iStatus = KRequestPending;
-        return;
-        }
-    
-    // If we don't have a primary channel, we have no open channels and may as
-    // well quit
-    if ( !iAudioChannel && !iVideoChannel )
-        {
-        iMonitor->StreamEndReached();
-        return;
-        }    
-
-    // streaming case:
-    // Try to demux as long as we have a free block in the primary output queue
-    // and we can find more frames 
-    // If we have both video and audio, we'll check the available space only
-    // in the primary audio queue, and the video queue will allocate more
-    // blocks as needed. This way the audio decoder will get more data as
-    // needed, no matter what the video bitrate is.            
-
-    // in file-reading case, GetFrameInfo() checks if there's available space
-    // in queues, and this info is contained in variable iGotFrame       
-
-    // send frame(s) if:
-    // a frame is available AND
-    // there are free blocks in output queue AND
-    // we have not demuxed too much during this run so other objects get CPU AND
-    // the stream end has not been demuxed    
-
-    iBytesDemuxed = 0;
-
-    // NOTE: only video queue fullness checked for now
-    CActiveQueue *queue = iVideoChannel->iTargetQueue;
-
-    TInt error = GetFrameInfo();
-    if (error != KErrNone)
-        return;
-
-    while ( iGotFrame && ( (iInputQueue && NumFreeBlocks() > 0) || 
-          ( (queue->NumDataBlocks() < KMaxBlocksInQueue) && (iBytesDemuxed < KMaxBytesPerRun) ) ) && 
-          (!iStreamEndDemuxed) )
-        {
-        // Read & send frame(s)        
-        TInt error = ReadAndSendFrames();
-        
-        if ( error != KErrNone )
-            {
-            iMonitor->Error(error);
-            return;        
-            }
-        
-        // And to try get info for new frame
-        error = GetFrameInfo();
-        if (error != KErrNone)
-            return;
-        }
-    
-    // If we have demultiplexed everything up to stream end, signal the queues
-    // and don't demux any more. If we have no output channels, notify the
-    // status monitor.
-    if ( iStreamEnd && (!iGotFrame) )
-        {
-        // report stream end in streaming case
-        // in file-reading case, its reported in GetFrameInfo
-        if ( iNumOutputChannels )
-            {
-            if ( iInputQueue )
-                {
-                TUint i;
-                for ( i = 0; i < iNumOutputChannels; i++ )
-                    iOutputChannels[i].iTargetQueue->WriteStreamEnd();
-                }
-            }
-        else
-            {
-            iMonitor->StreamEndReached();
-            }
-        iStreamEndDemuxed = ETrue;
-        return;
-        }
-    
-    // Re-activate to get signals about new blocks
-    SetActive();
-    iStatus = KRequestPending;
-
-    PRINT((_L("MP4Demux::RunL() out") ));
-    }
-
-
-// ---------------------------------------------------------
-// CMP4Demux::StreamEndReached
-// Informs the object that stream end has been reached
-// (when we have an input queue, not used in file-reading case)
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-void CMP4Demux::StreamEndReached(TAny* /*aUserPointer*/)
-    {
-    iStreamEnd = ETrue;
-    
-    // Signal ourselves if we are demultiplexing
-    if ( iDemultiplexing && (iStatus == KRequestPending) )
-        {
-        TRequestStatus *status = &iStatus;
-        User::RequestComplete(status, KErrNone);
-        }
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::DoCancel
-// Standard active object cancellation method
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-void CMP4Demux::DoCancel()
-    {
-    // Cancel our internal request
-    if ( iStatus == KRequestPending )
-        {
-        TRequestStatus *status = &iStatus;
-        User::RequestComplete(status, KErrCancel);
-        }
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::GetFrameInfo
-// Gets information regarding the next frame. In file-reading
-// case, also sets the type of next frame to be read. 
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-TInt CMP4Demux::GetFrameInfo()
-    {     
-    
-    if ( iGotFrame )
-        return KErrNone;
-    
-    if ( !iInputQueue )
-        {
-        // file-reading case: set frame type according to 
-        // queue fullness 
-        
-        SetFrameType();
-        if ( iFrameType == EDataNone )            
-            return KErrNone;
-
-        }
-    
-    TBool frameAvailable = EFalse;
-    // check if parser has info & data for next frame available
-    TInt error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
-        iFrameLen, frameAvailable);
-    
-    if ( error != KErrNone )
-        {
-        if ( error != CParser::EParserEndOfStream )
-            {            
-            iMonitor->Error(error);
-            return error;
-            }
-        else
-            {            
-            DASSERT( iStreamEnd );
-            return KErrNone;
-            }
-        
-        }
-    
-    if ( iInputQueue ) 
-        {                             
-        
-        // Read data from input queue until we know the frame type and length
-        // and have data for it available        
-        while ( !frameAvailable )
-            {
-            // Get a new input block with data
-            while ( !iInputBlock )
-                {
-                if ( (iInputBlock = iInputQueue->ReadBlock()) == NULL )
-                    return KErrNone;                    
-                
-                // Return empty blocks immediately
-                if ( iInputBlock->Length() == 0 ) 
-                    {
-                    iInputQueue->ReturnBlock(iInputBlock);
-                    iInputBlock = 0;
-                    }
-                }      
-            
-            // give input block to parser
-            error = iParser->WriteDataBlock(*iInputBlock);
-            if ( error != KErrNone )
-                {
-                iMonitor->Error(error);
-                return error;
-                }
-            
-            // Return our current input block 
-            iInputQueue->ReturnBlock(iInputBlock);
-            iInputBlock = 0;                                             
-            
-            // check if parser has info & data for next frame available
-            error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
-                iFrameLen, frameAvailable);
-            
-            if ( error != KErrNone ) 
-                {
-                iMonitor->Error(error);                
-                return error;
-                }
-            }
-        }
-    else {
-        while ( !frameAvailable )
-        {
-            if ( iFrameType == EDataAudio )
-            {
-                iAudioEnd = ETrue;
-                iAudioChannel->iTargetQueue->WriteStreamEnd();
-                PRINT((_L("MP4Demux, audio ended\n") ));
-            }
-            else
-            {
-                iVideoEnd = ETrue;
-                iVideoChannel->iTargetQueue->WriteStreamEnd();
-                PRINT((_L("MP4Demux, video ended\n") ));
-            }
-            if ( iVideoEnd && (iAudioChannel == 0 || iAudioEnd) )
-            {
-                iStreamEnd = ETrue;
-                return KErrNone;
-            }
-            iFrameType = EDataNone;
-            SetFrameType();
-            if ( iFrameType == EDataNone )
-                return KErrNone;
-            error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
-                iFrameLen, frameAvailable);
-            if ( error != KErrNone ) 
-            {
-                iMonitor->Error(error);                
-                return error;
-            }
-        }
-    }
-           
-    // at least one frame available
-    iGotFrame = ETrue;    
-    return KErrNone;
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::NumFreeBlocks
-// Gets the number of free blocks in target queue
-// Relevant in streaming -case
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-TUint CMP4Demux::NumFreeBlocks()
-    {
-    // check if there's space available for next frame    
-    
-    CActiveQueue *queue = 0;
-    
-    // streaming case: use audio queue value for both so
-    // that enough audio is always available regardless of 
-    // video bitrate.
-
-    if ( iAudioChannel )    
-        queue = iAudioChannel->iTargetQueue;    
-    else     
-        queue = iVideoChannel->iTargetQueue;
-    
-    DASSERT(queue);
-
-    return queue->NumFreeBlocks();
-    
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::SetFrameType
-// Sets the type of next frame to be read
-// Relevant in file-reading case
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-void CMP4Demux::SetFrameType()
-    {   
-    
-    TUint audioDataBlocks = 0;
-    TUint audioInQueue = 0;
-    TUint videoDataBlocks = iVideoChannel->iTargetQueue->NumDataBlocks();    
-    TUint videoInQueue = videoDataBlocks * iPicturePeriodMs;    
-
-    DASSERT( iFrameType == EDataNone );
-
-    if ( iAudioChannel )
-    {
-        audioDataBlocks = iAudioChannel->iTargetQueue->NumDataBlocks();
-        audioInQueue = audioDataBlocks * 20 * iAudioFramesInSample;
-    }
-
-    if ( iAudioChannel == 0 || iAudioEnd )
-    {
-        iFrameType = EDataVideo;
-    }        
-
-    else if ( iVideoEnd )
-    {    
-        iFrameType = EDataAudio;        
-    }
-
-    else 
-    {
-        if ( audioInQueue > videoInQueue + KAudioReadAheadTimeMs )
-            iFrameType = EDataVideo;
-        else 
-            iFrameType = EDataAudio;            
-    }
-    
-    //if ( ( iFrameType == EDataVideo && videoInQueue >= KMaxMsInQueue ) || 
-    //     ( iFrameType == EDataAudio && audioInQueue >= KMaxMsInQueue + KAudioReadAheadTimeMs ) )
-    //    iFrameType = EDataNone;          
-    
-    }
-
-// ---------------------------------------------------------
-// CMP4Demux::ReadVideoFrames
-// Read video frames to video queue
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-TInt CMP4Demux::ReadVideoFrames(TInt aCount)
-{
-    
-    while (aCount--)
-    {
-        iFrameType = EDataVideo;
-
-        TBool frameAvailable = 0;
-        TInt error = iParser->GetNextFrameInformation((CMP4Parser::TFrameType&)iFrameType, 
-            iFrameLen, frameAvailable);
-
-        if (error !=KErrNone)
-            return error;
-
-        DASSERT(frameAvailable);
-
-        iGotFrame = ETrue;
-        error = ReadAndSendFrames();
-        if (error !=KErrNone)
-            return error;
-    }
-    return KErrNone;
-
-}
-
-// ---------------------------------------------------------
-// CMP4Demux::StreamEndReached
-// Reads the next frame(s) from parser and writes
-// them to the target queue
-// (other items were commented in a header).
-// ---------------------------------------------------------
-//
-
-TInt CMP4Demux::ReadAndSendFrames()
-    {    
-
-    DASSERT( iGotFrame );
-
-    // Find the correct channel. If there is no channel open for this
-    // type of frames, we'll simply ignore it
-    TOutputChannel *chan = 0;
-    TUint i;
-    for ( i = 0; i < iNumOutputChannels; i++ )
-        {
-        if ( iOutputChannels[i].iDataType == iFrameType )
-            chan = &iOutputChannels[i];
-        }    
-    
-    if ( chan )
-        {
-        // OK, we have a target channel. Get a block from its queue
-        
-        TPtr8 *block = 0;                       
-        
-        // NOTE: if output block does not need to be saved in any case, make it a local variable
-
-        //PRINT((_L("framelen = %d, bytesdemuxed = %d\n"), iFrameLen, iBytesDemuxed));
-
-        TUint blockLen = iFrameLen;
-        TPtr8 readDes(0,0);        
-        TInt error;
-
-        if ( iFrameType == EDataVideo ) 
-        {
-            // make room for timestamp
-            blockLen += 4;
-        }              
-        
-
-
-        TRAP( error, (block = chan->iTargetQueue->GetFreeBlockL(blockLen)) );
-        if ( error != KErrNone )
-            return error;        
-
-        if ( iFrameType == EDataVideo ) 
-        {
-            TUint8 *p = (TUint8 *)(block->Ptr()) + 4;
-            readDes.Set( p, 0, TInt(iFrameLen) );
-        }
-        else
-        {
-            readDes.Set( *block );
-        }
-                
-        TUint32 numReadFrames = 0;
-        TUint32 timeStamp;
-
-        // read frame(s) from parser
-        error = iParser->ReadFrames(readDes, CMP4Parser::TFrameType(iFrameType), 
-            numReadFrames, timeStamp);
-   
-        if ( error != KErrNone )
-            return error;
-
-        DASSERT( numReadFrames > 0 );   
-        
-        if ( iFrameType == EDataAudio )
-        {
-            block->SetLength(readDes.Length());            
-        }
-        else
-        {            
-            block->SetLength(readDes.Length() + 4);
-
-            // put timestamp in the output block before the actual frame data                       
-            TUint* d = (TUint *)(block->Ptr());            
-            Mem::Copy(d, &timeStamp, 4);
-        }
-
-        iBytesDemuxed += TUint( readDes.Length() );
-        
-        // Send the block
-        chan->iTargetQueue->WriteBlock(block);        
-        iFrameLen = 0;
-        iFrameType = EDataNone;
-        iGotFrame = EFalse;
-        }
-    else
-        {     
-        PRINT((_L("Unknown channel\n")));
-        }    
-    
-    return KErrNone;
-    }
-