1 /*
2 * Copyright (C) 2009 The Android Open Source Project
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 express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OMXNodeInstance"
19 #include <utils/Log.h>
20
21 #include "../include/OMXNodeInstance.h"
22
23 #include "pv_omxcore.h"
24
25 #include <binder/IMemory.h>
26 #include <media/stagefright/MediaDebug.h>
27
28 namespace android {
29
30 struct BufferMeta {
BufferMetaandroid::BufferMeta31 BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
32 : mMem(mem),
33 mIsBackup(is_backup) {
34 }
35
BufferMetaandroid::BufferMeta36 BufferMeta(size_t size)
37 : mSize(size),
38 mIsBackup(false) {
39 }
40
CopyFromOMXandroid::BufferMeta41 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
42 if (!mIsBackup) {
43 return;
44 }
45
46 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
47 header->pBuffer + header->nOffset,
48 header->nFilledLen);
49 }
50
CopyToOMXandroid::BufferMeta51 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
52 if (!mIsBackup) {
53 return;
54 }
55
56 memcpy(header->pBuffer + header->nOffset,
57 (const OMX_U8 *)mMem->pointer() + header->nOffset,
58 header->nFilledLen);
59 }
60
61 private:
62 sp<IMemory> mMem;
63 size_t mSize;
64 bool mIsBackup;
65
66 BufferMeta(const BufferMeta &);
67 BufferMeta &operator=(const BufferMeta &);
68 };
69
70 // static
71 OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
72 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
73 };
74
OMXNodeInstance(OMX * owner,const sp<IOMXObserver> & observer)75 OMXNodeInstance::OMXNodeInstance(
76 OMX *owner, const sp<IOMXObserver> &observer)
77 : mOwner(owner),
78 mNodeID(NULL),
79 mHandle(NULL),
80 mObserver(observer) {
81 }
82
~OMXNodeInstance()83 OMXNodeInstance::~OMXNodeInstance() {
84 CHECK_EQ(mHandle, NULL);
85 }
86
setHandle(OMX::node_id node_id,OMX_HANDLETYPE handle)87 void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
88 CHECK_EQ(mHandle, NULL);
89 mNodeID = node_id;
90 mHandle = handle;
91 }
92
owner()93 OMX *OMXNodeInstance::owner() {
94 return mOwner;
95 }
96
observer()97 sp<IOMXObserver> OMXNodeInstance::observer() {
98 return mObserver;
99 }
100
nodeID()101 OMX::node_id OMXNodeInstance::nodeID() {
102 return mNodeID;
103 }
104
StatusFromOMXError(OMX_ERRORTYPE err)105 static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
106 return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR;
107 }
108
freeNode()109 status_t OMXNodeInstance::freeNode() {
110 // Transition the node from its current state all the way down
111 // to "Loaded".
112 // This ensures that all active buffers are properly freed even
113 // for components that don't do this themselves on a call to
114 // "FreeHandle".
115
116 OMX_STATETYPE state;
117 CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
118 switch (state) {
119 case OMX_StateExecuting:
120 {
121 LOGV("forcing Executing->Idle");
122 sendCommand(OMX_CommandStateSet, OMX_StateIdle);
123 OMX_ERRORTYPE err;
124 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
125 && state != OMX_StateIdle) {
126 usleep(100000);
127 }
128 CHECK_EQ(err, OMX_ErrorNone);
129
130 // fall through
131 }
132
133 case OMX_StateIdle:
134 {
135 LOGV("forcing Idle->Loaded");
136 sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
137
138 freeActiveBuffers();
139
140 OMX_ERRORTYPE err;
141 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
142 && state != OMX_StateLoaded) {
143 LOGV("waiting for Loaded state...");
144 usleep(100000);
145 }
146 CHECK_EQ(err, OMX_ErrorNone);
147
148 // fall through
149 }
150
151 case OMX_StateLoaded:
152 case OMX_StateInvalid:
153 break;
154
155 default:
156 CHECK(!"should not be here, unknown state.");
157 break;
158 }
159
160 OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
161 mHandle = NULL;
162
163 if (err != OMX_ErrorNone) {
164 LOGE("FreeHandle FAILED with error 0x%08x.", err);
165 }
166
167 mOwner->invalidateNodeID(mNodeID);
168 mNodeID = NULL;
169
170 LOGV("OMXNodeInstance going away.");
171 delete this;
172
173 return StatusFromOMXError(err);
174 }
175
sendCommand(OMX_COMMANDTYPE cmd,OMX_S32 param)176 status_t OMXNodeInstance::sendCommand(
177 OMX_COMMANDTYPE cmd, OMX_S32 param) {
178 Mutex::Autolock autoLock(mLock);
179
180 OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
181 return StatusFromOMXError(err);
182 }
183
getParameter(OMX_INDEXTYPE index,void * params,size_t size)184 status_t OMXNodeInstance::getParameter(
185 OMX_INDEXTYPE index, void *params, size_t size) {
186 Mutex::Autolock autoLock(mLock);
187
188 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
189 return StatusFromOMXError(err);
190 }
191
setParameter(OMX_INDEXTYPE index,const void * params,size_t size)192 status_t OMXNodeInstance::setParameter(
193 OMX_INDEXTYPE index, const void *params, size_t size) {
194 Mutex::Autolock autoLock(mLock);
195
196 OMX_ERRORTYPE err = OMX_SetParameter(
197 mHandle, index, const_cast<void *>(params));
198
199 return StatusFromOMXError(err);
200 }
201
getConfig(OMX_INDEXTYPE index,void * params,size_t size)202 status_t OMXNodeInstance::getConfig(
203 OMX_INDEXTYPE index, void *params, size_t size) {
204 Mutex::Autolock autoLock(mLock);
205
206 OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
207 return StatusFromOMXError(err);
208 }
209
setConfig(OMX_INDEXTYPE index,const void * params,size_t size)210 status_t OMXNodeInstance::setConfig(
211 OMX_INDEXTYPE index, const void *params, size_t size) {
212 Mutex::Autolock autoLock(mLock);
213
214 OMX_ERRORTYPE err = OMX_SetConfig(
215 mHandle, index, const_cast<void *>(params));
216
217 return StatusFromOMXError(err);
218 }
219
useBuffer(OMX_U32 portIndex,const sp<IMemory> & params,OMX::buffer_id * buffer)220 status_t OMXNodeInstance::useBuffer(
221 OMX_U32 portIndex, const sp<IMemory> ¶ms,
222 OMX::buffer_id *buffer) {
223 Mutex::Autolock autoLock(mLock);
224
225 BufferMeta *buffer_meta = new BufferMeta(params);
226
227 OMX_BUFFERHEADERTYPE *header;
228
229 OMX_ERRORTYPE err = OMX_UseBuffer(
230 mHandle, &header, portIndex, buffer_meta,
231 params->size(), static_cast<OMX_U8 *>(params->pointer()));
232
233 if (err != OMX_ErrorNone) {
234 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
235
236 delete buffer_meta;
237 buffer_meta = NULL;
238
239 *buffer = 0;
240
241 return UNKNOWN_ERROR;
242 }
243
244 *buffer = header;
245
246 addActiveBuffer(portIndex, *buffer);
247
248 return OK;
249 }
250
allocateBuffer(OMX_U32 portIndex,size_t size,OMX::buffer_id * buffer)251 status_t OMXNodeInstance::allocateBuffer(
252 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
253 Mutex::Autolock autoLock(mLock);
254
255 BufferMeta *buffer_meta = new BufferMeta(size);
256
257 OMX_BUFFERHEADERTYPE *header;
258
259 OMX_ERRORTYPE err = OMX_AllocateBuffer(
260 mHandle, &header, portIndex, buffer_meta, size);
261
262 if (err != OMX_ErrorNone) {
263 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
264
265 delete buffer_meta;
266 buffer_meta = NULL;
267
268 *buffer = 0;
269
270 return UNKNOWN_ERROR;
271 }
272
273 *buffer = header;
274
275 addActiveBuffer(portIndex, *buffer);
276
277 return OK;
278 }
279
allocateBufferWithBackup(OMX_U32 portIndex,const sp<IMemory> & params,OMX::buffer_id * buffer)280 status_t OMXNodeInstance::allocateBufferWithBackup(
281 OMX_U32 portIndex, const sp<IMemory> ¶ms,
282 OMX::buffer_id *buffer) {
283 Mutex::Autolock autoLock(mLock);
284
285 BufferMeta *buffer_meta = new BufferMeta(params, true);
286
287 OMX_BUFFERHEADERTYPE *header;
288
289 OMX_ERRORTYPE err = OMX_AllocateBuffer(
290 mHandle, &header, portIndex, buffer_meta, params->size());
291
292 if (err != OMX_ErrorNone) {
293 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
294
295 delete buffer_meta;
296 buffer_meta = NULL;
297
298 *buffer = 0;
299
300 return UNKNOWN_ERROR;
301 }
302
303 *buffer = header;
304
305 addActiveBuffer(portIndex, *buffer);
306
307 return OK;
308 }
309
freeBuffer(OMX_U32 portIndex,OMX::buffer_id buffer)310 status_t OMXNodeInstance::freeBuffer(
311 OMX_U32 portIndex, OMX::buffer_id buffer) {
312 Mutex::Autolock autoLock(mLock);
313
314 removeActiveBuffer(portIndex, buffer);
315
316 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
317 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
318
319 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
320
321 delete buffer_meta;
322 buffer_meta = NULL;
323
324 return StatusFromOMXError(err);
325 }
326
fillBuffer(OMX::buffer_id buffer)327 status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
328 Mutex::Autolock autoLock(mLock);
329
330 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
331 header->nFilledLen = 0;
332 header->nOffset = 0;
333 header->nFlags = 0;
334
335 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
336
337 return StatusFromOMXError(err);
338 }
339
emptyBuffer(OMX::buffer_id buffer,OMX_U32 rangeOffset,OMX_U32 rangeLength,OMX_U32 flags,OMX_TICKS timestamp)340 status_t OMXNodeInstance::emptyBuffer(
341 OMX::buffer_id buffer,
342 OMX_U32 rangeOffset, OMX_U32 rangeLength,
343 OMX_U32 flags, OMX_TICKS timestamp) {
344 Mutex::Autolock autoLock(mLock);
345
346 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
347 header->nFilledLen = rangeLength;
348 header->nOffset = rangeOffset;
349 header->nFlags = flags;
350 header->nTimeStamp = timestamp;
351
352 BufferMeta *buffer_meta =
353 static_cast<BufferMeta *>(header->pAppPrivate);
354 buffer_meta->CopyToOMX(header);
355
356 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
357
358 return StatusFromOMXError(err);
359 }
360
getExtensionIndex(const char * parameterName,OMX_INDEXTYPE * index)361 status_t OMXNodeInstance::getExtensionIndex(
362 const char *parameterName, OMX_INDEXTYPE *index) {
363 Mutex::Autolock autoLock(mLock);
364
365 OMX_ERRORTYPE err = OMX_GetExtensionIndex(
366 mHandle, const_cast<char *>(parameterName), index);
367
368 return StatusFromOMXError(err);
369 }
370
onMessage(const omx_message & msg)371 void OMXNodeInstance::onMessage(const omx_message &msg) {
372 if (msg.type == omx_message::FILL_BUFFER_DONE) {
373 OMX_BUFFERHEADERTYPE *buffer =
374 static_cast<OMX_BUFFERHEADERTYPE *>(
375 msg.u.extended_buffer_data.buffer);
376
377 BufferMeta *buffer_meta =
378 static_cast<BufferMeta *>(buffer->pAppPrivate);
379
380 buffer_meta->CopyFromOMX(buffer);
381 }
382
383 mObserver->onMessage(msg);
384 }
385
onObserverDied()386 void OMXNodeInstance::onObserverDied() {
387 LOGE("!!! Observer died. Quickly, do something, ... anything...");
388
389 // Try to force shutdown of the node and hope for the best.
390 freeNode();
391 }
392
onGetHandleFailed()393 void OMXNodeInstance::onGetHandleFailed() {
394 delete this;
395 }
396
397 // static
OnEvent(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_EVENTTYPE eEvent,OMX_IN OMX_U32 nData1,OMX_IN OMX_U32 nData2,OMX_IN OMX_PTR pEventData)398 OMX_ERRORTYPE OMXNodeInstance::OnEvent(
399 OMX_IN OMX_HANDLETYPE hComponent,
400 OMX_IN OMX_PTR pAppData,
401 OMX_IN OMX_EVENTTYPE eEvent,
402 OMX_IN OMX_U32 nData1,
403 OMX_IN OMX_U32 nData2,
404 OMX_IN OMX_PTR pEventData) {
405 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
406 return instance->owner()->OnEvent(
407 instance->nodeID(), eEvent, nData1, nData2, pEventData);
408 }
409
410 // static
OnEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)411 OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
412 OMX_IN OMX_HANDLETYPE hComponent,
413 OMX_IN OMX_PTR pAppData,
414 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
415 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
416 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
417 }
418
419 // static
OnFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)420 OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
421 OMX_IN OMX_HANDLETYPE hComponent,
422 OMX_IN OMX_PTR pAppData,
423 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
424 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
425 return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
426 }
427
addActiveBuffer(OMX_U32 portIndex,OMX::buffer_id id)428 void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
429 ActiveBuffer active;
430 active.mPortIndex = portIndex;
431 active.mID = id;
432 mActiveBuffers.push(active);
433 }
434
removeActiveBuffer(OMX_U32 portIndex,OMX::buffer_id id)435 void OMXNodeInstance::removeActiveBuffer(
436 OMX_U32 portIndex, OMX::buffer_id id) {
437 bool found = false;
438 for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
439 if (mActiveBuffers[i].mPortIndex == portIndex
440 && mActiveBuffers[i].mID == id) {
441 found = true;
442 mActiveBuffers.removeItemsAt(i);
443 break;
444 }
445 }
446
447 if (!found) {
448 LOGW("Attempt to remove an active buffer we know nothing about...");
449 }
450 }
451
freeActiveBuffers()452 void OMXNodeInstance::freeActiveBuffers() {
453 // Make sure to count down here, as freeBuffer will in turn remove
454 // the active buffer from the vector...
455 for (size_t i = mActiveBuffers.size(); i--;) {
456 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
457 }
458 }
459
460 } // namespace android
461
462