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