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