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