C++程序  |  3156行  |  107.4 KB

/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/**
 * @file pvmp4ffcn_node.cpp
 * @brief Node for PV MPEG4 file format composer
 */

/*
 * FIXME:
 * The current implementation of the file writer is NOT
 * thread-safe.
 *
 * A separate delete queue should be used to
 * pass back the fragments from the file writer thread
 * to the composer node and to let the composer node
 * handle the deallocation of any fragments; otherwise,
 * race condition may occur. Some lost free chunk
 * notification has been found due to this race
 * condition.
 *
 * The reason why there is race condition is that the
 * rest of the OpenCore assumes a single-thread model.
 * In other words, everything is scheduled to
 * run within a single omx thread. A separate file writer
 * thread breaks this model, and deallocate fragments
 * here may cause deallocate() be called within two
 * separate thread, and thus the free chunk available
 * flag can be corrupted.
 *
 * Don't remove the following #undef line unless you
 * fix the above issue.
 */
#undef ANDROID

#ifdef ANDROID
// #define LOG_NDEBUG 0
#define LOG_TAG "PvMp4Composer"
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#endif // ANDROID

#ifndef PVMP4FFCN_NODE_H_INCLUDED
#include "pvmp4ffcn_node.h"
#endif
#ifndef PVMP4FFCN_FACTORY_H_INCLUDED
#include "pvmp4ffcn_factory.h"
#endif
#ifndef PVMP4FFCN_PORT_H_INCLUDED
#include "pvmp4ffcn_port.h"
#endif
#ifndef OSCL_DLL_H_INCLUDED
#include "oscl_dll.h"
#endif
#ifndef OSCL_MEM_BASIC_FUNCTIONS_H
#include "oscl_mem_basic_functions.h"
#endif

#ifdef ANDROID
namespace android
{

// FragmentWriter is a queue of media fragment to be written in the
// media file. The caller enqueues the next fragment and returns
// immediately. An separate thread dequeues the fragment and writes it.
//
// This class is friend with the composer node it belongs to, in order
// to be able to call the original AddMemFragToTrack which does all
// the work.

#define FRAME_QUEUE_DEFAULT_SIZE 20

class FragmentWriter: public Thread
{
    public:
        FragmentWriter(PVMp4FFComposerNode *composer) :
                Thread(kThreadCallJava), mComposer(composer),
                mPrevWriteStatus(PVMFSuccess), mTid(NULL), mExitRequested(false)
        {
            mQueue.reserve(FRAME_QUEUE_DEFAULT_SIZE);
        }

        virtual ~FragmentWriter()
        {
            Mutex::Autolock l(mRequestMutex);

            LOG_ASSERT(mExitRequested, "Deleting an active instance.");
            LOGD_IF(!mQueue.empty(), "Releasing %d fragments in dtor", mQueue.size());

            while (!mQueue.empty())  // make sure we are flushed
            {
                releaseQueuedFrame(mQueue.begin());
            }
        }

        // Mark the thread as exiting and kick it so it can see the
        // exitPending state.
        virtual void requestExit()
        {
            mExitRequested = true;
            Thread::requestExit();

            mRequestMutex.lock();
            mRequestCv.signal();
            mRequestMutex.unlock();
        }

        // Wait for all the fragment to be written.
        virtual void flush()
        {
            LOG_ASSERT(androidGetThreadId() != mTid, "Reentrant call");

            bool done = false;
            size_t iter = 0;
            while (!done)
            {
                mRequestMutex.lock();
                done = mQueue.empty();
                if (!done) mRequestCv.signal();
                mRequestMutex.unlock();
                if (!done) {
                    usleep(kFlushSleepMicros);
                    if ((++iter % kMaxFlushAttemptsWarning) == 0) {
                        if (iter >= kMaxFlushAttemptsCrashing) {
                            LOGE("Fragment flush takes way too long!");
                            // Crash media server!
                            *((char *) 0) = 0x01;
                        } else {
                            LOGW("Fragement writer flush takes %d us", iter * kFlushSleepMicros);
                        }
                    }
                }
            }
        }

        // Called by the ProcessIncomingMsg method from the
        // PVMp4FFComposerNode to append the fragment to the track.
        // @return The result of the *previous* fragment written. Since the call
        //         is asynch we cannot wait.
        PVMFStatus enqueueMemFragToTrack(Oscl_Vector<OsclMemoryFragment, OsclMemAllocator> aFrame,
                                         OsclRefCounterMemFrag& aMemFrag, PVMFFormatType aFormat,
                                         uint32& aTimestamp, int32 aTrackId, PVMp4FFComposerPort *aPort)
        {
            if (mExitRequested) {
                LOGW("Enqueue fragment after exit request!");
                aFrame.clear();  // Release the frame
                return PVMFErrCancelled;
            }

            Mutex::Autolock lock(mRequestMutex);
            Request frame = {aFrame, aMemFrag, aFormat, aTimestamp, aTrackId, aPort};
            mQueue.push_back(frame);
            mRequestCv.signal();
            return mPrevWriteStatus;
        }

    private:
        static const bool kThreadCallJava = false;
        static const OsclRefCounterMemFrag kEmptyFrag;
        static const int kFlushSleepMicros = 200 * 1000;    // 200 ms
        static const size_t kMaxFlushAttemptsWarning = 10;  // 2 seconds
        static const size_t kMaxFlushAttemptsCrashing = 30; // 6 seconds

        struct Request
        {
            Oscl_Vector<OsclMemoryFragment, OsclMemAllocator> mFrame;
            OsclRefCounterMemFrag mFrag;
            PVMFFormatType mFormat;
            uint32 mTimestamp;
            uint32 mTrackId;
            PVMp4FFComposerPort *mPort;
        };

        void releaseQueuedFrame(Request *frame)
        {
            if (!frame) {
                LOGE("Frame not valid");
                return;
            }
            frame->mFrame.clear();
            // Release the memory fragment tracked using a refcount
            // class. Need to assign an empty frag to release the memory
            // fragment. We cannot wait for the array to wrap around.
            frame->mFrag = kEmptyFrag;  // FIXME: This assignement to decr the ref count is ugly.
            mQueue.erase(frame);
        }

        // Called by the base class Thread.
        // @return true if there more work to do. false when done.
        // @Override Thread
        virtual bool threadLoop()
        {
            if (!mTid) mTid = androidGetThreadId();

            LOG_ASSERT(androidGetThreadId() == mTid,
                       "Thread id has changed!: %p != %p", mTid, androidGetThreadId());
            if (mExitRequested)
                return false;

            mRequestMutex.lock();
            if (mQueue.empty())
                mRequestCv.wait(mRequestMutex);

            if (!mQueue.empty()) {
                // Hold the lock while writing the fragment
                Request frame = mQueue[0];  // Make a local copy
                mPrevWriteStatus = mComposer->AddMemFragToTrack(
                        frame.mFrame, frame.mFrag, frame.mFormat,
                        frame.mTimestamp, frame.mTrackId, frame.mPort);
                if (!mQueue.empty()) {
                    releaseQueuedFrame(mQueue.begin());
                }
            }
            mRequestMutex.unlock();

            return true;
        }


        Mutex mRequestMutex;  // Protects mRequestCv, mQueue
        Condition mRequestCv;
        Oscl_Vector<Request, OsclMemAllocator> mQueue;
        // mComposer with the real implementation of the AddMemFragToTrack method.
        PVMp4FFComposerNode *mComposer;
        // TODO: lock needed for mPrevWriteStatus? Are int assignement atomic on arm?
        PVMFStatus mPrevWriteStatus;

        android_thread_id_t mTid;
        // Unlike exitPending(), stays to true once exit has been called.
        bool mExitRequested;
};
const OsclRefCounterMemFrag FragmentWriter::kEmptyFrag;
}
#endif // ANDROID

#define LOG_STACK_TRACE(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, m);
#define LOG_DEBUG(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, m);
#define LOG_ERR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m);
#define LOGDATATRAFFIC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDataPathLogger,PVLOGMSG_INFO,m);

#ifdef _TEST_AE_ERROR_HANDLING
const uint32 FAIL_NODE_CMD_START = 2;
const uint32 FAIL_NODE_CMD_STOP = 3;
const uint32 FAIL_NODE_CMD_FLUSH = 4;
const uint32 FAIL_NODE_CMD_PAUSE = 5;
const uint32 FAIL_NODE_CMD_RELEASE_PORT = 7;
#endif

#define SLASH '/'

#define LANG_CODE_SIZE 3

// Define entry point for this DLL
OSCL_DLL_ENTRY_POINT_DEFAULT()



////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFNodeInterface* PVMp4FFComposerNodeFactory::CreateMp4FFComposer(int32 aPriority)
{
    int32 err = 0;
    PVMFNodeInterface* node = NULL;

    OSCL_TRY(err,
             node = (PVMFNodeInterface*)OSCL_NEW(PVMp4FFComposerNode, (aPriority));
             if (!node)
             OSCL_LEAVE(OsclErrNoMemory);
            );

    OSCL_FIRST_CATCH_ANY(err, return NULL;);
    return node;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMp4FFComposerNodeFactory::DeleteMp4FFComposer(PVMFNodeInterface* aComposer)
{
    if (aComposer)
    {
        PVMp4FFComposerNode* node = (PVMp4FFComposerNode*)aComposer;
        OSCL_DELETE(node);
        return true;
    }

    return false;
}

////////////////////////////////////////////////////////////////////////////
PVMp4FFComposerNode::PVMp4FFComposerNode(int32 aPriority)
        : OsclActiveObject(aPriority, "PVMp4FFComposerNode")
        , iMpeg4File(NULL)
        , iFileType(0)
        , iAuthoringMode(PVMP4FF_3GPP_DOWNLOAD_MODE)
        , iPresentationTimescale(1000)
        , iMovieFragmentDuration(2000)
        , iRecordingYear(0)
        , iClockConverter(8000)
        , iExtensionRefCount(0)
        , iRealTimeTS(false)
        , iInitTSOffset(false)
        , iTSOffset(0)
        , iMaxFileSizeEnabled(false)
        , iMaxDurationEnabled(false)
        , iMaxFileSize(0)
        , iMaxTimeDuration(0)
        , iFileSizeReportEnabled(false)
        , iDurationReportEnabled(false)
        , iFileSizeReportFreq(0)
        , iDurationReportFreq(0)
        , iNextDurationReport(0)
        , iNextFileSizeReport(0)
        , iCacheSize(0)
        , iConfigSize(0)
        , pConfig(NULL)
        , iTrackId_H264(0)
        , iTrackId_Text(0)
        , iSyncSample(0)
        , iformat_h264(PVMF_MIME_FORMAT_UNKNOWN)
        , iformat_text(PVMF_MIME_FORMAT_UNKNOWN)
        , iNodeEndOfDataReached(false)
        , iSampleInTrack(false)
        , iFileRendered(false)
{
    iInterfaceState = EPVMFNodeCreated;
    iNum_PPS_Set = 0;
    iNum_SPS_Set = 0;
    iText_sdIndex = 0;
    iFileObject = NULL;
#if PROFILING_ON
    iMaxSampleAddTime = 0;
    iMinSampleAddTime = 0;
    iMinSampleSize = 0;
    iMaxSampleSize = 0;
    iNumSamplesAdded = 0;
    oDiagnosticsLogged = false;
    iDiagnosticsLogger = PVLogger::GetLoggerObject("pvauthordiagnostics.composer.mp4");
    // Statistics
    for (uint32 i = 0; i < 3; i++)
        oscl_memset(&(iStats[i]), 0, sizeof(PVMp4FFCNStats));
#endif

    iLogger = PVLogger::GetLoggerObject("PVMp4FFComposerNode");
    iDataPathLogger = PVLogger::GetLoggerObject("datapath.sinknode.mp4composer");
    int32 err;
    OSCL_TRY(err,
             //Create the input command queue.  Use a reserve to avoid lots of
             //dynamic memory allocation.
             iCmdQueue.Construct(PVMF_MP4FFCN_COMMAND_ID_START, PVMF_MP4FFCN_COMMAND_VECTOR_RESERVE);
             iCurrentCmd.Construct(0, 1); // There's only 1 current command


             //Create the port vector.
             iInPorts.Construct(PVMF_MP4FFCN_PORT_VECTOR_RESERVE);
            );

    OSCL_FIRST_CATCH_ANY(err,
                         //if a leave happened, cleanup and re-throw the error
                         iCmdQueue.clear();
                         iCurrentCmd.clear();
                         iInPorts.clear();
                         memvector_sps.clear();
                         memvector_pps.clear();
                         OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface);
                         OSCL_CLEANUP_BASE_CLASS(OsclActiveObject);
                         OSCL_LEAVE(err);
                        );

#ifdef ANDROID
    iMaxReachedEvent = 0;
    iMaxReachedReported = false;
    iFragmentWriter = new android::FragmentWriter(this);
    iFragmentWriter->run(LOG_TAG);
#endif

#ifdef _TEST_AE_ERROR_HANDLING
    iErrorHandlingAddMemFrag = false;
    iErrorHandlingAddTrack = false;
    iErrorCreateComposer = false;
    iErrorRenderToFile = false;
    iErrorAddTrack = PVMF_MIME_FORMAT_UNKNOWN;
    iErrorNodeCmd = 0;
    iTestFileSize = 0;
    iTestTimeStamp = 0;
    iErrorAddSample = 0;
    iFileSize = 0;
    iFileDuration = 0;
    iErrorDataPathStall = 0;
#endif
}

