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