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