OMXNodeInstance.cpp revision 56ce726019f700a95ce5b45beebceadae4836e30
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::prepareForAdaptivePlayback(
421        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
422        OMX_U32 maxFrameHeight) {
423    Mutex::Autolock autolock(mLock);
424
425    OMX_INDEXTYPE index;
426    OMX_STRING name = const_cast<OMX_STRING>(
427            "OMX.google.android.index.prepareForAdaptivePlayback");
428
429    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
430    if (err != OMX_ErrorNone) {
431        ALOGW_IF(enable, "OMX_GetExtensionIndex %s failed", name);
432        return StatusFromOMXError(err);
433    }
434
435    PrepareForAdaptivePlaybackParams params;
436    params.nSize = sizeof(params);
437    params.nVersion.s.nVersionMajor = 1;
438    params.nVersion.s.nVersionMinor = 0;
439    params.nVersion.s.nRevision = 0;
440    params.nVersion.s.nStep = 0;
441
442    params.nPortIndex = portIndex;
443    params.bEnable = enable;
444    params.nMaxFrameWidth = maxFrameWidth;
445    params.nMaxFrameHeight = maxFrameHeight;
446    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
447        ALOGW("OMX_SetParameter failed for PrepareForAdaptivePlayback "
448              "with error %d (0x%08x)", err, err);
449        return UNKNOWN_ERROR;
450    }
451    return err;
452}
453
454status_t OMXNodeInstance::useBuffer(
455        OMX_U32 portIndex, const sp<IMemory> &params,
456        OMX::buffer_id *buffer) {
457    Mutex::Autolock autoLock(mLock);
458
459    BufferMeta *buffer_meta = new BufferMeta(params);
460
461    OMX_BUFFERHEADERTYPE *header;
462
463    OMX_ERRORTYPE err = OMX_UseBuffer(
464            mHandle, &header, portIndex, buffer_meta,
465            params->size(), static_cast<OMX_U8 *>(params->pointer()));
466
467    if (err != OMX_ErrorNone) {
468        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
469
470        delete buffer_meta;
471        buffer_meta = NULL;
472
473        *buffer = 0;
474
475        return UNKNOWN_ERROR;
476    }
477
478    CHECK_EQ(header->pAppPrivate, buffer_meta);
479
480    *buffer = header;
481
482    addActiveBuffer(portIndex, *buffer);
483
484    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
485    if (bufferSource != NULL && portIndex == kPortIndexInput) {
486        bufferSource->addCodecBuffer(header);
487    }
488
489    return OK;
490}
491
492status_t OMXNodeInstance::useGraphicBuffer2_l(
493        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
494        OMX::buffer_id *buffer) {
495
496    // port definition
497    OMX_PARAM_PORTDEFINITIONTYPE def;
498    def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
499    def.nVersion.s.nVersionMajor = 1;
500    def.nVersion.s.nVersionMinor = 0;
501    def.nVersion.s.nRevision = 0;
502    def.nVersion.s.nStep = 0;
503    def.nPortIndex = portIndex;
504    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
505    if (err != OMX_ErrorNone)
506    {
507        ALOGE("%s::%d:Error getting OMX_IndexParamPortDefinition", __FUNCTION__, __LINE__);
508        return err;
509    }
510
511    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
512
513    OMX_BUFFERHEADERTYPE *header = NULL;
514    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
515            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
516
517    err = OMX_UseBuffer(
518            mHandle,
519            &header,
520            portIndex,
521            bufferMeta,
522            def.nBufferSize,
523            bufferHandle);
524
525    if (err != OMX_ErrorNone) {
526        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
527        delete bufferMeta;
528        bufferMeta = NULL;
529        *buffer = 0;
530        return UNKNOWN_ERROR;
531    }
532
533    CHECK_EQ(header->pBuffer, bufferHandle);
534    CHECK_EQ(header->pAppPrivate, bufferMeta);
535
536    *buffer = header;
537
538    addActiveBuffer(portIndex, *buffer);
539
540    return OK;
541}
542
543// XXX: This function is here for backwards compatibility.  Once the OMX
544// implementations have been updated this can be removed and useGraphicBuffer2
545// can be renamed to useGraphicBuffer.
546status_t OMXNodeInstance::useGraphicBuffer(
547        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
548        OMX::buffer_id *buffer) {
549    Mutex::Autolock autoLock(mLock);
550
551    // See if the newer version of the extension is present.
552    OMX_INDEXTYPE index;
553    if (OMX_GetExtensionIndex(
554            mHandle,
555            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
556            &index) == OMX_ErrorNone) {
557        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
558    }
559
560    OMX_STRING name = const_cast<OMX_STRING>(
561        "OMX.google.android.index.useAndroidNativeBuffer");
562    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
563
564    if (err != OMX_ErrorNone) {
565        ALOGE("OMX_GetExtensionIndex %s failed", name);
566
567        return StatusFromOMXError(err);
568    }
569
570    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
571
572    OMX_BUFFERHEADERTYPE *header;
573
574    OMX_VERSIONTYPE ver;
575    ver.s.nVersionMajor = 1;
576    ver.s.nVersionMinor = 0;
577    ver.s.nRevision = 0;
578    ver.s.nStep = 0;
579    UseAndroidNativeBufferParams params = {
580        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
581        &header, graphicBuffer,
582    };
583
584    err = OMX_SetParameter(mHandle, index, &params);
585
586    if (err != OMX_ErrorNone) {
587        ALOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
588                err);
589
590        delete bufferMeta;
591        bufferMeta = NULL;
592
593        *buffer = 0;
594
595        return UNKNOWN_ERROR;
596    }
597
598    CHECK_EQ(header->pAppPrivate, bufferMeta);
599
600    *buffer = header;
601
602    addActiveBuffer(portIndex, *buffer);
603
604    return OK;
605}
606
607status_t OMXNodeInstance::updateGraphicBufferInMeta(
608        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
609        OMX::buffer_id buffer) {
610    Mutex::Autolock autoLock(mLock);
611
612    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)(buffer);
613    VideoDecoderOutputMetaData *metadata =
614        (VideoDecoderOutputMetaData *)(header->pBuffer);
615    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
616    bufferMeta->setGraphicBuffer(graphicBuffer);
617    metadata->eType = kMetadataBufferTypeGrallocSource;
618    metadata->pHandle = graphicBuffer->handle;
619
620    return OK;
621}
622
623status_t OMXNodeInstance::createInputSurface(
624        OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer) {
625    Mutex::Autolock autolock(mLock);
626    status_t err;
627
628    const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
629    if (surfaceCheck != NULL) {
630        return ALREADY_EXISTS;
631    }
632
633    // Input buffers will hold meta-data (gralloc references).
634    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE);
635    if (err != OK) {
636        return err;
637    }
638
639    // Retrieve the width and height of the graphic buffer, set when the
640    // codec was configured.
641    OMX_PARAM_PORTDEFINITIONTYPE def;
642    def.nSize = sizeof(def);
643    def.nVersion.s.nVersionMajor = 1;
644    def.nVersion.s.nVersionMinor = 0;
645    def.nVersion.s.nRevision = 0;
646    def.nVersion.s.nStep = 0;
647    def.nPortIndex = portIndex;
648    OMX_ERRORTYPE oerr = OMX_GetParameter(
649            mHandle, OMX_IndexParamPortDefinition, &def);
650    CHECK(oerr == OMX_ErrorNone);
651
652    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
653        ALOGE("createInputSurface requires COLOR_FormatSurface "
654              "(AndroidOpaque) color format");
655        return INVALID_OPERATION;
656    }
657
658    GraphicBufferSource* bufferSource = new GraphicBufferSource(
659            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
660            def.nBufferCountActual);
661    if ((err = bufferSource->initCheck()) != OK) {
662        delete bufferSource;
663        return err;
664    }
665    setGraphicBufferSource(bufferSource);
666
667    *bufferProducer = bufferSource->getIGraphicBufferProducer();
668    return OK;
669}
670
671status_t OMXNodeInstance::signalEndOfInputStream() {
672    // For non-Surface input, the MediaCodec should convert the call to a
673    // pair of requests (dequeue input buffer, queue input buffer with EOS
674    // flag set).  Seems easier than doing the equivalent from here.
675    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
676    if (bufferSource == NULL) {
677        ALOGW("signalEndOfInputStream can only be used with Surface input");
678        return INVALID_OPERATION;
679    };
680    return bufferSource->signalEndOfInputStream();
681}
682
683status_t OMXNodeInstance::allocateBuffer(
684        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
685        void **buffer_data) {
686    Mutex::Autolock autoLock(mLock);
687
688    BufferMeta *buffer_meta = new BufferMeta(size);
689
690    OMX_BUFFERHEADERTYPE *header;
691
692    OMX_ERRORTYPE err = OMX_AllocateBuffer(
693            mHandle, &header, portIndex, buffer_meta, size);
694
695    if (err != OMX_ErrorNone) {
696        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
697
698        delete buffer_meta;
699        buffer_meta = NULL;
700
701        *buffer = 0;
702
703        return UNKNOWN_ERROR;
704    }
705
706    CHECK_EQ(header->pAppPrivate, buffer_meta);
707
708    *buffer = header;
709    *buffer_data = header->pBuffer;
710
711    addActiveBuffer(portIndex, *buffer);
712
713    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
714    if (bufferSource != NULL && portIndex == kPortIndexInput) {
715        bufferSource->addCodecBuffer(header);
716    }
717
718    return OK;
719}
720
721status_t OMXNodeInstance::allocateBufferWithBackup(
722        OMX_U32 portIndex, const sp<IMemory> &params,
723        OMX::buffer_id *buffer) {
724    Mutex::Autolock autoLock(mLock);
725
726    BufferMeta *buffer_meta = new BufferMeta(params, true);
727
728    OMX_BUFFERHEADERTYPE *header;
729
730    OMX_ERRORTYPE err = OMX_AllocateBuffer(
731            mHandle, &header, portIndex, buffer_meta, params->size());
732
733    if (err != OMX_ErrorNone) {
734        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
735
736        delete buffer_meta;
737        buffer_meta = NULL;
738
739        *buffer = 0;
740
741        return UNKNOWN_ERROR;
742    }
743
744    CHECK_EQ(header->pAppPrivate, buffer_meta);
745
746    *buffer = header;
747
748    addActiveBuffer(portIndex, *buffer);
749
750    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
751    if (bufferSource != NULL && portIndex == kPortIndexInput) {
752        bufferSource->addCodecBuffer(header);
753    }
754
755    return OK;
756}
757
758status_t OMXNodeInstance::freeBuffer(
759        OMX_U32 portIndex, OMX::buffer_id buffer) {
760    Mutex::Autolock autoLock(mLock);
761
762    removeActiveBuffer(portIndex, buffer);
763
764    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
765    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
766
767    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
768
769    delete buffer_meta;
770    buffer_meta = NULL;
771
772    return StatusFromOMXError(err);
773}
774
775status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
776    Mutex::Autolock autoLock(mLock);
777
778    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
779    header->nFilledLen = 0;
780    header->nOffset = 0;
781    header->nFlags = 0;
782
783    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
784
785    return StatusFromOMXError(err);
786}
787
788status_t OMXNodeInstance::emptyBuffer(
789        OMX::buffer_id buffer,
790        OMX_U32 rangeOffset, OMX_U32 rangeLength,
791        OMX_U32 flags, OMX_TICKS timestamp) {
792    Mutex::Autolock autoLock(mLock);
793
794    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
795    header->nFilledLen = rangeLength;
796    header->nOffset = rangeOffset;
797    header->nFlags = flags;
798    header->nTimeStamp = timestamp;
799
800    BufferMeta *buffer_meta =
801        static_cast<BufferMeta *>(header->pAppPrivate);
802    buffer_meta->CopyToOMX(header);
803
804    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
805
806    return StatusFromOMXError(err);
807}
808
809// like emptyBuffer, but the data is already in header->pBuffer
810status_t OMXNodeInstance::emptyDirectBuffer(
811        OMX_BUFFERHEADERTYPE *header,
812        OMX_U32 rangeOffset, OMX_U32 rangeLength,
813        OMX_U32 flags, OMX_TICKS timestamp) {
814    Mutex::Autolock autoLock(mLock);
815
816    header->nFilledLen = rangeLength;
817    header->nOffset = rangeOffset;
818    header->nFlags = flags;
819    header->nTimeStamp = timestamp;
820
821    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
822    if (err != OMX_ErrorNone) {
823        ALOGW("emptyDirectBuffer failed, OMX err=0x%x", err);
824    }
825
826    return StatusFromOMXError(err);
827}
828
829status_t OMXNodeInstance::getExtensionIndex(
830        const char *parameterName, OMX_INDEXTYPE *index) {
831    Mutex::Autolock autoLock(mLock);
832
833    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
834            mHandle, const_cast<char *>(parameterName), index);
835
836    return StatusFromOMXError(err);
837}
838
839status_t OMXNodeInstance::setInternalOption(
840        OMX_U32 portIndex,
841        IOMX::InternalOptionType type,
842        const void *data,
843        size_t size) {
844    switch (type) {
845        case IOMX::INTERNAL_OPTION_SUSPEND:
846        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
847        {
848            const sp<GraphicBufferSource> &bufferSource =
849                getGraphicBufferSource();
850
851            if (bufferSource == NULL || portIndex != kPortIndexInput) {
852                return ERROR_UNSUPPORTED;
853            }
854
855            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
856                if (size != sizeof(bool)) {
857                    return INVALID_OPERATION;
858                }
859
860                bool suspend = *(bool *)data;
861                bufferSource->suspend(suspend);
862            } else {
863                if (size != sizeof(int64_t)) {
864                    return INVALID_OPERATION;
865                }
866
867                int64_t delayUs = *(int64_t *)data;
868
869                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
870            }
871
872            return OK;
873        }
874
875        default:
876            return ERROR_UNSUPPORTED;
877    }
878}
879
880void OMXNodeInstance::onMessage(const omx_message &msg) {
881    if (msg.type == omx_message::FILL_BUFFER_DONE) {
882        OMX_BUFFERHEADERTYPE *buffer =
883            static_cast<OMX_BUFFERHEADERTYPE *>(
884                    msg.u.extended_buffer_data.buffer);
885
886        BufferMeta *buffer_meta =
887            static_cast<BufferMeta *>(buffer->pAppPrivate);
888
889        buffer_meta->CopyFromOMX(buffer);
890    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
891        const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
892
893        if (bufferSource != NULL) {
894            // This is one of the buffers used exclusively by
895            // GraphicBufferSource.
896            // Don't dispatch a message back to ACodec, since it doesn't
897            // know that anyone asked to have the buffer emptied and will
898            // be very confused.
899
900            OMX_BUFFERHEADERTYPE *buffer =
901                static_cast<OMX_BUFFERHEADERTYPE *>(
902                        msg.u.buffer_data.buffer);
903
904            bufferSource->codecBufferEmptied(buffer);
905            return;
906        }
907    }
908
909    mObserver->onMessage(msg);
910}
911
912void OMXNodeInstance::onObserverDied(OMXMaster *master) {
913    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
914
915    // Try to force shutdown of the node and hope for the best.
916    freeNode(master);
917}
918
919void OMXNodeInstance::onGetHandleFailed() {
920    delete this;
921}
922
923// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
924// Don't try to acquire mLock here -- in rare circumstances this will hang.
925void OMXNodeInstance::onEvent(
926        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
927    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
928
929    if (bufferSource != NULL
930            && event == OMX_EventCmdComplete
931            && arg1 == OMX_CommandStateSet
932            && arg2 == OMX_StateExecuting) {
933        bufferSource->omxExecuting();
934    }
935}
936
937// static
938OMX_ERRORTYPE OMXNodeInstance::OnEvent(
939        OMX_IN OMX_HANDLETYPE hComponent,
940        OMX_IN OMX_PTR pAppData,
941        OMX_IN OMX_EVENTTYPE eEvent,
942        OMX_IN OMX_U32 nData1,
943        OMX_IN OMX_U32 nData2,
944        OMX_IN OMX_PTR pEventData) {
945    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
946    if (instance->mDying) {
947        return OMX_ErrorNone;
948    }
949    return instance->owner()->OnEvent(
950            instance->nodeID(), eEvent, nData1, nData2, pEventData);
951}
952
953// static
954OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
955        OMX_IN OMX_HANDLETYPE hComponent,
956        OMX_IN OMX_PTR pAppData,
957        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
958    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
959    if (instance->mDying) {
960        return OMX_ErrorNone;
961    }
962    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
963}
964
965// static
966OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
967        OMX_IN OMX_HANDLETYPE hComponent,
968        OMX_IN OMX_PTR pAppData,
969        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
970    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
971    if (instance->mDying) {
972        return OMX_ErrorNone;
973    }
974    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
975}
976
977void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
978    ActiveBuffer active;
979    active.mPortIndex = portIndex;
980    active.mID = id;
981    mActiveBuffers.push(active);
982}
983
984void OMXNodeInstance::removeActiveBuffer(
985        OMX_U32 portIndex, OMX::buffer_id id) {
986    bool found = false;
987    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
988        if (mActiveBuffers[i].mPortIndex == portIndex
989            && mActiveBuffers[i].mID == id) {
990            found = true;
991            mActiveBuffers.removeItemsAt(i);
992            break;
993        }
994    }
995
996    if (!found) {
997        ALOGW("Attempt to remove an active buffer we know nothing about...");
998    }
999}
1000
1001void OMXNodeInstance::freeActiveBuffers() {
1002    // Make sure to count down here, as freeBuffer will in turn remove
1003    // the active buffer from the vector...
1004    for (size_t i = mActiveBuffers.size(); i--;) {
1005        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
1006    }
1007}
1008
1009}  // namespace android
1010