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