blob: c07b7412dc9cda8fc3a2e77eab3d4fc2eb50cc10 [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.luo7f403102024-07-04 10:33:01 +0800455
xuesong.jiangae1548e2022-05-06 16:38:46 +0800456}
457
458/* Support for 32bit off_t, this wrapper is casting off_t to gint64 */
459#ifdef HAVE_LIBV4L2
460#if SIZEOF_OFF_T < 8
461
462static gpointer
bo.xiao857b8682024-09-12 16:40:32 +0800463v4l2_mmap_wrapper (gpointer start, gsize length, gint prot, gint flags, gint fd,
464 off_t offset)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800465{
bo.xiao857b8682024-09-12 16:40:32 +0800466 return v4l2_mmap (start, length, prot, flags, fd, (gint64) offset);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800467}
468
469#define v4l2_mmap v4l2_mmap_wrapper
470
471#endif /* SIZEOF_OFF_T < 8 */
472#endif /* HAVE_LIBV4L2 */
473
474GstAmlV4l2Object *
bo.xiao857b8682024-09-12 16:40:32 +0800475gst_aml_v4l2_object_new (GstElement * element,
476 GstObject * debug_object,
477 enum v4l2_buf_type type,
478 const char *default_device,
479 GstAmlV4l2GetInOutFunction get_in_out_func,
480 GstAmlV4l2SetInOutFunction set_in_out_func,
481 GstAmlV4l2UpdateFpsFunction update_fps_func)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800482{
bo.xiao857b8682024-09-12 16:40:32 +0800483 GstAmlV4l2Object *v4l2object;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800484
bo.xiao857b8682024-09-12 16:40:32 +0800485 /*
486 * some default values
487 */
488 v4l2object = g_new0 (GstAmlV4l2Object, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800489
bo.xiao857b8682024-09-12 16:40:32 +0800490 if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == type || V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type))
491 {
492 const char *default_mode = getenv("GST_DEFAULT_V4L2_BUF_MODE");
493 GST_DEBUG("amlmodbuf GST_AML_DEFAULT_V4L2_BUF_MODE:%s", default_mode);
494 //v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
495 if (default_mode)
496 {
497 if (strcmp(default_mode, "DMA_BUF_IMPORT") == 0)
498 v4l2object->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
499 else if (strcmp(default_mode, "DMA_BUF") == 0)
500 v4l2object->req_mode = GST_V4L2_IO_DMABUF;
501 GST_DEBUG("amlmodbuf set default buf default_mode:%d", v4l2object->req_mode);
502 }
503 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800504
bo.xiao857b8682024-09-12 16:40:32 +0800505 v4l2object->type = type;
506 v4l2object->formats = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800507
bo.xiao857b8682024-09-12 16:40:32 +0800508 v4l2object->element = element;
509 v4l2object->dbg_obj = debug_object;
510 v4l2object->get_in_out_func = get_in_out_func;
511 v4l2object->set_in_out_func = set_in_out_func;
512 v4l2object->update_fps_func = update_fps_func;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800513
bo.xiao857b8682024-09-12 16:40:32 +0800514 v4l2object->video_fd = -1;
515 v4l2object->active = FALSE;
516 v4l2object->videodev = g_strdup (default_device);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800517
bo.xiao857b8682024-09-12 16:40:32 +0800518 v4l2object->norms = NULL;
519 v4l2object->channels = NULL;
520 v4l2object->colors = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800521
bo.xiao857b8682024-09-12 16:40:32 +0800522 v4l2object->keep_aspect = TRUE;
523 v4l2object->stream_mode = FALSE;
524 v4l2object->secure_es = FALSE;
525 v4l2object->have_set_par = FALSE;
526 v4l2object->enable_cc_data = FALSE;
527 v4l2object->enable_nr = FALSE;
528 v4l2object->low_latency_mode = FALSE;
529 v4l2object->low_memory_mode = FALSE;
530 v4l2object->iframe_mode = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800531
bo.xiao857b8682024-09-12 16:40:32 +0800532 v4l2object->n_v4l2_planes = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800533
bo.xiao857b8682024-09-12 16:40:32 +0800534 v4l2object->no_initial_format = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800535
bo.xiao857b8682024-09-12 16:40:32 +0800536 /* We now disable libv4l2 by default, but have an env to enable it. */
xuesong.jiangae1548e2022-05-06 16:38:46 +0800537#ifdef HAVE_LIBV4L2
bo.xiao857b8682024-09-12 16:40:32 +0800538 if (g_getenv ("GST_V4L2_USE_LIBV4L2"))
539 {
540 v4l2object->fd_open = v4l2_fd_open;
541 v4l2object->close = v4l2_close;
542 v4l2object->dup = v4l2_dup;
543 v4l2object->ioctl = v4l2_ioctl;
544 v4l2object->read = v4l2_read;
545 v4l2object->mmap = v4l2_mmap;
546 v4l2object->munmap = v4l2_munmap;
547 }
548 else
xuesong.jiangae1548e2022-05-06 16:38:46 +0800549#endif
bo.xiao857b8682024-09-12 16:40:32 +0800550 {
551 v4l2object->fd_open = NULL;
552 v4l2object->close = close;
553 v4l2object->dup = dup;
554 v4l2object->ioctl = ioctl;
555 v4l2object->read = read;
556 v4l2object->mmap = mmap;
557 v4l2object->munmap = munmap;
558 }
559 v4l2object->poll = gst_poll_new (TRUE);
560 v4l2object->can_wait_event = FALSE;
561 v4l2object->can_poll_device = TRUE;
562 v4l2object->tvin_port = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800563
bo.xiao857b8682024-09-12 16:40:32 +0800564 v4l2object->dumpframefile = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800565
bo.xiao857b8682024-09-12 16:40:32 +0800566 /* jxsdbg resolution switching */
567 v4l2object->old_other_pool = NULL;
568 v4l2object->old_old_other_pool = NULL;
569 v4l2object->outstanding_buf_num = 0;
570 v4l2object->num_error_frames = 0;
571 v4l2object->error_frame_pts = 0;
le.han3b118242024-09-29 06:32:02 +0000572 v4l2object->stride = 0;
bo.xiao857b8682024-09-12 16:40:32 +0800573 return v4l2object;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800574}
575
bo.xiao857b8682024-09-12 16:40:32 +0800576static gboolean gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800577
bo.xiao857b8682024-09-12 16:40:32 +0800578void
579gst_aml_v4l2_object_destroy (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800580{
bo.xiao857b8682024-09-12 16:40:32 +0800581 g_return_if_fail (v4l2object != NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800582
bo.xiao857b8682024-09-12 16:40:32 +0800583 g_free (v4l2object->videodev);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800584
bo.xiao857b8682024-09-12 16:40:32 +0800585 g_free (v4l2object->channel);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800586
bo.xiao857b8682024-09-12 16:40:32 +0800587 if (v4l2object->formats)
588 {
589 gst_aml_v4l2_object_clear_format_list (v4l2object);
590 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800591
bo.xiao857b8682024-09-12 16:40:32 +0800592 if (v4l2object->probed_caps)
593 {
594 gst_caps_unref (v4l2object->probed_caps);
595 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800596
bo.xiao857b8682024-09-12 16:40:32 +0800597 if (v4l2object->extra_controls)
598 {
599 gst_structure_free (v4l2object->extra_controls);
600 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800601
bo.xiao857b8682024-09-12 16:40:32 +0800602 gst_poll_free (v4l2object->poll);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800603
bo.xiao857b8682024-09-12 16:40:32 +0800604 g_free(v4l2object->dumpframefile);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800605
bo.xiao857b8682024-09-12 16:40:32 +0800606 /* jxsdbg resolution switching */
607 if (v4l2object->old_other_pool)
608 {
609 gst_object_unref(v4l2object->old_other_pool);
610 v4l2object->old_other_pool = NULL;
611 }
612 if (v4l2object->old_old_other_pool)
613 {
614 gst_object_unref(v4l2object->old_old_other_pool);
615 v4l2object->old_old_other_pool = NULL;
616 }
617 v4l2object->outstanding_buf_num = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800618
bo.xiao857b8682024-09-12 16:40:32 +0800619 g_free (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800620}
621
622static gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800623gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800624{
bo.xiao857b8682024-09-12 16:40:32 +0800625 g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
626 g_slist_free (v4l2object->formats);
627 v4l2object->formats = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800628
bo.xiao857b8682024-09-12 16:40:32 +0800629 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800630}
631
632static gint
bo.xiao857b8682024-09-12 16:40:32 +0800633gst_aml_v4l2_object_prop_to_cid (guint prop_id)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800634{
bo.xiao857b8682024-09-12 16:40:32 +0800635 gint cid = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800636
bo.xiao857b8682024-09-12 16:40:32 +0800637 switch (prop_id)
638 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800639 case PROP_BRIGHTNESS:
bo.xiao857b8682024-09-12 16:40:32 +0800640 cid = V4L2_CID_BRIGHTNESS;
641 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800642 case PROP_CONTRAST:
bo.xiao857b8682024-09-12 16:40:32 +0800643 cid = V4L2_CID_CONTRAST;
644 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800645 case PROP_SATURATION:
bo.xiao857b8682024-09-12 16:40:32 +0800646 cid = V4L2_CID_SATURATION;
647 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800648 case PROP_HUE:
bo.xiao857b8682024-09-12 16:40:32 +0800649 cid = V4L2_CID_HUE;
650 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800651 default:
bo.xiao857b8682024-09-12 16:40:32 +0800652 GST_WARNING ("unmapped property id: %d", prop_id);
653 }
654 return cid;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800655}
656
657gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800658gst_aml_v4l2_object_set_property_helper (GstAmlV4l2Object * v4l2object,
659 guint prop_id, const GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800660{
bo.xiao857b8682024-09-12 16:40:32 +0800661 switch (prop_id)
662 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800663 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800664 g_free (v4l2object->videodev);
665 v4l2object->videodev = g_value_dup_string (value);
666 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800667 case PROP_BRIGHTNESS:
668 case PROP_CONTRAST:
669 case PROP_SATURATION:
670 case PROP_HUE:
671 {
bo.xiao857b8682024-09-12 16:40:32 +0800672 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800673
bo.xiao857b8682024-09-12 16:40:32 +0800674 if (cid != -1)
675 {
676 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800677 {
bo.xiao857b8682024-09-12 16:40:32 +0800678 gst_aml_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800679 }
bo.xiao857b8682024-09-12 16:40:32 +0800680 }
681 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800682 }
683 break;
684 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800685 v4l2object->req_mode = g_value_get_enum (value);
686 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800687 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800688 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
689 v4l2object->req_mode = g_value_get_enum (value);
690 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800691 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800692 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
693 v4l2object->req_mode = g_value_get_enum (value);
694 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800695 case PROP_EXTRA_CONTROLS:
696 {
bo.xiao857b8682024-09-12 16:40:32 +0800697 const GstStructure *s = gst_value_get_structure (value);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800698
bo.xiao857b8682024-09-12 16:40:32 +0800699 if (v4l2object->extra_controls)
700 gst_structure_free (v4l2object->extra_controls);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800701
bo.xiao857b8682024-09-12 16:40:32 +0800702 v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
703 if (GST_AML_V4L2_IS_OPEN (v4l2object))
704 gst_aml_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
705 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800706 }
707 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800708 if (v4l2object->par)
709 {
710 g_value_unset (v4l2object->par);
711 g_free (v4l2object->par);
712 }
713 v4l2object->par = g_new0 (GValue, 1);
714 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
715 if (!g_value_transform (value, v4l2object->par))
716 {
717 g_warning ("Could not transform string to aspect ratio");
718 gst_value_set_fraction (v4l2object->par, 1, 1);
719 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800720
sheng.liu641aa422023-12-26 07:05:59 +0000721 v4l2object->have_set_par = TRUE;
bo.xiao857b8682024-09-12 16:40:32 +0800722 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "set PAR to %d/%d",
723 gst_value_get_fraction_numerator (v4l2object->par),
724 gst_value_get_fraction_denominator (v4l2object->par));
725 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800726 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800727 v4l2object->keep_aspect = g_value_get_boolean (value);
728 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800729 case PROP_DUMP_FRAME_LOCATION:
730 g_free(v4l2object->dumpframefile);
731 v4l2object->dumpframefile = g_value_dup_string(value);
732 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000733 case PROP_STREAM_MODE:
734 v4l2object->stream_mode = g_value_get_boolean(value);
735 break;
hanghang.luoc54208e2023-09-22 02:43:54 +0000736 case PROP_LOW_LATENCY_MODE:
737 v4l2object->low_latency_mode = g_value_get_boolean(value);
738 GST_DEBUG_OBJECT(v4l2object, "set low latency: %d",v4l2object->low_latency_mode);
739 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800740 case PROP_CC_DATA:
741 v4l2object->enable_cc_data = g_value_get_boolean(value);
742 GST_DEBUG_OBJECT(v4l2object, "enable cc data: %d",v4l2object->enable_cc_data);
743 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800744 case PROP_ENABLE_NR:
745 v4l2object->enable_nr = g_value_get_boolean(value);
746 GST_DEBUG_OBJECT(v4l2object, "enable nr: %d",v4l2object->enable_nr);
747 break;
hanghang.luo75664712024-07-01 19:28:10 +0800748 case PROP_LOW_MEMORY_MODE:
749 v4l2object->low_memory_mode = g_value_get_boolean(value);
750 GST_DEBUG_OBJECT(v4l2object, "set low mem: %d",v4l2object->low_latency_mode);
751 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800752 case PROP_I_FRAME_MODE:
753 v4l2object->iframe_mode = g_value_get_boolean(value);
754 GST_DEBUG_OBJECT(v4l2object, "set I frame mode: %d",v4l2object->iframe_mode);
755 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800756 default:
bo.xiao857b8682024-09-12 16:40:32 +0800757 return FALSE;
758 break;
759 }
760 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800761}
762
763gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800764gst_aml_v4l2_object_get_property_helper (GstAmlV4l2Object * v4l2object,
765 guint prop_id, GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800766{
bo.xiao857b8682024-09-12 16:40:32 +0800767 switch (prop_id)
768 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800769 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800770 g_value_set_string (value, v4l2object->videodev);
771 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800772 case PROP_DEVICE_NAME:
773 {
bo.xiao857b8682024-09-12 16:40:32 +0800774 const guchar *name = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800775
bo.xiao857b8682024-09-12 16:40:32 +0800776 if (GST_AML_V4L2_IS_OPEN (v4l2object))
777 name = v4l2object->vcap.card;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800778
bo.xiao857b8682024-09-12 16:40:32 +0800779 g_value_set_string (value, (gchar *) name);
780 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800781 }
782 case PROP_DEVICE_FD:
783 {
bo.xiao857b8682024-09-12 16:40:32 +0800784 if (GST_AML_V4L2_IS_OPEN (v4l2object))
785 g_value_set_int (value, v4l2object->video_fd);
786 else
787 g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
788 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800789 }
790 case PROP_FLAGS:
791 {
bo.xiao857b8682024-09-12 16:40:32 +0800792 guint flags = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800793
bo.xiao857b8682024-09-12 16:40:32 +0800794 if (GST_AML_V4L2_IS_OPEN (v4l2object))
795 {
796 flags |= v4l2object->device_caps &
797 (V4L2_CAP_VIDEO_CAPTURE |
798 V4L2_CAP_VIDEO_OUTPUT |
799 V4L2_CAP_VIDEO_OVERLAY |
800 V4L2_CAP_VBI_CAPTURE |
801 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800802
bo.xiao857b8682024-09-12 16:40:32 +0800803 if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
804 flags |= V4L2_CAP_VIDEO_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800805
bo.xiao857b8682024-09-12 16:40:32 +0800806 if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
807 flags |= V4L2_CAP_VIDEO_OUTPUT;
808 }
809 g_value_set_flags (value, flags);
810 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800811 }
812 case PROP_BRIGHTNESS:
813 case PROP_CONTRAST:
814 case PROP_SATURATION:
815 case PROP_HUE:
816 {
bo.xiao857b8682024-09-12 16:40:32 +0800817 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800818
bo.xiao857b8682024-09-12 16:40:32 +0800819 if (cid != -1)
820 {
821 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800822 {
bo.xiao857b8682024-09-12 16:40:32 +0800823 gint v;
824 if (gst_aml_v4l2_get_attribute (v4l2object, cid, &v))
825 {
826 g_value_set_int (value, v);
827 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800828 }
bo.xiao857b8682024-09-12 16:40:32 +0800829 }
830 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800831 }
bo.xiao857b8682024-09-12 16:40:32 +0800832 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800833 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800834 g_value_set_enum (value, v4l2object->req_mode);
835 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800836 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800837 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
838 g_value_set_enum (value, v4l2object->req_mode);
839 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800840 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800841 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
842 g_value_set_enum (value, v4l2object->req_mode);
843 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800844 case PROP_EXTRA_CONTROLS:
bo.xiao857b8682024-09-12 16:40:32 +0800845 gst_value_set_structure (value, v4l2object->extra_controls);
846 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800847 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800848 if (v4l2object->par)
849 g_value_transform (v4l2object->par, value);
850 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800851 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800852 g_value_set_boolean (value, v4l2object->keep_aspect);
853 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800854 case PROP_DUMP_FRAME_LOCATION:
855 g_value_set_string(value, v4l2object->dumpframefile);
856 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000857 case PROP_STREAM_MODE:
858 g_value_set_boolean(value, v4l2object->stream_mode);
859 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800860 case PROP_CC_DATA:
861 g_value_set_boolean(value, v4l2object->enable_cc_data);
862 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800863 case PROP_ENABLE_NR:
864 g_value_set_boolean(value, v4l2object->enable_nr);
865 break;
hanghang.luob3157512024-06-24 16:18:04 +0800866 case PROP_LOW_LATENCY_MODE:
867 g_value_set_boolean(value, v4l2object->low_latency_mode);
868 break;
fei.dengaf682762024-06-24 19:06:03 +0800869 case PROP_DECODING_ERROR_FRAMES:
870 g_value_set_int(value, v4l2object->num_error_frames);
871 break;
hanghang.luo75664712024-07-01 19:28:10 +0800872 case PROP_LOW_MEMORY_MODE:
873 g_value_set_boolean(value, v4l2object->low_memory_mode);
874 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800875 case PROP_I_FRAME_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800876 g_value_set_boolean(value, v4l2object->iframe_mode);
877 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800878 default:
bo.xiao857b8682024-09-12 16:40:32 +0800879 return FALSE;
880 break;
881 }
882 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800883}
884
885static void
bo.xiao857b8682024-09-12 16:40:32 +0800886gst_aml_v4l2_get_driver_min_buffers (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800887{
bo.xiao857b8682024-09-12 16:40:32 +0800888 struct v4l2_control control = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +0800889
bo.xiao857b8682024-09-12 16:40:32 +0800890 g_return_if_fail (GST_AML_V4L2_IS_OPEN (v4l2object));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800891
bo.xiao857b8682024-09-12 16:40:32 +0800892 if (V4L2_TYPE_IS_OUTPUT (v4l2object->type))
893 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
894 else
895 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800896
bo.xiao857b8682024-09-12 16:40:32 +0800897 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0)
898 {
899 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
900 "driver requires a minimum of %d buffers", control.value);
901 v4l2object->min_buffers = control.value;
902 }
903 else
904 {
905 v4l2object->min_buffers = 0;
906 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800907}
908
909gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800910gst_aml_v4l2_object_open (GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800911{
bo.xiao857b8682024-09-12 16:40:32 +0800912 if (!gst_aml_v4l2_open(v4l2object))
913 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800914
bo.xiao857b8682024-09-12 16:40:32 +0800915 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800916}
917
918gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800919gst_aml_v4l2_object_open_shared (GstAmlV4l2Object * v4l2object, GstAmlV4l2Object * other)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800920{
bo.xiao857b8682024-09-12 16:40:32 +0800921 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800922
bo.xiao857b8682024-09-12 16:40:32 +0800923 ret = gst_aml_v4l2_dup (v4l2object, other);
924 if (ret && !V4L2_TYPE_IS_OUTPUT (v4l2object->type))
925 {
926 gst_poll_fd_init (&v4l2object->pollfd);
927 v4l2object->pollfd.fd = v4l2object->video_fd;
928 gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
929 /* used for dequeue event */
930 gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
931 gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
932 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800933
bo.xiao857b8682024-09-12 16:40:32 +0800934 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800935}
936
937gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800938gst_aml_v4l2_object_close (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800939{
bo.xiao857b8682024-09-12 16:40:32 +0800940 if (!gst_aml_v4l2_close (v4l2object))
941 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800942
bo.xiao857b8682024-09-12 16:40:32 +0800943 gst_caps_replace (&v4l2object->probed_caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800944
bo.xiao857b8682024-09-12 16:40:32 +0800945 /* reset our copy of the device caps */
946 v4l2object->device_caps = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800947
bo.xiao857b8682024-09-12 16:40:32 +0800948 if (v4l2object->formats)
949 {
950 gst_aml_v4l2_object_clear_format_list (v4l2object);
951 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800952
bo.xiao857b8682024-09-12 16:40:32 +0800953 if (v4l2object->par)
954 {
955 g_value_unset (v4l2object->par);
956 g_free (v4l2object->par);
957 v4l2object->par = NULL;
958 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800959
bo.xiao857b8682024-09-12 16:40:32 +0800960 if (v4l2object->fps)
961 {
962 g_value_unset(v4l2object->fps);
963 g_free(v4l2object->fps);
964 v4l2object->fps = NULL;
965 }
sheng.liudb26f7d2024-01-22 11:24:23 +0000966
bo.xiao857b8682024-09-12 16:40:32 +0800967 if (v4l2object->channel)
968 {
969 g_free (v4l2object->channel);
970 v4l2object->channel = NULL;
971 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800972
bo.xiao857b8682024-09-12 16:40:32 +0800973 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800974}
975
976static struct v4l2_fmtdesc *
bo.xiao857b8682024-09-12 16:40:32 +0800977gst_aml_v4l2_object_get_format_from_fourcc (GstAmlV4l2Object * v4l2object,
978 guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800979{
bo.xiao857b8682024-09-12 16:40:32 +0800980 struct v4l2_fmtdesc *fmt;
981 GSList *walk;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800982
bo.xiao857b8682024-09-12 16:40:32 +0800983 if (fourcc == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800984 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +0800985
986 walk = gst_aml_v4l2_object_get_format_list (v4l2object);
987 while (walk)
988 {
989 fmt = (struct v4l2_fmtdesc *) walk->data;
990 if (fmt->pixelformat == fourcc)
991 return fmt;
992 /* special case for jpeg */
993 if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
994 fmt->pixelformat == V4L2_PIX_FMT_JPEG ||
995 fmt->pixelformat == V4L2_PIX_FMT_PJPG)
996 {
997 if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG ||
998 fourcc == V4L2_PIX_FMT_PJPG)
999 {
1000 return fmt;
1001 }
1002 }
1003 walk = g_slist_next (walk);
1004 }
1005
1006 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001007}
1008
1009/* complete made up ranking, the values themselves are meaningless */
1010/* These ranks MUST be X such that X<<15 fits on a signed int - see
1011 the comment at the end of gst_aml_v4l2_object_format_get_rank. */
bo.xiao857b8682024-09-12 16:40:32 +08001012#define YUV_BASE_RANK 1000
1013#define JPEG_BASE_RANK 500
1014#define DV_BASE_RANK 200
1015#define RGB_BASE_RANK 100
1016#define YUV_ODD_BASE_RANK 50
1017#define RGB_ODD_BASE_RANK 25
1018#define BAYER_BASE_RANK 15
1019#define S910_BASE_RANK 10
1020#define GREY_BASE_RANK 5
1021#define PWC_BASE_RANK 1
xuesong.jiangae1548e2022-05-06 16:38:46 +08001022
1023static gint
bo.xiao857b8682024-09-12 16:40:32 +08001024gst_aml_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001025{
bo.xiao857b8682024-09-12 16:40:32 +08001026 guint32 fourcc = fmt->pixelformat;
1027 gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
1028 gint rank = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001029
bo.xiao857b8682024-09-12 16:40:32 +08001030 switch (fourcc)
1031 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001032 case V4L2_PIX_FMT_MJPEG:
1033 case V4L2_PIX_FMT_PJPG:
bo.xiao857b8682024-09-12 16:40:32 +08001034 rank = JPEG_BASE_RANK;
1035 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001036 case V4L2_PIX_FMT_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08001037 rank = JPEG_BASE_RANK + 1;
1038 break;
1039 case V4L2_PIX_FMT_MPEG: /* MPEG */
1040 rank = JPEG_BASE_RANK + 2;
1041 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001042
1043 case V4L2_PIX_FMT_RGB332:
1044 case V4L2_PIX_FMT_ARGB555:
1045 case V4L2_PIX_FMT_XRGB555:
1046 case V4L2_PIX_FMT_RGB555:
1047 case V4L2_PIX_FMT_ARGB555X:
1048 case V4L2_PIX_FMT_XRGB555X:
1049 case V4L2_PIX_FMT_RGB555X:
1050 case V4L2_PIX_FMT_BGR666:
1051 case V4L2_PIX_FMT_RGB565:
1052 case V4L2_PIX_FMT_RGB565X:
1053 case V4L2_PIX_FMT_RGB444:
1054 case V4L2_PIX_FMT_Y4:
1055 case V4L2_PIX_FMT_Y6:
1056 case V4L2_PIX_FMT_Y10:
1057 case V4L2_PIX_FMT_Y12:
1058 case V4L2_PIX_FMT_Y10BPACK:
1059 case V4L2_PIX_FMT_YUV555:
1060 case V4L2_PIX_FMT_YUV565:
1061 case V4L2_PIX_FMT_YUV32:
1062 case V4L2_PIX_FMT_NV12MT_16X16:
1063 case V4L2_PIX_FMT_NV42:
1064 case V4L2_PIX_FMT_H264_MVC:
bo.xiao857b8682024-09-12 16:40:32 +08001065 rank = RGB_ODD_BASE_RANK;
1066 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001067
1068 case V4L2_PIX_FMT_RGB24:
1069 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001070 rank = RGB_BASE_RANK - 1;
1071 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001072
1073 case V4L2_PIX_FMT_RGB32:
1074 case V4L2_PIX_FMT_BGR32:
1075 case V4L2_PIX_FMT_ABGR32:
1076 case V4L2_PIX_FMT_XBGR32:
1077 case V4L2_PIX_FMT_ARGB32:
1078 case V4L2_PIX_FMT_XRGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001079 rank = RGB_BASE_RANK;
1080 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001081
bo.xiao857b8682024-09-12 16:40:32 +08001082 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1083 rank = GREY_BASE_RANK;
1084 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001085
1086 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
1087 case V4L2_PIX_FMT_NV12M: /* Same as NV12 */
bo.xiao857b8682024-09-12 16:40:32 +08001088 case V4L2_PIX_FMT_NV12MT: /* NV12 64x32 tile */
1089 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
1090 case V4L2_PIX_FMT_NV21M: /* Same as NV21 */
1091 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1092 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
1093 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
1094 case V4L2_PIX_FMT_NV16M: /* Same as NV16 */
1095 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
1096 case V4L2_PIX_FMT_NV61M: /* Same as NV61 */
1097 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
1098 rank = YUV_ODD_BASE_RANK;
1099 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001100
bo.xiao857b8682024-09-12 16:40:32 +08001101 case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */
1102 rank = YUV_BASE_RANK + 3;
1103 break;
1104 case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */
1105 rank = YUV_BASE_RANK + 2;
1106 break;
1107 case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001108 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001109 rank = YUV_BASE_RANK + 7;
1110 break;
1111 case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */
1112 rank = YUV_BASE_RANK + 10;
1113 break;
1114 case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */
1115 rank = YUV_BASE_RANK + 6;
1116 break;
1117 case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */
1118 rank = YUV_BASE_RANK + 9;
1119 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001120 case V4L2_PIX_FMT_YUV444:
bo.xiao857b8682024-09-12 16:40:32 +08001121 rank = YUV_BASE_RANK + 6;
1122 break;
1123 case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */
1124 rank = YUV_BASE_RANK + 5;
1125 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001126 case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001127 rank = YUV_BASE_RANK + 4;
1128 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001129 case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001130 rank = YUV_BASE_RANK + 8;
1131 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001132
1133 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001134 rank = DV_BASE_RANK;
1135 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001136
bo.xiao857b8682024-09-12 16:40:32 +08001137 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1138 rank = 0;
1139 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001140
1141 case V4L2_PIX_FMT_SBGGR8:
1142 case V4L2_PIX_FMT_SGBRG8:
1143 case V4L2_PIX_FMT_SGRBG8:
1144 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001145 rank = BAYER_BASE_RANK;
1146 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001147
1148 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001149 rank = S910_BASE_RANK;
1150 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001151
1152 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001153 rank = PWC_BASE_RANK;
1154 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001155 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001156 rank = PWC_BASE_RANK;
1157 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001158
1159 default:
bo.xiao857b8682024-09-12 16:40:32 +08001160 rank = 0;
1161 break;
1162 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001163
bo.xiao857b8682024-09-12 16:40:32 +08001164 /* All ranks are below 1<<15 so a shift by 15
1165 * will a) make all non-emulated formats larger
1166 * than emulated and b) will not overflow
1167 */
1168 if (!emulated)
1169 rank <<= 15;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001170
bo.xiao857b8682024-09-12 16:40:32 +08001171 return rank;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001172}
1173
1174static gint
bo.xiao857b8682024-09-12 16:40:32 +08001175format_cmp_func (gconstpointer a, gconstpointer b)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001176{
bo.xiao857b8682024-09-12 16:40:32 +08001177 const struct v4l2_fmtdesc *fa = a;
1178 const struct v4l2_fmtdesc *fb = b;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001179
bo.xiao857b8682024-09-12 16:40:32 +08001180 if (fa->pixelformat == fb->pixelformat)
1181 return 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001182
bo.xiao857b8682024-09-12 16:40:32 +08001183 return gst_aml_v4l2_object_format_get_rank (fb) -
1184 gst_aml_v4l2_object_format_get_rank (fa);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001185}
1186
1187/******************************************************
1188 * gst_aml_v4l2_object_fill_format_list():
1189 * create list of supported capture formats
1190 * return value: TRUE on success, FALSE on error
1191 ******************************************************/
1192static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001193gst_aml_v4l2_object_fill_format_list (GstAmlV4l2Object * v4l2object,
1194 enum v4l2_buf_type type)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001195{
bo.xiao857b8682024-09-12 16:40:32 +08001196 gint n;
1197 struct v4l2_fmtdesc *format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001198
bo.xiao857b8682024-09-12 16:40:32 +08001199 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting src format enumerations");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001200
bo.xiao857b8682024-09-12 16:40:32 +08001201 /* format enumeration */
1202 for (n = 0;; n++)
1203 {
bo.xiaof61afd22024-10-16 17:18:55 +08001204 format = g_new0 (struct v4l2_fmtdesc, 1);
bo.xiao857b8682024-09-12 16:40:32 +08001205
1206 format->index = n;
1207 format->type = type;
1208
1209 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001210 {
bo.xiao857b8682024-09-12 16:40:32 +08001211 if (errno == EINVAL)
1212 {
1213 g_free (format);
1214 break; /* end of enumeration */
1215 }
1216 else
1217 {
1218 goto failed;
1219 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001220 }
1221
bo.xiao857b8682024-09-12 16:40:32 +08001222 GST_LOG_OBJECT (v4l2object->dbg_obj, "index: %u", format->index);
1223 GST_LOG_OBJECT (v4l2object->dbg_obj, "type: %d", format->type);
1224 GST_LOG_OBJECT (v4l2object->dbg_obj, "flags: %08x", format->flags);
1225 GST_LOG_OBJECT (v4l2object->dbg_obj, "description: '%s'",
1226 format->description);
1227 GST_LOG_OBJECT (v4l2object->dbg_obj, "pixelformat: %" GST_FOURCC_FORMAT,
1228 GST_FOURCC_ARGS (format->pixelformat));
1229
1230
1231 if (V4L2_PIX_FMT_YUV420M == format->pixelformat || V4L2_PIX_FMT_YUV420 == format->pixelformat)
1232 {
bo.xiaof61afd22024-10-16 17:18:55 +08001233 GST_LOG_OBJECT(v4l2object->dbg_obj, "not support YU12 and YM12");
1234 g_free (format);
bo.xiao857b8682024-09-12 16:40:32 +08001235 continue;
1236 }
1237
1238 /* sort formats according to our preference; we do this, because caps
1239 * are probed in the order the formats are in the list, and the order of
1240 * formats in the final probed caps matters for things like fixation */
1241 v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
1242 (GCompareFunc) format_cmp_func);
1243 }
1244
xuesong.jiangae1548e2022-05-06 16:38:46 +08001245#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08001246 {
1247 GSList *l;
1248
1249 GST_INFO_OBJECT (v4l2object->dbg_obj, "got %d format(s):", n);
1250 for (l = v4l2object->formats; l != NULL; l = l->next)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001251 {
bo.xiao857b8682024-09-12 16:40:32 +08001252 format = l->data;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001253
bo.xiao857b8682024-09-12 16:40:32 +08001254 GST_INFO_OBJECT (v4l2object->dbg_obj,
1255 " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
1256 ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001257 }
bo.xiao857b8682024-09-12 16:40:32 +08001258 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001259#endif
1260
bo.xiao857b8682024-09-12 16:40:32 +08001261 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001262
bo.xiao857b8682024-09-12 16:40:32 +08001263 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001264failed:
bo.xiao857b8682024-09-12 16:40:32 +08001265 {
1266 g_free (format);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001267
1268 if (v4l2object->element)
bo.xiao857b8682024-09-12 16:40:32 +08001269 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001270
bo.xiao857b8682024-09-12 16:40:32 +08001271 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1272 (_("Failed to enumerate possible video formats device '%s' can work "
1273 "with"), v4l2object->videodev),
1274 ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
1275 n, v4l2object->videodev, errno, g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001276
1277 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08001278 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001279}
1280
1281/*
1282 * Get the list of supported capture formats, a list of
1283 * <code>struct v4l2_fmtdesc</code>.
1284 */
1285static GSList *
bo.xiao857b8682024-09-12 16:40:32 +08001286gst_aml_v4l2_object_get_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001287{
bo.xiao857b8682024-09-12 16:40:32 +08001288 if (!v4l2object->formats)
1289 {
1290
1291 /* check usual way */
1292 gst_aml_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
1293
1294 /* if our driver supports multi-planar
1295 * and if formats are still empty then we can workaround driver bug
1296 * by also looking up formats as if our device was not supporting
1297 * multiplanar */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001298 if (!v4l2object->formats)
1299 {
bo.xiao857b8682024-09-12 16:40:32 +08001300 switch (v4l2object->type)
1301 {
1302 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1303 gst_aml_v4l2_object_fill_format_list (v4l2object,
1304 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1305 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001306
bo.xiao857b8682024-09-12 16:40:32 +08001307 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1308 gst_aml_v4l2_object_fill_format_list (v4l2object,
1309 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1310 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001311
bo.xiao857b8682024-09-12 16:40:32 +08001312 default:
1313 break;
1314 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001315 }
bo.xiao857b8682024-09-12 16:40:32 +08001316 }
1317 return v4l2object->formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001318}
1319
1320static GstVideoFormat
bo.xiao857b8682024-09-12 16:40:32 +08001321gst_aml_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001322{
bo.xiao857b8682024-09-12 16:40:32 +08001323 GstVideoFormat format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001324
bo.xiao857b8682024-09-12 16:40:32 +08001325 switch (fourcc)
1326 {
1327 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1328 format = GST_VIDEO_FORMAT_GRAY8;
1329 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001330 case V4L2_PIX_FMT_Y16:
bo.xiao857b8682024-09-12 16:40:32 +08001331 format = GST_VIDEO_FORMAT_GRAY16_LE;
1332 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001333 case V4L2_PIX_FMT_Y16_BE:
bo.xiao857b8682024-09-12 16:40:32 +08001334 format = GST_VIDEO_FORMAT_GRAY16_BE;
1335 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001336 case V4L2_PIX_FMT_XRGB555:
1337 case V4L2_PIX_FMT_RGB555:
bo.xiao857b8682024-09-12 16:40:32 +08001338 format = GST_VIDEO_FORMAT_RGB15;
1339 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001340 case V4L2_PIX_FMT_XRGB555X:
1341 case V4L2_PIX_FMT_RGB555X:
bo.xiao857b8682024-09-12 16:40:32 +08001342 format = GST_VIDEO_FORMAT_BGR15;
1343 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001344 case V4L2_PIX_FMT_RGB565:
bo.xiao857b8682024-09-12 16:40:32 +08001345 format = GST_VIDEO_FORMAT_RGB16;
1346 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001347 case V4L2_PIX_FMT_RGB24:
bo.xiao857b8682024-09-12 16:40:32 +08001348 format = GST_VIDEO_FORMAT_RGB;
1349 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001350 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001351 format = GST_VIDEO_FORMAT_BGR;
1352 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001353 case V4L2_PIX_FMT_XRGB32:
1354 case V4L2_PIX_FMT_RGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001355 format = GST_VIDEO_FORMAT_xRGB;
1356 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001357 case V4L2_PIX_FMT_XBGR32:
1358 case V4L2_PIX_FMT_BGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001359 format = GST_VIDEO_FORMAT_BGRx;
1360 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001361 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001362 format = GST_VIDEO_FORMAT_BGRA;
1363 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001364 case V4L2_PIX_FMT_ARGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001365 format = GST_VIDEO_FORMAT_ARGB;
1366 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001367 case V4L2_PIX_FMT_NV12:
1368 case V4L2_PIX_FMT_NV12M:
bo.xiao857b8682024-09-12 16:40:32 +08001369 format = GST_VIDEO_FORMAT_NV12;
1370 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001371 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001372 format = GST_VIDEO_FORMAT_NV12_64Z32;
1373 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001374 case V4L2_PIX_FMT_NV21:
1375 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001376 format = GST_VIDEO_FORMAT_NV21;
1377 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001378 case V4L2_PIX_FMT_YVU410:
bo.xiao857b8682024-09-12 16:40:32 +08001379 format = GST_VIDEO_FORMAT_YVU9;
1380 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001381 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001382 format = GST_VIDEO_FORMAT_YUV9;
1383 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001384 case V4L2_PIX_FMT_YUV420:
1385 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001386 format = GST_VIDEO_FORMAT_I420;
1387 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001388 case V4L2_PIX_FMT_YUYV:
bo.xiao857b8682024-09-12 16:40:32 +08001389 format = GST_VIDEO_FORMAT_YUY2;
1390 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001391 case V4L2_PIX_FMT_YVU420:
bo.xiao857b8682024-09-12 16:40:32 +08001392 format = GST_VIDEO_FORMAT_YV12;
1393 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001394 case V4L2_PIX_FMT_UYVY:
bo.xiao857b8682024-09-12 16:40:32 +08001395 format = GST_VIDEO_FORMAT_UYVY;
1396 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001397 case V4L2_PIX_FMT_YUV411P:
bo.xiao857b8682024-09-12 16:40:32 +08001398 format = GST_VIDEO_FORMAT_Y41B;
1399 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001400 case V4L2_PIX_FMT_YUV422P:
bo.xiao857b8682024-09-12 16:40:32 +08001401 format = GST_VIDEO_FORMAT_Y42B;
1402 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001403 case V4L2_PIX_FMT_YVYU:
bo.xiao857b8682024-09-12 16:40:32 +08001404 format = GST_VIDEO_FORMAT_YVYU;
1405 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001406 case V4L2_PIX_FMT_NV16:
1407 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001408 format = GST_VIDEO_FORMAT_NV16;
1409 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001410 case V4L2_PIX_FMT_NV61:
1411 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001412 format = GST_VIDEO_FORMAT_NV61;
1413 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001414 case V4L2_PIX_FMT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08001415 format = GST_VIDEO_FORMAT_NV24;
1416 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001417 default:
bo.xiao857b8682024-09-12 16:40:32 +08001418 format = GST_VIDEO_FORMAT_UNKNOWN;
1419 break;
1420 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001421
bo.xiao857b8682024-09-12 16:40:32 +08001422 return format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001423}
1424
1425static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001426gst_aml_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001427{
bo.xiao857b8682024-09-12 16:40:32 +08001428 gboolean ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001429
bo.xiao857b8682024-09-12 16:40:32 +08001430 switch (fourcc)
1431 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001432 case V4L2_PIX_FMT_XRGB555:
1433 case V4L2_PIX_FMT_RGB555:
1434 case V4L2_PIX_FMT_XRGB555X:
1435 case V4L2_PIX_FMT_RGB555X:
1436 case V4L2_PIX_FMT_RGB565:
1437 case V4L2_PIX_FMT_RGB24:
1438 case V4L2_PIX_FMT_BGR24:
1439 case V4L2_PIX_FMT_XRGB32:
1440 case V4L2_PIX_FMT_RGB32:
1441 case V4L2_PIX_FMT_XBGR32:
1442 case V4L2_PIX_FMT_BGR32:
1443 case V4L2_PIX_FMT_ABGR32:
1444 case V4L2_PIX_FMT_ARGB32:
1445 case V4L2_PIX_FMT_SBGGR8:
1446 case V4L2_PIX_FMT_SGBRG8:
1447 case V4L2_PIX_FMT_SGRBG8:
1448 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001449 ret = TRUE;
1450 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001451 default:
bo.xiao857b8682024-09-12 16:40:32 +08001452 break;
1453 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001454
bo.xiao857b8682024-09-12 16:40:32 +08001455 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001456}
1457
1458static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001459gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001460{
bo.xiao857b8682024-09-12 16:40:32 +08001461 GstStructure *structure = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001462
bo.xiao857b8682024-09-12 16:40:32 +08001463 switch (fourcc)
1464 {
1465 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
1466 structure = gst_structure_new_empty("video/mjpeg");
1467 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001468 case V4L2_PIX_FMT_MPEG1:
bo.xiao857b8682024-09-12 16:40:32 +08001469 structure = gst_structure_new ("video/mpeg",
1470 "mpegversion", G_TYPE_INT, 1, NULL);
1471
1472 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1473 GST_DEBUG("aml set mpeg1 systemstream to false");
1474 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001475 case V4L2_PIX_FMT_MPEG2:
bo.xiao857b8682024-09-12 16:40:32 +08001476 structure = gst_structure_new("video/mpeg",
1477 "mpegversion", G_TYPE_INT, 2, NULL);
1478 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1479 GST_DEBUG("aml set mpeg2 systemstream to false");
1480 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001481 case V4L2_PIX_FMT_MPEG4:
1482 case V4L2_PIX_FMT_XVID:
bo.xiao857b8682024-09-12 16:40:32 +08001483 structure = gst_structure_new ("video/mpeg",
1484 "mpegversion", G_TYPE_INT, 4, "systemstream",
1485 G_TYPE_BOOLEAN, FALSE, NULL);
1486 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001487 case V4L2_PIX_FMT_FWHT:
bo.xiao857b8682024-09-12 16:40:32 +08001488 structure = gst_structure_new_empty ("video/x-fwht");
1489 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001490 case V4L2_PIX_FMT_H263:
bo.xiao857b8682024-09-12 16:40:32 +08001491 structure = gst_structure_new ("video/x-h263",
1492 "variant", G_TYPE_STRING, "itu", NULL);
1493 break;
1494 case V4L2_PIX_FMT_H264: /* H.264 */
1495 structure = gst_structure_new ("video/x-h264",
1496 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1497 G_TYPE_STRING, "au", NULL);
1498 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001499 case V4L2_PIX_FMT_H264_NO_SC:
bo.xiao857b8682024-09-12 16:40:32 +08001500 structure = gst_structure_new ("video/x-h264",
1501 "stream-format", G_TYPE_STRING, "avc", "alignment",
1502 G_TYPE_STRING, "au", NULL);
1503 break;
1504 case V4L2_PIX_FMT_HEVC: /* H.265 */
1505 structure = gst_structure_new ("video/x-h265",
1506 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1507 G_TYPE_STRING, "au", NULL);
1508 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001509 case V4L2_PIX_FMT_VC1_ANNEX_G:
1510 case V4L2_PIX_FMT_VC1_ANNEX_L:
bo.xiao857b8682024-09-12 16:40:32 +08001511 structure = gst_structure_new ("video/x-wmv",
1512 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
1513 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001514 case V4L2_PIX_FMT_VP8:
bo.xiao857b8682024-09-12 16:40:32 +08001515 structure = gst_structure_new_empty ("video/x-vp8");
1516 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001517 case V4L2_PIX_FMT_VP9:
bo.xiao857b8682024-09-12 16:40:32 +08001518 structure = gst_structure_new_empty ("video/x-vp9");
1519 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001520 case V4L2_PIX_FMT_AV1:
1521 structure = gst_structure_new_empty("video/x-av1");
1522 break;
zengliang.li51f54b62023-10-10 12:14:49 +00001523 case V4L2_PIX_FMT_AVS:
1524 structure = gst_structure_new_empty("video/x-avs");
1525 break;
1526 case V4L2_PIX_FMT_AVS2:
1527 structure = gst_structure_new_empty("video/x-avs2");
1528 break;
1529 case V4L2_PIX_FMT_AVS3:
1530 structure = gst_structure_new_empty("video/x-avs3");
1531 break;
bo.xiao857b8682024-09-12 16:40:32 +08001532 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001533 case V4L2_PIX_FMT_Y16:
1534 case V4L2_PIX_FMT_Y16_BE:
1535 case V4L2_PIX_FMT_XRGB555:
1536 case V4L2_PIX_FMT_RGB555:
1537 case V4L2_PIX_FMT_XRGB555X:
1538 case V4L2_PIX_FMT_RGB555X:
1539 case V4L2_PIX_FMT_RGB565:
1540 case V4L2_PIX_FMT_RGB24:
1541 case V4L2_PIX_FMT_BGR24:
1542 case V4L2_PIX_FMT_RGB32:
1543 case V4L2_PIX_FMT_XRGB32:
1544 case V4L2_PIX_FMT_ARGB32:
1545 case V4L2_PIX_FMT_BGR32:
1546 case V4L2_PIX_FMT_XBGR32:
1547 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001548 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001549 case V4L2_PIX_FMT_NV12M:
1550 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001551 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001552 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001553 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001554 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001555 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001556 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001557 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001558 case V4L2_PIX_FMT_YVU410:
1559 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001560 case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001561 case V4L2_PIX_FMT_YUV420M:
1562 case V4L2_PIX_FMT_YUYV:
1563 case V4L2_PIX_FMT_YVU420:
1564 case V4L2_PIX_FMT_UYVY:
1565 case V4L2_PIX_FMT_YUV422P:
1566 case V4L2_PIX_FMT_YVYU:
1567 case V4L2_PIX_FMT_YUV411P:
1568 {
bo.xiao857b8682024-09-12 16:40:32 +08001569 GstVideoFormat format;
1570 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fourcc);
1571 if (format != GST_VIDEO_FORMAT_UNKNOWN)
1572 structure = gst_structure_new ("video/x-raw",
1573 "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
1574 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001575 }
1576 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001577 structure =
1578 gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1579 NULL);
1580 break;
1581 case V4L2_PIX_FMT_MPEG: /* MPEG */
1582 structure = gst_structure_new ("video/mpegts",
1583 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
1584 break;
1585 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1586 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001587 case V4L2_PIX_FMT_SBGGR8:
1588 case V4L2_PIX_FMT_SGBRG8:
1589 case V4L2_PIX_FMT_SGRBG8:
1590 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001591 structure = gst_structure_new ("video/x-bayer", "format", G_TYPE_STRING,
1592 fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" :
1593 fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg" :
1594 fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg" :
1595 /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb", NULL);
1596 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001597 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001598 structure = gst_structure_new_empty ("video/x-sonix");
1599 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001600 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001601 structure = gst_structure_new_empty ("video/x-pwc1");
1602 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001603 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001604 structure = gst_structure_new_empty ("video/x-pwc2");
1605 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001606 case V4L2_PIX_FMT_RGB332:
1607 case V4L2_PIX_FMT_BGR666:
1608 case V4L2_PIX_FMT_ARGB555X:
1609 case V4L2_PIX_FMT_RGB565X:
1610 case V4L2_PIX_FMT_RGB444:
bo.xiao857b8682024-09-12 16:40:32 +08001611 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1612 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001613 case V4L2_PIX_FMT_Y4:
1614 case V4L2_PIX_FMT_Y6:
1615 case V4L2_PIX_FMT_Y10:
1616 case V4L2_PIX_FMT_Y12:
1617 case V4L2_PIX_FMT_Y10BPACK:
1618 case V4L2_PIX_FMT_YUV444:
1619 case V4L2_PIX_FMT_YUV555:
1620 case V4L2_PIX_FMT_YUV565:
1621 case V4L2_PIX_FMT_Y41P:
1622 case V4L2_PIX_FMT_YUV32:
1623 case V4L2_PIX_FMT_NV12MT_16X16:
1624 case V4L2_PIX_FMT_NV42:
1625 case V4L2_PIX_FMT_H264_MVC:
1626 default:
bo.xiao857b8682024-09-12 16:40:32 +08001627 GST_DEBUG ("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
1628 fourcc, GST_FOURCC_ARGS (fourcc));
1629 break;
1630 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001631
bo.xiao857b8682024-09-12 16:40:32 +08001632 return structure;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001633}
1634
1635GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001636gst_aml_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001637{
bo.xiao857b8682024-09-12 16:40:32 +08001638 GstStructure *template;
1639 gint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001640
bo.xiao857b8682024-09-12 16:40:32 +08001641 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001642
bo.xiao857b8682024-09-12 16:40:32 +08001643 if (template == NULL)
1644 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001645
bo.xiao857b8682024-09-12 16:40:32 +08001646 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1647 {
1648 if (gst_aml_v4l2_formats[i].format != fourcc)
1649 continue;
1650
1651 if (gst_aml_v4l2_formats[i].dimensions)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001652 {
bo.xiao857b8682024-09-12 16:40:32 +08001653 gst_structure_set (template,
1654 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1655 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1656 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001657 }
bo.xiao857b8682024-09-12 16:40:32 +08001658 break;
1659 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001660
1661done:
bo.xiao857b8682024-09-12 16:40:32 +08001662 return template;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001663}
1664
1665static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001666gst_aml_v4l2_object_get_caps_helper (GstAmlV4L2FormatFlags flags)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001667{
bo.xiao857b8682024-09-12 16:40:32 +08001668 GstStructure *structure;
1669 GstCaps *caps;
1670 guint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001671
bo.xiao857b8682024-09-12 16:40:32 +08001672 caps = gst_caps_new_empty ();
1673 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1674 {
1675
1676 if ((gst_aml_v4l2_formats[i].flags & flags) == 0)
1677 continue;
1678
1679 structure =
1680 gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (gst_aml_v4l2_formats[i].format);
1681
1682 if (structure)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001683 {
bo.xiao857b8682024-09-12 16:40:32 +08001684 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001685
bo.xiao857b8682024-09-12 16:40:32 +08001686 if (gst_aml_v4l2_formats[i].dimensions)
1687 {
1688 gst_structure_set (structure,
1689 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1690 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1691 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1692 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001693
bo.xiao857b8682024-09-12 16:40:32 +08001694 switch (gst_aml_v4l2_formats[i].format)
1695 {
1696 case V4L2_PIX_FMT_RGB32:
1697 alt_s = gst_structure_copy (structure);
1698 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
1699 break;
1700 case V4L2_PIX_FMT_BGR32:
1701 alt_s = gst_structure_copy (structure);
1702 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
1703 default:
1704 break;
1705 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001706
bo.xiao857b8682024-09-12 16:40:32 +08001707 gst_caps_append_structure (caps, structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001708
bo.xiao857b8682024-09-12 16:40:32 +08001709 if (alt_s)
1710 gst_caps_append_structure (caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001711 }
bo.xiao857b8682024-09-12 16:40:32 +08001712 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001713
bo.xiao857b8682024-09-12 16:40:32 +08001714 return gst_caps_simplify(caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001715}
1716
1717GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001718gst_aml_v4l2_object_get_all_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001719{
bo.xiao857b8682024-09-12 16:40:32 +08001720 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001721
bo.xiao857b8682024-09-12 16:40:32 +08001722 if (g_once_init_enter (&caps))
1723 {
1724 GstCaps *all_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_ALL);
1725 GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1726 g_once_init_leave (&caps, all_caps);
1727 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001728
bo.xiao857b8682024-09-12 16:40:32 +08001729 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001730}
1731
1732GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001733gst_aml_v4l2_object_get_raw_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001734{
bo.xiao857b8682024-09-12 16:40:32 +08001735 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001736
bo.xiao857b8682024-09-12 16:40:32 +08001737 if (g_once_init_enter (&caps))
1738 {
1739 GstCaps *raw_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_RAW);
1740 GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1741 g_once_init_leave (&caps, raw_caps);
1742 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001743
bo.xiao857b8682024-09-12 16:40:32 +08001744 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001745}
1746
1747GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001748gst_aml_v4l2_object_get_codec_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001749{
bo.xiao857b8682024-09-12 16:40:32 +08001750 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001751
bo.xiao857b8682024-09-12 16:40:32 +08001752 if (g_once_init_enter (&caps))
1753 {
1754 GstCaps *codec_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
1755 GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1756 g_once_init_leave (&caps, codec_caps);
1757 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001758
bo.xiao857b8682024-09-12 16:40:32 +08001759 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001760}
1761
1762/* collect data for the given caps
1763 * @caps: given input caps
1764 * @format: location for the v4l format
1765 * @w/@h: location for width and height
1766 * @fps_n/@fps_d: location for framerate
1767 * @size: location for expected size of the frame or 0 if unknown
1768 */
1769static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001770gst_aml_v4l2_object_get_caps_info (GstAmlV4l2Object * v4l2object, GstCaps * caps,
1771 struct v4l2_fmtdesc **format, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001772{
bo.xiao857b8682024-09-12 16:40:32 +08001773 GstStructure *structure;
1774 guint32 fourcc = 0, fourcc_nc = 0;
1775 const gchar *mimetype;
1776 struct v4l2_fmtdesc *fmt = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001777
bo.xiao857b8682024-09-12 16:40:32 +08001778 GST_DEBUG_OBJECT(v4l2object, "got caps: %" GST_PTR_FORMAT, caps);
fei.denge9458472023-04-18 02:05:48 +00001779
bo.xiao857b8682024-09-12 16:40:32 +08001780 structure = gst_caps_get_structure (caps, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001781
bo.xiao857b8682024-09-12 16:40:32 +08001782 mimetype = gst_structure_get_name (structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001783
bo.xiao857b8682024-09-12 16:40:32 +08001784 if (!gst_video_info_from_caps (info, caps))
1785 goto invalid_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001786
bo.xiao857b8682024-09-12 16:40:32 +08001787 if (g_str_equal (mimetype, "video/x-raw"))
1788 {
1789 switch (GST_VIDEO_INFO_FORMAT (info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08001790 {
bo.xiao857b8682024-09-12 16:40:32 +08001791 case GST_VIDEO_FORMAT_I420:
1792 fourcc = V4L2_PIX_FMT_YUV420;
1793 fourcc_nc = V4L2_PIX_FMT_YUV420M;
1794 break;
1795 case GST_VIDEO_FORMAT_YUY2:
1796 fourcc = V4L2_PIX_FMT_YUYV;
1797 break;
1798 case GST_VIDEO_FORMAT_UYVY:
1799 fourcc = V4L2_PIX_FMT_UYVY;
1800 break;
1801 case GST_VIDEO_FORMAT_YV12:
1802 fourcc = V4L2_PIX_FMT_YVU420;
1803 break;
1804 case GST_VIDEO_FORMAT_Y41B:
1805 fourcc = V4L2_PIX_FMT_YUV411P;
1806 break;
1807 case GST_VIDEO_FORMAT_Y42B:
1808 fourcc = V4L2_PIX_FMT_YUV422P;
1809 break;
1810 case GST_VIDEO_FORMAT_NV12:
1811 fourcc = V4L2_PIX_FMT_NV12;
1812 fourcc_nc = V4L2_PIX_FMT_NV12M;
1813 break;
1814 case GST_VIDEO_FORMAT_NV12_64Z32:
1815 fourcc_nc = V4L2_PIX_FMT_NV12MT;
1816 break;
1817 case GST_VIDEO_FORMAT_NV21:
1818 fourcc = V4L2_PIX_FMT_NV21;
1819 fourcc_nc = V4L2_PIX_FMT_NV21M;
1820 break;
1821 case GST_VIDEO_FORMAT_NV16:
1822 fourcc = V4L2_PIX_FMT_NV16;
1823 fourcc_nc = V4L2_PIX_FMT_NV16M;
1824 break;
1825 case GST_VIDEO_FORMAT_NV61:
1826 fourcc = V4L2_PIX_FMT_NV61;
1827 fourcc_nc = V4L2_PIX_FMT_NV61M;
1828 break;
1829 case GST_VIDEO_FORMAT_NV24:
1830 fourcc = V4L2_PIX_FMT_NV24;
1831 break;
1832 case GST_VIDEO_FORMAT_YVYU:
1833 fourcc = V4L2_PIX_FMT_YVYU;
1834 break;
1835 case GST_VIDEO_FORMAT_RGB15:
1836 fourcc = V4L2_PIX_FMT_RGB555;
1837 fourcc_nc = V4L2_PIX_FMT_XRGB555;
1838 break;
1839 case GST_VIDEO_FORMAT_RGB16:
1840 fourcc = V4L2_PIX_FMT_RGB565;
1841 break;
1842 case GST_VIDEO_FORMAT_RGB:
1843 fourcc = V4L2_PIX_FMT_RGB24;
1844 break;
1845 case GST_VIDEO_FORMAT_BGR:
1846 fourcc = V4L2_PIX_FMT_BGR24;
1847 break;
1848 case GST_VIDEO_FORMAT_xRGB:
1849 fourcc = V4L2_PIX_FMT_RGB32;
1850 fourcc_nc = V4L2_PIX_FMT_XRGB32;
1851 break;
1852 case GST_VIDEO_FORMAT_ARGB:
1853 fourcc = V4L2_PIX_FMT_RGB32;
1854 fourcc_nc = V4L2_PIX_FMT_ARGB32;
1855 break;
1856 case GST_VIDEO_FORMAT_BGRx:
1857 fourcc = V4L2_PIX_FMT_BGR32;
1858 fourcc_nc = V4L2_PIX_FMT_XBGR32;
1859 break;
1860 case GST_VIDEO_FORMAT_BGRA:
1861 fourcc = V4L2_PIX_FMT_BGR32;
1862 fourcc_nc = V4L2_PIX_FMT_ABGR32;
1863 break;
1864 case GST_VIDEO_FORMAT_GRAY8:
1865 fourcc = V4L2_PIX_FMT_GREY;
1866 break;
1867 case GST_VIDEO_FORMAT_GRAY16_LE:
1868 fourcc = V4L2_PIX_FMT_Y16;
1869 break;
1870 case GST_VIDEO_FORMAT_GRAY16_BE:
1871 fourcc = V4L2_PIX_FMT_Y16_BE;
1872 break;
1873 case GST_VIDEO_FORMAT_BGR15:
1874 fourcc = V4L2_PIX_FMT_RGB555X;
1875 fourcc_nc = V4L2_PIX_FMT_XRGB555X;
1876 break;
1877 default:
1878 break;
1879 }
1880 }
1881 else
1882 {
1883 if (g_str_equal (mimetype, "video/mpegts"))
1884 {
1885 fourcc = V4L2_PIX_FMT_MPEG;
1886 }
1887 else if (g_str_equal (mimetype, "video/x-dv"))
1888 {
1889 fourcc = V4L2_PIX_FMT_DV;
1890 }
1891 else if (g_str_equal(mimetype, "video/mjpeg"))
1892 {
1893 fourcc = V4L2_PIX_FMT_JPEG;
1894 }
1895 else if (g_str_equal (mimetype, "video/mpeg"))
1896 {
1897 gint version;
1898 if (gst_structure_get_int (structure, "mpegversion", &version))
1899 {
1900 switch (version)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001901 {
bo.xiao857b8682024-09-12 16:40:32 +08001902 case 1:
1903 fourcc = V4L2_PIX_FMT_MPEG1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001904 break;
bo.xiao857b8682024-09-12 16:40:32 +08001905 case 2:
1906 fourcc = V4L2_PIX_FMT_MPEG2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001907 break;
bo.xiao857b8682024-09-12 16:40:32 +08001908 case 4:
1909 fourcc = V4L2_PIX_FMT_MPEG4;
1910 fourcc_nc = V4L2_PIX_FMT_XVID;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001911 break;
bo.xiao857b8682024-09-12 16:40:32 +08001912 default:
xuesong.jiangae1548e2022-05-06 16:38:46 +08001913 break;
1914 }
bo.xiao857b8682024-09-12 16:40:32 +08001915 }
1916 }
1917 else if (g_str_equal (mimetype, "video/x-fwht"))
1918 {
1919 fourcc = V4L2_PIX_FMT_FWHT;
1920 }
1921 else if (g_str_equal (mimetype, "video/x-h263"))
1922 {
1923 fourcc = V4L2_PIX_FMT_H263;
1924 }
1925 else if (g_str_equal (mimetype, "video/x-h264"))
1926 {
1927 const gchar *stream_format =
1928 gst_structure_get_string (structure, "stream-format");
1929 if (g_str_equal (stream_format, "avc"))
1930 fourcc = V4L2_PIX_FMT_H264_NO_SC;
1931 else
1932 fourcc = V4L2_PIX_FMT_H264;
1933 }
1934 else if (g_str_equal (mimetype, "video/x-h265"))
1935 {
1936 fourcc = V4L2_PIX_FMT_HEVC;
1937 }
1938 else if (g_str_equal (mimetype, "video/x-vp8"))
1939 {
1940 fourcc = V4L2_PIX_FMT_VP8;
1941 }
1942 else if (g_str_equal (mimetype, "video/x-vp9"))
1943 {
1944 fourcc = V4L2_PIX_FMT_VP9;
1945 }
1946 else if (g_str_equal(mimetype, "video/x-av1"))
1947 {
1948 fourcc = V4L2_PIX_FMT_AV1;
1949 }
1950 else if (g_str_equal(mimetype, "video/x-avs"))
1951 {
1952 fourcc = V4L2_PIX_FMT_AVS;
1953 }
1954 else if (g_str_equal(mimetype, "video/x-avs2"))
1955 {
1956 fourcc = V4L2_PIX_FMT_AVS2;
1957 }
1958 else if (g_str_equal(mimetype, "video/x-avs3"))
1959 {
1960 fourcc = V4L2_PIX_FMT_AVS3;
1961 }
1962 else if (g_str_equal (mimetype, "video/x-bayer"))
1963 {
1964 const gchar *vformat = gst_structure_get_string(structure, "format");
1965 if (vformat)
1966 {
1967 if (!g_ascii_strcasecmp(vformat, "bggr"))
1968 fourcc = V4L2_PIX_FMT_SBGGR8;
1969 else if (!g_ascii_strcasecmp(vformat, "gbrg"))
1970 fourcc = V4L2_PIX_FMT_SGBRG8;
1971 else if (!g_ascii_strcasecmp(vformat, "grbg"))
1972 fourcc = V4L2_PIX_FMT_SGRBG8;
1973 else if (!g_ascii_strcasecmp(vformat, "rggb"))
1974 fourcc = V4L2_PIX_FMT_SRGGB8;
1975 }
1976 }
1977 else if (g_str_equal (mimetype, "video/x-sonix"))
1978 {
1979 fourcc = V4L2_PIX_FMT_SN9C10X;
1980 }
1981 else if (g_str_equal (mimetype, "video/x-pwc1"))
1982 {
1983 fourcc = V4L2_PIX_FMT_PWC1;
1984 }
1985 else if (g_str_equal (mimetype, "video/x-pwc2"))
1986 {
1987 fourcc = V4L2_PIX_FMT_PWC2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001988 }
1989 else
1990 {
bo.xiao857b8682024-09-12 16:40:32 +08001991 GST_ERROR("Unknown video codec %s.", mimetype);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001992 }
bo.xiao857b8682024-09-12 16:40:32 +08001993 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001994
bo.xiao857b8682024-09-12 16:40:32 +08001995 /* Prefer the non-contiguous if supported */
1996 v4l2object->prefered_non_contiguous = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001997
bo.xiao857b8682024-09-12 16:40:32 +08001998 if (fourcc_nc)
1999 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_nc);
2000 else if (fourcc == 0)
2001 goto unhandled_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002002
bo.xiao857b8682024-09-12 16:40:32 +08002003 if (fmt == NULL)
2004 {
2005 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
2006 v4l2object->prefered_non_contiguous = FALSE;
2007 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002008
bo.xiao857b8682024-09-12 16:40:32 +08002009 if (fmt == NULL)
2010 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002011
bo.xiao857b8682024-09-12 16:40:32 +08002012 *format = fmt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002013
bo.xiao857b8682024-09-12 16:40:32 +08002014 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002015
bo.xiao857b8682024-09-12 16:40:32 +08002016 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002017invalid_format:
bo.xiao857b8682024-09-12 16:40:32 +08002018 {
2019 GST_DEBUG_OBJECT (v4l2object, "invalid format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002020 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002021 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002022unhandled_format:
bo.xiao857b8682024-09-12 16:40:32 +08002023 {
2024 GST_DEBUG_OBJECT (v4l2object, "unhandled format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002025 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002026 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002027unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08002028 {
2029 GST_DEBUG_OBJECT (v4l2object, "unsupported format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002030 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002031 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002032}
2033
2034static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002035gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
2036 guint32 pixelformat, gint * width, gint * height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002037
2038static void
bo.xiao857b8682024-09-12 16:40:32 +08002039gst_aml_v4l2_object_add_aspect_ratio (GstAmlV4l2Object * v4l2object, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002040{
bo.xiao857b8682024-09-12 16:40:32 +08002041 if (v4l2object->keep_aspect && v4l2object->par)
2042 gst_structure_set_value (s, "pixel-aspect-ratio", v4l2object->par);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002043}
2044
2045/* returns TRUE if the value was changed in place, otherwise FALSE */
2046static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002047gst_aml_v4l2src_value_simplify (GValue * val)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002048{
bo.xiao857b8682024-09-12 16:40:32 +08002049 /* simplify list of one value to one value */
2050 if (GST_VALUE_HOLDS_LIST (val) && gst_value_list_get_size (val) == 1)
2051 {
2052 const GValue *list_val;
2053 GValue new_val = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002054
bo.xiao857b8682024-09-12 16:40:32 +08002055 list_val = gst_value_list_get_value (val, 0);
2056 g_value_init (&new_val, G_VALUE_TYPE (list_val));
2057 g_value_copy (list_val, &new_val);
2058 g_value_unset (val);
2059 *val = new_val;
2060 return TRUE;
2061 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002062
bo.xiao857b8682024-09-12 16:40:32 +08002063 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002064}
2065
2066static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002067gst_aml_v4l2_object_get_interlace_mode (enum v4l2_field field,
2068 GstVideoInterlaceMode * interlace_mode)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002069{
bo.xiao857b8682024-09-12 16:40:32 +08002070 switch (field)
2071 {
2072 case V4L2_FIELD_ANY:
2073 GST_ERROR("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
2074 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002075 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002076 *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
2077 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002078 case V4L2_FIELD_INTERLACED:
2079 case V4L2_FIELD_INTERLACED_TB:
2080 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08002081 *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
2082 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002083 default:
bo.xiao857b8682024-09-12 16:40:32 +08002084 GST_ERROR ("Unknown enum v4l2_field %d", field);
2085 return FALSE;
2086 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002087}
2088
2089static gboolean
2090gst_aml_v4l2_object_get_colorspace(struct v4l2_format *fmt,
2091 GstVideoColorimetry *cinfo)
2092{
bo.xiao857b8682024-09-12 16:40:32 +08002093 gboolean is_rgb =
2094 gst_aml_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat);
2095 enum v4l2_colorspace colorspace;
2096 enum v4l2_quantization range;
2097 enum v4l2_ycbcr_encoding matrix;
2098 enum v4l2_xfer_func transfer;
2099 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002100
bo.xiao857b8682024-09-12 16:40:32 +08002101 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type))
2102 {
2103 colorspace = fmt->fmt.pix_mp.colorspace;
2104 range = fmt->fmt.pix_mp.quantization;
2105 matrix = fmt->fmt.pix_mp.ycbcr_enc;
2106 transfer = fmt->fmt.pix_mp.xfer_func;
2107 }
2108 else
2109 {
2110 colorspace = fmt->fmt.pix.colorspace;
2111 range = fmt->fmt.pix.quantization;
2112 matrix = fmt->fmt.pix.ycbcr_enc;
2113 transfer = fmt->fmt.pix.xfer_func;
2114 }
2115 GST_DEBUG("colorspace:%d, range:%d, matrix:%d, transfer:%d", colorspace, range, matrix, transfer);
2116 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 +08002117
bo.xiao857b8682024-09-12 16:40:32 +08002118 /* First step, set the defaults for each primaries */
2119 switch (colorspace)
2120 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002121 case V4L2_COLORSPACE_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08002122 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2123 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2124 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2125 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
2126 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002127 case V4L2_COLORSPACE_REC709:
bo.xiao857b8682024-09-12 16:40:32 +08002128 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2129 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2130 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2131 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2132 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002133 case V4L2_COLORSPACE_SRGB:
2134 case V4L2_COLORSPACE_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08002135 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2136 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2137 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2138 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2139 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002140 case V4L2_COLORSPACE_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002141 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2142 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2143 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2144 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
2145 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002146 case V4L2_COLORSPACE_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002147 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2148 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2149 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2150 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
2151 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002152 case V4L2_COLORSPACE_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002153 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2154 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2155 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2156 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
2157 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002158 case V4L2_COLORSPACE_470_SYSTEM_M:
bo.xiao857b8682024-09-12 16:40:32 +08002159 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2160 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2161 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2162 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
2163 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002164 case V4L2_COLORSPACE_470_SYSTEM_BG:
bo.xiao857b8682024-09-12 16:40:32 +08002165 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2166 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2167 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2168 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
2169 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002170 case V4L2_COLORSPACE_RAW:
bo.xiao857b8682024-09-12 16:40:32 +08002171 /* Explicitly unknown */
2172 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2173 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2174 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2175 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
2176 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002177 default:
bo.xiao857b8682024-09-12 16:40:32 +08002178 GST_DEBUG ("Unknown enum v4l2_colorspace %d", colorspace);
2179 ret = FALSE;
2180 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002181 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002182 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 +08002183
bo.xiao857b8682024-09-12 16:40:32 +08002184 if (!ret)
2185 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002186
bo.xiao857b8682024-09-12 16:40:32 +08002187 /* Second step, apply any custom variation */
2188 switch (range)
2189 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002190 case V4L2_QUANTIZATION_FULL_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002191 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2192 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002193 case V4L2_QUANTIZATION_LIM_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002194 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2195 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002196 case V4L2_QUANTIZATION_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002197 /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
2198 if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
2199 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2200 else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601
2201 || matrix == V4L2_YCBCR_ENC_XV709
2202 || colorspace == V4L2_COLORSPACE_JPEG)
2203 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2204 else
2205 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2206 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002207 default:
bo.xiao857b8682024-09-12 16:40:32 +08002208 GST_WARNING ("Unknown enum v4l2_quantization value %d", range);
2209 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2210 break;
2211 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002212 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 +08002213
bo.xiao857b8682024-09-12 16:40:32 +08002214 switch (matrix)
2215 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002216 case V4L2_YCBCR_ENC_XV601:
2217 case V4L2_YCBCR_ENC_SYCC:
bo.xiao857b8682024-09-12 16:40:32 +08002218 GST_FIXME ("XV601 and SYCC not defined, assuming 601");
2219 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002220 case V4L2_YCBCR_ENC_601:
bo.xiao857b8682024-09-12 16:40:32 +08002221 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2222 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002223 case V4L2_YCBCR_ENC_XV709:
bo.xiao857b8682024-09-12 16:40:32 +08002224 GST_FIXME ("XV709 not defined, assuming 709");
2225 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002226 case V4L2_YCBCR_ENC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002227 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2228 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002229 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
bo.xiao857b8682024-09-12 16:40:32 +08002230 GST_FIXME ("BT2020 with constant luma is not defined, assuming BT2020");
2231 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002232 case V4L2_YCBCR_ENC_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002233 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2234 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002235 case V4L2_YCBCR_ENC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002236 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2237 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002238 case V4L2_YCBCR_ENC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002239 /* nothing, just use defaults for colorspace */
2240 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002241 default:
bo.xiao857b8682024-09-12 16:40:32 +08002242 GST_WARNING ("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
2243 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2244 break;
2245 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002246 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 +08002247
bo.xiao857b8682024-09-12 16:40:32 +08002248 /* Set identity matrix for R'G'B' formats to avoid creating
2249 * confusion. This though is cosmetic as it's now properly ignored by
2250 * the video info API and videoconvert. */
2251 if (is_rgb)
2252 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002253
bo.xiao857b8682024-09-12 16:40:32 +08002254 switch (transfer)
2255 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002256 case V4L2_XFER_FUNC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002257 if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160)
2258 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2259 else
2260 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2261 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002262 case V4L2_XFER_FUNC_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002263 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2264 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002265 case V4L2_XFER_FUNC_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002266 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2267 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002268 case V4L2_XFER_FUNC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002269 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2270 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002271 case V4L2_XFER_FUNC_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002272 cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
2273 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002274 case V4L2_XFER_FUNC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002275 /* nothing, just use defaults for colorspace */
2276 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002277 default:
bo.xiao857b8682024-09-12 16:40:32 +08002278 GST_WARNING ("Unknown enum v4l2_xfer_func value %d", transfer);
2279 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2280 break;
2281 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002282 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 +08002283
2284done:
bo.xiao857b8682024-09-12 16:40:32 +08002285 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002286}
2287
2288static int
bo.xiao857b8682024-09-12 16:40:32 +08002289gst_aml_v4l2_object_try_fmt (GstAmlV4l2Object * v4l2object,
2290 struct v4l2_format *try_fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002291{
bo.xiao857b8682024-09-12 16:40:32 +08002292 int fd = v4l2object->video_fd;
2293 struct v4l2_format fmt;
2294 int r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002295
bo.xiao857b8682024-09-12 16:40:32 +08002296 memcpy (&fmt, try_fmt, sizeof (fmt));
2297 r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002298
bo.xiao857b8682024-09-12 16:40:32 +08002299 if (r < 0 && errno == ENOTTY)
2300 {
2301 /* The driver might not implement TRY_FMT, in which case we will try
2302 S_FMT to probe */
2303 if (GST_AML_V4L2_IS_ACTIVE (v4l2object))
2304 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002305
bo.xiao857b8682024-09-12 16:40:32 +08002306 memcpy (&fmt, try_fmt, sizeof (fmt));
2307 r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
2308 }
2309 memcpy (try_fmt, &fmt, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002310
bo.xiao857b8682024-09-12 16:40:32 +08002311 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002312
2313error:
bo.xiao857b8682024-09-12 16:40:32 +08002314 memcpy (try_fmt, &fmt, sizeof (fmt));
2315 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2316 "Unable to try format: %s", g_strerror (errno));
2317 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002318}
2319
2320static void
bo.xiao857b8682024-09-12 16:40:32 +08002321gst_aml_v4l2_object_add_interlace_mode (GstAmlV4l2Object * v4l2object,
2322 GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002323{
bo.xiao857b8682024-09-12 16:40:32 +08002324 struct v4l2_format fmt;
2325 GValue interlace_formats = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002326
bo.xiao857b8682024-09-12 16:40:32 +08002327 enum v4l2_field formats[] = {V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED};
2328 gsize i;
2329 GstVideoInterlaceMode interlace_mode, prev = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002330
bo.xiao857b8682024-09-12 16:40:32 +08002331 if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08002332 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002333
bo.xiao857b8682024-09-12 16:40:32 +08002334 if (v4l2object->never_interlaced)
2335 {
2336 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
2337 return;
2338 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002339
bo.xiao857b8682024-09-12 16:40:32 +08002340 g_value_init (&interlace_formats, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002341
bo.xiao857b8682024-09-12 16:40:32 +08002342 /* Try twice - once for NONE, once for INTERLACED. */
2343 for (i = 0; i < G_N_ELEMENTS (formats); i++)
2344 {
2345 memset (&fmt, 0, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002346 fmt.type = v4l2object->type;
2347 fmt.fmt.pix.width = width;
2348 fmt.fmt.pix.height = height;
2349 fmt.fmt.pix.pixelformat = pixelformat;
bo.xiao857b8682024-09-12 16:40:32 +08002350 fmt.fmt.pix.field = formats[i];
xuesong.jiangae1548e2022-05-06 16:38:46 +08002351
bo.xiao857b8682024-09-12 16:40:32 +08002352 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0 &&
2353 gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode)
2354 {
2355 GValue interlace_enum = { 0, };
2356 const gchar *mode_string;
2357 g_value_init (&interlace_enum, G_TYPE_STRING);
2358 mode_string = gst_video_interlace_mode_to_string (interlace_mode);
2359 g_value_set_string (&interlace_enum, mode_string);
2360 gst_value_list_append_and_take_value (&interlace_formats,
2361 &interlace_enum);
2362 prev = interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002363 }
bo.xiao857b8682024-09-12 16:40:32 +08002364 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002365
bo.xiao857b8682024-09-12 16:40:32 +08002366 if (gst_aml_v4l2src_value_simplify (&interlace_formats)
2367 || gst_value_list_get_size (&interlace_formats) > 0)
2368 gst_structure_take_value (s, "interlace-mode", &interlace_formats);
2369 else
2370 GST_WARNING_OBJECT (v4l2object, "Failed to determine interlace mode");
2371
2372 return;
2373}
2374
2375static void
2376gst_aml_v4l2_object_fill_colorimetry_list (GValue * list,
2377 GstVideoColorimetry * cinfo)
2378{
2379 GValue colorimetry = G_VALUE_INIT;
2380 guint size;
2381 guint i;
2382 gboolean found = FALSE;
2383
2384 g_value_init (&colorimetry, G_TYPE_STRING);
2385 g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo));
2386 GST_DEBUG("fill colorimetry:%s into list", gst_video_colorimetry_to_string(cinfo));
2387
2388 /* only insert if no duplicate */
2389 size = gst_value_list_get_size (list);
2390 for (i = 0; i < size; i++)
2391 {
2392 const GValue *tmp;
2393
2394 tmp = gst_value_list_get_value (list, i);
2395 if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002396 {
bo.xiao857b8682024-09-12 16:40:32 +08002397 found = TRUE;
2398 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002399 }
bo.xiao857b8682024-09-12 16:40:32 +08002400 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002401
bo.xiao857b8682024-09-12 16:40:32 +08002402 if (!found)
2403 gst_value_list_append_and_take_value (list, &colorimetry);
2404 else
2405 g_value_unset (&colorimetry);
2406}
xuesong.jiange1a19662022-06-21 20:30:22 +08002407
bo.xiao857b8682024-09-12 16:40:32 +08002408static void
2409gst_aml_v4l2_object_add_colorspace (GstAmlV4l2Object * v4l2object, GstStructure * s,
2410 guint32 width, guint32 height, guint32 pixelformat)
2411{
2412 struct v4l2_format fmt;
2413 GValue list = G_VALUE_INIT;
2414 GstVideoColorimetry cinfo;
2415 enum v4l2_colorspace req_cspace;
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002416
bo.xiao857b8682024-09-12 16:40:32 +08002417 memset (&fmt, 0, sizeof (fmt));
2418 fmt.type = v4l2object->type;
2419 fmt.fmt.pix.width = width;
2420 fmt.fmt.pix.height = height;
2421 fmt.fmt.pix.pixelformat = pixelformat;
xuesong.jiang5c9aca72022-07-12 16:29:24 +08002422
bo.xiao857b8682024-09-12 16:40:32 +08002423 g_value_init (&list, GST_TYPE_LIST);
fei.dengccc89632022-07-15 19:10:17 +08002424
bo.xiao857b8682024-09-12 16:40:32 +08002425 /* step 1: get device default colorspace and insert it first as
2426 * it should be the preferred one */
2427 GST_DEBUG("try for pixl format");
2428 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2429 {
2430 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2431 gst_aml_v4l2_object_fill_colorimetry_list (&list, &cinfo);
2432 }
fei.dengca85b052022-07-19 14:49:23 +08002433
bo.xiao857b8682024-09-12 16:40:32 +08002434 /* step 2: probe all colorspace other than default
2435 * We don't probe all colorspace, range, matrix and transfer combination to
2436 * avoid ioctl flooding which could greatly increase initialization time
2437 * with low-speed devices (UVC...) */
2438 for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
2439 req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++)
2440 {
2441 GST_DEBUG("try for pixl format in while loop :%d", req_cspace);
2442 /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
2443 if (req_cspace == V4L2_COLORSPACE_BT878)
2444 continue;
sheng.liua326d202022-07-20 14:15:34 +08002445
bo.xiao857b8682024-09-12 16:40:32 +08002446 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2447 fmt.fmt.pix_mp.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002448 else
bo.xiao857b8682024-09-12 16:40:32 +08002449 fmt.fmt.pix.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002450
bo.xiao857b8682024-09-12 16:40:32 +08002451 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2452 {
2453 GST_DEBUG("try for pixl format in while loop :%d tried ok", req_cspace);
2454 enum v4l2_colorspace colorspace;
2455
2456 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2457 colorspace = fmt.fmt.pix_mp.colorspace;
2458 else
2459 colorspace = fmt.fmt.pix.colorspace;
2460
2461 if (colorspace == req_cspace)
2462 {
2463 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2464 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2465 }
2466 }
2467 }
2468
2469 GST_DEBUG("deal: caps with colorimetry 2,3,14,7");
2470 cinfo.range = 2;
2471 cinfo.matrix = 3;
2472 cinfo.transfer = 14;
2473 cinfo.primaries = 7;
2474 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2475
2476 GST_DEBUG("deal: caps with colorimetry 2,6,13,7");
2477 cinfo.range = 2;
2478 cinfo.matrix = 6;
2479 cinfo.transfer = 13;
2480 cinfo.primaries = 7;
2481 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2482
2483 GST_DEBUG("deal: caps with colorimetry 2,6,14,7");
2484 cinfo.range = 2;
2485 cinfo.matrix = 6;
2486 cinfo.transfer = 14;
2487 cinfo.primaries = 7;
2488 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2489
2490 GST_DEBUG("deal: caps with colorimetry 2,6,0,7");
2491 cinfo.range = 2;
2492 cinfo.matrix = 6;
2493 cinfo.transfer = 0;
2494 cinfo.primaries = 7;
2495 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2496
2497 GST_DEBUG("deal: caps with colorimetry 0,6,0,7");
2498 cinfo.range = 0;
2499 cinfo.matrix = 6;
2500 cinfo.transfer = 0;
2501 cinfo.primaries = 7;
2502 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2503
2504 GST_DEBUG("deal: caps with colorimetry 2,3,0,0");
2505 cinfo.range = 2;
2506 cinfo.matrix = 3;
2507 cinfo.transfer = 0;
2508 cinfo.primaries = 0;
2509 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2510
2511 GST_DEBUG("deal: caps with colorimetry 2,6,14,0");
2512 cinfo.range = 2;
2513 cinfo.matrix = 6;
2514 cinfo.transfer = 14;
2515 cinfo.primaries = 0;
2516 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2517
2518 if (gst_value_list_get_size (&list) > 0)
2519 gst_structure_take_value (s, "colorimetry", &list);
2520 else
2521 g_value_unset (&list);
2522
2523 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002524}
2525
2526/* The frame interval enumeration code first appeared in Linux 2.6.19. */
2527static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08002528gst_aml_v4l2_object_probe_caps_for_format_and_size (GstAmlV4l2Object * v4l2object,
2529 guint32 pixelformat,
2530 guint32 width, guint32 height, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002531{
bo.xiao857b8682024-09-12 16:40:32 +08002532 gint fd = v4l2object->video_fd;
2533 struct v4l2_frmivalenum ival;
2534 guint32 num, denom;
2535 GstStructure *s;
2536 GValue rates = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002537
bo.xiao857b8682024-09-12 16:40:32 +08002538 memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
2539 ival.index = 0;
2540 ival.pixel_format = pixelformat;
2541 ival.width = width;
2542 ival.height = height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002543
bo.xiao857b8682024-09-12 16:40:32 +08002544 GST_LOG_OBJECT (v4l2object->dbg_obj,
2545 "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
2546 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002547
bo.xiao857b8682024-09-12 16:40:32 +08002548 /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
2549 * fraction to get framerate */
2550 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
2551 goto enum_frameintervals_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002552
bo.xiao857b8682024-09-12 16:40:32 +08002553 if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
2554 {
2555 GValue rate = { 0, };
2556
2557 g_value_init (&rates, GST_TYPE_LIST);
2558 g_value_init (&rate, GST_TYPE_FRACTION);
2559
2560 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002561 {
bo.xiao857b8682024-09-12 16:40:32 +08002562 num = ival.discrete.numerator;
2563 denom = ival.discrete.denominator;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002564
bo.xiao857b8682024-09-12 16:40:32 +08002565 if (num > G_MAXINT || denom > G_MAXINT)
2566 {
2567 /* let us hope we don't get here... */
2568 num >>= 1;
2569 denom >>= 1;
2570 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002571
bo.xiao857b8682024-09-12 16:40:32 +08002572 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
2573 denom, num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002574
bo.xiao857b8682024-09-12 16:40:32 +08002575 /* swap to get the framerate */
2576 gst_value_set_fraction (&rate, denom, num);
2577 gst_value_list_append_value (&rates, &rate);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002578
bo.xiao857b8682024-09-12 16:40:32 +08002579 ival.index++;
2580 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
2581 }
2582 else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
2583 {
2584 GValue min = { 0, };
2585 GValue step = { 0, };
2586 GValue max = { 0, };
2587 gboolean added = FALSE;
2588 guint32 minnum, mindenom;
2589 guint32 maxnum, maxdenom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002590
bo.xiao857b8682024-09-12 16:40:32 +08002591 g_value_init (&rates, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002592
bo.xiao857b8682024-09-12 16:40:32 +08002593 g_value_init (&min, GST_TYPE_FRACTION);
2594 g_value_init (&step, GST_TYPE_FRACTION);
2595 g_value_init (&max, GST_TYPE_FRACTION);
2596
2597 /* get the min */
2598 minnum = ival.stepwise.min.numerator;
2599 mindenom = ival.stepwise.min.denominator;
2600 if (minnum > G_MAXINT || mindenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002601 {
bo.xiao857b8682024-09-12 16:40:32 +08002602 minnum >>= 1;
2603 mindenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002604 }
bo.xiao857b8682024-09-12 16:40:32 +08002605 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
2606 minnum, mindenom);
2607 gst_value_set_fraction (&min, minnum, mindenom);
2608
2609 /* get the max */
2610 maxnum = ival.stepwise.max.numerator;
2611 maxdenom = ival.stepwise.max.denominator;
2612 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002613 {
bo.xiao857b8682024-09-12 16:40:32 +08002614 maxnum >>= 1;
2615 maxdenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002616 }
bo.xiao857b8682024-09-12 16:40:32 +08002617
2618 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
2619 maxnum, maxdenom);
2620 gst_value_set_fraction (&max, maxnum, maxdenom);
2621
2622 /* get the step */
2623 num = ival.stepwise.step.numerator;
2624 denom = ival.stepwise.step.denominator;
2625 if (num > G_MAXINT || denom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002626 {
bo.xiao857b8682024-09-12 16:40:32 +08002627 num >>= 1;
2628 denom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002629 }
2630
bo.xiao857b8682024-09-12 16:40:32 +08002631 if (num == 0 || denom == 0)
2632 {
2633 /* in this case we have a wrong fraction or no step, set the step to max
2634 * so that we only add the min value in the loop below */
2635 num = maxnum;
2636 denom = maxdenom;
2637 }
2638
2639 /* since we only have gst_value_fraction_subtract and not add, negate the
2640 * numerator */
2641 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
2642 num, denom);
2643 gst_value_set_fraction (&step, -num, denom);
2644
2645 while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN)
2646 {
2647 GValue rate = { 0, };
2648
2649 num = gst_value_get_fraction_numerator (&min);
2650 denom = gst_value_get_fraction_denominator (&min);
2651 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
2652 denom, num);
2653
2654 /* invert to get the framerate */
2655 g_value_init (&rate, GST_TYPE_FRACTION);
2656 gst_value_set_fraction (&rate, denom, num);
2657 gst_value_list_append_value (&rates, &rate);
2658 added = TRUE;
2659
2660 /* we're actually adding because step was negated above. This is because
2661 * there is no _add function... */
2662 if (!gst_value_fraction_subtract (&min, &min, &step))
2663 {
2664 GST_WARNING_OBJECT (v4l2object->dbg_obj, "could not step fraction!");
2665 break;
2666 }
2667 }
2668 if (!added)
2669 {
2670 /* no range was added, leave the default range from the template */
2671 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2672 "no range added, leaving default");
2673 g_value_unset (&rates);
2674 }
2675 }
2676 else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
2677 {
2678 guint32 maxnum, maxdenom;
2679
2680 g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
2681
2682 num = ival.stepwise.min.numerator;
2683 denom = ival.stepwise.min.denominator;
2684 if (num > G_MAXINT || denom > G_MAXINT)
2685 {
2686 num >>= 1;
2687 denom >>= 1;
2688 }
2689
2690 maxnum = ival.stepwise.max.numerator;
2691 maxdenom = ival.stepwise.max.denominator;
2692 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2693 {
2694 maxnum >>= 1;
2695 maxdenom >>= 1;
2696 }
2697
2698 GST_LOG_OBJECT (v4l2object->dbg_obj,
2699 "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2700 num);
2701
2702 gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
2703 }
2704 else
2705 {
2706 goto unknown_type;
2707 }
2708
xuesong.jiangae1548e2022-05-06 16:38:46 +08002709return_data:
bo.xiao857b8682024-09-12 16:40:32 +08002710 s = gst_structure_copy (template);
2711 gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
2712 "height", G_TYPE_INT, (gint) height, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002713
bo.xiao857b8682024-09-12 16:40:32 +08002714 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002715
bo.xiao857b8682024-09-12 16:40:32 +08002716 if (!v4l2object->skip_try_fmt_probes)
2717 {
2718 gst_aml_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
2719 pixelformat);
2720 // gst_aml_v4l2_object_add_colorspace(v4l2object, s, width, height, pixelformat);
2721 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002722
bo.xiao857b8682024-09-12 16:40:32 +08002723 if (G_IS_VALUE (&rates))
2724 {
2725 gst_aml_v4l2src_value_simplify (&rates);
2726 /* only change the framerate on the template when we have a valid probed new
2727 * value */
2728 gst_structure_take_value (s, "framerate", &rates);
2729 }
2730 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2731 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2732 {
2733 gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
2734 1, NULL);
2735 }
2736 return s;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002737
bo.xiao857b8682024-09-12 16:40:32 +08002738 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002739enum_frameintervals_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002740 {
2741 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2742 "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2743 GST_FOURCC_ARGS (pixelformat), width, height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002744 goto return_data;
bo.xiao857b8682024-09-12 16:40:32 +08002745 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002746unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08002747 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002748 /* I don't see how this is actually an error, we ignore the format then */
bo.xiao857b8682024-09-12 16:40:32 +08002749 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2750 "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2751 GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002752 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +08002753 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002754}
2755
2756static gint
bo.xiao857b8682024-09-12 16:40:32 +08002757sort_by_frame_size (GstStructure * s1, GstStructure * s2)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002758{
bo.xiao857b8682024-09-12 16:40:32 +08002759 int w1, h1, w2, h2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002760
bo.xiao857b8682024-09-12 16:40:32 +08002761 gst_structure_get_int (s1, "width", &w1);
2762 gst_structure_get_int (s1, "height", &h1);
2763 gst_structure_get_int (s2, "width", &w2);
2764 gst_structure_get_int (s2, "height", &h2);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002765
bo.xiao857b8682024-09-12 16:40:32 +08002766 /* I think it's safe to assume that this won't overflow for a while */
2767 return ((w2 * h2) - (w1 * h1));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002768}
2769
2770static void
bo.xiao857b8682024-09-12 16:40:32 +08002771gst_aml_v4l2_object_update_and_append (GstAmlV4l2Object * v4l2object,
2772 guint32 format, GstCaps * caps, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002773{
bo.xiao857b8682024-09-12 16:40:32 +08002774 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002775
bo.xiao857b8682024-09-12 16:40:32 +08002776 /* Encoded stream on output buffer need to be parsed */
2777 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
2778 v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2779 {
2780 gint i = 0;
2781
2782 for (; i < GST_AML_V4L2_FORMAT_COUNT; i++)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002783 {
bo.xiao857b8682024-09-12 16:40:32 +08002784 if (format == gst_aml_v4l2_formats[i].format &&
2785 gst_aml_v4l2_formats[i].flags & GST_V4L2_CODEC &&
2786 !(gst_aml_v4l2_formats[i].flags & GST_V4L2_NO_PARSE))
2787 {
2788 gst_structure_set (s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2789 break;
2790 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002791 }
bo.xiao857b8682024-09-12 16:40:32 +08002792 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002793
bo.xiao857b8682024-09-12 16:40:32 +08002794 if (v4l2object->has_alpha_component &&
2795 (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2796 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
2797 {
2798 switch (format)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002799 {
bo.xiao857b8682024-09-12 16:40:32 +08002800 case V4L2_PIX_FMT_RGB32:
2801 alt_s = gst_structure_copy (s);
2802 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
2803 break;
2804 case V4L2_PIX_FMT_BGR32:
2805 alt_s = gst_structure_copy (s);
2806 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
2807 break;
2808 default:
2809 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002810 }
bo.xiao857b8682024-09-12 16:40:32 +08002811 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002812
bo.xiao857b8682024-09-12 16:40:32 +08002813 gst_caps_append_structure(caps, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002814
bo.xiao857b8682024-09-12 16:40:32 +08002815 if (alt_s)
2816 gst_caps_append_structure(caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002817}
2818
2819static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08002820gst_aml_v4l2_object_probe_caps_for_format (GstAmlV4l2Object * v4l2object,
2821 guint32 pixelformat, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002822{
bo.xiao857b8682024-09-12 16:40:32 +08002823 GstCaps *ret = gst_caps_new_empty ();
2824 GstStructure *tmp;
2825 gint fd = v4l2object->video_fd;
2826 struct v4l2_frmsizeenum size;
2827 GList *results = NULL;
2828 guint32 w, h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002829
bo.xiao857b8682024-09-12 16:40:32 +08002830 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
2831 {
2832 gst_caps_append_structure (ret, gst_structure_copy (template));
2833 return ret;
2834 }
2835
2836 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
2837 size.index = 0;
2838 size.pixel_format = pixelformat;
2839
2840 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2841 "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2842 GST_FOURCC_ARGS (pixelformat));
2843
2844 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2845 goto enum_framesizes_failed;
2846
2847 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
2848 {
2849 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002850 {
bo.xiao857b8682024-09-12 16:40:32 +08002851 GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
2852 size.discrete.width, size.discrete.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002853
bo.xiao857b8682024-09-12 16:40:32 +08002854 w = MIN (size.discrete.width, G_MAXINT);
2855 h = MIN (size.discrete.height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002856
bo.xiao857b8682024-09-12 16:40:32 +08002857 if (w && h)
2858 {
2859 tmp =
2860 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2861 pixelformat, w, h, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002862
bo.xiao857b8682024-09-12 16:40:32 +08002863 if (tmp)
2864 results = g_list_prepend (results, tmp);
2865 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002866
bo.xiao857b8682024-09-12 16:40:32 +08002867 size.index++;
2868 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2869 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2870 "done iterating discrete frame sizes");
2871 }
2872 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
2873 {
2874 guint32 maxw, maxh, step_w, step_h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002875
bo.xiao857b8682024-09-12 16:40:32 +08002876 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have stepwise frame sizes:");
2877 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2878 size.stepwise.min_width);
2879 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2880 size.stepwise.min_height);
2881 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2882 size.stepwise.max_width);
2883 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2884 size.stepwise.max_height);
2885 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step width: %d",
2886 size.stepwise.step_width);
2887 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step height: %d",
2888 size.stepwise.step_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002889
fei.dengf21a6c92024-09-05 11:30:36 +08002890 if (pixelformat == V4L2_PIX_FMT_NV12 ||
2891 pixelformat == V4L2_PIX_FMT_NV21 ||
2892 pixelformat == V4L2_PIX_FMT_NV12M ||
2893 pixelformat == V4L2_PIX_FMT_NV21M) {
2894 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2895 "set %" GST_FOURCC_FORMAT " min width and height to 16",
2896 GST_FOURCC_ARGS(pixelformat));
2897 w = 16;
2898 h = 16;
2899 } else {
2900 w = MAX(size.stepwise.min_width, 1);
2901 h = MAX(size.stepwise.min_height, 1);
2902 }
bo.xiao857b8682024-09-12 16:40:32 +08002903 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2904 maxh = MIN (size.stepwise.max_height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002905
bo.xiao857b8682024-09-12 16:40:32 +08002906 /* in this position,updating resolution only to pass the negotiation
2907 * actually, the details about resolution refer to function:
2908 * gst_aml_v4l2_object_set_format_full for checking.
2909 */
2910 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "update maxw_maxh to MAX(maxw,maxh)_MAX(maxw,maxh)");
2911 maxh = MAX (maxw, maxh);
2912 maxw = maxh;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00002913
bo.xiao857b8682024-09-12 16:40:32 +08002914 step_w = MAX (size.stepwise.step_width, 1);
2915 step_h = MAX (size.stepwise.step_height, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002916
bo.xiao857b8682024-09-12 16:40:32 +08002917 /* FIXME: check for sanity and that min/max are multiples of the steps */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002918
bo.xiao857b8682024-09-12 16:40:32 +08002919 /* we only query details for the max width/height since it's likely the
2920 * most restricted if there are any resolution-dependent restrictions */
2921 tmp = gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2922 pixelformat, maxw, maxh, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002923
bo.xiao857b8682024-09-12 16:40:32 +08002924 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002925 {
bo.xiao857b8682024-09-12 16:40:32 +08002926 GValue step_range = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002927
bo.xiao857b8682024-09-12 16:40:32 +08002928 g_value_init (&step_range, GST_TYPE_INT_RANGE);
2929 gst_value_set_int_range_step (&step_range, w, maxw, step_w);
2930 gst_structure_set_value (tmp, "width", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002931
bo.xiao857b8682024-09-12 16:40:32 +08002932 gst_value_set_int_range_step (&step_range, h, maxh, step_h);
2933 gst_structure_take_value (tmp, "height", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002934
bo.xiao857b8682024-09-12 16:40:32 +08002935 /* no point using the results list here, since there's only one struct */
2936 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002937 }
bo.xiao857b8682024-09-12 16:40:32 +08002938 }
2939 else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
2940 {
2941 guint32 maxw, maxh;
2942
2943 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have continuous frame sizes:");
2944 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2945 size.stepwise.min_width);
2946 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2947 size.stepwise.min_height);
2948 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2949 size.stepwise.max_width);
2950 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2951 size.stepwise.max_height);
2952
2953 w = MAX (size.stepwise.min_width, 1);
2954 h = MAX (size.stepwise.min_height, 1);
2955 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2956 maxh = MIN (size.stepwise.max_height, G_MAXINT);
2957
2958 tmp =
2959 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
2960 w, h, template);
2961 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002962 {
bo.xiao857b8682024-09-12 16:40:32 +08002963 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
2964 (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
2965 NULL);
2966
2967 /* no point using the results list here, since there's only one struct */
2968 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002969 }
bo.xiao857b8682024-09-12 16:40:32 +08002970 }
2971 else
2972 {
2973 goto unknown_type;
2974 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002975
bo.xiao857b8682024-09-12 16:40:32 +08002976 /* we use an intermediary list to store and then sort the results of the
2977 * probing because we can't make any assumptions about the order in which
2978 * the driver will give us the sizes, but we want the final caps to contain
2979 * the results starting with the highest resolution and having the lowest
2980 * resolution last, since order in caps matters for things like fixation. */
2981 results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
2982 while (results != NULL)
2983 {
2984 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret,
2985 results->data);
2986 results = g_list_delete_link (results, results);
2987 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002988
bo.xiao857b8682024-09-12 16:40:32 +08002989 if (gst_caps_is_empty (ret))
2990 goto enum_framesizes_no_results;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002991
bo.xiao857b8682024-09-12 16:40:32 +08002992 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002993
bo.xiao857b8682024-09-12 16:40:32 +08002994 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002995enum_framesizes_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002996 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002997 /* I don't see how this is actually an error */
bo.xiao857b8682024-09-12 16:40:32 +08002998 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2999 "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
3000 " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003001 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003002 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003003enum_framesizes_no_results:
bo.xiao857b8682024-09-12 16:40:32 +08003004 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003005 /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
3006 * question doesn't actually support it yet */
bo.xiao857b8682024-09-12 16:40:32 +08003007 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3008 "No results for pixelformat %" GST_FOURCC_FORMAT
3009 " enumerating frame sizes, trying fallback",
3010 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003011 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003012 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003013unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08003014 {
3015 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3016 "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
3017 ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003018 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003019 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003020
3021default_frame_sizes:
bo.xiao857b8682024-09-12 16:40:32 +08003022 {
bo.xiao34e36202024-07-17 16:04:01 +08003023 gint min_w, max_w, min_h, max_h;
3024
3025#ifdef DELETE_FOR_LGE
3026 gint fix_num = 0, fix_denom = 0;
3027#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08003028
3029 /* This code is for Linux < 2.6.19 */
3030 min_w = min_h = 1;
3031 max_w = max_h = GST_AML_V4L2_MAX_SIZE;
bo.xiao857b8682024-09-12 16:40:32 +08003032 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
3033 &min_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003034 {
bo.xiao857b8682024-09-12 16:40:32 +08003035 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3036 "Could not probe minimum capture size for pixelformat %"
3037 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003038 }
bo.xiao857b8682024-09-12 16:40:32 +08003039 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
3040 &max_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003041 {
bo.xiao857b8682024-09-12 16:40:32 +08003042 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3043 "Could not probe maximum capture size for pixelformat %"
3044 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003045 }
3046
bo.xiao857b8682024-09-12 16:40:32 +08003047
3048 tmp = gst_structure_copy (template);
hanghang.luo3128f102022-08-18 10:36:19 +08003049#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08003050 if (fix_num)
3051 {
bo.xiao857b8682024-09-12 16:40:32 +08003052 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
3053 fix_denom, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003054 }
hanghang.luo3128f102022-08-18 10:36:19 +08003055 else
3056#endif
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003057 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
3058 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003059 {
bo.xiao857b8682024-09-12 16:40:32 +08003060 /* if norm can't be used, copy the template framerate */
3061 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
3062 G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003063 }
3064
3065 if (min_w == max_w)
bo.xiao857b8682024-09-12 16:40:32 +08003066 gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003067 else
bo.xiao857b8682024-09-12 16:40:32 +08003068 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003069
3070 if (min_h == max_h)
bo.xiao857b8682024-09-12 16:40:32 +08003071 gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003072 else
bo.xiao857b8682024-09-12 16:40:32 +08003073 gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003074
bo.xiao857b8682024-09-12 16:40:32 +08003075 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003076
3077 if (!v4l2object->skip_try_fmt_probes)
3078 {
bo.xiao857b8682024-09-12 16:40:32 +08003079 /* We could consider setting interlace mode from min and max. */
3080 gst_aml_v4l2_object_add_interlace_mode(v4l2object, tmp, max_w, max_h,
3081 pixelformat);
3082 /* We could consider to check colorspace for min too, in case it depends on
3083 * the size. But in this case, min and max could not be enough */
3084 gst_aml_v4l2_object_add_colorspace(v4l2object, tmp, max_w, max_h,
3085 pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003086 }
3087
bo.xiao857b8682024-09-12 16:40:32 +08003088 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003089 return ret;
bo.xiao857b8682024-09-12 16:40:32 +08003090 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003091}
3092
3093static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003094gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
3095 guint32 pixelformat, gint * width, gint * height)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003096{
bo.xiao857b8682024-09-12 16:40:32 +08003097 struct v4l2_format fmt;
3098 gboolean ret = FALSE;
3099 GstVideoInterlaceMode interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003100
bo.xiao857b8682024-09-12 16:40:32 +08003101 g_return_val_if_fail (width != NULL, FALSE);
3102 g_return_val_if_fail (height != NULL, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003103
bo.xiao857b8682024-09-12 16:40:32 +08003104 GST_LOG_OBJECT (v4l2object->dbg_obj,
3105 "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
3106 *width, *height, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003107
bo.xiao857b8682024-09-12 16:40:32 +08003108 memset (&fmt, 0, sizeof (struct v4l2_format));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003109
bo.xiao857b8682024-09-12 16:40:32 +08003110 /* get size delimiters */
3111 memset (&fmt, 0, sizeof (fmt));
3112 fmt.type = v4l2object->type;
3113 fmt.fmt.pix.width = *width;
3114 fmt.fmt.pix.height = *height;
3115 fmt.fmt.pix.pixelformat = pixelformat;
3116 fmt.fmt.pix.field = V4L2_FIELD_ANY;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003117
bo.xiao857b8682024-09-12 16:40:32 +08003118 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
3119 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003120
bo.xiao857b8682024-09-12 16:40:32 +08003121 GST_LOG_OBJECT (v4l2object->dbg_obj,
3122 "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003123
bo.xiao857b8682024-09-12 16:40:32 +08003124 *width = fmt.fmt.pix.width;
3125 *height = fmt.fmt.pix.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003126
bo.xiao857b8682024-09-12 16:40:32 +08003127 if (!gst_aml_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode))
3128 {
3129 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3130 "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
3131 GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
3132 goto error;
3133 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003134
bo.xiao857b8682024-09-12 16:40:32 +08003135 ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003136
3137error:
bo.xiao857b8682024-09-12 16:40:32 +08003138 if (!ret)
3139 {
3140 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3141 "Unable to try format: %s", g_strerror (errno));
3142 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003143
bo.xiao857b8682024-09-12 16:40:32 +08003144 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003145}
3146
3147static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003148gst_aml_v4l2_object_is_dmabuf_supported (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003149{
bo.xiao857b8682024-09-12 16:40:32 +08003150 gboolean ret = TRUE;
3151 struct v4l2_exportbuffer expbuf = {
3152 .type = v4l2object->type,
3153 .index = -1,
3154 .plane = -1,
3155 .flags = O_CLOEXEC | O_RDWR,
3156 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003157
bo.xiao857b8682024-09-12 16:40:32 +08003158 if (v4l2object->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
3159 {
3160 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3161 "libv4l2 converter detected, disabling DMABuf");
3162 ret = FALSE;
3163 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003164
bo.xiao857b8682024-09-12 16:40:32 +08003165 /* Expected to fail, but ENOTTY tells us that it is not implemented. */
3166 v4l2object->ioctl (v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
3167 if (errno == ENOTTY)
3168 ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003169
bo.xiao857b8682024-09-12 16:40:32 +08003170 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003171}
3172
3173static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003174gst_aml_v4l2_object_setup_pool (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003175{
bo.xiao857b8682024-09-12 16:40:32 +08003176 GstAmlV4l2IOMode mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003177
bo.xiao857b8682024-09-12 16:40:32 +08003178 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "initializing the %s system",
3179 V4L2_TYPE_IS_OUTPUT (v4l2object->type) ? "output" : "capture");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003180
bo.xiao857b8682024-09-12 16:40:32 +08003181 GST_AML_V4L2_CHECK_OPEN (v4l2object);
3182 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003183
bo.xiao857b8682024-09-12 16:40:32 +08003184 /* find transport */
3185 mode = v4l2object->req_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003186
bo.xiao857b8682024-09-12 16:40:32 +08003187 if (v4l2object->device_caps & V4L2_CAP_READWRITE)
3188 {
3189 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3190 mode = GST_V4L2_IO_RW;
3191 }
3192 else if (v4l2object->req_mode == GST_V4L2_IO_RW)
3193 goto method_not_supported;
3194
3195 if (v4l2object->device_caps & V4L2_CAP_STREAMING)
3196 {
3197 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003198 {
bo.xiao857b8682024-09-12 16:40:32 +08003199 if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
3200 gst_aml_v4l2_object_is_dmabuf_supported (v4l2object))
3201 {
3202 mode = GST_V4L2_IO_DMABUF;
3203 }
3204 else
3205 {
3206 mode = GST_V4L2_IO_MMAP;
3207 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003208 }
bo.xiao857b8682024-09-12 16:40:32 +08003209 }
3210 else if (v4l2object->req_mode == GST_V4L2_IO_MMAP ||
3211 v4l2object->req_mode == GST_V4L2_IO_DMABUF)
3212 goto method_not_supported;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003213
bo.xiao857b8682024-09-12 16:40:32 +08003214 /* if still no transport selected, error out */
3215 if (mode == GST_V4L2_IO_AUTO)
3216 goto no_supported_capture_method;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003217
bo.xiao857b8682024-09-12 16:40:32 +08003218 GST_INFO_OBJECT (v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
3219 v4l2object->mode = mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003220
bo.xiao857b8682024-09-12 16:40:32 +08003221 /* If min_buffers is not set, the driver either does not support the control or
3222 it has not been asked yet via propose_allocation/decide_allocation. */
3223 if (!v4l2object->min_buffers)
3224 gst_aml_v4l2_get_driver_min_buffers (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003225
bo.xiao857b8682024-09-12 16:40:32 +08003226 /* Map the buffers */
3227 GST_LOG_OBJECT (v4l2object->dbg_obj, "initiating buffer pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003228
3229 if (!(v4l2object->pool = gst_aml_v4l2_buffer_pool_new(v4l2object, caps)))
bo.xiao857b8682024-09-12 16:40:32 +08003230 goto buffer_pool_new_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003231
bo.xiao857b8682024-09-12 16:40:32 +08003232 GST_AML_V4L2_SET_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003233
bo.xiao857b8682024-09-12 16:40:32 +08003234 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003235
bo.xiao857b8682024-09-12 16:40:32 +08003236 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003237buffer_pool_new_failed:
bo.xiao857b8682024-09-12 16:40:32 +08003238 {
3239 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3240 (_("Could not map buffers from device '%s'"),
3241 v4l2object->videodev),
3242 ("Failed to create buffer pool: %s", g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003243 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003244 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003245method_not_supported:
bo.xiao857b8682024-09-12 16:40:32 +08003246 {
3247 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3248 (_("The driver of device '%s' does not support the IO method %d"),
3249 v4l2object->videodev, mode), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003250 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003251 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003252no_supported_capture_method:
bo.xiao857b8682024-09-12 16:40:32 +08003253 {
3254 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3255 (_("The driver of device '%s' does not support any known IO "
3256 "method."), v4l2object->videodev), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003257 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003258 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003259}
3260
3261static void
bo.xiao857b8682024-09-12 16:40:32 +08003262gst_aml_v4l2_object_set_stride (GstVideoInfo * info, GstVideoAlignment * align,
3263 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003264{
bo.xiao857b8682024-09-12 16:40:32 +08003265 const GstVideoFormatInfo *finfo = info->finfo;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003266
bo.xiao857b8682024-09-12 16:40:32 +08003267 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3268 {
3269 gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003270
bo.xiao857b8682024-09-12 16:40:32 +08003271 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
3272 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3273 tile_height = 1 << hs;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003274
bo.xiao857b8682024-09-12 16:40:32 +08003275 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
3276 info->height + align->padding_top + align->padding_bottom);
3277 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003278
bo.xiao857b8682024-09-12 16:40:32 +08003279 x_tiles = stride >> ws;
3280 y_tiles = padded_height >> hs;
3281 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
3282 }
3283 else
3284 {
3285 info->stride[plane] = stride;
3286 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003287}
3288
3289static void
bo.xiao857b8682024-09-12 16:40:32 +08003290gst_aml_v4l2_object_extrapolate_info (GstAmlV4l2Object * v4l2object,
3291 GstVideoInfo * info, GstVideoAlignment * align, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003292{
bo.xiao857b8682024-09-12 16:40:32 +08003293 const GstVideoFormatInfo *finfo = info->finfo;
3294 gint i, estride, padded_height;
3295 gsize offs = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003296
bo.xiao857b8682024-09-12 16:40:32 +08003297 g_return_if_fail (v4l2object->n_v4l2_planes == 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003298
bo.xiao857b8682024-09-12 16:40:32 +08003299 padded_height = info->height + align->padding_top + align->padding_bottom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003300
bo.xiao857b8682024-09-12 16:40:32 +08003301 for (i = 0; i < finfo->n_planes; i++)
3302 {
3303 estride = gst_aml_v4l2_object_extrapolate_stride (finfo, i, stride);
3304
3305 gst_aml_v4l2_object_set_stride (info, align, i, estride);
3306
3307 info->offset[i] = offs;
3308 offs += estride *
3309 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, padded_height);
3310
3311 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3312 "Extrapolated for plane %d with base stride %d: "
3313 "stride %d, offset %" G_GSIZE_FORMAT, i, stride, info->stride[i],
3314 info->offset[i]);
3315 }
3316
3317 /* Update the image size according the amount of data we are going to
3318 * read/write. This workaround bugs in driver where the sizeimage provided
3319 * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
3320 * bytesused (buffer size). */
3321 if (offs < info->size)
3322 info->size = offs;
3323}
3324
3325static void
3326gst_aml_v4l2_object_save_format (GstAmlV4l2Object * v4l2object,
3327 struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
3328 GstVideoInfo * info, GstVideoAlignment * align)
3329{
3330 const GstVideoFormatInfo *finfo = info->finfo;
3331 gboolean standard_stride = TRUE;
3332 gint stride, pstride, padded_width, padded_height, i;
3333
3334 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED)
3335 {
3336 v4l2object->n_v4l2_planes = 1;
3337 info->size = format->fmt.pix.sizeimage;
3338 goto store_info;
3339 }
3340
3341 /* adjust right padding */
3342 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3343 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3344 else
3345 stride = format->fmt.pix.bytesperline;
3346
3347 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (finfo, 0);
3348 if (pstride)
3349 {
3350 padded_width = stride / pstride;
3351 }
3352 else
3353 {
3354 /* pstride can be 0 for complex formats */
3355 GST_WARNING_OBJECT (v4l2object->element,
3356 "format %s has a pstride of 0, cannot compute padded with",
3357 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
3358 padded_width = stride;
3359 }
3360
3361 if (padded_width < format->fmt.pix.width)
3362 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3363 "Driver bug detected, stride (%d) is too small for the width (%d)",
3364 padded_width, format->fmt.pix.width);
3365
3366 align->padding_right = padded_width - info->width - align->padding_left;
3367
3368 /* adjust bottom padding */
3369 padded_height = format->fmt.pix.height;
3370
3371 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3372 {
3373 guint hs, tile_height;
3374
3375 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3376 tile_height = 1 << hs;
3377
3378 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
3379 }
3380
3381 align->padding_bottom = padded_height - info->height - align->padding_top;
3382
3383 /* setup the strides and offset */
3384 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3385 {
3386 struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
3387
3388 /* figure out the frame layout */
3389 v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes);
3390 info->size = 0;
3391 for (i = 0; i < v4l2object->n_v4l2_planes; i++)
3392 {
3393 stride = pix_mp->plane_fmt[i].bytesperline;
3394
3395 if (info->stride[i] != stride)
3396 standard_stride = FALSE;
3397
3398 gst_aml_v4l2_object_set_stride (info, align, i, stride);
3399 info->offset[i] = info->size;
3400 info->size += pix_mp->plane_fmt[i].sizeimage;
3401 }
3402
3403 /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
3404 if (v4l2object->n_v4l2_planes < finfo->n_planes)
3405 {
3406 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3407 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3408 }
3409 }
3410 else
3411 {
3412 /* only one plane in non-MPLANE mode */
3413 v4l2object->n_v4l2_planes = 1;
3414 info->size = format->fmt.pix.sizeimage;
3415 stride = format->fmt.pix.bytesperline;
3416
3417 if (info->stride[0] != stride)
3418 standard_stride = FALSE;
3419
3420 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3421 }
3422
3423 /* adjust the offset to take into account left and top */
3424 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3425 {
3426 if ((align->padding_left + align->padding_top) > 0)
3427 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3428 "Left and top padding is not permitted for tiled formats");
3429 }
3430 else
3431 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003432 for (i = 0; i < finfo->n_planes; i++)
3433 {
bo.xiao857b8682024-09-12 16:40:32 +08003434 gint vedge, hedge;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003435
bo.xiao857b8682024-09-12 16:40:32 +08003436 /* FIXME we assume plane as component as this is true for all supported
3437 * format we support. */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003438
bo.xiao857b8682024-09-12 16:40:32 +08003439 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, align->padding_left);
3440 vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, align->padding_top);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003441
bo.xiao857b8682024-09-12 16:40:32 +08003442 info->offset[i] += (vedge * info->stride[i]) +
3443 (hedge * GST_VIDEO_INFO_COMP_PSTRIDE (info, i));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003444 }
bo.xiao857b8682024-09-12 16:40:32 +08003445 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003446
3447store_info:
bo.xiao857b8682024-09-12 16:40:32 +08003448 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
3449 info->size);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003450
bo.xiao857b8682024-09-12 16:40:32 +08003451 /* to avoid copies we need video meta if there is padding */
3452 v4l2object->need_video_meta =
3453 ((align->padding_top + align->padding_left + align->padding_right +
xuesong.jiangae1548e2022-05-06 16:38:46 +08003454 align->padding_bottom) != 0);
3455
bo.xiao857b8682024-09-12 16:40:32 +08003456 /* ... or if stride is non "standard" */
3457 if (!standard_stride)
3458 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003459
bo.xiao857b8682024-09-12 16:40:32 +08003460 /* ... or also video meta if we use multiple, non-contiguous, planes */
3461 if (v4l2object->n_v4l2_planes > 1)
3462 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003463
bo.xiao857b8682024-09-12 16:40:32 +08003464 v4l2object->info = *info;
3465 v4l2object->align = *align;
3466 v4l2object->format = *format;
3467 v4l2object->fmtdesc = fmtdesc;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003468
bo.xiao857b8682024-09-12 16:40:32 +08003469 /* if we have a framerate pre-calculate duration */
3470 if (info->fps_n > 0 && info->fps_d > 0)
3471 {
3472 v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
3473 info->fps_n);
3474 }
3475 else
3476 {
3477 v4l2object->duration = GST_CLOCK_TIME_NONE;
3478 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003479}
3480
bo.xiao857b8682024-09-12 16:40:32 +08003481gint
3482gst_aml_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
3483 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003484{
bo.xiao857b8682024-09-12 16:40:32 +08003485 gint estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003486
bo.xiao857b8682024-09-12 16:40:32 +08003487 switch (finfo->format)
3488 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003489 case GST_VIDEO_FORMAT_NV12:
3490 case GST_VIDEO_FORMAT_NV12_64Z32:
3491 case GST_VIDEO_FORMAT_NV21:
3492 case GST_VIDEO_FORMAT_NV16:
3493 case GST_VIDEO_FORMAT_NV61:
3494 case GST_VIDEO_FORMAT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08003495 estride = (plane == 0 ? 1 : 2) *
3496 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3497 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003498 default:
bo.xiao857b8682024-09-12 16:40:32 +08003499 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3500 break;
3501 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003502
bo.xiao857b8682024-09-12 16:40:32 +08003503 return estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003504}
3505
3506static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003507gst_aml_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
xuesong.jiangae1548e2022-05-06 16:38:46 +08003508 const gchar *color)
3509{
bo.xiao857b8682024-09-12 16:40:32 +08003510 GstVideoColorimetry ci;
3511 static const GstVideoColorimetry ci_likely_jpeg = {
3512 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3513 GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN
3514 };
3515 static const GstVideoColorimetry ci_jpeg = {
3516 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3517 GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709
3518 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003519
bo.xiao857b8682024-09-12 16:40:32 +08003520 if (!gst_video_colorimetry_from_string(&ci, color))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003521 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003522
3523 if (gst_video_colorimetry_is_equal(&ci, cinfo))
3524 return TRUE;
3525
3526 /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */
3527 if (gst_video_colorimetry_is_equal(&ci, &ci_likely_jpeg) && gst_video_colorimetry_is_equal(cinfo, &ci_jpeg))
3528 return TRUE;
3529
3530 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003531}
3532
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003533static gboolean needSpecConfigForFg(GstAmlV4l2Object *v4l2object)
3534{
bo.xiao857b8682024-09-12 16:40:32 +08003535 gboolean result= FALSE;
3536 int fd = -1;
3537 char valstr[64];
3538 const char* path= "/sys/class/video/film_grain_support";
3539 uint32_t val= 0;
3540 struct v4l2_control ctl;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003541
bo.xiao857b8682024-09-12 16:40:32 +08003542 GST_LOG("configForFilmGrain: enter");
3543 fd = open(path, O_RDONLY|O_CLOEXEC);
3544 if ( fd < 0 )
3545 {
3546 GST_DEBUG("unable to open file (%s)", path);
3547 goto exit;
3548 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003549
bo.xiao857b8682024-09-12 16:40:32 +08003550 memset(valstr, 0, sizeof(valstr));
3551 if (read(fd, valstr, sizeof(valstr) - 1) == -1 )
3552 {
3553 GST_DEBUG("unable to read fg flag");
3554 goto exit;
3555 }
bo.xiao34e36202024-07-17 16:04:01 +08003556
bo.xiao857b8682024-09-12 16:40:32 +08003557 valstr[strlen(valstr)] = '\0';
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003558
bo.xiao857b8682024-09-12 16:40:32 +08003559 if ( sscanf(valstr, "%u", &val) < 1)
3560 {
3561 GST_DEBUG("unable to get flag from: (%s)", valstr);
3562 goto exit;
3563 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003564
bo.xiao857b8682024-09-12 16:40:32 +08003565 GST_LOG("got film_grain_support:%d from node", val);
3566 if (val != 0)
3567 {
3568 goto exit;
3569 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003570
bo.xiao857b8682024-09-12 16:40:32 +08003571 memset( &ctl, 0, sizeof(ctl));
bo.xiao4ef6d272024-10-15 16:18:25 +08003572 ctl.id = AML_V4L2_GET_FILMGRAIN_INFO;
3573 v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CTRL, &ctl);
bo.xiao857b8682024-09-12 16:40:32 +08003574 GST_LOG("got VIDIOC_G_CTRL value: %d", ctl.value);
3575 if (ctl.value == 0)
3576 {
3577 goto exit;
3578 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003579
bo.xiao857b8682024-09-12 16:40:32 +08003580 result= TRUE;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003581
3582exit:
bo.xiao857b8682024-09-12 16:40:32 +08003583 if ( fd >= 0 )
3584 {
3585 close(fd);
3586 }
3587 GST_LOG("configForFilmGrain: exit: result %d", result);
3588 return result;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003589}
hanghang.luobfc63f82024-07-05 11:04:56 +08003590
3591static gboolean
bo.xiao7659cda2024-07-18 16:16:50 +08003592get_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm)
hanghang.luobfc63f82024-07-05 11:04:56 +08003593{
bo.xiao857b8682024-09-12 16:40:32 +08003594 struct v4l2_ext_control control;
3595 struct v4l2_ext_controls ctrls;
3596 gboolean use_ext_config = FALSE;
3597 int major = 0,minor = 0;
3598 struct utsname info;
3599 struct aml_dec_params *pdecParm = (struct aml_dec_params *)streamparm->parm.raw_data;
bo.xiao7659cda2024-07-18 16:16:50 +08003600
bo.xiao857b8682024-09-12 16:40:32 +08003601 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3602 {
3603 GST_DEBUG("get linux version failed");
3604 return FALSE;
3605 }
3606 GST_DEBUG("linux major version %d %d", major,minor);
3607 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003608
bo.xiao857b8682024-09-12 16:40:32 +08003609 if (use_ext_config)
3610 {
3611 memset(&ctrls, 0, sizeof(ctrls));
3612 memset(&control, 0, sizeof(control));
3613 control.id = AML_V4L2_DEC_PARMS_CONFIG;
3614 control.ptr = pdecParm;
3615 control.size = sizeof(struct aml_dec_params);
3616 ctrls.count = 1;
3617 ctrls.controls = &control;
3618 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls ) <0)
3619 {
3620 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3621 return FALSE;
3622 }
3623 GST_DEBUG("dw: %d, flag: %d, status: %d, margin: %d",pdecParm->cfg.double_write_mode,
3624 pdecParm->cfg.metadata_config_flag, pdecParm->parms_status, pdecParm->cfg.ref_buf_margin);
3625 }
3626 else
3627 {
3628 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, streamparm) < 0)
3629 {
3630 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3631 return FALSE;
3632 }
3633 }
3634 return TRUE;
hanghang.luobfc63f82024-07-05 11:04:56 +08003635}
3636
bo.xiao34e36202024-07-17 16:04:01 +08003637static int gst_aml_config_dw(GstAmlV4l2Object *v4l2object, guint32 pixFormat, guint width, guint height, gboolean interlace)
3638{
bo.xiao857b8682024-09-12 16:40:32 +08003639 const char *env_dw;
3640 int double_write = VDEC_DW_NO_AFBC;
bo.xiao34e36202024-07-17 16:04:01 +08003641
bo.xiao857b8682024-09-12 16:40:32 +08003642 GST_DEBUG("pixFormat: %d", pixFormat);
3643 switch (pixFormat)
3644 {
3645 case V4L2_PIX_FMT_MPEG:
3646 case V4L2_PIX_FMT_MPEG1:
3647 case V4L2_PIX_FMT_MPEG2:
3648 case V4L2_PIX_FMT_MPEG4:
3649 double_write = VDEC_DW_NO_AFBC;
le.han3b118242024-09-29 06:32:02 +00003650 if (v4l2object->low_memory_mode && !interlace)
3651 double_write = VDEC_DW_AFBC_ONLY;
bo.xiao857b8682024-09-12 16:40:32 +08003652 break;
3653 case V4L2_PIX_FMT_H264:
3654 {
3655 if (width > 1920 && height > 1080 && !interlace)
3656 double_write = VDEC_DW_AFBC_1_4_DW;
3657 else
3658 double_write = VDEC_DW_NO_AFBC;
le.han3b118242024-09-29 06:32:02 +00003659 if (v4l2object->low_memory_mode && !interlace)
3660 double_write = VDEC_DW_AFBC_ONLY;
bo.xiao857b8682024-09-12 16:40:32 +08003661 break;
3662 }
3663 case V4L2_PIX_FMT_HEVC:
3664 double_write = VDEC_DW_AFBC_AUTO_1_4;
3665 if (interlace)
3666 double_write = VDEC_DW_AFBC_1_1_DW;
le.han3b118242024-09-29 06:32:02 +00003667 if (v4l2object->low_memory_mode && !interlace)
bo.xiao857b8682024-09-12 16:40:32 +08003668 double_write = VDEC_DW_AFBC_ONLY;
3669 break;
3670 case V4L2_PIX_FMT_VP9:
3671 case V4L2_PIX_FMT_AV1:
le.han3b118242024-09-29 06:32:02 +00003672 double_write = VDEC_DW_AFBC_AUTO_1_4;
3673 if (v4l2object->low_memory_mode && !interlace)
3674 double_write = VDEC_DW_AFBC_ONLY;
bo.xiao857b8682024-09-12 16:40:32 +08003675 break;
3676 default:
3677 GST_WARNING("unknown video format %d", pixFormat);
3678 break;
3679 }
bo.xiao34e36202024-07-17 16:04:01 +08003680
bo.xiao857b8682024-09-12 16:40:32 +08003681 env_dw = getenv("V4L2_SET_AMLOGIC_DW_MODE");
3682 if (env_dw)
3683 double_write = atoi(env_dw);
bo.xiao34e36202024-07-17 16:04:01 +08003684
bo.xiao857b8682024-09-12 16:40:32 +08003685 return double_write;
bo.xiao34e36202024-07-17 16:04:01 +08003686}
hanghang.luobfc63f82024-07-05 11:04:56 +08003687
xuesong.jiangae1548e2022-05-06 16:38:46 +08003688static void
fei.deng7c3d67f2022-11-09 11:06:05 +08003689set_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm, GstCaps *caps, guint32 pixFormat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003690{
3691 struct aml_dec_params *decParm = (struct aml_dec_params *)streamparm->parm.raw_data;
3692 const char *env;
zengliang.lic9f869d2023-02-15 08:32:32 +00003693 struct v4l2_ext_control control;
3694 struct v4l2_ext_controls ctrls;
3695 gboolean use_ext_config = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003696 int major = 0, minor = 0;
zengliang.lic9f869d2023-02-15 08:32:32 +00003697 struct utsname info;
bo.xiao34e36202024-07-17 16:04:01 +08003698 gboolean is_interlaced = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003699 guint width = 0, height = 0;
3700
3701 streamparm->type = v4l2object->type;
bo.xiao34e36202024-07-17 16:04:01 +08003702
fei.deng355dfb52024-09-14 15:04:31 +08003703 env = getenv("V4L2DEC_LOW_MEM_MODE");
3704 if (env) {
3705 GST_DEBUG("%s",env);
3706 v4l2object->low_memory_mode = atoi(env) > 0? TRUE: FALSE;
3707 }
hanghang.luo7f403102024-07-04 10:33:01 +08003708 GST_DEBUG("low mem: %d",v4l2object->low_memory_mode);
bo.xiao34e36202024-07-17 16:04:01 +08003709
bo.xiao7659cda2024-07-18 16:16:50 +08003710 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3711 {
3712 GST_DEBUG("get linux version failed");
3713 }
3714 GST_DEBUG("linux major version %d %d", major,minor);
3715 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
3716
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003717 GstStructure *structure = gst_caps_get_structure(caps, 0);
3718 if (structure == NULL)
3719 {
3720 return;
3721 }
3722 gst_structure_get_uint(structure,"width",&width);
3723 gst_structure_get_uint(structure,"height",&height);
3724 if (gst_structure_has_field(structure, "interlace-mode"))
3725 {
bo.xiao34e36202024-07-17 16:04:01 +08003726 const gchar *mode = gst_structure_get_string(structure,"interlace-mode");
3727 is_interlaced = !strcmp(mode, "progressive") ? FALSE:TRUE;
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003728 GST_DEBUG("is_interlaced: %d",is_interlaced);
3729 }
hanghang.luo7f403102024-07-04 10:33:01 +08003730
xuesong.jiangae1548e2022-05-06 16:38:46 +08003731 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3732 {
fei.dengccc89632022-07-15 19:10:17 +08003733 /*set bit12 value to 1,
3734 *v4l2 output 0 pts of second interlace field frame */
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003735 decParm->cfg.metadata_config_flag |= (1 << 12);
fei.deng7c3d67f2022-11-09 11:06:05 +08003736 decParm->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003737
3738 decParm->cfg.metadata_config_flag |= 1 << 13;
3739
3740 /*set bit18 value to 1
3741 *release vpp in advance */
3742 decParm->cfg.metadata_config_flag |= (1 << 18);
3743 decParm->cfg.low_latency_mode = v4l2object->low_latency_mode;
3744
zengliang.li8f538aa2024-06-25 17:31:20 +08003745 if (v4l2object->enable_nr)
3746 {
3747 GST_DEBUG("enable nr in di");
3748 decParm->cfg.metadata_config_flag |= (1 << 14);
3749 decParm->cfg.metadata_config_flag |= (1 << 15);
3750 }
3751
bo.xiao34e36202024-07-17 16:04:01 +08003752 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, pixFormat, width, height, is_interlaced);
hanghang.luo75664712024-07-01 19:28:10 +08003753 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg dw mode to %d", decParm->cfg.double_write_mode);
bo.xiao7659cda2024-07-18 16:16:50 +08003754 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo75664712024-07-01 19:28:10 +08003755
fei.deng17693b62024-08-28 20:13:17 +08003756 if (v4l2object->low_memory_mode) {
3757 decParm->cfg.ref_buf_margin = GST_AML_V4L2_LOW_MEMORY_CAP_BUF_MARGIN;
3758 } else {
3759 decParm->cfg.ref_buf_margin = GST_AML_V4L2_DEFAULT_CAP_BUF_MARGIN;
3760 }
3761
le.hancd3f2842024-06-26 09:37:50 +00003762 env = getenv("V4L2_SET_AMLOGIC_MARGIN_NUM");
3763 if (env)
3764 {
3765 decParm->cfg.ref_buf_margin = atoi(env);
bo.xiao7659cda2024-07-18 16:16:50 +08003766 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg margin to %d", decParm->cfg.ref_buf_margin);
le.hancd3f2842024-06-26 09:37:50 +00003767 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003768
bo.xiaof42b0082024-08-22 14:08:53 +08003769 // d v
3770 gboolean bl_present_flag, el_present_flag;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003771 int dvBaseLayerPresent = -1;
3772 int dvEnhancementLayerPresent = -1;
3773 /* have base and enhancement layers both, that means its dual layer,
bo.xiaof42b0082024-08-22 14:08:53 +08003774 d v two layer flag will be true */
3775 if (gst_structure_get_boolean( structure, "bl_present_flag", &bl_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003776 {
bo.xiaof42b0082024-08-22 14:08:53 +08003777 dvBaseLayerPresent= bl_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003778 }
bo.xiaof42b0082024-08-22 14:08:53 +08003779 if (gst_structure_get_boolean( structure, "el_present_flag", &el_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003780 {
bo.xiaof42b0082024-08-22 14:08:53 +08003781 dvEnhancementLayerPresent= el_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003782 }
3783
3784 /* have base and enhancement layers both, that means its dual layer, dv two layer flag will be true */
3785 if ( (dvBaseLayerPresent == 1) && (dvEnhancementLayerPresent == 1) )
3786 {
3787 decParm->cfg.metadata_config_flag |= (1 << 0);
3788 }
3789 else
3790 {
3791 decParm->cfg.metadata_config_flag |= (0 << 0);
3792 }
3793
3794 /* have one of then, it's standard dv stream, Non-standard dv flag will be false */
3795 if ( (dvBaseLayerPresent == 0) && (dvEnhancementLayerPresent == 0) )
3796 {
3797 decParm->cfg.metadata_config_flag |= (1 << 1);
3798 }
3799 else
3800 {
3801 decParm->cfg.metadata_config_flag |= (0 << 1);
3802 }
3803
3804 // HDR
xuesong.jiange1a19662022-06-21 20:30:22 +08003805 if ( gst_structure_has_field(structure, "colorimetry") )
3806 {
3807 const char *colorimetry= gst_structure_get_string(structure,"colorimetry");
3808 GstVideoColorimetry vci = {0};
3809 if ( colorimetry && gst_video_colorimetry_from_string( &vci, colorimetry ))
3810 {
3811 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO;
3812 decParm->hdr.signal_type= (1<<29); /* present flag */
3813 /*set default value, this is to keep up with driver hdr info synchronization*/
3814 decParm->hdr.signal_type |= (5<<26) | (1<<24);
3815
3816 gint hdrColorimetry[4] = {0};
3817 hdrColorimetry[0]= (int)vci.range;
3818 hdrColorimetry[1]= (int)vci.matrix;
3819 hdrColorimetry[2]= (int)vci.transfer;
3820 hdrColorimetry[3]= (int)vci.primaries;
3821 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "colorimetry: [%d,%d,%d,%d]",
3822 hdrColorimetry[0],
3823 hdrColorimetry[1],
3824 hdrColorimetry[2],
3825 hdrColorimetry[3] );
3826 /* range */
3827 switch ( hdrColorimetry[0] )
3828 {
le.han8d28eb82024-06-05 08:11:12 +00003829 case GST_VIDEO_COLOR_RANGE_0_255:
3830 case GST_VIDEO_COLOR_RANGE_16_235:
xuesong.jiange1a19662022-06-21 20:30:22 +08003831 decParm->hdr.signal_type |= ((hdrColorimetry[0] % 2)<<25);
3832 break;
3833 default:
3834 break;
3835 }
3836 /* matrix coefficient */
3837 switch ( hdrColorimetry[1] )
3838 {
le.han8d28eb82024-06-05 08:11:12 +00003839 case GST_VIDEO_COLOR_MATRIX_RGB: /* RGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003840 decParm->hdr.signal_type |= 0;
3841 break;
le.han8d28eb82024-06-05 08:11:12 +00003842 case GST_VIDEO_COLOR_MATRIX_FCC: /* FCC */
xuesong.jiange1a19662022-06-21 20:30:22 +08003843 decParm->hdr.signal_type |= 4;
3844 break;
le.han8d28eb82024-06-05 08:11:12 +00003845 case GST_VIDEO_COLOR_MATRIX_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003846 decParm->hdr.signal_type |= 1;
3847 break;
le.han8d28eb82024-06-05 08:11:12 +00003848 case GST_VIDEO_COLOR_MATRIX_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003849 decParm->hdr.signal_type |= 3;
3850 break;
le.han8d28eb82024-06-05 08:11:12 +00003851 case GST_VIDEO_COLOR_MATRIX_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003852 decParm->hdr.signal_type |= 7;
3853 break;
le.han8d28eb82024-06-05 08:11:12 +00003854 case GST_VIDEO_COLOR_MATRIX_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003855 decParm->hdr.signal_type |= 9;
3856 break;
3857 default: /* unknown */
3858 decParm->hdr.signal_type |= 2;
3859 break;
3860 }
3861 /* transfer function */
3862 switch ( hdrColorimetry[2] )
3863 {
le.han8d28eb82024-06-05 08:11:12 +00003864 case GST_VIDEO_TRANSFER_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003865 decParm->hdr.signal_type |= (1<<8);
3866 break;
le.han8d28eb82024-06-05 08:11:12 +00003867 case GST_VIDEO_TRANSFER_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003868 decParm->hdr.signal_type |= (7<<8);
3869 break;
le.han8d28eb82024-06-05 08:11:12 +00003870 case GST_VIDEO_TRANSFER_LOG100: /* LOG100 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003871 decParm->hdr.signal_type |= (9<<8);
3872 break;
le.han8d28eb82024-06-05 08:11:12 +00003873 case GST_VIDEO_TRANSFER_LOG316: /* LOG316 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003874 decParm->hdr.signal_type |= (10<<8);
3875 break;
le.han8d28eb82024-06-05 08:11:12 +00003876 case GST_VIDEO_TRANSFER_BT2020_12: /* BT2020_12 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003877 decParm->hdr.signal_type |= (15<<8);
3878 break;
le.han8d28eb82024-06-05 08:11:12 +00003879 case GST_VIDEO_TRANSFER_BT2020_10: /* BT2020_10 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003880 decParm->hdr.signal_type |= (14<<8);
3881 break;
le.han8d28eb82024-06-05 08:11:12 +00003882 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
3883 case GST_VIDEO_TRANSFER_SMPTE2084: /* SMPTE2084 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003884 decParm->hdr.signal_type |= (16<<8);
3885 break;
le.han8d28eb82024-06-05 08:11:12 +00003886 #else
3887 case GST_VIDEO_TRANSFER_SMPTE_ST_2084: /* SMPTE2084 */
3888 decParm->hdr.signal_type |= (16<<8);
3889 break;
3890 #endif
3891 case GST_VIDEO_TRANSFER_ARIB_STD_B67: /* ARIB_STD_B67 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003892 decParm->hdr.signal_type |= (18<<8);
3893 break;
3894 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
le.han8d28eb82024-06-05 08:11:12 +00003895 case GST_VIDEO_TRANSFER_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003896 decParm->hdr.signal_type |= (3<<8);
3897 break;
3898 #endif
le.han8d28eb82024-06-05 08:11:12 +00003899 case GST_VIDEO_TRANSFER_GAMMA10: /* GAMMA10 */
3900 case GST_VIDEO_TRANSFER_GAMMA18: /* GAMMA18 */
3901 case GST_VIDEO_TRANSFER_GAMMA20: /* GAMMA20 */
3902 case GST_VIDEO_TRANSFER_GAMMA22: /* GAMMA22 */
3903 case GST_VIDEO_TRANSFER_SRGB: /* SRGB */
3904 case GST_VIDEO_TRANSFER_GAMMA28: /* GAMMA28 */
3905 case GST_VIDEO_TRANSFER_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003906 default:
3907 break;
3908 }
3909 /* primaries */
3910 switch ( hdrColorimetry[3] )
3911 {
le.han8d28eb82024-06-05 08:11:12 +00003912 case GST_VIDEO_COLOR_PRIMARIES_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003913 decParm->hdr.signal_type |= ((1<<24)|(1<<16));
3914 break;
le.han8d28eb82024-06-05 08:11:12 +00003915 case GST_VIDEO_COLOR_PRIMARIES_BT470M: /* BT470M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003916 decParm->hdr.signal_type |= ((1<<24)|(4<<16));
3917 break;
le.han8d28eb82024-06-05 08:11:12 +00003918 case GST_VIDEO_COLOR_PRIMARIES_BT470BG: /* BT470BG */
xuesong.jiange1a19662022-06-21 20:30:22 +08003919 decParm->hdr.signal_type |= ((1<<24)|(5<<16));
3920 break;
le.han8d28eb82024-06-05 08:11:12 +00003921 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M: /* SMPTE170M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003922 decParm->hdr.signal_type |= ((1<<24)|(6<<16));
3923 break;
le.han8d28eb82024-06-05 08:11:12 +00003924 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003925 decParm->hdr.signal_type |= ((1<<24)|(7<<16));
3926 break;
le.han8d28eb82024-06-05 08:11:12 +00003927 case GST_VIDEO_COLOR_PRIMARIES_FILM: /* FILM */
xuesong.jiange1a19662022-06-21 20:30:22 +08003928 decParm->hdr.signal_type |= ((1<<24)|(8<<16));
3929 break;
le.han8d28eb82024-06-05 08:11:12 +00003930 case GST_VIDEO_COLOR_PRIMARIES_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003931 decParm->hdr.signal_type |= ((1<<24)|(9<<16));
3932 break;
le.han8d28eb82024-06-05 08:11:12 +00003933 case GST_VIDEO_COLOR_PRIMARIES_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003934 default:
3935 break;
3936 }
3937 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR signal_type %X", decParm->hdr.signal_type);
3938 }
3939
bo.xiao7659cda2024-07-18 16:16:50 +08003940 //why remove this colorimetry?
xuesong.jiange1a19662022-06-21 20:30:22 +08003941 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "got caps %" GST_PTR_FORMAT, caps);
3942 GstStructure *st = gst_caps_get_structure(caps, 0);
3943 GstCapsFeatures *features = gst_caps_get_features(caps, 0);
3944
3945 if (gst_structure_has_field(st, "colorimetry"))
3946 {
3947 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "have colorimetry");
3948 }
3949
3950 if (st && features)
3951 {
3952 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "trace in remove colorimetry");
3953 gst_structure_remove_field(st, "colorimetry");
3954 gst_caps_features_remove(features, "colorimetry");
3955 }
3956 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove colorimetry %" GST_PTR_FORMAT, caps);
3957 }
3958
le.han7d0af792024-06-05 08:44:18 +00003959 const char * field = NULL;
3960 if (gst_structure_has_field(structure, "mastering-display-metadata")) {
3961 field = "mastering-display-metadata";
3962 } else if (gst_structure_has_field(structure, "mastering-display-info")) {
3963 field = "mastering-display-info";
3964 }
3965
3966 if ( field )
xuesong.jiange1a19662022-06-21 20:30:22 +08003967 {
le.han7d0af792024-06-05 08:44:18 +00003968 const char *masteringDisplay= gst_structure_get_string(structure, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08003969 float hdrMasteringDisplay[10];
3970 if ( masteringDisplay && sscanf( masteringDisplay, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
3971 &hdrMasteringDisplay[0],
3972 &hdrMasteringDisplay[1],
3973 &hdrMasteringDisplay[2],
3974 &hdrMasteringDisplay[3],
3975 &hdrMasteringDisplay[4],
3976 &hdrMasteringDisplay[5],
3977 &hdrMasteringDisplay[6],
3978 &hdrMasteringDisplay[7],
3979 &hdrMasteringDisplay[8],
3980 &hdrMasteringDisplay[9] ) == 10 )
3981 {
3982 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "mastering display [%f,%f,%f,%f,%f,%f,%f,%f,%f,%f]",
3983 hdrMasteringDisplay[0],
3984 hdrMasteringDisplay[1],
3985 hdrMasteringDisplay[2],
3986 hdrMasteringDisplay[3],
3987 hdrMasteringDisplay[4],
3988 hdrMasteringDisplay[5],
3989 hdrMasteringDisplay[6],
3990 hdrMasteringDisplay[7],
3991 hdrMasteringDisplay[8],
3992 hdrMasteringDisplay[9] );
3993
3994 decParm->hdr.color_parms.present_flag= 1;
3995 decParm->hdr.color_parms.primaries[2][0]= (uint32_t)(hdrMasteringDisplay[0]*50000); /* R.x */
3996 decParm->hdr.color_parms.primaries[2][1]= (uint32_t)(hdrMasteringDisplay[1]*50000); /* R.y */
3997 decParm->hdr.color_parms.primaries[0][0]= (uint32_t)(hdrMasteringDisplay[2]*50000); /* G.x */
3998 decParm->hdr.color_parms.primaries[0][1]= (uint32_t)(hdrMasteringDisplay[3]*50000); /* G.y */
3999 decParm->hdr.color_parms.primaries[1][0]= (uint32_t)(hdrMasteringDisplay[4]*50000); /* B.x */
4000 decParm->hdr.color_parms.primaries[1][1]= (uint32_t)(hdrMasteringDisplay[5]*50000); /* B.y */
4001 decParm->hdr.color_parms.white_point[0]= (uint32_t)(hdrMasteringDisplay[6]*50000);
4002 decParm->hdr.color_parms.white_point[1]= (uint32_t)(hdrMasteringDisplay[7]*50000);
4003 decParm->hdr.color_parms.luminance[0]= (uint32_t)(hdrMasteringDisplay[8]);
4004 decParm->hdr.color_parms.luminance[1]= (uint32_t)(hdrMasteringDisplay[9]);
4005 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: primaries %X %X %X %X %X %X",
4006 decParm->hdr.color_parms.primaries[2][0],
4007 decParm->hdr.color_parms.primaries[2][1],
4008 decParm->hdr.color_parms.primaries[0][0],
4009 decParm->hdr.color_parms.primaries[0][1],
4010 decParm->hdr.color_parms.primaries[1][0],
4011 decParm->hdr.color_parms.primaries[1][1] );
4012 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: white point: %X %X",
4013 decParm->hdr.color_parms.white_point[0],
4014 decParm->hdr.color_parms.white_point[1] );
4015 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: luminance: %X %X",
4016 decParm->hdr.color_parms.luminance[0],
4017 decParm->hdr.color_parms.luminance[1] );
4018 }
4019
4020 GstStructure *st = gst_caps_get_structure(caps, 0);
4021 GstCapsFeatures * features = gst_caps_get_features(caps, 0);
4022 if (st && features)
4023 {
le.han7d0af792024-06-05 08:44:18 +00004024 gst_structure_remove_fields(st, field, NULL);
4025 gst_caps_features_remove(features, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08004026 }
le.han7d0af792024-06-05 08:44:18 +00004027 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove %s %" GST_PTR_FORMAT, field, caps);
xuesong.jiange1a19662022-06-21 20:30:22 +08004028 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004029 }
hanghang.luo75664712024-07-01 19:28:10 +08004030 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004031 {
hanghang.luo75664712024-07-01 19:28:10 +08004032 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao7659cda2024-07-18 16:16:50 +08004033
4034 if (!get_amlogic_vdec_parm(v4l2object, streamparm))
hanghang.luobfc63f82024-07-05 11:04:56 +08004035 {
4036 GST_ERROR_OBJECT(v4l2object->dbg_obj, "can't get vdec parm");
4037 return;
4038 }
hanghang.luo75664712024-07-01 19:28:10 +08004039
bo.xiao7659cda2024-07-18 16:16:50 +08004040 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, self->v4l2output->fmtdesc->pixelformat,
bo.xiao34e36202024-07-17 16:04:01 +08004041 width, height, is_interlaced);
bo.xiao7659cda2024-07-18 16:16:50 +08004042 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "capture cfg dw mode to %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004043
4044 if (needSpecConfigForFg(v4l2object))
4045 {
bo.xiao7659cda2024-07-18 16:16:50 +08004046 decParm->cfg.double_write_mode = VDEC_DW_MMU_1;
4047 GST_DEBUG_OBJECT(v4l2object->dbg_obj,"set fg dw mode %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004048 }
bo.xiao7659cda2024-07-18 16:16:50 +08004049 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004050 }
4051 else
4052 {
hanghang.luo75664712024-07-01 19:28:10 +08004053 GST_ERROR_OBJECT(v4l2object->dbg_obj,"can't deal with. please check buffer type.");
bo.xiao7659cda2024-07-18 16:16:50 +08004054 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004055 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004056
bo.xiao7659cda2024-07-18 16:16:50 +08004057 if (use_ext_config)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004058 {
bo.xiao7659cda2024-07-18 16:16:50 +08004059 memset(&ctrls, 0, sizeof(ctrls));
4060 memset(&control, 0, sizeof(control));
4061 control.id = AML_V4L2_DEC_PARMS_CONFIG;
4062 control.ptr = decParm;
4063 control.size = sizeof(struct aml_dec_params);
4064 ctrls.count = 1;
4065 ctrls.controls = &control;
4066 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls ) < 0)
4067 {
4068 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4069 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004070 }
bo.xiao7659cda2024-07-18 16:16:50 +08004071 else
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004072 {
bo.xiao7659cda2024-07-18 16:16:50 +08004073 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_PARM, streamparm) < 0)
4074 {
4075 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4076 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004077 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004078}
4079
xuesong.jiangae1548e2022-05-06 16:38:46 +08004080static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004081gst_aml_v4l2_object_set_format_full (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4082 gboolean try_only, GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004083{
le.han3b118242024-09-29 06:32:02 +00004084 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao857b8682024-09-12 16:40:32 +08004085 gint fd = v4l2object->video_fd;
4086 struct v4l2_format format;
4087 struct v4l2_streamparm streamparm;
4088 enum v4l2_field field;
4089 guint32 pixelformat;
4090 struct v4l2_fmtdesc *fmtdesc;
4091 GstVideoInfo info;
4092 GstVideoAlignment align;
4093 gint width, height, fps_n, fps_d;
4094 gint n_v4l_planes;
4095 gint i = 0;
4096 gboolean is_mplane;
4097 enum v4l2_colorspace colorspace = 0;
4098 enum v4l2_quantization range = 0;
4099 enum v4l2_ycbcr_encoding matrix = 0;
4100 enum v4l2_xfer_func transfer = 0;
4101 GstStructure *s;
4102 gboolean disable_colorimetry = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004103
bo.xiao857b8682024-09-12 16:40:32 +08004104 g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
4105 gst_caps_is_writable (caps), FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004106
bo.xiao857b8682024-09-12 16:40:32 +08004107 GST_AML_V4L2_CHECK_OPEN (v4l2object);
4108 if (!try_only)
4109 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004110
bo.xiao857b8682024-09-12 16:40:32 +08004111 is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004112
bo.xiao857b8682024-09-12 16:40:32 +08004113 gst_video_info_init (&info);
4114 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004115
bo.xiao857b8682024-09-12 16:40:32 +08004116 if (!gst_aml_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
4117 goto invalid_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004118
bo.xiao857b8682024-09-12 16:40:32 +08004119 pixelformat = fmtdesc->pixelformat;
4120 width = GST_VIDEO_INFO_WIDTH (&info);
4121 height = GST_VIDEO_INFO_HEIGHT (&info);
4122 fps_n = GST_VIDEO_INFO_FPS_N (&info);
4123 fps_d = GST_VIDEO_INFO_FPS_D (&info);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004124
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004125 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size");
4126 struct v4l2_frmsizeenum size;
4127 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
4128 size.index = 0;
4129 size.pixel_format = pixelformat;
4130 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
bo.xiao857b8682024-09-12 16:40:32 +08004131 return FALSE;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004132 if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
4133 {
bo.xiao857b8682024-09-12 16:40:32 +08004134 guint32 maxw, maxh;
4135 maxw = MIN (size.stepwise.max_width, G_MAXINT);
4136 maxh = MIN (size.stepwise.max_height, G_MAXINT);
4137 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "image from caps w_h:%d_%d", width, height);
4138 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "v4l2 support max w_h:%d_%d", maxw, maxh);
4139 if (width*height > maxw*maxh)
4140 return FALSE;
4141 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size ok");
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004142 }
4143
bo.xiao857b8682024-09-12 16:40:32 +08004144 //set amlogic params here,because we need pix format to set dw mode
4145 memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
4146 set_amlogic_vdec_parm(v4l2object, &streamparm, caps, pixelformat);
fei.deng7c3d67f2022-11-09 11:06:05 +08004147
bo.xiao857b8682024-09-12 16:40:32 +08004148 /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
4149 * or if contiguous is preferred */
4150 n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
4151 if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
4152 n_v4l_planes = 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004153
bo.xiao857b8682024-09-12 16:40:32 +08004154 if (GST_VIDEO_INFO_IS_INTERLACED(&info))
4155 {
4156 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "interlaced video");
4157 /* ideally we would differentiate between types of interlaced video
4158 * but there is not sufficient information in the caps..
4159 */
4160 field = V4L2_FIELD_INTERLACED;
4161 }
4162 else
4163 {
4164 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "progressive video");
4165 field = V4L2_FIELD_NONE;
4166 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004167
bo.xiao857b8682024-09-12 16:40:32 +08004168 /* We first pick the main colorspace from the primaries */
4169 switch (info.colorimetry.primaries)
4170 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004171 case GST_VIDEO_COLOR_PRIMARIES_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004172 /* There is two colorspaces using these primaries, use the range to
4173 * differentiate */
4174 if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
4175 colorspace = V4L2_COLORSPACE_REC709;
4176 else
4177 colorspace = V4L2_COLORSPACE_SRGB;
4178 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004179 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004180 colorspace = V4L2_COLORSPACE_BT2020;
4181 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004182 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
bo.xiao857b8682024-09-12 16:40:32 +08004183 colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
4184 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004185 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
bo.xiao857b8682024-09-12 16:40:32 +08004186 colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
4187 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004188 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08004189 colorspace = V4L2_COLORSPACE_SMPTE170M;
4190 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004191 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004192 colorspace = V4L2_COLORSPACE_SMPTE240M;
4193 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004194
4195 case GST_VIDEO_COLOR_PRIMARIES_FILM:
4196 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004197 /* We don't know, we will guess */
4198 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004199
4200 default:
bo.xiao857b8682024-09-12 16:40:32 +08004201 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4202 "Unknown colorimetry primaries %d", info.colorimetry.primaries);
4203 break;
4204 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004205
bo.xiao857b8682024-09-12 16:40:32 +08004206 switch (info.colorimetry.range)
4207 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004208 case GST_VIDEO_COLOR_RANGE_0_255:
bo.xiao857b8682024-09-12 16:40:32 +08004209 range = V4L2_QUANTIZATION_FULL_RANGE;
4210 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004211 case GST_VIDEO_COLOR_RANGE_16_235:
bo.xiao857b8682024-09-12 16:40:32 +08004212 range = V4L2_QUANTIZATION_LIM_RANGE;
4213 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004214 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004215 /* We let the driver pick a default one */
4216 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004217 default:
bo.xiao857b8682024-09-12 16:40:32 +08004218 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4219 "Unknown colorimetry range %d", info.colorimetry.range);
4220 break;
4221 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004222
bo.xiao857b8682024-09-12 16:40:32 +08004223 switch (info.colorimetry.matrix)
4224 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004225 case GST_VIDEO_COLOR_MATRIX_RGB:
bo.xiao857b8682024-09-12 16:40:32 +08004226 /* Unspecified, leave to default */
4227 break;
4228 /* FCC is about the same as BT601 with less digit */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004229 case GST_VIDEO_COLOR_MATRIX_FCC:
4230 case GST_VIDEO_COLOR_MATRIX_BT601:
bo.xiao857b8682024-09-12 16:40:32 +08004231 matrix = V4L2_YCBCR_ENC_601;
4232 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004233 case GST_VIDEO_COLOR_MATRIX_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004234 matrix = V4L2_YCBCR_ENC_709;
4235 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004236 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004237 matrix = V4L2_YCBCR_ENC_SMPTE240M;
4238 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004239 case GST_VIDEO_COLOR_MATRIX_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004240 matrix = V4L2_YCBCR_ENC_BT2020;
4241 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004242 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004243 /* We let the driver pick a default one */
4244 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004245 default:
bo.xiao857b8682024-09-12 16:40:32 +08004246 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4247 "Unknown colorimetry matrix %d", info.colorimetry.matrix);
4248 break;
4249 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004250
bo.xiao857b8682024-09-12 16:40:32 +08004251 switch (info.colorimetry.transfer)
4252 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004253 case GST_VIDEO_TRANSFER_GAMMA18:
4254 case GST_VIDEO_TRANSFER_GAMMA20:
4255 case GST_VIDEO_TRANSFER_GAMMA22:
4256 case GST_VIDEO_TRANSFER_GAMMA28:
bo.xiao857b8682024-09-12 16:40:32 +08004257 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4258 "GAMMA 18, 20, 22, 28 transfer functions not supported");
4259 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004260 case GST_VIDEO_TRANSFER_GAMMA10:
bo.xiao857b8682024-09-12 16:40:32 +08004261 transfer = V4L2_XFER_FUNC_NONE;
4262 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004263 case GST_VIDEO_TRANSFER_BT2020_12:
4264 case GST_VIDEO_TRANSFER_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004265 transfer = V4L2_XFER_FUNC_709;
4266 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004267 case GST_VIDEO_TRANSFER_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004268 transfer = V4L2_XFER_FUNC_SMPTE240M;
4269 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004270 case GST_VIDEO_TRANSFER_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08004271 transfer = V4L2_XFER_FUNC_SRGB;
4272 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004273 case GST_VIDEO_TRANSFER_LOG100:
4274 case GST_VIDEO_TRANSFER_LOG316:
bo.xiao857b8682024-09-12 16:40:32 +08004275 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4276 "LOG 100, 316 transfer functions not supported");
4277 /* FIXME No known sensible default, maybe AdobeRGB ? */
4278 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004279 case GST_VIDEO_TRANSFER_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004280 /* We let the driver pick a default one */
4281 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004282 default:
bo.xiao857b8682024-09-12 16:40:32 +08004283 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4284 "Unknown colorimetry transfer %d", info.colorimetry.transfer);
4285 break;
4286 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004287
bo.xiao857b8682024-09-12 16:40:32 +08004288 if (colorspace == 0)
4289 {
4290 /* Try to guess colorspace according to pixelformat and size */
4291 if (GST_VIDEO_INFO_IS_YUV (&info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004292 {
bo.xiao857b8682024-09-12 16:40:32 +08004293 if (range == V4L2_QUANTIZATION_FULL_RANGE
4294 && matrix == V4L2_YCBCR_ENC_601 && transfer == 0)
4295 {
4296 /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
4297 * function most likely is JPEG */
4298 colorspace = V4L2_COLORSPACE_JPEG;
4299 transfer = V4L2_XFER_FUNC_SRGB;
4300 }
4301 else
4302 {
4303 /* SD streams likely use SMPTE170M and HD streams REC709 */
4304 if (width <= 720 && height <= 576)
4305 colorspace = V4L2_COLORSPACE_SMPTE170M;
4306 else
4307 colorspace = V4L2_COLORSPACE_REC709;
4308 }
4309 }
4310 else if (GST_VIDEO_INFO_IS_RGB (&info))
4311 {
4312 colorspace = V4L2_COLORSPACE_SRGB;
4313 transfer = V4L2_XFER_FUNC_NONE;
4314 }
4315 }
4316
4317 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format "
4318 "%" GST_FOURCC_FORMAT " stride: %d", width, height,
4319 GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
4320
4321 memset (&format, 0x00, sizeof (struct v4l2_format));
4322 format.type = v4l2object->type;
4323
4324 if (is_mplane)
4325 {
4326 format.type = v4l2object->type;
4327 format.fmt.pix_mp.pixelformat = pixelformat;
4328 format.fmt.pix_mp.width = width;
4329 format.fmt.pix_mp.height = height;
4330 format.fmt.pix_mp.field = field;
4331 format.fmt.pix_mp.num_planes = n_v4l_planes;
4332
4333 /* try to ask our preferred stride but it's not a failure if not
4334 * accepted */
4335 for (i = 0; i < n_v4l_planes; i++)
4336 {
4337 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
4338
4339 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4340 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4341 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4342
4343 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004344 }
4345
bo.xiao857b8682024-09-12 16:40:32 +08004346 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
4347 {
4348 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4349 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4350 else
4351 format.fmt.pix_mp.plane_fmt[0].sizeimage = v4l2object->low_memory_mode ? LOW_MEM_ENCODED_BUFFER_SIZE : ENCODED_BUFFER_SIZE;
4352 }
4353 }
4354 else
4355 {
4356 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004357
xuesong.jiangae1548e2022-05-06 16:38:46 +08004358 format.type = v4l2object->type;
4359
bo.xiao857b8682024-09-12 16:40:32 +08004360 format.fmt.pix.width = width;
4361 format.fmt.pix.height = height;
4362 format.fmt.pix.pixelformat = pixelformat;
4363 format.fmt.pix.field = field;
4364
4365 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4366 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4367 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4368
4369 /* try to ask our preferred stride */
4370 format.fmt.pix.bytesperline = stride;
4371
4372 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004373 {
bo.xiao857b8682024-09-12 16:40:32 +08004374 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4375 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4376 else
4377 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 +08004378 }
bo.xiao857b8682024-09-12 16:40:32 +08004379 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004380
bo.xiao857b8682024-09-12 16:40:32 +08004381 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
4382 "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
4383 format.fmt.pix_mp.height,
4384 GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
4385 is_mplane ? format.fmt.pix_mp.num_planes : 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004386
4387#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004388 if (is_mplane)
4389 {
4390 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4391 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4392 format.fmt.pix_mp.plane_fmt[i].bytesperline);
4393 }
4394 else
4395 {
4396 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4397 format.fmt.pix.bytesperline);
4398 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004399#endif
4400
bo.xiao857b8682024-09-12 16:40:32 +08004401 if (is_mplane)
4402 {
4403 format.fmt.pix_mp.colorspace = colorspace;
4404 format.fmt.pix_mp.quantization = range;
4405 format.fmt.pix_mp.ycbcr_enc = matrix;
4406 format.fmt.pix_mp.xfer_func = transfer;
4407 }
4408 else
4409 {
4410 format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
4411 format.fmt.pix.colorspace = colorspace;
4412 format.fmt.pix.quantization = range;
4413 format.fmt.pix.ycbcr_enc = matrix;
4414 format.fmt.pix.xfer_func = transfer;
4415 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004416
bo.xiao857b8682024-09-12 16:40:32 +08004417 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
4418 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004419
bo.xiao857b8682024-09-12 16:40:32 +08004420 if (try_only)
4421 {
4422 if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
4423 goto try_fmt_failed;
4424 }
4425 else
4426 {
4427 if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
4428 goto set_fmt_failed;
4429 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004430
bo.xiao857b8682024-09-12 16:40:32 +08004431 if (is_mplane)
4432 {
4433 colorspace = format.fmt.pix_mp.colorspace;
4434 range = format.fmt.pix_mp.quantization;
4435 matrix = format.fmt.pix_mp.ycbcr_enc;
4436 transfer = format.fmt.pix_mp.xfer_func;
4437 }
4438 else
4439 {
4440 colorspace = format.fmt.pix.colorspace;
4441 range = format.fmt.pix.quantization;
4442 matrix = format.fmt.pix.ycbcr_enc;
4443 transfer = format.fmt.pix.xfer_func;
4444 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004445
bo.xiao857b8682024-09-12 16:40:32 +08004446 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got format of %dx%d, format "
4447 "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d",
4448 format.fmt.pix.width, format.fmt.pix_mp.height,
4449 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4450 is_mplane ? format.fmt.pix_mp.num_planes : 1,
4451 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004452
le.han3b118242024-09-29 06:32:02 +00004453 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY)
4454 {
4455 self->v4l2output->stride = format.fmt.pix_mp.plane_fmt[0].bytesperline;
4456 //because driver return src w,h when AFBC_ONLY
4457 format.fmt.pix.width = format.fmt.pix.height = 64;
4458 format.fmt.pix_mp.plane_fmt[0].bytesperline = format.fmt.pix_mp.plane_fmt[1].bytesperline = 64;
4459 }
4460
xuesong.jiangae1548e2022-05-06 16:38:46 +08004461#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004462 if (is_mplane)
4463 {
4464 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4465 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4466 format.fmt.pix_mp.plane_fmt[i].bytesperline,
4467 format.fmt.pix_mp.plane_fmt[i].sizeimage);
4468 }
4469 else
4470 {
4471 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4472 format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
4473 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004474#endif
4475
bo.xiao857b8682024-09-12 16:40:32 +08004476 if (format.fmt.pix.pixelformat != pixelformat)
4477 goto invalid_pixelformat;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004478
bo.xiao857b8682024-09-12 16:40:32 +08004479 /* Only negotiate size with raw data.
4480 * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
4481 * in ASF mode for example, there is also not reason for a driver to
4482 * change the size. */
4483 if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED)
4484 {
4485 /* We can crop larger images */
4486 if (format.fmt.pix.width < width || format.fmt.pix.height < height)
4487 goto invalid_dimensions;
4488
4489 /* Note, this will be adjusted if upstream has non-centered cropping. */
4490 align.padding_top = 0;
4491 align.padding_bottom = format.fmt.pix.height - height;
4492 align.padding_left = 0;
4493 align.padding_right = format.fmt.pix.width - width;
4494 }
4495
4496 if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
4497 goto invalid_planes;
4498
4499 /* used to check colorimetry and interlace mode fields presence */
4500 s = gst_caps_get_structure (caps, 0);
4501
4502 if (!gst_aml_v4l2_object_get_interlace_mode(format.fmt.pix.field,
4503 &info.interlace_mode))
4504 goto invalid_field;
4505 if (gst_structure_has_field(s, "interlace-mode"))
4506 {
4507 if (format.fmt.pix.field != field)
4508 goto invalid_field;
4509 }
4510
4511 if (gst_aml_v4l2_object_get_colorspace(&format, &info.colorimetry))
4512 {
4513 if (gst_structure_has_field(s, "colorimetry"))
4514 {
4515 if (!gst_aml_v4l2_video_colorimetry_matches(&info.colorimetry, gst_structure_get_string(s, "colorimetry")))
4516 {
4517 // goto invalid_colorimetry;
4518 }
4519 }
4520 }
4521 else
4522 {
4523 /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
4524 * the TRY_FMT */
4525 disable_colorimetry = TRUE;
4526 if (gst_structure_has_field (s, "colorimetry"))
4527 gst_structure_remove_field (s, "colorimetry");
4528 }
4529
4530 /* In case we have skipped the try_fmt probes, we'll need to set the
4531 * colorimetry and interlace-mode back into the caps. */
4532 if (v4l2object->skip_try_fmt_probes)
4533 {
4534 if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004535 {
bo.xiao857b8682024-09-12 16:40:32 +08004536 gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
4537 gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
4538 g_free (str);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004539 }
4540
bo.xiao857b8682024-09-12 16:40:32 +08004541 if (!gst_structure_has_field(s, "interlace-mode"))
4542 gst_structure_set(s, "interlace-mode", G_TYPE_STRING,
4543 gst_video_interlace_mode_to_string(info.interlace_mode), NULL);
4544 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004545
bo.xiao857b8682024-09-12 16:40:32 +08004546 if (try_only) /* good enough for trying only */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004547 return TRUE;
4548
bo.xiao857b8682024-09-12 16:40:32 +08004549 if (GST_VIDEO_INFO_HAS_ALPHA (&info))
4550 {
4551 struct v4l2_control ctl = { 0, };
4552 ctl.id = V4L2_CID_ALPHA_COMPONENT;
4553 ctl.value = 0xff;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004554
bo.xiao857b8682024-09-12 16:40:32 +08004555 if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
4556 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4557 "Failed to set alpha component value");
4558 }
4559
4560 /* Is there a reason we require the caller to always specify a framerate? */
4561 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
4562 fps_d);
4563
4564 if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
4565 goto get_parm_failed;
4566
4567 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
4568 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
4569 {
4570 GST_VIDEO_INFO_FPS_N (&info) =
4571 streamparm.parm.capture.timeperframe.denominator;
4572 GST_VIDEO_INFO_FPS_D (&info) =
4573 streamparm.parm.capture.timeperframe.numerator;
4574
4575 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u",
4576 streamparm.parm.capture.timeperframe.denominator,
4577 streamparm.parm.capture.timeperframe.numerator);
4578
4579 /* We used to skip frame rate setup if the camera was already setup
4580 * with the requested frame rate. This breaks some cameras though,
4581 * causing them to not output data (several models of Thinkpad cameras
4582 * have this problem at least).
4583 * So, don't skip. */
4584 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
4585 fps_n, fps_d);
4586 /* We want to change the frame rate, so check whether we can. Some cheap USB
4587 * cameras don't have the capability */
4588 if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004589 {
bo.xiao857b8682024-09-12 16:40:32 +08004590 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4591 "Not setting capture framerate (not supported)");
4592 goto done;
4593 }
4594
4595 /* Note: V4L2 wants the frame interval, we have the frame rate */
4596 streamparm.parm.capture.timeperframe.numerator = fps_d;
4597 streamparm.parm.capture.timeperframe.denominator = fps_n;
4598
4599 if (streamparm.parm.capture.timeperframe.numerator > 0 &&
4600 streamparm.parm.capture.timeperframe.denominator > 0)
4601 {
4602 /* get new values */
4603 fps_d = streamparm.parm.capture.timeperframe.numerator;
4604 fps_n = streamparm.parm.capture.timeperframe.denominator;
4605
4606 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set capture framerate to %u/%u",
4607 fps_n, fps_d);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004608 }
4609 else
4610 {
bo.xiao857b8682024-09-12 16:40:32 +08004611 /* fix v4l2 capture driver to provide framerate values */
4612 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4613 "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
4614 }
4615
4616 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4617 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4618 }
4619 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
4620 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4621 {
4622 GST_VIDEO_INFO_FPS_N (&info) =
4623 streamparm.parm.output.timeperframe.denominator;
4624 GST_VIDEO_INFO_FPS_D (&info) =
4625 streamparm.parm.output.timeperframe.numerator;
4626
4627 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u",
4628 streamparm.parm.output.timeperframe.denominator,
4629 streamparm.parm.output.timeperframe.numerator);
4630
4631 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting output framerate to %u/%u",
4632 fps_n, fps_d);
4633 if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4634 {
4635 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4636 "Not setting output framerate (not supported)");
4637 goto done;
4638 }
4639
4640 /* Note: V4L2 wants the frame interval, we have the frame rate */
4641 streamparm.parm.output.timeperframe.numerator = fps_d;
4642 streamparm.parm.output.timeperframe.denominator = fps_n;
4643
4644 if (streamparm.parm.output.timeperframe.numerator > 0 &&
4645 streamparm.parm.output.timeperframe.denominator > 0)
4646 {
4647 /* get new values */
4648 fps_d = streamparm.parm.output.timeperframe.numerator;
4649 fps_n = streamparm.parm.output.timeperframe.denominator;
4650
4651 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set output framerate to %u/%u",
4652 fps_n, fps_d);
4653 }
4654 else
4655 {
4656 /* fix v4l2 output driver to provide framerate values */
4657 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4658 "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
4659 }
4660
4661 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4662 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4663 }
4664
4665done:
4666 /* add boolean return, so we can fail on drivers bugs */
4667 gst_aml_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info, &align);
4668
4669 /* now configure the pool */
4670 if (!gst_aml_v4l2_object_setup_pool (v4l2object, caps))
4671 goto pool_failed;
4672
4673 return TRUE;
4674
4675 /* ERRORS */
4676invalid_caps:
4677 {
4678 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
4679 caps);
4680
4681 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4682 (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps));
4683 return FALSE;
4684 }
4685try_fmt_failed:
4686 {
4687 if (errno == EINVAL)
4688 {
4689 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4690 (_("Device '%s' has no supported format"), v4l2object->videodev),
4691 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4692 GST_FOURCC_ARGS (pixelformat), width, height,
4693 g_strerror (errno)));
4694 }
4695 else
4696 {
4697 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4698 (_("Device '%s' failed during initialization"),
4699 v4l2object->videodev),
4700 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4701 GST_FOURCC_ARGS (pixelformat), width, height,
4702 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004703 }
4704 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004705 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004706set_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004707 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004708 if (errno == EBUSY)
4709 {
bo.xiao857b8682024-09-12 16:40:32 +08004710 GST_AML_V4L2_ERROR (error, RESOURCE, BUSY,
4711 (_("Device '%s' is busy"), v4l2object->videodev),
4712 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4713 GST_FOURCC_ARGS (pixelformat), width, height,
4714 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004715 }
4716 else if (errno == EINVAL)
4717 {
bo.xiao857b8682024-09-12 16:40:32 +08004718 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4719 (_("Device '%s' has no supported format"), v4l2object->videodev),
4720 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4721 GST_FOURCC_ARGS (pixelformat), width, height,
4722 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004723 }
4724 else
4725 {
bo.xiao857b8682024-09-12 16:40:32 +08004726 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4727 (_("Device '%s' failed during initialization"),
4728 v4l2object->videodev),
4729 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4730 GST_FOURCC_ARGS (pixelformat), width, height,
4731 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004732 }
4733 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004734 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004735invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08004736 {
4737 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4738 (_("Device '%s' cannot capture at %dx%d"),
4739 v4l2object->videodev, width, height),
4740 ("Tried to capture at %dx%d, but device returned size %dx%d",
4741 width, height, format.fmt.pix.width, format.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004742 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004743 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004744invalid_pixelformat:
bo.xiao857b8682024-09-12 16:40:32 +08004745 {
4746 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4747 (_("Device '%s' cannot capture in the specified format"),
4748 v4l2object->videodev),
4749 ("Tried to capture in %" GST_FOURCC_FORMAT
4750 ", but device returned format" " %" GST_FOURCC_FORMAT,
4751 GST_FOURCC_ARGS (pixelformat),
4752 GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004753 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004754 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004755invalid_planes:
bo.xiao857b8682024-09-12 16:40:32 +08004756 {
4757 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4758 (_("Device '%s' does support non-contiguous planes"),
4759 v4l2object->videodev),
4760 ("Device wants %d planes", format.fmt.pix_mp.num_planes));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004761 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004762 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004763invalid_field:
bo.xiao857b8682024-09-12 16:40:32 +08004764 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004765 enum v4l2_field wanted_field;
4766
4767 if (is_mplane)
bo.xiao857b8682024-09-12 16:40:32 +08004768 wanted_field = format.fmt.pix_mp.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004769 else
bo.xiao857b8682024-09-12 16:40:32 +08004770 wanted_field = format.fmt.pix.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004771
bo.xiao857b8682024-09-12 16:40:32 +08004772 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4773 (_("Device '%s' does not support %s interlacing"),
4774 v4l2object->videodev,
4775 field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
4776 ("Device wants %s interlacing",
4777 wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004778 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004779 }
hanghang.luo3128f102022-08-18 10:36:19 +08004780#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08004781invalid_colorimetry:
bo.xiao857b8682024-09-12 16:40:32 +08004782 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004783 gchar *wanted_colorimetry;
4784
bo.xiao857b8682024-09-12 16:40:32 +08004785 wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004786
bo.xiao857b8682024-09-12 16:40:32 +08004787 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4788 (_("Device '%s' does not support %s colorimetry"),
4789 v4l2object->videodev, gst_structure_get_string (s, "colorimetry")),
4790 ("Device wants %s colorimetry", wanted_colorimetry));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004791
bo.xiao857b8682024-09-12 16:40:32 +08004792 g_free (wanted_colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004793 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004794 }
hanghang.luo3128f102022-08-18 10:36:19 +08004795#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08004796get_parm_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004797 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004798 /* it's possible that this call is not supported */
4799 if (errno != EINVAL && errno != ENOTTY)
4800 {
bo.xiao857b8682024-09-12 16:40:32 +08004801 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4802 (_("Could not get parameters on device '%s'"),
4803 v4l2object->videodev), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004804 }
4805 goto done;
bo.xiao857b8682024-09-12 16:40:32 +08004806 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004807pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004808 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004809 /* setup_pool already send the error */
4810 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004811 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004812}
4813
4814gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004815gst_aml_v4l2_object_set_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4816 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004817{
bo.xiao857b8682024-09-12 16:40:32 +08004818 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
4819 caps);
4820 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, FALSE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004821}
4822
4823gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004824gst_aml_v4l2_object_try_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4825 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004826{
bo.xiao857b8682024-09-12 16:40:32 +08004827 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
4828 caps);
4829 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004830}
4831
4832GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004833gst_aml_v4l2_object_poll (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004834{
bo.xiao857b8682024-09-12 16:40:32 +08004835 gint ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004836
bo.xiao857b8682024-09-12 16:40:32 +08004837 if (!v4l2object->can_poll_device)
4838 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004839
bo.xiao857b8682024-09-12 16:40:32 +08004840 GST_LOG_OBJECT (v4l2object, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004841
4842again:
bo.xiao857b8682024-09-12 16:40:32 +08004843 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
4844 if (G_UNLIKELY (ret < 0))
4845 {
4846 switch (errno)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004847 {
bo.xiao857b8682024-09-12 16:40:32 +08004848 case EBUSY:
4849 goto stopped;
4850 case EAGAIN:
4851 case EINTR:
4852 goto again;
4853 case ENXIO:
4854 GST_WARNING_OBJECT (v4l2object,
4855 "v4l2 device doesn't support polling. Disabling"
4856 " using libv4l2 in this case may cause deadlocks");
4857 v4l2object->can_poll_device = FALSE;
4858 goto done;
4859 default:
4860 goto select_error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004861 }
bo.xiao857b8682024-09-12 16:40:32 +08004862 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004863
4864done:
bo.xiao857b8682024-09-12 16:40:32 +08004865 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004866
bo.xiao857b8682024-09-12 16:40:32 +08004867 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004868stopped:
bo.xiao857b8682024-09-12 16:40:32 +08004869 {
4870 GST_DEBUG_OBJECT (v4l2object, "stop called");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004871 return GST_FLOW_FLUSHING;
bo.xiao857b8682024-09-12 16:40:32 +08004872 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004873select_error:
bo.xiao857b8682024-09-12 16:40:32 +08004874 {
4875 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
4876 ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004877 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004878 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004879}
4880
4881GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004882gst_aml_v4l2_object_dqevent (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004883{
bo.xiao857b8682024-09-12 16:40:32 +08004884 GstFlowReturn res;
4885 struct v4l2_event evt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004886
bo.xiao857b8682024-09-12 16:40:32 +08004887 if ((res = gst_aml_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
4888 goto poll_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004889
bo.xiao857b8682024-09-12 16:40:32 +08004890 //only read v4l2 pri event
4891 if (!gst_poll_fd_can_read_pri(v4l2object->poll, &v4l2object->pollfd))
4892 {
4893 GST_DEBUG_OBJECT(v4l2object, "not v4l2 pri event");
4894 return GST_FLOW_OK;
4895 }
4896 memset (&evt, 0x00, sizeof (struct v4l2_event));
4897 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
4898 goto dqevent_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004899
bo.xiao857b8682024-09-12 16:40:32 +08004900 switch (evt.type)
4901 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004902 case V4L2_EVENT_SOURCE_CHANGE:
bo.xiao857b8682024-09-12 16:40:32 +08004903 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
4904 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004905 case V4L2_EVENT_EOS:
bo.xiao857b8682024-09-12 16:40:32 +08004906 return GST_AML_V4L2_FLOW_LAST_BUFFER;
4907 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004908 default:
bo.xiao857b8682024-09-12 16:40:32 +08004909 break;
4910 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004911
bo.xiao857b8682024-09-12 16:40:32 +08004912 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004913
bo.xiao857b8682024-09-12 16:40:32 +08004914 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004915poll_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004916 {
4917 GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004918 return res;
bo.xiao857b8682024-09-12 16:40:32 +08004919 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004920dqevent_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004921 {
fei.deng678f7052024-07-10 20:11:26 +08004922 GST_DEBUG_OBJECT(v4l2object, "dqevent failed");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004923 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004924 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004925}
4926
4927/**
4928 * gst_aml_v4l2_object_acquire_format:
bo.xiao857b8682024-09-12 16:40:32 +08004929 * @v4l2object: the object
4930 * @info: a GstVideoInfo to be filled
xuesong.jiangae1548e2022-05-06 16:38:46 +08004931 *
bo.xiao857b8682024-09-12 16:40:32 +08004932 * Acquire the driver chosen format. This is useful in decoder or encoder elements where
4933 * the output format is chosen by the HW.
xuesong.jiangae1548e2022-05-06 16:38:46 +08004934 *
4935 * Returns: %TRUE on success, %FALSE on failure.
4936 */
4937gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004938gst_aml_v4l2_object_acquire_format (GstAmlV4l2Object * v4l2object, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004939{
le.han3b118242024-09-29 06:32:02 +00004940 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao857b8682024-09-12 16:40:32 +08004941 struct v4l2_fmtdesc *fmtdesc;
4942 struct v4l2_format fmt;
4943 struct v4l2_crop crop;
4944 struct v4l2_selection sel;
4945 struct v4l2_cropcap cropcap;
4946 struct v4l2_rect *r = NULL;
4947 GstVideoFormat format;
4948 guint width, height;
4949 GstVideoAlignment align;
4950 gdouble pixelAspectRatio = 0.0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004951
bo.xiao857b8682024-09-12 16:40:32 +08004952 gst_video_info_init (info);
4953 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004954
bo.xiao857b8682024-09-12 16:40:32 +08004955 memset (&fmt, 0x00, sizeof (struct v4l2_format));
4956 fmt.type = v4l2object->type;
4957 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "fmt.type:%d", fmt.type);
4958 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
4959 goto get_fmt_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004960
bo.xiao857b8682024-09-12 16:40:32 +08004961 fmtdesc = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object,
4962 fmt.fmt.pix.pixelformat);
4963 if (fmtdesc == NULL)
4964 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004965
bo.xiao857b8682024-09-12 16:40:32 +08004966 /* No need to care about mplane, the four first params are the same */
4967 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004968
bo.xiao857b8682024-09-12 16:40:32 +08004969 /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
4970 if (format == GST_VIDEO_FORMAT_UNKNOWN)
4971 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004972
bo.xiao857b8682024-09-12 16:40:32 +08004973 if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
4974 goto invalid_dimensions;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004975
le.han3b118242024-09-29 06:32:02 +00004976 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY)
4977 {
4978 self->v4l2output->stride = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
4979 //because driver return src w,h when AFBC_ONLY
4980 fmt.fmt.pix.width = fmt.fmt.pix.height = 64;
4981 fmt.fmt.pix_mp.plane_fmt[0].bytesperline = fmt.fmt.pix_mp.plane_fmt[1].bytesperline = 64;
4982 }
4983
bo.xiao857b8682024-09-12 16:40:32 +08004984 width = fmt.fmt.pix.width;
4985 height = fmt.fmt.pix.height;
4986
4987 /* Use the default compose rectangle */
4988 memset (&sel, 0, sizeof (struct v4l2_selection));
4989 sel.type = v4l2object->type;
4990 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
4991 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
4992 {
4993 r = &sel.r;
4994 }
4995 else
4996 {
4997 /* For ancient kernels, fall back to G_CROP */
4998 memset (&crop, 0, sizeof (struct v4l2_crop));
4999 crop.type = v4l2object->type;
5000 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
5001 r = &crop.c;
5002 }
5003
5004 if (r)
5005 {
bo.xiao857b8682024-09-12 16:40:32 +08005006 align.padding_left = r->left;
5007 align.padding_top = r->top;
5008 align.padding_right = width - r->width - r->left;
5009 align.padding_bottom = height - r->height - r->top;
5010 width = r->width;
5011 height = r->height;
5012
5013 if (self->v4l2output->dw_mode >= 0 && self->v4l2output->dw_mode != VDEC_DW_NO_AFBC)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005014 {
bo.xiao857b8682024-09-12 16:40:32 +08005015 width = (width/2) *2; // align for dw
5016 height = (height/2) *2; // align for dw
xuesong.jiangae1548e2022-05-06 16:38:46 +08005017 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005018
bo.xiao857b8682024-09-12 16:40:32 +08005019 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY)
5020 height = width = 64; //because driver return src w,h when AFBC_ONLY
5021 }
5022 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "final w:%d, h:%d", width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005023
bo.xiao857b8682024-09-12 16:40:32 +08005024 gst_video_info_set_format(info, format, width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005025
bo.xiao857b8682024-09-12 16:40:32 +08005026 switch (fmt.fmt.pix.field)
5027 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005028 case V4L2_FIELD_ANY:
5029 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08005030 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
5031 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005032 case V4L2_FIELD_INTERLACED:
5033 case V4L2_FIELD_INTERLACED_TB:
5034 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08005035 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
5036 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005037 default:
bo.xiao857b8682024-09-12 16:40:32 +08005038 goto unsupported_field;
5039 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005040
bo.xiao857b8682024-09-12 16:40:32 +08005041 gst_aml_v4l2_object_get_colorspace(&fmt, &info->colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005042
bo.xiao857b8682024-09-12 16:40:32 +08005043 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &fmt, info, &align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005044
bo.xiao857b8682024-09-12 16:40:32 +08005045 if (v4l2object->par)
5046 {
5047 width = gst_value_get_fraction_numerator(v4l2object->par);
5048 height = gst_value_get_fraction_denominator(v4l2object->par);
5049 pixelAspectRatio = (gdouble)width/(gdouble)height;
5050 }
sheng.liu641aa422023-12-26 07:05:59 +00005051
bo.xiao857b8682024-09-12 16:40:32 +08005052 if (!v4l2object->par || pixelAspectRatio == 1.0)
5053 {
5054 memset(&cropcap, 0, sizeof(cropcap));
5055 width= height= 1;
5056 cropcap.type = v4l2object->type;
5057 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) >= 0)
5058 {
5059 width= cropcap.pixelaspect.denominator;
5060 height= cropcap.pixelaspect.numerator;
5061 GST_DEBUG("cropcap: pixel aspect ratio %d:%d", width, height);
5062 if ( !width || !height )
5063 {
5064 GST_DEBUG("force pixel aspect of 1:1");
5065 width= height= 1;
5066 }
5067 }
5068 }
sheng.liudb26f7d2024-01-22 11:24:23 +00005069
bo.xiao857b8682024-09-12 16:40:32 +08005070 GST_VIDEO_INFO_PAR_N(info) = width;
5071 GST_VIDEO_INFO_PAR_D(info) = height;
sheng.liud9027ca2024-01-24 09:21:49 +00005072
bo.xiao857b8682024-09-12 16:40:32 +08005073 if (v4l2object->fps)
5074 {
5075 GST_VIDEO_INFO_FPS_N(info) = gst_value_get_fraction_numerator(v4l2object->fps);
5076 GST_VIDEO_INFO_FPS_D(info) = gst_value_get_fraction_denominator(v4l2object->fps);
5077 }
5078 /* Shall we setup the pool ? */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005079
bo.xiao857b8682024-09-12 16:40:32 +08005080 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005081
5082get_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005083 {
5084 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5085 (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005086 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005087 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005088invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08005089 {
5090 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5091 (_("Video device returned invalid dimensions.")),
5092 ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
5093 fmt.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005094 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005095 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005096unsupported_field:
bo.xiao857b8682024-09-12 16:40:32 +08005097 {
5098 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5099 (_("Video device uses an unsupported interlacing method.")),
5100 ("V4L2 field type %d not supported", fmt.fmt.pix.field));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005101 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005102 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005103unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08005104 {
5105 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5106 (_("Video device uses an unsupported pixel format.")),
5107 ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
5108 GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005109 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005110 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005111}
5112
5113gboolean
5114gst_aml_v4l2_object_set_crop(GstAmlV4l2Object *obj)
5115{
bo.xiao857b8682024-09-12 16:40:32 +08005116 struct v4l2_selection sel = { 0 };
5117 struct v4l2_crop crop = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005118
bo.xiao857b8682024-09-12 16:40:32 +08005119 sel.type = obj->type;
5120 sel.target = V4L2_SEL_TGT_CROP;
5121 sel.flags = 0;
5122 sel.r.left = obj->align.padding_left;
5123 sel.r.top = obj->align.padding_top;
5124 sel.r.width = obj->info.width;
5125 sel.r.height = obj->info.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005126
bo.xiao857b8682024-09-12 16:40:32 +08005127 crop.type = obj->type;
5128 crop.c = sel.r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005129
bo.xiao857b8682024-09-12 16:40:32 +08005130 if (obj->align.padding_left + obj->align.padding_top +
5131 obj->align.padding_right + obj->align.padding_bottom ==
5132 0)
5133 {
5134 GST_DEBUG_OBJECT(obj->dbg_obj, "no cropping needed");
5135 return TRUE;
5136 }
5137
5138 GST_DEBUG_OBJECT (obj->dbg_obj,
5139 "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5140 crop.c.width, crop.c.height);
5141
5142 if (obj->ioctl (obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0)
5143 {
5144 if (errno != ENOTTY)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005145 {
bo.xiao857b8682024-09-12 16:40:32 +08005146 GST_WARNING_OBJECT (obj->dbg_obj,
5147 "Failed to set crop rectangle with VIDIOC_S_SELECTION: %s",
5148 g_strerror (errno));
5149 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005150 }
bo.xiao857b8682024-09-12 16:40:32 +08005151 else
xuesong.jiangae1548e2022-05-06 16:38:46 +08005152 {
bo.xiao857b8682024-09-12 16:40:32 +08005153 if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0)
5154 {
5155 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_S_CROP failed");
5156 return FALSE;
5157 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005158
bo.xiao857b8682024-09-12 16:40:32 +08005159 if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0)
5160 {
5161 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_G_CROP failed");
5162 return FALSE;
5163 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005164
bo.xiao857b8682024-09-12 16:40:32 +08005165 sel.r = crop.c;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005166 }
bo.xiao857b8682024-09-12 16:40:32 +08005167 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005168
bo.xiao857b8682024-09-12 16:40:32 +08005169 GST_DEBUG_OBJECT (obj->dbg_obj,
5170 "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5171 crop.c.width, crop.c.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005172
bo.xiao857b8682024-09-12 16:40:32 +08005173 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005174}
5175
5176gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005177gst_aml_v4l2_object_caps_equal (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005178{
bo.xiao857b8682024-09-12 16:40:32 +08005179 GstStructure *config;
5180 GstCaps *oldcaps;
5181 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005182
bo.xiao857b8682024-09-12 16:40:32 +08005183 if (!v4l2object->pool)
5184 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005185
bo.xiao857b8682024-09-12 16:40:32 +08005186 config = gst_buffer_pool_get_config(v4l2object->pool);
5187 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005188
bo.xiao857b8682024-09-12 16:40:32 +08005189 ret = oldcaps && gst_caps_is_equal (caps, oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005190
bo.xiao857b8682024-09-12 16:40:32 +08005191 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005192
bo.xiao857b8682024-09-12 16:40:32 +08005193 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005194}
5195
5196gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005197gst_aml_v4l2_object_caps_is_subset (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005198{
bo.xiao857b8682024-09-12 16:40:32 +08005199 GstStructure *config;
5200 GstCaps *oldcaps;
5201 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005202
bo.xiao857b8682024-09-12 16:40:32 +08005203 if (!v4l2object->pool)
5204 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005205
bo.xiao857b8682024-09-12 16:40:32 +08005206 config = gst_buffer_pool_get_config(v4l2object->pool);
5207 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005208
bo.xiao857b8682024-09-12 16:40:32 +08005209 ret = oldcaps && gst_caps_is_subset (oldcaps, caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005210
bo.xiao857b8682024-09-12 16:40:32 +08005211 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005212
bo.xiao857b8682024-09-12 16:40:32 +08005213 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005214}
5215
5216GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005217gst_aml_v4l2_object_get_current_caps (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005218{
bo.xiao857b8682024-09-12 16:40:32 +08005219 GstStructure *config;
5220 GstCaps *oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005221
bo.xiao857b8682024-09-12 16:40:32 +08005222 if (!v4l2object->pool)
5223 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005224
bo.xiao857b8682024-09-12 16:40:32 +08005225 config = gst_buffer_pool_get_config(v4l2object->pool);
5226 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005227
bo.xiao857b8682024-09-12 16:40:32 +08005228 if (oldcaps)
5229 gst_caps_ref (oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005230
bo.xiao857b8682024-09-12 16:40:32 +08005231 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005232
bo.xiao857b8682024-09-12 16:40:32 +08005233 return oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005234}
5235
5236gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005237gst_aml_v4l2_object_flush_start(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005238{
bo.xiao857b8682024-09-12 16:40:32 +08005239 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005240
bo.xiao857b8682024-09-12 16:40:32 +08005241 GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005242
bo.xiao857b8682024-09-12 16:40:32 +08005243 gst_poll_set_flushing (v4l2object->poll, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005244
bo.xiao857b8682024-09-12 16:40:32 +08005245 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5246 gst_buffer_pool_set_flushing(v4l2object->pool, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005247
bo.xiao857b8682024-09-12 16:40:32 +08005248 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005249}
5250
5251gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005252gst_aml_v4l2_object_flush_stop(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005253{
bo.xiao857b8682024-09-12 16:40:32 +08005254 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005255
bo.xiao857b8682024-09-12 16:40:32 +08005256 GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005257
bo.xiao857b8682024-09-12 16:40:32 +08005258 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5259 gst_buffer_pool_set_flushing(v4l2object->pool, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005260
bo.xiao857b8682024-09-12 16:40:32 +08005261 gst_poll_set_flushing(v4l2object->poll, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005262
bo.xiao857b8682024-09-12 16:40:32 +08005263 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005264}
5265
5266gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005267gst_aml_v4l2_object_stop (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005268{
bo.xiao857b8682024-09-12 16:40:32 +08005269 GstAmlV4l2BufferPool *bpool = GST_AML_V4L2_BUFFER_POOL(v4l2object->pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005270
bo.xiao857b8682024-09-12 16:40:32 +08005271 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stopping");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005272
bo.xiao857b8682024-09-12 16:40:32 +08005273 if (!GST_AML_V4L2_IS_OPEN (v4l2object))
5274 goto done;
5275 if (!GST_AML_V4L2_IS_ACTIVE (v4l2object))
5276 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005277
bo.xiao857b8682024-09-12 16:40:32 +08005278 if (bpool && bpool->other_pool) /* jxsdbg for resolution switch */
5279 {
5280 if (v4l2object->old_other_pool)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005281 {
bo.xiao857b8682024-09-12 16:40:32 +08005282 /* this case indicate 1st switch did not wait all old pool buf recycle and 2nd switch is coming.
5283 so save 1st old pool */
5284 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching occurs during last switching buf recycle flow");
5285 v4l2object->old_old_other_pool = v4l2object->old_other_pool;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005286 }
5287
bo.xiao857b8682024-09-12 16:40:32 +08005288 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching flow, ref old drmbufferpool");
5289 v4l2object->old_other_pool = bpool->other_pool;
5290 gst_object_ref(v4l2object->old_other_pool);
5291 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005292
bo.xiao857b8682024-09-12 16:40:32 +08005293 if (v4l2object->pool)
5294 {
5295 if (!gst_aml_v4l2_buffer_pool_orphan(&v4l2object->pool))
5296 {
5297 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "deactivating pool");
5298 gst_buffer_pool_set_active(v4l2object->pool, FALSE);
5299 gst_object_unref(v4l2object->pool);
5300 }
5301 v4l2object->pool = NULL;
5302 }
5303
5304 GST_AML_V4L2_SET_INACTIVE (v4l2object);
5305 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "stopped");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005306done:
bo.xiao857b8682024-09-12 16:40:32 +08005307 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005308}
5309
5310GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005311gst_aml_v4l2_object_probe_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005312{
bo.xiao857b8682024-09-12 16:40:32 +08005313 GstCaps *ret;
5314 GSList *walk;
5315 GSList *formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005316
bo.xiao857b8682024-09-12 16:40:32 +08005317 GST_INFO_OBJECT(v4l2object->dbg_obj, "filter caps: %" GST_PTR_FORMAT, filter);
5318 formats = gst_aml_v4l2_object_get_format_list (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005319
bo.xiao857b8682024-09-12 16:40:32 +08005320 ret = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005321
sheng.liu641aa422023-12-26 07:05:59 +00005322// At this time, decoder will return defult aspect, and it is not usful.
5323// so, do not probe cropcap at this time and do this action after decoding.
5324#if 0
bo.xiao857b8682024-09-12 16:40:32 +08005325 if (v4l2object->keep_aspect && !v4l2object->par)
5326 {
5327 struct v4l2_cropcap cropcap;
5328
5329 memset (&cropcap, 0, sizeof (cropcap));
5330
5331 cropcap.type = v4l2object->type;
5332 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005333 {
bo.xiao857b8682024-09-12 16:40:32 +08005334 if (errno != ENOTTY)
5335 GST_WARNING_OBJECT (v4l2object->dbg_obj,
5336 "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
5337 g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005338 }
bo.xiao857b8682024-09-12 16:40:32 +08005339 else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator)
5340 {
5341 v4l2object->par = g_new0 (GValue, 1);
5342 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
5343 gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
5344 cropcap.pixelaspect.denominator);
5345 }
5346 }
sheng.liu641aa422023-12-26 07:05:59 +00005347#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08005348
bo.xiao857b8682024-09-12 16:40:32 +08005349 for (walk = formats; walk; walk = walk->next)
5350 {
5351 struct v4l2_fmtdesc *format;
5352 GstStructure *template;
5353 GstCaps *tmp, *tmp2;
5354
5355 format = (struct v4l2_fmtdesc *) walk->data;
5356
5357 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (format->pixelformat);
5358
5359 if (!template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005360 {
bo.xiao857b8682024-09-12 16:40:32 +08005361 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
5362 "unknown format %" GST_FOURCC_FORMAT,
5363 GST_FOURCC_ARGS (format->pixelformat));
5364 continue;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005365 }
5366
bo.xiao857b8682024-09-12 16:40:32 +08005367 /* If we have a filter, check if we need to probe this format or not */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005368 if (filter)
5369 {
bo.xiao857b8682024-09-12 16:40:32 +08005370 GstCaps *format_caps = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005371
bo.xiao857b8682024-09-12 16:40:32 +08005372 gst_caps_append_structure (format_caps, gst_structure_copy (template));
5373 GST_INFO_OBJECT(v4l2object->dbg_obj, "format_caps: %" GST_PTR_FORMAT, format_caps);
5374
5375 if (!gst_caps_can_intersect (format_caps, filter))
5376 {
5377 gst_caps_unref (format_caps);
5378 gst_structure_free (template);
5379 continue;
5380 }
5381
5382 gst_caps_unref (format_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005383 }
5384
bo.xiao857b8682024-09-12 16:40:32 +08005385 tmp = gst_aml_v4l2_object_probe_caps_for_format (v4l2object,
5386 format->pixelformat, template);
5387 GST_INFO_OBJECT(v4l2object->dbg_obj, "tmp caps: %" GST_PTR_FORMAT, tmp);
5388
5389 if (tmp)
xuesong.jiang22a9b112023-05-24 09:01:59 +00005390 {
bo.xiao857b8682024-09-12 16:40:32 +08005391 tmp2 = gst_caps_copy(tmp);
5392 gst_caps_set_features_simple(tmp2, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
5393 gst_caps_append (ret, tmp);
5394 gst_caps_append (ret, tmp2);
xuesong.jiang22a9b112023-05-24 09:01:59 +00005395 }
5396
bo.xiao857b8682024-09-12 16:40:32 +08005397 gst_structure_free (template);
5398 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005399
bo.xiao857b8682024-09-12 16:40:32 +08005400 if (filter)
5401 {
5402 GstCaps *tmp;
5403
5404 tmp = ret;
5405 ret = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
5406 gst_caps_unref (tmp);
5407 }
5408
5409 if (v4l2object->stream_mode)
5410 {
5411 GST_INFO_OBJECT(v4l2object->dbg_obj, "ret caps: %" GST_PTR_FORMAT, ret);
5412 for (guint i = 0; i < gst_caps_get_size(ret); i++)
5413 {
5414 GstStructure *s = gst_caps_get_structure(ret, i);
5415 if (s)
5416 gst_structure_remove_field(s, "alignment");
5417
5418 GST_DEBUG("i:%d, s:%p", i, s);
5419 }
5420 GST_INFO_OBJECT(v4l2object->dbg_obj, "new ret caps: %" GST_PTR_FORMAT, ret);
5421 }
5422
5423 GST_INFO_OBJECT (v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
5424
5425 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005426}
5427
5428GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005429gst_aml_v4l2_object_get_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005430{
bo.xiao857b8682024-09-12 16:40:32 +08005431 GstCaps *ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005432
bo.xiao857b8682024-09-12 16:40:32 +08005433 if (v4l2object->probed_caps == NULL)
5434 v4l2object->probed_caps = gst_aml_v4l2_object_probe_caps (v4l2object, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005435
bo.xiao857b8682024-09-12 16:40:32 +08005436 if (filter)
5437 {
5438 ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
5439 GST_CAPS_INTERSECT_FIRST);
5440 }
5441 else
5442 {
5443 ret = gst_caps_ref (v4l2object->probed_caps);
5444 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005445
bo.xiao857b8682024-09-12 16:40:32 +08005446 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005447}
5448
5449gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005450gst_aml_v4l2_object_decide_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005451{
bo.xiao857b8682024-09-12 16:40:32 +08005452 GstCaps *caps;
5453 GstBufferPool *pool = NULL, *other_pool = NULL;
5454 GstStructure *config;
5455 guint size, min, max, own_min = 0;
5456 gboolean update;
5457 gboolean has_video_meta;
5458 gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
5459 GstAllocator *allocator = NULL;
5460 GstAllocationParams params = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005461
bo.xiao857b8682024-09-12 16:40:32 +08005462 GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005463
bo.xiao857b8682024-09-12 16:40:32 +08005464 g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
5465 obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005466
bo.xiao857b8682024-09-12 16:40:32 +08005467 gst_query_parse_allocation (query, &caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005468
bo.xiao857b8682024-09-12 16:40:32 +08005469 if (obj->pool == NULL)
5470 {
5471 if (!gst_aml_v4l2_object_setup_pool (obj, caps))
5472 goto pool_failed;
5473 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005474
bo.xiao857b8682024-09-12 16:40:32 +08005475 if (gst_query_get_n_allocation_params (query) > 0)
5476 gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005477
bo.xiao857b8682024-09-12 16:40:32 +08005478 if (gst_query_get_n_allocation_pools (query) > 0)
5479 {
5480 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
5481 update = TRUE;
5482 }
5483 else
5484 {
5485 pool = NULL;
5486 min = max = 0;
5487 size = 0;
5488 update = FALSE;
5489 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005490
bo.xiao857b8682024-09-12 16:40:32 +08005491 GST_DEBUG_OBJECT (obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%"
5492 GST_PTR_FORMAT, size, min, max, pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005493
bo.xiao857b8682024-09-12 16:40:32 +08005494 has_video_meta =
5495 gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005496
bo.xiao857b8682024-09-12 16:40:32 +08005497 can_share_own_pool = (has_video_meta || !obj->need_video_meta);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005498
bo.xiao857b8682024-09-12 16:40:32 +08005499 gst_aml_v4l2_get_driver_min_buffers (obj);
5500 /* We can't share our own pool, if it exceed V4L2 capacity */
5501 if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
5502 can_share_own_pool = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005503
bo.xiao857b8682024-09-12 16:40:32 +08005504 /* select a pool */
5505 switch (obj->mode)
5506 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005507 case GST_V4L2_IO_RW:
bo.xiao857b8682024-09-12 16:40:32 +08005508 if (pool)
5509 {
5510 /* in READ/WRITE mode, prefer a downstream pool because our own pool
5511 * doesn't help much, we have to write to it as well */
5512 GST_DEBUG_OBJECT (obj->dbg_obj,
5513 "read/write mode: using downstream pool");
5514 /* use the bigest size, when we use our own pool we can't really do any
5515 * other size than what the hardware gives us but for downstream pools
5516 * we can try */
5517 size = MAX (size, obj->info.size);
5518 }
5519 else if (can_share_own_pool)
5520 {
5521 /* no downstream pool, use our own then */
5522 GST_DEBUG_OBJECT (obj->dbg_obj,
5523 "read/write mode: no downstream pool, using our own");
5524 pool = gst_object_ref(obj->pool);
5525 size = obj->info.size;
5526 pushing_from_our_pool = TRUE;
5527 }
5528 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005529
5530 case GST_V4L2_IO_USERPTR:
5531 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005532 /* in importing mode, prefer our own pool, and pass the other pool to
5533 * our own, so it can serve itself */
5534 if (pool == NULL)
5535 goto no_downstream_pool;
5536 gst_aml_v4l2_buffer_pool_set_other_pool(GST_AML_V4L2_BUFFER_POOL(obj->pool), pool);
5537 other_pool = pool;
5538 gst_object_unref (pool);
5539 pool = gst_object_ref(obj->pool);
5540 size = obj->info.size;
5541 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005542
5543 case GST_V4L2_IO_MMAP:
5544 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005545 /* in streaming mode, prefer our own pool */
5546 /* Check if we can use it ... */
5547 if (can_share_own_pool)
5548 {
5549 if (pool)
5550 gst_object_unref (pool);
5551 pool = gst_object_ref (obj->pool);
5552 size = obj->info.size;
5553 GST_DEBUG_OBJECT (obj->dbg_obj,
5554 "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
5555 pushing_from_our_pool = TRUE;
5556 }
5557 else if (pool)
5558 {
5559 GST_DEBUG_OBJECT (obj->dbg_obj,
5560 "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
5561 pool);
5562 }
5563 else
5564 {
5565 GST_DEBUG_OBJECT (obj->dbg_obj,
5566 "streaming mode: no usable pool, copying to generic pool");
5567 size = MAX (size, obj->info.size);
5568 }
5569 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005570 case GST_V4L2_IO_AUTO:
5571 default:
bo.xiao857b8682024-09-12 16:40:32 +08005572 GST_WARNING_OBJECT (obj->dbg_obj, "unhandled mode");
5573 break;
5574 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005575
bo.xiao857b8682024-09-12 16:40:32 +08005576 if (size == 0)
5577 goto no_size;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005578
bo.xiao857b8682024-09-12 16:40:32 +08005579 /* If pushing from our own pool, configure it with queried minimum,
5580 * otherwise use the minimum required */
5581 if (pushing_from_our_pool)
5582 {
5583 /* When pushing from our own pool, we need what downstream one, to be able
5584 * to fill the pipeline, the minimum required to decoder according to the
5585 * driver and 2 more, so we don't endup up with everything downstream or
5586 * held by the decoder. We account 2 buffers for v4l2 so when one is being
5587 * pushed downstream the other one can already be queued for the next
5588 * frame. */
5589 own_min = min + obj->min_buffers + 2;
5590
5591 /* If no allocation parameters where provided, allow for a little more
5592 * buffers and enable copy threshold */
5593 if (!update)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005594 {
bo.xiao857b8682024-09-12 16:40:32 +08005595 own_min += 2;
5596 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5597 TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005598 }
5599 else
5600 {
bo.xiao857b8682024-09-12 16:40:32 +08005601 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5602 FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005603 }
5604
bo.xiao857b8682024-09-12 16:40:32 +08005605 }
5606 else
5607 {
5608 min = obj->min_buffers;
5609 max = min;
5610 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005611
bo.xiao857b8682024-09-12 16:40:32 +08005612 /* Request a bigger max, if one was suggested but it's too small */
5613 if (max != 0)
5614 max = MAX (min, max);
5615
5616 /* First step, configure our own pool */
5617 config = gst_buffer_pool_get_config(obj->pool);
5618
5619 if (obj->need_video_meta || has_video_meta)
5620 {
5621 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5622 gst_buffer_pool_config_add_option (config,
5623 GST_BUFFER_POOL_OPTION_VIDEO_META);
5624 }
5625
5626 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5627 gst_buffer_pool_config_set_params(config, caps, size, min, max);
5628
5629 GST_DEBUG_OBJECT (obj->dbg_obj, "setting own pool config to %"
5630 GST_PTR_FORMAT, config);
5631
5632 /* Our pool often need to adjust the value */
5633 if (!gst_buffer_pool_set_config (obj->pool, config))
5634 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005635 config = gst_buffer_pool_get_config(obj->pool);
5636
bo.xiao857b8682024-09-12 16:40:32 +08005637 GST_DEBUG_OBJECT (obj->dbg_obj, "own pool config changed to %"
5638 GST_PTR_FORMAT, config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005639
bo.xiao857b8682024-09-12 16:40:32 +08005640 /* our pool will adjust the maximum buffer, which we are fine with */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005641 if (!gst_buffer_pool_set_config(obj->pool, config))
bo.xiao857b8682024-09-12 16:40:32 +08005642 goto config_failed;
5643 }
5644
5645 /* Now configure the other pool if different */
5646 if (obj->pool != pool)
5647 other_pool = pool;
5648
5649 if (other_pool)
5650 {
5651 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)obj->element;
5652 guint other_min = min;
5653 guint other_max = max;
5654
5655 if (obj->old_other_pool || obj->old_old_other_pool) //jxsdbg for switching
5656 {
5657 obj->outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
5658 if (obj->outstanding_buf_num > 0) {
5659 if (obj->outstanding_buf_num >= obj->min_buffers)
5660 {
5661 other_min = 1;
5662 }
5663 else
5664 {
5665 other_min = other_max = obj->min_buffers - obj->outstanding_buf_num;
5666 }
5667 }
5668 GST_DEBUG_OBJECT(obj, "oop:%p, ooop:%p, outstanding buf num:%d, set min, max to %d,%d",
5669 obj->old_other_pool, obj->old_old_other_pool,
5670 obj->outstanding_buf_num, other_min, other_max);
5671 }
5672
5673 if (self->is_secure_path)
5674 {
5675 params.flags |= GST_MEMORY_FLAG_LAST << 1; // in drmallocator GST_MEMORY_FLAG_LAST << 1 represent GST_MEMORY_FLAG_SECURE
5676 GST_DEBUG_OBJECT(obj, "set secure flag for drmbufferpool flag:0x%x", params.flags);
5677 }
5678 config = gst_buffer_pool_get_config (other_pool);
5679 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5680 gst_buffer_pool_config_set_params (config, caps, size, other_min, other_max);
5681 gst_buffer_pool_config_set_video_alignment(config, &obj->align);
5682
5683 GST_DEBUG_OBJECT (obj->dbg_obj, "setting other pool config to %"
5684 GST_PTR_FORMAT, config);
5685
5686 /* if downstream supports video metadata, add this to the pool config */
5687 if (has_video_meta)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005688 {
bo.xiao857b8682024-09-12 16:40:32 +08005689 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5690 gst_buffer_pool_config_add_option (config,
5691 GST_BUFFER_POOL_OPTION_VIDEO_META);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005692 }
5693
bo.xiao857b8682024-09-12 16:40:32 +08005694 if (!gst_buffer_pool_set_config (other_pool, config))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005695 {
bo.xiao857b8682024-09-12 16:40:32 +08005696 config = gst_buffer_pool_get_config (other_pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005697
bo.xiao857b8682024-09-12 16:40:32 +08005698 if (!gst_buffer_pool_config_validate_params (config, caps, size, min,
5699 max))
5700 {
5701 gst_structure_free (config);
5702 goto config_failed;
5703 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005704
bo.xiao857b8682024-09-12 16:40:32 +08005705 if (!gst_buffer_pool_set_config (other_pool, config))
5706 goto config_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005707 }
bo.xiao857b8682024-09-12 16:40:32 +08005708 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005709
bo.xiao857b8682024-09-12 16:40:32 +08005710 if (pool)
5711 {
5712 /* For simplicity, simply read back the active configuration, so our base
5713 * class get the right information */
5714 config = gst_buffer_pool_get_config (pool);
5715 gst_buffer_pool_config_get_params (config, NULL, &size, &min, &max);
5716 gst_structure_free (config);
5717 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005718
bo.xiao857b8682024-09-12 16:40:32 +08005719 if (update)
5720 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
5721 else
5722 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005723
bo.xiao857b8682024-09-12 16:40:32 +08005724 if (allocator)
5725 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005726
bo.xiao857b8682024-09-12 16:40:32 +08005727 if (pool)
5728 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005729
bo.xiao857b8682024-09-12 16:40:32 +08005730 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005731
5732pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005733 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005734 /* setup_pool already send the error */
5735 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005736 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005737config_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005738 {
5739 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5740 (_("Failed to configure internal buffer pool.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005741 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005742 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005743no_size:
bo.xiao857b8682024-09-12 16:40:32 +08005744 {
5745 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5746 (_("Video device did not suggest any buffer size.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005747 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005748 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005749cleanup:
bo.xiao857b8682024-09-12 16:40:32 +08005750 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005751 if (allocator)
bo.xiao857b8682024-09-12 16:40:32 +08005752 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005753
5754 if (pool)
bo.xiao857b8682024-09-12 16:40:32 +08005755 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005756 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005757 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005758no_downstream_pool:
bo.xiao857b8682024-09-12 16:40:32 +08005759 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005760 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5761 (_("No downstream pool to import from.")),
5762 ("When importing DMABUF or USERPTR, we need a pool to import from"));
5763 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005764 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005765}
5766
5767gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005768gst_aml_v4l2_object_propose_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005769{
bo.xiao857b8682024-09-12 16:40:32 +08005770 GstBufferPool *pool = NULL;
5771 /* we need at least 2 buffers to operate */
5772 guint size, min, max;
5773 GstCaps *caps;
5774 gboolean need_pool;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005775
bo.xiao857b8682024-09-12 16:40:32 +08005776 /* Set defaults allocation parameters */
5777 size = obj->info.size;
5778 min = GST_AML_V4L2_MIN_BUFFERS;
5779 max = VIDEO_MAX_FRAME;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005780
bo.xiao857b8682024-09-12 16:40:32 +08005781 gst_query_parse_allocation (query, &caps, &need_pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005782
bo.xiao857b8682024-09-12 16:40:32 +08005783 if (caps == NULL)
5784 goto no_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005785
bo.xiao857b8682024-09-12 16:40:32 +08005786 switch (obj->mode)
5787 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005788 case GST_V4L2_IO_MMAP:
5789 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005790 if ((pool = obj->pool))
5791 gst_object_ref(pool);
5792 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005793 default:
bo.xiao857b8682024-09-12 16:40:32 +08005794 pool = NULL;
5795 break;
5796 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005797
bo.xiao857b8682024-09-12 16:40:32 +08005798 if (pool != NULL)
5799 {
5800 GstCaps *pcaps;
5801 GstStructure *config;
5802
5803 /* we had a pool, check caps */
5804 config = gst_buffer_pool_get_config (pool);
5805 gst_buffer_pool_config_get_params (config, &pcaps, NULL, NULL, NULL);
5806
5807 GST_DEBUG_OBJECT (obj->dbg_obj,
5808 "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
5809 if (!gst_caps_is_equal (caps, pcaps))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005810 {
bo.xiao857b8682024-09-12 16:40:32 +08005811 gst_structure_free (config);
5812 gst_object_unref (pool);
5813 goto different_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005814 }
bo.xiao857b8682024-09-12 16:40:32 +08005815 gst_structure_free (config);
5816 }
5817 gst_aml_v4l2_get_driver_min_buffers (obj);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005818
bo.xiao857b8682024-09-12 16:40:32 +08005819 min = MAX(obj->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005820
bo.xiao857b8682024-09-12 16:40:32 +08005821 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005822
bo.xiao857b8682024-09-12 16:40:32 +08005823 /* we also support various metadata */
5824 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005825
bo.xiao857b8682024-09-12 16:40:32 +08005826 if (pool)
5827 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005828
bo.xiao857b8682024-09-12 16:40:32 +08005829 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005830
bo.xiao857b8682024-09-12 16:40:32 +08005831 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005832no_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005833 {
5834 GST_DEBUG_OBJECT (obj->dbg_obj, "no caps specified");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005835 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005836 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005837different_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005838 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005839 /* different caps, we can't use this pool */
bo.xiao857b8682024-09-12 16:40:32 +08005840 GST_DEBUG_OBJECT (obj->dbg_obj, "pool has different caps");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005841 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005842 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005843}
5844
5845gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005846gst_aml_v4l2_object_try_import (GstAmlV4l2Object * obj, GstBuffer * buffer)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005847{
bo.xiao857b8682024-09-12 16:40:32 +08005848 GstVideoMeta *vmeta;
5849 guint n_mem = gst_buffer_n_memory (buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005850
bo.xiao857b8682024-09-12 16:40:32 +08005851 /* only import if requested */
5852 switch (obj->mode)
5853 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005854 case GST_V4L2_IO_USERPTR:
5855 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005856 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005857 default:
bo.xiao857b8682024-09-12 16:40:32 +08005858 GST_DEBUG_OBJECT (obj->dbg_obj,
5859 "The io-mode does not enable importation");
5860 return FALSE;
5861 }
5862
5863 vmeta = gst_buffer_get_video_meta (buffer);
5864 if (!vmeta && obj->need_video_meta)
5865 {
5866 GST_DEBUG_OBJECT (obj->dbg_obj, "Downstream buffer uses standard "
5867 "stride/offset while the driver does not.");
5868 return FALSE;
5869 }
5870
5871 /* we need matching strides/offsets and size */
5872 if (vmeta)
5873 {
5874 guint p;
5875 gboolean need_fmt_update = FALSE;
5876
5877 if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES(&obj->info))
5878 {
5879 GST_WARNING_OBJECT(obj->dbg_obj,
5880 "Cannot import buffers with different number planes");
5881 return FALSE;
5882 }
5883
5884 for (p = 0; p < vmeta->n_planes; p++)
5885 {
5886 if (vmeta->stride[p] < obj->info.stride[p])
5887 {
5888 GST_DEBUG_OBJECT(obj->dbg_obj,
5889 "Not importing as remote stride %i is smaller then %i on plane %u",
5890 vmeta->stride[p], obj->info.stride[p], p);
5891 return FALSE;
5892 }
5893 else if (vmeta->stride[p] > obj->info.stride[p])
5894 {
5895 need_fmt_update = TRUE;
5896 }
5897
5898 if (vmeta->offset[p] < obj->info.offset[p])
5899 {
5900 GST_DEBUG_OBJECT(obj->dbg_obj,
5901 "Not importing as offset %" G_GSIZE_FORMAT
5902 " is smaller then %" G_GSIZE_FORMAT " on plane %u",
5903 vmeta->offset[p], obj->info.offset[p], p);
5904 return FALSE;
5905 }
5906 else if (vmeta->offset[p] > obj->info.offset[p])
5907 {
5908 need_fmt_update = TRUE;
5909 }
5910 }
5911
5912 if (need_fmt_update)
5913 {
5914 struct v4l2_format format;
5915 gint wanted_stride[GST_VIDEO_MAX_PLANES] = {
5916 0,
5917 };
5918
5919 format = obj->format;
5920
5921 /* update the current format with the stride we want to import from */
5922 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5923 {
5924 guint i;
5925
5926 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted strides:");
5927
5928 for (i = 0; i < obj->n_v4l2_planes; i++)
5929 {
5930 gint stride = vmeta->stride[i];
5931
5932 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5933 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5934
5935 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
5936 wanted_stride[i] = stride;
5937 GST_DEBUG_OBJECT(obj->dbg_obj, " [%u] %i", i, wanted_stride[i]);
5938 }
5939 }
5940 else
5941 {
5942 gint stride = vmeta->stride[0];
5943
5944 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted stride: %i", stride);
5945
5946 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5947 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5948
5949 format.fmt.pix.bytesperline = stride;
5950 wanted_stride[0] = stride;
5951 }
5952
5953 if (obj->ioctl(obj->video_fd, VIDIOC_S_FMT, &format) < 0)
5954 {
5955 GST_WARNING_OBJECT(obj->dbg_obj,
5956 "Something went wrong trying to update current format: %s",
5957 g_strerror(errno));
5958 return FALSE;
5959 }
5960
5961 gst_aml_v4l2_object_save_format(obj, obj->fmtdesc, &format, &obj->info,
5962 &obj->align);
5963
5964 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5965 {
5966 guint i;
5967
5968 for (i = 0; i < obj->n_v4l2_planes; i++)
5969 {
5970 if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i])
5971 {
5972 GST_DEBUG_OBJECT(obj->dbg_obj,
5973 "[%i] Driver did not accept the new stride (wants %i, got %i)",
5974 i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
5975 wanted_stride[i]);
5976 return FALSE;
5977 }
5978 }
5979 }
5980 else
5981 {
5982 if (format.fmt.pix.bytesperline != wanted_stride[0])
5983 {
5984 GST_DEBUG_OBJECT(obj->dbg_obj,
5985 "Driver did not accept the new stride (wants %i, got %i)",
5986 format.fmt.pix.bytesperline, wanted_stride[0]);
5987 return FALSE;
5988 }
5989 }
5990 }
5991 }
5992
5993 /* we can always import single memory buffer, but otherwise we need the same
5994 * amount of memory object. */
5995 if (n_mem != 1 && n_mem != obj->n_v4l2_planes)
5996 {
5997 GST_DEBUG_OBJECT (obj->dbg_obj, "Can only import %i memory, "
5998 "buffers contains %u memory", obj->n_v4l2_planes, n_mem);
5999 return FALSE;
6000 }
6001
6002 /* For DMABuf importation we need DMABuf of course */
6003 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
6004 {
6005 guint i;
6006
6007 for (i = 0; i < n_mem; i++)
6008 {
6009 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
6010
6011 if (!gst_is_dmabuf_memory (mem))
6012 {
6013 GST_DEBUG_OBJECT (obj->dbg_obj, "Cannot import non-DMABuf memory.");
xuesong.jiangae1548e2022-05-06 16:38:46 +08006014 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08006015 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08006016 }
bo.xiao857b8682024-09-12 16:40:32 +08006017 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08006018
bo.xiao857b8682024-09-12 16:40:32 +08006019 /* for the remaining, only the kernel driver can tell */
6020 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006021}
6022
xuesong.jiang22a9b112023-05-24 09:01:59 +00006023static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl)
6024{
bo.xiao857b8682024-09-12 16:40:32 +08006025 int rc;
6026 struct v4l2_queryctrl queryctrl;
6027 struct v4l2_control control;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006028
bo.xiao857b8682024-09-12 16:40:32 +08006029 memset(&queryctrl, 0, sizeof(queryctrl));
6030 queryctrl.id = ctl;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006031
bo.xiao857b8682024-09-12 16:40:32 +08006032 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_QUERYCTRL, &queryctrl);
6033 if (rc == 0)
6034 {
6035 if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
6036 {
6037 memset(&control, 0, sizeof(control));
6038 control.id = ctl;
6039 control.value = 1;
6040 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6041 if (rc != 0)
6042 {
6043 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x fail rc %d", ctl, rc);
6044 return FALSE;
6045 }
6046 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x succ", ctl);
6047 return TRUE;
6048 }
6049 else
6050 {
6051 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "ctl:0x%x is disabled", ctl);
6052 return TRUE;
6053 }
6054 }
6055 else
6056 {
6057 GST_ERROR_OBJECT(v4l2object->dbg_obj, "VIDIOC_QUERYCTRL for 0x:%x fail", ctl);
6058 return FALSE;
6059 }
xuesong.jiang22a9b112023-05-24 09:01:59 +00006060}
6061
hanghang.luo7f403102024-07-04 10:33:01 +08006062gboolean gst_aml_v4l2_set_I_frame_mode(GstAmlV4l2Object *v4l2object)
6063{
bo.xiao857b8682024-09-12 16:40:32 +08006064 if (v4l2object->iframe_mode)
6065 {
6066 int rc;
6067 struct v4l2_control control;
6068 memset(&control, 0, sizeof(control));
6069 control.id = AML_V4L2_SET_I_FRAME;
6070 control.value = 1;
6071 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6072 if (rc != 0)
6073 {
6074 GST_ERROR_OBJECT(v4l2object->dbg_obj, "rc: %d", rc);
6075 return FALSE;
6076 }
6077 }
6078 GST_DEBUG("set I frame ok");
6079 return TRUE;
hanghang.luo7f403102024-07-04 10:33:01 +08006080}
xuesong.jiang22a9b112023-05-24 09:01:59 +00006081
xuesong.jiangae1548e2022-05-06 16:38:46 +08006082gboolean gst_aml_v4l2_set_drm_mode(GstAmlV4l2Object *v4l2object)
6083{
bo.xiao857b8682024-09-12 16:40:32 +08006084 /* On AmLogic, output obj use of GST_V4L2_IO_DMABUF_IMPORT implies secure memory */
6085 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT && v4l2object->secure_es)
6086 {
6087 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)v4l2object->element;
6088 self->is_secure_path = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006089
bo.xiao857b8682024-09-12 16:40:32 +08006090 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_DRMMODE))
6091 {
6092 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set succ");
6093 return TRUE;
6094 }
6095 else
6096 {
6097 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set fail");
6098 return FALSE;
6099 }
6100 }
6101 return TRUE;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006102}
6103
6104gboolean gst_aml_v4l2_set_stream_mode(GstAmlV4l2Object *v4l2object)
6105{
bo.xiao857b8682024-09-12 16:40:32 +08006106 if (v4l2object->stream_mode)
6107 {
6108 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_STREAM_MODE))
6109 {
6110 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set succ");
6111 return TRUE;
6112 }
6113 else
6114 {
6115 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set fail");
6116 return FALSE;
6117 }
6118 }
6119 else
6120 {
6121 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not stream mode, frame mode in configured by default");
6122 return TRUE;
6123 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006124}
6125
6126gint gst_aml_v4l2_object_get_outstanding_capture_buf_num(GstAmlV4l2Object *obj)
6127{
bo.xiao857b8682024-09-12 16:40:32 +08006128 gint ret = 0;
6129 gint count = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006130
bo.xiao857b8682024-09-12 16:40:32 +08006131 if (obj->old_other_pool)
6132 {
6133 count = gst_buffer_pool_get_outstanding_num(obj->old_other_pool);
6134 if (count)
6135 {
6136 ret += count;
6137 }
6138 else
6139 {
6140 gst_object_unref(obj->old_other_pool);
6141 obj->old_other_pool = NULL;
6142 }
6143 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006144
bo.xiao857b8682024-09-12 16:40:32 +08006145 count = 0;
6146 if (obj->old_old_other_pool)
6147 {
6148 count = gst_buffer_pool_get_outstanding_num(obj->old_old_other_pool);
6149 if (count)
6150 {
6151 ret += count;
6152 }
6153 else
6154 {
6155 gst_object_unref(obj->old_old_other_pool);
6156 obj->old_old_other_pool = NULL;
6157 }
6158 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006159
bo.xiao857b8682024-09-12 16:40:32 +08006160 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006161}