OMXNodeInstance.cpp revision e40cda70eec141fa05cbcca1de420fdb22b98be6
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 AndroidOpaque color format");
600        return INVALID_OPERATION;
601    }
602
603    GraphicBufferSource* bufferSource = new GraphicBufferSource(
604            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
605            def.nBufferCountActual);
606    if ((err = bufferSource->initCheck()) != OK) {
607        delete bufferSource;
608        return err;
609    }
610    setGraphicBufferSource(bufferSource);
611
612    *bufferProducer = bufferSource->getIGraphicBufferProducer();
613    return OK;
614}
615
616status_t OMXNodeInstance::signalEndOfInputStream() {
617    // For non-Surface input, the MediaCodec should convert the call to a
618    // pair of requests (dequeue input buffer, queue input buffer with EOS
619    // flag set).  Seems easier than doing the equivalent from here.
620    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
621    if (bufferSource == NULL) {
622        ALOGW("signalEndOfInputStream can only be used with Surface input");
623        return INVALID_OPERATION;
624    };
625    return bufferSource->signalEndOfInputStream();
626}
627
628status_t OMXNodeInstance::allocateBuffer(
629        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
630        void **buffer_data) {
631    Mutex::Autolock autoLock(mLock);
632
633    BufferMeta *buffer_meta = new BufferMeta(size);
634
635    OMX_BUFFERHEADERTYPE *header;
636
637    OMX_ERRORTYPE err = OMX_AllocateBuffer(
638            mHandle, &header, portIndex, buffer_meta, size);
639
640    if (err != OMX_ErrorNone) {
641        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
642
643        delete buffer_meta;
644        buffer_meta = NULL;
645
646        *buffer = 0;
647
648        return UNKNOWN_ERROR;
649    }
650
651    CHECK_EQ(header->pAppPrivate, buffer_meta);
652
653    *buffer = header;
654    *buffer_data = header->pBuffer;
655
656    addActiveBuffer(portIndex, *buffer);
657
658    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
659    if (bufferSource != NULL && portIndex == kPortIndexInput) {
660        bufferSource->addCodecBuffer(header);
661    }
662
663    return OK;
664}
665
666status_t OMXNodeInstance::allocateBufferWithBackup(
667        OMX_U32 portIndex, const sp<IMemory> &params,
668        OMX::buffer_id *buffer) {
669    Mutex::Autolock autoLock(mLock);
670
671    BufferMeta *buffer_meta = new BufferMeta(params, true);
672
673    OMX_BUFFERHEADERTYPE *header;
674
675    OMX_ERRORTYPE err = OMX_AllocateBuffer(
676            mHandle, &header, portIndex, buffer_meta, params->size());
677
678    if (err != OMX_ErrorNone) {
679        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
680
681        delete buffer_meta;
682        buffer_meta = NULL;
683
684        *buffer = 0;
685
686        return UNKNOWN_ERROR;
687    }
688
689    CHECK_EQ(header->pAppPrivate, buffer_meta);
690
691    *buffer = header;
692
693    addActiveBuffer(portIndex, *buffer);
694
695    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
696    if (bufferSource != NULL && portIndex == kPortIndexInput) {
697        bufferSource->addCodecBuffer(header);
698    }
699
700    return OK;
701}
702
703status_t OMXNodeInstance::freeBuffer(
704        OMX_U32 portIndex, OMX::buffer_id buffer) {
705    Mutex::Autolock autoLock(mLock);
706
707    removeActiveBuffer(portIndex, buffer);
708
709    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
710    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
711
712    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
713
714    delete buffer_meta;
715    buffer_meta = NULL;
716
717    return StatusFromOMXError(err);
718}
719
720status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
721    Mutex::Autolock autoLock(mLock);
722
723    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
724    header->nFilledLen = 0;
725    header->nOffset = 0;
726    header->nFlags = 0;
727
728    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
729
730    return StatusFromOMXError(err);
731}
732
733status_t OMXNodeInstance::emptyBuffer(
734        OMX::buffer_id buffer,
735        OMX_U32 rangeOffset, OMX_U32 rangeLength,
736        OMX_U32 flags, OMX_TICKS timestamp) {
737    Mutex::Autolock autoLock(mLock);
738
739    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
740    header->nFilledLen = rangeLength;
741    header->nOffset = rangeOffset;
742    header->nFlags = flags;
743    header->nTimeStamp = timestamp;
744
745    BufferMeta *buffer_meta =
746        static_cast<BufferMeta *>(header->pAppPrivate);
747    buffer_meta->CopyToOMX(header);
748
749    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
750
751    return StatusFromOMXError(err);
752}
753
754// like emptyBuffer, but the data is already in header->pBuffer
755status_t OMXNodeInstance::emptyDirectBuffer(
756        OMX_BUFFERHEADERTYPE *header,
757        OMX_U32 rangeOffset, OMX_U32 rangeLength,
758        OMX_U32 flags, OMX_TICKS timestamp) {
759    Mutex::Autolock autoLock(mLock);
760
761    header->nFilledLen = rangeLength;
762    header->nOffset = rangeOffset;
763    header->nFlags = flags;
764    header->nTimeStamp = timestamp;
765
766    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
767    if (err != OMX_ErrorNone) {
768        ALOGW("emptyDirectBuffer failed, OMX err=0x%x", err);
769    }
770
771    return StatusFromOMXError(err);
772}
773
774status_t OMXNodeInstance::getExtensionIndex(
775        const char *parameterName, OMX_INDEXTYPE *index) {
776    Mutex::Autolock autoLock(mLock);
777
778    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
779            mHandle, const_cast<char *>(parameterName), index);
780
781    return StatusFromOMXError(err);
782}
783
784status_t OMXNodeInstance::setInternalOption(
785        OMX_U32 portIndex,
786        IOMX::InternalOptionType type,
787        const void *data,
788        size_t size) {
789    switch (type) {
790        case IOMX::INTERNAL_OPTION_SUSPEND:
791        {
792            const sp<GraphicBufferSource> &bufferSource =
793                getGraphicBufferSource();
794
795            if (bufferSource == NULL || portIndex != kPortIndexInput) {
796                return ERROR_UNSUPPORTED;
797            }
798
799            if (size != sizeof(bool)) {
800                return INVALID_OPERATION;
801            }
802
803            bool suspend = *(bool *)data;
804            bufferSource->suspend(suspend);
805
806            return OK;
807        }
808
809        default:
810            return ERROR_UNSUPPORTED;
811    }
812}
813
814void OMXNodeInstance::onMessage(const omx_message &msg) {
815    if (msg.type == omx_message::FILL_BUFFER_DONE) {
816        OMX_BUFFERHEADERTYPE *buffer =
817            static_cast<OMX_BUFFERHEADERTYPE *>(
818                    msg.u.extended_buffer_data.buffer);
819
820        BufferMeta *buffer_meta =
821            static_cast<BufferMeta *>(buffer->pAppPrivate);
822
823        buffer_meta->CopyFromOMX(buffer);
824    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
825        const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
826
827        if (bufferSource != NULL) {
828            // This is one of the buffers used exclusively by
829            // GraphicBufferSource.
830            // Don't dispatch a message back to ACodec, since it doesn't
831            // know that anyone asked to have the buffer emptied and will
832            // be very confused.
833
834            OMX_BUFFERHEADERTYPE *buffer =
835                static_cast<OMX_BUFFERHEADERTYPE *>(
836                        msg.u.buffer_data.buffer);
837
838            bufferSource->codecBufferEmptied(buffer);
839            return;
840        }
841    }
842
843    mObserver->onMessage(msg);
844}
845
846void OMXNodeInstance::onObserverDied(OMXMaster *master) {
847    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
848
849    // Try to force shutdown of the node and hope for the best.
850    freeNode(master);
851}
852
853void OMXNodeInstance::onGetHandleFailed() {
854    delete this;
855}
856
857// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
858// Don't try to acquire mLock here -- in rare circumstances this will hang.
859void OMXNodeInstance::onEvent(
860        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
861    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
862
863    if (bufferSource != NULL
864            && event == OMX_EventCmdComplete
865            && arg1 == OMX_CommandStateSet
866            && arg2 == OMX_StateExecuting) {
867        bufferSource->omxExecuting();
868    }
869}
870
871// static
872OMX_ERRORTYPE OMXNodeInstance::OnEvent(
873        OMX_IN OMX_HANDLETYPE hComponent,
874        OMX_IN OMX_PTR pAppData,
875        OMX_IN OMX_EVENTTYPE eEvent,
876        OMX_IN OMX_U32 nData1,
877        OMX_IN OMX_U32 nData2,
878        OMX_IN OMX_PTR pEventData) {
879    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
880    if (instance->mDying) {
881        return OMX_ErrorNone;
882    }
883    return instance->owner()->OnEvent(
884            instance->nodeID(), eEvent, nData1, nData2, pEventData);
885}
886
887// static
888OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
889        OMX_IN OMX_HANDLETYPE hComponent,
890        OMX_IN OMX_PTR pAppData,
891        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
892    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
893    if (instance->mDying) {
894        return OMX_ErrorNone;
895    }
896    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
897}
898
899// static
900OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
901        OMX_IN OMX_HANDLETYPE hComponent,
902        OMX_IN OMX_PTR pAppData,
903        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
904    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
905    if (instance->mDying) {
906        return OMX_ErrorNone;
907    }
908    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
909}
910
911void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
912    ActiveBuffer active;
913    active.mPortIndex = portIndex;
914    active.mID = id;
915    mActiveBuffers.push(active);
916}
917
918void OMXNodeInstance::removeActiveBuffer(
919        OMX_U32 portIndex, OMX::buffer_id id) {
920    bool found = false;
921    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
922        if (mActiveBuffers[i].mPortIndex == portIndex
923            && mActiveBuffers[i].mID == id) {
924            found = true;
925            mActiveBuffers.removeItemsAt(i);
926            break;
927        }
928    }
929
930    if (!found) {
931        ALOGW("Attempt to remove an active buffer we know nothing about...");
932    }
933}
934
935void OMXNodeInstance::freeActiveBuffers() {
936    // Make sure to count down here, as freeBuffer will in turn remove
937    // the active buffer from the vector...
938    for (size_t i = mActiveBuffers.size(); i--;) {
939        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
940    }
941}
942
943}  // namespace android
944