blob: f1fdbdc56b7e57ffb61f5a987fbe2f9d7e644c02 [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.xiaof61afd22024-10-16 17:18:55 +08001203 format = g_new0 (struct v4l2_fmtdesc, 1);
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 {
bo.xiaof61afd22024-10-16 17:18:55 +08001232 GST_LOG_OBJECT(v4l2object->dbg_obj, "not support YU12 and YM12");
1233 g_free (format);
bo.xiao857b8682024-09-12 16:40:32 +08001234 continue;
1235 }
1236
1237 /* sort formats according to our preference; we do this, because caps
1238 * are probed in the order the formats are in the list, and the order of
1239 * formats in the final probed caps matters for things like fixation */
1240 v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
1241 (GCompareFunc) format_cmp_func);
1242 }
1243
xuesong.jiangae1548e2022-05-06 16:38:46 +08001244#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08001245 {
1246 GSList *l;
1247
1248 GST_INFO_OBJECT (v4l2object->dbg_obj, "got %d format(s):", n);
1249 for (l = v4l2object->formats; l != NULL; l = l->next)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001250 {
bo.xiao857b8682024-09-12 16:40:32 +08001251 format = l->data;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001252
bo.xiao857b8682024-09-12 16:40:32 +08001253 GST_INFO_OBJECT (v4l2object->dbg_obj,
1254 " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
1255 ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001256 }
bo.xiao857b8682024-09-12 16:40:32 +08001257 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001258#endif
1259
bo.xiao857b8682024-09-12 16:40:32 +08001260 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001261
bo.xiao857b8682024-09-12 16:40:32 +08001262 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001263failed:
bo.xiao857b8682024-09-12 16:40:32 +08001264 {
1265 g_free (format);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001266
1267 if (v4l2object->element)
bo.xiao857b8682024-09-12 16:40:32 +08001268 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001269
bo.xiao857b8682024-09-12 16:40:32 +08001270 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1271 (_("Failed to enumerate possible video formats device '%s' can work "
1272 "with"), v4l2object->videodev),
1273 ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
1274 n, v4l2object->videodev, errno, g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001275
1276 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08001277 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001278}
1279
1280/*
1281 * Get the list of supported capture formats, a list of
1282 * <code>struct v4l2_fmtdesc</code>.
1283 */
1284static GSList *
bo.xiao857b8682024-09-12 16:40:32 +08001285gst_aml_v4l2_object_get_format_list (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001286{
bo.xiao857b8682024-09-12 16:40:32 +08001287 if (!v4l2object->formats)
1288 {
1289
1290 /* check usual way */
1291 gst_aml_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
1292
1293 /* if our driver supports multi-planar
1294 * and if formats are still empty then we can workaround driver bug
1295 * by also looking up formats as if our device was not supporting
1296 * multiplanar */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001297 if (!v4l2object->formats)
1298 {
bo.xiao857b8682024-09-12 16:40:32 +08001299 switch (v4l2object->type)
1300 {
1301 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1302 gst_aml_v4l2_object_fill_format_list (v4l2object,
1303 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1304 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001305
bo.xiao857b8682024-09-12 16:40:32 +08001306 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1307 gst_aml_v4l2_object_fill_format_list (v4l2object,
1308 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1309 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001310
bo.xiao857b8682024-09-12 16:40:32 +08001311 default:
1312 break;
1313 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001314 }
bo.xiao857b8682024-09-12 16:40:32 +08001315 }
1316 return v4l2object->formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001317}
1318
1319static GstVideoFormat
bo.xiao857b8682024-09-12 16:40:32 +08001320gst_aml_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001321{
bo.xiao857b8682024-09-12 16:40:32 +08001322 GstVideoFormat format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001323
bo.xiao857b8682024-09-12 16:40:32 +08001324 switch (fourcc)
1325 {
1326 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
1327 format = GST_VIDEO_FORMAT_GRAY8;
1328 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001329 case V4L2_PIX_FMT_Y16:
bo.xiao857b8682024-09-12 16:40:32 +08001330 format = GST_VIDEO_FORMAT_GRAY16_LE;
1331 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001332 case V4L2_PIX_FMT_Y16_BE:
bo.xiao857b8682024-09-12 16:40:32 +08001333 format = GST_VIDEO_FORMAT_GRAY16_BE;
1334 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001335 case V4L2_PIX_FMT_XRGB555:
1336 case V4L2_PIX_FMT_RGB555:
bo.xiao857b8682024-09-12 16:40:32 +08001337 format = GST_VIDEO_FORMAT_RGB15;
1338 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001339 case V4L2_PIX_FMT_XRGB555X:
1340 case V4L2_PIX_FMT_RGB555X:
bo.xiao857b8682024-09-12 16:40:32 +08001341 format = GST_VIDEO_FORMAT_BGR15;
1342 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001343 case V4L2_PIX_FMT_RGB565:
bo.xiao857b8682024-09-12 16:40:32 +08001344 format = GST_VIDEO_FORMAT_RGB16;
1345 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001346 case V4L2_PIX_FMT_RGB24:
bo.xiao857b8682024-09-12 16:40:32 +08001347 format = GST_VIDEO_FORMAT_RGB;
1348 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001349 case V4L2_PIX_FMT_BGR24:
bo.xiao857b8682024-09-12 16:40:32 +08001350 format = GST_VIDEO_FORMAT_BGR;
1351 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001352 case V4L2_PIX_FMT_XRGB32:
1353 case V4L2_PIX_FMT_RGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001354 format = GST_VIDEO_FORMAT_xRGB;
1355 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001356 case V4L2_PIX_FMT_XBGR32:
1357 case V4L2_PIX_FMT_BGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001358 format = GST_VIDEO_FORMAT_BGRx;
1359 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001360 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001361 format = GST_VIDEO_FORMAT_BGRA;
1362 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001363 case V4L2_PIX_FMT_ARGB32:
bo.xiao857b8682024-09-12 16:40:32 +08001364 format = GST_VIDEO_FORMAT_ARGB;
1365 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001366 case V4L2_PIX_FMT_NV12:
1367 case V4L2_PIX_FMT_NV12M:
bo.xiao857b8682024-09-12 16:40:32 +08001368 format = GST_VIDEO_FORMAT_NV12;
1369 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001370 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001371 format = GST_VIDEO_FORMAT_NV12_64Z32;
1372 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001373 case V4L2_PIX_FMT_NV21:
1374 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001375 format = GST_VIDEO_FORMAT_NV21;
1376 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001377 case V4L2_PIX_FMT_YVU410:
bo.xiao857b8682024-09-12 16:40:32 +08001378 format = GST_VIDEO_FORMAT_YVU9;
1379 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001380 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001381 format = GST_VIDEO_FORMAT_YUV9;
1382 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001383 case V4L2_PIX_FMT_YUV420:
1384 case V4L2_PIX_FMT_YUV420M:
bo.xiao857b8682024-09-12 16:40:32 +08001385 format = GST_VIDEO_FORMAT_I420;
1386 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001387 case V4L2_PIX_FMT_YUYV:
bo.xiao857b8682024-09-12 16:40:32 +08001388 format = GST_VIDEO_FORMAT_YUY2;
1389 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001390 case V4L2_PIX_FMT_YVU420:
bo.xiao857b8682024-09-12 16:40:32 +08001391 format = GST_VIDEO_FORMAT_YV12;
1392 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001393 case V4L2_PIX_FMT_UYVY:
bo.xiao857b8682024-09-12 16:40:32 +08001394 format = GST_VIDEO_FORMAT_UYVY;
1395 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001396 case V4L2_PIX_FMT_YUV411P:
bo.xiao857b8682024-09-12 16:40:32 +08001397 format = GST_VIDEO_FORMAT_Y41B;
1398 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001399 case V4L2_PIX_FMT_YUV422P:
bo.xiao857b8682024-09-12 16:40:32 +08001400 format = GST_VIDEO_FORMAT_Y42B;
1401 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001402 case V4L2_PIX_FMT_YVYU:
bo.xiao857b8682024-09-12 16:40:32 +08001403 format = GST_VIDEO_FORMAT_YVYU;
1404 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001405 case V4L2_PIX_FMT_NV16:
1406 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001407 format = GST_VIDEO_FORMAT_NV16;
1408 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001409 case V4L2_PIX_FMT_NV61:
1410 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001411 format = GST_VIDEO_FORMAT_NV61;
1412 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001413 case V4L2_PIX_FMT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08001414 format = GST_VIDEO_FORMAT_NV24;
1415 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001416 default:
bo.xiao857b8682024-09-12 16:40:32 +08001417 format = GST_VIDEO_FORMAT_UNKNOWN;
1418 break;
1419 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001420
bo.xiao857b8682024-09-12 16:40:32 +08001421 return format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001422}
1423
1424static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001425gst_aml_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001426{
bo.xiao857b8682024-09-12 16:40:32 +08001427 gboolean ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001428
bo.xiao857b8682024-09-12 16:40:32 +08001429 switch (fourcc)
1430 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001431 case V4L2_PIX_FMT_XRGB555:
1432 case V4L2_PIX_FMT_RGB555:
1433 case V4L2_PIX_FMT_XRGB555X:
1434 case V4L2_PIX_FMT_RGB555X:
1435 case V4L2_PIX_FMT_RGB565:
1436 case V4L2_PIX_FMT_RGB24:
1437 case V4L2_PIX_FMT_BGR24:
1438 case V4L2_PIX_FMT_XRGB32:
1439 case V4L2_PIX_FMT_RGB32:
1440 case V4L2_PIX_FMT_XBGR32:
1441 case V4L2_PIX_FMT_BGR32:
1442 case V4L2_PIX_FMT_ABGR32:
1443 case V4L2_PIX_FMT_ARGB32:
1444 case V4L2_PIX_FMT_SBGGR8:
1445 case V4L2_PIX_FMT_SGBRG8:
1446 case V4L2_PIX_FMT_SGRBG8:
1447 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001448 ret = TRUE;
1449 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001450 default:
bo.xiao857b8682024-09-12 16:40:32 +08001451 break;
1452 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001453
bo.xiao857b8682024-09-12 16:40:32 +08001454 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001455}
1456
1457static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001458gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001459{
bo.xiao857b8682024-09-12 16:40:32 +08001460 GstStructure *structure = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001461
bo.xiao857b8682024-09-12 16:40:32 +08001462 switch (fourcc)
1463 {
1464 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
1465 structure = gst_structure_new_empty("video/mjpeg");
1466 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001467 case V4L2_PIX_FMT_MPEG1:
bo.xiao857b8682024-09-12 16:40:32 +08001468 structure = gst_structure_new ("video/mpeg",
1469 "mpegversion", G_TYPE_INT, 1, NULL);
1470
1471 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1472 GST_DEBUG("aml set mpeg1 systemstream to false");
1473 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001474 case V4L2_PIX_FMT_MPEG2:
bo.xiao857b8682024-09-12 16:40:32 +08001475 structure = gst_structure_new("video/mpeg",
1476 "mpegversion", G_TYPE_INT, 2, NULL);
1477 gst_structure_set(structure, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1478 GST_DEBUG("aml set mpeg2 systemstream to false");
1479 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001480 case V4L2_PIX_FMT_MPEG4:
1481 case V4L2_PIX_FMT_XVID:
bo.xiao857b8682024-09-12 16:40:32 +08001482 structure = gst_structure_new ("video/mpeg",
1483 "mpegversion", G_TYPE_INT, 4, "systemstream",
1484 G_TYPE_BOOLEAN, FALSE, NULL);
1485 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001486 case V4L2_PIX_FMT_FWHT:
bo.xiao857b8682024-09-12 16:40:32 +08001487 structure = gst_structure_new_empty ("video/x-fwht");
1488 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001489 case V4L2_PIX_FMT_H263:
bo.xiao857b8682024-09-12 16:40:32 +08001490 structure = gst_structure_new ("video/x-h263",
1491 "variant", G_TYPE_STRING, "itu", NULL);
1492 break;
1493 case V4L2_PIX_FMT_H264: /* H.264 */
1494 structure = gst_structure_new ("video/x-h264",
1495 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1496 G_TYPE_STRING, "au", NULL);
1497 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001498 case V4L2_PIX_FMT_H264_NO_SC:
bo.xiao857b8682024-09-12 16:40:32 +08001499 structure = gst_structure_new ("video/x-h264",
1500 "stream-format", G_TYPE_STRING, "avc", "alignment",
1501 G_TYPE_STRING, "au", NULL);
1502 break;
1503 case V4L2_PIX_FMT_HEVC: /* H.265 */
1504 structure = gst_structure_new ("video/x-h265",
1505 "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1506 G_TYPE_STRING, "au", NULL);
1507 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001508 case V4L2_PIX_FMT_VC1_ANNEX_G:
1509 case V4L2_PIX_FMT_VC1_ANNEX_L:
bo.xiao857b8682024-09-12 16:40:32 +08001510 structure = gst_structure_new ("video/x-wmv",
1511 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
1512 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001513 case V4L2_PIX_FMT_VP8:
bo.xiao857b8682024-09-12 16:40:32 +08001514 structure = gst_structure_new_empty ("video/x-vp8");
1515 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001516 case V4L2_PIX_FMT_VP9:
bo.xiao857b8682024-09-12 16:40:32 +08001517 structure = gst_structure_new_empty ("video/x-vp9");
1518 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001519 case V4L2_PIX_FMT_AV1:
1520 structure = gst_structure_new_empty("video/x-av1");
1521 break;
zengliang.li51f54b62023-10-10 12:14:49 +00001522 case V4L2_PIX_FMT_AVS:
1523 structure = gst_structure_new_empty("video/x-avs");
1524 break;
1525 case V4L2_PIX_FMT_AVS2:
1526 structure = gst_structure_new_empty("video/x-avs2");
1527 break;
1528 case V4L2_PIX_FMT_AVS3:
1529 structure = gst_structure_new_empty("video/x-avs3");
1530 break;
bo.xiao857b8682024-09-12 16:40:32 +08001531 case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001532 case V4L2_PIX_FMT_Y16:
1533 case V4L2_PIX_FMT_Y16_BE:
1534 case V4L2_PIX_FMT_XRGB555:
1535 case V4L2_PIX_FMT_RGB555:
1536 case V4L2_PIX_FMT_XRGB555X:
1537 case V4L2_PIX_FMT_RGB555X:
1538 case V4L2_PIX_FMT_RGB565:
1539 case V4L2_PIX_FMT_RGB24:
1540 case V4L2_PIX_FMT_BGR24:
1541 case V4L2_PIX_FMT_RGB32:
1542 case V4L2_PIX_FMT_XRGB32:
1543 case V4L2_PIX_FMT_ARGB32:
1544 case V4L2_PIX_FMT_BGR32:
1545 case V4L2_PIX_FMT_XBGR32:
1546 case V4L2_PIX_FMT_ABGR32:
bo.xiao857b8682024-09-12 16:40:32 +08001547 case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001548 case V4L2_PIX_FMT_NV12M:
1549 case V4L2_PIX_FMT_NV12MT:
bo.xiao857b8682024-09-12 16:40:32 +08001550 case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001551 case V4L2_PIX_FMT_NV21M:
bo.xiao857b8682024-09-12 16:40:32 +08001552 case V4L2_PIX_FMT_NV16: /* 16 Y/CbCr 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001553 case V4L2_PIX_FMT_NV16M:
bo.xiao857b8682024-09-12 16:40:32 +08001554 case V4L2_PIX_FMT_NV61: /* 16 Y/CrCb 4:2:2 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001555 case V4L2_PIX_FMT_NV61M:
bo.xiao857b8682024-09-12 16:40:32 +08001556 case V4L2_PIX_FMT_NV24: /* 24 Y/CrCb 4:4:4 */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001557 case V4L2_PIX_FMT_YVU410:
1558 case V4L2_PIX_FMT_YUV410:
bo.xiao857b8682024-09-12 16:40:32 +08001559 case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001560 case V4L2_PIX_FMT_YUV420M:
1561 case V4L2_PIX_FMT_YUYV:
1562 case V4L2_PIX_FMT_YVU420:
1563 case V4L2_PIX_FMT_UYVY:
1564 case V4L2_PIX_FMT_YUV422P:
1565 case V4L2_PIX_FMT_YVYU:
1566 case V4L2_PIX_FMT_YUV411P:
1567 {
bo.xiao857b8682024-09-12 16:40:32 +08001568 GstVideoFormat format;
1569 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fourcc);
1570 if (format != GST_VIDEO_FORMAT_UNKNOWN)
1571 structure = gst_structure_new ("video/x-raw",
1572 "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
1573 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001574 }
1575 case V4L2_PIX_FMT_DV:
bo.xiao857b8682024-09-12 16:40:32 +08001576 structure =
1577 gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1578 NULL);
1579 break;
1580 case V4L2_PIX_FMT_MPEG: /* MPEG */
1581 structure = gst_structure_new ("video/mpegts",
1582 "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
1583 break;
1584 case V4L2_PIX_FMT_WNVA: /* Winnov hw compress */
1585 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001586 case V4L2_PIX_FMT_SBGGR8:
1587 case V4L2_PIX_FMT_SGBRG8:
1588 case V4L2_PIX_FMT_SGRBG8:
1589 case V4L2_PIX_FMT_SRGGB8:
bo.xiao857b8682024-09-12 16:40:32 +08001590 structure = gst_structure_new ("video/x-bayer", "format", G_TYPE_STRING,
1591 fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" :
1592 fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg" :
1593 fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg" :
1594 /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb", NULL);
1595 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001596 case V4L2_PIX_FMT_SN9C10X:
bo.xiao857b8682024-09-12 16:40:32 +08001597 structure = gst_structure_new_empty ("video/x-sonix");
1598 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001599 case V4L2_PIX_FMT_PWC1:
bo.xiao857b8682024-09-12 16:40:32 +08001600 structure = gst_structure_new_empty ("video/x-pwc1");
1601 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001602 case V4L2_PIX_FMT_PWC2:
bo.xiao857b8682024-09-12 16:40:32 +08001603 structure = gst_structure_new_empty ("video/x-pwc2");
1604 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001605 case V4L2_PIX_FMT_RGB332:
1606 case V4L2_PIX_FMT_BGR666:
1607 case V4L2_PIX_FMT_ARGB555X:
1608 case V4L2_PIX_FMT_RGB565X:
1609 case V4L2_PIX_FMT_RGB444:
bo.xiao857b8682024-09-12 16:40:32 +08001610 case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
1611 case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
xuesong.jiangae1548e2022-05-06 16:38:46 +08001612 case V4L2_PIX_FMT_Y4:
1613 case V4L2_PIX_FMT_Y6:
1614 case V4L2_PIX_FMT_Y10:
1615 case V4L2_PIX_FMT_Y12:
1616 case V4L2_PIX_FMT_Y10BPACK:
1617 case V4L2_PIX_FMT_YUV444:
1618 case V4L2_PIX_FMT_YUV555:
1619 case V4L2_PIX_FMT_YUV565:
1620 case V4L2_PIX_FMT_Y41P:
1621 case V4L2_PIX_FMT_YUV32:
1622 case V4L2_PIX_FMT_NV12MT_16X16:
1623 case V4L2_PIX_FMT_NV42:
1624 case V4L2_PIX_FMT_H264_MVC:
1625 default:
bo.xiao857b8682024-09-12 16:40:32 +08001626 GST_DEBUG ("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
1627 fourcc, GST_FOURCC_ARGS (fourcc));
1628 break;
1629 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001630
bo.xiao857b8682024-09-12 16:40:32 +08001631 return structure;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001632}
1633
1634GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08001635gst_aml_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001636{
bo.xiao857b8682024-09-12 16:40:32 +08001637 GstStructure *template;
1638 gint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001639
bo.xiao857b8682024-09-12 16:40:32 +08001640 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001641
bo.xiao857b8682024-09-12 16:40:32 +08001642 if (template == NULL)
1643 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001644
bo.xiao857b8682024-09-12 16:40:32 +08001645 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1646 {
1647 if (gst_aml_v4l2_formats[i].format != fourcc)
1648 continue;
1649
1650 if (gst_aml_v4l2_formats[i].dimensions)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001651 {
bo.xiao857b8682024-09-12 16:40:32 +08001652 gst_structure_set (template,
1653 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1654 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1655 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001656 }
bo.xiao857b8682024-09-12 16:40:32 +08001657 break;
1658 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001659
1660done:
bo.xiao857b8682024-09-12 16:40:32 +08001661 return template;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001662}
1663
1664static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001665gst_aml_v4l2_object_get_caps_helper (GstAmlV4L2FormatFlags flags)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001666{
bo.xiao857b8682024-09-12 16:40:32 +08001667 GstStructure *structure;
1668 GstCaps *caps;
1669 guint i;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001670
bo.xiao857b8682024-09-12 16:40:32 +08001671 caps = gst_caps_new_empty ();
1672 for (i = 0; i < GST_AML_V4L2_FORMAT_COUNT; i++)
1673 {
1674
1675 if ((gst_aml_v4l2_formats[i].flags & flags) == 0)
1676 continue;
1677
1678 structure =
1679 gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (gst_aml_v4l2_formats[i].format);
1680
1681 if (structure)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001682 {
bo.xiao857b8682024-09-12 16:40:32 +08001683 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001684
bo.xiao857b8682024-09-12 16:40:32 +08001685 if (gst_aml_v4l2_formats[i].dimensions)
1686 {
1687 gst_structure_set (structure,
1688 "width", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1689 "height", GST_TYPE_INT_RANGE, 1, GST_AML_V4L2_MAX_SIZE,
1690 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1691 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001692
bo.xiao857b8682024-09-12 16:40:32 +08001693 switch (gst_aml_v4l2_formats[i].format)
1694 {
1695 case V4L2_PIX_FMT_RGB32:
1696 alt_s = gst_structure_copy (structure);
1697 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
1698 break;
1699 case V4L2_PIX_FMT_BGR32:
1700 alt_s = gst_structure_copy (structure);
1701 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
1702 default:
1703 break;
1704 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001705
bo.xiao857b8682024-09-12 16:40:32 +08001706 gst_caps_append_structure (caps, structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001707
bo.xiao857b8682024-09-12 16:40:32 +08001708 if (alt_s)
1709 gst_caps_append_structure (caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001710 }
bo.xiao857b8682024-09-12 16:40:32 +08001711 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001712
bo.xiao857b8682024-09-12 16:40:32 +08001713 return gst_caps_simplify(caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001714}
1715
1716GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001717gst_aml_v4l2_object_get_all_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001718{
bo.xiao857b8682024-09-12 16:40:32 +08001719 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001720
bo.xiao857b8682024-09-12 16:40:32 +08001721 if (g_once_init_enter (&caps))
1722 {
1723 GstCaps *all_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_ALL);
1724 GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1725 g_once_init_leave (&caps, all_caps);
1726 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001727
bo.xiao857b8682024-09-12 16:40:32 +08001728 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001729}
1730
1731GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001732gst_aml_v4l2_object_get_raw_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001733{
bo.xiao857b8682024-09-12 16:40:32 +08001734 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001735
bo.xiao857b8682024-09-12 16:40:32 +08001736 if (g_once_init_enter (&caps))
1737 {
1738 GstCaps *raw_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_RAW);
1739 GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1740 g_once_init_leave (&caps, raw_caps);
1741 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001742
bo.xiao857b8682024-09-12 16:40:32 +08001743 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001744}
1745
1746GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08001747gst_aml_v4l2_object_get_codec_caps (void)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001748{
bo.xiao857b8682024-09-12 16:40:32 +08001749 static GstCaps *caps = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001750
bo.xiao857b8682024-09-12 16:40:32 +08001751 if (g_once_init_enter (&caps))
1752 {
1753 GstCaps *codec_caps = gst_aml_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
1754 GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1755 g_once_init_leave (&caps, codec_caps);
1756 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001757
bo.xiao857b8682024-09-12 16:40:32 +08001758 return caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001759}
1760
1761/* collect data for the given caps
1762 * @caps: given input caps
1763 * @format: location for the v4l format
1764 * @w/@h: location for width and height
1765 * @fps_n/@fps_d: location for framerate
1766 * @size: location for expected size of the frame or 0 if unknown
1767 */
1768static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08001769gst_aml_v4l2_object_get_caps_info (GstAmlV4l2Object * v4l2object, GstCaps * caps,
1770 struct v4l2_fmtdesc **format, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001771{
bo.xiao857b8682024-09-12 16:40:32 +08001772 GstStructure *structure;
1773 guint32 fourcc = 0, fourcc_nc = 0;
1774 const gchar *mimetype;
1775 struct v4l2_fmtdesc *fmt = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001776
bo.xiao857b8682024-09-12 16:40:32 +08001777 GST_DEBUG_OBJECT(v4l2object, "got caps: %" GST_PTR_FORMAT, caps);
fei.denge9458472023-04-18 02:05:48 +00001778
bo.xiao857b8682024-09-12 16:40:32 +08001779 structure = gst_caps_get_structure (caps, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001780
bo.xiao857b8682024-09-12 16:40:32 +08001781 mimetype = gst_structure_get_name (structure);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001782
bo.xiao857b8682024-09-12 16:40:32 +08001783 if (!gst_video_info_from_caps (info, caps))
1784 goto invalid_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001785
bo.xiao857b8682024-09-12 16:40:32 +08001786 if (g_str_equal (mimetype, "video/x-raw"))
1787 {
1788 switch (GST_VIDEO_INFO_FORMAT (info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08001789 {
bo.xiao857b8682024-09-12 16:40:32 +08001790 case GST_VIDEO_FORMAT_I420:
1791 fourcc = V4L2_PIX_FMT_YUV420;
1792 fourcc_nc = V4L2_PIX_FMT_YUV420M;
1793 break;
1794 case GST_VIDEO_FORMAT_YUY2:
1795 fourcc = V4L2_PIX_FMT_YUYV;
1796 break;
1797 case GST_VIDEO_FORMAT_UYVY:
1798 fourcc = V4L2_PIX_FMT_UYVY;
1799 break;
1800 case GST_VIDEO_FORMAT_YV12:
1801 fourcc = V4L2_PIX_FMT_YVU420;
1802 break;
1803 case GST_VIDEO_FORMAT_Y41B:
1804 fourcc = V4L2_PIX_FMT_YUV411P;
1805 break;
1806 case GST_VIDEO_FORMAT_Y42B:
1807 fourcc = V4L2_PIX_FMT_YUV422P;
1808 break;
1809 case GST_VIDEO_FORMAT_NV12:
1810 fourcc = V4L2_PIX_FMT_NV12;
1811 fourcc_nc = V4L2_PIX_FMT_NV12M;
1812 break;
1813 case GST_VIDEO_FORMAT_NV12_64Z32:
1814 fourcc_nc = V4L2_PIX_FMT_NV12MT;
1815 break;
1816 case GST_VIDEO_FORMAT_NV21:
1817 fourcc = V4L2_PIX_FMT_NV21;
1818 fourcc_nc = V4L2_PIX_FMT_NV21M;
1819 break;
1820 case GST_VIDEO_FORMAT_NV16:
1821 fourcc = V4L2_PIX_FMT_NV16;
1822 fourcc_nc = V4L2_PIX_FMT_NV16M;
1823 break;
1824 case GST_VIDEO_FORMAT_NV61:
1825 fourcc = V4L2_PIX_FMT_NV61;
1826 fourcc_nc = V4L2_PIX_FMT_NV61M;
1827 break;
1828 case GST_VIDEO_FORMAT_NV24:
1829 fourcc = V4L2_PIX_FMT_NV24;
1830 break;
1831 case GST_VIDEO_FORMAT_YVYU:
1832 fourcc = V4L2_PIX_FMT_YVYU;
1833 break;
1834 case GST_VIDEO_FORMAT_RGB15:
1835 fourcc = V4L2_PIX_FMT_RGB555;
1836 fourcc_nc = V4L2_PIX_FMT_XRGB555;
1837 break;
1838 case GST_VIDEO_FORMAT_RGB16:
1839 fourcc = V4L2_PIX_FMT_RGB565;
1840 break;
1841 case GST_VIDEO_FORMAT_RGB:
1842 fourcc = V4L2_PIX_FMT_RGB24;
1843 break;
1844 case GST_VIDEO_FORMAT_BGR:
1845 fourcc = V4L2_PIX_FMT_BGR24;
1846 break;
1847 case GST_VIDEO_FORMAT_xRGB:
1848 fourcc = V4L2_PIX_FMT_RGB32;
1849 fourcc_nc = V4L2_PIX_FMT_XRGB32;
1850 break;
1851 case GST_VIDEO_FORMAT_ARGB:
1852 fourcc = V4L2_PIX_FMT_RGB32;
1853 fourcc_nc = V4L2_PIX_FMT_ARGB32;
1854 break;
1855 case GST_VIDEO_FORMAT_BGRx:
1856 fourcc = V4L2_PIX_FMT_BGR32;
1857 fourcc_nc = V4L2_PIX_FMT_XBGR32;
1858 break;
1859 case GST_VIDEO_FORMAT_BGRA:
1860 fourcc = V4L2_PIX_FMT_BGR32;
1861 fourcc_nc = V4L2_PIX_FMT_ABGR32;
1862 break;
1863 case GST_VIDEO_FORMAT_GRAY8:
1864 fourcc = V4L2_PIX_FMT_GREY;
1865 break;
1866 case GST_VIDEO_FORMAT_GRAY16_LE:
1867 fourcc = V4L2_PIX_FMT_Y16;
1868 break;
1869 case GST_VIDEO_FORMAT_GRAY16_BE:
1870 fourcc = V4L2_PIX_FMT_Y16_BE;
1871 break;
1872 case GST_VIDEO_FORMAT_BGR15:
1873 fourcc = V4L2_PIX_FMT_RGB555X;
1874 fourcc_nc = V4L2_PIX_FMT_XRGB555X;
1875 break;
1876 default:
1877 break;
1878 }
1879 }
1880 else
1881 {
1882 if (g_str_equal (mimetype, "video/mpegts"))
1883 {
1884 fourcc = V4L2_PIX_FMT_MPEG;
1885 }
1886 else if (g_str_equal (mimetype, "video/x-dv"))
1887 {
1888 fourcc = V4L2_PIX_FMT_DV;
1889 }
1890 else if (g_str_equal(mimetype, "video/mjpeg"))
1891 {
1892 fourcc = V4L2_PIX_FMT_JPEG;
1893 }
1894 else if (g_str_equal (mimetype, "video/mpeg"))
1895 {
1896 gint version;
1897 if (gst_structure_get_int (structure, "mpegversion", &version))
1898 {
1899 switch (version)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001900 {
bo.xiao857b8682024-09-12 16:40:32 +08001901 case 1:
1902 fourcc = V4L2_PIX_FMT_MPEG1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001903 break;
bo.xiao857b8682024-09-12 16:40:32 +08001904 case 2:
1905 fourcc = V4L2_PIX_FMT_MPEG2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001906 break;
bo.xiao857b8682024-09-12 16:40:32 +08001907 case 4:
1908 fourcc = V4L2_PIX_FMT_MPEG4;
1909 fourcc_nc = V4L2_PIX_FMT_XVID;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001910 break;
bo.xiao857b8682024-09-12 16:40:32 +08001911 default:
xuesong.jiangae1548e2022-05-06 16:38:46 +08001912 break;
1913 }
bo.xiao857b8682024-09-12 16:40:32 +08001914 }
1915 }
1916 else if (g_str_equal (mimetype, "video/x-fwht"))
1917 {
1918 fourcc = V4L2_PIX_FMT_FWHT;
1919 }
1920 else if (g_str_equal (mimetype, "video/x-h263"))
1921 {
1922 fourcc = V4L2_PIX_FMT_H263;
1923 }
1924 else if (g_str_equal (mimetype, "video/x-h264"))
1925 {
1926 const gchar *stream_format =
1927 gst_structure_get_string (structure, "stream-format");
1928 if (g_str_equal (stream_format, "avc"))
1929 fourcc = V4L2_PIX_FMT_H264_NO_SC;
1930 else
1931 fourcc = V4L2_PIX_FMT_H264;
1932 }
1933 else if (g_str_equal (mimetype, "video/x-h265"))
1934 {
1935 fourcc = V4L2_PIX_FMT_HEVC;
1936 }
1937 else if (g_str_equal (mimetype, "video/x-vp8"))
1938 {
1939 fourcc = V4L2_PIX_FMT_VP8;
1940 }
1941 else if (g_str_equal (mimetype, "video/x-vp9"))
1942 {
1943 fourcc = V4L2_PIX_FMT_VP9;
1944 }
1945 else if (g_str_equal(mimetype, "video/x-av1"))
1946 {
1947 fourcc = V4L2_PIX_FMT_AV1;
1948 }
1949 else if (g_str_equal(mimetype, "video/x-avs"))
1950 {
1951 fourcc = V4L2_PIX_FMT_AVS;
1952 }
1953 else if (g_str_equal(mimetype, "video/x-avs2"))
1954 {
1955 fourcc = V4L2_PIX_FMT_AVS2;
1956 }
1957 else if (g_str_equal(mimetype, "video/x-avs3"))
1958 {
1959 fourcc = V4L2_PIX_FMT_AVS3;
1960 }
1961 else if (g_str_equal (mimetype, "video/x-bayer"))
1962 {
1963 const gchar *vformat = gst_structure_get_string(structure, "format");
1964 if (vformat)
1965 {
1966 if (!g_ascii_strcasecmp(vformat, "bggr"))
1967 fourcc = V4L2_PIX_FMT_SBGGR8;
1968 else if (!g_ascii_strcasecmp(vformat, "gbrg"))
1969 fourcc = V4L2_PIX_FMT_SGBRG8;
1970 else if (!g_ascii_strcasecmp(vformat, "grbg"))
1971 fourcc = V4L2_PIX_FMT_SGRBG8;
1972 else if (!g_ascii_strcasecmp(vformat, "rggb"))
1973 fourcc = V4L2_PIX_FMT_SRGGB8;
1974 }
1975 }
1976 else if (g_str_equal (mimetype, "video/x-sonix"))
1977 {
1978 fourcc = V4L2_PIX_FMT_SN9C10X;
1979 }
1980 else if (g_str_equal (mimetype, "video/x-pwc1"))
1981 {
1982 fourcc = V4L2_PIX_FMT_PWC1;
1983 }
1984 else if (g_str_equal (mimetype, "video/x-pwc2"))
1985 {
1986 fourcc = V4L2_PIX_FMT_PWC2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001987 }
1988 else
1989 {
bo.xiao857b8682024-09-12 16:40:32 +08001990 GST_ERROR("Unknown video codec %s.", mimetype);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001991 }
bo.xiao857b8682024-09-12 16:40:32 +08001992 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001993
bo.xiao857b8682024-09-12 16:40:32 +08001994 /* Prefer the non-contiguous if supported */
1995 v4l2object->prefered_non_contiguous = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001996
bo.xiao857b8682024-09-12 16:40:32 +08001997 if (fourcc_nc)
1998 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_nc);
1999 else if (fourcc == 0)
2000 goto unhandled_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002001
bo.xiao857b8682024-09-12 16:40:32 +08002002 if (fmt == NULL)
2003 {
2004 fmt = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
2005 v4l2object->prefered_non_contiguous = FALSE;
2006 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002007
bo.xiao857b8682024-09-12 16:40:32 +08002008 if (fmt == NULL)
2009 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002010
bo.xiao857b8682024-09-12 16:40:32 +08002011 *format = fmt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002012
bo.xiao857b8682024-09-12 16:40:32 +08002013 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002014
bo.xiao857b8682024-09-12 16:40:32 +08002015 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002016invalid_format:
bo.xiao857b8682024-09-12 16:40:32 +08002017 {
2018 GST_DEBUG_OBJECT (v4l2object, "invalid format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002019 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002020 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002021unhandled_format:
bo.xiao857b8682024-09-12 16:40:32 +08002022 {
2023 GST_DEBUG_OBJECT (v4l2object, "unhandled format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002024 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002025 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002026unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08002027 {
2028 GST_DEBUG_OBJECT (v4l2object, "unsupported format");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002029 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08002030 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002031}
2032
2033static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002034gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
2035 guint32 pixelformat, gint * width, gint * height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002036
2037static void
bo.xiao857b8682024-09-12 16:40:32 +08002038gst_aml_v4l2_object_add_aspect_ratio (GstAmlV4l2Object * v4l2object, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002039{
bo.xiao857b8682024-09-12 16:40:32 +08002040 if (v4l2object->keep_aspect && v4l2object->par)
2041 gst_structure_set_value (s, "pixel-aspect-ratio", v4l2object->par);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002042}
2043
2044/* returns TRUE if the value was changed in place, otherwise FALSE */
2045static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002046gst_aml_v4l2src_value_simplify (GValue * val)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002047{
bo.xiao857b8682024-09-12 16:40:32 +08002048 /* simplify list of one value to one value */
2049 if (GST_VALUE_HOLDS_LIST (val) && gst_value_list_get_size (val) == 1)
2050 {
2051 const GValue *list_val;
2052 GValue new_val = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002053
bo.xiao857b8682024-09-12 16:40:32 +08002054 list_val = gst_value_list_get_value (val, 0);
2055 g_value_init (&new_val, G_VALUE_TYPE (list_val));
2056 g_value_copy (list_val, &new_val);
2057 g_value_unset (val);
2058 *val = new_val;
2059 return TRUE;
2060 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002061
bo.xiao857b8682024-09-12 16:40:32 +08002062 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002063}
2064
2065static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08002066gst_aml_v4l2_object_get_interlace_mode (enum v4l2_field field,
2067 GstVideoInterlaceMode * interlace_mode)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002068{
bo.xiao857b8682024-09-12 16:40:32 +08002069 switch (field)
2070 {
2071 case V4L2_FIELD_ANY:
2072 GST_ERROR("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
2073 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002074 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002075 *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
2076 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002077 case V4L2_FIELD_INTERLACED:
2078 case V4L2_FIELD_INTERLACED_TB:
2079 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08002080 *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
2081 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002082 default:
bo.xiao857b8682024-09-12 16:40:32 +08002083 GST_ERROR ("Unknown enum v4l2_field %d", field);
2084 return FALSE;
2085 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002086}
2087
2088static gboolean
2089gst_aml_v4l2_object_get_colorspace(struct v4l2_format *fmt,
2090 GstVideoColorimetry *cinfo)
2091{
bo.xiao857b8682024-09-12 16:40:32 +08002092 gboolean is_rgb =
2093 gst_aml_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat);
2094 enum v4l2_colorspace colorspace;
2095 enum v4l2_quantization range;
2096 enum v4l2_ycbcr_encoding matrix;
2097 enum v4l2_xfer_func transfer;
2098 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002099
bo.xiao857b8682024-09-12 16:40:32 +08002100 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type))
2101 {
2102 colorspace = fmt->fmt.pix_mp.colorspace;
2103 range = fmt->fmt.pix_mp.quantization;
2104 matrix = fmt->fmt.pix_mp.ycbcr_enc;
2105 transfer = fmt->fmt.pix_mp.xfer_func;
2106 }
2107 else
2108 {
2109 colorspace = fmt->fmt.pix.colorspace;
2110 range = fmt->fmt.pix.quantization;
2111 matrix = fmt->fmt.pix.ycbcr_enc;
2112 transfer = fmt->fmt.pix.xfer_func;
2113 }
2114 GST_DEBUG("colorspace:%d, range:%d, matrix:%d, transfer:%d", colorspace, range, matrix, transfer);
2115 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 +08002116
bo.xiao857b8682024-09-12 16:40:32 +08002117 /* First step, set the defaults for each primaries */
2118 switch (colorspace)
2119 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002120 case V4L2_COLORSPACE_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08002121 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2122 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2123 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2124 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
2125 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002126 case V4L2_COLORSPACE_REC709:
bo.xiao857b8682024-09-12 16:40:32 +08002127 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2128 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2129 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2130 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2131 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002132 case V4L2_COLORSPACE_SRGB:
2133 case V4L2_COLORSPACE_JPEG:
bo.xiao857b8682024-09-12 16:40:32 +08002134 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2135 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2136 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2137 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2138 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002139 case V4L2_COLORSPACE_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002140 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2141 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2142 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2143 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
2144 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002145 case V4L2_COLORSPACE_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002146 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2147 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2148 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2149 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
2150 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002151 case V4L2_COLORSPACE_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002152 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2153 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2154 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2155 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
2156 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002157 case V4L2_COLORSPACE_470_SYSTEM_M:
bo.xiao857b8682024-09-12 16:40:32 +08002158 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2159 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2160 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2161 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
2162 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002163 case V4L2_COLORSPACE_470_SYSTEM_BG:
bo.xiao857b8682024-09-12 16:40:32 +08002164 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2165 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2166 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2167 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
2168 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002169 case V4L2_COLORSPACE_RAW:
bo.xiao857b8682024-09-12 16:40:32 +08002170 /* Explicitly unknown */
2171 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2172 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2173 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2174 cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
2175 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002176 default:
bo.xiao857b8682024-09-12 16:40:32 +08002177 GST_DEBUG ("Unknown enum v4l2_colorspace %d", colorspace);
2178 ret = FALSE;
2179 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002180 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002181 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 +08002182
bo.xiao857b8682024-09-12 16:40:32 +08002183 if (!ret)
2184 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002185
bo.xiao857b8682024-09-12 16:40:32 +08002186 /* Second step, apply any custom variation */
2187 switch (range)
2188 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002189 case V4L2_QUANTIZATION_FULL_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002190 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2191 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002192 case V4L2_QUANTIZATION_LIM_RANGE:
bo.xiao857b8682024-09-12 16:40:32 +08002193 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2194 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002195 case V4L2_QUANTIZATION_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002196 /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
2197 if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
2198 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2199 else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601
2200 || matrix == V4L2_YCBCR_ENC_XV709
2201 || colorspace == V4L2_COLORSPACE_JPEG)
2202 cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
2203 else
2204 cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
2205 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002206 default:
bo.xiao857b8682024-09-12 16:40:32 +08002207 GST_WARNING ("Unknown enum v4l2_quantization value %d", range);
2208 cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
2209 break;
2210 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002211 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 +08002212
bo.xiao857b8682024-09-12 16:40:32 +08002213 switch (matrix)
2214 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002215 case V4L2_YCBCR_ENC_XV601:
2216 case V4L2_YCBCR_ENC_SYCC:
bo.xiao857b8682024-09-12 16:40:32 +08002217 GST_FIXME ("XV601 and SYCC not defined, assuming 601");
2218 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002219 case V4L2_YCBCR_ENC_601:
bo.xiao857b8682024-09-12 16:40:32 +08002220 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
2221 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002222 case V4L2_YCBCR_ENC_XV709:
bo.xiao857b8682024-09-12 16:40:32 +08002223 GST_FIXME ("XV709 not defined, assuming 709");
2224 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002225 case V4L2_YCBCR_ENC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002226 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2227 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002228 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
bo.xiao857b8682024-09-12 16:40:32 +08002229 GST_FIXME ("BT2020 with constant luma is not defined, assuming BT2020");
2230 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002231 case V4L2_YCBCR_ENC_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08002232 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
2233 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002234 case V4L2_YCBCR_ENC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002235 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
2236 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002237 case V4L2_YCBCR_ENC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002238 /* nothing, just use defaults for colorspace */
2239 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002240 default:
bo.xiao857b8682024-09-12 16:40:32 +08002241 GST_WARNING ("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
2242 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
2243 break;
2244 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002245 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 +08002246
bo.xiao857b8682024-09-12 16:40:32 +08002247 /* Set identity matrix for R'G'B' formats to avoid creating
2248 * confusion. This though is cosmetic as it's now properly ignored by
2249 * the video info API and videoconvert. */
2250 if (is_rgb)
2251 cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002252
bo.xiao857b8682024-09-12 16:40:32 +08002253 switch (transfer)
2254 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002255 case V4L2_XFER_FUNC_709:
bo.xiao857b8682024-09-12 16:40:32 +08002256 if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160)
2257 cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
2258 else
2259 cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
2260 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002261 case V4L2_XFER_FUNC_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002262 cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
2263 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002264 case V4L2_XFER_FUNC_OPRGB:
bo.xiao857b8682024-09-12 16:40:32 +08002265 cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
2266 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002267 case V4L2_XFER_FUNC_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08002268 cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
2269 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002270 case V4L2_XFER_FUNC_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08002271 cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
2272 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002273 case V4L2_XFER_FUNC_DEFAULT:
bo.xiao857b8682024-09-12 16:40:32 +08002274 /* nothing, just use defaults for colorspace */
2275 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002276 default:
bo.xiao857b8682024-09-12 16:40:32 +08002277 GST_WARNING ("Unknown enum v4l2_xfer_func value %d", transfer);
2278 cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
2279 break;
2280 }
xuesong.jiange1a19662022-06-21 20:30:22 +08002281 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 +08002282
2283done:
bo.xiao857b8682024-09-12 16:40:32 +08002284 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002285}
2286
2287static int
bo.xiao857b8682024-09-12 16:40:32 +08002288gst_aml_v4l2_object_try_fmt (GstAmlV4l2Object * v4l2object,
2289 struct v4l2_format *try_fmt)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002290{
bo.xiao857b8682024-09-12 16:40:32 +08002291 int fd = v4l2object->video_fd;
2292 struct v4l2_format fmt;
2293 int r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002294
bo.xiao857b8682024-09-12 16:40:32 +08002295 memcpy (&fmt, try_fmt, sizeof (fmt));
2296 r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002297
bo.xiao857b8682024-09-12 16:40:32 +08002298 if (r < 0 && errno == ENOTTY)
2299 {
2300 /* The driver might not implement TRY_FMT, in which case we will try
2301 S_FMT to probe */
2302 if (GST_AML_V4L2_IS_ACTIVE (v4l2object))
2303 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002304
bo.xiao857b8682024-09-12 16:40:32 +08002305 memcpy (&fmt, try_fmt, sizeof (fmt));
2306 r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
2307 }
2308 memcpy (try_fmt, &fmt, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002309
bo.xiao857b8682024-09-12 16:40:32 +08002310 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002311
2312error:
bo.xiao857b8682024-09-12 16:40:32 +08002313 memcpy (try_fmt, &fmt, sizeof (fmt));
2314 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2315 "Unable to try format: %s", g_strerror (errno));
2316 return r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002317}
2318
2319static void
bo.xiao857b8682024-09-12 16:40:32 +08002320gst_aml_v4l2_object_add_interlace_mode (GstAmlV4l2Object * v4l2object,
2321 GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002322{
bo.xiao857b8682024-09-12 16:40:32 +08002323 struct v4l2_format fmt;
2324 GValue interlace_formats = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002325
bo.xiao857b8682024-09-12 16:40:32 +08002326 enum v4l2_field formats[] = {V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED};
2327 gsize i;
2328 GstVideoInterlaceMode interlace_mode, prev = -1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002329
bo.xiao857b8682024-09-12 16:40:32 +08002330 if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08002331 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002332
bo.xiao857b8682024-09-12 16:40:32 +08002333 if (v4l2object->never_interlaced)
2334 {
2335 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
2336 return;
2337 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002338
bo.xiao857b8682024-09-12 16:40:32 +08002339 g_value_init (&interlace_formats, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002340
bo.xiao857b8682024-09-12 16:40:32 +08002341 /* Try twice - once for NONE, once for INTERLACED. */
2342 for (i = 0; i < G_N_ELEMENTS (formats); i++)
2343 {
2344 memset (&fmt, 0, sizeof (fmt));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002345 fmt.type = v4l2object->type;
2346 fmt.fmt.pix.width = width;
2347 fmt.fmt.pix.height = height;
2348 fmt.fmt.pix.pixelformat = pixelformat;
bo.xiao857b8682024-09-12 16:40:32 +08002349 fmt.fmt.pix.field = formats[i];
xuesong.jiangae1548e2022-05-06 16:38:46 +08002350
bo.xiao857b8682024-09-12 16:40:32 +08002351 if (gst_aml_v4l2_object_try_fmt(v4l2object, &fmt) == 0 &&
2352 gst_aml_v4l2_object_get_interlace_mode(fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode)
2353 {
2354 GValue interlace_enum = { 0, };
2355 const gchar *mode_string;
2356 g_value_init (&interlace_enum, G_TYPE_STRING);
2357 mode_string = gst_video_interlace_mode_to_string (interlace_mode);
2358 g_value_set_string (&interlace_enum, mode_string);
2359 gst_value_list_append_and_take_value (&interlace_formats,
2360 &interlace_enum);
2361 prev = interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002362 }
bo.xiao857b8682024-09-12 16:40:32 +08002363 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002364
bo.xiao857b8682024-09-12 16:40:32 +08002365 if (gst_aml_v4l2src_value_simplify (&interlace_formats)
2366 || gst_value_list_get_size (&interlace_formats) > 0)
2367 gst_structure_take_value (s, "interlace-mode", &interlace_formats);
2368 else
2369 GST_WARNING_OBJECT (v4l2object, "Failed to determine interlace mode");
2370
2371 return;
2372}
2373
2374static void
2375gst_aml_v4l2_object_fill_colorimetry_list (GValue * list,
2376 GstVideoColorimetry * cinfo)
2377{
2378 GValue colorimetry = G_VALUE_INIT;
2379 guint size;
2380 guint i;
2381 gboolean found = FALSE;
2382
2383 g_value_init (&colorimetry, G_TYPE_STRING);
2384 g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo));
2385 GST_DEBUG("fill colorimetry:%s into list", gst_video_colorimetry_to_string(cinfo));
2386
2387 /* only insert if no duplicate */
2388 size = gst_value_list_get_size (list);
2389 for (i = 0; i < size; i++)
2390 {
2391 const GValue *tmp;
2392
2393 tmp = gst_value_list_get_value (list, i);
2394 if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002395 {
bo.xiao857b8682024-09-12 16:40:32 +08002396 found = TRUE;
2397 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002398 }
bo.xiao857b8682024-09-12 16:40:32 +08002399 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002400
bo.xiao857b8682024-09-12 16:40:32 +08002401 if (!found)
2402 gst_value_list_append_and_take_value (list, &colorimetry);
2403 else
2404 g_value_unset (&colorimetry);
2405}
xuesong.jiange1a19662022-06-21 20:30:22 +08002406
bo.xiao857b8682024-09-12 16:40:32 +08002407static void
2408gst_aml_v4l2_object_add_colorspace (GstAmlV4l2Object * v4l2object, GstStructure * s,
2409 guint32 width, guint32 height, guint32 pixelformat)
2410{
2411 struct v4l2_format fmt;
2412 GValue list = G_VALUE_INIT;
2413 GstVideoColorimetry cinfo;
2414 enum v4l2_colorspace req_cspace;
xuesong.jiang7b0882c2022-06-22 14:10:30 +08002415
bo.xiao857b8682024-09-12 16:40:32 +08002416 memset (&fmt, 0, sizeof (fmt));
2417 fmt.type = v4l2object->type;
2418 fmt.fmt.pix.width = width;
2419 fmt.fmt.pix.height = height;
2420 fmt.fmt.pix.pixelformat = pixelformat;
xuesong.jiang5c9aca72022-07-12 16:29:24 +08002421
bo.xiao857b8682024-09-12 16:40:32 +08002422 g_value_init (&list, GST_TYPE_LIST);
fei.dengccc89632022-07-15 19:10:17 +08002423
bo.xiao857b8682024-09-12 16:40:32 +08002424 /* step 1: get device default colorspace and insert it first as
2425 * it should be the preferred one */
2426 GST_DEBUG("try for pixl format");
2427 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2428 {
2429 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2430 gst_aml_v4l2_object_fill_colorimetry_list (&list, &cinfo);
2431 }
fei.dengca85b052022-07-19 14:49:23 +08002432
bo.xiao857b8682024-09-12 16:40:32 +08002433 /* step 2: probe all colorspace other than default
2434 * We don't probe all colorspace, range, matrix and transfer combination to
2435 * avoid ioctl flooding which could greatly increase initialization time
2436 * with low-speed devices (UVC...) */
2437 for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
2438 req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++)
2439 {
2440 GST_DEBUG("try for pixl format in while loop :%d", req_cspace);
2441 /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
2442 if (req_cspace == V4L2_COLORSPACE_BT878)
2443 continue;
sheng.liua326d202022-07-20 14:15:34 +08002444
bo.xiao857b8682024-09-12 16:40:32 +08002445 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2446 fmt.fmt.pix_mp.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002447 else
bo.xiao857b8682024-09-12 16:40:32 +08002448 fmt.fmt.pix.colorspace = req_cspace;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002449
bo.xiao857b8682024-09-12 16:40:32 +08002450 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) == 0)
2451 {
2452 GST_DEBUG("try for pixl format in while loop :%d tried ok", req_cspace);
2453 enum v4l2_colorspace colorspace;
2454
2455 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
2456 colorspace = fmt.fmt.pix_mp.colorspace;
2457 else
2458 colorspace = fmt.fmt.pix.colorspace;
2459
2460 if (colorspace == req_cspace)
2461 {
2462 if (gst_aml_v4l2_object_get_colorspace(&fmt, &cinfo))
2463 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2464 }
2465 }
2466 }
2467
2468 GST_DEBUG("deal: caps with colorimetry 2,3,14,7");
2469 cinfo.range = 2;
2470 cinfo.matrix = 3;
2471 cinfo.transfer = 14;
2472 cinfo.primaries = 7;
2473 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2474
2475 GST_DEBUG("deal: caps with colorimetry 2,6,13,7");
2476 cinfo.range = 2;
2477 cinfo.matrix = 6;
2478 cinfo.transfer = 13;
2479 cinfo.primaries = 7;
2480 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2481
2482 GST_DEBUG("deal: caps with colorimetry 2,6,14,7");
2483 cinfo.range = 2;
2484 cinfo.matrix = 6;
2485 cinfo.transfer = 14;
2486 cinfo.primaries = 7;
2487 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2488
2489 GST_DEBUG("deal: caps with colorimetry 2,6,0,7");
2490 cinfo.range = 2;
2491 cinfo.matrix = 6;
2492 cinfo.transfer = 0;
2493 cinfo.primaries = 7;
2494 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2495
2496 GST_DEBUG("deal: caps with colorimetry 0,6,0,7");
2497 cinfo.range = 0;
2498 cinfo.matrix = 6;
2499 cinfo.transfer = 0;
2500 cinfo.primaries = 7;
2501 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2502
2503 GST_DEBUG("deal: caps with colorimetry 2,3,0,0");
2504 cinfo.range = 2;
2505 cinfo.matrix = 3;
2506 cinfo.transfer = 0;
2507 cinfo.primaries = 0;
2508 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2509
2510 GST_DEBUG("deal: caps with colorimetry 2,6,14,0");
2511 cinfo.range = 2;
2512 cinfo.matrix = 6;
2513 cinfo.transfer = 14;
2514 cinfo.primaries = 0;
2515 gst_aml_v4l2_object_fill_colorimetry_list(&list, &cinfo);
2516
2517 if (gst_value_list_get_size (&list) > 0)
2518 gst_structure_take_value (s, "colorimetry", &list);
2519 else
2520 g_value_unset (&list);
2521
2522 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002523}
2524
2525/* The frame interval enumeration code first appeared in Linux 2.6.19. */
2526static GstStructure *
bo.xiao857b8682024-09-12 16:40:32 +08002527gst_aml_v4l2_object_probe_caps_for_format_and_size (GstAmlV4l2Object * v4l2object,
2528 guint32 pixelformat,
2529 guint32 width, guint32 height, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002530{
bo.xiao857b8682024-09-12 16:40:32 +08002531 gint fd = v4l2object->video_fd;
2532 struct v4l2_frmivalenum ival;
2533 guint32 num, denom;
2534 GstStructure *s;
2535 GValue rates = { 0, };
xuesong.jiangae1548e2022-05-06 16:38:46 +08002536
bo.xiao857b8682024-09-12 16:40:32 +08002537 memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
2538 ival.index = 0;
2539 ival.pixel_format = pixelformat;
2540 ival.width = width;
2541 ival.height = height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002542
bo.xiao857b8682024-09-12 16:40:32 +08002543 GST_LOG_OBJECT (v4l2object->dbg_obj,
2544 "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
2545 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002546
bo.xiao857b8682024-09-12 16:40:32 +08002547 /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
2548 * fraction to get framerate */
2549 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
2550 goto enum_frameintervals_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002551
bo.xiao857b8682024-09-12 16:40:32 +08002552 if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
2553 {
2554 GValue rate = { 0, };
2555
2556 g_value_init (&rates, GST_TYPE_LIST);
2557 g_value_init (&rate, GST_TYPE_FRACTION);
2558
2559 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002560 {
bo.xiao857b8682024-09-12 16:40:32 +08002561 num = ival.discrete.numerator;
2562 denom = ival.discrete.denominator;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002563
bo.xiao857b8682024-09-12 16:40:32 +08002564 if (num > G_MAXINT || denom > G_MAXINT)
2565 {
2566 /* let us hope we don't get here... */
2567 num >>= 1;
2568 denom >>= 1;
2569 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002570
bo.xiao857b8682024-09-12 16:40:32 +08002571 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
2572 denom, num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002573
bo.xiao857b8682024-09-12 16:40:32 +08002574 /* swap to get the framerate */
2575 gst_value_set_fraction (&rate, denom, num);
2576 gst_value_list_append_value (&rates, &rate);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002577
bo.xiao857b8682024-09-12 16:40:32 +08002578 ival.index++;
2579 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
2580 }
2581 else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
2582 {
2583 GValue min = { 0, };
2584 GValue step = { 0, };
2585 GValue max = { 0, };
2586 gboolean added = FALSE;
2587 guint32 minnum, mindenom;
2588 guint32 maxnum, maxdenom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002589
bo.xiao857b8682024-09-12 16:40:32 +08002590 g_value_init (&rates, GST_TYPE_LIST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002591
bo.xiao857b8682024-09-12 16:40:32 +08002592 g_value_init (&min, GST_TYPE_FRACTION);
2593 g_value_init (&step, GST_TYPE_FRACTION);
2594 g_value_init (&max, GST_TYPE_FRACTION);
2595
2596 /* get the min */
2597 minnum = ival.stepwise.min.numerator;
2598 mindenom = ival.stepwise.min.denominator;
2599 if (minnum > G_MAXINT || mindenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002600 {
bo.xiao857b8682024-09-12 16:40:32 +08002601 minnum >>= 1;
2602 mindenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002603 }
bo.xiao857b8682024-09-12 16:40:32 +08002604 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
2605 minnum, mindenom);
2606 gst_value_set_fraction (&min, minnum, mindenom);
2607
2608 /* get the max */
2609 maxnum = ival.stepwise.max.numerator;
2610 maxdenom = ival.stepwise.max.denominator;
2611 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002612 {
bo.xiao857b8682024-09-12 16:40:32 +08002613 maxnum >>= 1;
2614 maxdenom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002615 }
bo.xiao857b8682024-09-12 16:40:32 +08002616
2617 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
2618 maxnum, maxdenom);
2619 gst_value_set_fraction (&max, maxnum, maxdenom);
2620
2621 /* get the step */
2622 num = ival.stepwise.step.numerator;
2623 denom = ival.stepwise.step.denominator;
2624 if (num > G_MAXINT || denom > G_MAXINT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002625 {
bo.xiao857b8682024-09-12 16:40:32 +08002626 num >>= 1;
2627 denom >>= 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002628 }
2629
bo.xiao857b8682024-09-12 16:40:32 +08002630 if (num == 0 || denom == 0)
2631 {
2632 /* in this case we have a wrong fraction or no step, set the step to max
2633 * so that we only add the min value in the loop below */
2634 num = maxnum;
2635 denom = maxdenom;
2636 }
2637
2638 /* since we only have gst_value_fraction_subtract and not add, negate the
2639 * numerator */
2640 GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
2641 num, denom);
2642 gst_value_set_fraction (&step, -num, denom);
2643
2644 while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN)
2645 {
2646 GValue rate = { 0, };
2647
2648 num = gst_value_get_fraction_numerator (&min);
2649 denom = gst_value_get_fraction_denominator (&min);
2650 GST_LOG_OBJECT (v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
2651 denom, num);
2652
2653 /* invert to get the framerate */
2654 g_value_init (&rate, GST_TYPE_FRACTION);
2655 gst_value_set_fraction (&rate, denom, num);
2656 gst_value_list_append_value (&rates, &rate);
2657 added = TRUE;
2658
2659 /* we're actually adding because step was negated above. This is because
2660 * there is no _add function... */
2661 if (!gst_value_fraction_subtract (&min, &min, &step))
2662 {
2663 GST_WARNING_OBJECT (v4l2object->dbg_obj, "could not step fraction!");
2664 break;
2665 }
2666 }
2667 if (!added)
2668 {
2669 /* no range was added, leave the default range from the template */
2670 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2671 "no range added, leaving default");
2672 g_value_unset (&rates);
2673 }
2674 }
2675 else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
2676 {
2677 guint32 maxnum, maxdenom;
2678
2679 g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
2680
2681 num = ival.stepwise.min.numerator;
2682 denom = ival.stepwise.min.denominator;
2683 if (num > G_MAXINT || denom > G_MAXINT)
2684 {
2685 num >>= 1;
2686 denom >>= 1;
2687 }
2688
2689 maxnum = ival.stepwise.max.numerator;
2690 maxdenom = ival.stepwise.max.denominator;
2691 if (maxnum > G_MAXINT || maxdenom > G_MAXINT)
2692 {
2693 maxnum >>= 1;
2694 maxdenom >>= 1;
2695 }
2696
2697 GST_LOG_OBJECT (v4l2object->dbg_obj,
2698 "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2699 num);
2700
2701 gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
2702 }
2703 else
2704 {
2705 goto unknown_type;
2706 }
2707
xuesong.jiangae1548e2022-05-06 16:38:46 +08002708return_data:
bo.xiao857b8682024-09-12 16:40:32 +08002709 s = gst_structure_copy (template);
2710 gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
2711 "height", G_TYPE_INT, (gint) height, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002712
bo.xiao857b8682024-09-12 16:40:32 +08002713 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002714
bo.xiao857b8682024-09-12 16:40:32 +08002715 if (!v4l2object->skip_try_fmt_probes)
2716 {
2717 gst_aml_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
2718 pixelformat);
2719 // gst_aml_v4l2_object_add_colorspace(v4l2object, s, width, height, pixelformat);
2720 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002721
bo.xiao857b8682024-09-12 16:40:32 +08002722 if (G_IS_VALUE (&rates))
2723 {
2724 gst_aml_v4l2src_value_simplify (&rates);
2725 /* only change the framerate on the template when we have a valid probed new
2726 * value */
2727 gst_structure_take_value (s, "framerate", &rates);
2728 }
2729 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2730 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2731 {
2732 gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
2733 1, NULL);
2734 }
2735 return s;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002736
bo.xiao857b8682024-09-12 16:40:32 +08002737 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002738enum_frameintervals_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002739 {
2740 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2741 "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2742 GST_FOURCC_ARGS (pixelformat), width, height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002743 goto return_data;
bo.xiao857b8682024-09-12 16:40:32 +08002744 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002745unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08002746 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002747 /* I don't see how this is actually an error, we ignore the format then */
bo.xiao857b8682024-09-12 16:40:32 +08002748 GST_WARNING_OBJECT (v4l2object->dbg_obj,
2749 "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2750 GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002751 return NULL;
bo.xiao857b8682024-09-12 16:40:32 +08002752 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002753}
2754
2755static gint
bo.xiao857b8682024-09-12 16:40:32 +08002756sort_by_frame_size (GstStructure * s1, GstStructure * s2)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002757{
bo.xiao857b8682024-09-12 16:40:32 +08002758 int w1, h1, w2, h2;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002759
bo.xiao857b8682024-09-12 16:40:32 +08002760 gst_structure_get_int (s1, "width", &w1);
2761 gst_structure_get_int (s1, "height", &h1);
2762 gst_structure_get_int (s2, "width", &w2);
2763 gst_structure_get_int (s2, "height", &h2);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002764
bo.xiao857b8682024-09-12 16:40:32 +08002765 /* I think it's safe to assume that this won't overflow for a while */
2766 return ((w2 * h2) - (w1 * h1));
xuesong.jiangae1548e2022-05-06 16:38:46 +08002767}
2768
2769static void
bo.xiao857b8682024-09-12 16:40:32 +08002770gst_aml_v4l2_object_update_and_append (GstAmlV4l2Object * v4l2object,
2771 guint32 format, GstCaps * caps, GstStructure * s)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002772{
bo.xiao857b8682024-09-12 16:40:32 +08002773 GstStructure *alt_s = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002774
bo.xiao857b8682024-09-12 16:40:32 +08002775 /* Encoded stream on output buffer need to be parsed */
2776 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
2777 v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2778 {
2779 gint i = 0;
2780
2781 for (; i < GST_AML_V4L2_FORMAT_COUNT; i++)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002782 {
bo.xiao857b8682024-09-12 16:40:32 +08002783 if (format == gst_aml_v4l2_formats[i].format &&
2784 gst_aml_v4l2_formats[i].flags & GST_V4L2_CODEC &&
2785 !(gst_aml_v4l2_formats[i].flags & GST_V4L2_NO_PARSE))
2786 {
2787 gst_structure_set (s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2788 break;
2789 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002790 }
bo.xiao857b8682024-09-12 16:40:32 +08002791 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002792
bo.xiao857b8682024-09-12 16:40:32 +08002793 if (v4l2object->has_alpha_component &&
2794 (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2795 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
2796 {
2797 switch (format)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002798 {
bo.xiao857b8682024-09-12 16:40:32 +08002799 case V4L2_PIX_FMT_RGB32:
2800 alt_s = gst_structure_copy (s);
2801 gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
2802 break;
2803 case V4L2_PIX_FMT_BGR32:
2804 alt_s = gst_structure_copy (s);
2805 gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
2806 break;
2807 default:
2808 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002809 }
bo.xiao857b8682024-09-12 16:40:32 +08002810 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002811
bo.xiao857b8682024-09-12 16:40:32 +08002812 gst_caps_append_structure(caps, s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002813
bo.xiao857b8682024-09-12 16:40:32 +08002814 if (alt_s)
2815 gst_caps_append_structure(caps, alt_s);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002816}
2817
2818static GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08002819gst_aml_v4l2_object_probe_caps_for_format (GstAmlV4l2Object * v4l2object,
2820 guint32 pixelformat, const GstStructure * template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002821{
bo.xiao857b8682024-09-12 16:40:32 +08002822 GstCaps *ret = gst_caps_new_empty ();
2823 GstStructure *tmp;
2824 gint fd = v4l2object->video_fd;
2825 struct v4l2_frmsizeenum size;
2826 GList *results = NULL;
2827 guint32 w, h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002828
bo.xiao857b8682024-09-12 16:40:32 +08002829 if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
2830 {
2831 gst_caps_append_structure (ret, gst_structure_copy (template));
2832 return ret;
2833 }
2834
2835 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
2836 size.index = 0;
2837 size.pixel_format = pixelformat;
2838
2839 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2840 "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2841 GST_FOURCC_ARGS (pixelformat));
2842
2843 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2844 goto enum_framesizes_failed;
2845
2846 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
2847 {
2848 do
xuesong.jiangae1548e2022-05-06 16:38:46 +08002849 {
bo.xiao857b8682024-09-12 16:40:32 +08002850 GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
2851 size.discrete.width, size.discrete.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002852
bo.xiao857b8682024-09-12 16:40:32 +08002853 w = MIN (size.discrete.width, G_MAXINT);
2854 h = MIN (size.discrete.height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002855
bo.xiao857b8682024-09-12 16:40:32 +08002856 if (w && h)
2857 {
2858 tmp =
2859 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2860 pixelformat, w, h, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002861
bo.xiao857b8682024-09-12 16:40:32 +08002862 if (tmp)
2863 results = g_list_prepend (results, tmp);
2864 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002865
bo.xiao857b8682024-09-12 16:40:32 +08002866 size.index++;
2867 } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2868 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2869 "done iterating discrete frame sizes");
2870 }
2871 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
2872 {
2873 guint32 maxw, maxh, step_w, step_h;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002874
bo.xiao857b8682024-09-12 16:40:32 +08002875 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have stepwise frame sizes:");
2876 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2877 size.stepwise.min_width);
2878 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2879 size.stepwise.min_height);
2880 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2881 size.stepwise.max_width);
2882 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2883 size.stepwise.max_height);
2884 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step width: %d",
2885 size.stepwise.step_width);
2886 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step height: %d",
2887 size.stepwise.step_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002888
fei.dengf21a6c92024-09-05 11:30:36 +08002889 if (pixelformat == V4L2_PIX_FMT_NV12 ||
2890 pixelformat == V4L2_PIX_FMT_NV21 ||
2891 pixelformat == V4L2_PIX_FMT_NV12M ||
2892 pixelformat == V4L2_PIX_FMT_NV21M) {
2893 GST_DEBUG_OBJECT(v4l2object->dbg_obj,
2894 "set %" GST_FOURCC_FORMAT " min width and height to 16",
2895 GST_FOURCC_ARGS(pixelformat));
2896 w = 16;
2897 h = 16;
2898 } else {
2899 w = MAX(size.stepwise.min_width, 1);
2900 h = MAX(size.stepwise.min_height, 1);
2901 }
bo.xiao857b8682024-09-12 16:40:32 +08002902 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2903 maxh = MIN (size.stepwise.max_height, G_MAXINT);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002904
bo.xiao857b8682024-09-12 16:40:32 +08002905 /* in this position,updating resolution only to pass the negotiation
2906 * actually, the details about resolution refer to function:
2907 * gst_aml_v4l2_object_set_format_full for checking.
2908 */
2909 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "update maxw_maxh to MAX(maxw,maxh)_MAX(maxw,maxh)");
2910 maxh = MAX (maxw, maxh);
2911 maxw = maxh;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00002912
bo.xiao857b8682024-09-12 16:40:32 +08002913 step_w = MAX (size.stepwise.step_width, 1);
2914 step_h = MAX (size.stepwise.step_height, 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002915
bo.xiao857b8682024-09-12 16:40:32 +08002916 /* FIXME: check for sanity and that min/max are multiples of the steps */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002917
bo.xiao857b8682024-09-12 16:40:32 +08002918 /* we only query details for the max width/height since it's likely the
2919 * most restricted if there are any resolution-dependent restrictions */
2920 tmp = gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2921 pixelformat, maxw, maxh, template);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002922
bo.xiao857b8682024-09-12 16:40:32 +08002923 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002924 {
bo.xiao857b8682024-09-12 16:40:32 +08002925 GValue step_range = G_VALUE_INIT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002926
bo.xiao857b8682024-09-12 16:40:32 +08002927 g_value_init (&step_range, GST_TYPE_INT_RANGE);
2928 gst_value_set_int_range_step (&step_range, w, maxw, step_w);
2929 gst_structure_set_value (tmp, "width", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002930
bo.xiao857b8682024-09-12 16:40:32 +08002931 gst_value_set_int_range_step (&step_range, h, maxh, step_h);
2932 gst_structure_take_value (tmp, "height", &step_range);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002933
bo.xiao857b8682024-09-12 16:40:32 +08002934 /* no point using the results list here, since there's only one struct */
2935 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002936 }
bo.xiao857b8682024-09-12 16:40:32 +08002937 }
2938 else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
2939 {
2940 guint32 maxw, maxh;
2941
2942 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have continuous frame sizes:");
2943 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width: %d",
2944 size.stepwise.min_width);
2945 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2946 size.stepwise.min_height);
2947 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width: %d",
2948 size.stepwise.max_width);
2949 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height: %d",
2950 size.stepwise.max_height);
2951
2952 w = MAX (size.stepwise.min_width, 1);
2953 h = MAX (size.stepwise.min_height, 1);
2954 maxw = MIN (size.stepwise.max_width, G_MAXINT);
2955 maxh = MIN (size.stepwise.max_height, G_MAXINT);
2956
2957 tmp =
2958 gst_aml_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
2959 w, h, template);
2960 if (tmp)
xuesong.jiangae1548e2022-05-06 16:38:46 +08002961 {
bo.xiao857b8682024-09-12 16:40:32 +08002962 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
2963 (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
2964 NULL);
2965
2966 /* no point using the results list here, since there's only one struct */
2967 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002968 }
bo.xiao857b8682024-09-12 16:40:32 +08002969 }
2970 else
2971 {
2972 goto unknown_type;
2973 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002974
bo.xiao857b8682024-09-12 16:40:32 +08002975 /* we use an intermediary list to store and then sort the results of the
2976 * probing because we can't make any assumptions about the order in which
2977 * the driver will give us the sizes, but we want the final caps to contain
2978 * the results starting with the highest resolution and having the lowest
2979 * resolution last, since order in caps matters for things like fixation. */
2980 results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
2981 while (results != NULL)
2982 {
2983 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret,
2984 results->data);
2985 results = g_list_delete_link (results, results);
2986 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002987
bo.xiao857b8682024-09-12 16:40:32 +08002988 if (gst_caps_is_empty (ret))
2989 goto enum_framesizes_no_results;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002990
bo.xiao857b8682024-09-12 16:40:32 +08002991 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002992
bo.xiao857b8682024-09-12 16:40:32 +08002993 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08002994enum_framesizes_failed:
bo.xiao857b8682024-09-12 16:40:32 +08002995 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002996 /* I don't see how this is actually an error */
bo.xiao857b8682024-09-12 16:40:32 +08002997 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
2998 "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
2999 " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003000 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003001 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003002enum_framesizes_no_results:
bo.xiao857b8682024-09-12 16:40:32 +08003003 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003004 /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
3005 * question doesn't actually support it yet */
bo.xiao857b8682024-09-12 16:40:32 +08003006 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3007 "No results for pixelformat %" GST_FOURCC_FORMAT
3008 " enumerating frame sizes, trying fallback",
3009 GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003010 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003011 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003012unknown_type:
bo.xiao857b8682024-09-12 16:40:32 +08003013 {
3014 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3015 "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
3016 ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003017 goto default_frame_sizes;
bo.xiao857b8682024-09-12 16:40:32 +08003018 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003019
3020default_frame_sizes:
bo.xiao857b8682024-09-12 16:40:32 +08003021 {
bo.xiao34e36202024-07-17 16:04:01 +08003022 gint min_w, max_w, min_h, max_h;
3023
3024#ifdef DELETE_FOR_LGE
3025 gint fix_num = 0, fix_denom = 0;
3026#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08003027
3028 /* This code is for Linux < 2.6.19 */
3029 min_w = min_h = 1;
3030 max_w = max_h = GST_AML_V4L2_MAX_SIZE;
bo.xiao857b8682024-09-12 16:40:32 +08003031 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
3032 &min_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003033 {
bo.xiao857b8682024-09-12 16:40:32 +08003034 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3035 "Could not probe minimum capture size for pixelformat %"
3036 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003037 }
bo.xiao857b8682024-09-12 16:40:32 +08003038 if (!gst_aml_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
3039 &max_h))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003040 {
bo.xiao857b8682024-09-12 16:40:32 +08003041 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3042 "Could not probe maximum capture size for pixelformat %"
3043 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003044 }
3045
bo.xiao857b8682024-09-12 16:40:32 +08003046
3047 tmp = gst_structure_copy (template);
hanghang.luo3128f102022-08-18 10:36:19 +08003048#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08003049 if (fix_num)
3050 {
bo.xiao857b8682024-09-12 16:40:32 +08003051 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
3052 fix_denom, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003053 }
hanghang.luo3128f102022-08-18 10:36:19 +08003054 else
3055#endif
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08003056 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
3057 v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003058 {
bo.xiao857b8682024-09-12 16:40:32 +08003059 /* if norm can't be used, copy the template framerate */
3060 gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
3061 G_MAXINT, 1, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003062 }
3063
3064 if (min_w == max_w)
bo.xiao857b8682024-09-12 16:40:32 +08003065 gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003066 else
bo.xiao857b8682024-09-12 16:40:32 +08003067 gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003068
3069 if (min_h == max_h)
bo.xiao857b8682024-09-12 16:40:32 +08003070 gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003071 else
bo.xiao857b8682024-09-12 16:40:32 +08003072 gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003073
bo.xiao857b8682024-09-12 16:40:32 +08003074 gst_aml_v4l2_object_add_aspect_ratio (v4l2object, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003075
3076 if (!v4l2object->skip_try_fmt_probes)
3077 {
bo.xiao857b8682024-09-12 16:40:32 +08003078 /* We could consider setting interlace mode from min and max. */
3079 gst_aml_v4l2_object_add_interlace_mode(v4l2object, tmp, max_w, max_h,
3080 pixelformat);
3081 /* We could consider to check colorspace for min too, in case it depends on
3082 * the size. But in this case, min and max could not be enough */
3083 gst_aml_v4l2_object_add_colorspace(v4l2object, tmp, max_w, max_h,
3084 pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003085 }
3086
bo.xiao857b8682024-09-12 16:40:32 +08003087 gst_aml_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003088 return ret;
bo.xiao857b8682024-09-12 16:40:32 +08003089 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003090}
3091
3092static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003093gst_aml_v4l2_object_get_nearest_size (GstAmlV4l2Object * v4l2object,
3094 guint32 pixelformat, gint * width, gint * height)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003095{
bo.xiao857b8682024-09-12 16:40:32 +08003096 struct v4l2_format fmt;
3097 gboolean ret = FALSE;
3098 GstVideoInterlaceMode interlace_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003099
bo.xiao857b8682024-09-12 16:40:32 +08003100 g_return_val_if_fail (width != NULL, FALSE);
3101 g_return_val_if_fail (height != NULL, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003102
bo.xiao857b8682024-09-12 16:40:32 +08003103 GST_LOG_OBJECT (v4l2object->dbg_obj,
3104 "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
3105 *width, *height, GST_FOURCC_ARGS (pixelformat));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003106
bo.xiao857b8682024-09-12 16:40:32 +08003107 memset (&fmt, 0, sizeof (struct v4l2_format));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003108
bo.xiao857b8682024-09-12 16:40:32 +08003109 /* get size delimiters */
3110 memset (&fmt, 0, sizeof (fmt));
3111 fmt.type = v4l2object->type;
3112 fmt.fmt.pix.width = *width;
3113 fmt.fmt.pix.height = *height;
3114 fmt.fmt.pix.pixelformat = pixelformat;
3115 fmt.fmt.pix.field = V4L2_FIELD_ANY;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003116
bo.xiao857b8682024-09-12 16:40:32 +08003117 if (gst_aml_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
3118 goto error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003119
bo.xiao857b8682024-09-12 16:40:32 +08003120 GST_LOG_OBJECT (v4l2object->dbg_obj,
3121 "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003122
bo.xiao857b8682024-09-12 16:40:32 +08003123 *width = fmt.fmt.pix.width;
3124 *height = fmt.fmt.pix.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003125
bo.xiao857b8682024-09-12 16:40:32 +08003126 if (!gst_aml_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode))
3127 {
3128 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3129 "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
3130 GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
3131 goto error;
3132 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003133
bo.xiao857b8682024-09-12 16:40:32 +08003134 ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003135
3136error:
bo.xiao857b8682024-09-12 16:40:32 +08003137 if (!ret)
3138 {
3139 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3140 "Unable to try format: %s", g_strerror (errno));
3141 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003142
bo.xiao857b8682024-09-12 16:40:32 +08003143 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003144}
3145
3146static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003147gst_aml_v4l2_object_is_dmabuf_supported (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003148{
bo.xiao857b8682024-09-12 16:40:32 +08003149 gboolean ret = TRUE;
3150 struct v4l2_exportbuffer expbuf = {
3151 .type = v4l2object->type,
3152 .index = -1,
3153 .plane = -1,
3154 .flags = O_CLOEXEC | O_RDWR,
3155 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003156
bo.xiao857b8682024-09-12 16:40:32 +08003157 if (v4l2object->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
3158 {
3159 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3160 "libv4l2 converter detected, disabling DMABuf");
3161 ret = FALSE;
3162 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003163
bo.xiao857b8682024-09-12 16:40:32 +08003164 /* Expected to fail, but ENOTTY tells us that it is not implemented. */
3165 v4l2object->ioctl (v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
3166 if (errno == ENOTTY)
3167 ret = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003168
bo.xiao857b8682024-09-12 16:40:32 +08003169 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003170}
3171
3172static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003173gst_aml_v4l2_object_setup_pool (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003174{
bo.xiao857b8682024-09-12 16:40:32 +08003175 GstAmlV4l2IOMode mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003176
bo.xiao857b8682024-09-12 16:40:32 +08003177 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "initializing the %s system",
3178 V4L2_TYPE_IS_OUTPUT (v4l2object->type) ? "output" : "capture");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003179
bo.xiao857b8682024-09-12 16:40:32 +08003180 GST_AML_V4L2_CHECK_OPEN (v4l2object);
3181 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003182
bo.xiao857b8682024-09-12 16:40:32 +08003183 /* find transport */
3184 mode = v4l2object->req_mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003185
bo.xiao857b8682024-09-12 16:40:32 +08003186 if (v4l2object->device_caps & V4L2_CAP_READWRITE)
3187 {
3188 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
3189 mode = GST_V4L2_IO_RW;
3190 }
3191 else if (v4l2object->req_mode == GST_V4L2_IO_RW)
3192 goto method_not_supported;
3193
3194 if (v4l2object->device_caps & V4L2_CAP_STREAMING)
3195 {
3196 if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003197 {
bo.xiao857b8682024-09-12 16:40:32 +08003198 if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
3199 gst_aml_v4l2_object_is_dmabuf_supported (v4l2object))
3200 {
3201 mode = GST_V4L2_IO_DMABUF;
3202 }
3203 else
3204 {
3205 mode = GST_V4L2_IO_MMAP;
3206 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003207 }
bo.xiao857b8682024-09-12 16:40:32 +08003208 }
3209 else if (v4l2object->req_mode == GST_V4L2_IO_MMAP ||
3210 v4l2object->req_mode == GST_V4L2_IO_DMABUF)
3211 goto method_not_supported;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003212
bo.xiao857b8682024-09-12 16:40:32 +08003213 /* if still no transport selected, error out */
3214 if (mode == GST_V4L2_IO_AUTO)
3215 goto no_supported_capture_method;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003216
bo.xiao857b8682024-09-12 16:40:32 +08003217 GST_INFO_OBJECT (v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
3218 v4l2object->mode = mode;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003219
bo.xiao857b8682024-09-12 16:40:32 +08003220 /* If min_buffers is not set, the driver either does not support the control or
3221 it has not been asked yet via propose_allocation/decide_allocation. */
3222 if (!v4l2object->min_buffers)
3223 gst_aml_v4l2_get_driver_min_buffers (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003224
bo.xiao857b8682024-09-12 16:40:32 +08003225 /* Map the buffers */
3226 GST_LOG_OBJECT (v4l2object->dbg_obj, "initiating buffer pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08003227
3228 if (!(v4l2object->pool = gst_aml_v4l2_buffer_pool_new(v4l2object, caps)))
bo.xiao857b8682024-09-12 16:40:32 +08003229 goto buffer_pool_new_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003230
bo.xiao857b8682024-09-12 16:40:32 +08003231 GST_AML_V4L2_SET_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003232
bo.xiao857b8682024-09-12 16:40:32 +08003233 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003234
bo.xiao857b8682024-09-12 16:40:32 +08003235 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003236buffer_pool_new_failed:
bo.xiao857b8682024-09-12 16:40:32 +08003237 {
3238 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3239 (_("Could not map buffers from device '%s'"),
3240 v4l2object->videodev),
3241 ("Failed to create buffer pool: %s", g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003242 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003243 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003244method_not_supported:
bo.xiao857b8682024-09-12 16:40:32 +08003245 {
3246 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3247 (_("The driver of device '%s' does not support the IO method %d"),
3248 v4l2object->videodev, mode), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003249 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003250 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003251no_supported_capture_method:
bo.xiao857b8682024-09-12 16:40:32 +08003252 {
3253 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
3254 (_("The driver of device '%s' does not support any known IO "
3255 "method."), v4l2object->videodev), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003256 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003257 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003258}
3259
3260static void
bo.xiao857b8682024-09-12 16:40:32 +08003261gst_aml_v4l2_object_set_stride (GstVideoInfo * info, GstVideoAlignment * align,
3262 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003263{
bo.xiao857b8682024-09-12 16:40:32 +08003264 const GstVideoFormatInfo *finfo = info->finfo;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003265
bo.xiao857b8682024-09-12 16:40:32 +08003266 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3267 {
3268 gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003269
bo.xiao857b8682024-09-12 16:40:32 +08003270 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
3271 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3272 tile_height = 1 << hs;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003273
bo.xiao857b8682024-09-12 16:40:32 +08003274 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
3275 info->height + align->padding_top + align->padding_bottom);
3276 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003277
bo.xiao857b8682024-09-12 16:40:32 +08003278 x_tiles = stride >> ws;
3279 y_tiles = padded_height >> hs;
3280 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
3281 }
3282 else
3283 {
3284 info->stride[plane] = stride;
3285 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003286}
3287
3288static void
bo.xiao857b8682024-09-12 16:40:32 +08003289gst_aml_v4l2_object_extrapolate_info (GstAmlV4l2Object * v4l2object,
3290 GstVideoInfo * info, GstVideoAlignment * align, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003291{
bo.xiao857b8682024-09-12 16:40:32 +08003292 const GstVideoFormatInfo *finfo = info->finfo;
3293 gint i, estride, padded_height;
3294 gsize offs = 0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003295
bo.xiao857b8682024-09-12 16:40:32 +08003296 g_return_if_fail (v4l2object->n_v4l2_planes == 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003297
bo.xiao857b8682024-09-12 16:40:32 +08003298 padded_height = info->height + align->padding_top + align->padding_bottom;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003299
bo.xiao857b8682024-09-12 16:40:32 +08003300 for (i = 0; i < finfo->n_planes; i++)
3301 {
3302 estride = gst_aml_v4l2_object_extrapolate_stride (finfo, i, stride);
3303
3304 gst_aml_v4l2_object_set_stride (info, align, i, estride);
3305
3306 info->offset[i] = offs;
3307 offs += estride *
3308 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, padded_height);
3309
3310 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
3311 "Extrapolated for plane %d with base stride %d: "
3312 "stride %d, offset %" G_GSIZE_FORMAT, i, stride, info->stride[i],
3313 info->offset[i]);
3314 }
3315
3316 /* Update the image size according the amount of data we are going to
3317 * read/write. This workaround bugs in driver where the sizeimage provided
3318 * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
3319 * bytesused (buffer size). */
3320 if (offs < info->size)
3321 info->size = offs;
3322}
3323
3324static void
3325gst_aml_v4l2_object_save_format (GstAmlV4l2Object * v4l2object,
3326 struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
3327 GstVideoInfo * info, GstVideoAlignment * align)
3328{
3329 const GstVideoFormatInfo *finfo = info->finfo;
3330 gboolean standard_stride = TRUE;
3331 gint stride, pstride, padded_width, padded_height, i;
3332
3333 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED)
3334 {
3335 v4l2object->n_v4l2_planes = 1;
3336 info->size = format->fmt.pix.sizeimage;
3337 goto store_info;
3338 }
3339
3340 /* adjust right padding */
3341 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3342 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3343 else
3344 stride = format->fmt.pix.bytesperline;
3345
3346 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (finfo, 0);
3347 if (pstride)
3348 {
3349 padded_width = stride / pstride;
3350 }
3351 else
3352 {
3353 /* pstride can be 0 for complex formats */
3354 GST_WARNING_OBJECT (v4l2object->element,
3355 "format %s has a pstride of 0, cannot compute padded with",
3356 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
3357 padded_width = stride;
3358 }
3359
3360 if (padded_width < format->fmt.pix.width)
3361 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3362 "Driver bug detected, stride (%d) is too small for the width (%d)",
3363 padded_width, format->fmt.pix.width);
3364
3365 align->padding_right = padded_width - info->width - align->padding_left;
3366
3367 /* adjust bottom padding */
3368 padded_height = format->fmt.pix.height;
3369
3370 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3371 {
3372 guint hs, tile_height;
3373
3374 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
3375 tile_height = 1 << hs;
3376
3377 padded_height = GST_ROUND_UP_N (padded_height, tile_height);
3378 }
3379
3380 align->padding_bottom = padded_height - info->height - align->padding_top;
3381
3382 /* setup the strides and offset */
3383 if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
3384 {
3385 struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
3386
3387 /* figure out the frame layout */
3388 v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes);
3389 info->size = 0;
3390 for (i = 0; i < v4l2object->n_v4l2_planes; i++)
3391 {
3392 stride = pix_mp->plane_fmt[i].bytesperline;
3393
3394 if (info->stride[i] != stride)
3395 standard_stride = FALSE;
3396
3397 gst_aml_v4l2_object_set_stride (info, align, i, stride);
3398 info->offset[i] = info->size;
3399 info->size += pix_mp->plane_fmt[i].sizeimage;
3400 }
3401
3402 /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
3403 if (v4l2object->n_v4l2_planes < finfo->n_planes)
3404 {
3405 stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
3406 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3407 }
3408 }
3409 else
3410 {
3411 /* only one plane in non-MPLANE mode */
3412 v4l2object->n_v4l2_planes = 1;
3413 info->size = format->fmt.pix.sizeimage;
3414 stride = format->fmt.pix.bytesperline;
3415
3416 if (info->stride[0] != stride)
3417 standard_stride = FALSE;
3418
3419 gst_aml_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
3420 }
3421
3422 /* adjust the offset to take into account left and top */
3423 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
3424 {
3425 if ((align->padding_left + align->padding_top) > 0)
3426 GST_WARNING_OBJECT (v4l2object->dbg_obj,
3427 "Left and top padding is not permitted for tiled formats");
3428 }
3429 else
3430 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003431 for (i = 0; i < finfo->n_planes; i++)
3432 {
bo.xiao857b8682024-09-12 16:40:32 +08003433 gint vedge, hedge;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003434
bo.xiao857b8682024-09-12 16:40:32 +08003435 /* FIXME we assume plane as component as this is true for all supported
3436 * format we support. */
xuesong.jiangae1548e2022-05-06 16:38:46 +08003437
bo.xiao857b8682024-09-12 16:40:32 +08003438 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, align->padding_left);
3439 vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, align->padding_top);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003440
bo.xiao857b8682024-09-12 16:40:32 +08003441 info->offset[i] += (vedge * info->stride[i]) +
3442 (hedge * GST_VIDEO_INFO_COMP_PSTRIDE (info, i));
xuesong.jiangae1548e2022-05-06 16:38:46 +08003443 }
bo.xiao857b8682024-09-12 16:40:32 +08003444 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003445
3446store_info:
bo.xiao857b8682024-09-12 16:40:32 +08003447 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
3448 info->size);
xuesong.jiangae1548e2022-05-06 16:38:46 +08003449
bo.xiao857b8682024-09-12 16:40:32 +08003450 /* to avoid copies we need video meta if there is padding */
3451 v4l2object->need_video_meta =
3452 ((align->padding_top + align->padding_left + align->padding_right +
xuesong.jiangae1548e2022-05-06 16:38:46 +08003453 align->padding_bottom) != 0);
3454
bo.xiao857b8682024-09-12 16:40:32 +08003455 /* ... or if stride is non "standard" */
3456 if (!standard_stride)
3457 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003458
bo.xiao857b8682024-09-12 16:40:32 +08003459 /* ... or also video meta if we use multiple, non-contiguous, planes */
3460 if (v4l2object->n_v4l2_planes > 1)
3461 v4l2object->need_video_meta = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003462
bo.xiao857b8682024-09-12 16:40:32 +08003463 v4l2object->info = *info;
3464 v4l2object->align = *align;
3465 v4l2object->format = *format;
3466 v4l2object->fmtdesc = fmtdesc;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003467
bo.xiao857b8682024-09-12 16:40:32 +08003468 /* if we have a framerate pre-calculate duration */
3469 if (info->fps_n > 0 && info->fps_d > 0)
3470 {
3471 v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
3472 info->fps_n);
3473 }
3474 else
3475 {
3476 v4l2object->duration = GST_CLOCK_TIME_NONE;
3477 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003478}
3479
bo.xiao857b8682024-09-12 16:40:32 +08003480gint
3481gst_aml_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
3482 gint plane, gint stride)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003483{
bo.xiao857b8682024-09-12 16:40:32 +08003484 gint estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003485
bo.xiao857b8682024-09-12 16:40:32 +08003486 switch (finfo->format)
3487 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08003488 case GST_VIDEO_FORMAT_NV12:
3489 case GST_VIDEO_FORMAT_NV12_64Z32:
3490 case GST_VIDEO_FORMAT_NV21:
3491 case GST_VIDEO_FORMAT_NV16:
3492 case GST_VIDEO_FORMAT_NV61:
3493 case GST_VIDEO_FORMAT_NV24:
bo.xiao857b8682024-09-12 16:40:32 +08003494 estride = (plane == 0 ? 1 : 2) *
3495 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3496 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003497 default:
bo.xiao857b8682024-09-12 16:40:32 +08003498 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
3499 break;
3500 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003501
bo.xiao857b8682024-09-12 16:40:32 +08003502 return estride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003503}
3504
3505static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08003506gst_aml_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
xuesong.jiangae1548e2022-05-06 16:38:46 +08003507 const gchar *color)
3508{
bo.xiao857b8682024-09-12 16:40:32 +08003509 GstVideoColorimetry ci;
3510 static const GstVideoColorimetry ci_likely_jpeg = {
3511 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3512 GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN
3513 };
3514 static const GstVideoColorimetry ci_jpeg = {
3515 GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
3516 GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709
3517 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08003518
bo.xiao857b8682024-09-12 16:40:32 +08003519 if (!gst_video_colorimetry_from_string(&ci, color))
xuesong.jiangae1548e2022-05-06 16:38:46 +08003520 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08003521
3522 if (gst_video_colorimetry_is_equal(&ci, cinfo))
3523 return TRUE;
3524
3525 /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */
3526 if (gst_video_colorimetry_is_equal(&ci, &ci_likely_jpeg) && gst_video_colorimetry_is_equal(cinfo, &ci_jpeg))
3527 return TRUE;
3528
3529 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08003530}
3531
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003532static gboolean needSpecConfigForFg(GstAmlV4l2Object *v4l2object)
3533{
bo.xiao857b8682024-09-12 16:40:32 +08003534 gboolean result= FALSE;
3535 int fd = -1;
3536 char valstr[64];
3537 const char* path= "/sys/class/video/film_grain_support";
3538 uint32_t val= 0;
3539 struct v4l2_control ctl;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003540
bo.xiao857b8682024-09-12 16:40:32 +08003541 GST_LOG("configForFilmGrain: enter");
3542 fd = open(path, O_RDONLY|O_CLOEXEC);
3543 if ( fd < 0 )
3544 {
3545 GST_DEBUG("unable to open file (%s)", path);
3546 goto exit;
3547 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003548
bo.xiao857b8682024-09-12 16:40:32 +08003549 memset(valstr, 0, sizeof(valstr));
3550 if (read(fd, valstr, sizeof(valstr) - 1) == -1 )
3551 {
3552 GST_DEBUG("unable to read fg flag");
3553 goto exit;
3554 }
bo.xiao34e36202024-07-17 16:04:01 +08003555
bo.xiao857b8682024-09-12 16:40:32 +08003556 valstr[strlen(valstr)] = '\0';
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003557
bo.xiao857b8682024-09-12 16:40:32 +08003558 if ( sscanf(valstr, "%u", &val) < 1)
3559 {
3560 GST_DEBUG("unable to get flag from: (%s)", valstr);
3561 goto exit;
3562 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003563
bo.xiao857b8682024-09-12 16:40:32 +08003564 GST_LOG("got film_grain_support:%d from node", val);
3565 if (val != 0)
3566 {
3567 goto exit;
3568 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003569
bo.xiao857b8682024-09-12 16:40:32 +08003570 memset( &ctl, 0, sizeof(ctl));
bo.xiao4ef6d272024-10-15 16:18:25 +08003571 ctl.id = AML_V4L2_GET_FILMGRAIN_INFO;
3572 v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_CTRL, &ctl);
bo.xiao857b8682024-09-12 16:40:32 +08003573 GST_LOG("got VIDIOC_G_CTRL value: %d", ctl.value);
3574 if (ctl.value == 0)
3575 {
3576 goto exit;
3577 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003578
bo.xiao857b8682024-09-12 16:40:32 +08003579 result= TRUE;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003580
3581exit:
bo.xiao857b8682024-09-12 16:40:32 +08003582 if ( fd >= 0 )
3583 {
3584 close(fd);
3585 }
3586 GST_LOG("configForFilmGrain: exit: result %d", result);
3587 return result;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003588}
hanghang.luobfc63f82024-07-05 11:04:56 +08003589
3590static gboolean
bo.xiao7659cda2024-07-18 16:16:50 +08003591get_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm)
hanghang.luobfc63f82024-07-05 11:04:56 +08003592{
bo.xiao857b8682024-09-12 16:40:32 +08003593 struct v4l2_ext_control control;
3594 struct v4l2_ext_controls ctrls;
3595 gboolean use_ext_config = FALSE;
3596 int major = 0,minor = 0;
3597 struct utsname info;
3598 struct aml_dec_params *pdecParm = (struct aml_dec_params *)streamparm->parm.raw_data;
bo.xiao7659cda2024-07-18 16:16:50 +08003599
bo.xiao857b8682024-09-12 16:40:32 +08003600 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3601 {
3602 GST_DEBUG("get linux version failed");
3603 return FALSE;
3604 }
3605 GST_DEBUG("linux major version %d %d", major,minor);
3606 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003607
bo.xiao857b8682024-09-12 16:40:32 +08003608 if (use_ext_config)
3609 {
3610 memset(&ctrls, 0, sizeof(ctrls));
3611 memset(&control, 0, sizeof(control));
3612 control.id = AML_V4L2_DEC_PARMS_CONFIG;
3613 control.ptr = pdecParm;
3614 control.size = sizeof(struct aml_dec_params);
3615 ctrls.count = 1;
3616 ctrls.controls = &control;
3617 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls ) <0)
3618 {
3619 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3620 return FALSE;
3621 }
3622 GST_DEBUG("dw: %d, flag: %d, status: %d, margin: %d",pdecParm->cfg.double_write_mode,
3623 pdecParm->cfg.metadata_config_flag, pdecParm->parms_status, pdecParm->cfg.ref_buf_margin);
3624 }
3625 else
3626 {
3627 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_G_PARM, streamparm) < 0)
3628 {
3629 GST_ERROR_OBJECT(v4l2object->dbg_obj, "get vdec parm fail");
3630 return FALSE;
3631 }
3632 }
3633 return TRUE;
hanghang.luobfc63f82024-07-05 11:04:56 +08003634}
3635
bo.xiao34e36202024-07-17 16:04:01 +08003636static int gst_aml_config_dw(GstAmlV4l2Object *v4l2object, guint32 pixFormat, guint width, guint height, gboolean interlace)
3637{
bo.xiao857b8682024-09-12 16:40:32 +08003638 const char *env_dw;
3639 int double_write = VDEC_DW_NO_AFBC;
bo.xiao34e36202024-07-17 16:04:01 +08003640
bo.xiao857b8682024-09-12 16:40:32 +08003641 GST_DEBUG("pixFormat: %d", pixFormat);
3642 switch (pixFormat)
3643 {
3644 case V4L2_PIX_FMT_MPEG:
3645 case V4L2_PIX_FMT_MPEG1:
3646 case V4L2_PIX_FMT_MPEG2:
3647 case V4L2_PIX_FMT_MPEG4:
3648 double_write = VDEC_DW_NO_AFBC;
3649 break;
3650 case V4L2_PIX_FMT_H264:
3651 {
3652 if (width > 1920 && height > 1080 && !interlace)
3653 double_write = VDEC_DW_AFBC_1_4_DW;
3654 else
3655 double_write = VDEC_DW_NO_AFBC;
3656 break;
3657 }
3658 case V4L2_PIX_FMT_HEVC:
3659 double_write = VDEC_DW_AFBC_AUTO_1_4;
3660 if (interlace)
3661 double_write = VDEC_DW_AFBC_1_1_DW;
3662 if (v4l2object->low_memory_mode)
3663 double_write = VDEC_DW_AFBC_ONLY;
3664 break;
3665 case V4L2_PIX_FMT_VP9:
3666 case V4L2_PIX_FMT_AV1:
3667 double_write = v4l2object->low_memory_mode ? VDEC_DW_AFBC_ONLY:VDEC_DW_AFBC_AUTO_1_4;
3668 break;
3669 default:
3670 GST_WARNING("unknown video format %d", pixFormat);
3671 break;
3672 }
bo.xiao34e36202024-07-17 16:04:01 +08003673
bo.xiao857b8682024-09-12 16:40:32 +08003674 env_dw = getenv("V4L2_SET_AMLOGIC_DW_MODE");
3675 if (env_dw)
3676 double_write = atoi(env_dw);
bo.xiao34e36202024-07-17 16:04:01 +08003677
bo.xiao857b8682024-09-12 16:40:32 +08003678 return double_write;
bo.xiao34e36202024-07-17 16:04:01 +08003679}
hanghang.luobfc63f82024-07-05 11:04:56 +08003680
xuesong.jiangae1548e2022-05-06 16:38:46 +08003681static void
fei.deng7c3d67f2022-11-09 11:06:05 +08003682set_amlogic_vdec_parm(GstAmlV4l2Object *v4l2object, struct v4l2_streamparm *streamparm, GstCaps *caps, guint32 pixFormat)
xuesong.jiangae1548e2022-05-06 16:38:46 +08003683{
3684 struct aml_dec_params *decParm = (struct aml_dec_params *)streamparm->parm.raw_data;
3685 const char *env;
zengliang.lic9f869d2023-02-15 08:32:32 +00003686 struct v4l2_ext_control control;
3687 struct v4l2_ext_controls ctrls;
3688 gboolean use_ext_config = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003689 int major = 0, minor = 0;
zengliang.lic9f869d2023-02-15 08:32:32 +00003690 struct utsname info;
bo.xiao34e36202024-07-17 16:04:01 +08003691 gboolean is_interlaced = FALSE;
bo.xiao7659cda2024-07-18 16:16:50 +08003692 guint width = 0, height = 0;
3693
3694 streamparm->type = v4l2object->type;
bo.xiao34e36202024-07-17 16:04:01 +08003695
fei.deng355dfb52024-09-14 15:04:31 +08003696 env = getenv("V4L2DEC_LOW_MEM_MODE");
3697 if (env) {
3698 GST_DEBUG("%s",env);
3699 v4l2object->low_memory_mode = atoi(env) > 0? TRUE: FALSE;
3700 }
hanghang.luo7f403102024-07-04 10:33:01 +08003701 GST_DEBUG("low mem: %d",v4l2object->low_memory_mode);
bo.xiao34e36202024-07-17 16:04:01 +08003702
bo.xiao7659cda2024-07-18 16:16:50 +08003703 if (uname(&info) || sscanf(info.release, "%d.%d", &major, &minor) <= 0)
3704 {
3705 GST_DEBUG("get linux version failed");
3706 }
3707 GST_DEBUG("linux major version %d %d", major,minor);
3708 use_ext_config = ((major == 5 && minor >= 15) || major >= 6) ? TRUE: FALSE;
3709
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003710 GstStructure *structure = gst_caps_get_structure(caps, 0);
3711 if (structure == NULL)
3712 {
3713 return;
3714 }
3715 gst_structure_get_uint(structure,"width",&width);
3716 gst_structure_get_uint(structure,"height",&height);
3717 if (gst_structure_has_field(structure, "interlace-mode"))
3718 {
bo.xiao34e36202024-07-17 16:04:01 +08003719 const gchar *mode = gst_structure_get_string(structure,"interlace-mode");
3720 is_interlaced = !strcmp(mode, "progressive") ? FALSE:TRUE;
hanghang.luo2dfa0ac2024-07-09 11:33:39 +08003721 GST_DEBUG("is_interlaced: %d",is_interlaced);
3722 }
hanghang.luo7f403102024-07-04 10:33:01 +08003723
xuesong.jiangae1548e2022-05-06 16:38:46 +08003724 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3725 {
fei.dengccc89632022-07-15 19:10:17 +08003726 /*set bit12 value to 1,
3727 *v4l2 output 0 pts of second interlace field frame */
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003728 decParm->cfg.metadata_config_flag |= (1 << 12);
fei.deng7c3d67f2022-11-09 11:06:05 +08003729 decParm->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003730
3731 decParm->cfg.metadata_config_flag |= 1 << 13;
3732
3733 /*set bit18 value to 1
3734 *release vpp in advance */
3735 decParm->cfg.metadata_config_flag |= (1 << 18);
3736 decParm->cfg.low_latency_mode = v4l2object->low_latency_mode;
3737
zengliang.li8f538aa2024-06-25 17:31:20 +08003738 if (v4l2object->enable_nr)
3739 {
3740 GST_DEBUG("enable nr in di");
3741 decParm->cfg.metadata_config_flag |= (1 << 14);
3742 decParm->cfg.metadata_config_flag |= (1 << 15);
3743 }
3744
bo.xiao34e36202024-07-17 16:04:01 +08003745 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, pixFormat, width, height, is_interlaced);
hanghang.luo75664712024-07-01 19:28:10 +08003746 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg dw mode to %d", decParm->cfg.double_write_mode);
bo.xiao7659cda2024-07-18 16:16:50 +08003747 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo75664712024-07-01 19:28:10 +08003748
fei.deng17693b62024-08-28 20:13:17 +08003749 if (v4l2object->low_memory_mode) {
3750 decParm->cfg.ref_buf_margin = GST_AML_V4L2_LOW_MEMORY_CAP_BUF_MARGIN;
3751 } else {
3752 decParm->cfg.ref_buf_margin = GST_AML_V4L2_DEFAULT_CAP_BUF_MARGIN;
3753 }
3754
le.hancd3f2842024-06-26 09:37:50 +00003755 env = getenv("V4L2_SET_AMLOGIC_MARGIN_NUM");
3756 if (env)
3757 {
3758 decParm->cfg.ref_buf_margin = atoi(env);
bo.xiao7659cda2024-07-18 16:16:50 +08003759 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "output cfg margin to %d", decParm->cfg.ref_buf_margin);
le.hancd3f2842024-06-26 09:37:50 +00003760 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08003761
bo.xiaof42b0082024-08-22 14:08:53 +08003762 // d v
3763 gboolean bl_present_flag, el_present_flag;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003764 int dvBaseLayerPresent = -1;
3765 int dvEnhancementLayerPresent = -1;
3766 /* have base and enhancement layers both, that means its dual layer,
bo.xiaof42b0082024-08-22 14:08:53 +08003767 d v two layer flag will be true */
3768 if (gst_structure_get_boolean( structure, "bl_present_flag", &bl_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003769 {
bo.xiaof42b0082024-08-22 14:08:53 +08003770 dvBaseLayerPresent= bl_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003771 }
bo.xiaof42b0082024-08-22 14:08:53 +08003772 if (gst_structure_get_boolean( structure, "el_present_flag", &el_present_flag))
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003773 {
bo.xiaof42b0082024-08-22 14:08:53 +08003774 dvEnhancementLayerPresent= el_present_flag?1:0;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00003775 }
3776
3777 /* have base and enhancement layers both, that means its dual layer, dv two layer flag will be true */
3778 if ( (dvBaseLayerPresent == 1) && (dvEnhancementLayerPresent == 1) )
3779 {
3780 decParm->cfg.metadata_config_flag |= (1 << 0);
3781 }
3782 else
3783 {
3784 decParm->cfg.metadata_config_flag |= (0 << 0);
3785 }
3786
3787 /* have one of then, it's standard dv stream, Non-standard dv flag will be false */
3788 if ( (dvBaseLayerPresent == 0) && (dvEnhancementLayerPresent == 0) )
3789 {
3790 decParm->cfg.metadata_config_flag |= (1 << 1);
3791 }
3792 else
3793 {
3794 decParm->cfg.metadata_config_flag |= (0 << 1);
3795 }
3796
3797 // HDR
xuesong.jiange1a19662022-06-21 20:30:22 +08003798 if ( gst_structure_has_field(structure, "colorimetry") )
3799 {
3800 const char *colorimetry= gst_structure_get_string(structure,"colorimetry");
3801 GstVideoColorimetry vci = {0};
3802 if ( colorimetry && gst_video_colorimetry_from_string( &vci, colorimetry ))
3803 {
3804 decParm->parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO;
3805 decParm->hdr.signal_type= (1<<29); /* present flag */
3806 /*set default value, this is to keep up with driver hdr info synchronization*/
3807 decParm->hdr.signal_type |= (5<<26) | (1<<24);
3808
3809 gint hdrColorimetry[4] = {0};
3810 hdrColorimetry[0]= (int)vci.range;
3811 hdrColorimetry[1]= (int)vci.matrix;
3812 hdrColorimetry[2]= (int)vci.transfer;
3813 hdrColorimetry[3]= (int)vci.primaries;
3814 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "colorimetry: [%d,%d,%d,%d]",
3815 hdrColorimetry[0],
3816 hdrColorimetry[1],
3817 hdrColorimetry[2],
3818 hdrColorimetry[3] );
3819 /* range */
3820 switch ( hdrColorimetry[0] )
3821 {
le.han8d28eb82024-06-05 08:11:12 +00003822 case GST_VIDEO_COLOR_RANGE_0_255:
3823 case GST_VIDEO_COLOR_RANGE_16_235:
xuesong.jiange1a19662022-06-21 20:30:22 +08003824 decParm->hdr.signal_type |= ((hdrColorimetry[0] % 2)<<25);
3825 break;
3826 default:
3827 break;
3828 }
3829 /* matrix coefficient */
3830 switch ( hdrColorimetry[1] )
3831 {
le.han8d28eb82024-06-05 08:11:12 +00003832 case GST_VIDEO_COLOR_MATRIX_RGB: /* RGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003833 decParm->hdr.signal_type |= 0;
3834 break;
le.han8d28eb82024-06-05 08:11:12 +00003835 case GST_VIDEO_COLOR_MATRIX_FCC: /* FCC */
xuesong.jiange1a19662022-06-21 20:30:22 +08003836 decParm->hdr.signal_type |= 4;
3837 break;
le.han8d28eb82024-06-05 08:11:12 +00003838 case GST_VIDEO_COLOR_MATRIX_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003839 decParm->hdr.signal_type |= 1;
3840 break;
le.han8d28eb82024-06-05 08:11:12 +00003841 case GST_VIDEO_COLOR_MATRIX_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003842 decParm->hdr.signal_type |= 3;
3843 break;
le.han8d28eb82024-06-05 08:11:12 +00003844 case GST_VIDEO_COLOR_MATRIX_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003845 decParm->hdr.signal_type |= 7;
3846 break;
le.han8d28eb82024-06-05 08:11:12 +00003847 case GST_VIDEO_COLOR_MATRIX_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003848 decParm->hdr.signal_type |= 9;
3849 break;
3850 default: /* unknown */
3851 decParm->hdr.signal_type |= 2;
3852 break;
3853 }
3854 /* transfer function */
3855 switch ( hdrColorimetry[2] )
3856 {
le.han8d28eb82024-06-05 08:11:12 +00003857 case GST_VIDEO_TRANSFER_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003858 decParm->hdr.signal_type |= (1<<8);
3859 break;
le.han8d28eb82024-06-05 08:11:12 +00003860 case GST_VIDEO_TRANSFER_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003861 decParm->hdr.signal_type |= (7<<8);
3862 break;
le.han8d28eb82024-06-05 08:11:12 +00003863 case GST_VIDEO_TRANSFER_LOG100: /* LOG100 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003864 decParm->hdr.signal_type |= (9<<8);
3865 break;
le.han8d28eb82024-06-05 08:11:12 +00003866 case GST_VIDEO_TRANSFER_LOG316: /* LOG316 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003867 decParm->hdr.signal_type |= (10<<8);
3868 break;
le.han8d28eb82024-06-05 08:11:12 +00003869 case GST_VIDEO_TRANSFER_BT2020_12: /* BT2020_12 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003870 decParm->hdr.signal_type |= (15<<8);
3871 break;
le.han8d28eb82024-06-05 08:11:12 +00003872 case GST_VIDEO_TRANSFER_BT2020_10: /* BT2020_10 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003873 decParm->hdr.signal_type |= (14<<8);
3874 break;
le.han8d28eb82024-06-05 08:11:12 +00003875 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
3876 case GST_VIDEO_TRANSFER_SMPTE2084: /* SMPTE2084 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003877 decParm->hdr.signal_type |= (16<<8);
3878 break;
le.han8d28eb82024-06-05 08:11:12 +00003879 #else
3880 case GST_VIDEO_TRANSFER_SMPTE_ST_2084: /* SMPTE2084 */
3881 decParm->hdr.signal_type |= (16<<8);
3882 break;
3883 #endif
3884 case GST_VIDEO_TRANSFER_ARIB_STD_B67: /* ARIB_STD_B67 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003885 decParm->hdr.signal_type |= (18<<8);
3886 break;
3887 #if ((GST_VERSION_MAJOR == 1) && (GST_VERSION_MINOR >= 18))
le.han8d28eb82024-06-05 08:11:12 +00003888 case GST_VIDEO_TRANSFER_BT601: /* BT601 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003889 decParm->hdr.signal_type |= (3<<8);
3890 break;
3891 #endif
le.han8d28eb82024-06-05 08:11:12 +00003892 case GST_VIDEO_TRANSFER_GAMMA10: /* GAMMA10 */
3893 case GST_VIDEO_TRANSFER_GAMMA18: /* GAMMA18 */
3894 case GST_VIDEO_TRANSFER_GAMMA20: /* GAMMA20 */
3895 case GST_VIDEO_TRANSFER_GAMMA22: /* GAMMA22 */
3896 case GST_VIDEO_TRANSFER_SRGB: /* SRGB */
3897 case GST_VIDEO_TRANSFER_GAMMA28: /* GAMMA28 */
3898 case GST_VIDEO_TRANSFER_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003899 default:
3900 break;
3901 }
3902 /* primaries */
3903 switch ( hdrColorimetry[3] )
3904 {
le.han8d28eb82024-06-05 08:11:12 +00003905 case GST_VIDEO_COLOR_PRIMARIES_BT709: /* BT709 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003906 decParm->hdr.signal_type |= ((1<<24)|(1<<16));
3907 break;
le.han8d28eb82024-06-05 08:11:12 +00003908 case GST_VIDEO_COLOR_PRIMARIES_BT470M: /* BT470M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003909 decParm->hdr.signal_type |= ((1<<24)|(4<<16));
3910 break;
le.han8d28eb82024-06-05 08:11:12 +00003911 case GST_VIDEO_COLOR_PRIMARIES_BT470BG: /* BT470BG */
xuesong.jiange1a19662022-06-21 20:30:22 +08003912 decParm->hdr.signal_type |= ((1<<24)|(5<<16));
3913 break;
le.han8d28eb82024-06-05 08:11:12 +00003914 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M: /* SMPTE170M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003915 decParm->hdr.signal_type |= ((1<<24)|(6<<16));
3916 break;
le.han8d28eb82024-06-05 08:11:12 +00003917 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M: /* SMPTE240M */
xuesong.jiange1a19662022-06-21 20:30:22 +08003918 decParm->hdr.signal_type |= ((1<<24)|(7<<16));
3919 break;
le.han8d28eb82024-06-05 08:11:12 +00003920 case GST_VIDEO_COLOR_PRIMARIES_FILM: /* FILM */
xuesong.jiange1a19662022-06-21 20:30:22 +08003921 decParm->hdr.signal_type |= ((1<<24)|(8<<16));
3922 break;
le.han8d28eb82024-06-05 08:11:12 +00003923 case GST_VIDEO_COLOR_PRIMARIES_BT2020: /* BT2020 */
xuesong.jiange1a19662022-06-21 20:30:22 +08003924 decParm->hdr.signal_type |= ((1<<24)|(9<<16));
3925 break;
le.han8d28eb82024-06-05 08:11:12 +00003926 case GST_VIDEO_COLOR_PRIMARIES_ADOBERGB: /* ADOBERGB */
xuesong.jiange1a19662022-06-21 20:30:22 +08003927 default:
3928 break;
3929 }
3930 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR signal_type %X", decParm->hdr.signal_type);
3931 }
3932
bo.xiao7659cda2024-07-18 16:16:50 +08003933 //why remove this colorimetry?
xuesong.jiange1a19662022-06-21 20:30:22 +08003934 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "got caps %" GST_PTR_FORMAT, caps);
3935 GstStructure *st = gst_caps_get_structure(caps, 0);
3936 GstCapsFeatures *features = gst_caps_get_features(caps, 0);
3937
3938 if (gst_structure_has_field(st, "colorimetry"))
3939 {
3940 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "have colorimetry");
3941 }
3942
3943 if (st && features)
3944 {
3945 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "trace in remove colorimetry");
3946 gst_structure_remove_field(st, "colorimetry");
3947 gst_caps_features_remove(features, "colorimetry");
3948 }
3949 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove colorimetry %" GST_PTR_FORMAT, caps);
3950 }
3951
le.han7d0af792024-06-05 08:44:18 +00003952 const char * field = NULL;
3953 if (gst_structure_has_field(structure, "mastering-display-metadata")) {
3954 field = "mastering-display-metadata";
3955 } else if (gst_structure_has_field(structure, "mastering-display-info")) {
3956 field = "mastering-display-info";
3957 }
3958
3959 if ( field )
xuesong.jiange1a19662022-06-21 20:30:22 +08003960 {
le.han7d0af792024-06-05 08:44:18 +00003961 const char *masteringDisplay= gst_structure_get_string(structure, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08003962 float hdrMasteringDisplay[10];
3963 if ( masteringDisplay && sscanf( masteringDisplay, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
3964 &hdrMasteringDisplay[0],
3965 &hdrMasteringDisplay[1],
3966 &hdrMasteringDisplay[2],
3967 &hdrMasteringDisplay[3],
3968 &hdrMasteringDisplay[4],
3969 &hdrMasteringDisplay[5],
3970 &hdrMasteringDisplay[6],
3971 &hdrMasteringDisplay[7],
3972 &hdrMasteringDisplay[8],
3973 &hdrMasteringDisplay[9] ) == 10 )
3974 {
3975 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "mastering display [%f,%f,%f,%f,%f,%f,%f,%f,%f,%f]",
3976 hdrMasteringDisplay[0],
3977 hdrMasteringDisplay[1],
3978 hdrMasteringDisplay[2],
3979 hdrMasteringDisplay[3],
3980 hdrMasteringDisplay[4],
3981 hdrMasteringDisplay[5],
3982 hdrMasteringDisplay[6],
3983 hdrMasteringDisplay[7],
3984 hdrMasteringDisplay[8],
3985 hdrMasteringDisplay[9] );
3986
3987 decParm->hdr.color_parms.present_flag= 1;
3988 decParm->hdr.color_parms.primaries[2][0]= (uint32_t)(hdrMasteringDisplay[0]*50000); /* R.x */
3989 decParm->hdr.color_parms.primaries[2][1]= (uint32_t)(hdrMasteringDisplay[1]*50000); /* R.y */
3990 decParm->hdr.color_parms.primaries[0][0]= (uint32_t)(hdrMasteringDisplay[2]*50000); /* G.x */
3991 decParm->hdr.color_parms.primaries[0][1]= (uint32_t)(hdrMasteringDisplay[3]*50000); /* G.y */
3992 decParm->hdr.color_parms.primaries[1][0]= (uint32_t)(hdrMasteringDisplay[4]*50000); /* B.x */
3993 decParm->hdr.color_parms.primaries[1][1]= (uint32_t)(hdrMasteringDisplay[5]*50000); /* B.y */
3994 decParm->hdr.color_parms.white_point[0]= (uint32_t)(hdrMasteringDisplay[6]*50000);
3995 decParm->hdr.color_parms.white_point[1]= (uint32_t)(hdrMasteringDisplay[7]*50000);
3996 decParm->hdr.color_parms.luminance[0]= (uint32_t)(hdrMasteringDisplay[8]);
3997 decParm->hdr.color_parms.luminance[1]= (uint32_t)(hdrMasteringDisplay[9]);
3998 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: primaries %X %X %X %X %X %X",
3999 decParm->hdr.color_parms.primaries[2][0],
4000 decParm->hdr.color_parms.primaries[2][1],
4001 decParm->hdr.color_parms.primaries[0][0],
4002 decParm->hdr.color_parms.primaries[0][1],
4003 decParm->hdr.color_parms.primaries[1][0],
4004 decParm->hdr.color_parms.primaries[1][1] );
4005 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: white point: %X %X",
4006 decParm->hdr.color_parms.white_point[0],
4007 decParm->hdr.color_parms.white_point[1] );
4008 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "HDR mastering: luminance: %X %X",
4009 decParm->hdr.color_parms.luminance[0],
4010 decParm->hdr.color_parms.luminance[1] );
4011 }
4012
4013 GstStructure *st = gst_caps_get_structure(caps, 0);
4014 GstCapsFeatures * features = gst_caps_get_features(caps, 0);
4015 if (st && features)
4016 {
le.han7d0af792024-06-05 08:44:18 +00004017 gst_structure_remove_fields(st, field, NULL);
4018 gst_caps_features_remove(features, field);
xuesong.jiange1a19662022-06-21 20:30:22 +08004019 }
le.han7d0af792024-06-05 08:44:18 +00004020 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "caps after remove %s %" GST_PTR_FORMAT, field, caps);
xuesong.jiange1a19662022-06-21 20:30:22 +08004021 }
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004022 }
hanghang.luo75664712024-07-01 19:28:10 +08004023 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004024 {
hanghang.luo75664712024-07-01 19:28:10 +08004025 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
bo.xiao7659cda2024-07-18 16:16:50 +08004026
4027 if (!get_amlogic_vdec_parm(v4l2object, streamparm))
hanghang.luobfc63f82024-07-05 11:04:56 +08004028 {
4029 GST_ERROR_OBJECT(v4l2object->dbg_obj, "can't get vdec parm");
4030 return;
4031 }
hanghang.luo75664712024-07-01 19:28:10 +08004032
bo.xiao7659cda2024-07-18 16:16:50 +08004033 decParm->cfg.double_write_mode = gst_aml_config_dw(v4l2object, self->v4l2output->fmtdesc->pixelformat,
bo.xiao34e36202024-07-17 16:04:01 +08004034 width, height, is_interlaced);
bo.xiao7659cda2024-07-18 16:16:50 +08004035 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "capture cfg dw mode to %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004036
4037 if (needSpecConfigForFg(v4l2object))
4038 {
bo.xiao7659cda2024-07-18 16:16:50 +08004039 decParm->cfg.double_write_mode = VDEC_DW_MMU_1;
4040 GST_DEBUG_OBJECT(v4l2object->dbg_obj,"set fg dw mode %d", decParm->cfg.double_write_mode);
hanghang.luo75664712024-07-01 19:28:10 +08004041 }
bo.xiao7659cda2024-07-18 16:16:50 +08004042 v4l2object->dw_mode = decParm->cfg.double_write_mode;
hanghang.luo6a5bdff2024-04-15 06:29:43 +00004043 }
4044 else
4045 {
hanghang.luo75664712024-07-01 19:28:10 +08004046 GST_ERROR_OBJECT(v4l2object->dbg_obj,"can't deal with. please check buffer type.");
bo.xiao7659cda2024-07-18 16:16:50 +08004047 return;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004048 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004049
bo.xiao7659cda2024-07-18 16:16:50 +08004050 if (use_ext_config)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004051 {
bo.xiao7659cda2024-07-18 16:16:50 +08004052 memset(&ctrls, 0, sizeof(ctrls));
4053 memset(&control, 0, sizeof(control));
4054 control.id = AML_V4L2_DEC_PARMS_CONFIG;
4055 control.ptr = decParm;
4056 control.size = sizeof(struct aml_dec_params);
4057 ctrls.count = 1;
4058 ctrls.controls = &control;
4059 if (v4l2object->ioctl( v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls ) < 0)
4060 {
4061 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4062 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004063 }
bo.xiao7659cda2024-07-18 16:16:50 +08004064 else
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004065 {
bo.xiao7659cda2024-07-18 16:16:50 +08004066 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_PARM, streamparm) < 0)
4067 {
4068 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set vdec parm fail");
4069 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004070 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004071}
4072
xuesong.jiangae1548e2022-05-06 16:38:46 +08004073static gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004074gst_aml_v4l2_object_set_format_full (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4075 gboolean try_only, GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004076{
bo.xiao857b8682024-09-12 16:40:32 +08004077 gint fd = v4l2object->video_fd;
4078 struct v4l2_format format;
4079 struct v4l2_streamparm streamparm;
4080 enum v4l2_field field;
4081 guint32 pixelformat;
4082 struct v4l2_fmtdesc *fmtdesc;
4083 GstVideoInfo info;
4084 GstVideoAlignment align;
4085 gint width, height, fps_n, fps_d;
4086 gint n_v4l_planes;
4087 gint i = 0;
4088 gboolean is_mplane;
4089 enum v4l2_colorspace colorspace = 0;
4090 enum v4l2_quantization range = 0;
4091 enum v4l2_ycbcr_encoding matrix = 0;
4092 enum v4l2_xfer_func transfer = 0;
4093 GstStructure *s;
4094 gboolean disable_colorimetry = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004095
bo.xiao857b8682024-09-12 16:40:32 +08004096 g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
4097 gst_caps_is_writable (caps), FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004098
bo.xiao857b8682024-09-12 16:40:32 +08004099 GST_AML_V4L2_CHECK_OPEN (v4l2object);
4100 if (!try_only)
4101 GST_AML_V4L2_CHECK_NOT_ACTIVE (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004102
bo.xiao857b8682024-09-12 16:40:32 +08004103 is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004104
bo.xiao857b8682024-09-12 16:40:32 +08004105 gst_video_info_init (&info);
4106 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004107
bo.xiao857b8682024-09-12 16:40:32 +08004108 if (!gst_aml_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
4109 goto invalid_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004110
bo.xiao857b8682024-09-12 16:40:32 +08004111 pixelformat = fmtdesc->pixelformat;
4112 width = GST_VIDEO_INFO_WIDTH (&info);
4113 height = GST_VIDEO_INFO_HEIGHT (&info);
4114 fps_n = GST_VIDEO_INFO_FPS_N (&info);
4115 fps_d = GST_VIDEO_INFO_FPS_D (&info);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004116
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004117 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size");
4118 struct v4l2_frmsizeenum size;
4119 memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
4120 size.index = 0;
4121 size.pixel_format = pixelformat;
4122 if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
bo.xiao857b8682024-09-12 16:40:32 +08004123 return FALSE;
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004124 if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE)
4125 {
bo.xiao857b8682024-09-12 16:40:32 +08004126 guint32 maxw, maxh;
4127 maxw = MIN (size.stepwise.max_width, G_MAXINT);
4128 maxh = MIN (size.stepwise.max_height, G_MAXINT);
4129 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "image from caps w_h:%d_%d", width, height);
4130 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "v4l2 support max w_h:%d_%d", maxw, maxh);
4131 if (width*height > maxw*maxh)
4132 return FALSE;
4133 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Check image size ok");
hanghang.luo9edfc7d2023-05-17 07:01:05 +00004134 }
4135
bo.xiao857b8682024-09-12 16:40:32 +08004136 //set amlogic params here,because we need pix format to set dw mode
4137 memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
4138 set_amlogic_vdec_parm(v4l2object, &streamparm, caps, pixelformat);
fei.deng7c3d67f2022-11-09 11:06:05 +08004139
bo.xiao857b8682024-09-12 16:40:32 +08004140 /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
4141 * or if contiguous is preferred */
4142 n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
4143 if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
4144 n_v4l_planes = 1;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004145
bo.xiao857b8682024-09-12 16:40:32 +08004146 if (GST_VIDEO_INFO_IS_INTERLACED(&info))
4147 {
4148 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "interlaced video");
4149 /* ideally we would differentiate between types of interlaced video
4150 * but there is not sufficient information in the caps..
4151 */
4152 field = V4L2_FIELD_INTERLACED;
4153 }
4154 else
4155 {
4156 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "progressive video");
4157 field = V4L2_FIELD_NONE;
4158 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004159
bo.xiao857b8682024-09-12 16:40:32 +08004160 /* We first pick the main colorspace from the primaries */
4161 switch (info.colorimetry.primaries)
4162 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004163 case GST_VIDEO_COLOR_PRIMARIES_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004164 /* There is two colorspaces using these primaries, use the range to
4165 * differentiate */
4166 if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
4167 colorspace = V4L2_COLORSPACE_REC709;
4168 else
4169 colorspace = V4L2_COLORSPACE_SRGB;
4170 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004171 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004172 colorspace = V4L2_COLORSPACE_BT2020;
4173 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004174 case GST_VIDEO_COLOR_PRIMARIES_BT470M:
bo.xiao857b8682024-09-12 16:40:32 +08004175 colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
4176 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004177 case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
bo.xiao857b8682024-09-12 16:40:32 +08004178 colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
4179 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004180 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
bo.xiao857b8682024-09-12 16:40:32 +08004181 colorspace = V4L2_COLORSPACE_SMPTE170M;
4182 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004183 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004184 colorspace = V4L2_COLORSPACE_SMPTE240M;
4185 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004186
4187 case GST_VIDEO_COLOR_PRIMARIES_FILM:
4188 case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004189 /* We don't know, we will guess */
4190 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004191
4192 default:
bo.xiao857b8682024-09-12 16:40:32 +08004193 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4194 "Unknown colorimetry primaries %d", info.colorimetry.primaries);
4195 break;
4196 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004197
bo.xiao857b8682024-09-12 16:40:32 +08004198 switch (info.colorimetry.range)
4199 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004200 case GST_VIDEO_COLOR_RANGE_0_255:
bo.xiao857b8682024-09-12 16:40:32 +08004201 range = V4L2_QUANTIZATION_FULL_RANGE;
4202 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004203 case GST_VIDEO_COLOR_RANGE_16_235:
bo.xiao857b8682024-09-12 16:40:32 +08004204 range = V4L2_QUANTIZATION_LIM_RANGE;
4205 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004206 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004207 /* We let the driver pick a default one */
4208 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004209 default:
bo.xiao857b8682024-09-12 16:40:32 +08004210 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4211 "Unknown colorimetry range %d", info.colorimetry.range);
4212 break;
4213 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004214
bo.xiao857b8682024-09-12 16:40:32 +08004215 switch (info.colorimetry.matrix)
4216 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004217 case GST_VIDEO_COLOR_MATRIX_RGB:
bo.xiao857b8682024-09-12 16:40:32 +08004218 /* Unspecified, leave to default */
4219 break;
4220 /* FCC is about the same as BT601 with less digit */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004221 case GST_VIDEO_COLOR_MATRIX_FCC:
4222 case GST_VIDEO_COLOR_MATRIX_BT601:
bo.xiao857b8682024-09-12 16:40:32 +08004223 matrix = V4L2_YCBCR_ENC_601;
4224 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004225 case GST_VIDEO_COLOR_MATRIX_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004226 matrix = V4L2_YCBCR_ENC_709;
4227 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004228 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004229 matrix = V4L2_YCBCR_ENC_SMPTE240M;
4230 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004231 case GST_VIDEO_COLOR_MATRIX_BT2020:
bo.xiao857b8682024-09-12 16:40:32 +08004232 matrix = V4L2_YCBCR_ENC_BT2020;
4233 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004234 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004235 /* We let the driver pick a default one */
4236 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004237 default:
bo.xiao857b8682024-09-12 16:40:32 +08004238 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4239 "Unknown colorimetry matrix %d", info.colorimetry.matrix);
4240 break;
4241 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004242
bo.xiao857b8682024-09-12 16:40:32 +08004243 switch (info.colorimetry.transfer)
4244 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004245 case GST_VIDEO_TRANSFER_GAMMA18:
4246 case GST_VIDEO_TRANSFER_GAMMA20:
4247 case GST_VIDEO_TRANSFER_GAMMA22:
4248 case GST_VIDEO_TRANSFER_GAMMA28:
bo.xiao857b8682024-09-12 16:40:32 +08004249 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4250 "GAMMA 18, 20, 22, 28 transfer functions not supported");
4251 /* fallthrough */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004252 case GST_VIDEO_TRANSFER_GAMMA10:
bo.xiao857b8682024-09-12 16:40:32 +08004253 transfer = V4L2_XFER_FUNC_NONE;
4254 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004255 case GST_VIDEO_TRANSFER_BT2020_12:
4256 case GST_VIDEO_TRANSFER_BT709:
bo.xiao857b8682024-09-12 16:40:32 +08004257 transfer = V4L2_XFER_FUNC_709;
4258 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004259 case GST_VIDEO_TRANSFER_SMPTE240M:
bo.xiao857b8682024-09-12 16:40:32 +08004260 transfer = V4L2_XFER_FUNC_SMPTE240M;
4261 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004262 case GST_VIDEO_TRANSFER_SRGB:
bo.xiao857b8682024-09-12 16:40:32 +08004263 transfer = V4L2_XFER_FUNC_SRGB;
4264 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004265 case GST_VIDEO_TRANSFER_LOG100:
4266 case GST_VIDEO_TRANSFER_LOG316:
bo.xiao857b8682024-09-12 16:40:32 +08004267 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4268 "LOG 100, 316 transfer functions not supported");
4269 /* FIXME No known sensible default, maybe AdobeRGB ? */
4270 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004271 case GST_VIDEO_TRANSFER_UNKNOWN:
bo.xiao857b8682024-09-12 16:40:32 +08004272 /* We let the driver pick a default one */
4273 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004274 default:
bo.xiao857b8682024-09-12 16:40:32 +08004275 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4276 "Unknown colorimetry transfer %d", info.colorimetry.transfer);
4277 break;
4278 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004279
bo.xiao857b8682024-09-12 16:40:32 +08004280 if (colorspace == 0)
4281 {
4282 /* Try to guess colorspace according to pixelformat and size */
4283 if (GST_VIDEO_INFO_IS_YUV (&info))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004284 {
bo.xiao857b8682024-09-12 16:40:32 +08004285 if (range == V4L2_QUANTIZATION_FULL_RANGE
4286 && matrix == V4L2_YCBCR_ENC_601 && transfer == 0)
4287 {
4288 /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
4289 * function most likely is JPEG */
4290 colorspace = V4L2_COLORSPACE_JPEG;
4291 transfer = V4L2_XFER_FUNC_SRGB;
4292 }
4293 else
4294 {
4295 /* SD streams likely use SMPTE170M and HD streams REC709 */
4296 if (width <= 720 && height <= 576)
4297 colorspace = V4L2_COLORSPACE_SMPTE170M;
4298 else
4299 colorspace = V4L2_COLORSPACE_REC709;
4300 }
4301 }
4302 else if (GST_VIDEO_INFO_IS_RGB (&info))
4303 {
4304 colorspace = V4L2_COLORSPACE_SRGB;
4305 transfer = V4L2_XFER_FUNC_NONE;
4306 }
4307 }
4308
4309 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format "
4310 "%" GST_FOURCC_FORMAT " stride: %d", width, height,
4311 GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
4312
4313 memset (&format, 0x00, sizeof (struct v4l2_format));
4314 format.type = v4l2object->type;
4315
4316 if (is_mplane)
4317 {
4318 format.type = v4l2object->type;
4319 format.fmt.pix_mp.pixelformat = pixelformat;
4320 format.fmt.pix_mp.width = width;
4321 format.fmt.pix_mp.height = height;
4322 format.fmt.pix_mp.field = field;
4323 format.fmt.pix_mp.num_planes = n_v4l_planes;
4324
4325 /* try to ask our preferred stride but it's not a failure if not
4326 * accepted */
4327 for (i = 0; i < n_v4l_planes; i++)
4328 {
4329 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
4330
4331 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4332 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4333 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4334
4335 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004336 }
4337
bo.xiao857b8682024-09-12 16:40:32 +08004338 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
4339 {
4340 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4341 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4342 else
4343 format.fmt.pix_mp.plane_fmt[0].sizeimage = v4l2object->low_memory_mode ? LOW_MEM_ENCODED_BUFFER_SIZE : ENCODED_BUFFER_SIZE;
4344 }
4345 }
4346 else
4347 {
4348 gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004349
xuesong.jiangae1548e2022-05-06 16:38:46 +08004350 format.type = v4l2object->type;
4351
bo.xiao857b8682024-09-12 16:40:32 +08004352 format.fmt.pix.width = width;
4353 format.fmt.pix.height = height;
4354 format.fmt.pix.pixelformat = pixelformat;
4355 format.fmt.pix.field = field;
4356
4357 if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
4358 stride = GST_VIDEO_TILE_X_TILES (stride) <<
4359 GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
4360
4361 /* try to ask our preferred stride */
4362 format.fmt.pix.bytesperline = stride;
4363
4364 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004365 {
bo.xiao857b8682024-09-12 16:40:32 +08004366 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT)
4367 format.fmt.pix_mp.plane_fmt[0].sizeimage = 1;
4368 else
4369 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 +08004370 }
bo.xiao857b8682024-09-12 16:40:32 +08004371 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004372
bo.xiao857b8682024-09-12 16:40:32 +08004373 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
4374 "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
4375 format.fmt.pix_mp.height,
4376 GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
4377 is_mplane ? format.fmt.pix_mp.num_planes : 1);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004378
4379#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004380 if (is_mplane)
4381 {
4382 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4383 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4384 format.fmt.pix_mp.plane_fmt[i].bytesperline);
4385 }
4386 else
4387 {
4388 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d",
4389 format.fmt.pix.bytesperline);
4390 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004391#endif
4392
bo.xiao857b8682024-09-12 16:40:32 +08004393 if (is_mplane)
4394 {
4395 format.fmt.pix_mp.colorspace = colorspace;
4396 format.fmt.pix_mp.quantization = range;
4397 format.fmt.pix_mp.ycbcr_enc = matrix;
4398 format.fmt.pix_mp.xfer_func = transfer;
4399 }
4400 else
4401 {
4402 format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
4403 format.fmt.pix.colorspace = colorspace;
4404 format.fmt.pix.quantization = range;
4405 format.fmt.pix.ycbcr_enc = matrix;
4406 format.fmt.pix.xfer_func = transfer;
4407 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004408
bo.xiao857b8682024-09-12 16:40:32 +08004409 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
4410 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004411
bo.xiao857b8682024-09-12 16:40:32 +08004412 if (try_only)
4413 {
4414 if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
4415 goto try_fmt_failed;
4416 }
4417 else
4418 {
4419 if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
4420 goto set_fmt_failed;
4421 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004422
bo.xiao857b8682024-09-12 16:40:32 +08004423 if (is_mplane)
4424 {
4425 colorspace = format.fmt.pix_mp.colorspace;
4426 range = format.fmt.pix_mp.quantization;
4427 matrix = format.fmt.pix_mp.ycbcr_enc;
4428 transfer = format.fmt.pix_mp.xfer_func;
4429 }
4430 else
4431 {
4432 colorspace = format.fmt.pix.colorspace;
4433 range = format.fmt.pix.quantization;
4434 matrix = format.fmt.pix.ycbcr_enc;
4435 transfer = format.fmt.pix.xfer_func;
4436 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004437
bo.xiao857b8682024-09-12 16:40:32 +08004438 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "Got format of %dx%d, format "
4439 "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d",
4440 format.fmt.pix.width, format.fmt.pix_mp.height,
4441 GST_FOURCC_ARGS(format.fmt.pix.pixelformat),
4442 is_mplane ? format.fmt.pix_mp.num_planes : 1,
4443 colorspace, range, matrix, transfer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004444
4445#ifndef GST_DISABLE_GST_DEBUG
bo.xiao857b8682024-09-12 16:40:32 +08004446 if (is_mplane)
4447 {
4448 for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
4449 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4450 format.fmt.pix_mp.plane_fmt[i].bytesperline,
4451 format.fmt.pix_mp.plane_fmt[i].sizeimage);
4452 }
4453 else
4454 {
4455 GST_DEBUG_OBJECT (v4l2object->dbg_obj, " stride %d, sizeimage %d",
4456 format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
4457 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004458#endif
4459
bo.xiao857b8682024-09-12 16:40:32 +08004460 if (format.fmt.pix.pixelformat != pixelformat)
4461 goto invalid_pixelformat;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004462
bo.xiao857b8682024-09-12 16:40:32 +08004463 /* Only negotiate size with raw data.
4464 * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
4465 * in ASF mode for example, there is also not reason for a driver to
4466 * change the size. */
4467 if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED)
4468 {
4469 /* We can crop larger images */
4470 if (format.fmt.pix.width < width || format.fmt.pix.height < height)
4471 goto invalid_dimensions;
4472
4473 /* Note, this will be adjusted if upstream has non-centered cropping. */
4474 align.padding_top = 0;
4475 align.padding_bottom = format.fmt.pix.height - height;
4476 align.padding_left = 0;
4477 align.padding_right = format.fmt.pix.width - width;
4478 }
4479
4480 if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
4481 goto invalid_planes;
4482
4483 /* used to check colorimetry and interlace mode fields presence */
4484 s = gst_caps_get_structure (caps, 0);
4485
4486 if (!gst_aml_v4l2_object_get_interlace_mode(format.fmt.pix.field,
4487 &info.interlace_mode))
4488 goto invalid_field;
4489 if (gst_structure_has_field(s, "interlace-mode"))
4490 {
4491 if (format.fmt.pix.field != field)
4492 goto invalid_field;
4493 }
4494
4495 if (gst_aml_v4l2_object_get_colorspace(&format, &info.colorimetry))
4496 {
4497 if (gst_structure_has_field(s, "colorimetry"))
4498 {
4499 if (!gst_aml_v4l2_video_colorimetry_matches(&info.colorimetry, gst_structure_get_string(s, "colorimetry")))
4500 {
4501 // goto invalid_colorimetry;
4502 }
4503 }
4504 }
4505 else
4506 {
4507 /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
4508 * the TRY_FMT */
4509 disable_colorimetry = TRUE;
4510 if (gst_structure_has_field (s, "colorimetry"))
4511 gst_structure_remove_field (s, "colorimetry");
4512 }
4513
4514 /* In case we have skipped the try_fmt probes, we'll need to set the
4515 * colorimetry and interlace-mode back into the caps. */
4516 if (v4l2object->skip_try_fmt_probes)
4517 {
4518 if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry"))
xuesong.jiangae1548e2022-05-06 16:38:46 +08004519 {
bo.xiao857b8682024-09-12 16:40:32 +08004520 gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
4521 gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
4522 g_free (str);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004523 }
4524
bo.xiao857b8682024-09-12 16:40:32 +08004525 if (!gst_structure_has_field(s, "interlace-mode"))
4526 gst_structure_set(s, "interlace-mode", G_TYPE_STRING,
4527 gst_video_interlace_mode_to_string(info.interlace_mode), NULL);
4528 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004529
bo.xiao857b8682024-09-12 16:40:32 +08004530 if (try_only) /* good enough for trying only */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004531 return TRUE;
4532
bo.xiao857b8682024-09-12 16:40:32 +08004533 if (GST_VIDEO_INFO_HAS_ALPHA (&info))
4534 {
4535 struct v4l2_control ctl = { 0, };
4536 ctl.id = V4L2_CID_ALPHA_COMPONENT;
4537 ctl.value = 0xff;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004538
bo.xiao857b8682024-09-12 16:40:32 +08004539 if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
4540 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4541 "Failed to set alpha component value");
4542 }
4543
4544 /* Is there a reason we require the caller to always specify a framerate? */
4545 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
4546 fps_d);
4547
4548 if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
4549 goto get_parm_failed;
4550
4551 if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
4552 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
4553 {
4554 GST_VIDEO_INFO_FPS_N (&info) =
4555 streamparm.parm.capture.timeperframe.denominator;
4556 GST_VIDEO_INFO_FPS_D (&info) =
4557 streamparm.parm.capture.timeperframe.numerator;
4558
4559 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u",
4560 streamparm.parm.capture.timeperframe.denominator,
4561 streamparm.parm.capture.timeperframe.numerator);
4562
4563 /* We used to skip frame rate setup if the camera was already setup
4564 * with the requested frame rate. This breaks some cameras though,
4565 * causing them to not output data (several models of Thinkpad cameras
4566 * have this problem at least).
4567 * So, don't skip. */
4568 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
4569 fps_n, fps_d);
4570 /* We want to change the frame rate, so check whether we can. Some cheap USB
4571 * cameras don't have the capability */
4572 if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004573 {
bo.xiao857b8682024-09-12 16:40:32 +08004574 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4575 "Not setting capture framerate (not supported)");
4576 goto done;
4577 }
4578
4579 /* Note: V4L2 wants the frame interval, we have the frame rate */
4580 streamparm.parm.capture.timeperframe.numerator = fps_d;
4581 streamparm.parm.capture.timeperframe.denominator = fps_n;
4582
4583 if (streamparm.parm.capture.timeperframe.numerator > 0 &&
4584 streamparm.parm.capture.timeperframe.denominator > 0)
4585 {
4586 /* get new values */
4587 fps_d = streamparm.parm.capture.timeperframe.numerator;
4588 fps_n = streamparm.parm.capture.timeperframe.denominator;
4589
4590 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set capture framerate to %u/%u",
4591 fps_n, fps_d);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004592 }
4593 else
4594 {
bo.xiao857b8682024-09-12 16:40:32 +08004595 /* fix v4l2 capture driver to provide framerate values */
4596 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4597 "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
4598 }
4599
4600 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4601 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4602 }
4603 else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
4604 || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4605 {
4606 GST_VIDEO_INFO_FPS_N (&info) =
4607 streamparm.parm.output.timeperframe.denominator;
4608 GST_VIDEO_INFO_FPS_D (&info) =
4609 streamparm.parm.output.timeperframe.numerator;
4610
4611 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u",
4612 streamparm.parm.output.timeperframe.denominator,
4613 streamparm.parm.output.timeperframe.numerator);
4614
4615 GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting output framerate to %u/%u",
4616 fps_n, fps_d);
4617 if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0)
4618 {
4619 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
4620 "Not setting output framerate (not supported)");
4621 goto done;
4622 }
4623
4624 /* Note: V4L2 wants the frame interval, we have the frame rate */
4625 streamparm.parm.output.timeperframe.numerator = fps_d;
4626 streamparm.parm.output.timeperframe.denominator = fps_n;
4627
4628 if (streamparm.parm.output.timeperframe.numerator > 0 &&
4629 streamparm.parm.output.timeperframe.denominator > 0)
4630 {
4631 /* get new values */
4632 fps_d = streamparm.parm.output.timeperframe.numerator;
4633 fps_n = streamparm.parm.output.timeperframe.denominator;
4634
4635 GST_INFO_OBJECT (v4l2object->dbg_obj, "Set output framerate to %u/%u",
4636 fps_n, fps_d);
4637 }
4638 else
4639 {
4640 /* fix v4l2 output driver to provide framerate values */
4641 GST_WARNING_OBJECT (v4l2object->dbg_obj,
4642 "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
4643 }
4644
4645 GST_VIDEO_INFO_FPS_N (&info) = fps_n;
4646 GST_VIDEO_INFO_FPS_D (&info) = fps_d;
4647 }
4648
4649done:
4650 /* add boolean return, so we can fail on drivers bugs */
4651 gst_aml_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info, &align);
4652
4653 /* now configure the pool */
4654 if (!gst_aml_v4l2_object_setup_pool (v4l2object, caps))
4655 goto pool_failed;
4656
4657 return TRUE;
4658
4659 /* ERRORS */
4660invalid_caps:
4661 {
4662 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
4663 caps);
4664
4665 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4666 (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps));
4667 return FALSE;
4668 }
4669try_fmt_failed:
4670 {
4671 if (errno == EINVAL)
4672 {
4673 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4674 (_("Device '%s' has no supported format"), v4l2object->videodev),
4675 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4676 GST_FOURCC_ARGS (pixelformat), width, height,
4677 g_strerror (errno)));
4678 }
4679 else
4680 {
4681 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4682 (_("Device '%s' failed during initialization"),
4683 v4l2object->videodev),
4684 ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4685 GST_FOURCC_ARGS (pixelformat), width, height,
4686 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004687 }
4688 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004689 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004690set_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004691 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004692 if (errno == EBUSY)
4693 {
bo.xiao857b8682024-09-12 16:40:32 +08004694 GST_AML_V4L2_ERROR (error, RESOURCE, BUSY,
4695 (_("Device '%s' is busy"), v4l2object->videodev),
4696 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4697 GST_FOURCC_ARGS (pixelformat), width, height,
4698 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004699 }
4700 else if (errno == EINVAL)
4701 {
bo.xiao857b8682024-09-12 16:40:32 +08004702 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4703 (_("Device '%s' has no supported format"), v4l2object->videodev),
4704 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4705 GST_FOURCC_ARGS (pixelformat), width, height,
4706 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004707 }
4708 else
4709 {
bo.xiao857b8682024-09-12 16:40:32 +08004710 GST_AML_V4L2_ERROR (error, RESOURCE, FAILED,
4711 (_("Device '%s' failed during initialization"),
4712 v4l2object->videodev),
4713 ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
4714 GST_FOURCC_ARGS (pixelformat), width, height,
4715 g_strerror (errno)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004716 }
4717 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004718 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004719invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08004720 {
4721 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4722 (_("Device '%s' cannot capture at %dx%d"),
4723 v4l2object->videodev, width, height),
4724 ("Tried to capture at %dx%d, but device returned size %dx%d",
4725 width, height, format.fmt.pix.width, format.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004726 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004727 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004728invalid_pixelformat:
bo.xiao857b8682024-09-12 16:40:32 +08004729 {
4730 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4731 (_("Device '%s' cannot capture in the specified format"),
4732 v4l2object->videodev),
4733 ("Tried to capture in %" GST_FOURCC_FORMAT
4734 ", but device returned format" " %" GST_FOURCC_FORMAT,
4735 GST_FOURCC_ARGS (pixelformat),
4736 GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004737 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004738 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004739invalid_planes:
bo.xiao857b8682024-09-12 16:40:32 +08004740 {
4741 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4742 (_("Device '%s' does support non-contiguous planes"),
4743 v4l2object->videodev),
4744 ("Device wants %d planes", format.fmt.pix_mp.num_planes));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004745 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004746 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004747invalid_field:
bo.xiao857b8682024-09-12 16:40:32 +08004748 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004749 enum v4l2_field wanted_field;
4750
4751 if (is_mplane)
bo.xiao857b8682024-09-12 16:40:32 +08004752 wanted_field = format.fmt.pix_mp.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004753 else
bo.xiao857b8682024-09-12 16:40:32 +08004754 wanted_field = format.fmt.pix.field;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004755
bo.xiao857b8682024-09-12 16:40:32 +08004756 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4757 (_("Device '%s' does not support %s interlacing"),
4758 v4l2object->videodev,
4759 field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
4760 ("Device wants %s interlacing",
4761 wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004762 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004763 }
hanghang.luo3128f102022-08-18 10:36:19 +08004764#ifdef DELETE_FOR_LGE
xuesong.jiangae1548e2022-05-06 16:38:46 +08004765invalid_colorimetry:
bo.xiao857b8682024-09-12 16:40:32 +08004766 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004767 gchar *wanted_colorimetry;
4768
bo.xiao857b8682024-09-12 16:40:32 +08004769 wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004770
bo.xiao857b8682024-09-12 16:40:32 +08004771 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4772 (_("Device '%s' does not support %s colorimetry"),
4773 v4l2object->videodev, gst_structure_get_string (s, "colorimetry")),
4774 ("Device wants %s colorimetry", wanted_colorimetry));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004775
bo.xiao857b8682024-09-12 16:40:32 +08004776 g_free (wanted_colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004777 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004778 }
hanghang.luo3128f102022-08-18 10:36:19 +08004779#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08004780get_parm_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004781 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004782 /* it's possible that this call is not supported */
4783 if (errno != EINVAL && errno != ENOTTY)
4784 {
bo.xiao857b8682024-09-12 16:40:32 +08004785 GST_AML_V4L2_ERROR (error, RESOURCE, SETTINGS,
4786 (_("Could not get parameters on device '%s'"),
4787 v4l2object->videodev), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004788 }
4789 goto done;
bo.xiao857b8682024-09-12 16:40:32 +08004790 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004791pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004792 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004793 /* setup_pool already send the error */
4794 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08004795 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004796}
4797
4798gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004799gst_aml_v4l2_object_set_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4800 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004801{
bo.xiao857b8682024-09-12 16:40:32 +08004802 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
4803 caps);
4804 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, FALSE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004805}
4806
4807gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004808gst_aml_v4l2_object_try_format (GstAmlV4l2Object * v4l2object, GstCaps * caps,
4809 GstAmlV4l2Error * error)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004810{
bo.xiao857b8682024-09-12 16:40:32 +08004811 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
4812 caps);
4813 return gst_aml_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004814}
4815
4816GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004817gst_aml_v4l2_object_poll (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004818{
bo.xiao857b8682024-09-12 16:40:32 +08004819 gint ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004820
bo.xiao857b8682024-09-12 16:40:32 +08004821 if (!v4l2object->can_poll_device)
4822 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004823
bo.xiao857b8682024-09-12 16:40:32 +08004824 GST_LOG_OBJECT (v4l2object, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004825
4826again:
bo.xiao857b8682024-09-12 16:40:32 +08004827 ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
4828 if (G_UNLIKELY (ret < 0))
4829 {
4830 switch (errno)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004831 {
bo.xiao857b8682024-09-12 16:40:32 +08004832 case EBUSY:
4833 goto stopped;
4834 case EAGAIN:
4835 case EINTR:
4836 goto again;
4837 case ENXIO:
4838 GST_WARNING_OBJECT (v4l2object,
4839 "v4l2 device doesn't support polling. Disabling"
4840 " using libv4l2 in this case may cause deadlocks");
4841 v4l2object->can_poll_device = FALSE;
4842 goto done;
4843 default:
4844 goto select_error;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004845 }
bo.xiao857b8682024-09-12 16:40:32 +08004846 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004847
4848done:
bo.xiao857b8682024-09-12 16:40:32 +08004849 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004850
bo.xiao857b8682024-09-12 16:40:32 +08004851 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004852stopped:
bo.xiao857b8682024-09-12 16:40:32 +08004853 {
4854 GST_DEBUG_OBJECT (v4l2object, "stop called");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004855 return GST_FLOW_FLUSHING;
bo.xiao857b8682024-09-12 16:40:32 +08004856 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004857select_error:
bo.xiao857b8682024-09-12 16:40:32 +08004858 {
4859 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
4860 ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004861 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004862 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004863}
4864
4865GstFlowReturn
bo.xiao857b8682024-09-12 16:40:32 +08004866gst_aml_v4l2_object_dqevent (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004867{
bo.xiao857b8682024-09-12 16:40:32 +08004868 GstFlowReturn res;
4869 struct v4l2_event evt;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004870
bo.xiao857b8682024-09-12 16:40:32 +08004871 if ((res = gst_aml_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
4872 goto poll_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004873
bo.xiao857b8682024-09-12 16:40:32 +08004874 //only read v4l2 pri event
4875 if (!gst_poll_fd_can_read_pri(v4l2object->poll, &v4l2object->pollfd))
4876 {
4877 GST_DEBUG_OBJECT(v4l2object, "not v4l2 pri event");
4878 return GST_FLOW_OK;
4879 }
4880 memset (&evt, 0x00, sizeof (struct v4l2_event));
4881 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
4882 goto dqevent_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004883
bo.xiao857b8682024-09-12 16:40:32 +08004884 switch (evt.type)
4885 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08004886 case V4L2_EVENT_SOURCE_CHANGE:
bo.xiao857b8682024-09-12 16:40:32 +08004887 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
4888 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004889 case V4L2_EVENT_EOS:
bo.xiao857b8682024-09-12 16:40:32 +08004890 return GST_AML_V4L2_FLOW_LAST_BUFFER;
4891 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004892 default:
bo.xiao857b8682024-09-12 16:40:32 +08004893 break;
4894 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004895
bo.xiao857b8682024-09-12 16:40:32 +08004896 return GST_FLOW_OK;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004897
bo.xiao857b8682024-09-12 16:40:32 +08004898 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08004899poll_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004900 {
4901 GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
xuesong.jiangae1548e2022-05-06 16:38:46 +08004902 return res;
bo.xiao857b8682024-09-12 16:40:32 +08004903 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004904dqevent_failed:
bo.xiao857b8682024-09-12 16:40:32 +08004905 {
fei.deng678f7052024-07-10 20:11:26 +08004906 GST_DEBUG_OBJECT(v4l2object, "dqevent failed");
xuesong.jiangae1548e2022-05-06 16:38:46 +08004907 return GST_FLOW_ERROR;
bo.xiao857b8682024-09-12 16:40:32 +08004908 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08004909}
4910
4911/**
4912 * gst_aml_v4l2_object_acquire_format:
bo.xiao857b8682024-09-12 16:40:32 +08004913 * @v4l2object: the object
4914 * @info: a GstVideoInfo to be filled
xuesong.jiangae1548e2022-05-06 16:38:46 +08004915 *
bo.xiao857b8682024-09-12 16:40:32 +08004916 * Acquire the driver chosen format. This is useful in decoder or encoder elements where
4917 * the output format is chosen by the HW.
xuesong.jiangae1548e2022-05-06 16:38:46 +08004918 *
4919 * Returns: %TRUE on success, %FALSE on failure.
4920 */
4921gboolean
bo.xiao857b8682024-09-12 16:40:32 +08004922gst_aml_v4l2_object_acquire_format (GstAmlV4l2Object * v4l2object, GstVideoInfo * info)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004923{
bo.xiao857b8682024-09-12 16:40:32 +08004924 struct v4l2_fmtdesc *fmtdesc;
4925 struct v4l2_format fmt;
4926 struct v4l2_crop crop;
4927 struct v4l2_selection sel;
4928 struct v4l2_cropcap cropcap;
4929 struct v4l2_rect *r = NULL;
4930 GstVideoFormat format;
4931 guint width, height;
4932 GstVideoAlignment align;
4933 gdouble pixelAspectRatio = 0.0;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004934
bo.xiao857b8682024-09-12 16:40:32 +08004935 gst_video_info_init (info);
4936 gst_video_alignment_reset (&align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004937
bo.xiao857b8682024-09-12 16:40:32 +08004938 memset (&fmt, 0x00, sizeof (struct v4l2_format));
4939 fmt.type = v4l2object->type;
4940 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "fmt.type:%d", fmt.type);
4941 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
4942 goto get_fmt_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004943
bo.xiao857b8682024-09-12 16:40:32 +08004944 fmtdesc = gst_aml_v4l2_object_get_format_from_fourcc (v4l2object,
4945 fmt.fmt.pix.pixelformat);
4946 if (fmtdesc == NULL)
4947 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004948
bo.xiao857b8682024-09-12 16:40:32 +08004949 /* No need to care about mplane, the four first params are the same */
4950 format = gst_aml_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
xuesong.jiangae1548e2022-05-06 16:38:46 +08004951
bo.xiao857b8682024-09-12 16:40:32 +08004952 /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
4953 if (format == GST_VIDEO_FORMAT_UNKNOWN)
4954 goto unsupported_format;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004955
bo.xiao857b8682024-09-12 16:40:32 +08004956 if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
4957 goto invalid_dimensions;
xuesong.jiangae1548e2022-05-06 16:38:46 +08004958
bo.xiao857b8682024-09-12 16:40:32 +08004959 width = fmt.fmt.pix.width;
4960 height = fmt.fmt.pix.height;
4961
4962 /* Use the default compose rectangle */
4963 memset (&sel, 0, sizeof (struct v4l2_selection));
4964 sel.type = v4l2object->type;
4965 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
4966 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
4967 {
4968 r = &sel.r;
4969 }
4970 else
4971 {
4972 /* For ancient kernels, fall back to G_CROP */
4973 memset (&crop, 0, sizeof (struct v4l2_crop));
4974 crop.type = v4l2object->type;
4975 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
4976 r = &crop.c;
4977 }
4978
4979 if (r)
4980 {
4981 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec*) v4l2object->element;
4982
4983 align.padding_left = r->left;
4984 align.padding_top = r->top;
4985 align.padding_right = width - r->width - r->left;
4986 align.padding_bottom = height - r->height - r->top;
4987 width = r->width;
4988 height = r->height;
4989
4990 if (self->v4l2output->dw_mode >= 0 && self->v4l2output->dw_mode != VDEC_DW_NO_AFBC)
xuesong.jiangae1548e2022-05-06 16:38:46 +08004991 {
bo.xiao857b8682024-09-12 16:40:32 +08004992 width = (width/2) *2; // align for dw
4993 height = (height/2) *2; // align for dw
xuesong.jiangae1548e2022-05-06 16:38:46 +08004994 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08004995
bo.xiao857b8682024-09-12 16:40:32 +08004996 if (self->v4l2output->dw_mode == VDEC_DW_AFBC_ONLY)
4997 height = width = 64; //because driver return src w,h when AFBC_ONLY
4998 }
4999 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "final w:%d, h:%d", width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005000
bo.xiao857b8682024-09-12 16:40:32 +08005001 gst_video_info_set_format(info, format, width, height);
bo.xiao7659cda2024-07-18 16:16:50 +08005002
bo.xiao857b8682024-09-12 16:40:32 +08005003 switch (fmt.fmt.pix.field)
5004 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005005 case V4L2_FIELD_ANY:
5006 case V4L2_FIELD_NONE:
bo.xiao857b8682024-09-12 16:40:32 +08005007 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
5008 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005009 case V4L2_FIELD_INTERLACED:
5010 case V4L2_FIELD_INTERLACED_TB:
5011 case V4L2_FIELD_INTERLACED_BT:
bo.xiao857b8682024-09-12 16:40:32 +08005012 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
5013 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005014 default:
bo.xiao857b8682024-09-12 16:40:32 +08005015 goto unsupported_field;
5016 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005017
bo.xiao857b8682024-09-12 16:40:32 +08005018 gst_aml_v4l2_object_get_colorspace(&fmt, &info->colorimetry);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005019
bo.xiao857b8682024-09-12 16:40:32 +08005020 gst_aml_v4l2_object_save_format(v4l2object, fmtdesc, &fmt, info, &align);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005021
bo.xiao857b8682024-09-12 16:40:32 +08005022 if (v4l2object->par)
5023 {
5024 width = gst_value_get_fraction_numerator(v4l2object->par);
5025 height = gst_value_get_fraction_denominator(v4l2object->par);
5026 pixelAspectRatio = (gdouble)width/(gdouble)height;
5027 }
sheng.liu641aa422023-12-26 07:05:59 +00005028
bo.xiao857b8682024-09-12 16:40:32 +08005029 if (!v4l2object->par || pixelAspectRatio == 1.0)
5030 {
5031 memset(&cropcap, 0, sizeof(cropcap));
5032 width= height= 1;
5033 cropcap.type = v4l2object->type;
5034 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) >= 0)
5035 {
5036 width= cropcap.pixelaspect.denominator;
5037 height= cropcap.pixelaspect.numerator;
5038 GST_DEBUG("cropcap: pixel aspect ratio %d:%d", width, height);
5039 if ( !width || !height )
5040 {
5041 GST_DEBUG("force pixel aspect of 1:1");
5042 width= height= 1;
5043 }
5044 }
5045 }
sheng.liudb26f7d2024-01-22 11:24:23 +00005046
bo.xiao857b8682024-09-12 16:40:32 +08005047 GST_VIDEO_INFO_PAR_N(info) = width;
5048 GST_VIDEO_INFO_PAR_D(info) = height;
sheng.liud9027ca2024-01-24 09:21:49 +00005049
bo.xiao857b8682024-09-12 16:40:32 +08005050 if (v4l2object->fps)
5051 {
5052 GST_VIDEO_INFO_FPS_N(info) = gst_value_get_fraction_numerator(v4l2object->fps);
5053 GST_VIDEO_INFO_FPS_D(info) = gst_value_get_fraction_denominator(v4l2object->fps);
5054 }
5055 /* Shall we setup the pool ? */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005056
bo.xiao857b8682024-09-12 16:40:32 +08005057 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005058
5059get_fmt_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005060 {
5061 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5062 (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005063 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005064 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005065invalid_dimensions:
bo.xiao857b8682024-09-12 16:40:32 +08005066 {
5067 GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
5068 (_("Video device returned invalid dimensions.")),
5069 ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
5070 fmt.fmt.pix.height));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005071 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005072 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005073unsupported_field:
bo.xiao857b8682024-09-12 16:40:32 +08005074 {
5075 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5076 (_("Video device uses an unsupported interlacing method.")),
5077 ("V4L2 field type %d not supported", fmt.fmt.pix.field));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005078 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005079 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005080unsupported_format:
bo.xiao857b8682024-09-12 16:40:32 +08005081 {
5082 GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
5083 (_("Video device uses an unsupported pixel format.")),
5084 ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
5085 GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005086 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005087 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005088}
5089
5090gboolean
5091gst_aml_v4l2_object_set_crop(GstAmlV4l2Object *obj)
5092{
bo.xiao857b8682024-09-12 16:40:32 +08005093 struct v4l2_selection sel = { 0 };
5094 struct v4l2_crop crop = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005095
bo.xiao857b8682024-09-12 16:40:32 +08005096 sel.type = obj->type;
5097 sel.target = V4L2_SEL_TGT_CROP;
5098 sel.flags = 0;
5099 sel.r.left = obj->align.padding_left;
5100 sel.r.top = obj->align.padding_top;
5101 sel.r.width = obj->info.width;
5102 sel.r.height = obj->info.height;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005103
bo.xiao857b8682024-09-12 16:40:32 +08005104 crop.type = obj->type;
5105 crop.c = sel.r;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005106
bo.xiao857b8682024-09-12 16:40:32 +08005107 if (obj->align.padding_left + obj->align.padding_top +
5108 obj->align.padding_right + obj->align.padding_bottom ==
5109 0)
5110 {
5111 GST_DEBUG_OBJECT(obj->dbg_obj, "no cropping needed");
5112 return TRUE;
5113 }
5114
5115 GST_DEBUG_OBJECT (obj->dbg_obj,
5116 "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5117 crop.c.width, crop.c.height);
5118
5119 if (obj->ioctl (obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0)
5120 {
5121 if (errno != ENOTTY)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005122 {
bo.xiao857b8682024-09-12 16:40:32 +08005123 GST_WARNING_OBJECT (obj->dbg_obj,
5124 "Failed to set crop rectangle with VIDIOC_S_SELECTION: %s",
5125 g_strerror (errno));
5126 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005127 }
bo.xiao857b8682024-09-12 16:40:32 +08005128 else
xuesong.jiangae1548e2022-05-06 16:38:46 +08005129 {
bo.xiao857b8682024-09-12 16:40:32 +08005130 if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0)
5131 {
5132 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_S_CROP failed");
5133 return FALSE;
5134 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005135
bo.xiao857b8682024-09-12 16:40:32 +08005136 if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0)
5137 {
5138 GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_G_CROP failed");
5139 return FALSE;
5140 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005141
bo.xiao857b8682024-09-12 16:40:32 +08005142 sel.r = crop.c;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005143 }
bo.xiao857b8682024-09-12 16:40:32 +08005144 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005145
bo.xiao857b8682024-09-12 16:40:32 +08005146 GST_DEBUG_OBJECT (obj->dbg_obj,
5147 "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
5148 crop.c.width, crop.c.height);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005149
bo.xiao857b8682024-09-12 16:40:32 +08005150 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005151}
5152
5153gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005154gst_aml_v4l2_object_caps_equal (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005155{
bo.xiao857b8682024-09-12 16:40:32 +08005156 GstStructure *config;
5157 GstCaps *oldcaps;
5158 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005159
bo.xiao857b8682024-09-12 16:40:32 +08005160 if (!v4l2object->pool)
5161 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005162
bo.xiao857b8682024-09-12 16:40:32 +08005163 config = gst_buffer_pool_get_config(v4l2object->pool);
5164 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005165
bo.xiao857b8682024-09-12 16:40:32 +08005166 ret = oldcaps && gst_caps_is_equal (caps, oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005167
bo.xiao857b8682024-09-12 16:40:32 +08005168 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005169
bo.xiao857b8682024-09-12 16:40:32 +08005170 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005171}
5172
5173gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005174gst_aml_v4l2_object_caps_is_subset (GstAmlV4l2Object * v4l2object, GstCaps * caps)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005175{
bo.xiao857b8682024-09-12 16:40:32 +08005176 GstStructure *config;
5177 GstCaps *oldcaps;
5178 gboolean ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005179
bo.xiao857b8682024-09-12 16:40:32 +08005180 if (!v4l2object->pool)
5181 return FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005182
bo.xiao857b8682024-09-12 16:40:32 +08005183 config = gst_buffer_pool_get_config(v4l2object->pool);
5184 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005185
bo.xiao857b8682024-09-12 16:40:32 +08005186 ret = oldcaps && gst_caps_is_subset (oldcaps, caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005187
bo.xiao857b8682024-09-12 16:40:32 +08005188 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005189
bo.xiao857b8682024-09-12 16:40:32 +08005190 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005191}
5192
5193GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005194gst_aml_v4l2_object_get_current_caps (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005195{
bo.xiao857b8682024-09-12 16:40:32 +08005196 GstStructure *config;
5197 GstCaps *oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005198
bo.xiao857b8682024-09-12 16:40:32 +08005199 if (!v4l2object->pool)
5200 return NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005201
bo.xiao857b8682024-09-12 16:40:32 +08005202 config = gst_buffer_pool_get_config(v4l2object->pool);
5203 gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005204
bo.xiao857b8682024-09-12 16:40:32 +08005205 if (oldcaps)
5206 gst_caps_ref (oldcaps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005207
bo.xiao857b8682024-09-12 16:40:32 +08005208 gst_structure_free (config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005209
bo.xiao857b8682024-09-12 16:40:32 +08005210 return oldcaps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005211}
5212
5213gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005214gst_aml_v4l2_object_flush_start(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005215{
bo.xiao857b8682024-09-12 16:40:32 +08005216 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005217
bo.xiao857b8682024-09-12 16:40:32 +08005218 GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005219
bo.xiao857b8682024-09-12 16:40:32 +08005220 gst_poll_set_flushing (v4l2object->poll, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005221
bo.xiao857b8682024-09-12 16:40:32 +08005222 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5223 gst_buffer_pool_set_flushing(v4l2object->pool, TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005224
bo.xiao857b8682024-09-12 16:40:32 +08005225 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005226}
5227
5228gboolean
fei.deng6bccf822024-08-22 10:05:44 +08005229gst_aml_v4l2_object_flush_stop(GstAmlV4l2Object *v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005230{
bo.xiao857b8682024-09-12 16:40:32 +08005231 gboolean ret = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005232
bo.xiao857b8682024-09-12 16:40:32 +08005233 GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005234
bo.xiao857b8682024-09-12 16:40:32 +08005235 if (v4l2object->pool && gst_buffer_pool_is_active(v4l2object->pool))
5236 gst_buffer_pool_set_flushing(v4l2object->pool, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005237
bo.xiao857b8682024-09-12 16:40:32 +08005238 gst_poll_set_flushing(v4l2object->poll, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005239
bo.xiao857b8682024-09-12 16:40:32 +08005240 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005241}
5242
5243gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005244gst_aml_v4l2_object_stop (GstAmlV4l2Object * v4l2object)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005245{
bo.xiao857b8682024-09-12 16:40:32 +08005246 GstAmlV4l2BufferPool *bpool = GST_AML_V4L2_BUFFER_POOL(v4l2object->pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005247
bo.xiao857b8682024-09-12 16:40:32 +08005248 GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stopping");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005249
bo.xiao857b8682024-09-12 16:40:32 +08005250 if (!GST_AML_V4L2_IS_OPEN (v4l2object))
5251 goto done;
5252 if (!GST_AML_V4L2_IS_ACTIVE (v4l2object))
5253 goto done;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005254
bo.xiao857b8682024-09-12 16:40:32 +08005255 if (bpool && bpool->other_pool) /* jxsdbg for resolution switch */
5256 {
5257 if (v4l2object->old_other_pool)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005258 {
bo.xiao857b8682024-09-12 16:40:32 +08005259 /* this case indicate 1st switch did not wait all old pool buf recycle and 2nd switch is coming.
5260 so save 1st old pool */
5261 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching occurs during last switching buf recycle flow");
5262 v4l2object->old_old_other_pool = v4l2object->old_other_pool;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005263 }
5264
bo.xiao857b8682024-09-12 16:40:32 +08005265 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "switching flow, ref old drmbufferpool");
5266 v4l2object->old_other_pool = bpool->other_pool;
5267 gst_object_ref(v4l2object->old_other_pool);
5268 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005269
bo.xiao857b8682024-09-12 16:40:32 +08005270 if (v4l2object->pool)
5271 {
5272 if (!gst_aml_v4l2_buffer_pool_orphan(&v4l2object->pool))
5273 {
5274 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "deactivating pool");
5275 gst_buffer_pool_set_active(v4l2object->pool, FALSE);
5276 gst_object_unref(v4l2object->pool);
5277 }
5278 v4l2object->pool = NULL;
5279 }
5280
5281 GST_AML_V4L2_SET_INACTIVE (v4l2object);
5282 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "stopped");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005283done:
bo.xiao857b8682024-09-12 16:40:32 +08005284 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005285}
5286
5287GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005288gst_aml_v4l2_object_probe_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005289{
bo.xiao857b8682024-09-12 16:40:32 +08005290 GstCaps *ret;
5291 GSList *walk;
5292 GSList *formats;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005293
bo.xiao857b8682024-09-12 16:40:32 +08005294 GST_INFO_OBJECT(v4l2object->dbg_obj, "filter caps: %" GST_PTR_FORMAT, filter);
5295 formats = gst_aml_v4l2_object_get_format_list (v4l2object);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005296
bo.xiao857b8682024-09-12 16:40:32 +08005297 ret = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005298
sheng.liu641aa422023-12-26 07:05:59 +00005299// At this time, decoder will return defult aspect, and it is not usful.
5300// so, do not probe cropcap at this time and do this action after decoding.
5301#if 0
bo.xiao857b8682024-09-12 16:40:32 +08005302 if (v4l2object->keep_aspect && !v4l2object->par)
5303 {
5304 struct v4l2_cropcap cropcap;
5305
5306 memset (&cropcap, 0, sizeof (cropcap));
5307
5308 cropcap.type = v4l2object->type;
5309 if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005310 {
bo.xiao857b8682024-09-12 16:40:32 +08005311 if (errno != ENOTTY)
5312 GST_WARNING_OBJECT (v4l2object->dbg_obj,
5313 "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
5314 g_strerror (errno));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005315 }
bo.xiao857b8682024-09-12 16:40:32 +08005316 else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator)
5317 {
5318 v4l2object->par = g_new0 (GValue, 1);
5319 g_value_init (v4l2object->par, GST_TYPE_FRACTION);
5320 gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
5321 cropcap.pixelaspect.denominator);
5322 }
5323 }
sheng.liu641aa422023-12-26 07:05:59 +00005324#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08005325
bo.xiao857b8682024-09-12 16:40:32 +08005326 for (walk = formats; walk; walk = walk->next)
5327 {
5328 struct v4l2_fmtdesc *format;
5329 GstStructure *template;
5330 GstCaps *tmp, *tmp2;
5331
5332 format = (struct v4l2_fmtdesc *) walk->data;
5333
5334 template = gst_aml_v4l2_object_v4l2fourcc_to_bare_struct (format->pixelformat);
5335
5336 if (!template)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005337 {
bo.xiao857b8682024-09-12 16:40:32 +08005338 GST_DEBUG_OBJECT (v4l2object->dbg_obj,
5339 "unknown format %" GST_FOURCC_FORMAT,
5340 GST_FOURCC_ARGS (format->pixelformat));
5341 continue;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005342 }
5343
bo.xiao857b8682024-09-12 16:40:32 +08005344 /* If we have a filter, check if we need to probe this format or not */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005345 if (filter)
5346 {
bo.xiao857b8682024-09-12 16:40:32 +08005347 GstCaps *format_caps = gst_caps_new_empty ();
xuesong.jiangae1548e2022-05-06 16:38:46 +08005348
bo.xiao857b8682024-09-12 16:40:32 +08005349 gst_caps_append_structure (format_caps, gst_structure_copy (template));
5350 GST_INFO_OBJECT(v4l2object->dbg_obj, "format_caps: %" GST_PTR_FORMAT, format_caps);
5351
5352 if (!gst_caps_can_intersect (format_caps, filter))
5353 {
5354 gst_caps_unref (format_caps);
5355 gst_structure_free (template);
5356 continue;
5357 }
5358
5359 gst_caps_unref (format_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005360 }
5361
bo.xiao857b8682024-09-12 16:40:32 +08005362 tmp = gst_aml_v4l2_object_probe_caps_for_format (v4l2object,
5363 format->pixelformat, template);
5364 GST_INFO_OBJECT(v4l2object->dbg_obj, "tmp caps: %" GST_PTR_FORMAT, tmp);
5365
5366 if (tmp)
xuesong.jiang22a9b112023-05-24 09:01:59 +00005367 {
bo.xiao857b8682024-09-12 16:40:32 +08005368 tmp2 = gst_caps_copy(tmp);
5369 gst_caps_set_features_simple(tmp2, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
5370 gst_caps_append (ret, tmp);
5371 gst_caps_append (ret, tmp2);
xuesong.jiang22a9b112023-05-24 09:01:59 +00005372 }
5373
bo.xiao857b8682024-09-12 16:40:32 +08005374 gst_structure_free (template);
5375 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005376
bo.xiao857b8682024-09-12 16:40:32 +08005377 if (filter)
5378 {
5379 GstCaps *tmp;
5380
5381 tmp = ret;
5382 ret = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
5383 gst_caps_unref (tmp);
5384 }
5385
5386 if (v4l2object->stream_mode)
5387 {
5388 GST_INFO_OBJECT(v4l2object->dbg_obj, "ret caps: %" GST_PTR_FORMAT, ret);
5389 for (guint i = 0; i < gst_caps_get_size(ret); i++)
5390 {
5391 GstStructure *s = gst_caps_get_structure(ret, i);
5392 if (s)
5393 gst_structure_remove_field(s, "alignment");
5394
5395 GST_DEBUG("i:%d, s:%p", i, s);
5396 }
5397 GST_INFO_OBJECT(v4l2object->dbg_obj, "new ret caps: %" GST_PTR_FORMAT, ret);
5398 }
5399
5400 GST_INFO_OBJECT (v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
5401
5402 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005403}
5404
5405GstCaps *
bo.xiao857b8682024-09-12 16:40:32 +08005406gst_aml_v4l2_object_get_caps (GstAmlV4l2Object * v4l2object, GstCaps * filter)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005407{
bo.xiao857b8682024-09-12 16:40:32 +08005408 GstCaps *ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005409
bo.xiao857b8682024-09-12 16:40:32 +08005410 if (v4l2object->probed_caps == NULL)
5411 v4l2object->probed_caps = gst_aml_v4l2_object_probe_caps (v4l2object, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005412
bo.xiao857b8682024-09-12 16:40:32 +08005413 if (filter)
5414 {
5415 ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
5416 GST_CAPS_INTERSECT_FIRST);
5417 }
5418 else
5419 {
5420 ret = gst_caps_ref (v4l2object->probed_caps);
5421 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005422
bo.xiao857b8682024-09-12 16:40:32 +08005423 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005424}
5425
5426gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005427gst_aml_v4l2_object_decide_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005428{
bo.xiao857b8682024-09-12 16:40:32 +08005429 GstCaps *caps;
5430 GstBufferPool *pool = NULL, *other_pool = NULL;
5431 GstStructure *config;
5432 guint size, min, max, own_min = 0;
5433 gboolean update;
5434 gboolean has_video_meta;
5435 gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
5436 GstAllocator *allocator = NULL;
5437 GstAllocationParams params = { 0 };
xuesong.jiangae1548e2022-05-06 16:38:46 +08005438
bo.xiao857b8682024-09-12 16:40:32 +08005439 GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005440
bo.xiao857b8682024-09-12 16:40:32 +08005441 g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
5442 obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005443
bo.xiao857b8682024-09-12 16:40:32 +08005444 gst_query_parse_allocation (query, &caps, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005445
bo.xiao857b8682024-09-12 16:40:32 +08005446 if (obj->pool == NULL)
5447 {
5448 if (!gst_aml_v4l2_object_setup_pool (obj, caps))
5449 goto pool_failed;
5450 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005451
bo.xiao857b8682024-09-12 16:40:32 +08005452 if (gst_query_get_n_allocation_params (query) > 0)
5453 gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005454
bo.xiao857b8682024-09-12 16:40:32 +08005455 if (gst_query_get_n_allocation_pools (query) > 0)
5456 {
5457 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
5458 update = TRUE;
5459 }
5460 else
5461 {
5462 pool = NULL;
5463 min = max = 0;
5464 size = 0;
5465 update = FALSE;
5466 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005467
bo.xiao857b8682024-09-12 16:40:32 +08005468 GST_DEBUG_OBJECT (obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%"
5469 GST_PTR_FORMAT, size, min, max, pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005470
bo.xiao857b8682024-09-12 16:40:32 +08005471 has_video_meta =
5472 gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005473
bo.xiao857b8682024-09-12 16:40:32 +08005474 can_share_own_pool = (has_video_meta || !obj->need_video_meta);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005475
bo.xiao857b8682024-09-12 16:40:32 +08005476 gst_aml_v4l2_get_driver_min_buffers (obj);
5477 /* We can't share our own pool, if it exceed V4L2 capacity */
5478 if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
5479 can_share_own_pool = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005480
bo.xiao857b8682024-09-12 16:40:32 +08005481 /* select a pool */
5482 switch (obj->mode)
5483 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005484 case GST_V4L2_IO_RW:
bo.xiao857b8682024-09-12 16:40:32 +08005485 if (pool)
5486 {
5487 /* in READ/WRITE mode, prefer a downstream pool because our own pool
5488 * doesn't help much, we have to write to it as well */
5489 GST_DEBUG_OBJECT (obj->dbg_obj,
5490 "read/write mode: using downstream pool");
5491 /* use the bigest size, when we use our own pool we can't really do any
5492 * other size than what the hardware gives us but for downstream pools
5493 * we can try */
5494 size = MAX (size, obj->info.size);
5495 }
5496 else if (can_share_own_pool)
5497 {
5498 /* no downstream pool, use our own then */
5499 GST_DEBUG_OBJECT (obj->dbg_obj,
5500 "read/write mode: no downstream pool, using our own");
5501 pool = gst_object_ref(obj->pool);
5502 size = obj->info.size;
5503 pushing_from_our_pool = TRUE;
5504 }
5505 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005506
5507 case GST_V4L2_IO_USERPTR:
5508 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005509 /* in importing mode, prefer our own pool, and pass the other pool to
5510 * our own, so it can serve itself */
5511 if (pool == NULL)
5512 goto no_downstream_pool;
5513 gst_aml_v4l2_buffer_pool_set_other_pool(GST_AML_V4L2_BUFFER_POOL(obj->pool), pool);
5514 other_pool = pool;
5515 gst_object_unref (pool);
5516 pool = gst_object_ref(obj->pool);
5517 size = obj->info.size;
5518 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005519
5520 case GST_V4L2_IO_MMAP:
5521 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005522 /* in streaming mode, prefer our own pool */
5523 /* Check if we can use it ... */
5524 if (can_share_own_pool)
5525 {
5526 if (pool)
5527 gst_object_unref (pool);
5528 pool = gst_object_ref (obj->pool);
5529 size = obj->info.size;
5530 GST_DEBUG_OBJECT (obj->dbg_obj,
5531 "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
5532 pushing_from_our_pool = TRUE;
5533 }
5534 else if (pool)
5535 {
5536 GST_DEBUG_OBJECT (obj->dbg_obj,
5537 "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
5538 pool);
5539 }
5540 else
5541 {
5542 GST_DEBUG_OBJECT (obj->dbg_obj,
5543 "streaming mode: no usable pool, copying to generic pool");
5544 size = MAX (size, obj->info.size);
5545 }
5546 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005547 case GST_V4L2_IO_AUTO:
5548 default:
bo.xiao857b8682024-09-12 16:40:32 +08005549 GST_WARNING_OBJECT (obj->dbg_obj, "unhandled mode");
5550 break;
5551 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005552
bo.xiao857b8682024-09-12 16:40:32 +08005553 if (size == 0)
5554 goto no_size;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005555
bo.xiao857b8682024-09-12 16:40:32 +08005556 /* If pushing from our own pool, configure it with queried minimum,
5557 * otherwise use the minimum required */
5558 if (pushing_from_our_pool)
5559 {
5560 /* When pushing from our own pool, we need what downstream one, to be able
5561 * to fill the pipeline, the minimum required to decoder according to the
5562 * driver and 2 more, so we don't endup up with everything downstream or
5563 * held by the decoder. We account 2 buffers for v4l2 so when one is being
5564 * pushed downstream the other one can already be queued for the next
5565 * frame. */
5566 own_min = min + obj->min_buffers + 2;
5567
5568 /* If no allocation parameters where provided, allow for a little more
5569 * buffers and enable copy threshold */
5570 if (!update)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005571 {
bo.xiao857b8682024-09-12 16:40:32 +08005572 own_min += 2;
5573 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5574 TRUE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005575 }
5576 else
5577 {
bo.xiao857b8682024-09-12 16:40:32 +08005578 gst_aml_v4l2_buffer_pool_copy_at_threshold (GST_AML_V4L2_BUFFER_POOL (pool),
5579 FALSE);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005580 }
5581
bo.xiao857b8682024-09-12 16:40:32 +08005582 }
5583 else
5584 {
5585 min = obj->min_buffers;
5586 max = min;
5587 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005588
bo.xiao857b8682024-09-12 16:40:32 +08005589 /* Request a bigger max, if one was suggested but it's too small */
5590 if (max != 0)
5591 max = MAX (min, max);
5592
5593 /* First step, configure our own pool */
5594 config = gst_buffer_pool_get_config(obj->pool);
5595
5596 if (obj->need_video_meta || has_video_meta)
5597 {
5598 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5599 gst_buffer_pool_config_add_option (config,
5600 GST_BUFFER_POOL_OPTION_VIDEO_META);
5601 }
5602
5603 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5604 gst_buffer_pool_config_set_params(config, caps, size, min, max);
5605
5606 GST_DEBUG_OBJECT (obj->dbg_obj, "setting own pool config to %"
5607 GST_PTR_FORMAT, config);
5608
5609 /* Our pool often need to adjust the value */
5610 if (!gst_buffer_pool_set_config (obj->pool, config))
5611 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005612 config = gst_buffer_pool_get_config(obj->pool);
5613
bo.xiao857b8682024-09-12 16:40:32 +08005614 GST_DEBUG_OBJECT (obj->dbg_obj, "own pool config changed to %"
5615 GST_PTR_FORMAT, config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005616
bo.xiao857b8682024-09-12 16:40:32 +08005617 /* our pool will adjust the maximum buffer, which we are fine with */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005618 if (!gst_buffer_pool_set_config(obj->pool, config))
bo.xiao857b8682024-09-12 16:40:32 +08005619 goto config_failed;
5620 }
5621
5622 /* Now configure the other pool if different */
5623 if (obj->pool != pool)
5624 other_pool = pool;
5625
5626 if (other_pool)
5627 {
5628 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)obj->element;
5629 guint other_min = min;
5630 guint other_max = max;
5631
5632 if (obj->old_other_pool || obj->old_old_other_pool) //jxsdbg for switching
5633 {
5634 obj->outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
5635 if (obj->outstanding_buf_num > 0) {
5636 if (obj->outstanding_buf_num >= obj->min_buffers)
5637 {
5638 other_min = 1;
5639 }
5640 else
5641 {
5642 other_min = other_max = obj->min_buffers - obj->outstanding_buf_num;
5643 }
5644 }
5645 GST_DEBUG_OBJECT(obj, "oop:%p, ooop:%p, outstanding buf num:%d, set min, max to %d,%d",
5646 obj->old_other_pool, obj->old_old_other_pool,
5647 obj->outstanding_buf_num, other_min, other_max);
5648 }
5649
5650 if (self->is_secure_path)
5651 {
5652 params.flags |= GST_MEMORY_FLAG_LAST << 1; // in drmallocator GST_MEMORY_FLAG_LAST << 1 represent GST_MEMORY_FLAG_SECURE
5653 GST_DEBUG_OBJECT(obj, "set secure flag for drmbufferpool flag:0x%x", params.flags);
5654 }
5655 config = gst_buffer_pool_get_config (other_pool);
5656 gst_buffer_pool_config_set_allocator (config, allocator, &params);
5657 gst_buffer_pool_config_set_params (config, caps, size, other_min, other_max);
5658 gst_buffer_pool_config_set_video_alignment(config, &obj->align);
5659
5660 GST_DEBUG_OBJECT (obj->dbg_obj, "setting other pool config to %"
5661 GST_PTR_FORMAT, config);
5662
5663 /* if downstream supports video metadata, add this to the pool config */
5664 if (has_video_meta)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005665 {
bo.xiao857b8682024-09-12 16:40:32 +08005666 GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
5667 gst_buffer_pool_config_add_option (config,
5668 GST_BUFFER_POOL_OPTION_VIDEO_META);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005669 }
5670
bo.xiao857b8682024-09-12 16:40:32 +08005671 if (!gst_buffer_pool_set_config (other_pool, config))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005672 {
bo.xiao857b8682024-09-12 16:40:32 +08005673 config = gst_buffer_pool_get_config (other_pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005674
bo.xiao857b8682024-09-12 16:40:32 +08005675 if (!gst_buffer_pool_config_validate_params (config, caps, size, min,
5676 max))
5677 {
5678 gst_structure_free (config);
5679 goto config_failed;
5680 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08005681
bo.xiao857b8682024-09-12 16:40:32 +08005682 if (!gst_buffer_pool_set_config (other_pool, config))
5683 goto config_failed;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005684 }
bo.xiao857b8682024-09-12 16:40:32 +08005685 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005686
bo.xiao857b8682024-09-12 16:40:32 +08005687 if (pool)
5688 {
5689 /* For simplicity, simply read back the active configuration, so our base
5690 * class get the right information */
5691 config = gst_buffer_pool_get_config (pool);
5692 gst_buffer_pool_config_get_params (config, NULL, &size, &min, &max);
5693 gst_structure_free (config);
5694 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005695
bo.xiao857b8682024-09-12 16:40:32 +08005696 if (update)
5697 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
5698 else
5699 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005700
bo.xiao857b8682024-09-12 16:40:32 +08005701 if (allocator)
5702 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005703
bo.xiao857b8682024-09-12 16:40:32 +08005704 if (pool)
5705 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005706
bo.xiao857b8682024-09-12 16:40:32 +08005707 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005708
5709pool_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005710 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005711 /* setup_pool already send the error */
5712 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005713 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005714config_failed:
bo.xiao857b8682024-09-12 16:40:32 +08005715 {
5716 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5717 (_("Failed to configure internal buffer pool.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005718 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005719 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005720no_size:
bo.xiao857b8682024-09-12 16:40:32 +08005721 {
5722 GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
5723 (_("Video device did not suggest any buffer size.")), (NULL));
xuesong.jiangae1548e2022-05-06 16:38:46 +08005724 goto cleanup;
bo.xiao857b8682024-09-12 16:40:32 +08005725 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005726cleanup:
bo.xiao857b8682024-09-12 16:40:32 +08005727 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005728 if (allocator)
bo.xiao857b8682024-09-12 16:40:32 +08005729 gst_object_unref (allocator);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005730
5731 if (pool)
bo.xiao857b8682024-09-12 16:40:32 +08005732 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005733 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005734 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005735no_downstream_pool:
bo.xiao857b8682024-09-12 16:40:32 +08005736 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005737 GST_ELEMENT_ERROR(obj->element, RESOURCE, SETTINGS,
5738 (_("No downstream pool to import from.")),
5739 ("When importing DMABUF or USERPTR, we need a pool to import from"));
5740 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005741 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005742}
5743
5744gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005745gst_aml_v4l2_object_propose_allocation (GstAmlV4l2Object * obj, GstQuery * query)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005746{
bo.xiao857b8682024-09-12 16:40:32 +08005747 GstBufferPool *pool = NULL;
5748 /* we need at least 2 buffers to operate */
5749 guint size, min, max;
5750 GstCaps *caps;
5751 gboolean need_pool;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005752
bo.xiao857b8682024-09-12 16:40:32 +08005753 /* Set defaults allocation parameters */
5754 size = obj->info.size;
5755 min = GST_AML_V4L2_MIN_BUFFERS;
5756 max = VIDEO_MAX_FRAME;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005757
bo.xiao857b8682024-09-12 16:40:32 +08005758 gst_query_parse_allocation (query, &caps, &need_pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005759
bo.xiao857b8682024-09-12 16:40:32 +08005760 if (caps == NULL)
5761 goto no_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005762
bo.xiao857b8682024-09-12 16:40:32 +08005763 switch (obj->mode)
5764 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005765 case GST_V4L2_IO_MMAP:
5766 case GST_V4L2_IO_DMABUF:
bo.xiao857b8682024-09-12 16:40:32 +08005767 if ((pool = obj->pool))
5768 gst_object_ref(pool);
5769 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005770 default:
bo.xiao857b8682024-09-12 16:40:32 +08005771 pool = NULL;
5772 break;
5773 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005774
bo.xiao857b8682024-09-12 16:40:32 +08005775 if (pool != NULL)
5776 {
5777 GstCaps *pcaps;
5778 GstStructure *config;
5779
5780 /* we had a pool, check caps */
5781 config = gst_buffer_pool_get_config (pool);
5782 gst_buffer_pool_config_get_params (config, &pcaps, NULL, NULL, NULL);
5783
5784 GST_DEBUG_OBJECT (obj->dbg_obj,
5785 "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
5786 if (!gst_caps_is_equal (caps, pcaps))
xuesong.jiangae1548e2022-05-06 16:38:46 +08005787 {
bo.xiao857b8682024-09-12 16:40:32 +08005788 gst_structure_free (config);
5789 gst_object_unref (pool);
5790 goto different_caps;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005791 }
bo.xiao857b8682024-09-12 16:40:32 +08005792 gst_structure_free (config);
5793 }
5794 gst_aml_v4l2_get_driver_min_buffers (obj);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005795
bo.xiao857b8682024-09-12 16:40:32 +08005796 min = MAX(obj->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005797
bo.xiao857b8682024-09-12 16:40:32 +08005798 gst_query_add_allocation_pool (query, pool, size, min, max);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005799
bo.xiao857b8682024-09-12 16:40:32 +08005800 /* we also support various metadata */
5801 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005802
bo.xiao857b8682024-09-12 16:40:32 +08005803 if (pool)
5804 gst_object_unref (pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005805
bo.xiao857b8682024-09-12 16:40:32 +08005806 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005807
bo.xiao857b8682024-09-12 16:40:32 +08005808 /* ERRORS */
xuesong.jiangae1548e2022-05-06 16:38:46 +08005809no_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005810 {
5811 GST_DEBUG_OBJECT (obj->dbg_obj, "no caps specified");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005812 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005813 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005814different_caps:
bo.xiao857b8682024-09-12 16:40:32 +08005815 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005816 /* different caps, we can't use this pool */
bo.xiao857b8682024-09-12 16:40:32 +08005817 GST_DEBUG_OBJECT (obj->dbg_obj, "pool has different caps");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005818 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005819 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005820}
5821
5822gboolean
bo.xiao857b8682024-09-12 16:40:32 +08005823gst_aml_v4l2_object_try_import (GstAmlV4l2Object * obj, GstBuffer * buffer)
xuesong.jiangae1548e2022-05-06 16:38:46 +08005824{
bo.xiao857b8682024-09-12 16:40:32 +08005825 GstVideoMeta *vmeta;
5826 guint n_mem = gst_buffer_n_memory (buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08005827
bo.xiao857b8682024-09-12 16:40:32 +08005828 /* only import if requested */
5829 switch (obj->mode)
5830 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08005831 case GST_V4L2_IO_USERPTR:
5832 case GST_V4L2_IO_DMABUF_IMPORT:
bo.xiao857b8682024-09-12 16:40:32 +08005833 break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005834 default:
bo.xiao857b8682024-09-12 16:40:32 +08005835 GST_DEBUG_OBJECT (obj->dbg_obj,
5836 "The io-mode does not enable importation");
5837 return FALSE;
5838 }
5839
5840 vmeta = gst_buffer_get_video_meta (buffer);
5841 if (!vmeta && obj->need_video_meta)
5842 {
5843 GST_DEBUG_OBJECT (obj->dbg_obj, "Downstream buffer uses standard "
5844 "stride/offset while the driver does not.");
5845 return FALSE;
5846 }
5847
5848 /* we need matching strides/offsets and size */
5849 if (vmeta)
5850 {
5851 guint p;
5852 gboolean need_fmt_update = FALSE;
5853
5854 if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES(&obj->info))
5855 {
5856 GST_WARNING_OBJECT(obj->dbg_obj,
5857 "Cannot import buffers with different number planes");
5858 return FALSE;
5859 }
5860
5861 for (p = 0; p < vmeta->n_planes; p++)
5862 {
5863 if (vmeta->stride[p] < obj->info.stride[p])
5864 {
5865 GST_DEBUG_OBJECT(obj->dbg_obj,
5866 "Not importing as remote stride %i is smaller then %i on plane %u",
5867 vmeta->stride[p], obj->info.stride[p], p);
5868 return FALSE;
5869 }
5870 else if (vmeta->stride[p] > obj->info.stride[p])
5871 {
5872 need_fmt_update = TRUE;
5873 }
5874
5875 if (vmeta->offset[p] < obj->info.offset[p])
5876 {
5877 GST_DEBUG_OBJECT(obj->dbg_obj,
5878 "Not importing as offset %" G_GSIZE_FORMAT
5879 " is smaller then %" G_GSIZE_FORMAT " on plane %u",
5880 vmeta->offset[p], obj->info.offset[p], p);
5881 return FALSE;
5882 }
5883 else if (vmeta->offset[p] > obj->info.offset[p])
5884 {
5885 need_fmt_update = TRUE;
5886 }
5887 }
5888
5889 if (need_fmt_update)
5890 {
5891 struct v4l2_format format;
5892 gint wanted_stride[GST_VIDEO_MAX_PLANES] = {
5893 0,
5894 };
5895
5896 format = obj->format;
5897
5898 /* update the current format with the stride we want to import from */
5899 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5900 {
5901 guint i;
5902
5903 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted strides:");
5904
5905 for (i = 0; i < obj->n_v4l2_planes; i++)
5906 {
5907 gint stride = vmeta->stride[i];
5908
5909 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5910 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5911
5912 format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
5913 wanted_stride[i] = stride;
5914 GST_DEBUG_OBJECT(obj->dbg_obj, " [%u] %i", i, wanted_stride[i]);
5915 }
5916 }
5917 else
5918 {
5919 gint stride = vmeta->stride[0];
5920
5921 GST_DEBUG_OBJECT(obj->dbg_obj, "Wanted stride: %i", stride);
5922
5923 if (GST_VIDEO_FORMAT_INFO_IS_TILED(obj->info.finfo))
5924 stride = GST_VIDEO_TILE_X_TILES(stride) << GST_VIDEO_FORMAT_INFO_TILE_WS(obj->info.finfo);
5925
5926 format.fmt.pix.bytesperline = stride;
5927 wanted_stride[0] = stride;
5928 }
5929
5930 if (obj->ioctl(obj->video_fd, VIDIOC_S_FMT, &format) < 0)
5931 {
5932 GST_WARNING_OBJECT(obj->dbg_obj,
5933 "Something went wrong trying to update current format: %s",
5934 g_strerror(errno));
5935 return FALSE;
5936 }
5937
5938 gst_aml_v4l2_object_save_format(obj, obj->fmtdesc, &format, &obj->info,
5939 &obj->align);
5940
5941 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
5942 {
5943 guint i;
5944
5945 for (i = 0; i < obj->n_v4l2_planes; i++)
5946 {
5947 if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i])
5948 {
5949 GST_DEBUG_OBJECT(obj->dbg_obj,
5950 "[%i] Driver did not accept the new stride (wants %i, got %i)",
5951 i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
5952 wanted_stride[i]);
5953 return FALSE;
5954 }
5955 }
5956 }
5957 else
5958 {
5959 if (format.fmt.pix.bytesperline != wanted_stride[0])
5960 {
5961 GST_DEBUG_OBJECT(obj->dbg_obj,
5962 "Driver did not accept the new stride (wants %i, got %i)",
5963 format.fmt.pix.bytesperline, wanted_stride[0]);
5964 return FALSE;
5965 }
5966 }
5967 }
5968 }
5969
5970 /* we can always import single memory buffer, but otherwise we need the same
5971 * amount of memory object. */
5972 if (n_mem != 1 && n_mem != obj->n_v4l2_planes)
5973 {
5974 GST_DEBUG_OBJECT (obj->dbg_obj, "Can only import %i memory, "
5975 "buffers contains %u memory", obj->n_v4l2_planes, n_mem);
5976 return FALSE;
5977 }
5978
5979 /* For DMABuf importation we need DMABuf of course */
5980 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
5981 {
5982 guint i;
5983
5984 for (i = 0; i < n_mem; i++)
5985 {
5986 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
5987
5988 if (!gst_is_dmabuf_memory (mem))
5989 {
5990 GST_DEBUG_OBJECT (obj->dbg_obj, "Cannot import non-DMABuf memory.");
xuesong.jiangae1548e2022-05-06 16:38:46 +08005991 return FALSE;
bo.xiao857b8682024-09-12 16:40:32 +08005992 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005993 }
bo.xiao857b8682024-09-12 16:40:32 +08005994 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08005995
bo.xiao857b8682024-09-12 16:40:32 +08005996 /* for the remaining, only the kernel driver can tell */
5997 return TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08005998}
5999
xuesong.jiang22a9b112023-05-24 09:01:59 +00006000static gboolean gst_aml_v4l2_set_control(GstAmlV4l2Object *v4l2object, guint ctl)
6001{
bo.xiao857b8682024-09-12 16:40:32 +08006002 int rc;
6003 struct v4l2_queryctrl queryctrl;
6004 struct v4l2_control control;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006005
bo.xiao857b8682024-09-12 16:40:32 +08006006 memset(&queryctrl, 0, sizeof(queryctrl));
6007 queryctrl.id = ctl;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006008
bo.xiao857b8682024-09-12 16:40:32 +08006009 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_QUERYCTRL, &queryctrl);
6010 if (rc == 0)
6011 {
6012 if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
6013 {
6014 memset(&control, 0, sizeof(control));
6015 control.id = ctl;
6016 control.value = 1;
6017 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6018 if (rc != 0)
6019 {
6020 GST_ERROR_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x fail rc %d", ctl, rc);
6021 return FALSE;
6022 }
6023 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "set ctl:0x%x succ", ctl);
6024 return TRUE;
6025 }
6026 else
6027 {
6028 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "ctl:0x%x is disabled", ctl);
6029 return TRUE;
6030 }
6031 }
6032 else
6033 {
6034 GST_ERROR_OBJECT(v4l2object->dbg_obj, "VIDIOC_QUERYCTRL for 0x:%x fail", ctl);
6035 return FALSE;
6036 }
xuesong.jiang22a9b112023-05-24 09:01:59 +00006037}
6038
hanghang.luo7f403102024-07-04 10:33:01 +08006039gboolean gst_aml_v4l2_set_I_frame_mode(GstAmlV4l2Object *v4l2object)
6040{
bo.xiao857b8682024-09-12 16:40:32 +08006041 if (v4l2object->iframe_mode)
6042 {
6043 int rc;
6044 struct v4l2_control control;
6045 memset(&control, 0, sizeof(control));
6046 control.id = AML_V4L2_SET_I_FRAME;
6047 control.value = 1;
6048 rc = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_CTRL, &control);
6049 if (rc != 0)
6050 {
6051 GST_ERROR_OBJECT(v4l2object->dbg_obj, "rc: %d", rc);
6052 return FALSE;
6053 }
6054 }
6055 GST_DEBUG("set I frame ok");
6056 return TRUE;
hanghang.luo7f403102024-07-04 10:33:01 +08006057}
xuesong.jiang22a9b112023-05-24 09:01:59 +00006058
xuesong.jiangae1548e2022-05-06 16:38:46 +08006059gboolean gst_aml_v4l2_set_drm_mode(GstAmlV4l2Object *v4l2object)
6060{
bo.xiao857b8682024-09-12 16:40:32 +08006061 /* On AmLogic, output obj use of GST_V4L2_IO_DMABUF_IMPORT implies secure memory */
6062 if (v4l2object->req_mode == GST_V4L2_IO_DMABUF_IMPORT && v4l2object->secure_es)
6063 {
6064 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)v4l2object->element;
6065 self->is_secure_path = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006066
bo.xiao857b8682024-09-12 16:40:32 +08006067 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_DRMMODE))
6068 {
6069 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set succ");
6070 return TRUE;
6071 }
6072 else
6073 {
6074 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_DRMMODE set fail");
6075 return FALSE;
6076 }
6077 }
6078 return TRUE;
xuesong.jiang22a9b112023-05-24 09:01:59 +00006079}
6080
6081gboolean gst_aml_v4l2_set_stream_mode(GstAmlV4l2Object *v4l2object)
6082{
bo.xiao857b8682024-09-12 16:40:32 +08006083 if (v4l2object->stream_mode)
6084 {
6085 if (gst_aml_v4l2_set_control(v4l2object, AML_V4L2_SET_STREAM_MODE))
6086 {
6087 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set succ");
6088 return TRUE;
6089 }
6090 else
6091 {
6092 GST_ERROR_OBJECT(v4l2object->dbg_obj, "AML_V4L2_SET_STREAM_MODE set fail");
6093 return FALSE;
6094 }
6095 }
6096 else
6097 {
6098 GST_DEBUG_OBJECT(v4l2object->dbg_obj, "req mode is not stream mode, frame mode in configured by default");
6099 return TRUE;
6100 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006101}
6102
6103gint gst_aml_v4l2_object_get_outstanding_capture_buf_num(GstAmlV4l2Object *obj)
6104{
bo.xiao857b8682024-09-12 16:40:32 +08006105 gint ret = 0;
6106 gint count = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006107
bo.xiao857b8682024-09-12 16:40:32 +08006108 if (obj->old_other_pool)
6109 {
6110 count = gst_buffer_pool_get_outstanding_num(obj->old_other_pool);
6111 if (count)
6112 {
6113 ret += count;
6114 }
6115 else
6116 {
6117 gst_object_unref(obj->old_other_pool);
6118 obj->old_other_pool = NULL;
6119 }
6120 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006121
bo.xiao857b8682024-09-12 16:40:32 +08006122 count = 0;
6123 if (obj->old_old_other_pool)
6124 {
6125 count = gst_buffer_pool_get_outstanding_num(obj->old_old_other_pool);
6126 if (count)
6127 {
6128 ret += count;
6129 }
6130 else
6131 {
6132 gst_object_unref(obj->old_old_other_pool);
6133 obj->old_old_other_pool = NULL;
6134 }
6135 }
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08006136
bo.xiao857b8682024-09-12 16:40:32 +08006137 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08006138}