////////////////////////////////////////////////////////////////////////////
PVMp4FFComposerNode::~PVMp4FFComposerNode()
{
#if PROFILING_ON
    if (!oDiagnosticsLogged)
    {
        LogDiagnostics();
    }
#endif

#ifdef ANDROID
    if (iFragmentWriter != NULL)
    {
        iFragmentWriter->requestExit(); // kick the thread
        iFragmentWriter->requestExitAndWait();
    }
#endif

    if (iMpeg4File)
    {
        PVA_FF_IMpeg4File::DestroyMP4FileObject(iMpeg4File);

        if (!iFileRendered)
        {
            iFs.Connect();
            iFs.Oscl_DeleteFile(iFileName.get_cstr());
            iFs.Close();
        }
    }
    if (iFileObject)
    {
        iFileObject->Close();
        OSCL_DELETE(iFileObject);
        iFileObject = NULL;
    }
    for (uint32 i = 0; i < iKeyWordVector.size() ; i++)
    {
        if (iKeyWordVector[i] != NULL)
        {
            OSCL_DELETE(iKeyWordVector[i]);
            iKeyWordVector[i] = NULL;
        }

    }

    if (pConfig != NULL)
    {
        OSCL_FREE(pConfig);
        iConfigSize = 0;
    }

    if (iLocationInfo._location_name != NULL)
    {
        OSCL_FREE(iLocationInfo._location_name);
    }

    if (iLocationInfo._astronomical_body != NULL)
    {
        OSCL_FREE(iLocationInfo._astronomical_body);
    }

    if (iLocationInfo._additional_notes != NULL)
    {
        OSCL_FREE(iLocationInfo._additional_notes);
    }
    // Cleanup allocated ports
    while (!iInPorts.empty())
    {
        iInPorts.Erase(&iInPorts.front());

    }
    //Cleanup commands
    //The command queues are self-deleting, but we want to
    //notify the observer of unprocessed commands.
    while (!iCmdQueue.empty())
    {
        CommandComplete(iCmdQueue, iCmdQueue[0], PVMFFailure);
    }

    while (!iCurrentCmd.empty())
    {
        CommandComplete(iCurrentCmd, iCurrentCmd[0], PVMFFailure);
    }
    iNodeEndOfDataReached = false;

    Cancel();
    if (iInterfaceState != EPVMFNodeCreated)
        iInterfaceState = EPVMFNodeIdle;

}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::ThreadLogon()
{
    switch (iInterfaceState)
    {
        case EPVMFNodeCreated:
            if (!IsAdded())
                AddToScheduler();
            SetState(EPVMFNodeIdle);
            return PVMFSuccess;
        default:
            return PVMFErrInvalidState;
    }
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::ThreadLogoff()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMp4FFComposerNode:ThreadLogoff"));
    switch (iInterfaceState)
    {
        case EPVMFNodeIdle:
            if (IsAdded())
                RemoveFromScheduler();
            iLogger = NULL;
            iDataPathLogger = NULL;
            SetState(EPVMFNodeCreated);
            return PVMFSuccess;

        default:
            return PVMFErrInvalidState;
    }
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
    aNodeCapability.iCanSupportMultipleInputPorts = true;
    aNodeCapability.iCanSupportMultipleOutputPorts = false;
    aNodeCapability.iHasMaxNumberOfPorts = true;
    aNodeCapability.iMaxNumberOfPorts = PVMF_MP4FFCN_MAX_INPUT_PORT + PVMF_MP4FFCN_MAX_OUTPUT_PORT;
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_M4V);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_H264_VIDEO_MP4);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_H2631998);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_H2632000);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_AMR_IETF);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_AMRWB_IETF);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_3GPP_TIMEDTEXT);
    aNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_MPEG4_AUDIO);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFPortIter* PVMp4FFComposerNode::GetPorts(const PVMFPortFilter* aFilter)
{
    OSCL_UNUSED_ARG(aFilter);
    iInPorts.Reset();
    return &iInPorts;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::QueryUUID(PVMFSessionId aSession, const PvmfMimeString& aMimeType,
        Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
        bool aExactUuidsOnly, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::QueryUUID"));

    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::QueryInterface(PVMFSessionId aSession, const PVUuid& aUuid,
        PVInterface*& aInterfacePtr,
        const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMp4FFComposerNode::QueryInterface"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Init(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Init"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_INIT, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Prepare(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Prepare"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_PREPARE, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::RequestPort(PVMFSessionId aSession,
        int32 aPortTag,
        const PvmfMimeString* aPortConfig,
        const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::RequestPort"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::ReleasePort(PVMFSessionId aSession,
        PVMFPortInterface& aPort,
        const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::ReleasePort"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_RELEASEPORT, aPort, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Start(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Start"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_START, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Stop(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Stop"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_STOP, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Pause(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Pause"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_PAUSE, aContext);
    return QueueCommandL(cmd);
}

OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Flush(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Flush"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_FLUSH, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::Reset(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::Reset"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_RESET, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::CancelAllCommands(PVMFSessionId aSession, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::CancelAllCommands"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_CANCELALLCOMMANDS, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMp4FFComposerNode::CancelCommand(PVMFSessionId aSession, PVMFCommandId aCmdId, const OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::CancelCommand"));
    PVMp4FFCNCmd cmd;
    cmd.Construct(aSession, PVMF_GENERIC_NODE_CANCELCOMMAND, aCmdId, aContext);
    return QueueCommandL(cmd);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::addRef()
{
    ++iExtensionRefCount;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::removeRef()
{
    if (iExtensionRefCount > 0)
        --iExtensionRefCount;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMp4FFComposerNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
    if (uuid == KPVMp4FFCNClipConfigUuid)
    {
        PVMp4FFCNClipConfigInterface* myInterface = OSCL_STATIC_CAST(PVMp4FFCNClipConfigInterface*, this);
        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
        ++iExtensionRefCount;
    }
    else if (uuid == KPVMp4FFCNTrackConfigUuid)
    {
        PVMp4FFCNTrackConfigInterface* myInterface = OSCL_STATIC_CAST(PVMp4FFCNTrackConfigInterface*, this);
        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
        ++iExtensionRefCount;
    }
    else if (uuid == PvmfComposerSizeAndDurationUuid)
    {
        PvmfComposerSizeAndDurationInterface* myInterface = OSCL_STATIC_CAST(PvmfComposerSizeAndDurationInterface*, this);
        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
        ++iExtensionRefCount;
    }
    else if (uuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID)
    {
        PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, this);
        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
        ++iExtensionRefCount;
    }
    else
    {
        iface = NULL;
        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////
//            PVMp4FFCNClipConfigInterface routines
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF uint16 PVMp4FFComposerNode::ConvertLangCode(const OSCL_String & aLang)
{
    int i = 0;
    char lang[LANG_CODE_SIZE] = {0};
    oscl_strncpy(lang, aLang.get_cstr(), LANG_CODE_SIZE);

    uint16 lang_code = ((((uint16)lang[i] - 0x60) << 10) | (((uint16)lang[i+1] - 0x60) << 5) | ((uint16)lang[i+2] - 0x60));

    return lang_code;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetOutputFileName(const OSCL_wString& aFileName)
{
    if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized)
        return false;

    iFileName = aFileName;
    return PVMFSuccess;
}
//////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetOutputFileDescriptor(const OsclFileHandle* aFileHandle)
{
    if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized)
        return false;

    iFileObject = OSCL_NEW(Oscl_File, (0, (OsclFileHandle *)aFileHandle));
    iFileObject->SetPVCacheSize(0);
    iFileObject->SetAsyncReadBufferSize(0);
    iFileObject->SetNativeBufferSize(0);
    iFileObject->SetLoggingEnable(false);
    iFileObject->SetSummaryStatsLoggingEnable(false);
    iFileObject->SetFileHandle((OsclFileHandle*)aFileHandle);

    //call open
    int32 retval = iFileObject->Open(_STRLIT_CHAR("dummy"),
                                     Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY,
                                     iFs);

    if (retval == 0)
    {
        return PVMFSuccess;
    }
    return PVMFFailure;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetAuthoringMode(PVMp4FFCN_AuthoringMode aAuthoringMode)
{
    if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized)
        return PVMFErrInvalidState;

    iAuthoringMode = aAuthoringMode;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetPresentationTimescale(uint32 aTimescale)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iPresentationTimescale = aTimescale;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetVersion(const OSCL_wString& aVersion, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iVersion.iDataString = aVersion;
    iVersion.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetTitle(const OSCL_wString& aTitle, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iTitle.iDataString = aTitle;
    iTitle.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetAuthor(const OSCL_wString& aAuthor, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iAuthor.iDataString = aAuthor;
    iAuthor.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetCopyright(const OSCL_wString& aCopyright, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iCopyright.iDataString = aCopyright;
    iCopyright.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetDescription(const OSCL_wString& aDescription, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iDescription.iDataString = aDescription;
    iDescription.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetRating(const OSCL_wString& aRating, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iRating.iDataString = aRating;
    iRating.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetCreationDate(const OSCL_wString& aCreationDate)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iCreationDate = aCreationDate;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::SetRealTimeAuthoring(const bool aRealTime)
{
    if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized)
        return PVMFErrInvalidState;

    iRealTimeTS = aRealTime;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetAlbumInfo(const OSCL_wString& aAlbumTitle, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iAlbumTitle.iDataString = aAlbumTitle;
    iAlbumTitle.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}


////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetRecordingYear(uint16 aRecordingYear)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iRecordingYear = aRecordingYear;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetPerformer(const OSCL_wString& aPerformer, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iPerformer.iDataString = aPerformer;
    iPerformer.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetGenre(const OSCL_wString& aGenre, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iGenre.iDataString = aGenre;
    iGenre.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetClassification(const OSCL_wString& aClassificationInfo, uint32 aClassificationEntity, uint16 aClassificationTable, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iClassification.iDataString = aClassificationInfo;
    iClassification.iClassificationEntity = aClassificationEntity;
    iClassification.iClassificationTable = aClassificationTable;
    iClassification.iLangCode = ConvertLangCode(aLangCode);
    return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetKeyWord(const OSCL_wString& aKeyWordInfo, const OSCL_String& aLangCode)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    PVMP4FFCN_KeyWord *KeyWord = NULL;

    uint16 langCode = ConvertLangCode(aLangCode);
    KeyWord = OSCL_NEW(PVMP4FFCN_KeyWord, (aKeyWordInfo, aKeyWordInfo.get_size(), langCode));

    iKeyWordVector.push_back(KeyWord);


    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetLocationInfo(PvmfAssetInfo3GPPLocationStruct& aLocation_info)
{
    if (iInterfaceState != EPVMFNodeIdle &&
            iInterfaceState != EPVMFNodeInitialized &&
            iInterfaceState != EPVMFNodePrepared)
        return PVMFErrInvalidState;

    iLocationInfo._location_name = NULL;
    uint32 size = oscl_strlen(aLocation_info._location_name);
    iLocationInfo._location_name = (oscl_wchar*)oscl_malloc(sizeof(oscl_wchar) * size + 10);
    oscl_strncpy(iLocationInfo._location_name, aLocation_info._location_name, size);
    iLocationInfo._location_name[size+1] = 0;

    iLocationInfo._astronomical_body = NULL;
    size = oscl_strlen(aLocation_info._astronomical_body);
    iLocationInfo._astronomical_body = (oscl_wchar*)oscl_malloc(sizeof(oscl_wchar) * size + 10);
    oscl_strncpy(iLocationInfo._astronomical_body, aLocation_info._astronomical_body, size);
    iLocationInfo._astronomical_body[size+1] = 0;

    iLocationInfo._additional_notes = NULL;
    size = oscl_strlen(aLocation_info._additional_notes);
    iLocationInfo._additional_notes = (oscl_wchar*)oscl_malloc(sizeof(oscl_wchar) * size + 10);
    oscl_strncpy(iLocationInfo._additional_notes, aLocation_info._additional_notes, size);
    iLocationInfo._additional_notes[size+1] = 0;

    iLocationInfo._role = aLocation_info._role;
    iLocationInfo._longitude = aLocation_info._longitude;
    iLocationInfo._latitude = aLocation_info._latitude;
    iLocationInfo._altitude = aLocation_info._altitude;
    iLocationInfo._langCode = ConvertLangCode(aLocation_info.Lang_code);

    return PVMFSuccess;
}


////////////////////////////////////////////////////////////////////////////
//                PVMp4FFCNTrackConfigInterface routines
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetTrackReference(const PVMFPortInterface& aPort,
        const PVMFPortInterface& aReferencePort)
{
    if (iInterfaceState != EPVMFNodeInitialized)
        return PVMFErrInvalidState;

    int32 portIndex = -1;
    int32 refPortIndex = -1;
    PVMp4FFComposerPort* port = OSCL_REINTERPRET_CAST(PVMp4FFComposerPort*, &aPort);
    PVMp4FFComposerPort* refPort = OSCL_REINTERPRET_CAST(PVMp4FFComposerPort*, &aReferencePort);

    for (uint32 i = 0; i < iInPorts.size(); i++)
    {
        if (iInPorts[i] == port)
            portIndex = i;
        if (iInPorts[i] == refPort)
            refPortIndex = i;
    }

    if (portIndex > 0 && refPortIndex > 0)
    {
        iInPorts[portIndex]->SetReferencePort(iInPorts[refPortIndex]);
        return PVMFSuccess;
    }
    else
        return PVMFFailure;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetCodecSpecificInfo(const PVMFPortInterface& aPort,
        uint8* aInfo, int32 aSize)
{
    PVMFStatus status = PVMFFailure;

    if ((status == PVMFSuccess) &&
            (iInterfaceState == EPVMFNodeStarted))
    {
        PVMp4FFComposerPort* port = OSCL_STATIC_CAST(PVMp4FFComposerPort*, &aPort);
        iMpeg4File->setDecoderSpecificInfo(aInfo, aSize, port->GetTrackId());
    }

    return status;
}

////////////////////////////////////////////////////////////////////////////
//          PvmfComposerSizeAndDurationInterface routines
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetMaxFileSize(bool aEnable, uint32 aMaxFileSizeBytes)
{
    iMaxFileSizeEnabled = aEnable;
    if (iMaxFileSizeEnabled)
    {
        iMaxFileSize = aMaxFileSizeBytes;
    }
    else
    {
        iMaxFileSize = 0;
    }

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::GetMaxFileSizeConfig(bool& aEnable, uint32& aMaxFileSizeBytes)
{
    aEnable = iMaxFileSizeEnabled;
    aMaxFileSizeBytes = iMaxFileSize;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetMaxDuration(bool aEnable, uint32 aMaxDurationMilliseconds)
{
    iMaxDurationEnabled = aEnable;
    if (iMaxDurationEnabled)
    {
        iMaxTimeDuration = aMaxDurationMilliseconds;
    }
    else
    {
        iMaxTimeDuration = 0;
    }

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::GetMaxDurationConfig(bool& aEnable, uint32& aMaxDurationMilliseconds)
{
    aEnable = iMaxDurationEnabled;
    aMaxDurationMilliseconds = iMaxTimeDuration;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetFileSizeProgressReport(bool aEnable, uint32 aReportFrequency)
{
    iFileSizeReportEnabled = aEnable;
    if (iFileSizeReportEnabled)
    {
        iFileSizeReportFreq = aReportFrequency;
    }

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::GetFileSizeProgressReportConfig(bool& aEnable, uint32& aReportFrequency)
{
    aEnable = iFileSizeReportEnabled;
    aReportFrequency = iFileSizeReportFreq;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetDurationProgressReport(bool aEnable, uint32 aReportFrequency)
{
    iDurationReportEnabled = aEnable;
    if (iDurationReportEnabled)
    {
        iDurationReportFreq = aReportFrequency;
    }

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMp4FFComposerNode::GetDurationProgressReportConfig(bool& aEnable, uint32& aReportFrequency)
{
    aEnable = iDurationReportEnabled;
    aReportFrequency = iDurationReportFreq;
}

////////////////////////////////////////////////////////////////////////////
//            PVMFPortActivityHandler routines
////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::HandlePortActivity(const PVMFPortActivity& aActivity)
{
    OSCL_UNUSED_ARG(aActivity);
    // Scheduling to process port activities are handled in the port itself
}

////////////////////////////////////////////////////////////////////////////
//                    OsclActiveObject routines
////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::Run()
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::Run: iInterfaceState=%d", iInterfaceState));

    if (!iCmdQueue.empty())
    {
        if (ProcessCommand(iCmdQueue.front()))
        {
            //note: need to check the state before re-scheduling
            //since the node could have been reset in the ProcessCommand
            //call.
            if (iInterfaceState != EPVMFNodeCreated)
                RunIfNotReady();
            return;
        }
    }

    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::Run: Out. iInterfaceState=%d", iInterfaceState));
}


////////////////////////////////////////////////////////////////////////////
//                   Command Processing routines
////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMp4FFComposerNode::QueueCommandL(PVMp4FFCNCmd& aCmd)
{
    int32 err = 0;
    PVMFCommandId id = 0;

    OSCL_TRY(err, id = iCmdQueue.AddL(aCmd););
    OSCL_FIRST_CATCH_ANY(err,
                         OSCL_LEAVE(err);
                         return 0;
                        );

    // Wakeup the AO
    RunIfNotReady();
    return id;
}

////////////////////////////////////////////////////////////////////////////
bool PVMp4FFComposerNode::ProcessCommand(PVMp4FFCNCmd& aCmd)
{
    //normally this node will not start processing one command
    //until the prior one is finished.  However, a hi priority
    //command such as Cancel must be able to interrupt a command
    //in progress.
    if (!iCurrentCmd.empty() && !aCmd.hipri())
        return false;

    switch (aCmd.iCmd)
    {
        case PVMF_GENERIC_NODE_QUERYUUID:
            DoQueryUuid(aCmd);
            break;

        case PVMF_GENERIC_NODE_QUERYINTERFACE:
            DoQueryInterface(aCmd);
            break;

        case PVMF_GENERIC_NODE_REQUESTPORT:
            DoRequestPort(aCmd);
            break;

        case PVMF_GENERIC_NODE_RELEASEPORT:
            DoReleasePort(aCmd);
            break;

        case PVMF_GENERIC_NODE_INIT:
            DoInit(aCmd);
            break;

        case PVMF_GENERIC_NODE_PREPARE:
            DoPrepare(aCmd);
            break;

        case PVMF_GENERIC_NODE_START:
            DoStart(aCmd);
            break;

        case PVMF_GENERIC_NODE_STOP:
            DoStop(aCmd);
            break;

        case PVMF_GENERIC_NODE_FLUSH:
            DoFlush(aCmd);
            break;

        case PVMF_GENERIC_NODE_PAUSE:
            DoPause(aCmd);
            break;

        case PVMF_GENERIC_NODE_RESET:
            DoReset(aCmd);
            break;

        case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
            DoCancelAllCommands(aCmd);
            break;

        case PVMF_GENERIC_NODE_CANCELCOMMAND:
            DoCancelCommand(aCmd);
            break;

        default://unknown command type
            CommandComplete(iCmdQueue, aCmd, PVMFFailure);
            break;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::CommandComplete(PVMp4FFCNCmdQueue& aCmdQueue, PVMp4FFCNCmd& aCmd,
        PVMFStatus aStatus, OsclAny* aEventData)
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode:CommandComplete: Id %d Cmd %d Status %d Context %d Data %d"
                     , aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));

    //create response
    PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, aEventData);
    PVMFSessionId session = aCmd.iSession;

    //Erase the command from the queue.
    aCmdQueue.Erase(&aCmd);

    //Report completion to the session observer.
    ReportCmdCompleteEvent(session, resp);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoQueryUuid(PVMp4FFCNCmd& aCmd)
{
    OSCL_String* mimetype;
    Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
    bool exactmatch;
    aCmd.Parse(mimetype, uuidvec, exactmatch);

    uuidvec->push_back(KPVMp4FFCNClipConfigUuid);
    uuidvec->push_back(KPVMp4FFCNTrackConfigUuid);
    uuidvec->push_back(PvmfComposerSizeAndDurationUuid);

    CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoQueryInterface(PVMp4FFCNCmd& aCmd)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMp4FFComposerNode::DoQueryInterface"));

    PVUuid* uuid;
    PVInterface** ptr;
    aCmd.Parse(uuid, ptr);

    if (queryInterface(*uuid, *ptr))
    {
        CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
    }
    else
    {
        CommandComplete(iCmdQueue, aCmd, PVMFFailure);
    }
}


//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoRequestPort(PVMp4FFCNCmd& aCmd)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMp4FFComposerNode::DoRequestPort() In"));

    int32 tag;
    OSCL_String* portconfig;
    aCmd.Parse(tag, portconfig);

    //validate the tag...
    switch (tag)
    {
        case PVMF_MP4FFCN_PORT_TYPE_SINK:
            if (iInPorts.size() >= PVMF_MP4FFCN_MAX_INPUT_PORT)
            {
                LOG_ERR((0, "PVMp4FFComposerNode::DoRequestPort: Error - Max number of input port already allocated"));
                CommandComplete(iCmdQueue, aCmd, PVMFFailure);
                return;
            }
            break;

        default:
            //bad port tag
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                            (0, "PVMp4FFComposerNode::DoRequestPort: Error - Invalid port tag"));
            CommandComplete(iCmdQueue, aCmd, PVMFFailure);
            return;
    }

    //Allocate a new port
    OsclAny *ptr = NULL;
    int32 err;
    OSCL_TRY(err,
             ptr = iInPorts.Allocate();
             if (!ptr)
             OSCL_LEAVE(OsclErrNoMemory);
            );

    OSCL_FIRST_CATCH_ANY(err,
                         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                                         (0, "PVMp4FFComposerNode::DoRequestPort: Error - iInPorts Out of memory"));
                         CommandComplete(iCmdQueue, aCmd, PVMFErrNoMemory);
                         return;
                        );

    OSCL_StackString<20> portname;
    portname = "PVMP4ComposerIn";

    PVMp4FFComposerPort* port = OSCL_PLACEMENT_NEW(ptr, PVMp4FFComposerPort(tag, this, Priority(), portname.get_cstr()));

    // if format was provided in mimestring, set it now.
    if (portconfig)
    {
        PVMFFormatType format = portconfig->get_str();
        if (format == PVMF_MIME_3GPP_TIMEDTEXT ||
                format == PVMF_MIME_H264_VIDEO_MP4 ||
                format == PVMF_MIME_M4V ||
                format == PVMF_MIME_H2631998 ||
                format == PVMF_MIME_H2632000 ||
                format == PVMF_MIME_AMR_IETF ||
                format == PVMF_MIME_AMRWB_IETF ||
                format == PVMF_MIME_ADIF ||
                format == PVMF_MIME_ADTS ||
                format == PVMF_MIME_MPEG4_AUDIO)
        {
            port->SetFormat(format);
        }
        else
        {
            CommandComplete(iCmdQueue, aCmd, PVMFErrNotSupported);
            return;
        }
    }

    //Add the port to the port vector.
    OSCL_TRY(err, iInPorts.AddL(port););
    OSCL_FIRST_CATCH_ANY(err,
                         iInPorts.DestructAndDealloc(port);
                         CommandComplete(iCmdQueue, aCmd, PVMFErrNoMemory);
                         return;
                        );

    // Return the port pointer to the caller.
    CommandComplete(iCmdQueue, aCmd, PVMFSuccess, (OsclAny*)port);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoReleasePort(PVMp4FFCNCmd& aCmd)
{
    //Find the port in the port vector
    PVMFPortInterface* p = NULL;

    for (uint32 i = 0; i < iInPorts.size(); i++)
    {
        aCmd.Parse(p);

        PVMp4FFComposerPort* port = (PVMp4FFComposerPort*)p;

        PVMp4FFComposerPort** portPtr = iInPorts.FindByValue(port);
        if (portPtr)
        {
            //delete the port.
            iInPorts.Erase(portPtr);

#ifdef _TEST_AE_ERROR_HANDLING
            if (FAIL_NODE_CMD_RELEASE_PORT == iErrorNodeCmd)
            {
                CommandComplete(iCmdQueue, aCmd, PVMFFailure);

            }
            else
            {
                CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
            }
#else
            CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
#endif

        }
        else
        {
            //port not found.
            CommandComplete(iCmdQueue, aCmd, PVMFFailure);
        }

    }
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoInit(PVMp4FFCNCmd& aCmd)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMp4FFComposerNode::DoInitNode() In"));

    switch (iInterfaceState)
    {
        case EPVMFNodeIdle:
            // Creation of file format library is done in DoStart. Nothing to do here.
            SetState(EPVMFNodeInitialized);
            CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
            break;
        case EPVMFNodeInitialized:
            CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
            break;

        default:
            CommandComplete(iCmdQueue, aCmd, PVMFErrInvalidState);
            break;
    }
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoPrepare(PVMp4FFCNCmd& aCmd)
{
    switch (iInterfaceState)
    {
        case EPVMFNodeInitialized:
            // Creation of file format library is done in DoStart. Nothing to do here.
            SetState(EPVMFNodePrepared);
            CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
            break;
        case EPVMFNodePrepared:
            CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
            break;

        default:
            CommandComplete(iCmdQueue, aCmd, PVMFErrInvalidState);
            break;
    }
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoStart(PVMp4FFCNCmd& aCmd)
{
    PVMFStatus status = PVMFSuccess;
    uint32 i = 0;
#ifdef _TEST_AE_ERROR_HANDLING
    if (FAIL_NODE_CMD_START == iErrorNodeCmd)
    {
        iInterfaceState = EPVMFNodeError;
    }
#endif
    switch (iInterfaceState)
    {
        case EPVMFNodePrepared:
        {
            iPostfix = _STRLIT("00");
            iOutputPath = _STRLIT("");
            int32 pos = 0;
            for (pos = iFileName.get_size() - 1; pos >= 0; pos--)
            {
                if (iFileName[pos] == SLASH)
                    break;
            }

            if (pos == -1)
            {
                iOutputPath = _STRLIT(".");
            }
            else
            {
                for (i = 0; i <= (uint32) pos; i++)
                    iOutputPath += iFileName[i];
            }



            iFileType = 0;
            for (i = 0; i < iInPorts.size(); i++)
            {
                if (iInPorts[i]->GetFormat() == PVMF_MIME_H264_VIDEO_MP4 ||
                        iInPorts[i]->GetFormat() == PVMF_MIME_M4V ||
                        iInPorts[i]->GetFormat() == PVMF_MIME_H2631998 ||
                        iInPorts[i]->GetFormat() == PVMF_MIME_H2632000)
                {
                    iFileType |= FILE_TYPE_VIDEO;
                }
                else if (iInPorts[i]->GetFormat() == PVMF_MIME_AMR_IETF ||
                         iInPorts[i]->GetFormat() == PVMF_MIME_AMRWB_IETF ||
                         iInPorts[i]->GetFormat() == PVMF_MIME_MPEG4_AUDIO)
                {
                    iFileType |= FILE_TYPE_AUDIO;
                }
                else if (iInPorts[i]->GetFormat() == PVMF_MIME_3GPP_TIMEDTEXT)
                {
                    iFileType |= FILE_TYPE_TIMED_TEXT;
                }
                else
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::DoStart: Error - Unsupported format"));
                    return;
                }
            }

            if (iMpeg4File)
            {
                LOG_ERR((0, "PVMp4FFComposerNode::DoStart: Error - File format library already exists"));
                CommandComplete(iCmdQueue, aCmd, PVMFFailure);
                return;
            }

            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
                            (0, "PVMp4FFComposerNode::DoStart: Calling PVA_FF_IMpeg4File::createMP4File(%d,0x%x,%d)",
                             iFileType, &iFs, iAuthoringMode));
#ifdef _TEST_AE_ERROR_HANDLING //test case to fail mp4 file parser
            if (iErrorCreateComposer)
            {
                //to fail createMP4File()
                OSCL_wHeapString<OsclMemAllocator> ErrFileName;

                iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iOutputPath, iPostfix,
                             (void*) & iFs, iAuthoringMode, ErrFileName, iCacheSize);

            }
            else
            {
                if (iFileObject != NULL)
                {
                    iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iAuthoringMode, iFileObject, iCacheSize);

                }
                else
                {

                    iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iOutputPath, iPostfix,
                                 (void*) & iFs, iAuthoringMode, iFileName, iCacheSize);

                }
            }
#else
            if (iFileObject != NULL)
            {
                iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iAuthoringMode, iFileObject, iCacheSize);

            }
            else
            {
                iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iOutputPath, iPostfix,
                             (void*) & iFs, iAuthoringMode, iFileName, iCacheSize);
            }
#endif
            if (!iMpeg4File)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                (0, "PVMp4FFComposerNode::DoStart: Error - PVA_FF_IMpeg4File::createMP4File failed"));
                CommandComplete(iCmdQueue, aCmd, PVMFFailure);
                return;
            }

            iMpeg4File->setPresentationTimescale(iPresentationTimescale);
            iMpeg4File->setVersion(iVersion.iDataString, iVersion.iLangCode);
            iMpeg4File->setTitle(iTitle.iDataString, iTitle.iLangCode);
            iMpeg4File->setAuthor(iAuthor.iDataString, iAuthor.iLangCode);
            iMpeg4File->setCopyright(iCopyright.iDataString, iCopyright.iLangCode);
            iMpeg4File->setDescription(iDescription.iDataString, iDescription.iLangCode);
            iMpeg4File->setRating(iRating.iDataString, iRating.iLangCode);
            if(iCreationDate.get_size() > 0)
            {
                iMpeg4File->setCreationDate(iCreationDate);
            }
            iMpeg4File->setMovieFragmentDuration(iMovieFragmentDuration);
            iMpeg4File->setAlbumInfo(iAlbumTitle.iDataString, iAlbumTitle.iLangCode);
            iMpeg4File->setRecordingYear(iRecordingYear);

            iMpeg4File->setPerformer(iPerformer.iDataString, iPerformer.iLangCode);
            iMpeg4File->setGenre(iGenre.iDataString, iGenre.iLangCode);
            iMpeg4File->setClassification(iClassification.iDataString, iClassification.iClassificationEntity, iClassification.iClassificationTable, iClassification.iLangCode);

            for (i = 0; i < iKeyWordVector.size() ; i++)
            {
                iMpeg4File->setKeyWord(iKeyWordVector[i]->iKeyWordSize, iKeyWordVector[i]->iData_String, iKeyWordVector[i]->iLang_Code);
            }

            iMpeg4File->setLocationInfo(&iLocationInfo);
            for (i = 0; i < iInPorts.size(); i++)
            {
                status = AddTrack(iInPorts[i]);
                if (status != PVMFSuccess)
                {
                    CommandComplete(iCmdQueue, aCmd, status);
                    return;
                }
            }

            // Check for and set reference tracks after track IDs are assigned
            PVMp4FFComposerPort* refPort = NULL;
            for (i = 0; i < iInPorts.size(); i++)
            {
                refPort = OSCL_STATIC_CAST(PVMp4FFComposerPort*, iInPorts[i]->GetReferencePort());
                if (refPort)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
                                    (0, "PVMp4FFComposerNode::DoStart: Calling addTrackReference(%d, %d)",
                                     iInPorts[i]->GetTrackId(), refPort->GetTrackId()));
                    iMpeg4File->addTrackReference(iInPorts[i]->GetTrackId(), refPort->GetTrackId());
                }
            }

            iMpeg4File->prepareToEncode();

            iInitTSOffset = true;
            iTSOffset = 0;
            SetState(EPVMFNodeStarted);
            break;
        }

        case EPVMFNodePaused:
            SetState(EPVMFNodeStarted);
            for (i = 0; i < iInPorts.size(); i++)
                ((PVMp4FFComposerPort*)iInPorts[i])->ProcessIncomingMsgReady();
            break;
        case EPVMFNodeStarted:
            status = PVMFSuccess;
            break;
        default:
            status = PVMFErrInvalidState;
            break;
    }

    CommandComplete(iCmdQueue, aCmd, status);
}

//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::AddTrack(PVMp4FFComposerPort *aPort)
{
    int32 codecType = 0;
    int32 mediaType = 0;
    int32 trackId = 0;
    PVMP4FFCNFormatSpecificConfig* config = aPort->GetFormatSpecificConfig();
    if (!config)
    {
        LOG_ERR((0, "PVMp4FFComposerNode::AddTrack: Error - GetFormatSpecificConfig failed"));
        return PVMFFailure;
    }

    if (aPort->GetFormat() == PVMF_MIME_3GPP_TIMEDTEXT)
    {
        codecType = CODEC_TYPE_TIMED_TEXT;
        mediaType = MEDIA_TYPE_TEXT;
    }
    else if (aPort->GetFormat() == PVMF_MIME_H264_VIDEO_MP4)
    {
        codecType = CODEC_TYPE_AVC_VIDEO;
        mediaType = MEDIA_TYPE_VISUAL;
    }
    else if (aPort->GetFormat() == PVMF_MIME_M4V)
    {
        codecType = CODEC_TYPE_MPEG4_VIDEO;
        mediaType = MEDIA_TYPE_VISUAL;
    }
    else if (aPort->GetFormat() == PVMF_MIME_H2631998 ||
             aPort->GetFormat() == PVMF_MIME_H2632000)
    {
        codecType = CODEC_TYPE_BASELINE_H263_VIDEO;
        mediaType = MEDIA_TYPE_VISUAL;
    }
    else if (aPort->GetFormat() == PVMF_MIME_AMR_IETF)
    {
        codecType = CODEC_TYPE_AMR_AUDIO;
        mediaType = MEDIA_TYPE_AUDIO;
    }
    else if (aPort->GetFormat() == PVMF_MIME_AMRWB_IETF)
    {
        codecType = CODEC_TYPE_AMR_WB_AUDIO;
        mediaType = MEDIA_TYPE_AUDIO;
    }
    else if (aPort->GetFormat() ==  PVMF_MIME_MPEG4_AUDIO)
    {
        codecType = CODEC_TYPE_AAC_AUDIO;
        mediaType = MEDIA_TYPE_AUDIO;
    }
    else
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                        (0, "PVMp4FFComposerNode::AddTrack: Error - Unsupported format"));
        return PVMFFailure;
    }

    aPort->SetCodecType(codecType);

    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
                    (0, "PVMp4FFComposerNode::AddTrack: Calling PVA_FF_IMpeg4File::addTrack(0x%x,0x%x)",
                     mediaType, codecType));
#ifdef _TEST_AE_ERROR_HANDLING
    if (aPort->GetFormat() == iErrorAddTrack)
    {
        return PVMFFailure;
    }
#endif
    trackId = iMpeg4File->addTrack(mediaType, codecType);
#ifdef _TEST_AE_ERROR_HANDLING
    if (iErrorHandlingAddTrack)
    {
        trackId = 0;
    }
#endif
    if (trackId == 0)
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                        (0, "PVMp4FFComposerNode::AddTrack: Error - PVA_FF_IMpeg4File::addTrack failed"));
        return PVMFFailure;
    }
    aPort->SetTrackId(trackId);
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
                    (0, "PVMp4FFComposerNode::AddTrack: PVA_FF_IMpeg4File::addTrack success. trackID=%d", trackId));
#if PROFILING_ON

    for (uint32 k = 0; k < 3; k++)
    {
        if (iStats[k].iTrackId == 0)
        {
            iStats[k].iTrackId = trackId;
            break;
        }
    }
#endif

    switch (mediaType)
    {
        case MEDIA_TYPE_AUDIO:
        {
            iMpeg4File->setTargetBitrate(trackId, config->iBitrate);
            iMpeg4File->setTimeScale(trackId, config->iTimescale);
            PVMP4FFComposerAudioEncodeParams audioParams;
            audioParams.numberOfChannels = config->iNumberOfChannels;
            audioParams.samplingRate = config->iSamplingRate;
            audioParams.bitsPerSample = config->iBitsPerSample;
            iMpeg4File->setAudioEncodeParams(trackId, audioParams);
            break;
        }

        case MEDIA_TYPE_VISUAL:
            switch (codecType)
            {
                case CODEC_TYPE_BASELINE_H263_VIDEO:
                    iMpeg4File->setH263ProfileLevel(trackId, config->iH263Profile, config->iH263Level);
                    // Don't break here. Continue to set other video properties
                case CODEC_TYPE_AVC_VIDEO:
                case CODEC_TYPE_MPEG4_VIDEO:
                    iMpeg4File->setTargetBitrate(trackId, config->iBitrate, config->iBitrate, 0);
                    iMpeg4File->setTimeScale(trackId, config->iTimescale);
                    iMpeg4File->setVideoParams(trackId, (float)config->iFrameRate,
                                               (uint16)config->iIFrameInterval, config->iWidth, config->iHeight);
                    break;
            }
            break;
        case MEDIA_TYPE_TEXT:
            iMpeg4File->setTargetBitrate(trackId, config->iBitrate);
            iMpeg4File->setTimeScale(trackId, config->iTimescale);
            break;

    }

    return PVMFSuccess;
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoStop(PVMp4FFCNCmd& aCmd)
{
    PVMFStatus status = PVMFSuccess;
#if PROFILING_ON
    if (!oDiagnosticsLogged)
    {
        LogDiagnostics();
    }
#endif
#ifdef _TEST_AE_ERROR_HANDLING
    if (FAIL_NODE_CMD_STOP == iErrorNodeCmd)
    {
        iInterfaceState = EPVMFNodeError;
    }
#endif
    switch (iInterfaceState)
    {
        case EPVMFNodeStarted:
        case EPVMFNodePaused:
        {
#ifdef ANDROID
            iFragmentWriter->flush();
#endif
            if (!iNodeEndOfDataReached)
            {
                WriteDecoderSpecificInfo();
                if (iSampleInTrack)
                {
                    status = RenderToFile();
                }

                iSampleInTrack = false;
            }

            iNodeEndOfDataReached = false;
            for (uint32 ii = 0; ii < iInPorts.size(); ii++)
            {
                iInPorts[ii]->iEndOfDataReached = false;
            }
        }
        SetState(EPVMFNodePrepared);
        break;
        case EPVMFNodePrepared:
            status = PVMFSuccess;
            break;
        default:
            status = PVMFErrInvalidState;
            break;
    }

    CommandComplete(iCmdQueue, aCmd, status);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::WriteDecoderSpecificInfo()
{
    uint32 i;
    uint32 offset = 0;
    iConfigSize = 0;
    int32 trackId;

    if (iformat_h264 == PVMF_MIME_H264_VIDEO_MP4)
    {
        trackId = iTrackId_H264;

        for (i = 0; i < memvector_sps.size(); i++)
        {
            iConfigSize += 2;//2 bytes for SPS_len
            iConfigSize += memvector_sps[i]->len;
        }

        for (i = 0; i < memvector_pps.size(); i++)
        {
            iConfigSize += 2;//2 bytes for PPS_len
            iConfigSize += memvector_pps[i]->len;
        }
        iConfigSize = iConfigSize + 2;//extra two bytes for nunSPS and NumPPS
        pConfig = (uint8*)(OSCL_MALLOC(sizeof(uint8) * iConfigSize));


        //currently we are ignoring NAL Length information
        oscl_memcpy((void*)(pConfig + offset), (const void*)&iNum_SPS_Set, 1);//Writing Number of SPS sets
        offset += 1;

        for (i = 0; i < memvector_sps.size(); i++)
        {
            oscl_memcpy((void*)(pConfig + offset), (const void*)&memvector_sps[i]->len, 2);//Writing length of SPS
            offset += 2;
            oscl_memcpy((void*)(pConfig + offset), memvector_sps[i]->ptr, memvector_sps[i]->len);
            offset = offset + memvector_sps[i]->len;
        }

        oscl_memcpy((void*)(pConfig + offset), (const void*)&iNum_PPS_Set, 1);//Writing Number of PPS sets
        offset += 1;

        for (i = 0; i < memvector_pps.size(); i++)
        {
            oscl_memcpy((void*)(pConfig + offset), (const void*)&memvector_pps[i]->len, 2);//Writing length of PPS
            offset += 2;//2 bytes for PPS Length
            oscl_memcpy((void*)(pConfig + offset), memvector_pps[i]->ptr, memvector_pps[i]->len);
            offset = offset + memvector_pps[i]->len;
        }
        iMpeg4File->setDecoderSpecificInfo(pConfig, iConfigSize, trackId);
    }

    if (iformat_text == PVMF_MIME_3GPP_TIMEDTEXT)
    {
        for (uint32 ii = 0; ii < textdecodervector.size(); ii++)
        {
            trackId = iTrackId_Text;
            iMpeg4File->setTextDecoderSpecificInfo(textdecodervector[ii], trackId);
        }
    }

}
//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::RenderToFile()
{
    PVMFStatus status = PVMFSuccess;

    // Clear queued messages in ports
    uint32 i;
    for (i = 0; i < iInPorts.size(); i++)
        iInPorts[i]->ClearMsgQueues();
#ifdef _TEST_AE_ERROR_HANDLING //to fail renderToFile
    if (iErrorRenderToFile)
    {
        if (iMpeg4File)
        {
            PVA_FF_IMpeg4File::DestroyMP4FileObject(iMpeg4File);
            iMpeg4File = NULL;
        }
    }
#endif

#ifdef ANDROID
    iFragmentWriter->flush();
#endif

    if (!iMpeg4File || !iMpeg4File->renderToFile(iFileName))
    {
        LOG_ERR((0, "PVMp4FFComposerNode::RenderToFile: Error - renderToFile failed"));
        ReportErrorEvent(PVMF_MP4FFCN_ERROR_FINALIZE_OUTPUT_FILE_FAILED);
        status = PVMFFailure;
    }
    else
    {
#if PROFILING_ON
        // Statistics

        for (i = 0; i < 3; i++)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
                            (0, "PVMp4FFComposerNode Stats: TrackId=%d, NumFrame=%d, Duration=%d",
                             iStats[i].iTrackId, iStats[i].iNumFrames, iStats[i].iDuration));
            oscl_memset(&(iStats[i]), 0, sizeof(PVMp4FFCNStats));
        }
#endif

        LOGDATATRAFFIC((0, "PVMp4FFComposerNode::RenderToFile() Done"));
        // Delete file format library
        if (iMpeg4File)
        {
            PVA_FF_IMpeg4File::DestroyMP4FileObject(iMpeg4File);
            iMpeg4File = NULL;
        }

        // Change state
        SetState(EPVMFNodePrepared);
        status = PVMFSuccess;
    }

    if (PVMFSuccess == status)
    {
        iFileRendered = true;
    }
    return status;
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoFlush(PVMp4FFCNCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::DoFlush() iInterfaceState:%d", iInterfaceState));
#ifdef _TEST_AE_ERROR_HANDLING
    if (FAIL_NODE_CMD_FLUSH == iErrorNodeCmd)
    {
        iInterfaceState = EPVMFNodeError;
    }
#endif
    switch (iInterfaceState)
    {
        case EPVMFNodeStarted:
        case EPVMFNodePaused:
            int32 err;
            uint32 i;
            bool msgPending;
            msgPending = false;

            for (i = 0; i < iInPorts.size(); i++)
            {
                if (iInPorts[i]->IncomingMsgQueueSize() > 0)
                    msgPending = true;
                iInPorts[i]->SuspendInput();
                if (iInterfaceState != EPVMFNodeStarted)
                {
                    // Port is in idle if node state is not started. Call ProcessIncomingMsgReady
                    // to wake up port AO
                    ((PVMp4FFComposerPort*)iInPorts[i])->ProcessIncomingMsgReady();
                }
            }

            // Move the command from the input command queue to the current command, where
            // it will remain until the flush completes.
            err = StoreCurrentCommand(iCurrentCmd, aCmd, iCmdQueue);
            if (0 != err)
                return;

            iCmdQueue.Erase(&aCmd);

            if (!msgPending)
            {
                FlushComplete();
                return;
            }
            break;

        default:
            CommandComplete(iCmdQueue, aCmd, PVMFFailure);
            break;
    }
}

////////////////////////////////////////////////////////////////////////////
bool PVMp4FFComposerNode::IsFlushPending()
{
    return (iCurrentCmd.size() > 0
            && iCurrentCmd.front().iCmd == PVMF_GENERIC_NODE_FLUSH);
}

////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::FlushComplete()
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::FlushComplete"));
    uint32 i = 0;
    PVMFStatus status = PVMFSuccess;
    // Flush is complete only when all queues of all ports are clear.
    // Other wise, just return from this method and wait for FlushComplete
    // from the remaining ports.
    for (i = 0; i < iInPorts.size(); i++)
    {
        if (iInPorts[i]->IncomingMsgQueueSize() > 0 ||
                iInPorts[i]->OutgoingMsgQueueSize() > 0)
        {
            return;
        }
    }
#ifdef ANDROID
    iFragmentWriter->flush();
#endif
    if (!iNodeEndOfDataReached)
    {
        WriteDecoderSpecificInfo();
        // Finalize output file
        if (iSampleInTrack)
        {
            status = RenderToFile();
        }

        iSampleInTrack = false;

        if (status != PVMFSuccess)
            LOG_ERR((0, "PVMp4FFComposerNode::FlushComplete: Error - RenderToFile failed"));
    }

    // Resume port input so the ports can be re-started.
    for (i = 0; i < iInPorts.size(); i++)
        iInPorts[i]->ResumeInput();

    SetState(EPVMFNodePrepared);

    if (!iCurrentCmd.empty())
    {
        CommandComplete(iCurrentCmd, iCurrentCmd[0], status);
    }

    if (!iCmdQueue.empty())
    {
        // If command queue is not empty, schedule to process the next command
        RunIfNotReady();
    }


}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoPause(PVMp4FFCNCmd& aCmd)
{
    PVMFStatus status = PVMFSuccess;

#ifdef _TEST_AE_ERROR_HANDLING
    if (FAIL_NODE_CMD_PAUSE == iErrorNodeCmd)
    {
        iInterfaceState = EPVMFNodeError;
    }
#endif
    switch (iInterfaceState)
    {
        case EPVMFNodeStarted:
            SetState(EPVMFNodePaused);
            break;
        case EPVMFNodePaused:
            break;
        default:
            status = PVMFErrInvalidState;
            break;
    }

    CommandComplete(iCmdQueue, aCmd, status);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoReset(PVMp4FFCNCmd& aCmd)
{
    PVMFStatus status = PVMFSuccess;
#if PROFILING_ON
    if (!oDiagnosticsLogged)
    {
        LogDiagnostics();
    }
#endif

    if (IsAdded())
    {
        if (iSampleInTrack)
        {
            WriteDecoderSpecificInfo();
            status = RenderToFile();
            iSampleInTrack = false;
        }

        //delete all ports and notify observer.
        while (!iInPorts.empty())
            iInPorts.Erase(&iInPorts.front());

        //restore original port vector reserve.
        iInPorts.Reconstruct();
        iNodeEndOfDataReached = false;

        //logoff & go back to Created state.
        SetState(EPVMFNodeIdle);
        status = PVMFSuccess;
    }
    else
    {
        OSCL_LEAVE(OsclErrInvalidState);
    }

    CommandComplete(iCmdQueue, aCmd, status);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoCancelAllCommands(PVMp4FFCNCmd& aCmd)
{
    //first cancel the current command if any
    while (!iCurrentCmd.empty())
        CommandComplete(iCurrentCmd, iCurrentCmd[0], PVMFErrCancelled);

    //next cancel all queued commands
    //start at element 1 since this cancel command is element 0.
    while (iCmdQueue.size() > 1)
        CommandComplete(iCmdQueue, iCmdQueue[1], PVMFErrCancelled);

    //finally, report cancel complete.
    CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
}

//////////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::DoCancelCommand(PVMp4FFCNCmd& aCmd)
{
    //extract the command ID from the parameters.
    PVMFCommandId id;
    aCmd.Parse(id);

    //first check "current" command if any
    PVMp4FFCNCmd* cmd = iCurrentCmd.FindById(id);
    if (cmd)
    {
        //cancel the queued command
        CommandComplete(iCurrentCmd, *cmd, PVMFErrCancelled);
        //report cancel success
        CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
        return;
    }

    //next check input queue.
    //start at element 1 since this cancel command is element 0.
    cmd = iCmdQueue.FindById(id, 1);
    if (cmd)
    {
        //cancel the queued command
        CommandComplete(iCmdQueue, *cmd, PVMFErrCancelled);
        //report cancel success
        CommandComplete(iCmdQueue, aCmd, PVMFSuccess);
        return;
    }

    //if we get here the command isn't queued so the cancel fails.
    CommandComplete(iCmdQueue, aCmd, PVMFFailure);
}

//////////////////////////////////////////////////////////////////////////////////
//                  Port activity processing routines
//////////////////////////////////////////////////////////////////////////////////
bool PVMp4FFComposerNode::IsProcessIncomingMsgReady()
{
    if (iInterfaceState == EPVMFNodeStarted || IsFlushPending())
        return true;
    else
        return false;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::ProcessIncomingMsg(PVMFPortInterface* aPort)
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::ProcessIncomingMsg: aPort=0x%x", aPort));
    PVMFStatus status = PVMFSuccess;

    switch (aPort->GetPortTag())
    {
        case PVMF_MP4FFCN_PORT_TYPE_SINK:
        {
            PVMp4FFComposerPort* port = OSCL_REINTERPRET_CAST(PVMp4FFComposerPort*, aPort);
            if (!IsProcessIncomingMsgReady())
            {
                LOG_ERR((0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error - Not ready."));
                return PVMFErrBusy;
            }

            PVMFSharedMediaMsgPtr msg;
            status = port->DequeueIncomingMsg(msg);
            if (status != PVMFSuccess)
            {
                LOG_ERR((0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error - DequeueIncomingMsg failed"));
                return status;
            }
            if (msg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
            {
                LOGDATATRAFFIC((0, "PVMp4FFComposerNode::ProcessIncomingMsg: EOS Recvd - TrackID=%d, StreamID=%d, TS=%d, Mime=%s",
                                port->GetTrackId(), msg->getStreamID(), msg->getTimestamp(), port->GetMimeType().get_cstr()));

                port->iEndOfDataReached = true;
                //check if EOS has been received on all connected ports.
                uint32 ii = 0;
                iNodeEndOfDataReached = true;
                for (ii = 0; ii < iInPorts.size(); ii++)
                {
                    if (!iInPorts[ii]->iEndOfDataReached)
                    {
                        iNodeEndOfDataReached = false;
                    }
                }

                if (iNodeEndOfDataReached)
                {
                    //Close the file since EOS is received on every connected port
                    WriteDecoderSpecificInfo();
                    if (iSampleInTrack)
                    {
                        status = RenderToFile();
                        iSampleInTrack = false;
                    }

                    //report EOS info to engine
                    ReportInfoEvent(PVMF_COMPOSER_EOS_REACHED);
                }

                //since we do not have data to process, we can safely break here.
                break;
            }

            PVMFSharedMediaDataPtr mediaDataPtr;
            convertToPVMFMediaData(mediaDataPtr, msg);

            int32 trackId = port->GetTrackId();
            if ((mediaDataPtr->getSeqNum() == 0) && (port->GetFormat() == PVMF_MIME_M4V))
            {
                // Set VOL Header
                OsclRefCounterMemFrag volHeader;
                if (mediaDataPtr->getFormatSpecificInfo(volHeader) == false ||
                        volHeader.getMemFragSize() == 0)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error - VOL Header not available"));
                    return PVMFFailure;
                }

                iMpeg4File->setDecoderSpecificInfo((uint8*)volHeader.getMemFragPtr(),
                                                   (int32)volHeader.getMemFragSize(), trackId);
            }
            if ((mediaDataPtr->getSeqNum() == 0) && (port->GetFormat() == PVMF_MIME_H264_VIDEO_MP4))
            {
                iTrackId_H264 = port->GetTrackId();
                iformat_h264 = port->GetFormat();
            }
            if (port->GetFormat() == PVMF_MIME_3GPP_TIMEDTEXT)
            {
                iTrackId_Text = port->GetTrackId();
                iformat_text = port->GetFormat();
                GetTextSDIndex(mediaDataPtr->getSeqNum(), iText_sdIndex);
            }
            if (((port->GetFormat() == PVMF_MIME_AMR_IETF) ||
                    (port->GetFormat() == PVMF_MIME_AMRWB_IETF)) && mediaDataPtr->getErrorsFlag())
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_NOTICE,
                                (0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error flag set for AMR!"));
                return PVMFSuccess;
            }

            if ((mediaDataPtr->getSeqNum() == 0) && (port->GetFormat() == PVMF_MIME_MPEG4_AUDIO))
            {
                // Set AAC Config
                OsclRefCounterMemFrag decSpecInfo;
                if (mediaDataPtr->getFormatSpecificInfo(decSpecInfo) == false ||
                        decSpecInfo.getMemFragSize() == 0)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error - Decoder Specific not available"));
                    return PVMFFailure;
                }

                iMpeg4File->setDecoderSpecificInfo((uint8*)decSpecInfo.getMemFragPtr(),
                                                   (int32)decSpecInfo.getMemFragSize(), trackId);
            }

            // Retrieve data from incoming queue
            OsclRefCounterMemFrag memFrag;
            uint32 numFrags = mediaDataPtr->getNumFragments();
            uint32 timestamp = mediaDataPtr->getTimestamp();
            iSyncSample = 0;
            if (mediaDataPtr->getMarkerInfo()&PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT)
            {
                iSyncSample = 1;
            }

            Oscl_Vector<OsclMemoryFragment, OsclMemAllocator> pFrame; //vector to store the nals in the particular case of AVC
            for (uint32 i = 0; (i < numFrags) && status == PVMFSuccess; i++)
            {
                if (!mediaDataPtr->getMediaFragment(i, memFrag))
                {
                    status = PVMFFailure;
                }
                else
                {
                    OsclMemoryFragment memfragment;
                    memfragment.len = memFrag.getMemFragSize();
                    memfragment.ptr = memFrag.getMemFragPtr();
                    pFrame.push_back(memfragment);
                }
            }

#ifdef ANDROID
            if (!iMaxReachedEvent)
            {
                // TODO: We are passing port and port->GetFormat(), should pass port only.
                status = iFragmentWriter->enqueueMemFragToTrack(
                             pFrame, memFrag, port->GetFormat(), timestamp,
                             trackId, (PVMp4FFComposerPort*)aPort);
            }
            else if (!iMaxReachedReported)
            {
                iMaxReachedReported = true;
                ReportInfoEvent(static_cast<PVMFComposerSizeAndDurationEvent>(iMaxReachedEvent), NULL);
                status = PVMFSuccess;
            }
#else
            status = AddMemFragToTrack(pFrame, memFrag, port->GetFormat(), timestamp,
                                       trackId, (PVMp4FFComposerPort*)aPort);
#endif
            if (status == PVMFFailure)
                ReportErrorEvent(PVMF_MP4FFCN_ERROR_ADD_SAMPLE_TO_TRACK_FAILED, (OsclAny*)aPort);
        }
        break;

        default:
            LOG_ERR((0, "PVMp4FFComposerNode::ProcessIncomingMsg: Error - Invalid port tag"));
            ReportErrorEvent(PVMF_MP4FFCN_ERROR_ADD_SAMPLE_TO_TRACK_FAILED, (OsclAny*)aPort);
            status = PVMFFailure;
            break;
    }

    return status;
}

//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::AddMemFragToTrack(Oscl_Vector<OsclMemoryFragment, OsclMemAllocator> aFrame, OsclRefCounterMemFrag& aMemFrag,
        PVMFFormatType aFormat,
        uint32& aTimestamp,
        int32 aTrackId,
        PVMp4FFComposerPort *aPort)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: aFormat=%s, aTimestamp=%d, aTrackId=%d",
                     aFormat.getMIMEStrPtr(), aTimestamp, aTrackId));

    if (iRealTimeTS)
    {
        if (iInitTSOffset && (aMemFrag.getMemFragSize() > 0))
        {
            iTSOffset = aTimestamp;
            iInitTSOffset = false;
        }

        aTimestamp = aTimestamp - iTSOffset;
    }

    uint32 timeScale = 0;
    PVMP4FFCNFormatSpecificConfig* config = aPort->GetFormatSpecificConfig();
    if (config)
    {
        timeScale = config->iTimescale;
    }

    uint32 i = 0;
#if PROFILING_ON
    PVMp4FFCNStats* stats = NULL;
    for (i = 0; i < 3; i++)
    {
        if (aTrackId == iStats[i].iTrackId)
        {
            stats = &(iStats[i]);
            break;
        }
    }
#endif

    PVMFStatus status = PVMFSuccess;
    uint8 flags = 0;
    uint32 size = 0;
    uint8* data = NULL;
    for (i = 0; i < aFrame.size(); i++)
    {
        size = aFrame[i].len;
        data = OSCL_REINTERPRET_CAST(uint8*, aFrame[i].ptr);
        if (!data || size == 0)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - Invalid data or data size"));
            return PVMFFailure;
        }
    }

    if (aFormat == PVMF_MIME_3GPP_TIMEDTEXT ||
            aFormat == PVMF_MIME_H264_VIDEO_MP4 ||
            aFormat == PVMF_MIME_M4V ||
            aFormat == PVMF_MIME_H2631998 ||
            aFormat == PVMF_MIME_H2632000)
    {
        status = CheckMaxDuration(aTimestamp);
        if (status == PVMFFailure)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxDuration failed"));
            return status;
        }
        else if (status == PVMFSuccess)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum duration reached"));
            return status;
        }

        for (i = 0; i < aFrame.size(); i++)
        {
            size = aFrame[i].len;
            status = CheckMaxFileSize(size);
            if (status == PVMFFailure)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxFileSize failed"));
                return status;
            }
            else if (status == PVMFSuccess)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum file size reached"));
                return status;
            }

            //No data for some reason.
            if (size == 0)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_NOTICE,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: no data in frag!"));
                return PVMFSuccess;
            }
        }
        uint8 codingType = CODING_TYPE_P;

        if (iRealTimeTS)
        {
            if (aTimestamp <= aPort->GetLastTS())
            {
                aTimestamp = aPort->GetLastTS() + 1;
            }

            aPort->SetLastTS(aTimestamp);
        }

        //iSyncSample is obtained from the marker info
        //to identify the I Frame
        if (iSyncSample)
        {
            codingType = CODING_TYPE_I;
        }

        // Format: mtb (1) | layer_id (3) | coding_type (2) | ref_select_code (2)
        // flags |= ((stream->iHintTrack.MTB & 0x01) << 7);
        // flags |= ((stream->iHintTrack.LayerID & 0x07) << 4);
        flags |= ((codingType & 0x03) << 2);
        // flags |= (stream->iHintTrack.RefSelCode & 0x03);

        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                        (0, "PVMp4FFComposerNode::AddMemFragToTrack: Calling addSampleToTrack(%d, 0x%x, %d, %d, %d)",
                         aTrackId, data, size, aTimestamp, flags));

        LOGDATATRAFFIC((0, "PVMp4FFComposerNode::AddMemFragToTrack: TrackID=%d, Size=%d, TS=%d, Flags=%d, Mime=%s",
                        aTrackId, size, aTimestamp, flags, aPort->GetMimeType().get_cstr()));

        if (aFormat == PVMF_MIME_3GPP_TIMEDTEXT)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Calling addtextSampleToTrack(%d, 0x%x, %d, %d, %d)",
                             aTrackId, data, size, aTimestamp, flags));
            int32 index = iText_sdIndex;

            if (index >= 0)
            {
#if PROFILING_ON
                uint32 start = OsclTickCount::TickCount();
#endif
                if (!iMpeg4File->addTextSampleToTrack(aTrackId, aFrame, aTimestamp, flags, index, NULL))
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addTextSampleToTrack for Timed Text failed"));
                    return PVMFFailure;
                }
                iSampleInTrack = true;
