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