Update contrib.
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
20 #include <openmax/il/khronos/v1_x/OMX_Core.h>
21 #include <openmax/il/khronos/v1_x/OMX_Audio.h>
24 #include "OmxPCMCodec.h"
26 const TInt KPCMBufferSize = 4096;
28 const TInt KThreadStackSize = 16384;
30 const TInt KShutDownTime = 5000000;
33 TInt ProcessingThread(TAny* aComponent)
36 CCodecProcessor* codecprocessor = static_cast<CCodecProcessor*>(aComponent);
39 TRAPD(err, codecprocessor->RunThreadL());
40 // thread has exited or failed to start so return error to the client.
45 TInt COmxPCMCodec::CreateComponent(OMX_HANDLETYPE hComponent)
47 COmxPCMCodec* self = new COmxPCMCodec(hComponent);
52 TRAPD(err, self->ConstructL());
53 // self is stored in the handle, so we won't return it
57 OMX_ERRORTYPE COmxPCMCodec::GetComponentVersion(
58 OMX_STRING /*pComponentName*/,
59 OMX_VERSIONTYPE* /*pComponentVersion*/,
60 OMX_VERSIONTYPE* /*pSpecVersion*/,
61 OMX_UUIDTYPE* /*pComponentUUID*/)
68 void COmxPCMCodec::ConstructL()
70 iCodecProcessor = CCodecProcessor::NewL(*this);
71 iState = OMX_StateLoaded;
74 COmxPCMCodec::COmxPCMCodec(OMX_HANDLETYPE hComponent)
75 :COmxComponentImpl(hComponent)
79 COmxPCMCodec::~COmxPCMCodec()
81 if (iState == OMX_StateExecuting)
83 iCodecProcessor->Stop();
84 iState = OMX_StateIdle;
87 if (iCreatedThread &&(iProcessingThread.Handle() != KNullHandle) && (iProcessingThread.ExitType() == EExitPending))
89 TRequestStatus logonStatus;
90 TBool logonFailed = EFalse;
91 iProcessingThread.Logon(logonStatus);
92 if(logonStatus != KRequestPending)
93 {//logon failed. Mostly due to no memory
96 iCodecProcessor->Exit();
98 TInt err = timer.CreateLocal();
99 if(err==KErrNone && !logonFailed) //both timer and logon successful
101 TRequestStatus timeout;
102 timer.After(timeout, KShutDownTime);
103 User::WaitForRequest(logonStatus, timeout);
104 if(logonStatus==KRequestPending)
105 {//Thread has not exited after the timeout. Kill it!
106 iProcessingThread.LogonCancel(logonStatus);
107 User::WaitForRequest(logonStatus);
108 iProcessingThread.Kill(KErrDied);
111 {//Thread exited. Cancel the timer
113 User::WaitForRequest(timeout);
117 {//either timer or Logon method has failed.Poll the thread status a maximum
118 // of 10 times and kill the thread if it hasn't exited after the polling
119 for (TInt i=0; i<10 && iProcessingThread.ExitType() == EExitPending; ++i)
121 User::After(KShutDownTime/10); // wait for a while
124 if (iProcessingThread.ExitType() == EExitPending)
126 // The polling hasn't been succesful so we kill the thread
127 iProcessingThread.Kill(KErrDied);
131 User::WaitForRequest(logonStatus);
134 iProcessingThread.Close();
136 delete iCodecProcessor;
139 OMX_ERRORTYPE COmxPCMCodec::SendCommand(
144 OMX_ERRORTYPE error = OMX_ErrorNone;
147 case OMX_CommandStateSet:
148 OMX_STATETYPE state = (OMX_STATETYPE)nParam1;
151 error = OMX_ErrorSameState;
155 // notify client of the state change
160 if (iState == OMX_StateExecuting)
162 iCodecProcessor->Stop();
166 case OMX_StateExecuting:
173 EventHandlerCallback(
174 OMX_EventCmdComplete,
184 OMX_ERRORTYPE COmxPCMCodec::GetParameter(
185 OMX_INDEXTYPE nParamIndex,
186 TAny* ComponentParameterStructure)
190 case OMX_IndexParamAudioInit :
192 OMX_PORT_PARAM_TYPE* param = static_cast<OMX_PORT_PARAM_TYPE*>(ComponentParameterStructure);
196 case OMX_IndexParamPortDefinition:
198 OMX_PARAM_PORTDEFINITIONTYPE* portDef = static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(ComponentParameterStructure);
199 if (portDef->nPortIndex==0)
201 portDef->eDir = OMX_DirInput;
202 portDef->nBufferSize = KPCMBufferSize;
206 portDef->eDir = OMX_DirOutput;
207 portDef->nBufferSize = KPCMBufferSize;
212 return OMX_ErrorUnsupportedIndex;
214 return OMX_ErrorNone;
217 OMX_ERRORTYPE COmxPCMCodec::SetParameter(
218 OMX_INDEXTYPE nIndex,
219 TAny* ComponentParameterStructure)
221 ASSERT(iState == OMX_StateLoaded);
224 case OMX_IndexParamAudioPcm:
226 OMX_AUDIO_PARAM_PCMMODETYPE* param = static_cast<OMX_AUDIO_PARAM_PCMMODETYPE*>(ComponentParameterStructure);
227 switch(param->nPortIndex)
229 case 0: // Input port
231 iCodecProcessor->SetInputBitsPerSample(param->nBitPerSample);
232 iCodecProcessor->SetInputDataType(param->eNumData);
234 return OMX_ErrorNone;
236 case 1: // Output port
238 iCodecProcessor->SetOutputBitsPerSample(param->nBitPerSample);
239 iCodecProcessor->SetOutputDataType(param->eNumData);
241 return OMX_ErrorNone;
245 return OMX_ErrorUnsupportedIndex;
251 return OMX_ErrorUnsupportedIndex;
254 //return OMX_ErrorNone;
257 OMX_ERRORTYPE COmxPCMCodec::GetConfig(
258 OMX_INDEXTYPE /*nIndex*/,
261 return OMX_ErrorUnsupportedIndex;
264 OMX_ERRORTYPE COmxPCMCodec::SetConfig(
265 OMX_INDEXTYPE /*nIndex*/,
268 return OMX_ErrorUnsupportedIndex;
271 OMX_ERRORTYPE COmxPCMCodec::GetExtensionIndex(
272 OMX_STRING /*ParameterName*/,
273 OMX_INDEXTYPE* /*pIndexType*/)
275 return OMX_ErrorNotImplemented;
278 OMX_ERRORTYPE COmxPCMCodec::GetState(
279 OMX_STATETYPE* pState)
282 return OMX_ErrorNone;
285 OMX_ERRORTYPE COmxPCMCodec::ComponentTunnelRequest(
286 OMX_HANDLETYPE /*hInput*/,
287 TUint32 /*nInputPort*/,
288 OMX_HANDLETYPE /*hOutput*/,
289 TUint32 /*nOutputPort*/,
290 OMX_TUNNELSETUPTYPE* /*pTunnelSetup*/)
292 return OMX_ErrorNotImplemented;
295 OMX_ERRORTYPE COmxPCMCodec::UseBuffer(
296 OMX_BUFFERHEADERTYPE** ppBufferHeader,
297 TUint32 /*nPortIndex*/,
302 ASSERT(iState == OMX_StateLoaded);
303 *ppBufferHeader = new OMX_BUFFERHEADERTYPE;
304 if (*ppBufferHeader != NULL)
306 (*ppBufferHeader)->pBuffer = pBuffer;
307 (*ppBufferHeader)->pAppPrivate = pAppPrivate;
308 (*ppBufferHeader)->nAllocLen = nSizeBytes;
309 (*ppBufferHeader)->nFilledLen = 0;
310 (*ppBufferHeader)->nFlags = 0;
311 (*ppBufferHeader)->pInputPortPrivate = NULL;
312 (*ppBufferHeader)->pOutputPortPrivate = NULL;
317 return OMX_ErrorNone;
321 return OMX_ErrorInsufficientResources;
325 OMX_ERRORTYPE COmxPCMCodec::AllocateBuffer(
326 OMX_BUFFERHEADERTYPE** pBuffer,
331 ASSERT(iState == OMX_StateLoaded);
333 *pBuffer = new OMX_BUFFERHEADERTYPE;
334 if (*pBuffer != NULL)
336 (*pBuffer)->pBuffer = new unsigned char[nSizeBytes];
337 // store our allocated memory in component's private store
341 (*pBuffer)->pInputPortPrivate = (*pBuffer)->pBuffer;
342 (*pBuffer)->pOutputPortPrivate = NULL;
345 (*pBuffer)->pOutputPortPrivate = (*pBuffer)->pBuffer;
346 (*pBuffer)->pInputPortPrivate = NULL;
351 (*pBuffer)->nAllocLen = nSizeBytes;
352 (*pBuffer)->nFilledLen = 0;
353 (*pBuffer)->pAppPrivate = pAppData;
356 if (*pBuffer && (*pBuffer)->pBuffer)
358 return OMX_ErrorNone;
362 return OMX_ErrorInsufficientResources;
366 OMX_ERRORTYPE COmxPCMCodec::FreeBuffer(
367 TUint32 /*nPortIndex*/,
368 OMX_BUFFERHEADERTYPE* pBuffer)
370 if (pBuffer->pInputPortPrivate ||
371 pBuffer->pOutputPortPrivate)
372 delete[] pBuffer->pBuffer;
374 return OMX_ErrorNone;
376 OMX_ERRORTYPE COmxPCMCodec::EmptyThisBuffer(
377 OMX_BUFFERHEADERTYPE* pBuffer)
379 ASSERT(iState == OMX_StateExecuting ||
380 iState == OMX_StateIdle ||
381 iState == OMX_StatePause);
382 return iCodecProcessor->EmptyThisBuffer(pBuffer);
384 OMX_ERRORTYPE COmxPCMCodec::FillThisBuffer(
385 OMX_BUFFERHEADERTYPE* pBuffer)
387 ASSERT(iState == OMX_StateExecuting ||
388 iState == OMX_StateIdle ||
389 iState == OMX_StatePause);
390 return iCodecProcessor->FillThisBuffer(pBuffer);
393 OMX_ERRORTYPE COmxPCMCodec::SetCallbacks(
394 OMX_CALLBACKTYPE* pCallbacks,
397 iCallback = pCallbacks;
399 return OMX_ErrorNone;
403 CCodecProcessor::CCodecProcessor(COmxPCMCodec& aParent)
408 void CCodecProcessor::RunThreadL()
410 iQueueStatus = KRequestPending;
411 iMessageQueue.NotifyDataAvailable(iQueueStatus);
415 User::WaitForRequest(iQueueStatus);
420 while (iMessageQueue.Receive(msg)==KErrNone)
424 case EStopProcessing:
431 iBuffersToEmpty.Append(msg.iBuffer);
434 iBuffersToFill.Append(msg.iBuffer);
445 // process all available buffers
446 ProcessAvailableBuffers();
448 // request notification of further queue events
449 iQueueStatus = KRequestPending;
450 iMessageQueue.NotifyDataAvailable(iQueueStatus);
457 CCodecProcessor* CCodecProcessor::NewL(COmxPCMCodec& aParent)
459 CCodecProcessor* self = new (ELeave) CCodecProcessor(aParent);
460 CleanupStack::PushL(self);
462 CleanupStack::Pop(self);
467 void CCodecProcessor::ConstructL()
469 User::LeaveIfError(iMessageQueue.CreateLocal(10));
470 // set the default case
471 iInputBitsPerSample = 8;
472 iInputDataType = OMX_NumericalDataUnsigned;
473 iOutputBitsPerSample = 16;
474 iOutputDataType = OMX_NumericalDataSigned;
477 OMX_ERRORTYPE CCodecProcessor::EmptyThisBuffer(
478 OMX_BUFFERHEADERTYPE* pBuffer)
480 TCodecMessage message;
481 message.iType = EInputBuffer;
482 message.iBuffer = pBuffer;
483 if (iMessageQueue.Send(message) == KErrNone)
485 return OMX_ErrorNone;
489 return OMX_ErrorUndefined;
493 void CCodecProcessor::Stop()
495 TCodecMessage message;
496 message.iType = EStopProcessing;
497 message.iBuffer = NULL;
498 iMessageQueue.Send(message);
501 void CCodecProcessor::Exit()
503 TCodecMessage message;
504 message.iType = EExit;
505 message.iBuffer = NULL;
506 iMessageQueue.SendBlocking(message);
509 OMX_ERRORTYPE CCodecProcessor::FillThisBuffer(
510 OMX_BUFFERHEADERTYPE* pBuffer)
512 TCodecMessage message;
513 message.iType = EOutputBuffer;
514 message.iBuffer = pBuffer;
515 if (iMessageQueue.Send(message)== KErrNone)
517 return OMX_ErrorNone;
521 return OMX_ErrorUndefined;
525 void CCodecProcessor::SetInputBitsPerSample(TInt aInputBitsPerSample)
527 iInputBitsPerSample = aInputBitsPerSample;
530 void CCodecProcessor::SetInputDataType(OMX_NUMERICALDATATYPE aType)
532 iInputDataType = aType;
535 void CCodecProcessor::SetOutputBitsPerSample(TInt aInputBitsPerSample)
537 iOutputBitsPerSample = aInputBitsPerSample;
540 void CCodecProcessor::SetOutputDataType(OMX_NUMERICALDATATYPE aType)
542 iOutputDataType = aType;
545 void CCodecProcessor::ChooseCodec()
547 // choose correct conversion codec
548 if (iInputBitsPerSample == 8 && iOutputBitsPerSample == 16)
550 iOutputSamplesPerInputSample = 2;
551 if (iInputDataType == OMX_NumericalDataSigned &&
552 iOutputDataType == OMX_NumericalDataSigned)
554 iCurrentCodec = &iAudioS8ToS16PcmCodec;
556 else if (iInputDataType == OMX_NumericalDataUnsigned &&
557 iOutputDataType == OMX_NumericalDataSigned)
559 iCurrentCodec = &iAudioU8ToS16PcmCodec;
562 else if (iInputBitsPerSample == 16 && iOutputBitsPerSample == 8)
564 iOutputSamplesPerInputSample = .5;
565 if (iInputDataType == OMX_NumericalDataSigned &&
566 iOutputDataType == OMX_NumericalDataSigned)
568 iCurrentCodec = &iAudioS16ToS8PcmCodec;
570 else if (iInputDataType == OMX_NumericalDataSigned &&
571 iOutputDataType == OMX_NumericalDataUnsigned)
573 iCurrentCodec = &iAudioS16ToU8PcmCodec;
579 void CCodecProcessor::ProcessAvailableBuffers()
581 // Setup wait for data in queue
582 while (iBuffersToFill.Count()>0 && iBuffersToEmpty.Count() > 0)
584 TBool lastBuffer = EFalse;
591 OMX_BUFFERHEADERTYPE* srcBuffer = iBuffersToEmpty[0];
592 OMX_BUFFERHEADERTYPE* destBuffer = iBuffersToFill[0];
593 if (srcBuffer->nFlags & OMX_BUFFERFLAG_EOS)
597 TInt destBufferPos = destBuffer->nFilledLen;
599 TInt destBufferSize = destBuffer->nAllocLen - destBufferPos;
600 TInt inputSamplesRequired = (TInt)((TReal)destBufferSize / iOutputSamplesPerInputSample);
602 TInt availableSamples = srcBuffer->nFilledLen - iInputBufferPos;
604 if (availableSamples <= inputSamplesRequired)
606 TInt samplesToConvert = availableSamples;
607 if (iOutputSamplesPerInputSample == .5)
609 samplesToConvert >>= 1;
611 iCurrentCodec->Convert(&srcBuffer->pBuffer[iInputBufferPos], &destBuffer->pBuffer[destBufferPos], samplesToConvert);
612 iInputBufferPos = 0; // finished buffer - so reset
613 inputSamplesRequired -= availableSamples;
614 destBuffer->nFilledLen = (TInt)((TReal)availableSamples * iOutputSamplesPerInputSample);
615 srcBuffer->nFilledLen = 0;
616 iBuffersToEmpty.Remove(0);
617 iParent->EmptyBufferDoneCallback(srcBuffer);
619 if (inputSamplesRequired == 0 || lastBuffer)
621 iBuffersToFill.Remove(0);
624 destBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
625 // propagate the EOS flag
626 iParent->EventHandlerCallback(
632 iParent->FillBufferDoneCallback(destBuffer);
637 TInt samplesToConvert = inputSamplesRequired;
638 if (iOutputSamplesPerInputSample == .5)
640 samplesToConvert >>= 2;
643 iCurrentCodec->Convert(&srcBuffer->pBuffer[iInputBufferPos], &destBuffer->pBuffer[destBufferPos], samplesToConvert);
644 iInputBufferPos += inputSamplesRequired;
645 destBuffer->nFilledLen = destBuffer->nAllocLen;
646 iBuffersToFill.Remove(0);
647 iParent->FillBufferDoneCallback(destBuffer);
652 CCodecProcessor::~CCodecProcessor()
654 iBuffersToEmpty.Close();
655 iBuffersToFill.Close();
656 iMessageQueue.Close();
660 TInt COmxPCMCodec::StartExecution()
662 // create thread with current thread's heap
663 // we can thus allocate and free memory across threads
666 TInt err = iProcessingThread.Create(_L("PCMCodec"),
676 iCreatedThread = ETrue;
677 iThreadDeath = KRequestPending;
678 iProcessingThread.Resume();
684 // Callbacks for the PCM codec
685 void COmxPCMCodec::EventHandlerCallback(
686 OMX_OUT OMX_EVENTTYPE eEvent,
687 OMX_OUT TUint32 nData1,
688 OMX_OUT TUint32 nData2,
689 OMX_OUT OMX_STRING cExtraInfo)
691 iCallback->EventHandler(
701 void COmxPCMCodec::FillBufferDoneCallback(OMX_BUFFERHEADERTYPE* aBuffer)
703 iCallback->FillBufferDone(
709 void COmxPCMCodec::EmptyBufferDoneCallback(OMX_BUFFERHEADERTYPE* aBuffer)
711 iCallback->EmptyBufferDone(
717 // Component Entry Point
718 OMX_ERRORTYPE OMX_ComponentInit(OMX_HANDLETYPE hComponent)
720 TInt err = COmxPCMCodec::CreateComponent(hComponent);
723 return OMX_ErrorNone;
728 return OMX_ErrorInsufficientResources;