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