#if PROFILING_ON
                uint32 stop = OsclTickCount::TickCount();
                uint32 comptime = OsclTickCount::TicksToMsec(stop - start);
                uint32 dataSize = 0;
                for (uint32 ii = 0; ii < aFrame.size(); ii++)
                {
                    dataSize += aFrame[ii].len;
                }
                GenerateDiagnostics(comptime, dataSize);
#endif
            }
        }
        else
        {

#if PROFILING_ON
            uint32 start = OsclTickCount::TickCount();
#endif

#ifdef _TEST_AE_ERROR_HANDLING

            if (1 == iErrorAddSample)
            {
                if (iTestFileSize <= iFileSize) //iTestFileSize set in sendProgressReport()
                {
                    if (!iMpeg4File->addSampleToTrack(aTrackId, aFrame, aTimestamp, flags))
                    {
                        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                        (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
                        return PVMFFailure;
                    }
                }
            }
            else if (2 == iErrorAddSample)
            {

                if (aTimestamp <= iFileDuration)
                {
                    if (!iMpeg4File->addSampleToTrack(aTrackId, aFrame, aTimestamp, flags))
                    {
                        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                        (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
                        return PVMFFailure;
                    }
                }
            }
            else
            {
                if (!iMpeg4File->addSampleToTrack(aTrackId, aFrame, aTimestamp, flags))
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
                    return PVMFFailure;
                }
            }

#else
            if (!iMpeg4File->addSampleToTrack(aTrackId, aFrame, aTimestamp, flags))
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
                return PVMFFailure;
            }
#endif
            iSampleInTrack = true;
#ifdef _TEST_AE_ERROR_HANDLING
            if (iErrorHandlingAddMemFrag == true)
            {
                return PVMFFailure; //Just to trigger error handling
            }
#endif

#if PROFILING_ON
            uint32 stop = OsclTickCount::TickCount();
            uint32 comptime = OsclTickCount::TicksToMsec(stop - start);
            uint32 dataSize = 0;
            for (uint32 ii = 0; ii < aFrame.size(); ii++)
            {
                dataSize += aFrame[ii].len;
            }
            GenerateDiagnostics(comptime, dataSize);
#endif
        }


        // Send progress report after sample is successfully added
        SendProgressReport(aTimestamp);

