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