1/*
2 * Copyright 2016, 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 "TWGraphicBufferSource"
19
20#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
21#include <media/stagefright/omx/1.0/WOmxNode.h>
22#include <media/stagefright/omx/1.0/Conversion.h>
23#include <media/stagefright/omx/OMXUtils.h>
24#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
25#include <android/hardware/media/omx/1.0/IOmxNode.h>
26#include <media/openmax/OMX_Component.h>
27#include <media/openmax/OMX_IndexExt.h>
28
29namespace android {
30namespace hardware {
31namespace media {
32namespace omx {
33namespace V1_0 {
34namespace implementation {
35
36static const OMX_U32 kPortIndexInput = 0;
37
38struct TWGraphicBufferSource::TWOmxNodeWrapper : public IOmxNodeWrapper {
39    sp<IOmxNode> mOmxNode;
40
41    TWOmxNodeWrapper(const sp<IOmxNode> &omxNode): mOmxNode(omxNode) {
42    }
43
44    virtual status_t emptyBuffer(
45            int32_t bufferId, uint32_t flags,
46            const sp<GraphicBuffer> &buffer,
47            int64_t timestamp, int fenceFd) override {
48        CodecBuffer tBuffer;
49        native_handle_t* fenceNh = native_handle_create_from_fd(fenceFd);
50        status_t err = toStatusT(mOmxNode->emptyBuffer(
51              bufferId,
52              *wrapAs(&tBuffer, buffer),
53              flags,
54              toRawTicks(timestamp),
55              fenceNh));
56        native_handle_close(fenceNh);
57        native_handle_delete(fenceNh);
58        return err;
59    }
60
61    virtual void dispatchDataSpaceChanged(
62            int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
63        Message tMsg;
64        tMsg.type = Message::Type::EVENT;
65        tMsg.fence = native_handle_create(0, 0);
66        tMsg.data.eventData.event = uint32_t(OMX_EventDataSpaceChanged);
67        tMsg.data.eventData.data1 = dataSpace;
68        tMsg.data.eventData.data2 = aspects;
69        tMsg.data.eventData.data3 = pixelFormat;
70        if (!mOmxNode->dispatchMessage(tMsg).isOk()) {
71            ALOGE("TWOmxNodeWrapper failed to dispatch message "
72                    "OMX_EventDataSpaceChanged: "
73                    "dataSpace = %ld, aspects = %ld, pixelFormat = %ld",
74                    static_cast<long>(dataSpace),
75                    static_cast<long>(aspects),
76                    static_cast<long>(pixelFormat));
77        }
78    }
79};
80
81struct TWGraphicBufferSource::TWOmxBufferSource : public IOmxBufferSource {
82    sp<OmxGraphicBufferSource> mSource;
83
84    TWOmxBufferSource(const sp<OmxGraphicBufferSource> &source): mSource(source) {
85    }
86
87    Return<void> onOmxExecuting() override {
88        mSource->onOmxExecuting();
89        return Void();
90    }
91
92    Return<void> onOmxIdle() override {
93        mSource->onOmxIdle();
94        return Void();
95    }
96
97    Return<void> onOmxLoaded() override {
98        mSource->onOmxLoaded();
99        return Void();
100    }
101
102    Return<void> onInputBufferAdded(uint32_t bufferId) override {
103        mSource->onInputBufferAdded(static_cast<int32_t>(bufferId));
104        return Void();
105    }
106
107    Return<void> onInputBufferEmptied(
108            uint32_t bufferId, hidl_handle const& tFence) override {
109        mSource->onInputBufferEmptied(
110                static_cast<int32_t>(bufferId),
111                native_handle_read_fd(tFence));
112        return Void();
113    }
114};
115
116// TWGraphicBufferSource
117TWGraphicBufferSource::TWGraphicBufferSource(
118        sp<OmxGraphicBufferSource> const& base) :
119    mBase(base),
120    mOmxBufferSource(new TWOmxBufferSource(base)) {
121}
122
123Return<Status> TWGraphicBufferSource::configure(
124        const sp<IOmxNode>& omxNode, Dataspace dataspace) {
125    if (omxNode == NULL) {
126        return toStatus(BAD_VALUE);
127    }
128
129    // Do setInputSurface() first, the node will try to enable metadata
130    // mode on input, and does necessary error checking. If this fails,
131    // we can't use this input surface on the node.
132    Return<Status> err(omxNode->setInputSurface(mOmxBufferSource));
133    status_t fnStatus = toStatusT(err);
134    if (fnStatus != NO_ERROR) {
135        ALOGE("Unable to set input surface: %d", fnStatus);
136        return err;
137    }
138
139    // use consumer usage bits queried from encoder, but always add
140    // HW_VIDEO_ENCODER for backward compatibility.
141    uint32_t  consumerUsage;
142    void *_params = &consumerUsage;
143    uint8_t *params = static_cast<uint8_t*>(_params);
144    fnStatus = UNKNOWN_ERROR;
145    IOmxNode::getParameter_cb _hidl_cb(
146            [&fnStatus, &params](Status status, hidl_vec<uint8_t> const& outParams) {
147                fnStatus = toStatusT(status);
148                std::copy(
149                        outParams.data(),
150                        outParams.data() + outParams.size(),
151                        params);
152            });
153    auto transStatus = omxNode->getParameter(
154            static_cast<uint32_t>(OMX_IndexParamConsumerUsageBits),
155            inHidlBytes(&consumerUsage, sizeof(consumerUsage)),
156            _hidl_cb);
157    if (!transStatus.isOk()) {
158        return toStatus(FAILED_TRANSACTION);
159    }
160    if (fnStatus != OK) {
161        consumerUsage = 0;
162    }
163
164    OMX_PARAM_PORTDEFINITIONTYPE def;
165    InitOMXParams(&def);
166    def.nPortIndex = kPortIndexInput;
167
168    _params = &def;
169    params = static_cast<uint8_t*>(_params);
170    transStatus = omxNode->getParameter(
171            static_cast<uint32_t>(OMX_IndexParamPortDefinition),
172            inHidlBytes(&def, sizeof(def)),
173            _hidl_cb);
174    if (!transStatus.isOk()) {
175        return toStatus(FAILED_TRANSACTION);
176    }
177    if (fnStatus != NO_ERROR) {
178        ALOGE("Failed to get port definition: %d", fnStatus);
179        return toStatus(fnStatus);
180    }
181
182
183    return toStatus(mBase->configure(
184            new TWOmxNodeWrapper(omxNode),
185            toRawDataspace(dataspace),
186            def.nBufferCountActual,
187            def.format.video.nFrameWidth,
188            def.format.video.nFrameHeight,
189            consumerUsage));
190}
191
192Return<Status> TWGraphicBufferSource::setSuspend(
193        bool suspend, int64_t timeUs) {
194    return toStatus(mBase->setSuspend(suspend, timeUs));
195}
196
197Return<Status> TWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
198        int64_t repeatAfterUs) {
199    return toStatus(mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs));
200}
201
202Return<Status> TWGraphicBufferSource::setMaxFps(float maxFps) {
203    return toStatus(mBase->setMaxFps(maxFps));
204}
205
206Return<Status> TWGraphicBufferSource::setTimeLapseConfig(
207        double fps, double captureFps) {
208    return toStatus(mBase->setTimeLapseConfig(fps, captureFps));
209}
210
211Return<Status> TWGraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
212    return toStatus(mBase->setStartTimeUs(startTimeUs));
213}
214
215Return<Status> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
216    return toStatus(mBase->setStopTimeUs(stopTimeUs));
217}
218
219Return<void> TWGraphicBufferSource::getStopTimeOffsetUs(
220        getStopTimeOffsetUs_cb _hidl_cb) {
221    status_t status;
222    int64_t stopTimeOffsetUs;
223    status = mBase->getStopTimeOffsetUs(&stopTimeOffsetUs);
224    _hidl_cb(toStatus(status), stopTimeOffsetUs);
225    return Void();
226}
227
228Return<Status> TWGraphicBufferSource::setColorAspects(
229        const ColorAspects& aspects) {
230    return toStatus(mBase->setColorAspects(toCompactColorAspects(aspects)));
231}
232
233Return<Status> TWGraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
234    return toStatus(mBase->setTimeOffsetUs(timeOffsetUs));
235}
236
237Return<Status> TWGraphicBufferSource::signalEndOfInputStream() {
238    return toStatus(mBase->signalEndOfInputStream());
239}
240
241}  // namespace implementation
242}  // namespace V1_0
243}  // namespace omx
244}  // namespace media
245}  // namespace hardware
246}  // namespace android
247