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