1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 #include "oscl_base.h"
19 #include "pv_omxdefs.h"
20 #include "omx_mp3_component.h"
21
22 #if PROXY_INTERFACE
23 #include "omx_proxy_interface.h"
24 #endif
25
26 // Use default DLL entry point
27 #ifndef OSCL_DLL_H_INCLUDED
28 #include "oscl_dll.h"
29 #endif
30
31 #define OMX_HALFRANGE_THRESHOLD 0x7FFFFFFF
32
OSCL_DLL_ENTRY_POINT_DEFAULT()33 OSCL_DLL_ENTRY_POINT_DEFAULT()
34
35 // This function is called by OMX_GetHandle and it creates an instance of the mp3 component AO
36 OSCL_EXPORT_REF OMX_ERRORTYPE Mp3OmxComponentFactory(OMX_OUT OMX_HANDLETYPE* pHandle, OMX_IN OMX_PTR pAppData, OMX_PTR pProxy, OMX_STRING aOmxLibName, OMX_PTR &aOmxLib, OMX_PTR aOsclUuid, OMX_U32 &aRefCount)
37 {
38 OSCL_UNUSED_ARG(aOmxLibName);
39 OSCL_UNUSED_ARG(aOmxLib);
40 OSCL_UNUSED_ARG(aOsclUuid);
41 OSCL_UNUSED_ARG(aRefCount);
42
43 OpenmaxMp3AO* pOpenmaxAOType;
44 OMX_ERRORTYPE Status;
45
46 // move InitMp3OmxComponentFields content to actual constructor
47
48 pOpenmaxAOType = (OpenmaxMp3AO*) OSCL_NEW(OpenmaxMp3AO, ());
49
50 if (NULL == pOpenmaxAOType)
51 {
52 return OMX_ErrorInsufficientResources;
53 }
54
55 //Call the construct component to initialize OMX types
56 Status = pOpenmaxAOType->ConstructComponent(pAppData, pProxy);
57
58 *pHandle = pOpenmaxAOType->GetOmxHandle();
59
60 return Status;
61 ///////////////////////////////////////////////////////////////////////////////////////
62 }
63
64 // This function is called by OMX_FreeHandle when component AO needs to be destroyed
Mp3OmxComponentDestructor(OMX_IN OMX_HANDLETYPE pHandle,OMX_PTR & aOmxLib,OMX_PTR aOsclUuid,OMX_U32 & aRefCount)65 OSCL_EXPORT_REF OMX_ERRORTYPE Mp3OmxComponentDestructor(OMX_IN OMX_HANDLETYPE pHandle, OMX_PTR &aOmxLib, OMX_PTR aOsclUuid, OMX_U32 &aRefCount)
66 {
67 OSCL_UNUSED_ARG(aOmxLib);
68 OSCL_UNUSED_ARG(aOsclUuid);
69 OSCL_UNUSED_ARG(aRefCount);
70
71 // get pointer to component AO
72 OpenmaxMp3AO* pOpenmaxAOType = (OpenmaxMp3AO*)((OMX_COMPONENTTYPE*)pHandle)->pComponentPrivate;
73
74 // clean up decoder, OMX component stuff
75 pOpenmaxAOType->DestroyComponent();
76
77 // destroy the AO class
78 OSCL_DELETE(pOpenmaxAOType);
79
80 return OMX_ErrorNone;
81 }
82 #if DYNAMIC_LOAD_OMX_MP3_COMPONENT
83 class Mp3OmxSharedLibraryInterface: public OsclSharedLibraryInterface,
84 public OmxSharedLibraryInterface
85 {
86 public:
QueryOmxComponentInterface(const OsclUuid & aOmxTypeId,const OsclUuid & aInterfaceId)87 OsclAny *QueryOmxComponentInterface(const OsclUuid& aOmxTypeId, const OsclUuid& aInterfaceId)
88 {
89 if (PV_OMX_MP3DEC_UUID == aOmxTypeId)
90 {
91 if (PV_OMX_CREATE_INTERFACE == aInterfaceId)
92 {
93 return ((OsclAny*)(&Mp3OmxComponentFactory));
94 }
95 else if (PV_OMX_DESTROY_INTERFACE == aInterfaceId)
96 {
97 return ((OsclAny*)(&Mp3OmxComponentDestructor));
98 }
99 }
100 return NULL;
101 };
SharedLibraryLookup(const OsclUuid & aInterfaceId)102 OsclAny *SharedLibraryLookup(const OsclUuid& aInterfaceId)
103 {
104 if (aInterfaceId == PV_OMX_SHARED_INTERFACE)
105 {
106 return OSCL_STATIC_CAST(OmxSharedLibraryInterface*, this);
107 }
108 return NULL;
109 };
110
Mp3OmxSharedLibraryInterface()111 Mp3OmxSharedLibraryInterface() {};
112 };
113
114 // function to obtain the interface object from the shared library
115 extern "C"
116 {
PVGetInterface()117 OSCL_EXPORT_REF OsclAny* PVGetInterface()
118 {
119 return (OsclAny*) OSCL_NEW(Mp3OmxSharedLibraryInterface, ());
120 }
121
PVReleaseInterface(OsclSharedLibraryInterface * aInstance)122 OSCL_EXPORT_REF void PVReleaseInterface(OsclSharedLibraryInterface* aInstance)
123 {
124 Mp3OmxSharedLibraryInterface* module = (Mp3OmxSharedLibraryInterface*)aInstance;
125 OSCL_DELETE(module);
126 }
127 }
128
129 #endif
130
131 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
132
ConstructComponent(OMX_PTR pAppData,OMX_PTR pProxy)133 OMX_ERRORTYPE OpenmaxMp3AO::ConstructComponent(OMX_PTR pAppData, OMX_PTR pProxy)
134 {
135 ComponentPortType* pInPort, *pOutPort;
136 OMX_ERRORTYPE Status;
137
138 iNumPorts = 2;
139 iOmxComponent.nSize = sizeof(OMX_COMPONENTTYPE);
140 iOmxComponent.pComponentPrivate = (OMX_PTR) this; // pComponentPrivate points to THIS component AO class
141 iOmxComponent.pApplicationPrivate = pAppData; // init the App data
142
143 ipComponentProxy = pProxy;
144
145
146 #if PROXY_INTERFACE
147 iPVCapabilityFlags.iIsOMXComponentMultiThreaded = OMX_TRUE;
148
149 iOmxComponent.SendCommand = OpenmaxMp3AO::BaseComponentProxySendCommand;
150 iOmxComponent.GetParameter = OpenmaxMp3AO::BaseComponentProxyGetParameter;
151 iOmxComponent.SetParameter = OpenmaxMp3AO::BaseComponentProxySetParameter;
152 iOmxComponent.GetConfig = OpenmaxMp3AO::BaseComponentProxyGetConfig;
153 iOmxComponent.SetConfig = OpenmaxMp3AO::BaseComponentProxySetConfig;
154 iOmxComponent.GetExtensionIndex = OpenmaxMp3AO::BaseComponentProxyGetExtensionIndex;
155 iOmxComponent.GetState = OpenmaxMp3AO::BaseComponentProxyGetState;
156 iOmxComponent.UseBuffer = OpenmaxMp3AO::BaseComponentProxyUseBuffer;
157 iOmxComponent.AllocateBuffer = OpenmaxMp3AO::BaseComponentProxyAllocateBuffer;
158 iOmxComponent.FreeBuffer = OpenmaxMp3AO::BaseComponentProxyFreeBuffer;
159 iOmxComponent.EmptyThisBuffer = OpenmaxMp3AO::BaseComponentProxyEmptyThisBuffer;
160 iOmxComponent.FillThisBuffer = OpenmaxMp3AO::BaseComponentProxyFillThisBuffer;
161
162 #else
163 iPVCapabilityFlags.iIsOMXComponentMultiThreaded = OMX_FALSE;
164
165 iOmxComponent.SendCommand = OpenmaxMp3AO::BaseComponentSendCommand;
166 iOmxComponent.GetParameter = OpenmaxMp3AO::BaseComponentGetParameter;
167 iOmxComponent.SetParameter = OpenmaxMp3AO::BaseComponentSetParameter;
168 iOmxComponent.GetConfig = OpenmaxMp3AO::BaseComponentGetConfig;
169 iOmxComponent.SetConfig = OpenmaxMp3AO::BaseComponentSetConfig;
170 iOmxComponent.GetExtensionIndex = OpenmaxMp3AO::BaseComponentGetExtensionIndex;
171 iOmxComponent.GetState = OpenmaxMp3AO::BaseComponentGetState;
172 iOmxComponent.UseBuffer = OpenmaxMp3AO::BaseComponentUseBuffer;
173 iOmxComponent.AllocateBuffer = OpenmaxMp3AO::BaseComponentAllocateBuffer;
174 iOmxComponent.FreeBuffer = OpenmaxMp3AO::BaseComponentFreeBuffer;
175 iOmxComponent.EmptyThisBuffer = OpenmaxMp3AO::BaseComponentEmptyThisBuffer;
176 iOmxComponent.FillThisBuffer = OpenmaxMp3AO::BaseComponentFillThisBuffer;
177 #endif
178
179 iOmxComponent.SetCallbacks = OpenmaxMp3AO::BaseComponentSetCallbacks;
180 iOmxComponent.nVersion.s.nVersionMajor = SPECVERSIONMAJOR;
181 iOmxComponent.nVersion.s.nVersionMinor = SPECVERSIONMINOR;
182 iOmxComponent.nVersion.s.nRevision = SPECREVISION;
183 iOmxComponent.nVersion.s.nStep = SPECSTEP;
184
185 // PV capability
186 iPVCapabilityFlags.iOMXComponentSupportsExternalInputBufferAlloc = OMX_TRUE;
187 iPVCapabilityFlags.iOMXComponentSupportsExternalOutputBufferAlloc = OMX_TRUE;
188 iPVCapabilityFlags.iOMXComponentSupportsMovableInputBuffers = OMX_TRUE;
189 iPVCapabilityFlags.iOMXComponentSupportsPartialFrames = OMX_TRUE;
190 iPVCapabilityFlags.iOMXComponentUsesNALStartCodes = OMX_FALSE;
191 iPVCapabilityFlags.iOMXComponentCanHandleIncompleteFrames = OMX_TRUE;
192 iPVCapabilityFlags.iOMXComponentUsesFullAVCFrames = OMX_FALSE;
193
194 if (ipAppPriv)
195 {
196 oscl_free(ipAppPriv);
197 ipAppPriv = NULL;
198 }
199
200 ipAppPriv = (ComponentPrivateType*) oscl_malloc(sizeof(ComponentPrivateType));
201 if (NULL == ipAppPriv)
202 {
203 return OMX_ErrorInsufficientResources;
204 }
205
206 //Construct base class now
207 Status = ConstructBaseComponent(pAppData);
208
209 if (OMX_ErrorNone != Status)
210 {
211 return Status;
212 }
213
214 /** Domain specific section for the ports. */
215 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nPortIndex = OMX_PORT_INPUTPORT_INDEX;
216 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainAudio;
217 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.cMIMEType = (OMX_STRING)"audio/mpeg";
218 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.pNativeRender = 0;
219 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.bFlagErrorConcealment = OMX_FALSE;
220 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
221 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.eDir = OMX_DirInput;
222 //Set to a default value, will change later during setparameter call
223 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferCountActual = NUMBER_INPUT_BUFFER_MP3;
224 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferCountMin = 1;
225 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize = INPUT_BUFFER_SIZE_MP3;
226 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE;
227 ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE;
228
229
230 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nPortIndex = OMX_PORT_OUTPUTPORT_INDEX;
231 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainAudio;
232 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.cMIMEType = (OMX_STRING)"raw";
233 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.pNativeRender = 0;
234 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.bFlagErrorConcealment = OMX_FALSE;
235 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
236 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.eDir = OMX_DirOutput;
237 //Set to a default value, will change later during setparameter call
238 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferCountActual = NUMBER_OUTPUT_BUFFER_MP3;
239 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferCountMin = 1;
240 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferSize = OUTPUT_BUFFER_SIZE_MP3 * 6;
241 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE;
242 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE;
243
244 //Default values for Mp3 audio param port
245 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.nPortIndex = OMX_PORT_INPUTPORT_INDEX;
246 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.nChannels = 2;
247 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.nBitRate = 0;
248 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.nSampleRate = 44100;
249 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.nAudioBandWidth = 0;
250 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.eChannelMode = OMX_AUDIO_ChannelModeStereo;
251 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
252
253 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioEqualizerType.nPortIndex = OMX_PORT_INPUTPORT_INDEX;
254 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioEqualizerType.sBandIndex.nMin = 0;
255 //Taken these value from from mp3 decoder component
256 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioEqualizerType.sBandIndex.nValue = (e_equalization) flat;
257 ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioEqualizerType.sBandIndex.nMax = (e_equalization) flat_;
258
259
260 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nPortIndex = OMX_PORT_OUTPUTPORT_INDEX;
261 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nChannels = 2;
262 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eNumData = OMX_NumericalDataSigned;
263 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.bInterleaved = OMX_TRUE;
264 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nBitPerSample = 16;
265 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nSamplingRate = 44100;
266 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.ePCMMode = OMX_AUDIO_PCMModeLinear;
267 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
268 ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
269
270 iPortTypesParam.nPorts = 2;
271 iPortTypesParam.nStartPortNumber = 0;
272
273 pInPort = (ComponentPortType*) ipPorts[OMX_PORT_INPUTPORT_INDEX];
274 pOutPort = (ComponentPortType*) ipPorts[OMX_PORT_OUTPUTPORT_INDEX];
275
276 SetHeader(&pInPort->AudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE));
277 pInPort->AudioParam.nPortIndex = 0;
278 pInPort->AudioParam.nIndex = 0;
279 pInPort->AudioParam.eEncoding = OMX_AUDIO_CodingMP3;
280
281 SetHeader(&pOutPort->AudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE));
282 pOutPort->AudioParam.nPortIndex = 1;
283 pOutPort->AudioParam.nIndex = 0;
284 pOutPort->AudioParam.eEncoding = OMX_AUDIO_CodingPCM;
285
286 oscl_strncpy((OMX_STRING)iComponentRole, (OMX_STRING)"audio_decoder.mp3", OMX_MAX_STRINGNAME_SIZE);
287
288 iOutputFrameLength = OUTPUT_BUFFER_SIZE_MP3;
289
290 if (ipMp3Dec)
291 {
292 OSCL_DELETE(ipMp3Dec);
293 ipMp3Dec = NULL;
294 }
295
296 ipMp3Dec = OSCL_NEW(Mp3Decoder, ());
297 if (ipMp3Dec == NULL)
298 {
299 return OMX_ErrorInsufficientResources;
300 }
301
302 oscl_memset(ipMp3Dec, 0, sizeof(Mp3Decoder));
303
304 iSamplesPerFrame = DEFAULT_SAMPLES_PER_FRAME_MP3;
305 iOutputMicroSecPerFrame = iCurrentFrameTS.GetFrameDuration();
306
307 #if PROXY_INTERFACE
308
309 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSendCommand = BaseComponentSendCommand;
310 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetParameter = BaseComponentGetParameter;
311 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSetParameter = BaseComponentSetParameter;
312 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetConfig = BaseComponentGetConfig;
313 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSetConfig = BaseComponentSetConfig;
314 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetExtensionIndex = BaseComponentGetExtensionIndex;
315 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetState = BaseComponentGetState;
316 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentUseBuffer = BaseComponentUseBuffer;
317 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentAllocateBuffer = BaseComponentAllocateBuffer;
318 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentFreeBuffer = BaseComponentFreeBuffer;
319 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentEmptyThisBuffer = BaseComponentEmptyThisBuffer;
320 ((ProxyApplication_OMX*)ipComponentProxy)->ComponentFillThisBuffer = BaseComponentFillThisBuffer;
321
322 #endif
323 return OMX_ErrorNone;
324 }
325
326
327 /** This function is called by the omx core when the component
328 * is disposed by the IL client with a call to FreeHandle().
329 */
330
DestroyComponent()331 OMX_ERRORTYPE OpenmaxMp3AO::DestroyComponent()
332 {
333 if (iIsInit != OMX_FALSE)
334 {
335 ComponentDeInit();
336 }
337
338 //Destroy the base class now
339 DestroyBaseComponent();
340
341 if (ipMp3Dec)
342 {
343 OSCL_DELETE(ipMp3Dec);
344 ipMp3Dec = NULL;
345 }
346
347 if (ipAppPriv)
348 {
349 ipAppPriv->CompHandle = NULL;
350
351 oscl_free(ipAppPriv);
352 ipAppPriv = NULL;
353 }
354
355 return OMX_ErrorNone;
356 }
357
358
SyncWithInputTimestamp()359 void OpenmaxMp3AO::SyncWithInputTimestamp()
360 {
361 //Do not check for silence insertion if the clip is repositioned
362 if (OMX_FALSE == iRepositionFlag)
363 {
364 CheckForSilenceInsertion();
365 }
366
367 /* Set the current timestamp equal to input buffer timestamp in case of
368 * a) All input frames
369 * b) First frame after repositioning */
370 if (OMX_FALSE == iSilenceInsertionInProgress || OMX_TRUE == iRepositionFlag)
371 {
372 // Set the current timestamp equal to input buffer timestamp
373 iCurrentFrameTS.SetFromInputTimestamp(iFrameTimestamp);
374
375 //Reset the flag back to false, once timestamp has been updated from input frame
376 if (OMX_TRUE == iRepositionFlag)
377 {
378 iRepositionFlag = OMX_FALSE;
379 }
380 }
381 }
382
ResetComponent()383 void OpenmaxMp3AO::ResetComponent()
384 {
385 // reset decoder
386 if (ipMp3Dec)
387 {
388 ipMp3Dec->ResetDecoder();
389 //Set this length to zero for flushing the current input buffer
390 ipMp3Dec->iInputUsedLength = 0;
391 //ipMp3Dec->iInitFlag = 0;
392 }
393 }
394
395
ProcessInBufferFlag()396 void OpenmaxMp3AO::ProcessInBufferFlag()
397 {
398 iIsInputBufferEnded = OMX_FALSE;
399 }
400
401
ProcessData()402 void OpenmaxMp3AO::ProcessData()
403 {
404 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData IN"));
405
406 QueueType* pInputQueue = ipPorts[OMX_PORT_INPUTPORT_INDEX]->pBufferQueue;
407 QueueType* pOutputQueue = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->pBufferQueue;
408
409 ComponentPortType* pInPort = (ComponentPortType*) ipPorts[OMX_PORT_INPUTPORT_INDEX];
410 ComponentPortType* pOutPort = ipPorts[OMX_PORT_OUTPUTPORT_INDEX];
411 OMX_COMPONENTTYPE* pHandle = &iOmxComponent;
412
413 OMX_U8* pOutBuffer;
414 OMX_U32 OutputLength;
415 OMX_S32 DecodeReturn;
416 OMX_BOOL ResizeNeeded = OMX_FALSE;
417
418 OMX_U32 TempInputBufferSize = (2 * sizeof(uint8) * (ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize));
419
420 if ((!iIsInputBufferEnded) || iEndofStream)
421 {
422 if (OMX_TRUE == iSilenceInsertionInProgress)
423 {
424 DoSilenceInsertion();
425 //If the flag is still true, come back to this routine again
426 if (OMX_TRUE == iSilenceInsertionInProgress)
427 {
428 return;
429 }
430 }
431
432 //Check whether prev output bufer has been released or not
433 if (OMX_TRUE == iNewOutBufRequired)
434 {
435 //Check whether a new output buffer is available or not
436 if (0 == (GetQueueNumElem(pOutputQueue)))
437 {
438 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData OUT output buffer unavailable"));
439 return;
440 }
441
442 ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue);
443 if (NULL == ipOutputBuffer)
444 {
445 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData Error, Output Buffer Dequeue returned NULL, OUT"));
446 return;
447 }
448 ipOutputBuffer->nFilledLen = 0;
449 iNewOutBufRequired = OMX_FALSE;
450
451 //Set the current timestamp to the output buffer timestamp
452 ipOutputBuffer->nTimeStamp = iCurrentFrameTS.GetConvertedTs();
453
454 // Copy the output buffer that was stored locally before dynamic port reconfiguration
455 // in the new omx buffer received.
456 if (OMX_TRUE == iSendOutBufferAfterPortReconfigFlag)
457 {
458 if ((ipTempOutBufferForPortReconfig)
459 && (iSizeOutBufferForPortReconfig <= ipOutputBuffer->nAllocLen))
460 {
461 oscl_memcpy(ipOutputBuffer->pBuffer, ipTempOutBufferForPortReconfig, iSizeOutBufferForPortReconfig);
462 ipOutputBuffer->nFilledLen = iSizeOutBufferForPortReconfig;
463 ipOutputBuffer->nTimeStamp = iTimestampOutBufferForPortReconfig;
464 }
465
466 iSendOutBufferAfterPortReconfigFlag = OMX_FALSE;
467
468 //Send the output buffer back only when it has become full
469 if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength)
470 {
471 ReturnOutputBuffer(ipOutputBuffer, pOutPort);
472 }
473
474 //Free the temp output buffer
475 if (ipTempOutBufferForPortReconfig)
476 {
477 oscl_free(ipTempOutBufferForPortReconfig);
478 ipTempOutBufferForPortReconfig = NULL;
479 iSizeOutBufferForPortReconfig = 0;
480 }
481
482 //Dequeue new output buffer if required to continue decoding the next frame
483 if (OMX_TRUE == iNewOutBufRequired)
484 {
485 if (0 == (GetQueueNumElem(pOutputQueue)))
486 {
487 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData OUT, output buffer unavailable"));
488 return;
489 }
490
491 ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue);
492 if (NULL == ipOutputBuffer)
493 {
494 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData Error, Output Buffer Dequeue returned NULL, OUT"));
495 return;
496 }
497
498 ipOutputBuffer->nFilledLen = 0;
499 iNewOutBufRequired = OMX_FALSE;
500
501 ipOutputBuffer->nTimeStamp = iCurrentFrameTS.GetConvertedTs();
502 }
503 }
504 }
505
506 /* Code for the marking buffer. Takes care of the OMX_CommandMarkBuffer
507 * command and hMarkTargetComponent as given by the specifications
508 */
509 if (ipMark != NULL)
510 {
511 ipOutputBuffer->hMarkTargetComponent = ipMark->hMarkTargetComponent;
512 ipOutputBuffer->pMarkData = ipMark->pMarkData;
513 ipMark = NULL;
514 }
515
516 if (ipTargetComponent != NULL)
517 {
518 ipOutputBuffer->hMarkTargetComponent = ipTargetComponent;
519 ipOutputBuffer->pMarkData = iTargetMarkData;
520 ipTargetComponent = NULL;
521
522 }
523 //Mark buffer code ends here
524
525 pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen];
526 OutputLength = (ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) >> 1;
527
528 /* Copy the left-over data from last input buffer that is stored in temporary
529 * buffer to the next incoming buffer.
530 */
531 if (iTempInputBufferLength > 0 &&
532 ((iInputCurrLength + iTempInputBufferLength) < TempInputBufferSize))
533 {
534 oscl_memcpy(&ipTempInputBuffer[iTempInputBufferLength], ipFrameDecodeBuffer, iInputCurrLength);
535 iInputCurrLength += iTempInputBufferLength;
536 iTempInputBufferLength = 0;
537 ipFrameDecodeBuffer = ipTempInputBuffer;
538 }
539
540 //Output buffer is passed as a short pointer
541 DecodeReturn = ipMp3Dec->Mp3DecodeAudio((OMX_S16*) pOutBuffer,
542 (OMX_U32*) & OutputLength,
543 &(ipFrameDecodeBuffer),
544 &iInputCurrLength,
545 &iFrameCount,
546 &(ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode),
547 &(ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioMp3Param),
548 iEndOfFrameFlag,
549 &ResizeNeeded);
550
551 if (ResizeNeeded == OMX_TRUE)
552 {
553 if (0 != OutputLength)
554 {
555 iOutputFrameLength = OutputLength * 2;
556
557 //Update the timestamp
558 iSamplesPerFrame = OutputLength / ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nChannels;
559
560 iCurrentFrameTS.SetParameters(ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nSamplingRate, iSamplesPerFrame);
561 iOutputMicroSecPerFrame = iCurrentFrameTS.GetFrameDuration();
562
563 }
564
565 // set the flag to disable further processing until Client reacts to this
566 // by doing dynamic port reconfiguration
567 iResizePending = OMX_TRUE;
568
569 /* Do not return the output buffer generated yet, store it locally
570 * and wait for the dynamic port reconfig to complete */
571 if ((NULL == ipTempOutBufferForPortReconfig))
572 {
573 ipTempOutBufferForPortReconfig = (OMX_U8*) oscl_malloc(sizeof(uint8) * OutputLength * 2);
574 if (NULL == ipTempOutBufferForPortReconfig)
575 {
576 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData error, insufficient resources"));
577 return;
578 }
579 }
580
581 //Copy the omx output buffer to the temporary internal buffer
582 oscl_memcpy(ipTempOutBufferForPortReconfig, pOutBuffer, OutputLength * 2);
583 iSizeOutBufferForPortReconfig = OutputLength * 2;
584
585 //Set the current timestamp to the output buffer timestamp for the first output frame
586 //Later it will be done at the time of dequeue
587 iTimestampOutBufferForPortReconfig = iCurrentFrameTS.GetConvertedTs();
588
589 iCurrentFrameTS.UpdateTimestamp(iSamplesPerFrame);
590 //Make this length 0 so that no output buffer is returned by the component
591 OutputLength = 0;
592
593 // send port settings changed event
594 OMX_COMPONENTTYPE* pHandle = (OMX_COMPONENTTYPE*) ipAppPriv->CompHandle;
595
596 (*(ipCallbacks->EventHandler))
597 (pHandle,
598 iCallbackData,
599 OMX_EventPortSettingsChanged, //The command was completed
600 OMX_PORT_OUTPUTPORT_INDEX,
601 0,
602 NULL);
603 }
604
605 ipOutputBuffer->nFilledLen += OutputLength * 2;
606 //offset not required in our case, set it to zero
607 ipOutputBuffer->nOffset = 0;
608
609 if (OutputLength > 0)
610 {
611 iCurrentFrameTS.UpdateTimestamp(iSamplesPerFrame);
612 }
613
614 /* If EOS flag has come from the client & there are no more
615 * input buffers to decode, send the callback to the client
616 */
617 if (OMX_TRUE == iEndofStream)
618 {
619 /* Changed the condition here. If EOS has come and decoder can't decode
620 * the buffer, do not wait for buffer length to become zero and return
621 * the callback as the current buffer may contain partial frame and
622 * no other data is going to come now
623 */
624 if (MP3DEC_SUCCESS != DecodeReturn)
625 {
626 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData EOS callback send"));
627
628 (*(ipCallbacks->EventHandler))
629 (pHandle,
630 iCallbackData,
631 OMX_EventBufferFlag,
632 1,
633 OMX_BUFFERFLAG_EOS,
634 NULL);
635
636 iEndofStream = OMX_FALSE;
637
638 ipOutputBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
639
640 ReturnOutputBuffer(ipOutputBuffer, pOutPort);
641 ipOutputBuffer = NULL;
642
643 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData OUT"));
644
645 return;
646 }
647 }
648
649
650 if (MP3DEC_SUCCESS == DecodeReturn)
651 {
652 ipInputBuffer->nFilledLen = iInputCurrLength;
653 }
654 else if ((MP3DEC_INCOMPLETE_FRAME == DecodeReturn) ||
655 (MP3DEC_OUTPUT_BUFFER_TOO_SMALL == DecodeReturn))
656 {
657 /* If decoder returns MP4AUDEC_INCOMPLETE_FRAME,
658 * this indicates the input buffer contains less than a frame data
659 * Copy it to a temp buffer to be used in next decode call
660 */
661 oscl_memcpy(ipTempInputBuffer, ipFrameDecodeBuffer, iInputCurrLength);
662 iTempInputBufferLength = iInputCurrLength;
663
664 ipInputBuffer->nFilledLen = 0;
665 iInputCurrLength = 0;
666 }
667 else
668 {
669 //bitstream error, discard the current data as it can't be decoded further
670 ipInputBuffer->nFilledLen = 0;
671 iInputCurrLength = 0;
672
673 //Report it to the client via a callback
674 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData ErrorStreamCorrupt callback send"));
675
676 (*(ipCallbacks->EventHandler))
677 (pHandle,
678 iCallbackData,
679 OMX_EventError,
680 OMX_ErrorStreamCorrupt,
681 0,
682 NULL);
683
684 }
685
686 //Return the input buffer if it has been consumed fully by the decoder
687 if (0 == ipInputBuffer->nFilledLen)
688 {
689 ReturnInputBuffer(ipInputBuffer, pInPort);
690 ipInputBuffer = NULL;
691 iIsInputBufferEnded = OMX_TRUE;
692 iInputCurrLength = 0;
693 }
694
695 /*
696 * Send the output buffer back when it has become full
697 * or when there is not room to hold next decoded output
698 */
699 if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < (iOutputFrameLength) ||
700 (MP3DEC_OUTPUT_BUFFER_TOO_SMALL == DecodeReturn))
701 {
702 ReturnOutputBuffer(ipOutputBuffer, pOutPort);
703 ipOutputBuffer = NULL;
704 }
705
706 /* If there is some more processing left with current buffers, re-schedule the AO
707 * Do not go for more than one round of processing at a time.
708 * This may block the AO longer than required.
709 */
710 if (((iInputCurrLength != 0 || GetQueueNumElem(pInputQueue) > 0)
711 && (GetQueueNumElem(pOutputQueue) > 0) && (ResizeNeeded == OMX_FALSE))
712 || (OMX_TRUE == iEndofStream))
713 {
714 RunIfNotReady();
715 }
716 }
717
718 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ProcessData OUT"));
719 return;
720 }
721
722
ComponentGetRolesOfComponent(OMX_STRING * aRoleString)723 void OpenmaxMp3AO::ComponentGetRolesOfComponent(OMX_STRING* aRoleString)
724 {
725 *aRoleString = (OMX_STRING)"audio_decoder.mp3";
726 }
727
728
729 //Active object constructor
OpenmaxMp3AO()730 OpenmaxMp3AO::OpenmaxMp3AO()
731 {
732 ipMp3Dec = NULL;
733
734 if (!IsAdded())
735 {
736 AddToScheduler();
737 }
738
739 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : constructed"));
740 }
741
742
743 //Active object destructor
~OpenmaxMp3AO()744 OpenmaxMp3AO::~OpenmaxMp3AO()
745 {
746 if (IsAdded())
747 {
748 RemoveFromScheduler();
749 }
750
751 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : destructed"));
752 }
753
754
755 /** The Initialization function
756 */
ComponentInit()757 OMX_ERRORTYPE OpenmaxMp3AO::ComponentInit()
758 {
759 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ComponentInit IN"));
760
761 OMX_BOOL Status = OMX_FALSE;
762
763 if (OMX_TRUE == iIsInit)
764 {
765 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ComponentInit error incorrect operation"));
766 return OMX_ErrorIncorrectStateOperation;
767 }
768 iIsInit = OMX_TRUE;
769
770 //Mp3 lib init
771 if (!iCodecReady)
772 {
773 Status = ipMp3Dec->Mp3DecInit(&(ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioEqualizerType));
774 iCodecReady = OMX_TRUE;
775 }
776
777 iInputCurrLength = 0;
778 //Used in dynamic port reconfiguration
779 iFrameCount = 0;
780
781 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ComponentInit OUT"));
782
783 if (OMX_TRUE == Status)
784 {
785 return OMX_ErrorNone;
786 }
787 else
788 {
789 return OMX_ErrorInvalidComponent;
790 }
791 }
792
793 /** This function is called upon a transition to the idle or invalid state.
794 * Also it is called by the Mp3ComponentDestructor() function
795 */
ComponentDeInit()796 OMX_ERRORTYPE OpenmaxMp3AO::ComponentDeInit()
797 {
798 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ComponentDeInit IN"));
799
800 iIsInit = OMX_FALSE;
801
802 if (iCodecReady)
803 {
804 ipMp3Dec->Mp3DecDeinit();
805 iCodecReady = OMX_FALSE;
806 }
807
808 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : ComponentDeInit OUT"));
809
810 return OMX_ErrorNone;
811
812 }
813
814
815 //Check whether silence insertion is required here or not
CheckForSilenceInsertion()816 void OpenmaxMp3AO::CheckForSilenceInsertion()
817 {
818
819 OMX_TICKS CurrTimestamp, TimestampGap;
820 //Set the flag to false by default
821 iSilenceInsertionInProgress = OMX_FALSE;
822
823 CurrTimestamp = iCurrentFrameTS.GetCurrentTimestamp();
824 TimestampGap = iFrameTimestamp - CurrTimestamp;
825
826 if ((TimestampGap > OMX_HALFRANGE_THRESHOLD) || (TimestampGap < iOutputMicroSecPerFrame && iFrameCount > 0))
827 {
828 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : CheckForSilenceInsertion OUT - No need to insert silence"));
829 return;
830 }
831
832 //Silence insertion needed, mark the flag to true
833 if (iFrameCount > 0)
834 {
835 iSilenceInsertionInProgress = OMX_TRUE;
836 //Determine the number of silence frames to insert
837 if (0 != iOutputMicroSecPerFrame)
838 {
839 iSilenceFramesNeeded = TimestampGap / iOutputMicroSecPerFrame;
840 }
841 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : CheckForSilenceInsertion OUT - Silence Insertion required here"));
842 }
843
844 return;
845 }
846
847 //Currently we are doing zero frame insertion in this routine
DoSilenceInsertion()848 void OpenmaxMp3AO::DoSilenceInsertion()
849 {
850 QueueType* pOutputQueue = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->pBufferQueue;
851 ComponentPortType* pOutPort = ipPorts[OMX_PORT_OUTPUTPORT_INDEX];
852 OMX_U8* pOutBuffer = NULL;
853
854
855 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : DoSilenceInsertion IN"));
856
857 while (iSilenceFramesNeeded > 0)
858 {
859 //Check whether prev output bufer has been consumed or not
860 if (OMX_TRUE == iNewOutBufRequired)
861 {
862 //Check whether a new output buffer is available or not
863 if (0 == (GetQueueNumElem(pOutputQueue)))
864 {
865 //Resume Silence insertion next time when component will be called
866 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : DoSilenceInsertion OUT output buffer unavailable"));
867 iSilenceInsertionInProgress = OMX_TRUE;
868 return;
869 }
870
871 ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue);
872 if (NULL == ipOutputBuffer)
873 {
874 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : DoSilenceInsertion Error, Output Buffer Dequeue returned NULL, OUT"));
875 iSilenceInsertionInProgress = OMX_TRUE;
876 return;
877 }
878 ipOutputBuffer->nFilledLen = 0;
879 iNewOutBufRequired = OMX_FALSE;
880
881 //Set the current timestamp to the output buffer timestamp
882 ipOutputBuffer->nTimeStamp = iCurrentFrameTS.GetConvertedTs();
883 }
884
885
886 pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen];
887 oscl_memset(pOutBuffer, 0, iOutputFrameLength);
888
889 ipOutputBuffer->nFilledLen += iOutputFrameLength;
890 ipOutputBuffer->nOffset = 0;
891 iCurrentFrameTS.UpdateTimestamp(iSamplesPerFrame);
892
893 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : DoSilenceInsertion - One frame of zeros inserted"));
894
895 //Send the output buffer back when it has become full
896 if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength)
897 {
898 ReturnOutputBuffer(ipOutputBuffer, pOutPort);
899 ipOutputBuffer = NULL;
900 }
901
902 // Decrement the silence frame counter
903 --iSilenceFramesNeeded;
904 }
905
906 /* Completed Silence insertion successfully, now consider the input buffer already dequeued
907 * for decoding & update the timestamps */
908
909 iSilenceInsertionInProgress = OMX_FALSE;
910 iCurrentFrameTS.SetFromInputTimestamp(iFrameTimestamp);
911 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxMp3AO : DoSilenceInsertion OUT - Done successfully"));
912
913 return;
914 }
915
916
GetConfig(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_INDEXTYPE nIndex,OMX_INOUT OMX_PTR pComponentConfigStructure)917 OMX_ERRORTYPE OpenmaxMp3AO::GetConfig(
918 OMX_IN OMX_HANDLETYPE hComponent,
919 OMX_IN OMX_INDEXTYPE nIndex,
920 OMX_INOUT OMX_PTR pComponentConfigStructure)
921 {
922 OSCL_UNUSED_ARG(hComponent);
923 OSCL_UNUSED_ARG(nIndex);
924 OSCL_UNUSED_ARG(pComponentConfigStructure);
925 return OMX_ErrorNotImplemented;
926 }
927