Files
svcmobrel-release 3f221c626f Updating prebuilts and/or headers
44b0e909f18f7e2f457ba501fc47d80ecedd150b - nvbufsurface.h
2c5c20979e5fca5ed70b425187c3d09b39c03171 - v4l2_nv_extensions.h
d27a433ddeaefb9f42d0312c23472514b0cd6a45 - gst-nvcustomevent.h
e9519308cbf7b36481da7665e3b74d36569cc3d1 - gst-v4l2/gstv4l2.c
ba87c2bc0bea986ef461e1bc2ab3ded89700a986 - gst-v4l2/gstv4l2h264enc.c
93eaaa0797c1f1dc21c20fbad1885dc109ccffd3 - gst-v4l2/gstv4l2bufferpool.c
9ff38f38c224577c4aaadc4ac4d808429f37ca69 - gst-v4l2/gstv4l2allocator.c
3d06f0b9ae8e465e8aecd7ef101e652ff62268c4 - gst-v4l2/Makefile
02d142337f4b96fcb0c9f2405a3cbe90c5917cca - gst-v4l2/gstv4l2vp9enc.c
34adbcb7d5cf5a360d28432429b735710bfe49c5 - gst-v4l2/wsl_utils.h
afc982d855f80b1e21ce1831930a9f327c41832b - gst-v4l2/gstv4l2h265enc.c
55a2c81ab3ffd72e07fc680369683d9635a3665c - gst-v4l2/gstv4l2h265enc.h
c81eacb7d88c4fb839506dd70055e30d7a9feeec - gst-v4l2/v4l2-utils.h
b1cd923335aa60985ff9866fba91a2068e8671c7 - gst-v4l2/LICENSE.gst-nvvideo4linux2
aa816d369be13e7cb2f6f5283c74bb00f7f1c76e - gst-v4l2/v4l2_calls.c
d89a680415f6ff5acec2571cde0fce9054d8e81f - gst-v4l2/gstv4l2vp9enc.h
da6c40e84b3b99e443b76c72cbb433541bdc9bcf - gst-v4l2/gstv4l2videodec.c
0d69b17838c57184dace9bfa1d30bbe8f2f83848 - gst-v4l2/gstv4l2object.h
c3ac3836a2d29d813c3c274cde82d2a59dd45a5a - gst-v4l2/gstv4l2videodec.h
4b70823ac5f9a70cce0c909e284c73aed4bccbd6 - gst-v4l2/gstv4l2h26xparser.c
39fcb2f599e6906ab0fd7ab9a46fef3ea58a8cab - gst-v4l2/gstv4l2vp8enc.h
08d68910b07d04e1429763ad1e6dbbeb41c5277d - gst-v4l2/gstv4l2av1enc.h
a002edef13a3bbbdc41e42a7fca40e574ad1bb3e - gst-v4l2/v4l2-utils.c
870a72e5038dba9f4df37f900d53a059beee9bbc - gst-v4l2/gstv4l2h26xparser.h
fac36b61500cf8d1b5f2513d6d2319ef73aa870e - gst-v4l2/sei_parse.c
b827fd6cb1e3b8ecebd6a07f8556e846e26cba17 - gst-v4l2/gstv4l2allocator.h
e18e54d84e643676bfc88fd559d834f26f5b4d4d - gst-v4l2/wsl_utils.c
d0af17fd51ec44b79ef54c1279b631a46cf31f49 - gst-v4l2/gstv4l2videoenc.h
4e79cf75c4fa29791e1f5141318dc8aec13a7835 - gst-v4l2/nalutils.h
add535643bbb5c58b7eb98b45496204e4d63ebb1 - gst-v4l2/gstv4l2bufferpool.h
5ecd059e5ef9be4014eface37e5e2f7598960f4e - gst-v4l2/nalutils.c
719c8569e894b0146a6e027550187df5aaf5adc1 - gst-v4l2/gstv4l2av1enc.c
bb104683f5e4f7402e3f765a891e149edc794e02 - gst-v4l2/gstv4l2h264enc.h
eb5134c907dd4b25097491e4273591db6ac386fc - gst-v4l2/gstv4l2videoenc.c
807bc9859585a540b0f85e98f147756aab24e1bd - gst-v4l2/gstv4l2vp8enc.c
9c3d135576125a6620cc8fa0b249ac73c070110b - gst-v4l2/gstv4l2object.c
20c4f7c0cb89c83256650bc3353ed82154cf3a9d - gst-v4l2/gst/gst-i18n-plugin.h
e864ee6647f3572b144403d799f68152e9900da1 - gst-v4l2/gst/gettext.h
499a9feb17ceabf1f1443923dffa1e0180bf5972 - gst-v4l2/gst/glib-compat-private.h
72a34a694337f8f6da3bb94c9faced6730cbd2fc - gst-v4l2/ext/types-compat.h
583075e89482f1faa08be7f7b278336bf7756def - gst-v4l2/ext/v4l2-controls.h
fe847595bb202501a56702a7c602f0514d23c328 - gst-v4l2/ext/v4l2-common.h
2253e5f55e37aace35af706d5662ef017f17e877 - gst-v4l2/ext/videodev2.h

