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#include "interface/mmal/mmal.h"
28#include "mmal_encodings.h"
29#include "mmal_util.h"
30#include "mmal_logging.h"
31#include <string.h>
32#include <stdio.h>
33
34#define STATUS_TO_STR(x) { MMAL_##x, #x }
35
36static struct {
37 MMAL_STATUS_T status;
38 const char *str;
39} status_to_string_map[] =
40{
41 STATUS_TO_STR(SUCCESS),
42 STATUS_TO_STR(ENOMEM),
43 STATUS_TO_STR(ENOSPC),
44 STATUS_TO_STR(EINVAL),
45 STATUS_TO_STR(ENOSYS),
46 STATUS_TO_STR(ENOENT),
47 STATUS_TO_STR(ENXIO),
48 STATUS_TO_STR(EIO),
49 STATUS_TO_STR(ESPIPE),
50 STATUS_TO_STR(ECORRUPT),
51 STATUS_TO_STR(ENOTREADY),
52 STATUS_TO_STR(ECONFIG),
53 {0, 0}
54};
55
56const char *mmal_status_to_string(MMAL_STATUS_T status)
57{
58 unsigned i;
59
60 for (i=0; status_to_string_map[i].str; i++)
61 if (status_to_string_map[i].status == status)
62 break;
63
64 return status_to_string_map[i].str ? status_to_string_map[i].str : "UNKNOWN";
65}
66
67static struct {
68 uint32_t encoding;
69 uint32_t pitch_num;
70 uint32_t pitch_den;
71 uint32_t alignment;
72} pixel_pitch[] =
73{
74 {MMAL_ENCODING_I420, 1, 1, 1},
75 {MMAL_ENCODING_YV12, 1, 1, 1},
76 {MMAL_ENCODING_I422, 1, 1, 1},
77 {MMAL_ENCODING_NV21, 1, 1, 1},
78 {MMAL_ENCODING_NV12, 1, 1, 1},
79 {MMAL_ENCODING_ARGB, 4, 1, 1},
80 {MMAL_ENCODING_RGBA, 4, 1, 1},
81 {MMAL_ENCODING_RGB32, 4, 1, 1},
82 {MMAL_ENCODING_ABGR, 4, 1, 1},
83 {MMAL_ENCODING_BGRA, 4, 1, 1},
84 {MMAL_ENCODING_BGR32, 4, 1, 1},
85 {MMAL_ENCODING_RGB16, 2, 1, 1},
86 {MMAL_ENCODING_RGB24, 3, 1, 1},
87 {MMAL_ENCODING_BGR16, 2, 1, 1},
88 {MMAL_ENCODING_BGR24, 3, 1, 1},
89 {MMAL_ENCODING_I420_16, 2, 1, 1},
90 {MMAL_ENCODING_I420_10, 2, 1, 1},
91 {MMAL_ENCODING_I420_S, 1, 1, 1},
92
93 {MMAL_ENCODING_I420_SLICE, 1, 1, 1},
94 {MMAL_ENCODING_I422_SLICE, 1, 1, 1},
95 {MMAL_ENCODING_ARGB_SLICE, 4, 1, 1},
96 {MMAL_ENCODING_RGBA_SLICE, 4, 1, 1},
97 {MMAL_ENCODING_RGB32_SLICE, 4, 1, 1},
98 {MMAL_ENCODING_ABGR_SLICE, 4, 1, 1},
99 {MMAL_ENCODING_BGRA_SLICE, 4, 1, 1},
100 {MMAL_ENCODING_BGR32_SLICE, 4, 1, 1},
101 {MMAL_ENCODING_RGB16_SLICE, 2, 1, 1},
102 {MMAL_ENCODING_RGB24_SLICE, 3, 1, 1},
103 {MMAL_ENCODING_BGR16_SLICE, 2, 1, 1},
104 {MMAL_ENCODING_BGR24_SLICE, 3, 1, 1},
105
106 {MMAL_ENCODING_YUYV, 2, 1, 1},
107 {MMAL_ENCODING_YVYU, 2, 1, 1},
108 {MMAL_ENCODING_UYVY, 2, 1, 1},
109 {MMAL_ENCODING_VYUY, 2, 1, 1},
110
111 // Bayer formats, the resulting alignment must also be a multiple of 16.
112 // Camplus padded to a multiple of 32, so let's copy that.
113 {MMAL_ENCODING_BAYER_SBGGR8, 1, 1, 32},
114 {MMAL_ENCODING_BAYER_SGBRG8, 1, 1, 32},
115 {MMAL_ENCODING_BAYER_SGRBG8, 1, 1, 32},
116 {MMAL_ENCODING_BAYER_SRGGB8, 1, 1, 32},
117 {MMAL_ENCODING_BAYER_SBGGR10DPCM8, 1, 1, 32},
118 {MMAL_ENCODING_BAYER_SGBRG10DPCM8, 1, 1, 32},
119 {MMAL_ENCODING_BAYER_SGRBG10DPCM8, 1, 1, 32},
120 {MMAL_ENCODING_BAYER_SRGGB10DPCM8, 1, 1, 32},
121 {MMAL_ENCODING_BAYER_SBGGR10P, 10,8, 32},
122 {MMAL_ENCODING_BAYER_SGRBG10P, 10,8, 32},
123 {MMAL_ENCODING_BAYER_SGBRG10P, 10,8, 32},
124 {MMAL_ENCODING_BAYER_SRGGB10P, 10,8, 32},
125 {MMAL_ENCODING_BAYER_SBGGR12P, 12,8, 32},
126 {MMAL_ENCODING_BAYER_SGRBG12P, 12,8, 32},
127 {MMAL_ENCODING_BAYER_SGBRG12P, 12,8, 32},
128 {MMAL_ENCODING_BAYER_SRGGB12P, 12,8, 32},
129 {MMAL_ENCODING_BAYER_SBGGR16, 2, 1, 32},
130 {MMAL_ENCODING_BAYER_SGBRG16, 2, 1, 32},
131 {MMAL_ENCODING_BAYER_SGRBG16, 2, 1, 32},
132 {MMAL_ENCODING_BAYER_SRGGB16, 2, 1, 32},
133
134 /* {MMAL_ENCODING_YUVUV128, 1, 1}, That's a special case which must not be included */
135 /* {MMAL_ENCODING_YUVUV64_16, 1, 1}, That's a special case which must not be included */
136 /* {MMAL_ENCODING_YUVUV64_10, 1, 1}, That's a special case which must not be included */
137 /* {MMAL_ENCODING_YUV10_COL, 1, 1}, That's a special case which must not be included */
138 {MMAL_ENCODING_UNKNOWN, 0, 0}
139};
140
141static struct {
142 uint32_t encoding;
143 uint32_t sliced_encoding;
144} slice_equivalents[] =
145{
146 { MMAL_ENCODING_I420, MMAL_ENCODING_I420_SLICE },
147 { MMAL_ENCODING_I422, MMAL_ENCODING_I422_SLICE },
148 { MMAL_ENCODING_ARGB, MMAL_ENCODING_ARGB_SLICE },
149 { MMAL_ENCODING_RGBA, MMAL_ENCODING_RGBA_SLICE },
150 { MMAL_ENCODING_RGB32, MMAL_ENCODING_RGB32_SLICE },
151 { MMAL_ENCODING_ABGR, MMAL_ENCODING_ABGR_SLICE },
152 { MMAL_ENCODING_BGRA, MMAL_ENCODING_BGRA_SLICE },
153 { MMAL_ENCODING_BGR32, MMAL_ENCODING_BGR32_SLICE },
154 { MMAL_ENCODING_RGB16, MMAL_ENCODING_RGB16_SLICE },
155 { MMAL_ENCODING_RGB24, MMAL_ENCODING_RGB24_SLICE },
156 { MMAL_ENCODING_BGR16, MMAL_ENCODING_BGR16_SLICE },
157 { MMAL_ENCODING_BGR24, MMAL_ENCODING_BGR24_SLICE },
158 { MMAL_ENCODING_UNKNOWN, MMAL_ENCODING_UNKNOWN },
159};
160
161
162uint32_t mmal_encoding_stride_to_width(uint32_t encoding, uint32_t stride)
163{
164 unsigned int i;
165
166 for(i = 0; pixel_pitch[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
167 if(pixel_pitch[i].encoding == encoding) break;
168
169 if(pixel_pitch[i].encoding == MMAL_ENCODING_UNKNOWN)
170 return 0;
171
172 return pixel_pitch[i].pitch_den * stride / pixel_pitch[i].pitch_num;
173}
174
175uint32_t mmal_encoding_width_to_stride(uint32_t encoding, uint32_t width)
176{
177 unsigned int i;
178
179 for(i = 0; pixel_pitch[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
180 if(pixel_pitch[i].encoding == encoding) break;
181
182 if(pixel_pitch[i].encoding == MMAL_ENCODING_UNKNOWN)
183 return 0;
184
185 return VCOS_ALIGN_UP(pixel_pitch[i].pitch_num * width / pixel_pitch[i].pitch_den, pixel_pitch[i].alignment);
186}
187
188uint32_t mmal_encoding_get_slice_variant(uint32_t encoding)
189{
190 unsigned int i;
191
192 for(i = 0; slice_equivalents[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
193 if(slice_equivalents[i].encoding == encoding) break;
194
195 return slice_equivalents[i].sliced_encoding;
196}
197
198const char* mmal_port_type_to_string(MMAL_PORT_TYPE_T type)
199{
200 const char *str;
201
202 switch (type)
203 {
204 case MMAL_PORT_TYPE_INPUT: str = "in"; break;
205 case MMAL_PORT_TYPE_OUTPUT: str = "out"; break;
206 case MMAL_PORT_TYPE_CLOCK: str = "clk"; break;
207 case MMAL_PORT_TYPE_CONTROL: str = "ctr"; break;
208 default: str = "invalid"; break;
209 }
210
211 return str;
212}
213
214MMAL_PARAMETER_HEADER_T *mmal_port_parameter_alloc_get(MMAL_PORT_T *port,
215 uint32_t id, uint32_t size, MMAL_STATUS_T *p_status)
216{
217 MMAL_PARAMETER_HEADER_T *param = NULL;
218 MMAL_STATUS_T status = MMAL_ENOSYS;
219
220 if (size < sizeof(MMAL_PARAMETER_HEADER_T))
221 size = sizeof(MMAL_PARAMETER_HEADER_T);
222
223 if ((param = vcos_calloc(1, size, "mmal_port_param_get")) == NULL)
224 {
225 status = MMAL_ENOMEM;
226 goto error;
227 }
228
229 param->id = id;
230 param->size = size;
231
232 if ((status = mmal_port_parameter_get(port, param)) == MMAL_ENOSPC)
233 {
234 /* We need to reallocate to get enough space for all parameter data */
235 size = param->size;
236 vcos_free(param);
237 if ((param = vcos_calloc(1, size, "mmal_port_param_get")) == NULL)
238 {
239 status = MMAL_ENOMEM;
240 goto error;
241 }
242
243 /* Now retrieve it again */
244 param->id = id;
245 param->size = size;
246 status = mmal_port_parameter_get(port, param);
247 }
248
249 if (status != MMAL_SUCCESS)
250 goto error;
251
252end:
253 if (p_status) *p_status = status;
254 return param;
255error:
256 if (param) vcos_free(param);
257 param = NULL;
258 goto end;
259}
260
261void mmal_port_parameter_free(MMAL_PARAMETER_HEADER_T *param)
262{
263 vcos_free(param);
264}
265
266/** Copy buffer header metadata from source to dest
267 */
268void mmal_buffer_header_copy_header(MMAL_BUFFER_HEADER_T *dest, const MMAL_BUFFER_HEADER_T *src)
269{
270 dest->cmd = src->cmd;
271 dest->offset = src->offset;
272 dest->length = src->length;
273 dest->flags = src->flags;
274 dest->pts = src->pts;
275 dest->dts = src->dts;
276 *dest->type = *src->type;
277}
278
279/** Create a pool of MMAL_BUFFER_HEADER_T */
280MMAL_POOL_T *mmal_port_pool_create(MMAL_PORT_T *port, unsigned int headers, uint32_t payload_size)
281{
282 if (!port || !port->priv)
283 return NULL;
284
285 LOG_TRACE("%s(%i:%i) port %p, headers %u, size %i", port->component->name,
286 (int)port->type, (int)port->index, port, headers, (int)payload_size);
287
288 /* Create a pool and ask the port for some memory */
289 return mmal_pool_create_with_allocator(headers, payload_size, (void *)port,
290 (mmal_pool_allocator_alloc_t)mmal_port_payload_alloc,
291 (mmal_pool_allocator_free_t)mmal_port_payload_free);
292}
293
294/** Destroy a pool of MMAL_BUFFER_HEADER_T */
295void mmal_port_pool_destroy(MMAL_PORT_T *port, MMAL_POOL_T *pool)
296{
297 if (!port || !port->priv || !pool)
298 return;
299
300 LOG_TRACE("%s(%i:%i) port %p, pool %p", port->component->name,
301 (int)port->type, (int)port->index, port, pool);
302
303 if (!vcos_verify(!port->is_enabled))
304 {
305 LOG_ERROR("port %p, pool %p destroyed while port enabled", port, pool);
306 mmal_port_disable(port);
307 }
308
309 mmal_pool_destroy(pool);
310}
311
312/*****************************************************************************/
313void mmal_log_dump_port(MMAL_PORT_T *port)
314{
315 if (!port)
316 return;
317
318 LOG_DEBUG("%s(%p)", port->name, port);
319
320 mmal_log_dump_format(port->format);
321
322 LOG_DEBUG(" buffers num: %i(opt %i, min %i), size: %i(opt %i, min: %i), align: %i",
323 port->buffer_num, port->buffer_num_recommended, port->buffer_num_min,
324 port->buffer_size, port->buffer_size_recommended, port->buffer_size_min,
325 port->buffer_alignment_min);
326}
327
328/*****************************************************************************/
329void mmal_log_dump_format(MMAL_ES_FORMAT_T *format)
330{
331 const char *name_type;
332
333 if (!format)
334 return;
335
336 switch(format->type)
337 {
338 case MMAL_ES_TYPE_AUDIO: name_type = "audio"; break;
339 case MMAL_ES_TYPE_VIDEO: name_type = "video"; break;
340 case MMAL_ES_TYPE_SUBPICTURE: name_type = "subpicture"; break;
341 default: name_type = "unknown"; break;
342 }
343
344 LOG_DEBUG("type: %s, fourcc: %4.4s", name_type, (char *)&format->encoding);
345 LOG_DEBUG(" bitrate: %i, framed: %i", format->bitrate,
346 !!(format->flags & MMAL_ES_FORMAT_FLAG_FRAMED));
347 LOG_DEBUG(" extra data: %i, %p", format->extradata_size, format->extradata);
348 switch(format->type)
349 {
350 case MMAL_ES_TYPE_AUDIO:
351 LOG_DEBUG(" samplerate: %i, channels: %i, bps: %i, block align: %i",
352 format->es->audio.sample_rate, format->es->audio.channels,
353 format->es->audio.bits_per_sample, format->es->audio.block_align);
354 break;
355
356 case MMAL_ES_TYPE_VIDEO:
357 LOG_DEBUG(" width: %i, height: %i, (%i,%i,%i,%i)",
358 format->es->video.width, format->es->video.height,
359 format->es->video.crop.x, format->es->video.crop.y,
360 format->es->video.crop.width, format->es->video.crop.height);
361 LOG_DEBUG(" pixel aspect ratio: %i/%i, frame rate: %i/%i",
362 format->es->video.par.num, format->es->video.par.den,
363 format->es->video.frame_rate.num, format->es->video.frame_rate.den);
364 break;
365
366 case MMAL_ES_TYPE_SUBPICTURE:
367 break;
368
369 default: break;
370 }
371}
372
373MMAL_PORT_T *mmal_util_get_port(MMAL_COMPONENT_T *comp, MMAL_PORT_TYPE_T type, unsigned index)
374{
375 unsigned num;
376 MMAL_PORT_T **list;
377
378 switch (type)
379 {
380 case MMAL_PORT_TYPE_INPUT:
381 num = comp->input_num;
382 list = comp->input;
383 break;
384
385 case MMAL_PORT_TYPE_OUTPUT:
386 num = comp->output_num;
387 list = comp->output;
388 break;
389
390 case MMAL_PORT_TYPE_CLOCK:
391 num = comp->clock_num;
392 list = comp->clock;
393 break;
394
395 case MMAL_PORT_TYPE_CONTROL:
396 num = 1;
397 list = &comp->control;
398 break;
399
400 default:
401 vcos_assert(0);
402 return NULL;
403 }
404 if (index < num)
405 /* coverity[ptr_arith] num is 1 here */
406 return list[index];
407 else
408 return NULL;
409}
410
411char *mmal_4cc_to_string(char *buf, size_t len, uint32_t fourcc)
412{
413 char *src = (char*)&fourcc;
414 vcos_assert(len >= 5);
415 if (len < 5)
416 {
417 buf[0] = '\0';
418 }
419 else if (fourcc)
420 {
421 memcpy(buf, src, 4);
422 buf[4] = '\0';
423 }
424 else
425 {
426 snprintf(buf, len, "<0>");
427 }
428 return buf;
429}
430
431#define MAX_ENCODINGS_NUM 25
432typedef struct {
433 MMAL_PARAMETER_HEADER_T header;
434 MMAL_FOURCC_T encodings[MAX_ENCODINGS_NUM];
435} MMAL_SUPPORTED_ENCODINGS_T;
436
437
438int mmal_util_rgb_order_fixed(MMAL_PORT_T *port)
439{
440 int new_fw = 0;
441 MMAL_STATUS_T ret;
442 //Firmware support of RGB24 vs BGR24 colour ordering from camera
443 //and video splitter components has been corrected as of June 2016.
444 //New firmwares always report MMAL_ENCODING_RGB24 before BGR24, and
445 //that is the format we want.
446 //Old firmware reported BGR24 first, and also returned an error on
447 //the still port on querying MMAL_PARAMETER_SUPPORTED_ENCODINGS.
448
449 MMAL_SUPPORTED_ENCODINGS_T sup_encodings = {{MMAL_PARAMETER_SUPPORTED_ENCODINGS, sizeof(sup_encodings)}, {0}};
450 ret = mmal_port_parameter_get(port, &sup_encodings.header);
451 if (ret == MMAL_SUCCESS || ret == MMAL_ENOSPC)
452 {
453 //Allow ENOSPC error and hope that the desired formats are in the first
454 //MAX_ENCODINGS_NUM entries.
455 int i;
456 int num_encodings = (sup_encodings.header.size - sizeof(sup_encodings.header)) /
457 sizeof(sup_encodings.encodings[0]);
458 if(num_encodings > MAX_ENCODINGS_NUM)
459 num_encodings = MAX_ENCODINGS_NUM;
460 for (i=0; i<num_encodings; i++)
461 {
462 if (sup_encodings.encodings[i] == MMAL_ENCODING_BGR24)
463 {
464 //Found BGR24 first - old firmware.
465 break;
466 }
467 if (sup_encodings.encodings[i] == MMAL_ENCODING_RGB24)
468 {
469 //Found RGB24 first - new firmware, so use RGB24.
470 new_fw = 1;
471 }
472 }
473 }
474 return new_fw;
475}
476