blob: 6d6cb794fc224f9600d54b57b54a9fd9e7603d14 [file] [log] [blame]
xuesong.jiangae1548e2022-05-06 16:38:46 +08001/* GStreamer
2 * Copyright (C) 2022 <xuesong.jiang@amlogic.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 * Boston, MA 02110-1335, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <string.h>
28#include <sys/mman.h>
29#include <sys/ioctl.h>
xuesong.jiange1a19662022-06-21 20:30:22 +080030#include <stdio.h>
zengliang.lic9f869d2023-02-15 08:32:32 +000031#include <sys/utsname.h>
xuesong.jiangae1548e2022-05-06 16:38:46 +080032
33#ifdef HAVE_GUDEV
34#include <gudev/gudev.h>
35#endif
36
37#include "ext/videodev2.h"
38#include "gstamlv4l2object.h"
39
40#include "gst/gst-i18n-plugin.h"
41
42#include <gst/video/video.h>
43#include <gst/allocators/gstdmabuf.h>
44
45GST_DEBUG_CATEGORY_EXTERN(aml_v4l2_debug);
46#define GST_CAT_DEFAULT aml_v4l2_debug
47
48#define DEFAULT_PROP_DEVICE_NAME NULL
49#define DEFAULT_PROP_DEVICE_FD -1
50#define DEFAULT_PROP_FLAGS 0
51#define DEFAULT_PROP_TV_NORM 0
52#define DEFAULT_PROP_IO_MODE GST_V4L2_IO_AUTO
53
xuesong.jiangc5dac0f2023-02-01 14:42:24 +080054#define ENCODED_BUFFER_SIZE (3 * 1024 * 1024)
xuesong.jiangae1548e2022-05-06 16:38:46 +080055
xuesong.jiange1a19662022-06-21 20:30:22 +080056#define V4L2_CONFIG_PARM_DECODE_CFGINFO (1 << 0)
57#define V4L2_CONFIG_PARM_DECODE_PSINFO (1 << 1)
58#define V4L2_CONFIG_PARM_DECODE_HDRINFO (1 << 2)
59#define V4L2_CONFIG_PARM_DECODE_CNTINFO (1 << 3)
60
zengliang.lic9f869d2023-02-15 08:32:32 +000061#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
62#define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0)
63#define AML_V4L2_DEC_PARMS_CONFIG (V4L2_CID_USER_AMLOGIC_BASE + 7)
xuesong.jiang22a9b112023-05-24 09:01:59 +000064#define AML_V4L2_SET_STREAM_MODE (V4L2_CID_USER_AMLOGIC_BASE + 9)
zengliang.lic9f869d2023-02-15 08:32:32 +000065
xuesong.jiangae1548e2022-05-06 16:38:46 +080066enum
67{
68 PROP_0,
69 V4L2_STD_OBJECT_PROPS,
70};
71
72/*
73 * common format / caps utilities:
74 */
75typedef enum
76{
77 GST_V4L2_RAW = 1 << 0,
78 GST_V4L2_CODEC = 1 << 1,
79 GST_V4L2_TRANSPORT = 1 << 2,
80 GST_V4L2_NO_PARSE = 1 << 3,
81 GST_V4L2_ALL = 0xffff
82} GstAmlV4L2FormatFlags;
83
84typedef struct
85{
86 guint32 format;
87 gboolean dimensions;
88 GstAmlV4L2FormatFlags flags;
89} GstAmlV4L2FormatDesc;
90
91static const GstAmlV4L2FormatDesc gst_aml_v4l2_formats[] = {
92 /* RGB formats */
93 {V4L2_PIX_FMT_RGB332, TRUE, GST_V4L2_RAW},
94 {V4L2_PIX_FMT_ARGB555, TRUE, GST_V4L2_RAW},
95 {V4L2_PIX_FMT_XRGB555, TRUE, GST_V4L2_RAW},
96 {V4L2_PIX_FMT_ARGB555X, TRUE, GST_V4L2_RAW},
97 {V4L2_PIX_FMT_XRGB555X, TRUE, GST_V4L2_RAW},
98 {V4L2_PIX_FMT_RGB565, TRUE, GST_V4L2_RAW},
99 {V4L2_PIX_FMT_RGB565X, TRUE, GST_V4L2_RAW},
100 {V4L2_PIX_FMT_BGR666, TRUE, GST_V4L2_RAW},
101 {V4L2_PIX_FMT_BGR24, TRUE, GST_V4L2_RAW},
102 {V4L2_PIX_FMT_RGB24, TRUE, GST_V4L2_RAW},
103 {V4L2_PIX_FMT_ABGR32, TRUE, GST_V4L2_RAW},
104 {V4L2_PIX_FMT_XBGR32, TRUE, GST_V4L2_RAW},
105 {V4L2_PIX_FMT_ARGB32, TRUE, GST_V4L2_RAW},
106 {V4L2_PIX_FMT_XRGB32, TRUE, GST_V4L2_RAW},
107
108 /* Deprecated Packed RGB Image Formats (alpha ambiguity) */
109 {V4L2_PIX_FMT_RGB444, TRUE, GST_V4L2_RAW},
110 {V4L2_PIX_FMT_RGB555, TRUE, GST_V4L2_RAW},
111 {V4L2_PIX_FMT_RGB555X, TRUE, GST_V4L2_RAW},
112 {V4L2_PIX_FMT_BGR32, TRUE, GST_V4L2_RAW},
113 {V4L2_PIX_FMT_RGB32, TRUE, GST_V4L2_RAW},
114
115 /* Grey formats */
116 {V4L2_PIX_FMT_GREY, TRUE, GST_V4L2_RAW},
117 {V4L2_PIX_FMT_Y4, TRUE, GST_V4L2_RAW},
118 {V4L2_PIX_FMT_Y6, TRUE, GST_V4L2_RAW},
119 {V4L2_PIX_FMT_Y10, TRUE, GST_V4L2_RAW},
120 {V4L2_PIX_FMT_Y12, TRUE, GST_V4L2_RAW},
121 {V4L2_PIX_FMT_Y16, TRUE, GST_V4L2_RAW},
122 {V4L2_PIX_FMT_Y16_BE, TRUE, GST_V4L2_RAW},
123 {V4L2_PIX_FMT_Y10BPACK, TRUE, GST_V4L2_RAW},
124
125 /* Palette formats */
126 {V4L2_PIX_FMT_PAL8, TRUE, GST_V4L2_RAW},
127
128 /* Chrominance formats */
129 {V4L2_PIX_FMT_UV8, TRUE, GST_V4L2_RAW},
130
131 /* Luminance+Chrominance formats */
132 {V4L2_PIX_FMT_YVU410, TRUE, GST_V4L2_RAW},
133 {V4L2_PIX_FMT_YVU420, TRUE, GST_V4L2_RAW},
134 {V4L2_PIX_FMT_YVU420M, TRUE, GST_V4L2_RAW},
135 {V4L2_PIX_FMT_YUYV, TRUE, GST_V4L2_RAW},
136 {V4L2_PIX_FMT_YYUV, TRUE, GST_V4L2_RAW},
137 {V4L2_PIX_FMT_YVYU, TRUE, GST_V4L2_RAW},
138 {V4L2_PIX_FMT_UYVY, TRUE, GST_V4L2_RAW},
139 {V4L2_PIX_FMT_VYUY, TRUE, GST_V4L2_RAW},
140 {V4L2_PIX_FMT_YUV422P, TRUE, GST_V4L2_RAW},
141 {V4L2_PIX_FMT_YUV411P, TRUE, GST_V4L2_RAW},
142 {V4L2_PIX_FMT_Y41P, TRUE, GST_V4L2_RAW},
143 {V4L2_PIX_FMT_YUV444, TRUE, GST_V4L2_RAW},
144 {V4L2_PIX_FMT_YUV555, TRUE, GST_V4L2_RAW},
145 {V4L2_PIX_FMT_YUV565, TRUE, GST_V4L2_RAW},
146 {V4L2_PIX_FMT_YUV32, TRUE, GST_V4L2_RAW},
147 {V4L2_PIX_FMT_YUV410, TRUE, GST_V4L2_RAW},
148 {V4L2_PIX_FMT_YUV420, TRUE, GST_V4L2_RAW},
149 {V4L2_PIX_FMT_YUV420M, TRUE, GST_V4L2_RAW},
150 {V4L2_PIX_FMT_HI240, TRUE, GST_V4L2_RAW},
151 {V4L2_PIX_FMT_HM12, TRUE, GST_V4L2_RAW},
152 {V4L2_PIX_FMT_M420, TRUE, GST_V4L2_RAW},
153
154 /* two planes -- one Y, one Cr + Cb interleaved */
155 {V4L2_PIX_FMT_NV12, TRUE, GST_V4L2_RAW},
156 {V4L2_PIX_FMT_NV12M, TRUE, GST_V4L2_RAW},
157 {V4L2_PIX_FMT_NV12MT, TRUE, GST_V4L2_RAW},
158 {V4L2_PIX_FMT_NV12MT_16X16, TRUE, GST_V4L2_RAW},
159 {V4L2_PIX_FMT_NV21, TRUE, GST_V4L2_RAW},
160 {V4L2_PIX_FMT_NV21M, TRUE, GST_V4L2_RAW},
161 {V4L2_PIX_FMT_NV16, TRUE, GST_V4L2_RAW},
162 {V4L2_PIX_FMT_NV16M, TRUE, GST_V4L2_RAW},
163 {V4L2_PIX_FMT_NV61, TRUE, GST_V4L2_RAW},
164 {V4L2_PIX_FMT_NV61M, TRUE, GST_V4L2_RAW},
165 {V4L2_PIX_FMT_NV24, TRUE, GST_V4L2_RAW},
166 {V4L2_PIX_FMT_NV42, TRUE, GST_V4L2_RAW},
167
168 /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
169 {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_RAW},
170 {V4L2_PIX_FMT_SGBRG8, TRUE, GST_V4L2_RAW},
171 {V4L2_PIX_FMT_SGRBG8, TRUE, GST_V4L2_RAW},
172 {V4L2_PIX_FMT_SRGGB8, TRUE, GST_V4L2_RAW},
173
174 /* compressed formats */
175 {V4L2_PIX_FMT_MJPEG, FALSE, GST_V4L2_CODEC},
176 {V4L2_PIX_FMT_JPEG, FALSE, GST_V4L2_CODEC},
177 {V4L2_PIX_FMT_PJPG, FALSE, GST_V4L2_CODEC},
178 {V4L2_PIX_FMT_DV, FALSE, GST_V4L2_TRANSPORT},
179 {V4L2_PIX_FMT_MPEG, FALSE, GST_V4L2_TRANSPORT},
180 {V4L2_PIX_FMT_FWHT, FALSE, GST_V4L2_CODEC},
xuesong.jiang26fa9792023-09-21 11:34:40 +0000181 {V4L2_PIX_FMT_H264, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
182 {V4L2_PIX_FMT_H264_NO_SC, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800183 {V4L2_PIX_FMT_H264_MVC, FALSE, GST_V4L2_CODEC},
184 {V4L2_PIX_FMT_HEVC, FALSE, GST_V4L2_CODEC},
185 {V4L2_PIX_FMT_H263, FALSE, GST_V4L2_CODEC},
186 {V4L2_PIX_FMT_MPEG1, FALSE, GST_V4L2_CODEC},
187 {V4L2_PIX_FMT_MPEG2, FALSE, GST_V4L2_CODEC},
188 {V4L2_PIX_FMT_MPEG4, FALSE, GST_V4L2_CODEC},
189 {V4L2_PIX_FMT_XVID, FALSE, GST_V4L2_CODEC},
190 {V4L2_PIX_FMT_VC1_ANNEX_G, FALSE, GST_V4L2_CODEC},
191 {V4L2_PIX_FMT_VC1_ANNEX_L, FALSE, GST_V4L2_CODEC},
192 {V4L2_PIX_FMT_VP8, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
193 {V4L2_PIX_FMT_VP9, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
194 {V4L2_PIX_FMT_AV1, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
zengliang.li51f54b62023-10-10 12:14:49 +0000195 {V4L2_PIX_FMT_AVS, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
196 {V4L2_PIX_FMT_AVS2, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
197 {V4L2_PIX_FMT_AVS3, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800198
199 /* Vendor-specific formats */
200 {V4L2_PIX_FMT_WNVA, TRUE, GST_V4L2_CODEC},
201 {V4L2_PIX_FMT_SN9C10X, TRUE, GST_V4L2_CODEC},
202 {V4L2_PIX_FMT_PWC1, TRUE, GST_V4L2_CODEC},
203 {V4L2_PIX_FMT_PWC2, TRUE, GST_V4L2_CODEC},
204};
205
206#define GST_AML_V4L2_FORMAT_COUNT (G_N_ELEMENTS(gst_aml_v4l2_formats))
207
208static GSList *gst_aml_v4l2_object_get_format_list(GstAmlV4l2Object *v4l2object);
xuesong.jiang22a9b112023-05-24 09:01:59 +0000209static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800210
211#define GST_TYPE_AML_V4L2_DEVICE_FLAGS (gst_aml_v4l2_device_get_type())
212static GType
213gst_aml_v4l2_device_get_type(void)
214{
215 static GType v4l2_device_type = 0;
216
217 if (v4l2_device_type == 0)
218 {
219 static const GFlagsValue values[] = {
220 {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"},
221 {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
222 {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
223
224 {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
225 {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
226
227 {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
228 {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
229
230 {0, NULL, NULL}};
231
232 v4l2_device_type =
233 g_flags_register_static("GstAmlV4l2DeviceTypeFlags", values);
234 }
235
236 return v4l2_device_type;
237}
238
239GType gst_aml_v4l2_io_mode_get_type(void)
240{
241 static GType v4l2_io_mode = 0;
242
243 if (!v4l2_io_mode)
244 {
245 static const GEnumValue io_modes[] = {
246 {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
247 {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
248 {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
249 {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
250 {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
251 {GST_V4L2_IO_DMABUF_IMPORT, "GST_V4L2_IO_DMABUF_IMPORT",
252 "dmabuf-import"},
253
254 {0, NULL, NULL}};
255 v4l2_io_mode = g_enum_register_static("GstAmlV4l2IOMode", io_modes);
256 }
257 return v4l2_io_mode;
258}
259
260void gst_aml_v4l2_object_install_properties_helper(GObjectClass *gobject_class,
261 const char *default_device)
262{
263 g_object_class_install_property(gobject_class, PROP_DEVICE,
264 g_param_spec_string("device", "Device", "Device location",
265 default_device, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266 g_object_class_install_property(gobject_class, PROP_DEVICE_NAME,
267 g_param_spec_string("device-name", "Device name",
268 "Name of the device", DEFAULT_PROP_DEVICE_NAME,
269 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
270 g_object_class_install_property(gobject_class, PROP_DEVICE_FD,
271 g_param_spec_int("device-fd", "File descriptor",
272 "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
273 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
274 g_object_class_install_property(gobject_class, PROP_FLAGS,
275 g_param_spec_flags("flags", "Flags", "Device type flags",
276 GST_TYPE_AML_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS,
277 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
278
279 /**
280 * GstV4l2Src:brightness:
281 *
282 * Picture brightness, or more precisely, the black level
283 */
284 g_object_class_install_property(gobject_class, PROP_BRIGHTNESS,
285 g_param_spec_int("brightness", "Brightness",
286 "Picture brightness, or more precisely, the black level", G_MININT,
287 G_MAXINT, 0,
288 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
289 /**
290 * GstV4l2Src:contrast:
291 *
292 * Picture contrast or luma gain
293 */
294 g_object_class_install_property(gobject_class, PROP_CONTRAST,
295 g_param_spec_int("contrast", "Contrast",
296 "Picture contrast or luma gain", G_MININT,
297 G_MAXINT, 0,
298 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
299 /**
300 * GstV4l2Src:saturation:
301 *
302 * Picture color saturation or chroma gain
303 */
304 g_object_class_install_property(gobject_class, PROP_SATURATION,
305 g_param_spec_int("saturation", "Saturation",
306 "Picture color saturation or chroma gain", G_MININT,
307 G_MAXINT, 0,
308 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
309 /**
310 * GstV4l2Src:hue:
311 *
312 * Hue or color balance
313 */
314 g_object_class_install_property(gobject_class, PROP_HUE,
315 g_param_spec_int("hue", "Hue",
316 "Hue or color balance", G_MININT,
317 G_MAXINT, 0,
318 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
319
320 /**
321 * GstV4l2Src:io-mode:
322 *
323 * IO Mode
324 */
325 g_object_class_install_property(gobject_class, PROP_IO_MODE,
326 g_param_spec_enum("io-mode", "IO mode",
327 "I/O mode",
328 GST_TYPE_AML_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
329 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
330
331 /**
332 * GstV4l2Src:extra-controls:
333 *
334 * Additional v4l2 controls for the device. The controls are identified
335 * by the control name (lowercase with '_' for any non-alphanumeric
336 * characters).
337 *
338 * Since: 1.2
339 */
340 g_object_class_install_property(gobject_class, PROP_EXTRA_CONTROLS,
341 g_param_spec_boxed("extra-controls", "Extra Controls",
342 "Extra v4l2 controls (CIDs) for the device",
343 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344
345 /**
346 * GstV4l2Src:pixel-aspect-ratio:
347 *
348 * The pixel aspect ratio of the device. This overwrites the pixel aspect
349 * ratio queried from the device.
350 *
351 * Since: 1.2
352 */
353 g_object_class_install_property(gobject_class, PROP_PIXEL_ASPECT_RATIO,
354 g_param_spec_string("pixel-aspect-ratio", "Pixel Aspect Ratio",
355 "Overwrite the pixel aspect ratio of the device", "1/1",
356 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357
358 /**
359 * GstV4l2Src:force-aspect-ratio:
360 *
361 * When enabled, the pixel aspect ratio queried from the device or set
362 * with the pixel-aspect-ratio property will be enforced.
363 *
364 * Since: 1.2
365 */
366 g_object_class_install_property(gobject_class, PROP_FORCE_ASPECT_RATIO,
367 g_param_spec_boolean("force-aspect-ratio", "Force aspect ratio",
368 "When enabled, the pixel aspect ratio will be enforced", TRUE,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370}
371
372void gst_aml_v4l2_object_install_m2m_properties_helper(GObjectClass *gobject_class)
373{
374 g_object_class_install_property(gobject_class, PROP_DEVICE,
375 g_param_spec_string("device", "Device", "Device location",
376 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
377
378 g_object_class_install_property(gobject_class, PROP_DEVICE_NAME,
379 g_param_spec_string("device-name", "Device name",
380 "Name of the device", DEFAULT_PROP_DEVICE_NAME,
381 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
382
383 g_object_class_install_property(gobject_class, PROP_DEVICE_FD,
384 g_param_spec_int("device-fd", "File descriptor",
385 "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
386 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
387
388 g_object_class_install_property(gobject_class, PROP_OUTPUT_IO_MODE,
389 g_param_spec_enum("output-io-mode", "Output IO mode",
390 "Output side I/O mode (matches sink pad)",
391 GST_TYPE_AML_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
392 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
393
394 g_object_class_install_property(gobject_class, PROP_CAPTURE_IO_MODE,
395 g_param_spec_enum("capture-io-mode", "Capture IO mode",
396 "Capture I/O mode (matches src pad)",
397 GST_TYPE_AML_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
398 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
399
400 g_object_class_install_property(gobject_class, PROP_EXTRA_CONTROLS,
401 g_param_spec_boxed("extra-controls", "Extra Controls",
402 "Extra v4l2 controls (CIDs) for the device",
403 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
404
405 g_object_class_install_property(gobject_class, PROP_DUMP_FRAME_LOCATION,
406 g_param_spec_string("dump-frame-location", "dump frame location",
407 "Location of the file to write decoder frames", NULL,
408 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiang22a9b112023-05-24 09:01:59 +0000409
410 g_object_class_install_property(gobject_class, PROP_STREAM_MODE,
411 g_param_spec_boolean("stream-mode", "Configure v4l2 stream mode",
412 "TRUE for stream mode, FALSE for frame mode",
413 FALSE,
414 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
hanghang.luoc54208e2023-09-22 02:43:54 +0000415 g_object_class_install_property(gobject_class, PROP_LOW_LATENCY_MODE,
416 g_param_spec_boolean("low-latency-mode", "set low latency mode",
417 "enable is TURE, disable is FALSE, default is disable",
418 FALSE,
419 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800420}
421
422/* Support for 32bit off_t, this wrapper is casting off_t to gint64 */
423#ifdef HAVE_LIBV4L2
424#if SIZEOF_OFF_T < 8
425
426static gpointer
427v4l2_mmap_wrapper(gpointer start, gsize length, gint prot, gint flags, gint fd,
428 off_t offset)
429{
430 return v4l2_mmap(start, length, prot, flags, fd, (gint64)offset);
431}
432
433#define v4l2_mmap v4l2_mmap_wrapper
434
435#endif /* SIZEOF_OFF_T < 8 */
436#endif /* HAVE_LIBV4L2 */
437
438GstAmlV4l2Object *
439gst_aml_v4l2_object_new(GstElement *element,
440 GstObject *debug_object,
441 enum v4l2_buf_type type,
442 const char *default_device,
443 GstAmlV4l2GetInOutFunction get_in_out_func,
444 GstAmlV4l2SetInOutFunction set_in_out_func,
445 GstAmlV4l2UpdateFpsFunction update_fps_func)
446{
447 GstAmlV4l2Object *v4l2object;
448
449 /*
450 * some default values
451 */
452 v4l2object = g_new0(GstAmlV4l2Object, 1);
453
454 if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == type || V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type))
455 {
456 const char *default_mode = getenv("GST_DEFAULT_V4L2_BUF_MODE");
457 GST_DEBUG("amlmodbuf GST_AML_DEFAULT_V4L2_BUF_MODE:%s", default_mode);
fei.denge9458472023-04-18 02:05:48 +0000458 //v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800459 if (default_mode)
460 {
461 if (strcmp(default_mode, "DMA_BUF_IMPORT") == 0)
462 v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
463 else if (strcmp(default_mode, "DMA_BUF") == 0)
464 v4l2object->req_mode = GST_V4L2_IO_DMABUF;
465 GST_DEBUG("amlmodbuf set default buf default_mode:%d", v4l2object->req_mode);
466 }
467 }
468
469 v4l2object->type = type;
470 v4l2object->formats = NULL;
471
472 v4l2object->element = element;
473 v4l2object->dbg_obj = debug_object;
474 v4l2object->get_in_out_func = get_in_out_func;
475 v4l2object->set_in_out_func = set_in_out_func;
476 v4l2object->update_fps_func = update_fps_func;
477
478 v4l2object->video_fd = -1;
479 v4l2object->active = FALSE;
480 v4l2object->videodev = g_strdup(default_device);
481
482 v4l2object->norms = NULL;
483 v4l2object->channels = NULL;
484 v4l2object->colors = NULL;
485
486 v4l2object->keep_aspect = TRUE;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000487 v4l2object->stream_mode = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800488
489 v4l2object->n_v4l2_planes = 0;
490
491 v4l2object->no_initial_format = FALSE;
492
493 /* We now disable libv4l2 by default, but have an env to enable it. */
494#ifdef HAVE_LIBV4L2
495 if (g_getenv("GST_V4L2_USE_LIBV4L2"))
496 {
497 v4l2object->fd_open = v4l2_fd_open;
498 v4l2object->close = v4l2_close;
499 v4l2object->dup = v4l2_dup;
500 v4l2object->ioctl = v4l2_ioctl;
501 v4l2object->read = v4l2_read;
502 v4l2object->mmap = v4l2_mmap;
503 v4l2object->munmap = v4l2_munmap;
504 }
505 else
506#endif
507 {
508 v4l2object->fd_open = NULL;
509 v4l2object->close = close;
510 v4l2object->dup = dup;
511 v4l2object->ioctl = ioctl;
512 v4l2object->read = read;
513 v4l2object->mmap = mmap;
514 v4l2object->munmap = munmap;
515 }
516 v4l2object->poll = gst_poll_new(TRUE);
517 v4l2object->can_wait_event = FALSE;
518 v4l2object->can_poll_device = TRUE;
519 v4l2object->tvin_port = -1;
520
521 v4l2object->dumpframefile = NULL;
522
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800523 /* jxsdbg resolution switching */
524 v4l2object->old_other_pool = NULL;
525 v4l2object->old_old_other_pool = NULL;
526 v4l2object->outstanding_buf_num = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800527 return v4l2object;
528}
529
530static gboolean gst_aml_v4l2_object_clear_format_list(GstAmlV4l2Object *v4l2object);
531
532void gst_aml_v4l2_object_destroy(GstAmlV4l2Object *v4l2object)
533{
534 g_return_if_fail(v4l2object != NULL);
535
536 g_free(v4l2object->videodev);
537
538 g_free(v4l2object->channel);
539
540 if (v4l2object->formats)
541 {
542 gst_aml_v4l2_object_clear_format_list(v4l2object);
543 }
544
545 if (v4l2object->probed_caps)
546 {
547 gst_caps_unref(v4l2object->probed_caps);
548 }
549
550 if (v4l2object->extra_controls)
551 {
552 gst_structure_free(v4l2object->extra_controls);
553 }
554
555 gst_poll_free(v4l2object->poll);
556
557 g_free(v4l2object->dumpframefile);
558
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800559 /* jxsdbg resolution switching */
560 if (v4l2object->old_other_pool)
561 {
562 gst_object_unref(v4l2object->old_other_pool);
563 v4l2object->old_other_pool = NULL;
564 }
565 if (v4l2object->old_old_other_pool)
566 {
567 gst_object_unref(v4l2object->old_old_other_pool);
568 v4l2object->old_old_other_pool = NULL;
569 }
570 v4l2object->outstanding_buf_num = 0;
571
xuesong.jiangae1548e2022-05-06 16:38:46 +0800572 g_free(v4l2object);
573}
574
575static gboolean
576gst_aml_v4l2_object_clear_format_list(GstAmlV4l2Object *v4l2object)
577{
578 g_slist_foreach(v4l2object->formats, (GFunc)g_free, NULL);
579 g_slist_free(v4l2object->formats);
580 v4l2object->formats = NULL;
581
582 return TRUE;
583}
584
585static gint
586gst_aml_v4l2_object_prop_to_cid(guint prop_id)
587{
588 gint cid = -1;
589
590 switch (prop_id)
591 {
592 case PROP_BRIGHTNESS:
593 cid = V4L2_CID_BRIGHTNESS;
594 break;
595 case PROP_CONTRAST:
596 cid = V4L2_CID_CONTRAST;
597 break;
598 case PROP_SATURATION:
599 cid = V4L2_CID_SATURATION;
600 break;
601 case PROP_HUE:
602 cid = V4L2_CID_HUE;
603 break;
604 default:
605 GST_WARNING("unmapped property id: %d", prop_id);
606 }
607 return cid;
608}
609
610gboolean
611gst_aml_v4l2_object_set_property_helper(GstAmlV4l2Object *v4l2object,
612 guint prop_id, const GValue *value, GParamSpec *pspec)
613{
614 switch (prop_id)
615 {
616 case PROP_DEVICE:
617 g_free(v4l2object->videodev);
618 v4l2object->videodev = g_value_dup_string(value);
619 break;
620 case PROP_BRIGHTNESS:
621 case PROP_CONTRAST:
622 case PROP_SATURATION:
623 case PROP_HUE:
624 {
625 gint cid = gst_aml_v4l2_object_prop_to_cid(prop_id);
626
627 if (cid != -1)
628 {
629 if (GST_AML_V4L2_IS_OPEN(v4l2object))
630 {
631 gst_aml_v4l2_set_attribute(v4l2object, cid, g_value_get_int(value));
632 }
633 }
634 return TRUE;
635 }
636 break;
637 case PROP_IO_MODE:
638 v4l2object->req_mode = g_value_get_enum(value);
639 break;
640 case PROP_CAPTURE_IO_MODE:
641 g_return_val_if_fail(!V4L2_TYPE_IS_OUTPUT(v4l2object->type), FALSE);
642 v4l2object->req_mode = g_value_get_enum(value);
643 break;
644 case PROP_OUTPUT_IO_MODE:
645 g_return_val_if_fail(V4L2_TYPE_IS_OUTPUT(v4l2object->type), FALSE);
646 v4l2object->req_mode = g_value_get_enum(value);
647 break;
648 case PROP_EXTRA_CONTROLS:
649 {
650 const GstStructure *s = gst_value_get_structure(value);
651
652 if (v4l2object->extra_controls)
653 gst_structure_free(v4l2object->extra_controls);
654
655 v4l2object->extra_controls = s ? gst_structure_copy(s) : NULL;
656 if (GST_AML_V4L2_IS_OPEN(v4l2object))
657 gst_aml_v4l2_set_controls(v4l2object, v4l2object->extra_controls);
658 break;
659 }
660 case PROP_PIXEL_ASPECT_RATIO:
661 if (v4l2object->par)
662 {
663 g_value_unset(v4l2object->par);
664 g_free(v4l2object->par);
665 }
666 v4l2object->par = g_new0(GValue, 1);
667 g_value_init(v4l2object->par, GST_TYPE_FRACTION);
668 if (!g_value_transform(value, v4l2object->par))
669 {
670 g_warning("Could not transform string to aspect ratio");
671 gst_value_set_fraction(v4l2object->par, 1, 1);
672 }
673
674 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set PAR to %d/%d",
675 gst_value_get_fraction_numerator(v4l2object->par),
676 gst_value_get_fraction_denominator(v4l2object->par));
677 break;
678 case PROP_FORCE_ASPECT_RATIO:
679 v4l2object->keep_aspect = g_value_get_boolean(value);
680 break;
681 case PROP_DUMP_FRAME_LOCATION:
682 g_free(v4l2object->dumpframefile);
683 v4l2object->dumpframefile = g_value_dup_string(value);
684 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000685 case PROP_STREAM_MODE:
686 v4l2object->stream_mode = g_value_get_boolean(value);
687 break;
hanghang.luoc54208e2023-09-22 02:43:54 +0000688 case PROP_LOW_LATENCY_MODE:
689 v4l2object->low_latency_mode = g_value_get_boolean(value);
690 GST_DEBUG_OBJECT(v4l2object, "set low latency: %d",v4l2object->low_latency_mode);
691 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800692 default:
693 return FALSE;
694 break;
695 }
696 return TRUE;
697}
698
699gboolean
700gst_aml_v4l2_object_get_property_helper(GstAmlV4l2Object *v4l2object,
701 guint prop_id, GValue *value, GParamSpec *pspec)
702{
703 switch (prop_id)
704 {
705 case PROP_DEVICE:
706 g_value_set_string(value, v4l2object->videodev);
707 break;
708 case PROP_DEVICE_NAME:
709 {
710 const guchar *name = NULL;
711
712 if (GST_AML_V4L2_IS_OPEN(v4l2object))
713 name = v4l2object->vcap.card;
714
715 g_value_set_string(value, (gchar *)name);
716 break;
717 }
718 case PROP_DEVICE_FD:
719 {
720 if (GST_AML_V4L2_IS_OPEN(v4l2object))
721 g_value_set_int(value, v4l2object->video_fd);
722 else
723 g_value_set_int(value, DEFAULT_PROP_DEVICE_FD);
724 break;
725 }
726 case PROP_FLAGS:
727 {
728 guint flags = 0;
729
730 if (GST_AML_V4L2_IS_OPEN(v4l2object))
731 {
732 flags |= v4l2object->device_caps &
733 (V4L2_CAP_VIDEO_CAPTURE |
734 V4L2_CAP_VIDEO_OUTPUT |
735 V4L2_CAP_VIDEO_OVERLAY |
736 V4L2_CAP_VBI_CAPTURE |
737 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
738
739 if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
740 flags |= V4L2_CAP_VIDEO_CAPTURE;
741
742 if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
743 flags |= V4L2_CAP_VIDEO_OUTPUT;
744 }
745 g_value_set_flags(value, flags);
746 break;
747 }
748 case PROP_BRIGHTNESS:
749 case PROP_CONTRAST:
750 case PROP_SATURATION:
751 case PROP_HUE:
752 {
753 gint cid = gst_aml_v4l2_object_prop_to_cid(prop_id);
754
755 if (cid != -1)
756 {
757 if (GST_AML_V4L2_IS_OPEN(v4l2object))
758 {
759 gint v;
760 if (gst_aml_v4l2_get_attribute(v4l2object, cid, &v))
761 {
762 g_value_set_int(value, v);
763 }
764 }
765 }
766 return TRUE;
767 }
768 break;
769 case PROP_IO_MODE:
770 g_value_set_enum(value, v4l2object->req_mode);
771 break;
772 case PROP_CAPTURE_IO_MODE:
773 g_return_val_if_fail(!V4L2_TYPE_IS_OUTPUT(v4l2object->type), FALSE);
774 g_value_set_enum(value, v4l2object->req_mode);
775 break;
776 case PROP_OUTPUT_IO_MODE:
777 g_return_val_if_fail(V4L2_TYPE_IS_OUTPUT(v4l2object->type), FALSE);
778 g_value_set_enum(value, v4l2object->req_mode);
779 break;
780 case PROP_EXTRA_CONTROLS:
781 gst_value_set_structure(value, v4l2object->extra_controls);
782 break;
783 case PROP_PIXEL_ASPECT_RATIO:
784 if (v4l2object->par)
785 g_value_transform(v4l2object->par, value);
786 break;
787 case PROP_FORCE_ASPECT_RATIO:
788 g_value_set_boolean(value, v4l2object->keep_aspect);
789 break;
790 case PROP_DUMP_FRAME_LOCATION:
791 g_value_set_string(value, v4l2object->dumpframefile);
792 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000793 case PROP_STREAM_MODE:
794 g_value_set_boolean(value, v4l2object->stream_mode);
795 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800796 default:
797 return FALSE;
798 break;
799 }
800 return TRUE;
801}
802
803static void
804gst_aml_v4l2_get_driver_min_buffers(GstAmlV4l2Object *v4l2object)
805{
806 struct v4l2_control control = {
807 0,
808 };
809
810 g_return_if_fail(GST_AML_V4L2_IS_OPEN(v4l2object));
811
812 if (V4L2_TYPE_IS_OUTPUT(v4l2object->type))
813 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
814 else
815 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
816
817 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0)
818 {
819 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
820 "driver requires a minimum of %d buffers", control.value);
821 v4l2object->min_buffers = control.value;
822 }
823 else
824 {
825 v4l2object->min_buffers = 0;
826 }
827}
828
829gboolean
830gst_aml_v4l2_object_open(GstAmlV4l2Object *v4l2object)
831{
832 if (!gst_aml_v4l2_open(v4l2object))
833 return FALSE;
834
835 return TRUE;
836}
837
838gboolean
839gst_aml_v4l2_object_open_shared(GstAmlV4l2Object *v4l2object, GstAmlV4l2Object *other)
840{
841 gboolean ret;
842
843 ret = gst_aml_v4l2_dup(v4l2object, other);
844
845 if (ret && !V4L2_TYPE_IS_OUTPUT(v4l2object->type))
846 {
847 gst_poll_fd_init(&v4l2object->pollfd);
848 v4l2object->pollfd.fd = v4l2object->video_fd;
849 gst_poll_add_fd(v4l2object->poll, &v4l2object->pollfd);
850 /* used for dequeue event */
851 gst_poll_fd_ctl_read(v4l2object->poll, &v4l2object->pollfd, TRUE);
852 gst_poll_fd_ctl_pri(v4l2object->poll, &v4l2object->pollfd, TRUE);
853 }
854
855 return ret;
856}
857
858gboolean
859gst_aml_v4l2_object_close(GstAmlV4l2Object *v4l2object)
860{
861 if (!gst_aml_v4l2_close(v4l2object))
862 return FALSE;
863
864 gst_caps_replace(&v4l2object->probed_caps, NULL);
865
866 /* reset our copy of the device caps */
867 v4l2object->device_caps = 0;
868
869 if (v4l2object->formats)
870 {
871 gst_aml_v4l2_object_clear_format_list(v4l2object);
872 }
873
874 if (v4l2object->par)
875 {
876 g_value_unset(v4l2object->par);
877 g_free(v4l2object->par);
878 v4l2object->par = NULL;
879 }
880
881 if (v4l2object->channel)
882 {
883 g_free(v4l2object->channel);
884 v4l2object->channel = NULL;
885 }
886
887 return TRUE;
888}
889
890static struct v4l2_fmtdesc *
891gst_aml_v4l2_object_get_format_from_fourcc(GstAmlV4l2Object *v4l2object,
892 guint32 fourcc)
893{
894 struct v4l2_fmtdesc *fmt;
895 GSList *walk;
896
897 if (fourcc == 0)
898 return NULL;
899
900 walk = gst_aml_v4l2_object_get_format_list(v4l2object);
901 while (walk)
902 {
903 fmt = (struct v4l2_fmtdesc *)walk->data;
904 if (fmt->pixelformat == fourcc)
905 return fmt;
906 /* special case for jpeg */
907 if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
908 fmt->pixelformat == V4L2_PIX_FMT_JPEG ||
909 fmt->pixelformat == V4L2_PIX_FMT_PJPG)
910 {
911 if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG ||
912 fourcc == V4L2_PIX_FMT_PJPG)
913 {
914 return fmt;
915 }
916 }
917 walk = g_slist_next(walk);
918 }
919
920 return NULL;
921}
922
923/* complete made up ranking, the values themselves are meaningless */
924/* These ranks MUST be X such that X<<15 fits on a signed int - see
925 the comment at the end of gst_aml_v4l2_object_format_get_rank. */
926#define YUV_BASE_RANK 1000
927#define JPEG_BASE_RANK 500
928#define DV_BASE_RANK 200
929#define RGB_BASE_RANK 100
930#define YUV_ODD_BASE_RANK 50
931#define RGB_ODD_BASE_RANK 25
932#define BAYER_BASE_RANK 15
933#define S910_BASE_RANK 10
934#define GREY_BASE_RANK 5
935#define PWC_BASE_RANK 1
936
937static gint
938gst_aml_v4l2_object_format_get_rank(const struct v4l2_fmtdesc *fmt)
939{
940 guint32 fourcc = fmt->pixelformat;
941 gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
942 gint rank = 0;
943
944 switch (fourcc)
945 {
946 case V4L2_PIX_FMT_MJPEG:
947 case V4L2_PIX_FMT_PJPG:
948 rank = JPEG_BASE_RANK;
949 break;
950 case V4L2_PIX_FMT_JPEG:
951 rank = JPEG_BASE_RANK + 1;
952 break;
953 case V4L2_PIX_FMT_MPEG: /* MPEG */
954 rank = JPEG_BASE_RANK + 2;
955 break;
956
957 case V4L2_PIX_FMT_RGB332:
958 case V4L2_PIX_FMT_ARGB555:
959 case V4L2_PIX_FMT_XRGB555:
960 case V4L2_PIX_FMT_RGB555:
961 case V4L2_PIX_FMT_ARGB555X:
962 case V4L2_PIX_FMT_XRGB555X:
963 case V4L2_PIX_FMT_RGB555X:
964 case V4L2_PIX_FMT_BGR666:
965 case V4L2_PIX_FMT_RGB565:
966 case V4L2_PIX_FMT_RGB565X:
967 case V4L2_PIX_FMT_RGB444:
968 case V4L2_PIX_FMT_Y4:
969 case V4L2_PIX_FMT_Y6:
970 case V4L2_PIX_FMT_Y10:
971 case V4L2_PIX_FMT_Y12:
972 case V4L2_PIX_FMT_Y10BPACK:
973 case V4L2_PIX_FMT_YUV555:
974 case V4L2_PIX_FMT_YUV565:
975 case V4L2_PIX_FMT_YUV32:
976 case V4L2_PIX_FMT_NV12MT_16X16:
977 case V4L2_PIX_FMT_NV42:
978 case V4L2_PIX_FMT_H264_MVC:
979 rank = RGB_ODD_BASE_RANK;
980 break;
981
982 case V4L2_PIX_FMT_RGB24:
983 case V4L2_PIX_FMT_BGR24:
984 rank = RGB_BASE_RANK - 1;
985 break;
986
987 case V4L2_PIX_FMT_RGB32:
988 case V4L2_PIX_FMT_BGR32:
989 case V4L2_PIX_FMT_ABGR32:
990 case V4L2_PIX_FMT_XBGR32:
991 case V4L2_PIX_FMT_ARGB32:
992 case V4L2_PIX_FMT_XRGB32:
993 rank = RGB_BASE_RANK;
994 break;
995
996 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
997 rank = GREY_BASE_RANK;
998 break;
999
1000 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
1001 case V4L2_PIX_FMT_NV12M: /* Same as NV12 */
1002 case V4L2_PIX_FMT_NV12MT: /* NV12 64x32 tile */
1003 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
1004 case V4L2_PIX_FMT_NV21M: /* Same as NV21 */
1005 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1006 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
1007 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
1008 case V4L2_PIX_FMT_NV16M: /* Same as NV16 */
1009 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
1010 case V4L2_PIX_FMT_NV61M: /* Same as NV61 */
1011 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
1012 rank = YUV_ODD_BASE_RANK;
1013 break;
1014
1015 case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */
1016 rank = YUV_BASE_RANK + 3;
1017 break;
1018 case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */
1019 rank = YUV_BASE_RANK + 2;
1020 break;
1021 case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */
1022 case V4L2_PIX_FMT_YUV420M:
1023 rank = YUV_BASE_RANK + 7;
1024 break;
1025 case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */
1026 rank = YUV_BASE_RANK + 10;
1027 break;
1028 case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */
1029 rank = YUV_BASE_RANK + 6;
1030 break;
1031 case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */
1032 rank = YUV_BASE_RANK + 9;
1033 break;
1034 case V4L2_PIX_FMT_YUV444:
1035 rank = YUV_BASE_RANK + 6;
1036 break;
1037 case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */
1038 rank = YUV_BASE_RANK + 5;
1039 break;
1040 case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
1041 rank = YUV_BASE_RANK + 4;
1042 break;
1043 case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
1044 rank = YUV_BASE_RANK + 8;
1045 break;
1046
1047 case V4L2_PIX_FMT_DV:
1048 rank = DV_BASE_RANK;
1049 break;
1050
1051 case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */
1052 rank = 0;
1053 break;
1054
1055 case V4L2_PIX_FMT_SBGGR8:
1056 case V4L2_PIX_FMT_SGBRG8:
1057 case V4L2_PIX_FMT_SGRBG8:
1058 case V4L2_PIX_FMT_SRGGB8:
1059 rank = BAYER_BASE_RANK;
1060 break;
1061
1062 case V4L2_PIX_FMT_SN9C10X:
1063 rank = S910_BASE_RANK;
1064 break;
1065
1066 case V4L2_PIX_FMT_PWC1:
1067 rank = PWC_BASE_RANK;
1068 break;
1069 case V4L2_PIX_FMT_PWC2:
1070 rank = PWC_BASE_RANK;
1071 break;
1072
1073 default:
1074 rank = 0;
1075 break;
1076 }
1077
1078 /* All ranks are below 1<<15 so a shift by 15
1079 * will a) make all non-emulated formats larger
1080 * than emulated and b) will not overflow
1081 */
1082 if (!emulated)
1083 rank <<= 15;
1084
1085 return rank;
1086}
1087
1088static gint
1089format_cmp_func(gconstpointer a, gconstpointer b)
1090{
1091 const struct v4l2_fmtdesc *fa = a;
1092 const struct v4l2_fmtdesc *fb = b;
1093
1094 if (fa->pixelformat == fb->pixelformat)
1095 return 0;
1096
1097 return gst_aml_v4l2_object_format_get_rank(fb) -
1098 gst_aml_v4l2_object_format_get_rank(fa);
1099}
1100
1101/******************************************************
1102 * gst_aml_v4l2_object_fill_format_list():
1103 * create list of supported capture formats
1104 * return value: TRUE on success, FALSE on error
1105 ******************************************************/
1106static gboolean
1107gst_aml_v4l2_object_fill_format_list(GstAmlV4l2Object *v4l2object,
1108 enum v4l2_buf_type type)
1109{
1110 gint n;
1111 struct v4l2_fmtdesc *format;
1112
1113 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "getting src format enumerations");
1114
1115 /* format enumeration */
1116 for (n = 0;; n++)
1117 {
1118 format = g_new0(struct v4l2_fmtdesc, 1);
1119
1120 format->index = n;
1121 format->type = type;
1122
1123 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0)
1124 {
1125 if (errno == EINVAL)
1126 {
1127 g_free(format);
1128 break; /* end of enumeration */
1129 }
1130 else
1131 {
1132 goto failed;
1133 }
1134 }
1135
1136 GST_LOG_OBJECT(v4l2object->dbg_obj, "index: %u", format->index);
1137 GST_LOG_OBJECT(v4l2object->dbg_obj, "type: %d", format->type);
1138 GST_LOG_OBJECT(v4l2object->dbg_obj, "flags: %08x", format->flags);
1139 GST_LOG_OBJECT(v4l2object->dbg_obj, "description: '%s'",
1140 format->description);
1141 GST_LOG_OBJECT(v4l2object->dbg_obj, "pixelformat: %" GST_FOURCC_FORMAT,
1142 GST_FOURCC_ARGS(format->pixelformat));
1143
xuesong.jiang282ca572023-05-05 09:03:32 +00001144
1145 if (V4L2_PIX_FMT_YUV420M == format->pixelformat || V4L2_PIX_FMT_YUV420 == format->pixelformat)
1146 {
1147 GST_LOG_OBJECT(v4l2object->dbg_obj, "aml v4l2 driver didn't real support YU12 and YM12, ignore it");
1148 continue;
1149 }
1150
xuesong.jiangae1548e2022-05-06 16:38:46 +08001151 /* sort formats according to our preference; we do this, because caps
1152 * are probed in the order the formats are in the list, and the order of
1153 * formats in the final probed caps matters for things like fixation */
1154 v4l2object->formats = g_slist_insert_sorted(v4l2object->formats, format,
1155 (GCompareFunc)format_cmp_func);
1156 }
1157
1158#ifndef GST_DISABLE_GST_DEBUG
1159 {
1160 GSList *l;
1161
1162 GST_INFO_OBJECT(v4l2object->dbg_obj, "got %d format(s):", n);
1163 for (l = v4l2object->formats; l != NULL; l = l->next)
1164 {
1165 format = l->data;
1166
1167 GST_INFO_OBJECT(v4l2object->dbg_obj,
1168 " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS(format->pixelformat),
1169 ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
1170 }
1171 }
1172#endif
1173
1174 return TRUE;
1175
1176 /* ERRORS */
1177failed:
1178{
1179 g_free(format);
1180
1181 if (v4l2object->element)
1182 return FALSE;
1183
1184 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, SETTINGS,
1185 (_("Failed to enumerate possible video formats device '%s' can work "
1186 "with"),
1187 v4l2object->videodev),
1188 ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
1189 n, v4l2object->videodev, errno, g_strerror(errno)));
1190
1191 return FALSE;
1192}
1193}
1194
1195/*
1196 * Get the list of supported capture formats, a list of
1197 * <code>struct v4l2_fmtdesc</code>.
1198 */
1199static GSList *
1200gst_aml_v4l2_object_get_format_list(GstAmlV4l2Object *v4l2object)
1201{
1202 if (!v4l2object->formats)
1203 {
1204
1205 /* check usual way */
1206 gst_aml_v4l2_object_fill_format_list(v4l2object, v4l2object->type);
1207
1208 /* if our driver supports multi-planar
1209 * and if formats are still empty then we can workaround driver bug
1210 * by also looking up formats as if our device was not supporting
1211 * multiplanar */
1212 if (!v4l2object->formats)
1213 {
1214 switch (v4l2object->type)
1215 {
1216 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1217 gst_aml_v4l2_object_fill_format_list(v4l2object,
1218 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1219 break;
1220
1221 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1222 gst_aml_v4l2_object_fill_format_list(v4l2object,
1223 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1224 break;
1225
1226 default:
1227 break;
1228 }
1229 }
1230 }
1231 return v4l2object->formats;
1232}
1233
1234static GstVideoFormat
1235gst_aml_v4l2_object_v4l2fourcc_to_video_format(guint32 fourcc)
1236{
1237 GstVideoFormat format;
1238
1239 switch (fourcc)
1240 {
1241 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1242 format = GST_VIDEO_FORMAT_GRAY8;
1243 break;
1244 case V4L2_PIX_FMT_Y16:
1245 format = GST_VIDEO_FORMAT_GRAY16_LE;
1246 break;
1247 case V4L2_PIX_FMT_Y16_BE:
1248 format = GST_VIDEO_FORMAT_GRAY16_BE;
1249 break;
1250 case V4L2_PIX_FMT_XRGB555:
1251 case V4L2_PIX_FMT_RGB555:
1252 format = GST_VIDEO_FORMAT_RGB15;
1253 break;
1254 case V4L2_PIX_FMT_XRGB555X:
1255 case V4L2_PIX_FMT_RGB555X:
1256 format = GST_VIDEO_FORMAT_BGR15;
1257 break;
1258 case V4L2_PIX_FMT_RGB565:
1259 format = GST_VIDEO_FORMAT_RGB16;
1260 break;
1261 case V4L2_PIX_FMT_RGB24:
1262 format = GST_VIDEO_FORMAT_RGB;
1263 break;
1264 case V4L2_PIX_FMT_BGR24:
1265 format = GST_VIDEO_FORMAT_BGR;
1266 break;
1267 case V4L2_PIX_FMT_XRGB32:
1268 case V4L2_PIX_FMT_RGB32:
1269 format = GST_VIDEO_FORMAT_xRGB;
1270 break;
1271 case V4L2_PIX_FMT_XBGR32:
1272 case V4L2_PIX_FMT_BGR32:
1273 format = GST_VIDEO_FORMAT_BGRx;
1274 break;
1275 case V4L2_PIX_FMT_ABGR32:
1276 format = GST_VIDEO_FORMAT_BGRA;
1277 break;
1278 case V4L2_PIX_FMT_ARGB32:
1279 format = GST_VIDEO_FORMAT_ARGB;
1280 break;
1281 case V4L2_PIX_FMT_NV12:
1282 case V4L2_PIX_FMT_NV12M:
1283 format = GST_VIDEO_FORMAT_NV12;
1284 break;
1285 case V4L2_PIX_FMT_NV12MT:
1286 format = GST_VIDEO_FORMAT_NV12_64Z32;
1287 break;
1288 case V4L2_PIX_FMT_NV21:
1289 case V4L2_PIX_FMT_NV21M:
1290 format = GST_VIDEO_FORMAT_NV21;
1291 break;
1292 case V4L2_PIX_FMT_YVU410:
1293 format = GST_VIDEO_FORMAT_YVU9;
1294 break;
1295 case V4L2_PIX_FMT_YUV410:
1296 format = GST_VIDEO_FORMAT_YUV9;
1297 break;
1298 case V4L2_PIX_FMT_YUV420:
1299 case V4L2_PIX_FMT_YUV420M:
1300 format = GST_VIDEO_FORMAT_I420;
1301 break;
1302 case V4L2_PIX_FMT_YUYV:
1303 format = GST_VIDEO_FORMAT_YUY2;
1304 break;
1305 case V4L2_PIX_FMT_YVU420:
1306 format = GST_VIDEO_FORMAT_YV12;
1307 break;
1308 case V4L2_PIX_FMT_UYVY:
1309 format = GST_VIDEO_FORMAT_UYVY;
1310 break;
1311 case V4L2_PIX_FMT_YUV411P:
1312 format = GST_VIDEO_FORMAT_Y41B;
1313 break;
1314 case V4L2_PIX_FMT_YUV422P:
1315 format = GST_VIDEO_FORMAT_Y42B;
1316 break;
1317 case V4L2_PIX_FMT_YVYU:
1318 format = GST_VIDEO_FORMAT_YVYU;
1319 break;
1320 case V4L2_PIX_FMT_NV16:
1321 case V4L2_PIX_FMT_NV16M:
1322 format = GST_VIDEO_FORMAT_NV16;
1323 break;
1324 case V4L2_PIX_FMT_NV61:
1325 case V4L2_PIX_FMT_NV61M:
1326 format = GST_VIDEO_FORMAT_NV61;
1327 break;
1328 case V4L2_PIX_FMT_NV24:
1329 format = GST_VIDEO_FORMAT_NV24;
1330 break;
1331 default:
1332 format = GST_VIDEO_FORMAT_UNKNOWN;
1333 break;
1334 }
1335
1336 return format;
1337}
1338
1339static gboolean
1340gst_amL_v4l2_object_v4l2fourcc_is_rgb(guint32 fourcc)
1341{
1342 gboolean ret = FALSE;
1343
1344 switch (fourcc)
1345 {
1346 case V4L2_PIX_FMT_XRGB555:
1347 case V4L2_PIX_FMT_RGB555:
1348 case V4L2_PIX_FMT_XRGB555X:
1349 case V4L2_PIX_FMT_RGB555X:
1350 case V4L2_PIX_FMT_RGB565:
1351 case V4L2_PIX_FMT_RGB24:
1352 case V4L2_PIX_FMT_BGR24:
1353 case V4L2_PIX_FMT_XRGB32:
1354 case V4L2_PIX_FMT_RGB32:
1355 case V4L2_PIX_FMT_XBGR32:
1356 case V4L2_PIX_FMT_BGR32:
1357 case V4L2_PIX_FMT_ABGR32:
1358 case V4L2_PIX_FMT_ARGB32:
1359 case V4L2_PIX_FMT_SBGGR8:
1360 case V4L2_PIX_FMT_SGBRG8:
1361 case V4L2_PIX_FMT_SGRBG8:
1362 case V4L2_PIX_FMT_SRGGB8:
1363 ret = TRUE;
1364 break;
1365 default:
1366 break;
1367 }
1368
1369 return ret;
1370}
1371
1372static GstStructure *
1373gst_aml_v4l2_object_v4l2fourcc_to_bare_struct(guint32 fourcc)
1374{
1375 GstStructure *structure = NULL;
1376
1377 switch (fourcc)
1378 {
1379 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
1380 case V4L2_PIX_FMT_PJPG: /* Progressive-JPEG */
1381 case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */
1382 structure = gst_structure_new_empty("image/jpeg");
1383 break;
1384 case V4L2_PIX_FMT_MPEG1:
1385 structure = gst_structure_new("video/mpeg",
1386 "mpegversion", G_TYPE_INT, 1, NULL);
fei.dengb5bfaa82022-07-12 17:27:13 +08001387 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1388 GST_DEBUG("aml set mpeg1 systemstream to false");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001389 break;
1390 case V4L2_PIX_FMT_MPEG2:
1391 structure = gst_structure_new("video/mpeg",
1392 "mpegversion", G_TYPE_INT, 2, NULL);
1393 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1394 GST_DEBUG("aml set mpeg2 systemstream to false");
1395 break;
1396 case V4L2_PIX_FMT_MPEG4:
1397 case V4L2_PIX_FMT_XVID:
1398 structure = gst_structure_new("video/mpeg",
1399 "mpegversion", G_TYPE_INT, 4, "systemstream",
1400 G_TYPE_BOOLEAN, FALSE, NULL);
1401 break;
1402 case V4L2_PIX_FMT_FWHT:
1403 structure = gst_structure_new_empty("video/x-fwht");
1404 break;
1405 case V4L2_PIX_FMT_H263:
1406 structure = gst_structure_new("video/x-h263",
1407 "variant", G_TYPE_STRING, "itu", NULL);
1408 break;
1409 case V4L2_PIX_FMT_H264: /* H.264 */
1410 structure = gst_structure_new("video/x-h264",
1411 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1412 G_TYPE_STRING, "au", NULL);
1413 break;
1414 case V4L2_PIX_FMT_H264_NO_SC:
1415 structure = gst_structure_new("video/x-h264",
1416 "stream-format", G_TYPE_STRING, "avc", "alignment",
1417 G_TYPE_STRING, "au", NULL);
1418 break;
1419 case V4L2_PIX_FMT_HEVC: /* H.265 */
1420 structure = gst_structure_new("video/x-h265",
1421 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1422 G_TYPE_STRING, "au", NULL);
1423 break;
1424 case V4L2_PIX_FMT_VC1_ANNEX_G:
1425 case V4L2_PIX_FMT_VC1_ANNEX_L:
1426 structure = gst_structure_new("video/x-wmv",
1427 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
1428 break;
1429 case V4L2_PIX_FMT_VP8:
1430 structure = gst_structure_new_empty("video/x-vp8");
1431 break;
1432 case V4L2_PIX_FMT_VP9:
1433 structure = gst_structure_new_empty("video/x-vp9");
1434 break;
1435 case V4L2_PIX_FMT_AV1:
1436 structure = gst_structure_new_empty("video/x-av1");
1437 break;
zengliang.li51f54b62023-10-10 12:14:49 +00001438 case V4L2_PIX_FMT_AVS:
1439 structure = gst_structure_new_empty("video/x-avs");
1440 break;
1441 case V4L2_PIX_FMT_AVS2:
1442 structure = gst_structure_new_empty("video/x-avs2");
1443 break;
1444 case V4L2_PIX_FMT_AVS3:
1445 structure = gst_structure_new_empty("video/x-avs3");
1446 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001447 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1448 case V4L2_PIX_FMT_Y16:
1449 case V4L2_PIX_FMT_Y16_BE:
1450 case V4L2_PIX_FMT_XRGB555:
1451 case V4L2_PIX_FMT_RGB555:
1452 case V4L2_PIX_FMT_XRGB555X:
1453 case V4L2_PIX_FMT_RGB555X:
1454 case V4L2_PIX_FMT_RGB565:
1455 case V4L2_PIX_FMT_RGB24:
1456 case V4L2_PIX_FMT_BGR24:
1457 case V4L2_PIX_FMT_RGB32:
1458 case V4L2_PIX_FMT_XRGB32:
1459 case V4L2_PIX_FMT_ARGB32:
1460 case V4L2_PIX_FMT_BGR32:
1461 case V4L2_PIX_FMT_XBGR32:
1462 case V4L2_PIX_FMT_ABGR32:
1463 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
1464 case V4L2_PIX_FMT_NV12M:
1465 case V4L2_PIX_FMT_NV12MT:
1466 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
1467 case V4L2_PIX_FMT_NV21M:
1468 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
1469 case V4L2_PIX_FMT_NV16M:
1470 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
1471 case V4L2_PIX_FMT_NV61M:
1472 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
1473 case V4L2_PIX_FMT_YVU410:
1474 case V4L2_PIX_FMT_YUV410:
1475 case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
1476 case V4L2_PIX_FMT_YUV420M:
1477 case V4L2_PIX_FMT_YUYV:
1478 case V4L2_PIX_FMT_YVU420:
1479 case V4L2_PIX_FMT_UYVY:
1480 case V4L2_PIX_FMT_YUV422P:
1481 case V4L2_PIX_FMT_YVYU:
1482 case V4L2_PIX_FMT_YUV411P:
1483 {
1484 GstVideoFormat format;
1485 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format(fourcc);
1486 if (format != GST_VIDEO_FORMAT_UNKNOWN)
1487 structure = gst_structure_new("video/x-raw",
1488 "format", G_TYPE_STRING, gst_video_format_to_string(format), NULL);
1489 break;
1490 }
1491 case V4L2_PIX_FMT_DV:
1492 structure =
1493 gst_structure_new("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1494 NULL);
1495 break;
1496 case V4L2_PIX_FMT_MPEG: /* MPEG */
1497 structure = gst_structure_new("video/mpegts",
1498 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
1499 break;
1500 case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */
1501 break;
1502 case V4L2_PIX_FMT_SBGGR8:
1503 case V4L2_PIX_FMT_SGBRG8:
1504 case V4L2_PIX_FMT_SGRBG8:
1505 case V4L2_PIX_FMT_SRGGB8:
1506 structure = gst_structure_new("video/x-bayer", "format", G_TYPE_STRING,
1507 fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" : fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg"
1508 : fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg"
1509 :
1510 /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb",
1511 NULL);
1512 break;
1513 case V4L2_PIX_FMT_SN9C10X:
1514 structure = gst_structure_new_empty("video/x-sonix");
1515 break;
1516 case V4L2_PIX_FMT_PWC1:
1517 structure = gst_structure_new_empty("video/x-pwc1");
1518 break;
1519 case V4L2_PIX_FMT_PWC2:
1520 structure = gst_structure_new_empty("video/x-pwc2");
1521 break;
1522 case V4L2_PIX_FMT_RGB332:
1523 case V4L2_PIX_FMT_BGR666:
1524 case V4L2_PIX_FMT_ARGB555X:
1525 case V4L2_PIX_FMT_RGB565X:
1526 case V4L2_PIX_FMT_RGB444:
1527 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1528 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
1529 case V4L2_PIX_FMT_Y4:
1530 case V4L2_PIX_FMT_Y6:
1531 case V4L2_PIX_FMT_Y10:
1532 case V4L2_PIX_FMT_Y12:
1533 case V4L2_PIX_FMT_Y10BPACK:
1534 case V4L2_PIX_FMT_YUV444:
1535 case V4L2_PIX_FMT_YUV555:
1536 case V4L2_PIX_FMT_YUV565:
1537 case V4L2_PIX_FMT_Y41P:
1538 case V4L2_PIX_FMT_YUV32:
1539 case V4L2_PIX_FMT_NV12MT_16X16:
1540 case V4L2_PIX_FMT_NV42:
1541 case V4L2_PIX_FMT_H264_MVC:
1542 default:
1543 GST_DEBUG("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
1544 fourcc, GST_FOURCC_ARGS(fourcc));
1545 break;
1546 }
1547
1548 return structure;
1549}
1550
1551GstStructure *
1552gst_aml_v4l2_object_v4l2fourcc_to_structure(guint32 fourcc)
1553{
1554 GstStructure *template;
1555 gint i;
1556
1557 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct(fourcc);
1558
1559 if (template == NULL)
1560 goto done;
1561
1562 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1563 {
1564 if (gst_aml_v4l2_formats[i].format != fourcc)
1565 continue;
1566
1567 if (gst_aml_v4l2_formats[i].dimensions)
1568 {
1569 gst_structure_set(template,
1570 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1571 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1572 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1573 }
1574 break;
1575 }
1576
1577done:
1578 return template;
1579}
1580
1581static GstCaps *
1582gst_aml_v4l2_object_get_caps_helper(GstAmlV4L2FormatFlags flags)
1583{
1584 GstStructure *structure;
1585 GstCaps *caps;
1586 guint i;
1587
1588 caps = gst_caps_new_empty();
1589 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1590 {
1591
1592 if ((gst_aml_v4l2_formats[i].flags & flags) == 0)
1593 continue;
1594
1595 structure =
1596 gst_aml_v4l2_object_v4l2fourcc_to_bare_struct(gst_aml_v4l2_formats[i].format);
1597
1598 if (structure)
1599 {
1600 GstStructure *alt_s = NULL;
1601
1602 if (gst_aml_v4l2_formats[i].dimensions)
1603 {
1604 gst_structure_set(structure,
1605 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1606 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1607 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1608 }
1609
1610 switch (gst_aml_v4l2_formats[i].format)
1611 {
1612 case V4L2_PIX_FMT_RGB32:
1613 alt_s = gst_structure_copy(structure);
1614 gst_structure_set(alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
1615 break;
1616 case V4L2_PIX_FMT_BGR32:
1617 alt_s = gst_structure_copy(structure);
1618 gst_structure_set(alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
1619 default:
1620 break;
1621 }
1622
1623 gst_caps_append_structure(caps, structure);
1624
1625 if (alt_s)
1626 gst_caps_append_structure(caps, alt_s);
1627 }
1628 }
1629
1630 return gst_caps_simplify(caps);
1631}
1632
1633GstCaps *
1634gst_aml_v4l2_object_get_all_caps(void)
1635{
1636 static GstCaps *caps = NULL;
1637
1638 if (g_once_init_enter(&caps))
1639 {
1640 GstCaps *all_caps = gst_aml_v4l2_object_get_caps_helper(GST_V4L2_ALL);
1641 GST_MINI_OBJECT_FLAG_SET(all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1642 g_once_init_leave(&caps, all_caps);
1643 }
1644
1645 return caps;
1646}
1647
1648GstCaps *
1649gst_aml_v4l2_object_get_raw_caps(void)
1650{
1651 static GstCaps *caps = NULL;
1652
1653 if (g_once_init_enter(&caps))
1654 {
1655 GstCaps *raw_caps = gst_aml_v4l2_object_get_caps_helper(GST_V4L2_RAW);
1656 GST_MINI_OBJECT_FLAG_SET(raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1657 g_once_init_leave(&caps, raw_caps);
1658 }
1659
1660 return caps;
1661}
1662
1663GstCaps *
1664gst_aml_v4l2_object_get_codec_caps(void)
1665{
1666 static GstCaps *caps = NULL;
1667
1668 if (g_once_init_enter(&caps))
1669 {
1670 GstCaps *codec_caps = gst_aml_v4l2_object_get_caps_helper(GST_V4L2_CODEC);
1671 GST_MINI_OBJECT_FLAG_SET(codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1672 g_once_init_leave(&caps, codec_caps);
1673 }
1674
1675 return caps;
1676}
1677
1678/* collect data for the given caps
1679 * @caps: given input caps
1680 * @format: location for the v4l format
1681 * @w/@h: location for width and height
1682 * @fps_n/@fps_d: location for framerate
1683 * @size: location for expected size of the frame or 0 if unknown
1684 */
1685static gboolean
1686gst_aml_v4l2_object_get_caps_info(GstAmlV4l2Object *v4l2object, GstCaps *caps,
1687 struct v4l2_fmtdesc **format, GstVideoInfo *info)
1688{
1689 GstStructure *structure;
1690 guint32 fourcc = 0, fourcc_nc = 0;
1691 const gchar *mimetype;
1692 struct v4l2_fmtdesc *fmt = NULL;
1693
fei.denge9458472023-04-18 02:05:48 +00001694 GST_DEBUG_OBJECT(v4l2object, "got caps: %" GST_PTR_FORMAT, caps);
1695
xuesong.jiangae1548e2022-05-06 16:38:46 +08001696 structure = gst_caps_get_structure(caps, 0);
1697
1698 mimetype = gst_structure_get_name(structure);
1699
1700 if (!gst_video_info_from_caps(info, caps))
1701 goto invalid_format;
1702
1703 if (g_str_equal(mimetype, "video/x-raw"))
1704 {
1705 switch (GST_VIDEO_INFO_FORMAT(info))
1706 {
1707 case GST_VIDEO_FORMAT_I420:
1708 fourcc = V4L2_PIX_FMT_YUV420;
1709 fourcc_nc = V4L2_PIX_FMT_YUV420M;
1710 break;
1711 case GST_VIDEO_FORMAT_YUY2:
1712 fourcc = V4L2_PIX_FMT_YUYV;
1713 break;
1714 case GST_VIDEO_FORMAT_UYVY:
1715 fourcc = V4L2_PIX_FMT_UYVY;
1716 break;
1717 case GST_VIDEO_FORMAT_YV12:
1718 fourcc = V4L2_PIX_FMT_YVU420;
1719 break;
1720 case GST_VIDEO_FORMAT_Y41B:
1721 fourcc = V4L2_PIX_FMT_YUV411P;
1722 break;
1723 case GST_VIDEO_FORMAT_Y42B:
1724 fourcc = V4L2_PIX_FMT_YUV422P;
1725 break;
1726 case GST_VIDEO_FORMAT_NV12:
1727 fourcc = V4L2_PIX_FMT_NV12;
1728 fourcc_nc = V4L2_PIX_FMT_NV12M;
1729 break;
1730 case GST_VIDEO_FORMAT_NV12_64Z32:
1731 fourcc_nc = V4L2_PIX_FMT_NV12MT;
1732 break;
1733 case GST_VIDEO_FORMAT_NV21:
1734 fourcc = V4L2_PIX_FMT_NV21;
1735 fourcc_nc = V4L2_PIX_FMT_NV21M;
1736 break;
1737 case GST_VIDEO_FORMAT_NV16:
1738 fourcc = V4L2_PIX_FMT_NV16;
1739 fourcc_nc = V4L2_PIX_FMT_NV16M;
1740 break;
1741 case GST_VIDEO_FORMAT_NV61:
1742 fourcc = V4L2_PIX_FMT_NV61;
1743 fourcc_nc = V4L2_PIX_FMT_NV61M;
1744 break;
1745 case GST_VIDEO_FORMAT_NV24:
1746 fourcc = V4L2_PIX_FMT_NV24;
1747 break;
1748 case GST_VIDEO_FORMAT_YVYU:
1749 fourcc = V4L2_PIX_FMT_YVYU;
1750 break;
1751 case GST_VIDEO_FORMAT_RGB15:
1752 fourcc = V4L2_PIX_FMT_RGB555;
1753 fourcc_nc = V4L2_PIX_FMT_XRGB555;
1754 break;
1755 case GST_VIDEO_FORMAT_RGB16:
1756 fourcc = V4L2_PIX_FMT_RGB565;
1757 break;
1758 case GST_VIDEO_FORMAT_RGB:
1759 fourcc = V4L2_PIX_FMT_RGB24;
1760 break;
1761 case GST_VIDEO_FORMAT_BGR:
1762 fourcc = V4L2_PIX_FMT_BGR24;
1763 break;
1764 case GST_VIDEO_FORMAT_xRGB:
1765 fourcc = V4L2_PIX_FMT_RGB32;
1766 fourcc_nc = V4L2_PIX_FMT_XRGB32;
1767 break;
1768 case GST_VIDEO_FORMAT_ARGB:
1769 fourcc = V4L2_PIX_FMT_RGB32;
1770 fourcc_nc = V4L2_PIX_FMT_ARGB32;
1771 break;
1772 case GST_VIDEO_FORMAT_BGRx:
1773 fourcc = V4L2_PIX_FMT_BGR32;
1774 fourcc_nc = V4L2_PIX_FMT_XBGR32;
1775 break;
1776 case GST_VIDEO_FORMAT_BGRA:
1777 fourcc = V4L2_PIX_FMT_BGR32;
1778 fourcc_nc = V4L2_PIX_FMT_ABGR32;
1779 break;
1780 case GST_VIDEO_FORMAT_GRAY8:
1781 fourcc = V4L2_PIX_FMT_GREY;
1782 break;
1783 case GST_VIDEO_FORMAT_GRAY16_LE:
1784 fourcc = V4L2_PIX_FMT_Y16;
1785 break;
1786 case GST_VIDEO_FORMAT_GRAY16_BE:
1787 fourcc = V4L2_PIX_FMT_Y16_BE;
1788 break;
1789 case GST_VIDEO_FORMAT_BGR15:
1790 fourcc = V4L2_PIX_FMT_RGB555X;
1791 fourcc_nc = V4L2_PIX_FMT_XRGB555X;
1792 break;
1793 default:
1794 break;
1795 }
1796 }
1797 else
1798 {
1799 if (g_str_equal(mimetype, "video/mpegts"))
1800 {
1801 fourcc = V4L2_PIX_FMT_MPEG;
1802 }
1803 else if (g_str_equal(mimetype, "video/x-dv"))
1804 {
1805 fourcc = V4L2_PIX_FMT_DV;
1806 }
1807 else if (g_str_equal(mimetype, "image/jpeg"))
1808 {
1809 fourcc = V4L2_PIX_FMT_JPEG;
1810 }
1811 else if (g_str_equal(mimetype, "video/mpeg"))
1812 {
1813 gint version;
1814 if (gst_structure_get_int(structure, "mpegversion", &version))
1815 {
1816 switch (version)
1817 {
1818 case 1:
1819 fourcc = V4L2_PIX_FMT_MPEG1;
1820 break;
1821 case 2:
1822 fourcc = V4L2_PIX_FMT_MPEG2;
1823 break;
1824 case 4:
1825 fourcc = V4L2_PIX_FMT_MPEG4;
1826 fourcc_nc = V4L2_PIX_FMT_XVID;
1827 break;
1828 default:
1829 break;
1830 }
1831 }
1832 }
1833 else if (g_str_equal(mimetype, "video/x-fwht"))
1834 {
1835 fourcc = V4L2_PIX_FMT_FWHT;
1836 }
1837 else if (g_str_equal(mimetype, "video/x-h263"))
1838 {
1839 fourcc = V4L2_PIX_FMT_H263;
1840 }
1841 else if (g_str_equal(mimetype, "video/x-h264"))
1842 {
1843 const gchar *stream_format =
1844 gst_structure_get_string(structure, "stream-format");
1845 if (g_str_equal(stream_format, "avc"))
1846 fourcc = V4L2_PIX_FMT_H264_NO_SC;
1847 else
1848 fourcc = V4L2_PIX_FMT_H264;
1849 }
1850 else if (g_str_equal(mimetype, "video/x-h265"))
1851 {
1852 fourcc = V4L2_PIX_FMT_HEVC;
1853 }
1854 else if (g_str_equal(mimetype, "video/x-vp8"))
1855 {
1856 fourcc = V4L2_PIX_FMT_VP8;
1857 }
1858 else if (g_str_equal(mimetype, "video/x-vp9"))
1859 {
1860 fourcc = V4L2_PIX_FMT_VP9;
1861 }
1862 else if (g_str_equal(mimetype, "video/x-av1"))
1863 {
1864 fourcc = V4L2_PIX_FMT_AV1;
1865 }
zengliang.li51f54b62023-10-10 12:14:49 +00001866 else if (g_str_equal(mimetype, "video/x-avs"))
1867 {
1868 fourcc = V4L2_PIX_FMT_AVS;
1869 }
1870 else if (g_str_equal(mimetype, "video/x-avs2"))
1871 {
1872 fourcc = V4L2_PIX_FMT_AVS2;
1873 }
1874 else if (g_str_equal(mimetype, "video/x-avs3"))
1875 {
1876 fourcc = V4L2_PIX_FMT_AVS3;
1877 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001878 else if (g_str_equal(mimetype, "video/x-bayer"))
1879 {
hanghang.luo3128f102022-08-18 10:36:19 +08001880 const gchar *vformat = gst_structure_get_string(structure, "format");
1881 if (vformat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001882 {
1883 if (!g_ascii_strcasecmp(format, "bggr"))
1884 fourcc = V4L2_PIX_FMT_SBGGR8;
1885 else if (!g_ascii_strcasecmp(format, "gbrg"))
1886 fourcc = V4L2_PIX_FMT_SGBRG8;
1887 else if (!g_ascii_strcasecmp(format, "grbg"))
1888 fourcc = V4L2_PIX_FMT_SGRBG8;
1889 else if (!g_ascii_strcasecmp(format, "rggb"))
1890 fourcc = V4L2_PIX_FMT_SRGGB8;
1891 }
1892 }
1893 else if (g_str_equal(mimetype, "video/x-sonix"))
1894 {
1895 fourcc = V4L2_PIX_FMT_SN9C10X;
1896 }
1897 else if (g_str_equal(mimetype, "video/x-pwc1"))
1898 {
1899 fourcc = V4L2_PIX_FMT_PWC1;
1900 }
1901 else if (g_str_equal(mimetype, "video/x-pwc2"))
1902 {
1903 fourcc = V4L2_PIX_FMT_PWC2;
1904 }
1905 }
1906
1907 /* Prefer the non-contiguous if supported */
1908 v4l2object->prefered_non_contiguous = TRUE;
1909
1910 if (fourcc_nc)
1911 fmt = gst_aml_v4l2_object_get_format_from_fourcc(v4l2object, fourcc_nc);
1912 else if (fourcc == 0)
1913 goto unhandled_format;
1914
1915 if (fmt == NULL)
1916 {
1917 fmt = gst_aml_v4l2_object_get_format_from_fourcc(v4l2object, fourcc);
1918 v4l2object->prefered_non_contiguous = FALSE;
1919 }
1920
1921 if (fmt == NULL)
1922 goto unsupported_format;
1923
1924 *format = fmt;
1925
1926 return TRUE;
1927
1928 /* ERRORS */
1929invalid_format:
1930{
1931 GST_DEBUG_OBJECT(v4l2object, "invalid format");
1932 return FALSE;
1933}
1934unhandled_format:
1935{
1936 GST_DEBUG_OBJECT(v4l2object, "unhandled format");
1937 return FALSE;
1938}
1939unsupported_format:
1940{
1941 GST_DEBUG_OBJECT(v4l2object, "unsupported format");
1942 return FALSE;
1943}
1944}
1945
1946static gboolean
1947gst_aml_v4l2_object_get_nearest_size(GstAmlV4l2Object *v4l2object,
1948 guint32 pixelformat, gint *width, gint *height);
1949
1950static void
1951gst_aml_v4l2_object_add_aspect_ratio(GstAmlV4l2Object *v4l2object, GstStructure *s)
1952{
1953 if (v4l2object->keep_aspect && v4l2object->par)
1954 gst_structure_set_value(s, "pixel-aspect-ratio", v4l2object->par);
1955}
1956
1957/* returns TRUE if the value was changed in place, otherwise FALSE */
1958static gboolean
1959gst_aml_v4l2src_value_simplify(GValue *val)
1960{
1961 /* simplify list of one value to one value */
1962 if (GST_VALUE_HOLDS_LIST(val) && gst_value_list_get_size(val) == 1)
1963 {
1964 const GValue *list_val;
1965 GValue new_val = G_VALUE_INIT;
1966
1967 list_val = gst_value_list_get_value(val, 0);
1968 g_value_init(&new_val, G_VALUE_TYPE(list_val));
1969 g_value_copy(list_val, &new_val);
1970 g_value_unset(val);
1971 *val = new_val;
1972 return TRUE;
1973 }
1974
1975 return FALSE;
1976}
1977
1978static gboolean
1979gst_aml_v4l2_object_get_interlace_mode(enum v4l2_field field,
1980 GstVideoInterlaceMode *interlace_mode)
1981{
1982 switch (field)
1983 {
1984 case V4L2_FIELD_ANY:
1985 GST_ERROR("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
1986 /* fallthrough */
1987 case V4L2_FIELD_NONE:
1988 *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
1989 return TRUE;
1990 case V4L2_FIELD_INTERLACED:
1991 case V4L2_FIELD_INTERLACED_TB:
1992 case V4L2_FIELD_INTERLACED_BT:
1993 *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1994 return TRUE;
1995 default:
1996 GST_ERROR("Unknown enum v4l2_field %d", field);
1997 return FALSE;
1998 }
1999}
2000
2001static gboolean
2002gst_aml_v4l2_object_get_colorspace(struct v4l2_format *fmt,
2003 GstVideoColorimetry *cinfo)
2004{
2005 gboolean is_rgb =
2006 gst_amL_v4l2_object_v4l2fourcc_is_rgb(fmt->fmt.pix.pixelformat);
2007 enum v4l2_colorspace colorspace;
2008 enum v4l2_quantization range;
2009 enum v4l2_ycbcr_encoding matrix;
2010 enum v4l2_xfer_func transfer;
2011 gboolean ret = TRUE;
2012
2013 if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type))
2014 {
2015 colorspace = fmt->fmt.pix_mp.colorspace;
2016 range = fmt->fmt.pix_mp.quantization;
2017 matrix = fmt->fmt.pix_mp.ycbcr_enc;
2018 transfer = fmt->fmt.pix_mp.xfer_func;
2019 }
2020 else
2021 {
2022 colorspace = fmt->fmt.pix.colorspace;
2023 range = fmt->fmt.pix.quantization;
2024 matrix = fmt->fmt.pix.ycbcr_enc;
2025 transfer = fmt->fmt.pix.xfer_func;
2026 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002027 GST_DEBUG("colorspace:%d, range:%d, matrix:%d, transfer:%d", colorspace, range, matrix, transfer);
2028 GST_DEBUG("cinfo update 1 time | range:%d, matrix:%d, transfer:%d, primaries:%d", cinfo->range, cinfo->matrix, cinfo->transfer, cinfo->primaries);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002029
2030 /* First step, set the defaults for each primaries */
2031 switch (colorspace)
2032 {
2033 case V4L2_COLORSPACE_SMPTE170M:
2034 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2035 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2036 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2037 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
2038 break;
2039 case V4L2_COLORSPACE_REC709:
2040 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2041 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2042 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2043 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2044 break;
2045 case V4L2_COLORSPACE_SRGB:
2046 case V4L2_COLORSPACE_JPEG:
2047 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2048 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2049 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2050 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2051 break;
2052 case V4L2_COLORSPACE_OPRGB:
2053 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2054 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2055 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2056 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
2057 break;
2058 case V4L2_COLORSPACE_BT2020:
2059 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2060 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2061 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2062 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
2063 break;
2064 case V4L2_COLORSPACE_SMPTE240M:
2065 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2066 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2067 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2068 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
2069 break;
2070 case V4L2_COLORSPACE_470_SYSTEM_M:
2071 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2072 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2073 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2074 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
2075 break;
2076 case V4L2_COLORSPACE_470_SYSTEM_BG:
2077 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2078 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2079 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2080 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
2081 break;
2082 case V4L2_COLORSPACE_RAW:
2083 /* Explicitly unknown */
2084 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2085 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2086 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2087 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
2088 break;
2089 default:
2090 GST_DEBUG("Unknown enum v4l2_colorspace %d", colorspace);
2091 ret = FALSE;
2092 break;
2093 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002094 GST_DEBUG("cinfo update 2 time | range:%d, matrix:%d, transfer:%d, primaries:%d", cinfo->range, cinfo->matrix, cinfo->transfer, cinfo->primaries);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002095
2096 if (!ret)
2097 goto done;
2098
2099 /* Second step, apply any custom variation */
2100 switch (range)
2101 {
2102 case V4L2_QUANTIZATION_FULL_RANGE:
2103 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2104 break;
2105 case V4L2_QUANTIZATION_LIM_RANGE:
2106 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2107 break;
2108 case V4L2_QUANTIZATION_DEFAULT:
2109 /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
2110 if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
2111 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2112 else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601 || matrix == V4L2_YCBCR_ENC_XV709 || colorspace == V4L2_COLORSPACE_JPEG)
2113 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2114 else
2115 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2116 break;
2117 default:
2118 GST_WARNING("Unknown enum v4l2_quantization value %d", range);
2119 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2120 break;
2121 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002122 GST_DEBUG("cinfo update 3 time | range:%d, matrix:%d, transfer:%d, primaries:%d", cinfo->range, cinfo->matrix, cinfo->transfer, cinfo->primaries);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002123
2124 switch (matrix)
2125 {
2126 case V4L2_YCBCR_ENC_XV601:
2127 case V4L2_YCBCR_ENC_SYCC:
2128 GST_FIXME("XV601 and SYCC not defined, assuming 601");
2129 /* fallthrough */
2130 case V4L2_YCBCR_ENC_601:
2131 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2132 break;
2133 case V4L2_YCBCR_ENC_XV709:
2134 GST_FIXME("XV709 not defined, assuming 709");
2135 /* fallthrough */
2136 case V4L2_YCBCR_ENC_709:
2137 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2138 break;
2139 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
2140 GST_FIXME("BT2020 with constant luma is not defined, assuming BT2020");
2141 /* fallthrough */
2142 case V4L2_YCBCR_ENC_BT2020:
2143 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2144 break;
2145 case V4L2_YCBCR_ENC_SMPTE240M:
2146 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2147 break;
2148 case V4L2_YCBCR_ENC_DEFAULT:
2149 /* nothing, just use defaults for colorspace */
2150 break;
2151 default:
2152 GST_WARNING("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
2153 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2154 break;
2155 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002156 GST_DEBUG("cinfo update 4 time | range:%d, matrix:%d, transfer:%d, primaries:%d", cinfo->range, cinfo->matrix, cinfo->transfer, cinfo->primaries);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002157
2158 /* Set identity matrix for R'G'B' formats to avoid creating
2159 * confusion. This though is cosmetic as it's now properly ignored by
2160 * the video info API and videoconvert. */
2161 if (is_rgb)
2162 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2163
2164 switch (transfer)
2165 {
2166 case V4L2_XFER_FUNC_709:
2167 if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160)
2168 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2169 else
2170 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2171 break;
2172 case V4L2_XFER_FUNC_SRGB:
2173 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2174 break;
2175 case V4L2_XFER_FUNC_OPRGB:
2176 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2177 break;
2178 case V4L2_XFER_FUNC_SMPTE240M:
2179 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2180 break;
2181 case V4L2_XFER_FUNC_NONE:
2182 cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
2183 break;
2184 case V4L2_XFER_FUNC_DEFAULT:
2185 /* nothing, just use defaults for colorspace */
2186 break;
2187 default:
2188 GST_WARNING("Unknown enum v4l2_xfer_func value %d", transfer);
2189 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2190 break;
2191 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002192 GST_DEBUG("cinfo update 5 time | range:%d, matrix:%d, transfer:%d, primaries:%d", cinfo->range, cinfo->matrix, cinfo->transfer, cinfo->primaries);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002193
2194done:
2195 return ret;
2196}
2197
2198static int
2199gst_aml_v4l2_object_try_fmt(GstAmlV4l2Object *v4l2object,
2200 struct v4l2_format *try_fmt)
2201{
2202 int fd = v4l2object->video_fd;
2203 struct v4l2_format fmt;
2204 int r;
2205
2206 memcpy(&fmt, try_fmt, sizeof(fmt));
2207 r = v4l2object->ioctl(fd, VIDIOC_TRY_FMT, &fmt);
2208
2209 if (r < 0 && errno == ENOTTY)
2210 {
2211 /* The driver might not implement TRY_FMT, in which case we will try
2212 S_FMT to probe */
2213 if (GST_AML_V4L2_IS_ACTIVE(v4l2object))
2214 goto error;
2215
2216 memcpy(&fmt, try_fmt, sizeof(fmt));
2217 r = v4l2object->ioctl(fd, VIDIOC_S_FMT, &fmt);
2218 }
2219 memcpy(try_fmt, &fmt, sizeof(fmt));
2220
2221 return r;
2222
2223error:
2224 memcpy(try_fmt, &fmt, sizeof(fmt));
2225 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2226 "Unable to try format: %s", g_strerror(errno));
2227 return r;
2228}
2229
2230static void
2231gst_aml_v4l2_object_add_interlace_mode(GstAmlV4l2Object *v4l2object,
2232 GstStructure *s, guint32 width, guint32 height, guint32 pixelformat)
2233{
2234 struct v4l2_format fmt;
2235 GValue interlace_formats = {
2236 0,
2237 };
2238 enum v4l2_field formats[] = {V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED};
2239 gsize i;
2240 GstVideoInterlaceMode interlace_mode, prev = -1;
2241
2242 if (!g_str_equal(gst_structure_get_name(s), "video/x-raw"))
2243 return;
2244
2245 if (v4l2object->never_interlaced)
2246 {
2247 gst_structure_set(s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
2248 return;
2249 }
2250
2251 g_value_init(&interlace_formats, GST_TYPE_LIST);
2252
2253 /* Try twice - once for NONE, once for INTERLACED. */
2254 for (i = 0; i < G_N_ELEMENTS(formats); i++)
2255 {
2256 memset(&fmt, 0, sizeof(fmt));
2257 fmt.type = v4l2object->type;
2258 fmt.fmt.pix.width = width;
2259 fmt.fmt.pix.height = height;
2260 fmt.fmt.pix.pixelformat = pixelformat;
2261 fmt.fmt.pix.field = formats[i];
2262
2263 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0 &&
2264 gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode)
2265 {
2266 GValue interlace_enum = {
2267 0,
2268 };
2269 const gchar *mode_string;
2270 g_value_init(&interlace_enum, G_TYPE_STRING);
2271 mode_string = gst_video_interlace_mode_to_string(interlace_mode);
2272 g_value_set_string(&interlace_enum, mode_string);
2273 gst_value_list_append_and_take_value(&interlace_formats,
2274 &interlace_enum);
2275 prev = interlace_mode;
2276 }
2277 }
2278
2279 if (gst_aml_v4l2src_value_simplify(&interlace_formats) || gst_value_list_get_size(&interlace_formats) > 0)
2280 gst_structure_take_value(s, "interlace-mode", &interlace_formats);
2281 else
2282 GST_WARNING_OBJECT(v4l2object, "Failed to determine interlace mode");
2283
2284 return;
2285}
2286
2287static void
2288gst_aml_v4l2_object_fill_colorimetry_list(GValue *list,
2289 GstVideoColorimetry *cinfo)
2290{
2291 GValue colorimetry = G_VALUE_INIT;
2292 guint size;
2293 guint i;
2294 gboolean found = FALSE;
2295
2296 g_value_init(&colorimetry, G_TYPE_STRING);
2297 g_value_take_string(&colorimetry, gst_video_colorimetry_to_string(cinfo));
xuesong.jiange1a19662022-06-21 20:30:22 +08002298 GST_DEBUG("fill colorimetry:%s into list", gst_video_colorimetry_to_string(cinfo));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002299
2300 /* only insert if no duplicate */
2301 size = gst_value_list_get_size(list);
2302 for (i = 0; i < size; i++)
2303 {
2304 const GValue *tmp;
2305
2306 tmp = gst_value_list_get_value(list, i);
2307 if (gst_value_compare(&colorimetry, tmp) == GST_VALUE_EQUAL)
2308 {
2309 found = TRUE;
2310 break;
2311 }
2312 }
2313
2314 if (!found)
2315 gst_value_list_append_and_take_value(list, &colorimetry);
2316 else
2317 g_value_unset(&colorimetry);
2318}
2319
2320static void
2321gst_aml_v4l2_object_add_colorspace(GstAmlV4l2Object *v4l2object, GstStructure *s,
2322 guint32 width, guint32 height, guint32 pixelformat)
2323{
2324 struct v4l2_format fmt;
2325 GValue list = G_VALUE_INIT;
2326 GstVideoColorimetry cinfo;
2327 enum v4l2_colorspace req_cspace;
2328
2329 memset(&fmt, 0, sizeof(fmt));
2330 fmt.type = v4l2object->type;
2331 fmt.fmt.pix.width = width;
2332 fmt.fmt.pix.height = height;
2333 fmt.fmt.pix.pixelformat = pixelformat;
2334
2335 g_value_init(&list, GST_TYPE_LIST);
2336
2337 /* step 1: get device default colorspace and insert it first as
2338 * it should be the preferred one */
xuesong.jiange1a19662022-06-21 20:30:22 +08002339 GST_DEBUG("try for pixl format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002340 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0)
2341 {
2342 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2343 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2344 }
2345
2346 /* step 2: probe all colorspace other than default
2347 * We don't probe all colorspace, range, matrix and transfer combination to
2348 * avoid ioctl flooding which could greatly increase initialization time
2349 * with low-speed devices (UVC...) */
2350 for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
2351 req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++)
2352 {
xuesong.jiange1a19662022-06-21 20:30:22 +08002353 GST_DEBUG("try for pixl format in while loop :%d", req_cspace);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002354 /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
2355 if (req_cspace == V4L2_COLORSPACE_BT878)
2356 continue;
2357
2358 if (V4L2_TYPE_IS_MULTIPLANAR(v4l2object->type))
2359 fmt.fmt.pix_mp.colorspace = req_cspace;
2360 else
2361 fmt.fmt.pix.colorspace = req_cspace;
2362
2363 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0)
2364 {
xuesong.jiange1a19662022-06-21 20:30:22 +08002365 GST_DEBUG("try for pixl format in while loop :%d tried ok", req_cspace);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002366 enum v4l2_colorspace colorspace;
2367
2368 if (V4L2_TYPE_IS_MULTIPLANAR(v4l2object->type))
2369 colorspace = fmt.fmt.pix_mp.colorspace;
2370 else
2371 colorspace = fmt.fmt.pix.colorspace;
2372
2373 if (colorspace == req_cspace)
2374 {
2375 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2376 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2377 }
2378 }
2379 }
2380
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002381 GST_DEBUG("deal: caps with colorimetry 2,3,14,7");
xuesong.jiange1a19662022-06-21 20:30:22 +08002382 cinfo.range = 2;
2383 cinfo.matrix = 3;
2384 cinfo.transfer = 14;
2385 cinfo.primaries = 7;
2386 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2387
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002388 GST_DEBUG("deal: caps with colorimetry 2,6,13,7");
2389 cinfo.range = 2;
2390 cinfo.matrix = 6;
2391 cinfo.transfer = 13;
2392 cinfo.primaries = 7;
2393 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2394
xuesong.jiang5c9aca72022-07-12 16:29:24 +08002395 GST_DEBUG("deal: caps with colorimetry 2,6,14,7");
2396 cinfo.range = 2;
2397 cinfo.matrix = 6;
2398 cinfo.transfer = 14;
2399 cinfo.primaries = 7;
2400 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2401
fei.dengccc89632022-07-15 19:10:17 +08002402 GST_DEBUG("deal: caps with colorimetry 2,6,0,7");
2403 cinfo.range = 2;
2404 cinfo.matrix = 6;
2405 cinfo.transfer = 0;
2406 cinfo.primaries = 7;
2407 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2408
fei.dengca85b052022-07-19 14:49:23 +08002409 GST_DEBUG("deal: caps with colorimetry 0,6,0,7");
2410 cinfo.range = 0;
2411 cinfo.matrix = 6;
2412 cinfo.transfer = 0;
2413 cinfo.primaries = 7;
2414 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2415
sheng.liua326d202022-07-20 14:15:34 +08002416 GST_DEBUG("deal: caps with colorimetry 2,3,0,0");
2417 cinfo.range = 2;
2418 cinfo.matrix = 3;
2419 cinfo.transfer = 0;
2420 cinfo.primaries = 0;
2421 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2422
hanghang.luoc54208e2023-09-22 02:43:54 +00002423 GST_DEBUG("deal: caps with colorimetry 2,6,14,0");
2424 cinfo.range = 2;
2425 cinfo.matrix = 6;
2426 cinfo.transfer = 14;
2427 cinfo.primaries = 0;
2428 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2429
xuesong.jiangae1548e2022-05-06 16:38:46 +08002430 if (gst_value_list_get_size(&list) > 0)
2431 gst_structure_take_value(s, "colorimetry", &list);
2432 else
2433 g_value_unset(&list);
2434
2435 return;
2436}
2437
2438/* The frame interval enumeration code first appeared in Linux 2.6.19. */
2439static GstStructure *
2440gst_aml_v4l2_object_probe_caps_for_format_and_size(GstAmlV4l2Object *v4l2object,
2441 guint32 pixelformat,
2442 guint32 width, guint32 height, const GstStructure *template)
2443{
2444 gint fd = v4l2object->video_fd;
2445 struct v4l2_frmivalenum ival;
2446 guint32 num, denom;
2447 GstStructure *s;
2448 GValue rates = {
2449 0,
2450 };
2451
2452 memset(&ival, 0, sizeof(struct v4l2_frmivalenum));
2453 ival.index = 0;
2454 ival.pixel_format = pixelformat;
2455 ival.width = width;
2456 ival.height = height;
2457
2458 GST_LOG_OBJECT(v4l2object->dbg_obj,
2459 "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
2460 GST_FOURCC_ARGS(pixelformat));
2461
2462 /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
2463 * fraction to get framerate */
2464 if (v4l2object->ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
2465 goto enum_frameintervals_failed;
2466
2467 if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
2468 {
2469 GValue rate = {
2470 0,
2471 };
2472
2473 g_value_init(&rates, GST_TYPE_LIST);
2474 g_value_init(&rate, GST_TYPE_FRACTION);
2475
2476 do
2477 {
2478 num = ival.discrete.numerator;
2479 denom = ival.discrete.denominator;
2480
2481 if (num > G_MAXINT || denom > G_MAXINT)
2482 {
2483 /* let us hope we don't get here... */
2484 num >>= 1;
2485 denom >>= 1;
2486 }
2487
2488 GST_LOG_OBJECT(v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
2489 denom, num);
2490
2491 /* swap to get the framerate */
2492 gst_value_set_fraction(&rate, denom, num);
2493 gst_value_list_append_value(&rates, &rate);
2494
2495 ival.index++;
2496 } while (v4l2object->ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
2497 }
2498 else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
2499 {
2500 GValue min = {
2501 0,
2502 };
2503 GValue step = {
2504 0,
2505 };
2506 GValue max = {
2507 0,
2508 };
2509 gboolean added = FALSE;
2510 guint32 minnum, mindenom;
2511 guint32 maxnum, maxdenom;
2512
2513 g_value_init(&rates, GST_TYPE_LIST);
2514
2515 g_value_init(&min, GST_TYPE_FRACTION);
2516 g_value_init(&step, GST_TYPE_FRACTION);
2517 g_value_init(&max, GST_TYPE_FRACTION);
2518
2519 /* get the min */
2520 minnum = ival.stepwise.min.numerator;
2521 mindenom = ival.stepwise.min.denominator;
2522 if (minnum > G_MAXINT || mindenom > G_MAXINT)
2523 {
2524 minnum >>= 1;
2525 mindenom >>= 1;
2526 }
2527 GST_LOG_OBJECT(v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
2528 minnum, mindenom);
2529 gst_value_set_fraction(&min, minnum, mindenom);
2530
2531 /* get the max */
2532 maxnum = ival.stepwise.max.numerator;
2533 maxdenom = ival.stepwise.max.denominator;
2534 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2535 {
2536 maxnum >>= 1;
2537 maxdenom >>= 1;
2538 }
2539
2540 GST_LOG_OBJECT(v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
2541 maxnum, maxdenom);
2542 gst_value_set_fraction(&max, maxnum, maxdenom);
2543
2544 /* get the step */
2545 num = ival.stepwise.step.numerator;
2546 denom = ival.stepwise.step.denominator;
2547 if (num > G_MAXINT || denom > G_MAXINT)
2548 {
2549 num >>= 1;
2550 denom >>= 1;
2551 }
2552
2553 if (num == 0 || denom == 0)
2554 {
2555 /* in this case we have a wrong fraction or no step, set the step to max
2556 * so that we only add the min value in the loop below */
2557 num = maxnum;
2558 denom = maxdenom;
2559 }
2560
2561 /* since we only have gst_value_fraction_subtract and not add, negate the
2562 * numerator */
2563 GST_LOG_OBJECT(v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
2564 num, denom);
2565 gst_value_set_fraction(&step, -num, denom);
2566
2567 while (gst_value_compare(&min, &max) != GST_VALUE_GREATER_THAN)
2568 {
2569 GValue rate = {
2570 0,
2571 };
2572
2573 num = gst_value_get_fraction_numerator(&min);
2574 denom = gst_value_get_fraction_denominator(&min);
2575 GST_LOG_OBJECT(v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
2576 denom, num);
2577
2578 /* invert to get the framerate */
2579 g_value_init(&rate, GST_TYPE_FRACTION);
2580 gst_value_set_fraction(&rate, denom, num);
2581 gst_value_list_append_value(&rates, &rate);
2582 added = TRUE;
2583
2584 /* we're actually adding because step was negated above. This is because
2585 * there is no _add function... */
2586 if (!gst_value_fraction_subtract(&min, &min, &step))
2587 {
2588 GST_WARNING_OBJECT(v4l2object->dbg_obj, "could not step fraction!");
2589 break;
2590 }
2591 }
2592 if (!added)
2593 {
2594 /* no range was added, leave the default range from the template */
2595 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2596 "no range added, leaving default");
2597 g_value_unset(&rates);
2598 }
2599 }
2600 else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
2601 {
2602 guint32 maxnum, maxdenom;
2603
2604 g_value_init(&rates, GST_TYPE_FRACTION_RANGE);
2605
2606 num = ival.stepwise.min.numerator;
2607 denom = ival.stepwise.min.denominator;
2608 if (num > G_MAXINT || denom > G_MAXINT)
2609 {
2610 num >>= 1;
2611 denom >>= 1;
2612 }
2613
2614 maxnum = ival.stepwise.max.numerator;
2615 maxdenom = ival.stepwise.max.denominator;
2616 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2617 {
2618 maxnum >>= 1;
2619 maxdenom >>= 1;
2620 }
2621
2622 GST_LOG_OBJECT(v4l2object->dbg_obj,
2623 "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2624 num);
2625
2626 gst_value_set_fraction_range_full(&rates, maxdenom, maxnum, denom, num);
2627 }
2628 else
2629 {
2630 goto unknown_type;
2631 }
2632
2633return_data:
2634 s = gst_structure_copy(template);
2635 gst_structure_set(s, "width", G_TYPE_INT, (gint)width,
2636 "height", G_TYPE_INT, (gint)height, NULL);
2637
2638 gst_aml_v4l2_object_add_aspect_ratio(v4l2object, s);
2639
2640 if (!v4l2object->skip_try_fmt_probes)
2641 {
2642 gst_aml_v4l2_object_add_interlace_mode(v4l2object, s, width, height,
2643 pixelformat);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002644 // gst_aml_v4l2_object_add_colorspace(v4l2object, s, width, height, pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002645 }
2646
2647 if (G_IS_VALUE(&rates))
2648 {
2649 gst_aml_v4l2src_value_simplify(&rates);
2650 /* only change the framerate on the template when we have a valid probed new
2651 * value */
2652 gst_structure_take_value(s, "framerate", &rates);
2653 }
2654 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2655 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2656 {
2657 gst_structure_set(s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
2658 1, NULL);
2659 }
2660 return s;
2661
2662 /* ERRORS */
2663enum_frameintervals_failed:
2664{
2665 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2666 "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2667 GST_FOURCC_ARGS(pixelformat), width, height);
2668 goto return_data;
2669}
2670unknown_type:
2671{
2672 /* I don't see how this is actually an error, we ignore the format then */
2673 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2674 "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2675 GST_FOURCC_ARGS(pixelformat), width, height, ival.type);
2676 return NULL;
2677}
2678}
2679
2680static gint
2681sort_by_frame_size(GstStructure *s1, GstStructure *s2)
2682{
2683 int w1, h1, w2, h2;
2684
2685 gst_structure_get_int(s1, "width", &w1);
2686 gst_structure_get_int(s1, "height", &h1);
2687 gst_structure_get_int(s2, "width", &w2);
2688 gst_structure_get_int(s2, "height", &h2);
2689
2690 /* I think it's safe to assume that this won't overflow for a while */
2691 return ((w2 * h2) - (w1 * h1));
2692}
2693
2694static void
2695gst_aml_v4l2_object_update_and_append(GstAmlV4l2Object *v4l2object,
2696 guint32 format, GstCaps *caps, GstStructure *s)
2697{
2698 GstStructure *alt_s = NULL;
2699
2700 /* Encoded stream on output buffer need to be parsed */
2701 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
2702 v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2703 {
2704 gint i = 0;
2705
2706 for (; i < GST_AML_V4L2_FORMAT_COUNT; i++)
2707 {
2708 if (format == gst_aml_v4l2_formats[i].format &&
2709 gst_aml_v4l2_formats[i].flags & GST_V4L2_CODEC &&
2710 !(gst_aml_v4l2_formats[i].flags & GST_V4L2_NO_PARSE))
2711 {
2712 gst_structure_set(s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2713 break;
2714 }
2715 }
2716 }
2717
2718 if (v4l2object->has_alpha_component &&
2719 (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2720 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
2721 {
2722 switch (format)
2723 {
2724 case V4L2_PIX_FMT_RGB32:
2725 alt_s = gst_structure_copy(s);
2726 gst_structure_set(alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
2727 break;
2728 case V4L2_PIX_FMT_BGR32:
2729 alt_s = gst_structure_copy(s);
2730 gst_structure_set(alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
2731 break;
2732 default:
2733 break;
2734 }
2735 }
2736
2737 gst_caps_append_structure(caps, s);
2738
2739 if (alt_s)
2740 gst_caps_append_structure(caps, alt_s);
2741}
2742
2743static GstCaps *
2744gst_aml_v4l2_object_probe_caps_for_format(GstAmlV4l2Object *v4l2object,
2745 guint32 pixelformat, const GstStructure *template)
2746{
2747 GstCaps *ret = gst_caps_new_empty();
2748 GstStructure *tmp;
2749 gint fd = v4l2object->video_fd;
2750 struct v4l2_frmsizeenum size;
2751 GList *results = NULL;
2752 guint32 w, h;
2753
2754 if (pixelformat == GST_MAKE_FOURCC('M', 'P', 'E', 'G'))
2755 {
2756 gst_caps_append_structure(ret, gst_structure_copy(template));
2757 return ret;
2758 }
2759
2760 memset(&size, 0, sizeof(struct v4l2_frmsizeenum));
2761 size.index = 0;
2762 size.pixel_format = pixelformat;
2763
2764 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2765 "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2766 GST_FOURCC_ARGS(pixelformat));
2767
2768 if (v4l2object->ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2769 goto enum_framesizes_failed;
2770
2771 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
2772 {
2773 do
2774 {
2775 GST_LOG_OBJECT(v4l2object->dbg_obj, "got discrete frame size %dx%d",
2776 size.discrete.width, size.discrete.height);
2777
2778 w = MIN(size.discrete.width, G_MAXINT);
2779 h = MIN(size.discrete.height, G_MAXINT);
2780
2781 if (w && h)
2782 {
2783 tmp =
2784 gst_aml_v4l2_object_probe_caps_for_format_and_size(v4l2object,
2785 pixelformat, w, h, template);
2786
2787 if (tmp)
2788 results = g_list_prepend(results, tmp);
2789 }
2790
2791 size.index++;
2792 } while (v4l2object->ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2793 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2794 "done iterating discrete frame sizes");
2795 }
2796 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
2797 {
2798 guint32 maxw, maxh, step_w, step_h;
2799
2800 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "we have stepwise frame sizes:");
2801 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min width: %d",
2802 size.stepwise.min_width);
2803 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min height: %d",
2804 size.stepwise.min_height);
2805 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "max width: %d",
2806 size.stepwise.max_width);
2807 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min height: %d",
2808 size.stepwise.max_height);
2809 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "step width: %d",
2810 size.stepwise.step_width);
2811 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "step height: %d",
2812 size.stepwise.step_height);
2813
2814 w = MAX(size.stepwise.min_width, 1);
2815 h = MAX(size.stepwise.min_height, 1);
2816 maxw = MIN(size.stepwise.max_width, G_MAXINT);
2817 maxh = MIN(size.stepwise.max_height, G_MAXINT);
2818
hanghang.luo9edfc7d2023-05-17 07:01:05 +00002819 /* in this position,updating resolution only to pass the negotiation
2820 * actually, the details about resolution refer to function:
2821 * gst_aml_v4l2_object_set_format_full for checking.
2822 */
2823 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "update maxw_maxh to MAX(maxw,maxh)_MAX(maxw,maxh)");
2824 maxh = MAX (maxw, maxh);
2825 maxw = maxh;
2826
xuesong.jiangae1548e2022-05-06 16:38:46 +08002827 step_w = MAX(size.stepwise.step_width, 1);
2828 step_h = MAX(size.stepwise.step_height, 1);
2829
2830 /* FIXME: check for sanity and that min/max are multiples of the steps */
2831
2832 /* we only query details for the max width/height since it's likely the
2833 * most restricted if there are any resolution-dependent restrictions */
2834 tmp = gst_aml_v4l2_object_probe_caps_for_format_and_size(v4l2object,
2835 pixelformat, maxw, maxh, template);
2836
2837 if (tmp)
2838 {
2839 GValue step_range = G_VALUE_INIT;
2840
2841 g_value_init(&step_range, GST_TYPE_INT_RANGE);
2842 gst_value_set_int_range_step(&step_range, w, maxw, step_w);
2843 gst_structure_set_value(tmp, "width", &step_range);
2844
2845 gst_value_set_int_range_step(&step_range, h, maxh, step_h);
2846 gst_structure_take_value(tmp, "height", &step_range);
2847
2848 /* no point using the results list here, since there's only one struct */
2849 gst_aml_v4l2_object_update_and_append(v4l2object, pixelformat, ret, tmp);
2850 }
2851 }
2852 else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
2853 {
2854 guint32 maxw, maxh;
2855
2856 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "we have continuous frame sizes:");
2857 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min width: %d",
2858 size.stepwise.min_width);
2859 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min height: %d",
2860 size.stepwise.min_height);
2861 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "max width: %d",
2862 size.stepwise.max_width);
2863 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "min height: %d",
2864 size.stepwise.max_height);
2865
2866 w = MAX(size.stepwise.min_width, 1);
2867 h = MAX(size.stepwise.min_height, 1);
2868 maxw = MIN(size.stepwise.max_width, G_MAXINT);
2869 maxh = MIN(size.stepwise.max_height, G_MAXINT);
2870
2871 tmp =
2872 gst_aml_v4l2_object_probe_caps_for_format_and_size(v4l2object, pixelformat,
2873 w, h, template);
2874 if (tmp)
2875 {
2876 gst_structure_set(tmp, "width", GST_TYPE_INT_RANGE, (gint)w,
2877 (gint)maxw, "height", GST_TYPE_INT_RANGE, (gint)h, (gint)maxh,
2878 NULL);
2879
2880 /* no point using the results list here, since there's only one struct */
2881 gst_aml_v4l2_object_update_and_append(v4l2object, pixelformat, ret, tmp);
2882 }
2883 }
2884 else
2885 {
2886 goto unknown_type;
2887 }
2888
2889 /* we use an intermediary list to store and then sort the results of the
2890 * probing because we can't make any assumptions about the order in which
2891 * the driver will give us the sizes, but we want the final caps to contain
2892 * the results starting with the highest resolution and having the lowest
2893 * resolution last, since order in caps matters for things like fixation. */
2894 results = g_list_sort(results, (GCompareFunc)sort_by_frame_size);
2895 while (results != NULL)
2896 {
2897 gst_aml_v4l2_object_update_and_append(v4l2object, pixelformat, ret,
2898 results->data);
2899 results = g_list_delete_link(results, results);
2900 }
2901
2902 if (gst_caps_is_empty(ret))
2903 goto enum_framesizes_no_results;
2904
2905 return ret;
2906
2907 /* ERRORS */
2908enum_framesizes_failed:
2909{
2910 /* I don't see how this is actually an error */
2911 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2912 "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
2913 " (%s)",
2914 GST_FOURCC_ARGS(pixelformat), g_strerror(errno));
2915 goto default_frame_sizes;
2916}
2917enum_framesizes_no_results:
2918{
2919 /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
2920 * question doesn't actually support it yet */
2921 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2922 "No results for pixelformat %" GST_FOURCC_FORMAT
2923 " enumerating frame sizes, trying fallback",
2924 GST_FOURCC_ARGS(pixelformat));
2925 goto default_frame_sizes;
2926}
2927unknown_type:
2928{
2929 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2930 "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
2931 ": %u",
2932 GST_FOURCC_ARGS(pixelformat), size.type);
2933 goto default_frame_sizes;
2934}
2935
2936default_frame_sizes:
2937{
2938 gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0;
2939
2940 /* This code is for Linux < 2.6.19 */
2941 min_w = min_h = 1;
2942 max_w = max_h = GST_AML_V4L2_MAX_SIZE;
2943 if (!gst_aml_v4l2_object_get_nearest_size(v4l2object, pixelformat, &min_w,
2944 &min_h))
2945 {
2946 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2947 "Could not probe minimum capture size for pixelformat %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(pixelformat));
2948 }
2949 if (!gst_aml_v4l2_object_get_nearest_size(v4l2object, pixelformat, &max_w,
2950 &max_h))
2951 {
2952 GST_WARNING_OBJECT(v4l2object->dbg_obj,
2953 "Could not probe maximum capture size for pixelformat %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(pixelformat));
2954 }
2955
2956 tmp = gst_structure_copy(template);
hanghang.luo3128f102022-08-18 10:36:19 +08002957#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08002958 if (fix_num)
2959 {
2960 gst_structure_set(tmp, "framerate", GST_TYPE_FRACTION, fix_num,
2961 fix_denom, NULL);
2962 }
hanghang.luo3128f102022-08-18 10:36:19 +08002963 else
2964#endif
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002965 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2966 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002967 {
2968 /* if norm can't be used, copy the template framerate */
2969 gst_structure_set(tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
2970 G_MAXINT, 1, NULL);
2971 }
2972
2973 if (min_w == max_w)
2974 gst_structure_set(tmp, "width", G_TYPE_INT, max_w, NULL);
2975 else
2976 gst_structure_set(tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
2977
2978 if (min_h == max_h)
2979 gst_structure_set(tmp, "height", G_TYPE_INT, max_h, NULL);
2980 else
2981 gst_structure_set(tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
2982
2983 gst_aml_v4l2_object_add_aspect_ratio(v4l2object, tmp);
2984
2985 if (!v4l2object->skip_try_fmt_probes)
2986 {
2987 /* We could consider setting interlace mode from min and max. */
2988 gst_aml_v4l2_object_add_interlace_mode(v4l2object, tmp, max_w, max_h,
2989 pixelformat);
2990 /* We could consider to check colorspace for min too, in case it depends on
2991 * the size. But in this case, min and max could not be enough */
2992 gst_aml_v4l2_object_add_colorspace(v4l2object, tmp, max_w, max_h,
2993 pixelformat);
2994 }
2995
2996 gst_aml_v4l2_object_update_and_append(v4l2object, pixelformat, ret, tmp);
2997 return ret;
2998}
2999}
3000
3001static gboolean
3002gst_aml_v4l2_object_get_nearest_size(GstAmlV4l2Object *v4l2object,
3003 guint32 pixelformat, gint *width, gint *height)
3004{
3005 struct v4l2_format fmt;
3006 gboolean ret = FALSE;
3007 GstVideoInterlaceMode interlace_mode;
3008
3009 g_return_val_if_fail(width != NULL, FALSE);
3010 g_return_val_if_fail(height != NULL, FALSE);
3011
3012 GST_LOG_OBJECT(v4l2object->dbg_obj,
3013 "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
3014 *width, *height, GST_FOURCC_ARGS(pixelformat));
3015
3016 memset(&fmt, 0, sizeof(struct v4l2_format));
3017
3018 /* get size delimiters */
3019 memset(&fmt, 0, sizeof(fmt));
3020 fmt.type = v4l2object->type;
3021 fmt.fmt.pix.width = *width;
3022 fmt.fmt.pix.height = *height;
3023 fmt.fmt.pix.pixelformat = pixelformat;
3024 fmt.fmt.pix.field = V4L2_FIELD_ANY;
3025
3026 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) < 0)
3027 goto error;
3028
3029 GST_LOG_OBJECT(v4l2object->dbg_obj,
3030 "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
3031
3032 *width = fmt.fmt.pix.width;
3033 *height = fmt.fmt.pix.height;
3034
3035 if (!gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode))
3036 {
3037 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3038 "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
3039 GST_FOURCC_ARGS(pixelformat), *width, *height, fmt.fmt.pix.field);
3040 goto error;
3041 }
3042
3043 ret = TRUE;
3044
3045error:
3046 if (!ret)
3047 {
3048 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3049 "Unable to try format: %s", g_strerror(errno));
3050 }
3051
3052 return ret;
3053}
3054
3055static gboolean
3056gst_aml_v4l2_object_is_dmabuf_supported(GstAmlV4l2Object *v4l2object)
3057{
3058 gboolean ret = TRUE;
3059 struct v4l2_exportbuffer expbuf = {
3060 .type = v4l2object->type,
3061 .index = -1,
3062 .plane = -1,
3063 .flags = O_CLOEXEC | O_RDWR,
3064 };
3065
3066 if (v4l2object->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
3067 {
3068 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3069 "libv4l2 converter detected, disabling DMABuf");
3070 ret = FALSE;
3071 }
3072
3073 /* Expected to fail, but ENOTTY tells us that it is not implemented. */
3074 v4l2object->ioctl(v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
3075 if (errno == ENOTTY)
3076 ret = FALSE;
3077
3078 return ret;
3079}
3080
3081static gboolean
3082gst_aml_v4l2_object_setup_pool(GstAmlV4l2Object *v4l2object, GstCaps *caps)
3083{
3084 GstAmlV4l2IOMode mode;
3085
3086 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "initializing the %s system",
3087 V4L2_TYPE_IS_OUTPUT(v4l2object->type) ? "output" : "capture");
3088
3089 GST_AML_V4L2_CHECK_OPEN(v4l2object);
3090 GST_AML_V4L2_CHECK_NOT_ACTIVE(v4l2object);
3091
3092 /* find transport */
3093 mode = v4l2object->req_mode;
3094
3095 if (v4l2object->device_caps & V4L2_CAP_READWRITE)
3096 {
3097 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3098 mode = GST_V4L2_IO_RW;
3099 }
3100 else if (v4l2object->req_mode == GST_V4L2_IO_RW)
3101 goto method_not_supported;
3102
3103 if (v4l2object->device_caps & V4L2_CAP_STREAMING)
3104 {
3105 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3106 {
3107 if (!V4L2_TYPE_IS_OUTPUT(v4l2object->type) &&
3108 gst_aml_v4l2_object_is_dmabuf_supported(v4l2object))
3109 {
3110 mode = GST_V4L2_IO_DMABUF;
3111 }
3112 else
3113 {
3114 mode = GST_V4L2_IO_MMAP;
3115 }
3116 }
3117 }
3118 else if (v4l2object->req_mode == GST_V4L2_IO_MMAP ||
3119 v4l2object->req_mode == GST_V4L2_IO_DMABUF)
3120 goto method_not_supported;
3121
3122 /* if still no transport selected, error out */
3123 if (mode == GST_V4L2_IO_AUTO)
3124 goto no_supported_capture_method;
3125
3126 GST_INFO_OBJECT(v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
3127 v4l2object->mode = mode;
3128
3129 /* If min_buffers is not set, the driver either does not support the control or
3130 it has not been asked yet via propose_allocation/decide_allocation. */
3131 if (!v4l2object->min_buffers)
3132 gst_aml_v4l2_get_driver_min_buffers(v4l2object);
3133
3134 /* Map the buffers */
3135 GST_LOG_OBJECT(v4l2object->dbg_obj, "initiating buffer pool");
3136
3137 if (!(v4l2object->pool = gst_aml_v4l2_buffer_pool_new(v4l2object, caps)))
3138 goto buffer_pool_new_failed;
3139
3140 GST_AML_V4L2_SET_ACTIVE(v4l2object);
3141
3142 return TRUE;
3143
3144 /* ERRORS */
3145buffer_pool_new_failed:
3146{
3147 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, READ,
3148 (_("Could not map buffers from device '%s'"),
3149 v4l2object->videodev),
3150 ("Failed to create buffer pool: %s", g_strerror(errno)));
3151 return FALSE;
3152}
3153method_not_supported:
3154{
3155 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, READ,
3156 (_("The driver of device '%s' does not support the IO method %d"),
3157 v4l2object->videodev, mode),
3158 (NULL));
3159 return FALSE;
3160}
3161no_supported_capture_method:
3162{
3163 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, READ,
3164 (_("The driver of device '%s' does not support any known IO "
3165 "method."),
3166 v4l2object->videodev),
3167 (NULL));
3168 return FALSE;
3169}
3170}
3171
3172static void
3173gst_aml_v4l2_object_set_stride(GstVideoInfo *info, GstVideoAlignment *align,
3174 gint plane, gint stride)
3175{
3176 const GstVideoFormatInfo *finfo = info->finfo;
3177
3178 if (GST_VIDEO_FORMAT_INFO_IS_TILED(finfo))
3179 {
3180 gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
3181
3182 ws = GST_VIDEO_FORMAT_INFO_TILE_WS(finfo);
3183 hs = GST_VIDEO_FORMAT_INFO_TILE_HS(finfo);
3184 tile_height = 1 << hs;
3185
3186 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(finfo, plane,
3187 info->height + align->padding_top + align->padding_bottom);
3188 padded_height = GST_ROUND_UP_N(padded_height, tile_height);
3189
3190 x_tiles = stride >> ws;
3191 y_tiles = padded_height >> hs;
3192 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE(x_tiles, y_tiles);
3193 }
3194 else
3195 {
3196 info->stride[plane] = stride;
3197 }
3198}
3199
3200static void
3201gst_aml_v4l2_object_extrapolate_info(GstAmlV4l2Object *v4l2object,
3202 GstVideoInfo *info, GstVideoAlignment *align, gint stride)
3203{
3204 const GstVideoFormatInfo *finfo = info->finfo;
3205 gint i, estride, padded_height;
3206 gsize offs = 0;
3207
3208 g_return_if_fail(v4l2object->n_v4l2_planes == 1);
3209
3210 padded_height = info->height + align->padding_top + align->padding_bottom;
3211
3212 for (i = 0; i < finfo->n_planes; i++)
3213 {
3214 estride = gst_aml_v4l2_object_extrapolate_stride(finfo, i, stride);
3215
3216 gst_aml_v4l2_object_set_stride(info, align, i, estride);
3217
3218 info->offset[i] = offs;
3219 offs += estride *
3220 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(finfo, i, padded_height);
3221
3222 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
3223 "Extrapolated for plane %d with base stride %d: "
3224 "stride %d, offset %" G_GSIZE_FORMAT,
3225 i, stride, info->stride[i],
3226 info->offset[i]);
3227 }
3228
3229 /* Update the image size according the amount of data we are going to
3230 * read/write. This workaround bugs in driver where the sizeimage provided
3231 * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
3232 * bytesused (buffer size). */
3233 if (offs < info->size)
3234 info->size = offs;
3235}
3236
3237static void
3238gst_aml_v4l2_object_save_format(GstAmlV4l2Object *v4l2object,
3239 struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
3240 GstVideoInfo *info, GstVideoAlignment *align)
3241{
3242 const GstVideoFormatInfo *finfo = info->finfo;
3243 gboolean standard_stride = TRUE;
3244 gint stride, pstride, padded_width, padded_height, i;
3245
3246 if (GST_VIDEO_INFO_FORMAT(info) == GST_VIDEO_FORMAT_ENCODED)
3247 {
3248 v4l2object->n_v4l2_planes = 1;
3249 info->size = format->fmt.pix.sizeimage;
3250 goto store_info;
3251 }
3252
3253 /* adjust right padding */
3254 if (V4L2_TYPE_IS_MULTIPLANAR(v4l2object->type))
3255 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3256 else
3257 stride = format->fmt.pix.bytesperline;
3258
3259 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE(finfo, 0);
3260 if (pstride)
3261 {
3262 padded_width = stride / pstride;
3263 }
3264 else
3265 {
3266 /* pstride can be 0 for complex formats */
3267 GST_WARNING_OBJECT(v4l2object->element,
3268 "format %s has a pstride of 0, cannot compute padded with",
3269 gst_video_format_to_string(GST_VIDEO_INFO_FORMAT(info)));
3270 padded_width = stride;
3271 }
3272
3273 if (padded_width < format->fmt.pix.width)
3274 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3275 "Driver bug detected, stride (%d) is too small for the width (%d)",
3276 padded_width, format->fmt.pix.width);
3277
3278 align->padding_right = padded_width - info->width - align->padding_left;
3279
3280 /* adjust bottom padding */
3281 padded_height = format->fmt.pix.height;
3282
3283 if (GST_VIDEO_FORMAT_INFO_IS_TILED(finfo))
3284 {
3285 guint hs, tile_height;
3286
3287 hs = GST_VIDEO_FORMAT_INFO_TILE_HS(finfo);
3288 tile_height = 1 << hs;
3289
3290 padded_height = GST_ROUND_UP_N(padded_height, tile_height);
3291 }
3292
3293 align->padding_bottom = padded_height - info->height - align->padding_top;
3294
3295 /* setup the strides and offset */
3296 if (V4L2_TYPE_IS_MULTIPLANAR(v4l2object->type))
3297 {
3298 struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
3299
3300 /* figure out the frame layout */
3301 v4l2object->n_v4l2_planes = MAX(1, pix_mp->num_planes);
3302 info->size = 0;
3303 for (i = 0; i < v4l2object->n_v4l2_planes; i++)
3304 {
3305 stride = pix_mp->plane_fmt[i].bytesperline;
3306
3307 if (info->stride[i] != stride)
3308 standard_stride = FALSE;
3309
3310 gst_aml_v4l2_object_set_stride(info, align, i, stride);
3311 info->offset[i] = info->size;
3312 info->size += pix_mp->plane_fmt[i].sizeimage;
3313 }
3314
3315 /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
3316 if (v4l2object->n_v4l2_planes < finfo->n_planes)
3317 {
3318 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3319 gst_aml_v4l2_object_extrapolate_info(v4l2object, info, align, stride);
3320 }
3321 }
3322 else
3323 {
3324 /* only one plane in non-MPLANE mode */
3325 v4l2object->n_v4l2_planes = 1;
3326 info->size = format->fmt.pix.sizeimage;
3327 stride = format->fmt.pix.bytesperline;
3328
3329 if (info->stride[0] != stride)
3330 standard_stride = FALSE;
3331
3332 gst_aml_v4l2_object_extrapolate_info(v4l2object, info, align, stride);
3333 }
3334
3335 /* adjust the offset to take into account left and top */
3336 if (GST_VIDEO_FORMAT_INFO_IS_TILED(finfo))
3337 {
3338 if ((align->padding_left + align->padding_top) > 0)
3339 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3340 "Left and top padding is not permitted for tiled formats");
3341 }
3342 else
3343 {
3344 for (i = 0; i < finfo->n_planes; i++)
3345 {
3346 gint vedge, hedge;
3347
3348 /* FIXME we assume plane as component as this is true for all supported
3349 * format we support. */
3350
3351 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(finfo, i, align->padding_left);
3352 vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(finfo, i, align->padding_top);
3353
3354 info->offset[i] += (vedge * info->stride[i]) +
3355 (hedge * GST_VIDEO_INFO_COMP_PSTRIDE(info, i));
3356 }
3357 }
3358
3359store_info:
3360 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
3361 info->size);
3362
3363 /* to avoid copies we need video meta if there is padding */
3364 v4l2object->need_video_meta =
3365 ((align->padding_top + align->padding_left + align->padding_right +
3366 align->padding_bottom) != 0);
3367
3368 /* ... or if stride is non "standard" */
3369 if (!standard_stride)
3370 v4l2object->need_video_meta = TRUE;
3371
3372 /* ... or also video meta if we use multiple, non-contiguous, planes */
3373 if (v4l2object->n_v4l2_planes > 1)
3374 v4l2object->need_video_meta = TRUE;
3375
3376 v4l2object->info = *info;
3377 v4l2object->align = *align;
3378 v4l2object->format = *format;
3379 v4l2object->fmtdesc = fmtdesc;
3380
3381 /* if we have a framerate pre-calculate duration */
3382 if (info->fps_n > 0 && info->fps_d > 0)
3383 {
3384 v4l2object->duration = gst_util_uint64_scale_int(GST_SECOND, info->fps_d,
3385 info->fps_n);
3386 }
3387 else
3388 {
3389 v4l2object->duration = GST_CLOCK_TIME_NONE;
3390 }
3391}
3392
3393gint gst_aml_v4l2_object_extrapolate_stride(const GstVideoFormatInfo *finfo,
3394 gint plane, gint stride)
3395{
3396 gint estride;
3397
3398 switch (finfo->format)
3399 {
3400 case GST_VIDEO_FORMAT_NV12:
3401 case GST_VIDEO_FORMAT_NV12_64Z32:
3402 case GST_VIDEO_FORMAT_NV21:
3403 case GST_VIDEO_FORMAT_NV16:
3404 case GST_VIDEO_FORMAT_NV61:
3405 case GST_VIDEO_FORMAT_NV24:
3406 estride = (plane == 0 ? 1 : 2) *
3407 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(finfo, plane, stride);
3408 break;
3409 default:
3410 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(finfo, plane, stride);
3411 break;
3412 }
3413
3414 return estride;
3415}
3416
3417static gboolean
3418gst_aml_v4l2_video_colorimetry_matches(const GstVideoColorimetry *cinfo,
3419 const gchar *color)
3420{
3421 GstVideoColorimetry ci;
3422 static const GstVideoColorimetry ci_likely_jpeg = {
3423 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3424 GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN};
3425 static const GstVideoColorimetry ci_jpeg = {
3426 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3427 GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709};
3428
3429 if (!gst_video_colorimetry_from_string(&ci, color))
3430 return FALSE;
3431
3432 if (gst_video_colorimetry_is_equal(&ci, cinfo))
3433 return TRUE;
3434
3435 /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */
3436 if (gst_video_colorimetry_is_equal(&ci, &ci_likely_jpeg) && gst_video_colorimetry_is_equal(cinfo, &ci_jpeg))
3437 return TRUE;
3438
3439 return FALSE;
3440}
3441
3442static void
fei.deng7c3d67f2022-11-09 11:06:05 +08003443set_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm, GstCaps *caps, guint32 pixFormat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003444{
3445 struct aml_dec_params *decParm = (struct aml_dec_params *)streamparm->parm.raw_data;
3446 const char *env;
zengliang.lic9f869d2023-02-15 08:32:32 +00003447 struct v4l2_ext_control control;
3448 struct v4l2_ext_controls ctrls;
3449 gboolean use_ext_config = FALSE;
3450 int major = 0,minor = 0;
3451 struct utsname info;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003452
xuesong.jiang22a9b112023-05-24 09:01:59 +00003453 decParm->cfg.data[0] = 0;
3454 decParm->cfg.data[1] = 0;
3455 decParm->cfg.data[2] = 0;
3456 decParm->cfg.data[3] = 0;
3457 decParm->cfg.data[4] = 0;
3458
xuesong.jiangae1548e2022-05-06 16:38:46 +08003459 decParm->cfg.metadata_config_flag = 1 << 13;
hanghang.luoc54208e2023-09-22 02:43:54 +00003460 decParm->cfg.low_latency_mode = v4l2object->low_latency_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003461 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3462 {
fei.dengccc89632022-07-15 19:10:17 +08003463 /*set bit12 value to 1,
3464 *v4l2 output 0 pts of second interlace field frame */
fei.denga6ae3282022-07-15 19:50:30 +08003465 //decParm->cfg.metadata_config_flag |= (1 << 12);
fei.deng7c3d67f2022-11-09 11:06:05 +08003466 decParm->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
3467 switch (pixFormat)
3468 {
3469 default:
3470 case V4L2_PIX_FMT_MPEG:
3471 case V4L2_PIX_FMT_H264:
3472 decParm->cfg.double_write_mode= VDEC_DW_NO_AFBC;
3473 break;
3474 case V4L2_PIX_FMT_HEVC:
3475 case V4L2_PIX_FMT_VP9:
3476 case V4L2_PIX_FMT_AV1:
zengliang.lib1725ae2023-03-08 03:20:21 +00003477 decParm->cfg.double_write_mode= VDEC_DW_AFBC_AUTO_1_4;
fei.deng7c3d67f2022-11-09 11:06:05 +08003478 break;
3479 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003480 env = getenv("V4L2_SET_AMLOGIC_DW_MODE");
3481 if (env)
3482 {
3483 int dwMode = atoi(env);
3484 switch (dwMode)
3485 {
3486 case 0:
3487 case 1:
3488 case 2:
3489 case 3:
3490 case 4:
3491 case 16:
zengliang.lib1725ae2023-03-08 03:20:21 +00003492 case 256:
3493 case 512:
xuesong.jiangae1548e2022-05-06 16:38:46 +08003494 decParm->cfg.double_write_mode = dwMode;
3495 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO;
3496 break;
3497 }
3498 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003499 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "cfg dw mode to %d", decParm->cfg.double_write_mode);
3500
3501 // decParm->cfg.double_write_mode = 0x03;
3502 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO;
3503
3504 decParm->cfg.ref_buf_margin = GST_AML_V4L2_DEFAULT_CAP_BUF_MARGIN;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003505
zengliang.lic9f869d2023-02-15 08:32:32 +00003506 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003507 {
zengliang.lic9f869d2023-02-15 08:32:32 +00003508 GST_DEBUG("get linux version failed");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003509 }
zengliang.lic9f869d2023-02-15 08:32:32 +00003510 GST_DEBUG("linux major version %d %d", major,minor);
3511
3512 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
3513
3514 if (use_ext_config)
3515 {
3516 memset(&ctrls, 0, sizeof(ctrls));
3517 memset(&control, 0, sizeof(control));
3518 control.id = AML_V4L2_DEC_PARMS_CONFIG;
3519 control.ptr = decParm;
3520 control.size = sizeof(struct aml_dec_params);
3521 ctrls.count = 1;
3522 ctrls.controls = &control;
3523 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls ) <0)
3524 {
3525 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
3526 }
3527 else
3528 {
3529 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set dwMode to %d, margin to %d", decParm->cfg.double_write_mode, decParm->cfg.ref_buf_margin);
3530 }
3531 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003532 else
3533 {
zengliang.lic9f869d2023-02-15 08:32:32 +00003534 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_PARM, streamparm) < 0)
3535 {
3536 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
3537 }
3538 else
3539 {
3540 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Set dwMode to %d, margin to %d", decParm->cfg.double_write_mode, decParm->cfg.ref_buf_margin);
3541 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003542 }
xuesong.jiange1a19662022-06-21 20:30:22 +08003543
3544 GstStructure *structure= gst_caps_get_structure(caps, 0);
3545 if (structure == NULL)
3546 {
3547 return;
3548 }
3549 if ( gst_structure_has_field(structure, "colorimetry") )
3550 {
3551 const char *colorimetry= gst_structure_get_string(structure,"colorimetry");
3552 GstVideoColorimetry vci = {0};
3553 if ( colorimetry && gst_video_colorimetry_from_string( &vci, colorimetry ))
3554 {
3555 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO;
3556 decParm->hdr.signal_type= (1<<29); /* present flag */
3557 /*set default value, this is to keep up with driver hdr info synchronization*/
3558 decParm->hdr.signal_type |= (5<<26) | (1<<24);
3559
3560 gint hdrColorimetry[4] = {0};
3561 hdrColorimetry[0]= (int)vci.range;
3562 hdrColorimetry[1]= (int)vci.matrix;
3563 hdrColorimetry[2]= (int)vci.transfer;
3564 hdrColorimetry[3]= (int)vci.primaries;
3565 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "colorimetry: [%d,%d,%d,%d]",
3566 hdrColorimetry[0],
3567 hdrColorimetry[1],
3568 hdrColorimetry[2],
3569 hdrColorimetry[3] );
3570 /* range */
3571 switch ( hdrColorimetry[0] )
3572 {
3573 case 1:
3574 case 2:
3575 decParm->hdr.signal_type |= ((hdrColorimetry[0] % 2)<<25);
3576 break;
3577 default:
3578 break;
3579 }
3580 /* matrix coefficient */
3581 switch ( hdrColorimetry[1] )
3582 {
3583 case 1: /* RGB */
3584 decParm->hdr.signal_type |= 0;
3585 break;
3586 case 2: /* FCC */
3587 decParm->hdr.signal_type |= 4;
3588 break;
3589 case 3: /* BT709 */
3590 decParm->hdr.signal_type |= 1;
3591 break;
3592 case 4: /* BT601 */
3593 decParm->hdr.signal_type |= 3;
3594 break;
3595 case 5: /* SMPTE240M */
3596 decParm->hdr.signal_type |= 7;
3597 break;
3598 case 6: /* BT2020 */
3599 decParm->hdr.signal_type |= 9;
3600 break;
3601 default: /* unknown */
3602 decParm->hdr.signal_type |= 2;
3603 break;
3604 }
3605 /* transfer function */
3606 switch ( hdrColorimetry[2] )
3607 {
3608 case 5: /* BT709 */
3609 decParm->hdr.signal_type |= (1<<8);
3610 break;
3611 case 6: /* SMPTE240M */
3612 decParm->hdr.signal_type |= (7<<8);
3613 break;
3614 case 9: /* LOG100 */
3615 decParm->hdr.signal_type |= (9<<8);
3616 break;
3617 case 10: /* LOG316 */
3618 decParm->hdr.signal_type |= (10<<8);
3619 break;
3620 case 12: /* BT2020_12 */
3621 decParm->hdr.signal_type |= (15<<8);
3622 break;
3623 case 11: /* BT2020_10 */
3624 decParm->hdr.signal_type |= (14<<8);
3625 break;
3626 case 13: /* SMPTE2084 */
3627 decParm->hdr.signal_type |= (16<<8);
3628 break;
3629 case 14: /* ARIB_STD_B67 */
3630 decParm->hdr.signal_type |= (18<<8);
3631 break;
3632 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
3633 case 16: /* BT601 */
3634 decParm->hdr.signal_type |= (3<<8);
3635 break;
3636 #endif
3637 case 1: /* GAMMA10 */
3638 case 2: /* GAMMA18 */
3639 case 3: /* GAMMA20 */
3640 case 4: /* GAMMA22 */
3641 case 7: /* SRGB */
3642 case 8: /* GAMMA28 */
3643 case 15: /* ADOBERGB */
3644 default:
3645 break;
3646 }
3647 /* primaries */
3648 switch ( hdrColorimetry[3] )
3649 {
3650 case 1: /* BT709 */
3651 decParm->hdr.signal_type |= ((1<<24)|(1<<16));
3652 break;
3653 case 2: /* BT470M */
3654 decParm->hdr.signal_type |= ((1<<24)|(4<<16));
3655 break;
3656 case 3: /* BT470BG */
3657 decParm->hdr.signal_type |= ((1<<24)|(5<<16));
3658 break;
3659 case 4: /* SMPTE170M */
3660 decParm->hdr.signal_type |= ((1<<24)|(6<<16));
3661 break;
3662 case 5: /* SMPTE240M */
3663 decParm->hdr.signal_type |= ((1<<24)|(7<<16));
3664 break;
3665 case 6: /* FILM */
3666 decParm->hdr.signal_type |= ((1<<24)|(8<<16));
3667 break;
3668 case 7: /* BT2020 */
3669 decParm->hdr.signal_type |= ((1<<24)|(9<<16));
3670 break;
3671 case 8: /* ADOBERGB */
3672 default:
3673 break;
3674 }
3675 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR signal_type %X", decParm->hdr.signal_type);
3676 }
3677
3678 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "got caps %" GST_PTR_FORMAT, caps);
3679 GstStructure *st = gst_caps_get_structure(caps, 0);
3680 GstCapsFeatures *features = gst_caps_get_features(caps, 0);
3681
3682 if (gst_structure_has_field(st, "colorimetry"))
3683 {
3684 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "have colorimetry");
3685 }
3686
3687 if (st && features)
3688 {
3689 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "trace in remove colorimetry");
3690 gst_structure_remove_field(st, "colorimetry");
3691 gst_caps_features_remove(features, "colorimetry");
3692 }
3693 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove colorimetry %" GST_PTR_FORMAT, caps);
3694 }
3695
3696 if ( gst_structure_has_field(structure, "mastering-display-metadata") )
3697 {
3698 const char *masteringDisplay= gst_structure_get_string(structure,"mastering-display-metadata");
3699 float hdrMasteringDisplay[10];
3700 if ( masteringDisplay && sscanf( masteringDisplay, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
3701 &hdrMasteringDisplay[0],
3702 &hdrMasteringDisplay[1],
3703 &hdrMasteringDisplay[2],
3704 &hdrMasteringDisplay[3],
3705 &hdrMasteringDisplay[4],
3706 &hdrMasteringDisplay[5],
3707 &hdrMasteringDisplay[6],
3708 &hdrMasteringDisplay[7],
3709 &hdrMasteringDisplay[8],
3710 &hdrMasteringDisplay[9] ) == 10 )
3711 {
3712 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "mastering display [%f,%f,%f,%f,%f,%f,%f,%f,%f,%f]",
3713 hdrMasteringDisplay[0],
3714 hdrMasteringDisplay[1],
3715 hdrMasteringDisplay[2],
3716 hdrMasteringDisplay[3],
3717 hdrMasteringDisplay[4],
3718 hdrMasteringDisplay[5],
3719 hdrMasteringDisplay[6],
3720 hdrMasteringDisplay[7],
3721 hdrMasteringDisplay[8],
3722 hdrMasteringDisplay[9] );
3723
3724 decParm->hdr.color_parms.present_flag= 1;
3725 decParm->hdr.color_parms.primaries[2][0]= (uint32_t)(hdrMasteringDisplay[0]*50000); /* R.x */
3726 decParm->hdr.color_parms.primaries[2][1]= (uint32_t)(hdrMasteringDisplay[1]*50000); /* R.y */
3727 decParm->hdr.color_parms.primaries[0][0]= (uint32_t)(hdrMasteringDisplay[2]*50000); /* G.x */
3728 decParm->hdr.color_parms.primaries[0][1]= (uint32_t)(hdrMasteringDisplay[3]*50000); /* G.y */
3729 decParm->hdr.color_parms.primaries[1][0]= (uint32_t)(hdrMasteringDisplay[4]*50000); /* B.x */
3730 decParm->hdr.color_parms.primaries[1][1]= (uint32_t)(hdrMasteringDisplay[5]*50000); /* B.y */
3731 decParm->hdr.color_parms.white_point[0]= (uint32_t)(hdrMasteringDisplay[6]*50000);
3732 decParm->hdr.color_parms.white_point[1]= (uint32_t)(hdrMasteringDisplay[7]*50000);
3733 decParm->hdr.color_parms.luminance[0]= (uint32_t)(hdrMasteringDisplay[8]);
3734 decParm->hdr.color_parms.luminance[1]= (uint32_t)(hdrMasteringDisplay[9]);
3735 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: primaries %X %X %X %X %X %X",
3736 decParm->hdr.color_parms.primaries[2][0],
3737 decParm->hdr.color_parms.primaries[2][1],
3738 decParm->hdr.color_parms.primaries[0][0],
3739 decParm->hdr.color_parms.primaries[0][1],
3740 decParm->hdr.color_parms.primaries[1][0],
3741 decParm->hdr.color_parms.primaries[1][1] );
3742 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: white point: %X %X",
3743 decParm->hdr.color_parms.white_point[0],
3744 decParm->hdr.color_parms.white_point[1] );
3745 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: luminance: %X %X",
3746 decParm->hdr.color_parms.luminance[0],
3747 decParm->hdr.color_parms.luminance[1] );
3748 }
3749
3750 GstStructure *st = gst_caps_get_structure(caps, 0);
3751 GstCapsFeatures * features = gst_caps_get_features(caps, 0);
3752 if (st && features)
3753 {
3754 gst_structure_remove_fields(st, "mastering-display-metadata", NULL);
3755 gst_caps_features_remove(features, "mastering-display-metadata");
3756 }
3757 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove mastering-display-metadata %" GST_PTR_FORMAT, caps);
3758 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003759 }
3760}
3761
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003762static gint gst_aml_v4l2_object_get_dw_mode(GstAmlV4l2Object *v4l2object)
3763{
3764 struct v4l2_streamparm streamparm;
3765 struct aml_dec_params *decParm = (struct aml_dec_params *)(&streamparm.parm.raw_data);
3766 memset(&streamparm, 0x00, sizeof(struct v4l2_streamparm));
3767
3768 streamparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
3769 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, &streamparm) >= 0)
3770 {
3771 GST_DEBUG_OBJECT(v4l2object, "get dw mode:%d in type V4L2_BUF_TYPE_VIDEO_OUTPUT", decParm->cfg.double_write_mode);
3772 return decParm->cfg.double_write_mode;
3773 }
3774
3775 streamparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
3776 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, &streamparm) >= 0)
3777 {
3778 GST_DEBUG_OBJECT(v4l2object, "get dw mode:%d in type V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE", decParm->cfg.double_write_mode);
3779 return decParm->cfg.double_write_mode;
3780 }
3781
3782 GST_ERROR_OBJECT(v4l2object, "can't get dw mode in type V4L2_BUF_TYPE_VIDEO_OUTPUT or V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ret -1");
3783 return -1;
3784}
3785
xuesong.jiangae1548e2022-05-06 16:38:46 +08003786static gboolean
3787gst_aml_v4l2_object_set_format_full(GstAmlV4l2Object *v4l2object, GstCaps *caps,
3788 gboolean try_only, GstAmlV4l2Error *error)
3789{
3790 gint fd = v4l2object->video_fd;
3791 struct v4l2_format format;
3792 struct v4l2_streamparm streamparm;
3793 enum v4l2_field field;
3794 guint32 pixelformat;
3795 struct v4l2_fmtdesc *fmtdesc;
3796 GstVideoInfo info;
3797 GstVideoAlignment align;
3798 gint width, height, fps_n, fps_d;
3799 gint n_v4l_planes;
3800 gint i = 0;
3801 gboolean is_mplane;
3802 enum v4l2_colorspace colorspace = 0;
3803 enum v4l2_quantization range = 0;
3804 enum v4l2_ycbcr_encoding matrix = 0;
3805 enum v4l2_xfer_func transfer = 0;
3806 GstStructure *s;
3807 gboolean disable_colorimetry = FALSE;
3808
3809 g_return_val_if_fail(!v4l2object->skip_try_fmt_probes ||
3810 gst_caps_is_writable(caps),
3811 FALSE);
3812
3813 GST_AML_V4L2_CHECK_OPEN(v4l2object);
3814 if (!try_only)
3815 GST_AML_V4L2_CHECK_NOT_ACTIVE(v4l2object);
3816
xuesong.jiangae1548e2022-05-06 16:38:46 +08003817 is_mplane = V4L2_TYPE_IS_MULTIPLANAR(v4l2object->type);
3818
3819 gst_video_info_init(&info);
3820 gst_video_alignment_reset(&align);
3821
3822 if (!gst_aml_v4l2_object_get_caps_info(v4l2object, caps, &fmtdesc, &info))
3823 goto invalid_caps;
3824
3825 pixelformat = fmtdesc->pixelformat;
3826 width = GST_VIDEO_INFO_WIDTH(&info);
3827 height = GST_VIDEO_INFO_HEIGHT(&info);
3828 fps_n = GST_VIDEO_INFO_FPS_N(&info);
3829 fps_d = GST_VIDEO_INFO_FPS_D(&info);
3830
hanghang.luo9edfc7d2023-05-17 07:01:05 +00003831 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size");
3832 struct v4l2_frmsizeenum size;
3833 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
3834 size.index = 0;
3835 size.pixel_format = pixelformat;
3836 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
3837 return FALSE;
3838 if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
3839 {
3840 guint32 maxw, maxh;
3841 maxw = MIN (size.stepwise.max_width, G_MAXINT);
3842 maxh = MIN (size.stepwise.max_height, G_MAXINT);
3843 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "image from caps w_h:%d_%d", width, height);
3844 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "v4l2 support max w_h:%d_%d", maxw, maxh);
3845 if (width*height > maxw*maxh)
3846 return FALSE;
3847 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size ok");
3848 }
3849
fei.deng7c3d67f2022-11-09 11:06:05 +08003850 //set amlogic params here,because we need pix format to set dw mode
3851 memset(&streamparm, 0x00, sizeof(struct v4l2_streamparm));
3852 streamparm.type = v4l2object->type;
3853 set_amlogic_vdec_parm(v4l2object, &streamparm, caps, pixelformat);
3854
xuesong.jiangae1548e2022-05-06 16:38:46 +08003855 /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
3856 * or if contiguous is prefered */
3857 n_v4l_planes = GST_VIDEO_INFO_N_PLANES(&info);
3858 if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
3859 n_v4l_planes = 1;
3860
3861 if (GST_VIDEO_INFO_IS_INTERLACED(&info))
3862 {
3863 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "interlaced video");
3864 /* ideally we would differentiate between types of interlaced video
3865 * but there is not sufficient information in the caps..
3866 */
3867 field = V4L2_FIELD_INTERLACED;
3868 }
3869 else
3870 {
3871 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "progressive video");
3872 field = V4L2_FIELD_NONE;
3873 }
3874
3875 /* We first pick the main colorspace from the primaries */
3876 switch (info.colorimetry.primaries)
3877 {
3878 case GST_VIDEO_COLOR_PRIMARIES_BT709:
3879 /* There is two colorspaces using these primaries, use the range to
3880 * differentiate */
3881 if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
3882 colorspace = V4L2_COLORSPACE_REC709;
3883 else
3884 colorspace = V4L2_COLORSPACE_SRGB;
3885 break;
3886 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
3887 colorspace = V4L2_COLORSPACE_BT2020;
3888 break;
3889 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
3890 colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
3891 break;
3892 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
3893 colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
3894 break;
3895 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
3896 colorspace = V4L2_COLORSPACE_SMPTE170M;
3897 break;
3898 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
3899 colorspace = V4L2_COLORSPACE_SMPTE240M;
3900 break;
3901
3902 case GST_VIDEO_COLOR_PRIMARIES_FILM:
3903 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
3904 /* We don't know, we will guess */
3905 break;
3906
3907 default:
3908 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3909 "Unknown colorimetry primaries %d", info.colorimetry.primaries);
3910 break;
3911 }
3912
3913 switch (info.colorimetry.range)
3914 {
3915 case GST_VIDEO_COLOR_RANGE_0_255:
3916 range = V4L2_QUANTIZATION_FULL_RANGE;
3917 break;
3918 case GST_VIDEO_COLOR_RANGE_16_235:
3919 range = V4L2_QUANTIZATION_LIM_RANGE;
3920 break;
3921 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
3922 /* We let the driver pick a default one */
3923 break;
3924 default:
3925 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3926 "Unknown colorimetry range %d", info.colorimetry.range);
3927 break;
3928 }
3929
3930 switch (info.colorimetry.matrix)
3931 {
3932 case GST_VIDEO_COLOR_MATRIX_RGB:
3933 /* Unspecified, leave to default */
3934 break;
3935 /* FCC is about the same as BT601 with less digit */
3936 case GST_VIDEO_COLOR_MATRIX_FCC:
3937 case GST_VIDEO_COLOR_MATRIX_BT601:
3938 matrix = V4L2_YCBCR_ENC_601;
3939 break;
3940 case GST_VIDEO_COLOR_MATRIX_BT709:
3941 matrix = V4L2_YCBCR_ENC_709;
3942 break;
3943 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
3944 matrix = V4L2_YCBCR_ENC_SMPTE240M;
3945 break;
3946 case GST_VIDEO_COLOR_MATRIX_BT2020:
3947 matrix = V4L2_YCBCR_ENC_BT2020;
3948 break;
3949 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
3950 /* We let the driver pick a default one */
3951 break;
3952 default:
3953 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3954 "Unknown colorimetry matrix %d", info.colorimetry.matrix);
3955 break;
3956 }
3957
3958 switch (info.colorimetry.transfer)
3959 {
3960 case GST_VIDEO_TRANSFER_GAMMA18:
3961 case GST_VIDEO_TRANSFER_GAMMA20:
3962 case GST_VIDEO_TRANSFER_GAMMA22:
3963 case GST_VIDEO_TRANSFER_GAMMA28:
3964 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3965 "GAMMA 18, 20, 22, 28 transfer functions not supported");
3966 /* fallthrough */
3967 case GST_VIDEO_TRANSFER_GAMMA10:
3968 transfer = V4L2_XFER_FUNC_NONE;
3969 break;
3970 case GST_VIDEO_TRANSFER_BT2020_12:
3971 case GST_VIDEO_TRANSFER_BT709:
3972 transfer = V4L2_XFER_FUNC_709;
3973 break;
3974 case GST_VIDEO_TRANSFER_SMPTE240M:
3975 transfer = V4L2_XFER_FUNC_SMPTE240M;
3976 break;
3977 case GST_VIDEO_TRANSFER_SRGB:
3978 transfer = V4L2_XFER_FUNC_SRGB;
3979 break;
3980 case GST_VIDEO_TRANSFER_LOG100:
3981 case GST_VIDEO_TRANSFER_LOG316:
3982 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3983 "LOG 100, 316 transfer functions not supported");
3984 /* FIXME No known sensible default, maybe AdobeRGB ? */
3985 break;
3986 case GST_VIDEO_TRANSFER_UNKNOWN:
3987 /* We let the driver pick a default one */
3988 break;
3989 default:
3990 GST_WARNING_OBJECT(v4l2object->dbg_obj,
3991 "Unknown colorimetry tranfer %d", info.colorimetry.transfer);
3992 break;
3993 }
3994
3995 if (colorspace == 0)
3996 {
3997 /* Try to guess colorspace according to pixelformat and size */
3998 if (GST_VIDEO_INFO_IS_YUV(&info))
3999 {
4000 if (range == V4L2_QUANTIZATION_FULL_RANGE && matrix == V4L2_YCBCR_ENC_601 && transfer == 0)
4001 {
4002 /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
4003 * function most likely is JPEG */
4004 colorspace = V4L2_COLORSPACE_JPEG;
4005 transfer = V4L2_XFER_FUNC_SRGB;
4006 }
4007 else
4008 {
4009 /* SD streams likely use SMPTE170M and HD streams REC709 */
4010 if (width <= 720 && height <= 576)
4011 colorspace = V4L2_COLORSPACE_SMPTE170M;
4012 else
4013 colorspace = V4L2_COLORSPACE_REC709;
4014 }
4015 }
4016 else if (GST_VIDEO_INFO_IS_RGB(&info))
4017 {
4018 colorspace = V4L2_COLORSPACE_SRGB;
4019 transfer = V4L2_XFER_FUNC_NONE;
4020 }
4021 }
4022
4023 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Desired format %dx%d, format "
4024 "%" GST_FOURCC_FORMAT " stride: %d",
4025 width, height,
4026 GST_FOURCC_ARGS(pixelformat), GST_VIDEO_INFO_PLANE_STRIDE(&info, 0));
4027
4028 memset(&format, 0x00, sizeof(struct v4l2_format));
4029 format.type = v4l2object->type;
4030
4031 if (is_mplane)
4032 {
4033 format.type = v4l2object->type;
4034 format.fmt.pix_mp.pixelformat = pixelformat;
4035 format.fmt.pix_mp.width = width;
4036 format.fmt.pix_mp.height = height;
4037 format.fmt.pix_mp.field = field;
4038 format.fmt.pix_mp.num_planes = n_v4l_planes;
4039
4040 /* try to ask our prefered stride but it's not a failure if not
4041 * accepted */
4042 for (i = 0; i < n_v4l_planes; i++)
4043 {
4044 gint stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, i);
4045
4046 if (GST_VIDEO_FORMAT_INFO_IS_TILED(info.finfo))
4047 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(info.finfo);
4048
4049 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
4050 }
4051
4052 if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_ENCODED)
4053 {
4054 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4055 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4056 else
4057 format.fmt.pix_mp.plane_fmt[0].sizeimage = ENCODED_BUFFER_SIZE;
4058 }
4059 }
4060 else
4061 {
4062 gint stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0);
4063
4064 format.type = v4l2object->type;
4065
4066 format.fmt.pix.width = width;
4067 format.fmt.pix.height = height;
4068 format.fmt.pix.pixelformat = pixelformat;
4069 format.fmt.pix.field = field;
4070
4071 if (GST_VIDEO_FORMAT_INFO_IS_TILED(info.finfo))
4072 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(info.finfo);
4073
4074 /* try to ask our prefered stride */
4075 format.fmt.pix.bytesperline = stride;
4076
4077 if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_ENCODED)
4078 {
4079 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4080 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4081 else
4082 format.fmt.pix_mp.plane_fmt[0].sizeimage = ENCODED_BUFFER_SIZE;
4083 }
4084 }
4085
4086 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Desired format is %dx%d, format "
4087 "%" GST_FOURCC_FORMAT ", nb planes %d",
4088 format.fmt.pix.width,
4089 format.fmt.pix_mp.height,
4090 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4091 is_mplane ? format.fmt.pix_mp.num_planes : 1);
4092
4093#ifndef GST_DISABLE_GST_DEBUG
4094 if (is_mplane)
4095 {
4096 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4097 GST_DEBUG_OBJECT(v4l2object->dbg_obj, " stride %d",
4098 format.fmt.pix_mp.plane_fmt[i].bytesperline);
4099 }
4100 else
4101 {
4102 GST_DEBUG_OBJECT(v4l2object->dbg_obj, " stride %d",
4103 format.fmt.pix.bytesperline);
4104 }
4105#endif
4106
4107 if (is_mplane)
4108 {
4109 format.fmt.pix_mp.colorspace = colorspace;
4110 format.fmt.pix_mp.quantization = range;
4111 format.fmt.pix_mp.ycbcr_enc = matrix;
4112 format.fmt.pix_mp.xfer_func = transfer;
4113 }
4114 else
4115 {
4116 format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
4117 format.fmt.pix.colorspace = colorspace;
4118 format.fmt.pix.quantization = range;
4119 format.fmt.pix.ycbcr_enc = matrix;
4120 format.fmt.pix.xfer_func = transfer;
4121 }
4122
4123 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
4124 colorspace, range, matrix, transfer);
4125
4126 if (try_only)
4127 {
4128 if (v4l2object->ioctl(fd, VIDIOC_TRY_FMT, &format) < 0)
4129 goto try_fmt_failed;
4130 }
4131 else
4132 {
4133 if (v4l2object->ioctl(fd, VIDIOC_S_FMT, &format) < 0)
4134 goto set_fmt_failed;
4135 }
4136
4137 if (is_mplane)
4138 {
4139 colorspace = format.fmt.pix_mp.colorspace;
4140 range = format.fmt.pix_mp.quantization;
4141 matrix = format.fmt.pix_mp.ycbcr_enc;
4142 transfer = format.fmt.pix_mp.xfer_func;
4143 }
4144 else
4145 {
4146 colorspace = format.fmt.pix.colorspace;
4147 range = format.fmt.pix.quantization;
4148 matrix = format.fmt.pix.ycbcr_enc;
4149 transfer = format.fmt.pix.xfer_func;
4150 }
4151
4152 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got format of %dx%d, format "
4153 "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d",
4154 format.fmt.pix.width, format.fmt.pix_mp.height,
4155 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4156 is_mplane ? format.fmt.pix_mp.num_planes : 1,
4157 colorspace, range, matrix, transfer);
4158
4159#ifndef GST_DISABLE_GST_DEBUG
4160 if (is_mplane)
4161 {
4162 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4163 GST_DEBUG_OBJECT(v4l2object->dbg_obj, " stride %d, sizeimage %d",
4164 format.fmt.pix_mp.plane_fmt[i].bytesperline,
4165 format.fmt.pix_mp.plane_fmt[i].sizeimage);
4166 }
4167 else
4168 {
4169 GST_DEBUG_OBJECT(v4l2object->dbg_obj, " stride %d, sizeimage %d",
4170 format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
4171 }
4172#endif
4173
4174 if (format.fmt.pix.pixelformat != pixelformat)
4175 goto invalid_pixelformat;
4176
4177 /* Only negotiate size with raw data.
4178 * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
4179 * in ASF mode for example, there is also not reason for a driver to
4180 * change the size. */
4181 if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED)
4182 {
4183 /* We can crop larger images */
4184 if (format.fmt.pix.width < width || format.fmt.pix.height < height)
4185 goto invalid_dimensions;
4186
4187 /* Note, this will be adjusted if upstream has non-centered cropping. */
4188 align.padding_top = 0;
4189 align.padding_bottom = format.fmt.pix.height - height;
4190 align.padding_left = 0;
4191 align.padding_right = format.fmt.pix.width - width;
4192 }
4193
4194 if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
4195 goto invalid_planes;
4196
4197 /* used to check colorimetry and interlace mode fields presence */
4198 s = gst_caps_get_structure(caps, 0);
4199
4200 if (!gst_aml_v4l2_object_get_interlace_mode(format.fmt.pix.field,
4201 &info.interlace_mode))
4202 goto invalid_field;
4203 if (gst_structure_has_field(s, "interlace-mode"))
4204 {
4205 if (format.fmt.pix.field != field)
4206 goto invalid_field;
4207 }
4208
4209 if (gst_aml_v4l2_object_get_colorspace(&format, &info.colorimetry))
4210 {
4211 if (gst_structure_has_field(s, "colorimetry"))
4212 {
xuesong.jiange1a19662022-06-21 20:30:22 +08004213 if (!gst_aml_v4l2_video_colorimetry_matches(&info.colorimetry, gst_structure_get_string(s, "colorimetry")))
4214 {
4215 // goto invalid_colorimetry;
4216 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004217 }
4218 }
4219 else
4220 {
4221 /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
4222 * the TRY_FMT */
4223 disable_colorimetry = TRUE;
4224 if (gst_structure_has_field(s, "colorimetry"))
4225 gst_structure_remove_field(s, "colorimetry");
4226 }
4227
4228 /* In case we have skipped the try_fmt probes, we'll need to set the
4229 * colorimetry and interlace-mode back into the caps. */
4230 if (v4l2object->skip_try_fmt_probes)
4231 {
4232 if (!disable_colorimetry && !gst_structure_has_field(s, "colorimetry"))
4233 {
4234 gchar *str = gst_video_colorimetry_to_string(&info.colorimetry);
4235 gst_structure_set(s, "colorimetry", G_TYPE_STRING, str, NULL);
4236 g_free(str);
4237 }
4238
4239 if (!gst_structure_has_field(s, "interlace-mode"))
4240 gst_structure_set(s, "interlace-mode", G_TYPE_STRING,
4241 gst_video_interlace_mode_to_string(info.interlace_mode), NULL);
4242 }
4243
4244 if (try_only) /* good enough for trying only */
4245 return TRUE;
4246
4247 if (GST_VIDEO_INFO_HAS_ALPHA(&info))
4248 {
4249 struct v4l2_control ctl = {
4250 0,
4251 };
4252 ctl.id = V4L2_CID_ALPHA_COMPONENT;
4253 ctl.value = 0xff;
4254
4255 if (v4l2object->ioctl(fd, VIDIOC_S_CTRL, &ctl) < 0)
4256 GST_WARNING_OBJECT(v4l2object->dbg_obj,
4257 "Failed to set alpha component value");
4258 }
4259
4260 /* Is there a reason we require the caller to always specify a framerate? */
4261 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
4262 fps_d);
4263
4264 if (v4l2object->ioctl(fd, VIDIOC_G_PARM, &streamparm) < 0)
4265 goto get_parm_failed;
4266
4267 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
4268 {
4269 GST_VIDEO_INFO_FPS_N(&info) =
4270 streamparm.parm.capture.timeperframe.denominator;
4271 GST_VIDEO_INFO_FPS_D(&info) =
4272 streamparm.parm.capture.timeperframe.numerator;
4273
4274 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got capture framerate: %u/%u",
4275 streamparm.parm.capture.timeperframe.denominator,
4276 streamparm.parm.capture.timeperframe.numerator);
4277
4278 /* We used to skip frame rate setup if the camera was already setup
4279 * with the requested frame rate. This breaks some cameras though,
4280 * causing them to not output data (several models of Thinkpad cameras
4281 * have this problem at least).
4282 * So, don't skip. */
4283 GST_LOG_OBJECT(v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
4284 fps_n, fps_d);
4285 /* We want to change the frame rate, so check whether we can. Some cheap USB
4286 * cameras don't have the capability */
4287 if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4288 {
4289 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
4290 "Not setting capture framerate (not supported)");
4291 goto done;
4292 }
4293
4294 /* Note: V4L2 wants the frame interval, we have the frame rate */
4295 streamparm.parm.capture.timeperframe.numerator = fps_d;
4296 streamparm.parm.capture.timeperframe.denominator = fps_n;
4297
zengliang.lic9f869d2023-02-15 08:32:32 +00004298 /* Amlogic sets parameters to the decoder and only supports delivery of private structures */
4299 //some cheap USB cam's won't accept any change */
4300 //if (v4l2object->ioctl(fd, VIDIOC_S_PARM, &streamparm) < 0)
4301 //goto set_parm_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004302
4303 if (streamparm.parm.capture.timeperframe.numerator > 0 &&
4304 streamparm.parm.capture.timeperframe.denominator > 0)
4305 {
4306 /* get new values */
4307 fps_d = streamparm.parm.capture.timeperframe.numerator;
4308 fps_n = streamparm.parm.capture.timeperframe.denominator;
4309
4310 GST_INFO_OBJECT(v4l2object->dbg_obj, "Set capture framerate to %u/%u",
4311 fps_n, fps_d);
4312 }
4313 else
4314 {
4315 /* fix v4l2 capture driver to provide framerate values */
4316 GST_WARNING_OBJECT(v4l2object->dbg_obj,
4317 "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
4318 }
4319
4320 GST_VIDEO_INFO_FPS_N(&info) = fps_n;
4321 GST_VIDEO_INFO_FPS_D(&info) = fps_d;
4322 }
4323 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4324 {
4325 GST_VIDEO_INFO_FPS_N(&info) =
4326 streamparm.parm.output.timeperframe.denominator;
4327 GST_VIDEO_INFO_FPS_D(&info) =
4328 streamparm.parm.output.timeperframe.numerator;
4329
4330 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got output framerate: %u/%u",
4331 streamparm.parm.output.timeperframe.denominator,
4332 streamparm.parm.output.timeperframe.numerator);
4333
4334 GST_LOG_OBJECT(v4l2object->dbg_obj, "Setting output framerate to %u/%u",
4335 fps_n, fps_d);
4336 if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4337 {
4338 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
4339 "Not setting output framerate (not supported)");
4340 goto done;
4341 }
4342
4343 /* Note: V4L2 wants the frame interval, we have the frame rate */
4344 streamparm.parm.output.timeperframe.numerator = fps_d;
4345 streamparm.parm.output.timeperframe.denominator = fps_n;
4346
zengliang.lic9f869d2023-02-15 08:32:32 +00004347 /*Amlogic sets parameters to the decoder and only supports delivery of private structures*/
4348 //if (v4l2object->ioctl(fd, VIDIOC_S_PARM, &streamparm) < 0)
4349 //goto set_parm_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004350
4351 if (streamparm.parm.output.timeperframe.numerator > 0 &&
4352 streamparm.parm.output.timeperframe.denominator > 0)
4353 {
4354 /* get new values */
4355 fps_d = streamparm.parm.output.timeperframe.numerator;
4356 fps_n = streamparm.parm.output.timeperframe.denominator;
4357
4358 GST_INFO_OBJECT(v4l2object->dbg_obj, "Set output framerate to %u/%u",
4359 fps_n, fps_d);
4360 }
4361 else
4362 {
4363 /* fix v4l2 output driver to provide framerate values */
4364 GST_WARNING_OBJECT(v4l2object->dbg_obj,
4365 "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
4366 }
4367
4368 GST_VIDEO_INFO_FPS_N(&info) = fps_n;
4369 GST_VIDEO_INFO_FPS_D(&info) = fps_d;
4370 }
4371
4372done:
4373 /* add boolean return, so we can fail on drivers bugs */
4374 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &format, &info, &align);
4375
4376 /* now configure the pool */
4377 if (!gst_aml_v4l2_object_setup_pool(v4l2object, caps))
4378 goto pool_failed;
4379
4380 return TRUE;
4381
4382 /* ERRORS */
4383invalid_caps:
4384{
4385 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
4386 caps);
4387
4388 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4389 (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps));
4390 return FALSE;
4391}
4392try_fmt_failed:
4393{
4394 if (errno == EINVAL)
4395 {
4396 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4397 (_("Device '%s' has no supported format"), v4l2object->videodev),
4398 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4399 GST_FOURCC_ARGS(pixelformat), width, height,
4400 g_strerror(errno)));
4401 }
4402 else
4403 {
4404 GST_AML_V4L2_ERROR(error, RESOURCE, FAILED,
4405 (_("Device '%s' failed during initialization"),
4406 v4l2object->videodev),
4407 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4408 GST_FOURCC_ARGS(pixelformat), width, height,
4409 g_strerror(errno)));
4410 }
4411 return FALSE;
4412}
4413set_fmt_failed:
4414{
4415 if (errno == EBUSY)
4416 {
4417 GST_AML_V4L2_ERROR(error, RESOURCE, BUSY,
4418 (_("Device '%s' is busy"), v4l2object->videodev),
4419 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4420 GST_FOURCC_ARGS(pixelformat), width, height,
4421 g_strerror(errno)));
4422 }
4423 else if (errno == EINVAL)
4424 {
4425 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4426 (_("Device '%s' has no supported format"), v4l2object->videodev),
4427 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4428 GST_FOURCC_ARGS(pixelformat), width, height,
4429 g_strerror(errno)));
4430 }
4431 else
4432 {
4433 GST_AML_V4L2_ERROR(error, RESOURCE, FAILED,
4434 (_("Device '%s' failed during initialization"),
4435 v4l2object->videodev),
4436 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4437 GST_FOURCC_ARGS(pixelformat), width, height,
4438 g_strerror(errno)));
4439 }
4440 return FALSE;
4441}
4442invalid_dimensions:
4443{
4444 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4445 (_("Device '%s' cannot capture at %dx%d"),
4446 v4l2object->videodev, width, height),
4447 ("Tried to capture at %dx%d, but device returned size %dx%d",
4448 width, height, format.fmt.pix.width, format.fmt.pix.height));
4449 return FALSE;
4450}
4451invalid_pixelformat:
4452{
4453 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4454 (_("Device '%s' cannot capture in the specified format"),
4455 v4l2object->videodev),
4456 ("Tried to capture in %" GST_FOURCC_FORMAT
4457 ", but device returned format"
4458 " %" GST_FOURCC_FORMAT,
4459 GST_FOURCC_ARGS(pixelformat),
4460 GST_FOURCC_ARGS(format.fmt.pix.pixelformat)));
4461 return FALSE;
4462}
4463invalid_planes:
4464{
4465 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4466 (_("Device '%s' does support non-contiguous planes"),
4467 v4l2object->videodev),
4468 ("Device wants %d planes", format.fmt.pix_mp.num_planes));
4469 return FALSE;
4470}
4471invalid_field:
4472{
4473 enum v4l2_field wanted_field;
4474
4475 if (is_mplane)
4476 wanted_field = format.fmt.pix_mp.field;
4477 else
4478 wanted_field = format.fmt.pix.field;
4479
4480 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4481 (_("Device '%s' does not support %s interlacing"),
4482 v4l2object->videodev,
4483 field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
4484 ("Device wants %s interlacing",
4485 wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
4486 return FALSE;
4487}
hanghang.luo3128f102022-08-18 10:36:19 +08004488#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08004489invalid_colorimetry:
4490{
4491 gchar *wanted_colorimetry;
4492
4493 wanted_colorimetry = gst_video_colorimetry_to_string(&info.colorimetry);
4494
4495 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4496 (_("Device '%s' does not support %s colorimetry"),
4497 v4l2object->videodev, gst_structure_get_string(s, "colorimetry")),
4498 ("Device wants %s colorimetry", wanted_colorimetry));
4499
4500 g_free(wanted_colorimetry);
4501 return FALSE;
4502}
hanghang.luo3128f102022-08-18 10:36:19 +08004503#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08004504get_parm_failed:
4505{
4506 /* it's possible that this call is not supported */
4507 if (errno != EINVAL && errno != ENOTTY)
4508 {
4509 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4510 (_("Could not get parameters on device '%s'"),
4511 v4l2object->videodev),
4512 GST_ERROR_SYSTEM);
4513 }
4514 goto done;
4515}
4516set_parm_failed:
4517{
4518 GST_AML_V4L2_ERROR(error, RESOURCE, SETTINGS,
4519 (_("Video device did not accept new frame rate setting.")),
4520 GST_ERROR_SYSTEM);
4521 goto done;
4522}
4523pool_failed:
4524{
4525 /* setup_pool already send the error */
4526 return FALSE;
4527}
4528}
4529
4530gboolean
4531gst_aml_v4l2_object_set_format(GstAmlV4l2Object *v4l2object, GstCaps *caps,
4532 GstAmlV4l2Error *error)
4533{
4534 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
4535 caps);
4536 return gst_aml_v4l2_object_set_format_full(v4l2object, caps, FALSE, error);
4537}
4538
4539gboolean
4540gst_aml_v4l2_object_try_format(GstAmlV4l2Object *v4l2object, GstCaps *caps,
4541 GstAmlV4l2Error *error)
4542{
4543 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
4544 caps);
4545 return gst_aml_v4l2_object_set_format_full(v4l2object, caps, TRUE, error);
4546}
4547
4548GstFlowReturn
4549gst_aml_v4l2_object_poll(GstAmlV4l2Object *v4l2object)
4550{
4551 gint ret;
4552
4553 if (!v4l2object->can_poll_device)
4554 goto done;
4555
4556 GST_LOG_OBJECT(v4l2object, "polling device");
4557
4558again:
4559 ret = gst_poll_wait(v4l2object->poll, GST_CLOCK_TIME_NONE);
4560 if (G_UNLIKELY(ret < 0))
4561 {
4562 switch (errno)
4563 {
4564 case EBUSY:
4565 goto stopped;
4566 case EAGAIN:
4567 case EINTR:
4568 goto again;
4569 case ENXIO:
4570 GST_WARNING_OBJECT(v4l2object,
4571 "v4l2 device doesn't support polling. Disabling"
4572 " using libv4l2 in this case may cause deadlocks");
4573 v4l2object->can_poll_device = FALSE;
4574 goto done;
4575 default:
4576 goto select_error;
4577 }
4578 }
4579
4580done:
4581 return GST_FLOW_OK;
4582
4583 /* ERRORS */
4584stopped:
4585{
4586 GST_DEBUG_OBJECT(v4l2object, "stop called");
4587 return GST_FLOW_FLUSHING;
4588}
4589select_error:
4590{
4591 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, READ, (NULL),
4592 ("poll error %d: %s (%d)", ret, g_strerror(errno), errno));
4593 return GST_FLOW_ERROR;
4594}
4595}
4596
4597GstFlowReturn
4598gst_aml_v4l2_object_dqevent(GstAmlV4l2Object *v4l2object)
4599{
4600 GstFlowReturn res;
4601 struct v4l2_event evt;
4602
4603 if ((res = gst_aml_v4l2_object_poll(v4l2object)) != GST_FLOW_OK)
4604 goto poll_failed;
4605
4606 memset(&evt, 0x00, sizeof(struct v4l2_event));
4607 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
4608 goto dqevent_failed;
4609
4610 switch (evt.type)
4611 {
4612 case V4L2_EVENT_SOURCE_CHANGE:
4613 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
4614 break;
4615 case V4L2_EVENT_EOS:
4616 return GST_AML_V4L2_FLOW_LAST_BUFFER;
4617 break;
4618 default:
4619 break;
4620 }
4621
4622 return GST_FLOW_OK;
4623
4624 /* ERRORS */
4625poll_failed:
4626{
4627 GST_DEBUG_OBJECT(v4l2object, "poll error %s", gst_flow_get_name(res));
4628 return res;
4629}
4630dqevent_failed:
4631{
4632 return GST_FLOW_ERROR;
4633}
4634}
4635
4636/**
4637 * gst_aml_v4l2_object_acquire_format:
4638 * @v4l2object the object
4639 * @info a GstVideoInfo to be filled
4640 *
4641 * Acquire the driver choosen format. This is useful in decoder or encoder elements where
4642 * the output format is choosen by the HW.
4643 *
4644 * Returns: %TRUE on success, %FALSE on failure.
4645 */
4646gboolean
4647gst_aml_v4l2_object_acquire_format(GstAmlV4l2Object *v4l2object, GstVideoInfo *info)
4648{
4649 struct v4l2_fmtdesc *fmtdesc;
4650 struct v4l2_format fmt;
4651 struct v4l2_crop crop;
4652 struct v4l2_selection sel;
4653 struct v4l2_rect *r = NULL;
4654 GstVideoFormat format;
4655 guint width, height;
4656 GstVideoAlignment align;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004657 gint dw_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004658
4659 gst_video_info_init(info);
4660 gst_video_alignment_reset(&align);
4661
4662 memset(&fmt, 0x00, sizeof(struct v4l2_format));
4663 fmt.type = v4l2object->type;
fei.denge9458472023-04-18 02:05:48 +00004664 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "fmt.type:%d", fmt.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004665 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
4666 goto get_fmt_failed;
4667
4668 fmtdesc = gst_aml_v4l2_object_get_format_from_fourcc(v4l2object,
4669 fmt.fmt.pix.pixelformat);
4670 if (fmtdesc == NULL)
4671 goto unsupported_format;
4672
4673 /* No need to care about mplane, the four first params are the same */
4674 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format(fmt.fmt.pix.pixelformat);
4675
4676 /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
4677 if (format == GST_VIDEO_FORMAT_UNKNOWN)
4678 goto unsupported_format;
4679
4680 if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
4681 goto invalid_dimensions;
4682
4683 width = fmt.fmt.pix.width;
4684 height = fmt.fmt.pix.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004685 /* Use the default compose rectangle */
4686 memset(&sel, 0, sizeof(struct v4l2_selection));
4687 sel.type = v4l2object->type;
4688 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
4689 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
4690 {
4691 r = &sel.r;
4692 }
4693 else
4694 {
4695 /* For ancient kernels, fall back to G_CROP */
4696 memset(&crop, 0, sizeof(struct v4l2_crop));
4697 crop.type = v4l2object->type;
4698 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
4699 r = &crop.c;
4700 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004701
4702 dw_mode = gst_aml_v4l2_object_get_dw_mode(v4l2object);
sheng.liu07337c82023-12-01 03:21:57 +00004703 if (r)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004704 {
4705 align.padding_left = r->left;
4706 align.padding_top = r->top;
4707 align.padding_right = width - r->width - r->left;
4708 align.padding_bottom = height - r->height - r->top;
4709 width = r->width;
4710 height = r->height;
sheng.liu07337c82023-12-01 03:21:57 +00004711 if (dw_mode >= 0 && dw_mode != 16)
4712 {
4713 width = (width/2) *2; /* align for dw*/
4714 height = (height/2) *2; /* align for dw*/
4715 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004716 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004717 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "final w:%d, h:%d", width, height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004718
4719 gst_video_info_set_format(info, format, width, height);
4720
4721 switch (fmt.fmt.pix.field)
4722 {
4723 case V4L2_FIELD_ANY:
4724 case V4L2_FIELD_NONE:
4725 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
4726 break;
4727 case V4L2_FIELD_INTERLACED:
4728 case V4L2_FIELD_INTERLACED_TB:
4729 case V4L2_FIELD_INTERLACED_BT:
4730 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
4731 break;
4732 default:
4733 goto unsupported_field;
4734 }
4735
4736 gst_aml_v4l2_object_get_colorspace(&fmt, &info->colorimetry);
4737
4738 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &fmt, info, &align);
4739
4740 /* Shall we setup the pool ? */
4741
4742 return TRUE;
4743
4744get_fmt_failed:
4745{
4746 GST_ELEMENT_WARNING(v4l2object->element, RESOURCE, SETTINGS,
4747 (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
4748 return FALSE;
4749}
4750invalid_dimensions:
4751{
4752 GST_ELEMENT_WARNING(v4l2object->element, RESOURCE, SETTINGS,
4753 (_("Video device returned invalid dimensions.")),
4754 ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
4755 fmt.fmt.pix.height));
4756 return FALSE;
4757}
4758unsupported_field:
4759{
4760 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, SETTINGS,
4761 (_("Video device uses an unsupported interlacing method.")),
4762 ("V4L2 field type %d not supported", fmt.fmt.pix.field));
4763 return FALSE;
4764}
4765unsupported_format:
4766{
4767 GST_ELEMENT_ERROR(v4l2object->element, RESOURCE, SETTINGS,
4768 (_("Video device uses an unsupported pixel format.")),
4769 ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
4770 GST_FOURCC_ARGS(fmt.fmt.pix.pixelformat)));
4771 return FALSE;
4772}
4773}
4774
4775gboolean
4776gst_aml_v4l2_object_set_crop(GstAmlV4l2Object *obj)
4777{
4778 struct v4l2_selection sel = {0};
4779 struct v4l2_crop crop = {0};
4780
4781 sel.type = obj->type;
4782 sel.target = V4L2_SEL_TGT_CROP;
4783 sel.flags = 0;
4784 sel.r.left = obj->align.padding_left;
4785 sel.r.top = obj->align.padding_top;
4786 sel.r.width = obj->info.width;
4787 sel.r.height = obj->info.height;
4788
4789 crop.type = obj->type;
4790 crop.c = sel.r;
4791
4792 if (obj->align.padding_left + obj->align.padding_top +
4793 obj->align.padding_right + obj->align.padding_bottom ==
4794 0)
4795 {
4796 GST_DEBUG_OBJECT(obj->dbg_obj, "no cropping needed");
4797 return TRUE;
4798 }
4799
4800 GST_DEBUG_OBJECT(obj->dbg_obj,
4801 "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
4802 crop.c.width, crop.c.height);
4803
4804 if (obj->ioctl(obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0)
4805 {
4806 if (errno != ENOTTY)
4807 {
4808 GST_WARNING_OBJECT(obj->dbg_obj,
4809 "Failed to set crop rectangle with VIDIOC_S_SELECTION: %s",
4810 g_strerror(errno));
4811 return FALSE;
4812 }
4813 else
4814 {
4815 if (obj->ioctl(obj->video_fd, VIDIOC_S_CROP, &crop) < 0)
4816 {
4817 GST_WARNING_OBJECT(obj->dbg_obj, "VIDIOC_S_CROP failed");
4818 return FALSE;
4819 }
4820
4821 if (obj->ioctl(obj->video_fd, VIDIOC_G_CROP, &crop) < 0)
4822 {
4823 GST_WARNING_OBJECT(obj->dbg_obj, "VIDIOC_G_CROP failed");
4824 return FALSE;
4825 }
4826
4827 sel.r = crop.c;
4828 }
4829 }
4830
4831 GST_DEBUG_OBJECT(obj->dbg_obj,
4832 "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
4833 crop.c.width, crop.c.height);
4834
4835 return TRUE;
4836}
4837
4838gboolean
4839gst_aml_v4l2_object_caps_equal(GstAmlV4l2Object *v4l2object, GstCaps *caps)
4840{
4841 GstStructure *config;
4842 GstCaps *oldcaps;
4843 gboolean ret;
4844
4845 if (!v4l2object->pool)
4846 return FALSE;
4847
4848 config = gst_buffer_pool_get_config(v4l2object->pool);
4849 gst_buffer_pool_config_get_params(config, &oldcaps, NULL, NULL, NULL);
4850
4851 ret = oldcaps && gst_caps_is_equal(caps, oldcaps);
4852
4853 gst_structure_free(config);
4854
4855 return ret;
4856}
4857
4858gboolean
4859gst_aml_v4l2_object_caps_is_subset(GstAmlV4l2Object *v4l2object, GstCaps *caps)
4860{
4861 GstStructure *config;
4862 GstCaps *oldcaps;
4863 gboolean ret;
4864
4865 if (!v4l2object->pool)
4866 return FALSE;
4867
4868 config = gst_buffer_pool_get_config(v4l2object->pool);
4869 gst_buffer_pool_config_get_params(config, &oldcaps, NULL, NULL, NULL);
4870
4871 ret = oldcaps && gst_caps_is_subset(oldcaps, caps);
4872
4873 gst_structure_free(config);
4874
4875 return ret;
4876}
4877
4878GstCaps *
4879gst_aml_v4l2_object_get_current_caps(GstAmlV4l2Object *v4l2object)
4880{
4881 GstStructure *config;
4882 GstCaps *oldcaps;
4883
4884 if (!v4l2object->pool)
4885 return NULL;
4886
4887 config = gst_buffer_pool_get_config(v4l2object->pool);
4888 gst_buffer_pool_config_get_params(config, &oldcaps, NULL, NULL, NULL);
4889
4890 if (oldcaps)
4891 gst_caps_ref(oldcaps);
4892
4893 gst_structure_free(config);
4894
4895 return oldcaps;
4896}
4897
4898gboolean
4899gst_aml_v4l2_object_unlock(GstAmlV4l2Object *v4l2object)
4900{
4901 gboolean ret = TRUE;
4902
4903 GST_LOG_OBJECT(v4l2object->dbg_obj, "start flushing");
4904
4905 gst_poll_set_flushing(v4l2object->poll, TRUE);
4906
4907 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
4908 gst_buffer_pool_set_flushing(v4l2object->pool, TRUE);
4909
4910 return ret;
4911}
4912
4913gboolean
4914gst_aml_v4l2_object_unlock_stop(GstAmlV4l2Object *v4l2object)
4915{
4916 gboolean ret = TRUE;
4917
4918 GST_LOG_OBJECT(v4l2object->dbg_obj, "stop flushing");
4919
4920 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
4921 gst_buffer_pool_set_flushing(v4l2object->pool, FALSE);
4922
4923 gst_poll_set_flushing(v4l2object->poll, FALSE);
4924
4925 return ret;
4926}
4927
4928gboolean
4929gst_aml_v4l2_object_stop(GstAmlV4l2Object *v4l2object)
4930{
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004931 GstAmlV4l2BufferPool *bpool = GST_AML_V4L2_BUFFER_POOL(v4l2object->pool);
4932
xuesong.jiangae1548e2022-05-06 16:38:46 +08004933 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "stopping");
4934
4935 if (!GST_AML_V4L2_IS_OPEN(v4l2object))
4936 goto done;
4937 if (!GST_AML_V4L2_IS_ACTIVE(v4l2object))
4938 goto done;
4939
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004940 if (bpool && bpool->other_pool) /* jxsdbg for resolution switch */
4941 {
4942 if (v4l2object->old_other_pool)
4943 {
4944 /* this case indicate 1st switch did not wait all old pool buf recycle and 2nd switch is coming.
4945 so save 1st old pool */
4946 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching occurs during last switching buf recycle flow");
4947 v4l2object->old_old_other_pool = v4l2object->old_other_pool;
4948 }
4949
4950 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching flow, ref old drmbufferpool");
4951 v4l2object->old_other_pool = bpool->other_pool;
4952 gst_object_ref(v4l2object->old_other_pool);
4953 }
4954
xuesong.jiangae1548e2022-05-06 16:38:46 +08004955 if (v4l2object->pool)
4956 {
4957 if (!gst_aml_v4l2_buffer_pool_orphan(&v4l2object->pool))
4958 {
4959 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "deactivating pool");
4960 gst_buffer_pool_set_active(v4l2object->pool, FALSE);
4961 gst_object_unref(v4l2object->pool);
4962 }
4963 v4l2object->pool = NULL;
4964 }
4965
4966 GST_AML_V4L2_SET_INACTIVE(v4l2object);
4967
4968done:
4969 return TRUE;
4970}
4971
4972GstCaps *
4973gst_aml_v4l2_object_probe_caps(GstAmlV4l2Object *v4l2object, GstCaps *filter)
4974{
4975 GstCaps *ret;
4976 GSList *walk;
4977 GSList *formats;
4978
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004979 GST_INFO_OBJECT(v4l2object->dbg_obj, "filter caps: %" GST_PTR_FORMAT, filter);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004980 formats = gst_aml_v4l2_object_get_format_list(v4l2object);
4981
4982 ret = gst_caps_new_empty();
4983
4984 if (v4l2object->keep_aspect && !v4l2object->par)
4985 {
4986 struct v4l2_cropcap cropcap;
4987
4988 memset(&cropcap, 0, sizeof(cropcap));
4989
4990 cropcap.type = v4l2object->type;
4991 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
4992 {
4993 if (errno != ENOTTY)
4994 GST_WARNING_OBJECT(v4l2object->dbg_obj,
4995 "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
4996 g_strerror(errno));
4997 }
4998 else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator)
4999 {
5000 v4l2object->par = g_new0(GValue, 1);
5001 g_value_init(v4l2object->par, GST_TYPE_FRACTION);
5002 gst_value_set_fraction(v4l2object->par, cropcap.pixelaspect.numerator,
5003 cropcap.pixelaspect.denominator);
5004 }
5005 }
5006
5007 for (walk = formats; walk; walk = walk->next)
5008 {
5009 struct v4l2_fmtdesc *format;
5010 GstStructure *template;
5011 GstCaps *tmp, *tmp2;
5012
5013 format = (struct v4l2_fmtdesc *)walk->data;
5014
5015 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct(format->pixelformat);
5016
5017 if (!template)
5018 {
5019 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
5020 "unknown format %" GST_FOURCC_FORMAT,
5021 GST_FOURCC_ARGS(format->pixelformat));
5022 continue;
5023 }
5024
5025 /* If we have a filter, check if we need to probe this format or not */
5026 if (filter)
5027 {
5028 GstCaps *format_caps = gst_caps_new_empty();
5029
5030 gst_caps_append_structure(format_caps, gst_structure_copy(template));
xuesong.jiange1a19662022-06-21 20:30:22 +08005031 GST_INFO_OBJECT(v4l2object->dbg_obj, "format_caps: %" GST_PTR_FORMAT, format_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005032
5033 if (!gst_caps_can_intersect(format_caps, filter))
5034 {
5035 gst_caps_unref(format_caps);
5036 gst_structure_free(template);
5037 continue;
5038 }
5039
5040 gst_caps_unref(format_caps);
5041 }
5042
5043 tmp = gst_aml_v4l2_object_probe_caps_for_format(v4l2object,
5044 format->pixelformat, template);
xuesong.jiange1a19662022-06-21 20:30:22 +08005045 GST_INFO_OBJECT(v4l2object->dbg_obj, "tmp caps: %" GST_PTR_FORMAT, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005046
5047 if (tmp)
5048 {
5049 tmp2 = gst_caps_copy(tmp);
5050 gst_caps_set_features_simple(tmp2, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
5051 gst_caps_append(ret, tmp);
5052 gst_caps_append(ret, tmp2);
5053 }
5054
5055 gst_structure_free(template);
5056 }
5057
5058 if (filter)
5059 {
5060 GstCaps *tmp;
5061
5062 tmp = ret;
5063 ret = gst_caps_intersect_full(filter, ret, GST_CAPS_INTERSECT_FIRST);
5064 gst_caps_unref(tmp);
5065 }
5066
xuesong.jiang22a9b112023-05-24 09:01:59 +00005067 if (v4l2object->stream_mode)
5068 {
5069 GST_INFO_OBJECT(v4l2object->dbg_obj, "ret caps: %" GST_PTR_FORMAT, ret);
5070 for (guint i = 0; i < gst_caps_get_size(ret); i++)
5071 {
5072 GstStructure *s = gst_caps_get_structure(ret, i);
5073 if (s)
5074 gst_structure_remove_field(s, "alignment");
5075
5076 GST_DEBUG("i:%d, s:%p", i, s);
5077 }
5078 GST_INFO_OBJECT(v4l2object->dbg_obj, "new ret caps: %" GST_PTR_FORMAT, ret);
5079 }
5080
xuesong.jiangae1548e2022-05-06 16:38:46 +08005081 GST_INFO_OBJECT(v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
5082
5083 return ret;
5084}
5085
5086GstCaps *
5087gst_aml_v4l2_object_get_caps(GstAmlV4l2Object *v4l2object, GstCaps *filter)
5088{
5089 GstCaps *ret;
5090
5091 if (v4l2object->probed_caps == NULL)
5092 v4l2object->probed_caps = gst_aml_v4l2_object_probe_caps(v4l2object, NULL);
5093
5094 if (filter)
5095 {
5096 ret = gst_caps_intersect_full(filter, v4l2object->probed_caps,
5097 GST_CAPS_INTERSECT_FIRST);
5098 }
5099 else
5100 {
5101 ret = gst_caps_ref(v4l2object->probed_caps);
5102 }
5103
5104 return ret;
5105}
5106
5107gboolean
5108gst_aml_v4l2_object_decide_allocation(GstAmlV4l2Object *obj, GstQuery *query)
5109{
5110 GstCaps *caps;
5111 GstBufferPool *pool = NULL, *other_pool = NULL;
5112 GstStructure *config;
5113 guint size, min, max, own_min = 0;
5114 gboolean update;
5115 gboolean has_video_meta;
5116 gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
5117 GstAllocator *allocator = NULL;
5118 GstAllocationParams params = {0};
5119
5120 GST_DEBUG_OBJECT(obj->dbg_obj, "decide allocation");
5121
5122 g_return_val_if_fail(obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
5123 obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
5124 FALSE);
5125
5126 gst_query_parse_allocation(query, &caps, NULL);
5127
5128 if (obj->pool == NULL)
5129 {
5130 if (!gst_aml_v4l2_object_setup_pool(obj, caps))
5131 goto pool_failed;
5132 }
5133
5134 if (gst_query_get_n_allocation_params(query) > 0)
5135 gst_query_parse_nth_allocation_param(query, 0, &allocator, &params);
5136
5137 if (gst_query_get_n_allocation_pools(query) > 0)
5138 {
5139 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
5140 update = TRUE;
5141 }
5142 else
5143 {
5144 pool = NULL;
5145 min = max = 0;
5146 size = 0;
5147 update = FALSE;
5148 }
5149
5150 GST_DEBUG_OBJECT(obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%" GST_PTR_FORMAT, size, min, max, pool);
5151
5152 has_video_meta =
5153 gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
5154
5155 can_share_own_pool = (has_video_meta || !obj->need_video_meta);
5156
5157 gst_aml_v4l2_get_driver_min_buffers(obj);
5158 /* We can't share our own pool, if it exceed V4L2 capacity */
5159 if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
5160 can_share_own_pool = FALSE;
5161
5162 /* select a pool */
5163 switch (obj->mode)
5164 {
5165 case GST_V4L2_IO_RW:
5166 if (pool)
5167 {
5168 /* in READ/WRITE mode, prefer a downstream pool because our own pool
5169 * doesn't help much, we have to write to it as well */
5170 GST_DEBUG_OBJECT(obj->dbg_obj,
5171 "read/write mode: using downstream pool");
5172 /* use the bigest size, when we use our own pool we can't really do any
5173 * other size than what the hardware gives us but for downstream pools
5174 * we can try */
5175 size = MAX(size, obj->info.size);
5176 }
5177 else if (can_share_own_pool)
5178 {
5179 /* no downstream pool, use our own then */
5180 GST_DEBUG_OBJECT(obj->dbg_obj,
5181 "read/write mode: no downstream pool, using our own");
5182 pool = gst_object_ref(obj->pool);
5183 size = obj->info.size;
5184 pushing_from_our_pool = TRUE;
5185 }
5186 break;
5187
5188 case GST_V4L2_IO_USERPTR:
5189 case GST_V4L2_IO_DMABUF_IMPORT:
5190 /* in importing mode, prefer our own pool, and pass the other pool to
5191 * our own, so it can serve itself */
5192 if (pool == NULL)
5193 goto no_downstream_pool;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005194 gst_aml_v4l2_buffer_pool_set_other_pool(GST_AML_V4L2_BUFFER_POOL(obj->pool), pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005195 other_pool = pool;
5196 gst_object_unref(pool);
5197 pool = gst_object_ref(obj->pool);
5198 size = obj->info.size;
5199 break;
5200
5201 case GST_V4L2_IO_MMAP:
5202 case GST_V4L2_IO_DMABUF:
5203 /* in streaming mode, prefer our own pool */
5204 /* Check if we can use it ... */
5205 if (can_share_own_pool)
5206 {
5207 if (pool)
5208 gst_object_unref(pool);
5209 pool = gst_object_ref(obj->pool);
5210 size = obj->info.size;
5211 GST_DEBUG_OBJECT(obj->dbg_obj,
5212 "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
5213 pushing_from_our_pool = TRUE;
5214 }
5215 else if (pool)
5216 {
5217 GST_DEBUG_OBJECT(obj->dbg_obj,
5218 "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
5219 pool);
5220 }
5221 else
5222 {
5223 GST_DEBUG_OBJECT(obj->dbg_obj,
5224 "streaming mode: no usable pool, copying to generic pool");
5225 size = MAX(size, obj->info.size);
5226 }
5227 break;
5228 case GST_V4L2_IO_AUTO:
5229 default:
5230 GST_WARNING_OBJECT(obj->dbg_obj, "unhandled mode");
5231 break;
5232 }
5233
5234 if (size == 0)
5235 goto no_size;
5236
5237 /* If pushing from our own pool, configure it with queried minimum,
5238 * otherwise use the minimum required */
5239 if (pushing_from_our_pool)
5240 {
5241 /* When pushing from our own pool, we need what downstream one, to be able
5242 * to fill the pipeline, the minimum required to decoder according to the
5243 * driver and 2 more, so we don't endup up with everything downstream or
5244 * held by the decoder. We account 2 buffers for v4l2 so when one is being
5245 * pushed downstream the other one can already be queued for the next
5246 * frame. */
5247 own_min = min + obj->min_buffers + 2;
5248
5249 /* If no allocation parameters where provided, allow for a little more
5250 * buffers and enable copy threshold */
5251 if (!update)
5252 {
5253 own_min += 2;
5254 gst_aml_v4l2_buffer_pool_copy_at_threshold(GST_AML_V4L2_BUFFER_POOL(pool),
5255 TRUE);
5256 }
5257 else
5258 {
5259 gst_aml_v4l2_buffer_pool_copy_at_threshold(GST_AML_V4L2_BUFFER_POOL(pool),
5260 FALSE);
5261 }
5262 }
5263 else
5264 {
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005265 min = obj->min_buffers;
5266 max = min;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005267 }
5268
5269 /* Request a bigger max, if one was suggested but it's too small */
5270 if (max != 0)
5271 max = MAX(min, max);
5272
5273 /* First step, configure our own pool */
5274 config = gst_buffer_pool_get_config(obj->pool);
5275
5276 if (obj->need_video_meta || has_video_meta)
5277 {
5278 GST_DEBUG_OBJECT(obj->dbg_obj, "activate Video Meta");
5279 gst_buffer_pool_config_add_option(config,
5280 GST_BUFFER_POOL_OPTION_VIDEO_META);
5281 }
5282
5283 gst_buffer_pool_config_set_allocator(config, allocator, &params);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005284 gst_buffer_pool_config_set_params(config, caps, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005285
5286 GST_DEBUG_OBJECT(obj->dbg_obj, "setting own pool config to %" GST_PTR_FORMAT, config);
5287
5288 /* Our pool often need to adjust the value */
5289 if (!gst_buffer_pool_set_config(obj->pool, config))
5290 {
5291 config = gst_buffer_pool_get_config(obj->pool);
5292
5293 GST_DEBUG_OBJECT(obj->dbg_obj, "own pool config changed to %" GST_PTR_FORMAT, config);
5294
5295 /* our pool will adjust the maximum buffer, which we are fine with */
5296 if (!gst_buffer_pool_set_config(obj->pool, config))
5297 goto config_failed;
5298 }
5299
5300 /* Now configure the other pool if different */
5301 if (obj->pool != pool)
5302 other_pool = pool;
5303
5304 if (other_pool)
5305 {
5306 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)obj->element;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005307 guint other_min = min;
5308 guint other_max = max;
5309
5310 if (obj->old_other_pool || obj->old_old_other_pool) //jxsdbg for switching
5311 {
5312 obj->outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
5313 other_min = min - obj->outstanding_buf_num;
5314 other_max = max - obj->outstanding_buf_num;
5315 GST_DEBUG_OBJECT(obj, "oop:%p, ooop:%p, outstanding buf num:%d, set min, max to %d,%d",
5316 obj->old_other_pool, obj->old_old_other_pool,
5317 obj->outstanding_buf_num, other_min, other_max);
5318 }
5319
xuesong.jiangae1548e2022-05-06 16:38:46 +08005320 if (self->is_secure_path)
5321 {
5322 params.flags |= GST_MEMORY_FLAG_LAST << 1; // in drmallocator GST_MEMORY_FLAG_LAST << 1 represent GST_MEMORY_FLAG_SECURE
5323 GST_DEBUG_OBJECT(obj, "set secure flag for drmbufferpool flag:0x%x", params.flags);
5324 }
5325 config = gst_buffer_pool_get_config(other_pool);
5326 gst_buffer_pool_config_set_allocator(config, allocator, &params);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005327 gst_buffer_pool_config_set_params (config, caps, size, other_min, other_max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005328 gst_buffer_pool_config_set_video_alignment(config, &obj->align);
5329
5330 GST_DEBUG_OBJECT(obj->dbg_obj, "setting other pool config to %" GST_PTR_FORMAT, config);
5331
5332 /* if downstream supports video metadata, add this to the pool config */
5333 if (has_video_meta)
5334 {
5335 GST_DEBUG_OBJECT(obj->dbg_obj, "activate Video Meta");
5336 gst_buffer_pool_config_add_option(config,
5337 GST_BUFFER_POOL_OPTION_VIDEO_META);
5338 }
5339
5340 if (!gst_buffer_pool_set_config(other_pool, config))
5341 {
5342 config = gst_buffer_pool_get_config(other_pool);
5343
5344 if (!gst_buffer_pool_config_validate_params(config, caps, size, min,
5345 max))
5346 {
5347 gst_structure_free(config);
5348 goto config_failed;
5349 }
5350
5351 if (!gst_buffer_pool_set_config(other_pool, config))
5352 goto config_failed;
5353 }
5354 }
5355
5356 if (pool)
5357 {
5358 /* For simplicity, simply read back the active configuration, so our base
5359 * class get the right information */
5360 config = gst_buffer_pool_get_config(pool);
5361 gst_buffer_pool_config_get_params(config, NULL, &size, &min, &max);
5362 gst_structure_free(config);
5363 }
5364
5365 if (update)
5366 gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
5367 else
5368 gst_query_add_allocation_pool(query, pool, size, min, max);
5369
5370 if (allocator)
5371 gst_object_unref(allocator);
5372
5373 if (pool)
5374 gst_object_unref(pool);
5375
5376 return TRUE;
5377
5378pool_failed:
5379{
5380 /* setup_pool already send the error */
5381 goto cleanup;
5382}
5383config_failed:
5384{
5385 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5386 (_("Failed to configure internal buffer pool.")), (NULL));
5387 goto cleanup;
5388}
5389no_size:
5390{
5391 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5392 (_("Video device did not suggest any buffer size.")), (NULL));
5393 goto cleanup;
5394}
5395cleanup:
5396{
5397 if (allocator)
5398 gst_object_unref(allocator);
5399
5400 if (pool)
5401 gst_object_unref(pool);
5402 return FALSE;
5403}
5404no_downstream_pool:
5405{
5406 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5407 (_("No downstream pool to import from.")),
5408 ("When importing DMABUF or USERPTR, we need a pool to import from"));
5409 return FALSE;
5410}
5411}
5412
5413gboolean
5414gst_aml_v4l2_object_propose_allocation(GstAmlV4l2Object *obj, GstQuery *query)
5415{
5416 GstBufferPool *pool;
5417 /* we need at least 2 buffers to operate */
5418 guint size, min, max;
5419 GstCaps *caps;
5420 gboolean need_pool;
5421
5422 /* Set defaults allocation parameters */
5423 size = obj->info.size;
5424 min = GST_AML_V4L2_MIN_BUFFERS;
5425 max = VIDEO_MAX_FRAME;
5426
5427 gst_query_parse_allocation(query, &caps, &need_pool);
5428
5429 if (caps == NULL)
5430 goto no_caps;
5431
5432 switch (obj->mode)
5433 {
5434 case GST_V4L2_IO_MMAP:
5435 case GST_V4L2_IO_DMABUF:
5436 if ((pool = obj->pool))
5437 gst_object_ref(pool);
5438 break;
5439 default:
5440 pool = NULL;
5441 break;
5442 }
5443
5444 if (pool != NULL)
5445 {
5446 GstCaps *pcaps;
5447 GstStructure *config;
5448
5449 /* we had a pool, check caps */
5450 config = gst_buffer_pool_get_config(pool);
5451 gst_buffer_pool_config_get_params(config, &pcaps, NULL, NULL, NULL);
5452
5453 GST_DEBUG_OBJECT(obj->dbg_obj,
5454 "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
5455 if (!gst_caps_is_equal(caps, pcaps))
5456 {
5457 gst_structure_free(config);
5458 gst_object_unref(pool);
5459 goto different_caps;
5460 }
5461 gst_structure_free(config);
5462 }
5463 gst_aml_v4l2_get_driver_min_buffers(obj);
5464
5465 min = MAX(obj->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
5466
5467 gst_query_add_allocation_pool(query, pool, size, min, max);
5468
5469 /* we also support various metadata */
5470 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
5471
5472 if (pool)
5473 gst_object_unref(pool);
5474
5475 return TRUE;
5476
5477 /* ERRORS */
5478no_caps:
5479{
5480 GST_DEBUG_OBJECT(obj->dbg_obj, "no caps specified");
5481 return FALSE;
5482}
5483different_caps:
5484{
5485 /* different caps, we can't use this pool */
5486 GST_DEBUG_OBJECT(obj->dbg_obj, "pool has different caps");
5487 return FALSE;
5488}
5489}
5490
5491gboolean
5492gst_aml_v4l2_object_try_import(GstAmlV4l2Object *obj, GstBuffer *buffer)
5493{
5494 GstVideoMeta *vmeta;
5495 guint n_mem = gst_buffer_n_memory(buffer);
5496
5497 /* only import if requested */
5498 switch (obj->mode)
5499 {
5500 case GST_V4L2_IO_USERPTR:
5501 case GST_V4L2_IO_DMABUF_IMPORT:
5502 break;
5503 default:
5504 GST_DEBUG_OBJECT(obj->dbg_obj,
5505 "The io-mode does not enable importation");
5506 return FALSE;
5507 }
5508
5509 vmeta = gst_buffer_get_video_meta(buffer);
5510 if (!vmeta && obj->need_video_meta)
5511 {
5512 GST_DEBUG_OBJECT(obj->dbg_obj, "Downstream buffer uses standard "
5513 "stride/offset while the driver does not.");
5514 return FALSE;
5515 }
5516
5517 /* we need matching strides/offsets and size */
5518 if (vmeta)
5519 {
5520 guint p;
5521 gboolean need_fmt_update = FALSE;
5522
5523 if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES(&obj->info))
5524 {
5525 GST_WARNING_OBJECT(obj->dbg_obj,
5526 "Cannot import buffers with different number planes");
5527 return FALSE;
5528 }
5529
5530 for (p = 0; p < vmeta->n_planes; p++)
5531 {
5532 if (vmeta->stride[p] < obj->info.stride[p])
5533 {
5534 GST_DEBUG_OBJECT(obj->dbg_obj,
5535 "Not importing as remote stride %i is smaller then %i on plane %u",
5536 vmeta->stride[p], obj->info.stride[p], p);
5537 return FALSE;
5538 }
5539 else if (vmeta->stride[p] > obj->info.stride[p])
5540 {
5541 need_fmt_update = TRUE;
5542 }
5543
5544 if (vmeta->offset[p] < obj->info.offset[p])
5545 {
5546 GST_DEBUG_OBJECT(obj->dbg_obj,
5547 "Not importing as offset %" G_GSIZE_FORMAT
5548 " is smaller then %" G_GSIZE_FORMAT " on plane %u",
5549 vmeta->offset[p], obj->info.offset[p], p);
5550 return FALSE;
5551 }
5552 else if (vmeta->offset[p] > obj->info.offset[p])
5553 {
5554 need_fmt_update = TRUE;
5555 }
5556 }
5557
5558 if (need_fmt_update)
5559 {
5560 struct v4l2_format format;
5561 gint wanted_stride[GST_VIDEO_MAX_PLANES] = {
5562 0,
5563 };
5564
5565 format = obj->format;
5566
5567 /* update the current format with the stride we want to import from */
5568 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5569 {
5570 guint i;
5571
5572 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted strides:");
5573
5574 for (i = 0; i < obj->n_v4l2_planes; i++)
5575 {
5576 gint stride = vmeta->stride[i];
5577
5578 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5579 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5580
5581 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
5582 wanted_stride[i] = stride;
5583 GST_DEBUG_OBJECT(obj->dbg_obj, " [%u] %i", i, wanted_stride[i]);
5584 }
5585 }
5586 else
5587 {
5588 gint stride = vmeta->stride[0];
5589
5590 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted stride: %i", stride);
5591
5592 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5593 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5594
5595 format.fmt.pix.bytesperline = stride;
5596 wanted_stride[0] = stride;
5597 }
5598
5599 if (obj->ioctl(obj->video_fd, VIDIOC_S_FMT, &format) < 0)
5600 {
5601 GST_WARNING_OBJECT(obj->dbg_obj,
5602 "Something went wrong trying to update current format: %s",
5603 g_strerror(errno));
5604 return FALSE;
5605 }
5606
5607 gst_aml_v4l2_object_save_format(obj, obj->fmtdesc, &format, &obj->info,
5608 &obj->align);
5609
5610 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5611 {
5612 guint i;
5613
5614 for (i = 0; i < obj->n_v4l2_planes; i++)
5615 {
5616 if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i])
5617 {
5618 GST_DEBUG_OBJECT(obj->dbg_obj,
5619 "[%i] Driver did not accept the new stride (wants %i, got %i)",
5620 i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
5621 wanted_stride[i]);
5622 return FALSE;
5623 }
5624 }
5625 }
5626 else
5627 {
5628 if (format.fmt.pix.bytesperline != wanted_stride[0])
5629 {
5630 GST_DEBUG_OBJECT(obj->dbg_obj,
5631 "Driver did not accept the new stride (wants %i, got %i)",
5632 format.fmt.pix.bytesperline, wanted_stride[0]);
5633 return FALSE;
5634 }
5635 }
5636 }
5637 }
5638
5639 /* we can always import single memory buffer, but otherwise we need the same
5640 * amount of memory object. */
5641 if (n_mem != 1 && n_mem != obj->n_v4l2_planes)
5642 {
5643 GST_DEBUG_OBJECT(obj->dbg_obj, "Can only import %i memory, "
5644 "buffers contains %u memory",
5645 obj->n_v4l2_planes, n_mem);
5646 return FALSE;
5647 }
5648
5649 /* For DMABuf importation we need DMABuf of course */
5650 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
5651 {
5652 guint i;
5653
5654 for (i = 0; i < n_mem; i++)
5655 {
5656 GstMemory *mem = gst_buffer_peek_memory(buffer, i);
5657
5658 if (!gst_is_dmabuf_memory(mem))
5659 {
5660 GST_DEBUG_OBJECT(obj->dbg_obj, "Cannot import non-DMABuf memory.");
5661 return FALSE;
5662 }
5663 }
5664 }
5665
5666 /* for the remaining, only the kernel driver can tell */
5667 return TRUE;
5668}
5669
xuesong.jiang22a9b112023-05-24 09:01:59 +00005670static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl)
5671{
5672 int rc;
5673 struct v4l2_queryctrl queryctrl;
5674 struct v4l2_control control;
5675
5676 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)v4l2object->element;
5677 self->is_secure_path = TRUE;
5678
5679 memset(&queryctrl, 0, sizeof(queryctrl));
5680 queryctrl.id = ctl;
5681
5682 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_QUERYCTRL, &queryctrl);
5683 if (rc == 0)
5684 {
5685 if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
5686 {
5687 memset(&control, 0, sizeof(control));
5688 control.id = ctl;
5689 control.value = 1;
5690 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
5691 if (rc != 0)
5692 {
5693 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x fail rc %d", ctl, rc);
5694 return FALSE;
5695 }
5696 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x succ", ctl);
5697 return TRUE;
5698 }
5699 else
5700 {
5701 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "ctl:0x%x is disabled", ctl);
5702 return TRUE;
5703 }
5704 }
5705 else
5706 {
5707 GST_ERROR_OBJECT(v4l2object->dbg_obj, "VIDIOC_QUERYCTRL for 0x:%x fail", ctl);
5708 return FALSE;
5709 }
5710}
5711
5712
xuesong.jiangae1548e2022-05-06 16:38:46 +08005713gboolean gst_aml_v4l2_set_drm_mode(GstAmlV4l2Object *v4l2object)
5714{
5715 /* On AmLogic, output obj use of GST_V4L2_IO_DMABUF_IMPORT implies secure memory */
5716 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
5717 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005718
xuesong.jiang22a9b112023-05-24 09:01:59 +00005719 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_DRMMODE))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005720 {
xuesong.jiang22a9b112023-05-24 09:01:59 +00005721 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set succ");
5722 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005723 }
5724 else
5725 {
xuesong.jiang22a9b112023-05-24 09:01:59 +00005726 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set fail");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005727 return FALSE;
5728 }
5729 }
5730 else
5731 {
xuesong.jiang22a9b112023-05-24 09:01:59 +00005732 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not GST_V4L2_IO_DMABUF_IMPORT, DRM mode does not need to be configured");
5733 return TRUE;
5734 }
5735}
5736
5737gboolean gst_aml_v4l2_set_stream_mode(GstAmlV4l2Object *v4l2object)
5738{
5739 if (v4l2object->stream_mode)
5740 {
5741 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_STREAM_MODE))
5742 {
5743 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set succ");
5744 return TRUE;
5745 }
5746 else
5747 {
5748 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set fail");
5749 return FALSE;
5750 }
5751 }
5752 else
5753 {
5754 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not stream mode, frame mode in configured by default");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005755 return TRUE;
5756 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005757}
5758
5759gint gst_aml_v4l2_object_get_outstanding_capture_buf_num(GstAmlV4l2Object *obj)
5760{
5761 gint ret = 0;
5762 gint count = 0;
5763
5764 if (obj->old_other_pool)
5765 {
5766 count = gst_buffer_pool_get_outstanding_num(obj->old_other_pool);
5767 if (count)
5768 {
5769 ret += count;
5770 }
5771 else
5772 {
5773 gst_object_unref(obj->old_other_pool);
5774 obj->old_other_pool = NULL;
5775 }
5776 }
5777
5778 count = 0;
5779 if (obj->old_old_other_pool)
5780 {
5781 count = gst_buffer_pool_get_outstanding_num(obj->old_old_other_pool);
5782 if (count)
5783 {
5784 ret += count;
5785 }
5786 else
5787 {
5788 gst_object_unref(obj->old_old_other_pool);
5789 obj->old_old_other_pool = NULL;
5790 }
5791 }
5792
5793 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005794}