• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &params,
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> &params,
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