sl@0
|
1 |
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
//
|
sl@0
|
15 |
|
sl@0
|
16 |
#include <e32debug.h>
|
sl@0
|
17 |
#include <stdio.h>
|
sl@0
|
18 |
#include <string.h>
|
sl@0
|
19 |
#include <stdlib.h>
|
sl@0
|
20 |
#include <openmax/il/khronos/v1_x/OMX_Core.h>
|
sl@0
|
21 |
#include <openmax/il/khronos/v1_x/OMX_Audio.h>
|
sl@0
|
22 |
|
sl@0
|
23 |
#include "OmxImpl.h"
|
sl@0
|
24 |
#include "OmxPCMCodec.h"
|
sl@0
|
25 |
|
sl@0
|
26 |
const TInt KPCMBufferSize = 4096;
|
sl@0
|
27 |
|
sl@0
|
28 |
const TInt KThreadStackSize = 16384;
|
sl@0
|
29 |
|
sl@0
|
30 |
const TInt KShutDownTime = 5000000;
|
sl@0
|
31 |
|
sl@0
|
32 |
|
sl@0
|
33 |
TInt ProcessingThread(TAny* aComponent)
|
sl@0
|
34 |
{
|
sl@0
|
35 |
// get our class
|
sl@0
|
36 |
CCodecProcessor* codecprocessor = static_cast<CCodecProcessor*>(aComponent);
|
sl@0
|
37 |
|
sl@0
|
38 |
// run the thread
|
sl@0
|
39 |
TRAPD(err, codecprocessor->RunThreadL());
|
sl@0
|
40 |
// thread has exited or failed to start so return error to the client.
|
sl@0
|
41 |
return err;
|
sl@0
|
42 |
}
|
sl@0
|
43 |
|
sl@0
|
44 |
|
sl@0
|
45 |
TInt COmxPCMCodec::CreateComponent(OMX_HANDLETYPE hComponent)
|
sl@0
|
46 |
{
|
sl@0
|
47 |
COmxPCMCodec* self = new COmxPCMCodec(hComponent);
|
sl@0
|
48 |
if (self==NULL)
|
sl@0
|
49 |
{
|
sl@0
|
50 |
return KErrNoMemory;
|
sl@0
|
51 |
}
|
sl@0
|
52 |
TRAPD(err, self->ConstructL());
|
sl@0
|
53 |
// self is stored in the handle, so we won't return it
|
sl@0
|
54 |
return err;
|
sl@0
|
55 |
}
|
sl@0
|
56 |
|
sl@0
|
57 |
OMX_ERRORTYPE COmxPCMCodec::GetComponentVersion(
|
sl@0
|
58 |
OMX_STRING /*pComponentName*/,
|
sl@0
|
59 |
OMX_VERSIONTYPE* /*pComponentVersion*/,
|
sl@0
|
60 |
OMX_VERSIONTYPE* /*pSpecVersion*/,
|
sl@0
|
61 |
OMX_UUIDTYPE* /*pComponentUUID*/)
|
sl@0
|
62 |
{
|
sl@0
|
63 |
// to be implemented
|
sl@0
|
64 |
return OMX_ErrorNone;
|
sl@0
|
65 |
}
|
sl@0
|
66 |
|
sl@0
|
67 |
|
sl@0
|
68 |
void COmxPCMCodec::ConstructL()
|
sl@0
|
69 |
{
|
sl@0
|
70 |
iCodecProcessor = CCodecProcessor::NewL(*this);
|
sl@0
|
71 |
iState = OMX_StateLoaded;
|
sl@0
|
72 |
}
|
sl@0
|
73 |
|
sl@0
|
74 |
COmxPCMCodec::COmxPCMCodec(OMX_HANDLETYPE hComponent)
|
sl@0
|
75 |
:COmxComponentImpl(hComponent)
|
sl@0
|
76 |
{
|
sl@0
|
77 |
}
|
sl@0
|
78 |
|
sl@0
|
79 |
COmxPCMCodec::~COmxPCMCodec()
|
sl@0
|
80 |
{
|
sl@0
|
81 |
if (iState == OMX_StateExecuting)
|
sl@0
|
82 |
{
|
sl@0
|
83 |
iCodecProcessor->Stop();
|
sl@0
|
84 |
iState = OMX_StateIdle;
|
sl@0
|
85 |
}
|
sl@0
|
86 |
|
sl@0
|
87 |
if (iCreatedThread &&(iProcessingThread.Handle() != KNullHandle) && (iProcessingThread.ExitType() == EExitPending))
|
sl@0
|
88 |
{
|
sl@0
|
89 |
TRequestStatus logonStatus;
|
sl@0
|
90 |
TBool logonFailed = EFalse;
|
sl@0
|
91 |
iProcessingThread.Logon(logonStatus);
|
sl@0
|
92 |
if(logonStatus != KRequestPending)
|
sl@0
|
93 |
{//logon failed. Mostly due to no memory
|
sl@0
|
94 |
logonFailed = ETrue;
|
sl@0
|
95 |
}
|
sl@0
|
96 |
iCodecProcessor->Exit();
|
sl@0
|
97 |
RTimer timer;
|
sl@0
|
98 |
TInt err = timer.CreateLocal();
|
sl@0
|
99 |
if(err==KErrNone && !logonFailed) //both timer and logon successful
|
sl@0
|
100 |
{
|
sl@0
|
101 |
TRequestStatus timeout;
|
sl@0
|
102 |
timer.After(timeout, KShutDownTime);
|
sl@0
|
103 |
User::WaitForRequest(logonStatus, timeout);
|
sl@0
|
104 |
if(logonStatus==KRequestPending)
|
sl@0
|
105 |
{//Thread has not exited after the timeout. Kill it!
|
sl@0
|
106 |
iProcessingThread.LogonCancel(logonStatus);
|
sl@0
|
107 |
User::WaitForRequest(logonStatus);
|
sl@0
|
108 |
iProcessingThread.Kill(KErrDied);
|
sl@0
|
109 |
}
|
sl@0
|
110 |
else
|
sl@0
|
111 |
{//Thread exited. Cancel the timer
|
sl@0
|
112 |
timer.Cancel();
|
sl@0
|
113 |
User::WaitForRequest(timeout);
|
sl@0
|
114 |
}
|
sl@0
|
115 |
}
|
sl@0
|
116 |
else
|
sl@0
|
117 |
{//either timer or Logon method has failed.Poll the thread status a maximum
|
sl@0
|
118 |
// of 10 times and kill the thread if it hasn't exited after the polling
|
sl@0
|
119 |
for (TInt i=0; i<10 && iProcessingThread.ExitType() == EExitPending; ++i)
|
sl@0
|
120 |
{
|
sl@0
|
121 |
User::After(KShutDownTime/10); // wait for a while
|
sl@0
|
122 |
}
|
sl@0
|
123 |
|
sl@0
|
124 |
if (iProcessingThread.ExitType() == EExitPending)
|
sl@0
|
125 |
{
|
sl@0
|
126 |
// The polling hasn't been succesful so we kill the thread
|
sl@0
|
127 |
iProcessingThread.Kill(KErrDied);
|
sl@0
|
128 |
}
|
sl@0
|
129 |
if(!logonFailed)
|
sl@0
|
130 |
{
|
sl@0
|
131 |
User::WaitForRequest(logonStatus);
|
sl@0
|
132 |
}
|
sl@0
|
133 |
}
|
sl@0
|
134 |
iProcessingThread.Close();
|
sl@0
|
135 |
}
|
sl@0
|
136 |
delete iCodecProcessor;
|
sl@0
|
137 |
}
|
sl@0
|
138 |
|
sl@0
|
139 |
OMX_ERRORTYPE COmxPCMCodec::SendCommand(
|
sl@0
|
140 |
OMX_COMMANDTYPE Cmd,
|
sl@0
|
141 |
TUint32 nParam1,
|
sl@0
|
142 |
TAny* /*pCmdData*/)
|
sl@0
|
143 |
{
|
sl@0
|
144 |
OMX_ERRORTYPE error = OMX_ErrorNone;
|
sl@0
|
145 |
switch (Cmd)
|
sl@0
|
146 |
{
|
sl@0
|
147 |
case OMX_CommandStateSet:
|
sl@0
|
148 |
OMX_STATETYPE state = (OMX_STATETYPE)nParam1;
|
sl@0
|
149 |
if (state == iState)
|
sl@0
|
150 |
{
|
sl@0
|
151 |
error = OMX_ErrorSameState;
|
sl@0
|
152 |
}
|
sl@0
|
153 |
else
|
sl@0
|
154 |
{
|
sl@0
|
155 |
// notify client of the state change
|
sl@0
|
156 |
switch (state)
|
sl@0
|
157 |
{
|
sl@0
|
158 |
case OMX_StateIdle:
|
sl@0
|
159 |
{
|
sl@0
|
160 |
if (iState == OMX_StateExecuting)
|
sl@0
|
161 |
{
|
sl@0
|
162 |
iCodecProcessor->Stop();
|
sl@0
|
163 |
}
|
sl@0
|
164 |
break;
|
sl@0
|
165 |
}
|
sl@0
|
166 |
case OMX_StateExecuting:
|
sl@0
|
167 |
StartExecution();
|
sl@0
|
168 |
break;
|
sl@0
|
169 |
};
|
sl@0
|
170 |
|
sl@0
|
171 |
iState = state;
|
sl@0
|
172 |
|
sl@0
|
173 |
EventHandlerCallback(
|
sl@0
|
174 |
OMX_EventCmdComplete,
|
sl@0
|
175 |
OMX_CommandStateSet,
|
sl@0
|
176 |
iState,
|
sl@0
|
177 |
NULL);
|
sl@0
|
178 |
break;
|
sl@0
|
179 |
}
|
sl@0
|
180 |
};
|
sl@0
|
181 |
return error;
|
sl@0
|
182 |
}
|
sl@0
|
183 |
|
sl@0
|
184 |
OMX_ERRORTYPE COmxPCMCodec::GetParameter(
|
sl@0
|
185 |
OMX_INDEXTYPE nParamIndex,
|
sl@0
|
186 |
TAny* ComponentParameterStructure)
|
sl@0
|
187 |
{
|
sl@0
|
188 |
switch (nParamIndex)
|
sl@0
|
189 |
{
|
sl@0
|
190 |
case OMX_IndexParamAudioInit :
|
sl@0
|
191 |
{
|
sl@0
|
192 |
OMX_PORT_PARAM_TYPE* param = static_cast<OMX_PORT_PARAM_TYPE*>(ComponentParameterStructure);
|
sl@0
|
193 |
param->nPorts = 2;
|
sl@0
|
194 |
}
|
sl@0
|
195 |
break;
|
sl@0
|
196 |
case OMX_IndexParamPortDefinition:
|
sl@0
|
197 |
{
|
sl@0
|
198 |
OMX_PARAM_PORTDEFINITIONTYPE* portDef = static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(ComponentParameterStructure);
|
sl@0
|
199 |
if (portDef->nPortIndex==0)
|
sl@0
|
200 |
{
|
sl@0
|
201 |
portDef->eDir = OMX_DirInput;
|
sl@0
|
202 |
portDef->nBufferSize = KPCMBufferSize;
|
sl@0
|
203 |
}
|
sl@0
|
204 |
else
|
sl@0
|
205 |
{
|
sl@0
|
206 |
portDef->eDir = OMX_DirOutput;
|
sl@0
|
207 |
portDef->nBufferSize = KPCMBufferSize;
|
sl@0
|
208 |
}
|
sl@0
|
209 |
}
|
sl@0
|
210 |
break;
|
sl@0
|
211 |
default:
|
sl@0
|
212 |
return OMX_ErrorUnsupportedIndex;
|
sl@0
|
213 |
}
|
sl@0
|
214 |
return OMX_ErrorNone;
|
sl@0
|
215 |
}
|
sl@0
|
216 |
|
sl@0
|
217 |
OMX_ERRORTYPE COmxPCMCodec::SetParameter(
|
sl@0
|
218 |
OMX_INDEXTYPE nIndex,
|
sl@0
|
219 |
TAny* ComponentParameterStructure)
|
sl@0
|
220 |
{
|
sl@0
|
221 |
ASSERT(iState == OMX_StateLoaded);
|
sl@0
|
222 |
switch (nIndex)
|
sl@0
|
223 |
{
|
sl@0
|
224 |
case OMX_IndexParamAudioPcm:
|
sl@0
|
225 |
{
|
sl@0
|
226 |
OMX_AUDIO_PARAM_PCMMODETYPE* param = static_cast<OMX_AUDIO_PARAM_PCMMODETYPE*>(ComponentParameterStructure);
|
sl@0
|
227 |
switch(param->nPortIndex)
|
sl@0
|
228 |
{
|
sl@0
|
229 |
case 0: // Input port
|
sl@0
|
230 |
{
|
sl@0
|
231 |
iCodecProcessor->SetInputBitsPerSample(param->nBitPerSample);
|
sl@0
|
232 |
iCodecProcessor->SetInputDataType(param->eNumData);
|
sl@0
|
233 |
//break;
|
sl@0
|
234 |
return OMX_ErrorNone;
|
sl@0
|
235 |
}
|
sl@0
|
236 |
case 1: // Output port
|
sl@0
|
237 |
{
|
sl@0
|
238 |
iCodecProcessor->SetOutputBitsPerSample(param->nBitPerSample);
|
sl@0
|
239 |
iCodecProcessor->SetOutputDataType(param->eNumData);
|
sl@0
|
240 |
//break;
|
sl@0
|
241 |
return OMX_ErrorNone;
|
sl@0
|
242 |
}
|
sl@0
|
243 |
default:
|
sl@0
|
244 |
{
|
sl@0
|
245 |
return OMX_ErrorUnsupportedIndex;
|
sl@0
|
246 |
}
|
sl@0
|
247 |
};
|
sl@0
|
248 |
}
|
sl@0
|
249 |
default:
|
sl@0
|
250 |
{
|
sl@0
|
251 |
return OMX_ErrorUnsupportedIndex;
|
sl@0
|
252 |
}
|
sl@0
|
253 |
};
|
sl@0
|
254 |
//return OMX_ErrorNone;
|
sl@0
|
255 |
}
|
sl@0
|
256 |
|
sl@0
|
257 |
OMX_ERRORTYPE COmxPCMCodec::GetConfig(
|
sl@0
|
258 |
OMX_INDEXTYPE /*nIndex*/,
|
sl@0
|
259 |
TAny* /*value*/)
|
sl@0
|
260 |
{
|
sl@0
|
261 |
return OMX_ErrorUnsupportedIndex;
|
sl@0
|
262 |
}
|
sl@0
|
263 |
|
sl@0
|
264 |
OMX_ERRORTYPE COmxPCMCodec::SetConfig(
|
sl@0
|
265 |
OMX_INDEXTYPE /*nIndex*/,
|
sl@0
|
266 |
TAny* /*value*/)
|
sl@0
|
267 |
{
|
sl@0
|
268 |
return OMX_ErrorUnsupportedIndex;
|
sl@0
|
269 |
}
|
sl@0
|
270 |
|
sl@0
|
271 |
OMX_ERRORTYPE COmxPCMCodec::GetExtensionIndex(
|
sl@0
|
272 |
OMX_STRING /*ParameterName*/,
|
sl@0
|
273 |
OMX_INDEXTYPE* /*pIndexType*/)
|
sl@0
|
274 |
{
|
sl@0
|
275 |
return OMX_ErrorNotImplemented;
|
sl@0
|
276 |
}
|
sl@0
|
277 |
|
sl@0
|
278 |
OMX_ERRORTYPE COmxPCMCodec::GetState(
|
sl@0
|
279 |
OMX_STATETYPE* pState)
|
sl@0
|
280 |
{
|
sl@0
|
281 |
*pState = iState;
|
sl@0
|
282 |
return OMX_ErrorNone;
|
sl@0
|
283 |
}
|
sl@0
|
284 |
|
sl@0
|
285 |
OMX_ERRORTYPE COmxPCMCodec::ComponentTunnelRequest(
|
sl@0
|
286 |
OMX_HANDLETYPE /*hInput*/,
|
sl@0
|
287 |
TUint32 /*nInputPort*/,
|
sl@0
|
288 |
OMX_HANDLETYPE /*hOutput*/,
|
sl@0
|
289 |
TUint32 /*nOutputPort*/,
|
sl@0
|
290 |
OMX_TUNNELSETUPTYPE* /*pTunnelSetup*/)
|
sl@0
|
291 |
{
|
sl@0
|
292 |
return OMX_ErrorNotImplemented;
|
sl@0
|
293 |
}
|
sl@0
|
294 |
|
sl@0
|
295 |
OMX_ERRORTYPE COmxPCMCodec::UseBuffer(
|
sl@0
|
296 |
OMX_BUFFERHEADERTYPE** ppBufferHeader,
|
sl@0
|
297 |
TUint32 /*nPortIndex*/,
|
sl@0
|
298 |
TAny* pAppPrivate,
|
sl@0
|
299 |
TUint32 nSizeBytes,
|
sl@0
|
300 |
TUint8* pBuffer)
|
sl@0
|
301 |
{
|
sl@0
|
302 |
ASSERT(iState == OMX_StateLoaded);
|
sl@0
|
303 |
*ppBufferHeader = new OMX_BUFFERHEADERTYPE;
|
sl@0
|
304 |
if (*ppBufferHeader != NULL)
|
sl@0
|
305 |
{
|
sl@0
|
306 |
(*ppBufferHeader)->pBuffer = pBuffer;
|
sl@0
|
307 |
(*ppBufferHeader)->pAppPrivate = pAppPrivate;
|
sl@0
|
308 |
(*ppBufferHeader)->nAllocLen = nSizeBytes;
|
sl@0
|
309 |
(*ppBufferHeader)->nFilledLen = 0;
|
sl@0
|
310 |
(*ppBufferHeader)->nFlags = 0;
|
sl@0
|
311 |
(*ppBufferHeader)->pInputPortPrivate = NULL;
|
sl@0
|
312 |
(*ppBufferHeader)->pOutputPortPrivate = NULL;
|
sl@0
|
313 |
}
|
sl@0
|
314 |
|
sl@0
|
315 |
if (*ppBufferHeader)
|
sl@0
|
316 |
{
|
sl@0
|
317 |
return OMX_ErrorNone;
|
sl@0
|
318 |
}
|
sl@0
|
319 |
else
|
sl@0
|
320 |
{
|
sl@0
|
321 |
return OMX_ErrorInsufficientResources;
|
sl@0
|
322 |
}
|
sl@0
|
323 |
}
|
sl@0
|
324 |
|
sl@0
|
325 |
OMX_ERRORTYPE COmxPCMCodec::AllocateBuffer(
|
sl@0
|
326 |
OMX_BUFFERHEADERTYPE** pBuffer,
|
sl@0
|
327 |
TUint32 nPortIndex,
|
sl@0
|
328 |
TAny* pAppData,
|
sl@0
|
329 |
TUint32 nSizeBytes)
|
sl@0
|
330 |
{
|
sl@0
|
331 |
ASSERT(iState == OMX_StateLoaded);
|
sl@0
|
332 |
|
sl@0
|
333 |
*pBuffer = new OMX_BUFFERHEADERTYPE;
|
sl@0
|
334 |
if (*pBuffer != NULL)
|
sl@0
|
335 |
{
|
sl@0
|
336 |
(*pBuffer)->pBuffer = new unsigned char[nSizeBytes];
|
sl@0
|
337 |
// store our allocated memory in component's private store
|
sl@0
|
338 |
switch (nPortIndex)
|
sl@0
|
339 |
{
|
sl@0
|
340 |
case 0:
|
sl@0
|
341 |
(*pBuffer)->pInputPortPrivate = (*pBuffer)->pBuffer;
|
sl@0
|
342 |
(*pBuffer)->pOutputPortPrivate = NULL;
|
sl@0
|
343 |
break;
|
sl@0
|
344 |
case 1:
|
sl@0
|
345 |
(*pBuffer)->pOutputPortPrivate = (*pBuffer)->pBuffer;
|
sl@0
|
346 |
(*pBuffer)->pInputPortPrivate = NULL;
|
sl@0
|
347 |
break;
|
sl@0
|
348 |
};
|
sl@0
|
349 |
|
sl@0
|
350 |
|
sl@0
|
351 |
(*pBuffer)->nAllocLen = nSizeBytes;
|
sl@0
|
352 |
(*pBuffer)->nFilledLen = 0;
|
sl@0
|
353 |
(*pBuffer)->pAppPrivate = pAppData;
|
sl@0
|
354 |
}
|
sl@0
|
355 |
|
sl@0
|
356 |
if (*pBuffer && (*pBuffer)->pBuffer)
|
sl@0
|
357 |
{
|
sl@0
|
358 |
return OMX_ErrorNone;
|
sl@0
|
359 |
}
|
sl@0
|
360 |
else
|
sl@0
|
361 |
{
|
sl@0
|
362 |
return OMX_ErrorInsufficientResources;
|
sl@0
|
363 |
}
|
sl@0
|
364 |
}
|
sl@0
|
365 |
|
sl@0
|
366 |
OMX_ERRORTYPE COmxPCMCodec::FreeBuffer(
|
sl@0
|
367 |
TUint32 /*nPortIndex*/,
|
sl@0
|
368 |
OMX_BUFFERHEADERTYPE* pBuffer)
|
sl@0
|
369 |
{
|
sl@0
|
370 |
if (pBuffer->pInputPortPrivate ||
|
sl@0
|
371 |
pBuffer->pOutputPortPrivate)
|
sl@0
|
372 |
delete[] pBuffer->pBuffer;
|
sl@0
|
373 |
delete pBuffer;
|
sl@0
|
374 |
return OMX_ErrorNone;
|
sl@0
|
375 |
}
|
sl@0
|
376 |
OMX_ERRORTYPE COmxPCMCodec::EmptyThisBuffer(
|
sl@0
|
377 |
OMX_BUFFERHEADERTYPE* pBuffer)
|
sl@0
|
378 |
{
|
sl@0
|
379 |
ASSERT(iState == OMX_StateExecuting ||
|
sl@0
|
380 |
iState == OMX_StateIdle ||
|
sl@0
|
381 |
iState == OMX_StatePause);
|
sl@0
|
382 |
return iCodecProcessor->EmptyThisBuffer(pBuffer);
|
sl@0
|
383 |
}
|
sl@0
|
384 |
OMX_ERRORTYPE COmxPCMCodec::FillThisBuffer(
|
sl@0
|
385 |
OMX_BUFFERHEADERTYPE* pBuffer)
|
sl@0
|
386 |
{
|
sl@0
|
387 |
ASSERT(iState == OMX_StateExecuting ||
|
sl@0
|
388 |
iState == OMX_StateIdle ||
|
sl@0
|
389 |
iState == OMX_StatePause);
|
sl@0
|
390 |
return iCodecProcessor->FillThisBuffer(pBuffer);
|
sl@0
|
391 |
}
|
sl@0
|
392 |
|
sl@0
|
393 |
OMX_ERRORTYPE COmxPCMCodec::SetCallbacks(
|
sl@0
|
394 |
OMX_CALLBACKTYPE* pCallbacks,
|
sl@0
|
395 |
TAny* pAppData)
|
sl@0
|
396 |
{
|
sl@0
|
397 |
iCallback = pCallbacks;
|
sl@0
|
398 |
iAppData = pAppData;
|
sl@0
|
399 |
return OMX_ErrorNone;
|
sl@0
|
400 |
}
|
sl@0
|
401 |
|
sl@0
|
402 |
|
sl@0
|
403 |
CCodecProcessor::CCodecProcessor(COmxPCMCodec& aParent)
|
sl@0
|
404 |
: iParent(&aParent)
|
sl@0
|
405 |
{
|
sl@0
|
406 |
}
|
sl@0
|
407 |
|
sl@0
|
408 |
void CCodecProcessor::RunThreadL()
|
sl@0
|
409 |
{
|
sl@0
|
410 |
iQueueStatus = KRequestPending;
|
sl@0
|
411 |
iMessageQueue.NotifyDataAvailable(iQueueStatus);
|
sl@0
|
412 |
|
sl@0
|
413 |
for (;;)
|
sl@0
|
414 |
{
|
sl@0
|
415 |
User::WaitForRequest(iQueueStatus);
|
sl@0
|
416 |
TCodecMessage msg;
|
sl@0
|
417 |
|
sl@0
|
418 |
TBool exit = EFalse;
|
sl@0
|
419 |
|
sl@0
|
420 |
while (iMessageQueue.Receive(msg)==KErrNone)
|
sl@0
|
421 |
{
|
sl@0
|
422 |
switch (msg.iType)
|
sl@0
|
423 |
{
|
sl@0
|
424 |
case EStopProcessing:
|
sl@0
|
425 |
iStarted = EFalse;
|
sl@0
|
426 |
break;
|
sl@0
|
427 |
case EExit:
|
sl@0
|
428 |
exit = ETrue;
|
sl@0
|
429 |
break;
|
sl@0
|
430 |
case EInputBuffer:
|
sl@0
|
431 |
iBuffersToEmpty.Append(msg.iBuffer);
|
sl@0
|
432 |
break;
|
sl@0
|
433 |
case EOutputBuffer:
|
sl@0
|
434 |
iBuffersToFill.Append(msg.iBuffer);
|
sl@0
|
435 |
break;
|
sl@0
|
436 |
}
|
sl@0
|
437 |
}
|
sl@0
|
438 |
|
sl@0
|
439 |
if (exit)
|
sl@0
|
440 |
{
|
sl@0
|
441 |
break;
|
sl@0
|
442 |
}
|
sl@0
|
443 |
else
|
sl@0
|
444 |
{
|
sl@0
|
445 |
// process all available buffers
|
sl@0
|
446 |
ProcessAvailableBuffers();
|
sl@0
|
447 |
|
sl@0
|
448 |
// request notification of further queue events
|
sl@0
|
449 |
iQueueStatus = KRequestPending;
|
sl@0
|
450 |
iMessageQueue.NotifyDataAvailable(iQueueStatus);
|
sl@0
|
451 |
}
|
sl@0
|
452 |
}
|
sl@0
|
453 |
|
sl@0
|
454 |
}
|
sl@0
|
455 |
|
sl@0
|
456 |
|
sl@0
|
457 |
CCodecProcessor* CCodecProcessor::NewL(COmxPCMCodec& aParent)
|
sl@0
|
458 |
{
|
sl@0
|
459 |
CCodecProcessor* self = new (ELeave) CCodecProcessor(aParent);
|
sl@0
|
460 |
CleanupStack::PushL(self);
|
sl@0
|
461 |
self->ConstructL();
|
sl@0
|
462 |
CleanupStack::Pop(self);
|
sl@0
|
463 |
return self;
|
sl@0
|
464 |
}
|
sl@0
|
465 |
|
sl@0
|
466 |
|
sl@0
|
467 |
void CCodecProcessor::ConstructL()
|
sl@0
|
468 |
{
|
sl@0
|
469 |
User::LeaveIfError(iMessageQueue.CreateLocal(10));
|
sl@0
|
470 |
// set the default case
|
sl@0
|
471 |
iInputBitsPerSample = 8;
|
sl@0
|
472 |
iInputDataType = OMX_NumericalDataUnsigned;
|
sl@0
|
473 |
iOutputBitsPerSample = 16;
|
sl@0
|
474 |
iOutputDataType = OMX_NumericalDataSigned;
|
sl@0
|
475 |
}
|
sl@0
|
476 |
|
sl@0
|
477 |
OMX_ERRORTYPE CCodecProcessor::EmptyThisBuffer(
|
sl@0
|
478 |
OMX_BUFFERHEADERTYPE* pBuffer)
|
sl@0
|
479 |
{
|
sl@0
|
480 |
TCodecMessage message;
|
sl@0
|
481 |
message.iType = EInputBuffer;
|
sl@0
|
482 |
message.iBuffer = pBuffer;
|
sl@0
|
483 |
if (iMessageQueue.Send(message) == KErrNone)
|
sl@0
|
484 |
{
|
sl@0
|
485 |
return OMX_ErrorNone;
|
sl@0
|
486 |
}
|
sl@0
|
487 |
else
|
sl@0
|
488 |
{
|
sl@0
|
489 |
return OMX_ErrorUndefined;
|
sl@0
|
490 |
}
|
sl@0
|
491 |
}
|
sl@0
|
492 |
|
sl@0
|
493 |
void CCodecProcessor::Stop()
|
sl@0
|
494 |
{
|
sl@0
|
495 |
TCodecMessage message;
|
sl@0
|
496 |
message.iType = EStopProcessing;
|
sl@0
|
497 |
message.iBuffer = NULL;
|
sl@0
|
498 |
iMessageQueue.Send(message);
|
sl@0
|
499 |
}
|
sl@0
|
500 |
|
sl@0
|
501 |
void CCodecProcessor::Exit()
|
sl@0
|
502 |
{
|
sl@0
|
503 |
TCodecMessage message;
|
sl@0
|
504 |
message.iType = EExit;
|
sl@0
|
505 |
message.iBuffer = NULL;
|
sl@0
|
506 |
iMessageQueue.SendBlocking(message);
|
sl@0
|
507 |
}
|
sl@0
|
508 |
|
sl@0
|
509 |
OMX_ERRORTYPE CCodecProcessor::FillThisBuffer(
|
sl@0
|
510 |
OMX_BUFFERHEADERTYPE* pBuffer)
|
sl@0
|
511 |
{
|
sl@0
|
512 |
TCodecMessage message;
|
sl@0
|
513 |
message.iType = EOutputBuffer;
|
sl@0
|
514 |
message.iBuffer = pBuffer;
|
sl@0
|
515 |
if (iMessageQueue.Send(message)== KErrNone)
|
sl@0
|
516 |
{
|
sl@0
|
517 |
return OMX_ErrorNone;
|
sl@0
|
518 |
}
|
sl@0
|
519 |
else
|
sl@0
|
520 |
{
|
sl@0
|
521 |
return OMX_ErrorUndefined;
|
sl@0
|
522 |
}
|
sl@0
|
523 |
}
|
sl@0
|
524 |
|
sl@0
|
525 |
void CCodecProcessor::SetInputBitsPerSample(TInt aInputBitsPerSample)
|
sl@0
|
526 |
{
|
sl@0
|
527 |
iInputBitsPerSample = aInputBitsPerSample;
|
sl@0
|
528 |
}
|
sl@0
|
529 |
|
sl@0
|
530 |
void CCodecProcessor::SetInputDataType(OMX_NUMERICALDATATYPE aType)
|
sl@0
|
531 |
{
|
sl@0
|
532 |
iInputDataType = aType;
|
sl@0
|
533 |
}
|
sl@0
|
534 |
|
sl@0
|
535 |
void CCodecProcessor::SetOutputBitsPerSample(TInt aInputBitsPerSample)
|
sl@0
|
536 |
{
|
sl@0
|
537 |
iOutputBitsPerSample = aInputBitsPerSample;
|
sl@0
|
538 |
}
|
sl@0
|
539 |
|
sl@0
|
540 |
void CCodecProcessor::SetOutputDataType(OMX_NUMERICALDATATYPE aType)
|
sl@0
|
541 |
{
|
sl@0
|
542 |
iOutputDataType = aType;
|
sl@0
|
543 |
}
|
sl@0
|
544 |
|
sl@0
|
545 |
void CCodecProcessor::ChooseCodec()
|
sl@0
|
546 |
{
|
sl@0
|
547 |
// choose correct conversion codec
|
sl@0
|
548 |
if (iInputBitsPerSample == 8 && iOutputBitsPerSample == 16)
|
sl@0
|
549 |
{
|
sl@0
|
550 |
iOutputSamplesPerInputSample = 2;
|
sl@0
|
551 |
if (iInputDataType == OMX_NumericalDataSigned &&
|
sl@0
|
552 |
iOutputDataType == OMX_NumericalDataSigned)
|
sl@0
|
553 |
{
|
sl@0
|
554 |
iCurrentCodec = &iAudioS8ToS16PcmCodec;
|
sl@0
|
555 |
}
|
sl@0
|
556 |
else if (iInputDataType == OMX_NumericalDataUnsigned &&
|
sl@0
|
557 |
iOutputDataType == OMX_NumericalDataSigned)
|
sl@0
|
558 |
{
|
sl@0
|
559 |
iCurrentCodec = &iAudioU8ToS16PcmCodec;
|
sl@0
|
560 |
}
|
sl@0
|
561 |
}
|
sl@0
|
562 |
else if (iInputBitsPerSample == 16 && iOutputBitsPerSample == 8)
|
sl@0
|
563 |
{
|
sl@0
|
564 |
iOutputSamplesPerInputSample = .5;
|
sl@0
|
565 |
if (iInputDataType == OMX_NumericalDataSigned &&
|
sl@0
|
566 |
iOutputDataType == OMX_NumericalDataSigned)
|
sl@0
|
567 |
{
|
sl@0
|
568 |
iCurrentCodec = &iAudioS16ToS8PcmCodec;
|
sl@0
|
569 |
}
|
sl@0
|
570 |
else if (iInputDataType == OMX_NumericalDataSigned &&
|
sl@0
|
571 |
iOutputDataType == OMX_NumericalDataUnsigned)
|
sl@0
|
572 |
{
|
sl@0
|
573 |
iCurrentCodec = &iAudioS16ToU8PcmCodec;
|
sl@0
|
574 |
}
|
sl@0
|
575 |
}
|
sl@0
|
576 |
|
sl@0
|
577 |
}
|
sl@0
|
578 |
|
sl@0
|
579 |
void CCodecProcessor::ProcessAvailableBuffers()
|
sl@0
|
580 |
{
|
sl@0
|
581 |
// Setup wait for data in queue
|
sl@0
|
582 |
while (iBuffersToFill.Count()>0 && iBuffersToEmpty.Count() > 0)
|
sl@0
|
583 |
{
|
sl@0
|
584 |
TBool lastBuffer = EFalse;
|
sl@0
|
585 |
if (!iStarted)
|
sl@0
|
586 |
{
|
sl@0
|
587 |
ChooseCodec();
|
sl@0
|
588 |
iStarted = ETrue;
|
sl@0
|
589 |
}
|
sl@0
|
590 |
|
sl@0
|
591 |
OMX_BUFFERHEADERTYPE* srcBuffer = iBuffersToEmpty[0];
|
sl@0
|
592 |
OMX_BUFFERHEADERTYPE* destBuffer = iBuffersToFill[0];
|
sl@0
|
593 |
if (srcBuffer->nFlags & OMX_BUFFERFLAG_EOS)
|
sl@0
|
594 |
{
|
sl@0
|
595 |
lastBuffer = ETrue;
|
sl@0
|
596 |
}
|
sl@0
|
597 |
TInt destBufferPos = destBuffer->nFilledLen;
|
sl@0
|
598 |
|
sl@0
|
599 |
TInt destBufferSize = destBuffer->nAllocLen - destBufferPos;
|
sl@0
|
600 |
TInt inputSamplesRequired = (TInt)((TReal)destBufferSize / iOutputSamplesPerInputSample);
|
sl@0
|
601 |
|
sl@0
|
602 |
TInt availableSamples = srcBuffer->nFilledLen - iInputBufferPos;
|
sl@0
|
603 |
|
sl@0
|
604 |
if (availableSamples <= inputSamplesRequired)
|
sl@0
|
605 |
{
|
sl@0
|
606 |
TInt samplesToConvert = availableSamples;
|
sl@0
|
607 |
if (iOutputSamplesPerInputSample == .5)
|
sl@0
|
608 |
{
|
sl@0
|
609 |
samplesToConvert >>= 1;
|
sl@0
|
610 |
}
|
sl@0
|
611 |
iCurrentCodec->Convert(&srcBuffer->pBuffer[iInputBufferPos], &destBuffer->pBuffer[destBufferPos], samplesToConvert);
|
sl@0
|
612 |
iInputBufferPos = 0; // finished buffer - so reset
|
sl@0
|
613 |
inputSamplesRequired -= availableSamples;
|
sl@0
|
614 |
destBuffer->nFilledLen = (TInt)((TReal)availableSamples * iOutputSamplesPerInputSample);
|
sl@0
|
615 |
srcBuffer->nFilledLen = 0;
|
sl@0
|
616 |
iBuffersToEmpty.Remove(0);
|
sl@0
|
617 |
iParent->EmptyBufferDoneCallback(srcBuffer);
|
sl@0
|
618 |
|
sl@0
|
619 |
if (inputSamplesRequired == 0 || lastBuffer)
|
sl@0
|
620 |
{
|
sl@0
|
621 |
iBuffersToFill.Remove(0);
|
sl@0
|
622 |
if (lastBuffer)
|
sl@0
|
623 |
{
|
sl@0
|
624 |
destBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
|
sl@0
|
625 |
// propagate the EOS flag
|
sl@0
|
626 |
iParent->EventHandlerCallback(
|
sl@0
|
627 |
OMX_EventBufferFlag,
|
sl@0
|
628 |
0,
|
sl@0
|
629 |
destBuffer->nFlags,
|
sl@0
|
630 |
NULL);
|
sl@0
|
631 |
}
|
sl@0
|
632 |
iParent->FillBufferDoneCallback(destBuffer);
|
sl@0
|
633 |
}
|
sl@0
|
634 |
}
|
sl@0
|
635 |
else
|
sl@0
|
636 |
{
|
sl@0
|
637 |
TInt samplesToConvert = inputSamplesRequired;
|
sl@0
|
638 |
if (iOutputSamplesPerInputSample == .5)
|
sl@0
|
639 |
{
|
sl@0
|
640 |
samplesToConvert >>= 2;
|
sl@0
|
641 |
}
|
sl@0
|
642 |
|
sl@0
|
643 |
iCurrentCodec->Convert(&srcBuffer->pBuffer[iInputBufferPos], &destBuffer->pBuffer[destBufferPos], samplesToConvert);
|
sl@0
|
644 |
iInputBufferPos += inputSamplesRequired;
|
sl@0
|
645 |
destBuffer->nFilledLen = destBuffer->nAllocLen;
|
sl@0
|
646 |
iBuffersToFill.Remove(0);
|
sl@0
|
647 |
iParent->FillBufferDoneCallback(destBuffer);
|
sl@0
|
648 |
}
|
sl@0
|
649 |
}
|
sl@0
|
650 |
}
|
sl@0
|
651 |
|
sl@0
|
652 |
CCodecProcessor::~CCodecProcessor()
|
sl@0
|
653 |
{
|
sl@0
|
654 |
iBuffersToEmpty.Close();
|
sl@0
|
655 |
iBuffersToFill.Close();
|
sl@0
|
656 |
iMessageQueue.Close();
|
sl@0
|
657 |
}
|
sl@0
|
658 |
|
sl@0
|
659 |
|
sl@0
|
660 |
TInt COmxPCMCodec::StartExecution()
|
sl@0
|
661 |
{
|
sl@0
|
662 |
// create thread with current thread's heap
|
sl@0
|
663 |
// we can thus allocate and free memory across threads
|
sl@0
|
664 |
if (!iCreatedThread)
|
sl@0
|
665 |
{
|
sl@0
|
666 |
TInt err = iProcessingThread.Create(_L("PCMCodec"),
|
sl@0
|
667 |
&ProcessingThread,
|
sl@0
|
668 |
KThreadStackSize,
|
sl@0
|
669 |
&User::Heap(),
|
sl@0
|
670 |
iCodecProcessor);
|
sl@0
|
671 |
|
sl@0
|
672 |
if (err!=KErrNone)
|
sl@0
|
673 |
{
|
sl@0
|
674 |
return err;
|
sl@0
|
675 |
}
|
sl@0
|
676 |
iCreatedThread = ETrue;
|
sl@0
|
677 |
iThreadDeath = KRequestPending;
|
sl@0
|
678 |
iProcessingThread.Resume();
|
sl@0
|
679 |
}
|
sl@0
|
680 |
|
sl@0
|
681 |
return KErrNone;
|
sl@0
|
682 |
}
|
sl@0
|
683 |
|
sl@0
|
684 |
// Callbacks for the PCM codec
|
sl@0
|
685 |
void COmxPCMCodec::EventHandlerCallback(
|
sl@0
|
686 |
OMX_OUT OMX_EVENTTYPE eEvent,
|
sl@0
|
687 |
OMX_OUT TUint32 nData1,
|
sl@0
|
688 |
OMX_OUT TUint32 nData2,
|
sl@0
|
689 |
OMX_OUT OMX_STRING cExtraInfo)
|
sl@0
|
690 |
{
|
sl@0
|
691 |
iCallback->EventHandler(
|
sl@0
|
692 |
this,
|
sl@0
|
693 |
iAppData,
|
sl@0
|
694 |
eEvent,
|
sl@0
|
695 |
nData1,
|
sl@0
|
696 |
nData2,
|
sl@0
|
697 |
cExtraInfo);
|
sl@0
|
698 |
}
|
sl@0
|
699 |
|
sl@0
|
700 |
|
sl@0
|
701 |
void COmxPCMCodec::FillBufferDoneCallback(OMX_BUFFERHEADERTYPE* aBuffer)
|
sl@0
|
702 |
{
|
sl@0
|
703 |
iCallback->FillBufferDone(
|
sl@0
|
704 |
*this,
|
sl@0
|
705 |
iAppData,
|
sl@0
|
706 |
aBuffer);
|
sl@0
|
707 |
}
|
sl@0
|
708 |
|
sl@0
|
709 |
void COmxPCMCodec::EmptyBufferDoneCallback(OMX_BUFFERHEADERTYPE* aBuffer)
|
sl@0
|
710 |
{
|
sl@0
|
711 |
iCallback->EmptyBufferDone(
|
sl@0
|
712 |
*this,
|
sl@0
|
713 |
iAppData,
|
sl@0
|
714 |
aBuffer);
|
sl@0
|
715 |
}
|
sl@0
|
716 |
|
sl@0
|
717 |
// Component Entry Point
|
sl@0
|
718 |
OMX_ERRORTYPE OMX_ComponentInit(OMX_HANDLETYPE hComponent)
|
sl@0
|
719 |
{
|
sl@0
|
720 |
TInt err = COmxPCMCodec::CreateComponent(hComponent);
|
sl@0
|
721 |
if (err == KErrNone)
|
sl@0
|
722 |
{
|
sl@0
|
723 |
return OMX_ErrorNone;
|
sl@0
|
724 |
}
|
sl@0
|
725 |
else
|
sl@0
|
726 |
{
|
sl@0
|
727 |
// return problem
|
sl@0
|
728 |
return OMX_ErrorInsufficientResources;
|
sl@0
|
729 |
}
|
sl@0
|
730 |
}
|