Change-Id: I434c689e81fa8bc261202840a7a285a3c08d4f94
2025-08-25 10:23:32 -07:00

505 lines
14 KiB
C

/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@gmail.com>
* SPDX-FileCopyrightText: Copyright (c) 2018-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* gstv4l2.c: plugin for v4l2 elements
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef _GNU_SOURCE
# define _GNU_SOURCE /* O_CLOEXEC */
#endif
#include "gst/gst-i18n-plugin.h"
#include <gst/gst.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "linux/videodev2.h"
#include "v4l2-utils.h"
#include "gstv4l2object.h"
#ifndef USE_V4L2_TARGET_NV
#include "gstv4l2src.h"
#include "gstv4l2sink.h"
#include "gstv4l2radio.h"
#include "gstv4l2h263enc.h"
#include "gstv4l2mpeg4enc.h"
#include "gstv4l2deviceprovider.h"
#include "gstv4l2transform.h"
#endif
#include "gstv4l2videodec.h"
#include "gstv4l2h264enc.h"
#include "gstv4l2h265enc.h"
#include "gstv4l2vp8enc.h"
#include "gstv4l2vp9enc.h"
#include "gstv4l2av1enc.h"
/* used in gstv4l2object.c and v4l2_calls.c */
GST_DEBUG_CATEGORY (v4l2_debug);
#define GST_CAT_DEFAULT v4l2_debug
#ifndef USE_V4L2_TARGET_NV_X86
gboolean is_cuvid;
#else
gboolean is_cuvid = TRUE;
#endif
#ifdef GST_V4L2_ENABLE_PROBE
/* This is a minimalist probe, for speed, we only enumerate formats */
static GstCaps *
gst_v4l2_probe_template_caps (const gchar * device, gint video_fd,
enum v4l2_buf_type type)
{
gint n;
struct v4l2_fmtdesc format;
GstCaps *caps;
GST_DEBUG ("Getting %s format enumerations", device);
caps = gst_caps_new_empty ();
for (n = 0;; n++) {
GstStructure *template;
memset (&format, 0, sizeof (format));
format.index = n;
format.type = type;
if (ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
break; /* end of enumeration */
GST_LOG ("index: %u", format.index);
GST_LOG ("type: %d", format.type);
GST_LOG ("flags: %08x", format.flags);
GST_LOG ("description: '%s'", format.description);
GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format.pixelformat));
template = gst_v4l2_object_v4l2fourcc_to_structure (format.pixelformat);
if (template) {
GstStructure *alt_t = NULL;
switch (format.pixelformat) {
case V4L2_PIX_FMT_RGB32:
alt_t = gst_structure_copy (template);
gst_structure_set (alt_t, "format", G_TYPE_STRING, "ARGB", NULL);
break;
case V4L2_PIX_FMT_BGR32:
alt_t = gst_structure_copy (template);
gst_structure_set (alt_t, "format", G_TYPE_STRING, "BGRA", NULL);
default:
break;
}
gst_caps_append_structure (caps, template);
if (alt_t)
gst_caps_append_structure (caps, alt_t);
}
}
return gst_caps_simplify (caps);
}
static gboolean
gst_v4l2_probe_and_register (GstPlugin * plugin)
{
GstV4l2Iterator *it;
gint video_fd = -1;
struct v4l2_capability vcap;
guint32 device_caps;
it = gst_v4l2_iterator_new ();
while (gst_v4l2_iterator_next (it)) {
GstCaps *src_caps, *sink_caps;
gchar *basename;
if (video_fd >= 0)
close (video_fd);
video_fd = open (it->device_path, O_RDWR | O_CLOEXEC);
if (video_fd == -1) {
GST_DEBUG ("Failed to open %s: %s", it->device_path, g_strerror (errno));
continue;
}
memset (&vcap, 0, sizeof (vcap));
if (ioctl (video_fd, VIDIOC_QUERYCAP, &vcap) < 0) {
GST_DEBUG ("Failed to get device capabilities: %s", g_strerror (errno));
continue;
}
if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
device_caps = vcap.device_caps;
else
device_caps = vcap.capabilities;
if (!((device_caps & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE)) ||
/* But legacy driver may expose both CAPTURE and OUTPUT */
((device_caps &
(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
(device_caps &
(V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
continue;
GST_DEBUG ("Probing '%s' located at '%s'",
it->device_name ? it->device_name : (const gchar *) vcap.driver,
it->device_path);
/* get sink supported format (no MPLANE for codec) */
sink_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT),
gst_v4l2_probe_template_caps (it->device_path, video_fd,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE));
/* get src supported format */
src_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE),
gst_v4l2_probe_template_caps (it->device_path, video_fd,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE));
/* Skip devices without any supported formats */
if (gst_caps_is_empty (sink_caps) || gst_caps_is_empty (src_caps)) {
gst_caps_unref (sink_caps);
gst_caps_unref (src_caps);
continue;
}
basename = g_path_get_basename (it->device_path);
if (gst_v4l2_is_video_dec (sink_caps, src_caps)) {
gst_v4l2_video_dec_register (plugin, basename, it->device_path,
sink_caps, src_caps);
} else if (gst_v4l2_is_video_enc (sink_caps, src_caps, NULL)) {
if (gst_v4l2_is_h264_enc (sink_caps, src_caps))
gst_v4l2_h264_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
if (gst_v4l2_is_mpeg4_enc (sink_caps, src_caps))
gst_v4l2_mpeg4_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
if (gst_v4l2_is_h263_enc (sink_caps, src_caps))
gst_v4l2_h263_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
if (gst_v4l2_is_vp8_enc (sink_caps, src_caps))
gst_v4l2_vp8_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
if (gst_v4l2_is_vp9_enc (sink_caps, src_caps))
gst_v4l2_vp9_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
if (gst_v4l2_is_av1_enc (sink_caps, src_caps))
gst_v4l2_av1_enc_register (plugin, basename, it->device_path,
sink_caps, src_caps);
} else if (gst_v4l2_is_transform (sink_caps, src_caps)) {
gst_v4l2_transform_register (plugin, basename, it->device_path,
sink_caps, src_caps);
}
/* else if ( ... etc. */
gst_caps_unref (sink_caps);
gst_caps_unref (src_caps);
g_free (basename);
}
if (video_fd >= 0)
close (video_fd);
gst_v4l2_iterator_free (it);
return TRUE;
}
#endif
#ifndef USE_V4L2_TARGET_NV
static gboolean
plugin_init (GstPlugin * plugin)
{
const gchar *paths[] = { "/dev", "/dev/v4l2", NULL };
const gchar *names[] = { "video", NULL };
GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
/* Add some depedency, so the dynamic features get updated upon changes in
* /dev/video* */
gst_plugin_add_dependency (plugin,
NULL, paths, names, GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
if (!gst_element_register (plugin, "v4l2src", GST_RANK_PRIMARY,
GST_TYPE_V4L2SRC) ||
!gst_element_register (plugin, "v4l2sink", GST_RANK_NONE,
GST_TYPE_V4L2SINK) ||
!gst_element_register (plugin, "v4l2radio", GST_RANK_NONE,
GST_TYPE_V4L2RADIO) ||
!gst_device_provider_register (plugin, "v4l2deviceprovider",
GST_RANK_PRIMARY, GST_TYPE_V4L2_DEVICE_PROVIDER)
/* etc. */
#ifdef GST_V4L2_ENABLE_PROBE
|| !gst_v4l2_probe_and_register (plugin)
#endif
)
return FALSE;
#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif /* ENABLE_NLS */
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
video4linux2,
"elements for Video 4 Linux",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
#else
static gboolean
gst_v4l2_has_vp8_encoder(void)
{
gboolean ret = FALSE;
int fd = -1, rval = 0;
long len = -1;
struct stat statbuf;
char info[128];
fd = open(V4L2_DEVICE_PATH_TEGRA_INFO, O_RDONLY);
if (fd < 0)
return ret;
rval = stat(V4L2_DEVICE_PATH_TEGRA_INFO, &statbuf);
if (rval < 0)
{
close(fd);
return ret;
}
if (statbuf.st_size > 8 && statbuf.st_size < 128)
{
rval = read(fd, info, statbuf.st_size);
if (rval <= 0)
{
close(fd);
return ret;
}
len = statbuf.st_size - 8;
for (int i = 0; i < len; i ++)
{
if (strncmp(&info[i], "tegra", 5) == 0)
{
if (strncmp(&info[i], "tegra186", 8) == 0 ||
strncmp(&info[i], "tegra210", 8) == 0)
ret = TRUE;
break;
}
}
}
close(fd);
return ret;
}
static gboolean
gst_v4l2_is_v4l2_nvenc_present(void)
{
gboolean ret = TRUE;
int fd = -1;
struct stat statbuf;
char info[128];
if (access(V4L2_DEVICE_INFO_SOM_EEPROM, F_OK) == 0)
{
stat(V4L2_DEVICE_INFO_SOM_EEPROM, &statbuf);
if (statbuf.st_size > 0 && statbuf.st_size < 128)
{
fd = open(V4L2_DEVICE_INFO_SOM_EEPROM, O_RDONLY);
read(fd, info, statbuf.st_size);
for (int i = 0; i <= (statbuf.st_size - 9); i++)
{
if (strncmp(&info[i], "3767", 4) == 0)
{
/*
* Jetson Orin Nano 8GB (P3767-0003) Commercial module
* Jetson Orin Nano 4GB (P3767-0004) Commercial module
* Jetson Orin Nano 8GB with SD card slot (P3767-0005) For the Developer Kit only
*/
if (strncmp(&info[i + 5], "0003", 4) == 0 ||
strncmp(&info[i + 5], "0004", 4) == 0 ||
strncmp(&info[i + 5], "0005", 4) == 0)
{
ret = FALSE;
break;
}
}
}
close(fd);
}
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret = TRUE;
g_setenv ("GST_V4L2_USE_LIBV4L2", "1", FALSE);
GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
#ifndef USE_V4L2_TARGET_NV_X86
int result = -1;
result = (gboolean)system("lsmod | grep 'nvgpu' > /dev/null");
if (result == 0)
is_cuvid = FALSE;
else
is_cuvid = TRUE;
if (getenv("AARCH64_DGPU"))
is_cuvid = TRUE;
else if (getenv("AARCH64_IGPU"))
is_cuvid = FALSE;
#endif
if (is_cuvid == TRUE)
gst_v4l2_video_dec_register (plugin,
V4L2_DEVICE_BASENAME_NVDEC,
V4L2_DEVICE_PATH_NVDEC_MCCOY,
NULL,
NULL);
else if (access (V4L2_DEVICE_PATH_NVDEC, F_OK) == 0)
gst_v4l2_video_dec_register (plugin,
V4L2_DEVICE_BASENAME_NVDEC,
V4L2_DEVICE_PATH_NVDEC,
NULL,
NULL);
else
gst_v4l2_video_dec_register (plugin,
V4L2_DEVICE_BASENAME_NVDEC,
V4L2_DEVICE_PATH_NVDEC_ALT,
NULL,
NULL);
if (access (V4L2_DEVICE_PATH_NVENC, F_OK) == 0) {
gst_v4l2_h264_enc_register(plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC,
NULL,
NULL);
gst_v4l2_h265_enc_register(plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC,
NULL,
NULL);
gst_v4l2_av1_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC,
NULL,
NULL);
} else {
if (!gst_v4l2_is_v4l2_nvenc_present()) {
// Orin Nano does not have HW encoders, so early return here.
return ret;
}
gst_v4l2_h264_enc_register(plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC_ALT,
NULL,
NULL);
gst_v4l2_h265_enc_register(plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC_ALT,
NULL,
NULL);
gst_v4l2_av1_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC_ALT,
NULL,
NULL);
}
if (is_cuvid == FALSE) {
if (access (V4L2_DEVICE_PATH_NVENC, F_OK) == 0) {
if (gst_v4l2_has_vp8_encoder()) {
gst_v4l2_vp8_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC,
NULL,
NULL);
}
gst_v4l2_vp9_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC,
NULL,
NULL);
} else {
if (gst_v4l2_has_vp8_encoder()) {
gst_v4l2_vp8_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC_ALT,
NULL,
NULL);
}
gst_v4l2_vp9_enc_register (plugin,
V4L2_DEVICE_BASENAME_NVENC,
V4L2_DEVICE_PATH_NVENC_ALT,
NULL,
NULL);
}
}
return ret;
}
#ifndef PACKAGE
#define PACKAGE "nvvideo4linux2"
#endif
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
nvvideo4linux2,
"Nvidia elements for Video 4 Linux",
plugin_init,
"1.14.0",
"LGPL",
"nvvideo4linux2",
"http://nvidia.com/")
#endif