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