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