#if PROFILING_ON
        ++(stats->iNumFrames);
        stats->iDuration = aTimestamp;
#endif
    }

    else if ((aFormat == PVMF_MIME_AMR_IETF) ||
             (aFormat == PVMF_MIME_AMRWB_IETF))
    {
        if (iRealTimeTS)
        {
            if (((int32) aTimestamp - (int32) aPort->GetLastTS()) < 20)
            {
                aTimestamp = aPort->GetLastTS() + 20;
            }

            aPort->SetLastTS(aTimestamp);
        }

        uint32 bytesProcessed = 0;
        uint32 frameSize = 0;
        Oscl_Vector<OsclMemoryFragment, OsclMemAllocator> amrfrags;
        for (i = 0; i < aFrame.size(); i++)
        {
            bytesProcessed = 0;
            size = aFrame[i].len;
            data = OSCL_REINTERPRET_CAST(uint8*, aFrame[i].ptr);
            // Parse audio data and add one 20ms frame to track at a time
            while (bytesProcessed < size)
            {
                // Check for max duration
                status = CheckMaxDuration(aTimestamp);
                if (status == PVMFFailure)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxDuration failed"));
                    return status;
                }
                else if (status == PVMFSuccess)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum duration reached"));
                    return status;
                }

                // Update clock converter
                iClockConverter.set_timescale(timeScale);
                iClockConverter.set_clock_other_timescale(aTimestamp, 1000);

                // Check max file size
                int32 frSize = GetIETFFrameSize(data[0], aPort->GetCodecType());
                if (frSize == -1)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - Frame Type Not Supported - Skipping"));
                    LOGDATATRAFFIC((0, "PVMp4FFComposerNode::AddMemFragToTrack - Invalid Frame: TrackID=%d, Byte=0x%x, Mime=%s",
                                    aTrackId, data[0], aPort->GetMimeType().get_cstr()));
                    return PVMFFailure;
                }
                frameSize = (uint32)frSize;

                status = CheckMaxFileSize(frameSize);
                if (status == PVMFFailure)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxFileSize failed"));
                    return status;
                }
                else if (status == PVMFSuccess)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum file size reached"));
                    return status;
                }

                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Calling addSampleToTrack(%d, 0x%x, %d, %d, %d)",
                                 aTrackId, data, frameSize, iClockConverter.get_current_timestamp(), flags));


                OsclMemoryFragment amr_memfrag;
                amr_memfrag.len = frameSize;
                amr_memfrag.ptr = data;
                amrfrags.push_back(amr_memfrag);

