/*
* Copyright (c) 2008 - 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
/**
@file
@internalComponent
*/
#include "log.h"
#include <openmax/il/common/omxilcallbacknotificationif.h>
#include <openmax/il/common/omxilutil.h>
#include "c3gpdemuxer.h"
#include "omxil3gpdemuxerpanic.h"
#include "comxil3gpdemuxertimeinputport.h"
#include "comxil3gpdemuxeraudiooutputport.h"
#include "comxil3gpdemuxervideooutputport.h"
C3GPDemuxer::CPort* C3GPDemuxer::CPort::NewL(TInt aBufferCount)
{
CPort* self = new (ELeave) CPort();
CleanupStack::PushL(self);
self->ConstructL(aBufferCount);
CleanupStack::Pop(self);
return self;
}
C3GPDemuxer::CPort::CPort() :
iEOS(EFalse)
{
}
void C3GPDemuxer::CPort::ConstructL(TInt aBufferCount)
{
iBuffers.ReserveL(aBufferCount);
}
C3GPDemuxer::CPort::~CPort()
{
iBuffers.Reset();
}
C3GPDemuxer* C3GPDemuxer::NewL(MOmxILCallbackNotificationIf& aCallbacks)
{
C3GPDemuxer* self = new (ELeave) C3GPDemuxer(aCallbacks);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void C3GPDemuxer::ConstructL()
{
i3GPParser = C3GPParse::NewL();
}
C3GPDemuxer::C3GPDemuxer(MOmxILCallbackNotificationIf& aCallbacks) :
CActive(EPriorityStandard),
iCallbacks(aCallbacks),
iVideoType(E3GPNoVideo),
iAudioType(E3GPNoAudio),
iFirstVideoFrame(ETrue),
iFirstAudioFrame(ETrue),
iAsyncBuf(0, 0)
{
iOmxAudioFormat.iCoding = OMX_AUDIO_CodingMax;
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMax;
for (TInt port = 0; port < COmxIL3GPDemuxer::EPortIndexMax; ++port)
{
iPort[port] = NULL;
}
CActiveScheduler::Add(this);
}
C3GPDemuxer::~C3GPDemuxer()
{
Cancel();
DeleteBufferQueue();
if (i3GPParser)
{
HandleIfError(i3GPParser->Complete());
delete i3GPParser;
}
}
OMX_ERRORTYPE C3GPDemuxer::AcquireResources(const TDesC& aFilename)
{
DEBUG_PRINTF(_L8("C3GPDemuxer::AcquireResources"));
TInt error = i3GPParser->Open(aFilename);
if (error == KErrNone)
{
iParserOpened = ETrue;
if (iStartTimePosition != 0)
{
SetPosition(iStartTimePosition, iStartKeyFrame);
iSeekPosition = iStartTimePosition;
iStartTimePosition = 0;
}
TRAP(error, CreateBufferQueueL());
}
return SymbianOSErrorToOmx(error);
}
void C3GPDemuxer::ReleaseResources()
{
DeleteBufferQueue();
if (i3GPParser)
{
HandleIfError(i3GPParser->Complete());
iParserOpened = EFalse;
}
}
void C3GPDemuxer::Start()
{
if (iPaused && iState != EStateWaitingToStart)
{
if (iState != EStateFillingBuffer)
{
Cancel();
// Self complete so that we start to process any buffer received while
// we were in paused state
CompleteSelf();
}
}
else
{
Cancel();
iState = EStateWaitingForBuffer;
// Self complete so that we start to process any buffer received while
// we were in idle state
CompleteSelf();
}
iPaused = EFalse;
}
OMX_ERRORTYPE C3GPDemuxer::Stop()
{
Cancel();
if (iState == EStateFillingBuffer)
{
i3GPParser->CancelReadFrame();
}
iState = EStateWaitingToStart;
StartWaitingForBuffer();
iAudioHeadersSent = EFalse;
iFirstAudioFrame = ETrue;
iVideoHeadersSent = EFalse;
iFirstVideoFrame = ETrue;
iPaused = EFalse;
TInt error = SetPosition(0, EFalse);
return SymbianOSErrorToOmx(error);
}
void C3GPDemuxer::Pause()
{
iPaused = ETrue;
}
TBool C3GPDemuxer::Invalid() const
{
return iInvalid;
}
void C3GPDemuxer::ProcessThisBufferL(OMX_BUFFERHEADERTYPE* aBufferHeader,
TUint32 aPortIndex)
{
__ASSERT_DEBUG(iBufferQueueCreated, Panic(EProcessThisBufferLNoBufferQueue));
aBufferHeader->nFilledLen = 0;
aBufferHeader->nOffset = 0;
aBufferHeader->nTimeStamp = 0;
aBufferHeader->nFlags = 0;
if (iBufferQueueCreated)
{
TBufferMessage buffer;
buffer.iBufferHeader = aBufferHeader;
buffer.iPortIndex = aPortIndex;
User::LeaveIfError(iBufferQueue.Send(buffer));
}
else
{
User::Leave(KErrNotReady);
}
}
void C3GPDemuxer::FlushBuffers(TUint32 aPortIndex)
{
__ASSERT_DEBUG(aPortIndex == OMX_ALL || aPortIndex < COmxIL3GPDemuxer::EPortIndexMax, User::Invariant());
if (aPortIndex == OMX_ALL || aPortIndex < COmxIL3GPDemuxer::EPortIndexMax)
{
Cancel();
ReceiveQueuedBuffers();
if (aPortIndex == OMX_ALL || iCurrentPort == aPortIndex)
{
if (iState == EStateFillingBuffer)
{
// We are about to flush a buffer that is being filled.
// Cancel the read operation.
i3GPParser->CancelReadFrame();
}
iState = EStateWaitingForBuffer;
}
if (aPortIndex == OMX_ALL)
{
for (TInt portIndex = 0; portIndex < COmxIL3GPDemuxer::EPortIndexMax; ++portIndex)
{
DoFlushBuffers(portIndex);
}
}
else
{
DoFlushBuffers(aPortIndex);
}
// Unless we are waiting for a read to complete, we need to self
// complete just in case the ReceiveQueuedBuffers() call above
// received new buffers
if (iState != EStateFillingBuffer)
{
CompleteSelf();
}
}
}
void C3GPDemuxer::DoFlushBuffers(TUint32 aPortIndex)
{
if (iPort[aPortIndex])
{
OMX_DIRTYPE direction = OMX_DirOutput;
if (aPortIndex == COmxIL3GPDemuxer::EPortIndexTimeInput)
{
direction = OMX_DirInput;
}
RQueuedBuffers& buffers = iPort[aPortIndex]->iBuffers;
while (buffers.Count() > 0)
{
iCallbacks.BufferDoneNotification(buffers[0], aPortIndex, direction);
buffers.Remove(0);
}
}
}
TBool C3GPDemuxer::RemoveBuffer(OMX_BUFFERHEADERTYPE* aBufferHeader,
OMX_DIRTYPE aDirection)
{
TInt port = 0;
if (aDirection == OMX_DirOutput)
{
port = aBufferHeader->nOutputPortIndex;
}
else if (aDirection == OMX_DirInput)
{
port = aBufferHeader->nInputPortIndex;
}
else
{
Panic(ERemoveBufferInvalidDirection);
}
__ASSERT_DEBUG(port >= 0 && port < COmxIL3GPDemuxer::EPortIndexMax, Panic(ERemoveBufferInvalidPort));
TBool found = EFalse;
if (port >= 0 && port < COmxIL3GPDemuxer::EPortIndexMax)
{
Cancel();
ReceiveQueuedBuffers();
if (iPort[port])
{
RQueuedBuffers& buffers = iPort[port]->iBuffers;
for (TInt buf = 0; buf < buffers.Count(); ++buf)
{
if (buffers[buf] == aBufferHeader)
{
if (iCurrentPort == port && buf == 0)
{
if (iState == EStateFillingBuffer)
{
// We are about to remove a buffer that is being filled.
// Cancel the read operation.
i3GPParser->CancelReadFrame();
}
iState = EStateWaitingForBuffer;
}
buffers[buf]->nFilledLen = 0;
buffers.Remove(buf);
found = ETrue;
break;
}
}
}
// Unless we are waiting for a read to complete, we need to self
// complete just in case the ReceiveQueuedBuffers() call above
// received new buffers
if (iState != EStateFillingBuffer)
{
CompleteSelf();
}
}
return found;
}
TBool C3GPDemuxer::GetVideoFormat(TSize& aFrameSize, TVideoFormat& aFormat) const
{
if (!iVideoPropertiesRead)
{
return EFalse;
}
aFrameSize.iWidth = iVideoWidth;
aFrameSize.iHeight = iVideoHeight;
aFormat = iOmxVideoFormat;
return ETrue;
}
TBool C3GPDemuxer::GetAudioFormat(TAudioFormat& aFormat) const
{
if (!iAudioPropertiesRead)
{
return EFalse;
}
aFormat = iOmxAudioFormat;
return ETrue;
}
OMX_ERRORTYPE C3GPDemuxer::GetVideoTimestamp(OMX_TICKS& aOmxticks)
{
TInt err = KErrNone;
TUint timestampInMilliSec(0);
if (iParserOpened)
{
// return last requested seek time
timestampInMilliSec = iSeekPosition;
}
else
{
timestampInMilliSec = iStartTimePosition;
}
if (err == KErrNone)
{
aOmxticks = timestampInMilliSec * 1000;
}
return SymbianOSErrorToOmx(err);
}
OMX_ERRORTYPE C3GPDemuxer::Seek(const OMX_TICKS& aOmxticks, OMX_TIME_SEEKMODETYPE aSeekModeType)
{
TInt err = KErrNone;
//Set the firstFrame flags to true
iFirstVideoFrame = ETrue;
iFirstAudioFrame = ETrue;
TUint timeInMilliSec = aOmxticks / 1000;
TBool keyFrame(aSeekModeType == OMX_TIME_SeekModeFast);
if (iParserOpened)
{
err = SetPosition(timeInMilliSec, keyFrame);
if (err != KErrNone)
{
iSeekPosition = timeInMilliSec;
}
}
else
{
iStartTimePosition = timeInMilliSec;
iStartKeyFrame = keyFrame;
}
return SymbianOSErrorToOmx(err);
}
OMX_ERRORTYPE C3GPDemuxer::DetectStreams()
{
iAudioPropertiesRead = EFalse;
TUint s_audioLength;
TInt s_audioFramesPerSample;
TUint s_audioAvgBitRate;
TUint s_audioTimeScale;
TInt error = i3GPParser->GetAudioProperties(iAudioType, s_audioLength,
s_audioFramesPerSample, s_audioAvgBitRate, s_audioTimeScale);
if (error != KErrNotSupported)
{
if (error)
{
return SymbianOSErrorToOmx(error);
}
else
{
iOmxAudioFormat.iFramesPerSample = s_audioFramesPerSample;
iOmxAudioFormat.iSampleRate = s_audioTimeScale;
iOmxAudioFormat.iAverageBitrate = s_audioAvgBitRate;
switch (iAudioType)
{
case E3GPQcelp13K:
{
iOmxAudioFormat.iCoding = OMX_AUDIO_CodingQCELP13;
}
break;
case E3GPMpeg4Audio:
{
iOmxAudioFormat.iCoding = OMX_AUDIO_CodingAAC;
}
break;
case E3GPAmrNB:
case E3GPAmrWB:
{
iOmxAudioFormat.iCoding = OMX_AUDIO_CodingAMR;
}
break;
default:
{
iOmxAudioFormat.iCoding = OMX_AUDIO_CodingMax;
}
}
iAudioPropertiesRead = ETrue;
}
}
iVideoPropertiesRead = EFalse;
TSize vidSize(iVideoWidth, iVideoHeight);
TUint s_vidLength = 0;
TReal s_vidFrameRate = 0.0;
TUint s_vidAvgBitRate = 0;
TSize s_vidSize;
TUint s_vidTimeScale = 0;
error = i3GPParser->GetVideoProperties(iVideoType, s_vidLength,
s_vidFrameRate, s_vidAvgBitRate, s_vidSize, s_vidTimeScale);
if (error != KErrNotSupported)
{
if (error)
{
return SymbianOSErrorToOmx(error);
}
else
{
iVideoWidth = s_vidSize.iWidth;
iVideoHeight = s_vidSize.iHeight;
// translate library video type to OpenMAX IL coding and profile type
switch (iVideoType)
{
case E3GPMpeg4Video:
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMPEG4;
break;
case E3GPH263Profile0:
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingH263;
iOmxVideoFormat.iProfile.h263
= OMX_VIDEO_H263ProfileBaseline;
break;
case E3GPH263Profile3:
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingH263;
iOmxVideoFormat.iProfile.h263 = OMX_VIDEO_H263ProfileISWV2;
break;
case E3GPAvcProfileBaseline:
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingAVC;
iOmxVideoFormat.iProfile.avc = OMX_VIDEO_AVCProfileBaseline;
break;
default:
// do not return an error here, the error is signalled after the transition to Executing
iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMax;
break;
}
}
iVideoPropertiesRead = ETrue;
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE C3GPDemuxer::GetMetadataL(OMX_CONFIG_METADATAITEMTYPE* aMetadata)
{
// Metadata key size must be at least 4
if (aMetadata->nKeySizeUsed < 4)
{
return OMX_ErrorBadParameter;
}
T3GPUdtaLocation udtaLocation;
TUint32 udtaAtomType = Pack32(aMetadata->nKey);
TUint32 buffersize = aMetadata->nValueMaxSize;
RBuf8 buffer;
CleanupClosePushL(buffer);
User::LeaveIfError(buffer.Create(buffersize));
TUint atomIndex = 0;
if (aMetadata->nMetadataItemIndex != OMX_ALL)
{
atomIndex = aMetadata->nMetadataItemIndex;
}
TInt error = KErrNone;
switch (aMetadata->eScopeMode)
{
case OMX_MetadataScopeAllLevels:
{
TUint subatomCount = 0;
udtaLocation = E3GPUdtaMoov;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, subatomCount);
if (error == KErrNone)
{
if (atomIndex == 0)
{
break;
}
else if (atomIndex <= subatomCount)
{
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
break;
}
else
{
atomIndex -= (subatomCount + 1);
}
}
else if (error != KErrNotFound)
{
break;
}
subatomCount = 0;
udtaLocation = E3GPUdtaVideoTrak;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
buffer, subatomCount);
if (error == KErrNone)
{
if (atomIndex == 0)
{
break;
}
else if (atomIndex <= subatomCount)
{
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
break;
}
else
{
atomIndex -= (subatomCount + 1);
}
}
else if (error != KErrNotFound)
{
break;
}
udtaLocation = E3GPUdtaAudioTrak;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
buffer, atomIndex);
}
break;
case OMX_MetadataScopeTopLevel:
{
udtaLocation = E3GPUdtaMoov;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
buffer, atomIndex);
}
break;
case OMX_MetadataScopePortLevel:
{
if (aMetadata->nScopeSpecifier
== COmxIL3GPDemuxer::EPortIndexVideoOutput)
{
udtaLocation = E3GPUdtaVideoTrak;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
buffer, atomIndex);
}
else if (aMetadata->nScopeSpecifier == COmxIL3GPDemuxer::EPortIndexAudioOutput)
{
udtaLocation = E3GPUdtaAudioTrak;
error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
}
else
{
error = KErrArgument;
}
}
break;
default:
{
error = KErrArgument;
}
}
if (error == KErrNone)
{
// strip size and atom type from the buffer
Mem::Copy(aMetadata->nValue, (buffer.Ptr() + 8), (buffer.Size() - 8));
aMetadata->nValueSizeUsed = (buffer.Size() - 8);
}
CleanupStack::PopAndDestroy();//buffer
return SymbianOSErrorToOmx(error);
}
void C3GPDemuxer::RunL()
{
iWaitingOnBufferQueue = EFalse;
ReceiveQueuedBuffers();
if (iPaused || iInvalid || iState == EStateWaitingToStart)
{
StartWaitingForBuffer();
return;
}
if (iState == EStateWaitingToSubmit)
{
SubmitBuffer();
}
if (!ProcessBuffers())
{
iState = EStateWaitingForBuffer;
StartWaitingForBuffer();
}
}
void C3GPDemuxer::DoCancel()
{
if (iWaitingOnBufferQueue)
{
iWaitingOnBufferQueue = EFalse;
iBufferQueue.CancelDataAvailable();
}
}
TBool C3GPDemuxer::ProcessBuffers()
{
TUint32 startPort = iCurrentPort;
do
{
if (iPort[iCurrentPort]->iBuffers.Count() > 0 && !iPort[iCurrentPort]->iEOS)
{
DoProcessBuffer();
return ETrue;
}
}
while (NextPort() != startPort);
return EFalse;
}
void C3GPDemuxer::DoProcessBuffer()
{
iState = EStateFillingBuffer;
iCurrentBuffer = iPort[iCurrentPort]->iBuffers[0];
iPort[iCurrentPort]->iBuffers.Remove(0);
switch(iCurrentPort)
{
case COmxIL3GPDemuxer::EPortIndexTimeInput:
{
ProcessTimeBuffer();
break;
}
case COmxIL3GPDemuxer::EPortIndexAudioOutput:
{
FillAudioBuffer();
break;
}
case COmxIL3GPDemuxer::EPortIndexVideoOutput:
{
FillVideoBuffer();
break;
}
}
}
void C3GPDemuxer::ProcessTimeBuffer()
{
// TODO
User::Invariant();
}
void C3GPDemuxer::FillAudioBuffer()
{
if (!iAudioHeadersSent)
{
TPtr8 audioBuffer(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen,
0,
static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
TInt error = i3GPParser->GetAudioDecoderSpecificInfo(audioBuffer);
if (error == KErrNone)
{
iCurrentBuffer->nFilledLen = audioBuffer.Length();
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
iAudioHeadersSent = ETrue;
SubmitBuffer();
CompleteSelf();
}
else
{
HandleIfError(error);
}
return;
}
iAsyncBuf.Set(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen
,0
,static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
i3GPParser->ReadAudioFrames(*this, iAsyncBuf);
}
void C3GPDemuxer::FillVideoBuffer()
{
if (!iVideoHeadersSent)
{
iCurrentBuffer->nOffset = 0;
TPtr8 videoBuffer(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen,
0,
static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
TInt error = i3GPParser->GetVideoDecoderSpecificInfo(videoBuffer);
if (error == KErrNone)
{
iCurrentBuffer->nFilledLen = videoBuffer.Length();
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
iVideoHeadersSent = ETrue;
SubmitBuffer();
CompleteSelf();
}
else
{
HandleIfError(error);
}
return;
}
iAsyncBuf.Set(&iCurrentBuffer->pBuffer[0]
,static_cast<TInt>((iCurrentBuffer->nFilledLen + iCurrentBuffer->nOffset))
,static_cast<TInt>(iCurrentBuffer->nAllocLen));
i3GPParser->ReadVideoFrame(*this, iAsyncBuf);
}
void C3GPDemuxer::AudioFramesAvailable(TInt aError, TUint /*aReturnedFrames*/,
TUint aTimeStampInMs, TUint /*aTimeStampInTimescale*/)
{
HandleIfError(aError);
if (!iInvalid)
{
// Check if this is the last frame. It is the last frame if
// GetAudioFramesSize returns KErrNotFound
TUint frameSize = 0;
TInt nextFrameError = i3GPParser->GetAudioFramesSize(frameSize);
FileReadComplete(nextFrameError, aTimeStampInMs, iFirstAudioFrame, EFalse);
}
}
void C3GPDemuxer::VideoFrameAvailable(TInt aError, TBool aKeyFrame, TUint
aTimeStampInMs, TUint /*aTimeStampInTimescale*/)
{
HandleIfError(aError);
if (!iInvalid)
{
// Check if this is the last frame. It is the last frame if
// GetVideoFramesSize returns KErrNotFound
TUint frameSize = 0;
TInt nextFrameError = i3GPParser->GetVideoFrameSize(frameSize);
FileReadComplete(nextFrameError, aTimeStampInMs, iFirstVideoFrame, aKeyFrame);
}
}
void C3GPDemuxer::FileReadComplete(TInt aNextFrameError, TUint32 aTimeStamp, TBool& aFirstFrame, TBool aKeyFrame)
{
// aNextFrameError is the error code returned when checking the size of the
// next audio or video frame. If the error code is KErrNotFound, this
// shows that no more frames exist in that stream so the end of stream flag
// should be set when sending out the buffer.
if (aNextFrameError == KErrNotFound)
{
iPort[iCurrentPort]->iEOS = ETrue;
}
else
{
HandleIfError(aNextFrameError);
}
if (!iInvalid)
{
iCurrentBuffer->nFilledLen += iAsyncBuf.Length();
// Set presentation time
iCurrentBuffer->nTimeStamp = aTimeStamp * 1000;
if (aFirstFrame)
{
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_STARTTIME;
aFirstFrame = EFalse;
}
else
{
iCurrentBuffer->nFlags &= ~OMX_BUFFERFLAG_STARTTIME;
}
if (aKeyFrame)
{
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
}
else
{
iCurrentBuffer->nFlags &= ~OMX_BUFFERFLAG_SYNCFRAME;
}
// Demuxer just puts one whole frame into a buffer so we
// can set the end of frame flag
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
SubmitBuffer();
CompleteSelf();
}
}
void C3GPDemuxer::SubmitBuffer()
{
if (!iPaused)
{
if (iPort[iCurrentPort]->iEOS)
{
iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
iCallbacks.EventNotification(OMX_EventBufferFlag, iCurrentPort,
iCurrentBuffer->nFlags, NULL);
}
#if 0
else if (iCurrentBuffer->nFlags & OMX_BUFFERFLAG_STARTTIME)
{
iCallbacks.EventNotification(OMX_EventBufferFlag, iCurrentPort,
iCurrentBuffer->nFlags, NULL);
}
#endif
iCallbacks.BufferDoneNotification(iCurrentBuffer, iCurrentPort,
OMX_DirOutput);
iState = EStateWaitingForBuffer;
NextPort();
}
else
{
iState = EStateWaitingToSubmit;
}
}
void C3GPDemuxer::CreateBufferQueueL()
{
DEBUG_PRINTF(_L8("C3GPDemuxer::CreateBufferQueueL++"));
iPort[COmxIL3GPDemuxer::EPortIndexTimeInput] = CPort::NewL(KMaxTimeBuffers);
iPort[COmxIL3GPDemuxer::EPortIndexAudioOutput] = CPort::NewL(KMaxAudioBuffers);
iPort[COmxIL3GPDemuxer::EPortIndexVideoOutput] = CPort::NewL(KMaxVideoBuffers);
User::LeaveIfError(iBufferQueue.CreateLocal(KMaxTimeBuffers + KMaxAudioBuffers + KMaxVideoBuffers));
iBufferQueueCreated = ETrue;
iState = EStateWaitingToStart;
StartWaitingForBuffer();
DEBUG_PRINTF(_L8("C3GPDemuxer::CreateBufferQueueL--"));
}
void C3GPDemuxer::DeleteBufferQueue()
{
if (iBufferQueueCreated)
{
Cancel();
iBufferQueueCreated = EFalse;
iBufferQueue.Close();
}
for (TInt port = 0; port < COmxIL3GPDemuxer::EPortIndexMax; ++port)
{
delete iPort[port];
iPort[port] = NULL;
}
}
void C3GPDemuxer::HandleIfError(TInt aError)
{
OMX_ERRORTYPE omxError = SymbianOSErrorToOmx(aError);
if (omxError != OMX_ErrorNone)
{
iInvalid = ETrue;
iCallbacks.ErrorEventNotification(omxError);
}
}
// Helper function to convert Symbian OS standard error code to c style error code
OMX_ERRORTYPE C3GPDemuxer::SymbianOSErrorToOmx(TInt aError) const
{
OMX_ERRORTYPE error = OMX_ErrorUndefined;
switch (aError)
{
case (KErrNone):
{
error = OMX_ErrorNone;
}
break;
case (KErrNoMemory):
{
error = OMX_ErrorInsufficientResources;
}
break;
case (KErrOverflow):
{
error = OMX_ErrorOverflow;
}
break;
case (KErrAccessDenied):
{
error = OMX_ErrorContentPipeOpenFailed;
}
break;
case (KErrCorrupt):
{
error = OMX_ErrorStreamCorrupt;
}
break;
case (KErrArgument):
{
error = OMX_ErrorUnsupportedSetting;
}
break;
default:
{
error = OMX_ErrorUndefined;
}
}
return error;
}
void C3GPDemuxer::ReceiveQueuedBuffers()
{
if (iBufferQueueCreated)
{
TBufferMessage message;
while(iBufferQueue.Receive(message) != KErrUnderflow)
{
// Port buffers are pre-reserved so append should always work
if (iPort[message.iPortIndex]->iBuffers.Append(message.iBufferHeader) != KErrNone)
{
Panic(EReceiveQueuedBuffersAppendFailed);
}
}
}
}
void C3GPDemuxer::StartWaitingForBuffer()
{
if (iBufferQueueCreated)
{
iWaitingOnBufferQueue = ETrue;
iBufferQueue.NotifyDataAvailable(iStatus);
SetActive();
}
}
void C3GPDemuxer::CompleteSelf()
{
iStatus = KRequestPending;
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
}
TInt C3GPDemuxer::NextPort()
{
++iCurrentPort;
iCurrentPort %= COmxIL3GPDemuxer::EPortIndexMax;
return iCurrentPort;
}
/** Packs four bytes into a 32bit number */
TUint32 C3GPDemuxer::Pack32(const TUint8* aPtr)
{
TUint32 x = *aPtr++ << 24;
x |= *aPtr++ << 16;
x |= *aPtr++ << 8;
x |= *aPtr++;
return x;
}
TInt C3GPDemuxer::SetPosition(TUint aTimePosition, TBool aKeyFrame)
{
TUint audioPosition = 0;
TUint videoPosition = 0;
TInt err = i3GPParser->Seek(aTimePosition, aKeyFrame, audioPosition, videoPosition);
if(err)
{
return err;
}
// clear EOS state so buffer handling resumes if previously hit EOS
// TODO is this thread safe?
iPort[0]->iEOS = EFalse;
iPort[1]->iEOS = EFalse;
return KErrNone;
}