omxilvideocomps/omxil3gpdemuxer/src/c3gpdemuxer.cpp
changeset 0 5d29cba61097
equal deleted inserted replaced
-1:000000000000 0:5d29cba61097
       
     1 /*
       
     2 * Copyright (c) 2008 - 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalComponent
       
    22  */
       
    23 
       
    24 #include "log.h"
       
    25 #include <openmax/il/common/omxilcallbacknotificationif.h>
       
    26 #include <openmax/il/common/omxilutil.h>
       
    27 #include "c3gpdemuxer.h"
       
    28 #include "omxil3gpdemuxerpanic.h"
       
    29 #include "comxil3gpdemuxertimeinputport.h"
       
    30 #include "comxil3gpdemuxeraudiooutputport.h"
       
    31 #include "comxil3gpdemuxervideooutputport.h"
       
    32 
       
    33 C3GPDemuxer::CPort* C3GPDemuxer::CPort::NewL(TInt aBufferCount)
       
    34 	{
       
    35 	CPort* self = new (ELeave) CPort();
       
    36 	CleanupStack::PushL(self);
       
    37 	self->ConstructL(aBufferCount);
       
    38 	CleanupStack::Pop(self);
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 C3GPDemuxer::CPort::CPort() :
       
    43 	iEOS(EFalse)
       
    44 	{
       
    45 	}
       
    46 
       
    47 void C3GPDemuxer::CPort::ConstructL(TInt aBufferCount)
       
    48 	{
       
    49 	iBuffers.ReserveL(aBufferCount);
       
    50 	}
       
    51 
       
    52 C3GPDemuxer::CPort::~CPort()
       
    53 	{
       
    54 	iBuffers.Reset();
       
    55 	}
       
    56 
       
    57 C3GPDemuxer* C3GPDemuxer::NewL(MOmxILCallbackNotificationIf& aCallbacks)
       
    58 	{
       
    59 	C3GPDemuxer* self = new (ELeave) C3GPDemuxer(aCallbacks);
       
    60 	CleanupStack::PushL(self);
       
    61 	self->ConstructL();
       
    62 	CleanupStack::Pop(self);
       
    63 	return self;
       
    64 	}
       
    65 
       
    66 void C3GPDemuxer::ConstructL()
       
    67 	{
       
    68 	i3GPParser = C3GPParse::NewL();
       
    69 	}
       
    70 
       
    71 C3GPDemuxer::C3GPDemuxer(MOmxILCallbackNotificationIf& aCallbacks) :
       
    72 	CActive(EPriorityStandard),
       
    73 	iCallbacks(aCallbacks),
       
    74 	iVideoType(E3GPNoVideo),
       
    75 	iAudioType(E3GPNoAudio),
       
    76 	iFirstVideoFrame(ETrue),
       
    77 	iFirstAudioFrame(ETrue),
       
    78 	iAsyncBuf(0, 0)
       
    79 	{
       
    80 	iOmxAudioFormat.iCoding = OMX_AUDIO_CodingMax;
       
    81 	iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMax;
       
    82 
       
    83 	for (TInt port = 0; port < COmxIL3GPDemuxer::EPortIndexMax; ++port)
       
    84 		{
       
    85 		iPort[port] = NULL;
       
    86 		}
       
    87 
       
    88 	CActiveScheduler::Add(this);
       
    89 	}
       
    90 
       
    91 C3GPDemuxer::~C3GPDemuxer()
       
    92 	{
       
    93 	Cancel();
       
    94 
       
    95 	DeleteBufferQueue();
       
    96 
       
    97 	if (i3GPParser)
       
    98 		{
       
    99 		HandleIfError(i3GPParser->Complete());
       
   100 		delete i3GPParser;
       
   101 		}
       
   102 	}
       
   103 
       
   104 OMX_ERRORTYPE C3GPDemuxer::AcquireResources(const TDesC& aFilename)
       
   105 	{
       
   106 	DEBUG_PRINTF(_L8("C3GPDemuxer::AcquireResources"));
       
   107 
       
   108 	TInt error = i3GPParser->Open(aFilename);
       
   109 	if (error == KErrNone)
       
   110 		{
       
   111 		iParserOpened = ETrue;
       
   112 
       
   113 		if (iStartTimePosition != 0)
       
   114 			{
       
   115 			SetPosition(iStartTimePosition, iStartKeyFrame);
       
   116 			iSeekPosition = iStartTimePosition;
       
   117 			iStartTimePosition = 0;
       
   118 			}
       
   119 
       
   120 		TRAP(error, CreateBufferQueueL());
       
   121 		}
       
   122 
       
   123 	return SymbianOSErrorToOmx(error);
       
   124 	}
       
   125 
       
   126 void C3GPDemuxer::ReleaseResources()
       
   127 	{
       
   128 	DeleteBufferQueue();
       
   129 
       
   130 	if (i3GPParser)
       
   131 		{
       
   132 		HandleIfError(i3GPParser->Complete());
       
   133 		iParserOpened = EFalse;
       
   134 		}
       
   135 	}
       
   136 
       
   137 void C3GPDemuxer::Start()
       
   138 	{
       
   139 	if (iPaused && iState != EStateWaitingToStart)
       
   140 		{
       
   141 		if (iState != EStateFillingBuffer)
       
   142 			{
       
   143 			Cancel();
       
   144 			
       
   145 			// Self complete so that we start to process any buffer received while
       
   146 			// we were in paused state
       
   147 			CompleteSelf();
       
   148 			}
       
   149 		}
       
   150 	else
       
   151 		{
       
   152 		Cancel();
       
   153 		iState = EStateWaitingForBuffer;
       
   154 		// Self complete so that we start to process any buffer received while
       
   155 		// we were in idle state
       
   156 		CompleteSelf();
       
   157 		}
       
   158 
       
   159 	iPaused = EFalse;
       
   160 	}
       
   161 
       
   162 OMX_ERRORTYPE C3GPDemuxer::Stop()
       
   163 	{
       
   164 	Cancel();
       
   165 
       
   166 	if (iState == EStateFillingBuffer)
       
   167 		{
       
   168 	 	i3GPParser->CancelReadFrame();
       
   169 		}
       
   170 
       
   171 	iState = EStateWaitingToStart;
       
   172 	StartWaitingForBuffer();
       
   173 
       
   174 	iAudioHeadersSent = EFalse;
       
   175 	iFirstAudioFrame = ETrue;
       
   176 	iVideoHeadersSent = EFalse;
       
   177 	iFirstVideoFrame = ETrue;
       
   178 	iPaused = EFalse;
       
   179 
       
   180 	TInt error = SetPosition(0, EFalse);
       
   181 
       
   182 	return SymbianOSErrorToOmx(error);
       
   183 	}
       
   184 
       
   185 void C3GPDemuxer::Pause()
       
   186 	{
       
   187 	iPaused = ETrue;
       
   188 	}
       
   189 
       
   190 TBool C3GPDemuxer::Invalid() const
       
   191 	{
       
   192 	return iInvalid;
       
   193 	}
       
   194 
       
   195 void C3GPDemuxer::ProcessThisBufferL(OMX_BUFFERHEADERTYPE* aBufferHeader,
       
   196 		TUint32 aPortIndex)
       
   197 	{
       
   198 	__ASSERT_DEBUG(iBufferQueueCreated, Panic(EProcessThisBufferLNoBufferQueue));
       
   199 
       
   200 	aBufferHeader->nFilledLen = 0;
       
   201 	aBufferHeader->nOffset = 0;
       
   202 	aBufferHeader->nTimeStamp = 0;
       
   203 	aBufferHeader->nFlags = 0;
       
   204 
       
   205 	if (iBufferQueueCreated)
       
   206 		{
       
   207 		TBufferMessage buffer;
       
   208 		buffer.iBufferHeader = aBufferHeader;
       
   209 		buffer.iPortIndex = aPortIndex;
       
   210 		User::LeaveIfError(iBufferQueue.Send(buffer));
       
   211 		}
       
   212 	else
       
   213 		{
       
   214 		User::Leave(KErrNotReady);
       
   215 		}
       
   216 	}
       
   217 
       
   218 void C3GPDemuxer::FlushBuffers(TUint32 aPortIndex)
       
   219 	{
       
   220 	__ASSERT_DEBUG(aPortIndex == OMX_ALL || aPortIndex < COmxIL3GPDemuxer::EPortIndexMax, User::Invariant());
       
   221 
       
   222 	if (aPortIndex == OMX_ALL || aPortIndex < COmxIL3GPDemuxer::EPortIndexMax)
       
   223 		{
       
   224 		Cancel();
       
   225 		ReceiveQueuedBuffers();
       
   226 
       
   227 		if (aPortIndex == OMX_ALL || iCurrentPort == aPortIndex)
       
   228 			{
       
   229 			if (iState == EStateFillingBuffer)
       
   230 				{
       
   231 				// We are about to flush a buffer that is being filled.
       
   232 			 	// Cancel the read operation.
       
   233 			 	i3GPParser->CancelReadFrame();
       
   234 				}
       
   235 
       
   236 		 	iState = EStateWaitingForBuffer;
       
   237 			}
       
   238 
       
   239 		if (aPortIndex == OMX_ALL)
       
   240 			{
       
   241 			for (TInt portIndex = 0; portIndex < COmxIL3GPDemuxer::EPortIndexMax; ++portIndex)
       
   242 				{
       
   243 				DoFlushBuffers(portIndex);
       
   244 				}
       
   245 			}
       
   246 		else
       
   247 			{
       
   248 			DoFlushBuffers(aPortIndex);
       
   249 			}
       
   250 
       
   251 		// Unless we are waiting for a read to complete, we need to self
       
   252 		// complete just in case the ReceiveQueuedBuffers() call above
       
   253 		// received new buffers
       
   254 		if (iState != EStateFillingBuffer)
       
   255 			{
       
   256 			CompleteSelf();
       
   257 			}
       
   258 		}
       
   259 	}
       
   260 
       
   261 void C3GPDemuxer::DoFlushBuffers(TUint32 aPortIndex)
       
   262 	{
       
   263 	if (iPort[aPortIndex])
       
   264 		{
       
   265 		OMX_DIRTYPE direction = OMX_DirOutput;
       
   266 		if (aPortIndex == COmxIL3GPDemuxer::EPortIndexTimeInput)
       
   267 			{
       
   268 			direction = OMX_DirInput;
       
   269 			}
       
   270 
       
   271 		RQueuedBuffers& buffers = iPort[aPortIndex]->iBuffers;
       
   272 		while (buffers.Count() > 0)
       
   273 			{
       
   274 			iCallbacks.BufferDoneNotification(buffers[0], aPortIndex, direction);
       
   275 			buffers.Remove(0);
       
   276 			}
       
   277 		}
       
   278 	}
       
   279 
       
   280 TBool C3GPDemuxer::RemoveBuffer(OMX_BUFFERHEADERTYPE* aBufferHeader,
       
   281                                 OMX_DIRTYPE aDirection)
       
   282 	{
       
   283 	TInt port = 0;
       
   284 	if (aDirection == OMX_DirOutput)
       
   285 		{
       
   286 		port = aBufferHeader->nOutputPortIndex;
       
   287 		}
       
   288 	else if (aDirection == OMX_DirInput)
       
   289 		{
       
   290 		port = aBufferHeader->nInputPortIndex;
       
   291 		}
       
   292 	else
       
   293 		{
       
   294 		Panic(ERemoveBufferInvalidDirection);
       
   295 		}
       
   296 
       
   297 	__ASSERT_DEBUG(port >= 0 && port < COmxIL3GPDemuxer::EPortIndexMax, Panic(ERemoveBufferInvalidPort));
       
   298 
       
   299 	TBool found = EFalse;
       
   300 
       
   301 	if (port >= 0 && port < COmxIL3GPDemuxer::EPortIndexMax)
       
   302 		{
       
   303 		Cancel();
       
   304 		ReceiveQueuedBuffers();
       
   305 
       
   306 		if (iPort[port])
       
   307 			{
       
   308 			RQueuedBuffers& buffers = iPort[port]->iBuffers;
       
   309 			for (TInt buf = 0; buf < buffers.Count(); ++buf)
       
   310 				{
       
   311 				if (buffers[buf] == aBufferHeader)
       
   312 					{
       
   313 					if (iCurrentPort == port && buf == 0)
       
   314 						{				
       
   315 						if (iState == EStateFillingBuffer)
       
   316 							{
       
   317 							// We are about to remove a buffer that is being filled.
       
   318 			 				// Cancel the read operation.
       
   319 			 				i3GPParser->CancelReadFrame();
       
   320 							}
       
   321 		 				iState = EStateWaitingForBuffer;
       
   322 						}
       
   323 
       
   324 					buffers[buf]->nFilledLen = 0;
       
   325 					buffers.Remove(buf);
       
   326 					found = ETrue;
       
   327 					break;
       
   328 					}
       
   329 				}
       
   330 			}
       
   331 
       
   332 		// Unless we are waiting for a read to complete, we need to self
       
   333 		// complete just in case the ReceiveQueuedBuffers() call above
       
   334 		// received new buffers
       
   335 		if (iState != EStateFillingBuffer)
       
   336 			{
       
   337 			CompleteSelf();
       
   338 			}
       
   339 		}
       
   340 
       
   341 	return found;
       
   342 	}
       
   343 
       
   344 TBool C3GPDemuxer::GetVideoFormat(TSize& aFrameSize, TVideoFormat& aFormat) const
       
   345 	{
       
   346 	if (!iVideoPropertiesRead)
       
   347 		{
       
   348 		return EFalse;
       
   349 		}
       
   350 	aFrameSize.iWidth = iVideoWidth;
       
   351 	aFrameSize.iHeight = iVideoHeight;
       
   352 	aFormat = iOmxVideoFormat;
       
   353 	return ETrue;
       
   354 	}
       
   355 
       
   356 TBool C3GPDemuxer::GetAudioFormat(TAudioFormat& aFormat) const
       
   357 	{
       
   358 	if (!iAudioPropertiesRead)
       
   359 		{
       
   360 		return EFalse;
       
   361 		}
       
   362 	aFormat = iOmxAudioFormat;
       
   363 	return ETrue;
       
   364 	}
       
   365 
       
   366 OMX_ERRORTYPE C3GPDemuxer::GetVideoTimestamp(OMX_TICKS& aOmxticks)
       
   367 	{
       
   368 	TInt err = KErrNone;
       
   369 
       
   370 	TUint timestampInMilliSec(0);
       
   371 
       
   372 	if (iParserOpened)
       
   373 		{
       
   374 		// return last requested seek time
       
   375 		timestampInMilliSec = iSeekPosition;
       
   376 		}
       
   377 	else
       
   378 		{
       
   379 		timestampInMilliSec = iStartTimePosition;
       
   380 		}
       
   381 
       
   382 	if (err == KErrNone)
       
   383 		{
       
   384 		aOmxticks = timestampInMilliSec * 1000;
       
   385 		}
       
   386 
       
   387 	return SymbianOSErrorToOmx(err);
       
   388 	}
       
   389 
       
   390 OMX_ERRORTYPE C3GPDemuxer::Seek(const OMX_TICKS& aOmxticks, OMX_TIME_SEEKMODETYPE aSeekModeType)
       
   391     {
       
   392 	TInt err = KErrNone;
       
   393 
       
   394 	//Set the firstFrame flags to true
       
   395 	iFirstVideoFrame = ETrue;
       
   396 	iFirstAudioFrame = ETrue;
       
   397 
       
   398 	TUint timeInMilliSec = aOmxticks / 1000;
       
   399 	TBool keyFrame(aSeekModeType == OMX_TIME_SeekModeFast);
       
   400 
       
   401 	if (iParserOpened)
       
   402 		{
       
   403 		err = SetPosition(timeInMilliSec, keyFrame);
       
   404 		if (err != KErrNone)
       
   405 			{
       
   406 			iSeekPosition = timeInMilliSec;
       
   407 			}
       
   408 		}
       
   409 	else
       
   410 		{
       
   411 		iStartTimePosition = timeInMilliSec;
       
   412 		iStartKeyFrame = keyFrame;
       
   413 		}
       
   414 
       
   415 	return SymbianOSErrorToOmx(err);
       
   416 	}
       
   417 
       
   418 OMX_ERRORTYPE C3GPDemuxer::DetectStreams()
       
   419 	{
       
   420 	iAudioPropertiesRead = EFalse;
       
   421 
       
   422 	TUint s_audioLength;
       
   423 	TInt s_audioFramesPerSample;
       
   424 	TUint s_audioAvgBitRate;
       
   425 	TUint s_audioTimeScale;
       
   426 	TInt error = i3GPParser->GetAudioProperties(iAudioType, s_audioLength,
       
   427 			s_audioFramesPerSample, s_audioAvgBitRate, s_audioTimeScale);
       
   428 
       
   429 	if (error != KErrNotSupported)
       
   430 		{
       
   431 		if (error)
       
   432 			{
       
   433 			return SymbianOSErrorToOmx(error);
       
   434 			}
       
   435 		else
       
   436 			{
       
   437 			iOmxAudioFormat.iFramesPerSample = s_audioFramesPerSample;
       
   438 			iOmxAudioFormat.iSampleRate = s_audioTimeScale;
       
   439 			iOmxAudioFormat.iAverageBitrate = s_audioAvgBitRate;
       
   440 			switch (iAudioType)
       
   441 				{
       
   442 				case E3GPQcelp13K:
       
   443 					{
       
   444 					iOmxAudioFormat.iCoding = OMX_AUDIO_CodingQCELP13;
       
   445 					}
       
   446 					break;
       
   447 				case E3GPMpeg4Audio:
       
   448 					{
       
   449 					iOmxAudioFormat.iCoding = OMX_AUDIO_CodingAAC;
       
   450 					}
       
   451 					break;
       
   452 				case E3GPAmrNB:
       
   453 				case E3GPAmrWB:
       
   454 					{
       
   455 					iOmxAudioFormat.iCoding = OMX_AUDIO_CodingAMR;
       
   456 					}
       
   457 					break;
       
   458 				default:
       
   459 					{
       
   460 					iOmxAudioFormat.iCoding = OMX_AUDIO_CodingMax;
       
   461 					}
       
   462 				}
       
   463 
       
   464 			iAudioPropertiesRead = ETrue;
       
   465 			}
       
   466 
       
   467 		}
       
   468 	iVideoPropertiesRead = EFalse;
       
   469 
       
   470 	TSize vidSize(iVideoWidth, iVideoHeight);
       
   471 	TUint s_vidLength = 0;
       
   472 	TReal s_vidFrameRate = 0.0;
       
   473 	TUint s_vidAvgBitRate = 0;
       
   474 	TSize s_vidSize;
       
   475 	TUint s_vidTimeScale = 0;
       
   476 
       
   477 	error = i3GPParser->GetVideoProperties(iVideoType, s_vidLength,
       
   478 			s_vidFrameRate, s_vidAvgBitRate, s_vidSize, s_vidTimeScale);
       
   479 
       
   480 	if (error != KErrNotSupported)
       
   481 		{
       
   482 		if (error)
       
   483 			{
       
   484 			return SymbianOSErrorToOmx(error);
       
   485 			}
       
   486 		else
       
   487 			{
       
   488 			iVideoWidth = s_vidSize.iWidth;
       
   489 			iVideoHeight = s_vidSize.iHeight;
       
   490 
       
   491 			// translate library video type to OpenMAX IL coding and profile type
       
   492 			switch (iVideoType)
       
   493 				{
       
   494 				case E3GPMpeg4Video:
       
   495 					iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMPEG4;
       
   496 					break;
       
   497 				case E3GPH263Profile0:
       
   498 					iOmxVideoFormat.iCoding = OMX_VIDEO_CodingH263;
       
   499 					iOmxVideoFormat.iProfile.h263
       
   500 							= OMX_VIDEO_H263ProfileBaseline;
       
   501 					break;
       
   502 				case E3GPH263Profile3:
       
   503 					iOmxVideoFormat.iCoding = OMX_VIDEO_CodingH263;
       
   504 					iOmxVideoFormat.iProfile.h263 = OMX_VIDEO_H263ProfileISWV2;
       
   505 					break;
       
   506 				case E3GPAvcProfileBaseline:
       
   507 					iOmxVideoFormat.iCoding = OMX_VIDEO_CodingAVC;
       
   508 					iOmxVideoFormat.iProfile.avc = OMX_VIDEO_AVCProfileBaseline;
       
   509 					break;
       
   510 				default:
       
   511 					// do not return an error here, the error is signalled after the transition to Executing
       
   512 					iOmxVideoFormat.iCoding = OMX_VIDEO_CodingMax;
       
   513 					break;
       
   514 				}
       
   515 			}
       
   516 			iVideoPropertiesRead = ETrue;
       
   517 		}
       
   518 
       
   519 	return OMX_ErrorNone;
       
   520 	}
       
   521 
       
   522 
       
   523 OMX_ERRORTYPE C3GPDemuxer::GetMetadataL(OMX_CONFIG_METADATAITEMTYPE* aMetadata)
       
   524 	{
       
   525 	// Metadata key size must be at least 4
       
   526 	if (aMetadata->nKeySizeUsed < 4)
       
   527 		{
       
   528 		return OMX_ErrorBadParameter;
       
   529 		}
       
   530 
       
   531 	T3GPUdtaLocation udtaLocation;
       
   532 	TUint32 udtaAtomType = Pack32(aMetadata->nKey);
       
   533 	TUint32 buffersize = aMetadata->nValueMaxSize;
       
   534 
       
   535 	RBuf8 buffer;
       
   536 	CleanupClosePushL(buffer);
       
   537 	User::LeaveIfError(buffer.Create(buffersize));
       
   538 
       
   539 	TUint atomIndex = 0;
       
   540 	if (aMetadata->nMetadataItemIndex != OMX_ALL)
       
   541 		{
       
   542 		atomIndex = aMetadata->nMetadataItemIndex;
       
   543 		}
       
   544 
       
   545 	TInt error = KErrNone;
       
   546 
       
   547 	switch (aMetadata->eScopeMode)
       
   548 		{
       
   549 		case OMX_MetadataScopeAllLevels:
       
   550 			{
       
   551 			TUint subatomCount = 0;
       
   552 			udtaLocation = E3GPUdtaMoov;
       
   553 
       
   554 			error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,	buffer, subatomCount);
       
   555 
       
   556 			if (error == KErrNone)
       
   557 				{
       
   558 				if (atomIndex == 0)
       
   559 					{
       
   560 					break;
       
   561 					}
       
   562 				else if (atomIndex <= subatomCount)
       
   563 					{
       
   564 					error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
       
   565 					break;
       
   566 					}
       
   567 				else
       
   568 					{
       
   569 					atomIndex -= (subatomCount + 1);
       
   570 					}
       
   571 				}
       
   572 			else if (error != KErrNotFound)
       
   573 				{
       
   574 				break;
       
   575 				}
       
   576 			
       
   577 			subatomCount = 0;
       
   578 			udtaLocation = E3GPUdtaVideoTrak;
       
   579 			error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
       
   580 					buffer, subatomCount);
       
   581 			if (error == KErrNone)
       
   582 				{
       
   583 				if (atomIndex == 0)
       
   584 					{
       
   585 					break;
       
   586 					}
       
   587 				else if (atomIndex <= subatomCount)
       
   588 					{
       
   589 					error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
       
   590 					break;
       
   591 					}
       
   592 				else
       
   593 					{
       
   594 					atomIndex -= (subatomCount + 1);
       
   595 					}
       
   596 				}
       
   597 			else if (error != KErrNotFound)
       
   598 				{
       
   599 				break;
       
   600 				}
       
   601 			
       
   602 			udtaLocation = E3GPUdtaAudioTrak;
       
   603 			error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
       
   604 					buffer, atomIndex);
       
   605 			}
       
   606 			break;
       
   607 		case OMX_MetadataScopeTopLevel:
       
   608 			{
       
   609 			udtaLocation = E3GPUdtaMoov;
       
   610 			error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
       
   611 					buffer, atomIndex);
       
   612 			}
       
   613 			break;
       
   614 		case OMX_MetadataScopePortLevel:
       
   615 			{
       
   616 			if (aMetadata->nScopeSpecifier
       
   617 					== COmxIL3GPDemuxer::EPortIndexVideoOutput)
       
   618 				{
       
   619 				udtaLocation = E3GPUdtaVideoTrak;
       
   620 				error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation,
       
   621 						buffer, atomIndex);
       
   622 				}
       
   623 			else if (aMetadata->nScopeSpecifier == COmxIL3GPDemuxer::EPortIndexAudioOutput)
       
   624 				{
       
   625 				udtaLocation = E3GPUdtaAudioTrak;
       
   626 				error = i3GPParser->GetUserDataAtom(udtaAtomType, udtaLocation, buffer, atomIndex);
       
   627 				}
       
   628 			else
       
   629 				{
       
   630 				error = KErrArgument;
       
   631 				}
       
   632 			}
       
   633 			break;
       
   634 		default:
       
   635 			{
       
   636 			error = KErrArgument;
       
   637 			}
       
   638 		}
       
   639 
       
   640 	if (error == KErrNone)
       
   641 		{
       
   642 		// strip size and atom type from the buffer
       
   643 		Mem::Copy(aMetadata->nValue, (buffer.Ptr() + 8), (buffer.Size() - 8));
       
   644 		aMetadata->nValueSizeUsed = (buffer.Size() - 8);
       
   645 		}
       
   646 
       
   647 	CleanupStack::PopAndDestroy();//buffer
       
   648 	return SymbianOSErrorToOmx(error);
       
   649 	}
       
   650 
       
   651 void C3GPDemuxer::RunL()
       
   652 	{
       
   653 	iWaitingOnBufferQueue = EFalse;
       
   654 	ReceiveQueuedBuffers();
       
   655 
       
   656 	if (iPaused || iInvalid || iState == EStateWaitingToStart)
       
   657 		{
       
   658 		StartWaitingForBuffer();
       
   659 		return;
       
   660 		}
       
   661 
       
   662 	if (iState == EStateWaitingToSubmit)
       
   663 		{
       
   664 		SubmitBuffer();
       
   665 		}
       
   666 
       
   667 	if (!ProcessBuffers())
       
   668 		{
       
   669 		iState = EStateWaitingForBuffer;
       
   670 		StartWaitingForBuffer();
       
   671 		}
       
   672 	}
       
   673 
       
   674 void C3GPDemuxer::DoCancel()
       
   675 	{
       
   676 	if (iWaitingOnBufferQueue)
       
   677 		{
       
   678 		iWaitingOnBufferQueue = EFalse;
       
   679 		iBufferQueue.CancelDataAvailable();
       
   680 		}
       
   681 	}
       
   682 
       
   683 TBool C3GPDemuxer::ProcessBuffers()
       
   684 	{
       
   685 	TUint32 startPort = iCurrentPort;
       
   686 
       
   687 	do
       
   688 		{
       
   689 		if (iPort[iCurrentPort]->iBuffers.Count() > 0 && !iPort[iCurrentPort]->iEOS)
       
   690 			{
       
   691 			DoProcessBuffer();
       
   692 			return ETrue;
       
   693 			}
       
   694 		}
       
   695 	while (NextPort() != startPort);
       
   696 
       
   697 	return EFalse;
       
   698 	}
       
   699 
       
   700 void C3GPDemuxer::DoProcessBuffer()
       
   701 	{
       
   702 	iState = EStateFillingBuffer;
       
   703 
       
   704 	iCurrentBuffer = iPort[iCurrentPort]->iBuffers[0];
       
   705 	iPort[iCurrentPort]->iBuffers.Remove(0);
       
   706 
       
   707 	switch(iCurrentPort)
       
   708 		{
       
   709 		case COmxIL3GPDemuxer::EPortIndexTimeInput:
       
   710 			{
       
   711 			ProcessTimeBuffer();
       
   712 			break;
       
   713 			}
       
   714 		case COmxIL3GPDemuxer::EPortIndexAudioOutput:
       
   715 			{
       
   716 			FillAudioBuffer();
       
   717 			break;
       
   718 			}
       
   719 		case COmxIL3GPDemuxer::EPortIndexVideoOutput:
       
   720 			{
       
   721 			FillVideoBuffer();
       
   722 			break;
       
   723 			}
       
   724 		}				
       
   725 	}
       
   726 
       
   727 void C3GPDemuxer::ProcessTimeBuffer()
       
   728 	{
       
   729 	// TODO
       
   730 	User::Invariant();
       
   731 	}
       
   732 
       
   733 void C3GPDemuxer::FillAudioBuffer()
       
   734 	{
       
   735 	if (!iAudioHeadersSent)
       
   736 		{
       
   737 		TPtr8 audioBuffer(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen,
       
   738 				0,
       
   739 				static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
       
   740 		TInt error = i3GPParser->GetAudioDecoderSpecificInfo(audioBuffer);
       
   741 
       
   742 		if (error == KErrNone)
       
   743 			{
       
   744 			iCurrentBuffer->nFilledLen = audioBuffer.Length();
       
   745 			iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
       
   746 			iAudioHeadersSent = ETrue;
       
   747 			SubmitBuffer();
       
   748 			CompleteSelf();
       
   749 			}
       
   750 		else
       
   751 			{
       
   752 			HandleIfError(error);
       
   753 			}
       
   754 		return;
       
   755 		}
       
   756 
       
   757 	iAsyncBuf.Set(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen
       
   758 	              ,0
       
   759 	              ,static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
       
   760 	i3GPParser->ReadAudioFrames(*this, iAsyncBuf);
       
   761 	}
       
   762 
       
   763 void C3GPDemuxer::FillVideoBuffer()
       
   764 	{
       
   765 	if (!iVideoHeadersSent)
       
   766 		{
       
   767 		iCurrentBuffer->nOffset = 0;
       
   768 
       
   769 		TPtr8 videoBuffer(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset + iCurrentBuffer->nFilledLen,
       
   770 				0,
       
   771 				static_cast<TInt>(iCurrentBuffer->nAllocLen - iCurrentBuffer->nOffset - iCurrentBuffer->nFilledLen));
       
   772 		TInt error = i3GPParser->GetVideoDecoderSpecificInfo(videoBuffer);
       
   773 
       
   774 		if (error == KErrNone)
       
   775 			{
       
   776 			iCurrentBuffer->nFilledLen = videoBuffer.Length();
       
   777 			iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
       
   778 			iVideoHeadersSent = ETrue;
       
   779 			SubmitBuffer();
       
   780 			CompleteSelf();
       
   781 			}
       
   782 		else
       
   783 			{
       
   784 			HandleIfError(error);
       
   785 			}
       
   786 		return;
       
   787 		}
       
   788 
       
   789 	iAsyncBuf.Set(&iCurrentBuffer->pBuffer[0]
       
   790 	              ,static_cast<TInt>((iCurrentBuffer->nFilledLen + iCurrentBuffer->nOffset))
       
   791 	              ,static_cast<TInt>(iCurrentBuffer->nAllocLen));
       
   792 	i3GPParser->ReadVideoFrame(*this, iAsyncBuf);
       
   793 	}
       
   794 
       
   795 void C3GPDemuxer::AudioFramesAvailable(TInt aError, TUint /*aReturnedFrames*/,
       
   796 		TUint aTimeStampInMs, TUint /*aTimeStampInTimescale*/)
       
   797 	{
       
   798 	HandleIfError(aError);
       
   799 
       
   800 	if (!iInvalid)
       
   801 		{
       
   802 		// Check if this is the last frame. It is the last frame if
       
   803 		// GetAudioFramesSize returns KErrNotFound
       
   804 		TUint frameSize = 0;
       
   805 		TInt nextFrameError = i3GPParser->GetAudioFramesSize(frameSize);
       
   806 
       
   807 		FileReadComplete(nextFrameError, aTimeStampInMs, iFirstAudioFrame, EFalse);
       
   808 		}
       
   809 	}
       
   810 
       
   811 void C3GPDemuxer::VideoFrameAvailable(TInt aError, TBool aKeyFrame, TUint
       
   812 aTimeStampInMs, TUint /*aTimeStampInTimescale*/)
       
   813 	{
       
   814 	HandleIfError(aError);
       
   815 
       
   816 	if (!iInvalid)
       
   817 		{
       
   818 		// Check if this is the last frame. It is the last frame if
       
   819 		// GetVideoFramesSize returns KErrNotFound
       
   820 		TUint frameSize = 0;
       
   821 		TInt nextFrameError = i3GPParser->GetVideoFrameSize(frameSize);
       
   822 
       
   823 		FileReadComplete(nextFrameError, aTimeStampInMs, iFirstVideoFrame, aKeyFrame);
       
   824 		}
       
   825 	}
       
   826 
       
   827 void C3GPDemuxer::FileReadComplete(TInt aNextFrameError, TUint32 aTimeStamp, TBool& aFirstFrame, TBool aKeyFrame)
       
   828 	{
       
   829 	// aNextFrameError is the error code returned when checking the size of the
       
   830 	// next audio or video frame. If the error code is KErrNotFound, this
       
   831 	// shows that no more frames exist in that stream so the end of stream flag
       
   832 	// should be set when sending out the buffer.
       
   833 	if (aNextFrameError == KErrNotFound)
       
   834 		{
       
   835 		iPort[iCurrentPort]->iEOS = ETrue;
       
   836 		}
       
   837 	else
       
   838 		{
       
   839 		HandleIfError(aNextFrameError);
       
   840 		}
       
   841 
       
   842 	if (!iInvalid)
       
   843 		{
       
   844 		iCurrentBuffer->nFilledLen += iAsyncBuf.Length();
       
   845 
       
   846 		// Set presentation time 	
       
   847 		iCurrentBuffer->nTimeStamp = aTimeStamp * 1000;
       
   848 
       
   849 		if (aFirstFrame)
       
   850 			{
       
   851 			iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_STARTTIME;
       
   852 			aFirstFrame = EFalse;
       
   853 			}
       
   854 		else
       
   855 			{
       
   856 			iCurrentBuffer->nFlags &= ~OMX_BUFFERFLAG_STARTTIME;
       
   857 			}
       
   858 
       
   859 		if (aKeyFrame)
       
   860 			{
       
   861 			iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
       
   862 			}
       
   863 		else
       
   864 			{
       
   865 			iCurrentBuffer->nFlags &= ~OMX_BUFFERFLAG_SYNCFRAME;			
       
   866 			}
       
   867 
       
   868 		// Demuxer just puts one whole frame into a buffer so we
       
   869 		// can set the end of frame flag
       
   870 		iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
       
   871 
       
   872 		SubmitBuffer();
       
   873 		CompleteSelf();
       
   874 		}
       
   875 	}
       
   876 
       
   877 void C3GPDemuxer::SubmitBuffer()
       
   878 	{
       
   879 	if (!iPaused)
       
   880 		{
       
   881 		if (iPort[iCurrentPort]->iEOS)
       
   882 			{
       
   883 			iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
       
   884 			iCallbacks.EventNotification(OMX_EventBufferFlag, iCurrentPort,
       
   885 					iCurrentBuffer->nFlags, NULL);
       
   886 			}
       
   887 		#if 0
       
   888 		else if (iCurrentBuffer->nFlags & OMX_BUFFERFLAG_STARTTIME)
       
   889 			{
       
   890 			iCallbacks.EventNotification(OMX_EventBufferFlag, iCurrentPort,
       
   891 				iCurrentBuffer->nFlags, NULL);
       
   892 			}
       
   893 		#endif
       
   894 
       
   895 		iCallbacks.BufferDoneNotification(iCurrentBuffer, iCurrentPort,
       
   896 				OMX_DirOutput);
       
   897 	
       
   898 		iState = EStateWaitingForBuffer;
       
   899 		NextPort();	
       
   900 		}
       
   901 	else
       
   902 		{
       
   903 		iState = EStateWaitingToSubmit;
       
   904 		}
       
   905 	}
       
   906 
       
   907 void C3GPDemuxer::CreateBufferQueueL()
       
   908 	{
       
   909 	DEBUG_PRINTF(_L8("C3GPDemuxer::CreateBufferQueueL++"));
       
   910 
       
   911 	iPort[COmxIL3GPDemuxer::EPortIndexTimeInput] = CPort::NewL(KMaxTimeBuffers);
       
   912 	iPort[COmxIL3GPDemuxer::EPortIndexAudioOutput] = CPort::NewL(KMaxAudioBuffers);
       
   913 	iPort[COmxIL3GPDemuxer::EPortIndexVideoOutput] = CPort::NewL(KMaxVideoBuffers);
       
   914 
       
   915 	User::LeaveIfError(iBufferQueue.CreateLocal(KMaxTimeBuffers + KMaxAudioBuffers + KMaxVideoBuffers));
       
   916 	iBufferQueueCreated = ETrue;
       
   917 	iState = EStateWaitingToStart;
       
   918 	StartWaitingForBuffer();
       
   919 
       
   920 	DEBUG_PRINTF(_L8("C3GPDemuxer::CreateBufferQueueL--"));
       
   921 	}
       
   922 
       
   923 void C3GPDemuxer::DeleteBufferQueue()
       
   924 	{
       
   925 	if (iBufferQueueCreated)
       
   926 		{
       
   927 		Cancel();
       
   928 		iBufferQueueCreated = EFalse;
       
   929 		iBufferQueue.Close();
       
   930 		}
       
   931 
       
   932 	for (TInt port = 0; port < COmxIL3GPDemuxer::EPortIndexMax; ++port)
       
   933 		{
       
   934 		delete iPort[port];
       
   935 		iPort[port] = NULL;
       
   936 		}
       
   937 	}
       
   938 
       
   939 void C3GPDemuxer::HandleIfError(TInt aError)
       
   940 	{
       
   941 	OMX_ERRORTYPE omxError = SymbianOSErrorToOmx(aError);
       
   942 
       
   943 	if (omxError != OMX_ErrorNone)
       
   944 		{
       
   945 		iInvalid = ETrue;
       
   946 		iCallbacks.ErrorEventNotification(omxError);
       
   947 		}
       
   948 	}
       
   949 
       
   950 // Helper function to convert Symbian OS standard error code to c style error code 
       
   951 OMX_ERRORTYPE C3GPDemuxer::SymbianOSErrorToOmx(TInt aError) const
       
   952 	{
       
   953 	OMX_ERRORTYPE error = OMX_ErrorUndefined;
       
   954 
       
   955 	switch (aError)
       
   956 		{
       
   957 		case (KErrNone):
       
   958 			{
       
   959 			error = OMX_ErrorNone;
       
   960 			}
       
   961 			break;
       
   962 		case (KErrNoMemory):
       
   963 			{
       
   964 			error = OMX_ErrorInsufficientResources;
       
   965 			}
       
   966 			break;
       
   967 		case (KErrOverflow):
       
   968 			{
       
   969 			error = OMX_ErrorOverflow;
       
   970 			}
       
   971 			break;
       
   972 		case (KErrAccessDenied):
       
   973 			{
       
   974 			error = OMX_ErrorContentPipeOpenFailed;
       
   975 			}
       
   976 			break;
       
   977 		case (KErrCorrupt):
       
   978 			{
       
   979 			error = OMX_ErrorStreamCorrupt;
       
   980 			}
       
   981 			break;
       
   982 		case (KErrArgument):
       
   983 			{
       
   984 			error = OMX_ErrorUnsupportedSetting;
       
   985 			}
       
   986 			break;
       
   987 		default:
       
   988 			{
       
   989 			error = OMX_ErrorUndefined;
       
   990 			}
       
   991 		}
       
   992 	return error;
       
   993 	}
       
   994 
       
   995 void C3GPDemuxer::ReceiveQueuedBuffers()
       
   996 	{
       
   997 	if (iBufferQueueCreated)
       
   998 		{
       
   999 		TBufferMessage message;
       
  1000 		while(iBufferQueue.Receive(message) != KErrUnderflow)
       
  1001 			{
       
  1002 			// Port buffers are pre-reserved so append should always work
       
  1003 			if (iPort[message.iPortIndex]->iBuffers.Append(message.iBufferHeader) != KErrNone)
       
  1004 				{
       
  1005 				Panic(EReceiveQueuedBuffersAppendFailed);
       
  1006 				}
       
  1007 			}
       
  1008 		}
       
  1009 	}
       
  1010 
       
  1011 void C3GPDemuxer::StartWaitingForBuffer()
       
  1012 	{
       
  1013 	if (iBufferQueueCreated)
       
  1014 		{
       
  1015 		iWaitingOnBufferQueue = ETrue;
       
  1016 		iBufferQueue.NotifyDataAvailable(iStatus);
       
  1017 		SetActive();
       
  1018 		}
       
  1019 	}
       
  1020 
       
  1021 void C3GPDemuxer::CompleteSelf()
       
  1022 	{
       
  1023 	iStatus = KRequestPending;
       
  1024 	SetActive();
       
  1025 	TRequestStatus* status = &iStatus;
       
  1026 	User::RequestComplete(status, KErrNone);
       
  1027 	}
       
  1028 
       
  1029 TInt C3GPDemuxer::NextPort()
       
  1030 	{
       
  1031 	++iCurrentPort;
       
  1032 	iCurrentPort %= COmxIL3GPDemuxer::EPortIndexMax;
       
  1033 	return iCurrentPort;
       
  1034 	}
       
  1035 
       
  1036 /** Packs four bytes into a 32bit number */
       
  1037 TUint32 C3GPDemuxer::Pack32(const TUint8* aPtr)
       
  1038 	{
       
  1039 	TUint32 x = *aPtr++ << 24;
       
  1040 	x |= *aPtr++ << 16;
       
  1041 	x |= *aPtr++ << 8;
       
  1042 	x |= *aPtr++;
       
  1043 	return x;
       
  1044 	}
       
  1045 
       
  1046 TInt C3GPDemuxer::SetPosition(TUint aTimePosition, TBool aKeyFrame)
       
  1047 	{
       
  1048 	TUint audioPosition = 0;
       
  1049 	TUint videoPosition = 0;
       
  1050 
       
  1051 	TInt err = i3GPParser->Seek(aTimePosition, aKeyFrame, audioPosition, videoPosition);
       
  1052 	if(err)
       
  1053 	    {
       
  1054 	    return err;
       
  1055 	    }
       
  1056 	
       
  1057 	// clear EOS state so buffer handling resumes if previously hit EOS
       
  1058 	// TODO is this thread safe?
       
  1059 	iPort[0]->iEOS = EFalse;
       
  1060 	iPort[1]->iEOS = EFalse;
       
  1061 	
       
  1062 	return KErrNone;
       
  1063 	}