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 
41 namespace android {
42 
43 namespace {
44 
45 class Buffer2D : public C2Buffer {
46 public:
Buffer2D(C2ConstGraphicBlock block)47     explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
48 };
49 
50 }  // namespace
51 
C2OMXNode(const std::shared_ptr<Codec2Client::Component> & comp)52 C2OMXNode::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 
freeNode()62 status_t C2OMXNode::freeNode() {
63     mComp.reset();
64     return OK;
65 }
66 
sendCommand(OMX_COMMANDTYPE cmd,OMX_S32 param)67 status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
68     (void)cmd;
69     (void)param;
70     return ERROR_UNSUPPORTED;
71 }
72 
getParameter(OMX_INDEXTYPE index,void * params,size_t size)73 status_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 
setParameter(OMX_INDEXTYPE index,const void * params,size_t size)101 status_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 
getConfig(OMX_INDEXTYPE index,void * config,size_t size)108 status_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 
setConfig(OMX_INDEXTYPE index,const void * config,size_t size)115 status_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 
setPortMode(OMX_U32 portIndex,IOMX::PortMode mode)122 status_t C2OMXNode::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
123     (void)portIndex;
124     (void)mode;
125     return ERROR_UNSUPPORTED;
126 }
127 
prepareForAdaptivePlayback(OMX_U32 portIndex,OMX_BOOL enable,OMX_U32 maxFrameWidth,OMX_U32 maxFrameHeight)128 status_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 
configureVideoTunnelMode(OMX_U32 portIndex,OMX_BOOL tunneled,OMX_U32 audioHwSync,native_handle_t ** sidebandHandle)138 status_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 
getGraphicBufferUsage(OMX_U32 portIndex,OMX_U32 * usage)148 status_t C2OMXNode::getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage) {
149     (void)portIndex;
150     *usage = 0;
151     return ERROR_UNSUPPORTED;
152 }
153 
setInputSurface(const sp<IOMXBufferSource> & bufferSource)154 status_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 
allocateSecureBuffer(OMX_U32 portIndex,size_t size,buffer_id * buffer,void ** bufferData,sp<NativeHandle> * nativeHandle)165 status_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 
useBuffer(OMX_U32 portIndex,const OMXBuffer & omxBuf,buffer_id * buffer)176 status_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 
freeBuffer(OMX_U32 portIndex,buffer_id buffer)184 status_t C2OMXNode::freeBuffer(OMX_U32 portIndex, buffer_id buffer) {
185     (void)portIndex;
186     (void)buffer;
187     return ERROR_UNSUPPORTED;
188 }
189 
fillBuffer(buffer_id buffer,const OMXBuffer & omxBuf,int fenceFd)190 status_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 
emptyBuffer(buffer_id buffer,const OMXBuffer & omxBuf,OMX_U32 flags,OMX_TICKS timestamp,int fenceFd)198 status_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 
getExtensionIndex(const char * parameterName,OMX_INDEXTYPE * index)265 status_t C2OMXNode::getExtensionIndex(
266         const char *parameterName, OMX_INDEXTYPE *index) {
267     (void)parameterName;
268     *index = OMX_IndexMax;
269     return ERROR_UNSUPPORTED;
270 }
271 
dispatchMessage(const omx_message & msg)272 status_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 
getSource()283 sp<IOMXBufferSource> C2OMXNode::getSource() {
284     return mBufferSource;
285 }
286 
setFrameSize(uint32_t width,uint32_t height)287 void C2OMXNode::setFrameSize(uint32_t width, uint32_t height) {
288     mWidth = width;
289     mHeight = height;
290 }
291 
292 }  // namespace android
293