OMXNodeInstance.cpp revision 2a3847ee1cbdaa8a65eee397a0173bb02211c459
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    *buffer = header;
268
269    addActiveBuffer(portIndex, *buffer);
270
271    return OK;
272}
273
274status_t OMXNodeInstance::allocateBuffer(
275        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
276        void **buffer_data) {
277    Mutex::Autolock autoLock(mLock);
278
279    BufferMeta *buffer_meta = new BufferMeta(size);
280
281    OMX_BUFFERHEADERTYPE *header;
282
283    OMX_ERRORTYPE err = OMX_AllocateBuffer(
284            mHandle, &header, portIndex, buffer_meta, size);
285
286    if (err != OMX_ErrorNone) {
287        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
288
289        delete buffer_meta;
290        buffer_meta = NULL;
291
292        *buffer = 0;
293
294        return UNKNOWN_ERROR;
295    }
296
297    *buffer = header;
298    *buffer_data = header->pBuffer;
299
300    addActiveBuffer(portIndex, *buffer);
301
302    return OK;
303}
304
305status_t OMXNodeInstance::allocateBufferWithBackup(
306        OMX_U32 portIndex, const sp<IMemory> &params,
307        OMX::buffer_id *buffer) {
308    Mutex::Autolock autoLock(mLock);
309
310    BufferMeta *buffer_meta = new BufferMeta(params, true);
311
312    OMX_BUFFERHEADERTYPE *header;
313
314    OMX_ERRORTYPE err = OMX_AllocateBuffer(
315            mHandle, &header, portIndex, buffer_meta, params->size());
316
317    if (err != OMX_ErrorNone) {
318        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
319
320        delete buffer_meta;
321        buffer_meta = NULL;
322
323        *buffer = 0;
324
325        return UNKNOWN_ERROR;
326    }
327
328    *buffer = header;
329
330    addActiveBuffer(portIndex, *buffer);
331
332    return OK;
333}
334
335status_t OMXNodeInstance::freeBuffer(
336        OMX_U32 portIndex, OMX::buffer_id buffer) {
337    Mutex::Autolock autoLock(mLock);
338
339    removeActiveBuffer(portIndex, buffer);
340
341    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
342    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
343
344    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
345
346    delete buffer_meta;
347    buffer_meta = NULL;
348
349    return StatusFromOMXError(err);
350}
351
352status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
353    Mutex::Autolock autoLock(mLock);
354
355    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
356    header->nFilledLen = 0;
357    header->nOffset = 0;
358    header->nFlags = 0;
359
360    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
361
362    return StatusFromOMXError(err);
363}
364
365status_t OMXNodeInstance::emptyBuffer(
366        OMX::buffer_id buffer,
367        OMX_U32 rangeOffset, OMX_U32 rangeLength,
368        OMX_U32 flags, OMX_TICKS timestamp) {
369    Mutex::Autolock autoLock(mLock);
370
371    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
372    header->nFilledLen = rangeLength;
373    header->nOffset = rangeOffset;
374    header->nFlags = flags;
375    header->nTimeStamp = timestamp;
376
377    BufferMeta *buffer_meta =
378        static_cast<BufferMeta *>(header->pAppPrivate);
379    buffer_meta->CopyToOMX(header);
380
381    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
382
383    return StatusFromOMXError(err);
384}
385
386status_t OMXNodeInstance::getExtensionIndex(
387        const char *parameterName, OMX_INDEXTYPE *index) {
388    Mutex::Autolock autoLock(mLock);
389
390    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
391            mHandle, const_cast<char *>(parameterName), index);
392
393    return StatusFromOMXError(err);
394}
395
396void OMXNodeInstance::onMessage(const omx_message &msg) {
397    if (msg.type == omx_message::FILL_BUFFER_DONE) {
398        OMX_BUFFERHEADERTYPE *buffer =
399            static_cast<OMX_BUFFERHEADERTYPE *>(
400                    msg.u.extended_buffer_data.buffer);
401
402        BufferMeta *buffer_meta =
403            static_cast<BufferMeta *>(buffer->pAppPrivate);
404
405        buffer_meta->CopyFromOMX(buffer);
406    }
407
408    mObserver->onMessage(msg);
409}
410
411void OMXNodeInstance::onObserverDied(OMXMaster *master) {
412    LOGE("!!! Observer died. Quickly, do something, ... anything...");
413
414    // Try to force shutdown of the node and hope for the best.
415    freeNode(master);
416}
417
418void OMXNodeInstance::onGetHandleFailed() {
419    delete this;
420}
421
422// static
423OMX_ERRORTYPE OMXNodeInstance::OnEvent(
424        OMX_IN OMX_HANDLETYPE hComponent,
425        OMX_IN OMX_PTR pAppData,
426        OMX_IN OMX_EVENTTYPE eEvent,
427        OMX_IN OMX_U32 nData1,
428        OMX_IN OMX_U32 nData2,
429        OMX_IN OMX_PTR pEventData) {
430    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
431    if (instance->mDying) {
432        return OMX_ErrorNone;
433    }
434    return instance->owner()->OnEvent(
435            instance->nodeID(), eEvent, nData1, nData2, pEventData);
436}
437
438// static
439OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
440        OMX_IN OMX_HANDLETYPE hComponent,
441        OMX_IN OMX_PTR pAppData,
442        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
443    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
444    if (instance->mDying) {
445        return OMX_ErrorNone;
446    }
447    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
448}
449
450// static
451OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
452        OMX_IN OMX_HANDLETYPE hComponent,
453        OMX_IN OMX_PTR pAppData,
454        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
455    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
456    if (instance->mDying) {
457        return OMX_ErrorNone;
458    }
459    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
460}
461
462void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
463    ActiveBuffer active;
464    active.mPortIndex = portIndex;
465    active.mID = id;
466    mActiveBuffers.push(active);
467}
468
469void OMXNodeInstance::removeActiveBuffer(
470        OMX_U32 portIndex, OMX::buffer_id id) {
471    bool found = false;
472    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
473        if (mActiveBuffers[i].mPortIndex == portIndex
474            && mActiveBuffers[i].mID == id) {
475            found = true;
476            mActiveBuffers.removeItemsAt(i);
477            break;
478        }
479    }
480
481    if (!found) {
482        LOGW("Attempt to remove an active buffer we know nothing about...");
483    }
484}
485
486void OMXNodeInstance::freeActiveBuffers() {
487    // Make sure to count down here, as freeBuffer will in turn remove
488    // the active buffer from the vector...
489    for (size_t i = mActiveBuffers.size(); i--;) {
490        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
491    }
492}
493
494}  // namespace android
495
496