OMXNodeInstance.cpp revision e2ce6458659c6e1bad420357b61dc10cd8bbe2ab
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
24#include <OMX_Component.h>
25
26#include <binder/IMemory.h>
27#include <media/stagefright/HardwareAPI.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaErrors.h>
30
31namespace android {
32
33struct BufferMeta {
34    BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
35        : mMem(mem),
36          mIsBackup(is_backup) {
37    }
38
39    BufferMeta(size_t size)
40        : mSize(size),
41          mIsBackup(false) {
42    }
43
44    BufferMeta(const sp<GraphicBuffer> &graphicBuffer)
45        : mGraphicBuffer(graphicBuffer),
46          mIsBackup(false) {
47    }
48
49    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
50        if (!mIsBackup) {
51            return;
52        }
53
54        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
55               header->pBuffer + header->nOffset,
56               header->nFilledLen);
57    }
58
59    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
60        if (!mIsBackup) {
61            return;
62        }
63
64        memcpy(header->pBuffer + header->nOffset,
65               (const OMX_U8 *)mMem->pointer() + header->nOffset,
66               header->nFilledLen);
67    }
68
69private:
70    sp<GraphicBuffer> mGraphicBuffer;
71    sp<IMemory> mMem;
72    size_t mSize;
73    bool mIsBackup;
74
75    BufferMeta(const BufferMeta &);
76    BufferMeta &operator=(const BufferMeta &);
77};
78
79// static
80OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
81    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
82};
83
84OMXNodeInstance::OMXNodeInstance(
85        OMX *owner, const sp<IOMXObserver> &observer)
86    : mOwner(owner),
87      mNodeID(NULL),
88      mHandle(NULL),
89      mObserver(observer),
90      mDying(false) {
91}
92
93OMXNodeInstance::~OMXNodeInstance() {
94    CHECK_EQ(mHandle, NULL);
95}
96
97void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
98    CHECK_EQ(mHandle, NULL);
99    mNodeID = node_id;
100    mHandle = handle;
101}
102
103OMX *OMXNodeInstance::owner() {
104    return mOwner;
105}
106
107sp<IOMXObserver> OMXNodeInstance::observer() {
108    return mObserver;
109}
110
111OMX::node_id OMXNodeInstance::nodeID() {
112    return mNodeID;
113}
114
115static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
116    switch (err) {
117        case OMX_ErrorNone:
118            return OK;
119        case OMX_ErrorUnsupportedSetting:
120            return ERROR_UNSUPPORTED;
121        default:
122            return UNKNOWN_ERROR;
123    }
124}
125
126status_t OMXNodeInstance::freeNode(OMXMaster *master) {
127    static int32_t kMaxNumIterations = 10;
128
129    // Transition the node from its current state all the way down
130    // to "Loaded".
131    // This ensures that all active buffers are properly freed even
132    // for components that don't do this themselves on a call to
133    // "FreeHandle".
134
135    // The code below may trigger some more events to be dispatched
136    // by the OMX component - we want to ignore them as our client
137    // does not expect them.
138    mDying = true;
139
140    OMX_STATETYPE state;
141    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
142    switch (state) {
143        case OMX_StateExecuting:
144        {
145            LOGV("forcing Executing->Idle");
146            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
147            OMX_ERRORTYPE err;
148            int32_t iteration = 0;
149            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
150                   && state != OMX_StateIdle
151                   && state != OMX_StateInvalid) {
152                if (++iteration > kMaxNumIterations) {
153                    LOGE("component failed to enter Idle state, aborting.");
154                    state = OMX_StateInvalid;
155                    break;
156                }
157
158                usleep(100000);
159            }
160            CHECK_EQ(err, OMX_ErrorNone);
161
162            if (state == OMX_StateInvalid) {
163                break;
164            }
165
166            // fall through
167        }
168
169        case OMX_StateIdle:
170        {
171            LOGV("forcing Idle->Loaded");
172            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
173
174            freeActiveBuffers();
175
176            OMX_ERRORTYPE err;
177            int32_t iteration = 0;
178            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
179                   && state != OMX_StateLoaded
180                   && state != OMX_StateInvalid) {
181                if (++iteration > kMaxNumIterations) {
182                    LOGE("component failed to enter Loaded state, aborting.");
183                    state = OMX_StateInvalid;
184                    break;
185                }
186
187                LOGV("waiting for Loaded state...");
188                usleep(100000);
189            }
190            CHECK_EQ(err, OMX_ErrorNone);
191
192            // fall through
193        }
194
195        case OMX_StateLoaded:
196        case OMX_StateInvalid:
197            break;
198
199        default:
200            CHECK(!"should not be here, unknown state.");
201            break;
202    }
203
204    LOGV("calling destroyComponentInstance");
205    OMX_ERRORTYPE err = master->destroyComponentInstance(
206            static_cast<OMX_COMPONENTTYPE *>(mHandle));
207    LOGV("destroyComponentInstance returned err %d", err);
208
209    mHandle = NULL;
210
211    if (err != OMX_ErrorNone) {
212        LOGE("FreeHandle FAILED with error 0x%08x.", err);
213    }
214
215    mOwner->invalidateNodeID(mNodeID);
216    mNodeID = NULL;
217
218    LOGV("OMXNodeInstance going away.");
219    delete this;
220
221    return StatusFromOMXError(err);
222}
223
224status_t OMXNodeInstance::sendCommand(
225        OMX_COMMANDTYPE cmd, OMX_S32 param) {
226    Mutex::Autolock autoLock(mLock);
227
228    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
229    return StatusFromOMXError(err);
230}
231
232status_t OMXNodeInstance::getParameter(
233        OMX_INDEXTYPE index, void *params, size_t size) {
234    Mutex::Autolock autoLock(mLock);
235
236    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
237    return StatusFromOMXError(err);
238}
239
240status_t OMXNodeInstance::setParameter(
241        OMX_INDEXTYPE index, const void *params, size_t size) {
242    Mutex::Autolock autoLock(mLock);
243
244    OMX_ERRORTYPE err = OMX_SetParameter(
245            mHandle, index, const_cast<void *>(params));
246
247    return StatusFromOMXError(err);
248}
249
250status_t OMXNodeInstance::getConfig(
251        OMX_INDEXTYPE index, void *params, size_t size) {
252    Mutex::Autolock autoLock(mLock);
253
254    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
255    return StatusFromOMXError(err);
256}
257
258status_t OMXNodeInstance::setConfig(
259        OMX_INDEXTYPE index, const void *params, size_t size) {
260    Mutex::Autolock autoLock(mLock);
261
262    OMX_ERRORTYPE err = OMX_SetConfig(
263            mHandle, index, const_cast<void *>(params));
264
265    return StatusFromOMXError(err);
266}
267
268status_t OMXNodeInstance::enableGraphicBuffers(
269        OMX_U32 portIndex, OMX_BOOL enable) {
270    Mutex::Autolock autoLock(mLock);
271
272    OMX_INDEXTYPE index;
273    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
274            mHandle,
275            const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"),
276            &index);
277
278    if (err != OMX_ErrorNone) {
279        LOGE("OMX_GetExtensionIndex failed");
280
281        return StatusFromOMXError(err);
282    }
283
284    OMX_VERSIONTYPE ver;
285    ver.s.nVersionMajor = 1;
286    ver.s.nVersionMinor = 0;
287    ver.s.nRevision = 0;
288    ver.s.nStep = 0;
289    EnableAndroidNativeBuffersParams params = {
290        sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
291    };
292
293    err = OMX_SetParameter(mHandle, index, &params);
294
295    if (err != OMX_ErrorNone) {
296        LOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
297                err, err);
298
299        return UNKNOWN_ERROR;
300    }
301
302    return OK;
303}
304
305status_t OMXNodeInstance::getGraphicBufferUsage(
306        OMX_U32 portIndex, OMX_U32* usage) {
307    Mutex::Autolock autoLock(mLock);
308
309    OMX_INDEXTYPE index;
310    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
311            mHandle,
312            const_cast<OMX_STRING>(
313                    "OMX.google.android.index.getAndroidNativeBufferUsage"),
314            &index);
315
316    if (err != OMX_ErrorNone) {
317        LOGE("OMX_GetExtensionIndex failed");
318
319        return StatusFromOMXError(err);
320    }
321
322    OMX_VERSIONTYPE ver;
323    ver.s.nVersionMajor = 1;
324    ver.s.nVersionMinor = 0;
325    ver.s.nRevision = 0;
326    ver.s.nStep = 0;
327    GetAndroidNativeBufferUsageParams params = {
328        sizeof(GetAndroidNativeBufferUsageParams), ver, portIndex, 0,
329    };
330
331    err = OMX_GetParameter(mHandle, index, &params);
332
333    if (err != OMX_ErrorNone) {
334        LOGE("OMX_GetAndroidNativeBufferUsage failed with error %d (0x%08x)",
335                err, err);
336        return UNKNOWN_ERROR;
337    }
338
339    *usage = params.nUsage;
340
341    return OK;
342}
343
344status_t OMXNodeInstance::storeMetaDataInBuffers(
345        OMX_U32 portIndex,
346        OMX_BOOL enable) {
347    Mutex::Autolock autolock(mLock);
348
349    OMX_INDEXTYPE index;
350    OMX_STRING name = const_cast<OMX_STRING>(
351            "OMX.google.android.index.storeMetaDataInBuffers");
352
353    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
354    if (err != OMX_ErrorNone) {
355        LOGE("OMX_GetExtensionIndex %s failed", name);
356        return StatusFromOMXError(err);
357    }
358
359    StoreMetaDataInBuffersParams params;
360    memset(&params, 0, sizeof(params));
361    params.nSize = sizeof(params);
362
363    // Version: 1.0.0.0
364    params.nVersion.s.nVersionMajor = 1;
365
366    params.nPortIndex = portIndex;
367    params.bStoreMetaData = enable;
368    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
369        LOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err);
370        return UNKNOWN_ERROR;
371    }
372    return err;
373}
374
375status_t OMXNodeInstance::useBuffer(
376        OMX_U32 portIndex, const sp<IMemory> &params,
377        OMX::buffer_id *buffer) {
378    Mutex::Autolock autoLock(mLock);
379
380    BufferMeta *buffer_meta = new BufferMeta(params);
381
382    OMX_BUFFERHEADERTYPE *header;
383
384    OMX_ERRORTYPE err = OMX_UseBuffer(
385            mHandle, &header, portIndex, buffer_meta,
386            params->size(), static_cast<OMX_U8 *>(params->pointer()));
387
388    if (err != OMX_ErrorNone) {
389        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
390
391        delete buffer_meta;
392        buffer_meta = NULL;
393
394        *buffer = 0;
395
396        return UNKNOWN_ERROR;
397    }
398
399    CHECK_EQ(header->pAppPrivate, buffer_meta);
400
401    *buffer = header;
402
403    addActiveBuffer(portIndex, *buffer);
404
405    return OK;
406}
407
408status_t OMXNodeInstance::useGraphicBuffer(
409        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
410        OMX::buffer_id *buffer) {
411    Mutex::Autolock autoLock(mLock);
412
413    OMX_INDEXTYPE index;
414    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
415            mHandle,
416            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"),
417            &index);
418
419    if (err != OMX_ErrorNone) {
420        LOGE("OMX_GetExtensionIndex failed");
421
422        return StatusFromOMXError(err);
423    }
424
425    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
426
427    OMX_BUFFERHEADERTYPE *header;
428
429    OMX_VERSIONTYPE ver;
430    ver.s.nVersionMajor = 1;
431    ver.s.nVersionMinor = 0;
432    ver.s.nRevision = 0;
433    ver.s.nStep = 0;
434    UseAndroidNativeBufferParams params = {
435        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
436        &header, graphicBuffer,
437    };
438
439    err = OMX_SetParameter(mHandle, index, &params);
440
441    if (err != OMX_ErrorNone) {
442        LOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
443                err);
444
445        delete bufferMeta;
446        bufferMeta = NULL;
447
448        *buffer = 0;
449
450        return UNKNOWN_ERROR;
451    }
452
453    CHECK_EQ(header->pAppPrivate, bufferMeta);
454
455    *buffer = header;
456
457    addActiveBuffer(portIndex, *buffer);
458
459    return OK;
460}
461
462status_t OMXNodeInstance::allocateBuffer(
463        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
464        void **buffer_data) {
465    Mutex::Autolock autoLock(mLock);
466
467    BufferMeta *buffer_meta = new BufferMeta(size);
468
469    OMX_BUFFERHEADERTYPE *header;
470
471    OMX_ERRORTYPE err = OMX_AllocateBuffer(
472            mHandle, &header, portIndex, buffer_meta, size);
473
474    if (err != OMX_ErrorNone) {
475        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
476
477        delete buffer_meta;
478        buffer_meta = NULL;
479
480        *buffer = 0;
481
482        return UNKNOWN_ERROR;
483    }
484
485    CHECK_EQ(header->pAppPrivate, buffer_meta);
486
487    *buffer = header;
488    *buffer_data = header->pBuffer;
489
490    addActiveBuffer(portIndex, *buffer);
491
492    return OK;
493}
494
495status_t OMXNodeInstance::allocateBufferWithBackup(
496        OMX_U32 portIndex, const sp<IMemory> &params,
497        OMX::buffer_id *buffer) {
498    Mutex::Autolock autoLock(mLock);
499
500    BufferMeta *buffer_meta = new BufferMeta(params, true);
501
502    OMX_BUFFERHEADERTYPE *header;
503
504    OMX_ERRORTYPE err = OMX_AllocateBuffer(
505            mHandle, &header, portIndex, buffer_meta, params->size());
506
507    if (err != OMX_ErrorNone) {
508        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
509
510        delete buffer_meta;
511        buffer_meta = NULL;
512
513        *buffer = 0;
514
515        return UNKNOWN_ERROR;
516    }
517
518    CHECK_EQ(header->pAppPrivate, buffer_meta);
519
520    *buffer = header;
521
522    addActiveBuffer(portIndex, *buffer);
523
524    return OK;
525}
526
527status_t OMXNodeInstance::freeBuffer(
528        OMX_U32 portIndex, OMX::buffer_id buffer) {
529    Mutex::Autolock autoLock(mLock);
530
531    removeActiveBuffer(portIndex, buffer);
532
533    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
534    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
535
536    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
537
538    delete buffer_meta;
539    buffer_meta = NULL;
540
541    return StatusFromOMXError(err);
542}
543
544status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
545    Mutex::Autolock autoLock(mLock);
546
547    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
548    header->nFilledLen = 0;
549    header->nOffset = 0;
550    header->nFlags = 0;
551
552    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
553
554    return StatusFromOMXError(err);
555}
556
557status_t OMXNodeInstance::emptyBuffer(
558        OMX::buffer_id buffer,
559        OMX_U32 rangeOffset, OMX_U32 rangeLength,
560        OMX_U32 flags, OMX_TICKS timestamp) {
561    Mutex::Autolock autoLock(mLock);
562
563    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
564    header->nFilledLen = rangeLength;
565    header->nOffset = rangeOffset;
566    header->nFlags = flags;
567    header->nTimeStamp = timestamp;
568
569    BufferMeta *buffer_meta =
570        static_cast<BufferMeta *>(header->pAppPrivate);
571    buffer_meta->CopyToOMX(header);
572
573    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
574
575    return StatusFromOMXError(err);
576}
577
578status_t OMXNodeInstance::getExtensionIndex(
579        const char *parameterName, OMX_INDEXTYPE *index) {
580    Mutex::Autolock autoLock(mLock);
581
582    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
583            mHandle, const_cast<char *>(parameterName), index);
584
585    return StatusFromOMXError(err);
586}
587
588void OMXNodeInstance::onMessage(const omx_message &msg) {
589    if (msg.type == omx_message::FILL_BUFFER_DONE) {
590        OMX_BUFFERHEADERTYPE *buffer =
591            static_cast<OMX_BUFFERHEADERTYPE *>(
592                    msg.u.extended_buffer_data.buffer);
593
594        BufferMeta *buffer_meta =
595            static_cast<BufferMeta *>(buffer->pAppPrivate);
596
597        buffer_meta->CopyFromOMX(buffer);
598    }
599
600    mObserver->onMessage(msg);
601}
602
603void OMXNodeInstance::onObserverDied(OMXMaster *master) {
604    LOGE("!!! Observer died. Quickly, do something, ... anything...");
605
606    // Try to force shutdown of the node and hope for the best.
607    freeNode(master);
608}
609
610void OMXNodeInstance::onGetHandleFailed() {
611    delete this;
612}
613
614// static
615OMX_ERRORTYPE OMXNodeInstance::OnEvent(
616        OMX_IN OMX_HANDLETYPE hComponent,
617        OMX_IN OMX_PTR pAppData,
618        OMX_IN OMX_EVENTTYPE eEvent,
619        OMX_IN OMX_U32 nData1,
620        OMX_IN OMX_U32 nData2,
621        OMX_IN OMX_PTR pEventData) {
622    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
623    if (instance->mDying) {
624        return OMX_ErrorNone;
625    }
626    return instance->owner()->OnEvent(
627            instance->nodeID(), eEvent, nData1, nData2, pEventData);
628}
629
630// static
631OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
632        OMX_IN OMX_HANDLETYPE hComponent,
633        OMX_IN OMX_PTR pAppData,
634        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
635    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
636    if (instance->mDying) {
637        return OMX_ErrorNone;
638    }
639    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
640}
641
642// static
643OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
644        OMX_IN OMX_HANDLETYPE hComponent,
645        OMX_IN OMX_PTR pAppData,
646        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
647    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
648    if (instance->mDying) {
649        return OMX_ErrorNone;
650    }
651    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
652}
653
654void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
655    ActiveBuffer active;
656    active.mPortIndex = portIndex;
657    active.mID = id;
658    mActiveBuffers.push(active);
659}
660
661void OMXNodeInstance::removeActiveBuffer(
662        OMX_U32 portIndex, OMX::buffer_id id) {
663    bool found = false;
664    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
665        if (mActiveBuffers[i].mPortIndex == portIndex
666            && mActiveBuffers[i].mID == id) {
667            found = true;
668            mActiveBuffers.removeItemsAt(i);
669            break;
670        }
671    }
672
673    if (!found) {
674        LOGW("Attempt to remove an active buffer we know nothing about...");
675    }
676}
677
678void OMXNodeInstance::freeActiveBuffers() {
679    // Make sure to count down here, as freeBuffer will in turn remove
680    // the active buffer from the vector...
681    for (size_t i = mActiveBuffers.size(); i--;) {
682        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
683    }
684}
685
686}  // namespace android
687