blob: 7ae55bb33c50db80e141a8c0802699878c540dd2 [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
bo.xiao857b8682024-09-12 16:40:32 +080045GST_DEBUG_CATEGORY_EXTERN (aml_v4l2_debug);
xuesong.jiangae1548e2022-05-06 16:38:46 +080046#define GST_CAT_DEFAULT aml_v4l2_debug
47
bo.xiao857b8682024-09-12 16:40:32 +080048#define DEFAULT_PROP_DEVICE_NAME NULL
49#define DEFAULT_PROP_DEVICE_FD -1
50#define DEFAULT_PROP_FLAGS 0
51#define DEFAULT_PROP_TV_NORM 0
52#define DEFAULT_PROP_IO_MODE GST_V4L2_IO_AUTO
xuesong.jiangae1548e2022-05-06 16:38:46 +080053
le.handd21c802024-06-13 09:17:41 +000054#define ENCODED_BUFFER_SIZE (4 * 1024 * 1024)
hanghang.luo75664712024-07-01 19:28:10 +080055#define LOW_MEM_ENCODED_BUFFER_SIZE (1 * 1024 * 1024)
xuesong.jiangae1548e2022-05-06 16:38:46 +080056
xuesong.jiange1a19662022-06-21 20:30:22 +080057#define V4L2_CONFIG_PARM_DECODE_CFGINFO (1 << 0)
58#define V4L2_CONFIG_PARM_DECODE_PSINFO (1 << 1)
59#define V4L2_CONFIG_PARM_DECODE_HDRINFO (1 << 2)
60#define V4L2_CONFIG_PARM_DECODE_CNTINFO (1 << 3)
61
zengliang.lic9f869d2023-02-15 08:32:32 +000062#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
63#define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0)
hanghang.luo6a5bdff2024-04-15 06:29:43 +000064#define AML_V4L2_GET_FILMGRAIN_INFO (V4L2_CID_USER_AMLOGIC_BASE + 3)
zengliang.lic9f869d2023-02-15 08:32:32 +000065#define AML_V4L2_DEC_PARMS_CONFIG (V4L2_CID_USER_AMLOGIC_BASE + 7)
xuesong.jiang22a9b112023-05-24 09:01:59 +000066#define AML_V4L2_SET_STREAM_MODE (V4L2_CID_USER_AMLOGIC_BASE + 9)
hanghang.luo7f403102024-07-04 10:33:01 +080067#define AML_V4L2_SET_I_FRAME (V4L2_CID_USER_AMLOGIC_BASE + 14)
68
zengliang.lic9f869d2023-02-15 08:32:32 +000069
xuesong.jiangae1548e2022-05-06 16:38:46 +080070enum
71{
bo.xiao857b8682024-09-12 16:40:32 +080072 PROP_0,
73 V4L2_STD_OBJECT_PROPS,
xuesong.jiangae1548e2022-05-06 16:38:46 +080074};
75
76/*
77 * common format / caps utilities:
78 */
79typedef enum
80{
bo.xiao857b8682024-09-12 16:40:32 +080081 GST_V4L2_RAW = 1 << 0,
82 GST_V4L2_CODEC = 1 << 1,
83 GST_V4L2_TRANSPORT = 1 << 2,
84 GST_V4L2_NO_PARSE = 1 << 3,
85 GST_V4L2_ALL = 0xffff
xuesong.jiangae1548e2022-05-06 16:38:46 +080086} GstAmlV4L2FormatFlags;
87
88typedef struct
89{
bo.xiao857b8682024-09-12 16:40:32 +080090 guint32 format;
91 gboolean dimensions;
92 GstAmlV4L2FormatFlags flags;
xuesong.jiangae1548e2022-05-06 16:38:46 +080093} GstAmlV4L2FormatDesc;
94
95static const GstAmlV4L2FormatDesc gst_aml_v4l2_formats[] = {
bo.xiao857b8682024-09-12 16:40:32 +080096 /* RGB formats */
97 {V4L2_PIX_FMT_RGB332, TRUE, GST_V4L2_RAW},
98 {V4L2_PIX_FMT_ARGB555, TRUE, GST_V4L2_RAW},
99 {V4L2_PIX_FMT_XRGB555, TRUE, GST_V4L2_RAW},
100 {V4L2_PIX_FMT_ARGB555X, TRUE, GST_V4L2_RAW},
101 {V4L2_PIX_FMT_XRGB555X, TRUE, GST_V4L2_RAW},
102 {V4L2_PIX_FMT_RGB565, TRUE, GST_V4L2_RAW},
103 {V4L2_PIX_FMT_RGB565X, TRUE, GST_V4L2_RAW},
104 {V4L2_PIX_FMT_BGR666, TRUE, GST_V4L2_RAW},
105 {V4L2_PIX_FMT_BGR24, TRUE, GST_V4L2_RAW},
106 {V4L2_PIX_FMT_RGB24, TRUE, GST_V4L2_RAW},
107 {V4L2_PIX_FMT_ABGR32, TRUE, GST_V4L2_RAW},
108 {V4L2_PIX_FMT_XBGR32, TRUE, GST_V4L2_RAW},
109 {V4L2_PIX_FMT_ARGB32, TRUE, GST_V4L2_RAW},
110 {V4L2_PIX_FMT_XRGB32, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800111
bo.xiao857b8682024-09-12 16:40:32 +0800112 /* Deprecated Packed RGB Image Formats (alpha ambiguity) */
113 {V4L2_PIX_FMT_RGB444, TRUE, GST_V4L2_RAW},
114 {V4L2_PIX_FMT_RGB555, TRUE, GST_V4L2_RAW},
115 {V4L2_PIX_FMT_RGB555X, TRUE, GST_V4L2_RAW},
116 {V4L2_PIX_FMT_BGR32, TRUE, GST_V4L2_RAW},
117 {V4L2_PIX_FMT_RGB32, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800118
bo.xiao857b8682024-09-12 16:40:32 +0800119 /* Grey formats */
120 {V4L2_PIX_FMT_GREY, TRUE, GST_V4L2_RAW},
121 {V4L2_PIX_FMT_Y4, TRUE, GST_V4L2_RAW},
122 {V4L2_PIX_FMT_Y6, TRUE, GST_V4L2_RAW},
123 {V4L2_PIX_FMT_Y10, TRUE, GST_V4L2_RAW},
124 {V4L2_PIX_FMT_Y12, TRUE, GST_V4L2_RAW},
125 {V4L2_PIX_FMT_Y16, TRUE, GST_V4L2_RAW},
126 {V4L2_PIX_FMT_Y16_BE, TRUE, GST_V4L2_RAW},
127 {V4L2_PIX_FMT_Y10BPACK, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800128
bo.xiao857b8682024-09-12 16:40:32 +0800129 /* Palette formats */
130 {V4L2_PIX_FMT_PAL8, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800131
bo.xiao857b8682024-09-12 16:40:32 +0800132 /* Chrominance formats */
133 {V4L2_PIX_FMT_UV8, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800134
bo.xiao857b8682024-09-12 16:40:32 +0800135 /* Luminance+Chrominance formats */
136 {V4L2_PIX_FMT_YVU410, TRUE, GST_V4L2_RAW},
137 {V4L2_PIX_FMT_YVU420, TRUE, GST_V4L2_RAW},
138 {V4L2_PIX_FMT_YVU420M, TRUE, GST_V4L2_RAW},
139 {V4L2_PIX_FMT_YUYV, TRUE, GST_V4L2_RAW},
140 {V4L2_PIX_FMT_YYUV, TRUE, GST_V4L2_RAW},
141 {V4L2_PIX_FMT_YVYU, TRUE, GST_V4L2_RAW},
142 {V4L2_PIX_FMT_UYVY, TRUE, GST_V4L2_RAW},
143 {V4L2_PIX_FMT_VYUY, TRUE, GST_V4L2_RAW},
144 {V4L2_PIX_FMT_YUV422P, TRUE, GST_V4L2_RAW},
145 {V4L2_PIX_FMT_YUV411P, TRUE, GST_V4L2_RAW},
146 {V4L2_PIX_FMT_Y41P, TRUE, GST_V4L2_RAW},
147 {V4L2_PIX_FMT_YUV444, TRUE, GST_V4L2_RAW},
148 {V4L2_PIX_FMT_YUV555, TRUE, GST_V4L2_RAW},
149 {V4L2_PIX_FMT_YUV565, TRUE, GST_V4L2_RAW},
150 {V4L2_PIX_FMT_YUV32, TRUE, GST_V4L2_RAW},
151 {V4L2_PIX_FMT_YUV410, TRUE, GST_V4L2_RAW},
152 {V4L2_PIX_FMT_YUV420, TRUE, GST_V4L2_RAW},
153 {V4L2_PIX_FMT_YUV420M, TRUE, GST_V4L2_RAW},
154 {V4L2_PIX_FMT_HI240, TRUE, GST_V4L2_RAW},
155 {V4L2_PIX_FMT_HM12, TRUE, GST_V4L2_RAW},
156 {V4L2_PIX_FMT_M420, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800157
bo.xiao857b8682024-09-12 16:40:32 +0800158 /* two planes -- one Y, one Cr + Cb interleaved */
159 {V4L2_PIX_FMT_NV12, TRUE, GST_V4L2_RAW},
160 {V4L2_PIX_FMT_NV12M, TRUE, GST_V4L2_RAW},
161 {V4L2_PIX_FMT_NV12MT, TRUE, GST_V4L2_RAW},
162 {V4L2_PIX_FMT_NV12MT_16X16, TRUE, GST_V4L2_RAW},
163 {V4L2_PIX_FMT_NV21, TRUE, GST_V4L2_RAW},
164 {V4L2_PIX_FMT_NV21M, TRUE, GST_V4L2_RAW},
165 {V4L2_PIX_FMT_NV16, TRUE, GST_V4L2_RAW},
166 {V4L2_PIX_FMT_NV16M, TRUE, GST_V4L2_RAW},
167 {V4L2_PIX_FMT_NV61, TRUE, GST_V4L2_RAW},
168 {V4L2_PIX_FMT_NV61M, TRUE, GST_V4L2_RAW},
169 {V4L2_PIX_FMT_NV24, TRUE, GST_V4L2_RAW},
170 {V4L2_PIX_FMT_NV42, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800171
bo.xiao857b8682024-09-12 16:40:32 +0800172 /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
173 {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_RAW},
174 {V4L2_PIX_FMT_SGBRG8, TRUE, GST_V4L2_RAW},
175 {V4L2_PIX_FMT_SGRBG8, TRUE, GST_V4L2_RAW},
176 {V4L2_PIX_FMT_SRGGB8, TRUE, GST_V4L2_RAW},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800177
bo.xiao857b8682024-09-12 16:40:32 +0800178 /* compressed formats */
179 {V4L2_PIX_FMT_MJPEG, FALSE, GST_V4L2_CODEC},
180 {V4L2_PIX_FMT_DV, FALSE, GST_V4L2_TRANSPORT},
181 {V4L2_PIX_FMT_MPEG, FALSE, GST_V4L2_TRANSPORT},
182 {V4L2_PIX_FMT_FWHT, FALSE, GST_V4L2_CODEC},
183 {V4L2_PIX_FMT_H264, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
184 {V4L2_PIX_FMT_H264_NO_SC, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
185 {V4L2_PIX_FMT_H264_MVC, FALSE, GST_V4L2_CODEC},
186 {V4L2_PIX_FMT_HEVC, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
187 {V4L2_PIX_FMT_H263, FALSE, GST_V4L2_CODEC},
188 {V4L2_PIX_FMT_MPEG1, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
189 {V4L2_PIX_FMT_MPEG2, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
190 {V4L2_PIX_FMT_MPEG4, FALSE, GST_V4L2_CODEC},
191 {V4L2_PIX_FMT_XVID, FALSE, GST_V4L2_CODEC},
192 {V4L2_PIX_FMT_VC1_ANNEX_G, FALSE, GST_V4L2_CODEC},
193 {V4L2_PIX_FMT_VC1_ANNEX_L, FALSE, GST_V4L2_CODEC},
194 {V4L2_PIX_FMT_VP8, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
195 {V4L2_PIX_FMT_VP9, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
196 {V4L2_PIX_FMT_AV1, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
197 {V4L2_PIX_FMT_AVS, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
198 {V4L2_PIX_FMT_AVS2, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
199 {V4L2_PIX_FMT_AVS3, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800200
bo.xiao857b8682024-09-12 16:40:32 +0800201 /* Vendor-specific formats */
202 {V4L2_PIX_FMT_WNVA, TRUE, GST_V4L2_CODEC},
203 {V4L2_PIX_FMT_SN9C10X, TRUE, GST_V4L2_CODEC},
204 {V4L2_PIX_FMT_PWC1, TRUE, GST_V4L2_CODEC},
205 {V4L2_PIX_FMT_PWC2, TRUE, GST_V4L2_CODEC},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800206};
207
bo.xiao857b8682024-09-12 16:40:32 +0800208#define GST_AML_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_aml_v4l2_formats))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800209
bo.xiao857b8682024-09-12 16:40:32 +0800210static GSList *gst_aml_v4l2_object_get_format_list (GstAmlV4l2Object * v4l2object);
xuesong.jiang22a9b112023-05-24 09:01:59 +0000211static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl);
bo.xiao7659cda2024-07-18 16:16:50 +0800212static gboolean get_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm);
bo.xiao34e36202024-07-17 16:04:01 +0800213static int gst_aml_config_dw(GstAmlV4l2Object *v4l2object, guint32 pixFormat, guint width, guint height, gboolean interlace);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800214
bo.xiao857b8682024-09-12 16:40:32 +0800215#define GST_TYPE_AML_V4L2_DEVICE_FLAGS (gst_aml_v4l2_device_get_type ())
xuesong.jiangae1548e2022-05-06 16:38:46 +0800216static GType
bo.xiao857b8682024-09-12 16:40:32 +0800217gst_aml_v4l2_device_get_type (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800218{
bo.xiao857b8682024-09-12 16:40:32 +0800219 static GType v4l2_device_type = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800220
bo.xiao857b8682024-09-12 16:40:32 +0800221 if (v4l2_device_type == 0)
222 {
223 static const GFlagsValue values[] = {
224 {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"},
225 {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
226 {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800227
bo.xiao857b8682024-09-12 16:40:32 +0800228 {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
229 {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800230
bo.xiao857b8682024-09-12 16:40:32 +0800231 {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
232 {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800233
bo.xiao857b8682024-09-12 16:40:32 +0800234 {0, NULL, NULL}
235 };
xuesong.jiangae1548e2022-05-06 16:38:46 +0800236
bo.xiao857b8682024-09-12 16:40:32 +0800237 v4l2_device_type =
238 g_flags_register_static ("GstAmlV4l2DeviceTypeFlags", values);
239 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800240
bo.xiao857b8682024-09-12 16:40:32 +0800241 return v4l2_device_type;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800242}
243
bo.xiao857b8682024-09-12 16:40:32 +0800244GType
245gst_aml_v4l2_io_mode_get_type (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800246{
bo.xiao857b8682024-09-12 16:40:32 +0800247 static GType v4l2_io_mode = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800248
bo.xiao857b8682024-09-12 16:40:32 +0800249 if (!v4l2_io_mode)
250 {
251 static const GEnumValue io_modes[] = {
252 {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
253 {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
254 {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
255 {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
256 {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
257 {GST_V4L2_IO_DMABUF_IMPORT, "GST_V4L2_IO_DMABUF_IMPORT",
258 "dmabuf-import"},
xuesong.jiangae1548e2022-05-06 16:38:46 +0800259
bo.xiao857b8682024-09-12 16:40:32 +0800260 {0, NULL, NULL}
261 };
262 v4l2_io_mode = g_enum_register_static ("GstAmlV4l2IOMode", io_modes);
263 }
264 return v4l2_io_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800265}
266
bo.xiao857b8682024-09-12 16:40:32 +0800267void
268gst_aml_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
269 const char *default_device)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800270{
bo.xiao857b8682024-09-12 16:40:32 +0800271 g_object_class_install_property (gobject_class, PROP_DEVICE,
272 g_param_spec_string ("device", "Device", "Device location",
273 default_device, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
274 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
275 g_param_spec_string ("device-name", "Device name",
276 "Name of the device", DEFAULT_PROP_DEVICE_NAME,
277 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
278 g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
279 g_param_spec_int ("device-fd", "File descriptor",
280 "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
281 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
282 g_object_class_install_property (gobject_class, PROP_FLAGS,
283 g_param_spec_flags ("flags", "Flags", "Device type flags",
284 GST_TYPE_AML_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS,
285 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800286
bo.xiao857b8682024-09-12 16:40:32 +0800287 /**
288 * GstV4l2Src:brightness:
289 *
290 * Picture brightness, or more precisely, the black level
291 */
292 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
293 g_param_spec_int ("brightness", "Brightness",
294 "Picture brightness, or more precisely, the black level", G_MININT,
295 G_MAXINT, 0,
296 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
297 /**
298 * GstV4l2Src:contrast:
299 *
300 * Picture contrast or luma gain
301 */
302 g_object_class_install_property (gobject_class, PROP_CONTRAST,
303 g_param_spec_int ("contrast", "Contrast",
304 "Picture contrast or luma gain", G_MININT,
305 G_MAXINT, 0,
306 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
307 /**
308 * GstV4l2Src:saturation:
309 *
310 * Picture color saturation or chroma gain
311 */
312 g_object_class_install_property (gobject_class, PROP_SATURATION,
313 g_param_spec_int ("saturation", "Saturation",
314 "Picture color saturation or chroma gain", G_MININT,
315 G_MAXINT, 0,
316 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
317 /**
318 * GstV4l2Src:hue:
319 *
320 * Hue or color balance
321 */
322 g_object_class_install_property (gobject_class, PROP_HUE,
323 g_param_spec_int ("hue", "Hue",
324 "Hue or color balance", G_MININT,
325 G_MAXINT, 0,
326 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800327
bo.xiao857b8682024-09-12 16:40:32 +0800328 /**
329 * GstV4l2Src:io-mode:
330 *
331 * IO Mode
332 */
333 g_object_class_install_property (gobject_class, PROP_IO_MODE,
334 g_param_spec_enum ("io-mode", "IO mode",
335 "I/O mode",
336 GST_TYPE_AML_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
337 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800338
bo.xiao857b8682024-09-12 16:40:32 +0800339 /**
340 * GstV4l2Src:extra-controls:
341 *
342 * Additional v4l2 controls for the device. The controls are identified
343 * by the control name (lowercase with '_' for any non-alphanumeric
344 * characters).
345 *
346 * Since: 1.2
347 */
348 g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
349 g_param_spec_boxed ("extra-controls", "Extra Controls",
350 "Extra v4l2 controls (CIDs) for the device",
351 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800352
bo.xiao857b8682024-09-12 16:40:32 +0800353 /**
354 * GstV4l2Src:pixel-aspect-ratio:
355 *
356 * The pixel aspect ratio of the device. This overwrites the pixel aspect
357 * ratio queried from the device.
358 *
359 * Since: 1.2
360 */
361 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
362 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
363 "Overwrite the pixel aspect ratio of the device", "1/1",
364 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800365
bo.xiao857b8682024-09-12 16:40:32 +0800366 /**
367 * GstV4l2Src:force-aspect-ratio:
368 *
369 * When enabled, the pixel aspect ratio queried from the device or set
370 * with the pixel-aspect-ratio property will be enforced.
371 *
372 * Since: 1.2
373 */
374 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
375 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
376 "When enabled, the pixel aspect ratio will be enforced", TRUE,
377 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800378}
379
bo.xiao857b8682024-09-12 16:40:32 +0800380void
381gst_aml_v4l2_object_install_m2m_properties_helper (GObjectClass * gobject_class)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800382{
bo.xiao857b8682024-09-12 16:40:32 +0800383 g_object_class_install_property (gobject_class, PROP_DEVICE,
384 g_param_spec_string ("device", "Device", "Device location",
385 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800386
bo.xiao857b8682024-09-12 16:40:32 +0800387 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
388 g_param_spec_string ("device-name", "Device name",
389 "Name of the device", DEFAULT_PROP_DEVICE_NAME,
390 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800391
bo.xiao857b8682024-09-12 16:40:32 +0800392 g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
393 g_param_spec_int ("device-fd", "File descriptor",
394 "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
395 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800396
bo.xiao857b8682024-09-12 16:40:32 +0800397 g_object_class_install_property (gobject_class, PROP_OUTPUT_IO_MODE,
398 g_param_spec_enum ("output-io-mode", "Output IO mode",
399 "Output side I/O mode (matches sink 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_CAPTURE_IO_MODE,
404 g_param_spec_enum ("capture-io-mode", "Capture IO mode",
405 "Capture I/O mode (matches src pad)",
406 GST_TYPE_AML_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
407 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
408
409 g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
410 g_param_spec_boxed ("extra-controls", "Extra Controls",
411 "Extra v4l2 controls (CIDs) for the device",
412 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
413
414 g_object_class_install_property(gobject_class, PROP_DUMP_FRAME_LOCATION,
415 g_param_spec_string("dump-frame-location", "dump frame location",
416 "Location of the file to write decoder frames", NULL,
xuesong.jiangae1548e2022-05-06 16:38:46 +0800417 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
418
bo.xiao857b8682024-09-12 16:40:32 +0800419 g_object_class_install_property(gobject_class, PROP_STREAM_MODE,
420 g_param_spec_boolean("stream-mode", "Configure v4l2 stream mode",
421 "TRUE for stream mode, FALSE for frame mode",
422 FALSE,
423 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800424
bo.xiao857b8682024-09-12 16:40:32 +0800425 g_object_class_install_property(gobject_class, PROP_LOW_LATENCY_MODE,
426 g_param_spec_boolean("low-latency-mode", "set low latency mode",
427 "enable is TURE, disable is FALSE, default is disable",
428 FALSE,
429 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800430
bo.xiao857b8682024-09-12 16:40:32 +0800431 g_object_class_install_property (gobject_class, PROP_CC_DATA,
432 g_param_spec_boolean ("enable-cc-data",
433 "enable get cc data",
434 "0: disable; 1: enable", FALSE, G_PARAM_READWRITE));
xuesong.jiang22a9b112023-05-24 09:01:59 +0000435
bo.xiao857b8682024-09-12 16:40:32 +0800436 g_object_class_install_property (gobject_class, PROP_ENABLE_NR,
437 g_param_spec_boolean ("enable-nr",
438 "enable nr in di",
439 "0: disable; 1: enable", FALSE, G_PARAM_READWRITE));
zengliang.lidcd41462024-06-19 16:05:12 +0800440
bo.xiao857b8682024-09-12 16:40:32 +0800441 g_object_class_install_property(gobject_class, PROP_DECODING_ERROR_FRAMES,
442 g_param_spec_int("decoding-error-frames", "decoding error frames",
443 "get number of decoding error frames",
444 0, G_MAXINT32, 0, G_PARAM_READABLE));
445 g_object_class_install_property(gobject_class, PROP_LOW_MEMORY_MODE,
446 g_param_spec_boolean("low-memory", "low memory mode",
447 "Reduce memory usage if possible,default is disable",
448 FALSE,
449 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
450 g_object_class_install_property(gobject_class, PROP_I_FRAME_MODE,
451 g_param_spec_boolean("iframe-mode", "use I frame mode",
452 "use for speed play",
453 FALSE,
454 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
hanghang.luoe80a8882024-11-29 17:02:12 +0800455 g_object_class_install_property(gobject_class, PROP_PIP,
456 g_param_spec_boolean("pip", "set pip for cfg dw",
457 "use for dw cfg",
458 FALSE,
459 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
hanghang.luo7f403102024-07-04 10:33:01 +0800460
xuesong.jiangae1548e2022-05-06 16:38:46 +0800461}
462
463/* Support for 32bit off_t, this wrapper is casting off_t to gint64 */
464#ifdef HAVE_LIBV4L2
465#if SIZEOF_OFF_T < 8
466
467static gpointer
bo.xiao857b8682024-09-12 16:40:32 +0800468v4l2_mmap_wrapper (gpointer start, gsize length, gint prot, gint flags, gint fd,
469 off_t offset)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800470{
bo.xiao857b8682024-09-12 16:40:32 +0800471 return v4l2_mmap (start, length, prot, flags, fd, (gint64) offset);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800472}
473
474#define v4l2_mmap v4l2_mmap_wrapper
475
476#endif /* SIZEOF_OFF_T < 8 */
477#endif /* HAVE_LIBV4L2 */
478
479GstAmlV4l2Object *
bo.xiao857b8682024-09-12 16:40:32 +0800480gst_aml_v4l2_object_new (GstElement * element,
481 GstObject * debug_object,
482 enum v4l2_buf_type type,
483 const char *default_device,
484 GstAmlV4l2GetInOutFunction get_in_out_func,
485 GstAmlV4l2SetInOutFunction set_in_out_func,
486 GstAmlV4l2UpdateFpsFunction update_fps_func)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800487{
bo.xiao857b8682024-09-12 16:40:32 +0800488 GstAmlV4l2Object *v4l2object;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800489
bo.xiao857b8682024-09-12 16:40:32 +0800490 /*
491 * some default values
492 */
493 v4l2object = g_new0 (GstAmlV4l2Object, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800494
bo.xiao857b8682024-09-12 16:40:32 +0800495 if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == type || V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type))
496 {
497 const char *default_mode = getenv("GST_DEFAULT_V4L2_BUF_MODE");
498 GST_DEBUG("amlmodbuf GST_AML_DEFAULT_V4L2_BUF_MODE:%s", default_mode);
499 //v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
500 if (default_mode)
501 {
502 if (strcmp(default_mode, "DMA_BUF_IMPORT") == 0)
503 v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
504 else if (strcmp(default_mode, "DMA_BUF") == 0)
505 v4l2object->req_mode = GST_V4L2_IO_DMABUF;
506 GST_DEBUG("amlmodbuf set default buf default_mode:%d", v4l2object->req_mode);
507 }
508 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800509
bo.xiao857b8682024-09-12 16:40:32 +0800510 v4l2object->type = type;
511 v4l2object->formats = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800512
bo.xiao857b8682024-09-12 16:40:32 +0800513 v4l2object->element = element;
514 v4l2object->dbg_obj = debug_object;
515 v4l2object->get_in_out_func = get_in_out_func;
516 v4l2object->set_in_out_func = set_in_out_func;
517 v4l2object->update_fps_func = update_fps_func;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800518
bo.xiao857b8682024-09-12 16:40:32 +0800519 v4l2object->video_fd = -1;
520 v4l2object->active = FALSE;
521 v4l2object->videodev = g_strdup (default_device);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800522
bo.xiao857b8682024-09-12 16:40:32 +0800523 v4l2object->norms = NULL;
524 v4l2object->channels = NULL;
525 v4l2object->colors = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800526
hanghang.luo53c47332024-12-09 20:10:49 +0800527 v4l2object->keep_aspect = FALSE;
bo.xiao857b8682024-09-12 16:40:32 +0800528 v4l2object->stream_mode = FALSE;
529 v4l2object->secure_es = FALSE;
530 v4l2object->have_set_par = FALSE;
531 v4l2object->enable_cc_data = FALSE;
532 v4l2object->enable_nr = FALSE;
533 v4l2object->low_latency_mode = FALSE;
534 v4l2object->low_memory_mode = FALSE;
535 v4l2object->iframe_mode = FALSE;
hanghang.luoe80a8882024-11-29 17:02:12 +0800536 v4l2object->pip = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800537
bo.xiao857b8682024-09-12 16:40:32 +0800538 v4l2object->n_v4l2_planes = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800539
bo.xiao857b8682024-09-12 16:40:32 +0800540 v4l2object->no_initial_format = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800541
bo.xiao857b8682024-09-12 16:40:32 +0800542 /* We now disable libv4l2 by default, but have an env to enable it. */
xuesong.jiangae1548e2022-05-06 16:38:46 +0800543#ifdef HAVE_LIBV4L2
bo.xiao857b8682024-09-12 16:40:32 +0800544 if (g_getenv ("GST_V4L2_USE_LIBV4L2"))
545 {
546 v4l2object->fd_open = v4l2_fd_open;
547 v4l2object->close = v4l2_close;
548 v4l2object->dup = v4l2_dup;
549 v4l2object->ioctl = v4l2_ioctl;
550 v4l2object->read = v4l2_read;
551 v4l2object->mmap = v4l2_mmap;
552 v4l2object->munmap = v4l2_munmap;
553 }
554 else
xuesong.jiangae1548e2022-05-06 16:38:46 +0800555#endif
bo.xiao857b8682024-09-12 16:40:32 +0800556 {
557 v4l2object->fd_open = NULL;
558 v4l2object->close = close;
559 v4l2object->dup = dup;
560 v4l2object->ioctl = ioctl;
561 v4l2object->read = read;
562 v4l2object->mmap = mmap;
563 v4l2object->munmap = munmap;
564 }
565 v4l2object->poll = gst_poll_new (TRUE);
566 v4l2object->can_wait_event = FALSE;
567 v4l2object->can_poll_device = TRUE;
568 v4l2object->tvin_port = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800569
bo.xiao857b8682024-09-12 16:40:32 +0800570 v4l2object->dumpframefile = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800571
bo.xiao857b8682024-09-12 16:40:32 +0800572 /* jxsdbg resolution switching */
573 v4l2object->old_other_pool = NULL;
574 v4l2object->old_old_other_pool = NULL;
575 v4l2object->outstanding_buf_num = 0;
576 v4l2object->num_error_frames = 0;
577 v4l2object->error_frame_pts = 0;
le.han3b118242024-09-29 06:32:02 +0000578 v4l2object->stride = 0;
bo.xiao857b8682024-09-12 16:40:32 +0800579 return v4l2object;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800580}
581
bo.xiao857b8682024-09-12 16:40:32 +0800582static gboolean gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800583
bo.xiao857b8682024-09-12 16:40:32 +0800584void
585gst_aml_v4l2_object_destroy (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800586{
bo.xiao857b8682024-09-12 16:40:32 +0800587 g_return_if_fail (v4l2object != NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800588
bo.xiao857b8682024-09-12 16:40:32 +0800589 g_free (v4l2object->videodev);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800590
bo.xiao857b8682024-09-12 16:40:32 +0800591 g_free (v4l2object->channel);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800592
bo.xiao857b8682024-09-12 16:40:32 +0800593 if (v4l2object->formats)
594 {
595 gst_aml_v4l2_object_clear_format_list (v4l2object);
596 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800597
bo.xiao857b8682024-09-12 16:40:32 +0800598 if (v4l2object->probed_caps)
599 {
600 gst_caps_unref (v4l2object->probed_caps);
601 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800602
bo.xiao857b8682024-09-12 16:40:32 +0800603 if (v4l2object->extra_controls)
604 {
605 gst_structure_free (v4l2object->extra_controls);
606 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800607
bo.xiao857b8682024-09-12 16:40:32 +0800608 gst_poll_free (v4l2object->poll);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800609
bo.xiao857b8682024-09-12 16:40:32 +0800610 g_free(v4l2object->dumpframefile);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800611
bo.xiao857b8682024-09-12 16:40:32 +0800612 /* jxsdbg resolution switching */
613 if (v4l2object->old_other_pool)
614 {
615 gst_object_unref(v4l2object->old_other_pool);
616 v4l2object->old_other_pool = NULL;
617 }
618 if (v4l2object->old_old_other_pool)
619 {
620 gst_object_unref(v4l2object->old_old_other_pool);
621 v4l2object->old_old_other_pool = NULL;
622 }
623 v4l2object->outstanding_buf_num = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800624
bo.xiao857b8682024-09-12 16:40:32 +0800625 g_free (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800626}
627
628static gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800629gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800630{
bo.xiao857b8682024-09-12 16:40:32 +0800631 g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
632 g_slist_free (v4l2object->formats);
633 v4l2object->formats = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800634
bo.xiao857b8682024-09-12 16:40:32 +0800635 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800636}
637
638static gint
bo.xiao857b8682024-09-12 16:40:32 +0800639gst_aml_v4l2_object_prop_to_cid (guint prop_id)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800640{
bo.xiao857b8682024-09-12 16:40:32 +0800641 gint cid = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800642
bo.xiao857b8682024-09-12 16:40:32 +0800643 switch (prop_id)
644 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800645 case PROP_BRIGHTNESS:
bo.xiao857b8682024-09-12 16:40:32 +0800646 cid = V4L2_CID_BRIGHTNESS;
647 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800648 case PROP_CONTRAST:
bo.xiao857b8682024-09-12 16:40:32 +0800649 cid = V4L2_CID_CONTRAST;
650 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800651 case PROP_SATURATION:
bo.xiao857b8682024-09-12 16:40:32 +0800652 cid = V4L2_CID_SATURATION;
653 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800654 case PROP_HUE:
bo.xiao857b8682024-09-12 16:40:32 +0800655 cid = V4L2_CID_HUE;
656 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800657 default:
bo.xiao857b8682024-09-12 16:40:32 +0800658 GST_WARNING ("unmapped property id: %d", prop_id);
659 }
660 return cid;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800661}
662
663gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800664gst_aml_v4l2_object_set_property_helper (GstAmlV4l2Object * v4l2object,
665 guint prop_id, const GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800666{
bo.xiao857b8682024-09-12 16:40:32 +0800667 switch (prop_id)
668 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800669 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800670 g_free (v4l2object->videodev);
671 v4l2object->videodev = g_value_dup_string (value);
672 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800673 case PROP_BRIGHTNESS:
674 case PROP_CONTRAST:
675 case PROP_SATURATION:
676 case PROP_HUE:
677 {
bo.xiao857b8682024-09-12 16:40:32 +0800678 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800679
bo.xiao857b8682024-09-12 16:40:32 +0800680 if (cid != -1)
681 {
682 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800683 {
bo.xiao857b8682024-09-12 16:40:32 +0800684 gst_aml_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800685 }
bo.xiao857b8682024-09-12 16:40:32 +0800686 }
687 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800688 }
689 break;
690 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800691 v4l2object->req_mode = g_value_get_enum (value);
692 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800693 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800694 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
695 v4l2object->req_mode = g_value_get_enum (value);
696 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800697 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800698 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
699 v4l2object->req_mode = g_value_get_enum (value);
700 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800701 case PROP_EXTRA_CONTROLS:
702 {
bo.xiao857b8682024-09-12 16:40:32 +0800703 const GstStructure *s = gst_value_get_structure (value);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800704
bo.xiao857b8682024-09-12 16:40:32 +0800705 if (v4l2object->extra_controls)
706 gst_structure_free (v4l2object->extra_controls);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800707
bo.xiao857b8682024-09-12 16:40:32 +0800708 v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
709 if (GST_AML_V4L2_IS_OPEN (v4l2object))
710 gst_aml_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
711 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800712 }
713 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800714 if (v4l2object->par)
715 {
716 g_value_unset (v4l2object->par);
717 g_free (v4l2object->par);
718 }
719 v4l2object->par = g_new0 (GValue, 1);
720 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
721 if (!g_value_transform (value, v4l2object->par))
722 {
723 g_warning ("Could not transform string to aspect ratio");
724 gst_value_set_fraction (v4l2object->par, 1, 1);
725 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800726
sheng.liu641aa422023-12-26 07:05:59 +0000727 v4l2object->have_set_par = TRUE;
bo.xiao857b8682024-09-12 16:40:32 +0800728 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "set PAR to %d/%d",
729 gst_value_get_fraction_numerator (v4l2object->par),
730 gst_value_get_fraction_denominator (v4l2object->par));
731 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800732 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800733 v4l2object->keep_aspect = g_value_get_boolean (value);
734 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800735 case PROP_DUMP_FRAME_LOCATION:
736 g_free(v4l2object->dumpframefile);
737 v4l2object->dumpframefile = g_value_dup_string(value);
738 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000739 case PROP_STREAM_MODE:
740 v4l2object->stream_mode = g_value_get_boolean(value);
741 break;
hanghang.luoc54208e2023-09-22 02:43:54 +0000742 case PROP_LOW_LATENCY_MODE:
743 v4l2object->low_latency_mode = g_value_get_boolean(value);
744 GST_DEBUG_OBJECT(v4l2object, "set low latency: %d",v4l2object->low_latency_mode);
745 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800746 case PROP_CC_DATA:
747 v4l2object->enable_cc_data = g_value_get_boolean(value);
748 GST_DEBUG_OBJECT(v4l2object, "enable cc data: %d",v4l2object->enable_cc_data);
749 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800750 case PROP_ENABLE_NR:
751 v4l2object->enable_nr = g_value_get_boolean(value);
752 GST_DEBUG_OBJECT(v4l2object, "enable nr: %d",v4l2object->enable_nr);
753 break;
hanghang.luo75664712024-07-01 19:28:10 +0800754 case PROP_LOW_MEMORY_MODE:
755 v4l2object->low_memory_mode = g_value_get_boolean(value);
756 GST_DEBUG_OBJECT(v4l2object, "set low mem: %d",v4l2object->low_latency_mode);
757 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800758 case PROP_I_FRAME_MODE:
759 v4l2object->iframe_mode = g_value_get_boolean(value);
760 GST_DEBUG_OBJECT(v4l2object, "set I frame mode: %d",v4l2object->iframe_mode);
761 break;
hanghang.luoe80a8882024-11-29 17:02:12 +0800762 case PROP_PIP:
763 v4l2object->pip = g_value_get_boolean(value);
764 GST_DEBUG_OBJECT(v4l2object, "set pip: %d",v4l2object->pip);
765 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800766 default:
bo.xiao857b8682024-09-12 16:40:32 +0800767 return FALSE;
768 break;
769 }
770 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800771}
772
773gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800774gst_aml_v4l2_object_get_property_helper (GstAmlV4l2Object * v4l2object,
775 guint prop_id, GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800776{
bo.xiao857b8682024-09-12 16:40:32 +0800777 switch (prop_id)
778 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800779 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800780 g_value_set_string (value, v4l2object->videodev);
781 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800782 case PROP_DEVICE_NAME:
783 {
bo.xiao857b8682024-09-12 16:40:32 +0800784 const guchar *name = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800785
bo.xiao857b8682024-09-12 16:40:32 +0800786 if (GST_AML_V4L2_IS_OPEN (v4l2object))
787 name = v4l2object->vcap.card;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800788
bo.xiao857b8682024-09-12 16:40:32 +0800789 g_value_set_string (value, (gchar *) name);
790 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800791 }
792 case PROP_DEVICE_FD:
793 {
bo.xiao857b8682024-09-12 16:40:32 +0800794 if (GST_AML_V4L2_IS_OPEN (v4l2object))
795 g_value_set_int (value, v4l2object->video_fd);
796 else
797 g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
798 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800799 }
800 case PROP_FLAGS:
801 {
bo.xiao857b8682024-09-12 16:40:32 +0800802 guint flags = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800803
bo.xiao857b8682024-09-12 16:40:32 +0800804 if (GST_AML_V4L2_IS_OPEN (v4l2object))
805 {
806 flags |= v4l2object->device_caps &
807 (V4L2_CAP_VIDEO_CAPTURE |
808 V4L2_CAP_VIDEO_OUTPUT |
809 V4L2_CAP_VIDEO_OVERLAY |
810 V4L2_CAP_VBI_CAPTURE |
811 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800812
bo.xiao857b8682024-09-12 16:40:32 +0800813 if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
814 flags |= V4L2_CAP_VIDEO_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800815
bo.xiao857b8682024-09-12 16:40:32 +0800816 if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
817 flags |= V4L2_CAP_VIDEO_OUTPUT;
818 }
819 g_value_set_flags (value, flags);
820 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800821 }
822 case PROP_BRIGHTNESS:
823 case PROP_CONTRAST:
824 case PROP_SATURATION:
825 case PROP_HUE:
826 {
bo.xiao857b8682024-09-12 16:40:32 +0800827 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800828
bo.xiao857b8682024-09-12 16:40:32 +0800829 if (cid != -1)
830 {
831 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800832 {
bo.xiao857b8682024-09-12 16:40:32 +0800833 gint v;
834 if (gst_aml_v4l2_get_attribute (v4l2object, cid, &v))
835 {
836 g_value_set_int (value, v);
837 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800838 }
bo.xiao857b8682024-09-12 16:40:32 +0800839 }
840 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800841 }
bo.xiao857b8682024-09-12 16:40:32 +0800842 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800843 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800844 g_value_set_enum (value, v4l2object->req_mode);
845 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800846 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800847 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
848 g_value_set_enum (value, v4l2object->req_mode);
849 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800850 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800851 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
852 g_value_set_enum (value, v4l2object->req_mode);
853 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800854 case PROP_EXTRA_CONTROLS:
bo.xiao857b8682024-09-12 16:40:32 +0800855 gst_value_set_structure (value, v4l2object->extra_controls);
856 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800857 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800858 if (v4l2object->par)
859 g_value_transform (v4l2object->par, value);
860 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800861 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800862 g_value_set_boolean (value, v4l2object->keep_aspect);
863 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800864 case PROP_DUMP_FRAME_LOCATION:
865 g_value_set_string(value, v4l2object->dumpframefile);
866 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000867 case PROP_STREAM_MODE:
868 g_value_set_boolean(value, v4l2object->stream_mode);
869 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800870 case PROP_CC_DATA:
871 g_value_set_boolean(value, v4l2object->enable_cc_data);
872 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800873 case PROP_ENABLE_NR:
874 g_value_set_boolean(value, v4l2object->enable_nr);
875 break;
hanghang.luob3157512024-06-24 16:18:04 +0800876 case PROP_LOW_LATENCY_MODE:
877 g_value_set_boolean(value, v4l2object->low_latency_mode);
878 break;
fei.dengaf682762024-06-24 19:06:03 +0800879 case PROP_DECODING_ERROR_FRAMES:
880 g_value_set_int(value, v4l2object->num_error_frames);
881 break;
hanghang.luo75664712024-07-01 19:28:10 +0800882 case PROP_LOW_MEMORY_MODE:
883 g_value_set_boolean(value, v4l2object->low_memory_mode);
884 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800885 case PROP_I_FRAME_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800886 g_value_set_boolean(value, v4l2object->iframe_mode);
887 break;
hanghang.luoe80a8882024-11-29 17:02:12 +0800888 case PROP_PIP:
889 g_value_set_boolean(value, v4l2object->pip);
890 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800891 default:
bo.xiao857b8682024-09-12 16:40:32 +0800892 return FALSE;
893 break;
894 }
895 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800896}
897
898static void
bo.xiao857b8682024-09-12 16:40:32 +0800899gst_aml_v4l2_get_driver_min_buffers (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800900{
bo.xiao857b8682024-09-12 16:40:32 +0800901 struct v4l2_control control = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +0800902
bo.xiao857b8682024-09-12 16:40:32 +0800903 g_return_if_fail (GST_AML_V4L2_IS_OPEN (v4l2object));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800904
bo.xiao857b8682024-09-12 16:40:32 +0800905 if (V4L2_TYPE_IS_OUTPUT (v4l2object->type))
906 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
907 else
908 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800909
bo.xiao857b8682024-09-12 16:40:32 +0800910 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0)
911 {
912 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
913 "driver requires a minimum of %d buffers", control.value);
914 v4l2object->min_buffers = control.value;
915 }
916 else
917 {
918 v4l2object->min_buffers = 0;
919 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800920}
921
922gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800923gst_aml_v4l2_object_open (GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800924{
bo.xiao857b8682024-09-12 16:40:32 +0800925 if (!gst_aml_v4l2_open(v4l2object))
926 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800927
bo.xiao857b8682024-09-12 16:40:32 +0800928 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800929}
930
931gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800932gst_aml_v4l2_object_open_shared (GstAmlV4l2Object * v4l2object, GstAmlV4l2Object * other)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800933{
bo.xiao857b8682024-09-12 16:40:32 +0800934 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800935
bo.xiao857b8682024-09-12 16:40:32 +0800936 ret = gst_aml_v4l2_dup (v4l2object, other);
937 if (ret && !V4L2_TYPE_IS_OUTPUT (v4l2object->type))
938 {
939 gst_poll_fd_init (&v4l2object->pollfd);
940 v4l2object->pollfd.fd = v4l2object->video_fd;
941 gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
942 /* used for dequeue event */
943 gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
944 gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
945 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800946
bo.xiao857b8682024-09-12 16:40:32 +0800947 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800948}
949
950gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800951gst_aml_v4l2_object_close (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800952{
bo.xiao857b8682024-09-12 16:40:32 +0800953 if (!gst_aml_v4l2_close (v4l2object))
954 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800955
bo.xiao857b8682024-09-12 16:40:32 +0800956 gst_caps_replace (&v4l2object->probed_caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800957
bo.xiao857b8682024-09-12 16:40:32 +0800958 /* reset our copy of the device caps */
959 v4l2object->device_caps = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800960
bo.xiao857b8682024-09-12 16:40:32 +0800961 if (v4l2object->formats)
962 {
963 gst_aml_v4l2_object_clear_format_list (v4l2object);
964 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800965
bo.xiao857b8682024-09-12 16:40:32 +0800966 if (v4l2object->par)
967 {
968 g_value_unset (v4l2object->par);
969 g_free (v4l2object->par);
970 v4l2object->par = NULL;
971 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800972
bo.xiao857b8682024-09-12 16:40:32 +0800973 if (v4l2object->fps)
974 {
975 g_value_unset(v4l2object->fps);
976 g_free(v4l2object->fps);
977 v4l2object->fps = NULL;
978 }
sheng.liudb26f7d2024-01-22 11:24:23 +0000979
bo.xiao857b8682024-09-12 16:40:32 +0800980 if (v4l2object->channel)
981 {
982 g_free (v4l2object->channel);
983 v4l2object->channel = NULL;
984 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800985
bo.xiao857b8682024-09-12 16:40:32 +0800986 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800987}
988
989static struct v4l2_fmtdesc *
bo.xiao857b8682024-09-12 16:40:32 +0800990gst_aml_v4l2_object_get_format_from_fourcc (GstAmlV4l2Object * v4l2object,
991 guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800992{
bo.xiao857b8682024-09-12 16:40:32 +0800993 struct v4l2_fmtdesc *fmt;
994 GSList *walk;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800995
bo.xiao857b8682024-09-12 16:40:32 +0800996 if (fourcc == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800997 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +0800998
999 walk = gst_aml_v4l2_object_get_format_list (v4l2object);
1000 while (walk)
1001 {
1002 fmt = (struct v4l2_fmtdesc *) walk->data;
1003 if (fmt->pixelformat == fourcc)
1004 return fmt;
1005 /* special case for jpeg */
1006 if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
1007 fmt->pixelformat == V4L2_PIX_FMT_JPEG ||
1008 fmt->pixelformat == V4L2_PIX_FMT_PJPG)
1009 {
1010 if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG ||
1011 fourcc == V4L2_PIX_FMT_PJPG)
1012 {
1013 return fmt;
1014 }
1015 }
1016 walk = g_slist_next (walk);
1017 }
1018
1019 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001020}
1021
1022/* complete made up ranking, the values themselves are meaningless */
1023/* These ranks MUST be X such that X<<15 fits on a signed int - see
1024 the comment at the end of gst_aml_v4l2_object_format_get_rank. */
bo.xiao857b8682024-09-12 16:40:32 +08001025#define YUV_BASE_RANK 1000
1026#define JPEG_BASE_RANK 500
1027#define DV_BASE_RANK 200
1028#define RGB_BASE_RANK 100
1029#define YUV_ODD_BASE_RANK 50
1030#define RGB_ODD_BASE_RANK 25
1031#define BAYER_BASE_RANK 15
1032#define S910_BASE_RANK 10
1033#define GREY_BASE_RANK 5
1034#define PWC_BASE_RANK 1
xuesong.jiangae1548e2022-05-06 16:38:46 +08001035
1036static gint
bo.xiao857b8682024-09-12 16:40:32 +08001037gst_aml_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001038{
bo.xiao857b8682024-09-12 16:40:32 +08001039 guint32 fourcc = fmt->pixelformat;
1040 gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
1041 gint rank = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001042
bo.xiao857b8682024-09-12 16:40:32 +08001043 switch (fourcc)
1044 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001045 case V4L2_PIX_FMT_MJPEG:
1046 case V4L2_PIX_FMT_PJPG:
bo.xiao857b8682024-09-12 16:40:32 +08001047 rank = JPEG_BASE_RANK;
1048 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001049 case V4L2_PIX_FMT_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08001050 rank = JPEG_BASE_RANK + 1;
1051 break;
1052 case V4L2_PIX_FMT_MPEG: /* MPEG */
1053 rank = JPEG_BASE_RANK + 2;
1054 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001055
1056 case V4L2_PIX_FMT_RGB332:
1057 case V4L2_PIX_FMT_ARGB555:
1058 case V4L2_PIX_FMT_XRGB555:
1059 case V4L2_PIX_FMT_RGB555:
1060 case V4L2_PIX_FMT_ARGB555X:
1061 case V4L2_PIX_FMT_XRGB555X:
1062 case V4L2_PIX_FMT_RGB555X:
1063 case V4L2_PIX_FMT_BGR666:
1064 case V4L2_PIX_FMT_RGB565:
1065 case V4L2_PIX_FMT_RGB565X:
1066 case V4L2_PIX_FMT_RGB444:
1067 case V4L2_PIX_FMT_Y4:
1068 case V4L2_PIX_FMT_Y6:
1069 case V4L2_PIX_FMT_Y10:
1070 case V4L2_PIX_FMT_Y12:
1071 case V4L2_PIX_FMT_Y10BPACK:
1072 case V4L2_PIX_FMT_YUV555:
1073 case V4L2_PIX_FMT_YUV565:
1074 case V4L2_PIX_FMT_YUV32:
1075 case V4L2_PIX_FMT_NV12MT_16X16:
1076 case V4L2_PIX_FMT_NV42:
1077 case V4L2_PIX_FMT_H264_MVC:
bo.xiao857b8682024-09-12 16:40:32 +08001078 rank = RGB_ODD_BASE_RANK;
1079 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001080
1081 case V4L2_PIX_FMT_RGB24:
1082 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001083 rank = RGB_BASE_RANK - 1;
1084 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001085
1086 case V4L2_PIX_FMT_RGB32:
1087 case V4L2_PIX_FMT_BGR32:
1088 case V4L2_PIX_FMT_ABGR32:
1089 case V4L2_PIX_FMT_XBGR32:
1090 case V4L2_PIX_FMT_ARGB32:
1091 case V4L2_PIX_FMT_XRGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001092 rank = RGB_BASE_RANK;
1093 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001094
bo.xiao857b8682024-09-12 16:40:32 +08001095 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1096 rank = GREY_BASE_RANK;
1097 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001098
1099 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
1100 case V4L2_PIX_FMT_NV12M: /* Same as NV12 */
bo.xiao857b8682024-09-12 16:40:32 +08001101 case V4L2_PIX_FMT_NV12MT: /* NV12 64x32 tile */
1102 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
1103 case V4L2_PIX_FMT_NV21M: /* Same as NV21 */
1104 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1105 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
1106 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
1107 case V4L2_PIX_FMT_NV16M: /* Same as NV16 */
1108 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
1109 case V4L2_PIX_FMT_NV61M: /* Same as NV61 */
1110 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
1111 rank = YUV_ODD_BASE_RANK;
1112 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001113
bo.xiao857b8682024-09-12 16:40:32 +08001114 case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */
1115 rank = YUV_BASE_RANK + 3;
1116 break;
1117 case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */
1118 rank = YUV_BASE_RANK + 2;
1119 break;
1120 case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001121 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001122 rank = YUV_BASE_RANK + 7;
1123 break;
1124 case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */
1125 rank = YUV_BASE_RANK + 10;
1126 break;
1127 case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */
1128 rank = YUV_BASE_RANK + 6;
1129 break;
1130 case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */
1131 rank = YUV_BASE_RANK + 9;
1132 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001133 case V4L2_PIX_FMT_YUV444:
bo.xiao857b8682024-09-12 16:40:32 +08001134 rank = YUV_BASE_RANK + 6;
1135 break;
1136 case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */
1137 rank = YUV_BASE_RANK + 5;
1138 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001139 case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001140 rank = YUV_BASE_RANK + 4;
1141 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001142 case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001143 rank = YUV_BASE_RANK + 8;
1144 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001145
1146 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001147 rank = DV_BASE_RANK;
1148 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001149
bo.xiao857b8682024-09-12 16:40:32 +08001150 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1151 rank = 0;
1152 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001153
1154 case V4L2_PIX_FMT_SBGGR8:
1155 case V4L2_PIX_FMT_SGBRG8:
1156 case V4L2_PIX_FMT_SGRBG8:
1157 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001158 rank = BAYER_BASE_RANK;
1159 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001160
1161 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001162 rank = S910_BASE_RANK;
1163 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001164
1165 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001166 rank = PWC_BASE_RANK;
1167 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001168 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001169 rank = PWC_BASE_RANK;
1170 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001171
1172 default:
bo.xiao857b8682024-09-12 16:40:32 +08001173 rank = 0;
1174 break;
1175 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001176
bo.xiao857b8682024-09-12 16:40:32 +08001177 /* All ranks are below 1<<15 so a shift by 15
1178 * will a) make all non-emulated formats larger
1179 * than emulated and b) will not overflow
1180 */
1181 if (!emulated)
1182 rank <<= 15;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001183
bo.xiao857b8682024-09-12 16:40:32 +08001184 return rank;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001185}
1186
1187static gint
bo.xiao857b8682024-09-12 16:40:32 +08001188format_cmp_func (gconstpointer a, gconstpointer b)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001189{
bo.xiao857b8682024-09-12 16:40:32 +08001190 const struct v4l2_fmtdesc *fa = a;
1191 const struct v4l2_fmtdesc *fb = b;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001192
bo.xiao857b8682024-09-12 16:40:32 +08001193 if (fa->pixelformat == fb->pixelformat)
1194 return 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001195
bo.xiao857b8682024-09-12 16:40:32 +08001196 return gst_aml_v4l2_object_format_get_rank (fb) -
1197 gst_aml_v4l2_object_format_get_rank (fa);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001198}
1199
1200/******************************************************
1201 * gst_aml_v4l2_object_fill_format_list():
1202 * create list of supported capture formats
1203 * return value: TRUE on success, FALSE on error
1204 ******************************************************/
1205static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001206gst_aml_v4l2_object_fill_format_list (GstAmlV4l2Object * v4l2object,
1207 enum v4l2_buf_type type)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001208{
bo.xiao857b8682024-09-12 16:40:32 +08001209 gint n;
1210 struct v4l2_fmtdesc *format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001211
bo.xiao857b8682024-09-12 16:40:32 +08001212 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting src format enumerations");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001213
bo.xiao857b8682024-09-12 16:40:32 +08001214 /* format enumeration */
1215 for (n = 0;; n++)
1216 {
bo.xiaof61afd22024-10-16 17:18:55 +08001217 format = g_new0 (struct v4l2_fmtdesc, 1);
bo.xiao857b8682024-09-12 16:40:32 +08001218
1219 format->index = n;
1220 format->type = type;
1221
1222 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001223 {
bo.xiao857b8682024-09-12 16:40:32 +08001224 if (errno == EINVAL)
1225 {
1226 g_free (format);
1227 break; /* end of enumeration */
1228 }
1229 else
1230 {
1231 goto failed;
1232 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001233 }
1234
bo.xiao857b8682024-09-12 16:40:32 +08001235 GST_LOG_OBJECT (v4l2object->dbg_obj, "index: %u", format->index);
1236 GST_LOG_OBJECT (v4l2object->dbg_obj, "type: %d", format->type);
1237 GST_LOG_OBJECT (v4l2object->dbg_obj, "flags: %08x", format->flags);
1238 GST_LOG_OBJECT (v4l2object->dbg_obj, "description: '%s'",
1239 format->description);
1240 GST_LOG_OBJECT (v4l2object->dbg_obj, "pixelformat: %" GST_FOURCC_FORMAT,
1241 GST_FOURCC_ARGS (format->pixelformat));
1242
1243
1244 if (V4L2_PIX_FMT_YUV420M == format->pixelformat || V4L2_PIX_FMT_YUV420 == format->pixelformat)
1245 {
bo.xiaof61afd22024-10-16 17:18:55 +08001246 GST_LOG_OBJECT(v4l2object->dbg_obj, "not support YU12 and YM12");
1247 g_free (format);
bo.xiao857b8682024-09-12 16:40:32 +08001248 continue;
1249 }
1250
1251 /* sort formats according to our preference; we do this, because caps
1252 * are probed in the order the formats are in the list, and the order of
1253 * formats in the final probed caps matters for things like fixation */
1254 v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
1255 (GCompareFunc) format_cmp_func);
1256 }
1257
xuesong.jiangae1548e2022-05-06 16:38:46 +08001258#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08001259 {
1260 GSList *l;
1261
1262 GST_INFO_OBJECT (v4l2object->dbg_obj, "got %d format(s):", n);
1263 for (l = v4l2object->formats; l != NULL; l = l->next)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001264 {
bo.xiao857b8682024-09-12 16:40:32 +08001265 format = l->data;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001266
bo.xiao857b8682024-09-12 16:40:32 +08001267 GST_INFO_OBJECT (v4l2object->dbg_obj,
1268 " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
1269 ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001270 }
bo.xiao857b8682024-09-12 16:40:32 +08001271 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001272#endif
1273
bo.xiao857b8682024-09-12 16:40:32 +08001274 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001275
bo.xiao857b8682024-09-12 16:40:32 +08001276 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001277failed:
bo.xiao857b8682024-09-12 16:40:32 +08001278 {
1279 g_free (format);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001280
1281 if (v4l2object->element)
bo.xiao857b8682024-09-12 16:40:32 +08001282 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001283
bo.xiao857b8682024-09-12 16:40:32 +08001284 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1285 (_("Failed to enumerate possible video formats device '%s' can work "
1286 "with"), v4l2object->videodev),
1287 ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
1288 n, v4l2object->videodev, errno, g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001289
1290 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08001291 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001292}
1293
1294/*
1295 * Get the list of supported capture formats, a list of
1296 * <code>struct v4l2_fmtdesc</code>.
1297 */
1298static GSList *
bo.xiao857b8682024-09-12 16:40:32 +08001299gst_aml_v4l2_object_get_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001300{
bo.xiao857b8682024-09-12 16:40:32 +08001301 if (!v4l2object->formats)
1302 {
1303
1304 /* check usual way */
1305 gst_aml_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
1306
1307 /* if our driver supports multi-planar
1308 * and if formats are still empty then we can workaround driver bug
1309 * by also looking up formats as if our device was not supporting
1310 * multiplanar */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001311 if (!v4l2object->formats)
1312 {
bo.xiao857b8682024-09-12 16:40:32 +08001313 switch (v4l2object->type)
1314 {
1315 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1316 gst_aml_v4l2_object_fill_format_list (v4l2object,
1317 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1318 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001319
bo.xiao857b8682024-09-12 16:40:32 +08001320 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1321 gst_aml_v4l2_object_fill_format_list (v4l2object,
1322 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1323 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001324
bo.xiao857b8682024-09-12 16:40:32 +08001325 default:
1326 break;
1327 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001328 }
bo.xiao857b8682024-09-12 16:40:32 +08001329 }
1330 return v4l2object->formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001331}
1332
1333static GstVideoFormat
bo.xiao857b8682024-09-12 16:40:32 +08001334gst_aml_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001335{
bo.xiao857b8682024-09-12 16:40:32 +08001336 GstVideoFormat format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001337
bo.xiao857b8682024-09-12 16:40:32 +08001338 switch (fourcc)
1339 {
1340 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1341 format = GST_VIDEO_FORMAT_GRAY8;
1342 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001343 case V4L2_PIX_FMT_Y16:
bo.xiao857b8682024-09-12 16:40:32 +08001344 format = GST_VIDEO_FORMAT_GRAY16_LE;
1345 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001346 case V4L2_PIX_FMT_Y16_BE:
bo.xiao857b8682024-09-12 16:40:32 +08001347 format = GST_VIDEO_FORMAT_GRAY16_BE;
1348 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001349 case V4L2_PIX_FMT_XRGB555:
1350 case V4L2_PIX_FMT_RGB555:
bo.xiao857b8682024-09-12 16:40:32 +08001351 format = GST_VIDEO_FORMAT_RGB15;
1352 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001353 case V4L2_PIX_FMT_XRGB555X:
1354 case V4L2_PIX_FMT_RGB555X:
bo.xiao857b8682024-09-12 16:40:32 +08001355 format = GST_VIDEO_FORMAT_BGR15;
1356 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001357 case V4L2_PIX_FMT_RGB565:
bo.xiao857b8682024-09-12 16:40:32 +08001358 format = GST_VIDEO_FORMAT_RGB16;
1359 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001360 case V4L2_PIX_FMT_RGB24:
bo.xiao857b8682024-09-12 16:40:32 +08001361 format = GST_VIDEO_FORMAT_RGB;
1362 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001363 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001364 format = GST_VIDEO_FORMAT_BGR;
1365 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001366 case V4L2_PIX_FMT_XRGB32:
1367 case V4L2_PIX_FMT_RGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001368 format = GST_VIDEO_FORMAT_xRGB;
1369 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001370 case V4L2_PIX_FMT_XBGR32:
1371 case V4L2_PIX_FMT_BGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001372 format = GST_VIDEO_FORMAT_BGRx;
1373 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001374 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001375 format = GST_VIDEO_FORMAT_BGRA;
1376 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001377 case V4L2_PIX_FMT_ARGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001378 format = GST_VIDEO_FORMAT_ARGB;
1379 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001380 case V4L2_PIX_FMT_NV12:
1381 case V4L2_PIX_FMT_NV12M:
bo.xiao857b8682024-09-12 16:40:32 +08001382 format = GST_VIDEO_FORMAT_NV12;
1383 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001384 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001385 format = GST_VIDEO_FORMAT_NV12_64Z32;
1386 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001387 case V4L2_PIX_FMT_NV21:
1388 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001389 format = GST_VIDEO_FORMAT_NV21;
1390 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001391 case V4L2_PIX_FMT_YVU410:
bo.xiao857b8682024-09-12 16:40:32 +08001392 format = GST_VIDEO_FORMAT_YVU9;
1393 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001394 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001395 format = GST_VIDEO_FORMAT_YUV9;
1396 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001397 case V4L2_PIX_FMT_YUV420:
1398 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001399 format = GST_VIDEO_FORMAT_I420;
1400 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001401 case V4L2_PIX_FMT_YUYV:
bo.xiao857b8682024-09-12 16:40:32 +08001402 format = GST_VIDEO_FORMAT_YUY2;
1403 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001404 case V4L2_PIX_FMT_YVU420:
bo.xiao857b8682024-09-12 16:40:32 +08001405 format = GST_VIDEO_FORMAT_YV12;
1406 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001407 case V4L2_PIX_FMT_UYVY:
bo.xiao857b8682024-09-12 16:40:32 +08001408 format = GST_VIDEO_FORMAT_UYVY;
1409 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001410 case V4L2_PIX_FMT_YUV411P:
bo.xiao857b8682024-09-12 16:40:32 +08001411 format = GST_VIDEO_FORMAT_Y41B;
1412 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001413 case V4L2_PIX_FMT_YUV422P:
bo.xiao857b8682024-09-12 16:40:32 +08001414 format = GST_VIDEO_FORMAT_Y42B;
1415 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001416 case V4L2_PIX_FMT_YVYU:
bo.xiao857b8682024-09-12 16:40:32 +08001417 format = GST_VIDEO_FORMAT_YVYU;
1418 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001419 case V4L2_PIX_FMT_NV16:
1420 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001421 format = GST_VIDEO_FORMAT_NV16;
1422 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001423 case V4L2_PIX_FMT_NV61:
1424 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001425 format = GST_VIDEO_FORMAT_NV61;
1426 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001427 case V4L2_PIX_FMT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08001428 format = GST_VIDEO_FORMAT_NV24;
1429 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001430 default:
bo.xiao857b8682024-09-12 16:40:32 +08001431 format = GST_VIDEO_FORMAT_UNKNOWN;
1432 break;
1433 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001434
bo.xiao857b8682024-09-12 16:40:32 +08001435 return format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001436}
1437
1438static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001439gst_aml_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001440{
bo.xiao857b8682024-09-12 16:40:32 +08001441 gboolean ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001442
bo.xiao857b8682024-09-12 16:40:32 +08001443 switch (fourcc)
1444 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001445 case V4L2_PIX_FMT_XRGB555:
1446 case V4L2_PIX_FMT_RGB555:
1447 case V4L2_PIX_FMT_XRGB555X:
1448 case V4L2_PIX_FMT_RGB555X:
1449 case V4L2_PIX_FMT_RGB565:
1450 case V4L2_PIX_FMT_RGB24:
1451 case V4L2_PIX_FMT_BGR24:
1452 case V4L2_PIX_FMT_XRGB32:
1453 case V4L2_PIX_FMT_RGB32:
1454 case V4L2_PIX_FMT_XBGR32:
1455 case V4L2_PIX_FMT_BGR32:
1456 case V4L2_PIX_FMT_ABGR32:
1457 case V4L2_PIX_FMT_ARGB32:
1458 case V4L2_PIX_FMT_SBGGR8:
1459 case V4L2_PIX_FMT_SGBRG8:
1460 case V4L2_PIX_FMT_SGRBG8:
1461 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001462 ret = TRUE;
1463 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001464 default:
bo.xiao857b8682024-09-12 16:40:32 +08001465 break;
1466 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001467
bo.xiao857b8682024-09-12 16:40:32 +08001468 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001469}
1470
1471static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001472gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001473{
bo.xiao857b8682024-09-12 16:40:32 +08001474 GstStructure *structure = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001475
bo.xiao857b8682024-09-12 16:40:32 +08001476 switch (fourcc)
1477 {
1478 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
1479 structure = gst_structure_new_empty("video/mjpeg");
1480 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001481 case V4L2_PIX_FMT_MPEG1:
bo.xiao857b8682024-09-12 16:40:32 +08001482 structure = gst_structure_new ("video/mpeg",
1483 "mpegversion", G_TYPE_INT, 1, NULL);
1484
1485 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1486 GST_DEBUG("aml set mpeg1 systemstream to false");
1487 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001488 case V4L2_PIX_FMT_MPEG2:
bo.xiao857b8682024-09-12 16:40:32 +08001489 structure = gst_structure_new("video/mpeg",
1490 "mpegversion", G_TYPE_INT, 2, NULL);
1491 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1492 GST_DEBUG("aml set mpeg2 systemstream to false");
1493 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001494 case V4L2_PIX_FMT_MPEG4:
1495 case V4L2_PIX_FMT_XVID:
bo.xiao857b8682024-09-12 16:40:32 +08001496 structure = gst_structure_new ("video/mpeg",
1497 "mpegversion", G_TYPE_INT, 4, "systemstream",
1498 G_TYPE_BOOLEAN, FALSE, NULL);
1499 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001500 case V4L2_PIX_FMT_FWHT:
bo.xiao857b8682024-09-12 16:40:32 +08001501 structure = gst_structure_new_empty ("video/x-fwht");
1502 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001503 case V4L2_PIX_FMT_H263:
bo.xiao857b8682024-09-12 16:40:32 +08001504 structure = gst_structure_new ("video/x-h263",
1505 "variant", G_TYPE_STRING, "itu", NULL);
1506 break;
1507 case V4L2_PIX_FMT_H264: /* H.264 */
1508 structure = gst_structure_new ("video/x-h264",
1509 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1510 G_TYPE_STRING, "au", NULL);
1511 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001512 case V4L2_PIX_FMT_H264_NO_SC:
bo.xiao857b8682024-09-12 16:40:32 +08001513 structure = gst_structure_new ("video/x-h264",
1514 "stream-format", G_TYPE_STRING, "avc", "alignment",
1515 G_TYPE_STRING, "au", NULL);
1516 break;
1517 case V4L2_PIX_FMT_HEVC: /* H.265 */
1518 structure = gst_structure_new ("video/x-h265",
1519 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1520 G_TYPE_STRING, "au", NULL);
1521 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001522 case V4L2_PIX_FMT_VC1_ANNEX_G:
1523 case V4L2_PIX_FMT_VC1_ANNEX_L:
bo.xiao857b8682024-09-12 16:40:32 +08001524 structure = gst_structure_new ("video/x-wmv",
1525 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
1526 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001527 case V4L2_PIX_FMT_VP8:
bo.xiao857b8682024-09-12 16:40:32 +08001528 structure = gst_structure_new_empty ("video/x-vp8");
1529 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001530 case V4L2_PIX_FMT_VP9:
bo.xiao857b8682024-09-12 16:40:32 +08001531 structure = gst_structure_new_empty ("video/x-vp9");
1532 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001533 case V4L2_PIX_FMT_AV1:
1534 structure = gst_structure_new_empty("video/x-av1");
1535 break;
zengliang.li51f54b62023-10-10 12:14:49 +00001536 case V4L2_PIX_FMT_AVS:
1537 structure = gst_structure_new_empty("video/x-avs");
1538 break;
1539 case V4L2_PIX_FMT_AVS2:
1540 structure = gst_structure_new_empty("video/x-avs2");
1541 break;
1542 case V4L2_PIX_FMT_AVS3:
1543 structure = gst_structure_new_empty("video/x-avs3");
1544 break;
bo.xiao857b8682024-09-12 16:40:32 +08001545 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001546 case V4L2_PIX_FMT_Y16:
1547 case V4L2_PIX_FMT_Y16_BE:
1548 case V4L2_PIX_FMT_XRGB555:
1549 case V4L2_PIX_FMT_RGB555:
1550 case V4L2_PIX_FMT_XRGB555X:
1551 case V4L2_PIX_FMT_RGB555X:
1552 case V4L2_PIX_FMT_RGB565:
1553 case V4L2_PIX_FMT_RGB24:
1554 case V4L2_PIX_FMT_BGR24:
1555 case V4L2_PIX_FMT_RGB32:
1556 case V4L2_PIX_FMT_XRGB32:
1557 case V4L2_PIX_FMT_ARGB32:
1558 case V4L2_PIX_FMT_BGR32:
1559 case V4L2_PIX_FMT_XBGR32:
1560 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001561 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001562 case V4L2_PIX_FMT_NV12M:
1563 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001564 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001565 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001566 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001567 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001568 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001569 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001570 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001571 case V4L2_PIX_FMT_YVU410:
1572 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001573 case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001574 case V4L2_PIX_FMT_YUV420M:
1575 case V4L2_PIX_FMT_YUYV:
1576 case V4L2_PIX_FMT_YVU420:
1577 case V4L2_PIX_FMT_UYVY:
1578 case V4L2_PIX_FMT_YUV422P:
1579 case V4L2_PIX_FMT_YVYU:
1580 case V4L2_PIX_FMT_YUV411P:
1581 {
bo.xiao857b8682024-09-12 16:40:32 +08001582 GstVideoFormat format;
1583 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fourcc);
1584 if (format != GST_VIDEO_FORMAT_UNKNOWN)
1585 structure = gst_structure_new ("video/x-raw",
1586 "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
1587 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001588 }
1589 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001590 structure =
1591 gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1592 NULL);
1593 break;
1594 case V4L2_PIX_FMT_MPEG: /* MPEG */
1595 structure = gst_structure_new ("video/mpegts",
1596 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
1597 break;
1598 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1599 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001600 case V4L2_PIX_FMT_SBGGR8:
1601 case V4L2_PIX_FMT_SGBRG8:
1602 case V4L2_PIX_FMT_SGRBG8:
1603 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001604 structure = gst_structure_new ("video/x-bayer", "format", G_TYPE_STRING,
1605 fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" :
1606 fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg" :
1607 fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg" :
1608 /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb", NULL);
1609 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001610 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001611 structure = gst_structure_new_empty ("video/x-sonix");
1612 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001613 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001614 structure = gst_structure_new_empty ("video/x-pwc1");
1615 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001616 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001617 structure = gst_structure_new_empty ("video/x-pwc2");
1618 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001619 case V4L2_PIX_FMT_RGB332:
1620 case V4L2_PIX_FMT_BGR666:
1621 case V4L2_PIX_FMT_ARGB555X:
1622 case V4L2_PIX_FMT_RGB565X:
1623 case V4L2_PIX_FMT_RGB444:
bo.xiao857b8682024-09-12 16:40:32 +08001624 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1625 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001626 case V4L2_PIX_FMT_Y4:
1627 case V4L2_PIX_FMT_Y6:
1628 case V4L2_PIX_FMT_Y10:
1629 case V4L2_PIX_FMT_Y12:
1630 case V4L2_PIX_FMT_Y10BPACK:
1631 case V4L2_PIX_FMT_YUV444:
1632 case V4L2_PIX_FMT_YUV555:
1633 case V4L2_PIX_FMT_YUV565:
1634 case V4L2_PIX_FMT_Y41P:
1635 case V4L2_PIX_FMT_YUV32:
1636 case V4L2_PIX_FMT_NV12MT_16X16:
1637 case V4L2_PIX_FMT_NV42:
1638 case V4L2_PIX_FMT_H264_MVC:
1639 default:
bo.xiao857b8682024-09-12 16:40:32 +08001640 GST_DEBUG ("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
1641 fourcc, GST_FOURCC_ARGS (fourcc));
1642 break;
1643 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001644
bo.xiao857b8682024-09-12 16:40:32 +08001645 return structure;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001646}
1647
1648GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001649gst_aml_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001650{
bo.xiao857b8682024-09-12 16:40:32 +08001651 GstStructure *template;
1652 gint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001653
bo.xiao857b8682024-09-12 16:40:32 +08001654 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001655
bo.xiao857b8682024-09-12 16:40:32 +08001656 if (template == NULL)
1657 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001658
bo.xiao857b8682024-09-12 16:40:32 +08001659 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1660 {
1661 if (gst_aml_v4l2_formats[i].format != fourcc)
1662 continue;
1663
1664 if (gst_aml_v4l2_formats[i].dimensions)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001665 {
bo.xiao857b8682024-09-12 16:40:32 +08001666 gst_structure_set (template,
1667 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1668 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1669 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001670 }
bo.xiao857b8682024-09-12 16:40:32 +08001671 break;
1672 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001673
1674done:
bo.xiao857b8682024-09-12 16:40:32 +08001675 return template;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001676}
1677
1678static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001679gst_aml_v4l2_object_get_caps_helper (GstAmlV4L2FormatFlags flags)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001680{
bo.xiao857b8682024-09-12 16:40:32 +08001681 GstStructure *structure;
1682 GstCaps *caps;
1683 guint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001684
bo.xiao857b8682024-09-12 16:40:32 +08001685 caps = gst_caps_new_empty ();
1686 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1687 {
1688
1689 if ((gst_aml_v4l2_formats[i].flags & flags) == 0)
1690 continue;
1691
1692 structure =
1693 gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (gst_aml_v4l2_formats[i].format);
1694
1695 if (structure)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001696 {
bo.xiao857b8682024-09-12 16:40:32 +08001697 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001698
bo.xiao857b8682024-09-12 16:40:32 +08001699 if (gst_aml_v4l2_formats[i].dimensions)
1700 {
1701 gst_structure_set (structure,
1702 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1703 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1704 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1705 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001706
bo.xiao857b8682024-09-12 16:40:32 +08001707 switch (gst_aml_v4l2_formats[i].format)
1708 {
1709 case V4L2_PIX_FMT_RGB32:
1710 alt_s = gst_structure_copy (structure);
1711 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
1712 break;
1713 case V4L2_PIX_FMT_BGR32:
1714 alt_s = gst_structure_copy (structure);
1715 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
1716 default:
1717 break;
1718 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001719
bo.xiao857b8682024-09-12 16:40:32 +08001720 gst_caps_append_structure (caps, structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001721
bo.xiao857b8682024-09-12 16:40:32 +08001722 if (alt_s)
1723 gst_caps_append_structure (caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001724 }
bo.xiao857b8682024-09-12 16:40:32 +08001725 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001726
bo.xiao857b8682024-09-12 16:40:32 +08001727 return gst_caps_simplify(caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001728}
1729
1730GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001731gst_aml_v4l2_object_get_all_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001732{
bo.xiao857b8682024-09-12 16:40:32 +08001733 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001734
bo.xiao857b8682024-09-12 16:40:32 +08001735 if (g_once_init_enter (&caps))
1736 {
1737 GstCaps *all_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_ALL);
1738 GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1739 g_once_init_leave (&caps, all_caps);
1740 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001741
bo.xiao857b8682024-09-12 16:40:32 +08001742 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001743}
1744
1745GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001746gst_aml_v4l2_object_get_raw_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001747{
bo.xiao857b8682024-09-12 16:40:32 +08001748 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001749
bo.xiao857b8682024-09-12 16:40:32 +08001750 if (g_once_init_enter (&caps))
1751 {
1752 GstCaps *raw_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_RAW);
1753 GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1754 g_once_init_leave (&caps, raw_caps);
1755 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001756
bo.xiao857b8682024-09-12 16:40:32 +08001757 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001758}
1759
1760GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001761gst_aml_v4l2_object_get_codec_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001762{
bo.xiao857b8682024-09-12 16:40:32 +08001763 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001764
bo.xiao857b8682024-09-12 16:40:32 +08001765 if (g_once_init_enter (&caps))
1766 {
1767 GstCaps *codec_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
1768 GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1769 g_once_init_leave (&caps, codec_caps);
1770 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001771
bo.xiao857b8682024-09-12 16:40:32 +08001772 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001773}
1774
1775/* collect data for the given caps
1776 * @caps: given input caps
1777 * @format: location for the v4l format
1778 * @w/@h: location for width and height
1779 * @fps_n/@fps_d: location for framerate
1780 * @size: location for expected size of the frame or 0 if unknown
1781 */
1782static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001783gst_aml_v4l2_object_get_caps_info (GstAmlV4l2Object * v4l2object, GstCaps * caps,
1784 struct v4l2_fmtdesc **format, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001785{
bo.xiao857b8682024-09-12 16:40:32 +08001786 GstStructure *structure;
1787 guint32 fourcc = 0, fourcc_nc = 0;
1788 const gchar *mimetype;
1789 struct v4l2_fmtdesc *fmt = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001790
bo.xiao857b8682024-09-12 16:40:32 +08001791 GST_DEBUG_OBJECT(v4l2object, "got caps: %" GST_PTR_FORMAT, caps);
fei.denge9458472023-04-18 02:05:48 +00001792
bo.xiao857b8682024-09-12 16:40:32 +08001793 structure = gst_caps_get_structure (caps, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001794
bo.xiao857b8682024-09-12 16:40:32 +08001795 mimetype = gst_structure_get_name (structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001796
bo.xiao857b8682024-09-12 16:40:32 +08001797 if (!gst_video_info_from_caps (info, caps))
1798 goto invalid_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001799
bo.xiao857b8682024-09-12 16:40:32 +08001800 if (g_str_equal (mimetype, "video/x-raw"))
1801 {
1802 switch (GST_VIDEO_INFO_FORMAT (info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08001803 {
bo.xiao857b8682024-09-12 16:40:32 +08001804 case GST_VIDEO_FORMAT_I420:
1805 fourcc = V4L2_PIX_FMT_YUV420;
1806 fourcc_nc = V4L2_PIX_FMT_YUV420M;
1807 break;
1808 case GST_VIDEO_FORMAT_YUY2:
1809 fourcc = V4L2_PIX_FMT_YUYV;
1810 break;
1811 case GST_VIDEO_FORMAT_UYVY:
1812 fourcc = V4L2_PIX_FMT_UYVY;
1813 break;
1814 case GST_VIDEO_FORMAT_YV12:
1815 fourcc = V4L2_PIX_FMT_YVU420;
1816 break;
1817 case GST_VIDEO_FORMAT_Y41B:
1818 fourcc = V4L2_PIX_FMT_YUV411P;
1819 break;
1820 case GST_VIDEO_FORMAT_Y42B:
1821 fourcc = V4L2_PIX_FMT_YUV422P;
1822 break;
1823 case GST_VIDEO_FORMAT_NV12:
1824 fourcc = V4L2_PIX_FMT_NV12;
1825 fourcc_nc = V4L2_PIX_FMT_NV12M;
1826 break;
1827 case GST_VIDEO_FORMAT_NV12_64Z32:
1828 fourcc_nc = V4L2_PIX_FMT_NV12MT;
1829 break;
1830 case GST_VIDEO_FORMAT_NV21:
1831 fourcc = V4L2_PIX_FMT_NV21;
1832 fourcc_nc = V4L2_PIX_FMT_NV21M;
1833 break;
1834 case GST_VIDEO_FORMAT_NV16:
1835 fourcc = V4L2_PIX_FMT_NV16;
1836 fourcc_nc = V4L2_PIX_FMT_NV16M;
1837 break;
1838 case GST_VIDEO_FORMAT_NV61:
1839 fourcc = V4L2_PIX_FMT_NV61;
1840 fourcc_nc = V4L2_PIX_FMT_NV61M;
1841 break;
1842 case GST_VIDEO_FORMAT_NV24:
1843 fourcc = V4L2_PIX_FMT_NV24;
1844 break;
1845 case GST_VIDEO_FORMAT_YVYU:
1846 fourcc = V4L2_PIX_FMT_YVYU;
1847 break;
1848 case GST_VIDEO_FORMAT_RGB15:
1849 fourcc = V4L2_PIX_FMT_RGB555;
1850 fourcc_nc = V4L2_PIX_FMT_XRGB555;
1851 break;
1852 case GST_VIDEO_FORMAT_RGB16:
1853 fourcc = V4L2_PIX_FMT_RGB565;
1854 break;
1855 case GST_VIDEO_FORMAT_RGB:
1856 fourcc = V4L2_PIX_FMT_RGB24;
1857 break;
1858 case GST_VIDEO_FORMAT_BGR:
1859 fourcc = V4L2_PIX_FMT_BGR24;
1860 break;
1861 case GST_VIDEO_FORMAT_xRGB:
1862 fourcc = V4L2_PIX_FMT_RGB32;
1863 fourcc_nc = V4L2_PIX_FMT_XRGB32;
1864 break;
1865 case GST_VIDEO_FORMAT_ARGB:
1866 fourcc = V4L2_PIX_FMT_RGB32;
1867 fourcc_nc = V4L2_PIX_FMT_ARGB32;
1868 break;
1869 case GST_VIDEO_FORMAT_BGRx:
1870 fourcc = V4L2_PIX_FMT_BGR32;
1871 fourcc_nc = V4L2_PIX_FMT_XBGR32;
1872 break;
1873 case GST_VIDEO_FORMAT_BGRA:
1874 fourcc = V4L2_PIX_FMT_BGR32;
1875 fourcc_nc = V4L2_PIX_FMT_ABGR32;
1876 break;
1877 case GST_VIDEO_FORMAT_GRAY8:
1878 fourcc = V4L2_PIX_FMT_GREY;
1879 break;
1880 case GST_VIDEO_FORMAT_GRAY16_LE:
1881 fourcc = V4L2_PIX_FMT_Y16;
1882 break;
1883 case GST_VIDEO_FORMAT_GRAY16_BE:
1884 fourcc = V4L2_PIX_FMT_Y16_BE;
1885 break;
1886 case GST_VIDEO_FORMAT_BGR15:
1887 fourcc = V4L2_PIX_FMT_RGB555X;
1888 fourcc_nc = V4L2_PIX_FMT_XRGB555X;
1889 break;
1890 default:
1891 break;
1892 }
1893 }
1894 else
1895 {
1896 if (g_str_equal (mimetype, "video/mpegts"))
1897 {
1898 fourcc = V4L2_PIX_FMT_MPEG;
1899 }
1900 else if (g_str_equal (mimetype, "video/x-dv"))
1901 {
1902 fourcc = V4L2_PIX_FMT_DV;
1903 }
1904 else if (g_str_equal(mimetype, "video/mjpeg"))
1905 {
1906 fourcc = V4L2_PIX_FMT_JPEG;
1907 }
1908 else if (g_str_equal (mimetype, "video/mpeg"))
1909 {
1910 gint version;
1911 if (gst_structure_get_int (structure, "mpegversion", &version))
1912 {
1913 switch (version)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001914 {
bo.xiao857b8682024-09-12 16:40:32 +08001915 case 1:
1916 fourcc = V4L2_PIX_FMT_MPEG1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001917 break;
bo.xiao857b8682024-09-12 16:40:32 +08001918 case 2:
1919 fourcc = V4L2_PIX_FMT_MPEG2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001920 break;
bo.xiao857b8682024-09-12 16:40:32 +08001921 case 4:
1922 fourcc = V4L2_PIX_FMT_MPEG4;
1923 fourcc_nc = V4L2_PIX_FMT_XVID;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001924 break;
bo.xiao857b8682024-09-12 16:40:32 +08001925 default:
xuesong.jiangae1548e2022-05-06 16:38:46 +08001926 break;
1927 }
bo.xiao857b8682024-09-12 16:40:32 +08001928 }
1929 }
1930 else if (g_str_equal (mimetype, "video/x-fwht"))
1931 {
1932 fourcc = V4L2_PIX_FMT_FWHT;
1933 }
1934 else if (g_str_equal (mimetype, "video/x-h263"))
1935 {
1936 fourcc = V4L2_PIX_FMT_H263;
1937 }
1938 else if (g_str_equal (mimetype, "video/x-h264"))
1939 {
1940 const gchar *stream_format =
1941 gst_structure_get_string (structure, "stream-format");
1942 if (g_str_equal (stream_format, "avc"))
1943 fourcc = V4L2_PIX_FMT_H264_NO_SC;
1944 else
1945 fourcc = V4L2_PIX_FMT_H264;
1946 }
1947 else if (g_str_equal (mimetype, "video/x-h265"))
1948 {
1949 fourcc = V4L2_PIX_FMT_HEVC;
1950 }
1951 else if (g_str_equal (mimetype, "video/x-vp8"))
1952 {
1953 fourcc = V4L2_PIX_FMT_VP8;
1954 }
1955 else if (g_str_equal (mimetype, "video/x-vp9"))
1956 {
1957 fourcc = V4L2_PIX_FMT_VP9;
1958 }
1959 else if (g_str_equal(mimetype, "video/x-av1"))
1960 {
1961 fourcc = V4L2_PIX_FMT_AV1;
1962 }
1963 else if (g_str_equal(mimetype, "video/x-avs"))
1964 {
1965 fourcc = V4L2_PIX_FMT_AVS;
1966 }
1967 else if (g_str_equal(mimetype, "video/x-avs2"))
1968 {
1969 fourcc = V4L2_PIX_FMT_AVS2;
1970 }
1971 else if (g_str_equal(mimetype, "video/x-avs3"))
1972 {
1973 fourcc = V4L2_PIX_FMT_AVS3;
1974 }
1975 else if (g_str_equal (mimetype, "video/x-bayer"))
1976 {
1977 const gchar *vformat = gst_structure_get_string(structure, "format");
1978 if (vformat)
1979 {
1980 if (!g_ascii_strcasecmp(vformat, "bggr"))
1981 fourcc = V4L2_PIX_FMT_SBGGR8;
1982 else if (!g_ascii_strcasecmp(vformat, "gbrg"))
1983 fourcc = V4L2_PIX_FMT_SGBRG8;
1984 else if (!g_ascii_strcasecmp(vformat, "grbg"))
1985 fourcc = V4L2_PIX_FMT_SGRBG8;
1986 else if (!g_ascii_strcasecmp(vformat, "rggb"))
1987 fourcc = V4L2_PIX_FMT_SRGGB8;
1988 }
1989 }
1990 else if (g_str_equal (mimetype, "video/x-sonix"))
1991 {
1992 fourcc = V4L2_PIX_FMT_SN9C10X;
1993 }
1994 else if (g_str_equal (mimetype, "video/x-pwc1"))
1995 {
1996 fourcc = V4L2_PIX_FMT_PWC1;
1997 }
1998 else if (g_str_equal (mimetype, "video/x-pwc2"))
1999 {
2000 fourcc = V4L2_PIX_FMT_PWC2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002001 }
2002 else
2003 {
bo.xiao857b8682024-09-12 16:40:32 +08002004 GST_ERROR("Unknown video codec %s.", mimetype);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002005 }
bo.xiao857b8682024-09-12 16:40:32 +08002006 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002007
bo.xiao857b8682024-09-12 16:40:32 +08002008 /* Prefer the non-contiguous if supported */
2009 v4l2object->prefered_non_contiguous = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002010
bo.xiao857b8682024-09-12 16:40:32 +08002011 if (fourcc_nc)
2012 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_nc);
2013 else if (fourcc == 0)
2014 goto unhandled_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002015
bo.xiao857b8682024-09-12 16:40:32 +08002016 if (fmt == NULL)
2017 {
2018 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
2019 v4l2object->prefered_non_contiguous = FALSE;
2020 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002021
bo.xiao857b8682024-09-12 16:40:32 +08002022 if (fmt == NULL)
2023 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002024
bo.xiao857b8682024-09-12 16:40:32 +08002025 *format = fmt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002026
bo.xiao857b8682024-09-12 16:40:32 +08002027 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002028
bo.xiao857b8682024-09-12 16:40:32 +08002029 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002030invalid_format:
bo.xiao857b8682024-09-12 16:40:32 +08002031 {
2032 GST_DEBUG_OBJECT (v4l2object, "invalid format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002033 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002034 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002035unhandled_format:
bo.xiao857b8682024-09-12 16:40:32 +08002036 {
2037 GST_DEBUG_OBJECT (v4l2object, "unhandled format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002038 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002039 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002040unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08002041 {
2042 GST_DEBUG_OBJECT (v4l2object, "unsupported format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002043 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002044 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002045}
2046
2047static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002048gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
2049 guint32 pixelformat, gint * width, gint * height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002050
2051static void
bo.xiao857b8682024-09-12 16:40:32 +08002052gst_aml_v4l2_object_add_aspect_ratio (GstAmlV4l2Object * v4l2object, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002053{
bo.xiao857b8682024-09-12 16:40:32 +08002054 if (v4l2object->keep_aspect && v4l2object->par)
2055 gst_structure_set_value (s, "pixel-aspect-ratio", v4l2object->par);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002056}
2057
2058/* returns TRUE if the value was changed in place, otherwise FALSE */
2059static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002060gst_aml_v4l2src_value_simplify (GValue * val)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002061{
bo.xiao857b8682024-09-12 16:40:32 +08002062 /* simplify list of one value to one value */
2063 if (GST_VALUE_HOLDS_LIST (val) && gst_value_list_get_size (val) == 1)
2064 {
2065 const GValue *list_val;
2066 GValue new_val = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002067
bo.xiao857b8682024-09-12 16:40:32 +08002068 list_val = gst_value_list_get_value (val, 0);
2069 g_value_init (&new_val, G_VALUE_TYPE (list_val));
2070 g_value_copy (list_val, &new_val);
2071 g_value_unset (val);
2072 *val = new_val;
2073 return TRUE;
2074 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002075
bo.xiao857b8682024-09-12 16:40:32 +08002076 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002077}
2078
2079static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002080gst_aml_v4l2_object_get_interlace_mode (enum v4l2_field field,
2081 GstVideoInterlaceMode * interlace_mode)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002082{
bo.xiao857b8682024-09-12 16:40:32 +08002083 switch (field)
2084 {
2085 case V4L2_FIELD_ANY:
2086 GST_ERROR("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
2087 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002088 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002089 *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
2090 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002091 case V4L2_FIELD_INTERLACED:
2092 case V4L2_FIELD_INTERLACED_TB:
2093 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08002094 *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
2095 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002096 default:
bo.xiao857b8682024-09-12 16:40:32 +08002097 GST_ERROR ("Unknown enum v4l2_field %d", field);
2098 return FALSE;
2099 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002100}
2101
2102static gboolean
2103gst_aml_v4l2_object_get_colorspace(struct v4l2_format *fmt,
2104 GstVideoColorimetry *cinfo)
2105{
bo.xiao857b8682024-09-12 16:40:32 +08002106 gboolean is_rgb =
2107 gst_aml_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat);
2108 enum v4l2_colorspace colorspace;
2109 enum v4l2_quantization range;
2110 enum v4l2_ycbcr_encoding matrix;
2111 enum v4l2_xfer_func transfer;
2112 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002113
bo.xiao857b8682024-09-12 16:40:32 +08002114 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type))
2115 {
2116 colorspace = fmt->fmt.pix_mp.colorspace;
2117 range = fmt->fmt.pix_mp.quantization;
2118 matrix = fmt->fmt.pix_mp.ycbcr_enc;
2119 transfer = fmt->fmt.pix_mp.xfer_func;
2120 }
2121 else
2122 {
2123 colorspace = fmt->fmt.pix.colorspace;
2124 range = fmt->fmt.pix.quantization;
2125 matrix = fmt->fmt.pix.ycbcr_enc;
2126 transfer = fmt->fmt.pix.xfer_func;
2127 }
2128 GST_DEBUG("colorspace:%d, range:%d, matrix:%d, transfer:%d", colorspace, range, matrix, transfer);
2129 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 +08002130
bo.xiao857b8682024-09-12 16:40:32 +08002131 /* First step, set the defaults for each primaries */
2132 switch (colorspace)
2133 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002134 case V4L2_COLORSPACE_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08002135 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2136 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2137 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2138 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
2139 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002140 case V4L2_COLORSPACE_REC709:
bo.xiao857b8682024-09-12 16:40:32 +08002141 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2142 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2143 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2144 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2145 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002146 case V4L2_COLORSPACE_SRGB:
2147 case V4L2_COLORSPACE_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08002148 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2149 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2150 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2151 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2152 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002153 case V4L2_COLORSPACE_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002154 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2155 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2156 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2157 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
2158 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002159 case V4L2_COLORSPACE_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002160 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2161 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2162 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2163 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
2164 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002165 case V4L2_COLORSPACE_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002166 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2167 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2168 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2169 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
2170 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002171 case V4L2_COLORSPACE_470_SYSTEM_M:
bo.xiao857b8682024-09-12 16:40:32 +08002172 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2173 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2174 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2175 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
2176 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002177 case V4L2_COLORSPACE_470_SYSTEM_BG:
bo.xiao857b8682024-09-12 16:40:32 +08002178 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2179 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2180 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2181 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
2182 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002183 case V4L2_COLORSPACE_RAW:
bo.xiao857b8682024-09-12 16:40:32 +08002184 /* Explicitly unknown */
2185 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2186 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2187 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2188 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
2189 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002190 default:
bo.xiao857b8682024-09-12 16:40:32 +08002191 GST_DEBUG ("Unknown enum v4l2_colorspace %d", colorspace);
2192 ret = FALSE;
2193 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002194 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002195 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 +08002196
bo.xiao857b8682024-09-12 16:40:32 +08002197 if (!ret)
2198 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002199
bo.xiao857b8682024-09-12 16:40:32 +08002200 /* Second step, apply any custom variation */
2201 switch (range)
2202 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002203 case V4L2_QUANTIZATION_FULL_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002204 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2205 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002206 case V4L2_QUANTIZATION_LIM_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002207 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2208 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002209 case V4L2_QUANTIZATION_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002210 /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
2211 if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
2212 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2213 else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601
2214 || matrix == V4L2_YCBCR_ENC_XV709
2215 || colorspace == V4L2_COLORSPACE_JPEG)
2216 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2217 else
2218 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2219 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002220 default:
bo.xiao857b8682024-09-12 16:40:32 +08002221 GST_WARNING ("Unknown enum v4l2_quantization value %d", range);
2222 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2223 break;
2224 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002225 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 +08002226
bo.xiao857b8682024-09-12 16:40:32 +08002227 switch (matrix)
2228 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002229 case V4L2_YCBCR_ENC_XV601:
2230 case V4L2_YCBCR_ENC_SYCC:
bo.xiao857b8682024-09-12 16:40:32 +08002231 GST_FIXME ("XV601 and SYCC not defined, assuming 601");
2232 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002233 case V4L2_YCBCR_ENC_601:
bo.xiao857b8682024-09-12 16:40:32 +08002234 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2235 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002236 case V4L2_YCBCR_ENC_XV709:
bo.xiao857b8682024-09-12 16:40:32 +08002237 GST_FIXME ("XV709 not defined, assuming 709");
2238 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002239 case V4L2_YCBCR_ENC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002240 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2241 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002242 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
bo.xiao857b8682024-09-12 16:40:32 +08002243 GST_FIXME ("BT2020 with constant luma is not defined, assuming BT2020");
2244 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002245 case V4L2_YCBCR_ENC_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002246 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2247 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002248 case V4L2_YCBCR_ENC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002249 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2250 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002251 case V4L2_YCBCR_ENC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002252 /* nothing, just use defaults for colorspace */
2253 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002254 default:
bo.xiao857b8682024-09-12 16:40:32 +08002255 GST_WARNING ("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
2256 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2257 break;
2258 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002259 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 +08002260
bo.xiao857b8682024-09-12 16:40:32 +08002261 /* Set identity matrix for R'G'B' formats to avoid creating
2262 * confusion. This though is cosmetic as it's now properly ignored by
2263 * the video info API and videoconvert. */
2264 if (is_rgb)
2265 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002266
bo.xiao857b8682024-09-12 16:40:32 +08002267 switch (transfer)
2268 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002269 case V4L2_XFER_FUNC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002270 if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160)
2271 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2272 else
2273 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2274 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002275 case V4L2_XFER_FUNC_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002276 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2277 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002278 case V4L2_XFER_FUNC_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002279 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2280 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002281 case V4L2_XFER_FUNC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002282 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2283 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002284 case V4L2_XFER_FUNC_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002285 cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
2286 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002287 case V4L2_XFER_FUNC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002288 /* nothing, just use defaults for colorspace */
2289 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002290 default:
bo.xiao857b8682024-09-12 16:40:32 +08002291 GST_WARNING ("Unknown enum v4l2_xfer_func value %d", transfer);
2292 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2293 break;
2294 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002295 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 +08002296
2297done:
bo.xiao857b8682024-09-12 16:40:32 +08002298 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002299}
2300
2301static int
bo.xiao857b8682024-09-12 16:40:32 +08002302gst_aml_v4l2_object_try_fmt (GstAmlV4l2Object * v4l2object,
2303 struct v4l2_format *try_fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002304{
bo.xiao857b8682024-09-12 16:40:32 +08002305 int fd = v4l2object->video_fd;
2306 struct v4l2_format fmt;
2307 int r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002308
bo.xiao857b8682024-09-12 16:40:32 +08002309 memcpy (&fmt, try_fmt, sizeof (fmt));
2310 r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002311
bo.xiao857b8682024-09-12 16:40:32 +08002312 if (r < 0 && errno == ENOTTY)
2313 {
2314 /* The driver might not implement TRY_FMT, in which case we will try
2315 S_FMT to probe */
2316 if (GST_AML_V4L2_IS_ACTIVE (v4l2object))
2317 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002318
bo.xiao857b8682024-09-12 16:40:32 +08002319 memcpy (&fmt, try_fmt, sizeof (fmt));
2320 r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
2321 }
2322 memcpy (try_fmt, &fmt, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002323
bo.xiao857b8682024-09-12 16:40:32 +08002324 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002325
2326error:
bo.xiao857b8682024-09-12 16:40:32 +08002327 memcpy (try_fmt, &fmt, sizeof (fmt));
2328 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2329 "Unable to try format: %s", g_strerror (errno));
2330 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002331}
2332
2333static void
bo.xiao857b8682024-09-12 16:40:32 +08002334gst_aml_v4l2_object_add_interlace_mode (GstAmlV4l2Object * v4l2object,
2335 GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002336{
bo.xiao857b8682024-09-12 16:40:32 +08002337 struct v4l2_format fmt;
2338 GValue interlace_formats = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002339
bo.xiao857b8682024-09-12 16:40:32 +08002340 enum v4l2_field formats[] = {V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED};
2341 gsize i;
2342 GstVideoInterlaceMode interlace_mode, prev = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002343
bo.xiao857b8682024-09-12 16:40:32 +08002344 if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08002345 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002346
bo.xiao857b8682024-09-12 16:40:32 +08002347 if (v4l2object->never_interlaced)
2348 {
2349 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
2350 return;
2351 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002352
bo.xiao857b8682024-09-12 16:40:32 +08002353 g_value_init (&interlace_formats, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002354
bo.xiao857b8682024-09-12 16:40:32 +08002355 /* Try twice - once for NONE, once for INTERLACED. */
2356 for (i = 0; i < G_N_ELEMENTS (formats); i++)
2357 {
2358 memset (&fmt, 0, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002359 fmt.type = v4l2object->type;
2360 fmt.fmt.pix.width = width;
2361 fmt.fmt.pix.height = height;
2362 fmt.fmt.pix.pixelformat = pixelformat;
bo.xiao857b8682024-09-12 16:40:32 +08002363 fmt.fmt.pix.field = formats[i];
xuesong.jiangae1548e2022-05-06 16:38:46 +08002364
bo.xiao857b8682024-09-12 16:40:32 +08002365 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0 &&
2366 gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode)
2367 {
2368 GValue interlace_enum = { 0, };
2369 const gchar *mode_string;
2370 g_value_init (&interlace_enum, G_TYPE_STRING);
2371 mode_string = gst_video_interlace_mode_to_string (interlace_mode);
2372 g_value_set_string (&interlace_enum, mode_string);
2373 gst_value_list_append_and_take_value (&interlace_formats,
2374 &interlace_enum);
2375 prev = interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002376 }
bo.xiao857b8682024-09-12 16:40:32 +08002377 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002378
bo.xiao857b8682024-09-12 16:40:32 +08002379 if (gst_aml_v4l2src_value_simplify (&interlace_formats)
2380 || gst_value_list_get_size (&interlace_formats) > 0)
2381 gst_structure_take_value (s, "interlace-mode", &interlace_formats);
2382 else
2383 GST_WARNING_OBJECT (v4l2object, "Failed to determine interlace mode");
2384
2385 return;
2386}
2387
2388static void
2389gst_aml_v4l2_object_fill_colorimetry_list (GValue * list,
2390 GstVideoColorimetry * cinfo)
2391{
2392 GValue colorimetry = G_VALUE_INIT;
2393 guint size;
2394 guint i;
2395 gboolean found = FALSE;
2396
2397 g_value_init (&colorimetry, G_TYPE_STRING);
2398 g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo));
2399 GST_DEBUG("fill colorimetry:%s into list", gst_video_colorimetry_to_string(cinfo));
2400
2401 /* only insert if no duplicate */
2402 size = gst_value_list_get_size (list);
2403 for (i = 0; i < size; i++)
2404 {
2405 const GValue *tmp;
2406
2407 tmp = gst_value_list_get_value (list, i);
2408 if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002409 {
bo.xiao857b8682024-09-12 16:40:32 +08002410 found = TRUE;
2411 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002412 }
bo.xiao857b8682024-09-12 16:40:32 +08002413 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002414
bo.xiao857b8682024-09-12 16:40:32 +08002415 if (!found)
2416 gst_value_list_append_and_take_value (list, &colorimetry);
2417 else
2418 g_value_unset (&colorimetry);
2419}
xuesong.jiange1a19662022-06-21 20:30:22 +08002420
bo.xiao857b8682024-09-12 16:40:32 +08002421static void
2422gst_aml_v4l2_object_add_colorspace (GstAmlV4l2Object * v4l2object, GstStructure * s,
2423 guint32 width, guint32 height, guint32 pixelformat)
2424{
2425 struct v4l2_format fmt;
2426 GValue list = G_VALUE_INIT;
2427 GstVideoColorimetry cinfo;
2428 enum v4l2_colorspace req_cspace;
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002429
bo.xiao857b8682024-09-12 16:40:32 +08002430 memset (&fmt, 0, sizeof (fmt));
2431 fmt.type = v4l2object->type;
2432 fmt.fmt.pix.width = width;
2433 fmt.fmt.pix.height = height;
2434 fmt.fmt.pix.pixelformat = pixelformat;
xuesong.jiang5c9aca72022-07-12 16:29:24 +08002435
bo.xiao857b8682024-09-12 16:40:32 +08002436 g_value_init (&list, GST_TYPE_LIST);
fei.dengccc89632022-07-15 19:10:17 +08002437
bo.xiao857b8682024-09-12 16:40:32 +08002438 /* step 1: get device default colorspace and insert it first as
2439 * it should be the preferred one */
2440 GST_DEBUG("try for pixl format");
2441 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2442 {
2443 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2444 gst_aml_v4l2_object_fill_colorimetry_list (&list, &cinfo);
2445 }
fei.dengca85b052022-07-19 14:49:23 +08002446
bo.xiao857b8682024-09-12 16:40:32 +08002447 /* step 2: probe all colorspace other than default
2448 * We don't probe all colorspace, range, matrix and transfer combination to
2449 * avoid ioctl flooding which could greatly increase initialization time
2450 * with low-speed devices (UVC...) */
2451 for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
2452 req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++)
2453 {
2454 GST_DEBUG("try for pixl format in while loop :%d", req_cspace);
2455 /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
2456 if (req_cspace == V4L2_COLORSPACE_BT878)
2457 continue;
sheng.liua326d202022-07-20 14:15:34 +08002458
bo.xiao857b8682024-09-12 16:40:32 +08002459 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2460 fmt.fmt.pix_mp.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002461 else
bo.xiao857b8682024-09-12 16:40:32 +08002462 fmt.fmt.pix.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002463
bo.xiao857b8682024-09-12 16:40:32 +08002464 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2465 {
2466 GST_DEBUG("try for pixl format in while loop :%d tried ok", req_cspace);
2467 enum v4l2_colorspace colorspace;
2468
2469 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2470 colorspace = fmt.fmt.pix_mp.colorspace;
2471 else
2472 colorspace = fmt.fmt.pix.colorspace;
2473
2474 if (colorspace == req_cspace)
2475 {
2476 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2477 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2478 }
2479 }
2480 }
2481
2482 GST_DEBUG("deal: caps with colorimetry 2,3,14,7");
2483 cinfo.range = 2;
2484 cinfo.matrix = 3;
2485 cinfo.transfer = 14;
2486 cinfo.primaries = 7;
2487 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2488
2489 GST_DEBUG("deal: caps with colorimetry 2,6,13,7");
2490 cinfo.range = 2;
2491 cinfo.matrix = 6;
2492 cinfo.transfer = 13;
2493 cinfo.primaries = 7;
2494 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2495
2496 GST_DEBUG("deal: caps with colorimetry 2,6,14,7");
2497 cinfo.range = 2;
2498 cinfo.matrix = 6;
2499 cinfo.transfer = 14;
2500 cinfo.primaries = 7;
2501 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2502
2503 GST_DEBUG("deal: caps with colorimetry 2,6,0,7");
2504 cinfo.range = 2;
2505 cinfo.matrix = 6;
2506 cinfo.transfer = 0;
2507 cinfo.primaries = 7;
2508 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2509
2510 GST_DEBUG("deal: caps with colorimetry 0,6,0,7");
2511 cinfo.range = 0;
2512 cinfo.matrix = 6;
2513 cinfo.transfer = 0;
2514 cinfo.primaries = 7;
2515 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2516
2517 GST_DEBUG("deal: caps with colorimetry 2,3,0,0");
2518 cinfo.range = 2;
2519 cinfo.matrix = 3;
2520 cinfo.transfer = 0;
2521 cinfo.primaries = 0;
2522 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2523
2524 GST_DEBUG("deal: caps with colorimetry 2,6,14,0");
2525 cinfo.range = 2;
2526 cinfo.matrix = 6;
2527 cinfo.transfer = 14;
2528 cinfo.primaries = 0;
2529 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2530
2531 if (gst_value_list_get_size (&list) > 0)
2532 gst_structure_take_value (s, "colorimetry", &list);
2533 else
2534 g_value_unset (&list);
2535
2536 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002537}
2538
2539/* The frame interval enumeration code first appeared in Linux 2.6.19. */
2540static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08002541gst_aml_v4l2_object_probe_caps_for_format_and_size (GstAmlV4l2Object * v4l2object,
2542 guint32 pixelformat,
2543 guint32 width, guint32 height, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002544{
bo.xiao857b8682024-09-12 16:40:32 +08002545 gint fd = v4l2object->video_fd;
2546 struct v4l2_frmivalenum ival;
2547 guint32 num, denom;
2548 GstStructure *s;
2549 GValue rates = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002550
bo.xiao857b8682024-09-12 16:40:32 +08002551 memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
2552 ival.index = 0;
2553 ival.pixel_format = pixelformat;
2554 ival.width = width;
2555 ival.height = height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002556
bo.xiao857b8682024-09-12 16:40:32 +08002557 GST_LOG_OBJECT (v4l2object->dbg_obj,
2558 "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
2559 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002560
bo.xiao857b8682024-09-12 16:40:32 +08002561 /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
2562 * fraction to get framerate */
2563 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
2564 goto enum_frameintervals_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002565
bo.xiao857b8682024-09-12 16:40:32 +08002566 if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
2567 {
2568 GValue rate = { 0, };
2569
2570 g_value_init (&rates, GST_TYPE_LIST);
2571 g_value_init (&rate, GST_TYPE_FRACTION);
2572
2573 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002574 {
bo.xiao857b8682024-09-12 16:40:32 +08002575 num = ival.discrete.numerator;
2576 denom = ival.discrete.denominator;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002577
bo.xiao857b8682024-09-12 16:40:32 +08002578 if (num > G_MAXINT || denom > G_MAXINT)
2579 {
2580 /* let us hope we don't get here... */
2581 num >>= 1;
2582 denom >>= 1;
2583 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002584
bo.xiao857b8682024-09-12 16:40:32 +08002585 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
2586 denom, num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002587
bo.xiao857b8682024-09-12 16:40:32 +08002588 /* swap to get the framerate */
2589 gst_value_set_fraction (&rate, denom, num);
2590 gst_value_list_append_value (&rates, &rate);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002591
bo.xiao857b8682024-09-12 16:40:32 +08002592 ival.index++;
2593 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
2594 }
2595 else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
2596 {
2597 GValue min = { 0, };
2598 GValue step = { 0, };
2599 GValue max = { 0, };
2600 gboolean added = FALSE;
2601 guint32 minnum, mindenom;
2602 guint32 maxnum, maxdenom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002603
bo.xiao857b8682024-09-12 16:40:32 +08002604 g_value_init (&rates, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002605
bo.xiao857b8682024-09-12 16:40:32 +08002606 g_value_init (&min, GST_TYPE_FRACTION);
2607 g_value_init (&step, GST_TYPE_FRACTION);
2608 g_value_init (&max, GST_TYPE_FRACTION);
2609
2610 /* get the min */
2611 minnum = ival.stepwise.min.numerator;
2612 mindenom = ival.stepwise.min.denominator;
2613 if (minnum > G_MAXINT || mindenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002614 {
bo.xiao857b8682024-09-12 16:40:32 +08002615 minnum >>= 1;
2616 mindenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002617 }
bo.xiao857b8682024-09-12 16:40:32 +08002618 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
2619 minnum, mindenom);
2620 gst_value_set_fraction (&min, minnum, mindenom);
2621
2622 /* get the max */
2623 maxnum = ival.stepwise.max.numerator;
2624 maxdenom = ival.stepwise.max.denominator;
2625 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002626 {
bo.xiao857b8682024-09-12 16:40:32 +08002627 maxnum >>= 1;
2628 maxdenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002629 }
bo.xiao857b8682024-09-12 16:40:32 +08002630
2631 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
2632 maxnum, maxdenom);
2633 gst_value_set_fraction (&max, maxnum, maxdenom);
2634
2635 /* get the step */
2636 num = ival.stepwise.step.numerator;
2637 denom = ival.stepwise.step.denominator;
2638 if (num > G_MAXINT || denom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002639 {
bo.xiao857b8682024-09-12 16:40:32 +08002640 num >>= 1;
2641 denom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002642 }
2643
bo.xiao857b8682024-09-12 16:40:32 +08002644 if (num == 0 || denom == 0)
2645 {
2646 /* in this case we have a wrong fraction or no step, set the step to max
2647 * so that we only add the min value in the loop below */
2648 num = maxnum;
2649 denom = maxdenom;
2650 }
2651
2652 /* since we only have gst_value_fraction_subtract and not add, negate the
2653 * numerator */
2654 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
2655 num, denom);
2656 gst_value_set_fraction (&step, -num, denom);
2657
2658 while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN)
2659 {
2660 GValue rate = { 0, };
2661
2662 num = gst_value_get_fraction_numerator (&min);
2663 denom = gst_value_get_fraction_denominator (&min);
2664 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
2665 denom, num);
2666
2667 /* invert to get the framerate */
2668 g_value_init (&rate, GST_TYPE_FRACTION);
2669 gst_value_set_fraction (&rate, denom, num);
2670 gst_value_list_append_value (&rates, &rate);
2671 added = TRUE;
2672
2673 /* we're actually adding because step was negated above. This is because
2674 * there is no _add function... */
2675 if (!gst_value_fraction_subtract (&min, &min, &step))
2676 {
2677 GST_WARNING_OBJECT (v4l2object->dbg_obj, "could not step fraction!");
2678 break;
2679 }
2680 }
2681 if (!added)
2682 {
2683 /* no range was added, leave the default range from the template */
2684 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2685 "no range added, leaving default");
2686 g_value_unset (&rates);
2687 }
2688 }
2689 else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
2690 {
2691 guint32 maxnum, maxdenom;
2692
2693 g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
2694
2695 num = ival.stepwise.min.numerator;
2696 denom = ival.stepwise.min.denominator;
2697 if (num > G_MAXINT || denom > G_MAXINT)
2698 {
2699 num >>= 1;
2700 denom >>= 1;
2701 }
2702
2703 maxnum = ival.stepwise.max.numerator;
2704 maxdenom = ival.stepwise.max.denominator;
2705 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2706 {
2707 maxnum >>= 1;
2708 maxdenom >>= 1;
2709 }
2710
2711 GST_LOG_OBJECT (v4l2object->dbg_obj,
2712 "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2713 num);
2714
2715 gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
2716 }
2717 else
2718 {
2719 goto unknown_type;
2720 }
2721
xuesong.jiangae1548e2022-05-06 16:38:46 +08002722return_data:
bo.xiao857b8682024-09-12 16:40:32 +08002723 s = gst_structure_copy (template);
2724 gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
2725 "height", G_TYPE_INT, (gint) height, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002726
bo.xiao857b8682024-09-12 16:40:32 +08002727 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002728
bo.xiao857b8682024-09-12 16:40:32 +08002729 if (!v4l2object->skip_try_fmt_probes)
2730 {
2731 gst_aml_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
2732 pixelformat);
2733 // gst_aml_v4l2_object_add_colorspace(v4l2object, s, width, height, pixelformat);
2734 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002735
bo.xiao857b8682024-09-12 16:40:32 +08002736 if (G_IS_VALUE (&rates))
2737 {
2738 gst_aml_v4l2src_value_simplify (&rates);
2739 /* only change the framerate on the template when we have a valid probed new
2740 * value */
2741 gst_structure_take_value (s, "framerate", &rates);
2742 }
2743 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2744 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2745 {
2746 gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
2747 1, NULL);
2748 }
2749 return s;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002750
bo.xiao857b8682024-09-12 16:40:32 +08002751 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002752enum_frameintervals_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002753 {
2754 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2755 "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2756 GST_FOURCC_ARGS (pixelformat), width, height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002757 goto return_data;
bo.xiao857b8682024-09-12 16:40:32 +08002758 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002759unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08002760 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002761 /* I don't see how this is actually an error, we ignore the format then */
bo.xiao857b8682024-09-12 16:40:32 +08002762 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2763 "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2764 GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002765 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +08002766 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002767}
2768
2769static gint
bo.xiao857b8682024-09-12 16:40:32 +08002770sort_by_frame_size (GstStructure * s1, GstStructure * s2)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002771{
bo.xiao857b8682024-09-12 16:40:32 +08002772 int w1, h1, w2, h2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002773
bo.xiao857b8682024-09-12 16:40:32 +08002774 gst_structure_get_int (s1, "width", &w1);
2775 gst_structure_get_int (s1, "height", &h1);
2776 gst_structure_get_int (s2, "width", &w2);
2777 gst_structure_get_int (s2, "height", &h2);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002778
bo.xiao857b8682024-09-12 16:40:32 +08002779 /* I think it's safe to assume that this won't overflow for a while */
2780 return ((w2 * h2) - (w1 * h1));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002781}
2782
2783static void
bo.xiao857b8682024-09-12 16:40:32 +08002784gst_aml_v4l2_object_update_and_append (GstAmlV4l2Object * v4l2object,
2785 guint32 format, GstCaps * caps, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002786{
bo.xiao857b8682024-09-12 16:40:32 +08002787 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002788
bo.xiao857b8682024-09-12 16:40:32 +08002789 /* Encoded stream on output buffer need to be parsed */
2790 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
2791 v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2792 {
2793 gint i = 0;
2794
2795 for (; i < GST_AML_V4L2_FORMAT_COUNT; i++)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002796 {
bo.xiao857b8682024-09-12 16:40:32 +08002797 if (format == gst_aml_v4l2_formats[i].format &&
2798 gst_aml_v4l2_formats[i].flags & GST_V4L2_CODEC &&
2799 !(gst_aml_v4l2_formats[i].flags & GST_V4L2_NO_PARSE))
2800 {
2801 gst_structure_set (s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2802 break;
2803 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002804 }
bo.xiao857b8682024-09-12 16:40:32 +08002805 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002806
bo.xiao857b8682024-09-12 16:40:32 +08002807 if (v4l2object->has_alpha_component &&
2808 (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2809 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
2810 {
2811 switch (format)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002812 {
bo.xiao857b8682024-09-12 16:40:32 +08002813 case V4L2_PIX_FMT_RGB32:
2814 alt_s = gst_structure_copy (s);
2815 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
2816 break;
2817 case V4L2_PIX_FMT_BGR32:
2818 alt_s = gst_structure_copy (s);
2819 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
2820 break;
2821 default:
2822 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002823 }
bo.xiao857b8682024-09-12 16:40:32 +08002824 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002825
bo.xiao857b8682024-09-12 16:40:32 +08002826 gst_caps_append_structure(caps, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002827
bo.xiao857b8682024-09-12 16:40:32 +08002828 if (alt_s)
2829 gst_caps_append_structure(caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002830}
2831
2832static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08002833gst_aml_v4l2_object_probe_caps_for_format (GstAmlV4l2Object * v4l2object,
2834 guint32 pixelformat, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002835{
bo.xiao857b8682024-09-12 16:40:32 +08002836 GstCaps *ret = gst_caps_new_empty ();
2837 GstStructure *tmp;
2838 gint fd = v4l2object->video_fd;
2839 struct v4l2_frmsizeenum size;
2840 GList *results = NULL;
2841 guint32 w, h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002842
bo.xiao857b8682024-09-12 16:40:32 +08002843 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
2844 {
2845 gst_caps_append_structure (ret, gst_structure_copy (template));
2846 return ret;
2847 }
2848
2849 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
2850 size.index = 0;
2851 size.pixel_format = pixelformat;
2852
2853 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2854 "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2855 GST_FOURCC_ARGS (pixelformat));
2856
2857 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2858 goto enum_framesizes_failed;
2859
2860 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
2861 {
2862 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002863 {
bo.xiao857b8682024-09-12 16:40:32 +08002864 GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
2865 size.discrete.width, size.discrete.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002866
bo.xiao857b8682024-09-12 16:40:32 +08002867 w = MIN (size.discrete.width, G_MAXINT);
2868 h = MIN (size.discrete.height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002869
bo.xiao857b8682024-09-12 16:40:32 +08002870 if (w && h)
2871 {
2872 tmp =
2873 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2874 pixelformat, w, h, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002875
bo.xiao857b8682024-09-12 16:40:32 +08002876 if (tmp)
2877 results = g_list_prepend (results, tmp);
2878 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002879
bo.xiao857b8682024-09-12 16:40:32 +08002880 size.index++;
2881 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2882 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2883 "done iterating discrete frame sizes");
2884 }
2885 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
2886 {
2887 guint32 maxw, maxh, step_w, step_h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002888
bo.xiao857b8682024-09-12 16:40:32 +08002889 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have stepwise frame sizes:");
2890 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2891 size.stepwise.min_width);
2892 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2893 size.stepwise.min_height);
2894 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2895 size.stepwise.max_width);
2896 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2897 size.stepwise.max_height);
2898 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step width: %d",
2899 size.stepwise.step_width);
2900 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step height: %d",
2901 size.stepwise.step_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002902
fei.dengf21a6c92024-09-05 11:30:36 +08002903 if (pixelformat == V4L2_PIX_FMT_NV12 ||
2904 pixelformat == V4L2_PIX_FMT_NV21 ||
2905 pixelformat == V4L2_PIX_FMT_NV12M ||
2906 pixelformat == V4L2_PIX_FMT_NV21M) {
2907 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2908 "set %" GST_FOURCC_FORMAT " min width and height to 16",
2909 GST_FOURCC_ARGS(pixelformat));
2910 w = 16;
2911 h = 16;
2912 } else {
2913 w = MAX(size.stepwise.min_width, 1);
2914 h = MAX(size.stepwise.min_height, 1);
2915 }
bo.xiao857b8682024-09-12 16:40:32 +08002916 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2917 maxh = MIN (size.stepwise.max_height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002918
bo.xiao857b8682024-09-12 16:40:32 +08002919 /* in this position,updating resolution only to pass the negotiation
2920 * actually, the details about resolution refer to function:
2921 * gst_aml_v4l2_object_set_format_full for checking.
2922 */
2923 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "update maxw_maxh to MAX(maxw,maxh)_MAX(maxw,maxh)");
2924 maxh = MAX (maxw, maxh);
2925 maxw = maxh;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00002926
bo.xiao857b8682024-09-12 16:40:32 +08002927 step_w = MAX (size.stepwise.step_width, 1);
2928 step_h = MAX (size.stepwise.step_height, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002929
bo.xiao857b8682024-09-12 16:40:32 +08002930 /* FIXME: check for sanity and that min/max are multiples of the steps */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002931
bo.xiao857b8682024-09-12 16:40:32 +08002932 /* we only query details for the max width/height since it's likely the
2933 * most restricted if there are any resolution-dependent restrictions */
2934 tmp = gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2935 pixelformat, maxw, maxh, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002936
bo.xiao857b8682024-09-12 16:40:32 +08002937 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002938 {
bo.xiao857b8682024-09-12 16:40:32 +08002939 GValue step_range = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002940
bo.xiao857b8682024-09-12 16:40:32 +08002941 g_value_init (&step_range, GST_TYPE_INT_RANGE);
2942 gst_value_set_int_range_step (&step_range, w, maxw, step_w);
2943 gst_structure_set_value (tmp, "width", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002944
bo.xiao857b8682024-09-12 16:40:32 +08002945 gst_value_set_int_range_step (&step_range, h, maxh, step_h);
2946 gst_structure_take_value (tmp, "height", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002947
bo.xiao857b8682024-09-12 16:40:32 +08002948 /* no point using the results list here, since there's only one struct */
2949 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002950 }
bo.xiao857b8682024-09-12 16:40:32 +08002951 }
2952 else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
2953 {
2954 guint32 maxw, maxh;
2955
2956 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have continuous frame sizes:");
2957 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2958 size.stepwise.min_width);
2959 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2960 size.stepwise.min_height);
2961 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2962 size.stepwise.max_width);
2963 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2964 size.stepwise.max_height);
2965
2966 w = MAX (size.stepwise.min_width, 1);
2967 h = MAX (size.stepwise.min_height, 1);
2968 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2969 maxh = MIN (size.stepwise.max_height, G_MAXINT);
2970
2971 tmp =
2972 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
2973 w, h, template);
2974 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002975 {
bo.xiao857b8682024-09-12 16:40:32 +08002976 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
2977 (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
2978 NULL);
2979
2980 /* no point using the results list here, since there's only one struct */
2981 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002982 }
bo.xiao857b8682024-09-12 16:40:32 +08002983 }
2984 else
2985 {
2986 goto unknown_type;
2987 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002988
bo.xiao857b8682024-09-12 16:40:32 +08002989 /* we use an intermediary list to store and then sort the results of the
2990 * probing because we can't make any assumptions about the order in which
2991 * the driver will give us the sizes, but we want the final caps to contain
2992 * the results starting with the highest resolution and having the lowest
2993 * resolution last, since order in caps matters for things like fixation. */
2994 results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
2995 while (results != NULL)
2996 {
2997 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret,
2998 results->data);
2999 results = g_list_delete_link (results, results);
3000 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003001
bo.xiao857b8682024-09-12 16:40:32 +08003002 if (gst_caps_is_empty (ret))
3003 goto enum_framesizes_no_results;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003004
bo.xiao857b8682024-09-12 16:40:32 +08003005 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003006
bo.xiao857b8682024-09-12 16:40:32 +08003007 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003008enum_framesizes_failed:
bo.xiao857b8682024-09-12 16:40:32 +08003009 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003010 /* I don't see how this is actually an error */
bo.xiao857b8682024-09-12 16:40:32 +08003011 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3012 "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
3013 " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003014 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003015 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003016enum_framesizes_no_results:
bo.xiao857b8682024-09-12 16:40:32 +08003017 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003018 /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
3019 * question doesn't actually support it yet */
bo.xiao857b8682024-09-12 16:40:32 +08003020 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3021 "No results for pixelformat %" GST_FOURCC_FORMAT
3022 " enumerating frame sizes, trying fallback",
3023 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003024 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003025 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003026unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08003027 {
3028 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3029 "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
3030 ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003031 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003032 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003033
3034default_frame_sizes:
bo.xiao857b8682024-09-12 16:40:32 +08003035 {
bo.xiao34e36202024-07-17 16:04:01 +08003036 gint min_w, max_w, min_h, max_h;
3037
3038#ifdef DELETE_FOR_LGE
3039 gint fix_num = 0, fix_denom = 0;
3040#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08003041
3042 /* This code is for Linux < 2.6.19 */
3043 min_w = min_h = 1;
3044 max_w = max_h = GST_AML_V4L2_MAX_SIZE;
bo.xiao857b8682024-09-12 16:40:32 +08003045 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
3046 &min_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003047 {
bo.xiao857b8682024-09-12 16:40:32 +08003048 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3049 "Could not probe minimum capture size for pixelformat %"
3050 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003051 }
bo.xiao857b8682024-09-12 16:40:32 +08003052 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
3053 &max_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003054 {
bo.xiao857b8682024-09-12 16:40:32 +08003055 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3056 "Could not probe maximum capture size for pixelformat %"
3057 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003058 }
3059
bo.xiao857b8682024-09-12 16:40:32 +08003060
3061 tmp = gst_structure_copy (template);
hanghang.luo3128f102022-08-18 10:36:19 +08003062#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08003063 if (fix_num)
3064 {
bo.xiao857b8682024-09-12 16:40:32 +08003065 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
3066 fix_denom, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003067 }
hanghang.luo3128f102022-08-18 10:36:19 +08003068 else
3069#endif
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003070 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
3071 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003072 {
bo.xiao857b8682024-09-12 16:40:32 +08003073 /* if norm can't be used, copy the template framerate */
3074 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
3075 G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003076 }
3077
3078 if (min_w == max_w)
bo.xiao857b8682024-09-12 16:40:32 +08003079 gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003080 else
bo.xiao857b8682024-09-12 16:40:32 +08003081 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003082
3083 if (min_h == max_h)
bo.xiao857b8682024-09-12 16:40:32 +08003084 gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003085 else
bo.xiao857b8682024-09-12 16:40:32 +08003086 gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003087
bo.xiao857b8682024-09-12 16:40:32 +08003088 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003089
3090 if (!v4l2object->skip_try_fmt_probes)
3091 {
bo.xiao857b8682024-09-12 16:40:32 +08003092 /* We could consider setting interlace mode from min and max. */
3093 gst_aml_v4l2_object_add_interlace_mode(v4l2object, tmp, max_w, max_h,
3094 pixelformat);
3095 /* We could consider to check colorspace for min too, in case it depends on
3096 * the size. But in this case, min and max could not be enough */
3097 gst_aml_v4l2_object_add_colorspace(v4l2object, tmp, max_w, max_h,
3098 pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003099 }
3100
bo.xiao857b8682024-09-12 16:40:32 +08003101 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003102 return ret;
bo.xiao857b8682024-09-12 16:40:32 +08003103 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003104}
3105
3106static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003107gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
3108 guint32 pixelformat, gint * width, gint * height)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003109{
bo.xiao857b8682024-09-12 16:40:32 +08003110 struct v4l2_format fmt;
3111 gboolean ret = FALSE;
3112 GstVideoInterlaceMode interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003113
bo.xiao857b8682024-09-12 16:40:32 +08003114 g_return_val_if_fail (width != NULL, FALSE);
3115 g_return_val_if_fail (height != NULL, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003116
bo.xiao857b8682024-09-12 16:40:32 +08003117 GST_LOG_OBJECT (v4l2object->dbg_obj,
3118 "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
3119 *width, *height, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003120
bo.xiao857b8682024-09-12 16:40:32 +08003121 memset (&fmt, 0, sizeof (struct v4l2_format));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003122
bo.xiao857b8682024-09-12 16:40:32 +08003123 /* get size delimiters */
3124 memset (&fmt, 0, sizeof (fmt));
3125 fmt.type = v4l2object->type;
3126 fmt.fmt.pix.width = *width;
3127 fmt.fmt.pix.height = *height;
3128 fmt.fmt.pix.pixelformat = pixelformat;
3129 fmt.fmt.pix.field = V4L2_FIELD_ANY;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003130
bo.xiao857b8682024-09-12 16:40:32 +08003131 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
3132 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003133
bo.xiao857b8682024-09-12 16:40:32 +08003134 GST_LOG_OBJECT (v4l2object->dbg_obj,
3135 "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003136
bo.xiao857b8682024-09-12 16:40:32 +08003137 *width = fmt.fmt.pix.width;
3138 *height = fmt.fmt.pix.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003139
bo.xiao857b8682024-09-12 16:40:32 +08003140 if (!gst_aml_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode))
3141 {
3142 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3143 "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
3144 GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
3145 goto error;
3146 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003147
bo.xiao857b8682024-09-12 16:40:32 +08003148 ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003149
3150error:
bo.xiao857b8682024-09-12 16:40:32 +08003151 if (!ret)
3152 {
3153 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3154 "Unable to try format: %s", g_strerror (errno));
3155 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003156
bo.xiao857b8682024-09-12 16:40:32 +08003157 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003158}
3159
3160static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003161gst_aml_v4l2_object_is_dmabuf_supported (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003162{
bo.xiao857b8682024-09-12 16:40:32 +08003163 gboolean ret = TRUE;
3164 struct v4l2_exportbuffer expbuf = {
3165 .type = v4l2object->type,
3166 .index = -1,
3167 .plane = -1,
3168 .flags = O_CLOEXEC | O_RDWR,
3169 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003170
bo.xiao857b8682024-09-12 16:40:32 +08003171 if (v4l2object->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
3172 {
3173 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3174 "libv4l2 converter detected, disabling DMABuf");
3175 ret = FALSE;
3176 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003177
bo.xiao857b8682024-09-12 16:40:32 +08003178 /* Expected to fail, but ENOTTY tells us that it is not implemented. */
3179 v4l2object->ioctl (v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
3180 if (errno == ENOTTY)
3181 ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003182
bo.xiao857b8682024-09-12 16:40:32 +08003183 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003184}
3185
3186static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003187gst_aml_v4l2_object_setup_pool (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003188{
bo.xiao857b8682024-09-12 16:40:32 +08003189 GstAmlV4l2IOMode mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003190
bo.xiao857b8682024-09-12 16:40:32 +08003191 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "initializing the %s system",
3192 V4L2_TYPE_IS_OUTPUT (v4l2object->type) ? "output" : "capture");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003193
bo.xiao857b8682024-09-12 16:40:32 +08003194 GST_AML_V4L2_CHECK_OPEN (v4l2object);
3195 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003196
bo.xiao857b8682024-09-12 16:40:32 +08003197 /* find transport */
3198 mode = v4l2object->req_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003199
bo.xiao857b8682024-09-12 16:40:32 +08003200 if (v4l2object->device_caps & V4L2_CAP_READWRITE)
3201 {
3202 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3203 mode = GST_V4L2_IO_RW;
3204 }
3205 else if (v4l2object->req_mode == GST_V4L2_IO_RW)
3206 goto method_not_supported;
3207
3208 if (v4l2object->device_caps & V4L2_CAP_STREAMING)
3209 {
3210 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003211 {
bo.xiao857b8682024-09-12 16:40:32 +08003212 if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
3213 gst_aml_v4l2_object_is_dmabuf_supported (v4l2object))
3214 {
3215 mode = GST_V4L2_IO_DMABUF;
3216 }
3217 else
3218 {
3219 mode = GST_V4L2_IO_MMAP;
3220 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003221 }
bo.xiao857b8682024-09-12 16:40:32 +08003222 }
3223 else if (v4l2object->req_mode == GST_V4L2_IO_MMAP ||
3224 v4l2object->req_mode == GST_V4L2_IO_DMABUF)
3225 goto method_not_supported;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003226
bo.xiao857b8682024-09-12 16:40:32 +08003227 /* if still no transport selected, error out */
3228 if (mode == GST_V4L2_IO_AUTO)
3229 goto no_supported_capture_method;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003230
bo.xiao857b8682024-09-12 16:40:32 +08003231 GST_INFO_OBJECT (v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
3232 v4l2object->mode = mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003233
bo.xiao857b8682024-09-12 16:40:32 +08003234 /* If min_buffers is not set, the driver either does not support the control or
3235 it has not been asked yet via propose_allocation/decide_allocation. */
3236 if (!v4l2object->min_buffers)
3237 gst_aml_v4l2_get_driver_min_buffers (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003238
bo.xiao857b8682024-09-12 16:40:32 +08003239 /* Map the buffers */
3240 GST_LOG_OBJECT (v4l2object->dbg_obj, "initiating buffer pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003241
3242 if (!(v4l2object->pool = gst_aml_v4l2_buffer_pool_new(v4l2object, caps)))
bo.xiao857b8682024-09-12 16:40:32 +08003243 goto buffer_pool_new_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003244
bo.xiao857b8682024-09-12 16:40:32 +08003245 GST_AML_V4L2_SET_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003246
bo.xiao857b8682024-09-12 16:40:32 +08003247 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003248
bo.xiao857b8682024-09-12 16:40:32 +08003249 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003250buffer_pool_new_failed:
bo.xiao857b8682024-09-12 16:40:32 +08003251 {
3252 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3253 (_("Could not map buffers from device '%s'"),
3254 v4l2object->videodev),
3255 ("Failed to create buffer pool: %s", g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003256 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003257 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003258method_not_supported:
bo.xiao857b8682024-09-12 16:40:32 +08003259 {
3260 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3261 (_("The driver of device '%s' does not support the IO method %d"),
3262 v4l2object->videodev, mode), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003263 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003264 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003265no_supported_capture_method:
bo.xiao857b8682024-09-12 16:40:32 +08003266 {
3267 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3268 (_("The driver of device '%s' does not support any known IO "
3269 "method."), v4l2object->videodev), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003270 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003271 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003272}
3273
3274static void
bo.xiao857b8682024-09-12 16:40:32 +08003275gst_aml_v4l2_object_set_stride (GstVideoInfo * info, GstVideoAlignment * align,
3276 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003277{
bo.xiao857b8682024-09-12 16:40:32 +08003278 const GstVideoFormatInfo *finfo = info->finfo;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003279
bo.xiao857b8682024-09-12 16:40:32 +08003280 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3281 {
3282 gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003283
bo.xiao857b8682024-09-12 16:40:32 +08003284 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
3285 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3286 tile_height = 1 << hs;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003287
bo.xiao857b8682024-09-12 16:40:32 +08003288 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
3289 info->height + align->padding_top + align->padding_bottom);
3290 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003291
bo.xiao857b8682024-09-12 16:40:32 +08003292 x_tiles = stride >> ws;
3293 y_tiles = padded_height >> hs;
3294 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
3295 }
3296 else
3297 {
3298 info->stride[plane] = stride;
3299 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003300}
3301
3302static void
bo.xiao857b8682024-09-12 16:40:32 +08003303gst_aml_v4l2_object_extrapolate_info (GstAmlV4l2Object * v4l2object,
3304 GstVideoInfo * info, GstVideoAlignment * align, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003305{
bo.xiao857b8682024-09-12 16:40:32 +08003306 const GstVideoFormatInfo *finfo = info->finfo;
3307 gint i, estride, padded_height;
3308 gsize offs = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003309
bo.xiao857b8682024-09-12 16:40:32 +08003310 g_return_if_fail (v4l2object->n_v4l2_planes == 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003311
bo.xiao857b8682024-09-12 16:40:32 +08003312 padded_height = info->height + align->padding_top + align->padding_bottom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003313
bo.xiao857b8682024-09-12 16:40:32 +08003314 for (i = 0; i < finfo->n_planes; i++)
3315 {
3316 estride = gst_aml_v4l2_object_extrapolate_stride (finfo, i, stride);
3317
3318 gst_aml_v4l2_object_set_stride (info, align, i, estride);
3319
3320 info->offset[i] = offs;
3321 offs += estride *
3322 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, padded_height);
3323
3324 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3325 "Extrapolated for plane %d with base stride %d: "
3326 "stride %d, offset %" G_GSIZE_FORMAT, i, stride, info->stride[i],
3327 info->offset[i]);
3328 }
3329
3330 /* Update the image size according the amount of data we are going to
3331 * read/write. This workaround bugs in driver where the sizeimage provided
3332 * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
3333 * bytesused (buffer size). */
3334 if (offs < info->size)
3335 info->size = offs;
3336}
3337
3338static void
3339gst_aml_v4l2_object_save_format (GstAmlV4l2Object * v4l2object,
3340 struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
3341 GstVideoInfo * info, GstVideoAlignment * align)
3342{
3343 const GstVideoFormatInfo *finfo = info->finfo;
3344 gboolean standard_stride = TRUE;
3345 gint stride, pstride, padded_width, padded_height, i;
3346
3347 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED)
3348 {
3349 v4l2object->n_v4l2_planes = 1;
3350 info->size = format->fmt.pix.sizeimage;
3351 goto store_info;
3352 }
3353
3354 /* adjust right padding */
3355 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3356 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3357 else
3358 stride = format->fmt.pix.bytesperline;
3359
3360 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (finfo, 0);
3361 if (pstride)
3362 {
3363 padded_width = stride / pstride;
3364 }
3365 else
3366 {
3367 /* pstride can be 0 for complex formats */
3368 GST_WARNING_OBJECT (v4l2object->element,
3369 "format %s has a pstride of 0, cannot compute padded with",
3370 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
3371 padded_width = stride;
3372 }
3373
3374 if (padded_width < format->fmt.pix.width)
3375 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3376 "Driver bug detected, stride (%d) is too small for the width (%d)",
3377 padded_width, format->fmt.pix.width);
3378
3379 align->padding_right = padded_width - info->width - align->padding_left;
3380
3381 /* adjust bottom padding */
3382 padded_height = format->fmt.pix.height;
3383
3384 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3385 {
3386 guint hs, tile_height;
3387
3388 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3389 tile_height = 1 << hs;
3390
3391 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
3392 }
3393
3394 align->padding_bottom = padded_height - info->height - align->padding_top;
3395
3396 /* setup the strides and offset */
3397 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3398 {
3399 struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
3400
3401 /* figure out the frame layout */
3402 v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes);
3403 info->size = 0;
3404 for (i = 0; i < v4l2object->n_v4l2_planes; i++)
3405 {
3406 stride = pix_mp->plane_fmt[i].bytesperline;
3407
3408 if (info->stride[i] != stride)
3409 standard_stride = FALSE;
3410
3411 gst_aml_v4l2_object_set_stride (info, align, i, stride);
3412 info->offset[i] = info->size;
3413 info->size += pix_mp->plane_fmt[i].sizeimage;
3414 }
3415
3416 /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
3417 if (v4l2object->n_v4l2_planes < finfo->n_planes)
3418 {
3419 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3420 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3421 }
3422 }
3423 else
3424 {
3425 /* only one plane in non-MPLANE mode */
3426 v4l2object->n_v4l2_planes = 1;
3427 info->size = format->fmt.pix.sizeimage;
3428 stride = format->fmt.pix.bytesperline;
3429
3430 if (info->stride[0] != stride)
3431 standard_stride = FALSE;
3432
3433 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3434 }
3435
3436 /* adjust the offset to take into account left and top */
3437 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3438 {
3439 if ((align->padding_left + align->padding_top) > 0)
3440 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3441 "Left and top padding is not permitted for tiled formats");
3442 }
3443 else
3444 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003445 for (i = 0; i < finfo->n_planes; i++)
3446 {
bo.xiao857b8682024-09-12 16:40:32 +08003447 gint vedge, hedge;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003448
bo.xiao857b8682024-09-12 16:40:32 +08003449 /* FIXME we assume plane as component as this is true for all supported
3450 * format we support. */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003451
bo.xiao857b8682024-09-12 16:40:32 +08003452 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, align->padding_left);
3453 vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, align->padding_top);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003454
bo.xiao857b8682024-09-12 16:40:32 +08003455 info->offset[i] += (vedge * info->stride[i]) +
3456 (hedge * GST_VIDEO_INFO_COMP_PSTRIDE (info, i));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003457 }
bo.xiao857b8682024-09-12 16:40:32 +08003458 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003459
3460store_info:
bo.xiao857b8682024-09-12 16:40:32 +08003461 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
3462 info->size);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003463
bo.xiao857b8682024-09-12 16:40:32 +08003464 /* to avoid copies we need video meta if there is padding */
3465 v4l2object->need_video_meta =
3466 ((align->padding_top + align->padding_left + align->padding_right +
xuesong.jiangae1548e2022-05-06 16:38:46 +08003467 align->padding_bottom) != 0);
3468
bo.xiao857b8682024-09-12 16:40:32 +08003469 /* ... or if stride is non "standard" */
3470 if (!standard_stride)
3471 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003472
bo.xiao857b8682024-09-12 16:40:32 +08003473 /* ... or also video meta if we use multiple, non-contiguous, planes */
3474 if (v4l2object->n_v4l2_planes > 1)
3475 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003476
bo.xiao857b8682024-09-12 16:40:32 +08003477 v4l2object->info = *info;
3478 v4l2object->align = *align;
3479 v4l2object->format = *format;
3480 v4l2object->fmtdesc = fmtdesc;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003481
bo.xiao857b8682024-09-12 16:40:32 +08003482 /* if we have a framerate pre-calculate duration */
3483 if (info->fps_n > 0 && info->fps_d > 0)
3484 {
3485 v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
3486 info->fps_n);
3487 }
3488 else
3489 {
3490 v4l2object->duration = GST_CLOCK_TIME_NONE;
3491 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003492}
3493
bo.xiao857b8682024-09-12 16:40:32 +08003494gint
3495gst_aml_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
3496 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003497{
bo.xiao857b8682024-09-12 16:40:32 +08003498 gint estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003499
bo.xiao857b8682024-09-12 16:40:32 +08003500 switch (finfo->format)
3501 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003502 case GST_VIDEO_FORMAT_NV12:
3503 case GST_VIDEO_FORMAT_NV12_64Z32:
3504 case GST_VIDEO_FORMAT_NV21:
3505 case GST_VIDEO_FORMAT_NV16:
3506 case GST_VIDEO_FORMAT_NV61:
3507 case GST_VIDEO_FORMAT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08003508 estride = (plane == 0 ? 1 : 2) *
3509 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3510 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003511 default:
bo.xiao857b8682024-09-12 16:40:32 +08003512 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3513 break;
3514 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003515
bo.xiao857b8682024-09-12 16:40:32 +08003516 return estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003517}
3518
3519static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003520gst_aml_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
xuesong.jiangae1548e2022-05-06 16:38:46 +08003521 const gchar *color)
3522{
bo.xiao857b8682024-09-12 16:40:32 +08003523 GstVideoColorimetry ci;
3524 static const GstVideoColorimetry ci_likely_jpeg = {
3525 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3526 GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN
3527 };
3528 static const GstVideoColorimetry ci_jpeg = {
3529 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3530 GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709
3531 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003532
bo.xiao857b8682024-09-12 16:40:32 +08003533 if (!gst_video_colorimetry_from_string(&ci, color))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003534 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003535
3536 if (gst_video_colorimetry_is_equal(&ci, cinfo))
3537 return TRUE;
3538
3539 /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */
3540 if (gst_video_colorimetry_is_equal(&ci, &ci_likely_jpeg) && gst_video_colorimetry_is_equal(cinfo, &ci_jpeg))
3541 return TRUE;
3542
3543 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003544}
3545
hanghang.luoe80a8882024-11-29 17:02:12 +08003546static gboolean needSpecConfigForFg (GstAmlV4l2Object *v4l2object)
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003547{
bo.xiao857b8682024-09-12 16:40:32 +08003548 gboolean result= FALSE;
3549 int fd = -1;
3550 char valstr[64];
3551 const char* path= "/sys/class/video/film_grain_support";
3552 uint32_t val= 0;
3553 struct v4l2_control ctl;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003554
bo.xiao857b8682024-09-12 16:40:32 +08003555 GST_LOG("configForFilmGrain: enter");
3556 fd = open(path, O_RDONLY|O_CLOEXEC);
3557 if ( fd < 0 )
3558 {
3559 GST_DEBUG("unable to open file (%s)", path);
3560 goto exit;
3561 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003562
bo.xiao857b8682024-09-12 16:40:32 +08003563 memset(valstr, 0, sizeof(valstr));
3564 if (read(fd, valstr, sizeof(valstr) - 1) == -1 )
3565 {
3566 GST_DEBUG("unable to read fg flag");
3567 goto exit;
3568 }
bo.xiao34e36202024-07-17 16:04:01 +08003569
bo.xiao857b8682024-09-12 16:40:32 +08003570 valstr[strlen(valstr)] = '\0';
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003571
bo.xiao857b8682024-09-12 16:40:32 +08003572 if ( sscanf(valstr, "%u", &val) < 1)
3573 {
3574 GST_DEBUG("unable to get flag from: (%s)", valstr);
3575 goto exit;
3576 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003577
bo.xiao857b8682024-09-12 16:40:32 +08003578 GST_LOG("got film_grain_support:%d from node", val);
3579 if (val != 0)
3580 {
3581 goto exit;
3582 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003583
bo.xiao857b8682024-09-12 16:40:32 +08003584 memset( &ctl, 0, sizeof(ctl));
bo.xiao4ef6d272024-10-15 16:18:25 +08003585 ctl.id = AML_V4L2_GET_FILMGRAIN_INFO;
3586 v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CTRL, &ctl);
bo.xiao857b8682024-09-12 16:40:32 +08003587 GST_LOG("got VIDIOC_G_CTRL value: %d", ctl.value);
3588 if (ctl.value == 0)
3589 {
3590 goto exit;
3591 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003592
bo.xiao857b8682024-09-12 16:40:32 +08003593 result= TRUE;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003594
3595exit:
bo.xiao857b8682024-09-12 16:40:32 +08003596 if ( fd >= 0 )
3597 {
3598 close(fd);
3599 }
3600 GST_LOG("configForFilmGrain: exit: result %d", result);
3601 return result;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003602}
hanghang.luobfc63f82024-07-05 11:04:56 +08003603
3604static gboolean
hanghang.luoe80a8882024-11-29 17:02:12 +08003605get_amlogic_vdec_parm (GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm)
hanghang.luobfc63f82024-07-05 11:04:56 +08003606{
bo.xiao857b8682024-09-12 16:40:32 +08003607 struct v4l2_ext_control control;
3608 struct v4l2_ext_controls ctrls;
3609 gboolean use_ext_config = FALSE;
3610 int major = 0,minor = 0;
3611 struct utsname info;
3612 struct aml_dec_params *pdecParm = (struct aml_dec_params *)streamparm->parm.raw_data;
bo.xiao7659cda2024-07-18 16:16:50 +08003613
bo.xiao857b8682024-09-12 16:40:32 +08003614 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3615 {
3616 GST_DEBUG("get linux version failed");
3617 return FALSE;
3618 }
3619 GST_DEBUG("linux major version %d %d", major,minor);
3620 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003621
bo.xiao857b8682024-09-12 16:40:32 +08003622 if (use_ext_config)
3623 {
3624 memset(&ctrls, 0, sizeof(ctrls));
3625 memset(&control, 0, sizeof(control));
3626 control.id = AML_V4L2_DEC_PARMS_CONFIG;
3627 control.ptr = pdecParm;
3628 control.size = sizeof(struct aml_dec_params);
3629 ctrls.count = 1;
3630 ctrls.controls = &control;
3631 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls ) <0)
3632 {
3633 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3634 return FALSE;
3635 }
3636 GST_DEBUG("dw: %d, flag: %d, status: %d, margin: %d",pdecParm->cfg.double_write_mode,
3637 pdecParm->cfg.metadata_config_flag, pdecParm->parms_status, pdecParm->cfg.ref_buf_margin);
3638 }
3639 else
3640 {
3641 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, streamparm) < 0)
3642 {
3643 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3644 return FALSE;
3645 }
3646 }
3647 return TRUE;
hanghang.luobfc63f82024-07-05 11:04:56 +08003648}
3649
hanghang.luoe80a8882024-11-29 17:02:12 +08003650static gboolean check_env_valid (const char * env)
3651{
3652 if (env)
3653 return (1 == atoi(env) || g_str_equal("TRUE",env) || g_str_equal("true",env));
3654 return FALSE;
3655}
3656
hanghang.luo7765f172024-12-19 17:07:09 +08003657static int gst_aml_config_dw_for_hevc_core (gboolean low_mem, gboolean interlace, gboolean pip, guint32 pixFormat)
hanghang.luoe80a8882024-11-29 17:02:12 +08003658{
3659 const char *env_4k;
3660 const char *env_de_counter;
3661 const char *env_ai_pq;
3662 int double_write = VDEC_DW_AFBC_AUTO_1_16;
3663
3664 if (interlace)
3665 {
hanghang.luo7765f172024-12-19 17:07:09 +08003666 if (V4L2_PIX_FMT_HEVC == pixFormat)
3667 {
3668 double_write = VDEC_DW_AFBC_1_1_DW;
3669 //need to cfg according to 8bit or 10bit in the future
3670 }
3671 else
3672 {
3673 double_write = VDEC_DW_NO_AFBC;
3674 }
3675 GST_DEBUG ("interlace set DW=%d for hevc core", double_write);
hanghang.luoe80a8882024-11-29 17:02:12 +08003676 return double_write;
3677 }
3678
3679 if (low_mem)
3680 {
3681 double_write = VDEC_DW_AFBC_ONLY;
hanghang.luo7765f172024-12-19 17:07:09 +08003682 GST_DEBUG ("low mem set DW=%d for hevc core", double_write);
hanghang.luoe80a8882024-11-29 17:02:12 +08003683 return double_write;
3684 }
3685
3686 env_4k = getenv("V4L2_SET_AMLOGIC_4K");
3687 env_de_counter = getenv("V4L2_SET_AMLOGIC_DE_COUNTER");
3688 env_ai_pq = getenv("V4L2_SET_AMLOGIC_AI_PQ");
3689
3690 if (!check_env_valid(env_4k) && !check_env_valid(env_de_counter) && !check_env_valid (env_ai_pq) && !pip)
3691 double_write = VDEC_DW_AFBC_x2_1_4_DW;
3692
hanghang.luo7765f172024-12-19 17:07:09 +08003693 GST_DEBUG ("default set DW=%d for hevc core", double_write);
hanghang.luoe80a8882024-11-29 17:02:12 +08003694 return double_write;
3695}
3696
3697static int gst_aml_config_dw (GstAmlV4l2Object *v4l2object, guint32 pixFormat, guint width, guint height, gboolean interlace)
bo.xiao34e36202024-07-17 16:04:01 +08003698{
bo.xiao857b8682024-09-12 16:40:32 +08003699 const char *env_dw;
3700 int double_write = VDEC_DW_NO_AFBC;
bo.xiao34e36202024-07-17 16:04:01 +08003701
bo.xiao857b8682024-09-12 16:40:32 +08003702 switch (pixFormat)
3703 {
hanghang.luoe80a8882024-11-29 17:02:12 +08003704 // for vdec core
bo.xiao857b8682024-09-12 16:40:32 +08003705 case V4L2_PIX_FMT_MPEG:
3706 case V4L2_PIX_FMT_MPEG1:
3707 case V4L2_PIX_FMT_MPEG2:
3708 case V4L2_PIX_FMT_MPEG4:
hanghang.luoe80a8882024-11-29 17:02:12 +08003709 case V4L2_PIX_FMT_AVS:
hanghang.luoc00dfad2024-12-20 17:57:30 +08003710 double_write = VDEC_DW_NO_AFBC;
bo.xiao857b8682024-09-12 16:40:32 +08003711 break;
hanghang.luo7765f172024-12-19 17:07:09 +08003712 // for hevc core, refer to gst_aml_config_dw_for_hevc_core
bo.xiao857b8682024-09-12 16:40:32 +08003713 case V4L2_PIX_FMT_H264:
bo.xiao857b8682024-09-12 16:40:32 +08003714 case V4L2_PIX_FMT_HEVC:
bo.xiao857b8682024-09-12 16:40:32 +08003715 case V4L2_PIX_FMT_VP9:
3716 case V4L2_PIX_FMT_AV1:
hanghang.luoe80a8882024-11-29 17:02:12 +08003717 case V4L2_PIX_FMT_AVS2:
3718 case V4L2_PIX_FMT_AVS3:
hanghang.luo7765f172024-12-19 17:07:09 +08003719 double_write = gst_aml_config_dw_for_hevc_core (v4l2object->low_memory_mode, interlace, v4l2object->pip, pixFormat);
hanghang.luoc00dfad2024-12-20 17:57:30 +08003720 env_dw = getenv("V4L2_SET_AMLOGIC_DW_MODE");
3721 if (env_dw)
3722 {
3723 double_write = atoi(env_dw);
3724 GST_DEBUG("DW: %d by setting directly for debug, user can't be allowed to use it", double_write);
3725 }
bo.xiao857b8682024-09-12 16:40:32 +08003726 break;
3727 default:
3728 GST_WARNING("unknown video format %d", pixFormat);
3729 break;
3730 }
bo.xiao34e36202024-07-17 16:04:01 +08003731
hanghang.luoe80a8882024-11-29 17:02:12 +08003732 GST_DEBUG("DW: %d final", double_write);
bo.xiao857b8682024-09-12 16:40:32 +08003733 return double_write;
bo.xiao34e36202024-07-17 16:04:01 +08003734}
hanghang.luobfc63f82024-07-05 11:04:56 +08003735
xuesong.jiangae1548e2022-05-06 16:38:46 +08003736static void
hanghang.luoe80a8882024-11-29 17:02:12 +08003737set_amlogic_vdec_parm (GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm, GstCaps *caps, guint32 pixFormat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003738{
3739 struct aml_dec_params *decParm = (struct aml_dec_params *)streamparm->parm.raw_data;
3740 const char *env;
zengliang.lic9f869d2023-02-15 08:32:32 +00003741 struct v4l2_ext_control control;
3742 struct v4l2_ext_controls ctrls;
3743 gboolean use_ext_config = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003744 int major = 0, minor = 0;
zengliang.lic9f869d2023-02-15 08:32:32 +00003745 struct utsname info;
bo.xiao34e36202024-07-17 16:04:01 +08003746 gboolean is_interlaced = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003747 guint width = 0, height = 0;
3748
3749 streamparm->type = v4l2object->type;
bo.xiao34e36202024-07-17 16:04:01 +08003750
fei.deng355dfb52024-09-14 15:04:31 +08003751 env = getenv("V4L2DEC_LOW_MEM_MODE");
3752 if (env) {
3753 GST_DEBUG("%s",env);
3754 v4l2object->low_memory_mode = atoi(env) > 0? TRUE: FALSE;
3755 }
hanghang.luo7f403102024-07-04 10:33:01 +08003756 GST_DEBUG("low mem: %d",v4l2object->low_memory_mode);
bo.xiao34e36202024-07-17 16:04:01 +08003757
bo.xiao7659cda2024-07-18 16:16:50 +08003758 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3759 {
3760 GST_DEBUG("get linux version failed");
3761 }
3762 GST_DEBUG("linux major version %d %d", major,minor);
3763 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
3764
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003765 GstStructure *structure = gst_caps_get_structure(caps, 0);
3766 if (structure == NULL)
3767 {
3768 return;
3769 }
3770 gst_structure_get_uint(structure,"width",&width);
3771 gst_structure_get_uint(structure,"height",&height);
3772 if (gst_structure_has_field(structure, "interlace-mode"))
3773 {
bo.xiao34e36202024-07-17 16:04:01 +08003774 const gchar *mode = gst_structure_get_string(structure,"interlace-mode");
3775 is_interlaced = !strcmp(mode, "progressive") ? FALSE:TRUE;
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003776 GST_DEBUG("is_interlaced: %d",is_interlaced);
3777 }
hanghang.luo7f403102024-07-04 10:33:01 +08003778
xuesong.jiangae1548e2022-05-06 16:38:46 +08003779 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3780 {
fei.dengccc89632022-07-15 19:10:17 +08003781 /*set bit12 value to 1,
3782 *v4l2 output 0 pts of second interlace field frame */
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003783 decParm->cfg.metadata_config_flag |= (1 << 12);
fei.deng7c3d67f2022-11-09 11:06:05 +08003784 decParm->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003785
3786 decParm->cfg.metadata_config_flag |= 1 << 13;
3787
3788 /*set bit18 value to 1
3789 *release vpp in advance */
3790 decParm->cfg.metadata_config_flag |= (1 << 18);
3791 decParm->cfg.low_latency_mode = v4l2object->low_latency_mode;
3792
zengliang.li8f538aa2024-06-25 17:31:20 +08003793 if (v4l2object->enable_nr)
3794 {
3795 GST_DEBUG("enable nr in di");
3796 decParm->cfg.metadata_config_flag |= (1 << 14);
3797 decParm->cfg.metadata_config_flag |= (1 << 15);
3798 }
3799
bo.xiao34e36202024-07-17 16:04:01 +08003800 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, pixFormat, width, height, is_interlaced);
hanghang.luo75664712024-07-01 19:28:10 +08003801 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg dw mode to %d", decParm->cfg.double_write_mode);
bo.xiao7659cda2024-07-18 16:16:50 +08003802 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo75664712024-07-01 19:28:10 +08003803
fei.deng17693b62024-08-28 20:13:17 +08003804 if (v4l2object->low_memory_mode) {
3805 decParm->cfg.ref_buf_margin = GST_AML_V4L2_LOW_MEMORY_CAP_BUF_MARGIN;
3806 } else {
3807 decParm->cfg.ref_buf_margin = GST_AML_V4L2_DEFAULT_CAP_BUF_MARGIN;
3808 }
3809
le.hancd3f2842024-06-26 09:37:50 +00003810 env = getenv("V4L2_SET_AMLOGIC_MARGIN_NUM");
3811 if (env)
3812 {
3813 decParm->cfg.ref_buf_margin = atoi(env);
bo.xiao7659cda2024-07-18 16:16:50 +08003814 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg margin to %d", decParm->cfg.ref_buf_margin);
le.hancd3f2842024-06-26 09:37:50 +00003815 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003816
bo.xiaof42b0082024-08-22 14:08:53 +08003817 // d v
3818 gboolean bl_present_flag, el_present_flag;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003819 int dvBaseLayerPresent = -1;
3820 int dvEnhancementLayerPresent = -1;
3821 /* have base and enhancement layers both, that means its dual layer,
bo.xiaof42b0082024-08-22 14:08:53 +08003822 d v two layer flag will be true */
3823 if (gst_structure_get_boolean( structure, "bl_present_flag", &bl_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003824 {
bo.xiaof42b0082024-08-22 14:08:53 +08003825 dvBaseLayerPresent= bl_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003826 }
bo.xiaof42b0082024-08-22 14:08:53 +08003827 if (gst_structure_get_boolean( structure, "el_present_flag", &el_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003828 {
bo.xiaof42b0082024-08-22 14:08:53 +08003829 dvEnhancementLayerPresent= el_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003830 }
3831
3832 /* have base and enhancement layers both, that means its dual layer, dv two layer flag will be true */
3833 if ( (dvBaseLayerPresent == 1) && (dvEnhancementLayerPresent == 1) )
3834 {
3835 decParm->cfg.metadata_config_flag |= (1 << 0);
3836 }
3837 else
3838 {
3839 decParm->cfg.metadata_config_flag |= (0 << 0);
3840 }
3841
3842 /* have one of then, it's standard dv stream, Non-standard dv flag will be false */
3843 if ( (dvBaseLayerPresent == 0) && (dvEnhancementLayerPresent == 0) )
3844 {
3845 decParm->cfg.metadata_config_flag |= (1 << 1);
3846 }
3847 else
3848 {
3849 decParm->cfg.metadata_config_flag |= (0 << 1);
3850 }
3851
3852 // HDR
xuesong.jiange1a19662022-06-21 20:30:22 +08003853 if ( gst_structure_has_field(structure, "colorimetry") )
3854 {
3855 const char *colorimetry= gst_structure_get_string(structure,"colorimetry");
3856 GstVideoColorimetry vci = {0};
3857 if ( colorimetry && gst_video_colorimetry_from_string( &vci, colorimetry ))
3858 {
3859 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO;
3860 decParm->hdr.signal_type= (1<<29); /* present flag */
3861 /*set default value, this is to keep up with driver hdr info synchronization*/
3862 decParm->hdr.signal_type |= (5<<26) | (1<<24);
3863
3864 gint hdrColorimetry[4] = {0};
3865 hdrColorimetry[0]= (int)vci.range;
3866 hdrColorimetry[1]= (int)vci.matrix;
3867 hdrColorimetry[2]= (int)vci.transfer;
3868 hdrColorimetry[3]= (int)vci.primaries;
3869 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "colorimetry: [%d,%d,%d,%d]",
3870 hdrColorimetry[0],
3871 hdrColorimetry[1],
3872 hdrColorimetry[2],
3873 hdrColorimetry[3] );
3874 /* range */
3875 switch ( hdrColorimetry[0] )
3876 {
le.han8d28eb82024-06-05 08:11:12 +00003877 case GST_VIDEO_COLOR_RANGE_0_255:
3878 case GST_VIDEO_COLOR_RANGE_16_235:
xuesong.jiange1a19662022-06-21 20:30:22 +08003879 decParm->hdr.signal_type |= ((hdrColorimetry[0] % 2)<<25);
3880 break;
3881 default:
3882 break;
3883 }
3884 /* matrix coefficient */
3885 switch ( hdrColorimetry[1] )
3886 {
le.han8d28eb82024-06-05 08:11:12 +00003887 case GST_VIDEO_COLOR_MATRIX_RGB: /* RGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003888 decParm->hdr.signal_type |= 0;
3889 break;
le.han8d28eb82024-06-05 08:11:12 +00003890 case GST_VIDEO_COLOR_MATRIX_FCC: /* FCC */
xuesong.jiange1a19662022-06-21 20:30:22 +08003891 decParm->hdr.signal_type |= 4;
3892 break;
le.han8d28eb82024-06-05 08:11:12 +00003893 case GST_VIDEO_COLOR_MATRIX_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003894 decParm->hdr.signal_type |= 1;
3895 break;
le.han8d28eb82024-06-05 08:11:12 +00003896 case GST_VIDEO_COLOR_MATRIX_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003897 decParm->hdr.signal_type |= 3;
3898 break;
le.han8d28eb82024-06-05 08:11:12 +00003899 case GST_VIDEO_COLOR_MATRIX_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003900 decParm->hdr.signal_type |= 7;
3901 break;
le.han8d28eb82024-06-05 08:11:12 +00003902 case GST_VIDEO_COLOR_MATRIX_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003903 decParm->hdr.signal_type |= 9;
3904 break;
3905 default: /* unknown */
3906 decParm->hdr.signal_type |= 2;
3907 break;
3908 }
3909 /* transfer function */
3910 switch ( hdrColorimetry[2] )
3911 {
le.han8d28eb82024-06-05 08:11:12 +00003912 case GST_VIDEO_TRANSFER_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003913 decParm->hdr.signal_type |= (1<<8);
3914 break;
le.han8d28eb82024-06-05 08:11:12 +00003915 case GST_VIDEO_TRANSFER_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003916 decParm->hdr.signal_type |= (7<<8);
3917 break;
le.han8d28eb82024-06-05 08:11:12 +00003918 case GST_VIDEO_TRANSFER_LOG100: /* LOG100 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003919 decParm->hdr.signal_type |= (9<<8);
3920 break;
le.han8d28eb82024-06-05 08:11:12 +00003921 case GST_VIDEO_TRANSFER_LOG316: /* LOG316 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003922 decParm->hdr.signal_type |= (10<<8);
3923 break;
le.han8d28eb82024-06-05 08:11:12 +00003924 case GST_VIDEO_TRANSFER_BT2020_12: /* BT2020_12 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003925 decParm->hdr.signal_type |= (15<<8);
3926 break;
le.han8d28eb82024-06-05 08:11:12 +00003927 case GST_VIDEO_TRANSFER_BT2020_10: /* BT2020_10 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003928 decParm->hdr.signal_type |= (14<<8);
3929 break;
le.han8d28eb82024-06-05 08:11:12 +00003930 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
3931 case GST_VIDEO_TRANSFER_SMPTE2084: /* SMPTE2084 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003932 decParm->hdr.signal_type |= (16<<8);
3933 break;
le.han8d28eb82024-06-05 08:11:12 +00003934 #else
3935 case GST_VIDEO_TRANSFER_SMPTE_ST_2084: /* SMPTE2084 */
3936 decParm->hdr.signal_type |= (16<<8);
3937 break;
3938 #endif
3939 case GST_VIDEO_TRANSFER_ARIB_STD_B67: /* ARIB_STD_B67 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003940 decParm->hdr.signal_type |= (18<<8);
3941 break;
3942 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
le.han8d28eb82024-06-05 08:11:12 +00003943 case GST_VIDEO_TRANSFER_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003944 decParm->hdr.signal_type |= (3<<8);
3945 break;
3946 #endif
le.han8d28eb82024-06-05 08:11:12 +00003947 case GST_VIDEO_TRANSFER_GAMMA10: /* GAMMA10 */
3948 case GST_VIDEO_TRANSFER_GAMMA18: /* GAMMA18 */
3949 case GST_VIDEO_TRANSFER_GAMMA20: /* GAMMA20 */
3950 case GST_VIDEO_TRANSFER_GAMMA22: /* GAMMA22 */
3951 case GST_VIDEO_TRANSFER_SRGB: /* SRGB */
3952 case GST_VIDEO_TRANSFER_GAMMA28: /* GAMMA28 */
3953 case GST_VIDEO_TRANSFER_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003954 default:
3955 break;
3956 }
3957 /* primaries */
3958 switch ( hdrColorimetry[3] )
3959 {
le.han8d28eb82024-06-05 08:11:12 +00003960 case GST_VIDEO_COLOR_PRIMARIES_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003961 decParm->hdr.signal_type |= ((1<<24)|(1<<16));
3962 break;
le.han8d28eb82024-06-05 08:11:12 +00003963 case GST_VIDEO_COLOR_PRIMARIES_BT470M: /* BT470M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003964 decParm->hdr.signal_type |= ((1<<24)|(4<<16));
3965 break;
le.han8d28eb82024-06-05 08:11:12 +00003966 case GST_VIDEO_COLOR_PRIMARIES_BT470BG: /* BT470BG */
xuesong.jiange1a19662022-06-21 20:30:22 +08003967 decParm->hdr.signal_type |= ((1<<24)|(5<<16));
3968 break;
le.han8d28eb82024-06-05 08:11:12 +00003969 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M: /* SMPTE170M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003970 decParm->hdr.signal_type |= ((1<<24)|(6<<16));
3971 break;
le.han8d28eb82024-06-05 08:11:12 +00003972 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003973 decParm->hdr.signal_type |= ((1<<24)|(7<<16));
3974 break;
le.han8d28eb82024-06-05 08:11:12 +00003975 case GST_VIDEO_COLOR_PRIMARIES_FILM: /* FILM */
xuesong.jiange1a19662022-06-21 20:30:22 +08003976 decParm->hdr.signal_type |= ((1<<24)|(8<<16));
3977 break;
le.han8d28eb82024-06-05 08:11:12 +00003978 case GST_VIDEO_COLOR_PRIMARIES_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003979 decParm->hdr.signal_type |= ((1<<24)|(9<<16));
3980 break;
le.han8d28eb82024-06-05 08:11:12 +00003981 case GST_VIDEO_COLOR_PRIMARIES_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003982 default:
3983 break;
3984 }
3985 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR signal_type %X", decParm->hdr.signal_type);
3986 }
3987
bo.xiao7659cda2024-07-18 16:16:50 +08003988 //why remove this colorimetry?
xuesong.jiange1a19662022-06-21 20:30:22 +08003989 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "got caps %" GST_PTR_FORMAT, caps);
3990 GstStructure *st = gst_caps_get_structure(caps, 0);
3991 GstCapsFeatures *features = gst_caps_get_features(caps, 0);
3992
3993 if (gst_structure_has_field(st, "colorimetry"))
3994 {
3995 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "have colorimetry");
3996 }
3997
3998 if (st && features)
3999 {
4000 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "trace in remove colorimetry");
4001 gst_structure_remove_field(st, "colorimetry");
4002 gst_caps_features_remove(features, "colorimetry");
4003 }
4004 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove colorimetry %" GST_PTR_FORMAT, caps);
4005 }
4006
le.han7d0af792024-06-05 08:44:18 +00004007 const char * field = NULL;
4008 if (gst_structure_has_field(structure, "mastering-display-metadata")) {
4009 field = "mastering-display-metadata";
4010 } else if (gst_structure_has_field(structure, "mastering-display-info")) {
4011 field = "mastering-display-info";
4012 }
4013
4014 if ( field )
xuesong.jiange1a19662022-06-21 20:30:22 +08004015 {
le.han7d0af792024-06-05 08:44:18 +00004016 const char *masteringDisplay= gst_structure_get_string(structure, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08004017 float hdrMasteringDisplay[10];
4018 if ( masteringDisplay && sscanf( masteringDisplay, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
4019 &hdrMasteringDisplay[0],
4020 &hdrMasteringDisplay[1],
4021 &hdrMasteringDisplay[2],
4022 &hdrMasteringDisplay[3],
4023 &hdrMasteringDisplay[4],
4024 &hdrMasteringDisplay[5],
4025 &hdrMasteringDisplay[6],
4026 &hdrMasteringDisplay[7],
4027 &hdrMasteringDisplay[8],
4028 &hdrMasteringDisplay[9] ) == 10 )
4029 {
4030 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "mastering display [%f,%f,%f,%f,%f,%f,%f,%f,%f,%f]",
4031 hdrMasteringDisplay[0],
4032 hdrMasteringDisplay[1],
4033 hdrMasteringDisplay[2],
4034 hdrMasteringDisplay[3],
4035 hdrMasteringDisplay[4],
4036 hdrMasteringDisplay[5],
4037 hdrMasteringDisplay[6],
4038 hdrMasteringDisplay[7],
4039 hdrMasteringDisplay[8],
4040 hdrMasteringDisplay[9] );
4041
4042 decParm->hdr.color_parms.present_flag= 1;
4043 decParm->hdr.color_parms.primaries[2][0]= (uint32_t)(hdrMasteringDisplay[0]*50000); /* R.x */
4044 decParm->hdr.color_parms.primaries[2][1]= (uint32_t)(hdrMasteringDisplay[1]*50000); /* R.y */
4045 decParm->hdr.color_parms.primaries[0][0]= (uint32_t)(hdrMasteringDisplay[2]*50000); /* G.x */
4046 decParm->hdr.color_parms.primaries[0][1]= (uint32_t)(hdrMasteringDisplay[3]*50000); /* G.y */
4047 decParm->hdr.color_parms.primaries[1][0]= (uint32_t)(hdrMasteringDisplay[4]*50000); /* B.x */
4048 decParm->hdr.color_parms.primaries[1][1]= (uint32_t)(hdrMasteringDisplay[5]*50000); /* B.y */
4049 decParm->hdr.color_parms.white_point[0]= (uint32_t)(hdrMasteringDisplay[6]*50000);
4050 decParm->hdr.color_parms.white_point[1]= (uint32_t)(hdrMasteringDisplay[7]*50000);
4051 decParm->hdr.color_parms.luminance[0]= (uint32_t)(hdrMasteringDisplay[8]);
4052 decParm->hdr.color_parms.luminance[1]= (uint32_t)(hdrMasteringDisplay[9]);
4053 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: primaries %X %X %X %X %X %X",
4054 decParm->hdr.color_parms.primaries[2][0],
4055 decParm->hdr.color_parms.primaries[2][1],
4056 decParm->hdr.color_parms.primaries[0][0],
4057 decParm->hdr.color_parms.primaries[0][1],
4058 decParm->hdr.color_parms.primaries[1][0],
4059 decParm->hdr.color_parms.primaries[1][1] );
4060 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: white point: %X %X",
4061 decParm->hdr.color_parms.white_point[0],
4062 decParm->hdr.color_parms.white_point[1] );
4063 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: luminance: %X %X",
4064 decParm->hdr.color_parms.luminance[0],
4065 decParm->hdr.color_parms.luminance[1] );
4066 }
4067
4068 GstStructure *st = gst_caps_get_structure(caps, 0);
4069 GstCapsFeatures * features = gst_caps_get_features(caps, 0);
4070 if (st && features)
4071 {
le.han7d0af792024-06-05 08:44:18 +00004072 gst_structure_remove_fields(st, field, NULL);
4073 gst_caps_features_remove(features, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08004074 }
le.han7d0af792024-06-05 08:44:18 +00004075 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove %s %" GST_PTR_FORMAT, field, caps);
xuesong.jiange1a19662022-06-21 20:30:22 +08004076 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004077 }
hanghang.luo75664712024-07-01 19:28:10 +08004078 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004079 {
hanghang.luo75664712024-07-01 19:28:10 +08004080 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao7659cda2024-07-18 16:16:50 +08004081
4082 if (!get_amlogic_vdec_parm(v4l2object, streamparm))
hanghang.luobfc63f82024-07-05 11:04:56 +08004083 {
4084 GST_ERROR_OBJECT(v4l2object->dbg_obj, "can't get vdec parm");
4085 return;
4086 }
hanghang.luo75664712024-07-01 19:28:10 +08004087
bo.xiao7659cda2024-07-18 16:16:50 +08004088 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, self->v4l2output->fmtdesc->pixelformat,
bo.xiao34e36202024-07-17 16:04:01 +08004089 width, height, is_interlaced);
bo.xiao7659cda2024-07-18 16:16:50 +08004090 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "capture cfg dw mode to %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004091
4092 if (needSpecConfigForFg(v4l2object))
4093 {
bo.xiao7659cda2024-07-18 16:16:50 +08004094 decParm->cfg.double_write_mode = VDEC_DW_MMU_1;
4095 GST_DEBUG_OBJECT(v4l2object->dbg_obj,"set fg dw mode %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004096 }
bo.xiao7659cda2024-07-18 16:16:50 +08004097 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004098 }
4099 else
4100 {
hanghang.luo75664712024-07-01 19:28:10 +08004101 GST_ERROR_OBJECT(v4l2object->dbg_obj,"can't deal with. please check buffer type.");
bo.xiao7659cda2024-07-18 16:16:50 +08004102 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004103 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004104
bo.xiao7659cda2024-07-18 16:16:50 +08004105 if (use_ext_config)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004106 {
bo.xiao7659cda2024-07-18 16:16:50 +08004107 memset(&ctrls, 0, sizeof(ctrls));
4108 memset(&control, 0, sizeof(control));
4109 control.id = AML_V4L2_DEC_PARMS_CONFIG;
4110 control.ptr = decParm;
4111 control.size = sizeof(struct aml_dec_params);
4112 ctrls.count = 1;
4113 ctrls.controls = &control;
4114 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls ) < 0)
4115 {
4116 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4117 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004118 }
bo.xiao7659cda2024-07-18 16:16:50 +08004119 else
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004120 {
bo.xiao7659cda2024-07-18 16:16:50 +08004121 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_PARM, streamparm) < 0)
4122 {
4123 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4124 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004125 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004126}
4127
xuesong.jiangae1548e2022-05-06 16:38:46 +08004128static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004129gst_aml_v4l2_object_set_format_full (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4130 gboolean try_only, GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004131{
le.han3b118242024-09-29 06:32:02 +00004132 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao857b8682024-09-12 16:40:32 +08004133 gint fd = v4l2object->video_fd;
4134 struct v4l2_format format;
4135 struct v4l2_streamparm streamparm;
4136 enum v4l2_field field;
4137 guint32 pixelformat;
4138 struct v4l2_fmtdesc *fmtdesc;
4139 GstVideoInfo info;
4140 GstVideoAlignment align;
4141 gint width, height, fps_n, fps_d;
4142 gint n_v4l_planes;
4143 gint i = 0;
4144 gboolean is_mplane;
4145 enum v4l2_colorspace colorspace = 0;
4146 enum v4l2_quantization range = 0;
4147 enum v4l2_ycbcr_encoding matrix = 0;
4148 enum v4l2_xfer_func transfer = 0;
4149 GstStructure *s;
4150 gboolean disable_colorimetry = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004151
bo.xiao857b8682024-09-12 16:40:32 +08004152 g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
4153 gst_caps_is_writable (caps), FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004154
bo.xiao857b8682024-09-12 16:40:32 +08004155 GST_AML_V4L2_CHECK_OPEN (v4l2object);
4156 if (!try_only)
4157 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004158
bo.xiao857b8682024-09-12 16:40:32 +08004159 is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004160
bo.xiao857b8682024-09-12 16:40:32 +08004161 gst_video_info_init (&info);
4162 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004163
bo.xiao857b8682024-09-12 16:40:32 +08004164 if (!gst_aml_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
4165 goto invalid_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004166
bo.xiao857b8682024-09-12 16:40:32 +08004167 pixelformat = fmtdesc->pixelformat;
4168 width = GST_VIDEO_INFO_WIDTH (&info);
4169 height = GST_VIDEO_INFO_HEIGHT (&info);
4170 fps_n = GST_VIDEO_INFO_FPS_N (&info);
4171 fps_d = GST_VIDEO_INFO_FPS_D (&info);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004172
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004173 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size");
4174 struct v4l2_frmsizeenum size;
4175 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
4176 size.index = 0;
4177 size.pixel_format = pixelformat;
4178 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
bo.xiao857b8682024-09-12 16:40:32 +08004179 return FALSE;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004180 if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
4181 {
bo.xiao857b8682024-09-12 16:40:32 +08004182 guint32 maxw, maxh;
4183 maxw = MIN (size.stepwise.max_width, G_MAXINT);
4184 maxh = MIN (size.stepwise.max_height, G_MAXINT);
4185 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "image from caps w_h:%d_%d", width, height);
4186 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "v4l2 support max w_h:%d_%d", maxw, maxh);
4187 if (width*height > maxw*maxh)
4188 return FALSE;
4189 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size ok");
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004190 }
4191
bo.xiao857b8682024-09-12 16:40:32 +08004192 //set amlogic params here,because we need pix format to set dw mode
4193 memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
4194 set_amlogic_vdec_parm(v4l2object, &streamparm, caps, pixelformat);
fei.deng7c3d67f2022-11-09 11:06:05 +08004195
bo.xiao857b8682024-09-12 16:40:32 +08004196 /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
4197 * or if contiguous is preferred */
4198 n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
4199 if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
4200 n_v4l_planes = 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004201
bo.xiao857b8682024-09-12 16:40:32 +08004202 if (GST_VIDEO_INFO_IS_INTERLACED(&info))
4203 {
4204 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "interlaced video");
4205 /* ideally we would differentiate between types of interlaced video
4206 * but there is not sufficient information in the caps..
4207 */
4208 field = V4L2_FIELD_INTERLACED;
4209 }
4210 else
4211 {
4212 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "progressive video");
4213 field = V4L2_FIELD_NONE;
4214 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004215
bo.xiao857b8682024-09-12 16:40:32 +08004216 /* We first pick the main colorspace from the primaries */
4217 switch (info.colorimetry.primaries)
4218 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004219 case GST_VIDEO_COLOR_PRIMARIES_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004220 /* There is two colorspaces using these primaries, use the range to
4221 * differentiate */
4222 if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
4223 colorspace = V4L2_COLORSPACE_REC709;
4224 else
4225 colorspace = V4L2_COLORSPACE_SRGB;
4226 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004227 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004228 colorspace = V4L2_COLORSPACE_BT2020;
4229 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004230 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
bo.xiao857b8682024-09-12 16:40:32 +08004231 colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
4232 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004233 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
bo.xiao857b8682024-09-12 16:40:32 +08004234 colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
4235 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004236 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08004237 colorspace = V4L2_COLORSPACE_SMPTE170M;
4238 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004239 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004240 colorspace = V4L2_COLORSPACE_SMPTE240M;
4241 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004242
4243 case GST_VIDEO_COLOR_PRIMARIES_FILM:
4244 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004245 /* We don't know, we will guess */
4246 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004247
4248 default:
bo.xiao857b8682024-09-12 16:40:32 +08004249 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4250 "Unknown colorimetry primaries %d", info.colorimetry.primaries);
4251 break;
4252 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004253
bo.xiao857b8682024-09-12 16:40:32 +08004254 switch (info.colorimetry.range)
4255 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004256 case GST_VIDEO_COLOR_RANGE_0_255:
bo.xiao857b8682024-09-12 16:40:32 +08004257 range = V4L2_QUANTIZATION_FULL_RANGE;
4258 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004259 case GST_VIDEO_COLOR_RANGE_16_235:
bo.xiao857b8682024-09-12 16:40:32 +08004260 range = V4L2_QUANTIZATION_LIM_RANGE;
4261 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004262 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004263 /* We let the driver pick a default one */
4264 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004265 default:
bo.xiao857b8682024-09-12 16:40:32 +08004266 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4267 "Unknown colorimetry range %d", info.colorimetry.range);
4268 break;
4269 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004270
bo.xiao857b8682024-09-12 16:40:32 +08004271 switch (info.colorimetry.matrix)
4272 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004273 case GST_VIDEO_COLOR_MATRIX_RGB:
bo.xiao857b8682024-09-12 16:40:32 +08004274 /* Unspecified, leave to default */
4275 break;
4276 /* FCC is about the same as BT601 with less digit */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004277 case GST_VIDEO_COLOR_MATRIX_FCC:
4278 case GST_VIDEO_COLOR_MATRIX_BT601:
bo.xiao857b8682024-09-12 16:40:32 +08004279 matrix = V4L2_YCBCR_ENC_601;
4280 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004281 case GST_VIDEO_COLOR_MATRIX_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004282 matrix = V4L2_YCBCR_ENC_709;
4283 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004284 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004285 matrix = V4L2_YCBCR_ENC_SMPTE240M;
4286 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004287 case GST_VIDEO_COLOR_MATRIX_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004288 matrix = V4L2_YCBCR_ENC_BT2020;
4289 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004290 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004291 /* We let the driver pick a default one */
4292 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004293 default:
bo.xiao857b8682024-09-12 16:40:32 +08004294 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4295 "Unknown colorimetry matrix %d", info.colorimetry.matrix);
4296 break;
4297 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004298
bo.xiao857b8682024-09-12 16:40:32 +08004299 switch (info.colorimetry.transfer)
4300 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004301 case GST_VIDEO_TRANSFER_GAMMA18:
4302 case GST_VIDEO_TRANSFER_GAMMA20:
4303 case GST_VIDEO_TRANSFER_GAMMA22:
4304 case GST_VIDEO_TRANSFER_GAMMA28:
bo.xiao857b8682024-09-12 16:40:32 +08004305 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4306 "GAMMA 18, 20, 22, 28 transfer functions not supported");
4307 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004308 case GST_VIDEO_TRANSFER_GAMMA10:
bo.xiao857b8682024-09-12 16:40:32 +08004309 transfer = V4L2_XFER_FUNC_NONE;
4310 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004311 case GST_VIDEO_TRANSFER_BT2020_12:
4312 case GST_VIDEO_TRANSFER_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004313 transfer = V4L2_XFER_FUNC_709;
4314 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004315 case GST_VIDEO_TRANSFER_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004316 transfer = V4L2_XFER_FUNC_SMPTE240M;
4317 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004318 case GST_VIDEO_TRANSFER_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08004319 transfer = V4L2_XFER_FUNC_SRGB;
4320 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004321 case GST_VIDEO_TRANSFER_LOG100:
4322 case GST_VIDEO_TRANSFER_LOG316:
bo.xiao857b8682024-09-12 16:40:32 +08004323 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4324 "LOG 100, 316 transfer functions not supported");
4325 /* FIXME No known sensible default, maybe AdobeRGB ? */
4326 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004327 case GST_VIDEO_TRANSFER_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004328 /* We let the driver pick a default one */
4329 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004330 default:
bo.xiao857b8682024-09-12 16:40:32 +08004331 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4332 "Unknown colorimetry transfer %d", info.colorimetry.transfer);
4333 break;
4334 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004335
bo.xiao857b8682024-09-12 16:40:32 +08004336 if (colorspace == 0)
4337 {
4338 /* Try to guess colorspace according to pixelformat and size */
4339 if (GST_VIDEO_INFO_IS_YUV (&info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004340 {
bo.xiao857b8682024-09-12 16:40:32 +08004341 if (range == V4L2_QUANTIZATION_FULL_RANGE
4342 && matrix == V4L2_YCBCR_ENC_601 && transfer == 0)
4343 {
4344 /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
4345 * function most likely is JPEG */
4346 colorspace = V4L2_COLORSPACE_JPEG;
4347 transfer = V4L2_XFER_FUNC_SRGB;
4348 }
4349 else
4350 {
4351 /* SD streams likely use SMPTE170M and HD streams REC709 */
4352 if (width <= 720 && height <= 576)
4353 colorspace = V4L2_COLORSPACE_SMPTE170M;
4354 else
4355 colorspace = V4L2_COLORSPACE_REC709;
4356 }
4357 }
4358 else if (GST_VIDEO_INFO_IS_RGB (&info))
4359 {
4360 colorspace = V4L2_COLORSPACE_SRGB;
4361 transfer = V4L2_XFER_FUNC_NONE;
4362 }
4363 }
4364
4365 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format "
4366 "%" GST_FOURCC_FORMAT " stride: %d", width, height,
4367 GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
4368
4369 memset (&format, 0x00, sizeof (struct v4l2_format));
4370 format.type = v4l2object->type;
4371
4372 if (is_mplane)
4373 {
4374 format.type = v4l2object->type;
4375 format.fmt.pix_mp.pixelformat = pixelformat;
4376 format.fmt.pix_mp.width = width;
4377 format.fmt.pix_mp.height = height;
4378 format.fmt.pix_mp.field = field;
4379 format.fmt.pix_mp.num_planes = n_v4l_planes;
4380
4381 /* try to ask our preferred stride but it's not a failure if not
4382 * accepted */
4383 for (i = 0; i < n_v4l_planes; i++)
4384 {
4385 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
4386
4387 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4388 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4389 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4390
4391 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004392 }
4393
bo.xiao857b8682024-09-12 16:40:32 +08004394 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
4395 {
4396 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4397 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4398 else
4399 format.fmt.pix_mp.plane_fmt[0].sizeimage = v4l2object->low_memory_mode ? LOW_MEM_ENCODED_BUFFER_SIZE : ENCODED_BUFFER_SIZE;
4400 }
4401 }
4402 else
4403 {
4404 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004405
xuesong.jiangae1548e2022-05-06 16:38:46 +08004406 format.type = v4l2object->type;
4407
bo.xiao857b8682024-09-12 16:40:32 +08004408 format.fmt.pix.width = width;
4409 format.fmt.pix.height = height;
4410 format.fmt.pix.pixelformat = pixelformat;
4411 format.fmt.pix.field = field;
4412
4413 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4414 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4415 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4416
4417 /* try to ask our preferred stride */
4418 format.fmt.pix.bytesperline = stride;
4419
4420 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004421 {
bo.xiao857b8682024-09-12 16:40:32 +08004422 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4423 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4424 else
4425 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 +08004426 }
bo.xiao857b8682024-09-12 16:40:32 +08004427 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004428
bo.xiao857b8682024-09-12 16:40:32 +08004429 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
4430 "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
4431 format.fmt.pix_mp.height,
4432 GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
4433 is_mplane ? format.fmt.pix_mp.num_planes : 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004434
4435#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004436 if (is_mplane)
4437 {
4438 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4439 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4440 format.fmt.pix_mp.plane_fmt[i].bytesperline);
4441 }
4442 else
4443 {
4444 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4445 format.fmt.pix.bytesperline);
4446 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004447#endif
4448
bo.xiao857b8682024-09-12 16:40:32 +08004449 if (is_mplane)
4450 {
4451 format.fmt.pix_mp.colorspace = colorspace;
4452 format.fmt.pix_mp.quantization = range;
4453 format.fmt.pix_mp.ycbcr_enc = matrix;
4454 format.fmt.pix_mp.xfer_func = transfer;
4455 }
4456 else
4457 {
4458 format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
4459 format.fmt.pix.colorspace = colorspace;
4460 format.fmt.pix.quantization = range;
4461 format.fmt.pix.ycbcr_enc = matrix;
4462 format.fmt.pix.xfer_func = transfer;
4463 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004464
bo.xiao857b8682024-09-12 16:40:32 +08004465 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
4466 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004467
bo.xiao857b8682024-09-12 16:40:32 +08004468 if (try_only)
4469 {
4470 if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
4471 goto try_fmt_failed;
4472 }
4473 else
4474 {
4475 if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
4476 goto set_fmt_failed;
4477 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004478
bo.xiao857b8682024-09-12 16:40:32 +08004479 if (is_mplane)
4480 {
4481 colorspace = format.fmt.pix_mp.colorspace;
4482 range = format.fmt.pix_mp.quantization;
4483 matrix = format.fmt.pix_mp.ycbcr_enc;
4484 transfer = format.fmt.pix_mp.xfer_func;
4485 }
4486 else
4487 {
4488 colorspace = format.fmt.pix.colorspace;
4489 range = format.fmt.pix.quantization;
4490 matrix = format.fmt.pix.ycbcr_enc;
4491 transfer = format.fmt.pix.xfer_func;
4492 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004493
bo.xiao857b8682024-09-12 16:40:32 +08004494 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got format of %dx%d, format "
4495 "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d",
4496 format.fmt.pix.width, format.fmt.pix_mp.height,
4497 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4498 is_mplane ? format.fmt.pix_mp.num_planes : 1,
4499 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004500
hanghang.luo3eeb8b32024-12-23 17:38:00 +08004501 if (v4l2object->dw_mode == VDEC_DW_AFBC_ONLY)
le.han3b118242024-09-29 06:32:02 +00004502 {
hanghang.luo3eeb8b32024-12-23 17:38:00 +08004503 v4l2object->stride = format.fmt.pix_mp.plane_fmt[0].bytesperline;
le.han3b118242024-09-29 06:32:02 +00004504 //because driver return src w,h when AFBC_ONLY
4505 format.fmt.pix.width = format.fmt.pix.height = 64;
4506 format.fmt.pix_mp.plane_fmt[0].bytesperline = format.fmt.pix_mp.plane_fmt[1].bytesperline = 64;
4507 }
4508
xuesong.jiangae1548e2022-05-06 16:38:46 +08004509#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004510 if (is_mplane)
4511 {
4512 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4513 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4514 format.fmt.pix_mp.plane_fmt[i].bytesperline,
4515 format.fmt.pix_mp.plane_fmt[i].sizeimage);
4516 }
4517 else
4518 {
4519 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4520 format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
4521 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004522#endif
4523
bo.xiao857b8682024-09-12 16:40:32 +08004524 if (format.fmt.pix.pixelformat != pixelformat)
4525 goto invalid_pixelformat;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004526
bo.xiao857b8682024-09-12 16:40:32 +08004527 /* Only negotiate size with raw data.
4528 * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
4529 * in ASF mode for example, there is also not reason for a driver to
4530 * change the size. */
4531 if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED)
4532 {
4533 /* We can crop larger images */
4534 if (format.fmt.pix.width < width || format.fmt.pix.height < height)
4535 goto invalid_dimensions;
4536
4537 /* Note, this will be adjusted if upstream has non-centered cropping. */
4538 align.padding_top = 0;
4539 align.padding_bottom = format.fmt.pix.height - height;
4540 align.padding_left = 0;
4541 align.padding_right = format.fmt.pix.width - width;
4542 }
4543
4544 if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
4545 goto invalid_planes;
4546
4547 /* used to check colorimetry and interlace mode fields presence */
4548 s = gst_caps_get_structure (caps, 0);
4549
4550 if (!gst_aml_v4l2_object_get_interlace_mode(format.fmt.pix.field,
4551 &info.interlace_mode))
4552 goto invalid_field;
4553 if (gst_structure_has_field(s, "interlace-mode"))
4554 {
4555 if (format.fmt.pix.field != field)
4556 goto invalid_field;
4557 }
4558
4559 if (gst_aml_v4l2_object_get_colorspace(&format, &info.colorimetry))
4560 {
4561 if (gst_structure_has_field(s, "colorimetry"))
4562 {
4563 if (!gst_aml_v4l2_video_colorimetry_matches(&info.colorimetry, gst_structure_get_string(s, "colorimetry")))
4564 {
4565 // goto invalid_colorimetry;
4566 }
4567 }
4568 }
4569 else
4570 {
4571 /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
4572 * the TRY_FMT */
4573 disable_colorimetry = TRUE;
4574 if (gst_structure_has_field (s, "colorimetry"))
4575 gst_structure_remove_field (s, "colorimetry");
4576 }
4577
4578 /* In case we have skipped the try_fmt probes, we'll need to set the
4579 * colorimetry and interlace-mode back into the caps. */
4580 if (v4l2object->skip_try_fmt_probes)
4581 {
4582 if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004583 {
bo.xiao857b8682024-09-12 16:40:32 +08004584 gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
4585 gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
4586 g_free (str);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004587 }
4588
bo.xiao857b8682024-09-12 16:40:32 +08004589 if (!gst_structure_has_field(s, "interlace-mode"))
4590 gst_structure_set(s, "interlace-mode", G_TYPE_STRING,
4591 gst_video_interlace_mode_to_string(info.interlace_mode), NULL);
4592 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004593
bo.xiao857b8682024-09-12 16:40:32 +08004594 if (try_only) /* good enough for trying only */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004595 return TRUE;
4596
bo.xiao857b8682024-09-12 16:40:32 +08004597 if (GST_VIDEO_INFO_HAS_ALPHA (&info))
4598 {
4599 struct v4l2_control ctl = { 0, };
4600 ctl.id = V4L2_CID_ALPHA_COMPONENT;
4601 ctl.value = 0xff;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004602
bo.xiao857b8682024-09-12 16:40:32 +08004603 if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
4604 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4605 "Failed to set alpha component value");
4606 }
4607
4608 /* Is there a reason we require the caller to always specify a framerate? */
4609 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
4610 fps_d);
4611
4612 if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
4613 goto get_parm_failed;
4614
4615 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
4616 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
4617 {
4618 GST_VIDEO_INFO_FPS_N (&info) =
4619 streamparm.parm.capture.timeperframe.denominator;
4620 GST_VIDEO_INFO_FPS_D (&info) =
4621 streamparm.parm.capture.timeperframe.numerator;
4622
4623 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u",
4624 streamparm.parm.capture.timeperframe.denominator,
4625 streamparm.parm.capture.timeperframe.numerator);
4626
4627 /* We used to skip frame rate setup if the camera was already setup
4628 * with the requested frame rate. This breaks some cameras though,
4629 * causing them to not output data (several models of Thinkpad cameras
4630 * have this problem at least).
4631 * So, don't skip. */
4632 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
4633 fps_n, fps_d);
4634 /* We want to change the frame rate, so check whether we can. Some cheap USB
4635 * cameras don't have the capability */
4636 if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004637 {
bo.xiao857b8682024-09-12 16:40:32 +08004638 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4639 "Not setting capture framerate (not supported)");
4640 goto done;
4641 }
4642
4643 /* Note: V4L2 wants the frame interval, we have the frame rate */
4644 streamparm.parm.capture.timeperframe.numerator = fps_d;
4645 streamparm.parm.capture.timeperframe.denominator = fps_n;
4646
4647 if (streamparm.parm.capture.timeperframe.numerator > 0 &&
4648 streamparm.parm.capture.timeperframe.denominator > 0)
4649 {
4650 /* get new values */
4651 fps_d = streamparm.parm.capture.timeperframe.numerator;
4652 fps_n = streamparm.parm.capture.timeperframe.denominator;
4653
4654 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set capture framerate to %u/%u",
4655 fps_n, fps_d);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004656 }
4657 else
4658 {
bo.xiao857b8682024-09-12 16:40:32 +08004659 /* fix v4l2 capture driver to provide framerate values */
4660 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4661 "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
4662 }
4663
4664 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4665 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4666 }
4667 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
4668 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4669 {
4670 GST_VIDEO_INFO_FPS_N (&info) =
4671 streamparm.parm.output.timeperframe.denominator;
4672 GST_VIDEO_INFO_FPS_D (&info) =
4673 streamparm.parm.output.timeperframe.numerator;
4674
4675 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u",
4676 streamparm.parm.output.timeperframe.denominator,
4677 streamparm.parm.output.timeperframe.numerator);
4678
4679 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting output framerate to %u/%u",
4680 fps_n, fps_d);
4681 if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4682 {
4683 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4684 "Not setting output framerate (not supported)");
4685 goto done;
4686 }
4687
4688 /* Note: V4L2 wants the frame interval, we have the frame rate */
4689 streamparm.parm.output.timeperframe.numerator = fps_d;
4690 streamparm.parm.output.timeperframe.denominator = fps_n;
4691
4692 if (streamparm.parm.output.timeperframe.numerator > 0 &&
4693 streamparm.parm.output.timeperframe.denominator > 0)
4694 {
4695 /* get new values */
4696 fps_d = streamparm.parm.output.timeperframe.numerator;
4697 fps_n = streamparm.parm.output.timeperframe.denominator;
4698
4699 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set output framerate to %u/%u",
4700 fps_n, fps_d);
4701 }
4702 else
4703 {
4704 /* fix v4l2 output driver to provide framerate values */
4705 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4706 "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
4707 }
4708
4709 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4710 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4711 }
4712
4713done:
4714 /* add boolean return, so we can fail on drivers bugs */
4715 gst_aml_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info, &align);
4716
4717 /* now configure the pool */
4718 if (!gst_aml_v4l2_object_setup_pool (v4l2object, caps))
4719 goto pool_failed;
4720
4721 return TRUE;
4722
4723 /* ERRORS */
4724invalid_caps:
4725 {
4726 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
4727 caps);
4728
4729 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4730 (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps));
4731 return FALSE;
4732 }
4733try_fmt_failed:
4734 {
4735 if (errno == EINVAL)
4736 {
4737 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4738 (_("Device '%s' has no supported format"), v4l2object->videodev),
4739 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4740 GST_FOURCC_ARGS (pixelformat), width, height,
4741 g_strerror (errno)));
4742 }
4743 else
4744 {
4745 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4746 (_("Device '%s' failed during initialization"),
4747 v4l2object->videodev),
4748 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4749 GST_FOURCC_ARGS (pixelformat), width, height,
4750 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004751 }
4752 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004753 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004754set_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004755 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004756 if (errno == EBUSY)
4757 {
bo.xiao857b8682024-09-12 16:40:32 +08004758 GST_AML_V4L2_ERROR (error, RESOURCE, BUSY,
4759 (_("Device '%s' is busy"), v4l2object->videodev),
4760 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4761 GST_FOURCC_ARGS (pixelformat), width, height,
4762 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004763 }
4764 else if (errno == EINVAL)
4765 {
bo.xiao857b8682024-09-12 16:40:32 +08004766 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4767 (_("Device '%s' has no supported format"), v4l2object->videodev),
4768 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4769 GST_FOURCC_ARGS (pixelformat), width, height,
4770 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004771 }
4772 else
4773 {
bo.xiao857b8682024-09-12 16:40:32 +08004774 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4775 (_("Device '%s' failed during initialization"),
4776 v4l2object->videodev),
4777 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4778 GST_FOURCC_ARGS (pixelformat), width, height,
4779 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004780 }
4781 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004782 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004783invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08004784 {
4785 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4786 (_("Device '%s' cannot capture at %dx%d"),
4787 v4l2object->videodev, width, height),
4788 ("Tried to capture at %dx%d, but device returned size %dx%d",
4789 width, height, format.fmt.pix.width, format.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004790 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004791 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004792invalid_pixelformat:
bo.xiao857b8682024-09-12 16:40:32 +08004793 {
4794 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4795 (_("Device '%s' cannot capture in the specified format"),
4796 v4l2object->videodev),
4797 ("Tried to capture in %" GST_FOURCC_FORMAT
4798 ", but device returned format" " %" GST_FOURCC_FORMAT,
4799 GST_FOURCC_ARGS (pixelformat),
4800 GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004801 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004802 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004803invalid_planes:
bo.xiao857b8682024-09-12 16:40:32 +08004804 {
4805 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4806 (_("Device '%s' does support non-contiguous planes"),
4807 v4l2object->videodev),
4808 ("Device wants %d planes", format.fmt.pix_mp.num_planes));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004809 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004810 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004811invalid_field:
bo.xiao857b8682024-09-12 16:40:32 +08004812 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004813 enum v4l2_field wanted_field;
4814
4815 if (is_mplane)
bo.xiao857b8682024-09-12 16:40:32 +08004816 wanted_field = format.fmt.pix_mp.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004817 else
bo.xiao857b8682024-09-12 16:40:32 +08004818 wanted_field = format.fmt.pix.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004819
bo.xiao857b8682024-09-12 16:40:32 +08004820 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4821 (_("Device '%s' does not support %s interlacing"),
4822 v4l2object->videodev,
4823 field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
4824 ("Device wants %s interlacing",
4825 wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004826 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004827 }
hanghang.luo3128f102022-08-18 10:36:19 +08004828#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08004829invalid_colorimetry:
bo.xiao857b8682024-09-12 16:40:32 +08004830 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004831 gchar *wanted_colorimetry;
4832
bo.xiao857b8682024-09-12 16:40:32 +08004833 wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004834
bo.xiao857b8682024-09-12 16:40:32 +08004835 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4836 (_("Device '%s' does not support %s colorimetry"),
4837 v4l2object->videodev, gst_structure_get_string (s, "colorimetry")),
4838 ("Device wants %s colorimetry", wanted_colorimetry));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004839
bo.xiao857b8682024-09-12 16:40:32 +08004840 g_free (wanted_colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004841 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004842 }
hanghang.luo3128f102022-08-18 10:36:19 +08004843#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08004844get_parm_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004845 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004846 /* it's possible that this call is not supported */
4847 if (errno != EINVAL && errno != ENOTTY)
4848 {
bo.xiao857b8682024-09-12 16:40:32 +08004849 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4850 (_("Could not get parameters on device '%s'"),
4851 v4l2object->videodev), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004852 }
4853 goto done;
bo.xiao857b8682024-09-12 16:40:32 +08004854 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004855pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004856 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004857 /* setup_pool already send the error */
4858 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004859 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004860}
4861
4862gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004863gst_aml_v4l2_object_set_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4864 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004865{
bo.xiao857b8682024-09-12 16:40:32 +08004866 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
4867 caps);
4868 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, FALSE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004869}
4870
4871gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004872gst_aml_v4l2_object_try_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4873 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004874{
bo.xiao857b8682024-09-12 16:40:32 +08004875 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
4876 caps);
4877 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004878}
4879
4880GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004881gst_aml_v4l2_object_poll (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004882{
bo.xiao857b8682024-09-12 16:40:32 +08004883 gint ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004884
bo.xiao857b8682024-09-12 16:40:32 +08004885 if (!v4l2object->can_poll_device)
4886 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004887
bo.xiao857b8682024-09-12 16:40:32 +08004888 GST_LOG_OBJECT (v4l2object, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004889
4890again:
bo.xiao857b8682024-09-12 16:40:32 +08004891 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
4892 if (G_UNLIKELY (ret < 0))
4893 {
4894 switch (errno)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004895 {
bo.xiao857b8682024-09-12 16:40:32 +08004896 case EBUSY:
4897 goto stopped;
4898 case EAGAIN:
4899 case EINTR:
4900 goto again;
4901 case ENXIO:
4902 GST_WARNING_OBJECT (v4l2object,
4903 "v4l2 device doesn't support polling. Disabling"
4904 " using libv4l2 in this case may cause deadlocks");
4905 v4l2object->can_poll_device = FALSE;
4906 goto done;
4907 default:
4908 goto select_error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004909 }
bo.xiao857b8682024-09-12 16:40:32 +08004910 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004911
4912done:
bo.xiao857b8682024-09-12 16:40:32 +08004913 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004914
bo.xiao857b8682024-09-12 16:40:32 +08004915 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004916stopped:
bo.xiao857b8682024-09-12 16:40:32 +08004917 {
4918 GST_DEBUG_OBJECT (v4l2object, "stop called");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004919 return GST_FLOW_FLUSHING;
bo.xiao857b8682024-09-12 16:40:32 +08004920 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004921select_error:
bo.xiao857b8682024-09-12 16:40:32 +08004922 {
4923 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
4924 ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004925 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004926 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004927}
4928
4929GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004930gst_aml_v4l2_object_dqevent (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004931{
bo.xiao857b8682024-09-12 16:40:32 +08004932 GstFlowReturn res;
4933 struct v4l2_event evt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004934
bo.xiao857b8682024-09-12 16:40:32 +08004935 if ((res = gst_aml_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
4936 goto poll_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004937
bo.xiao857b8682024-09-12 16:40:32 +08004938 //only read v4l2 pri event
4939 if (!gst_poll_fd_can_read_pri(v4l2object->poll, &v4l2object->pollfd))
4940 {
4941 GST_DEBUG_OBJECT(v4l2object, "not v4l2 pri event");
4942 return GST_FLOW_OK;
4943 }
4944 memset (&evt, 0x00, sizeof (struct v4l2_event));
4945 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
4946 goto dqevent_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004947
bo.xiao857b8682024-09-12 16:40:32 +08004948 switch (evt.type)
4949 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004950 case V4L2_EVENT_SOURCE_CHANGE:
bo.xiao857b8682024-09-12 16:40:32 +08004951 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
4952 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004953 case V4L2_EVENT_EOS:
bo.xiao857b8682024-09-12 16:40:32 +08004954 return GST_AML_V4L2_FLOW_LAST_BUFFER;
4955 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004956 default:
bo.xiao857b8682024-09-12 16:40:32 +08004957 break;
4958 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004959
bo.xiao857b8682024-09-12 16:40:32 +08004960 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004961
bo.xiao857b8682024-09-12 16:40:32 +08004962 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004963poll_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004964 {
4965 GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004966 return res;
bo.xiao857b8682024-09-12 16:40:32 +08004967 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004968dqevent_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004969 {
fei.deng678f7052024-07-10 20:11:26 +08004970 GST_DEBUG_OBJECT(v4l2object, "dqevent failed");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004971 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004972 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004973}
4974
4975/**
4976 * gst_aml_v4l2_object_acquire_format:
bo.xiao857b8682024-09-12 16:40:32 +08004977 * @v4l2object: the object
4978 * @info: a GstVideoInfo to be filled
xuesong.jiangae1548e2022-05-06 16:38:46 +08004979 *
bo.xiao857b8682024-09-12 16:40:32 +08004980 * Acquire the driver chosen format. This is useful in decoder or encoder elements where
4981 * the output format is chosen by the HW.
xuesong.jiangae1548e2022-05-06 16:38:46 +08004982 *
4983 * Returns: %TRUE on success, %FALSE on failure.
4984 */
4985gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004986gst_aml_v4l2_object_acquire_format (GstAmlV4l2Object * v4l2object, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004987{
le.han3b118242024-09-29 06:32:02 +00004988 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao857b8682024-09-12 16:40:32 +08004989 struct v4l2_fmtdesc *fmtdesc;
4990 struct v4l2_format fmt;
4991 struct v4l2_crop crop;
4992 struct v4l2_selection sel;
4993 struct v4l2_cropcap cropcap;
4994 struct v4l2_rect *r = NULL;
4995 GstVideoFormat format;
4996 guint width, height;
4997 GstVideoAlignment align;
4998 gdouble pixelAspectRatio = 0.0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004999
bo.xiao857b8682024-09-12 16:40:32 +08005000 gst_video_info_init (info);
5001 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005002
bo.xiao857b8682024-09-12 16:40:32 +08005003 memset (&fmt, 0x00, sizeof (struct v4l2_format));
5004 fmt.type = v4l2object->type;
5005 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "fmt.type:%d", fmt.type);
5006 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
5007 goto get_fmt_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005008
bo.xiao857b8682024-09-12 16:40:32 +08005009 fmtdesc = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object,
5010 fmt.fmt.pix.pixelformat);
5011 if (fmtdesc == NULL)
5012 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005013
bo.xiao857b8682024-09-12 16:40:32 +08005014 /* No need to care about mplane, the four first params are the same */
5015 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005016
bo.xiao857b8682024-09-12 16:40:32 +08005017 /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
5018 if (format == GST_VIDEO_FORMAT_UNKNOWN)
5019 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005020
bo.xiao857b8682024-09-12 16:40:32 +08005021 if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
5022 goto invalid_dimensions;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005023
hanghang.luo3eeb8b32024-12-23 17:38:00 +08005024 switch (fmt.fmt.pix.field)
5025 {
5026 case V4L2_FIELD_ANY:
5027 case V4L2_FIELD_NONE:
5028 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
5029 break;
5030 case V4L2_FIELD_INTERLACED:
5031 case V4L2_FIELD_INTERLACED_TB:
5032 case V4L2_FIELD_INTERLACED_BT:
5033 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
5034 break;
5035 default:
5036 goto unsupported_field;
5037 }
5038
5039 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY && info->interlace_mode != GST_VIDEO_INTERLACE_MODE_INTERLEAVED)
le.han3b118242024-09-29 06:32:02 +00005040 {
5041 self->v4l2output->stride = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
5042 //because driver return src w,h when AFBC_ONLY
5043 fmt.fmt.pix.width = fmt.fmt.pix.height = 64;
5044 fmt.fmt.pix_mp.plane_fmt[0].bytesperline = fmt.fmt.pix_mp.plane_fmt[1].bytesperline = 64;
5045 }
5046
bo.xiao857b8682024-09-12 16:40:32 +08005047 width = fmt.fmt.pix.width;
5048 height = fmt.fmt.pix.height;
5049
5050 /* Use the default compose rectangle */
5051 memset (&sel, 0, sizeof (struct v4l2_selection));
5052 sel.type = v4l2object->type;
5053 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
5054 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
5055 {
5056 r = &sel.r;
5057 }
5058 else
5059 {
5060 /* For ancient kernels, fall back to G_CROP */
5061 memset (&crop, 0, sizeof (struct v4l2_crop));
5062 crop.type = v4l2object->type;
5063 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
5064 r = &crop.c;
5065 }
5066
5067 if (r)
5068 {
bo.xiao857b8682024-09-12 16:40:32 +08005069 align.padding_left = r->left;
5070 align.padding_top = r->top;
5071 align.padding_right = width - r->width - r->left;
5072 align.padding_bottom = height - r->height - r->top;
5073 width = r->width;
5074 height = r->height;
5075
5076 if (self->v4l2output->dw_mode >= 0 && self->v4l2output->dw_mode != VDEC_DW_NO_AFBC)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005077 {
bo.xiao857b8682024-09-12 16:40:32 +08005078 width = (width/2) *2; // align for dw
5079 height = (height/2) *2; // align for dw
xuesong.jiangae1548e2022-05-06 16:38:46 +08005080 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005081
hanghang.luo3eeb8b32024-12-23 17:38:00 +08005082 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY && info->interlace_mode != GST_VIDEO_INTERLACE_MODE_INTERLEAVED)
bo.xiao857b8682024-09-12 16:40:32 +08005083 height = width = 64; //because driver return src w,h when AFBC_ONLY
5084 }
5085 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "final w:%d, h:%d", width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005086
bo.xiao857b8682024-09-12 16:40:32 +08005087 gst_video_info_set_format(info, format, width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005088
bo.xiao857b8682024-09-12 16:40:32 +08005089 switch (fmt.fmt.pix.field)
5090 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005091 case V4L2_FIELD_ANY:
5092 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08005093 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
5094 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005095 case V4L2_FIELD_INTERLACED:
5096 case V4L2_FIELD_INTERLACED_TB:
5097 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08005098 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
5099 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005100 default:
bo.xiao857b8682024-09-12 16:40:32 +08005101 goto unsupported_field;
5102 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005103
bo.xiao857b8682024-09-12 16:40:32 +08005104 gst_aml_v4l2_object_get_colorspace(&fmt, &info->colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005105
bo.xiao857b8682024-09-12 16:40:32 +08005106 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &fmt, info, &align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005107
bo.xiao857b8682024-09-12 16:40:32 +08005108 if (v4l2object->par)
5109 {
5110 width = gst_value_get_fraction_numerator(v4l2object->par);
5111 height = gst_value_get_fraction_denominator(v4l2object->par);
5112 pixelAspectRatio = (gdouble)width/(gdouble)height;
5113 }
sheng.liu641aa422023-12-26 07:05:59 +00005114
bo.xiao857b8682024-09-12 16:40:32 +08005115 if (!v4l2object->par || pixelAspectRatio == 1.0)
5116 {
5117 memset(&cropcap, 0, sizeof(cropcap));
5118 width= height= 1;
5119 cropcap.type = v4l2object->type;
5120 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) >= 0)
5121 {
5122 width= cropcap.pixelaspect.denominator;
5123 height= cropcap.pixelaspect.numerator;
5124 GST_DEBUG("cropcap: pixel aspect ratio %d:%d", width, height);
5125 if ( !width || !height )
5126 {
5127 GST_DEBUG("force pixel aspect of 1:1");
5128 width= height= 1;
5129 }
5130 }
5131 }
sheng.liudb26f7d2024-01-22 11:24:23 +00005132
bo.xiao857b8682024-09-12 16:40:32 +08005133 GST_VIDEO_INFO_PAR_N(info) = width;
5134 GST_VIDEO_INFO_PAR_D(info) = height;
sheng.liud9027ca2024-01-24 09:21:49 +00005135
bo.xiao857b8682024-09-12 16:40:32 +08005136 if (v4l2object->fps)
5137 {
5138 GST_VIDEO_INFO_FPS_N(info) = gst_value_get_fraction_numerator(v4l2object->fps);
5139 GST_VIDEO_INFO_FPS_D(info) = gst_value_get_fraction_denominator(v4l2object->fps);
5140 }
5141 /* Shall we setup the pool ? */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005142
bo.xiao857b8682024-09-12 16:40:32 +08005143 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005144
5145get_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005146 {
5147 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5148 (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005149 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005150 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005151invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08005152 {
5153 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5154 (_("Video device returned invalid dimensions.")),
5155 ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
5156 fmt.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005157 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005158 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005159unsupported_field:
bo.xiao857b8682024-09-12 16:40:32 +08005160 {
5161 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5162 (_("Video device uses an unsupported interlacing method.")),
5163 ("V4L2 field type %d not supported", fmt.fmt.pix.field));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005164 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005165 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005166unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08005167 {
5168 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5169 (_("Video device uses an unsupported pixel format.")),
5170 ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
5171 GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005172 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005173 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005174}
5175
5176gboolean
hanghang.luoe80a8882024-11-29 17:02:12 +08005177gst_aml_v4l2_object_set_crop (GstAmlV4l2Object *obj)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005178{
bo.xiao857b8682024-09-12 16:40:32 +08005179 struct v4l2_selection sel = { 0 };
5180 struct v4l2_crop crop = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005181
bo.xiao857b8682024-09-12 16:40:32 +08005182 sel.type = obj->type;
5183 sel.target = V4L2_SEL_TGT_CROP;
5184 sel.flags = 0;
5185 sel.r.left = obj->align.padding_left;
5186 sel.r.top = obj->align.padding_top;
5187 sel.r.width = obj->info.width;
5188 sel.r.height = obj->info.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005189
bo.xiao857b8682024-09-12 16:40:32 +08005190 crop.type = obj->type;
5191 crop.c = sel.r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005192
bo.xiao857b8682024-09-12 16:40:32 +08005193 if (obj->align.padding_left + obj->align.padding_top +
5194 obj->align.padding_right + obj->align.padding_bottom ==
5195 0)
5196 {
5197 GST_DEBUG_OBJECT(obj->dbg_obj, "no cropping needed");
5198 return TRUE;
5199 }
5200
5201 GST_DEBUG_OBJECT (obj->dbg_obj,
5202 "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5203 crop.c.width, crop.c.height);
5204
5205 if (obj->ioctl (obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0)
5206 {
5207 if (errno != ENOTTY)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005208 {
bo.xiao857b8682024-09-12 16:40:32 +08005209 GST_WARNING_OBJECT (obj->dbg_obj,
5210 "Failed to set crop rectangle with VIDIOC_S_SELECTION: %s",
5211 g_strerror (errno));
5212 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005213 }
bo.xiao857b8682024-09-12 16:40:32 +08005214 else
xuesong.jiangae1548e2022-05-06 16:38:46 +08005215 {
bo.xiao857b8682024-09-12 16:40:32 +08005216 if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0)
5217 {
5218 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_S_CROP failed");
5219 return FALSE;
5220 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005221
bo.xiao857b8682024-09-12 16:40:32 +08005222 if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0)
5223 {
5224 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_G_CROP failed");
5225 return FALSE;
5226 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005227
bo.xiao857b8682024-09-12 16:40:32 +08005228 sel.r = crop.c;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005229 }
bo.xiao857b8682024-09-12 16:40:32 +08005230 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005231
bo.xiao857b8682024-09-12 16:40:32 +08005232 GST_DEBUG_OBJECT (obj->dbg_obj,
5233 "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5234 crop.c.width, crop.c.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005235
bo.xiao857b8682024-09-12 16:40:32 +08005236 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005237}
5238
5239gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005240gst_aml_v4l2_object_caps_equal (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005241{
bo.xiao857b8682024-09-12 16:40:32 +08005242 GstStructure *config;
5243 GstCaps *oldcaps;
5244 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005245
bo.xiao857b8682024-09-12 16:40:32 +08005246 if (!v4l2object->pool)
5247 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005248
bo.xiao857b8682024-09-12 16:40:32 +08005249 config = gst_buffer_pool_get_config(v4l2object->pool);
5250 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005251
bo.xiao857b8682024-09-12 16:40:32 +08005252 ret = oldcaps && gst_caps_is_equal (caps, oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005253
bo.xiao857b8682024-09-12 16:40:32 +08005254 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005255
bo.xiao857b8682024-09-12 16:40:32 +08005256 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005257}
5258
5259gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005260gst_aml_v4l2_object_caps_is_subset (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005261{
bo.xiao857b8682024-09-12 16:40:32 +08005262 GstStructure *config;
5263 GstCaps *oldcaps;
5264 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005265
bo.xiao857b8682024-09-12 16:40:32 +08005266 if (!v4l2object->pool)
5267 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005268
bo.xiao857b8682024-09-12 16:40:32 +08005269 config = gst_buffer_pool_get_config(v4l2object->pool);
5270 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005271
bo.xiao857b8682024-09-12 16:40:32 +08005272 ret = oldcaps && gst_caps_is_subset (oldcaps, caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005273
bo.xiao857b8682024-09-12 16:40:32 +08005274 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005275
bo.xiao857b8682024-09-12 16:40:32 +08005276 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005277}
5278
5279GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005280gst_aml_v4l2_object_get_current_caps (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005281{
bo.xiao857b8682024-09-12 16:40:32 +08005282 GstStructure *config;
5283 GstCaps *oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005284
bo.xiao857b8682024-09-12 16:40:32 +08005285 if (!v4l2object->pool)
5286 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005287
bo.xiao857b8682024-09-12 16:40:32 +08005288 config = gst_buffer_pool_get_config(v4l2object->pool);
5289 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005290
bo.xiao857b8682024-09-12 16:40:32 +08005291 if (oldcaps)
5292 gst_caps_ref (oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005293
bo.xiao857b8682024-09-12 16:40:32 +08005294 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005295
bo.xiao857b8682024-09-12 16:40:32 +08005296 return oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005297}
5298
5299gboolean
hanghang.luoe80a8882024-11-29 17:02:12 +08005300gst_aml_v4l2_object_flush_start (GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005301{
bo.xiao857b8682024-09-12 16:40:32 +08005302 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005303
bo.xiao857b8682024-09-12 16:40:32 +08005304 GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005305
bo.xiao857b8682024-09-12 16:40:32 +08005306 gst_poll_set_flushing (v4l2object->poll, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005307
bo.xiao857b8682024-09-12 16:40:32 +08005308 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5309 gst_buffer_pool_set_flushing(v4l2object->pool, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005310
bo.xiao857b8682024-09-12 16:40:32 +08005311 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005312}
5313
5314gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005315gst_aml_v4l2_object_flush_stop(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005316{
bo.xiao857b8682024-09-12 16:40:32 +08005317 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005318
bo.xiao857b8682024-09-12 16:40:32 +08005319 GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005320
bo.xiao857b8682024-09-12 16:40:32 +08005321 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5322 gst_buffer_pool_set_flushing(v4l2object->pool, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005323
bo.xiao857b8682024-09-12 16:40:32 +08005324 gst_poll_set_flushing(v4l2object->poll, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005325
bo.xiao857b8682024-09-12 16:40:32 +08005326 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005327}
5328
5329gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005330gst_aml_v4l2_object_stop (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005331{
bo.xiao857b8682024-09-12 16:40:32 +08005332 GstAmlV4l2BufferPool *bpool = GST_AML_V4L2_BUFFER_POOL(v4l2object->pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005333
bo.xiao857b8682024-09-12 16:40:32 +08005334 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stopping");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005335
bo.xiao857b8682024-09-12 16:40:32 +08005336 if (!GST_AML_V4L2_IS_OPEN (v4l2object))
5337 goto done;
5338 if (!GST_AML_V4L2_IS_ACTIVE (v4l2object))
5339 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005340
bo.xiao857b8682024-09-12 16:40:32 +08005341 if (bpool && bpool->other_pool) /* jxsdbg for resolution switch */
5342 {
5343 if (v4l2object->old_other_pool)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005344 {
bo.xiao857b8682024-09-12 16:40:32 +08005345 /* this case indicate 1st switch did not wait all old pool buf recycle and 2nd switch is coming.
5346 so save 1st old pool */
5347 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching occurs during last switching buf recycle flow");
5348 v4l2object->old_old_other_pool = v4l2object->old_other_pool;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005349 }
5350
bo.xiao857b8682024-09-12 16:40:32 +08005351 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching flow, ref old drmbufferpool");
5352 v4l2object->old_other_pool = bpool->other_pool;
5353 gst_object_ref(v4l2object->old_other_pool);
5354 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005355
bo.xiao857b8682024-09-12 16:40:32 +08005356 if (v4l2object->pool)
5357 {
5358 if (!gst_aml_v4l2_buffer_pool_orphan(&v4l2object->pool))
5359 {
5360 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "deactivating pool");
5361 gst_buffer_pool_set_active(v4l2object->pool, FALSE);
5362 gst_object_unref(v4l2object->pool);
5363 }
5364 v4l2object->pool = NULL;
5365 }
5366
5367 GST_AML_V4L2_SET_INACTIVE (v4l2object);
5368 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "stopped");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005369done:
bo.xiao857b8682024-09-12 16:40:32 +08005370 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005371}
5372
5373GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005374gst_aml_v4l2_object_probe_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005375{
bo.xiao857b8682024-09-12 16:40:32 +08005376 GstCaps *ret;
5377 GSList *walk;
5378 GSList *formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005379
bo.xiao857b8682024-09-12 16:40:32 +08005380 GST_INFO_OBJECT(v4l2object->dbg_obj, "filter caps: %" GST_PTR_FORMAT, filter);
5381 formats = gst_aml_v4l2_object_get_format_list (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005382
bo.xiao857b8682024-09-12 16:40:32 +08005383 ret = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005384
sheng.liu641aa422023-12-26 07:05:59 +00005385// At this time, decoder will return defult aspect, and it is not usful.
5386// so, do not probe cropcap at this time and do this action after decoding.
5387#if 0
bo.xiao857b8682024-09-12 16:40:32 +08005388 if (v4l2object->keep_aspect && !v4l2object->par)
5389 {
5390 struct v4l2_cropcap cropcap;
5391
5392 memset (&cropcap, 0, sizeof (cropcap));
5393
5394 cropcap.type = v4l2object->type;
5395 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005396 {
bo.xiao857b8682024-09-12 16:40:32 +08005397 if (errno != ENOTTY)
5398 GST_WARNING_OBJECT (v4l2object->dbg_obj,
5399 "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
5400 g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005401 }
bo.xiao857b8682024-09-12 16:40:32 +08005402 else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator)
5403 {
5404 v4l2object->par = g_new0 (GValue, 1);
5405 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
5406 gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
5407 cropcap.pixelaspect.denominator);
5408 }
5409 }
sheng.liu641aa422023-12-26 07:05:59 +00005410#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08005411
bo.xiao857b8682024-09-12 16:40:32 +08005412 for (walk = formats; walk; walk = walk->next)
5413 {
5414 struct v4l2_fmtdesc *format;
5415 GstStructure *template;
5416 GstCaps *tmp, *tmp2;
5417
5418 format = (struct v4l2_fmtdesc *) walk->data;
5419
5420 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (format->pixelformat);
5421
5422 if (!template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005423 {
bo.xiao857b8682024-09-12 16:40:32 +08005424 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
5425 "unknown format %" GST_FOURCC_FORMAT,
5426 GST_FOURCC_ARGS (format->pixelformat));
5427 continue;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005428 }
5429
bo.xiao857b8682024-09-12 16:40:32 +08005430 /* If we have a filter, check if we need to probe this format or not */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005431 if (filter)
5432 {
bo.xiao857b8682024-09-12 16:40:32 +08005433 GstCaps *format_caps = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005434
bo.xiao857b8682024-09-12 16:40:32 +08005435 gst_caps_append_structure (format_caps, gst_structure_copy (template));
5436 GST_INFO_OBJECT(v4l2object->dbg_obj, "format_caps: %" GST_PTR_FORMAT, format_caps);
5437
5438 if (!gst_caps_can_intersect (format_caps, filter))
5439 {
5440 gst_caps_unref (format_caps);
5441 gst_structure_free (template);
5442 continue;
5443 }
5444
5445 gst_caps_unref (format_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005446 }
5447
bo.xiao857b8682024-09-12 16:40:32 +08005448 tmp = gst_aml_v4l2_object_probe_caps_for_format (v4l2object,
5449 format->pixelformat, template);
5450 GST_INFO_OBJECT(v4l2object->dbg_obj, "tmp caps: %" GST_PTR_FORMAT, tmp);
5451
5452 if (tmp)
xuesong.jiang22a9b112023-05-24 09:01:59 +00005453 {
bo.xiao857b8682024-09-12 16:40:32 +08005454 tmp2 = gst_caps_copy(tmp);
5455 gst_caps_set_features_simple(tmp2, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
5456 gst_caps_append (ret, tmp);
5457 gst_caps_append (ret, tmp2);
xuesong.jiang22a9b112023-05-24 09:01:59 +00005458 }
5459
bo.xiao857b8682024-09-12 16:40:32 +08005460 gst_structure_free (template);
5461 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005462
bo.xiao857b8682024-09-12 16:40:32 +08005463 if (filter)
5464 {
5465 GstCaps *tmp;
5466
5467 tmp = ret;
5468 ret = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
5469 gst_caps_unref (tmp);
5470 }
5471
5472 if (v4l2object->stream_mode)
5473 {
5474 GST_INFO_OBJECT(v4l2object->dbg_obj, "ret caps: %" GST_PTR_FORMAT, ret);
5475 for (guint i = 0; i < gst_caps_get_size(ret); i++)
5476 {
5477 GstStructure *s = gst_caps_get_structure(ret, i);
5478 if (s)
5479 gst_structure_remove_field(s, "alignment");
5480
5481 GST_DEBUG("i:%d, s:%p", i, s);
5482 }
5483 GST_INFO_OBJECT(v4l2object->dbg_obj, "new ret caps: %" GST_PTR_FORMAT, ret);
5484 }
5485
5486 GST_INFO_OBJECT (v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
5487
5488 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005489}
5490
5491GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005492gst_aml_v4l2_object_get_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005493{
bo.xiao857b8682024-09-12 16:40:32 +08005494 GstCaps *ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005495
bo.xiao857b8682024-09-12 16:40:32 +08005496 if (v4l2object->probed_caps == NULL)
5497 v4l2object->probed_caps = gst_aml_v4l2_object_probe_caps (v4l2object, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005498
bo.xiao857b8682024-09-12 16:40:32 +08005499 if (filter)
5500 {
5501 ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
5502 GST_CAPS_INTERSECT_FIRST);
5503 }
5504 else
5505 {
5506 ret = gst_caps_ref (v4l2object->probed_caps);
5507 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005508
bo.xiao857b8682024-09-12 16:40:32 +08005509 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005510}
5511
5512gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005513gst_aml_v4l2_object_decide_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005514{
bo.xiao857b8682024-09-12 16:40:32 +08005515 GstCaps *caps;
5516 GstBufferPool *pool = NULL, *other_pool = NULL;
5517 GstStructure *config;
5518 guint size, min, max, own_min = 0;
5519 gboolean update;
5520 gboolean has_video_meta;
5521 gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
5522 GstAllocator *allocator = NULL;
5523 GstAllocationParams params = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005524
bo.xiao857b8682024-09-12 16:40:32 +08005525 GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005526
bo.xiao857b8682024-09-12 16:40:32 +08005527 g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
5528 obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005529
bo.xiao857b8682024-09-12 16:40:32 +08005530 gst_query_parse_allocation (query, &caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005531
bo.xiao857b8682024-09-12 16:40:32 +08005532 if (obj->pool == NULL)
5533 {
5534 if (!gst_aml_v4l2_object_setup_pool (obj, caps))
5535 goto pool_failed;
5536 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005537
bo.xiao857b8682024-09-12 16:40:32 +08005538 if (gst_query_get_n_allocation_params (query) > 0)
5539 gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005540
bo.xiao857b8682024-09-12 16:40:32 +08005541 if (gst_query_get_n_allocation_pools (query) > 0)
5542 {
5543 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
5544 update = TRUE;
5545 }
5546 else
5547 {
5548 pool = NULL;
5549 min = max = 0;
5550 size = 0;
5551 update = FALSE;
5552 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005553
bo.xiao857b8682024-09-12 16:40:32 +08005554 GST_DEBUG_OBJECT (obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%"
5555 GST_PTR_FORMAT, size, min, max, pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005556
bo.xiao857b8682024-09-12 16:40:32 +08005557 has_video_meta =
5558 gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005559
bo.xiao857b8682024-09-12 16:40:32 +08005560 can_share_own_pool = (has_video_meta || !obj->need_video_meta);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005561
bo.xiao857b8682024-09-12 16:40:32 +08005562 gst_aml_v4l2_get_driver_min_buffers (obj);
5563 /* We can't share our own pool, if it exceed V4L2 capacity */
5564 if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
5565 can_share_own_pool = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005566
bo.xiao857b8682024-09-12 16:40:32 +08005567 /* select a pool */
5568 switch (obj->mode)
5569 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005570 case GST_V4L2_IO_RW:
bo.xiao857b8682024-09-12 16:40:32 +08005571 if (pool)
5572 {
5573 /* in READ/WRITE mode, prefer a downstream pool because our own pool
5574 * doesn't help much, we have to write to it as well */
5575 GST_DEBUG_OBJECT (obj->dbg_obj,
5576 "read/write mode: using downstream pool");
5577 /* use the bigest size, when we use our own pool we can't really do any
5578 * other size than what the hardware gives us but for downstream pools
5579 * we can try */
5580 size = MAX (size, obj->info.size);
5581 }
5582 else if (can_share_own_pool)
5583 {
5584 /* no downstream pool, use our own then */
5585 GST_DEBUG_OBJECT (obj->dbg_obj,
5586 "read/write mode: no downstream pool, using our own");
5587 pool = gst_object_ref(obj->pool);
5588 size = obj->info.size;
5589 pushing_from_our_pool = TRUE;
5590 }
5591 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005592
5593 case GST_V4L2_IO_USERPTR:
5594 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005595 /* in importing mode, prefer our own pool, and pass the other pool to
5596 * our own, so it can serve itself */
5597 if (pool == NULL)
5598 goto no_downstream_pool;
5599 gst_aml_v4l2_buffer_pool_set_other_pool(GST_AML_V4L2_BUFFER_POOL(obj->pool), pool);
5600 other_pool = pool;
5601 gst_object_unref (pool);
5602 pool = gst_object_ref(obj->pool);
5603 size = obj->info.size;
5604 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005605
5606 case GST_V4L2_IO_MMAP:
5607 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005608 /* in streaming mode, prefer our own pool */
5609 /* Check if we can use it ... */
5610 if (can_share_own_pool)
5611 {
5612 if (pool)
5613 gst_object_unref (pool);
5614 pool = gst_object_ref (obj->pool);
5615 size = obj->info.size;
5616 GST_DEBUG_OBJECT (obj->dbg_obj,
5617 "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
5618 pushing_from_our_pool = TRUE;
5619 }
5620 else if (pool)
5621 {
5622 GST_DEBUG_OBJECT (obj->dbg_obj,
5623 "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
5624 pool);
5625 }
5626 else
5627 {
5628 GST_DEBUG_OBJECT (obj->dbg_obj,
5629 "streaming mode: no usable pool, copying to generic pool");
5630 size = MAX (size, obj->info.size);
5631 }
5632 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005633 case GST_V4L2_IO_AUTO:
5634 default:
bo.xiao857b8682024-09-12 16:40:32 +08005635 GST_WARNING_OBJECT (obj->dbg_obj, "unhandled mode");
5636 break;
5637 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005638
bo.xiao857b8682024-09-12 16:40:32 +08005639 if (size == 0)
5640 goto no_size;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005641
bo.xiao857b8682024-09-12 16:40:32 +08005642 /* If pushing from our own pool, configure it with queried minimum,
5643 * otherwise use the minimum required */
5644 if (pushing_from_our_pool)
5645 {
5646 /* When pushing from our own pool, we need what downstream one, to be able
5647 * to fill the pipeline, the minimum required to decoder according to the
5648 * driver and 2 more, so we don't endup up with everything downstream or
5649 * held by the decoder. We account 2 buffers for v4l2 so when one is being
5650 * pushed downstream the other one can already be queued for the next
5651 * frame. */
5652 own_min = min + obj->min_buffers + 2;
5653
5654 /* If no allocation parameters where provided, allow for a little more
5655 * buffers and enable copy threshold */
5656 if (!update)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005657 {
bo.xiao857b8682024-09-12 16:40:32 +08005658 own_min += 2;
5659 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5660 TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005661 }
5662 else
5663 {
bo.xiao857b8682024-09-12 16:40:32 +08005664 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5665 FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005666 }
5667
bo.xiao857b8682024-09-12 16:40:32 +08005668 }
5669 else
5670 {
5671 min = obj->min_buffers;
5672 max = min;
5673 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005674
bo.xiao857b8682024-09-12 16:40:32 +08005675 /* Request a bigger max, if one was suggested but it's too small */
5676 if (max != 0)
5677 max = MAX (min, max);
5678
5679 /* First step, configure our own pool */
5680 config = gst_buffer_pool_get_config(obj->pool);
5681
5682 if (obj->need_video_meta || has_video_meta)
5683 {
5684 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5685 gst_buffer_pool_config_add_option (config,
5686 GST_BUFFER_POOL_OPTION_VIDEO_META);
5687 }
5688
5689 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5690 gst_buffer_pool_config_set_params(config, caps, size, min, max);
5691
5692 GST_DEBUG_OBJECT (obj->dbg_obj, "setting own pool config to %"
5693 GST_PTR_FORMAT, config);
5694
5695 /* Our pool often need to adjust the value */
5696 if (!gst_buffer_pool_set_config (obj->pool, config))
5697 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005698 config = gst_buffer_pool_get_config(obj->pool);
5699
bo.xiao857b8682024-09-12 16:40:32 +08005700 GST_DEBUG_OBJECT (obj->dbg_obj, "own pool config changed to %"
5701 GST_PTR_FORMAT, config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005702
bo.xiao857b8682024-09-12 16:40:32 +08005703 /* our pool will adjust the maximum buffer, which we are fine with */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005704 if (!gst_buffer_pool_set_config(obj->pool, config))
bo.xiao857b8682024-09-12 16:40:32 +08005705 goto config_failed;
5706 }
5707
5708 /* Now configure the other pool if different */
5709 if (obj->pool != pool)
5710 other_pool = pool;
5711
5712 if (other_pool)
5713 {
5714 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)obj->element;
5715 guint other_min = min;
5716 guint other_max = max;
5717
5718 if (obj->old_other_pool || obj->old_old_other_pool) //jxsdbg for switching
5719 {
5720 obj->outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
5721 if (obj->outstanding_buf_num > 0) {
5722 if (obj->outstanding_buf_num >= obj->min_buffers)
5723 {
5724 other_min = 1;
5725 }
5726 else
5727 {
5728 other_min = other_max = obj->min_buffers - obj->outstanding_buf_num;
5729 }
5730 }
5731 GST_DEBUG_OBJECT(obj, "oop:%p, ooop:%p, outstanding buf num:%d, set min, max to %d,%d",
5732 obj->old_other_pool, obj->old_old_other_pool,
5733 obj->outstanding_buf_num, other_min, other_max);
5734 }
5735
5736 if (self->is_secure_path)
5737 {
5738 params.flags |= GST_MEMORY_FLAG_LAST << 1; // in drmallocator GST_MEMORY_FLAG_LAST << 1 represent GST_MEMORY_FLAG_SECURE
5739 GST_DEBUG_OBJECT(obj, "set secure flag for drmbufferpool flag:0x%x", params.flags);
5740 }
5741 config = gst_buffer_pool_get_config (other_pool);
5742 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5743 gst_buffer_pool_config_set_params (config, caps, size, other_min, other_max);
5744 gst_buffer_pool_config_set_video_alignment(config, &obj->align);
5745
5746 GST_DEBUG_OBJECT (obj->dbg_obj, "setting other pool config to %"
5747 GST_PTR_FORMAT, config);
5748
5749 /* if downstream supports video metadata, add this to the pool config */
5750 if (has_video_meta)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005751 {
bo.xiao857b8682024-09-12 16:40:32 +08005752 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5753 gst_buffer_pool_config_add_option (config,
5754 GST_BUFFER_POOL_OPTION_VIDEO_META);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005755 }
5756
bo.xiao857b8682024-09-12 16:40:32 +08005757 if (!gst_buffer_pool_set_config (other_pool, config))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005758 {
bo.xiao857b8682024-09-12 16:40:32 +08005759 config = gst_buffer_pool_get_config (other_pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005760
bo.xiao857b8682024-09-12 16:40:32 +08005761 if (!gst_buffer_pool_config_validate_params (config, caps, size, min,
5762 max))
5763 {
5764 gst_structure_free (config);
5765 goto config_failed;
5766 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005767
bo.xiao857b8682024-09-12 16:40:32 +08005768 if (!gst_buffer_pool_set_config (other_pool, config))
5769 goto config_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005770 }
bo.xiao857b8682024-09-12 16:40:32 +08005771 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005772
bo.xiao857b8682024-09-12 16:40:32 +08005773 if (pool)
5774 {
5775 /* For simplicity, simply read back the active configuration, so our base
5776 * class get the right information */
5777 config = gst_buffer_pool_get_config (pool);
5778 gst_buffer_pool_config_get_params (config, NULL, &size, &min, &max);
5779 gst_structure_free (config);
5780 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005781
bo.xiao857b8682024-09-12 16:40:32 +08005782 if (update)
5783 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
5784 else
5785 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005786
bo.xiao857b8682024-09-12 16:40:32 +08005787 if (allocator)
5788 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005789
bo.xiao857b8682024-09-12 16:40:32 +08005790 if (pool)
5791 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005792
bo.xiao857b8682024-09-12 16:40:32 +08005793 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005794
5795pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005796 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005797 /* setup_pool already send the error */
5798 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005799 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005800config_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005801 {
5802 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5803 (_("Failed to configure internal buffer pool.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005804 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005805 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005806no_size:
bo.xiao857b8682024-09-12 16:40:32 +08005807 {
5808 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5809 (_("Video device did not suggest any buffer size.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005810 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005811 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005812cleanup:
bo.xiao857b8682024-09-12 16:40:32 +08005813 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005814 if (allocator)
bo.xiao857b8682024-09-12 16:40:32 +08005815 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005816
5817 if (pool)
bo.xiao857b8682024-09-12 16:40:32 +08005818 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005819 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005820 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005821no_downstream_pool:
bo.xiao857b8682024-09-12 16:40:32 +08005822 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005823 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5824 (_("No downstream pool to import from.")),
5825 ("When importing DMABUF or USERPTR, we need a pool to import from"));
5826 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005827 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005828}
5829
5830gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005831gst_aml_v4l2_object_propose_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005832{
bo.xiao857b8682024-09-12 16:40:32 +08005833 GstBufferPool *pool = NULL;
5834 /* we need at least 2 buffers to operate */
5835 guint size, min, max;
5836 GstCaps *caps;
5837 gboolean need_pool;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005838
bo.xiao857b8682024-09-12 16:40:32 +08005839 /* Set defaults allocation parameters */
5840 size = obj->info.size;
5841 min = GST_AML_V4L2_MIN_BUFFERS;
5842 max = VIDEO_MAX_FRAME;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005843
bo.xiao857b8682024-09-12 16:40:32 +08005844 gst_query_parse_allocation (query, &caps, &need_pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005845
bo.xiao857b8682024-09-12 16:40:32 +08005846 if (caps == NULL)
5847 goto no_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005848
bo.xiao857b8682024-09-12 16:40:32 +08005849 switch (obj->mode)
5850 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005851 case GST_V4L2_IO_MMAP:
5852 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005853 if ((pool = obj->pool))
5854 gst_object_ref(pool);
5855 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005856 default:
bo.xiao857b8682024-09-12 16:40:32 +08005857 pool = NULL;
5858 break;
5859 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005860
bo.xiao857b8682024-09-12 16:40:32 +08005861 if (pool != NULL)
5862 {
5863 GstCaps *pcaps;
5864 GstStructure *config;
5865
5866 /* we had a pool, check caps */
5867 config = gst_buffer_pool_get_config (pool);
5868 gst_buffer_pool_config_get_params (config, &pcaps, NULL, NULL, NULL);
5869
5870 GST_DEBUG_OBJECT (obj->dbg_obj,
5871 "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
5872 if (!gst_caps_is_equal (caps, pcaps))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005873 {
bo.xiao857b8682024-09-12 16:40:32 +08005874 gst_structure_free (config);
5875 gst_object_unref (pool);
5876 goto different_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005877 }
bo.xiao857b8682024-09-12 16:40:32 +08005878 gst_structure_free (config);
5879 }
5880 gst_aml_v4l2_get_driver_min_buffers (obj);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005881
bo.xiao857b8682024-09-12 16:40:32 +08005882 min = MAX(obj->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005883
bo.xiao857b8682024-09-12 16:40:32 +08005884 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005885
bo.xiao857b8682024-09-12 16:40:32 +08005886 /* we also support various metadata */
5887 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005888
bo.xiao857b8682024-09-12 16:40:32 +08005889 if (pool)
5890 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005891
bo.xiao857b8682024-09-12 16:40:32 +08005892 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005893
bo.xiao857b8682024-09-12 16:40:32 +08005894 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005895no_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005896 {
5897 GST_DEBUG_OBJECT (obj->dbg_obj, "no caps specified");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005898 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005899 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005900different_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005901 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005902 /* different caps, we can't use this pool */
bo.xiao857b8682024-09-12 16:40:32 +08005903 GST_DEBUG_OBJECT (obj->dbg_obj, "pool has different caps");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005904 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005905 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005906}
5907
5908gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005909gst_aml_v4l2_object_try_import (GstAmlV4l2Object * obj, GstBuffer * buffer)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005910{
bo.xiao857b8682024-09-12 16:40:32 +08005911 GstVideoMeta *vmeta;
5912 guint n_mem = gst_buffer_n_memory (buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005913
bo.xiao857b8682024-09-12 16:40:32 +08005914 /* only import if requested */
5915 switch (obj->mode)
5916 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005917 case GST_V4L2_IO_USERPTR:
5918 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005919 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005920 default:
bo.xiao857b8682024-09-12 16:40:32 +08005921 GST_DEBUG_OBJECT (obj->dbg_obj,
5922 "The io-mode does not enable importation");
5923 return FALSE;
5924 }
5925
5926 vmeta = gst_buffer_get_video_meta (buffer);
5927 if (!vmeta && obj->need_video_meta)
5928 {
5929 GST_DEBUG_OBJECT (obj->dbg_obj, "Downstream buffer uses standard "
5930 "stride/offset while the driver does not.");
5931 return FALSE;
5932 }
5933
5934 /* we need matching strides/offsets and size */
5935 if (vmeta)
5936 {
5937 guint p;
5938 gboolean need_fmt_update = FALSE;
5939
5940 if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES(&obj->info))
5941 {
5942 GST_WARNING_OBJECT(obj->dbg_obj,
5943 "Cannot import buffers with different number planes");
5944 return FALSE;
5945 }
5946
5947 for (p = 0; p < vmeta->n_planes; p++)
5948 {
5949 if (vmeta->stride[p] < obj->info.stride[p])
5950 {
5951 GST_DEBUG_OBJECT(obj->dbg_obj,
5952 "Not importing as remote stride %i is smaller then %i on plane %u",
5953 vmeta->stride[p], obj->info.stride[p], p);
5954 return FALSE;
5955 }
5956 else if (vmeta->stride[p] > obj->info.stride[p])
5957 {
5958 need_fmt_update = TRUE;
5959 }
5960
5961 if (vmeta->offset[p] < obj->info.offset[p])
5962 {
5963 GST_DEBUG_OBJECT(obj->dbg_obj,
5964 "Not importing as offset %" G_GSIZE_FORMAT
5965 " is smaller then %" G_GSIZE_FORMAT " on plane %u",
5966 vmeta->offset[p], obj->info.offset[p], p);
5967 return FALSE;
5968 }
5969 else if (vmeta->offset[p] > obj->info.offset[p])
5970 {
5971 need_fmt_update = TRUE;
5972 }
5973 }
5974
5975 if (need_fmt_update)
5976 {
5977 struct v4l2_format format;
5978 gint wanted_stride[GST_VIDEO_MAX_PLANES] = {
5979 0,
5980 };
5981
5982 format = obj->format;
5983
5984 /* update the current format with the stride we want to import from */
5985 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5986 {
5987 guint i;
5988
5989 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted strides:");
5990
5991 for (i = 0; i < obj->n_v4l2_planes; i++)
5992 {
5993 gint stride = vmeta->stride[i];
5994
5995 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5996 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5997
5998 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
5999 wanted_stride[i] = stride;
6000 GST_DEBUG_OBJECT(obj->dbg_obj, " [%u] %i", i, wanted_stride[i]);
6001 }
6002 }
6003 else
6004 {
6005 gint stride = vmeta->stride[0];
6006
6007 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted stride: %i", stride);
6008
6009 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
6010 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
6011
6012 format.fmt.pix.bytesperline = stride;
6013 wanted_stride[0] = stride;
6014 }
6015
6016 if (obj->ioctl(obj->video_fd, VIDIOC_S_FMT, &format) < 0)
6017 {
6018 GST_WARNING_OBJECT(obj->dbg_obj,
6019 "Something went wrong trying to update current format: %s",
6020 g_strerror(errno));
6021 return FALSE;
6022 }
6023
6024 gst_aml_v4l2_object_save_format(obj, obj->fmtdesc, &format, &obj->info,
6025 &obj->align);
6026
6027 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
6028 {
6029 guint i;
6030
6031 for (i = 0; i < obj->n_v4l2_planes; i++)
6032 {
6033 if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i])
6034 {
6035 GST_DEBUG_OBJECT(obj->dbg_obj,
6036 "[%i] Driver did not accept the new stride (wants %i, got %i)",
6037 i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
6038 wanted_stride[i]);
6039 return FALSE;
6040 }
6041 }
6042 }
6043 else
6044 {
6045 if (format.fmt.pix.bytesperline != wanted_stride[0])
6046 {
6047 GST_DEBUG_OBJECT(obj->dbg_obj,
6048 "Driver did not accept the new stride (wants %i, got %i)",
6049 format.fmt.pix.bytesperline, wanted_stride[0]);
6050 return FALSE;
6051 }
6052 }
6053 }
6054 }
6055
6056 /* we can always import single memory buffer, but otherwise we need the same
6057 * amount of memory object. */
6058 if (n_mem != 1 && n_mem != obj->n_v4l2_planes)
6059 {
6060 GST_DEBUG_OBJECT (obj->dbg_obj, "Can only import %i memory, "
6061 "buffers contains %u memory", obj->n_v4l2_planes, n_mem);
6062 return FALSE;
6063 }
6064
6065 /* For DMABuf importation we need DMABuf of course */
6066 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
6067 {
6068 guint i;
6069
6070 for (i = 0; i < n_mem; i++)
6071 {
6072 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
6073
6074 if (!gst_is_dmabuf_memory (mem))
6075 {
6076 GST_DEBUG_OBJECT (obj->dbg_obj, "Cannot import non-DMABuf memory.");
xuesong.jiangae1548e2022-05-06 16:38:46 +08006077 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08006078 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08006079 }
bo.xiao857b8682024-09-12 16:40:32 +08006080 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08006081
bo.xiao857b8682024-09-12 16:40:32 +08006082 /* for the remaining, only the kernel driver can tell */
6083 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006084}
6085
hanghang.luoe80a8882024-11-29 17:02:12 +08006086static gboolean gst_aml_v4l2_set_control (GstAmlV4l2Object *v4l2object, guint ctl)
xuesong.jiang22a9b112023-05-24 09:01:59 +00006087{
bo.xiao857b8682024-09-12 16:40:32 +08006088 int rc;
6089 struct v4l2_queryctrl queryctrl;
6090 struct v4l2_control control;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006091
bo.xiao857b8682024-09-12 16:40:32 +08006092 memset(&queryctrl, 0, sizeof(queryctrl));
6093 queryctrl.id = ctl;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006094
bo.xiao857b8682024-09-12 16:40:32 +08006095 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_QUERYCTRL, &queryctrl);
6096 if (rc == 0)
6097 {
6098 if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
6099 {
6100 memset(&control, 0, sizeof(control));
6101 control.id = ctl;
6102 control.value = 1;
6103 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6104 if (rc != 0)
6105 {
6106 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x fail rc %d", ctl, rc);
6107 return FALSE;
6108 }
6109 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x succ", ctl);
6110 return TRUE;
6111 }
6112 else
6113 {
6114 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "ctl:0x%x is disabled", ctl);
6115 return TRUE;
6116 }
6117 }
6118 else
6119 {
6120 GST_ERROR_OBJECT(v4l2object->dbg_obj, "VIDIOC_QUERYCTRL for 0x:%x fail", ctl);
6121 return FALSE;
6122 }
xuesong.jiang22a9b112023-05-24 09:01:59 +00006123}
6124
hanghang.luoe80a8882024-11-29 17:02:12 +08006125gboolean gst_aml_v4l2_set_I_frame_mode (GstAmlV4l2Object *v4l2object)
hanghang.luo7f403102024-07-04 10:33:01 +08006126{
bo.xiao857b8682024-09-12 16:40:32 +08006127 if (v4l2object->iframe_mode)
6128 {
6129 int rc;
6130 struct v4l2_control control;
6131 memset(&control, 0, sizeof(control));
6132 control.id = AML_V4L2_SET_I_FRAME;
6133 control.value = 1;
6134 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6135 if (rc != 0)
6136 {
6137 GST_ERROR_OBJECT(v4l2object->dbg_obj, "rc: %d", rc);
6138 return FALSE;
6139 }
6140 }
6141 GST_DEBUG("set I frame ok");
6142 return TRUE;
hanghang.luo7f403102024-07-04 10:33:01 +08006143}
xuesong.jiang22a9b112023-05-24 09:01:59 +00006144
hanghang.luoe80a8882024-11-29 17:02:12 +08006145gboolean gst_aml_v4l2_set_drm_mode (GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08006146{
bo.xiao857b8682024-09-12 16:40:32 +08006147 /* On AmLogic, output obj use of GST_V4L2_IO_DMABUF_IMPORT implies secure memory */
6148 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT && v4l2object->secure_es)
6149 {
6150 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)v4l2object->element;
6151 self->is_secure_path = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006152
bo.xiao857b8682024-09-12 16:40:32 +08006153 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_DRMMODE))
6154 {
6155 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set succ");
6156 return TRUE;
6157 }
6158 else
6159 {
6160 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set fail");
6161 return FALSE;
6162 }
6163 }
6164 return TRUE;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006165}
6166
hanghang.luoe80a8882024-11-29 17:02:12 +08006167gboolean gst_aml_v4l2_set_stream_mode (GstAmlV4l2Object *v4l2object)
xuesong.jiang22a9b112023-05-24 09:01:59 +00006168{
bo.xiao857b8682024-09-12 16:40:32 +08006169 if (v4l2object->stream_mode)
6170 {
6171 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_STREAM_MODE))
6172 {
6173 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set succ");
6174 return TRUE;
6175 }
6176 else
6177 {
6178 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set fail");
6179 return FALSE;
6180 }
6181 }
6182 else
6183 {
6184 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not stream mode, frame mode in configured by default");
6185 return TRUE;
6186 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006187}
6188
hanghang.luoe80a8882024-11-29 17:02:12 +08006189gint gst_aml_v4l2_object_get_outstanding_capture_buf_num (GstAmlV4l2Object *obj)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006190{
bo.xiao857b8682024-09-12 16:40:32 +08006191 gint ret = 0;
6192 gint count = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006193
bo.xiao857b8682024-09-12 16:40:32 +08006194 if (obj->old_other_pool)
6195 {
6196 count = gst_buffer_pool_get_outstanding_num(obj->old_other_pool);
6197 if (count)
6198 {
6199 ret += count;
6200 }
6201 else
6202 {
6203 gst_object_unref(obj->old_other_pool);
6204 obj->old_other_pool = NULL;
6205 }
6206 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006207
bo.xiao857b8682024-09-12 16:40:32 +08006208 count = 0;
6209 if (obj->old_old_other_pool)
6210 {
6211 count = gst_buffer_pool_get_outstanding_num(obj->old_old_other_pool);
6212 if (count)
6213 {
6214 ret += count;
6215 }
6216 else
6217 {
6218 gst_object_unref(obj->old_old_other_pool);
6219 obj->old_old_other_pool = NULL;
6220 }
6221 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006222
bo.xiao857b8682024-09-12 16:40:32 +08006223 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006224}