blob: 83ddc5f7f86886d39de033f641244c2c69ee0457 [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;
572 return v4l2object;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800573}
574
bo.xiao857b8682024-09-12 16:40:32 +0800575static gboolean gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800576
bo.xiao857b8682024-09-12 16:40:32 +0800577void
578gst_aml_v4l2_object_destroy (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800579{
bo.xiao857b8682024-09-12 16:40:32 +0800580 g_return_if_fail (v4l2object != NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800581
bo.xiao857b8682024-09-12 16:40:32 +0800582 g_free (v4l2object->videodev);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800583
bo.xiao857b8682024-09-12 16:40:32 +0800584 g_free (v4l2object->channel);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800585
bo.xiao857b8682024-09-12 16:40:32 +0800586 if (v4l2object->formats)
587 {
588 gst_aml_v4l2_object_clear_format_list (v4l2object);
589 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800590
bo.xiao857b8682024-09-12 16:40:32 +0800591 if (v4l2object->probed_caps)
592 {
593 gst_caps_unref (v4l2object->probed_caps);
594 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800595
bo.xiao857b8682024-09-12 16:40:32 +0800596 if (v4l2object->extra_controls)
597 {
598 gst_structure_free (v4l2object->extra_controls);
599 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800600
bo.xiao857b8682024-09-12 16:40:32 +0800601 gst_poll_free (v4l2object->poll);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800602
bo.xiao857b8682024-09-12 16:40:32 +0800603 g_free(v4l2object->dumpframefile);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800604
bo.xiao857b8682024-09-12 16:40:32 +0800605 /* jxsdbg resolution switching */
606 if (v4l2object->old_other_pool)
607 {
608 gst_object_unref(v4l2object->old_other_pool);
609 v4l2object->old_other_pool = NULL;
610 }
611 if (v4l2object->old_old_other_pool)
612 {
613 gst_object_unref(v4l2object->old_old_other_pool);
614 v4l2object->old_old_other_pool = NULL;
615 }
616 v4l2object->outstanding_buf_num = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800617
bo.xiao857b8682024-09-12 16:40:32 +0800618 g_free (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800619}
620
621static gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800622gst_aml_v4l2_object_clear_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800623{
bo.xiao857b8682024-09-12 16:40:32 +0800624 g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
625 g_slist_free (v4l2object->formats);
626 v4l2object->formats = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800627
bo.xiao857b8682024-09-12 16:40:32 +0800628 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800629}
630
631static gint
bo.xiao857b8682024-09-12 16:40:32 +0800632gst_aml_v4l2_object_prop_to_cid (guint prop_id)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800633{
bo.xiao857b8682024-09-12 16:40:32 +0800634 gint cid = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800635
bo.xiao857b8682024-09-12 16:40:32 +0800636 switch (prop_id)
637 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800638 case PROP_BRIGHTNESS:
bo.xiao857b8682024-09-12 16:40:32 +0800639 cid = V4L2_CID_BRIGHTNESS;
640 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800641 case PROP_CONTRAST:
bo.xiao857b8682024-09-12 16:40:32 +0800642 cid = V4L2_CID_CONTRAST;
643 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800644 case PROP_SATURATION:
bo.xiao857b8682024-09-12 16:40:32 +0800645 cid = V4L2_CID_SATURATION;
646 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800647 case PROP_HUE:
bo.xiao857b8682024-09-12 16:40:32 +0800648 cid = V4L2_CID_HUE;
649 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800650 default:
bo.xiao857b8682024-09-12 16:40:32 +0800651 GST_WARNING ("unmapped property id: %d", prop_id);
652 }
653 return cid;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800654}
655
656gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800657gst_aml_v4l2_object_set_property_helper (GstAmlV4l2Object * v4l2object,
658 guint prop_id, const GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800659{
bo.xiao857b8682024-09-12 16:40:32 +0800660 switch (prop_id)
661 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800662 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800663 g_free (v4l2object->videodev);
664 v4l2object->videodev = g_value_dup_string (value);
665 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800666 case PROP_BRIGHTNESS:
667 case PROP_CONTRAST:
668 case PROP_SATURATION:
669 case PROP_HUE:
670 {
bo.xiao857b8682024-09-12 16:40:32 +0800671 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800672
bo.xiao857b8682024-09-12 16:40:32 +0800673 if (cid != -1)
674 {
675 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800676 {
bo.xiao857b8682024-09-12 16:40:32 +0800677 gst_aml_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800678 }
bo.xiao857b8682024-09-12 16:40:32 +0800679 }
680 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800681 }
682 break;
683 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800684 v4l2object->req_mode = g_value_get_enum (value);
685 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800686 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800687 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
688 v4l2object->req_mode = g_value_get_enum (value);
689 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800690 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800691 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
692 v4l2object->req_mode = g_value_get_enum (value);
693 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800694 case PROP_EXTRA_CONTROLS:
695 {
bo.xiao857b8682024-09-12 16:40:32 +0800696 const GstStructure *s = gst_value_get_structure (value);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800697
bo.xiao857b8682024-09-12 16:40:32 +0800698 if (v4l2object->extra_controls)
699 gst_structure_free (v4l2object->extra_controls);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800700
bo.xiao857b8682024-09-12 16:40:32 +0800701 v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
702 if (GST_AML_V4L2_IS_OPEN (v4l2object))
703 gst_aml_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
704 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800705 }
706 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800707 if (v4l2object->par)
708 {
709 g_value_unset (v4l2object->par);
710 g_free (v4l2object->par);
711 }
712 v4l2object->par = g_new0 (GValue, 1);
713 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
714 if (!g_value_transform (value, v4l2object->par))
715 {
716 g_warning ("Could not transform string to aspect ratio");
717 gst_value_set_fraction (v4l2object->par, 1, 1);
718 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800719
sheng.liu641aa422023-12-26 07:05:59 +0000720 v4l2object->have_set_par = TRUE;
bo.xiao857b8682024-09-12 16:40:32 +0800721 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "set PAR to %d/%d",
722 gst_value_get_fraction_numerator (v4l2object->par),
723 gst_value_get_fraction_denominator (v4l2object->par));
724 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800725 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800726 v4l2object->keep_aspect = g_value_get_boolean (value);
727 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800728 case PROP_DUMP_FRAME_LOCATION:
729 g_free(v4l2object->dumpframefile);
730 v4l2object->dumpframefile = g_value_dup_string(value);
731 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000732 case PROP_STREAM_MODE:
733 v4l2object->stream_mode = g_value_get_boolean(value);
734 break;
hanghang.luoc54208e2023-09-22 02:43:54 +0000735 case PROP_LOW_LATENCY_MODE:
736 v4l2object->low_latency_mode = g_value_get_boolean(value);
737 GST_DEBUG_OBJECT(v4l2object, "set low latency: %d",v4l2object->low_latency_mode);
738 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800739 case PROP_CC_DATA:
740 v4l2object->enable_cc_data = g_value_get_boolean(value);
741 GST_DEBUG_OBJECT(v4l2object, "enable cc data: %d",v4l2object->enable_cc_data);
742 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800743 case PROP_ENABLE_NR:
744 v4l2object->enable_nr = g_value_get_boolean(value);
745 GST_DEBUG_OBJECT(v4l2object, "enable nr: %d",v4l2object->enable_nr);
746 break;
hanghang.luo75664712024-07-01 19:28:10 +0800747 case PROP_LOW_MEMORY_MODE:
748 v4l2object->low_memory_mode = g_value_get_boolean(value);
749 GST_DEBUG_OBJECT(v4l2object, "set low mem: %d",v4l2object->low_latency_mode);
750 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800751 case PROP_I_FRAME_MODE:
752 v4l2object->iframe_mode = g_value_get_boolean(value);
753 GST_DEBUG_OBJECT(v4l2object, "set I frame mode: %d",v4l2object->iframe_mode);
754 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800755 default:
bo.xiao857b8682024-09-12 16:40:32 +0800756 return FALSE;
757 break;
758 }
759 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800760}
761
762gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800763gst_aml_v4l2_object_get_property_helper (GstAmlV4l2Object * v4l2object,
764 guint prop_id, GValue * value, GParamSpec * pspec)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800765{
bo.xiao857b8682024-09-12 16:40:32 +0800766 switch (prop_id)
767 {
xuesong.jiangae1548e2022-05-06 16:38:46 +0800768 case PROP_DEVICE:
bo.xiao857b8682024-09-12 16:40:32 +0800769 g_value_set_string (value, v4l2object->videodev);
770 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800771 case PROP_DEVICE_NAME:
772 {
bo.xiao857b8682024-09-12 16:40:32 +0800773 const guchar *name = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800774
bo.xiao857b8682024-09-12 16:40:32 +0800775 if (GST_AML_V4L2_IS_OPEN (v4l2object))
776 name = v4l2object->vcap.card;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800777
bo.xiao857b8682024-09-12 16:40:32 +0800778 g_value_set_string (value, (gchar *) name);
779 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800780 }
781 case PROP_DEVICE_FD:
782 {
bo.xiao857b8682024-09-12 16:40:32 +0800783 if (GST_AML_V4L2_IS_OPEN (v4l2object))
784 g_value_set_int (value, v4l2object->video_fd);
785 else
786 g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
787 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800788 }
789 case PROP_FLAGS:
790 {
bo.xiao857b8682024-09-12 16:40:32 +0800791 guint flags = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800792
bo.xiao857b8682024-09-12 16:40:32 +0800793 if (GST_AML_V4L2_IS_OPEN (v4l2object))
794 {
795 flags |= v4l2object->device_caps &
796 (V4L2_CAP_VIDEO_CAPTURE |
797 V4L2_CAP_VIDEO_OUTPUT |
798 V4L2_CAP_VIDEO_OVERLAY |
799 V4L2_CAP_VBI_CAPTURE |
800 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800801
bo.xiao857b8682024-09-12 16:40:32 +0800802 if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
803 flags |= V4L2_CAP_VIDEO_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800804
bo.xiao857b8682024-09-12 16:40:32 +0800805 if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
806 flags |= V4L2_CAP_VIDEO_OUTPUT;
807 }
808 g_value_set_flags (value, flags);
809 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800810 }
811 case PROP_BRIGHTNESS:
812 case PROP_CONTRAST:
813 case PROP_SATURATION:
814 case PROP_HUE:
815 {
bo.xiao857b8682024-09-12 16:40:32 +0800816 gint cid = gst_aml_v4l2_object_prop_to_cid (prop_id);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800817
bo.xiao857b8682024-09-12 16:40:32 +0800818 if (cid != -1)
819 {
820 if (GST_AML_V4L2_IS_OPEN (v4l2object))
xuesong.jiangae1548e2022-05-06 16:38:46 +0800821 {
bo.xiao857b8682024-09-12 16:40:32 +0800822 gint v;
823 if (gst_aml_v4l2_get_attribute (v4l2object, cid, &v))
824 {
825 g_value_set_int (value, v);
826 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800827 }
bo.xiao857b8682024-09-12 16:40:32 +0800828 }
829 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800830 }
bo.xiao857b8682024-09-12 16:40:32 +0800831 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800832 case PROP_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800833 g_value_set_enum (value, v4l2object->req_mode);
834 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800835 case PROP_CAPTURE_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800836 g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
837 g_value_set_enum (value, v4l2object->req_mode);
838 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800839 case PROP_OUTPUT_IO_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800840 g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
841 g_value_set_enum (value, v4l2object->req_mode);
842 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800843 case PROP_EXTRA_CONTROLS:
bo.xiao857b8682024-09-12 16:40:32 +0800844 gst_value_set_structure (value, v4l2object->extra_controls);
845 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800846 case PROP_PIXEL_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800847 if (v4l2object->par)
848 g_value_transform (v4l2object->par, value);
849 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800850 case PROP_FORCE_ASPECT_RATIO:
bo.xiao857b8682024-09-12 16:40:32 +0800851 g_value_set_boolean (value, v4l2object->keep_aspect);
852 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800853 case PROP_DUMP_FRAME_LOCATION:
854 g_value_set_string(value, v4l2object->dumpframefile);
855 break;
xuesong.jiang22a9b112023-05-24 09:01:59 +0000856 case PROP_STREAM_MODE:
857 g_value_set_boolean(value, v4l2object->stream_mode);
858 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800859 case PROP_CC_DATA:
860 g_value_set_boolean(value, v4l2object->enable_cc_data);
861 break;
zengliang.li8f538aa2024-06-25 17:31:20 +0800862 case PROP_ENABLE_NR:
863 g_value_set_boolean(value, v4l2object->enable_nr);
864 break;
hanghang.luob3157512024-06-24 16:18:04 +0800865 case PROP_LOW_LATENCY_MODE:
866 g_value_set_boolean(value, v4l2object->low_latency_mode);
867 break;
fei.dengaf682762024-06-24 19:06:03 +0800868 case PROP_DECODING_ERROR_FRAMES:
869 g_value_set_int(value, v4l2object->num_error_frames);
870 break;
hanghang.luo75664712024-07-01 19:28:10 +0800871 case PROP_LOW_MEMORY_MODE:
872 g_value_set_boolean(value, v4l2object->low_memory_mode);
873 break;
hanghang.luo7f403102024-07-04 10:33:01 +0800874 case PROP_I_FRAME_MODE:
bo.xiao857b8682024-09-12 16:40:32 +0800875 g_value_set_boolean(value, v4l2object->iframe_mode);
876 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800877 default:
bo.xiao857b8682024-09-12 16:40:32 +0800878 return FALSE;
879 break;
880 }
881 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800882}
883
884static void
bo.xiao857b8682024-09-12 16:40:32 +0800885gst_aml_v4l2_get_driver_min_buffers (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800886{
bo.xiao857b8682024-09-12 16:40:32 +0800887 struct v4l2_control control = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +0800888
bo.xiao857b8682024-09-12 16:40:32 +0800889 g_return_if_fail (GST_AML_V4L2_IS_OPEN (v4l2object));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800890
bo.xiao857b8682024-09-12 16:40:32 +0800891 if (V4L2_TYPE_IS_OUTPUT (v4l2object->type))
892 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
893 else
894 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800895
bo.xiao857b8682024-09-12 16:40:32 +0800896 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0)
897 {
898 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
899 "driver requires a minimum of %d buffers", control.value);
900 v4l2object->min_buffers = control.value;
901 }
902 else
903 {
904 v4l2object->min_buffers = 0;
905 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800906}
907
908gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800909gst_aml_v4l2_object_open (GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800910{
bo.xiao857b8682024-09-12 16:40:32 +0800911 if (!gst_aml_v4l2_open(v4l2object))
912 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800913
bo.xiao857b8682024-09-12 16:40:32 +0800914 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800915}
916
917gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800918gst_aml_v4l2_object_open_shared (GstAmlV4l2Object * v4l2object, GstAmlV4l2Object * other)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800919{
bo.xiao857b8682024-09-12 16:40:32 +0800920 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800921
bo.xiao857b8682024-09-12 16:40:32 +0800922 ret = gst_aml_v4l2_dup (v4l2object, other);
923 if (ret && !V4L2_TYPE_IS_OUTPUT (v4l2object->type))
924 {
925 gst_poll_fd_init (&v4l2object->pollfd);
926 v4l2object->pollfd.fd = v4l2object->video_fd;
927 gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
928 /* used for dequeue event */
929 gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
930 gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
931 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800932
bo.xiao857b8682024-09-12 16:40:32 +0800933 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800934}
935
936gboolean
bo.xiao857b8682024-09-12 16:40:32 +0800937gst_aml_v4l2_object_close (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800938{
bo.xiao857b8682024-09-12 16:40:32 +0800939 if (!gst_aml_v4l2_close (v4l2object))
940 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800941
bo.xiao857b8682024-09-12 16:40:32 +0800942 gst_caps_replace (&v4l2object->probed_caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800943
bo.xiao857b8682024-09-12 16:40:32 +0800944 /* reset our copy of the device caps */
945 v4l2object->device_caps = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800946
bo.xiao857b8682024-09-12 16:40:32 +0800947 if (v4l2object->formats)
948 {
949 gst_aml_v4l2_object_clear_format_list (v4l2object);
950 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800951
bo.xiao857b8682024-09-12 16:40:32 +0800952 if (v4l2object->par)
953 {
954 g_value_unset (v4l2object->par);
955 g_free (v4l2object->par);
956 v4l2object->par = NULL;
957 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800958
bo.xiao857b8682024-09-12 16:40:32 +0800959 if (v4l2object->fps)
960 {
961 g_value_unset(v4l2object->fps);
962 g_free(v4l2object->fps);
963 v4l2object->fps = NULL;
964 }
sheng.liudb26f7d2024-01-22 11:24:23 +0000965
bo.xiao857b8682024-09-12 16:40:32 +0800966 if (v4l2object->channel)
967 {
968 g_free (v4l2object->channel);
969 v4l2object->channel = NULL;
970 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800971
bo.xiao857b8682024-09-12 16:40:32 +0800972 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800973}
974
975static struct v4l2_fmtdesc *
bo.xiao857b8682024-09-12 16:40:32 +0800976gst_aml_v4l2_object_get_format_from_fourcc (GstAmlV4l2Object * v4l2object,
977 guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800978{
bo.xiao857b8682024-09-12 16:40:32 +0800979 struct v4l2_fmtdesc *fmt;
980 GSList *walk;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800981
bo.xiao857b8682024-09-12 16:40:32 +0800982 if (fourcc == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +0800983 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +0800984
985 walk = gst_aml_v4l2_object_get_format_list (v4l2object);
986 while (walk)
987 {
988 fmt = (struct v4l2_fmtdesc *) walk->data;
989 if (fmt->pixelformat == fourcc)
990 return fmt;
991 /* special case for jpeg */
992 if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
993 fmt->pixelformat == V4L2_PIX_FMT_JPEG ||
994 fmt->pixelformat == V4L2_PIX_FMT_PJPG)
995 {
996 if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG ||
997 fourcc == V4L2_PIX_FMT_PJPG)
998 {
999 return fmt;
1000 }
1001 }
1002 walk = g_slist_next (walk);
1003 }
1004
1005 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001006}
1007
1008/* complete made up ranking, the values themselves are meaningless */
1009/* These ranks MUST be X such that X<<15 fits on a signed int - see
1010 the comment at the end of gst_aml_v4l2_object_format_get_rank. */
bo.xiao857b8682024-09-12 16:40:32 +08001011#define YUV_BASE_RANK 1000
1012#define JPEG_BASE_RANK 500
1013#define DV_BASE_RANK 200
1014#define RGB_BASE_RANK 100
1015#define YUV_ODD_BASE_RANK 50
1016#define RGB_ODD_BASE_RANK 25
1017#define BAYER_BASE_RANK 15
1018#define S910_BASE_RANK 10
1019#define GREY_BASE_RANK 5
1020#define PWC_BASE_RANK 1
xuesong.jiangae1548e2022-05-06 16:38:46 +08001021
1022static gint
bo.xiao857b8682024-09-12 16:40:32 +08001023gst_aml_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001024{
bo.xiao857b8682024-09-12 16:40:32 +08001025 guint32 fourcc = fmt->pixelformat;
1026 gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
1027 gint rank = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001028
bo.xiao857b8682024-09-12 16:40:32 +08001029 switch (fourcc)
1030 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001031 case V4L2_PIX_FMT_MJPEG:
1032 case V4L2_PIX_FMT_PJPG:
bo.xiao857b8682024-09-12 16:40:32 +08001033 rank = JPEG_BASE_RANK;
1034 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001035 case V4L2_PIX_FMT_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08001036 rank = JPEG_BASE_RANK + 1;
1037 break;
1038 case V4L2_PIX_FMT_MPEG: /* MPEG */
1039 rank = JPEG_BASE_RANK + 2;
1040 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001041
1042 case V4L2_PIX_FMT_RGB332:
1043 case V4L2_PIX_FMT_ARGB555:
1044 case V4L2_PIX_FMT_XRGB555:
1045 case V4L2_PIX_FMT_RGB555:
1046 case V4L2_PIX_FMT_ARGB555X:
1047 case V4L2_PIX_FMT_XRGB555X:
1048 case V4L2_PIX_FMT_RGB555X:
1049 case V4L2_PIX_FMT_BGR666:
1050 case V4L2_PIX_FMT_RGB565:
1051 case V4L2_PIX_FMT_RGB565X:
1052 case V4L2_PIX_FMT_RGB444:
1053 case V4L2_PIX_FMT_Y4:
1054 case V4L2_PIX_FMT_Y6:
1055 case V4L2_PIX_FMT_Y10:
1056 case V4L2_PIX_FMT_Y12:
1057 case V4L2_PIX_FMT_Y10BPACK:
1058 case V4L2_PIX_FMT_YUV555:
1059 case V4L2_PIX_FMT_YUV565:
1060 case V4L2_PIX_FMT_YUV32:
1061 case V4L2_PIX_FMT_NV12MT_16X16:
1062 case V4L2_PIX_FMT_NV42:
1063 case V4L2_PIX_FMT_H264_MVC:
bo.xiao857b8682024-09-12 16:40:32 +08001064 rank = RGB_ODD_BASE_RANK;
1065 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001066
1067 case V4L2_PIX_FMT_RGB24:
1068 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001069 rank = RGB_BASE_RANK - 1;
1070 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001071
1072 case V4L2_PIX_FMT_RGB32:
1073 case V4L2_PIX_FMT_BGR32:
1074 case V4L2_PIX_FMT_ABGR32:
1075 case V4L2_PIX_FMT_XBGR32:
1076 case V4L2_PIX_FMT_ARGB32:
1077 case V4L2_PIX_FMT_XRGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001078 rank = RGB_BASE_RANK;
1079 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001080
bo.xiao857b8682024-09-12 16:40:32 +08001081 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1082 rank = GREY_BASE_RANK;
1083 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001084
1085 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
1086 case V4L2_PIX_FMT_NV12M: /* Same as NV12 */
bo.xiao857b8682024-09-12 16:40:32 +08001087 case V4L2_PIX_FMT_NV12MT: /* NV12 64x32 tile */
1088 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
1089 case V4L2_PIX_FMT_NV21M: /* Same as NV21 */
1090 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1091 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
1092 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
1093 case V4L2_PIX_FMT_NV16M: /* Same as NV16 */
1094 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
1095 case V4L2_PIX_FMT_NV61M: /* Same as NV61 */
1096 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
1097 rank = YUV_ODD_BASE_RANK;
1098 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001099
bo.xiao857b8682024-09-12 16:40:32 +08001100 case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */
1101 rank = YUV_BASE_RANK + 3;
1102 break;
1103 case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */
1104 rank = YUV_BASE_RANK + 2;
1105 break;
1106 case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001107 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001108 rank = YUV_BASE_RANK + 7;
1109 break;
1110 case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */
1111 rank = YUV_BASE_RANK + 10;
1112 break;
1113 case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */
1114 rank = YUV_BASE_RANK + 6;
1115 break;
1116 case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */
1117 rank = YUV_BASE_RANK + 9;
1118 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001119 case V4L2_PIX_FMT_YUV444:
bo.xiao857b8682024-09-12 16:40:32 +08001120 rank = YUV_BASE_RANK + 6;
1121 break;
1122 case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */
1123 rank = YUV_BASE_RANK + 5;
1124 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001125 case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001126 rank = YUV_BASE_RANK + 4;
1127 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001128 case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
bo.xiao857b8682024-09-12 16:40:32 +08001129 rank = YUV_BASE_RANK + 8;
1130 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001131
1132 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001133 rank = DV_BASE_RANK;
1134 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001135
bo.xiao857b8682024-09-12 16:40:32 +08001136 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1137 rank = 0;
1138 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001139
1140 case V4L2_PIX_FMT_SBGGR8:
1141 case V4L2_PIX_FMT_SGBRG8:
1142 case V4L2_PIX_FMT_SGRBG8:
1143 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001144 rank = BAYER_BASE_RANK;
1145 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001146
1147 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001148 rank = S910_BASE_RANK;
1149 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001150
1151 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001152 rank = PWC_BASE_RANK;
1153 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001154 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001155 rank = PWC_BASE_RANK;
1156 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001157
1158 default:
bo.xiao857b8682024-09-12 16:40:32 +08001159 rank = 0;
1160 break;
1161 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001162
bo.xiao857b8682024-09-12 16:40:32 +08001163 /* All ranks are below 1<<15 so a shift by 15
1164 * will a) make all non-emulated formats larger
1165 * than emulated and b) will not overflow
1166 */
1167 if (!emulated)
1168 rank <<= 15;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001169
bo.xiao857b8682024-09-12 16:40:32 +08001170 return rank;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001171}
1172
1173static gint
bo.xiao857b8682024-09-12 16:40:32 +08001174format_cmp_func (gconstpointer a, gconstpointer b)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001175{
bo.xiao857b8682024-09-12 16:40:32 +08001176 const struct v4l2_fmtdesc *fa = a;
1177 const struct v4l2_fmtdesc *fb = b;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001178
bo.xiao857b8682024-09-12 16:40:32 +08001179 if (fa->pixelformat == fb->pixelformat)
1180 return 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001181
bo.xiao857b8682024-09-12 16:40:32 +08001182 return gst_aml_v4l2_object_format_get_rank (fb) -
1183 gst_aml_v4l2_object_format_get_rank (fa);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001184}
1185
1186/******************************************************
1187 * gst_aml_v4l2_object_fill_format_list():
1188 * create list of supported capture formats
1189 * return value: TRUE on success, FALSE on error
1190 ******************************************************/
1191static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001192gst_aml_v4l2_object_fill_format_list (GstAmlV4l2Object * v4l2object,
1193 enum v4l2_buf_type type)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001194{
bo.xiao857b8682024-09-12 16:40:32 +08001195 gint n;
1196 struct v4l2_fmtdesc *format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001197
bo.xiao857b8682024-09-12 16:40:32 +08001198 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting src format enumerations");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001199
bo.xiao857b8682024-09-12 16:40:32 +08001200 /* format enumeration */
1201 for (n = 0;; n++)
1202 {
bo.xiao4ef6d272024-10-15 16:18:25 +08001203 format = g_new0 (struct v4l2_fmtdesc, 1);//todo: leak
bo.xiao857b8682024-09-12 16:40:32 +08001204
1205 format->index = n;
1206 format->type = type;
1207
1208 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001209 {
bo.xiao857b8682024-09-12 16:40:32 +08001210 if (errno == EINVAL)
1211 {
1212 g_free (format);
1213 break; /* end of enumeration */
1214 }
1215 else
1216 {
1217 goto failed;
1218 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001219 }
1220
bo.xiao857b8682024-09-12 16:40:32 +08001221 GST_LOG_OBJECT (v4l2object->dbg_obj, "index: %u", format->index);
1222 GST_LOG_OBJECT (v4l2object->dbg_obj, "type: %d", format->type);
1223 GST_LOG_OBJECT (v4l2object->dbg_obj, "flags: %08x", format->flags);
1224 GST_LOG_OBJECT (v4l2object->dbg_obj, "description: '%s'",
1225 format->description);
1226 GST_LOG_OBJECT (v4l2object->dbg_obj, "pixelformat: %" GST_FOURCC_FORMAT,
1227 GST_FOURCC_ARGS (format->pixelformat));
1228
1229
1230 if (V4L2_PIX_FMT_YUV420M == format->pixelformat || V4L2_PIX_FMT_YUV420 == format->pixelformat)
1231 {
1232 GST_LOG_OBJECT(v4l2object->dbg_obj, "aml v4l2 driver didn't real support YU12 and YM12, ignore it");
1233 continue;
1234 }
1235
1236 /* sort formats according to our preference; we do this, because caps
1237 * are probed in the order the formats are in the list, and the order of
1238 * formats in the final probed caps matters for things like fixation */
1239 v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
1240 (GCompareFunc) format_cmp_func);
1241 }
1242
xuesong.jiangae1548e2022-05-06 16:38:46 +08001243#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08001244 {
1245 GSList *l;
1246
1247 GST_INFO_OBJECT (v4l2object->dbg_obj, "got %d format(s):", n);
1248 for (l = v4l2object->formats; l != NULL; l = l->next)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001249 {
bo.xiao857b8682024-09-12 16:40:32 +08001250 format = l->data;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001251
bo.xiao857b8682024-09-12 16:40:32 +08001252 GST_INFO_OBJECT (v4l2object->dbg_obj,
1253 " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
1254 ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001255 }
bo.xiao857b8682024-09-12 16:40:32 +08001256 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001257#endif
1258
bo.xiao857b8682024-09-12 16:40:32 +08001259 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001260
bo.xiao857b8682024-09-12 16:40:32 +08001261 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001262failed:
bo.xiao857b8682024-09-12 16:40:32 +08001263 {
1264 g_free (format);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001265
1266 if (v4l2object->element)
bo.xiao857b8682024-09-12 16:40:32 +08001267 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001268
bo.xiao857b8682024-09-12 16:40:32 +08001269 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1270 (_("Failed to enumerate possible video formats device '%s' can work "
1271 "with"), v4l2object->videodev),
1272 ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
1273 n, v4l2object->videodev, errno, g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001274
1275 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08001276 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001277}
1278
1279/*
1280 * Get the list of supported capture formats, a list of
1281 * <code>struct v4l2_fmtdesc</code>.
1282 */
1283static GSList *
bo.xiao857b8682024-09-12 16:40:32 +08001284gst_aml_v4l2_object_get_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001285{
bo.xiao857b8682024-09-12 16:40:32 +08001286 if (!v4l2object->formats)
1287 {
1288
1289 /* check usual way */
1290 gst_aml_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
1291
1292 /* if our driver supports multi-planar
1293 * and if formats are still empty then we can workaround driver bug
1294 * by also looking up formats as if our device was not supporting
1295 * multiplanar */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001296 if (!v4l2object->formats)
1297 {
bo.xiao857b8682024-09-12 16:40:32 +08001298 switch (v4l2object->type)
1299 {
1300 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1301 gst_aml_v4l2_object_fill_format_list (v4l2object,
1302 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1303 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001304
bo.xiao857b8682024-09-12 16:40:32 +08001305 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1306 gst_aml_v4l2_object_fill_format_list (v4l2object,
1307 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1308 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001309
bo.xiao857b8682024-09-12 16:40:32 +08001310 default:
1311 break;
1312 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001313 }
bo.xiao857b8682024-09-12 16:40:32 +08001314 }
1315 return v4l2object->formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001316}
1317
1318static GstVideoFormat
bo.xiao857b8682024-09-12 16:40:32 +08001319gst_aml_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001320{
bo.xiao857b8682024-09-12 16:40:32 +08001321 GstVideoFormat format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001322
bo.xiao857b8682024-09-12 16:40:32 +08001323 switch (fourcc)
1324 {
1325 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1326 format = GST_VIDEO_FORMAT_GRAY8;
1327 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001328 case V4L2_PIX_FMT_Y16:
bo.xiao857b8682024-09-12 16:40:32 +08001329 format = GST_VIDEO_FORMAT_GRAY16_LE;
1330 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001331 case V4L2_PIX_FMT_Y16_BE:
bo.xiao857b8682024-09-12 16:40:32 +08001332 format = GST_VIDEO_FORMAT_GRAY16_BE;
1333 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001334 case V4L2_PIX_FMT_XRGB555:
1335 case V4L2_PIX_FMT_RGB555:
bo.xiao857b8682024-09-12 16:40:32 +08001336 format = GST_VIDEO_FORMAT_RGB15;
1337 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001338 case V4L2_PIX_FMT_XRGB555X:
1339 case V4L2_PIX_FMT_RGB555X:
bo.xiao857b8682024-09-12 16:40:32 +08001340 format = GST_VIDEO_FORMAT_BGR15;
1341 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001342 case V4L2_PIX_FMT_RGB565:
bo.xiao857b8682024-09-12 16:40:32 +08001343 format = GST_VIDEO_FORMAT_RGB16;
1344 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001345 case V4L2_PIX_FMT_RGB24:
bo.xiao857b8682024-09-12 16:40:32 +08001346 format = GST_VIDEO_FORMAT_RGB;
1347 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001348 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001349 format = GST_VIDEO_FORMAT_BGR;
1350 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001351 case V4L2_PIX_FMT_XRGB32:
1352 case V4L2_PIX_FMT_RGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001353 format = GST_VIDEO_FORMAT_xRGB;
1354 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001355 case V4L2_PIX_FMT_XBGR32:
1356 case V4L2_PIX_FMT_BGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001357 format = GST_VIDEO_FORMAT_BGRx;
1358 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001359 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001360 format = GST_VIDEO_FORMAT_BGRA;
1361 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001362 case V4L2_PIX_FMT_ARGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001363 format = GST_VIDEO_FORMAT_ARGB;
1364 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001365 case V4L2_PIX_FMT_NV12:
1366 case V4L2_PIX_FMT_NV12M:
bo.xiao857b8682024-09-12 16:40:32 +08001367 format = GST_VIDEO_FORMAT_NV12;
1368 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001369 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001370 format = GST_VIDEO_FORMAT_NV12_64Z32;
1371 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001372 case V4L2_PIX_FMT_NV21:
1373 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001374 format = GST_VIDEO_FORMAT_NV21;
1375 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001376 case V4L2_PIX_FMT_YVU410:
bo.xiao857b8682024-09-12 16:40:32 +08001377 format = GST_VIDEO_FORMAT_YVU9;
1378 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001379 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001380 format = GST_VIDEO_FORMAT_YUV9;
1381 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001382 case V4L2_PIX_FMT_YUV420:
1383 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001384 format = GST_VIDEO_FORMAT_I420;
1385 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001386 case V4L2_PIX_FMT_YUYV:
bo.xiao857b8682024-09-12 16:40:32 +08001387 format = GST_VIDEO_FORMAT_YUY2;
1388 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001389 case V4L2_PIX_FMT_YVU420:
bo.xiao857b8682024-09-12 16:40:32 +08001390 format = GST_VIDEO_FORMAT_YV12;
1391 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001392 case V4L2_PIX_FMT_UYVY:
bo.xiao857b8682024-09-12 16:40:32 +08001393 format = GST_VIDEO_FORMAT_UYVY;
1394 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001395 case V4L2_PIX_FMT_YUV411P:
bo.xiao857b8682024-09-12 16:40:32 +08001396 format = GST_VIDEO_FORMAT_Y41B;
1397 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001398 case V4L2_PIX_FMT_YUV422P:
bo.xiao857b8682024-09-12 16:40:32 +08001399 format = GST_VIDEO_FORMAT_Y42B;
1400 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001401 case V4L2_PIX_FMT_YVYU:
bo.xiao857b8682024-09-12 16:40:32 +08001402 format = GST_VIDEO_FORMAT_YVYU;
1403 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001404 case V4L2_PIX_FMT_NV16:
1405 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001406 format = GST_VIDEO_FORMAT_NV16;
1407 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001408 case V4L2_PIX_FMT_NV61:
1409 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001410 format = GST_VIDEO_FORMAT_NV61;
1411 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001412 case V4L2_PIX_FMT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08001413 format = GST_VIDEO_FORMAT_NV24;
1414 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001415 default:
bo.xiao857b8682024-09-12 16:40:32 +08001416 format = GST_VIDEO_FORMAT_UNKNOWN;
1417 break;
1418 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001419
bo.xiao857b8682024-09-12 16:40:32 +08001420 return format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001421}
1422
1423static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001424gst_aml_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001425{
bo.xiao857b8682024-09-12 16:40:32 +08001426 gboolean ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001427
bo.xiao857b8682024-09-12 16:40:32 +08001428 switch (fourcc)
1429 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001430 case V4L2_PIX_FMT_XRGB555:
1431 case V4L2_PIX_FMT_RGB555:
1432 case V4L2_PIX_FMT_XRGB555X:
1433 case V4L2_PIX_FMT_RGB555X:
1434 case V4L2_PIX_FMT_RGB565:
1435 case V4L2_PIX_FMT_RGB24:
1436 case V4L2_PIX_FMT_BGR24:
1437 case V4L2_PIX_FMT_XRGB32:
1438 case V4L2_PIX_FMT_RGB32:
1439 case V4L2_PIX_FMT_XBGR32:
1440 case V4L2_PIX_FMT_BGR32:
1441 case V4L2_PIX_FMT_ABGR32:
1442 case V4L2_PIX_FMT_ARGB32:
1443 case V4L2_PIX_FMT_SBGGR8:
1444 case V4L2_PIX_FMT_SGBRG8:
1445 case V4L2_PIX_FMT_SGRBG8:
1446 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001447 ret = TRUE;
1448 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001449 default:
bo.xiao857b8682024-09-12 16:40:32 +08001450 break;
1451 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001452
bo.xiao857b8682024-09-12 16:40:32 +08001453 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001454}
1455
1456static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001457gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001458{
bo.xiao857b8682024-09-12 16:40:32 +08001459 GstStructure *structure = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001460
bo.xiao857b8682024-09-12 16:40:32 +08001461 switch (fourcc)
1462 {
1463 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
1464 structure = gst_structure_new_empty("video/mjpeg");
1465 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001466 case V4L2_PIX_FMT_MPEG1:
bo.xiao857b8682024-09-12 16:40:32 +08001467 structure = gst_structure_new ("video/mpeg",
1468 "mpegversion", G_TYPE_INT, 1, NULL);
1469
1470 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1471 GST_DEBUG("aml set mpeg1 systemstream to false");
1472 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001473 case V4L2_PIX_FMT_MPEG2:
bo.xiao857b8682024-09-12 16:40:32 +08001474 structure = gst_structure_new("video/mpeg",
1475 "mpegversion", G_TYPE_INT, 2, NULL);
1476 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1477 GST_DEBUG("aml set mpeg2 systemstream to false");
1478 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001479 case V4L2_PIX_FMT_MPEG4:
1480 case V4L2_PIX_FMT_XVID:
bo.xiao857b8682024-09-12 16:40:32 +08001481 structure = gst_structure_new ("video/mpeg",
1482 "mpegversion", G_TYPE_INT, 4, "systemstream",
1483 G_TYPE_BOOLEAN, FALSE, NULL);
1484 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001485 case V4L2_PIX_FMT_FWHT:
bo.xiao857b8682024-09-12 16:40:32 +08001486 structure = gst_structure_new_empty ("video/x-fwht");
1487 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001488 case V4L2_PIX_FMT_H263:
bo.xiao857b8682024-09-12 16:40:32 +08001489 structure = gst_structure_new ("video/x-h263",
1490 "variant", G_TYPE_STRING, "itu", NULL);
1491 break;
1492 case V4L2_PIX_FMT_H264: /* H.264 */
1493 structure = gst_structure_new ("video/x-h264",
1494 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1495 G_TYPE_STRING, "au", NULL);
1496 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001497 case V4L2_PIX_FMT_H264_NO_SC:
bo.xiao857b8682024-09-12 16:40:32 +08001498 structure = gst_structure_new ("video/x-h264",
1499 "stream-format", G_TYPE_STRING, "avc", "alignment",
1500 G_TYPE_STRING, "au", NULL);
1501 break;
1502 case V4L2_PIX_FMT_HEVC: /* H.265 */
1503 structure = gst_structure_new ("video/x-h265",
1504 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1505 G_TYPE_STRING, "au", NULL);
1506 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001507 case V4L2_PIX_FMT_VC1_ANNEX_G:
1508 case V4L2_PIX_FMT_VC1_ANNEX_L:
bo.xiao857b8682024-09-12 16:40:32 +08001509 structure = gst_structure_new ("video/x-wmv",
1510 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
1511 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001512 case V4L2_PIX_FMT_VP8:
bo.xiao857b8682024-09-12 16:40:32 +08001513 structure = gst_structure_new_empty ("video/x-vp8");
1514 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001515 case V4L2_PIX_FMT_VP9:
bo.xiao857b8682024-09-12 16:40:32 +08001516 structure = gst_structure_new_empty ("video/x-vp9");
1517 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001518 case V4L2_PIX_FMT_AV1:
1519 structure = gst_structure_new_empty("video/x-av1");
1520 break;
zengliang.li51f54b62023-10-10 12:14:49 +00001521 case V4L2_PIX_FMT_AVS:
1522 structure = gst_structure_new_empty("video/x-avs");
1523 break;
1524 case V4L2_PIX_FMT_AVS2:
1525 structure = gst_structure_new_empty("video/x-avs2");
1526 break;
1527 case V4L2_PIX_FMT_AVS3:
1528 structure = gst_structure_new_empty("video/x-avs3");
1529 break;
bo.xiao857b8682024-09-12 16:40:32 +08001530 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001531 case V4L2_PIX_FMT_Y16:
1532 case V4L2_PIX_FMT_Y16_BE:
1533 case V4L2_PIX_FMT_XRGB555:
1534 case V4L2_PIX_FMT_RGB555:
1535 case V4L2_PIX_FMT_XRGB555X:
1536 case V4L2_PIX_FMT_RGB555X:
1537 case V4L2_PIX_FMT_RGB565:
1538 case V4L2_PIX_FMT_RGB24:
1539 case V4L2_PIX_FMT_BGR24:
1540 case V4L2_PIX_FMT_RGB32:
1541 case V4L2_PIX_FMT_XRGB32:
1542 case V4L2_PIX_FMT_ARGB32:
1543 case V4L2_PIX_FMT_BGR32:
1544 case V4L2_PIX_FMT_XBGR32:
1545 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001546 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001547 case V4L2_PIX_FMT_NV12M:
1548 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001549 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001550 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001551 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001552 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001553 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001554 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001555 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001556 case V4L2_PIX_FMT_YVU410:
1557 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001558 case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001559 case V4L2_PIX_FMT_YUV420M:
1560 case V4L2_PIX_FMT_YUYV:
1561 case V4L2_PIX_FMT_YVU420:
1562 case V4L2_PIX_FMT_UYVY:
1563 case V4L2_PIX_FMT_YUV422P:
1564 case V4L2_PIX_FMT_YVYU:
1565 case V4L2_PIX_FMT_YUV411P:
1566 {
bo.xiao857b8682024-09-12 16:40:32 +08001567 GstVideoFormat format;
1568 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fourcc);
1569 if (format != GST_VIDEO_FORMAT_UNKNOWN)
1570 structure = gst_structure_new ("video/x-raw",
1571 "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
1572 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001573 }
1574 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001575 structure =
1576 gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1577 NULL);
1578 break;
1579 case V4L2_PIX_FMT_MPEG: /* MPEG */
1580 structure = gst_structure_new ("video/mpegts",
1581 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
1582 break;
1583 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1584 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001585 case V4L2_PIX_FMT_SBGGR8:
1586 case V4L2_PIX_FMT_SGBRG8:
1587 case V4L2_PIX_FMT_SGRBG8:
1588 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001589 structure = gst_structure_new ("video/x-bayer", "format", G_TYPE_STRING,
1590 fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" :
1591 fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg" :
1592 fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg" :
1593 /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb", NULL);
1594 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001595 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001596 structure = gst_structure_new_empty ("video/x-sonix");
1597 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001598 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001599 structure = gst_structure_new_empty ("video/x-pwc1");
1600 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001601 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001602 structure = gst_structure_new_empty ("video/x-pwc2");
1603 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001604 case V4L2_PIX_FMT_RGB332:
1605 case V4L2_PIX_FMT_BGR666:
1606 case V4L2_PIX_FMT_ARGB555X:
1607 case V4L2_PIX_FMT_RGB565X:
1608 case V4L2_PIX_FMT_RGB444:
bo.xiao857b8682024-09-12 16:40:32 +08001609 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1610 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001611 case V4L2_PIX_FMT_Y4:
1612 case V4L2_PIX_FMT_Y6:
1613 case V4L2_PIX_FMT_Y10:
1614 case V4L2_PIX_FMT_Y12:
1615 case V4L2_PIX_FMT_Y10BPACK:
1616 case V4L2_PIX_FMT_YUV444:
1617 case V4L2_PIX_FMT_YUV555:
1618 case V4L2_PIX_FMT_YUV565:
1619 case V4L2_PIX_FMT_Y41P:
1620 case V4L2_PIX_FMT_YUV32:
1621 case V4L2_PIX_FMT_NV12MT_16X16:
1622 case V4L2_PIX_FMT_NV42:
1623 case V4L2_PIX_FMT_H264_MVC:
1624 default:
bo.xiao857b8682024-09-12 16:40:32 +08001625 GST_DEBUG ("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
1626 fourcc, GST_FOURCC_ARGS (fourcc));
1627 break;
1628 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001629
bo.xiao857b8682024-09-12 16:40:32 +08001630 return structure;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001631}
1632
1633GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001634gst_aml_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001635{
bo.xiao857b8682024-09-12 16:40:32 +08001636 GstStructure *template;
1637 gint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001638
bo.xiao857b8682024-09-12 16:40:32 +08001639 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001640
bo.xiao857b8682024-09-12 16:40:32 +08001641 if (template == NULL)
1642 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001643
bo.xiao857b8682024-09-12 16:40:32 +08001644 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1645 {
1646 if (gst_aml_v4l2_formats[i].format != fourcc)
1647 continue;
1648
1649 if (gst_aml_v4l2_formats[i].dimensions)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001650 {
bo.xiao857b8682024-09-12 16:40:32 +08001651 gst_structure_set (template,
1652 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1653 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1654 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001655 }
bo.xiao857b8682024-09-12 16:40:32 +08001656 break;
1657 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001658
1659done:
bo.xiao857b8682024-09-12 16:40:32 +08001660 return template;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001661}
1662
1663static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001664gst_aml_v4l2_object_get_caps_helper (GstAmlV4L2FormatFlags flags)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001665{
bo.xiao857b8682024-09-12 16:40:32 +08001666 GstStructure *structure;
1667 GstCaps *caps;
1668 guint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001669
bo.xiao857b8682024-09-12 16:40:32 +08001670 caps = gst_caps_new_empty ();
1671 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1672 {
1673
1674 if ((gst_aml_v4l2_formats[i].flags & flags) == 0)
1675 continue;
1676
1677 structure =
1678 gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (gst_aml_v4l2_formats[i].format);
1679
1680 if (structure)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001681 {
bo.xiao857b8682024-09-12 16:40:32 +08001682 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001683
bo.xiao857b8682024-09-12 16:40:32 +08001684 if (gst_aml_v4l2_formats[i].dimensions)
1685 {
1686 gst_structure_set (structure,
1687 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1688 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1689 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1690 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001691
bo.xiao857b8682024-09-12 16:40:32 +08001692 switch (gst_aml_v4l2_formats[i].format)
1693 {
1694 case V4L2_PIX_FMT_RGB32:
1695 alt_s = gst_structure_copy (structure);
1696 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
1697 break;
1698 case V4L2_PIX_FMT_BGR32:
1699 alt_s = gst_structure_copy (structure);
1700 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
1701 default:
1702 break;
1703 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001704
bo.xiao857b8682024-09-12 16:40:32 +08001705 gst_caps_append_structure (caps, structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001706
bo.xiao857b8682024-09-12 16:40:32 +08001707 if (alt_s)
1708 gst_caps_append_structure (caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001709 }
bo.xiao857b8682024-09-12 16:40:32 +08001710 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001711
bo.xiao857b8682024-09-12 16:40:32 +08001712 return gst_caps_simplify(caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001713}
1714
1715GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001716gst_aml_v4l2_object_get_all_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001717{
bo.xiao857b8682024-09-12 16:40:32 +08001718 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001719
bo.xiao857b8682024-09-12 16:40:32 +08001720 if (g_once_init_enter (&caps))
1721 {
1722 GstCaps *all_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_ALL);
1723 GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1724 g_once_init_leave (&caps, all_caps);
1725 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001726
bo.xiao857b8682024-09-12 16:40:32 +08001727 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001728}
1729
1730GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001731gst_aml_v4l2_object_get_raw_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001732{
bo.xiao857b8682024-09-12 16:40:32 +08001733 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001734
bo.xiao857b8682024-09-12 16:40:32 +08001735 if (g_once_init_enter (&caps))
1736 {
1737 GstCaps *raw_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_RAW);
1738 GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1739 g_once_init_leave (&caps, raw_caps);
1740 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001741
bo.xiao857b8682024-09-12 16:40:32 +08001742 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001743}
1744
1745GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001746gst_aml_v4l2_object_get_codec_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001747{
bo.xiao857b8682024-09-12 16:40:32 +08001748 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001749
bo.xiao857b8682024-09-12 16:40:32 +08001750 if (g_once_init_enter (&caps))
1751 {
1752 GstCaps *codec_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
1753 GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1754 g_once_init_leave (&caps, codec_caps);
1755 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001756
bo.xiao857b8682024-09-12 16:40:32 +08001757 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001758}
1759
1760/* collect data for the given caps
1761 * @caps: given input caps
1762 * @format: location for the v4l format
1763 * @w/@h: location for width and height
1764 * @fps_n/@fps_d: location for framerate
1765 * @size: location for expected size of the frame or 0 if unknown
1766 */
1767static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001768gst_aml_v4l2_object_get_caps_info (GstAmlV4l2Object * v4l2object, GstCaps * caps,
1769 struct v4l2_fmtdesc **format, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001770{
bo.xiao857b8682024-09-12 16:40:32 +08001771 GstStructure *structure;
1772 guint32 fourcc = 0, fourcc_nc = 0;
1773 const gchar *mimetype;
1774 struct v4l2_fmtdesc *fmt = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001775
bo.xiao857b8682024-09-12 16:40:32 +08001776 GST_DEBUG_OBJECT(v4l2object, "got caps: %" GST_PTR_FORMAT, caps);
fei.denge9458472023-04-18 02:05:48 +00001777
bo.xiao857b8682024-09-12 16:40:32 +08001778 structure = gst_caps_get_structure (caps, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001779
bo.xiao857b8682024-09-12 16:40:32 +08001780 mimetype = gst_structure_get_name (structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001781
bo.xiao857b8682024-09-12 16:40:32 +08001782 if (!gst_video_info_from_caps (info, caps))
1783 goto invalid_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001784
bo.xiao857b8682024-09-12 16:40:32 +08001785 if (g_str_equal (mimetype, "video/x-raw"))
1786 {
1787 switch (GST_VIDEO_INFO_FORMAT (info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08001788 {
bo.xiao857b8682024-09-12 16:40:32 +08001789 case GST_VIDEO_FORMAT_I420:
1790 fourcc = V4L2_PIX_FMT_YUV420;
1791 fourcc_nc = V4L2_PIX_FMT_YUV420M;
1792 break;
1793 case GST_VIDEO_FORMAT_YUY2:
1794 fourcc = V4L2_PIX_FMT_YUYV;
1795 break;
1796 case GST_VIDEO_FORMAT_UYVY:
1797 fourcc = V4L2_PIX_FMT_UYVY;
1798 break;
1799 case GST_VIDEO_FORMAT_YV12:
1800 fourcc = V4L2_PIX_FMT_YVU420;
1801 break;
1802 case GST_VIDEO_FORMAT_Y41B:
1803 fourcc = V4L2_PIX_FMT_YUV411P;
1804 break;
1805 case GST_VIDEO_FORMAT_Y42B:
1806 fourcc = V4L2_PIX_FMT_YUV422P;
1807 break;
1808 case GST_VIDEO_FORMAT_NV12:
1809 fourcc = V4L2_PIX_FMT_NV12;
1810 fourcc_nc = V4L2_PIX_FMT_NV12M;
1811 break;
1812 case GST_VIDEO_FORMAT_NV12_64Z32:
1813 fourcc_nc = V4L2_PIX_FMT_NV12MT;
1814 break;
1815 case GST_VIDEO_FORMAT_NV21:
1816 fourcc = V4L2_PIX_FMT_NV21;
1817 fourcc_nc = V4L2_PIX_FMT_NV21M;
1818 break;
1819 case GST_VIDEO_FORMAT_NV16:
1820 fourcc = V4L2_PIX_FMT_NV16;
1821 fourcc_nc = V4L2_PIX_FMT_NV16M;
1822 break;
1823 case GST_VIDEO_FORMAT_NV61:
1824 fourcc = V4L2_PIX_FMT_NV61;
1825 fourcc_nc = V4L2_PIX_FMT_NV61M;
1826 break;
1827 case GST_VIDEO_FORMAT_NV24:
1828 fourcc = V4L2_PIX_FMT_NV24;
1829 break;
1830 case GST_VIDEO_FORMAT_YVYU:
1831 fourcc = V4L2_PIX_FMT_YVYU;
1832 break;
1833 case GST_VIDEO_FORMAT_RGB15:
1834 fourcc = V4L2_PIX_FMT_RGB555;
1835 fourcc_nc = V4L2_PIX_FMT_XRGB555;
1836 break;
1837 case GST_VIDEO_FORMAT_RGB16:
1838 fourcc = V4L2_PIX_FMT_RGB565;
1839 break;
1840 case GST_VIDEO_FORMAT_RGB:
1841 fourcc = V4L2_PIX_FMT_RGB24;
1842 break;
1843 case GST_VIDEO_FORMAT_BGR:
1844 fourcc = V4L2_PIX_FMT_BGR24;
1845 break;
1846 case GST_VIDEO_FORMAT_xRGB:
1847 fourcc = V4L2_PIX_FMT_RGB32;
1848 fourcc_nc = V4L2_PIX_FMT_XRGB32;
1849 break;
1850 case GST_VIDEO_FORMAT_ARGB:
1851 fourcc = V4L2_PIX_FMT_RGB32;
1852 fourcc_nc = V4L2_PIX_FMT_ARGB32;
1853 break;
1854 case GST_VIDEO_FORMAT_BGRx:
1855 fourcc = V4L2_PIX_FMT_BGR32;
1856 fourcc_nc = V4L2_PIX_FMT_XBGR32;
1857 break;
1858 case GST_VIDEO_FORMAT_BGRA:
1859 fourcc = V4L2_PIX_FMT_BGR32;
1860 fourcc_nc = V4L2_PIX_FMT_ABGR32;
1861 break;
1862 case GST_VIDEO_FORMAT_GRAY8:
1863 fourcc = V4L2_PIX_FMT_GREY;
1864 break;
1865 case GST_VIDEO_FORMAT_GRAY16_LE:
1866 fourcc = V4L2_PIX_FMT_Y16;
1867 break;
1868 case GST_VIDEO_FORMAT_GRAY16_BE:
1869 fourcc = V4L2_PIX_FMT_Y16_BE;
1870 break;
1871 case GST_VIDEO_FORMAT_BGR15:
1872 fourcc = V4L2_PIX_FMT_RGB555X;
1873 fourcc_nc = V4L2_PIX_FMT_XRGB555X;
1874 break;
1875 default:
1876 break;
1877 }
1878 }
1879 else
1880 {
1881 if (g_str_equal (mimetype, "video/mpegts"))
1882 {
1883 fourcc = V4L2_PIX_FMT_MPEG;
1884 }
1885 else if (g_str_equal (mimetype, "video/x-dv"))
1886 {
1887 fourcc = V4L2_PIX_FMT_DV;
1888 }
1889 else if (g_str_equal(mimetype, "video/mjpeg"))
1890 {
1891 fourcc = V4L2_PIX_FMT_JPEG;
1892 }
1893 else if (g_str_equal (mimetype, "video/mpeg"))
1894 {
1895 gint version;
1896 if (gst_structure_get_int (structure, "mpegversion", &version))
1897 {
1898 switch (version)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001899 {
bo.xiao857b8682024-09-12 16:40:32 +08001900 case 1:
1901 fourcc = V4L2_PIX_FMT_MPEG1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001902 break;
bo.xiao857b8682024-09-12 16:40:32 +08001903 case 2:
1904 fourcc = V4L2_PIX_FMT_MPEG2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001905 break;
bo.xiao857b8682024-09-12 16:40:32 +08001906 case 4:
1907 fourcc = V4L2_PIX_FMT_MPEG4;
1908 fourcc_nc = V4L2_PIX_FMT_XVID;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001909 break;
bo.xiao857b8682024-09-12 16:40:32 +08001910 default:
xuesong.jiangae1548e2022-05-06 16:38:46 +08001911 break;
1912 }
bo.xiao857b8682024-09-12 16:40:32 +08001913 }
1914 }
1915 else if (g_str_equal (mimetype, "video/x-fwht"))
1916 {
1917 fourcc = V4L2_PIX_FMT_FWHT;
1918 }
1919 else if (g_str_equal (mimetype, "video/x-h263"))
1920 {
1921 fourcc = V4L2_PIX_FMT_H263;
1922 }
1923 else if (g_str_equal (mimetype, "video/x-h264"))
1924 {
1925 const gchar *stream_format =
1926 gst_structure_get_string (structure, "stream-format");
1927 if (g_str_equal (stream_format, "avc"))
1928 fourcc = V4L2_PIX_FMT_H264_NO_SC;
1929 else
1930 fourcc = V4L2_PIX_FMT_H264;
1931 }
1932 else if (g_str_equal (mimetype, "video/x-h265"))
1933 {
1934 fourcc = V4L2_PIX_FMT_HEVC;
1935 }
1936 else if (g_str_equal (mimetype, "video/x-vp8"))
1937 {
1938 fourcc = V4L2_PIX_FMT_VP8;
1939 }
1940 else if (g_str_equal (mimetype, "video/x-vp9"))
1941 {
1942 fourcc = V4L2_PIX_FMT_VP9;
1943 }
1944 else if (g_str_equal(mimetype, "video/x-av1"))
1945 {
1946 fourcc = V4L2_PIX_FMT_AV1;
1947 }
1948 else if (g_str_equal(mimetype, "video/x-avs"))
1949 {
1950 fourcc = V4L2_PIX_FMT_AVS;
1951 }
1952 else if (g_str_equal(mimetype, "video/x-avs2"))
1953 {
1954 fourcc = V4L2_PIX_FMT_AVS2;
1955 }
1956 else if (g_str_equal(mimetype, "video/x-avs3"))
1957 {
1958 fourcc = V4L2_PIX_FMT_AVS3;
1959 }
1960 else if (g_str_equal (mimetype, "video/x-bayer"))
1961 {
1962 const gchar *vformat = gst_structure_get_string(structure, "format");
1963 if (vformat)
1964 {
1965 if (!g_ascii_strcasecmp(vformat, "bggr"))
1966 fourcc = V4L2_PIX_FMT_SBGGR8;
1967 else if (!g_ascii_strcasecmp(vformat, "gbrg"))
1968 fourcc = V4L2_PIX_FMT_SGBRG8;
1969 else if (!g_ascii_strcasecmp(vformat, "grbg"))
1970 fourcc = V4L2_PIX_FMT_SGRBG8;
1971 else if (!g_ascii_strcasecmp(vformat, "rggb"))
1972 fourcc = V4L2_PIX_FMT_SRGGB8;
1973 }
1974 }
1975 else if (g_str_equal (mimetype, "video/x-sonix"))
1976 {
1977 fourcc = V4L2_PIX_FMT_SN9C10X;
1978 }
1979 else if (g_str_equal (mimetype, "video/x-pwc1"))
1980 {
1981 fourcc = V4L2_PIX_FMT_PWC1;
1982 }
1983 else if (g_str_equal (mimetype, "video/x-pwc2"))
1984 {
1985 fourcc = V4L2_PIX_FMT_PWC2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001986 }
1987 else
1988 {
bo.xiao857b8682024-09-12 16:40:32 +08001989 GST_ERROR("Unknown video codec %s.", mimetype);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001990 }
bo.xiao857b8682024-09-12 16:40:32 +08001991 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001992
bo.xiao857b8682024-09-12 16:40:32 +08001993 /* Prefer the non-contiguous if supported */
1994 v4l2object->prefered_non_contiguous = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001995
bo.xiao857b8682024-09-12 16:40:32 +08001996 if (fourcc_nc)
1997 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_nc);
1998 else if (fourcc == 0)
1999 goto unhandled_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002000
bo.xiao857b8682024-09-12 16:40:32 +08002001 if (fmt == NULL)
2002 {
2003 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
2004 v4l2object->prefered_non_contiguous = FALSE;
2005 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002006
bo.xiao857b8682024-09-12 16:40:32 +08002007 if (fmt == NULL)
2008 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002009
bo.xiao857b8682024-09-12 16:40:32 +08002010 *format = fmt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002011
bo.xiao857b8682024-09-12 16:40:32 +08002012 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002013
bo.xiao857b8682024-09-12 16:40:32 +08002014 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002015invalid_format:
bo.xiao857b8682024-09-12 16:40:32 +08002016 {
2017 GST_DEBUG_OBJECT (v4l2object, "invalid format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002018 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002019 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002020unhandled_format:
bo.xiao857b8682024-09-12 16:40:32 +08002021 {
2022 GST_DEBUG_OBJECT (v4l2object, "unhandled format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002023 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002024 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002025unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08002026 {
2027 GST_DEBUG_OBJECT (v4l2object, "unsupported format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002028 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002029 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002030}
2031
2032static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002033gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
2034 guint32 pixelformat, gint * width, gint * height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002035
2036static void
bo.xiao857b8682024-09-12 16:40:32 +08002037gst_aml_v4l2_object_add_aspect_ratio (GstAmlV4l2Object * v4l2object, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002038{
bo.xiao857b8682024-09-12 16:40:32 +08002039 if (v4l2object->keep_aspect && v4l2object->par)
2040 gst_structure_set_value (s, "pixel-aspect-ratio", v4l2object->par);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002041}
2042
2043/* returns TRUE if the value was changed in place, otherwise FALSE */
2044static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002045gst_aml_v4l2src_value_simplify (GValue * val)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002046{
bo.xiao857b8682024-09-12 16:40:32 +08002047 /* simplify list of one value to one value */
2048 if (GST_VALUE_HOLDS_LIST (val) && gst_value_list_get_size (val) == 1)
2049 {
2050 const GValue *list_val;
2051 GValue new_val = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002052
bo.xiao857b8682024-09-12 16:40:32 +08002053 list_val = gst_value_list_get_value (val, 0);
2054 g_value_init (&new_val, G_VALUE_TYPE (list_val));
2055 g_value_copy (list_val, &new_val);
2056 g_value_unset (val);
2057 *val = new_val;
2058 return TRUE;
2059 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002060
bo.xiao857b8682024-09-12 16:40:32 +08002061 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002062}
2063
2064static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002065gst_aml_v4l2_object_get_interlace_mode (enum v4l2_field field,
2066 GstVideoInterlaceMode * interlace_mode)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002067{
bo.xiao857b8682024-09-12 16:40:32 +08002068 switch (field)
2069 {
2070 case V4L2_FIELD_ANY:
2071 GST_ERROR("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
2072 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002073 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002074 *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
2075 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002076 case V4L2_FIELD_INTERLACED:
2077 case V4L2_FIELD_INTERLACED_TB:
2078 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08002079 *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
2080 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002081 default:
bo.xiao857b8682024-09-12 16:40:32 +08002082 GST_ERROR ("Unknown enum v4l2_field %d", field);
2083 return FALSE;
2084 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002085}
2086
2087static gboolean
2088gst_aml_v4l2_object_get_colorspace(struct v4l2_format *fmt,
2089 GstVideoColorimetry *cinfo)
2090{
bo.xiao857b8682024-09-12 16:40:32 +08002091 gboolean is_rgb =
2092 gst_aml_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat);
2093 enum v4l2_colorspace colorspace;
2094 enum v4l2_quantization range;
2095 enum v4l2_ycbcr_encoding matrix;
2096 enum v4l2_xfer_func transfer;
2097 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002098
bo.xiao857b8682024-09-12 16:40:32 +08002099 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type))
2100 {
2101 colorspace = fmt->fmt.pix_mp.colorspace;
2102 range = fmt->fmt.pix_mp.quantization;
2103 matrix = fmt->fmt.pix_mp.ycbcr_enc;
2104 transfer = fmt->fmt.pix_mp.xfer_func;
2105 }
2106 else
2107 {
2108 colorspace = fmt->fmt.pix.colorspace;
2109 range = fmt->fmt.pix.quantization;
2110 matrix = fmt->fmt.pix.ycbcr_enc;
2111 transfer = fmt->fmt.pix.xfer_func;
2112 }
2113 GST_DEBUG("colorspace:%d, range:%d, matrix:%d, transfer:%d", colorspace, range, matrix, transfer);
2114 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 +08002115
bo.xiao857b8682024-09-12 16:40:32 +08002116 /* First step, set the defaults for each primaries */
2117 switch (colorspace)
2118 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002119 case V4L2_COLORSPACE_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08002120 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2121 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2122 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2123 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
2124 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002125 case V4L2_COLORSPACE_REC709:
bo.xiao857b8682024-09-12 16:40:32 +08002126 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2127 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2128 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2129 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2130 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002131 case V4L2_COLORSPACE_SRGB:
2132 case V4L2_COLORSPACE_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08002133 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2134 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2135 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2136 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2137 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002138 case V4L2_COLORSPACE_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002139 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2140 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2141 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2142 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
2143 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002144 case V4L2_COLORSPACE_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002145 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2146 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2147 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2148 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
2149 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002150 case V4L2_COLORSPACE_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002151 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2152 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2153 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2154 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
2155 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002156 case V4L2_COLORSPACE_470_SYSTEM_M:
bo.xiao857b8682024-09-12 16:40:32 +08002157 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2158 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2159 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2160 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
2161 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002162 case V4L2_COLORSPACE_470_SYSTEM_BG:
bo.xiao857b8682024-09-12 16:40:32 +08002163 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2164 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2165 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2166 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
2167 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002168 case V4L2_COLORSPACE_RAW:
bo.xiao857b8682024-09-12 16:40:32 +08002169 /* Explicitly unknown */
2170 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2171 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2172 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2173 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
2174 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002175 default:
bo.xiao857b8682024-09-12 16:40:32 +08002176 GST_DEBUG ("Unknown enum v4l2_colorspace %d", colorspace);
2177 ret = FALSE;
2178 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002179 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002180 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 +08002181
bo.xiao857b8682024-09-12 16:40:32 +08002182 if (!ret)
2183 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002184
bo.xiao857b8682024-09-12 16:40:32 +08002185 /* Second step, apply any custom variation */
2186 switch (range)
2187 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002188 case V4L2_QUANTIZATION_FULL_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002189 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2190 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002191 case V4L2_QUANTIZATION_LIM_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002192 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2193 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002194 case V4L2_QUANTIZATION_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002195 /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
2196 if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
2197 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2198 else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601
2199 || matrix == V4L2_YCBCR_ENC_XV709
2200 || colorspace == V4L2_COLORSPACE_JPEG)
2201 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2202 else
2203 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2204 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002205 default:
bo.xiao857b8682024-09-12 16:40:32 +08002206 GST_WARNING ("Unknown enum v4l2_quantization value %d", range);
2207 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2208 break;
2209 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002210 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 +08002211
bo.xiao857b8682024-09-12 16:40:32 +08002212 switch (matrix)
2213 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002214 case V4L2_YCBCR_ENC_XV601:
2215 case V4L2_YCBCR_ENC_SYCC:
bo.xiao857b8682024-09-12 16:40:32 +08002216 GST_FIXME ("XV601 and SYCC not defined, assuming 601");
2217 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002218 case V4L2_YCBCR_ENC_601:
bo.xiao857b8682024-09-12 16:40:32 +08002219 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2220 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002221 case V4L2_YCBCR_ENC_XV709:
bo.xiao857b8682024-09-12 16:40:32 +08002222 GST_FIXME ("XV709 not defined, assuming 709");
2223 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002224 case V4L2_YCBCR_ENC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002225 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2226 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002227 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
bo.xiao857b8682024-09-12 16:40:32 +08002228 GST_FIXME ("BT2020 with constant luma is not defined, assuming BT2020");
2229 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002230 case V4L2_YCBCR_ENC_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002231 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2232 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002233 case V4L2_YCBCR_ENC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002234 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2235 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002236 case V4L2_YCBCR_ENC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002237 /* nothing, just use defaults for colorspace */
2238 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002239 default:
bo.xiao857b8682024-09-12 16:40:32 +08002240 GST_WARNING ("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
2241 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2242 break;
2243 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002244 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 +08002245
bo.xiao857b8682024-09-12 16:40:32 +08002246 /* Set identity matrix for R'G'B' formats to avoid creating
2247 * confusion. This though is cosmetic as it's now properly ignored by
2248 * the video info API and videoconvert. */
2249 if (is_rgb)
2250 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002251
bo.xiao857b8682024-09-12 16:40:32 +08002252 switch (transfer)
2253 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002254 case V4L2_XFER_FUNC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002255 if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160)
2256 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2257 else
2258 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2259 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002260 case V4L2_XFER_FUNC_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002261 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2262 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002263 case V4L2_XFER_FUNC_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002264 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2265 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002266 case V4L2_XFER_FUNC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002267 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2268 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002269 case V4L2_XFER_FUNC_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002270 cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
2271 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002272 case V4L2_XFER_FUNC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002273 /* nothing, just use defaults for colorspace */
2274 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002275 default:
bo.xiao857b8682024-09-12 16:40:32 +08002276 GST_WARNING ("Unknown enum v4l2_xfer_func value %d", transfer);
2277 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2278 break;
2279 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002280 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 +08002281
2282done:
bo.xiao857b8682024-09-12 16:40:32 +08002283 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002284}
2285
2286static int
bo.xiao857b8682024-09-12 16:40:32 +08002287gst_aml_v4l2_object_try_fmt (GstAmlV4l2Object * v4l2object,
2288 struct v4l2_format *try_fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002289{
bo.xiao857b8682024-09-12 16:40:32 +08002290 int fd = v4l2object->video_fd;
2291 struct v4l2_format fmt;
2292 int r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002293
bo.xiao857b8682024-09-12 16:40:32 +08002294 memcpy (&fmt, try_fmt, sizeof (fmt));
2295 r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002296
bo.xiao857b8682024-09-12 16:40:32 +08002297 if (r < 0 && errno == ENOTTY)
2298 {
2299 /* The driver might not implement TRY_FMT, in which case we will try
2300 S_FMT to probe */
2301 if (GST_AML_V4L2_IS_ACTIVE (v4l2object))
2302 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002303
bo.xiao857b8682024-09-12 16:40:32 +08002304 memcpy (&fmt, try_fmt, sizeof (fmt));
2305 r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
2306 }
2307 memcpy (try_fmt, &fmt, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002308
bo.xiao857b8682024-09-12 16:40:32 +08002309 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002310
2311error:
bo.xiao857b8682024-09-12 16:40:32 +08002312 memcpy (try_fmt, &fmt, sizeof (fmt));
2313 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2314 "Unable to try format: %s", g_strerror (errno));
2315 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002316}
2317
2318static void
bo.xiao857b8682024-09-12 16:40:32 +08002319gst_aml_v4l2_object_add_interlace_mode (GstAmlV4l2Object * v4l2object,
2320 GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002321{
bo.xiao857b8682024-09-12 16:40:32 +08002322 struct v4l2_format fmt;
2323 GValue interlace_formats = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002324
bo.xiao857b8682024-09-12 16:40:32 +08002325 enum v4l2_field formats[] = {V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED};
2326 gsize i;
2327 GstVideoInterlaceMode interlace_mode, prev = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002328
bo.xiao857b8682024-09-12 16:40:32 +08002329 if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08002330 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002331
bo.xiao857b8682024-09-12 16:40:32 +08002332 if (v4l2object->never_interlaced)
2333 {
2334 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
2335 return;
2336 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002337
bo.xiao857b8682024-09-12 16:40:32 +08002338 g_value_init (&interlace_formats, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002339
bo.xiao857b8682024-09-12 16:40:32 +08002340 /* Try twice - once for NONE, once for INTERLACED. */
2341 for (i = 0; i < G_N_ELEMENTS (formats); i++)
2342 {
2343 memset (&fmt, 0, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002344 fmt.type = v4l2object->type;
2345 fmt.fmt.pix.width = width;
2346 fmt.fmt.pix.height = height;
2347 fmt.fmt.pix.pixelformat = pixelformat;
bo.xiao857b8682024-09-12 16:40:32 +08002348 fmt.fmt.pix.field = formats[i];
xuesong.jiangae1548e2022-05-06 16:38:46 +08002349
bo.xiao857b8682024-09-12 16:40:32 +08002350 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0 &&
2351 gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode)
2352 {
2353 GValue interlace_enum = { 0, };
2354 const gchar *mode_string;
2355 g_value_init (&interlace_enum, G_TYPE_STRING);
2356 mode_string = gst_video_interlace_mode_to_string (interlace_mode);
2357 g_value_set_string (&interlace_enum, mode_string);
2358 gst_value_list_append_and_take_value (&interlace_formats,
2359 &interlace_enum);
2360 prev = interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002361 }
bo.xiao857b8682024-09-12 16:40:32 +08002362 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002363
bo.xiao857b8682024-09-12 16:40:32 +08002364 if (gst_aml_v4l2src_value_simplify (&interlace_formats)
2365 || gst_value_list_get_size (&interlace_formats) > 0)
2366 gst_structure_take_value (s, "interlace-mode", &interlace_formats);
2367 else
2368 GST_WARNING_OBJECT (v4l2object, "Failed to determine interlace mode");
2369
2370 return;
2371}
2372
2373static void
2374gst_aml_v4l2_object_fill_colorimetry_list (GValue * list,
2375 GstVideoColorimetry * cinfo)
2376{
2377 GValue colorimetry = G_VALUE_INIT;
2378 guint size;
2379 guint i;
2380 gboolean found = FALSE;
2381
2382 g_value_init (&colorimetry, G_TYPE_STRING);
2383 g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo));
2384 GST_DEBUG("fill colorimetry:%s into list", gst_video_colorimetry_to_string(cinfo));
2385
2386 /* only insert if no duplicate */
2387 size = gst_value_list_get_size (list);
2388 for (i = 0; i < size; i++)
2389 {
2390 const GValue *tmp;
2391
2392 tmp = gst_value_list_get_value (list, i);
2393 if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002394 {
bo.xiao857b8682024-09-12 16:40:32 +08002395 found = TRUE;
2396 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002397 }
bo.xiao857b8682024-09-12 16:40:32 +08002398 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002399
bo.xiao857b8682024-09-12 16:40:32 +08002400 if (!found)
2401 gst_value_list_append_and_take_value (list, &colorimetry);
2402 else
2403 g_value_unset (&colorimetry);
2404}
xuesong.jiange1a19662022-06-21 20:30:22 +08002405
bo.xiao857b8682024-09-12 16:40:32 +08002406static void
2407gst_aml_v4l2_object_add_colorspace (GstAmlV4l2Object * v4l2object, GstStructure * s,
2408 guint32 width, guint32 height, guint32 pixelformat)
2409{
2410 struct v4l2_format fmt;
2411 GValue list = G_VALUE_INIT;
2412 GstVideoColorimetry cinfo;
2413 enum v4l2_colorspace req_cspace;
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002414
bo.xiao857b8682024-09-12 16:40:32 +08002415 memset (&fmt, 0, sizeof (fmt));
2416 fmt.type = v4l2object->type;
2417 fmt.fmt.pix.width = width;
2418 fmt.fmt.pix.height = height;
2419 fmt.fmt.pix.pixelformat = pixelformat;
xuesong.jiang5c9aca72022-07-12 16:29:24 +08002420
bo.xiao857b8682024-09-12 16:40:32 +08002421 g_value_init (&list, GST_TYPE_LIST);
fei.dengccc89632022-07-15 19:10:17 +08002422
bo.xiao857b8682024-09-12 16:40:32 +08002423 /* step 1: get device default colorspace and insert it first as
2424 * it should be the preferred one */
2425 GST_DEBUG("try for pixl format");
2426 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2427 {
2428 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2429 gst_aml_v4l2_object_fill_colorimetry_list (&list, &cinfo);
2430 }
fei.dengca85b052022-07-19 14:49:23 +08002431
bo.xiao857b8682024-09-12 16:40:32 +08002432 /* step 2: probe all colorspace other than default
2433 * We don't probe all colorspace, range, matrix and transfer combination to
2434 * avoid ioctl flooding which could greatly increase initialization time
2435 * with low-speed devices (UVC...) */
2436 for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
2437 req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++)
2438 {
2439 GST_DEBUG("try for pixl format in while loop :%d", req_cspace);
2440 /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
2441 if (req_cspace == V4L2_COLORSPACE_BT878)
2442 continue;
sheng.liua326d202022-07-20 14:15:34 +08002443
bo.xiao857b8682024-09-12 16:40:32 +08002444 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2445 fmt.fmt.pix_mp.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002446 else
bo.xiao857b8682024-09-12 16:40:32 +08002447 fmt.fmt.pix.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002448
bo.xiao857b8682024-09-12 16:40:32 +08002449 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2450 {
2451 GST_DEBUG("try for pixl format in while loop :%d tried ok", req_cspace);
2452 enum v4l2_colorspace colorspace;
2453
2454 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2455 colorspace = fmt.fmt.pix_mp.colorspace;
2456 else
2457 colorspace = fmt.fmt.pix.colorspace;
2458
2459 if (colorspace == req_cspace)
2460 {
2461 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2462 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2463 }
2464 }
2465 }
2466
2467 GST_DEBUG("deal: caps with colorimetry 2,3,14,7");
2468 cinfo.range = 2;
2469 cinfo.matrix = 3;
2470 cinfo.transfer = 14;
2471 cinfo.primaries = 7;
2472 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2473
2474 GST_DEBUG("deal: caps with colorimetry 2,6,13,7");
2475 cinfo.range = 2;
2476 cinfo.matrix = 6;
2477 cinfo.transfer = 13;
2478 cinfo.primaries = 7;
2479 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2480
2481 GST_DEBUG("deal: caps with colorimetry 2,6,14,7");
2482 cinfo.range = 2;
2483 cinfo.matrix = 6;
2484 cinfo.transfer = 14;
2485 cinfo.primaries = 7;
2486 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2487
2488 GST_DEBUG("deal: caps with colorimetry 2,6,0,7");
2489 cinfo.range = 2;
2490 cinfo.matrix = 6;
2491 cinfo.transfer = 0;
2492 cinfo.primaries = 7;
2493 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2494
2495 GST_DEBUG("deal: caps with colorimetry 0,6,0,7");
2496 cinfo.range = 0;
2497 cinfo.matrix = 6;
2498 cinfo.transfer = 0;
2499 cinfo.primaries = 7;
2500 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2501
2502 GST_DEBUG("deal: caps with colorimetry 2,3,0,0");
2503 cinfo.range = 2;
2504 cinfo.matrix = 3;
2505 cinfo.transfer = 0;
2506 cinfo.primaries = 0;
2507 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2508
2509 GST_DEBUG("deal: caps with colorimetry 2,6,14,0");
2510 cinfo.range = 2;
2511 cinfo.matrix = 6;
2512 cinfo.transfer = 14;
2513 cinfo.primaries = 0;
2514 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2515
2516 if (gst_value_list_get_size (&list) > 0)
2517 gst_structure_take_value (s, "colorimetry", &list);
2518 else
2519 g_value_unset (&list);
2520
2521 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002522}
2523
2524/* The frame interval enumeration code first appeared in Linux 2.6.19. */
2525static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08002526gst_aml_v4l2_object_probe_caps_for_format_and_size (GstAmlV4l2Object * v4l2object,
2527 guint32 pixelformat,
2528 guint32 width, guint32 height, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002529{
bo.xiao857b8682024-09-12 16:40:32 +08002530 gint fd = v4l2object->video_fd;
2531 struct v4l2_frmivalenum ival;
2532 guint32 num, denom;
2533 GstStructure *s;
2534 GValue rates = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002535
bo.xiao857b8682024-09-12 16:40:32 +08002536 memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
2537 ival.index = 0;
2538 ival.pixel_format = pixelformat;
2539 ival.width = width;
2540 ival.height = height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002541
bo.xiao857b8682024-09-12 16:40:32 +08002542 GST_LOG_OBJECT (v4l2object->dbg_obj,
2543 "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
2544 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002545
bo.xiao857b8682024-09-12 16:40:32 +08002546 /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
2547 * fraction to get framerate */
2548 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
2549 goto enum_frameintervals_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002550
bo.xiao857b8682024-09-12 16:40:32 +08002551 if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
2552 {
2553 GValue rate = { 0, };
2554
2555 g_value_init (&rates, GST_TYPE_LIST);
2556 g_value_init (&rate, GST_TYPE_FRACTION);
2557
2558 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002559 {
bo.xiao857b8682024-09-12 16:40:32 +08002560 num = ival.discrete.numerator;
2561 denom = ival.discrete.denominator;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002562
bo.xiao857b8682024-09-12 16:40:32 +08002563 if (num > G_MAXINT || denom > G_MAXINT)
2564 {
2565 /* let us hope we don't get here... */
2566 num >>= 1;
2567 denom >>= 1;
2568 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002569
bo.xiao857b8682024-09-12 16:40:32 +08002570 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
2571 denom, num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002572
bo.xiao857b8682024-09-12 16:40:32 +08002573 /* swap to get the framerate */
2574 gst_value_set_fraction (&rate, denom, num);
2575 gst_value_list_append_value (&rates, &rate);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002576
bo.xiao857b8682024-09-12 16:40:32 +08002577 ival.index++;
2578 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
2579 }
2580 else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
2581 {
2582 GValue min = { 0, };
2583 GValue step = { 0, };
2584 GValue max = { 0, };
2585 gboolean added = FALSE;
2586 guint32 minnum, mindenom;
2587 guint32 maxnum, maxdenom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002588
bo.xiao857b8682024-09-12 16:40:32 +08002589 g_value_init (&rates, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002590
bo.xiao857b8682024-09-12 16:40:32 +08002591 g_value_init (&min, GST_TYPE_FRACTION);
2592 g_value_init (&step, GST_TYPE_FRACTION);
2593 g_value_init (&max, GST_TYPE_FRACTION);
2594
2595 /* get the min */
2596 minnum = ival.stepwise.min.numerator;
2597 mindenom = ival.stepwise.min.denominator;
2598 if (minnum > G_MAXINT || mindenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002599 {
bo.xiao857b8682024-09-12 16:40:32 +08002600 minnum >>= 1;
2601 mindenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002602 }
bo.xiao857b8682024-09-12 16:40:32 +08002603 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
2604 minnum, mindenom);
2605 gst_value_set_fraction (&min, minnum, mindenom);
2606
2607 /* get the max */
2608 maxnum = ival.stepwise.max.numerator;
2609 maxdenom = ival.stepwise.max.denominator;
2610 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002611 {
bo.xiao857b8682024-09-12 16:40:32 +08002612 maxnum >>= 1;
2613 maxdenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002614 }
bo.xiao857b8682024-09-12 16:40:32 +08002615
2616 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
2617 maxnum, maxdenom);
2618 gst_value_set_fraction (&max, maxnum, maxdenom);
2619
2620 /* get the step */
2621 num = ival.stepwise.step.numerator;
2622 denom = ival.stepwise.step.denominator;
2623 if (num > G_MAXINT || denom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002624 {
bo.xiao857b8682024-09-12 16:40:32 +08002625 num >>= 1;
2626 denom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002627 }
2628
bo.xiao857b8682024-09-12 16:40:32 +08002629 if (num == 0 || denom == 0)
2630 {
2631 /* in this case we have a wrong fraction or no step, set the step to max
2632 * so that we only add the min value in the loop below */
2633 num = maxnum;
2634 denom = maxdenom;
2635 }
2636
2637 /* since we only have gst_value_fraction_subtract and not add, negate the
2638 * numerator */
2639 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
2640 num, denom);
2641 gst_value_set_fraction (&step, -num, denom);
2642
2643 while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN)
2644 {
2645 GValue rate = { 0, };
2646
2647 num = gst_value_get_fraction_numerator (&min);
2648 denom = gst_value_get_fraction_denominator (&min);
2649 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
2650 denom, num);
2651
2652 /* invert to get the framerate */
2653 g_value_init (&rate, GST_TYPE_FRACTION);
2654 gst_value_set_fraction (&rate, denom, num);
2655 gst_value_list_append_value (&rates, &rate);
2656 added = TRUE;
2657
2658 /* we're actually adding because step was negated above. This is because
2659 * there is no _add function... */
2660 if (!gst_value_fraction_subtract (&min, &min, &step))
2661 {
2662 GST_WARNING_OBJECT (v4l2object->dbg_obj, "could not step fraction!");
2663 break;
2664 }
2665 }
2666 if (!added)
2667 {
2668 /* no range was added, leave the default range from the template */
2669 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2670 "no range added, leaving default");
2671 g_value_unset (&rates);
2672 }
2673 }
2674 else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
2675 {
2676 guint32 maxnum, maxdenom;
2677
2678 g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
2679
2680 num = ival.stepwise.min.numerator;
2681 denom = ival.stepwise.min.denominator;
2682 if (num > G_MAXINT || denom > G_MAXINT)
2683 {
2684 num >>= 1;
2685 denom >>= 1;
2686 }
2687
2688 maxnum = ival.stepwise.max.numerator;
2689 maxdenom = ival.stepwise.max.denominator;
2690 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2691 {
2692 maxnum >>= 1;
2693 maxdenom >>= 1;
2694 }
2695
2696 GST_LOG_OBJECT (v4l2object->dbg_obj,
2697 "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2698 num);
2699
2700 gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
2701 }
2702 else
2703 {
2704 goto unknown_type;
2705 }
2706
xuesong.jiangae1548e2022-05-06 16:38:46 +08002707return_data:
bo.xiao857b8682024-09-12 16:40:32 +08002708 s = gst_structure_copy (template);
2709 gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
2710 "height", G_TYPE_INT, (gint) height, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002711
bo.xiao857b8682024-09-12 16:40:32 +08002712 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002713
bo.xiao857b8682024-09-12 16:40:32 +08002714 if (!v4l2object->skip_try_fmt_probes)
2715 {
2716 gst_aml_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
2717 pixelformat);
2718 // gst_aml_v4l2_object_add_colorspace(v4l2object, s, width, height, pixelformat);
2719 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002720
bo.xiao857b8682024-09-12 16:40:32 +08002721 if (G_IS_VALUE (&rates))
2722 {
2723 gst_aml_v4l2src_value_simplify (&rates);
2724 /* only change the framerate on the template when we have a valid probed new
2725 * value */
2726 gst_structure_take_value (s, "framerate", &rates);
2727 }
2728 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2729 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2730 {
2731 gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
2732 1, NULL);
2733 }
2734 return s;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002735
bo.xiao857b8682024-09-12 16:40:32 +08002736 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002737enum_frameintervals_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002738 {
2739 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2740 "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2741 GST_FOURCC_ARGS (pixelformat), width, height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002742 goto return_data;
bo.xiao857b8682024-09-12 16:40:32 +08002743 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002744unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08002745 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002746 /* I don't see how this is actually an error, we ignore the format then */
bo.xiao857b8682024-09-12 16:40:32 +08002747 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2748 "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2749 GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002750 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +08002751 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002752}
2753
2754static gint
bo.xiao857b8682024-09-12 16:40:32 +08002755sort_by_frame_size (GstStructure * s1, GstStructure * s2)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002756{
bo.xiao857b8682024-09-12 16:40:32 +08002757 int w1, h1, w2, h2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002758
bo.xiao857b8682024-09-12 16:40:32 +08002759 gst_structure_get_int (s1, "width", &w1);
2760 gst_structure_get_int (s1, "height", &h1);
2761 gst_structure_get_int (s2, "width", &w2);
2762 gst_structure_get_int (s2, "height", &h2);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002763
bo.xiao857b8682024-09-12 16:40:32 +08002764 /* I think it's safe to assume that this won't overflow for a while */
2765 return ((w2 * h2) - (w1 * h1));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002766}
2767
2768static void
bo.xiao857b8682024-09-12 16:40:32 +08002769gst_aml_v4l2_object_update_and_append (GstAmlV4l2Object * v4l2object,
2770 guint32 format, GstCaps * caps, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002771{
bo.xiao857b8682024-09-12 16:40:32 +08002772 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002773
bo.xiao857b8682024-09-12 16:40:32 +08002774 /* Encoded stream on output buffer need to be parsed */
2775 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
2776 v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2777 {
2778 gint i = 0;
2779
2780 for (; i < GST_AML_V4L2_FORMAT_COUNT; i++)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002781 {
bo.xiao857b8682024-09-12 16:40:32 +08002782 if (format == gst_aml_v4l2_formats[i].format &&
2783 gst_aml_v4l2_formats[i].flags & GST_V4L2_CODEC &&
2784 !(gst_aml_v4l2_formats[i].flags & GST_V4L2_NO_PARSE))
2785 {
2786 gst_structure_set (s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2787 break;
2788 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002789 }
bo.xiao857b8682024-09-12 16:40:32 +08002790 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002791
bo.xiao857b8682024-09-12 16:40:32 +08002792 if (v4l2object->has_alpha_component &&
2793 (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2794 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
2795 {
2796 switch (format)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002797 {
bo.xiao857b8682024-09-12 16:40:32 +08002798 case V4L2_PIX_FMT_RGB32:
2799 alt_s = gst_structure_copy (s);
2800 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
2801 break;
2802 case V4L2_PIX_FMT_BGR32:
2803 alt_s = gst_structure_copy (s);
2804 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
2805 break;
2806 default:
2807 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002808 }
bo.xiao857b8682024-09-12 16:40:32 +08002809 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002810
bo.xiao857b8682024-09-12 16:40:32 +08002811 gst_caps_append_structure(caps, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002812
bo.xiao857b8682024-09-12 16:40:32 +08002813 if (alt_s)
2814 gst_caps_append_structure(caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002815}
2816
2817static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08002818gst_aml_v4l2_object_probe_caps_for_format (GstAmlV4l2Object * v4l2object,
2819 guint32 pixelformat, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002820{
bo.xiao857b8682024-09-12 16:40:32 +08002821 GstCaps *ret = gst_caps_new_empty ();
2822 GstStructure *tmp;
2823 gint fd = v4l2object->video_fd;
2824 struct v4l2_frmsizeenum size;
2825 GList *results = NULL;
2826 guint32 w, h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002827
bo.xiao857b8682024-09-12 16:40:32 +08002828 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
2829 {
2830 gst_caps_append_structure (ret, gst_structure_copy (template));
2831 return ret;
2832 }
2833
2834 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
2835 size.index = 0;
2836 size.pixel_format = pixelformat;
2837
2838 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2839 "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2840 GST_FOURCC_ARGS (pixelformat));
2841
2842 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2843 goto enum_framesizes_failed;
2844
2845 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
2846 {
2847 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002848 {
bo.xiao857b8682024-09-12 16:40:32 +08002849 GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
2850 size.discrete.width, size.discrete.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002851
bo.xiao857b8682024-09-12 16:40:32 +08002852 w = MIN (size.discrete.width, G_MAXINT);
2853 h = MIN (size.discrete.height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002854
bo.xiao857b8682024-09-12 16:40:32 +08002855 if (w && h)
2856 {
2857 tmp =
2858 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2859 pixelformat, w, h, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002860
bo.xiao857b8682024-09-12 16:40:32 +08002861 if (tmp)
2862 results = g_list_prepend (results, tmp);
2863 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002864
bo.xiao857b8682024-09-12 16:40:32 +08002865 size.index++;
2866 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2867 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2868 "done iterating discrete frame sizes");
2869 }
2870 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
2871 {
2872 guint32 maxw, maxh, step_w, step_h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002873
bo.xiao857b8682024-09-12 16:40:32 +08002874 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have stepwise frame sizes:");
2875 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2876 size.stepwise.min_width);
2877 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2878 size.stepwise.min_height);
2879 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2880 size.stepwise.max_width);
2881 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2882 size.stepwise.max_height);
2883 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step width: %d",
2884 size.stepwise.step_width);
2885 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step height: %d",
2886 size.stepwise.step_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002887
fei.dengf21a6c92024-09-05 11:30:36 +08002888 if (pixelformat == V4L2_PIX_FMT_NV12 ||
2889 pixelformat == V4L2_PIX_FMT_NV21 ||
2890 pixelformat == V4L2_PIX_FMT_NV12M ||
2891 pixelformat == V4L2_PIX_FMT_NV21M) {
2892 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2893 "set %" GST_FOURCC_FORMAT " min width and height to 16",
2894 GST_FOURCC_ARGS(pixelformat));
2895 w = 16;
2896 h = 16;
2897 } else {
2898 w = MAX(size.stepwise.min_width, 1);
2899 h = MAX(size.stepwise.min_height, 1);
2900 }
bo.xiao857b8682024-09-12 16:40:32 +08002901 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2902 maxh = MIN (size.stepwise.max_height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002903
bo.xiao857b8682024-09-12 16:40:32 +08002904 /* in this position,updating resolution only to pass the negotiation
2905 * actually, the details about resolution refer to function:
2906 * gst_aml_v4l2_object_set_format_full for checking.
2907 */
2908 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "update maxw_maxh to MAX(maxw,maxh)_MAX(maxw,maxh)");
2909 maxh = MAX (maxw, maxh);
2910 maxw = maxh;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00002911
bo.xiao857b8682024-09-12 16:40:32 +08002912 step_w = MAX (size.stepwise.step_width, 1);
2913 step_h = MAX (size.stepwise.step_height, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002914
bo.xiao857b8682024-09-12 16:40:32 +08002915 /* FIXME: check for sanity and that min/max are multiples of the steps */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002916
bo.xiao857b8682024-09-12 16:40:32 +08002917 /* we only query details for the max width/height since it's likely the
2918 * most restricted if there are any resolution-dependent restrictions */
2919 tmp = gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2920 pixelformat, maxw, maxh, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002921
bo.xiao857b8682024-09-12 16:40:32 +08002922 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002923 {
bo.xiao857b8682024-09-12 16:40:32 +08002924 GValue step_range = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002925
bo.xiao857b8682024-09-12 16:40:32 +08002926 g_value_init (&step_range, GST_TYPE_INT_RANGE);
2927 gst_value_set_int_range_step (&step_range, w, maxw, step_w);
2928 gst_structure_set_value (tmp, "width", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002929
bo.xiao857b8682024-09-12 16:40:32 +08002930 gst_value_set_int_range_step (&step_range, h, maxh, step_h);
2931 gst_structure_take_value (tmp, "height", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002932
bo.xiao857b8682024-09-12 16:40:32 +08002933 /* no point using the results list here, since there's only one struct */
2934 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002935 }
bo.xiao857b8682024-09-12 16:40:32 +08002936 }
2937 else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
2938 {
2939 guint32 maxw, maxh;
2940
2941 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have continuous frame sizes:");
2942 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2943 size.stepwise.min_width);
2944 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2945 size.stepwise.min_height);
2946 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2947 size.stepwise.max_width);
2948 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2949 size.stepwise.max_height);
2950
2951 w = MAX (size.stepwise.min_width, 1);
2952 h = MAX (size.stepwise.min_height, 1);
2953 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2954 maxh = MIN (size.stepwise.max_height, G_MAXINT);
2955
2956 tmp =
2957 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
2958 w, h, template);
2959 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002960 {
bo.xiao857b8682024-09-12 16:40:32 +08002961 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
2962 (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
2963 NULL);
2964
2965 /* no point using the results list here, since there's only one struct */
2966 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002967 }
bo.xiao857b8682024-09-12 16:40:32 +08002968 }
2969 else
2970 {
2971 goto unknown_type;
2972 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002973
bo.xiao857b8682024-09-12 16:40:32 +08002974 /* we use an intermediary list to store and then sort the results of the
2975 * probing because we can't make any assumptions about the order in which
2976 * the driver will give us the sizes, but we want the final caps to contain
2977 * the results starting with the highest resolution and having the lowest
2978 * resolution last, since order in caps matters for things like fixation. */
2979 results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
2980 while (results != NULL)
2981 {
2982 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret,
2983 results->data);
2984 results = g_list_delete_link (results, results);
2985 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002986
bo.xiao857b8682024-09-12 16:40:32 +08002987 if (gst_caps_is_empty (ret))
2988 goto enum_framesizes_no_results;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002989
bo.xiao857b8682024-09-12 16:40:32 +08002990 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002991
bo.xiao857b8682024-09-12 16:40:32 +08002992 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002993enum_framesizes_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002994 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002995 /* I don't see how this is actually an error */
bo.xiao857b8682024-09-12 16:40:32 +08002996 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2997 "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
2998 " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002999 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003000 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003001enum_framesizes_no_results:
bo.xiao857b8682024-09-12 16:40:32 +08003002 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003003 /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
3004 * question doesn't actually support it yet */
bo.xiao857b8682024-09-12 16:40:32 +08003005 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3006 "No results for pixelformat %" GST_FOURCC_FORMAT
3007 " enumerating frame sizes, trying fallback",
3008 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003009 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003010 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003011unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08003012 {
3013 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3014 "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
3015 ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003016 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003017 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003018
3019default_frame_sizes:
bo.xiao857b8682024-09-12 16:40:32 +08003020 {
bo.xiao34e36202024-07-17 16:04:01 +08003021 gint min_w, max_w, min_h, max_h;
3022
3023#ifdef DELETE_FOR_LGE
3024 gint fix_num = 0, fix_denom = 0;
3025#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08003026
3027 /* This code is for Linux < 2.6.19 */
3028 min_w = min_h = 1;
3029 max_w = max_h = GST_AML_V4L2_MAX_SIZE;
bo.xiao857b8682024-09-12 16:40:32 +08003030 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
3031 &min_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003032 {
bo.xiao857b8682024-09-12 16:40:32 +08003033 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3034 "Could not probe minimum capture size for pixelformat %"
3035 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003036 }
bo.xiao857b8682024-09-12 16:40:32 +08003037 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
3038 &max_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003039 {
bo.xiao857b8682024-09-12 16:40:32 +08003040 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3041 "Could not probe maximum capture size for pixelformat %"
3042 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003043 }
3044
bo.xiao857b8682024-09-12 16:40:32 +08003045
3046 tmp = gst_structure_copy (template);
hanghang.luo3128f102022-08-18 10:36:19 +08003047#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08003048 if (fix_num)
3049 {
bo.xiao857b8682024-09-12 16:40:32 +08003050 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
3051 fix_denom, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003052 }
hanghang.luo3128f102022-08-18 10:36:19 +08003053 else
3054#endif
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003055 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
3056 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003057 {
bo.xiao857b8682024-09-12 16:40:32 +08003058 /* if norm can't be used, copy the template framerate */
3059 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
3060 G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003061 }
3062
3063 if (min_w == max_w)
bo.xiao857b8682024-09-12 16:40:32 +08003064 gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003065 else
bo.xiao857b8682024-09-12 16:40:32 +08003066 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003067
3068 if (min_h == max_h)
bo.xiao857b8682024-09-12 16:40:32 +08003069 gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003070 else
bo.xiao857b8682024-09-12 16:40:32 +08003071 gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003072
bo.xiao857b8682024-09-12 16:40:32 +08003073 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003074
3075 if (!v4l2object->skip_try_fmt_probes)
3076 {
bo.xiao857b8682024-09-12 16:40:32 +08003077 /* We could consider setting interlace mode from min and max. */
3078 gst_aml_v4l2_object_add_interlace_mode(v4l2object, tmp, max_w, max_h,
3079 pixelformat);
3080 /* We could consider to check colorspace for min too, in case it depends on
3081 * the size. But in this case, min and max could not be enough */
3082 gst_aml_v4l2_object_add_colorspace(v4l2object, tmp, max_w, max_h,
3083 pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003084 }
3085
bo.xiao857b8682024-09-12 16:40:32 +08003086 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003087 return ret;
bo.xiao857b8682024-09-12 16:40:32 +08003088 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003089}
3090
3091static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003092gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
3093 guint32 pixelformat, gint * width, gint * height)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003094{
bo.xiao857b8682024-09-12 16:40:32 +08003095 struct v4l2_format fmt;
3096 gboolean ret = FALSE;
3097 GstVideoInterlaceMode interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003098
bo.xiao857b8682024-09-12 16:40:32 +08003099 g_return_val_if_fail (width != NULL, FALSE);
3100 g_return_val_if_fail (height != NULL, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003101
bo.xiao857b8682024-09-12 16:40:32 +08003102 GST_LOG_OBJECT (v4l2object->dbg_obj,
3103 "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
3104 *width, *height, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003105
bo.xiao857b8682024-09-12 16:40:32 +08003106 memset (&fmt, 0, sizeof (struct v4l2_format));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003107
bo.xiao857b8682024-09-12 16:40:32 +08003108 /* get size delimiters */
3109 memset (&fmt, 0, sizeof (fmt));
3110 fmt.type = v4l2object->type;
3111 fmt.fmt.pix.width = *width;
3112 fmt.fmt.pix.height = *height;
3113 fmt.fmt.pix.pixelformat = pixelformat;
3114 fmt.fmt.pix.field = V4L2_FIELD_ANY;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003115
bo.xiao857b8682024-09-12 16:40:32 +08003116 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
3117 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003118
bo.xiao857b8682024-09-12 16:40:32 +08003119 GST_LOG_OBJECT (v4l2object->dbg_obj,
3120 "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003121
bo.xiao857b8682024-09-12 16:40:32 +08003122 *width = fmt.fmt.pix.width;
3123 *height = fmt.fmt.pix.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003124
bo.xiao857b8682024-09-12 16:40:32 +08003125 if (!gst_aml_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode))
3126 {
3127 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3128 "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
3129 GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
3130 goto error;
3131 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003132
bo.xiao857b8682024-09-12 16:40:32 +08003133 ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003134
3135error:
bo.xiao857b8682024-09-12 16:40:32 +08003136 if (!ret)
3137 {
3138 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3139 "Unable to try format: %s", g_strerror (errno));
3140 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003141
bo.xiao857b8682024-09-12 16:40:32 +08003142 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003143}
3144
3145static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003146gst_aml_v4l2_object_is_dmabuf_supported (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003147{
bo.xiao857b8682024-09-12 16:40:32 +08003148 gboolean ret = TRUE;
3149 struct v4l2_exportbuffer expbuf = {
3150 .type = v4l2object->type,
3151 .index = -1,
3152 .plane = -1,
3153 .flags = O_CLOEXEC | O_RDWR,
3154 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003155
bo.xiao857b8682024-09-12 16:40:32 +08003156 if (v4l2object->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
3157 {
3158 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3159 "libv4l2 converter detected, disabling DMABuf");
3160 ret = FALSE;
3161 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003162
bo.xiao857b8682024-09-12 16:40:32 +08003163 /* Expected to fail, but ENOTTY tells us that it is not implemented. */
3164 v4l2object->ioctl (v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
3165 if (errno == ENOTTY)
3166 ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003167
bo.xiao857b8682024-09-12 16:40:32 +08003168 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003169}
3170
3171static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003172gst_aml_v4l2_object_setup_pool (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003173{
bo.xiao857b8682024-09-12 16:40:32 +08003174 GstAmlV4l2IOMode mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003175
bo.xiao857b8682024-09-12 16:40:32 +08003176 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "initializing the %s system",
3177 V4L2_TYPE_IS_OUTPUT (v4l2object->type) ? "output" : "capture");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003178
bo.xiao857b8682024-09-12 16:40:32 +08003179 GST_AML_V4L2_CHECK_OPEN (v4l2object);
3180 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003181
bo.xiao857b8682024-09-12 16:40:32 +08003182 /* find transport */
3183 mode = v4l2object->req_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003184
bo.xiao857b8682024-09-12 16:40:32 +08003185 if (v4l2object->device_caps & V4L2_CAP_READWRITE)
3186 {
3187 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3188 mode = GST_V4L2_IO_RW;
3189 }
3190 else if (v4l2object->req_mode == GST_V4L2_IO_RW)
3191 goto method_not_supported;
3192
3193 if (v4l2object->device_caps & V4L2_CAP_STREAMING)
3194 {
3195 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003196 {
bo.xiao857b8682024-09-12 16:40:32 +08003197 if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
3198 gst_aml_v4l2_object_is_dmabuf_supported (v4l2object))
3199 {
3200 mode = GST_V4L2_IO_DMABUF;
3201 }
3202 else
3203 {
3204 mode = GST_V4L2_IO_MMAP;
3205 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003206 }
bo.xiao857b8682024-09-12 16:40:32 +08003207 }
3208 else if (v4l2object->req_mode == GST_V4L2_IO_MMAP ||
3209 v4l2object->req_mode == GST_V4L2_IO_DMABUF)
3210 goto method_not_supported;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003211
bo.xiao857b8682024-09-12 16:40:32 +08003212 /* if still no transport selected, error out */
3213 if (mode == GST_V4L2_IO_AUTO)
3214 goto no_supported_capture_method;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003215
bo.xiao857b8682024-09-12 16:40:32 +08003216 GST_INFO_OBJECT (v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
3217 v4l2object->mode = mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003218
bo.xiao857b8682024-09-12 16:40:32 +08003219 /* If min_buffers is not set, the driver either does not support the control or
3220 it has not been asked yet via propose_allocation/decide_allocation. */
3221 if (!v4l2object->min_buffers)
3222 gst_aml_v4l2_get_driver_min_buffers (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003223
bo.xiao857b8682024-09-12 16:40:32 +08003224 /* Map the buffers */
3225 GST_LOG_OBJECT (v4l2object->dbg_obj, "initiating buffer pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003226
3227 if (!(v4l2object->pool = gst_aml_v4l2_buffer_pool_new(v4l2object, caps)))
bo.xiao857b8682024-09-12 16:40:32 +08003228 goto buffer_pool_new_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003229
bo.xiao857b8682024-09-12 16:40:32 +08003230 GST_AML_V4L2_SET_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003231
bo.xiao857b8682024-09-12 16:40:32 +08003232 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003233
bo.xiao857b8682024-09-12 16:40:32 +08003234 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003235buffer_pool_new_failed:
bo.xiao857b8682024-09-12 16:40:32 +08003236 {
3237 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3238 (_("Could not map buffers from device '%s'"),
3239 v4l2object->videodev),
3240 ("Failed to create buffer pool: %s", g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003241 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003242 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003243method_not_supported:
bo.xiao857b8682024-09-12 16:40:32 +08003244 {
3245 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3246 (_("The driver of device '%s' does not support the IO method %d"),
3247 v4l2object->videodev, mode), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003248 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003249 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003250no_supported_capture_method:
bo.xiao857b8682024-09-12 16:40:32 +08003251 {
3252 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3253 (_("The driver of device '%s' does not support any known IO "
3254 "method."), v4l2object->videodev), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003255 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003256 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003257}
3258
3259static void
bo.xiao857b8682024-09-12 16:40:32 +08003260gst_aml_v4l2_object_set_stride (GstVideoInfo * info, GstVideoAlignment * align,
3261 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003262{
bo.xiao857b8682024-09-12 16:40:32 +08003263 const GstVideoFormatInfo *finfo = info->finfo;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003264
bo.xiao857b8682024-09-12 16:40:32 +08003265 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3266 {
3267 gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003268
bo.xiao857b8682024-09-12 16:40:32 +08003269 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
3270 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3271 tile_height = 1 << hs;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003272
bo.xiao857b8682024-09-12 16:40:32 +08003273 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
3274 info->height + align->padding_top + align->padding_bottom);
3275 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003276
bo.xiao857b8682024-09-12 16:40:32 +08003277 x_tiles = stride >> ws;
3278 y_tiles = padded_height >> hs;
3279 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
3280 }
3281 else
3282 {
3283 info->stride[plane] = stride;
3284 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003285}
3286
3287static void
bo.xiao857b8682024-09-12 16:40:32 +08003288gst_aml_v4l2_object_extrapolate_info (GstAmlV4l2Object * v4l2object,
3289 GstVideoInfo * info, GstVideoAlignment * align, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003290{
bo.xiao857b8682024-09-12 16:40:32 +08003291 const GstVideoFormatInfo *finfo = info->finfo;
3292 gint i, estride, padded_height;
3293 gsize offs = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003294
bo.xiao857b8682024-09-12 16:40:32 +08003295 g_return_if_fail (v4l2object->n_v4l2_planes == 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003296
bo.xiao857b8682024-09-12 16:40:32 +08003297 padded_height = info->height + align->padding_top + align->padding_bottom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003298
bo.xiao857b8682024-09-12 16:40:32 +08003299 for (i = 0; i < finfo->n_planes; i++)
3300 {
3301 estride = gst_aml_v4l2_object_extrapolate_stride (finfo, i, stride);
3302
3303 gst_aml_v4l2_object_set_stride (info, align, i, estride);
3304
3305 info->offset[i] = offs;
3306 offs += estride *
3307 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, padded_height);
3308
3309 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3310 "Extrapolated for plane %d with base stride %d: "
3311 "stride %d, offset %" G_GSIZE_FORMAT, i, stride, info->stride[i],
3312 info->offset[i]);
3313 }
3314
3315 /* Update the image size according the amount of data we are going to
3316 * read/write. This workaround bugs in driver where the sizeimage provided
3317 * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
3318 * bytesused (buffer size). */
3319 if (offs < info->size)
3320 info->size = offs;
3321}
3322
3323static void
3324gst_aml_v4l2_object_save_format (GstAmlV4l2Object * v4l2object,
3325 struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
3326 GstVideoInfo * info, GstVideoAlignment * align)
3327{
3328 const GstVideoFormatInfo *finfo = info->finfo;
3329 gboolean standard_stride = TRUE;
3330 gint stride, pstride, padded_width, padded_height, i;
3331
3332 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED)
3333 {
3334 v4l2object->n_v4l2_planes = 1;
3335 info->size = format->fmt.pix.sizeimage;
3336 goto store_info;
3337 }
3338
3339 /* adjust right padding */
3340 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3341 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3342 else
3343 stride = format->fmt.pix.bytesperline;
3344
3345 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (finfo, 0);
3346 if (pstride)
3347 {
3348 padded_width = stride / pstride;
3349 }
3350 else
3351 {
3352 /* pstride can be 0 for complex formats */
3353 GST_WARNING_OBJECT (v4l2object->element,
3354 "format %s has a pstride of 0, cannot compute padded with",
3355 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
3356 padded_width = stride;
3357 }
3358
3359 if (padded_width < format->fmt.pix.width)
3360 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3361 "Driver bug detected, stride (%d) is too small for the width (%d)",
3362 padded_width, format->fmt.pix.width);
3363
3364 align->padding_right = padded_width - info->width - align->padding_left;
3365
3366 /* adjust bottom padding */
3367 padded_height = format->fmt.pix.height;
3368
3369 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3370 {
3371 guint hs, tile_height;
3372
3373 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3374 tile_height = 1 << hs;
3375
3376 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
3377 }
3378
3379 align->padding_bottom = padded_height - info->height - align->padding_top;
3380
3381 /* setup the strides and offset */
3382 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3383 {
3384 struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
3385
3386 /* figure out the frame layout */
3387 v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes);
3388 info->size = 0;
3389 for (i = 0; i < v4l2object->n_v4l2_planes; i++)
3390 {
3391 stride = pix_mp->plane_fmt[i].bytesperline;
3392
3393 if (info->stride[i] != stride)
3394 standard_stride = FALSE;
3395
3396 gst_aml_v4l2_object_set_stride (info, align, i, stride);
3397 info->offset[i] = info->size;
3398 info->size += pix_mp->plane_fmt[i].sizeimage;
3399 }
3400
3401 /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
3402 if (v4l2object->n_v4l2_planes < finfo->n_planes)
3403 {
3404 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3405 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3406 }
3407 }
3408 else
3409 {
3410 /* only one plane in non-MPLANE mode */
3411 v4l2object->n_v4l2_planes = 1;
3412 info->size = format->fmt.pix.sizeimage;
3413 stride = format->fmt.pix.bytesperline;
3414
3415 if (info->stride[0] != stride)
3416 standard_stride = FALSE;
3417
3418 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3419 }
3420
3421 /* adjust the offset to take into account left and top */
3422 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3423 {
3424 if ((align->padding_left + align->padding_top) > 0)
3425 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3426 "Left and top padding is not permitted for tiled formats");
3427 }
3428 else
3429 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003430 for (i = 0; i < finfo->n_planes; i++)
3431 {
bo.xiao857b8682024-09-12 16:40:32 +08003432 gint vedge, hedge;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003433
bo.xiao857b8682024-09-12 16:40:32 +08003434 /* FIXME we assume plane as component as this is true for all supported
3435 * format we support. */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003436
bo.xiao857b8682024-09-12 16:40:32 +08003437 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, align->padding_left);
3438 vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, align->padding_top);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003439
bo.xiao857b8682024-09-12 16:40:32 +08003440 info->offset[i] += (vedge * info->stride[i]) +
3441 (hedge * GST_VIDEO_INFO_COMP_PSTRIDE (info, i));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003442 }
bo.xiao857b8682024-09-12 16:40:32 +08003443 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003444
3445store_info:
bo.xiao857b8682024-09-12 16:40:32 +08003446 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
3447 info->size);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003448
bo.xiao857b8682024-09-12 16:40:32 +08003449 /* to avoid copies we need video meta if there is padding */
3450 v4l2object->need_video_meta =
3451 ((align->padding_top + align->padding_left + align->padding_right +
xuesong.jiangae1548e2022-05-06 16:38:46 +08003452 align->padding_bottom) != 0);
3453
bo.xiao857b8682024-09-12 16:40:32 +08003454 /* ... or if stride is non "standard" */
3455 if (!standard_stride)
3456 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003457
bo.xiao857b8682024-09-12 16:40:32 +08003458 /* ... or also video meta if we use multiple, non-contiguous, planes */
3459 if (v4l2object->n_v4l2_planes > 1)
3460 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003461
bo.xiao857b8682024-09-12 16:40:32 +08003462 v4l2object->info = *info;
3463 v4l2object->align = *align;
3464 v4l2object->format = *format;
3465 v4l2object->fmtdesc = fmtdesc;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003466
bo.xiao857b8682024-09-12 16:40:32 +08003467 /* if we have a framerate pre-calculate duration */
3468 if (info->fps_n > 0 && info->fps_d > 0)
3469 {
3470 v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
3471 info->fps_n);
3472 }
3473 else
3474 {
3475 v4l2object->duration = GST_CLOCK_TIME_NONE;
3476 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003477}
3478
bo.xiao857b8682024-09-12 16:40:32 +08003479gint
3480gst_aml_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
3481 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003482{
bo.xiao857b8682024-09-12 16:40:32 +08003483 gint estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003484
bo.xiao857b8682024-09-12 16:40:32 +08003485 switch (finfo->format)
3486 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003487 case GST_VIDEO_FORMAT_NV12:
3488 case GST_VIDEO_FORMAT_NV12_64Z32:
3489 case GST_VIDEO_FORMAT_NV21:
3490 case GST_VIDEO_FORMAT_NV16:
3491 case GST_VIDEO_FORMAT_NV61:
3492 case GST_VIDEO_FORMAT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08003493 estride = (plane == 0 ? 1 : 2) *
3494 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3495 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003496 default:
bo.xiao857b8682024-09-12 16:40:32 +08003497 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3498 break;
3499 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003500
bo.xiao857b8682024-09-12 16:40:32 +08003501 return estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003502}
3503
3504static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003505gst_aml_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
xuesong.jiangae1548e2022-05-06 16:38:46 +08003506 const gchar *color)
3507{
bo.xiao857b8682024-09-12 16:40:32 +08003508 GstVideoColorimetry ci;
3509 static const GstVideoColorimetry ci_likely_jpeg = {
3510 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3511 GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN
3512 };
3513 static const GstVideoColorimetry ci_jpeg = {
3514 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3515 GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709
3516 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003517
bo.xiao857b8682024-09-12 16:40:32 +08003518 if (!gst_video_colorimetry_from_string(&ci, color))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003519 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003520
3521 if (gst_video_colorimetry_is_equal(&ci, cinfo))
3522 return TRUE;
3523
3524 /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */
3525 if (gst_video_colorimetry_is_equal(&ci, &ci_likely_jpeg) && gst_video_colorimetry_is_equal(cinfo, &ci_jpeg))
3526 return TRUE;
3527
3528 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003529}
3530
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003531static gboolean needSpecConfigForFg(GstAmlV4l2Object *v4l2object)
3532{
bo.xiao857b8682024-09-12 16:40:32 +08003533 gboolean result= FALSE;
3534 int fd = -1;
3535 char valstr[64];
3536 const char* path= "/sys/class/video/film_grain_support";
3537 uint32_t val= 0;
3538 struct v4l2_control ctl;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003539
bo.xiao857b8682024-09-12 16:40:32 +08003540 GST_LOG("configForFilmGrain: enter");
3541 fd = open(path, O_RDONLY|O_CLOEXEC);
3542 if ( fd < 0 )
3543 {
3544 GST_DEBUG("unable to open file (%s)", path);
3545 goto exit;
3546 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003547
bo.xiao857b8682024-09-12 16:40:32 +08003548 memset(valstr, 0, sizeof(valstr));
3549 if (read(fd, valstr, sizeof(valstr) - 1) == -1 )
3550 {
3551 GST_DEBUG("unable to read fg flag");
3552 goto exit;
3553 }
bo.xiao34e36202024-07-17 16:04:01 +08003554
bo.xiao857b8682024-09-12 16:40:32 +08003555 valstr[strlen(valstr)] = '\0';
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003556
bo.xiao857b8682024-09-12 16:40:32 +08003557 if ( sscanf(valstr, "%u", &val) < 1)
3558 {
3559 GST_DEBUG("unable to get flag from: (%s)", valstr);
3560 goto exit;
3561 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003562
bo.xiao857b8682024-09-12 16:40:32 +08003563 GST_LOG("got film_grain_support:%d from node", val);
3564 if (val != 0)
3565 {
3566 goto exit;
3567 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003568
bo.xiao857b8682024-09-12 16:40:32 +08003569 memset( &ctl, 0, sizeof(ctl));
bo.xiao4ef6d272024-10-15 16:18:25 +08003570 ctl.id = AML_V4L2_GET_FILMGRAIN_INFO;
3571 v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CTRL, &ctl);
bo.xiao857b8682024-09-12 16:40:32 +08003572 GST_LOG("got VIDIOC_G_CTRL value: %d", ctl.value);
3573 if (ctl.value == 0)
3574 {
3575 goto exit;
3576 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003577
bo.xiao857b8682024-09-12 16:40:32 +08003578 result= TRUE;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003579
3580exit:
bo.xiao857b8682024-09-12 16:40:32 +08003581 if ( fd >= 0 )
3582 {
3583 close(fd);
3584 }
3585 GST_LOG("configForFilmGrain: exit: result %d", result);
3586 return result;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003587}
hanghang.luobfc63f82024-07-05 11:04:56 +08003588
3589static gboolean
bo.xiao7659cda2024-07-18 16:16:50 +08003590get_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm)
hanghang.luobfc63f82024-07-05 11:04:56 +08003591{
bo.xiao857b8682024-09-12 16:40:32 +08003592 struct v4l2_ext_control control;
3593 struct v4l2_ext_controls ctrls;
3594 gboolean use_ext_config = FALSE;
3595 int major = 0,minor = 0;
3596 struct utsname info;
3597 struct aml_dec_params *pdecParm = (struct aml_dec_params *)streamparm->parm.raw_data;
bo.xiao7659cda2024-07-18 16:16:50 +08003598
bo.xiao857b8682024-09-12 16:40:32 +08003599 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3600 {
3601 GST_DEBUG("get linux version failed");
3602 return FALSE;
3603 }
3604 GST_DEBUG("linux major version %d %d", major,minor);
3605 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003606
bo.xiao857b8682024-09-12 16:40:32 +08003607 if (use_ext_config)
3608 {
3609 memset(&ctrls, 0, sizeof(ctrls));
3610 memset(&control, 0, sizeof(control));
3611 control.id = AML_V4L2_DEC_PARMS_CONFIG;
3612 control.ptr = pdecParm;
3613 control.size = sizeof(struct aml_dec_params);
3614 ctrls.count = 1;
3615 ctrls.controls = &control;
3616 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls ) <0)
3617 {
3618 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3619 return FALSE;
3620 }
3621 GST_DEBUG("dw: %d, flag: %d, status: %d, margin: %d",pdecParm->cfg.double_write_mode,
3622 pdecParm->cfg.metadata_config_flag, pdecParm->parms_status, pdecParm->cfg.ref_buf_margin);
3623 }
3624 else
3625 {
3626 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, streamparm) < 0)
3627 {
3628 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3629 return FALSE;
3630 }
3631 }
3632 return TRUE;
hanghang.luobfc63f82024-07-05 11:04:56 +08003633}
3634
bo.xiao34e36202024-07-17 16:04:01 +08003635static int gst_aml_config_dw(GstAmlV4l2Object *v4l2object, guint32 pixFormat, guint width, guint height, gboolean interlace)
3636{
bo.xiao857b8682024-09-12 16:40:32 +08003637 const char *env_dw;
3638 int double_write = VDEC_DW_NO_AFBC;
bo.xiao34e36202024-07-17 16:04:01 +08003639
bo.xiao857b8682024-09-12 16:40:32 +08003640 GST_DEBUG("pixFormat: %d", pixFormat);
3641 switch (pixFormat)
3642 {
3643 case V4L2_PIX_FMT_MPEG:
3644 case V4L2_PIX_FMT_MPEG1:
3645 case V4L2_PIX_FMT_MPEG2:
3646 case V4L2_PIX_FMT_MPEG4:
3647 double_write = VDEC_DW_NO_AFBC;
3648 break;
3649 case V4L2_PIX_FMT_H264:
3650 {
3651 if (width > 1920 && height > 1080 && !interlace)
3652 double_write = VDEC_DW_AFBC_1_4_DW;
3653 else
3654 double_write = VDEC_DW_NO_AFBC;
3655 break;
3656 }
3657 case V4L2_PIX_FMT_HEVC:
3658 double_write = VDEC_DW_AFBC_AUTO_1_4;
3659 if (interlace)
3660 double_write = VDEC_DW_AFBC_1_1_DW;
3661 if (v4l2object->low_memory_mode)
3662 double_write = VDEC_DW_AFBC_ONLY;
3663 break;
3664 case V4L2_PIX_FMT_VP9:
3665 case V4L2_PIX_FMT_AV1:
3666 double_write = v4l2object->low_memory_mode ? VDEC_DW_AFBC_ONLY:VDEC_DW_AFBC_AUTO_1_4;
3667 break;
3668 default:
3669 GST_WARNING("unknown video format %d", pixFormat);
3670 break;
3671 }
bo.xiao34e36202024-07-17 16:04:01 +08003672
bo.xiao857b8682024-09-12 16:40:32 +08003673 env_dw = getenv("V4L2_SET_AMLOGIC_DW_MODE");
3674 if (env_dw)
3675 double_write = atoi(env_dw);
bo.xiao34e36202024-07-17 16:04:01 +08003676
bo.xiao857b8682024-09-12 16:40:32 +08003677 return double_write;
bo.xiao34e36202024-07-17 16:04:01 +08003678}
hanghang.luobfc63f82024-07-05 11:04:56 +08003679
xuesong.jiangae1548e2022-05-06 16:38:46 +08003680static void
fei.deng7c3d67f2022-11-09 11:06:05 +08003681set_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm, GstCaps *caps, guint32 pixFormat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003682{
3683 struct aml_dec_params *decParm = (struct aml_dec_params *)streamparm->parm.raw_data;
3684 const char *env;
zengliang.lic9f869d2023-02-15 08:32:32 +00003685 struct v4l2_ext_control control;
3686 struct v4l2_ext_controls ctrls;
3687 gboolean use_ext_config = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003688 int major = 0, minor = 0;
zengliang.lic9f869d2023-02-15 08:32:32 +00003689 struct utsname info;
bo.xiao34e36202024-07-17 16:04:01 +08003690 gboolean is_interlaced = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003691 guint width = 0, height = 0;
3692
3693 streamparm->type = v4l2object->type;
bo.xiao34e36202024-07-17 16:04:01 +08003694
fei.deng355dfb52024-09-14 15:04:31 +08003695 env = getenv("V4L2DEC_LOW_MEM_MODE");
3696 if (env) {
3697 GST_DEBUG("%s",env);
3698 v4l2object->low_memory_mode = atoi(env) > 0? TRUE: FALSE;
3699 }
hanghang.luo7f403102024-07-04 10:33:01 +08003700 GST_DEBUG("low mem: %d",v4l2object->low_memory_mode);
bo.xiao34e36202024-07-17 16:04:01 +08003701
bo.xiao7659cda2024-07-18 16:16:50 +08003702 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3703 {
3704 GST_DEBUG("get linux version failed");
3705 }
3706 GST_DEBUG("linux major version %d %d", major,minor);
3707 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
3708
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003709 GstStructure *structure = gst_caps_get_structure(caps, 0);
3710 if (structure == NULL)
3711 {
3712 return;
3713 }
3714 gst_structure_get_uint(structure,"width",&width);
3715 gst_structure_get_uint(structure,"height",&height);
3716 if (gst_structure_has_field(structure, "interlace-mode"))
3717 {
bo.xiao34e36202024-07-17 16:04:01 +08003718 const gchar *mode = gst_structure_get_string(structure,"interlace-mode");
3719 is_interlaced = !strcmp(mode, "progressive") ? FALSE:TRUE;
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003720 GST_DEBUG("is_interlaced: %d",is_interlaced);
3721 }
hanghang.luo7f403102024-07-04 10:33:01 +08003722
xuesong.jiangae1548e2022-05-06 16:38:46 +08003723 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3724 {
fei.dengccc89632022-07-15 19:10:17 +08003725 /*set bit12 value to 1,
3726 *v4l2 output 0 pts of second interlace field frame */
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003727 decParm->cfg.metadata_config_flag |= (1 << 12);
fei.deng7c3d67f2022-11-09 11:06:05 +08003728 decParm->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003729
3730 decParm->cfg.metadata_config_flag |= 1 << 13;
3731
3732 /*set bit18 value to 1
3733 *release vpp in advance */
3734 decParm->cfg.metadata_config_flag |= (1 << 18);
3735 decParm->cfg.low_latency_mode = v4l2object->low_latency_mode;
3736
zengliang.li8f538aa2024-06-25 17:31:20 +08003737 if (v4l2object->enable_nr)
3738 {
3739 GST_DEBUG("enable nr in di");
3740 decParm->cfg.metadata_config_flag |= (1 << 14);
3741 decParm->cfg.metadata_config_flag |= (1 << 15);
3742 }
3743
bo.xiao34e36202024-07-17 16:04:01 +08003744 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, pixFormat, width, height, is_interlaced);
hanghang.luo75664712024-07-01 19:28:10 +08003745 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg dw mode to %d", decParm->cfg.double_write_mode);
bo.xiao7659cda2024-07-18 16:16:50 +08003746 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo75664712024-07-01 19:28:10 +08003747
fei.deng17693b62024-08-28 20:13:17 +08003748 if (v4l2object->low_memory_mode) {
3749 decParm->cfg.ref_buf_margin = GST_AML_V4L2_LOW_MEMORY_CAP_BUF_MARGIN;
3750 } else {
3751 decParm->cfg.ref_buf_margin = GST_AML_V4L2_DEFAULT_CAP_BUF_MARGIN;
3752 }
3753
le.hancd3f2842024-06-26 09:37:50 +00003754 env = getenv("V4L2_SET_AMLOGIC_MARGIN_NUM");
3755 if (env)
3756 {
3757 decParm->cfg.ref_buf_margin = atoi(env);
bo.xiao7659cda2024-07-18 16:16:50 +08003758 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg margin to %d", decParm->cfg.ref_buf_margin);
le.hancd3f2842024-06-26 09:37:50 +00003759 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003760
bo.xiaof42b0082024-08-22 14:08:53 +08003761 // d v
3762 gboolean bl_present_flag, el_present_flag;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003763 int dvBaseLayerPresent = -1;
3764 int dvEnhancementLayerPresent = -1;
3765 /* have base and enhancement layers both, that means its dual layer,
bo.xiaof42b0082024-08-22 14:08:53 +08003766 d v two layer flag will be true */
3767 if (gst_structure_get_boolean( structure, "bl_present_flag", &bl_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003768 {
bo.xiaof42b0082024-08-22 14:08:53 +08003769 dvBaseLayerPresent= bl_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003770 }
bo.xiaof42b0082024-08-22 14:08:53 +08003771 if (gst_structure_get_boolean( structure, "el_present_flag", &el_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003772 {
bo.xiaof42b0082024-08-22 14:08:53 +08003773 dvEnhancementLayerPresent= el_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003774 }
3775
3776 /* have base and enhancement layers both, that means its dual layer, dv two layer flag will be true */
3777 if ( (dvBaseLayerPresent == 1) && (dvEnhancementLayerPresent == 1) )
3778 {
3779 decParm->cfg.metadata_config_flag |= (1 << 0);
3780 }
3781 else
3782 {
3783 decParm->cfg.metadata_config_flag |= (0 << 0);
3784 }
3785
3786 /* have one of then, it's standard dv stream, Non-standard dv flag will be false */
3787 if ( (dvBaseLayerPresent == 0) && (dvEnhancementLayerPresent == 0) )
3788 {
3789 decParm->cfg.metadata_config_flag |= (1 << 1);
3790 }
3791 else
3792 {
3793 decParm->cfg.metadata_config_flag |= (0 << 1);
3794 }
3795
3796 // HDR
xuesong.jiange1a19662022-06-21 20:30:22 +08003797 if ( gst_structure_has_field(structure, "colorimetry") )
3798 {
3799 const char *colorimetry= gst_structure_get_string(structure,"colorimetry");
3800 GstVideoColorimetry vci = {0};
3801 if ( colorimetry && gst_video_colorimetry_from_string( &vci, colorimetry ))
3802 {
3803 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO;
3804 decParm->hdr.signal_type= (1<<29); /* present flag */
3805 /*set default value, this is to keep up with driver hdr info synchronization*/
3806 decParm->hdr.signal_type |= (5<<26) | (1<<24);
3807
3808 gint hdrColorimetry[4] = {0};
3809 hdrColorimetry[0]= (int)vci.range;
3810 hdrColorimetry[1]= (int)vci.matrix;
3811 hdrColorimetry[2]= (int)vci.transfer;
3812 hdrColorimetry[3]= (int)vci.primaries;
3813 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "colorimetry: [%d,%d,%d,%d]",
3814 hdrColorimetry[0],
3815 hdrColorimetry[1],
3816 hdrColorimetry[2],
3817 hdrColorimetry[3] );
3818 /* range */
3819 switch ( hdrColorimetry[0] )
3820 {
le.han8d28eb82024-06-05 08:11:12 +00003821 case GST_VIDEO_COLOR_RANGE_0_255:
3822 case GST_VIDEO_COLOR_RANGE_16_235:
xuesong.jiange1a19662022-06-21 20:30:22 +08003823 decParm->hdr.signal_type |= ((hdrColorimetry[0] % 2)<<25);
3824 break;
3825 default:
3826 break;
3827 }
3828 /* matrix coefficient */
3829 switch ( hdrColorimetry[1] )
3830 {
le.han8d28eb82024-06-05 08:11:12 +00003831 case GST_VIDEO_COLOR_MATRIX_RGB: /* RGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003832 decParm->hdr.signal_type |= 0;
3833 break;
le.han8d28eb82024-06-05 08:11:12 +00003834 case GST_VIDEO_COLOR_MATRIX_FCC: /* FCC */
xuesong.jiange1a19662022-06-21 20:30:22 +08003835 decParm->hdr.signal_type |= 4;
3836 break;
le.han8d28eb82024-06-05 08:11:12 +00003837 case GST_VIDEO_COLOR_MATRIX_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003838 decParm->hdr.signal_type |= 1;
3839 break;
le.han8d28eb82024-06-05 08:11:12 +00003840 case GST_VIDEO_COLOR_MATRIX_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003841 decParm->hdr.signal_type |= 3;
3842 break;
le.han8d28eb82024-06-05 08:11:12 +00003843 case GST_VIDEO_COLOR_MATRIX_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003844 decParm->hdr.signal_type |= 7;
3845 break;
le.han8d28eb82024-06-05 08:11:12 +00003846 case GST_VIDEO_COLOR_MATRIX_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003847 decParm->hdr.signal_type |= 9;
3848 break;
3849 default: /* unknown */
3850 decParm->hdr.signal_type |= 2;
3851 break;
3852 }
3853 /* transfer function */
3854 switch ( hdrColorimetry[2] )
3855 {
le.han8d28eb82024-06-05 08:11:12 +00003856 case GST_VIDEO_TRANSFER_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003857 decParm->hdr.signal_type |= (1<<8);
3858 break;
le.han8d28eb82024-06-05 08:11:12 +00003859 case GST_VIDEO_TRANSFER_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003860 decParm->hdr.signal_type |= (7<<8);
3861 break;
le.han8d28eb82024-06-05 08:11:12 +00003862 case GST_VIDEO_TRANSFER_LOG100: /* LOG100 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003863 decParm->hdr.signal_type |= (9<<8);
3864 break;
le.han8d28eb82024-06-05 08:11:12 +00003865 case GST_VIDEO_TRANSFER_LOG316: /* LOG316 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003866 decParm->hdr.signal_type |= (10<<8);
3867 break;
le.han8d28eb82024-06-05 08:11:12 +00003868 case GST_VIDEO_TRANSFER_BT2020_12: /* BT2020_12 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003869 decParm->hdr.signal_type |= (15<<8);
3870 break;
le.han8d28eb82024-06-05 08:11:12 +00003871 case GST_VIDEO_TRANSFER_BT2020_10: /* BT2020_10 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003872 decParm->hdr.signal_type |= (14<<8);
3873 break;
le.han8d28eb82024-06-05 08:11:12 +00003874 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
3875 case GST_VIDEO_TRANSFER_SMPTE2084: /* SMPTE2084 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003876 decParm->hdr.signal_type |= (16<<8);
3877 break;
le.han8d28eb82024-06-05 08:11:12 +00003878 #else
3879 case GST_VIDEO_TRANSFER_SMPTE_ST_2084: /* SMPTE2084 */
3880 decParm->hdr.signal_type |= (16<<8);
3881 break;
3882 #endif
3883 case GST_VIDEO_TRANSFER_ARIB_STD_B67: /* ARIB_STD_B67 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003884 decParm->hdr.signal_type |= (18<<8);
3885 break;
3886 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
le.han8d28eb82024-06-05 08:11:12 +00003887 case GST_VIDEO_TRANSFER_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003888 decParm->hdr.signal_type |= (3<<8);
3889 break;
3890 #endif
le.han8d28eb82024-06-05 08:11:12 +00003891 case GST_VIDEO_TRANSFER_GAMMA10: /* GAMMA10 */
3892 case GST_VIDEO_TRANSFER_GAMMA18: /* GAMMA18 */
3893 case GST_VIDEO_TRANSFER_GAMMA20: /* GAMMA20 */
3894 case GST_VIDEO_TRANSFER_GAMMA22: /* GAMMA22 */
3895 case GST_VIDEO_TRANSFER_SRGB: /* SRGB */
3896 case GST_VIDEO_TRANSFER_GAMMA28: /* GAMMA28 */
3897 case GST_VIDEO_TRANSFER_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003898 default:
3899 break;
3900 }
3901 /* primaries */
3902 switch ( hdrColorimetry[3] )
3903 {
le.han8d28eb82024-06-05 08:11:12 +00003904 case GST_VIDEO_COLOR_PRIMARIES_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003905 decParm->hdr.signal_type |= ((1<<24)|(1<<16));
3906 break;
le.han8d28eb82024-06-05 08:11:12 +00003907 case GST_VIDEO_COLOR_PRIMARIES_BT470M: /* BT470M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003908 decParm->hdr.signal_type |= ((1<<24)|(4<<16));
3909 break;
le.han8d28eb82024-06-05 08:11:12 +00003910 case GST_VIDEO_COLOR_PRIMARIES_BT470BG: /* BT470BG */
xuesong.jiange1a19662022-06-21 20:30:22 +08003911 decParm->hdr.signal_type |= ((1<<24)|(5<<16));
3912 break;
le.han8d28eb82024-06-05 08:11:12 +00003913 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M: /* SMPTE170M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003914 decParm->hdr.signal_type |= ((1<<24)|(6<<16));
3915 break;
le.han8d28eb82024-06-05 08:11:12 +00003916 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003917 decParm->hdr.signal_type |= ((1<<24)|(7<<16));
3918 break;
le.han8d28eb82024-06-05 08:11:12 +00003919 case GST_VIDEO_COLOR_PRIMARIES_FILM: /* FILM */
xuesong.jiange1a19662022-06-21 20:30:22 +08003920 decParm->hdr.signal_type |= ((1<<24)|(8<<16));
3921 break;
le.han8d28eb82024-06-05 08:11:12 +00003922 case GST_VIDEO_COLOR_PRIMARIES_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003923 decParm->hdr.signal_type |= ((1<<24)|(9<<16));
3924 break;
le.han8d28eb82024-06-05 08:11:12 +00003925 case GST_VIDEO_COLOR_PRIMARIES_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003926 default:
3927 break;
3928 }
3929 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR signal_type %X", decParm->hdr.signal_type);
3930 }
3931
bo.xiao7659cda2024-07-18 16:16:50 +08003932 //why remove this colorimetry?
xuesong.jiange1a19662022-06-21 20:30:22 +08003933 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "got caps %" GST_PTR_FORMAT, caps);
3934 GstStructure *st = gst_caps_get_structure(caps, 0);
3935 GstCapsFeatures *features = gst_caps_get_features(caps, 0);
3936
3937 if (gst_structure_has_field(st, "colorimetry"))
3938 {
3939 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "have colorimetry");
3940 }
3941
3942 if (st && features)
3943 {
3944 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "trace in remove colorimetry");
3945 gst_structure_remove_field(st, "colorimetry");
3946 gst_caps_features_remove(features, "colorimetry");
3947 }
3948 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove colorimetry %" GST_PTR_FORMAT, caps);
3949 }
3950
le.han7d0af792024-06-05 08:44:18 +00003951 const char * field = NULL;
3952 if (gst_structure_has_field(structure, "mastering-display-metadata")) {
3953 field = "mastering-display-metadata";
3954 } else if (gst_structure_has_field(structure, "mastering-display-info")) {
3955 field = "mastering-display-info";
3956 }
3957
3958 if ( field )
xuesong.jiange1a19662022-06-21 20:30:22 +08003959 {
le.han7d0af792024-06-05 08:44:18 +00003960 const char *masteringDisplay= gst_structure_get_string(structure, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08003961 float hdrMasteringDisplay[10];
3962 if ( masteringDisplay && sscanf( masteringDisplay, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
3963 &hdrMasteringDisplay[0],
3964 &hdrMasteringDisplay[1],
3965 &hdrMasteringDisplay[2],
3966 &hdrMasteringDisplay[3],
3967 &hdrMasteringDisplay[4],
3968 &hdrMasteringDisplay[5],
3969 &hdrMasteringDisplay[6],
3970 &hdrMasteringDisplay[7],
3971 &hdrMasteringDisplay[8],
3972 &hdrMasteringDisplay[9] ) == 10 )
3973 {
3974 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "mastering display [%f,%f,%f,%f,%f,%f,%f,%f,%f,%f]",
3975 hdrMasteringDisplay[0],
3976 hdrMasteringDisplay[1],
3977 hdrMasteringDisplay[2],
3978 hdrMasteringDisplay[3],
3979 hdrMasteringDisplay[4],
3980 hdrMasteringDisplay[5],
3981 hdrMasteringDisplay[6],
3982 hdrMasteringDisplay[7],
3983 hdrMasteringDisplay[8],
3984 hdrMasteringDisplay[9] );
3985
3986 decParm->hdr.color_parms.present_flag= 1;
3987 decParm->hdr.color_parms.primaries[2][0]= (uint32_t)(hdrMasteringDisplay[0]*50000); /* R.x */
3988 decParm->hdr.color_parms.primaries[2][1]= (uint32_t)(hdrMasteringDisplay[1]*50000); /* R.y */
3989 decParm->hdr.color_parms.primaries[0][0]= (uint32_t)(hdrMasteringDisplay[2]*50000); /* G.x */
3990 decParm->hdr.color_parms.primaries[0][1]= (uint32_t)(hdrMasteringDisplay[3]*50000); /* G.y */
3991 decParm->hdr.color_parms.primaries[1][0]= (uint32_t)(hdrMasteringDisplay[4]*50000); /* B.x */
3992 decParm->hdr.color_parms.primaries[1][1]= (uint32_t)(hdrMasteringDisplay[5]*50000); /* B.y */
3993 decParm->hdr.color_parms.white_point[0]= (uint32_t)(hdrMasteringDisplay[6]*50000);
3994 decParm->hdr.color_parms.white_point[1]= (uint32_t)(hdrMasteringDisplay[7]*50000);
3995 decParm->hdr.color_parms.luminance[0]= (uint32_t)(hdrMasteringDisplay[8]);
3996 decParm->hdr.color_parms.luminance[1]= (uint32_t)(hdrMasteringDisplay[9]);
3997 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: primaries %X %X %X %X %X %X",
3998 decParm->hdr.color_parms.primaries[2][0],
3999 decParm->hdr.color_parms.primaries[2][1],
4000 decParm->hdr.color_parms.primaries[0][0],
4001 decParm->hdr.color_parms.primaries[0][1],
4002 decParm->hdr.color_parms.primaries[1][0],
4003 decParm->hdr.color_parms.primaries[1][1] );
4004 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: white point: %X %X",
4005 decParm->hdr.color_parms.white_point[0],
4006 decParm->hdr.color_parms.white_point[1] );
4007 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: luminance: %X %X",
4008 decParm->hdr.color_parms.luminance[0],
4009 decParm->hdr.color_parms.luminance[1] );
4010 }
4011
4012 GstStructure *st = gst_caps_get_structure(caps, 0);
4013 GstCapsFeatures * features = gst_caps_get_features(caps, 0);
4014 if (st && features)
4015 {
le.han7d0af792024-06-05 08:44:18 +00004016 gst_structure_remove_fields(st, field, NULL);
4017 gst_caps_features_remove(features, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08004018 }
le.han7d0af792024-06-05 08:44:18 +00004019 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove %s %" GST_PTR_FORMAT, field, caps);
xuesong.jiange1a19662022-06-21 20:30:22 +08004020 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004021 }
hanghang.luo75664712024-07-01 19:28:10 +08004022 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004023 {
hanghang.luo75664712024-07-01 19:28:10 +08004024 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao7659cda2024-07-18 16:16:50 +08004025
4026 if (!get_amlogic_vdec_parm(v4l2object, streamparm))
hanghang.luobfc63f82024-07-05 11:04:56 +08004027 {
4028 GST_ERROR_OBJECT(v4l2object->dbg_obj, "can't get vdec parm");
4029 return;
4030 }
hanghang.luo75664712024-07-01 19:28:10 +08004031
bo.xiao7659cda2024-07-18 16:16:50 +08004032 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, self->v4l2output->fmtdesc->pixelformat,
bo.xiao34e36202024-07-17 16:04:01 +08004033 width, height, is_interlaced);
bo.xiao7659cda2024-07-18 16:16:50 +08004034 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "capture cfg dw mode to %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004035
4036 if (needSpecConfigForFg(v4l2object))
4037 {
bo.xiao7659cda2024-07-18 16:16:50 +08004038 decParm->cfg.double_write_mode = VDEC_DW_MMU_1;
4039 GST_DEBUG_OBJECT(v4l2object->dbg_obj,"set fg dw mode %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004040 }
bo.xiao7659cda2024-07-18 16:16:50 +08004041 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004042 }
4043 else
4044 {
hanghang.luo75664712024-07-01 19:28:10 +08004045 GST_ERROR_OBJECT(v4l2object->dbg_obj,"can't deal with. please check buffer type.");
bo.xiao7659cda2024-07-18 16:16:50 +08004046 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004047 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004048
bo.xiao7659cda2024-07-18 16:16:50 +08004049 if (use_ext_config)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004050 {
bo.xiao7659cda2024-07-18 16:16:50 +08004051 memset(&ctrls, 0, sizeof(ctrls));
4052 memset(&control, 0, sizeof(control));
4053 control.id = AML_V4L2_DEC_PARMS_CONFIG;
4054 control.ptr = decParm;
4055 control.size = sizeof(struct aml_dec_params);
4056 ctrls.count = 1;
4057 ctrls.controls = &control;
4058 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls ) < 0)
4059 {
4060 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4061 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004062 }
bo.xiao7659cda2024-07-18 16:16:50 +08004063 else
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004064 {
bo.xiao7659cda2024-07-18 16:16:50 +08004065 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_PARM, streamparm) < 0)
4066 {
4067 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4068 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004069 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004070}
4071
xuesong.jiangae1548e2022-05-06 16:38:46 +08004072static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004073gst_aml_v4l2_object_set_format_full (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4074 gboolean try_only, GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004075{
bo.xiao857b8682024-09-12 16:40:32 +08004076 gint fd = v4l2object->video_fd;
4077 struct v4l2_format format;
4078 struct v4l2_streamparm streamparm;
4079 enum v4l2_field field;
4080 guint32 pixelformat;
4081 struct v4l2_fmtdesc *fmtdesc;
4082 GstVideoInfo info;
4083 GstVideoAlignment align;
4084 gint width, height, fps_n, fps_d;
4085 gint n_v4l_planes;
4086 gint i = 0;
4087 gboolean is_mplane;
4088 enum v4l2_colorspace colorspace = 0;
4089 enum v4l2_quantization range = 0;
4090 enum v4l2_ycbcr_encoding matrix = 0;
4091 enum v4l2_xfer_func transfer = 0;
4092 GstStructure *s;
4093 gboolean disable_colorimetry = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004094
bo.xiao857b8682024-09-12 16:40:32 +08004095 g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
4096 gst_caps_is_writable (caps), FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004097
bo.xiao857b8682024-09-12 16:40:32 +08004098 GST_AML_V4L2_CHECK_OPEN (v4l2object);
4099 if (!try_only)
4100 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004101
bo.xiao857b8682024-09-12 16:40:32 +08004102 is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004103
bo.xiao857b8682024-09-12 16:40:32 +08004104 gst_video_info_init (&info);
4105 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004106
bo.xiao857b8682024-09-12 16:40:32 +08004107 if (!gst_aml_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
4108 goto invalid_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004109
bo.xiao857b8682024-09-12 16:40:32 +08004110 pixelformat = fmtdesc->pixelformat;
4111 width = GST_VIDEO_INFO_WIDTH (&info);
4112 height = GST_VIDEO_INFO_HEIGHT (&info);
4113 fps_n = GST_VIDEO_INFO_FPS_N (&info);
4114 fps_d = GST_VIDEO_INFO_FPS_D (&info);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004115
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004116 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size");
4117 struct v4l2_frmsizeenum size;
4118 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
4119 size.index = 0;
4120 size.pixel_format = pixelformat;
4121 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
bo.xiao857b8682024-09-12 16:40:32 +08004122 return FALSE;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004123 if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
4124 {
bo.xiao857b8682024-09-12 16:40:32 +08004125 guint32 maxw, maxh;
4126 maxw = MIN (size.stepwise.max_width, G_MAXINT);
4127 maxh = MIN (size.stepwise.max_height, G_MAXINT);
4128 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "image from caps w_h:%d_%d", width, height);
4129 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "v4l2 support max w_h:%d_%d", maxw, maxh);
4130 if (width*height > maxw*maxh)
4131 return FALSE;
4132 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size ok");
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004133 }
4134
bo.xiao857b8682024-09-12 16:40:32 +08004135 //set amlogic params here,because we need pix format to set dw mode
4136 memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
4137 set_amlogic_vdec_parm(v4l2object, &streamparm, caps, pixelformat);
fei.deng7c3d67f2022-11-09 11:06:05 +08004138
bo.xiao857b8682024-09-12 16:40:32 +08004139 /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
4140 * or if contiguous is preferred */
4141 n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
4142 if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
4143 n_v4l_planes = 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004144
bo.xiao857b8682024-09-12 16:40:32 +08004145 if (GST_VIDEO_INFO_IS_INTERLACED(&info))
4146 {
4147 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "interlaced video");
4148 /* ideally we would differentiate between types of interlaced video
4149 * but there is not sufficient information in the caps..
4150 */
4151 field = V4L2_FIELD_INTERLACED;
4152 }
4153 else
4154 {
4155 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "progressive video");
4156 field = V4L2_FIELD_NONE;
4157 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004158
bo.xiao857b8682024-09-12 16:40:32 +08004159 /* We first pick the main colorspace from the primaries */
4160 switch (info.colorimetry.primaries)
4161 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004162 case GST_VIDEO_COLOR_PRIMARIES_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004163 /* There is two colorspaces using these primaries, use the range to
4164 * differentiate */
4165 if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
4166 colorspace = V4L2_COLORSPACE_REC709;
4167 else
4168 colorspace = V4L2_COLORSPACE_SRGB;
4169 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004170 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004171 colorspace = V4L2_COLORSPACE_BT2020;
4172 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004173 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
bo.xiao857b8682024-09-12 16:40:32 +08004174 colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
4175 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004176 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
bo.xiao857b8682024-09-12 16:40:32 +08004177 colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
4178 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004179 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08004180 colorspace = V4L2_COLORSPACE_SMPTE170M;
4181 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004182 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004183 colorspace = V4L2_COLORSPACE_SMPTE240M;
4184 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004185
4186 case GST_VIDEO_COLOR_PRIMARIES_FILM:
4187 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004188 /* We don't know, we will guess */
4189 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004190
4191 default:
bo.xiao857b8682024-09-12 16:40:32 +08004192 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4193 "Unknown colorimetry primaries %d", info.colorimetry.primaries);
4194 break;
4195 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004196
bo.xiao857b8682024-09-12 16:40:32 +08004197 switch (info.colorimetry.range)
4198 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004199 case GST_VIDEO_COLOR_RANGE_0_255:
bo.xiao857b8682024-09-12 16:40:32 +08004200 range = V4L2_QUANTIZATION_FULL_RANGE;
4201 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004202 case GST_VIDEO_COLOR_RANGE_16_235:
bo.xiao857b8682024-09-12 16:40:32 +08004203 range = V4L2_QUANTIZATION_LIM_RANGE;
4204 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004205 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004206 /* We let the driver pick a default one */
4207 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004208 default:
bo.xiao857b8682024-09-12 16:40:32 +08004209 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4210 "Unknown colorimetry range %d", info.colorimetry.range);
4211 break;
4212 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004213
bo.xiao857b8682024-09-12 16:40:32 +08004214 switch (info.colorimetry.matrix)
4215 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004216 case GST_VIDEO_COLOR_MATRIX_RGB:
bo.xiao857b8682024-09-12 16:40:32 +08004217 /* Unspecified, leave to default */
4218 break;
4219 /* FCC is about the same as BT601 with less digit */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004220 case GST_VIDEO_COLOR_MATRIX_FCC:
4221 case GST_VIDEO_COLOR_MATRIX_BT601:
bo.xiao857b8682024-09-12 16:40:32 +08004222 matrix = V4L2_YCBCR_ENC_601;
4223 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004224 case GST_VIDEO_COLOR_MATRIX_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004225 matrix = V4L2_YCBCR_ENC_709;
4226 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004227 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004228 matrix = V4L2_YCBCR_ENC_SMPTE240M;
4229 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004230 case GST_VIDEO_COLOR_MATRIX_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004231 matrix = V4L2_YCBCR_ENC_BT2020;
4232 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004233 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004234 /* We let the driver pick a default one */
4235 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004236 default:
bo.xiao857b8682024-09-12 16:40:32 +08004237 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4238 "Unknown colorimetry matrix %d", info.colorimetry.matrix);
4239 break;
4240 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004241
bo.xiao857b8682024-09-12 16:40:32 +08004242 switch (info.colorimetry.transfer)
4243 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004244 case GST_VIDEO_TRANSFER_GAMMA18:
4245 case GST_VIDEO_TRANSFER_GAMMA20:
4246 case GST_VIDEO_TRANSFER_GAMMA22:
4247 case GST_VIDEO_TRANSFER_GAMMA28:
bo.xiao857b8682024-09-12 16:40:32 +08004248 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4249 "GAMMA 18, 20, 22, 28 transfer functions not supported");
4250 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004251 case GST_VIDEO_TRANSFER_GAMMA10:
bo.xiao857b8682024-09-12 16:40:32 +08004252 transfer = V4L2_XFER_FUNC_NONE;
4253 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004254 case GST_VIDEO_TRANSFER_BT2020_12:
4255 case GST_VIDEO_TRANSFER_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004256 transfer = V4L2_XFER_FUNC_709;
4257 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004258 case GST_VIDEO_TRANSFER_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004259 transfer = V4L2_XFER_FUNC_SMPTE240M;
4260 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004261 case GST_VIDEO_TRANSFER_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08004262 transfer = V4L2_XFER_FUNC_SRGB;
4263 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004264 case GST_VIDEO_TRANSFER_LOG100:
4265 case GST_VIDEO_TRANSFER_LOG316:
bo.xiao857b8682024-09-12 16:40:32 +08004266 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4267 "LOG 100, 316 transfer functions not supported");
4268 /* FIXME No known sensible default, maybe AdobeRGB ? */
4269 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004270 case GST_VIDEO_TRANSFER_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004271 /* We let the driver pick a default one */
4272 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004273 default:
bo.xiao857b8682024-09-12 16:40:32 +08004274 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4275 "Unknown colorimetry transfer %d", info.colorimetry.transfer);
4276 break;
4277 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004278
bo.xiao857b8682024-09-12 16:40:32 +08004279 if (colorspace == 0)
4280 {
4281 /* Try to guess colorspace according to pixelformat and size */
4282 if (GST_VIDEO_INFO_IS_YUV (&info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004283 {
bo.xiao857b8682024-09-12 16:40:32 +08004284 if (range == V4L2_QUANTIZATION_FULL_RANGE
4285 && matrix == V4L2_YCBCR_ENC_601 && transfer == 0)
4286 {
4287 /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
4288 * function most likely is JPEG */
4289 colorspace = V4L2_COLORSPACE_JPEG;
4290 transfer = V4L2_XFER_FUNC_SRGB;
4291 }
4292 else
4293 {
4294 /* SD streams likely use SMPTE170M and HD streams REC709 */
4295 if (width <= 720 && height <= 576)
4296 colorspace = V4L2_COLORSPACE_SMPTE170M;
4297 else
4298 colorspace = V4L2_COLORSPACE_REC709;
4299 }
4300 }
4301 else if (GST_VIDEO_INFO_IS_RGB (&info))
4302 {
4303 colorspace = V4L2_COLORSPACE_SRGB;
4304 transfer = V4L2_XFER_FUNC_NONE;
4305 }
4306 }
4307
4308 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format "
4309 "%" GST_FOURCC_FORMAT " stride: %d", width, height,
4310 GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
4311
4312 memset (&format, 0x00, sizeof (struct v4l2_format));
4313 format.type = v4l2object->type;
4314
4315 if (is_mplane)
4316 {
4317 format.type = v4l2object->type;
4318 format.fmt.pix_mp.pixelformat = pixelformat;
4319 format.fmt.pix_mp.width = width;
4320 format.fmt.pix_mp.height = height;
4321 format.fmt.pix_mp.field = field;
4322 format.fmt.pix_mp.num_planes = n_v4l_planes;
4323
4324 /* try to ask our preferred stride but it's not a failure if not
4325 * accepted */
4326 for (i = 0; i < n_v4l_planes; i++)
4327 {
4328 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
4329
4330 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4331 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4332 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4333
4334 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004335 }
4336
bo.xiao857b8682024-09-12 16:40:32 +08004337 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
4338 {
4339 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4340 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4341 else
4342 format.fmt.pix_mp.plane_fmt[0].sizeimage = v4l2object->low_memory_mode ? LOW_MEM_ENCODED_BUFFER_SIZE : ENCODED_BUFFER_SIZE;
4343 }
4344 }
4345 else
4346 {
4347 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004348
xuesong.jiangae1548e2022-05-06 16:38:46 +08004349 format.type = v4l2object->type;
4350
bo.xiao857b8682024-09-12 16:40:32 +08004351 format.fmt.pix.width = width;
4352 format.fmt.pix.height = height;
4353 format.fmt.pix.pixelformat = pixelformat;
4354 format.fmt.pix.field = field;
4355
4356 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4357 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4358 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4359
4360 /* try to ask our preferred stride */
4361 format.fmt.pix.bytesperline = stride;
4362
4363 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004364 {
bo.xiao857b8682024-09-12 16:40:32 +08004365 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4366 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4367 else
4368 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 +08004369 }
bo.xiao857b8682024-09-12 16:40:32 +08004370 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004371
bo.xiao857b8682024-09-12 16:40:32 +08004372 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
4373 "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
4374 format.fmt.pix_mp.height,
4375 GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
4376 is_mplane ? format.fmt.pix_mp.num_planes : 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004377
4378#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004379 if (is_mplane)
4380 {
4381 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4382 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4383 format.fmt.pix_mp.plane_fmt[i].bytesperline);
4384 }
4385 else
4386 {
4387 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4388 format.fmt.pix.bytesperline);
4389 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004390#endif
4391
bo.xiao857b8682024-09-12 16:40:32 +08004392 if (is_mplane)
4393 {
4394 format.fmt.pix_mp.colorspace = colorspace;
4395 format.fmt.pix_mp.quantization = range;
4396 format.fmt.pix_mp.ycbcr_enc = matrix;
4397 format.fmt.pix_mp.xfer_func = transfer;
4398 }
4399 else
4400 {
4401 format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
4402 format.fmt.pix.colorspace = colorspace;
4403 format.fmt.pix.quantization = range;
4404 format.fmt.pix.ycbcr_enc = matrix;
4405 format.fmt.pix.xfer_func = transfer;
4406 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004407
bo.xiao857b8682024-09-12 16:40:32 +08004408 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
4409 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004410
bo.xiao857b8682024-09-12 16:40:32 +08004411 if (try_only)
4412 {
4413 if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
4414 goto try_fmt_failed;
4415 }
4416 else
4417 {
4418 if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
4419 goto set_fmt_failed;
4420 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004421
bo.xiao857b8682024-09-12 16:40:32 +08004422 if (is_mplane)
4423 {
4424 colorspace = format.fmt.pix_mp.colorspace;
4425 range = format.fmt.pix_mp.quantization;
4426 matrix = format.fmt.pix_mp.ycbcr_enc;
4427 transfer = format.fmt.pix_mp.xfer_func;
4428 }
4429 else
4430 {
4431 colorspace = format.fmt.pix.colorspace;
4432 range = format.fmt.pix.quantization;
4433 matrix = format.fmt.pix.ycbcr_enc;
4434 transfer = format.fmt.pix.xfer_func;
4435 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004436
bo.xiao857b8682024-09-12 16:40:32 +08004437 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got format of %dx%d, format "
4438 "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d",
4439 format.fmt.pix.width, format.fmt.pix_mp.height,
4440 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4441 is_mplane ? format.fmt.pix_mp.num_planes : 1,
4442 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004443
4444#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004445 if (is_mplane)
4446 {
4447 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4448 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4449 format.fmt.pix_mp.plane_fmt[i].bytesperline,
4450 format.fmt.pix_mp.plane_fmt[i].sizeimage);
4451 }
4452 else
4453 {
4454 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4455 format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
4456 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004457#endif
4458
bo.xiao857b8682024-09-12 16:40:32 +08004459 if (format.fmt.pix.pixelformat != pixelformat)
4460 goto invalid_pixelformat;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004461
bo.xiao857b8682024-09-12 16:40:32 +08004462 /* Only negotiate size with raw data.
4463 * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
4464 * in ASF mode for example, there is also not reason for a driver to
4465 * change the size. */
4466 if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED)
4467 {
4468 /* We can crop larger images */
4469 if (format.fmt.pix.width < width || format.fmt.pix.height < height)
4470 goto invalid_dimensions;
4471
4472 /* Note, this will be adjusted if upstream has non-centered cropping. */
4473 align.padding_top = 0;
4474 align.padding_bottom = format.fmt.pix.height - height;
4475 align.padding_left = 0;
4476 align.padding_right = format.fmt.pix.width - width;
4477 }
4478
4479 if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
4480 goto invalid_planes;
4481
4482 /* used to check colorimetry and interlace mode fields presence */
4483 s = gst_caps_get_structure (caps, 0);
4484
4485 if (!gst_aml_v4l2_object_get_interlace_mode(format.fmt.pix.field,
4486 &info.interlace_mode))
4487 goto invalid_field;
4488 if (gst_structure_has_field(s, "interlace-mode"))
4489 {
4490 if (format.fmt.pix.field != field)
4491 goto invalid_field;
4492 }
4493
4494 if (gst_aml_v4l2_object_get_colorspace(&format, &info.colorimetry))
4495 {
4496 if (gst_structure_has_field(s, "colorimetry"))
4497 {
4498 if (!gst_aml_v4l2_video_colorimetry_matches(&info.colorimetry, gst_structure_get_string(s, "colorimetry")))
4499 {
4500 // goto invalid_colorimetry;
4501 }
4502 }
4503 }
4504 else
4505 {
4506 /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
4507 * the TRY_FMT */
4508 disable_colorimetry = TRUE;
4509 if (gst_structure_has_field (s, "colorimetry"))
4510 gst_structure_remove_field (s, "colorimetry");
4511 }
4512
4513 /* In case we have skipped the try_fmt probes, we'll need to set the
4514 * colorimetry and interlace-mode back into the caps. */
4515 if (v4l2object->skip_try_fmt_probes)
4516 {
4517 if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004518 {
bo.xiao857b8682024-09-12 16:40:32 +08004519 gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
4520 gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
4521 g_free (str);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004522 }
4523
bo.xiao857b8682024-09-12 16:40:32 +08004524 if (!gst_structure_has_field(s, "interlace-mode"))
4525 gst_structure_set(s, "interlace-mode", G_TYPE_STRING,
4526 gst_video_interlace_mode_to_string(info.interlace_mode), NULL);
4527 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004528
bo.xiao857b8682024-09-12 16:40:32 +08004529 if (try_only) /* good enough for trying only */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004530 return TRUE;
4531
bo.xiao857b8682024-09-12 16:40:32 +08004532 if (GST_VIDEO_INFO_HAS_ALPHA (&info))
4533 {
4534 struct v4l2_control ctl = { 0, };
4535 ctl.id = V4L2_CID_ALPHA_COMPONENT;
4536 ctl.value = 0xff;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004537
bo.xiao857b8682024-09-12 16:40:32 +08004538 if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
4539 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4540 "Failed to set alpha component value");
4541 }
4542
4543 /* Is there a reason we require the caller to always specify a framerate? */
4544 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
4545 fps_d);
4546
4547 if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
4548 goto get_parm_failed;
4549
4550 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
4551 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
4552 {
4553 GST_VIDEO_INFO_FPS_N (&info) =
4554 streamparm.parm.capture.timeperframe.denominator;
4555 GST_VIDEO_INFO_FPS_D (&info) =
4556 streamparm.parm.capture.timeperframe.numerator;
4557
4558 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u",
4559 streamparm.parm.capture.timeperframe.denominator,
4560 streamparm.parm.capture.timeperframe.numerator);
4561
4562 /* We used to skip frame rate setup if the camera was already setup
4563 * with the requested frame rate. This breaks some cameras though,
4564 * causing them to not output data (several models of Thinkpad cameras
4565 * have this problem at least).
4566 * So, don't skip. */
4567 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
4568 fps_n, fps_d);
4569 /* We want to change the frame rate, so check whether we can. Some cheap USB
4570 * cameras don't have the capability */
4571 if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004572 {
bo.xiao857b8682024-09-12 16:40:32 +08004573 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4574 "Not setting capture framerate (not supported)");
4575 goto done;
4576 }
4577
4578 /* Note: V4L2 wants the frame interval, we have the frame rate */
4579 streamparm.parm.capture.timeperframe.numerator = fps_d;
4580 streamparm.parm.capture.timeperframe.denominator = fps_n;
4581
4582 if (streamparm.parm.capture.timeperframe.numerator > 0 &&
4583 streamparm.parm.capture.timeperframe.denominator > 0)
4584 {
4585 /* get new values */
4586 fps_d = streamparm.parm.capture.timeperframe.numerator;
4587 fps_n = streamparm.parm.capture.timeperframe.denominator;
4588
4589 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set capture framerate to %u/%u",
4590 fps_n, fps_d);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004591 }
4592 else
4593 {
bo.xiao857b8682024-09-12 16:40:32 +08004594 /* fix v4l2 capture driver to provide framerate values */
4595 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4596 "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
4597 }
4598
4599 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4600 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4601 }
4602 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
4603 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4604 {
4605 GST_VIDEO_INFO_FPS_N (&info) =
4606 streamparm.parm.output.timeperframe.denominator;
4607 GST_VIDEO_INFO_FPS_D (&info) =
4608 streamparm.parm.output.timeperframe.numerator;
4609
4610 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u",
4611 streamparm.parm.output.timeperframe.denominator,
4612 streamparm.parm.output.timeperframe.numerator);
4613
4614 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting output framerate to %u/%u",
4615 fps_n, fps_d);
4616 if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4617 {
4618 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4619 "Not setting output framerate (not supported)");
4620 goto done;
4621 }
4622
4623 /* Note: V4L2 wants the frame interval, we have the frame rate */
4624 streamparm.parm.output.timeperframe.numerator = fps_d;
4625 streamparm.parm.output.timeperframe.denominator = fps_n;
4626
4627 if (streamparm.parm.output.timeperframe.numerator > 0 &&
4628 streamparm.parm.output.timeperframe.denominator > 0)
4629 {
4630 /* get new values */
4631 fps_d = streamparm.parm.output.timeperframe.numerator;
4632 fps_n = streamparm.parm.output.timeperframe.denominator;
4633
4634 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set output framerate to %u/%u",
4635 fps_n, fps_d);
4636 }
4637 else
4638 {
4639 /* fix v4l2 output driver to provide framerate values */
4640 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4641 "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
4642 }
4643
4644 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4645 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4646 }
4647
4648done:
4649 /* add boolean return, so we can fail on drivers bugs */
4650 gst_aml_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info, &align);
4651
4652 /* now configure the pool */
4653 if (!gst_aml_v4l2_object_setup_pool (v4l2object, caps))
4654 goto pool_failed;
4655
4656 return TRUE;
4657
4658 /* ERRORS */
4659invalid_caps:
4660 {
4661 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
4662 caps);
4663
4664 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4665 (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps));
4666 return FALSE;
4667 }
4668try_fmt_failed:
4669 {
4670 if (errno == EINVAL)
4671 {
4672 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4673 (_("Device '%s' has no supported format"), v4l2object->videodev),
4674 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4675 GST_FOURCC_ARGS (pixelformat), width, height,
4676 g_strerror (errno)));
4677 }
4678 else
4679 {
4680 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4681 (_("Device '%s' failed during initialization"),
4682 v4l2object->videodev),
4683 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4684 GST_FOURCC_ARGS (pixelformat), width, height,
4685 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004686 }
4687 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004688 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004689set_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004690 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004691 if (errno == EBUSY)
4692 {
bo.xiao857b8682024-09-12 16:40:32 +08004693 GST_AML_V4L2_ERROR (error, RESOURCE, BUSY,
4694 (_("Device '%s' is busy"), v4l2object->videodev),
4695 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4696 GST_FOURCC_ARGS (pixelformat), width, height,
4697 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004698 }
4699 else if (errno == EINVAL)
4700 {
bo.xiao857b8682024-09-12 16:40:32 +08004701 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4702 (_("Device '%s' has no supported format"), v4l2object->videodev),
4703 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4704 GST_FOURCC_ARGS (pixelformat), width, height,
4705 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004706 }
4707 else
4708 {
bo.xiao857b8682024-09-12 16:40:32 +08004709 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4710 (_("Device '%s' failed during initialization"),
4711 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 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004717 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004718invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08004719 {
4720 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4721 (_("Device '%s' cannot capture at %dx%d"),
4722 v4l2object->videodev, width, height),
4723 ("Tried to capture at %dx%d, but device returned size %dx%d",
4724 width, height, format.fmt.pix.width, format.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004725 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004726 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004727invalid_pixelformat:
bo.xiao857b8682024-09-12 16:40:32 +08004728 {
4729 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4730 (_("Device '%s' cannot capture in the specified format"),
4731 v4l2object->videodev),
4732 ("Tried to capture in %" GST_FOURCC_FORMAT
4733 ", but device returned format" " %" GST_FOURCC_FORMAT,
4734 GST_FOURCC_ARGS (pixelformat),
4735 GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004736 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004737 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004738invalid_planes:
bo.xiao857b8682024-09-12 16:40:32 +08004739 {
4740 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4741 (_("Device '%s' does support non-contiguous planes"),
4742 v4l2object->videodev),
4743 ("Device wants %d planes", format.fmt.pix_mp.num_planes));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004744 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004745 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004746invalid_field:
bo.xiao857b8682024-09-12 16:40:32 +08004747 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004748 enum v4l2_field wanted_field;
4749
4750 if (is_mplane)
bo.xiao857b8682024-09-12 16:40:32 +08004751 wanted_field = format.fmt.pix_mp.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004752 else
bo.xiao857b8682024-09-12 16:40:32 +08004753 wanted_field = format.fmt.pix.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004754
bo.xiao857b8682024-09-12 16:40:32 +08004755 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4756 (_("Device '%s' does not support %s interlacing"),
4757 v4l2object->videodev,
4758 field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
4759 ("Device wants %s interlacing",
4760 wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004761 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004762 }
hanghang.luo3128f102022-08-18 10:36:19 +08004763#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08004764invalid_colorimetry:
bo.xiao857b8682024-09-12 16:40:32 +08004765 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004766 gchar *wanted_colorimetry;
4767
bo.xiao857b8682024-09-12 16:40:32 +08004768 wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004769
bo.xiao857b8682024-09-12 16:40:32 +08004770 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4771 (_("Device '%s' does not support %s colorimetry"),
4772 v4l2object->videodev, gst_structure_get_string (s, "colorimetry")),
4773 ("Device wants %s colorimetry", wanted_colorimetry));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004774
bo.xiao857b8682024-09-12 16:40:32 +08004775 g_free (wanted_colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004776 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004777 }
hanghang.luo3128f102022-08-18 10:36:19 +08004778#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08004779get_parm_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004780 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004781 /* it's possible that this call is not supported */
4782 if (errno != EINVAL && errno != ENOTTY)
4783 {
bo.xiao857b8682024-09-12 16:40:32 +08004784 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4785 (_("Could not get parameters on device '%s'"),
4786 v4l2object->videodev), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004787 }
4788 goto done;
bo.xiao857b8682024-09-12 16:40:32 +08004789 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004790pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004791 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004792 /* setup_pool already send the error */
4793 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004794 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004795}
4796
4797gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004798gst_aml_v4l2_object_set_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4799 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004800{
bo.xiao857b8682024-09-12 16:40:32 +08004801 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
4802 caps);
4803 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, FALSE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004804}
4805
4806gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004807gst_aml_v4l2_object_try_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4808 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004809{
bo.xiao857b8682024-09-12 16:40:32 +08004810 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
4811 caps);
4812 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004813}
4814
4815GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004816gst_aml_v4l2_object_poll (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004817{
bo.xiao857b8682024-09-12 16:40:32 +08004818 gint ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004819
bo.xiao857b8682024-09-12 16:40:32 +08004820 if (!v4l2object->can_poll_device)
4821 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004822
bo.xiao857b8682024-09-12 16:40:32 +08004823 GST_LOG_OBJECT (v4l2object, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004824
4825again:
bo.xiao857b8682024-09-12 16:40:32 +08004826 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
4827 if (G_UNLIKELY (ret < 0))
4828 {
4829 switch (errno)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004830 {
bo.xiao857b8682024-09-12 16:40:32 +08004831 case EBUSY:
4832 goto stopped;
4833 case EAGAIN:
4834 case EINTR:
4835 goto again;
4836 case ENXIO:
4837 GST_WARNING_OBJECT (v4l2object,
4838 "v4l2 device doesn't support polling. Disabling"
4839 " using libv4l2 in this case may cause deadlocks");
4840 v4l2object->can_poll_device = FALSE;
4841 goto done;
4842 default:
4843 goto select_error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004844 }
bo.xiao857b8682024-09-12 16:40:32 +08004845 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004846
4847done:
bo.xiao857b8682024-09-12 16:40:32 +08004848 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004849
bo.xiao857b8682024-09-12 16:40:32 +08004850 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004851stopped:
bo.xiao857b8682024-09-12 16:40:32 +08004852 {
4853 GST_DEBUG_OBJECT (v4l2object, "stop called");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004854 return GST_FLOW_FLUSHING;
bo.xiao857b8682024-09-12 16:40:32 +08004855 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004856select_error:
bo.xiao857b8682024-09-12 16:40:32 +08004857 {
4858 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
4859 ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004860 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004861 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004862}
4863
4864GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004865gst_aml_v4l2_object_dqevent (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004866{
bo.xiao857b8682024-09-12 16:40:32 +08004867 GstFlowReturn res;
4868 struct v4l2_event evt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004869
bo.xiao857b8682024-09-12 16:40:32 +08004870 if ((res = gst_aml_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
4871 goto poll_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004872
bo.xiao857b8682024-09-12 16:40:32 +08004873 //only read v4l2 pri event
4874 if (!gst_poll_fd_can_read_pri(v4l2object->poll, &v4l2object->pollfd))
4875 {
4876 GST_DEBUG_OBJECT(v4l2object, "not v4l2 pri event");
4877 return GST_FLOW_OK;
4878 }
4879 memset (&evt, 0x00, sizeof (struct v4l2_event));
4880 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
4881 goto dqevent_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004882
bo.xiao857b8682024-09-12 16:40:32 +08004883 switch (evt.type)
4884 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004885 case V4L2_EVENT_SOURCE_CHANGE:
bo.xiao857b8682024-09-12 16:40:32 +08004886 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
4887 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004888 case V4L2_EVENT_EOS:
bo.xiao857b8682024-09-12 16:40:32 +08004889 return GST_AML_V4L2_FLOW_LAST_BUFFER;
4890 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004891 default:
bo.xiao857b8682024-09-12 16:40:32 +08004892 break;
4893 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004894
bo.xiao857b8682024-09-12 16:40:32 +08004895 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004896
bo.xiao857b8682024-09-12 16:40:32 +08004897 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004898poll_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004899 {
4900 GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004901 return res;
bo.xiao857b8682024-09-12 16:40:32 +08004902 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004903dqevent_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004904 {
fei.deng678f7052024-07-10 20:11:26 +08004905 GST_DEBUG_OBJECT(v4l2object, "dqevent failed");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004906 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004907 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004908}
4909
4910/**
4911 * gst_aml_v4l2_object_acquire_format:
bo.xiao857b8682024-09-12 16:40:32 +08004912 * @v4l2object: the object
4913 * @info: a GstVideoInfo to be filled
xuesong.jiangae1548e2022-05-06 16:38:46 +08004914 *
bo.xiao857b8682024-09-12 16:40:32 +08004915 * Acquire the driver chosen format. This is useful in decoder or encoder elements where
4916 * the output format is chosen by the HW.
xuesong.jiangae1548e2022-05-06 16:38:46 +08004917 *
4918 * Returns: %TRUE on success, %FALSE on failure.
4919 */
4920gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004921gst_aml_v4l2_object_acquire_format (GstAmlV4l2Object * v4l2object, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004922{
bo.xiao857b8682024-09-12 16:40:32 +08004923 struct v4l2_fmtdesc *fmtdesc;
4924 struct v4l2_format fmt;
4925 struct v4l2_crop crop;
4926 struct v4l2_selection sel;
4927 struct v4l2_cropcap cropcap;
4928 struct v4l2_rect *r = NULL;
4929 GstVideoFormat format;
4930 guint width, height;
4931 GstVideoAlignment align;
4932 gdouble pixelAspectRatio = 0.0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004933
bo.xiao857b8682024-09-12 16:40:32 +08004934 gst_video_info_init (info);
4935 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004936
bo.xiao857b8682024-09-12 16:40:32 +08004937 memset (&fmt, 0x00, sizeof (struct v4l2_format));
4938 fmt.type = v4l2object->type;
4939 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "fmt.type:%d", fmt.type);
4940 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
4941 goto get_fmt_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004942
bo.xiao857b8682024-09-12 16:40:32 +08004943 fmtdesc = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object,
4944 fmt.fmt.pix.pixelformat);
4945 if (fmtdesc == NULL)
4946 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004947
bo.xiao857b8682024-09-12 16:40:32 +08004948 /* No need to care about mplane, the four first params are the same */
4949 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004950
bo.xiao857b8682024-09-12 16:40:32 +08004951 /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
4952 if (format == GST_VIDEO_FORMAT_UNKNOWN)
4953 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004954
bo.xiao857b8682024-09-12 16:40:32 +08004955 if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
4956 goto invalid_dimensions;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004957
bo.xiao857b8682024-09-12 16:40:32 +08004958 width = fmt.fmt.pix.width;
4959 height = fmt.fmt.pix.height;
4960
4961 /* Use the default compose rectangle */
4962 memset (&sel, 0, sizeof (struct v4l2_selection));
4963 sel.type = v4l2object->type;
4964 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
4965 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
4966 {
4967 r = &sel.r;
4968 }
4969 else
4970 {
4971 /* For ancient kernels, fall back to G_CROP */
4972 memset (&crop, 0, sizeof (struct v4l2_crop));
4973 crop.type = v4l2object->type;
4974 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
4975 r = &crop.c;
4976 }
4977
4978 if (r)
4979 {
4980 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
4981
4982 align.padding_left = r->left;
4983 align.padding_top = r->top;
4984 align.padding_right = width - r->width - r->left;
4985 align.padding_bottom = height - r->height - r->top;
4986 width = r->width;
4987 height = r->height;
4988
4989 if (self->v4l2output->dw_mode >= 0 && self->v4l2output->dw_mode != VDEC_DW_NO_AFBC)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004990 {
bo.xiao857b8682024-09-12 16:40:32 +08004991 width = (width/2) *2; // align for dw
4992 height = (height/2) *2; // align for dw
xuesong.jiangae1548e2022-05-06 16:38:46 +08004993 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004994
bo.xiao857b8682024-09-12 16:40:32 +08004995 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY)
4996 height = width = 64; //because driver return src w,h when AFBC_ONLY
4997 }
4998 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "final w:%d, h:%d", width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08004999
bo.xiao857b8682024-09-12 16:40:32 +08005000 gst_video_info_set_format(info, format, width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005001
bo.xiao857b8682024-09-12 16:40:32 +08005002 switch (fmt.fmt.pix.field)
5003 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005004 case V4L2_FIELD_ANY:
5005 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08005006 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
5007 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005008 case V4L2_FIELD_INTERLACED:
5009 case V4L2_FIELD_INTERLACED_TB:
5010 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08005011 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
5012 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005013 default:
bo.xiao857b8682024-09-12 16:40:32 +08005014 goto unsupported_field;
5015 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005016
bo.xiao857b8682024-09-12 16:40:32 +08005017 gst_aml_v4l2_object_get_colorspace(&fmt, &info->colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005018
bo.xiao857b8682024-09-12 16:40:32 +08005019 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &fmt, info, &align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005020
bo.xiao857b8682024-09-12 16:40:32 +08005021 if (v4l2object->par)
5022 {
5023 width = gst_value_get_fraction_numerator(v4l2object->par);
5024 height = gst_value_get_fraction_denominator(v4l2object->par);
5025 pixelAspectRatio = (gdouble)width/(gdouble)height;
5026 }
sheng.liu641aa422023-12-26 07:05:59 +00005027
bo.xiao857b8682024-09-12 16:40:32 +08005028 if (!v4l2object->par || pixelAspectRatio == 1.0)
5029 {
5030 memset(&cropcap, 0, sizeof(cropcap));
5031 width= height= 1;
5032 cropcap.type = v4l2object->type;
5033 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) >= 0)
5034 {
5035 width= cropcap.pixelaspect.denominator;
5036 height= cropcap.pixelaspect.numerator;
5037 GST_DEBUG("cropcap: pixel aspect ratio %d:%d", width, height);
5038 if ( !width || !height )
5039 {
5040 GST_DEBUG("force pixel aspect of 1:1");
5041 width= height= 1;
5042 }
5043 }
5044 }
sheng.liudb26f7d2024-01-22 11:24:23 +00005045
bo.xiao857b8682024-09-12 16:40:32 +08005046 GST_VIDEO_INFO_PAR_N(info) = width;
5047 GST_VIDEO_INFO_PAR_D(info) = height;
sheng.liud9027ca2024-01-24 09:21:49 +00005048
bo.xiao857b8682024-09-12 16:40:32 +08005049 if (v4l2object->fps)
5050 {
5051 GST_VIDEO_INFO_FPS_N(info) = gst_value_get_fraction_numerator(v4l2object->fps);
5052 GST_VIDEO_INFO_FPS_D(info) = gst_value_get_fraction_denominator(v4l2object->fps);
5053 }
5054 /* Shall we setup the pool ? */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005055
bo.xiao857b8682024-09-12 16:40:32 +08005056 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005057
5058get_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005059 {
5060 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5061 (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005062 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005063 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005064invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08005065 {
5066 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5067 (_("Video device returned invalid dimensions.")),
5068 ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
5069 fmt.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005070 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005071 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005072unsupported_field:
bo.xiao857b8682024-09-12 16:40:32 +08005073 {
5074 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5075 (_("Video device uses an unsupported interlacing method.")),
5076 ("V4L2 field type %d not supported", fmt.fmt.pix.field));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005077 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005078 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005079unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08005080 {
5081 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5082 (_("Video device uses an unsupported pixel format.")),
5083 ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
5084 GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005085 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005086 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005087}
5088
5089gboolean
5090gst_aml_v4l2_object_set_crop(GstAmlV4l2Object *obj)
5091{
bo.xiao857b8682024-09-12 16:40:32 +08005092 struct v4l2_selection sel = { 0 };
5093 struct v4l2_crop crop = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005094
bo.xiao857b8682024-09-12 16:40:32 +08005095 sel.type = obj->type;
5096 sel.target = V4L2_SEL_TGT_CROP;
5097 sel.flags = 0;
5098 sel.r.left = obj->align.padding_left;
5099 sel.r.top = obj->align.padding_top;
5100 sel.r.width = obj->info.width;
5101 sel.r.height = obj->info.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005102
bo.xiao857b8682024-09-12 16:40:32 +08005103 crop.type = obj->type;
5104 crop.c = sel.r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005105
bo.xiao857b8682024-09-12 16:40:32 +08005106 if (obj->align.padding_left + obj->align.padding_top +
5107 obj->align.padding_right + obj->align.padding_bottom ==
5108 0)
5109 {
5110 GST_DEBUG_OBJECT(obj->dbg_obj, "no cropping needed");
5111 return TRUE;
5112 }
5113
5114 GST_DEBUG_OBJECT (obj->dbg_obj,
5115 "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5116 crop.c.width, crop.c.height);
5117
5118 if (obj->ioctl (obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0)
5119 {
5120 if (errno != ENOTTY)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005121 {
bo.xiao857b8682024-09-12 16:40:32 +08005122 GST_WARNING_OBJECT (obj->dbg_obj,
5123 "Failed to set crop rectangle with VIDIOC_S_SELECTION: %s",
5124 g_strerror (errno));
5125 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005126 }
bo.xiao857b8682024-09-12 16:40:32 +08005127 else
xuesong.jiangae1548e2022-05-06 16:38:46 +08005128 {
bo.xiao857b8682024-09-12 16:40:32 +08005129 if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0)
5130 {
5131 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_S_CROP failed");
5132 return FALSE;
5133 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005134
bo.xiao857b8682024-09-12 16:40:32 +08005135 if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0)
5136 {
5137 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_G_CROP failed");
5138 return FALSE;
5139 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005140
bo.xiao857b8682024-09-12 16:40:32 +08005141 sel.r = crop.c;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005142 }
bo.xiao857b8682024-09-12 16:40:32 +08005143 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005144
bo.xiao857b8682024-09-12 16:40:32 +08005145 GST_DEBUG_OBJECT (obj->dbg_obj,
5146 "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5147 crop.c.width, crop.c.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005148
bo.xiao857b8682024-09-12 16:40:32 +08005149 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005150}
5151
5152gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005153gst_aml_v4l2_object_caps_equal (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005154{
bo.xiao857b8682024-09-12 16:40:32 +08005155 GstStructure *config;
5156 GstCaps *oldcaps;
5157 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005158
bo.xiao857b8682024-09-12 16:40:32 +08005159 if (!v4l2object->pool)
5160 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005161
bo.xiao857b8682024-09-12 16:40:32 +08005162 config = gst_buffer_pool_get_config(v4l2object->pool);
5163 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005164
bo.xiao857b8682024-09-12 16:40:32 +08005165 ret = oldcaps && gst_caps_is_equal (caps, oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005166
bo.xiao857b8682024-09-12 16:40:32 +08005167 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005168
bo.xiao857b8682024-09-12 16:40:32 +08005169 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005170}
5171
5172gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005173gst_aml_v4l2_object_caps_is_subset (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005174{
bo.xiao857b8682024-09-12 16:40:32 +08005175 GstStructure *config;
5176 GstCaps *oldcaps;
5177 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005178
bo.xiao857b8682024-09-12 16:40:32 +08005179 if (!v4l2object->pool)
5180 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005181
bo.xiao857b8682024-09-12 16:40:32 +08005182 config = gst_buffer_pool_get_config(v4l2object->pool);
5183 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005184
bo.xiao857b8682024-09-12 16:40:32 +08005185 ret = oldcaps && gst_caps_is_subset (oldcaps, caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005186
bo.xiao857b8682024-09-12 16:40:32 +08005187 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005188
bo.xiao857b8682024-09-12 16:40:32 +08005189 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005190}
5191
5192GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005193gst_aml_v4l2_object_get_current_caps (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005194{
bo.xiao857b8682024-09-12 16:40:32 +08005195 GstStructure *config;
5196 GstCaps *oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005197
bo.xiao857b8682024-09-12 16:40:32 +08005198 if (!v4l2object->pool)
5199 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005200
bo.xiao857b8682024-09-12 16:40:32 +08005201 config = gst_buffer_pool_get_config(v4l2object->pool);
5202 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005203
bo.xiao857b8682024-09-12 16:40:32 +08005204 if (oldcaps)
5205 gst_caps_ref (oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005206
bo.xiao857b8682024-09-12 16:40:32 +08005207 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005208
bo.xiao857b8682024-09-12 16:40:32 +08005209 return oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005210}
5211
5212gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005213gst_aml_v4l2_object_flush_start(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005214{
bo.xiao857b8682024-09-12 16:40:32 +08005215 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005216
bo.xiao857b8682024-09-12 16:40:32 +08005217 GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005218
bo.xiao857b8682024-09-12 16:40:32 +08005219 gst_poll_set_flushing (v4l2object->poll, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005220
bo.xiao857b8682024-09-12 16:40:32 +08005221 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5222 gst_buffer_pool_set_flushing(v4l2object->pool, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005223
bo.xiao857b8682024-09-12 16:40:32 +08005224 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005225}
5226
5227gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005228gst_aml_v4l2_object_flush_stop(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005229{
bo.xiao857b8682024-09-12 16:40:32 +08005230 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005231
bo.xiao857b8682024-09-12 16:40:32 +08005232 GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005233
bo.xiao857b8682024-09-12 16:40:32 +08005234 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5235 gst_buffer_pool_set_flushing(v4l2object->pool, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005236
bo.xiao857b8682024-09-12 16:40:32 +08005237 gst_poll_set_flushing(v4l2object->poll, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005238
bo.xiao857b8682024-09-12 16:40:32 +08005239 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005240}
5241
5242gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005243gst_aml_v4l2_object_stop (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005244{
bo.xiao857b8682024-09-12 16:40:32 +08005245 GstAmlV4l2BufferPool *bpool = GST_AML_V4L2_BUFFER_POOL(v4l2object->pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005246
bo.xiao857b8682024-09-12 16:40:32 +08005247 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stopping");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005248
bo.xiao857b8682024-09-12 16:40:32 +08005249 if (!GST_AML_V4L2_IS_OPEN (v4l2object))
5250 goto done;
5251 if (!GST_AML_V4L2_IS_ACTIVE (v4l2object))
5252 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005253
bo.xiao857b8682024-09-12 16:40:32 +08005254 if (bpool && bpool->other_pool) /* jxsdbg for resolution switch */
5255 {
5256 if (v4l2object->old_other_pool)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005257 {
bo.xiao857b8682024-09-12 16:40:32 +08005258 /* this case indicate 1st switch did not wait all old pool buf recycle and 2nd switch is coming.
5259 so save 1st old pool */
5260 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching occurs during last switching buf recycle flow");
5261 v4l2object->old_old_other_pool = v4l2object->old_other_pool;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005262 }
5263
bo.xiao857b8682024-09-12 16:40:32 +08005264 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching flow, ref old drmbufferpool");
5265 v4l2object->old_other_pool = bpool->other_pool;
5266 gst_object_ref(v4l2object->old_other_pool);
5267 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005268
bo.xiao857b8682024-09-12 16:40:32 +08005269 if (v4l2object->pool)
5270 {
5271 if (!gst_aml_v4l2_buffer_pool_orphan(&v4l2object->pool))
5272 {
5273 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "deactivating pool");
5274 gst_buffer_pool_set_active(v4l2object->pool, FALSE);
5275 gst_object_unref(v4l2object->pool);
5276 }
5277 v4l2object->pool = NULL;
5278 }
5279
5280 GST_AML_V4L2_SET_INACTIVE (v4l2object);
5281 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "stopped");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005282done:
bo.xiao857b8682024-09-12 16:40:32 +08005283 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005284}
5285
5286GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005287gst_aml_v4l2_object_probe_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005288{
bo.xiao857b8682024-09-12 16:40:32 +08005289 GstCaps *ret;
5290 GSList *walk;
5291 GSList *formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005292
bo.xiao857b8682024-09-12 16:40:32 +08005293 GST_INFO_OBJECT(v4l2object->dbg_obj, "filter caps: %" GST_PTR_FORMAT, filter);
5294 formats = gst_aml_v4l2_object_get_format_list (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005295
bo.xiao857b8682024-09-12 16:40:32 +08005296 ret = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005297
sheng.liu641aa422023-12-26 07:05:59 +00005298// At this time, decoder will return defult aspect, and it is not usful.
5299// so, do not probe cropcap at this time and do this action after decoding.
5300#if 0
bo.xiao857b8682024-09-12 16:40:32 +08005301 if (v4l2object->keep_aspect && !v4l2object->par)
5302 {
5303 struct v4l2_cropcap cropcap;
5304
5305 memset (&cropcap, 0, sizeof (cropcap));
5306
5307 cropcap.type = v4l2object->type;
5308 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005309 {
bo.xiao857b8682024-09-12 16:40:32 +08005310 if (errno != ENOTTY)
5311 GST_WARNING_OBJECT (v4l2object->dbg_obj,
5312 "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
5313 g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005314 }
bo.xiao857b8682024-09-12 16:40:32 +08005315 else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator)
5316 {
5317 v4l2object->par = g_new0 (GValue, 1);
5318 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
5319 gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
5320 cropcap.pixelaspect.denominator);
5321 }
5322 }
sheng.liu641aa422023-12-26 07:05:59 +00005323#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08005324
bo.xiao857b8682024-09-12 16:40:32 +08005325 for (walk = formats; walk; walk = walk->next)
5326 {
5327 struct v4l2_fmtdesc *format;
5328 GstStructure *template;
5329 GstCaps *tmp, *tmp2;
5330
5331 format = (struct v4l2_fmtdesc *) walk->data;
5332
5333 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (format->pixelformat);
5334
5335 if (!template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005336 {
bo.xiao857b8682024-09-12 16:40:32 +08005337 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
5338 "unknown format %" GST_FOURCC_FORMAT,
5339 GST_FOURCC_ARGS (format->pixelformat));
5340 continue;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005341 }
5342
bo.xiao857b8682024-09-12 16:40:32 +08005343 /* If we have a filter, check if we need to probe this format or not */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005344 if (filter)
5345 {
bo.xiao857b8682024-09-12 16:40:32 +08005346 GstCaps *format_caps = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005347
bo.xiao857b8682024-09-12 16:40:32 +08005348 gst_caps_append_structure (format_caps, gst_structure_copy (template));
5349 GST_INFO_OBJECT(v4l2object->dbg_obj, "format_caps: %" GST_PTR_FORMAT, format_caps);
5350
5351 if (!gst_caps_can_intersect (format_caps, filter))
5352 {
5353 gst_caps_unref (format_caps);
5354 gst_structure_free (template);
5355 continue;
5356 }
5357
5358 gst_caps_unref (format_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005359 }
5360
bo.xiao857b8682024-09-12 16:40:32 +08005361 tmp = gst_aml_v4l2_object_probe_caps_for_format (v4l2object,
5362 format->pixelformat, template);
5363 GST_INFO_OBJECT(v4l2object->dbg_obj, "tmp caps: %" GST_PTR_FORMAT, tmp);
5364
5365 if (tmp)
xuesong.jiang22a9b112023-05-24 09:01:59 +00005366 {
bo.xiao857b8682024-09-12 16:40:32 +08005367 tmp2 = gst_caps_copy(tmp);
5368 gst_caps_set_features_simple(tmp2, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
5369 gst_caps_append (ret, tmp);
5370 gst_caps_append (ret, tmp2);
xuesong.jiang22a9b112023-05-24 09:01:59 +00005371 }
5372
bo.xiao857b8682024-09-12 16:40:32 +08005373 gst_structure_free (template);
5374 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005375
bo.xiao857b8682024-09-12 16:40:32 +08005376 if (filter)
5377 {
5378 GstCaps *tmp;
5379
5380 tmp = ret;
5381 ret = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
5382 gst_caps_unref (tmp);
5383 }
5384
5385 if (v4l2object->stream_mode)
5386 {
5387 GST_INFO_OBJECT(v4l2object->dbg_obj, "ret caps: %" GST_PTR_FORMAT, ret);
5388 for (guint i = 0; i < gst_caps_get_size(ret); i++)
5389 {
5390 GstStructure *s = gst_caps_get_structure(ret, i);
5391 if (s)
5392 gst_structure_remove_field(s, "alignment");
5393
5394 GST_DEBUG("i:%d, s:%p", i, s);
5395 }
5396 GST_INFO_OBJECT(v4l2object->dbg_obj, "new ret caps: %" GST_PTR_FORMAT, ret);
5397 }
5398
5399 GST_INFO_OBJECT (v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
5400
5401 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005402}
5403
5404GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005405gst_aml_v4l2_object_get_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005406{
bo.xiao857b8682024-09-12 16:40:32 +08005407 GstCaps *ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005408
bo.xiao857b8682024-09-12 16:40:32 +08005409 if (v4l2object->probed_caps == NULL)
5410 v4l2object->probed_caps = gst_aml_v4l2_object_probe_caps (v4l2object, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005411
bo.xiao857b8682024-09-12 16:40:32 +08005412 if (filter)
5413 {
5414 ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
5415 GST_CAPS_INTERSECT_FIRST);
5416 }
5417 else
5418 {
5419 ret = gst_caps_ref (v4l2object->probed_caps);
5420 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005421
bo.xiao857b8682024-09-12 16:40:32 +08005422 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005423}
5424
5425gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005426gst_aml_v4l2_object_decide_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005427{
bo.xiao857b8682024-09-12 16:40:32 +08005428 GstCaps *caps;
5429 GstBufferPool *pool = NULL, *other_pool = NULL;
5430 GstStructure *config;
5431 guint size, min, max, own_min = 0;
5432 gboolean update;
5433 gboolean has_video_meta;
5434 gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
5435 GstAllocator *allocator = NULL;
5436 GstAllocationParams params = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005437
bo.xiao857b8682024-09-12 16:40:32 +08005438 GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005439
bo.xiao857b8682024-09-12 16:40:32 +08005440 g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
5441 obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005442
bo.xiao857b8682024-09-12 16:40:32 +08005443 gst_query_parse_allocation (query, &caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005444
bo.xiao857b8682024-09-12 16:40:32 +08005445 if (obj->pool == NULL)
5446 {
5447 if (!gst_aml_v4l2_object_setup_pool (obj, caps))
5448 goto pool_failed;
5449 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005450
bo.xiao857b8682024-09-12 16:40:32 +08005451 if (gst_query_get_n_allocation_params (query) > 0)
5452 gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005453
bo.xiao857b8682024-09-12 16:40:32 +08005454 if (gst_query_get_n_allocation_pools (query) > 0)
5455 {
5456 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
5457 update = TRUE;
5458 }
5459 else
5460 {
5461 pool = NULL;
5462 min = max = 0;
5463 size = 0;
5464 update = FALSE;
5465 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005466
bo.xiao857b8682024-09-12 16:40:32 +08005467 GST_DEBUG_OBJECT (obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%"
5468 GST_PTR_FORMAT, size, min, max, pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005469
bo.xiao857b8682024-09-12 16:40:32 +08005470 has_video_meta =
5471 gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005472
bo.xiao857b8682024-09-12 16:40:32 +08005473 can_share_own_pool = (has_video_meta || !obj->need_video_meta);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005474
bo.xiao857b8682024-09-12 16:40:32 +08005475 gst_aml_v4l2_get_driver_min_buffers (obj);
5476 /* We can't share our own pool, if it exceed V4L2 capacity */
5477 if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
5478 can_share_own_pool = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005479
bo.xiao857b8682024-09-12 16:40:32 +08005480 /* select a pool */
5481 switch (obj->mode)
5482 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005483 case GST_V4L2_IO_RW:
bo.xiao857b8682024-09-12 16:40:32 +08005484 if (pool)
5485 {
5486 /* in READ/WRITE mode, prefer a downstream pool because our own pool
5487 * doesn't help much, we have to write to it as well */
5488 GST_DEBUG_OBJECT (obj->dbg_obj,
5489 "read/write mode: using downstream pool");
5490 /* use the bigest size, when we use our own pool we can't really do any
5491 * other size than what the hardware gives us but for downstream pools
5492 * we can try */
5493 size = MAX (size, obj->info.size);
5494 }
5495 else if (can_share_own_pool)
5496 {
5497 /* no downstream pool, use our own then */
5498 GST_DEBUG_OBJECT (obj->dbg_obj,
5499 "read/write mode: no downstream pool, using our own");
5500 pool = gst_object_ref(obj->pool);
5501 size = obj->info.size;
5502 pushing_from_our_pool = TRUE;
5503 }
5504 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005505
5506 case GST_V4L2_IO_USERPTR:
5507 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005508 /* in importing mode, prefer our own pool, and pass the other pool to
5509 * our own, so it can serve itself */
5510 if (pool == NULL)
5511 goto no_downstream_pool;
5512 gst_aml_v4l2_buffer_pool_set_other_pool(GST_AML_V4L2_BUFFER_POOL(obj->pool), pool);
5513 other_pool = pool;
5514 gst_object_unref (pool);
5515 pool = gst_object_ref(obj->pool);
5516 size = obj->info.size;
5517 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005518
5519 case GST_V4L2_IO_MMAP:
5520 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005521 /* in streaming mode, prefer our own pool */
5522 /* Check if we can use it ... */
5523 if (can_share_own_pool)
5524 {
5525 if (pool)
5526 gst_object_unref (pool);
5527 pool = gst_object_ref (obj->pool);
5528 size = obj->info.size;
5529 GST_DEBUG_OBJECT (obj->dbg_obj,
5530 "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
5531 pushing_from_our_pool = TRUE;
5532 }
5533 else if (pool)
5534 {
5535 GST_DEBUG_OBJECT (obj->dbg_obj,
5536 "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
5537 pool);
5538 }
5539 else
5540 {
5541 GST_DEBUG_OBJECT (obj->dbg_obj,
5542 "streaming mode: no usable pool, copying to generic pool");
5543 size = MAX (size, obj->info.size);
5544 }
5545 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005546 case GST_V4L2_IO_AUTO:
5547 default:
bo.xiao857b8682024-09-12 16:40:32 +08005548 GST_WARNING_OBJECT (obj->dbg_obj, "unhandled mode");
5549 break;
5550 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005551
bo.xiao857b8682024-09-12 16:40:32 +08005552 if (size == 0)
5553 goto no_size;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005554
bo.xiao857b8682024-09-12 16:40:32 +08005555 /* If pushing from our own pool, configure it with queried minimum,
5556 * otherwise use the minimum required */
5557 if (pushing_from_our_pool)
5558 {
5559 /* When pushing from our own pool, we need what downstream one, to be able
5560 * to fill the pipeline, the minimum required to decoder according to the
5561 * driver and 2 more, so we don't endup up with everything downstream or
5562 * held by the decoder. We account 2 buffers for v4l2 so when one is being
5563 * pushed downstream the other one can already be queued for the next
5564 * frame. */
5565 own_min = min + obj->min_buffers + 2;
5566
5567 /* If no allocation parameters where provided, allow for a little more
5568 * buffers and enable copy threshold */
5569 if (!update)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005570 {
bo.xiao857b8682024-09-12 16:40:32 +08005571 own_min += 2;
5572 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5573 TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005574 }
5575 else
5576 {
bo.xiao857b8682024-09-12 16:40:32 +08005577 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5578 FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005579 }
5580
bo.xiao857b8682024-09-12 16:40:32 +08005581 }
5582 else
5583 {
5584 min = obj->min_buffers;
5585 max = min;
5586 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005587
bo.xiao857b8682024-09-12 16:40:32 +08005588 /* Request a bigger max, if one was suggested but it's too small */
5589 if (max != 0)
5590 max = MAX (min, max);
5591
5592 /* First step, configure our own pool */
5593 config = gst_buffer_pool_get_config(obj->pool);
5594
5595 if (obj->need_video_meta || has_video_meta)
5596 {
5597 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5598 gst_buffer_pool_config_add_option (config,
5599 GST_BUFFER_POOL_OPTION_VIDEO_META);
5600 }
5601
5602 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5603 gst_buffer_pool_config_set_params(config, caps, size, min, max);
5604
5605 GST_DEBUG_OBJECT (obj->dbg_obj, "setting own pool config to %"
5606 GST_PTR_FORMAT, config);
5607
5608 /* Our pool often need to adjust the value */
5609 if (!gst_buffer_pool_set_config (obj->pool, config))
5610 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005611 config = gst_buffer_pool_get_config(obj->pool);
5612
bo.xiao857b8682024-09-12 16:40:32 +08005613 GST_DEBUG_OBJECT (obj->dbg_obj, "own pool config changed to %"
5614 GST_PTR_FORMAT, config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005615
bo.xiao857b8682024-09-12 16:40:32 +08005616 /* our pool will adjust the maximum buffer, which we are fine with */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005617 if (!gst_buffer_pool_set_config(obj->pool, config))
bo.xiao857b8682024-09-12 16:40:32 +08005618 goto config_failed;
5619 }
5620
5621 /* Now configure the other pool if different */
5622 if (obj->pool != pool)
5623 other_pool = pool;
5624
5625 if (other_pool)
5626 {
5627 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)obj->element;
5628 guint other_min = min;
5629 guint other_max = max;
5630
5631 if (obj->old_other_pool || obj->old_old_other_pool) //jxsdbg for switching
5632 {
5633 obj->outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
5634 if (obj->outstanding_buf_num > 0) {
5635 if (obj->outstanding_buf_num >= obj->min_buffers)
5636 {
5637 other_min = 1;
5638 }
5639 else
5640 {
5641 other_min = other_max = obj->min_buffers - obj->outstanding_buf_num;
5642 }
5643 }
5644 GST_DEBUG_OBJECT(obj, "oop:%p, ooop:%p, outstanding buf num:%d, set min, max to %d,%d",
5645 obj->old_other_pool, obj->old_old_other_pool,
5646 obj->outstanding_buf_num, other_min, other_max);
5647 }
5648
5649 if (self->is_secure_path)
5650 {
5651 params.flags |= GST_MEMORY_FLAG_LAST << 1; // in drmallocator GST_MEMORY_FLAG_LAST << 1 represent GST_MEMORY_FLAG_SECURE
5652 GST_DEBUG_OBJECT(obj, "set secure flag for drmbufferpool flag:0x%x", params.flags);
5653 }
5654 config = gst_buffer_pool_get_config (other_pool);
5655 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5656 gst_buffer_pool_config_set_params (config, caps, size, other_min, other_max);
5657 gst_buffer_pool_config_set_video_alignment(config, &obj->align);
5658
5659 GST_DEBUG_OBJECT (obj->dbg_obj, "setting other pool config to %"
5660 GST_PTR_FORMAT, config);
5661
5662 /* if downstream supports video metadata, add this to the pool config */
5663 if (has_video_meta)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005664 {
bo.xiao857b8682024-09-12 16:40:32 +08005665 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5666 gst_buffer_pool_config_add_option (config,
5667 GST_BUFFER_POOL_OPTION_VIDEO_META);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005668 }
5669
bo.xiao857b8682024-09-12 16:40:32 +08005670 if (!gst_buffer_pool_set_config (other_pool, config))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005671 {
bo.xiao857b8682024-09-12 16:40:32 +08005672 config = gst_buffer_pool_get_config (other_pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005673
bo.xiao857b8682024-09-12 16:40:32 +08005674 if (!gst_buffer_pool_config_validate_params (config, caps, size, min,
5675 max))
5676 {
5677 gst_structure_free (config);
5678 goto config_failed;
5679 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005680
bo.xiao857b8682024-09-12 16:40:32 +08005681 if (!gst_buffer_pool_set_config (other_pool, config))
5682 goto config_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005683 }
bo.xiao857b8682024-09-12 16:40:32 +08005684 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005685
bo.xiao857b8682024-09-12 16:40:32 +08005686 if (pool)
5687 {
5688 /* For simplicity, simply read back the active configuration, so our base
5689 * class get the right information */
5690 config = gst_buffer_pool_get_config (pool);
5691 gst_buffer_pool_config_get_params (config, NULL, &size, &min, &max);
5692 gst_structure_free (config);
5693 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005694
bo.xiao857b8682024-09-12 16:40:32 +08005695 if (update)
5696 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
5697 else
5698 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005699
bo.xiao857b8682024-09-12 16:40:32 +08005700 if (allocator)
5701 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005702
bo.xiao857b8682024-09-12 16:40:32 +08005703 if (pool)
5704 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005705
bo.xiao857b8682024-09-12 16:40:32 +08005706 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005707
5708pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005709 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005710 /* setup_pool already send the error */
5711 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005712 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005713config_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005714 {
5715 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5716 (_("Failed to configure internal buffer pool.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005717 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005718 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005719no_size:
bo.xiao857b8682024-09-12 16:40:32 +08005720 {
5721 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5722 (_("Video device did not suggest any buffer size.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005723 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005724 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005725cleanup:
bo.xiao857b8682024-09-12 16:40:32 +08005726 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005727 if (allocator)
bo.xiao857b8682024-09-12 16:40:32 +08005728 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005729
5730 if (pool)
bo.xiao857b8682024-09-12 16:40:32 +08005731 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005732 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005733 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005734no_downstream_pool:
bo.xiao857b8682024-09-12 16:40:32 +08005735 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005736 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5737 (_("No downstream pool to import from.")),
5738 ("When importing DMABUF or USERPTR, we need a pool to import from"));
5739 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005740 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005741}
5742
5743gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005744gst_aml_v4l2_object_propose_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005745{
bo.xiao857b8682024-09-12 16:40:32 +08005746 GstBufferPool *pool = NULL;
5747 /* we need at least 2 buffers to operate */
5748 guint size, min, max;
5749 GstCaps *caps;
5750 gboolean need_pool;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005751
bo.xiao857b8682024-09-12 16:40:32 +08005752 /* Set defaults allocation parameters */
5753 size = obj->info.size;
5754 min = GST_AML_V4L2_MIN_BUFFERS;
5755 max = VIDEO_MAX_FRAME;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005756
bo.xiao857b8682024-09-12 16:40:32 +08005757 gst_query_parse_allocation (query, &caps, &need_pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005758
bo.xiao857b8682024-09-12 16:40:32 +08005759 if (caps == NULL)
5760 goto no_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005761
bo.xiao857b8682024-09-12 16:40:32 +08005762 switch (obj->mode)
5763 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005764 case GST_V4L2_IO_MMAP:
5765 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005766 if ((pool = obj->pool))
5767 gst_object_ref(pool);
5768 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005769 default:
bo.xiao857b8682024-09-12 16:40:32 +08005770 pool = NULL;
5771 break;
5772 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005773
bo.xiao857b8682024-09-12 16:40:32 +08005774 if (pool != NULL)
5775 {
5776 GstCaps *pcaps;
5777 GstStructure *config;
5778
5779 /* we had a pool, check caps */
5780 config = gst_buffer_pool_get_config (pool);
5781 gst_buffer_pool_config_get_params (config, &pcaps, NULL, NULL, NULL);
5782
5783 GST_DEBUG_OBJECT (obj->dbg_obj,
5784 "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
5785 if (!gst_caps_is_equal (caps, pcaps))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005786 {
bo.xiao857b8682024-09-12 16:40:32 +08005787 gst_structure_free (config);
5788 gst_object_unref (pool);
5789 goto different_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005790 }
bo.xiao857b8682024-09-12 16:40:32 +08005791 gst_structure_free (config);
5792 }
5793 gst_aml_v4l2_get_driver_min_buffers (obj);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005794
bo.xiao857b8682024-09-12 16:40:32 +08005795 min = MAX(obj->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005796
bo.xiao857b8682024-09-12 16:40:32 +08005797 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005798
bo.xiao857b8682024-09-12 16:40:32 +08005799 /* we also support various metadata */
5800 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005801
bo.xiao857b8682024-09-12 16:40:32 +08005802 if (pool)
5803 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005804
bo.xiao857b8682024-09-12 16:40:32 +08005805 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005806
bo.xiao857b8682024-09-12 16:40:32 +08005807 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005808no_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005809 {
5810 GST_DEBUG_OBJECT (obj->dbg_obj, "no caps specified");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005811 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005812 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005813different_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005814 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005815 /* different caps, we can't use this pool */
bo.xiao857b8682024-09-12 16:40:32 +08005816 GST_DEBUG_OBJECT (obj->dbg_obj, "pool has different caps");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005817 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005818 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005819}
5820
5821gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005822gst_aml_v4l2_object_try_import (GstAmlV4l2Object * obj, GstBuffer * buffer)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005823{
bo.xiao857b8682024-09-12 16:40:32 +08005824 GstVideoMeta *vmeta;
5825 guint n_mem = gst_buffer_n_memory (buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005826
bo.xiao857b8682024-09-12 16:40:32 +08005827 /* only import if requested */
5828 switch (obj->mode)
5829 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005830 case GST_V4L2_IO_USERPTR:
5831 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005832 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005833 default:
bo.xiao857b8682024-09-12 16:40:32 +08005834 GST_DEBUG_OBJECT (obj->dbg_obj,
5835 "The io-mode does not enable importation");
5836 return FALSE;
5837 }
5838
5839 vmeta = gst_buffer_get_video_meta (buffer);
5840 if (!vmeta && obj->need_video_meta)
5841 {
5842 GST_DEBUG_OBJECT (obj->dbg_obj, "Downstream buffer uses standard "
5843 "stride/offset while the driver does not.");
5844 return FALSE;
5845 }
5846
5847 /* we need matching strides/offsets and size */
5848 if (vmeta)
5849 {
5850 guint p;
5851 gboolean need_fmt_update = FALSE;
5852
5853 if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES(&obj->info))
5854 {
5855 GST_WARNING_OBJECT(obj->dbg_obj,
5856 "Cannot import buffers with different number planes");
5857 return FALSE;
5858 }
5859
5860 for (p = 0; p < vmeta->n_planes; p++)
5861 {
5862 if (vmeta->stride[p] < obj->info.stride[p])
5863 {
5864 GST_DEBUG_OBJECT(obj->dbg_obj,
5865 "Not importing as remote stride %i is smaller then %i on plane %u",
5866 vmeta->stride[p], obj->info.stride[p], p);
5867 return FALSE;
5868 }
5869 else if (vmeta->stride[p] > obj->info.stride[p])
5870 {
5871 need_fmt_update = TRUE;
5872 }
5873
5874 if (vmeta->offset[p] < obj->info.offset[p])
5875 {
5876 GST_DEBUG_OBJECT(obj->dbg_obj,
5877 "Not importing as offset %" G_GSIZE_FORMAT
5878 " is smaller then %" G_GSIZE_FORMAT " on plane %u",
5879 vmeta->offset[p], obj->info.offset[p], p);
5880 return FALSE;
5881 }
5882 else if (vmeta->offset[p] > obj->info.offset[p])
5883 {
5884 need_fmt_update = TRUE;
5885 }
5886 }
5887
5888 if (need_fmt_update)
5889 {
5890 struct v4l2_format format;
5891 gint wanted_stride[GST_VIDEO_MAX_PLANES] = {
5892 0,
5893 };
5894
5895 format = obj->format;
5896
5897 /* update the current format with the stride we want to import from */
5898 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5899 {
5900 guint i;
5901
5902 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted strides:");
5903
5904 for (i = 0; i < obj->n_v4l2_planes; i++)
5905 {
5906 gint stride = vmeta->stride[i];
5907
5908 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5909 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5910
5911 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
5912 wanted_stride[i] = stride;
5913 GST_DEBUG_OBJECT(obj->dbg_obj, " [%u] %i", i, wanted_stride[i]);
5914 }
5915 }
5916 else
5917 {
5918 gint stride = vmeta->stride[0];
5919
5920 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted stride: %i", stride);
5921
5922 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5923 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5924
5925 format.fmt.pix.bytesperline = stride;
5926 wanted_stride[0] = stride;
5927 }
5928
5929 if (obj->ioctl(obj->video_fd, VIDIOC_S_FMT, &format) < 0)
5930 {
5931 GST_WARNING_OBJECT(obj->dbg_obj,
5932 "Something went wrong trying to update current format: %s",
5933 g_strerror(errno));
5934 return FALSE;
5935 }
5936
5937 gst_aml_v4l2_object_save_format(obj, obj->fmtdesc, &format, &obj->info,
5938 &obj->align);
5939
5940 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5941 {
5942 guint i;
5943
5944 for (i = 0; i < obj->n_v4l2_planes; i++)
5945 {
5946 if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i])
5947 {
5948 GST_DEBUG_OBJECT(obj->dbg_obj,
5949 "[%i] Driver did not accept the new stride (wants %i, got %i)",
5950 i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
5951 wanted_stride[i]);
5952 return FALSE;
5953 }
5954 }
5955 }
5956 else
5957 {
5958 if (format.fmt.pix.bytesperline != wanted_stride[0])
5959 {
5960 GST_DEBUG_OBJECT(obj->dbg_obj,
5961 "Driver did not accept the new stride (wants %i, got %i)",
5962 format.fmt.pix.bytesperline, wanted_stride[0]);
5963 return FALSE;
5964 }
5965 }
5966 }
5967 }
5968
5969 /* we can always import single memory buffer, but otherwise we need the same
5970 * amount of memory object. */
5971 if (n_mem != 1 && n_mem != obj->n_v4l2_planes)
5972 {
5973 GST_DEBUG_OBJECT (obj->dbg_obj, "Can only import %i memory, "
5974 "buffers contains %u memory", obj->n_v4l2_planes, n_mem);
5975 return FALSE;
5976 }
5977
5978 /* For DMABuf importation we need DMABuf of course */
5979 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
5980 {
5981 guint i;
5982
5983 for (i = 0; i < n_mem; i++)
5984 {
5985 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
5986
5987 if (!gst_is_dmabuf_memory (mem))
5988 {
5989 GST_DEBUG_OBJECT (obj->dbg_obj, "Cannot import non-DMABuf memory.");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005990 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005991 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005992 }
bo.xiao857b8682024-09-12 16:40:32 +08005993 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005994
bo.xiao857b8682024-09-12 16:40:32 +08005995 /* for the remaining, only the kernel driver can tell */
5996 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005997}
5998
xuesong.jiang22a9b112023-05-24 09:01:59 +00005999static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl)
6000{
bo.xiao857b8682024-09-12 16:40:32 +08006001 int rc;
6002 struct v4l2_queryctrl queryctrl;
6003 struct v4l2_control control;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006004
bo.xiao857b8682024-09-12 16:40:32 +08006005 memset(&queryctrl, 0, sizeof(queryctrl));
6006 queryctrl.id = ctl;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006007
bo.xiao857b8682024-09-12 16:40:32 +08006008 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_QUERYCTRL, &queryctrl);
6009 if (rc == 0)
6010 {
6011 if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
6012 {
6013 memset(&control, 0, sizeof(control));
6014 control.id = ctl;
6015 control.value = 1;
6016 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6017 if (rc != 0)
6018 {
6019 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x fail rc %d", ctl, rc);
6020 return FALSE;
6021 }
6022 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x succ", ctl);
6023 return TRUE;
6024 }
6025 else
6026 {
6027 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "ctl:0x%x is disabled", ctl);
6028 return TRUE;
6029 }
6030 }
6031 else
6032 {
6033 GST_ERROR_OBJECT(v4l2object->dbg_obj, "VIDIOC_QUERYCTRL for 0x:%x fail", ctl);
6034 return FALSE;
6035 }
xuesong.jiang22a9b112023-05-24 09:01:59 +00006036}
6037
hanghang.luo7f403102024-07-04 10:33:01 +08006038gboolean gst_aml_v4l2_set_I_frame_mode(GstAmlV4l2Object *v4l2object)
6039{
bo.xiao857b8682024-09-12 16:40:32 +08006040 if (v4l2object->iframe_mode)
6041 {
6042 int rc;
6043 struct v4l2_control control;
6044 memset(&control, 0, sizeof(control));
6045 control.id = AML_V4L2_SET_I_FRAME;
6046 control.value = 1;
6047 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6048 if (rc != 0)
6049 {
6050 GST_ERROR_OBJECT(v4l2object->dbg_obj, "rc: %d", rc);
6051 return FALSE;
6052 }
6053 }
6054 GST_DEBUG("set I frame ok");
6055 return TRUE;
hanghang.luo7f403102024-07-04 10:33:01 +08006056}
xuesong.jiang22a9b112023-05-24 09:01:59 +00006057
xuesong.jiangae1548e2022-05-06 16:38:46 +08006058gboolean gst_aml_v4l2_set_drm_mode(GstAmlV4l2Object *v4l2object)
6059{
bo.xiao857b8682024-09-12 16:40:32 +08006060 /* On AmLogic, output obj use of GST_V4L2_IO_DMABUF_IMPORT implies secure memory */
6061 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT && v4l2object->secure_es)
6062 {
6063 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)v4l2object->element;
6064 self->is_secure_path = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006065
bo.xiao857b8682024-09-12 16:40:32 +08006066 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_DRMMODE))
6067 {
6068 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set succ");
6069 return TRUE;
6070 }
6071 else
6072 {
6073 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set fail");
6074 return FALSE;
6075 }
6076 }
6077 return TRUE;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006078}
6079
6080gboolean gst_aml_v4l2_set_stream_mode(GstAmlV4l2Object *v4l2object)
6081{
bo.xiao857b8682024-09-12 16:40:32 +08006082 if (v4l2object->stream_mode)
6083 {
6084 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_STREAM_MODE))
6085 {
6086 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set succ");
6087 return TRUE;
6088 }
6089 else
6090 {
6091 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set fail");
6092 return FALSE;
6093 }
6094 }
6095 else
6096 {
6097 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not stream mode, frame mode in configured by default");
6098 return TRUE;
6099 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006100}
6101
6102gint gst_aml_v4l2_object_get_outstanding_capture_buf_num(GstAmlV4l2Object *obj)
6103{
bo.xiao857b8682024-09-12 16:40:32 +08006104 gint ret = 0;
6105 gint count = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006106
bo.xiao857b8682024-09-12 16:40:32 +08006107 if (obj->old_other_pool)
6108 {
6109 count = gst_buffer_pool_get_outstanding_num(obj->old_other_pool);
6110 if (count)
6111 {
6112 ret += count;
6113 }
6114 else
6115 {
6116 gst_object_unref(obj->old_other_pool);
6117 obj->old_other_pool = NULL;
6118 }
6119 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006120
bo.xiao857b8682024-09-12 16:40:32 +08006121 count = 0;
6122 if (obj->old_old_other_pool)
6123 {
6124 count = gst_buffer_pool_get_outstanding_num(obj->old_old_other_pool);
6125 if (count)
6126 {
6127 ret += count;
6128 }
6129 else
6130 {
6131 gst_object_unref(obj->old_old_other_pool);
6132 obj->old_old_other_pool = NULL;
6133 }
6134 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006135
bo.xiao857b8682024-09-12 16:40:32 +08006136 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006137}