#if PROFILING_ON
                uint32 start = OsclTickCount::TickCount();
#endif
                uint32 amrts = iClockConverter.get_current_timestamp();

                LOGDATATRAFFIC((0, "PVMp4FFComposerNode::AddMemFragToTrack: TrackID=%d, Size=%d, TS=%d, Flags=%d, Mime=%s",
                                aTrackId, frameSize, amrts, flags, aPort->GetMimeType().get_cstr()));

                if (!iMpeg4File->addSampleToTrack(aTrackId, amrfrags, amrts, flags))
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                    (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
                    return PVMFFailure;
                }
                iSampleInTrack = true;
#if PROFILING_ON
                uint32 stop = OsclTickCount::TickCount();
                uint32 comptime = OsclTickCount::TicksToMsec(stop - start);
                uint32 dataSize = 0;
                for (uint32 ii = 0; ii < amrfrags.size(); ii++)
                {
                    dataSize += amrfrags[ii].len;
                }
                GenerateDiagnostics(comptime, dataSize);

#endif

                // Send progress report after sample is successfully added
                SendProgressReport(aTimestamp);

#if PROFILING_ON
                ++(stats->iNumFrames);
                stats->iDuration = aTimestamp;
#endif
                data += frameSize;
                bytesProcessed += frameSize;
                aTimestamp += 20;
                amrfrags.clear();
            }
        }
        if (iRealTimeTS)
        {
            aPort->SetLastTS(aTimestamp - 20);
        }
    }

    else if (aFormat == PVMF_MIME_MPEG4_AUDIO)
    {
        status = CheckMaxDuration(aTimestamp);
        if (status == PVMFFailure)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxDuration failed"));
            return status;
        }
        else if (status == PVMFSuccess)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum duration reached"));
            return status;
        }

        for (i = 0; i < aFrame.size(); i++)
        {
            size = aFrame[i].len;
            status = CheckMaxFileSize(size);
            if (status == PVMFFailure)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - CheckMaxFileSize failed"));
                return status;
            }
            else if (status == PVMFSuccess)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: Maxmimum file size reached"));
                return status;
            }

            //No data for some reason.
            if (size == 0)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_NOTICE,
                                (0, "PVMp4FFComposerNode::AddMemFragToTrack: no data in frag!"));
                return PVMFSuccess;
            }
        }

        if (iRealTimeTS)
        {
            if (aTimestamp <= aPort->GetLastTS())
            {
                aTimestamp = aPort->GetLastTS() + 1;
            }

            aPort->SetLastTS(aTimestamp);
        }

        iClockConverter.set_timescale(timeScale);
        iClockConverter.set_clock_other_timescale(aTimestamp, 1000);
        uint32 aacTS = iClockConverter.get_current_timestamp();

        if (!iMpeg4File->addSampleToTrack(aTrackId, aFrame, aacTS, flags))
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                            (0, "PVMp4FFComposerNode::AddMemFragToTrack: Error - addSampleToTrack failed"));
            return PVMFFailure;
        }
        iSampleInTrack = true;
        // Send progress report after sample is successfully added
        SendProgressReport(aTimestamp);

