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