OMXNodeInstance.cpp revision 92cb8f928dc9e237c356c942d10b5c0c1e04b2ae
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#include "GraphicBufferSource.h"
24
25#include <OMX_Component.h>
26
27#include <binder/IMemory.h>
28#include <gui/BufferQueue.h>
29#include <HardwareAPI.h>
30#include <media/stagefright/foundation/ADebug.h>
31#include <media/stagefright/MediaErrors.h>
32
33static const OMX_U32 kPortIndexInput = 0;
34
35namespace android {
36
37struct BufferMeta {
38    BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
39        : mMem(mem),
40          mIsBackup(is_backup) {
41    }
42
43    BufferMeta(size_t size)
44        : mSize(size),
45          mIsBackup(false) {
46    }
47
48    BufferMeta(const sp<GraphicBuffer> &graphicBuffer)
49        : mGraphicBuffer(graphicBuffer),
50          mIsBackup(false) {
51    }
52
53    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
54        if (!mIsBackup) {
55            return;
56        }
57
58        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
59               header->pBuffer + header->nOffset,
60               header->nFilledLen);
61    }
62
63    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
64        if (!mIsBackup) {
65            return;
66        }
67
68        memcpy(header->pBuffer + header->nOffset,
69               (const OMX_U8 *)mMem->pointer() + header->nOffset,
70               header->nFilledLen);
71    }
72
73private:
74    sp<GraphicBuffer> mGraphicBuffer;
75    sp<IMemory> mMem;
76    size_t mSize;
77    bool mIsBackup;
78
79    BufferMeta(const BufferMeta &);
80    BufferMeta &operator=(const BufferMeta &);
81};
82
83// static
84OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
85    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
86};
87
88OMXNodeInstance::OMXNodeInstance(
89        OMX *owner, const sp<IOMXObserver> &observer)
90    : mOwner(owner),
91      mNodeID(NULL),
92      mHandle(NULL),
93      mObserver(observer),
94      mDying(false) {
95}
96
97OMXNodeInstance::~OMXNodeInstance() {
98    CHECK(mHandle == NULL);
99}
100
101void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
102    CHECK(mHandle == NULL);
103    mNodeID = node_id;
104    mHandle = handle;
105}
106
107sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() {
108    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
109    return mGraphicBufferSource;
110}
111
112void OMXNodeInstance::setGraphicBufferSource(
113        const sp<GraphicBufferSource>& bufferSource) {
114    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
115    mGraphicBufferSource = bufferSource;
116}
117
118OMX *OMXNodeInstance::owner() {
119    return mOwner;
120}
121
122sp<IOMXObserver> OMXNodeInstance::observer() {
123    return mObserver;
124}
125
126OMX::node_id OMXNodeInstance::nodeID() {
127    return mNodeID;
128}
129
130static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
131    switch (err) {
132        case OMX_ErrorNone:
133            return OK;
134        case OMX_ErrorUnsupportedSetting:
135            return ERROR_UNSUPPORTED;
136        default:
137            return UNKNOWN_ERROR;
138    }
139}
140
141status_t OMXNodeInstance::freeNode(OMXMaster *master) {
142    static int32_t kMaxNumIterations = 10;
143
144    // Transition the node from its current state all the way down
145    // to "Loaded".
146    // This ensures that all active buffers are properly freed even
147    // for components that don't do this themselves on a call to
148    // "FreeHandle".
149
150    // The code below may trigger some more events to be dispatched
151    // by the OMX component - we want to ignore them as our client
152    // does not expect them.
153    mDying = true;
154
155    OMX_STATETYPE state;
156    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
157    switch (state) {
158        case OMX_StateExecuting:
159        {
160            ALOGV("forcing Executing->Idle");
161            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
162            OMX_ERRORTYPE err;
163            int32_t iteration = 0;
164            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
165                   && state != OMX_StateIdle
166                   && state != OMX_StateInvalid) {
167                if (++iteration > kMaxNumIterations) {
168                    ALOGE("component failed to enter Idle state, aborting.");
169                    state = OMX_StateInvalid;
170                    break;
171                }
172
173                usleep(100000);
174            }
175            CHECK_EQ(err, OMX_ErrorNone);
176
177            if (state == OMX_StateInvalid) {
178                break;
179            }
180
181            // fall through
182        }
183
184        case OMX_StateIdle:
185        {
186            ALOGV("forcing Idle->Loaded");
187            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
188
189            freeActiveBuffers();
190
191            OMX_ERRORTYPE err;
192            int32_t iteration = 0;
193            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
194                   && state != OMX_StateLoaded
195                   && state != OMX_StateInvalid) {
196                if (++iteration > kMaxNumIterations) {
197                    ALOGE("component failed to enter Loaded state, aborting.");
198                    state = OMX_StateInvalid;
199                    break;
200                }
201
202                ALOGV("waiting for Loaded state...");
203                usleep(100000);
204            }
205            CHECK_EQ(err, OMX_ErrorNone);
206
207            // fall through
208        }
209
210        case OMX_StateLoaded:
211        case OMX_StateInvalid:
212            break;
213
214        default:
215            CHECK(!"should not be here, unknown state.");
216            break;
217    }
218
219    ALOGV("calling destroyComponentInstance");
220    OMX_ERRORTYPE err = master->destroyComponentInstance(
221            static_cast<OMX_COMPONENTTYPE *>(mHandle));
222    ALOGV("destroyComponentInstance returned err %d", err);
223
224    mHandle = NULL;
225
226    if (err != OMX_ErrorNone) {
227        ALOGE("FreeHandle FAILED with error 0x%08x.", err);
228    }
229
230    mOwner->invalidateNodeID(mNodeID);
231    mNodeID = NULL;
232
233    ALOGV("OMXNodeInstance going away.");
234    delete this;
235
236    return StatusFromOMXError(err);
237}
238
239status_t OMXNodeInstance::sendCommand(
240        OMX_COMMANDTYPE cmd, OMX_S32 param) {
241    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
242    if (bufferSource != NULL
243            && cmd == OMX_CommandStateSet
244            && param == OMX_StateLoaded) {
245        // Initiating transition from Executing -> Loaded
246        // Buffers are about to be freed.
247        bufferSource->omxLoaded();
248        setGraphicBufferSource(NULL);
249
250        // fall through
251    }
252
253    Mutex::Autolock autoLock(mLock);
254
255    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
256    return StatusFromOMXError(err);
257}
258
259status_t OMXNodeInstance::getParameter(
260        OMX_INDEXTYPE index, void *params, size_t size) {
261    Mutex::Autolock autoLock(mLock);
262
263    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
264
265    return StatusFromOMXError(err);
266}
267
268status_t OMXNodeInstance::setParameter(
269        OMX_INDEXTYPE index, const void *params, size_t size) {
270    Mutex::Autolock autoLock(mLock);
271
272    OMX_ERRORTYPE err = OMX_SetParameter(
273            mHandle, index, const_cast<void *>(params));
274
275    return StatusFromOMXError(err);
276}
277
278status_t OMXNodeInstance::getConfig(
279        OMX_INDEXTYPE index, void *params, size_t size) {
280    Mutex::Autolock autoLock(mLock);
281
282    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
283    return StatusFromOMXError(err);
284}
285
286status_t OMXNodeInstance::setConfig(
287        OMX_INDEXTYPE index, const void *params, size_t size) {
288    Mutex::Autolock autoLock(mLock);
289
290    OMX_ERRORTYPE err = OMX_SetConfig(
291            mHandle, index, const_cast<void *>(params));
292
293    return StatusFromOMXError(err);
294}
295
296status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
297    Mutex::Autolock autoLock(mLock);
298
299    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
300
301    return StatusFromOMXError(err);
302}
303
304status_t OMXNodeInstance::enableGraphicBuffers(
305        OMX_U32 portIndex, OMX_BOOL enable) {
306    Mutex::Autolock autoLock(mLock);
307    OMX_STRING name = const_cast<OMX_STRING>(
308            "OMX.google.android.index.enableAndroidNativeBuffers");
309
310    OMX_INDEXTYPE index;
311    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
312
313    if (err != OMX_ErrorNone) {
314        if (enable) {
315            ALOGE("OMX_GetExtensionIndex %s failed", name);
316        }
317
318        return StatusFromOMXError(err);
319    }
320
321    OMX_VERSIONTYPE ver;
322    ver.s.nVersionMajor = 1;
323    ver.s.nVersionMinor = 0;
324    ver.s.nRevision = 0;
325    ver.s.nStep = 0;
326    EnableAndroidNativeBuffersParams params = {
327        sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
328    };
329
330    err = OMX_SetParameter(mHandle, index, &params);
331
332    if (err != OMX_ErrorNone) {
333        ALOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
334                err, err);
335
336        return UNKNOWN_ERROR;
337    }
338
339    return OK;
340}
341
342status_t OMXNodeInstance::getGraphicBufferUsage(
343        OMX_U32 portIndex, OMX_U32* usage) {
344    Mutex::Autolock autoLock(mLock);
345
346    OMX_INDEXTYPE index;
347    OMX_STRING name = const_cast<OMX_STRING>(
348            "OMX.google.android.index.getAndroidNativeBufferUsage");
349    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
350
351    if (err != OMX_ErrorNone) {
352        ALOGE("OMX_GetExtensionIndex %s failed", name);
353
354        return StatusFromOMXError(err);
355    }
356
357    OMX_VERSIONTYPE ver;
358    ver.s.nVersionMajor = 1;
359    ver.s.nVersionMinor = 0;
360    ver.s.nRevision = 0;
361    ver.s.nStep = 0;
362    GetAndroidNativeBufferUsageParams params = {
363        sizeof(GetAndroidNativeBufferUsageParams), ver, portIndex, 0,
364    };
365
366    err = OMX_GetParameter(mHandle, index, &params);
367
368    if (err != OMX_ErrorNone) {
369        ALOGE("OMX_GetAndroidNativeBufferUsage failed with error %d (0x%08x)",
370                err, err);
371        return UNKNOWN_ERROR;
372    }
373
374    *usage = params.nUsage;
375
376    return OK;
377}
378
379status_t OMXNodeInstance::storeMetaDataInBuffers(
380        OMX_U32 portIndex,
381        OMX_BOOL enable) {
382    Mutex::Autolock autolock(mLock);
383    return storeMetaDataInBuffers_l(portIndex, enable);
384}
385
386status_t OMXNodeInstance::storeMetaDataInBuffers_l(
387        OMX_U32 portIndex,
388        OMX_BOOL enable) {
389    OMX_INDEXTYPE index;
390    OMX_STRING name = const_cast<OMX_STRING>(
391            "OMX.google.android.index.storeMetaDataInBuffers");
392
393    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
394    if (err != OMX_ErrorNone) {
395        ALOGE("OMX_GetExtensionIndex %s failed", name);
396
397        return StatusFromOMXError(err);
398    }
399
400    StoreMetaDataInBuffersParams params;
401    memset(&params, 0, sizeof(params));
402    params.nSize = sizeof(params);
403
404    // Version: 1.0.0.0
405    params.nVersion.s.nVersionMajor = 1;
406
407    params.nPortIndex = portIndex;
408    params.bStoreMetaData = enable;
409    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
410        ALOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err);
411        return UNKNOWN_ERROR;
412    }
413    return err;
414}
415
416status_t OMXNodeInstance::useBuffer(
417        OMX_U32 portIndex, const sp<IMemory> &params,
418        OMX::buffer_id *buffer) {
419    Mutex::Autolock autoLock(mLock);
420
421    BufferMeta *buffer_meta = new BufferMeta(params);
422
423    OMX_BUFFERHEADERTYPE *header;
424
425    OMX_ERRORTYPE err = OMX_UseBuffer(
426            mHandle, &header, portIndex, buffer_meta,
427            params->size(), static_cast<OMX_U8 *>(params->pointer()));
428
429    if (err != OMX_ErrorNone) {
430        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
431
432        delete buffer_meta;
433        buffer_meta = NULL;
434
435        *buffer = 0;
436
437        return UNKNOWN_ERROR;
438    }
439
440    CHECK_EQ(header->pAppPrivate, buffer_meta);
441
442    *buffer = header;
443
444    addActiveBuffer(portIndex, *buffer);
445
446    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
447    if (bufferSource != NULL && portIndex == kPortIndexInput) {
448        bufferSource->addCodecBuffer(header);
449    }
450
451    return OK;
452}
453
454status_t OMXNodeInstance::useGraphicBuffer2_l(
455        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
456        OMX::buffer_id *buffer) {
457
458    // port definition
459    OMX_PARAM_PORTDEFINITIONTYPE def;
460    def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
461    def.nVersion.s.nVersionMajor = 1;
462    def.nVersion.s.nVersionMinor = 0;
463    def.nVersion.s.nRevision = 0;
464    def.nVersion.s.nStep = 0;
465    def.nPortIndex = portIndex;
466    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
467    if (err != OMX_ErrorNone)
468    {
469        ALOGE("%s::%d:Error getting OMX_IndexParamPortDefinition", __FUNCTION__, __LINE__);
470        return err;
471    }
472
473    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
474
475    OMX_BUFFERHEADERTYPE *header = NULL;
476    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
477            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
478
479    err = OMX_UseBuffer(
480            mHandle,
481            &header,
482            portIndex,
483            bufferMeta,
484            def.nBufferSize,
485            bufferHandle);
486
487    if (err != OMX_ErrorNone) {
488        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
489        delete bufferMeta;
490        bufferMeta = NULL;
491        *buffer = 0;
492        return UNKNOWN_ERROR;
493    }
494
495    CHECK_EQ(header->pBuffer, bufferHandle);
496    CHECK_EQ(header->pAppPrivate, bufferMeta);
497
498    *buffer = header;
499
500    addActiveBuffer(portIndex, *buffer);
501
502    return OK;
503}
504
505// XXX: This function is here for backwards compatibility.  Once the OMX
506// implementations have been updated this can be removed and useGraphicBuffer2
507// can be renamed to useGraphicBuffer.
508status_t OMXNodeInstance::useGraphicBuffer(
509        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
510        OMX::buffer_id *buffer) {
511    Mutex::Autolock autoLock(mLock);
512
513    // See if the newer version of the extension is present.
514    OMX_INDEXTYPE index;
515    if (OMX_GetExtensionIndex(
516            mHandle,
517            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
518            &index) == OMX_ErrorNone) {
519        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
520    }
521
522    OMX_STRING name = const_cast<OMX_STRING>(
523        "OMX.google.android.index.useAndroidNativeBuffer");
524    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
525
526    if (err != OMX_ErrorNone) {
527        ALOGE("OMX_GetExtensionIndex %s failed", name);
528
529        return StatusFromOMXError(err);
530    }
531
532    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
533
534    OMX_BUFFERHEADERTYPE *header;
535
536    OMX_VERSIONTYPE ver;
537    ver.s.nVersionMajor = 1;
538    ver.s.nVersionMinor = 0;
539    ver.s.nRevision = 0;
540    ver.s.nStep = 0;
541    UseAndroidNativeBufferParams params = {
542        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
543        &header, graphicBuffer,
544    };
545
546    err = OMX_SetParameter(mHandle, index, &params);
547
548    if (err != OMX_ErrorNone) {
549        ALOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
550                err);
551
552        delete bufferMeta;
553        bufferMeta = NULL;
554
555        *buffer = 0;
556
557        return UNKNOWN_ERROR;
558    }
559
560    CHECK_EQ(header->pAppPrivate, bufferMeta);
561
562    *buffer = header;
563
564    addActiveBuffer(portIndex, *buffer);
565
566    return OK;
567}
568
569status_t OMXNodeInstance::createInputSurface(
570        OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer) {
571    Mutex::Autolock autolock(mLock);
572    status_t err;
573
574    const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
575    if (surfaceCheck != NULL) {
576        return ALREADY_EXISTS;
577    }
578
579    // Input buffers will hold meta-data (gralloc references).
580    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE);
581    if (err != OK) {
582        return err;
583    }
584
585    // Retrieve the width and height of the graphic buffer, set when the
586    // codec was configured.
587    OMX_PARAM_PORTDEFINITIONTYPE def;
588    def.nSize = sizeof(def);
589    def.nVersion.s.nVersionMajor = 1;
590    def.nVersion.s.nVersionMinor = 0;
591    def.nVersion.s.nRevision = 0;
592    def.nVersion.s.nStep = 0;
593    def.nPortIndex = portIndex;
594    OMX_ERRORTYPE oerr = OMX_GetParameter(
595            mHandle, OMX_IndexParamPortDefinition, &def);
596    CHECK(oerr == OMX_ErrorNone);
597
598    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
599        ALOGE("createInputSurface requires COLOR_FormatSurface "
600              "(AndroidOpaque) color format");
601        return INVALID_OPERATION;
602    }
603
604    GraphicBufferSource* bufferSource = new GraphicBufferSource(
605            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
606            def.nBufferCountActual);
607    if ((err = bufferSource->initCheck()) != OK) {
608        delete bufferSource;
609        return err;
610    }
611    setGraphicBufferSource(bufferSource);
612
613    *bufferProducer = bufferSource->getIGraphicBufferProducer();
614    return OK;
615}
616
617status_t OMXNodeInstance::signalEndOfInputStream() {
618    // For non-Surface input, the MediaCodec should convert the call to a
619    // pair of requests (dequeue input buffer, queue input buffer with EOS
620    // flag set).  Seems easier than doing the equivalent from here.
621    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
622    if (bufferSource == NULL) {
623        ALOGW("signalEndOfInputStream can only be used with Surface input");
624        return INVALID_OPERATION;
625    };
626    return bufferSource->signalEndOfInputStream();
627}
628
629status_t OMXNodeInstance::allocateBuffer(
630        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
631        void **buffer_data) {
632    Mutex::Autolock autoLock(mLock);
633
634    BufferMeta *buffer_meta = new BufferMeta(size);
635
636    OMX_BUFFERHEADERTYPE *header;
637
638    OMX_ERRORTYPE err = OMX_AllocateBuffer(
639            mHandle, &header, portIndex, buffer_meta, size);
640
641    if (err != OMX_ErrorNone) {
642        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
643
644        delete buffer_meta;
645        buffer_meta = NULL;
646
647        *buffer = 0;
648
649        return UNKNOWN_ERROR;
650    }
651
652    CHECK_EQ(header->pAppPrivate, buffer_meta);
653
654    *buffer = header;
655    *buffer_data = header->pBuffer;
656
657    addActiveBuffer(portIndex, *buffer);
658
659    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
660    if (bufferSource != NULL && portIndex == kPortIndexInput) {
661        bufferSource->addCodecBuffer(header);
662    }
663
664    return OK;
665}
666
667status_t OMXNodeInstance::allocateBufferWithBackup(
668        OMX_U32 portIndex, const sp<IMemory> &params,
669        OMX::buffer_id *buffer) {
670    Mutex::Autolock autoLock(mLock);
671
672    BufferMeta *buffer_meta = new BufferMeta(params, true);
673
674    OMX_BUFFERHEADERTYPE *header;
675
676    OMX_ERRORTYPE err = OMX_AllocateBuffer(
677            mHandle, &header, portIndex, buffer_meta, params->size());
678
679    if (err != OMX_ErrorNone) {
680        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
681
682        delete buffer_meta;
683        buffer_meta = NULL;
684
685        *buffer = 0;
686
687        return UNKNOWN_ERROR;
688    }
689
690    CHECK_EQ(header->pAppPrivate, buffer_meta);
691
692    *buffer = header;
693
694    addActiveBuffer(portIndex, *buffer);
695
696    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
697    if (bufferSource != NULL && portIndex == kPortIndexInput) {
698        bufferSource->addCodecBuffer(header);
699    }
700
701    return OK;
702}
703
704status_t OMXNodeInstance::freeBuffer(
705        OMX_U32 portIndex, OMX::buffer_id buffer) {
706    Mutex::Autolock autoLock(mLock);
707
708    removeActiveBuffer(portIndex, buffer);
709
710    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
711    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
712
713    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
714
715    delete buffer_meta;
716    buffer_meta = NULL;
717
718    return StatusFromOMXError(err);
719}
720
721status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
722    Mutex::Autolock autoLock(mLock);
723
724    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
725    header->nFilledLen = 0;
726    header->nOffset = 0;
727    header->nFlags = 0;
728
729    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
730
731    return StatusFromOMXError(err);
732}
733
734status_t OMXNodeInstance::emptyBuffer(
735        OMX::buffer_id buffer,
736        OMX_U32 rangeOffset, OMX_U32 rangeLength,
737        OMX_U32 flags, OMX_TICKS timestamp) {
738    Mutex::Autolock autoLock(mLock);
739
740    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
741    header->nFilledLen = rangeLength;
742    header->nOffset = rangeOffset;
743    header->nFlags = flags;
744    header->nTimeStamp = timestamp;
745
746    BufferMeta *buffer_meta =
747        static_cast<BufferMeta *>(header->pAppPrivate);
748    buffer_meta->CopyToOMX(header);
749
750    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
751
752    return StatusFromOMXError(err);
753}
754
755// like emptyBuffer, but the data is already in header->pBuffer
756status_t OMXNodeInstance::emptyDirectBuffer(
757        OMX_BUFFERHEADERTYPE *header,
758        OMX_U32 rangeOffset, OMX_U32 rangeLength,
759        OMX_U32 flags, OMX_TICKS timestamp) {
760    Mutex::Autolock autoLock(mLock);
761
762    header->nFilledLen = rangeLength;
763    header->nOffset = rangeOffset;
764    header->nFlags = flags;
765    header->nTimeStamp = timestamp;
766
767    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
768    if (err != OMX_ErrorNone) {
769        ALOGW("emptyDirectBuffer failed, OMX err=0x%x", err);
770    }
771
772    return StatusFromOMXError(err);
773}
774
775status_t OMXNodeInstance::getExtensionIndex(
776        const char *parameterName, OMX_INDEXTYPE *index) {
777    Mutex::Autolock autoLock(mLock);
778
779    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
780            mHandle, const_cast<char *>(parameterName), index);
781
782    return StatusFromOMXError(err);
783}
784
785status_t OMXNodeInstance::setInternalOption(
786        OMX_U32 portIndex,
787        IOMX::InternalOptionType type,
788        const void *data,
789        size_t size) {
790    switch (type) {
791        case IOMX::INTERNAL_OPTION_SUSPEND:
792        {
793            const sp<GraphicBufferSource> &bufferSource =
794                getGraphicBufferSource();
795
796            if (bufferSource == NULL || portIndex != kPortIndexInput) {
797                return ERROR_UNSUPPORTED;
798            }
799
800            if (size != sizeof(bool)) {
801                return INVALID_OPERATION;
802            }
803
804            bool suspend = *(bool *)data;
805            bufferSource->suspend(suspend);
806
807            return OK;
808        }
809
810        default:
811            return ERROR_UNSUPPORTED;
812    }
813}
814
815void OMXNodeInstance::onMessage(const omx_message &msg) {
816    if (msg.type == omx_message::FILL_BUFFER_DONE) {
817        OMX_BUFFERHEADERTYPE *buffer =
818            static_cast<OMX_BUFFERHEADERTYPE *>(
819                    msg.u.extended_buffer_data.buffer);
820
821        BufferMeta *buffer_meta =
822            static_cast<BufferMeta *>(buffer->pAppPrivate);
823
824        buffer_meta->CopyFromOMX(buffer);
825    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
826        const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
827
828        if (bufferSource != NULL) {
829            // This is one of the buffers used exclusively by
830            // GraphicBufferSource.
831            // Don't dispatch a message back to ACodec, since it doesn't
832            // know that anyone asked to have the buffer emptied and will
833            // be very confused.
834
835            OMX_BUFFERHEADERTYPE *buffer =
836                static_cast<OMX_BUFFERHEADERTYPE *>(
837                        msg.u.buffer_data.buffer);
838
839            bufferSource->codecBufferEmptied(buffer);
840            return;
841        }
842    }
843
844    mObserver->onMessage(msg);
845}
846
847void OMXNodeInstance::onObserverDied(OMXMaster *master) {
848    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
849
850    // Try to force shutdown of the node and hope for the best.
851    freeNode(master);
852}
853
854void OMXNodeInstance::onGetHandleFailed() {
855    delete this;
856}
857
858// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
859// Don't try to acquire mLock here -- in rare circumstances this will hang.
860void OMXNodeInstance::onEvent(
861        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
862    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
863
864    if (bufferSource != NULL
865            && event == OMX_EventCmdComplete
866            && arg1 == OMX_CommandStateSet
867            && arg2 == OMX_StateExecuting) {
868        bufferSource->omxExecuting();
869    }
870}
871
872// static
873OMX_ERRORTYPE OMXNodeInstance::OnEvent(
874        OMX_IN OMX_HANDLETYPE hComponent,
875        OMX_IN OMX_PTR pAppData,
876        OMX_IN OMX_EVENTTYPE eEvent,
877        OMX_IN OMX_U32 nData1,
878        OMX_IN OMX_U32 nData2,
879        OMX_IN OMX_PTR pEventData) {
880    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
881    if (instance->mDying) {
882        return OMX_ErrorNone;
883    }
884    return instance->owner()->OnEvent(
885            instance->nodeID(), eEvent, nData1, nData2, pEventData);
886}
887
888// static
889OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
890        OMX_IN OMX_HANDLETYPE hComponent,
891        OMX_IN OMX_PTR pAppData,
892        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
893    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
894    if (instance->mDying) {
895        return OMX_ErrorNone;
896    }
897    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
898}
899
900// static
901OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
902        OMX_IN OMX_HANDLETYPE hComponent,
903        OMX_IN OMX_PTR pAppData,
904        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
905    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
906    if (instance->mDying) {
907        return OMX_ErrorNone;
908    }
909    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
910}
911
912void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
913    ActiveBuffer active;
914    active.mPortIndex = portIndex;
915    active.mID = id;
916    mActiveBuffers.push(active);
917}
918
919void OMXNodeInstance::removeActiveBuffer(
920        OMX_U32 portIndex, OMX::buffer_id id) {
921    bool found = false;
922    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
923        if (mActiveBuffers[i].mPortIndex == portIndex
924            && mActiveBuffers[i].mID == id) {
925            found = true;
926            mActiveBuffers.removeItemsAt(i);
927            break;
928        }
929    }
930
931    if (!found) {
932        ALOGW("Attempt to remove an active buffer we know nothing about...");
933    }
934}
935
936void OMXNodeInstance::freeActiveBuffers() {
937    // Make sure to count down here, as freeBuffer will in turn remove
938    // the active buffer from the vector...
939    for (size_t i = mActiveBuffers.size(); i--;) {
940        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
941    }
942}
943
944}  // namespace android
945