#if PROFILING_ON
        ++(stats->iNumFrames);
        stats->iDuration = aTimestamp;
#endif
    }

    return PVMFSuccess;
}


void PVMp4FFComposerNode::GenerateDiagnostics(uint32 aTime, uint32 aSize)
{
#if PROFILING_ON
    if ((iMinSampleAddTime > aTime) || (0 == iMinSampleAddTime))
    {
        iMinSampleAddTime = aTime;
    }
    if (iMaxSampleAddTime < aTime)
    {
        iMaxSampleAddTime = aTime;
    }

    if ((iMinSampleSize > aSize) || (0 == iMinSampleSize))
    {
        iMinSampleSize = aSize;
    }
    if (iMaxSampleSize < aSize)
    {
        iMaxSampleSize = aSize;
    }
    iNumSamplesAdded++;
#endif
    OSCL_UNUSED_ARG(aTime);
    OSCL_UNUSED_ARG(aSize);
}
//////////////////////////////////////////////////////////////////////////////////
int32 PVMp4FFComposerNode::GetIETFFrameSize(uint8 aFrameType,
        int32 aCodecType)
{
    uint8 frameType = (uint8)(aFrameType >> 3) & 0x0f;
    if (aCodecType == CODEC_TYPE_AMR_AUDIO)
    {
        // Find frame size for each frame type
        switch (frameType)
        {
            case 0: // AMR 4.75 Kbps
                return 13;
            case 1: // AMR 5.15 Kbps
                return 14;
            case 2: // AMR 5.90 Kbps
                return 16;
            case 3: // AMR 6.70 Kbps
                return 18;
            case 4: // AMR 7.40 Kbps
                return 20;
            case 5: // AMR 7.95 Kbps
                return 21;
            case 6: // AMR 10.2 Kbps
                return 27;
            case 7: // AMR 12.2 Kbps
                return 32;
            case 8: // AMR Frame SID
                return 6;
            case 9: // AMR Frame GSM EFR SID
                return 7;
            case 10:// AMR Frame TDMA EFR SID
            case 11:// AMR Frame PDC EFR SID
                return 6;
            case 15: // AMR Frame No Data
                return 1;
            default: // Error - For Future Use
                return -1;
        }
    }
    else if (aCodecType == CODEC_TYPE_AMR_WB_AUDIO)
    {
        // Find frame size for each frame type
        switch (frameType)
        {
            case 0: // AMR-WB 6.60 Kbps
                return 18;
            case 1: // AMR-WB 8.85 Kbps
                return 24;
            case 2: // AMR-WB 12.65 Kbps
                return 33;
            case 3: // AMR-WB 14.25 Kbps
                return 37;
            case 4: // AMR-WB 15.85 Kbps
                return 41;
            case 5: // AMR-WB 18.25 Kbps
                return 47;
            case 6: // AMR-WB 19.85 Kbps
                return 51;
            case 7: // AMR-WB 23.05 Kbps
                return 59;
            case 8: // AMR-WB 23.85 Kbps
                return 61;
            case 9: // AMR-WB SID Frame
                return 6;
            case 10: //Reserved
            case 11: //Reserved
            case 12: //Reserved
            case 13: //Reserved
                return -1;
            case 14: // AMR-WB Frame Lost
            case 15: // AMR-WB Frame No Data
                return 1;
            default: // Error - For Future Use
                return -1;
        }
    }
    return -1;
}

