2 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4 * Copyright (C) 2013, Collabora Ltd.
5 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> *
6 * Copyright 2014 Advanced Micro Devices, Inc.
7 * Author: Christian König <christian.koenig@amd.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation
12 * version 2.1 of the License.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "gstomxvideo.h"
33 GST_DEBUG_CATEGORY (gst_omx_video_debug_category);
34 #define GST_CAT_DEFAULT gst_omx_video_debug_category
36 /* Keep synced with GST_OMX_VIDEO_DEC_SUPPORTED_FORMATS */
38 gst_omx_video_get_format_from_omx (OMX_COLOR_FORMATTYPE omx_colorformat)
40 GstVideoFormat format;
42 switch (omx_colorformat) {
43 case OMX_COLOR_FormatL8:
44 format = GST_VIDEO_FORMAT_GRAY8;
46 case OMX_COLOR_FormatYUV420Planar:
47 case OMX_COLOR_FormatYUV420PackedPlanar:
48 format = GST_VIDEO_FORMAT_I420;
50 case OMX_COLOR_FormatYUV420SemiPlanar:
51 case OMX_COLOR_FormatYUV420PackedSemiPlanar:
52 format = GST_VIDEO_FORMAT_NV12;
54 case OMX_COLOR_FormatYUV422SemiPlanar:
55 format = GST_VIDEO_FORMAT_NV16;
57 case OMX_COLOR_FormatYCbYCr:
58 format = GST_VIDEO_FORMAT_YUY2;
60 case OMX_COLOR_FormatYCrYCb:
61 format = GST_VIDEO_FORMAT_YVYU;
63 case OMX_COLOR_FormatCbYCrY:
64 format = GST_VIDEO_FORMAT_UYVY;
66 case OMX_COLOR_Format32bitARGB8888:
67 /* There is a mismatch in omxil specification 4.2.1 between
68 * OMX_COLOR_Format32bitARGB8888 and its description
69 * Follow the description */
70 format = GST_VIDEO_FORMAT_ABGR;
72 case OMX_COLOR_Format32bitBGRA8888:
73 /* Same issue as OMX_COLOR_Format32bitARGB8888 */
74 format = GST_VIDEO_FORMAT_ARGB;
76 case OMX_COLOR_Format16bitRGB565:
77 format = GST_VIDEO_FORMAT_RGB16;
79 case OMX_COLOR_Format16bitBGR565:
80 format = GST_VIDEO_FORMAT_BGR16;
82 case OMX_COLOR_Format24bitBGR888:
83 format = GST_VIDEO_FORMAT_BGR;
85 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
86 /* Formats defined in extensions have their own enum so disable to -Wswitch warning */
87 #pragma GCC diagnostic push
88 #pragma GCC diagnostic ignored "-Wswitch"
89 case OMX_ALG_COLOR_FormatYUV420SemiPlanar10bitPacked:
90 format = GST_VIDEO_FORMAT_NV12_10LE32;
92 case OMX_ALG_COLOR_FormatYUV422SemiPlanar10bitPacked:
93 format = GST_VIDEO_FORMAT_NV16_10LE32;
95 #pragma GCC diagnostic pop
98 format = GST_VIDEO_FORMAT_UNKNOWN;
106 gst_omx_video_get_supported_colorformats (GstOMXPort * port,
107 GstVideoCodecState * state)
109 GstOMXComponent *comp = port->comp;
110 OMX_VIDEO_PARAM_PORTFORMATTYPE param;
112 GList *negotiation_map = NULL;
114 GstOMXVideoNegotiationMap *m;
117 GST_OMX_INIT_STRUCT (¶m);
118 param.nPortIndex = port->index;
121 state ? gst_omx_video_calculate_framerate_q16 (&state->info) : 0;
126 gst_omx_component_get_parameter (comp,
127 OMX_IndexParamVideoPortFormat, ¶m);
129 /* FIXME: Workaround for Bellagio that simply always
130 * returns the same value regardless of nIndex and
131 * never returns OMX_ErrorNoMore
133 if (old_index == param.nIndex)
136 if (err == OMX_ErrorNone || err == OMX_ErrorNoMore) {
137 f = gst_omx_video_get_format_from_omx (param.eColorFormat);
139 if (f != GST_VIDEO_FORMAT_UNKNOWN) {
140 m = g_slice_new (GstOMXVideoNegotiationMap);
142 m->type = param.eColorFormat;
143 negotiation_map = g_list_append (negotiation_map, m);
144 GST_DEBUG_OBJECT (comp->parent,
145 "Component port %d supports %s (%d) at index %u", port->index,
146 gst_video_format_to_string (f), param.eColorFormat,
147 (guint) param.nIndex);
149 GST_DEBUG_OBJECT (comp->parent,
150 "Component port %d supports unsupported color format %d at index %u",
151 port->index, param.eColorFormat, (guint) param.nIndex);
154 old_index = param.nIndex++;
155 } while (err == OMX_ErrorNone);
157 return negotiation_map;
161 gst_omx_video_get_caps_for_map (GList * map)
163 GstCaps *caps = gst_caps_new_empty ();
166 for (l = map; l; l = l->next) {
167 GstOMXVideoNegotiationMap *entry = l->data;
169 gst_caps_append_structure (caps,
170 gst_structure_new ("video/x-raw",
171 "format", G_TYPE_STRING,
172 gst_video_format_to_string (entry->format), NULL));
178 gst_omx_video_negotiation_map_free (GstOMXVideoNegotiationMap * m)
180 g_slice_free (GstOMXVideoNegotiationMap, m);
184 gst_omx_video_find_nearest_frame (GstElement * element, GstOMXBuffer * buf,
187 GstVideoCodecFrame *best = NULL;
188 GstClockTimeDiff best_diff = G_MAXINT64;
189 GstClockTime timestamp;
193 gst_util_uint64_scale (GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
194 GST_SECOND, OMX_TICKS_PER_SECOND);
196 GST_LOG_OBJECT (element, "look for ts %" GST_TIME_FORMAT,
197 GST_TIME_ARGS (timestamp));
199 for (l = frames; l; l = l->next) {
200 GstVideoCodecFrame *tmp = l->data;
201 GstClockTimeDiff diff = ABS (GST_CLOCK_DIFF (timestamp, tmp->pts));
203 GST_LOG_OBJECT (element,
204 " frame %u diff %" G_GINT64_FORMAT " ts %" GST_TIME_FORMAT,
205 tmp->system_frame_number, diff, GST_TIME_ARGS (tmp->pts));
207 if (diff < best_diff) {
217 gst_video_codec_frame_ref (best);
219 /* OMX timestamps are in microseconds while gst ones are in nanoseconds.
220 * So if the difference between them is higher than 1 microsecond we likely
221 * picked the wrong frame. */
222 if (best_diff >= GST_USECOND)
223 GST_WARNING_OBJECT (element,
224 "Difference between ts (%" GST_TIME_FORMAT ") and frame %u (%"
225 GST_TIME_FORMAT ") seems too high (%" GST_TIME_FORMAT ")",
226 GST_TIME_ARGS (timestamp), best->system_frame_number,
227 GST_TIME_ARGS (best->pts), GST_TIME_ARGS (best_diff));
229 GST_WARNING_OBJECT (element, "No best frame has been found");
231 g_list_foreach (frames, (GFunc) gst_video_codec_frame_unref, NULL);
232 g_list_free (frames);
238 gst_omx_video_calculate_framerate_q16 (GstVideoInfo * info)
245 /* OMX API expects frame rate to actually be the field rate, so twice
246 * the frame rate in interlace mode. */
247 return gst_util_uint64_scale_int (1 << 16, GST_VIDEO_INFO_FIELD_RATE_N (info),
252 gst_omx_video_is_equal_framerate_q16 (OMX_U32 q16_a, OMX_U32 q16_b)
254 /* If one of them is 0 use the classic comparison. The value 0 has a special
255 meaning and is used to indicate the frame rate is unknown, variable, or
257 if (!q16_a || !q16_b)
258 return q16_a == q16_b;
260 /* If the 'percentage change' is less than 1% then consider it equal to avoid
261 * an unnecessary re-negotiation. */
262 return fabs (((gdouble) q16_a) - ((gdouble) q16_b)) / (gdouble) q16_b < 0.01;
266 gst_omx_video_get_port_padding (GstOMXPort * port, GstVideoInfo * info_orig,
267 GstVideoAlignment * align)
272 gsize plane_size[GST_VIDEO_MAX_PLANES];
274 gst_video_alignment_reset (align);
276 /* Create a copy of @info_orig without any offset/stride as we need a
277 * 'standard' version to compute the paddings. */
278 gst_video_info_init (&info);
279 gst_video_info_set_interlaced_format (&info,
280 GST_VIDEO_INFO_FORMAT (info_orig),
281 GST_VIDEO_INFO_INTERLACE_MODE (info_orig),
282 GST_VIDEO_INFO_WIDTH (info_orig), GST_VIDEO_INFO_HEIGHT (info_orig));
284 /* Retrieve the plane sizes */
285 if (!gst_video_info_align_full (&info, align, plane_size)) {
286 GST_WARNING_OBJECT (port->comp->parent, "Failed to retrieve plane sizes");
290 nstride = port->port_def.format.video.nStride;
291 nslice_height = port->port_def.format.video.nSliceHeight;
293 if (nstride > GST_VIDEO_INFO_PLANE_STRIDE (&info, 0)) {
294 align->padding_right = nstride - GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
296 if (GST_VIDEO_FORMAT_INFO_IS_COMPLEX (info.finfo)) {
297 /* Stride is in bytes while padding is in pixels so we need to do manual
298 * conversions for complex formats. */
299 switch (GST_VIDEO_INFO_FORMAT (&info)) {
300 case GST_VIDEO_FORMAT_NV12_10LE32:
301 case GST_VIDEO_FORMAT_NV16_10LE32:
302 /* Need ((width + 2) / 3) 32-bits words to store one row,
303 * see unpack_NV12_10LE32 in -base.
306 * - W = the width, in pixels
307 * - S = the stride, in bytes
308 * - P = the padding, in bytes
309 * - Δ = the padding, in pixels
313 * S+P = ((W+2+Δ)/3) * 4
315 * By solving this system we get:
318 align->padding_right *= 0.75;
321 GST_FIXME_OBJECT (port->comp->parent,
322 "Stride conversion is not supported for format %s",
323 GST_VIDEO_INFO_NAME (&info));
328 GST_LOG_OBJECT (port->comp->parent,
329 "OMX stride (%d) is higher than standard (%d) for port %u; right padding: %d",
330 nstride, GST_VIDEO_INFO_PLANE_STRIDE (&info, 0), port->index,
331 align->padding_right);
334 if (nslice_height > GST_VIDEO_INFO_PLANE_HEIGHT (&info, 0, plane_size)) {
335 align->padding_bottom =
336 nslice_height - GST_VIDEO_INFO_PLANE_HEIGHT (&info, 0, plane_size);
338 if (GST_VIDEO_INFO_INTERLACE_MODE (&info) ==
339 GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
340 /* GstVideoAlignment defines the alignment for the full frame while
341 * OMX gives us the slice height for a single field, so we have to
342 * double the vertical padding. */
343 GST_DEBUG_OBJECT (port->comp->parent,
344 "Double bottom padding because of alternate stream");
345 align->padding_bottom *= 2;
348 GST_LOG_OBJECT (port->comp->parent,
349 "OMX slice height (%d) is higher than standard (%" G_GSIZE_FORMAT
350 ") for port %u; vertical padding: %d", nslice_height,
351 GST_VIDEO_INFO_PLANE_HEIGHT (&info, 0, plane_size), port->index,
352 align->padding_bottom);