OMXNodeInstance.cpp revision dc6ac201032d0f6ad0c8149ae2f009ec38693025
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 && cmd == OMX_CommandStateSet) {
247        if (param == OMX_StateIdle) {
248            // Initiating transition from Executing -> Idle
249            // ACodec is waiting for all buffers to be returned, do NOT
250            // submit any more buffers to the codec.
251            bufferSource->omxIdle();
252        } else if (param == OMX_StateLoaded) {
253            // Initiating transition from Idle/Executing -> Loaded
254            // Buffers are about to be freed.
255            bufferSource->omxLoaded();
256            setGraphicBufferSource(NULL);
257        }
258
259        // fall through
260    }
261
262    Mutex::Autolock autoLock(mLock);
263
264    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
265    return StatusFromOMXError(err);
266}
267
268status_t OMXNodeInstance::getParameter(
269        OMX_INDEXTYPE index, void *params, size_t /* size */) {
270    Mutex::Autolock autoLock(mLock);
271
272    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
273
274    return StatusFromOMXError(err);
275}
276
277status_t OMXNodeInstance::setParameter(
278        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
279    Mutex::Autolock autoLock(mLock);
280
281    OMX_ERRORTYPE err = OMX_SetParameter(
282            mHandle, index, const_cast<void *>(params));
283
284    return StatusFromOMXError(err);
285}
286
287status_t OMXNodeInstance::getConfig(
288        OMX_INDEXTYPE index, void *params, size_t /* size */) {
289    Mutex::Autolock autoLock(mLock);
290
291    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
292    return StatusFromOMXError(err);
293}
294
295status_t OMXNodeInstance::setConfig(
296        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
297    Mutex::Autolock autoLock(mLock);
298
299    OMX_ERRORTYPE err = OMX_SetConfig(
300            mHandle, index, const_cast<void *>(params));
301
302    return StatusFromOMXError(err);
303}
304
305status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
306    Mutex::Autolock autoLock(mLock);
307
308    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
309
310    return StatusFromOMXError(err);
311}
312
313status_t OMXNodeInstance::enableGraphicBuffers(
314        OMX_U32 portIndex, OMX_BOOL enable) {
315    Mutex::Autolock autoLock(mLock);
316    OMX_STRING name = const_cast<OMX_STRING>(
317            "OMX.google.android.index.enableAndroidNativeBuffers");
318
319    OMX_INDEXTYPE index;
320    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
321
322    if (err != OMX_ErrorNone) {
323        if (enable) {
324            ALOGE("OMX_GetExtensionIndex %s failed", name);
325        }
326
327        return StatusFromOMXError(err);
328    }
329
330    OMX_VERSIONTYPE ver;
331    ver.s.nVersionMajor = 1;
332    ver.s.nVersionMinor = 0;
333    ver.s.nRevision = 0;
334    ver.s.nStep = 0;
335    EnableAndroidNativeBuffersParams params = {
336        sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
337    };
338
339    err = OMX_SetParameter(mHandle, index, &params);
340
341    if (err != OMX_ErrorNone) {
342        ALOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
343                err, err);
344
345        return UNKNOWN_ERROR;
346    }
347
348    return OK;
349}
350
351status_t OMXNodeInstance::getGraphicBufferUsage(
352        OMX_U32 portIndex, OMX_U32* usage) {
353    Mutex::Autolock autoLock(mLock);
354
355    OMX_INDEXTYPE index;
356    OMX_STRING name = const_cast<OMX_STRING>(
357            "OMX.google.android.index.getAndroidNativeBufferUsage");
358    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
359
360    if (err != OMX_ErrorNone) {
361        ALOGE("OMX_GetExtensionIndex %s failed", name);
362
363        return StatusFromOMXError(err);
364    }
365
366    OMX_VERSIONTYPE ver;
367    ver.s.nVersionMajor = 1;
368    ver.s.nVersionMinor = 0;
369    ver.s.nRevision = 0;
370    ver.s.nStep = 0;
371    GetAndroidNativeBufferUsageParams params = {
372        sizeof(GetAndroidNativeBufferUsageParams), ver, portIndex, 0,
373    };
374
375    err = OMX_GetParameter(mHandle, index, &params);
376
377    if (err != OMX_ErrorNone) {
378        ALOGE("OMX_GetAndroidNativeBufferUsage failed with error %d (0x%08x)",
379                err, err);
380        return UNKNOWN_ERROR;
381    }
382
383    *usage = params.nUsage;
384
385    return OK;
386}
387
388status_t OMXNodeInstance::storeMetaDataInBuffers(
389        OMX_U32 portIndex,
390        OMX_BOOL enable) {
391    Mutex::Autolock autolock(mLock);
392    return storeMetaDataInBuffers_l(portIndex, enable);
393}
394
395status_t OMXNodeInstance::storeMetaDataInBuffers_l(
396        OMX_U32 portIndex,
397        OMX_BOOL enable) {
398    OMX_INDEXTYPE index;
399    OMX_STRING name = const_cast<OMX_STRING>(
400            "OMX.google.android.index.storeMetaDataInBuffers");
401
402    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
403    if (err != OMX_ErrorNone) {
404        ALOGE("OMX_GetExtensionIndex %s failed", name);
405
406        return StatusFromOMXError(err);
407    }
408
409    StoreMetaDataInBuffersParams params;
410    memset(&params, 0, sizeof(params));
411    params.nSize = sizeof(params);
412
413    // Version: 1.0.0.0
414    params.nVersion.s.nVersionMajor = 1;
415
416    params.nPortIndex = portIndex;
417    params.bStoreMetaData = enable;
418    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
419        ALOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err);
420        return UNKNOWN_ERROR;
421    }
422    return err;
423}
424
425status_t OMXNodeInstance::prepareForAdaptivePlayback(
426        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
427        OMX_U32 maxFrameHeight) {
428    Mutex::Autolock autolock(mLock);
429
430    OMX_INDEXTYPE index;
431    OMX_STRING name = const_cast<OMX_STRING>(
432            "OMX.google.android.index.prepareForAdaptivePlayback");
433
434    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
435    if (err != OMX_ErrorNone) {
436        ALOGW_IF(enable, "OMX_GetExtensionIndex %s failed", name);
437        return StatusFromOMXError(err);
438    }
439
440    PrepareForAdaptivePlaybackParams params;
441    params.nSize = sizeof(params);
442    params.nVersion.s.nVersionMajor = 1;
443    params.nVersion.s.nVersionMinor = 0;
444    params.nVersion.s.nRevision = 0;
445    params.nVersion.s.nStep = 0;
446
447    params.nPortIndex = portIndex;
448    params.bEnable = enable;
449    params.nMaxFrameWidth = maxFrameWidth;
450    params.nMaxFrameHeight = maxFrameHeight;
451    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
452        ALOGW("OMX_SetParameter failed for PrepareForAdaptivePlayback "
453              "with error %d (0x%08x)", err, err);
454        return UNKNOWN_ERROR;
455    }
456    return err;
457}
458
459status_t OMXNodeInstance::useBuffer(
460        OMX_U32 portIndex, const sp<IMemory> &params,
461        OMX::buffer_id *buffer) {
462    Mutex::Autolock autoLock(mLock);
463
464    BufferMeta *buffer_meta = new BufferMeta(params);
465
466    OMX_BUFFERHEADERTYPE *header;
467
468    OMX_ERRORTYPE err = OMX_UseBuffer(
469            mHandle, &header, portIndex, buffer_meta,
470            params->size(), static_cast<OMX_U8 *>(params->pointer()));
471
472    if (err != OMX_ErrorNone) {
473        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
474
475        delete buffer_meta;
476        buffer_meta = NULL;
477
478        *buffer = 0;
479
480        return UNKNOWN_ERROR;
481    }
482
483    CHECK_EQ(header->pAppPrivate, buffer_meta);
484
485    *buffer = header;
486
487    addActiveBuffer(portIndex, *buffer);
488
489    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
490    if (bufferSource != NULL && portIndex == kPortIndexInput) {
491        bufferSource->addCodecBuffer(header);
492    }
493
494    return OK;
495}
496
497status_t OMXNodeInstance::useGraphicBuffer2_l(
498        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
499        OMX::buffer_id *buffer) {
500
501    // port definition
502    OMX_PARAM_PORTDEFINITIONTYPE def;
503    def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
504    def.nVersion.s.nVersionMajor = 1;
505    def.nVersion.s.nVersionMinor = 0;
506    def.nVersion.s.nRevision = 0;
507    def.nVersion.s.nStep = 0;
508    def.nPortIndex = portIndex;
509    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
510    if (err != OMX_ErrorNone)
511    {
512        ALOGE("%s::%d:Error getting OMX_IndexParamPortDefinition", __FUNCTION__, __LINE__);
513        return err;
514    }
515
516    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
517
518    OMX_BUFFERHEADERTYPE *header = NULL;
519    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
520            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
521
522    err = OMX_UseBuffer(
523            mHandle,
524            &header,
525            portIndex,
526            bufferMeta,
527            def.nBufferSize,
528            bufferHandle);
529
530    if (err != OMX_ErrorNone) {
531        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
532        delete bufferMeta;
533        bufferMeta = NULL;
534        *buffer = 0;
535        return UNKNOWN_ERROR;
536    }
537
538    CHECK_EQ(header->pBuffer, bufferHandle);
539    CHECK_EQ(header->pAppPrivate, bufferMeta);
540
541    *buffer = header;
542
543    addActiveBuffer(portIndex, *buffer);
544
545    return OK;
546}
547
548// XXX: This function is here for backwards compatibility.  Once the OMX
549// implementations have been updated this can be removed and useGraphicBuffer2
550// can be renamed to useGraphicBuffer.
551status_t OMXNodeInstance::useGraphicBuffer(
552        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
553        OMX::buffer_id *buffer) {
554    Mutex::Autolock autoLock(mLock);
555
556    // See if the newer version of the extension is present.
557    OMX_INDEXTYPE index;
558    if (OMX_GetExtensionIndex(
559            mHandle,
560            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
561            &index) == OMX_ErrorNone) {
562        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
563    }
564
565    OMX_STRING name = const_cast<OMX_STRING>(
566        "OMX.google.android.index.useAndroidNativeBuffer");
567    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
568
569    if (err != OMX_ErrorNone) {
570        ALOGE("OMX_GetExtensionIndex %s failed", name);
571
572        return StatusFromOMXError(err);
573    }
574
575    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
576
577    OMX_BUFFERHEADERTYPE *header;
578
579    OMX_VERSIONTYPE ver;
580    ver.s.nVersionMajor = 1;
581    ver.s.nVersionMinor = 0;
582    ver.s.nRevision = 0;
583    ver.s.nStep = 0;
584    UseAndroidNativeBufferParams params = {
585        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
586        &header, graphicBuffer,
587    };
588
589    err = OMX_SetParameter(mHandle, index, &params);
590
591    if (err != OMX_ErrorNone) {
592        ALOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
593                err);
594
595        delete bufferMeta;
596        bufferMeta = NULL;
597
598        *buffer = 0;
599
600        return UNKNOWN_ERROR;
601    }
602
603    CHECK_EQ(header->pAppPrivate, bufferMeta);
604
605    *buffer = header;
606
607    addActiveBuffer(portIndex, *buffer);
608
609    return OK;
610}
611
612status_t OMXNodeInstance::updateGraphicBufferInMeta(
613        OMX_U32 /* portIndex */, const sp<GraphicBuffer>& graphicBuffer,
614        OMX::buffer_id buffer) {
615    Mutex::Autolock autoLock(mLock);
616
617    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)(buffer);
618    VideoDecoderOutputMetaData *metadata =
619        (VideoDecoderOutputMetaData *)(header->pBuffer);
620    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
621    bufferMeta->setGraphicBuffer(graphicBuffer);
622    metadata->eType = kMetadataBufferTypeGrallocSource;
623    metadata->pHandle = graphicBuffer->handle;
624
625    return OK;
626}
627
628status_t OMXNodeInstance::createInputSurface(
629        OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer) {
630    Mutex::Autolock autolock(mLock);
631    status_t err;
632
633    const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
634    if (surfaceCheck != NULL) {
635        return ALREADY_EXISTS;
636    }
637
638    // Input buffers will hold meta-data (gralloc references).
639    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE);
640    if (err != OK) {
641        return err;
642    }
643
644    // Retrieve the width and height of the graphic buffer, set when the
645    // codec was configured.
646    OMX_PARAM_PORTDEFINITIONTYPE def;
647    def.nSize = sizeof(def);
648    def.nVersion.s.nVersionMajor = 1;
649    def.nVersion.s.nVersionMinor = 0;
650    def.nVersion.s.nRevision = 0;
651    def.nVersion.s.nStep = 0;
652    def.nPortIndex = portIndex;
653    OMX_ERRORTYPE oerr = OMX_GetParameter(
654            mHandle, OMX_IndexParamPortDefinition, &def);
655    CHECK(oerr == OMX_ErrorNone);
656
657    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
658        ALOGE("createInputSurface requires COLOR_FormatSurface "
659              "(AndroidOpaque) color format");
660        return INVALID_OPERATION;
661    }
662
663    GraphicBufferSource* bufferSource = new GraphicBufferSource(
664            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
665            def.nBufferCountActual);
666    if ((err = bufferSource->initCheck()) != OK) {
667        delete bufferSource;
668        return err;
669    }
670    setGraphicBufferSource(bufferSource);
671
672    *bufferProducer = bufferSource->getIGraphicBufferProducer();
673    return OK;
674}
675
676status_t OMXNodeInstance::signalEndOfInputStream() {
677    // For non-Surface input, the MediaCodec should convert the call to a
678    // pair of requests (dequeue input buffer, queue input buffer with EOS
679    // flag set).  Seems easier than doing the equivalent from here.
680    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
681    if (bufferSource == NULL) {
682        ALOGW("signalEndOfInputStream can only be used with Surface input");
683        return INVALID_OPERATION;
684    };
685    return bufferSource->signalEndOfInputStream();
686}
687
688status_t OMXNodeInstance::allocateBuffer(
689        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
690        void **buffer_data) {
691    Mutex::Autolock autoLock(mLock);
692
693    BufferMeta *buffer_meta = new BufferMeta(size);
694
695    OMX_BUFFERHEADERTYPE *header;
696
697    OMX_ERRORTYPE err = OMX_AllocateBuffer(
698            mHandle, &header, portIndex, buffer_meta, size);
699
700    if (err != OMX_ErrorNone) {
701        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
702
703        delete buffer_meta;
704        buffer_meta = NULL;
705
706        *buffer = 0;
707
708        return UNKNOWN_ERROR;
709    }
710
711    CHECK_EQ(header->pAppPrivate, buffer_meta);
712
713    *buffer = header;
714    *buffer_data = header->pBuffer;
715
716    addActiveBuffer(portIndex, *buffer);
717
718    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
719    if (bufferSource != NULL && portIndex == kPortIndexInput) {
720        bufferSource->addCodecBuffer(header);
721    }
722
723    return OK;
724}
725
726status_t OMXNodeInstance::allocateBufferWithBackup(
727        OMX_U32 portIndex, const sp<IMemory> &params,
728        OMX::buffer_id *buffer) {
729    Mutex::Autolock autoLock(mLock);
730
731    BufferMeta *buffer_meta = new BufferMeta(params, true);
732
733    OMX_BUFFERHEADERTYPE *header;
734
735    OMX_ERRORTYPE err = OMX_AllocateBuffer(
736            mHandle, &header, portIndex, buffer_meta, params->size());
737
738    if (err != OMX_ErrorNone) {
739        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
740
741        delete buffer_meta;
742        buffer_meta = NULL;
743
744        *buffer = 0;
745
746        return UNKNOWN_ERROR;
747    }
748
749    CHECK_EQ(header->pAppPrivate, buffer_meta);
750
751    *buffer = header;
752
753    addActiveBuffer(portIndex, *buffer);
754
755    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
756    if (bufferSource != NULL && portIndex == kPortIndexInput) {
757        bufferSource->addCodecBuffer(header);
758    }
759
760    return OK;
761}
762
763status_t OMXNodeInstance::freeBuffer(
764        OMX_U32 portIndex, OMX::buffer_id buffer) {
765    Mutex::Autolock autoLock(mLock);
766
767    removeActiveBuffer(portIndex, buffer);
768
769    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
770    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
771
772    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
773
774    delete buffer_meta;
775    buffer_meta = NULL;
776
777    return StatusFromOMXError(err);
778}
779
780status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
781    Mutex::Autolock autoLock(mLock);
782
783    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
784    header->nFilledLen = 0;
785    header->nOffset = 0;
786    header->nFlags = 0;
787
788    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
789
790    return StatusFromOMXError(err);
791}
792
793status_t OMXNodeInstance::emptyBuffer(
794        OMX::buffer_id buffer,
795        OMX_U32 rangeOffset, OMX_U32 rangeLength,
796        OMX_U32 flags, OMX_TICKS timestamp) {
797    Mutex::Autolock autoLock(mLock);
798
799    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
800    header->nFilledLen = rangeLength;
801    header->nOffset = rangeOffset;
802    header->nFlags = flags;
803    header->nTimeStamp = timestamp;
804
805    BufferMeta *buffer_meta =
806        static_cast<BufferMeta *>(header->pAppPrivate);
807    buffer_meta->CopyToOMX(header);
808
809    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
810
811    return StatusFromOMXError(err);
812}
813
814// like emptyBuffer, but the data is already in header->pBuffer
815status_t OMXNodeInstance::emptyDirectBuffer(
816        OMX_BUFFERHEADERTYPE *header,
817        OMX_U32 rangeOffset, OMX_U32 rangeLength,
818        OMX_U32 flags, OMX_TICKS timestamp) {
819    Mutex::Autolock autoLock(mLock);
820
821    header->nFilledLen = rangeLength;
822    header->nOffset = rangeOffset;
823    header->nFlags = flags;
824    header->nTimeStamp = timestamp;
825
826    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
827    if (err != OMX_ErrorNone) {
828        ALOGW("emptyDirectBuffer failed, OMX err=0x%x", err);
829    }
830
831    return StatusFromOMXError(err);
832}
833
834status_t OMXNodeInstance::getExtensionIndex(
835        const char *parameterName, OMX_INDEXTYPE *index) {
836    Mutex::Autolock autoLock(mLock);
837
838    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
839            mHandle, const_cast<char *>(parameterName), index);
840
841    return StatusFromOMXError(err);
842}
843
844status_t OMXNodeInstance::setInternalOption(
845        OMX_U32 portIndex,
846        IOMX::InternalOptionType type,
847        const void *data,
848        size_t size) {
849    switch (type) {
850        case IOMX::INTERNAL_OPTION_SUSPEND:
851        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
852        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
853        case IOMX::INTERNAL_OPTION_START_TIME:
854        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
855        {
856            const sp<GraphicBufferSource> &bufferSource =
857                getGraphicBufferSource();
858
859            if (bufferSource == NULL || portIndex != kPortIndexInput) {
860                return ERROR_UNSUPPORTED;
861            }
862
863            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
864                if (size != sizeof(bool)) {
865                    return INVALID_OPERATION;
866                }
867
868                bool suspend = *(bool *)data;
869                bufferSource->suspend(suspend);
870            } else if (type ==
871                    IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){
872                if (size != sizeof(int64_t)) {
873                    return INVALID_OPERATION;
874                }
875
876                int64_t delayUs = *(int64_t *)data;
877
878                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
879            } else if (type ==
880                    IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){
881                if (size != sizeof(int64_t)) {
882                    return INVALID_OPERATION;
883                }
884
885                int64_t maxGapUs = *(int64_t *)data;
886
887                return bufferSource->setMaxTimestampGapUs(maxGapUs);
888            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
889                if (size != sizeof(int64_t)) {
890                    return INVALID_OPERATION;
891                }
892
893                int64_t skipFramesBeforeUs = *(int64_t *)data;
894
895                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
896            } else { // IOMX::INTERNAL_OPTION_TIME_LAPSE
897                if (size != sizeof(int64_t) * 2) {
898                    return INVALID_OPERATION;
899                }
900
901                bufferSource->setTimeLapseUs((int64_t *)data);
902            }
903
904            return OK;
905        }
906
907        default:
908            return ERROR_UNSUPPORTED;
909    }
910}
911
912void OMXNodeInstance::onMessage(const omx_message &msg) {
913    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
914
915    if (msg.type == omx_message::FILL_BUFFER_DONE) {
916        OMX_BUFFERHEADERTYPE *buffer =
917            static_cast<OMX_BUFFERHEADERTYPE *>(
918                    msg.u.extended_buffer_data.buffer);
919
920        BufferMeta *buffer_meta =
921            static_cast<BufferMeta *>(buffer->pAppPrivate);
922
923        buffer_meta->CopyFromOMX(buffer);
924
925        if (bufferSource != NULL) {
926            // fix up the buffer info (especially timestamp) if needed
927            bufferSource->codecBufferFilled(buffer);
928
929            omx_message newMsg = msg;
930            newMsg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
931            mObserver->onMessage(newMsg);
932            return;
933        }
934    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
935        if (bufferSource != NULL) {
936            // This is one of the buffers used exclusively by
937            // GraphicBufferSource.
938            // Don't dispatch a message back to ACodec, since it doesn't
939            // know that anyone asked to have the buffer emptied and will
940            // be very confused.
941
942            OMX_BUFFERHEADERTYPE *buffer =
943                static_cast<OMX_BUFFERHEADERTYPE *>(
944                        msg.u.buffer_data.buffer);
945
946            bufferSource->codecBufferEmptied(buffer);
947            return;
948        }
949    }
950
951    mObserver->onMessage(msg);
952}
953
954void OMXNodeInstance::onObserverDied(OMXMaster *master) {
955    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
956
957    // Try to force shutdown of the node and hope for the best.
958    freeNode(master);
959}
960
961void OMXNodeInstance::onGetHandleFailed() {
962    delete this;
963}
964
965// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
966// Don't try to acquire mLock here -- in rare circumstances this will hang.
967void OMXNodeInstance::onEvent(
968        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
969    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
970
971    if (bufferSource != NULL
972            && event == OMX_EventCmdComplete
973            && arg1 == OMX_CommandStateSet
974            && arg2 == OMX_StateExecuting) {
975        bufferSource->omxExecuting();
976    }
977}
978
979// static
980OMX_ERRORTYPE OMXNodeInstance::OnEvent(
981        OMX_IN OMX_HANDLETYPE /* hComponent */,
982        OMX_IN OMX_PTR pAppData,
983        OMX_IN OMX_EVENTTYPE eEvent,
984        OMX_IN OMX_U32 nData1,
985        OMX_IN OMX_U32 nData2,
986        OMX_IN OMX_PTR pEventData) {
987    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
988    if (instance->mDying) {
989        return OMX_ErrorNone;
990    }
991    return instance->owner()->OnEvent(
992            instance->nodeID(), eEvent, nData1, nData2, pEventData);
993}
994
995// static
996OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
997        OMX_IN OMX_HANDLETYPE /* hComponent */,
998        OMX_IN OMX_PTR pAppData,
999        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
1000    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
1001    if (instance->mDying) {
1002        return OMX_ErrorNone;
1003    }
1004    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
1005}
1006
1007// static
1008OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
1009        OMX_IN OMX_HANDLETYPE /* hComponent */,
1010        OMX_IN OMX_PTR pAppData,
1011        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
1012    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
1013    if (instance->mDying) {
1014        return OMX_ErrorNone;
1015    }
1016    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
1017}
1018
1019void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
1020    ActiveBuffer active;
1021    active.mPortIndex = portIndex;
1022    active.mID = id;
1023    mActiveBuffers.push(active);
1024}
1025
1026void OMXNodeInstance::removeActiveBuffer(
1027        OMX_U32 portIndex, OMX::buffer_id id) {
1028    bool found = false;
1029    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
1030        if (mActiveBuffers[i].mPortIndex == portIndex
1031            && mActiveBuffers[i].mID == id) {
1032            found = true;
1033            mActiveBuffers.removeItemsAt(i);
1034            break;
1035        }
1036    }
1037
1038    if (!found) {
1039        ALOGW("Attempt to remove an active buffer we know nothing about...");
1040    }
1041}
1042
1043void OMXNodeInstance::freeActiveBuffers() {
1044    // Make sure to count down here, as freeBuffer will in turn remove
1045    // the active buffer from the vector...
1046    for (size_t i = mActiveBuffers.size(); i--;) {
1047        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
1048    }
1049}
1050
1051}  // namespace android
1052