//////////////////////////////////////////////////////////////////////////////////
//                 Progress and max size / duration routines
//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::SendProgressReport(uint32 aTimestamp)
{
    if (iDurationReportEnabled &&
            aTimestamp >= iNextDurationReport)
    {
        iNextDurationReport = aTimestamp - (aTimestamp % iDurationReportFreq) + iDurationReportFreq;
        ReportInfoEvent(PVMF_COMPOSER_DURATION_PROGRESS, (OsclAny*)aTimestamp);
    }
    else if (iFileSizeReportEnabled)
    {
        uint32 metaDataSize = 0;
        uint32 mediaDataSize = 0;
        uint32 fileSize = 0;

        iMpeg4File->getTargetFileSize(metaDataSize, mediaDataSize);
        fileSize = metaDataSize + mediaDataSize;

        if (fileSize >= iNextFileSizeReport)
        {
            iNextFileSizeReport = fileSize - (fileSize % iFileSizeReportFreq) + iFileSizeReportFreq;
            ReportInfoEvent(PVMF_COMPOSER_FILESIZE_PROGRESS, (OsclAny*)fileSize);
        }
#ifdef _TEST_AE_ERROR_HANDLING
        iTestFileSize = fileSize; //iTestTimeStamp to fail the addSampleTrack() once a particulare time duration is reached as specified in testapp.
#endif
    }

    return PVMFSuccess;
}

