1/*
2 * Copyright 2018, 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#ifdef __LP64__
18#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
19#endif
20
21//#define LOG_NDEBUG 0
22#define LOG_TAG "C2OMXNode"
23#include <log/log.h>
24
25#include <C2AllocatorGralloc.h>
26#include <C2BlockInternal.h>
27#include <C2Component.h>
28#include <C2PlatformSupport.h>
29
30#include <OMX_Component.h>
31#include <OMX_Index.h>
32#include <OMX_IndexExt.h>
33
34#include <media/stagefright/omx/OMXUtils.h>
35#include <media/stagefright/MediaErrors.h>
36#include <ui/Fence.h>
37#include <ui/GraphicBuffer.h>
38
39#include "C2OMXNode.h"
40
41namespace android {
42
43namespace {
44
45class Buffer2D : public C2Buffer {
46public:
47    explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
48};
49
50}  // namespace
51
52C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp)
53    : mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0) {
54    // TODO: read from intf()
55    if (!strncmp(comp->getName().c_str(), "c2.android.", 11)) {
56        mUsage = GRALLOC_USAGE_SW_READ_OFTEN;
57    } else {
58        mUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
59    }
60}
61
62status_t C2OMXNode::freeNode() {
63    mComp.reset();
64    return OK;
65}
66
67status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
68    (void)cmd;
69    (void)param;
70    return ERROR_UNSUPPORTED;
71}
72
73status_t C2OMXNode::getParameter(OMX_INDEXTYPE index, void *params, size_t size) {
74    status_t err = ERROR_UNSUPPORTED;
75    switch ((uint32_t)index) {
76        case OMX_IndexParamConsumerUsageBits: {
77            OMX_U32 *usage = (OMX_U32 *)params;
78            *usage = mUsage;
79            err = OK;
80            break;
81        }
82        case OMX_IndexParamPortDefinition: {
83            if (size < sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
84                return BAD_VALUE;
85            }
86            OMX_PARAM_PORTDEFINITIONTYPE *pDef = (OMX_PARAM_PORTDEFINITIONTYPE *)params;
87            // TODO: read these from intf()
88            pDef->nBufferCountActual = 16;
89            pDef->eDomain = OMX_PortDomainVideo;
90            pDef->format.video.nFrameWidth = mWidth;
91            pDef->format.video.nFrameHeight = mHeight;
92            err = OK;
93            break;
94        }
95        default:
96            break;
97    }
98    return err;
99}
100
101status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
102    (void)index;
103    (void)params;
104    (void)size;
105    return ERROR_UNSUPPORTED;
106}
107
108status_t C2OMXNode::getConfig(OMX_INDEXTYPE index, void *config, size_t size) {
109    (void)index;
110    (void)config;
111    (void)size;
112    return ERROR_UNSUPPORTED;
113}
114
115status_t C2OMXNode::setConfig(OMX_INDEXTYPE index, const void *config, size_t size) {
116    (void)index;
117    (void)config;
118    (void)size;
119    return ERROR_UNSUPPORTED;
120}
121
122status_t C2OMXNode::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
123    (void)portIndex;
124    (void)mode;
125    return ERROR_UNSUPPORTED;
126}
127
128status_t C2OMXNode::prepareForAdaptivePlayback(
129        OMX_U32 portIndex, OMX_BOOL enable,
130        OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
131    (void)portIndex;
132    (void)enable;
133    (void)maxFrameWidth;
134    (void)maxFrameHeight;
135    return ERROR_UNSUPPORTED;
136}
137
138status_t C2OMXNode::configureVideoTunnelMode(
139        OMX_U32 portIndex, OMX_BOOL tunneled,
140        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
141    (void)portIndex;
142    (void)tunneled;
143    (void)audioHwSync;
144    *sidebandHandle = nullptr;
145    return ERROR_UNSUPPORTED;
146}
147
148status_t C2OMXNode::getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage) {
149    (void)portIndex;
150    *usage = 0;
151    return ERROR_UNSUPPORTED;
152}
153
154status_t C2OMXNode::setInputSurface(const sp<IOMXBufferSource> &bufferSource) {
155    c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
156            C2PlatformAllocatorStore::GRALLOC,
157            &mAllocator);
158    if (err != OK) {
159        return UNKNOWN_ERROR;
160    }
161    mBufferSource = bufferSource;
162    return OK;
163}
164
165status_t C2OMXNode::allocateSecureBuffer(
166        OMX_U32 portIndex, size_t size, buffer_id *buffer,
167        void **bufferData, sp<NativeHandle> *nativeHandle) {
168    (void)portIndex;
169    (void)size;
170    (void)nativeHandle;
171    *buffer = 0;
172    *bufferData = nullptr;
173    return ERROR_UNSUPPORTED;
174}
175
176status_t C2OMXNode::useBuffer(
177        OMX_U32 portIndex, const OMXBuffer &omxBuf, buffer_id *buffer) {
178    (void)portIndex;
179    (void)omxBuf;
180    *buffer = 0;
181    return ERROR_UNSUPPORTED;
182}
183
184status_t C2OMXNode::freeBuffer(OMX_U32 portIndex, buffer_id buffer) {
185    (void)portIndex;
186    (void)buffer;
187    return ERROR_UNSUPPORTED;
188}
189
190status_t C2OMXNode::fillBuffer(
191        buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) {
192    (void)buffer;
193    (void)omxBuf;
194    (void)fenceFd;
195    return ERROR_UNSUPPORTED;
196}
197
198status_t C2OMXNode::emptyBuffer(
199        buffer_id buffer, const OMXBuffer &omxBuf,
200        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
201    // TODO: better fence handling
202    if (fenceFd >= 0) {
203        sp<Fence> fence = new Fence(fenceFd);
204        fence->waitForever(LOG_TAG);
205    }
206    std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
207    if (!comp) {
208        return NO_INIT;
209    }
210
211    uint32_t c2Flags = (flags & OMX_BUFFERFLAG_EOS)
212            ? C2FrameData::FLAG_END_OF_STREAM : 0;
213    std::shared_ptr<C2GraphicBlock> block;
214
215    C2Handle *handle = nullptr;
216    if (omxBuf.mBufferType == OMXBuffer::kBufferTypeANWBuffer
217            && omxBuf.mGraphicBuffer != nullptr) {
218        std::shared_ptr<C2GraphicAllocation> alloc;
219        handle = WrapNativeCodec2GrallocHandle(
220                native_handle_clone(omxBuf.mGraphicBuffer->handle),
221                omxBuf.mGraphicBuffer->width,
222                omxBuf.mGraphicBuffer->height,
223                omxBuf.mGraphicBuffer->format,
224                omxBuf.mGraphicBuffer->usage,
225                omxBuf.mGraphicBuffer->stride);
226        c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
227        if (err != OK) {
228            return UNKNOWN_ERROR;
229        }
230        block = _C2BlockFactory::CreateGraphicBlock(alloc);
231    } else if (!(flags & OMX_BUFFERFLAG_EOS)) {
232        return BAD_VALUE;
233    }
234
235    std::unique_ptr<C2Work> work(new C2Work);
236    work->input.flags = (C2FrameData::flags_t)c2Flags;
237    work->input.ordinal.timestamp = timestamp;
238    work->input.ordinal.frameIndex = mFrameIndex++;
239    work->input.buffers.clear();
240    if (block) {
241        std::shared_ptr<C2Buffer> c2Buffer(
242                // TODO: fence
243                new Buffer2D(block->share(
244                        C2Rect(block->width(), block->height()), ::C2Fence())),
245                [buffer, source = getSource()](C2Buffer *ptr) {
246                    delete ptr;
247                    // TODO: fence
248                    (void)source->onInputBufferEmptied(buffer, -1);
249                });
250        work->input.buffers.push_back(c2Buffer);
251    }
252    work->worklets.clear();
253    work->worklets.emplace_back(new C2Worklet);
254    std::list<std::unique_ptr<C2Work>> items;
255    items.push_back(std::move(work));
256
257    c2_status_t err = comp->queue(&items);
258    if (err != C2_OK) {
259        return UNKNOWN_ERROR;
260    }
261
262    return OK;
263}
264
265status_t C2OMXNode::getExtensionIndex(
266        const char *parameterName, OMX_INDEXTYPE *index) {
267    (void)parameterName;
268    *index = OMX_IndexMax;
269    return ERROR_UNSUPPORTED;
270}
271
272status_t C2OMXNode::dispatchMessage(const omx_message& msg) {
273    if (msg.type != omx_message::EVENT) {
274        return ERROR_UNSUPPORTED;
275    }
276    if (msg.u.event_data.event != OMX_EventDataSpaceChanged) {
277        return ERROR_UNSUPPORTED;
278    }
279    // TODO: fill intf() with info inside |msg|.
280    return OK;
281}
282
283sp<IOMXBufferSource> C2OMXNode::getSource() {
284    return mBufferSource;
285}
286
287void C2OMXNode::setFrameSize(uint32_t width, uint32_t height) {
288    mWidth = width;
289    mHeight = height;
290}
291
292}  // namespace android
293