1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
29#include "mmalomx.h"
30#include "mmalomx_commands.h"
31#include "mmalomx_roles.h"
32#include "mmalomx_registry.h"
33#include "mmalomx_buffer.h"
34#include "mmalomx_parameters.h"
35#include "mmalomx_logging.h"
36
37#include <util/mmal_util.h>
38#include <util/mmal_util_params.h>
39#include <string.h>
40#include <stdio.h>
41
42#define MAX_CMD_BUFFERS 5
43
44#define PARAM_GET_PORT(port, component, index) \
45 if (index >= component->ports_num) return OMX_ErrorBadPortIndex; \
46 port = &component->ports[index]
47
48static void *mmalomx_cmd_thread_func(void *arg);
49#define MMALOMX_ZERO_COPY_THRESHOLD 256
50
51/*****************************************************************************/
52OMX_ERRORTYPE mmalomx_callback_event_handler(
53 MMALOMX_COMPONENT_T *component,
54 OMX_EVENTTYPE eEvent,
55 OMX_U32 nData1,
56 OMX_U32 nData2,
57 OMX_PTR pEventData)
58{
59 LOG_DEBUG("component %p, eEvent %i, nData1 %u, nData2 %u, pEventData %p",
60 component, (int)eEvent, (unsigned int)nData1, (unsigned int)nData2, pEventData);
61 return component->callbacks.EventHandler((OMX_HANDLETYPE)&component->omx,
62 component->callbacks_data, eEvent, nData1, nData2, pEventData);
63}
64
65/*****************************************************************************/
66static OMX_ERRORTYPE mmalomx_ComponentGetComponentVersion(
67 OMX_HANDLETYPE hComponent,
68 OMX_STRING pComponentName,
69 OMX_VERSIONTYPE* pComponentVersion,
70 OMX_VERSIONTYPE* pSpecVersion,
71 OMX_UUIDTYPE* pComponentUUID)
72{
73 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
74 const char *short_name, *prefix;
75
76 LOG_TRACE("hComponent %p, componentName %p, componentVersion %p, "
77 "pSpecVersion %p, componentUUID %p",
78 hComponent, pComponentName, pComponentVersion, pSpecVersion,
79 pComponentUUID);
80
81 /* Sanity checks */
82 if (!hComponent)
83 return OMX_ErrorInvalidComponent;
84 if (component->state == OMX_StateInvalid)
85 return OMX_ErrorInvalidState;
86 if (!pComponentName || !pComponentVersion || !pSpecVersion || !pComponentUUID )
87 return OMX_ErrorBadParameter;
88
89 short_name = mmalomx_registry_component_name(component->registry_id, &prefix);
90
91 snprintf(pComponentName, OMX_MAX_STRINGNAME_SIZE, "%s%s", short_name, prefix);
92 pComponentVersion->nVersion = 0;
93 pSpecVersion->nVersion = OMX_VERSION;
94 snprintf((char *)(*pComponentUUID), sizeof(OMX_UUIDTYPE), "%s", pComponentName);
95
96 return OMX_ErrorNone;
97}
98
99/*****************************************************************************/
100static OMX_ERRORTYPE mmalomx_ComponentSendCommand(
101 OMX_HANDLETYPE hComponent,
102 OMX_COMMANDTYPE Cmd,
103 OMX_U32 nParam1,
104 OMX_PTR pCmdData)
105{
106 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
107 OMX_ERRORTYPE status = OMX_ErrorNone;
108
109 LOG_TRACE("hComponent %p, Cmd %i (%s), nParam1 %i (%s), pCmdData %p",
110 hComponent, Cmd, mmalomx_cmd_to_string(Cmd), (int)nParam1,
111 Cmd == OMX_CommandStateSet ? mmalomx_state_to_string((OMX_STATETYPE)nParam1) : "",
112 pCmdData);
113
114 /* Sanity checks */
115 if (!hComponent)
116 return OMX_ErrorInvalidComponent;
117 if (component->state == OMX_StateInvalid)
118 return OMX_ErrorInvalidState;
119
120 /* Sanity check port index */
121 if (Cmd == OMX_CommandFlush || Cmd == OMX_CommandMarkBuffer ||
122 Cmd == OMX_CommandPortEnable || Cmd == OMX_CommandPortDisable)
123 {
124 if (nParam1 != OMX_ALL && nParam1 >= component->ports_num)
125 return OMX_ErrorBadPortIndex;
126 }
127
128 if (Cmd == OMX_CommandStateSet ||
129 Cmd == OMX_CommandFlush ||
130 Cmd == OMX_CommandPortEnable ||
131 Cmd == OMX_CommandPortDisable)
132 {
133 status = mmalomx_command_queue(component, Cmd, nParam1);
134 }
135 else if (Cmd == OMX_CommandMarkBuffer)
136 {
137 status = mmalomx_command_port_mark(hComponent, nParam1, pCmdData);
138 }
139 else
140 {
141 status = OMX_ErrorNotImplemented;
142 }
143
144 return status;
145}
146
147/*****************************************************************************/
148static MMAL_STATUS_T mmalomx_get_port_settings(MMALOMX_PORT_T *port, OMX_PARAM_PORTDEFINITIONTYPE *def)
149{
150 MMAL_STATUS_T status = MMAL_SUCCESS;
151 MMAL_PORT_T *mmal = port->mmal;
152
153 def->eDomain = mmalil_es_type_to_omx_domain(mmal->format->type);
154 def->eDir = OMX_DirInput;
155 if (mmal->type == MMAL_PORT_TYPE_OUTPUT)
156 def->eDir = OMX_DirOutput;
157
158 if (def->eDomain == OMX_PortDomainVideo)
159 {
160 def->format.video.eColorFormat = OMX_COLOR_FormatUnused;
161 def->format.video.eCompressionFormat = mmalil_encoding_to_omx_video_coding(mmal->format->encoding);
162 if (def->format.video.eCompressionFormat == OMX_VIDEO_CodingUnused)
163 def->format.video.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
164
165 def->format.video.nBitrate = mmal->format->bitrate;
166 def->format.video.nFrameWidth = mmal->format->es->video.width;
167 if (mmal->format->es->video.crop.width)
168 def->format.video.nFrameWidth = mmal->format->es->video.crop.width;
169 def->format.video.nStride = mmal->format->es->video.width;
170 if (port->no_cropping)
171 def->format.video.nFrameWidth = def->format.video.nStride;
172 def->format.video.nStride =
173 mmal_encoding_width_to_stride(mmal->format->encoding, def->format.video.nStride);
174 def->format.video.nFrameHeight = mmal->format->es->video.height;
175 if (mmal->format->es->video.crop.height)
176 def->format.video.nFrameHeight = mmal->format->es->video.crop.height;
177 def->format.video.nSliceHeight = mmal->format->es->video.height;
178 if (port->no_cropping)
179 def->format.video.nFrameHeight = def->format.video.nSliceHeight;
180 if (mmal->format->es->video.frame_rate.den)
181 def->format.video.xFramerate = (((int64_t)mmal->format->es->video.frame_rate.num) << 16) /
182 mmal->format->es->video.frame_rate.den;
183 else
184 def->format.video.xFramerate = 0;
185 }
186 else if (def->eDomain == OMX_PortDomainImage)
187 {
188 def->format.image.eColorFormat = OMX_COLOR_FormatUnused;
189 def->format.image.eCompressionFormat = mmalil_encoding_to_omx_image_coding(mmal->format->encoding);
190 if (def->format.image.eCompressionFormat == OMX_IMAGE_CodingUnused)
191 def->format.image.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
192 if (mmal->format->encoding == MMAL_ENCODING_UNKNOWN)
193 def->format.image.eCompressionFormat = OMX_IMAGE_CodingAutoDetect;
194 def->format.image.nFrameWidth = mmal->format->es->video.width;
195 if (mmal->format->es->video.crop.width)
196 def->format.image.nFrameWidth = mmal->format->es->video.crop.width;
197 def->format.image.nStride = mmal->format->es->video.width;
198 if (port->no_cropping)
199 def->format.image.nFrameWidth = def->format.image.nStride;
200 def->format.image.nStride =
201 mmal_encoding_width_to_stride(mmal->format->encoding, def->format.image.nStride);
202 def->format.image.nFrameHeight = mmal->format->es->video.height;
203 if (mmal->format->es->video.crop.height)
204 def->format.image.nFrameHeight = mmal->format->es->video.crop.height;
205 def->format.image.nSliceHeight = mmal->format->es->video.height;
206 if (port->no_cropping)
207 def->format.image.nFrameHeight = def->format.image.nSliceHeight;
208 }
209 else if(def->eDomain == OMX_PortDomainAudio)
210 {
211 def->format.audio.eEncoding = mmalil_encoding_to_omx_audio_coding(mmal->format->encoding);
212 }
213 else
214 {
215 LOG_ERROR("%s: unsupported domain (%u)", mmal->name, def->eDomain);
216 status = MMAL_EINVAL;
217 goto finish;
218 }
219
220 def->nBufferAlignment = mmal->buffer_alignment_min;
221 def->nBufferCountActual = mmal->buffer_num;
222 def->nBufferCountMin = mmal->buffer_num_min;
223 def->nBufferSize = mmal->buffer_size;
224 if (def->nBufferSize < mmal->buffer_size_min)
225 def->nBufferSize = mmal->buffer_size_min;
226 def->bEnabled = port->enabled;
227 def->bPopulated = port->populated;
228
229 finish:
230 return status;
231}
232
233/*****************************************************************************/
234static OMX_ERRORTYPE mmalomx_ComponentGetParameter(
235 OMX_HANDLETYPE hComponent,
236 OMX_INDEXTYPE nParamIndex,
237 OMX_PTR pParam)
238{
239 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
240 MMALOMX_PORT_T *port = NULL;
241
242 LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
243 hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
244
245 /* Sanity checks */
246 if (!hComponent)
247 return OMX_ErrorInvalidComponent;
248 if (!pParam)
249 return OMX_ErrorBadParameter;
250 if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
251 return OMX_ErrorBadParameter;
252 if (component->state == OMX_StateInvalid)
253 return OMX_ErrorInvalidState;
254
255 switch(nParamIndex)
256 {
257 case OMX_IndexParamAudioInit:
258 case OMX_IndexParamVideoInit:
259 case OMX_IndexParamImageInit:
260 case OMX_IndexParamOtherInit:
261 {
262 OMX_PORT_PARAM_TYPE *param = (OMX_PORT_PARAM_TYPE *)pParam;
263 param->nStartPortNumber = 0;
264 param->nPorts = component->ports_domain_num[OMX_PortDomainAudio];
265 if (nParamIndex == OMX_IndexParamAudioInit)
266 return OMX_ErrorNone;
267 param->nStartPortNumber += param->nPorts;
268 param->nPorts = component->ports_domain_num[OMX_PortDomainVideo];
269 if (nParamIndex == OMX_IndexParamVideoInit)
270 return OMX_ErrorNone;
271 param->nStartPortNumber += param->nPorts;
272 param->nPorts = component->ports_domain_num[OMX_PortDomainImage];
273 if (nParamIndex == OMX_IndexParamImageInit)
274 return OMX_ErrorNone;
275 param->nStartPortNumber += param->nPorts;
276 param->nPorts = component->ports_domain_num[OMX_PortDomainOther];
277 }
278 return OMX_ErrorNone;
279 break;
280 case OMX_IndexParamPortDefinition:
281 {
282 OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
283 PARAM_GET_PORT(port, component, param->nPortIndex);
284 return mmalil_error_to_omx(mmalomx_get_port_settings(port, param));
285 }
286 return OMX_ErrorNone;
287 break;
288 case OMX_IndexParamCompBufferSupplier:
289 {
290 OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
291 PARAM_GET_PORT(port, component, param->nPortIndex);
292 param->eBufferSupplier = OMX_BufferSupplyUnspecified;
293 }
294 return OMX_ErrorNone;
295 break;
296 case OMX_IndexParamPriorityMgmt:
297 {
298 OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
299 param->nGroupPriority = component->group_priority;
300 param->nGroupID = component->group_id;
301 }
302 return OMX_ErrorNone;
303 break;
304 case OMX_IndexParamVideoPortFormat:
305 case OMX_IndexParamAudioPortFormat:
306 {
307 OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
308 PARAM_GET_PORT(port, component, param->nPortIndex);
309
310 /* Populate our internal list of encodings the first time around */
311 if (!port->encodings_num)
312 {
313 port->encodings_header.id = MMAL_PARAMETER_SUPPORTED_ENCODINGS;
314 port->encodings_header.size = sizeof(port->encodings_header) + sizeof(port->encodings);
315 if (mmal_port_parameter_get(port->mmal, &port->encodings_header) == MMAL_SUCCESS)
316 {
317 port->encodings_num = (port->encodings_header.size - sizeof(port->encodings_header)) /
318 sizeof(port->encodings[0]);
319 }
320 if (!port->encodings_num)
321 {
322 port->encodings_num = 1;
323 port->encodings[0] = port->mmal->format->encoding;
324 }
325 }
326
327 if (param->nIndex >= port->encodings_num)
328 return OMX_ErrorNoMore;
329
330 if (nParamIndex == OMX_IndexParamVideoPortFormat)
331 {
332 param->eColorFormat = OMX_COLOR_FormatUnused;
333 param->eCompressionFormat =
334 mmalil_encoding_to_omx_video_coding(port->encodings[param->nIndex]);
335 if (param->eCompressionFormat == OMX_VIDEO_CodingUnused)
336 param->eColorFormat =
337 mmalil_encoding_to_omx_color_format(port->encodings[param->nIndex]);
338 param->xFramerate = 0;
339 }
340 else
341 {
342 OMX_AUDIO_PARAM_PORTFORMATTYPE *aparam =
343 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
344 aparam->eEncoding =
345 mmalil_encoding_to_omx_audio_coding(port->encodings[param->nIndex]);
346 }
347 return OMX_ErrorNone;
348 }
349 break;
350 case OMX_IndexParamImagePortFormat:
351 case OMX_IndexParamOtherPortFormat:
352 break;
353 case OMX_IndexParamStandardComponentRole:
354 {
355 OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
356 const char *role = mmalomx_role_to_name(component->role);
357 if (!role)
358 role = component->name;
359 snprintf((char *)param->cRole, sizeof(param->cRole), "%s", role);
360 }
361 return OMX_ErrorNone;
362 default:
363 return mmalomx_parameter_get(component, nParamIndex, pParam);
364 }
365
366 return OMX_ErrorNotImplemented;
367}
368
369/*****************************************************************************/
370static MMAL_STATUS_T mmalomx_set_port_settings(MMALOMX_PORT_T *mmalomx_port,
371 OMX_PARAM_PORTDEFINITIONTYPE *def)
372{
373 MMAL_PORT_T *port = mmalomx_port->mmal;
374 uint32_t buffer_size_min = port->buffer_size_min;
375 MMAL_STATUS_T status;
376
377 port->format->type = mmalil_omx_domain_to_es_type(def->eDomain);
378 port->format->encoding_variant = 0;
379
380 if(def->eDomain == OMX_PortDomainVideo)
381 {
382 if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused)
383 port->format->encoding = mmalil_omx_video_coding_to_encoding(def->format.video.eCompressionFormat);
384 else
385 port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.video.eColorFormat);
386
387 port->format->bitrate = def->format.video.nBitrate;
388 port->format->es->video.width = def->format.video.nFrameWidth;
389 if (!mmalomx_port->no_cropping)
390 port->format->es->video.crop.width = port->format->es->video.width;
391 if (mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride))
392 port->format->es->video.width =
393 mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride);
394 port->format->es->video.height = def->format.video.nFrameHeight;
395 if (!mmalomx_port->no_cropping)
396 port->format->es->video.crop.height = port->format->es->video.height;
397 if (def->format.video.nSliceHeight > def->format.video.nFrameHeight)
398 port->format->es->video.height = def->format.video.nSliceHeight;
399 port->format->es->video.frame_rate.num = def->format.video.xFramerate;
400 port->format->es->video.frame_rate.den = (1<<16);
401 }
402 else if(def->eDomain == OMX_PortDomainImage)
403 {
404 if (def->format.image.eCompressionFormat != OMX_IMAGE_CodingUnused)
405 port->format->encoding = mmalil_omx_image_coding_to_encoding(def->format.image.eCompressionFormat);
406 else
407 port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.image.eColorFormat);
408
409 port->format->es->video.width = def->format.image.nFrameWidth;
410 if (!mmalomx_port->no_cropping)
411 port->format->es->video.crop.width = port->format->es->video.width;
412 if (mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride))
413 port->format->es->video.width =
414 mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride);
415 port->format->es->video.height = def->format.image.nFrameHeight;
416 if (!mmalomx_port->no_cropping)
417 port->format->es->video.crop.height = port->format->es->video.height;
418 if (def->format.image.nSliceHeight > def->format.image.nFrameHeight)
419 port->format->es->video.height = def->format.image.nSliceHeight;
420 }
421 else if(def->eDomain == OMX_PortDomainAudio)
422 {
423 port->format->encoding = mmalil_omx_audio_coding_to_encoding(def->format.audio.eEncoding);
424 }
425 else
426 {
427 port->format->encoding = MMAL_ENCODING_UNKNOWN;
428 }
429
430 port->buffer_num = def->nBufferCountActual;
431 port->buffer_size = def->nBufferSize;
432 if (port->buffer_size < port->buffer_size_min)
433 port->buffer_size = port->buffer_size_min;
434
435 status = mmal_port_format_commit(port);
436 if (status != MMAL_SUCCESS)
437 return status;
438
439 /* Acknowledge any ongoing port format changed event */
440 mmalomx_port->format_changed = MMAL_FALSE;
441
442 /* The minimum buffer size only changes when the format significantly changes
443 * and in that case we want to advertise the new requirement to the client. */
444 if (port->buffer_size_min != buffer_size_min)
445 port->buffer_size = port->buffer_size_min;
446
447 return MMAL_SUCCESS;
448}
449
450/*****************************************************************************/
451static OMX_ERRORTYPE mmalomx_ComponentSetParameter(
452 OMX_HANDLETYPE hComponent,
453 OMX_INDEXTYPE nParamIndex,
454 OMX_PTR pParam)
455{
456 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
457 MMALOMX_PORT_T *port = NULL;
458
459 LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
460 hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
461
462 /* Sanity checks */
463 if (!hComponent)
464 return OMX_ErrorInvalidComponent;
465 if (!pParam)
466 return OMX_ErrorBadParameter;
467 if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
468 return OMX_ErrorBadParameter;
469 if (component->state == OMX_StateInvalid)
470 return OMX_ErrorInvalidState;
471
472 switch(nParamIndex)
473 {
474 case OMX_IndexParamPortDefinition:
475 {
476 OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
477 PARAM_GET_PORT(port, component, param->nPortIndex);
478 return mmalil_error_to_omx(mmalomx_set_port_settings(port, param));
479 }
480 return OMX_ErrorNone;
481 break;
482 case OMX_IndexParamCompBufferSupplier:
483 {
484 OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
485 PARAM_GET_PORT(port, component, param->nPortIndex);
486 //param->eBufferSupplier = OMX_BufferSupplyUnspecified;
487 }
488 return OMX_ErrorNone;
489 break;
490 case OMX_IndexParamPriorityMgmt:
491 {
492 OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
493
494 if (component->state != OMX_StateLoaded)
495 return OMX_ErrorIncorrectStateOperation;
496
497 component->group_priority = param->nGroupPriority;
498 component->group_id = param->nGroupID;
499 }
500 return OMX_ErrorNone;
501 break;
502 case OMX_IndexParamAudioPortFormat:
503 {
504 OMX_AUDIO_PARAM_PORTFORMATTYPE *param = (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
505 PARAM_GET_PORT(port, component, param->nPortIndex);
506 port->mmal->format->encoding = mmalil_omx_audio_coding_to_encoding(param->eEncoding);
507 port->mmal->format->encoding_variant = 0;
508 if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
509 LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
510 return OMX_ErrorNone;
511 }
512 break;
513 case OMX_IndexParamVideoPortFormat:
514 {
515 OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
516 PARAM_GET_PORT(port, component, param->nPortIndex);
517 if (param->eCompressionFormat != OMX_VIDEO_CodingUnused)
518 port->mmal->format->encoding = mmalil_omx_video_coding_to_encoding(param->eCompressionFormat);
519 else
520 port->mmal->format->encoding = mmalil_omx_color_format_to_encoding(param->eColorFormat);
521 port->mmal->format->encoding_variant = 0;
522
523 if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
524 LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
525 return OMX_ErrorNone;
526 }
527 break;
528 case OMX_IndexParamImagePortFormat:
529 case OMX_IndexParamOtherPortFormat:
530 break;
531 case OMX_IndexParamStandardComponentRole:
532 {
533 OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
534 return mmalomx_role_set(component, (const char *)param->cRole);
535 }
536 break;
537 default:
538 {
539 OMX_ERRORTYPE status = mmalomx_parameter_set(component, nParamIndex, pParam);
540
541 /* Keep track of the zero-copy state */
542 if (status == OMX_ErrorNone && nParamIndex == OMX_IndexParamBrcmZeroCopy)
543 {
544 PARAM_GET_PORT(port, component, ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->nPortIndex);
545 port->zero_copy = ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->bEnabled;
546 }
547
548 return status;
549 }
550 }
551
552 return OMX_ErrorNotImplemented;
553}
554
555/*****************************************************************************/
556static OMX_ERRORTYPE mmalomx_ComponentGetConfig(
557 OMX_HANDLETYPE hComponent,
558 OMX_INDEXTYPE nParamIndex,
559 OMX_PTR pParam)
560{
561 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
562
563 LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
564 hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
565
566 /* Sanity checks */
567 if (!hComponent)
568 return OMX_ErrorInvalidComponent;
569 if (!pParam)
570 return OMX_ErrorBadParameter;
571 if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
572 return OMX_ErrorBadParameter;
573 if (component->state == OMX_StateInvalid)
574 return OMX_ErrorInvalidState;
575
576 return mmalomx_parameter_get(component, nParamIndex, pParam);
577}
578
579/*****************************************************************************/
580static OMX_ERRORTYPE mmalomx_ComponentSetConfig(
581 OMX_HANDLETYPE hComponent,
582 OMX_INDEXTYPE nParamIndex,
583 OMX_PTR pParam)
584{
585 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
586
587 LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
588 hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
589
590 /* Sanity checks */
591 if (!hComponent)
592 return OMX_ErrorInvalidComponent;
593 if (!pParam)
594 return OMX_ErrorBadParameter;
595 if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
596 return OMX_ErrorBadParameter;
597 if (component->state == OMX_StateInvalid)
598 return OMX_ErrorInvalidState;
599
600 return mmalomx_parameter_set(component, nParamIndex, pParam);
601}
602
603/*****************************************************************************/
604static OMX_ERRORTYPE mmalomx_ComponentGetExtensionIndex(
605 OMX_HANDLETYPE hComponent,
606 OMX_STRING cParameterName,
607 OMX_INDEXTYPE* pIndexType)
608{
609 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
610
611 LOG_TRACE("hComponent %p, cParameterName %s, pIndexType %p",
612 hComponent, cParameterName, pIndexType);
613
614 /* Sanity checks */
615 if (!hComponent)
616 return OMX_ErrorInvalidComponent;
617 if (component->state == OMX_StateInvalid)
618 return OMX_ErrorInvalidState;
619
620 return mmalomx_parameter_extension_index_get(cParameterName, pIndexType);
621}
622
623/*****************************************************************************/
624static OMX_ERRORTYPE mmalomx_ComponentGetState(
625 OMX_HANDLETYPE hComponent,
626 OMX_STATETYPE* pState)
627{
628 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
629 MMAL_PARAM_UNUSED(component);
630
631 LOG_TRACE("hComponent %p, pState, %p", hComponent, pState);
632
633 /* Sanity checks */
634 if (!hComponent)
635 return OMX_ErrorInvalidComponent;
636 if (!pState)
637 return OMX_ErrorBadParameter;
638
639 *pState = component->state;
640 return OMX_ErrorNone;
641}
642
643/*****************************************************************************/
644static OMX_ERRORTYPE mmalomx_ComponentTunnelRequest(
645 OMX_HANDLETYPE hComponent,
646 OMX_U32 nPort,
647 OMX_HANDLETYPE hTunneledComp,
648 OMX_U32 nTunneledPort,
649 OMX_TUNNELSETUPTYPE* pTunnelSetup)
650{
651 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
652 MMAL_PARAM_UNUSED(component);
653
654 LOG_TRACE("hComponent %p, nPort %i, hTunneledComp %p, nTunneledPort %i, "
655 "pTunnelSetup %p", hComponent, (int)nPort, hTunneledComp,
656 (int)nTunneledPort, pTunnelSetup);
657
658 /* Sanity checks */
659 if (!hComponent)
660 return OMX_ErrorInvalidComponent;
661 if (component->state == OMX_StateInvalid)
662 return OMX_ErrorInvalidState;
663 if (nPort >= component->ports_num)
664 return OMX_ErrorBadPortIndex;
665 if (component->state != OMX_StateLoaded && component->ports[nPort].enabled)
666 return OMX_ErrorIncorrectStateOperation;
667 if (hTunneledComp && !pTunnelSetup)
668 return OMX_ErrorBadParameter;
669
670 if (!hTunneledComp)
671 return OMX_ErrorNone;
672 return OMX_ErrorNotImplemented;
673}
674
675/*****************************************************************************/
676static OMX_ERRORTYPE mmalomx_ComponentUseBuffer(
677 OMX_HANDLETYPE hComponent,
678 OMX_BUFFERHEADERTYPE** ppBuffer,
679 OMX_U32 nPortIndex,
680 OMX_PTR pAppPrivate,
681 OMX_U32 nSizeBytes,
682 OMX_U8* pBuffer)
683{
684 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
685 OMX_ERRORTYPE status = OMX_ErrorNone;
686 MMAL_BOOL_T populated = MMAL_FALSE;
687 OMX_BUFFERHEADERTYPE *buffer;
688 MMALOMX_PORT_T *port;
689
690 LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
691 " nSizeBytes %i, pBuffer %p", hComponent, ppBuffer,
692 (int)nPortIndex, pAppPrivate, (int)nSizeBytes, pBuffer);
693
694 /* Sanity checks */
695 if (!hComponent)
696 return OMX_ErrorInvalidComponent;
697 if (!ppBuffer)
698 return OMX_ErrorBadParameter;
699 if (component->state == OMX_StateInvalid)
700 return OMX_ErrorInvalidState;
701 if (nPortIndex >= component->ports_num)
702 return OMX_ErrorBadPortIndex;
703
704 /* Make sure any previous command has been processed.
705 * This is not ideal since done inline but in practice the actual
706 * notification to the client will not be done as part of this call. */
707 mmalomx_commands_actions_check(component);
708
709 port = &component->ports[nPortIndex];
710 MMALOMX_LOCK_PORT(component, port);
711
712 if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
713 status = OMX_ErrorIncorrectStateOperation;
714 if (port->populated)
715 status = OMX_ErrorIncorrectStateOperation;
716 if (status != OMX_ErrorNone)
717 goto error;
718
719 /* Check for mismatched calls to UseBuffer/AllocateBuffer */
720 if (port->buffers && port->buffers_allocated)
721 {
722 status = OMX_ErrorBadParameter;
723 goto error;
724 }
725
726 /* Sanity check buffer size */
727 if (nSizeBytes < port->mmal->buffer_size_min)
728 {
729 LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
730 (int)port->mmal->buffer_size_min);
731 status = OMX_ErrorBadParameter;
732 goto error;
733 }
734 if (!port->buffers)
735 port->mmal->buffer_size = nSizeBytes;
736 if (nSizeBytes > port->mmal->buffer_size)
737 {
738 LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
739 (int)port->mmal->buffer_size);
740 status = OMX_ErrorBadParameter;
741 goto error;
742 }
743
744 buffer = calloc( 1, sizeof(*buffer) );
745 if (!buffer)
746 {
747 status = OMX_ErrorInsufficientResources;
748 goto error;
749 }
750
751 buffer->nSize = sizeof(*buffer);
752 buffer->nVersion.nVersion = OMX_VERSION;
753 buffer->nAllocLen = nSizeBytes;
754 buffer->pBuffer = pBuffer;
755 buffer->pAppPrivate = pAppPrivate;
756 if (port->direction == OMX_DirInput)
757 {
758 buffer->nInputPortIndex = nPortIndex;
759 buffer->pOutputPortPrivate = pAppPrivate;
760 }
761 else
762 {
763 buffer->nOutputPortIndex = nPortIndex;
764 buffer->pInputPortPrivate = pAppPrivate;
765 }
766
767 *ppBuffer = buffer;
768 port->buffers++;
769 port->buffers_allocated = MMAL_FALSE;
770 port->populated = populated = port->buffers == port->mmal->buffer_num;
771
772 MMALOMX_UNLOCK_PORT(component, port);
773
774 LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
775
776 if (populated)
777 mmalomx_commands_actions_signal(component);
778
779 return OMX_ErrorNone;
780
781error:
782 MMALOMX_UNLOCK_PORT(component, port);
783 return status;
784}
785
786/*****************************************************************************/
787static OMX_ERRORTYPE mmalomx_ComponentAllocateBuffer(
788 OMX_HANDLETYPE hComponent,
789 OMX_BUFFERHEADERTYPE** ppBuffer,
790 OMX_U32 nPortIndex,
791 OMX_PTR pAppPrivate,
792 OMX_U32 nSizeBytes)
793{
794 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
795 OMX_ERRORTYPE status = OMX_ErrorNone;
796 MMAL_BOOL_T populated = MMAL_FALSE;
797 OMX_BUFFERHEADERTYPE *buffer = 0;
798 MMALOMX_PORT_T *port;
799
800 LOG_TRACE("hComponent %p, ppBuffer %p, nPortIndex %i, pAppPrivate %p, "
801 "nSizeBytes %i", hComponent, ppBuffer, (int)nPortIndex,
802 pAppPrivate, (int)nSizeBytes);
803
804 /* Sanity checks */
805 if (!hComponent)
806 return OMX_ErrorInvalidComponent;
807 if (!ppBuffer)
808 return OMX_ErrorBadParameter;
809 if (component->state == OMX_StateInvalid)
810 return OMX_ErrorInvalidState;
811 if (nPortIndex >= component->ports_num)
812 return OMX_ErrorBadPortIndex;
813
814 /* Make sure any previous command has been processed.
815 * This is not ideal since done inline but in practice the actual
816 * notification to the client will not be done as part of this call. */
817 mmalomx_commands_actions_check(component);
818
819 port = &component->ports[nPortIndex];
820 MMALOMX_LOCK_PORT(component, port);
821
822 if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
823 status = OMX_ErrorIncorrectStateOperation;
824 if (port->populated)
825 status = OMX_ErrorIncorrectStateOperation;
826 if (status != OMX_ErrorNone)
827 goto error;
828
829 /* Check for mismatched calls to UseBuffer/AllocateBuffer */
830 if (!status && port->buffers && !port->buffers_allocated)
831 {
832 status = OMX_ErrorBadParameter;
833 goto error;
834 }
835
836 /* Sanity check buffer size */
837 if (nSizeBytes < port->mmal->buffer_size_min)
838 {
839 LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
840 (int)port->mmal->buffer_size_min);
841 status = OMX_ErrorBadParameter;
842 goto error;
843 }
844 if (!port->buffers)
845 port->mmal->buffer_size = nSizeBytes;
846 if (nSizeBytes > port->mmal->buffer_size)
847 {
848 LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
849 (int)port->mmal->buffer_size);
850 status = OMX_ErrorBadParameter;
851 goto error;
852 }
853
854 /* Set the zero-copy mode */
855 if (!port->buffers_allocated && nSizeBytes > MMALOMX_ZERO_COPY_THRESHOLD &&
856 !port->zero_copy)
857 {
858 MMAL_STATUS_T status = mmal_port_parameter_set_boolean(port->mmal,
859 MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
860 if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
861 LOG_ERROR("failed to enable zero copy on %s", port->mmal->name);
862 }
863
864 buffer = calloc( 1, sizeof(*buffer) );
865 if (!buffer)
866 {
867 status = OMX_ErrorInsufficientResources;
868 goto error;
869 }
870
871 buffer->pBuffer = mmal_port_payload_alloc(port->mmal, nSizeBytes);
872 if (!buffer->pBuffer)
873 {
874 status = OMX_ErrorInsufficientResources;
875 goto error;
876 }
877
878 buffer->nSize = sizeof(*buffer);
879 buffer->nVersion.nVersion = OMX_VERSION;
880 buffer->nAllocLen = nSizeBytes;
881 buffer->pAppPrivate = pAppPrivate;
882 if (port->direction == OMX_DirInput)
883 {
884 buffer->nInputPortIndex = nPortIndex;
885 buffer->pOutputPortPrivate = pAppPrivate;
886 }
887 else
888 {
889 buffer->nOutputPortIndex = nPortIndex;
890 buffer->pInputPortPrivate = pAppPrivate;
891 }
892 /* Keep an unmodified copy of the pointer for when we come to free it */
893 buffer->pPlatformPrivate = (OMX_PTR)buffer->pBuffer;
894
895 *ppBuffer = buffer;
896 port->buffers++;
897 port->buffers_allocated = MMAL_TRUE;
898 port->populated = populated = port->buffers == port->mmal->buffer_num;
899
900 MMALOMX_UNLOCK_PORT(component, port);
901
902 LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
903
904 if (populated)
905 mmalomx_commands_actions_signal(component);
906
907 return OMX_ErrorNone;
908
909error:
910 if (!port->buffers_allocated && !port->zero_copy)
911 mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
912
913 MMALOMX_UNLOCK_PORT(component, port);
914 LOG_ERROR("failed to allocate %i/%i buffers", port->buffers, port->mmal->buffer_num);
915 if (buffer)
916 free(buffer);
917 return status;
918}
919
920/*****************************************************************************/
921static OMX_ERRORTYPE mmalomx_ComponentFreeBuffer(
922 OMX_HANDLETYPE hComponent,
923 OMX_U32 nPortIndex,
924 OMX_BUFFERHEADERTYPE* pBuffer)
925{
926 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
927 OMX_ERRORTYPE status = OMX_ErrorNone;
928 MMAL_BOOL_T unpopulated, allocated;
929 MMALOMX_PORT_T *port;
930 unsigned int buffers;
931
932 LOG_TRACE("hComponent %p, nPortIndex %i, pBuffer %p",
933 hComponent, (int)nPortIndex, pBuffer);
934
935 /* Sanity checks */
936 if (!hComponent)
937 return OMX_ErrorInvalidComponent;
938 if (!pBuffer)
939 return OMX_ErrorBadParameter;
940 if (nPortIndex >= component->ports_num)
941 return OMX_ErrorBadPortIndex;
942
943 /* Make sure any previous command has been processed.
944 * This is not ideal since done inline but in practice the actual
945 * notification to the client will not be done as part of this call. */
946 mmalomx_commands_actions_check(component);
947
948 port = &component->ports[nPortIndex];
949 MMALOMX_LOCK_PORT(component, port);
950
951 if (!port->buffers)
952 {
953 status = OMX_ErrorBadParameter;
954 goto error;
955 }
956
957 buffers = --port->buffers;
958 port->populated = MMAL_FALSE;
959 unpopulated = !(port->actions & MMALOMX_ACTION_CHECK_DEALLOCATED);
960 allocated = port->buffers_allocated;
961
962 MMALOMX_UNLOCK_PORT(component, port);
963
964 if (allocated) /* Free the unmodified pointer */
965 mmal_port_payload_free(port->mmal, pBuffer->pPlatformPrivate);
966 free(pBuffer);
967
968 if (allocated && !port->zero_copy) /* Reset the zero-copy status */
969 mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
970
971 LOG_DEBUG("freed %i/%i buffers", port->mmal->buffer_num - port->buffers, port->mmal->buffer_num);
972
973 if (unpopulated)
974 mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorPortUnpopulated, 0, NULL);
975
976 if (!buffers)
977 mmalomx_commands_actions_signal(component);
978
979 return OMX_ErrorNone;
980
981error:
982 MMALOMX_UNLOCK_PORT(component, port);
983 return status;
984}
985
986/*****************************************************************************/
987static OMX_ERRORTYPE mmalomx_ComponentEmptyThisBuffer(
988 OMX_HANDLETYPE hComponent,
989 OMX_BUFFERHEADERTYPE* pBuffer)
990{
991 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
992
993 if (ENABLE_MMAL_EXTRA_LOGGING)
994 LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
995 pBuffer ? (int)pBuffer->nInputPortIndex : -1, pBuffer);
996
997 return mmalomx_buffer_send(component, pBuffer, OMX_DirInput);
998}
999
1000/*****************************************************************************/
1001static OMX_ERRORTYPE mmalomx_ComponentFillThisBuffer(
1002 OMX_HANDLETYPE hComponent,
1003 OMX_BUFFERHEADERTYPE* pBuffer)
1004{
1005 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1006
1007 if (ENABLE_MMAL_EXTRA_LOGGING)
1008 LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
1009 pBuffer ? (int)pBuffer->nOutputPortIndex : -1, pBuffer);
1010
1011 return mmalomx_buffer_send(component, pBuffer, OMX_DirOutput);
1012}
1013
1014/*****************************************************************************/
1015static OMX_ERRORTYPE mmalomx_ComponentSetCallbacks(
1016 OMX_HANDLETYPE hComponent,
1017 OMX_CALLBACKTYPE* pCallbacks,
1018 OMX_PTR pAppData)
1019{
1020 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1021 MMAL_PARAM_UNUSED(component);
1022
1023 LOG_TRACE("hComponent %p, pCallbacks %p, pAppData %p",
1024 hComponent, pCallbacks, pAppData);
1025
1026 /* Sanity checks */
1027 if (!hComponent)
1028 return OMX_ErrorInvalidComponent;
1029 if (!pCallbacks)
1030 return OMX_ErrorBadParameter;
1031 if (component->state == OMX_StateInvalid)
1032 return OMX_ErrorInvalidState;
1033
1034 if (component->state != OMX_StateLoaded)
1035 return OMX_ErrorInvalidState;
1036
1037 component->callbacks = *pCallbacks;
1038 component->callbacks_data = pAppData;
1039 return OMX_ErrorNone;
1040}
1041
1042/*****************************************************************************/
1043static OMX_ERRORTYPE mmalomx_ComponentDeInit(
1044 OMX_HANDLETYPE hComponent)
1045{
1046 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1047 MMAL_PARAM_UNUSED(component);
1048
1049 LOG_TRACE("hComponent %p", hComponent);
1050
1051 /* Sanity checks */
1052 if (!hComponent)
1053 return OMX_ErrorInvalidComponent;
1054
1055 return OMX_ErrorNone;
1056}
1057
1058/*****************************************************************************/
1059static OMX_ERRORTYPE mmalomx_ComponentUseEGLImage(
1060 OMX_HANDLETYPE hComponent,
1061 OMX_BUFFERHEADERTYPE** ppBufferHdr,
1062 OMX_U32 nPortIndex,
1063 OMX_PTR pAppPrivate,
1064 void* eglImage)
1065{
1066 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1067 MMAL_PARAM_UNUSED(component);
1068
1069 LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
1070 " eglImage %p", hComponent, ppBufferHdr, (int)nPortIndex,
1071 pAppPrivate, eglImage);
1072
1073 /* Sanity checks */
1074 if (!hComponent)
1075 return OMX_ErrorInvalidComponent;
1076 if (component->state == OMX_StateInvalid)
1077 return OMX_ErrorInvalidState;
1078
1079 return OMX_ErrorNotImplemented;
1080}
1081
1082/*****************************************************************************/
1083static OMX_ERRORTYPE mmalomx_ComponentRoleEnum(
1084 OMX_HANDLETYPE hComponent,
1085 OMX_U8 *cRole,
1086 OMX_U32 nIndex)
1087{
1088 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1089 MMALOMX_ROLE_T role;
1090
1091 LOG_TRACE("hComponent %p, cRole %p, nIndex %i",
1092 hComponent, cRole, (int)nIndex);
1093
1094 /* Sanity checks */
1095 if (!hComponent)
1096 return OMX_ErrorInvalidComponent;
1097 if (component->state == OMX_StateInvalid)
1098 return OMX_ErrorInvalidState;
1099
1100 role = mmalomx_registry_component_roles(component->registry_id, nIndex);
1101 if (!role)
1102 return OMX_ErrorNoMore;
1103 if (!mmalomx_role_to_name(role))
1104 return OMX_ErrorNoMore;
1105
1106 strcpy((char *)cRole, mmalomx_role_to_name(role));
1107 return OMX_ErrorNone;
1108}
1109
1110/*****************************************************************************/
1111OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Init)(void)
1112{
1113 mmalomx_logging_init();
1114 LOG_TRACE("Init");
1115 return OMX_ErrorNone;
1116}
1117
1118/*****************************************************************************/
1119OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Deinit)(void)
1120{
1121 LOG_TRACE("Deinit");
1122 mmalomx_logging_deinit();
1123 return OMX_ErrorNone;
1124}
1125
1126/*****************************************************************************/
1127OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_ComponentNameEnum)(
1128 OMX_STRING cComponentName,
1129 OMX_U32 nNameLength,
1130 OMX_U32 nIndex)
1131{
1132 const char *prefix, *name;
1133 name = mmalomx_registry_component_name(nIndex, &prefix);
1134
1135 LOG_TRACE("cComponentName %p, nNameLength %i, nIndex %i",
1136 cComponentName, (int)nNameLength, (int)nIndex);
1137
1138 /* Sanity checking */
1139 if (!cComponentName)
1140 return OMX_ErrorBadParameter;
1141 if (!name)
1142 return OMX_ErrorNoMore;
1143 if (nNameLength <= strlen(name) + strlen(prefix))
1144 return OMX_ErrorBadParameter;
1145
1146 sprintf(cComponentName, "%s%s", prefix, name);
1147 LOG_TRACE("cComponentName: %s", cComponentName);
1148 return OMX_ErrorNone;
1149}
1150
1151/*****************************************************************************/
1152static void mmalomx_buffer_cb_control(
1153 MMAL_PORT_T *port,
1154 MMAL_BUFFER_HEADER_T *buffer)
1155{
1156 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)port->userdata;
1157
1158 LOG_DEBUG("received event %4.4s on port %s", (char *)&buffer->cmd, port->name);
1159
1160 if (buffer->cmd == MMAL_EVENT_ERROR)
1161 {
1162 mmalomx_callback_event_handler(component, OMX_EventError,
1163 mmalil_error_to_omx(*(MMAL_STATUS_T *)buffer->data), 0, NULL);
1164 }
1165 else if (buffer->cmd == MMAL_EVENT_EOS &&
1166 buffer->length == sizeof(MMAL_EVENT_END_OF_STREAM_T))
1167 {
1168 MMAL_EVENT_END_OF_STREAM_T *eos = (MMAL_EVENT_END_OF_STREAM_T *)buffer->data;
1169 if (eos->port_index < port->component->input_num)
1170 {
1171 MMALOMX_PORT_T *omx_port = (MMALOMX_PORT_T *)
1172 port->component->input[eos->port_index]->userdata;
1173 LOG_DEBUG("send EOS on %i", omx_port->index);
1174 mmalomx_callback_event_handler(component, OMX_EventBufferFlag,
1175 omx_port->index, OMX_BUFFERFLAG_EOS, NULL);
1176 }
1177 }
1178
1179 mmal_buffer_header_release(buffer);
1180}
1181
1182/*****************************************************************************/
1183OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_GetHandle)(
1184 OMX_HANDLETYPE* pHandle,
1185 OMX_STRING cComponentName,
1186 OMX_PTR pAppData,
1187 OMX_CALLBACKTYPE* pCallBacks)
1188{
1189 OMX_ERRORTYPE status = OMX_ErrorInsufficientResources;
1190 MMALOMX_COMPONENT_T *component = 0;
1191 MMAL_COMPONENT_T *mmal_component = 0;
1192 MMAL_STATUS_T mmal_status;
1193 unsigned int i, ports_num;
1194 OMX_PORTDOMAINTYPE domain;
1195 const char *mmal_name;
1196 int registry_id;
1197
1198 LOG_TRACE("pHandle %p, cComponentName %s, pAppData %p, pCallBacks %p",
1199 pHandle, cComponentName, pAppData, pCallBacks);
1200
1201 /* Sanity check params */
1202 if (!pHandle || !cComponentName || !pCallBacks)
1203 return OMX_ErrorBadParameter;
1204
1205 /* Find component */
1206 registry_id = mmalomx_registry_find_component(cComponentName);
1207 if (registry_id < 0)
1208 return OMX_ErrorComponentNotFound;
1209
1210 /* create and setup component */
1211 mmal_name = mmalomx_registry_component_mmal(registry_id);
1212 mmal_status = mmal_component_create(mmal_name, &mmal_component);
1213 if (mmal_status != MMAL_SUCCESS)
1214 {
1215 LOG_ERROR("could not create mmal component %s", mmal_name);
1216 return mmalil_error_to_omx(mmal_status);
1217 }
1218 mmal_status = mmal_port_enable(mmal_component->control, mmalomx_buffer_cb_control);
1219 if (mmal_status != MMAL_SUCCESS)
1220 {
1221 LOG_ERROR("could not enable %s", mmal_component->control->name);
1222 mmal_component_destroy(mmal_component);
1223 return mmalil_error_to_omx(mmal_status);
1224 }
1225
1226 ports_num = mmal_component->port_num - 1;
1227
1228 component = calloc(1, sizeof(*component) + ports_num * sizeof(*component->ports));
1229 if (!component)
1230 {
1231 mmal_component_destroy(mmal_component);
1232 return OMX_ErrorInsufficientResources;
1233 }
1234
1235 if (vcos_mutex_create(&component->lock, "mmalomx lock") != VCOS_SUCCESS)
1236 {
1237 mmal_component_destroy(mmal_component);
1238 free(component);
1239 return OMX_ErrorInsufficientResources;
1240 }
1241 if (vcos_mutex_create(&component->lock_port, "mmalomx port lock") != VCOS_SUCCESS)
1242 {
1243 vcos_mutex_delete(&component->lock);
1244 mmal_component_destroy(mmal_component);
1245 free(component);
1246 return OMX_ErrorInsufficientResources;
1247 }
1248
1249 component->omx.nSize = sizeof(component->omx);
1250 component->omx.nVersion.nVersion = OMX_VERSION;
1251 component->mmal = mmal_component;
1252 component->state = OMX_StateLoaded;
1253 component->callbacks = *pCallBacks;
1254 component->callbacks_data = pAppData;
1255 component->ports = (MMALOMX_PORT_T *)&component[1];
1256 component->registry_id = registry_id;
1257 component->name = mmalomx_registry_component_name(registry_id, 0);
1258 component->role = mmalomx_registry_component_roles(registry_id, 0);
1259
1260 // FIXME: make this configurable
1261 component->cmd_thread_used = MMAL_TRUE;
1262
1263 /* Sort the ports into separate OMX domains */
1264 for (domain = OMX_PortDomainAudio; domain < OMX_PortDomainOther; domain++)
1265 {
1266 for (i = 1; i < mmal_component->port_num; i++)
1267 {
1268 if (domain == mmalil_es_type_to_omx_domain(mmal_component->port[i]->format->type))
1269 {
1270 component->ports[component->ports_num].mmal = mmal_component->port[i];
1271 component->ports_domain_num[domain]++;
1272 component->ports_num++;
1273 }
1274 }
1275 }
1276 LOG_DEBUG("ports: %i audio, %i video",
1277 component->ports_domain_num[OMX_PortDomainAudio],
1278 component->ports_domain_num[OMX_PortDomainVideo]);
1279
1280 /* Setup our ports */
1281 for (i = 0; i < component->ports_num; i++)
1282 {
1283 component->ports[i].component = component;
1284 if (component->ports[i].mmal->type == MMAL_PORT_TYPE_OUTPUT)
1285 component->ports[i].direction = OMX_DirOutput;
1286 component->ports[i].index = i;
1287 component->ports[i].enabled = MMAL_TRUE;
1288 component->ports[i].pool =
1289 mmal_port_pool_create(component->ports[i].mmal, 0, 0);
1290 if (!component->ports[i].pool)
1291 goto error;
1292 component->ports[i].mmal->userdata = (struct MMAL_PORT_USERDATA_T *)&component->ports[i];
1293 }
1294 mmal_component->control->userdata = (struct MMAL_PORT_USERDATA_T *)component;
1295
1296 /* Create our OMX commands queue */
1297 component->cmd_queue = mmal_queue_create();
1298 if (!component->cmd_queue)
1299 goto error;
1300 component->cmd_pool = mmal_pool_create(MAX_CMD_BUFFERS, 0);
1301 if (!component->cmd_pool)
1302 goto error;
1303
1304 if (component->cmd_thread_used &&
1305 vcos_semaphore_create(&component->cmd_sema,
1306 "mmalomx sema", 0) != VCOS_SUCCESS)
1307 {
1308 component->cmd_thread_used = MMAL_FALSE;
1309 goto error;
1310 }
1311
1312 if (component->cmd_thread_used &&
1313 vcos_thread_create(&component->cmd_thread, component->name, NULL,
1314 mmalomx_cmd_thread_func, component) != VCOS_SUCCESS)
1315 {
1316 vcos_semaphore_delete(&component->cmd_sema);
1317 component->cmd_thread_used = MMAL_FALSE;
1318 goto error;
1319 }
1320
1321 /* Set the function pointer for the component's interface */
1322 component->omx.GetComponentVersion = mmalomx_ComponentGetComponentVersion;
1323 component->omx.SendCommand = mmalomx_ComponentSendCommand;
1324 component->omx.GetParameter = mmalomx_ComponentGetParameter;
1325 component->omx.SetParameter = mmalomx_ComponentSetParameter;
1326 component->omx.GetConfig = mmalomx_ComponentGetConfig;
1327 component->omx.SetConfig = mmalomx_ComponentSetConfig;
1328 component->omx.GetExtensionIndex = mmalomx_ComponentGetExtensionIndex;
1329 component->omx.GetState = mmalomx_ComponentGetState;
1330 component->omx.ComponentTunnelRequest = mmalomx_ComponentTunnelRequest;
1331 component->omx.UseBuffer = mmalomx_ComponentUseBuffer;
1332 component->omx.AllocateBuffer = mmalomx_ComponentAllocateBuffer;
1333 component->omx.FreeBuffer = mmalomx_ComponentFreeBuffer;
1334 component->omx.EmptyThisBuffer = mmalomx_ComponentEmptyThisBuffer;
1335 component->omx.FillThisBuffer = mmalomx_ComponentFillThisBuffer;
1336 component->omx.SetCallbacks = mmalomx_ComponentSetCallbacks;
1337 component->omx.ComponentDeInit = mmalomx_ComponentDeInit;
1338 component->omx.UseEGLImage = mmalomx_ComponentUseEGLImage;
1339 component->omx.ComponentRoleEnum = mmalomx_ComponentRoleEnum;
1340 *pHandle = (OMX_HANDLETYPE)&component->omx;
1341
1342 return OMX_ErrorNone;
1343
1344 error:
1345 MMALOMX_IMPORT(OMX_FreeHandle)((OMX_HANDLETYPE)&component->omx);
1346 return status;
1347}
1348
1349/*****************************************************************************/
1350OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_FreeHandle)(
1351 OMX_HANDLETYPE hComponent)
1352{
1353 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1354 OMX_ERRORTYPE status;
1355 unsigned int i;
1356
1357 LOG_TRACE("hComponent %p", hComponent);
1358
1359 /* Sanity check */
1360 if (!hComponent)
1361 return OMX_ErrorInvalidComponent;
1362
1363 if (component->omx.ComponentDeInit)
1364 {
1365 status = component->omx.ComponentDeInit(hComponent);
1366 if (status != OMX_ErrorNone)
1367 {
1368 LOG_ERROR("ComponentDeInit failed");
1369 return status;
1370 }
1371 }
1372
1373 if (component->cmd_thread_used)
1374 {
1375 component->cmd_thread_used = MMAL_FALSE;
1376 vcos_semaphore_post(&component->cmd_sema);
1377 vcos_thread_join(&component->cmd_thread, NULL);
1378 }
1379
1380 mmal_component_destroy(component->mmal);
1381 for (i = 0; i < component->ports_num; i++)
1382 if (component->ports[i].pool)
1383 mmal_pool_destroy(component->ports[i].pool);
1384
1385 if (component->cmd_pool)
1386 mmal_pool_destroy(component->cmd_pool);
1387 if (component->cmd_queue)
1388 mmal_queue_destroy(component->cmd_queue);
1389 if (component->cmd_thread_used)
1390 vcos_semaphore_delete(&component->cmd_sema);
1391 vcos_mutex_delete(&component->lock_port);
1392 vcos_mutex_delete(&component->lock);
1393 free(component);
1394 return OMX_ErrorNone;
1395}
1396
1397/*****************************************************************************/
1398OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetRolesOfComponent)(
1399 OMX_STRING compName,
1400 OMX_U32 *pNumRoles,
1401 OMX_U8 **roles)
1402{
1403 OMX_U32 i, num_roles;
1404 MMALOMX_ROLE_T role;
1405 int registry_id;
1406
1407 LOG_TRACE("compName %s, pNumRoles %p, roles %p", compName, pNumRoles, roles);
1408
1409 /* Sanity checks */
1410 if (!compName || !pNumRoles)
1411 return OMX_ErrorBadParameter;
1412
1413 if (!roles || *pNumRoles > MMALOMX_MAX_ROLES)
1414 num_roles = MMALOMX_MAX_ROLES;
1415 else
1416 num_roles = *pNumRoles;
1417 *pNumRoles = 0;
1418
1419 /* Find component */
1420 registry_id = mmalomx_registry_find_component(compName);
1421 if (registry_id < 0)
1422 return OMX_ErrorComponentNotFound;
1423
1424 /* Enumerate Roles */
1425 for (i = 0; i < num_roles; i++)
1426 {
1427 role = mmalomx_registry_component_roles(registry_id, i);
1428 if (!role || !mmalomx_role_to_name(role))
1429 break;
1430
1431 if(roles)
1432 {
1433 strncpy((char *)roles[i], mmalomx_role_to_name(role), OMX_MAX_STRINGNAME_SIZE);
1434 LOG_DEBUG("found role: %s", roles[i]);
1435 }
1436 }
1437 LOG_DEBUG("found %i roles", (int)i);
1438 *pNumRoles = i;
1439
1440 return OMX_ErrorNone;
1441}
1442
1443/*****************************************************************************/
1444OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetComponentsOfRole)(
1445 OMX_STRING role,
1446 OMX_U32 *pNumComps,
1447 OMX_U8 **compNames)
1448{
1449 OMX_ERRORTYPE status;
1450 OMX_HANDLETYPE handle;
1451 OMX_COMPONENTTYPE *comp;
1452 OMX_U8 name[OMX_MAX_STRINGNAME_SIZE], compRole[OMX_MAX_STRINGNAME_SIZE];
1453 OMX_U32 nNameLength = OMX_MAX_STRINGNAME_SIZE, nIndex = 0;
1454 OMX_U32 nRoles, nIndexRoles, nComps = 0;
1455 OMX_CALLBACKTYPE callbacks = {0,0,0};
1456
1457 LOG_TRACE("role %s, pNumComps %p, compNames %p", role, pNumComps, compNames);
1458
1459 /* Sanity checks */
1460 if (!role || !pNumComps)
1461 return OMX_ErrorBadParameter;
1462
1463 /* Enumerates components */
1464 while ((status = OMX_ComponentNameEnum((OMX_STRING)name, nNameLength,
1465 nIndex++)) == OMX_ErrorNone)
1466 {
1467 /* Find component */
1468 status = MMALOMX_IMPORT(OMX_GetHandle)(&handle, (OMX_STRING)name, 0, &callbacks);
1469 if(status != OMX_ErrorNone) continue;
1470 comp = (OMX_COMPONENTTYPE *)handle;
1471
1472 /* Enumerate Roles */
1473 status = MMALOMX_IMPORT(OMX_GetRolesOfComponent)((OMX_STRING)name, &nRoles, 0);
1474 if(status != OMX_ErrorNone) continue;
1475
1476 for (nIndexRoles = 0; nIndexRoles < nRoles; nIndexRoles++)
1477 {
1478 status = comp->ComponentRoleEnum(handle, compRole, nIndexRoles);
1479 if(status != OMX_ErrorNone) break;
1480
1481 if(!strncmp((char *)role, (char *)compRole, OMX_MAX_STRINGNAME_SIZE))
1482 {
1483 /* Found one */
1484 nComps++;
1485
1486 if(!compNames) break;
1487
1488 /* Check if enough space was provided for all the component names */
1489 if(nComps > *pNumComps) return OMX_ErrorBadParameter;
1490
1491 strncpy((char *)compNames[nComps-1], (char *)name, OMX_MAX_STRINGNAME_SIZE);
1492
1493 LOG_DEBUG("found component: %s", name);
1494 }
1495 }
1496
1497 MMALOMX_IMPORT(OMX_FreeHandle)(handle);
1498 }
1499 LOG_DEBUG("found %i components", (int)nComps);
1500 *pNumComps = nComps;
1501
1502 return OMX_ErrorNone;
1503}
1504
1505/*****************************************************************************/
1506OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_SetupTunnel)(
1507 OMX_HANDLETYPE hOutput,
1508 OMX_U32 nPortOutput,
1509 OMX_HANDLETYPE hInput,
1510 OMX_U32 nPortInput)
1511{
1512 OMX_TUNNELSETUPTYPE tunnel_setup = {0, OMX_BufferSupplyUnspecified};
1513 OMX_ERRORTYPE status = OMX_ErrorNone;
1514
1515 LOG_TRACE("hOutput %p, nPortOutput %d, hInput %p, nPortInput %d",
1516 hOutput, (int)nPortOutput, hInput, (int)nPortInput);
1517
1518 /* Sanity checks */
1519 if (!hOutput && !hInput)
1520 return OMX_ErrorBadParameter;
1521
1522 if (hOutput)
1523 {
1524 status = ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
1525 hOutput, nPortOutput, hInput, nPortInput, &tunnel_setup);
1526 if (status != OMX_ErrorNone)
1527 LOG_DEBUG("OMX_SetupTunnel failed on output port (%i)", status);
1528 }
1529
1530 if (status == OMX_ErrorNone && hInput)
1531 {
1532 status = ((OMX_COMPONENTTYPE *)hInput)->ComponentTunnelRequest(
1533 hInput, nPortInput, hOutput, nPortOutput, &tunnel_setup);
1534 if (status != OMX_ErrorNone)
1535 {
1536 LOG_DEBUG("OMX_SetupTunnel failed on input port (%i)", status);
1537 /* Cancel request on output port */
1538 if (hOutput)
1539 ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
1540 hOutput, nPortOutput, NULL, 0, NULL);
1541 }
1542 }
1543
1544 return status;
1545}
1546
1547OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetContentPipe)(
1548 OMX_HANDLETYPE *hPipe,
1549 OMX_STRING szURI)
1550{
1551 MMAL_PARAM_UNUSED(hPipe);
1552 MMAL_PARAM_UNUSED(szURI);
1553
1554 LOG_TRACE("hPipe %p, szURI %s", hPipe, szURI);
1555
1556 return OMX_ErrorNotImplemented;
1557}
1558
1559/*****************************************************************************
1560 * Processing thread
1561 *****************************************************************************/
1562static void *mmalomx_cmd_thread_func(void *arg)
1563{
1564 MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)arg;
1565 VCOS_STATUS_T status;
1566
1567 while (component->cmd_thread_used)
1568 {
1569 status = vcos_semaphore_wait(&component->cmd_sema);
1570 if (status == VCOS_EAGAIN)
1571 continue;
1572 mmalomx_commands_actions_check(component);
1573 }
1574
1575 return 0;
1576}
1577
1578