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