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#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "OMX"
21#include <utils/Log.h>
22
23#include <dlfcn.h>
24
25#include "../include/OMX.h"
26
27#include "../include/OMXNodeInstance.h"
28
29#include <media/stagefright/foundation/ADebug.h>
30#include "BWGraphicBufferSource.h"
31
32#include "OMXMaster.h"
33#include "OMXUtils.h"
34
35namespace android {
36
37// node ids are created by concatenating the pid with a 16-bit counter
38static size_t kMaxNodeInstances = (1 << 16);
39
40OMX::OMX() : mMaster(new OMXMaster), mParser() {
41}
42
43OMX::~OMX() {
44    delete mMaster;
45    mMaster = NULL;
46}
47
48void OMX::binderDied(const wp<IBinder> &the_late_who) {
49    sp<OMXNodeInstance> instance;
50
51    {
52        Mutex::Autolock autoLock(mLock);
53
54        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
55
56        if (index < 0) {
57            ALOGE("b/27597103, nonexistent observer on binderDied");
58            android_errorWriteLog(0x534e4554, "27597103");
59            return;
60        }
61
62        instance = mLiveNodes.editValueAt(index);
63        mLiveNodes.removeItemsAt(index);
64    }
65
66    instance->onObserverDied();
67}
68
69status_t OMX::listNodes(List<ComponentInfo> *list) {
70    list->clear();
71
72    OMX_U32 index = 0;
73    char componentName[256];
74    while (mMaster->enumerateComponents(
75                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
76        list->push_back(ComponentInfo());
77        ComponentInfo &info = *--list->end();
78
79        info.mName = componentName;
80
81        Vector<String8> roles;
82        OMX_ERRORTYPE err =
83            mMaster->getRolesOfComponent(componentName, &roles);
84
85        if (err == OMX_ErrorNone) {
86            for (OMX_U32 i = 0; i < roles.size(); ++i) {
87                info.mRoles.push_back(roles[i]);
88            }
89        }
90
91        ++index;
92    }
93
94    return OK;
95}
96
97status_t OMX::allocateNode(
98        const char *name, const sp<IOMXObserver> &observer,
99        sp<IOMXNode> *omxNode) {
100    Mutex::Autolock autoLock(mLock);
101
102    omxNode->clear();
103
104    if (mLiveNodes.size() == kMaxNodeInstances) {
105        return NO_MEMORY;
106    }
107
108    sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);
109
110    OMX_COMPONENTTYPE *handle;
111    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
112            name, &OMXNodeInstance::kCallbacks,
113            instance.get(), &handle);
114
115    if (err != OMX_ErrorNone) {
116        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
117
118        return StatusFromOMXError(err);
119    }
120    instance->setHandle(handle);
121    std::vector<AString> quirkVector;
122    if (mParser.getQuirks(name, &quirkVector) == OK) {
123        uint32_t quirks = 0;
124        for (const AString quirk : quirkVector) {
125            if (quirk == "requires-allocate-on-input-ports") {
126                quirks |= kRequiresAllocateBufferOnInputPorts;
127            }
128            if (quirk == "requires-allocate-on-output-ports") {
129                quirks |= kRequiresAllocateBufferOnOutputPorts;
130            }
131        }
132        instance->setQuirks(quirks);
133    }
134
135    mLiveNodes.add(IInterface::asBinder(observer), instance);
136    IInterface::asBinder(observer)->linkToDeath(this);
137
138    *omxNode = instance;
139
140    return OK;
141}
142
143status_t OMX::freeNode(const sp<OMXNodeInstance> &instance) {
144    if (instance == NULL) {
145        return OK;
146    }
147
148    {
149        Mutex::Autolock autoLock(mLock);
150        ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
151        if (index < 0) {
152            // This could conceivably happen if the observer dies at roughly the
153            // same time that a client attempts to free the node explicitly.
154
155            // NOTE: it's guaranteed that this method is called at most once per
156            //       instance.
157            ALOGV("freeNode: instance already removed from book-keeping.");
158        } else {
159            mLiveNodes.removeItemsAt(index);
160            IInterface::asBinder(instance->observer())->unlinkToDeath(this);
161        }
162    }
163
164    CHECK(instance->handle() != NULL);
165    OMX_ERRORTYPE err = mMaster->destroyComponentInstance(
166            static_cast<OMX_COMPONENTTYPE *>(instance->handle()));
167    ALOGV("freeNode: handle destroyed: %p", instance->handle());
168
169    return StatusFromOMXError(err);
170}
171
172status_t OMX::createInputSurface(
173        sp<IGraphicBufferProducer> *bufferProducer,
174        sp<IGraphicBufferSource> *bufferSource) {
175    if (bufferProducer == NULL || bufferSource == NULL) {
176        ALOGE("b/25884056");
177        return BAD_VALUE;
178    }
179
180    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
181    status_t err = graphicBufferSource->initCheck();
182    if (err != OK) {
183        ALOGE("Failed to create persistent input surface: %s (%d)",
184                strerror(-err), err);
185        return err;
186    }
187
188    *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
189    *bufferSource = new BWGraphicBufferSource(graphicBufferSource);
190
191    return OK;
192}
193
194}  // namespace android
195