//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::CheckMaxFileSize(uint32 aFrameSize)
{
    if (iMaxFileSizeEnabled)
    {
        uint32 metaDataSize = 0;
        uint32 mediaDataSize = 0;
        iMpeg4File->getTargetFileSize(metaDataSize, mediaDataSize);

        if ((metaDataSize + mediaDataSize + aFrameSize) >= iMaxFileSize)
        {
#ifdef ANDROID
            // This code is executed on the fragment writer thread, we
            // don't want to call RenderToFile since it will call
            // flush() on the writer from this very same
            // thread. Instead, we use a marker to report an event to
            // the author node next time a new fragment is processed.
            iMaxReachedEvent = PVMF_COMPOSER_MAXFILESIZE_REACHED;
#else
            // Finalized output file
            if (iSampleInTrack)
            {
                WriteDecoderSpecificInfo();
                iSampleInTrack = false;
                if (RenderToFile() != PVMFSuccess)
                    return PVMFFailure;
            }

            ReportInfoEvent(PVMF_COMPOSER_MAXFILESIZE_REACHED, NULL);
            return PVMFSuccess;
#endif
        }

        return PVMFPending;
    }

    return PVMFErrNotSupported;
}

//////////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMp4FFComposerNode::CheckMaxDuration(uint32 aTimestamp)
{
    //if(!iInfoObserver)
    //  return PVMFFailure;

    if (iMaxDurationEnabled)
    {
        if (aTimestamp >= iMaxTimeDuration)
        {
#ifdef ANDROID
            // This code is executed on the fragment writer thread, we
            // don't want to call RenderToFile since it will call
            // flush() on the writer from this very same
            // thread. Instead, we use a marker to report an event to
            // the author node next time a new fragment is processed.
            iMaxReachedEvent = PVMF_COMPOSER_MAXDURATION_REACHED;
#else

            // Finalize output file
            if (iSampleInTrack)
            {
                WriteDecoderSpecificInfo();
                iSampleInTrack = false;
                if (RenderToFile() != PVMFSuccess)
                    return PVMFFailure;
            }

            ReportInfoEvent(PVMF_COMPOSER_MAXDURATION_REACHED, NULL);
            return PVMFSuccess;
#endif
        }

        return PVMFPending;
    }

    return PVMFErrNotSupported;
}

////////////////////////////////////////////////////////////////////////////
//                   Event reporting routines.
////////////////////////////////////////////////////////////////////////////
void PVMp4FFComposerNode::SetState(TPVMFNodeInterfaceState aState)
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode::SetState: aState=%d", aState));
    PVMFNodeInterface::SetState(aState);
}

void PVMp4FFComposerNode::ReportErrorEvent(PvmfMp4FFCNError aErrorEvent, OsclAny* aEventData)
{
    LOG_ERR((0, "PVMp4FFComposerNode:ReportErrorEvent: aEventType=%d, aEventData=0x%x", aErrorEvent, aEventData));
    switch (aErrorEvent)
    {
        case PVMF_MP4FFCN_ERROR_FINALIZE_OUTPUT_FILE_FAILED:
        case PVMF_MP4FFCN_ERROR_ADD_SAMPLE_TO_TRACK_FAILED:
            PVMFNodeInterface::ReportErrorEvent(PVMFErrResourceConfiguration, aEventData);
            break;
        default:
            PVMFNodeInterface::ReportErrorEvent(PVMFFailure, aEventData);
            break;
    }
}

void PVMp4FFComposerNode::ReportInfoEvent(PVMFEventType aEventType, OsclAny* aEventData)
{
    LOG_STACK_TRACE((0, "PVMp4FFComposerNode:ReportInfoEvent: aEventType=%d, aEventData=0x%x", aEventType, aEventData));
    PVMFNodeInterface::ReportInfoEvent(aEventType, aEventData);
}



void PVMp4FFComposerNode::LogDiagnostics()
{
#if PROFILING_ON
    oDiagnosticsLogged = true;
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iDiagnosticsLogger, PVLOGMSG_DEBUG, (0, "PVMp4FFComposerNode Stats:Sample Add time (Min:%d, Max:%d), Sample Size(Min:%d, Max:%d), number of samples added:%d\n", iMinSampleAddTime, iMaxSampleAddTime, iMinSampleSize, iMaxSampleSize, iNumSamplesAdded));
#endif
}

int32 PVMp4FFComposerNode::StoreCurrentCommand(PVMp4FFCNCmdQueue& aCurrentCmd, PVMp4FFCNCmd& aCmd, PVMp4FFCNCmdQueue& aCmdQueue)
{
    int32 err = 0;
    OSCL_TRY(err, aCurrentCmd.StoreL(aCmd););
    OSCL_FIRST_CATCH_ANY(err,
                         CommandComplete(aCmdQueue, aCmd, PVMFErrNoMemory);
                         return err;
                        );
    return err;
}

void PVMp4FFComposerNode::GetTextSDIndex(uint32 aSampleNum, int32& aIndex)
{
    //default index is zero
    aIndex = 0;
    Oscl_Vector<PVA_FF_TextSampleDescInfo*, OsclMemAllocator>::iterator it;
    for (it = textdecodervector.begin(); it != textdecodervector.end(); it++)
    {
        if ((aSampleNum >= (*it)->start_sample_num) &&
                (aSampleNum <= (*it)->end_sample_num))
        {
            aIndex = (*it)->sdindex;
            break;
        }
    }
}