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
This commit is contained in:
svcmobrel-release
2025-08-25 10:23:32 -07:00
parent 7a8ebb805b
commit 3f221c626f
46 changed files with 33728 additions and 0 deletions

45
commitFile.txt Normal file
View File

@@ -0,0 +1,45 @@
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

235
gst-nvcustomevent.h Normal file
View File

@@ -0,0 +1,235 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file
* <b>NVIDIA GStreamer: Custom Events</b>
*
* @b Description: This file specifies the NVIDIA GStreamer custom
* event functions.
*
*/
/**
* @defgroup gstreamer_nvevent Events: Custom Events API
*
* Specifies GStreamer custom event functions.
*
* @ingroup gst_mess_evnt_qry
* @{
*/
#ifndef __GST_NVCUSTOMEVENT_H__
#define __GST_NVCUSTOMEVENT_H__
#include <gst/gst.h>
#ifdef __cplusplus
extern "C" {
#endif
#define FLAG(name) GST_EVENT_TYPE_##name
/** Defines supported types of custom events. */
typedef enum {
/** Specifies a custom event to indicate decoder drop frame interval update
of a particular stream. */
GST_NVEVENT_DEC_DROP_FRAME_INTERVAL_UPDATE
= GST_EVENT_MAKE_TYPE (500, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to indicate decoder skip frame update
of a particular stream. */
GST_NVEVENT_DEC_SKIP_FRAME_UPDATE
= GST_EVENT_MAKE_TYPE (501, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to enable decoder low-latency-mode
of a particular stream. */
GST_NVEVENT_DEC_ENABLE_LOW_LATENCY_MODE
= GST_EVENT_MAKE_TYPE (502, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to indicate encoder bitrate update
of a particular stream. */
GST_NVEVENT_ENC_BITRATE_UPDATE
= GST_EVENT_MAKE_TYPE (503, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to indicate encoder force IDR frame
of a particular stream. */
GST_NVEVENT_ENC_FORCE_IDR
= GST_EVENT_MAKE_TYPE (504, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to indicate encoder force Intra frame
of a particular stream. */
GST_NVEVENT_ENC_FORCE_INTRA
= GST_EVENT_MAKE_TYPE (505, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/** Specifies a custom event to indicate iframe interval update
of a particular stream. */
GST_NVEVENT_ENC_IFRAME_INTERVAL_UPDATE
= GST_EVENT_MAKE_TYPE (506, FLAG(DOWNSTREAM) | FLAG(SERIALIZED))
} GstNvCustomEventType;
#undef FLAG
/**
* Creates a new "nv-dec-drop-frame-interval-update" event.
*
* @param[out] stream_id Stream ID of the stream for which decoder-drop-frame-interval is to be sent
* @param[out] interval The decoder drop-frame interval obtained corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_dec_drop_frame_interval_update (gchar* stream_id, guint interval);
/**
* Parses a "nv-dec-drop-frame-interval-update" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a dec-drop-frame-interval-update event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] interval A pointer to the parsed interval
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_dec_drop_frame_interval_update (GstEvent * event, gchar** stream_id, guint *interval);
/**
* Creates a new "nv-dec-skip-frame-update" event.
*
* @param[out] stream_id Stream ID of the stream for which decoder-skip-frame-update is to be sent
* @param[out] frame_type The decoder frame-type to be skipped obtained corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_dec_skip_frame_update (gchar* stream_id, guint frame_type);
/**
* Parses a "nv-dec-skip-frame-update" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a skip-frame-update event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] frame_type A pointer to the parsed frame_type
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_dec_skip_frame_update (GstEvent * event, gchar** stream_id, guint *frame_type);
/**
* Creates a new "nv-dec-enable-low-latency-mode" event.
*
* @param[out] stream_id Stream ID of the stream for which decoder-low-latenct-mode is to be sent
* @param[out] enable The decoder low latency mode to be enabled corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_dec_enable_low_latency_mode (gchar* stream_id, gint enable);
/**
* Parses a "nv-dec-enable-low-latency-mode" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a enable-low-latency-mode event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] enable A pointer to the parsed enable flag
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_dec_enable_low_latency_mode (GstEvent * event, gchar** stream_id, gint *enable);
/**
* Creates a new "nv-enc-bitrate-update" event.
*
* @param[out] stream_id Stream ID of the stream for which encoder-bitrate-update is to be sent
* @param[out] bitrate The encoder bitrate to be set corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_enc_bitrate_update (gchar* stream_id, guint bitrate);
/**
* Parses a "nv-enc-bitrate-update" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a bitrate-update event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] bitrate A pointer to the parsed bitrate value
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_enc_bitrate_update (GstEvent * event, gchar** stream_id, guint *bitrate);
/**
* Creates a new "nv-enc-force-idr" event.
*
* @param[out] stream_id Stream ID of the stream for which encoder-force-idr is to be sent
* @param[out] force The encoder force IDR frame corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_enc_force_idr (gchar* stream_id, gint force);
/**
* Parses a "nv-enc-force-idr" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a force-idr event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] force A pointer to the parsed force value
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_enc_force_idr (GstEvent * event, gchar** stream_id, gint *force);
/**
* Creates a new "nv-enc-force-intra" event.
*
* @param[out] stream_id Stream ID of the stream for which encoder-force-intra is to be sent
* @param[out] force The encoder force Intra frame corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_enc_force_intra (gchar* stream_id, gint force);
/**
* Parses a "nv-enc-force-intra" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a force-intra event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] force A pointer to the parsed force value
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_enc_force_intra (GstEvent * event, gchar** stream_id, gint *force);
/**
* Creates a new "nv-enc-iframeinterval-update" event.
*
* @param[out] stream_id Stream ID of the stream for which encoder-iframeinterval-update is to be sent
* @param[out] interval The encoder iframeinterval to be set corresponding to stream ID for the event.
*/
GstEvent * gst_nvevent_enc_iframeinterval_update (gchar* stream_id, guint interval);
/**
* Parses a "nv-enc-iframeinterval-update" event received on the sinkpad.
*
* @param[in] event The event received on the sinkpad
* when the stream ID sends a iframeinterval-update event.
* @param[out] stream_id A pointer to the parsed stream ID for which
* the event is sent.
* @param[out] bitrate A pointer to the parsed interval value
* corresponding to stream ID for the event.
*/
void gst_nvevent_parse_enc_iframeinterval_update (GstEvent * event, gchar** stream_id, guint *interval);
#ifdef __cplusplus
}
#endif
#endif
/** @} */

View File

@@ -0,0 +1,397 @@
The software listed below is licensed under the terms of the LGPLv2
(see below). To obtain source code, contact oss-requests@nvidia.com.
gst-nvvideo4linux2 (libgstnvvideo4linux2.so)
------------------------------------
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your freedom to share
and change it. By contrast, the GNU General Public Licenses are intended to
guarantee your freedom to share and change free software--to make sure the
software is free for all its users.
This license, the Library General Public License, applies to some specially
designated Free Software Foundation software, and to any other libraries whose
authors decide to use it. You can use it for your libraries, too.
When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the freedom to
distribute copies of free software (and charge for this service if you wish),
that you receive source code or can get it if you want it, that you can change
the software or use pieces of it in new free programs; and that you know you can
do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny
you these rights or to ask you to surrender the rights. These restrictions
translate to certain responsibilities for you if you distribute copies of the
library, or if you modify it.
For example, if you distribute copies of the library, whether gratis or for a
fee, you must give the recipients all the rights that we gave you. You must make
sure that they, too, receive or can get the source code. If you link a program
with the library, you must provide complete object files to the recipients so
that they can relink them with the library, after making changes to the library
and recompiling it. And you must show them these terms so they know their
rights.
Our method of protecting your rights has two steps: (1) copyright the library,
and (2) offer you this license which gives you legal permission to copy,
distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain that everyone
understands that there is no warranty for this free library. If the library is
modified by someone else and passed on, we want its recipients to know that what
they have is not the original version, so that any problems introduced by others
will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish
to avoid the danger that companies distributing free software will individually
obtain patent licenses, thus in effect transforming the program into proprietary
software. To prevent this, we have made it clear that any patent must be
licensed for everyone's free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary GNU
General Public License, which was designed for utility programs. This license,
the GNU Library General Public License, applies to certain designated libraries.
This license is quite different from the ordinary one; be sure to read it in
full, and don't assume that anything in it is the same as in the ordinary
license.
The reason we have a separate public license for some libraries is that they
blur the distinction we usually make between modifying or adding to a program
and simply using it. Linking a program with a library, without changing the
library, is in some sense simply using the library, and is analogous to running
a utility program or application program. However, in a textual and legal sense,
the linked executable is a combined work, a derivative of the original library,
and the ordinary General Public License treats it as such.
Because of this blurred distinction, using the ordinary General Public License
for libraries did not effectively promote software sharing, because most
developers did not use the libraries. We concluded that weaker conditions might
promote sharing better.
However, unrestricted linking of non-free programs would deprive the users of
those programs of all benefit from the free status of the libraries themselves.
This Library General Public License is intended to permit developers of non-free
programs to use free libraries, while preserving your freedom as a user of such
programs to change the free libraries that are incorporated in them. (We have
not seen how to achieve this as regards changes in header files, but we have
achieved it as regards changes in the actual functions of the Library.) The hope
is that this will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and modification
follow. Pay close attention to the difference between a "work based on the
library" and a "work that uses the library". The former contains code derived
from the library, while the latter only works together with the library.
Note that it is possible for a library to be covered by the ordinary General
Public License rather than by this special one.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which contains a
notice placed by the copyright holder or other authorized party saying it may be
distributed under the terms of this Library General Public License (also called
"this License"). Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data prepared so as
to be conveniently linked with application programs (which use some of those
functions and data) to form executables.
The "Library", below, refers to any such software library or work which has been
distributed under these terms. A "work based on the Library" means either the
Library or any derivative work under copyright law: that is to say, a work
containing the Library or a portion of it, either verbatim or with modifications
and/or translated straightforwardly into another language. (Hereinafter,
translation is included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for making
modifications to it. For a library, complete source code means all the source
code for all modules it contains, plus any associated interface definition
files, plus the scripts used to control compilation and installation of the
library.
Activities other than copying, distribution and modification are not covered by
this License; they are outside its scope. The act of running a program using the
Library is not restricted, and output from such a program is covered only if its
contents constitute a work based on the Library (independent of the use of the
Library in a tool for writing it). Whether that is true depends on what the
Library does and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's complete source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this License
and to the absence of any warranty; and distribute a copy of this License along
with the Library.
You may charge a fee for the physical act of transferring a copy, and you may at
your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Library or any portion of it, thus
forming a work based on the Library, and copy and distribute such modifications
or work under the terms of Section 1 above, provided that you also meet all of
these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices stating that
you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no charge to all
third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a table of
data to be supplied by an application program that uses the facility, other than
as an argument passed when the facility is invoked, then you must make a good
faith effort to ensure that, in the event an application does not supply such
function or table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has a purpose
that is entirely well-defined independent of the application. Therefore,
Subsection 2d requires that any application-supplied function or table used by
this function must be optional: if the application does not supply it, the
square root function must still compute square roots.)
These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Library, and can be reasonably
considered independent and separate works in themselves, then this License, and
its terms, do not apply to those sections when you distribute them as separate
works. But when you distribute the same sections as part of a whole which is a
work based on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the entire whole,
and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your
rights to work written entirely by you; rather, the intent is to exercise the
right to control the distribution of derivative or collective works based on the
Library.
In addition, mere aggregation of another work not based on the Library with the
Library (or with a work based on the Library) on a volume of a storage or
distribution medium does not bring the other work under the scope of this
License.
3. You may opt to apply the terms of the ordinary GNU General Public License
instead of this License to a given copy of the Library. To do this, you must
alter all the notices that refer to this License, so that they refer to the
ordinary GNU General Public License, version 2, instead of to this License. (If
a newer version than version 2 of the ordinary GNU General Public License has
appeared, then you can specify that version instead if you wish.) Do not make
any other change in these notices.
Once this change is made in a given copy, it is irreversible for that copy, so
the ordinary GNU General Public License applies to all subsequent copies and
derivative works made from that copy.
This option is useful when you wish to copy part of the code of the Library into
a program that is not a library.
4. You may copy and distribute the Library (or a portion or derivative of it,
under Section 2) in object code or executable form under the terms of Sections 1
and 2 above provided that you accompany it with the complete corresponding
machine-readable source code, which must be distributed under the terms of
Sections 1 and 2 above on a medium customarily used for software interchange.
If distribution of object code is made by offering access to copy from a
designated place, then offering equivalent access to copy the source code from
the same place satisfies the requirement to distribute the source code, even
though third parties are not compelled to copy the source along with the object
code.
5. A program that contains no derivative of any portion of the Library, but is
designed to work with the Library by being compiled or linked with it, is called
a "work that uses the Library". Such a work, in isolation, is not a derivative
work of the Library, and therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library creates an
executable that is a derivative of the Library (because it contains portions of
the Library), rather than a "work that uses the library". The executable is
therefore covered by this License. Section 6 states terms for distribution of
such executables.
When a "work that uses the Library" uses material from a header file that is
part of the Library, the object code for the work may be a derivative work of
the Library even though the source code is not. Whether this is true is
especially significant if the work can be linked without the Library, or if the
work is itself a library. The threshold for this to be true is not precisely
defined by law.
If such an object file uses only numerical parameters, data structure layouts
and accessors, and small macros and small inline functions (ten lines or less in
length), then the use of the object file is unrestricted, regardless of whether
it is legally a derivative work. (Executables containing this object code plus
portions of the Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may distribute the
object code for the work under the terms of Section 6. Any executables
containing that work also fall under Section 6, whether or not they are linked
directly with the Library itself.
6. As an exception to the Sections above, you may also compile or link a "work
that uses the Library" with the Library to produce a work containing portions of
the Library, and distribute that work under terms of your choice, provided that
the terms permit modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the Library is
used in it and that the Library and its use are covered by this License. You
must supply a copy of this License. If the work during execution displays
copyright notices, you must include the copyright notice for the Library among
them, as well as a reference directing the user to the copy of this License.
Also, you must do one of these things:
a) Accompany the work with the complete corresponding machine-readable
source code for the Library including whatever changes were used in the work
(which must be distributed under Sections 1 and 2 above); and, if the work is an
executable linked with the Library, with the complete machine-readable "work
that uses the Library", as object code and/or source code, so that the user can
modify the Library and then relink to produce a modified executable containing
the modified Library. (It is understood that the user who changes the contents
of definitions files in the Library will not necessarily be able to recompile
the application to use the modified definitions.)
b) Accompany the work with a written offer, valid for at least three years,
to give the same user the materials specified in Subsection 6a, above, for a
charge no more than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy from a
designated place, offer equivalent access to copy the above specified materials
from the same place.
d) Verify that the user has already received a copy of these materials or
that you have already sent this user a copy.
For an executable, the required form of the "work that uses the Library" must
include any data and utility programs needed for reproducing the executable from
it. However, as a special exception, the source code distributed need not
include anything that is normally distributed (in either source or binary form)
with the major components (compiler, kernel, and so on) of the operating system
on which the executable runs, unless that component itself accompanies the
executable.
It may happen that this requirement contradicts the license restrictions of
other proprietary libraries that do not normally accompany the operating system.
Such a contradiction means you cannot use both them and the Library together in
an executable that you distribute.
7. You may place library facilities that are a work based on the Library
side-by-side in a single library together with other library facilities not
covered by this License, and distribute such a combined library, provided that
the separate distribution of the work based on the Library and of the other
library facilities is otherwise permitted, and provided that you do these two
things:
a) Accompany the combined library with a copy of the same work based on the
Library, uncombined with any other library facilities. This must be distributed
under the terms of the Sections above.
b) Give prominent notice with the combined library of the fact that part of
it is a work based on the Library, and explaining where to find the accompanying
uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute the Library
except as expressly provided under this License. Any attempt otherwise to copy,
modify, sublicense, link with, or distribute the Library is void, and will
automatically terminate your rights under this License. However, parties who
have received copies, or rights, from you under this License will not have their
licenses terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not signed it.
However, nothing else grants you permission to modify or distribute the Library
or its derivative works. These actions are prohibited by law if you do not
accept this License. Therefore, by modifying or distributing the Library (or any
work based on the Library), you indicate your acceptance of this License to do
so, and all its terms and conditions for copying, distributing or modifying the
Library or works based on it.
10. Each time you redistribute the Library (or any work based on the Library),
the recipient automatically receives a license from the original licensor to
copy, distribute, link with or modify the Library subject to these terms and
conditions. You may not impose any further restrictions on the recipients'
exercise of the rights granted herein. You are not responsible for enforcing
compliance by third parties to this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues), conditions
are imposed on you (whether by court order, agreement or otherwise) that
contradict the conditions of this License, they do not excuse you from the
conditions of this License. If you cannot distribute so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not distribute the Library at all.
For example, if a patent license would not permit royalty-free redistribution of
the Library by all those who receive copies directly or indirectly through you,
then the only way you could satisfy both it and this License would be to refrain
entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply, and
the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or
other property right claims or to contest validity of any such claims; this
section has the sole purpose of protecting the integrity of the free software
distribution system which is implemented by public license practices. Many
people have made generous contributions to the wide range of software
distributed through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing to
distribute software through any other system and a licensee cannot impose that
choice.
This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in certain
countries either by patents or by copyrighted interfaces, the original copyright
holder who places the Library under this License may add an explicit
geographical distribution limitation excluding those countries, so that
distribution is permitted only in or among countries not thus excluded. In such
case, this License incorporates the limitation as if written in the body of this
License.
13. The Free Software Foundation may publish revised and/or new versions of the
Library General Public License from time to time. Such new versions will be
similar in spirit to the present version, but may differ in detail to address
new problems or concerns.
Each version is given a distinguishing version number. If the Library specifies
a version number of this License which applies to it and "any later version",
you have the option of following the terms and conditions either of that version
or of any later version published by the Free Software Foundation. If the
Library does not specify a license version number, you may choose any version
ever published by the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free programs
whose distribution conditions are incompatible with these, write to the author
to ask for permission. For software which is copyrighted by the Free Software
Foundation, write to the Free Software Foundation; we sometimes make exceptions
for this. Our decision will be guided by the two goals of preserving the free
status of all derivatives of our free software and of promoting the sharing and
reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE
LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED
IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS
IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

70
gst-v4l2/Makefile Normal file
View File

@@ -0,0 +1,70 @@
###############################################################################
#
# Copyright (c) 2018-2025, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA Corporation and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA Corporation is strictly prohibited.
#
###############################################################################
SO_NAME := libgstnvvideo4linux2.so
TARGET_DEVICE = $(shell gcc -dumpmachine | cut -f1 -d -)
NVDS_VERSION:=8.0
ifeq ($(TARGET_DEVICE),aarch64)
GST_INSTALL_DIR?=/usr/lib/aarch64-linux-gnu/gstreamer-1.0/
LIB_INSTALL_DIR?=/usr/lib/aarch64-linux-gnu/tegra/
INCLUDES += -I/usr/src/jetson_multimedia_api/include/
CFLAGS:=
else
GST_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/gst-plugins/
LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/
CFLAGS:= -DUSE_V4L2_TARGET_NV_CODECSDK=1 -DUSE_V4L2_TARGET_NV_X86=1 -DUSE_V4L2_GST_HEADER_VER_1_8
endif
LIBS:= -lnvbufsurface -lnvbufsurftransform -lgstnvdsseimeta -lgstnvcustomhelper
SRCS := $(wildcard *.c)
INCLUDES += -I./ -I../ -I/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/sources/includes/
PKGS := gstreamer-1.0 \
gstreamer-base-1.0 \
gstreamer-video-1.0 \
gstreamer-allocators-1.0 \
glib-2.0 \
libv4l2
OBJS := $(SRCS:.c=.o)
CFLAGS += -fPIC \
-DEXPLICITLY_ADDED=1 \
-DGETTEXT_PACKAGE=1 \
-DHAVE_LIBV4L2=1 \
-DUSE_V4L2_TARGET_NV=1
CFLAGS += `pkg-config --cflags $(PKGS)`
LDFLAGS = -Wl,--no-undefined -L$(LIB_INSTALL_DIR) -Wl,-rpath,$(LIB_INSTALL_DIR)
LIBS += `pkg-config --libs $(PKGS)`
all: $(SO_NAME)
%.o: %.c
$(CC) -c $< $(CFLAGS) $(INCLUDES) -o $@
$(SO_NAME): $(OBJS)
$(CC) -shared -o $(SO_NAME) $(OBJS) $(LIBS) $(LDFLAGS)
.PHONY: install
install: $(SO_NAME)
cp -vp $(SO_NAME) $(GST_INSTALL_DIR)
.PHONY: clean
clean:
rm -rf $(OBJS) $(SO_NAME)

37
gst-v4l2/README.txt Normal file
View File

@@ -0,0 +1,37 @@
###############################################################################
#
# Copyright (c) 2018-2025, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA Corporation and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA Corporation is strictly prohibited.
#
###############################################################################
Steps to compile the "gst-nvvideo4linux2" sources natively:
1) Install gstreamer related packages on target using the command:
sudo apt-get install libgstreamer1.0-dev \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
libgstreamer-plugins-base1.0-dev \
libv4l-dev \
libegl1-mesa-dev
2) Download and extract the package "gst-nvvideo4linux_src.tbz2" as follow:
tar -I lbzip2 -xvf gst-nvvideo4linux2_src.tbz2
3) Run the following commands to build and install "libgstnvvideo4linux2.so":
make
make install
or
DEST_DIR=<dir> make install
Note: For Jetson, "make install" will copy library "libgstnvvideo4linux2.so"
into "/usr/lib/aarch64-linux-gnu/gstreamer-1.0" directory. For x86 platforms,
make install will copy the library "libgstnvvideo4linux2.so" into
/opt/nvidia/deepstream/deepstream/lib/gst-plugins

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas@ndufresne.ca>
* Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#include <glib.h>
#ifndef __TYPES_COMPAT_H__
#define __TYPES_COMPAT_H__
/* From linux/types.h */
#ifndef __bitwise__
# ifdef __CHECKER__
# define __bitwise__ __attribute__((bitwise))
# else
# define __bitwise__
# endif
#endif
#ifndef __bitwise
# ifdef __CHECK_ENDIAN__
# define __bitwise __bitwise__
# else
# define __bitwise
# endif
#endif
#define __u64 guint64
#define __u32 guint32
#define __u16 guint16
#define __u8 guint8
#ifdef USE_V4L2_TARGET_NV
#define __s8 gint8
#endif
#define __s64 gint64
#define __s32 gint32
#define __le32 guint32 __bitwise
#define __user
#endif /* __TYPES_COMPAT_H__ */

108
gst-v4l2/ext/v4l2-common.h Normal file
View File

@@ -0,0 +1,108 @@
/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* include/linux/v4l2-common.h
*
* Common V4L2 and V4L2 subdev definitions.
*
* Users are advised to #include this file either through videodev2.h
* (V4L2) or through v4l2-subdev.h (V4L2 subdev) rather than to refer
* to this file directly.
*
* Copyright (C) 2012 Nokia Corporation
* Contact: Sakari Ailus <sakari.ailus@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* Alternatively you can redistribute this file under the terms of the
* BSD license as stated below:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The names of its contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __V4L2_COMMON__
#define __V4L2_COMMON__
#include <linux/types.h>
/*
*
* Selection interface definitions
*
*/
/* Current cropping area */
#define V4L2_SEL_TGT_CROP 0x0000
/* Default cropping area */
#define V4L2_SEL_TGT_CROP_DEFAULT 0x0001
/* Cropping bounds */
#define V4L2_SEL_TGT_CROP_BOUNDS 0x0002
/* Native frame size */
#define V4L2_SEL_TGT_NATIVE_SIZE 0x0003
/* Current composing area */
#define V4L2_SEL_TGT_COMPOSE 0x0100
/* Default composing area */
#define V4L2_SEL_TGT_COMPOSE_DEFAULT 0x0101
/* Composing bounds */
#define V4L2_SEL_TGT_COMPOSE_BOUNDS 0x0102
/* Current composing area plus all padding pixels */
#define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103
/* Selection flags */
#define V4L2_SEL_FLAG_GE (1 << 0)
#define V4L2_SEL_FLAG_LE (1 << 1)
#define V4L2_SEL_FLAG_KEEP_CONFIG (1 << 2)
struct v4l2_edid {
__u32 pad;
__u32 start_block;
__u32 blocks;
__u32 reserved[5];
__u8 *edid;
};
/* Backward compatibility target definitions --- to be removed. */
#define V4L2_SEL_TGT_CROP_ACTIVE V4L2_SEL_TGT_CROP
#define V4L2_SEL_TGT_COMPOSE_ACTIVE V4L2_SEL_TGT_COMPOSE
#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL V4L2_SEL_TGT_CROP
#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS V4L2_SEL_TGT_CROP_BOUNDS
#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
/* Backward compatibility flag definitions --- to be removed. */
#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE V4L2_SEL_FLAG_GE
#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE V4L2_SEL_FLAG_LE
#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
#endif /* __V4L2_COMMON__ */

2019
gst-v4l2/ext/v4l2-controls.h Normal file
View File

File diff suppressed because it is too large Load Diff

2582
gst-v4l2/ext/videodev2.h Normal file
View File

File diff suppressed because it is too large Load Diff

69
gst-v4l2/gst/gettext.h Normal file
View File

@@ -0,0 +1,69 @@
/* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
This program 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, or (at your option)
any later version.
This program 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 program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
USA. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#ifdef ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
#else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
as well because people using "gettext.h" will not include <libintl.h>,
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
# include <locale.h>
#endif
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
# define gettext(Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define textdomain(Domainname) ((const char *) (Domainname))
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
#endif /* _LIBGETTEXT_H */

View File

@@ -0,0 +1,36 @@
/*
* glib-compat.c
* Functions copied from glib 2.10
*
* Copyright 2005 David Schleef <ds@schleef.org>
*
* 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.
*/
#ifndef __GLIB_COMPAT_PRIVATE_H__
#define __GLIB_COMPAT_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
/* copies */
/* adaptations */
G_END_DECLS
#endif

View File

@@ -0,0 +1,47 @@
/* GStreamer
* Copyright (C) 2004 Thomas Vander Stichele <thomas@apestaart.org>
*
* gst-i18n-plugins.h: internationalization macros for the GStreamer plugins
*
* 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.
*/
#ifndef __GST_I18N_PLUGIN_H__
#define __GST_I18N_PLUGIN_H__
#ifndef GETTEXT_PACKAGE
#error You must define GETTEXT_PACKAGE before including this header.
#endif
#ifdef ENABLE_NLS
#include <locale.h>
#include "gettext.h" /* included with gettext distribution and copied */
/* we want to use shorthand _() for translating and N_() for marking */
#define _(String) dgettext (GETTEXT_PACKAGE, String)
#define N_(String) gettext_noop (String)
/* FIXME: if we need it, we can add Q_ as well, like in glib */
#else
#define _(String) String
#define N_(String) String
#define ngettext(Singular,Plural,Count) ((Count>1)?Plural:Singular)
#endif
#endif /* __GST_I18N_PLUGIN_H__ */

504
gst-v4l2/gstv4l2.c Normal file
View File

@@ -0,0 +1,504 @@
/* 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

1628
gst-v4l2/gstv4l2allocator.c Normal file
View File

File diff suppressed because it is too large Load Diff

181
gst-v4l2/gstv4l2allocator.h Normal file
View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
* Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#ifndef __GST_V4L2_ALLOCATOR_H__
#define __GST_V4L2_ALLOCATOR_H__
#include "linux/videodev2.h"
#include <gst/gst.h>
#include <gst/gstatomicqueue.h>
G_BEGIN_DECLS
#define GST_TYPE_V4L2_ALLOCATOR (gst_v4l2_allocator_get_type())
#define GST_IS_V4L2_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_ALLOCATOR))
#define GST_IS_V4L2_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_ALLOCATOR))
#define GST_V4L2_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_ALLOCATOR, GstV4l2AllocatorClass))
#define GST_V4L2_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_ALLOCATOR, GstV4l2Allocator))
#define GST_V4L2_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_ALLOCATOR, GstV4l2AllocatorClass))
#define GST_V4L2_ALLOCATOR_CAST(obj) ((GstV4l2Allocator *)(obj))
#define GST_V4L2_ALLOCATOR_CAN_REQUEST(obj,type) \
(GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _REQBUFS))
#define GST_V4L2_ALLOCATOR_CAN_ALLOCATE(obj,type) \
(GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _CREATE_BUFS))
#define GST_V4L2_MEMORY_QUARK gst_v4l2_memory_quark ()
/* The structures are renamed as the name conflicts with the
* OSS v4l2 library structures. */
#ifdef USE_V4L2_TARGET_NV
#define GstV4l2Allocator GstNvV4l2Allocator
#define GstV4l2AllocatorClass GstNvV4l2AllocatorClass
#endif
#ifdef USE_V4L2_TARGET_NV
#define NV_VIDEO_MAX_FRAME 64
#endif
typedef struct _GstV4l2Allocator GstV4l2Allocator;
typedef struct _GstV4l2AllocatorClass GstV4l2AllocatorClass;
typedef struct _GstV4l2MemoryGroup GstV4l2MemoryGroup;
typedef struct _GstV4l2Memory GstV4l2Memory;
typedef enum _GstV4l2Capabilities GstV4l2Capabilities;
typedef enum _GstV4l2Return GstV4l2Return;
typedef struct _GstV4l2Object GstV4l2Object;
enum _GstV4l2AllocatorFlags
{
GST_V4L2_ALLOCATOR_FLAG_MMAP_REQBUFS = (GST_ALLOCATOR_FLAG_LAST << 0),
GST_V4L2_ALLOCATOR_FLAG_MMAP_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 1),
GST_V4L2_ALLOCATOR_FLAG_USERPTR_REQBUFS = (GST_ALLOCATOR_FLAG_LAST << 2),
GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 3),
GST_V4L2_ALLOCATOR_FLAG_DMABUF_REQBUFS = (GST_ALLOCATOR_FLAG_LAST << 4),
GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 5),
};
enum _GstV4l2Return
{
GST_V4L2_OK = 0,
GST_V4L2_ERROR = -1,
GST_V4L2_BUSY = -2
};
struct _GstV4l2Memory
{
GstMemory mem;
gint plane;
GstV4l2MemoryGroup *group;
gpointer data;
gint dmafd;
};
struct _GstV4l2MemoryGroup
{
gint n_mem;
GstMemory * mem[VIDEO_MAX_PLANES];
gint mems_allocated;
struct v4l2_buffer buffer;
struct v4l2_plane planes[VIDEO_MAX_PLANES];
};
struct _GstV4l2Allocator
{
GstAllocator parent;
GstV4l2Object *obj;
guint32 count;
guint32 memory;
gboolean can_allocate;
gboolean active;
#ifdef USE_V4L2_TARGET_NV
GstV4l2MemoryGroup * groups[NV_VIDEO_MAX_FRAME];
#else
GstV4l2MemoryGroup * groups[VIDEO_MAX_FRAME];
#endif
GstAtomicQueue *free_queue;
GstAtomicQueue *pending_queue;
#ifdef USE_V4L2_TARGET_NV
gboolean enable_dynamic_allocation; /* If dynamic_allocation should be set */
#endif
};
struct _GstV4l2AllocatorClass {
GstAllocatorClass parent_class;
};
GType gst_v4l2_allocator_get_type(void);
gboolean gst_is_v4l2_memory (GstMemory * mem);
GQuark gst_v4l2_memory_quark (void);
gboolean gst_v4l2_allocator_is_active (GstV4l2Allocator * allocator);
guint gst_v4l2_allocator_get_size (GstV4l2Allocator * allocator);
GstV4l2Allocator* gst_v4l2_allocator_new (GstObject *parent, GstV4l2Object * obj);
guint gst_v4l2_allocator_start (GstV4l2Allocator * allocator,
guint32 count, guint32 memory);
GstV4l2Return gst_v4l2_allocator_stop (GstV4l2Allocator * allocator);
GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator);
GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,
GstAllocator * dmabuf_allocator);
GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator);
GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_userptr (GstV4l2Allocator * allocator);
gboolean gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup *group,
gint n_mem, GstMemory ** dma_mem);
gboolean gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup *group,
gsize img_size, int n_planes,
gpointer * data, gsize * size);
void gst_v4l2_allocator_flush (GstV4l2Allocator * allocator);
gboolean gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group);
GstFlowReturn gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup ** group);
void gst_v4l2_allocator_reset_group (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group);
#ifdef USE_V4L2_TARGET_NV
void
gst_v4l2_allocator_enable_dynamic_allocation (GstV4l2Allocator * allocator,
gboolean enable_dynamic_allocation);
#endif
G_END_DECLS
#endif /* __GST_V4L2_ALLOCATOR_H__ */

368
gst-v4l2/gstv4l2av1enc.c Normal file
View File

@@ -0,0 +1,368 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "gstv4l2object.h"
#include "gstv4l2av1enc.h"
#include <string.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_v4l2_av1_enc_debug);
#define GST_CAT_DEFAULT gst_v4l2_av1_enc_debug
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-av1");
/* prototypes */
gboolean gst_v4l2_av1_enc_tile_configuration (GstV4l2Object * v4l2object,
gboolean enable_tile, guint32 log2_tile_rows, guint32 log2_tile_cols);
static gboolean gst_v4l2_video_enc_parse_tile_configuration (GstV4l2Av1Enc * self,
const gchar * arr);
gboolean set_v4l2_av1_encoder_properties (GstVideoEncoder * encoder);
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
PROP_ENABLE_HEADER,
PROP_ENABLE_TILE_CONFIG,
PROP_DISABLE_CDF,
PROP_ENABLE_SSIMRDO,
PROP_INSERT_SEQ_HDR,
PROP_NUM_REFERENCE_FRAMES,
};
#define DEFAULT_NUM_REFERENCE_FRAMES 0
#define MAX_NUM_REFERENCE_FRAMES 4
#define gst_v4l2_av1_enc_parent_class parent_class
G_DEFINE_TYPE (GstV4l2Av1Enc, gst_v4l2_av1_enc, GST_TYPE_V4L2_VIDEO_ENC);
static void
gst_v4l2_av1_enc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstV4l2Av1Enc *self = GST_V4L2_AV1_ENC (object);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
self->EnableHeaders = g_value_get_boolean (value);
video_enc->v4l2capture->Enable_headers = g_value_get_boolean (value);
break;
case PROP_ENABLE_TILE_CONFIG:
gst_v4l2_video_enc_parse_tile_configuration (self,
g_value_get_string (value));
self->EnableTileConfig = TRUE;
break;
case PROP_DISABLE_CDF:
self->DisableCDFUpdate = g_value_get_boolean (value);
break;
case PROP_ENABLE_SSIMRDO:
self->EnableSsimRdo = g_value_get_boolean (value);
break;
case PROP_INSERT_SEQ_HDR:
self->insert_sps_pps = g_value_get_boolean (value);
break;
case PROP_NUM_REFERENCE_FRAMES:
self->nRefFrames = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_v4l2_av1_enc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstV4l2Av1Enc *self = GST_V4L2_AV1_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
g_value_set_boolean (value, self->EnableHeaders);
break;
case PROP_ENABLE_TILE_CONFIG:
break;
case PROP_DISABLE_CDF:
g_value_set_boolean (value, self->DisableCDFUpdate);
break;
case PROP_ENABLE_SSIMRDO:
g_value_set_boolean (value, self->EnableSsimRdo);
break;
case PROP_INSERT_SEQ_HDR:
g_value_set_boolean (value, self->insert_sps_pps);
break;
case PROP_NUM_REFERENCE_FRAMES:
g_value_set_uint (value, self->nRefFrames);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gint
v4l2_profile_from_string (const gchar * profile)
{
gint v4l2_profile = -1;
if (g_str_equal (profile, "0"))
v4l2_profile = 0;
else if (g_str_equal (profile, "1"))
v4l2_profile = 1;
else if (g_str_equal (profile, "2"))
v4l2_profile = 2;
else if (g_str_equal (profile, "3"))
v4l2_profile = 3;
else
GST_WARNING ("Unsupported profile string '%s'", profile);
return v4l2_profile;
}
static const gchar *
v4l2_profile_to_string (gint v4l2_profile)
{
switch (v4l2_profile) {
case 0:
return "0";
case 1:
return "1";
case 2:
return "2";
case 3:
return "3";
default:
GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
break;
}
return NULL;
}
static gboolean
gst_v4l2_video_enc_parse_tile_configuration (GstV4l2Av1Enc * self,
const gchar * arr)
{
gchar *str;
self->Log2TileRows = atoi (arr);
str = g_strstr_len (arr, -1, ",");
self->Log2TileCols = atoi (str + 1);
return TRUE;
}
gboolean
gst_v4l2_av1_enc_tile_configuration (GstV4l2Object * v4l2object,
gboolean enable_tile, guint32 log2_tile_rows, guint32 log2_tile_cols)
{
struct v4l2_ext_control control;
struct v4l2_ext_controls ctrls;
gint ret;
v4l2_enc_av1_tile_config param =
{enable_tile, log2_tile_rows, log2_tile_cols};
memset (&control, 0, sizeof (control));
memset (&ctrls, 0, sizeof (ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_AV1_TILE_CONFIGURATION;
control.string = (gchar *) &param;
ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0) {
g_print ("Error while setting tile configuration\n");
return FALSE;
}
return TRUE;
}
gboolean
set_v4l2_av1_encoder_properties (GstVideoEncoder * encoder)
{
GstV4l2Av1Enc *self = GST_V4L2_AV1_ENC (encoder);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (encoder);
if (!GST_V4L2_IS_OPEN (video_enc->v4l2output)) {
g_print ("V4L2 device is not open\n");
return FALSE;
}
if (is_cuvid == FALSE) {
if (self->EnableTileConfig) {
if (!gst_v4l2_av1_enc_tile_configuration (video_enc->v4l2output,
self->EnableTileConfig, self->Log2TileRows, self->Log2TileCols)) {
g_print ("S_EXT_CTRLS for Tile Configuration failed\n");
return FALSE;
}
}
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_AV1_DISABLE_CDF_UPDATE, self->DisableCDFUpdate)) {
g_print ("S_EXT_CTRLS for DisableCDF Update failed\n");
return FALSE;
}
if (self->EnableSsimRdo) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_AV1_ENABLE_SSIMRDO, self->EnableSsimRdo)) {
g_print ("S_EXT_CTRLS for SSIM RDO failed\n");
return FALSE;
}
}
}
if (self->insert_sps_pps) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_SPS_PPS_AT_IDR, self->insert_sps_pps)) {
g_print ("S_EXT_CTRLS for SSIM RDO failed\n");
return FALSE;
}
}
if (self->nRefFrames) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_NUM_REFERENCE_FRAMES,
self->nRefFrames)) {
g_print ("S_EXT_CTRLS for NUM_REFERENCE_FRAMES failed\n");
return FALSE;
}
}
return TRUE;
}
static void
gst_v4l2_av1_enc_init (GstV4l2Av1Enc * self)
{
self->EnableTileConfig = FALSE;
self->DisableCDFUpdate = TRUE;
self->EnableSsimRdo = FALSE;
self->insert_sps_pps = FALSE;
self->Log2TileRows= 0;
self->Log2TileCols= 0;
}
static void
gst_v4l2_av1_enc_class_init (GstV4l2Av1EncClass * klass)
{
GstElementClass *element_class;
GObjectClass *gobject_class;
GstV4l2VideoEncClass *baseclass;
parent_class = g_type_class_peek_parent (klass);
element_class = (GstElementClass *) klass;
gobject_class = (GObjectClass *) klass;
baseclass = (GstV4l2VideoEncClass *) (klass);
GST_DEBUG_CATEGORY_INIT (gst_v4l2_av1_enc_debug, "v4l2av1enc", 0,
"V4L2 AV1 Encoder");
gst_element_class_set_static_metadata (element_class,
"V4L2 AV1 Encoder",
"Codec/Encoder/Video",
"Encode AV1 video streams via V4L2 API",
"Anuma Rathore <arathore@nvidia.com>");
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_v4l2_av1_enc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_v4l2_av1_enc_get_property);
g_object_class_install_property (gobject_class, PROP_ENABLE_HEADER,
g_param_spec_boolean ("enable-headers", "Enable AV1 headers",
"Enable AV1 file and frame headers, if enabled, dump elementary stream",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
#if !defined(USE_V4L2_TARGET_NV_X86) && !defined(AARCH64_IS_SBSA)
g_object_class_install_property (gobject_class, PROP_ENABLE_TILE_CONFIG,
g_param_spec_string ("tiles", "AV1 Log2 Tile Configuration",
"Use string with values of Tile Configuration"
"in Log2Rows:Log2Cols. Eg: \"1,0\"",
"0,0", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_DISABLE_CDF,
g_param_spec_boolean ("disable-cdf", "Disable CDF Update",
"Flag to control Disable CDF Update, enabled by default",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_ENABLE_SSIMRDO,
g_param_spec_boolean ("enable-srdo", "Enable SSIM RDO",
"Enable SSIM RDO",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
#endif
g_object_class_install_property (gobject_class, PROP_INSERT_SEQ_HDR,
g_param_spec_boolean ("insert-seq-hdr", "Insert sequence header",
"Insert sequence header at every IDR frame",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_NUM_REFERENCE_FRAMES,
g_param_spec_uint ("num-Ref-Frames",
"Sets the number of reference frames for encoder",
"Number of Reference Frames for encoder, default set by encoder",
0, MAX_NUM_REFERENCE_FRAMES, DEFAULT_NUM_REFERENCE_FRAMES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
baseclass->codec_name = "AV1";
baseclass->profile_cid = 0; /* Only single profile supported */
baseclass->profile_to_string = v4l2_profile_to_string;
baseclass->profile_from_string = v4l2_profile_from_string;
baseclass->set_encoder_properties = set_v4l2_av1_encoder_properties;
}
/* Probing functions */
gboolean
gst_v4l2_is_av1_enc (GstCaps * sink_caps, GstCaps * src_caps)
{
return gst_v4l2_is_video_enc (sink_caps, src_caps,
gst_static_caps_get (&src_template_caps));
}
void
gst_v4l2_av1_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
{
gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_AV1_ENC,
"av1", basename, device_path, sink_caps,
gst_static_caps_get (&src_template_caps), src_caps);
}

68
gst-v4l2/gstv4l2av1enc.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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.
*
*/
#ifndef __GST_V4L2_AV1_ENC_H__
#define __GST_V4L2_AV1_ENC_H__
#include <gst/gst.h>
#include "gstv4l2videoenc.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_AV1_ENC \
(gst_v4l2_av1_enc_get_type())
#define GST_V4L2_AV1_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_AV1_ENC,GstV4l2Av1Enc))
#define GST_V4L2_AV1_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_AV1_ENC,GstV4l2Av1EncClass))
#define GST_IS_V4L2_AV1_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_AV1_ENC))
#define GST_IS_V4L2_AV1_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_AV1_ENC))
typedef struct _GstV4l2Av1Enc GstV4l2Av1Enc;
typedef struct _GstV4l2Av1EncClass GstV4l2Av1EncClass;
struct _GstV4l2Av1Enc
{
GstV4l2VideoEnc parent;
gboolean EnableHeaders;
gboolean EnableTileConfig;
gboolean DisableCDFUpdate;
gboolean EnableSsimRdo;
gboolean insert_sps_pps;
guint32 Log2TileRows;
guint32 Log2TileCols;
guint32 nRefFrames;
};
struct _GstV4l2Av1EncClass
{
GstV4l2VideoEncClass parent_class;
};
GType gst_v4l2_av1_enc_get_type (void);
gboolean gst_v4l2_is_av1_enc (GstCaps * sink_caps, GstCaps * src_caps);
void gst_v4l2_av1_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_AV1_ENC_H__ */

2637
gst-v4l2/gstv4l2bufferpool.c Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@gmail.com>
* 2009 Texas Instruments, Inc - http://www.ti.com/
*
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* gstv4l2bufferpool.h V4L2 buffer pool class
*
* 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.
*/
#ifndef __GST_V4L2_BUFFER_POOL_H__
#define __GST_V4L2_BUFFER_POOL_H__
#include <gst/gst.h>
/* The structures are renamed as the name conflicts with the
* OSS v4l2 library structures. */
#ifdef USE_V4L2_TARGET_NV
#define GstV4l2BufferPool GstNvV4l2BufferPool
#define GstV4l2BufferPoolClass GstNvV4l2BufferPoolClass
#endif
typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
typedef struct _GstV4l2BufferPoolClass GstV4l2BufferPoolClass;
typedef struct _GstV4l2Meta GstV4l2Meta;
#include "gstv4l2object.h"
#include "gstv4l2allocator.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_BUFFER_POOL (gst_v4l2_buffer_pool_get_type())
#define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
#define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
#define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
/* This flow return is used to indicated that the last buffer of a
* drain or a resoltuion change has been found. This should normally
* only occure for mem-2-mem devices. */
#define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS
/* This flow return is used to indicated that the returned buffer was marked
* with the error flag and had no payload. This error should be recovered by
* simply waiting for next buffer. */
#define GST_V4L2_FLOW_CORRUPTED_BUFFER GST_FLOW_CUSTOM_SUCCESS_1
struct _GstV4l2BufferPool
{
GstBufferPool parent;
GstV4l2Object *obj; /* the v4l2 object */
gint video_fd; /* a dup(2) of the v4l2object's video_fd */
GstPoll *poll; /* a poll for video_fd */
GstPollFD pollfd;
gboolean can_poll_device;
gboolean empty;
GCond empty_cond;
GstV4l2Allocator *vallocator;
GstAllocator *allocator;
GstAllocationParams params;
GstBufferPool *other_pool;
guint size;
GstVideoInfo caps_info; /* Default video information */
gboolean add_videometa; /* set if video meta should be added */
gboolean enable_copy_threshold; /* If copy_threshold should be set */
guint min_latency; /* number of buffers we will hold */
guint max_latency; /* number of buffers we can hold */
guint num_queued; /* number of buffers queued in the driver */
guint num_allocated; /* number of buffers allocated */
guint copy_threshold; /* when our pool runs lower, start handing out copies */
gboolean streaming;
gboolean flushing;
#ifdef USE_V4L2_TARGET_NV
GstBuffer *buffers[NV_VIDEO_MAX_FRAME];
GQueue *allocated_surfaces_queue;
#else
GstBuffer *buffers[VIDEO_MAX_FRAME];
#endif
/* signal handlers */
gulong group_released_handler;
/* Control to warn only once on buggy feild driver bug */
gboolean has_warned_on_buggy_field;
#ifdef USE_V4L2_TARGET_NV
gboolean enable_dynamic_allocation; /* If dynamic_allocation should be set */
#endif
};
struct _GstV4l2BufferPoolClass
{
GstBufferPoolClass parent_class;
};
GType gst_v4l2_buffer_pool_get_type (void);
GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object *obj, GstCaps *caps);
GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer ** buf);
void gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
GstBufferPool * other_pool);
void gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool,
gboolean copy);
gboolean gst_v4l2_buffer_pool_flush (GstBufferPool *pool);
#ifdef USE_V4L2_TARGET_NV
void
gst_v4l2_buffer_pool_enable_dynamic_allocation (GstV4l2BufferPool * pool,
gboolean enable_dynamic_allocation);
gint
get_motion_vectors (GstV4l2Object *obj, guint32 bufferIndex,
v4l2_ctrl_videoenc_outputbuf_metadata_MV *enc_mv_metadata);
#endif
G_END_DECLS
#endif /*__GST_V4L2_BUFFER_POOL_H__ */

897
gst-v4l2/gstv4l2h264enc.c Normal file
View File

@@ -0,0 +1,897 @@
/*
* Copyright (C) 2014 SUMOMO Computer Association
* Author: ayaka <ayaka@soulik.info>
* SPDX-FileCopyrightText: Copyright (c) 2018-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "gstv4l2object.h"
#include "gstv4l2h264enc.h"
#include <string.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_v4l2_h264_enc_debug);
#define GST_CAT_DEFAULT gst_v4l2_h264_enc_debug
#ifdef USE_V4L2_TARGET_NV
static GType
gst_v4l2_videnc_profile_get_type (void);
#define GST_TYPE_V4L2_VID_ENC_PROFILE (gst_v4l2_videnc_profile_get_type ())
/* prototypes */
gboolean gst_v4l2_h264_enc_slice_header_spacing (GstV4l2Object * v4l2object,
guint32 slice_header_spacing, enum v4l2_enc_slice_length_type slice_length_type);
gboolean set_v4l2_h264_encoder_properties (GstVideoEncoder * encoder);
gboolean gst_v4l2_h264_enc_slice_intrarefresh (GstV4l2Object * v4l2object,
guint32 slice_count, guint32 slice_interval);
#endif
#ifdef USE_V4L2_TARGET_NV
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-h264, stream-format=(string) byte-stream, "
"alignment=(string) { au, nal }");
#else
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-h264, stream-format=(string) byte-stream, "
"alignment=(string) au");
#endif
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
#ifdef USE_V4L2_TARGET_NV
PROP_PROFILE,
PROP_INSERT_VUI,
PROP_EXTENDED_COLORFORMAT,
PROP_INSERT_SPS_PPS,
PROP_INSERT_AUD,
PROP_NUM_BFRAMES,
PROP_ENTROPY_CODING,
PROP_BIT_PACKETIZATION,
PROP_SLICE_INTRA_REFRESH,
PROP_SLICE_INTRA_REFRESH_INTERVAL,
PROP_TWO_PASS_CBR,
PROP_ENABLE_MV_META,
PROP_SLICE_HEADER_SPACING,
PROP_NUM_REFERENCE_FRAMES,
PROP_PIC_ORDER_CNT_TYPE,
PROP_ENABLE_LOSSLESS_ENC
#endif
/* TODO add H264 controls
* PROP_I_FRAME_QP,
* PROP_P_FRAME_QP,
* PROP_B_FRAME_QP,
* PROP_MIN_QP,
* PROP_MAX_QP,
* PROP_8x8_TRANSFORM,
* PROP_CPB_SIZE,
* PROP_ENTROPY_MODE,
* PROP_I_PERIOD,
* PROP_LOOP_FILTER_ALPHA,
* PROP_LOOP_FILTER_BETA,
* PROP_LOOP_FILTER_MODE,
* PROP_VUI_EXT_SAR_HEIGHT,
* PROP_VUI_EXT_SAR_WIDTH,
* PROP_VUI_SAR_ENABLED,
* PROP_VUI_SAR_IDC,
* PROP_SEI_FRAME_PACKING,
* PROP_SEI_FP_CURRENT_FRAME_0,
* PROP_SEI_FP_ARRANGEMENT_TYP,
* ...
* */
};
#ifdef USE_V4L2_TARGET_NV
#define DEFAULT_PROFILE V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE
#define DEFAULT_NUM_B_FRAMES 0
#define MAX_NUM_B_FRAMES 2
#define DEFAULT_NUM_REFERENCE_FRAMES 1
#define MAX_NUM_REFERENCE_FRAMES 8
#define DEFAULT_BIT_PACKETIZATION FALSE
#define DEFAULT_SLICE_HEADER_SPACING 0
#define DEFAULT_INTRA_REFRESH_FRAME_INTERVAL 0
#define DEFAULT_PIC_ORDER_CNT_TYPE 0
#endif
#define gst_v4l2_h264_enc_parent_class parent_class
G_DEFINE_TYPE (GstV4l2H264Enc, gst_v4l2_h264_enc, GST_TYPE_V4L2_VIDEO_ENC);
static void
gst_v4l2_h264_enc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2H264Enc *self = GST_V4L2_H264_ENC (object);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (object);
switch (prop_id) {
case PROP_PROFILE:
self->profile = g_value_get_enum (value);
if (GST_V4L2_IS_OPEN (video_enc->v4l2output)) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEO_H264_PROFILE, self->profile)) {
g_print ("S_EXT_CTRLS for H264_PROFILE failed\n");
}
}
break;
case PROP_NUM_BFRAMES:
self->nBFrames = g_value_get_uint (value);
if (self->nBFrames && self->nRefFrames == DEFAULT_NUM_REFERENCE_FRAMES)
{
self->nRefFrames = 2;
g_print ("Minimum 2 Ref-Frames are required for B-frames encoding\n");
}
break;
case PROP_INSERT_SPS_PPS:
self->insert_sps_pps = g_value_get_boolean (value);
break;
case PROP_INSERT_AUD:
self->insert_aud = g_value_get_boolean (value);
break;
case PROP_INSERT_VUI:
self->insert_vui = g_value_get_boolean (value);
break;
/* extended-colorformat property is available for cuvid path only*/
case PROP_EXTENDED_COLORFORMAT:
self->extended_colorformat = g_value_get_boolean (value);
break;
case PROP_ENTROPY_CODING:
self->disable_cabac_entropy_coding = g_value_get_boolean (value);
break;
case PROP_BIT_PACKETIZATION:
self->bit_packetization = g_value_get_boolean (value);
break;
case PROP_SLICE_HEADER_SPACING:
self->slice_header_spacing = g_value_get_uint64 (value);
if (self->slice_header_spacing)
video_enc->slice_output = TRUE;
else
video_enc->slice_output = FALSE;
break;
case PROP_SLICE_INTRA_REFRESH_INTERVAL:
self->SliceIntraRefreshInterval = g_value_get_uint (value);
break;
case PROP_TWO_PASS_CBR:
self->EnableTwopassCBR = g_value_get_boolean (value);
break;
case PROP_ENABLE_MV_META:
self->EnableMVBufferMeta = g_value_get_boolean (value);
video_enc->v4l2capture->enableMVBufferMeta = g_value_get_boolean (value);
break;
case PROP_NUM_REFERENCE_FRAMES:
self->nRefFrames = g_value_get_uint (value);
break;
case PROP_PIC_ORDER_CNT_TYPE:
self->poc_type = g_value_get_uint (value);
break;
case PROP_ENABLE_LOSSLESS_ENC:
self->enableLossless = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static void
gst_v4l2_h264_enc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2H264Enc *self = GST_V4L2_H264_ENC (object);
switch (prop_id) {
case PROP_PROFILE:
g_value_set_enum (value, self->profile);
break;
case PROP_NUM_BFRAMES:
g_value_set_uint (value, self->nBFrames);
break;
case PROP_INSERT_SPS_PPS:
g_value_set_boolean (value, self->insert_sps_pps);
break;
case PROP_INSERT_AUD:
g_value_set_boolean (value, self->insert_aud);
break;
case PROP_INSERT_VUI:
g_value_set_boolean (value, self->insert_vui);
break;
/* extended-colorformat property is available for cuvid path only*/
case PROP_EXTENDED_COLORFORMAT:
g_value_set_boolean (value, self->extended_colorformat);
break;
case PROP_ENTROPY_CODING:
g_value_set_boolean (value, self->disable_cabac_entropy_coding);
break;
case PROP_BIT_PACKETIZATION:
g_value_set_boolean (value, self->bit_packetization);
break;
case PROP_SLICE_HEADER_SPACING:
g_value_set_uint64 (value, self->slice_header_spacing);
break;
case PROP_SLICE_INTRA_REFRESH_INTERVAL:
g_value_set_uint (value, self->SliceIntraRefreshInterval);
break;
case PROP_TWO_PASS_CBR:
g_value_set_boolean (value, self->EnableTwopassCBR);
break;
case PROP_ENABLE_MV_META:
g_value_set_boolean (value, self->EnableMVBufferMeta);
break;
case PROP_NUM_REFERENCE_FRAMES:
g_value_set_uint (value, self->nRefFrames);
break;
case PROP_PIC_ORDER_CNT_TYPE:
g_value_set_uint (value, self->poc_type);
break;
case PROP_ENABLE_LOSSLESS_ENC:
g_value_set_boolean (value, self->enableLossless);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static gint
v4l2_profile_from_string (const gchar * profile)
{
gint v4l2_profile = -1;
if (g_str_equal (profile, "baseline")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
} else if (g_str_equal (profile, "constrained-baseline")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
} else if (g_str_equal (profile, "main")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
} else if (g_str_equal (profile, "extended")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
} else if (g_str_equal (profile, "high")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
} else if (g_str_equal (profile, "high-10")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
} else if (g_str_equal (profile, "high-4:2:2")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
} else if (g_str_equal (profile, "high-4:4:4")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
} else if (g_str_equal (profile, "high-10-intra")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA;
} else if (g_str_equal (profile, "high-4:2:2-intra")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA;
} else if (g_str_equal (profile, "high-4:4:4-intra")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA;
} else if (g_str_equal (profile, "cavlc-4:4:4-intra")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA;
} else if (g_str_equal (profile, "scalable-baseline")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
} else if (g_str_equal (profile, "scalable-high")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
} else if (g_str_equal (profile, "scalable-high-intra")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA;
} else if (g_str_equal (profile, "stereo-high")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
} else if (g_str_equal (profile, "multiview-high")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
} else if (g_str_equal (profile, "constrained-high")) {
v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH;
} else {
GST_WARNING ("Unsupported profile string '%s'", profile);
}
return v4l2_profile;
}
static const gchar *
v4l2_profile_to_string (gint v4l2_profile)
{
switch (v4l2_profile) {
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
return "baseline";
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
return "constrained-baseline";
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
return "main";
case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
return "extended";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
return "high";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
return "high-10";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
return "high-4:2:2";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
return "high-4:4:4";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA:
return "high-10-intra";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA:
return "high-4:2:2-intra";
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA:
return "high-4:4:4-intra";
case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA:
return "cavlc-4:4:4-intra";
case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE:
return "scalable-baseline";
case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH:
return "scalable-high";
case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA:
return "scalable-high-intra";
case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH:
return "stereo-high";
case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH:
return "multiview-high";
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
return "constrained-high";
default:
GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
break;
}
return NULL;
}
static gint
v4l2_level_from_string (const gchar * level)
{
gint v4l2_level = -1;
if (g_str_equal (level, "1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
else if (g_str_equal (level, "1b"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1B;
else if (g_str_equal (level, "1.1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
else if (g_str_equal (level, "1.2"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
else if (g_str_equal (level, "1.3"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
else if (g_str_equal (level, "2"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
else if (g_str_equal (level, "2.1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
else if (g_str_equal (level, "2.2"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
else if (g_str_equal (level, "3"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
else if (g_str_equal (level, "3.1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
else if (g_str_equal (level, "3.2"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
else if (g_str_equal (level, "4"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
else if (g_str_equal (level, "4.1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
else if (g_str_equal (level, "4.2"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
else if (g_str_equal (level, "5"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
else if (g_str_equal (level, "5.1"))
v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
else
GST_WARNING ("Unsupported level '%s'", level);
return v4l2_level;
}
static const gchar *
v4l2_level_to_string (gint v4l2_level)
{
switch (v4l2_level) {
case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
return "1";
case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
return "1b";
case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
return "1.1";
case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
return "1.2";
case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
return "1.3";
case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
return "2";
case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
return "2.1";
case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
return "2.2";
case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
return "3.0";
case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
return "3.1";
case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
return "3.2";
case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
return "4";
case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
return "4.1";
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
return "4.2";
case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
return "5";
case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
return "5.1";
default:
GST_WARNING ("Unsupported V4L2 level %i", v4l2_level);
break;
}
return NULL;
}
static void
gst_v4l2_h264_enc_init (GstV4l2H264Enc * self)
{
#ifdef USE_V4L2_TARGET_NV
self->profile = DEFAULT_PROFILE;
self->insert_sps_pps = FALSE;
self->insert_aud = FALSE;
self->enableLossless = FALSE;
self->nRefFrames = 1;
if (is_cuvid == TRUE)
{
self->extended_colorformat = FALSE;
self->nRefFrames = 0;
self->insert_vui = TRUE;
}
#if !defined(USE_V4L2_TARGET_NV_X86) && !defined(AARCH64_IS_SBSA)
self->insert_vui = FALSE;
#endif
self->nBFrames = 0;
self->bit_packetization = DEFAULT_BIT_PACKETIZATION;
self->slice_header_spacing = DEFAULT_SLICE_HEADER_SPACING;
self->poc_type = DEFAULT_PIC_ORDER_CNT_TYPE;
#endif
}
static void
gst_v4l2_h264_enc_class_init (GstV4l2H264EncClass * klass)
{
GstElementClass *element_class;
GObjectClass *gobject_class;
GstV4l2VideoEncClass *baseclass;
parent_class = g_type_class_peek_parent (klass);
element_class = (GstElementClass *) klass;
gobject_class = (GObjectClass *) klass;
baseclass = (GstV4l2VideoEncClass *) (klass);
GST_DEBUG_CATEGORY_INIT (gst_v4l2_h264_enc_debug, "v4l2h264enc", 0,
"V4L2 H.264 Encoder");
gst_element_class_set_static_metadata (element_class,
"V4L2 H.264 Encoder",
"Codec/Encoder/Video",
"Encode H.264 video streams via V4L2 API", "ayaka <ayaka@soulik.info>");
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_get_property);
#ifdef USE_V4L2_TARGET_NV
g_object_class_install_property (gobject_class, PROP_PROFILE,
g_param_spec_enum ("profile", "profile",
"Set profile for v4l2 encode",
GST_TYPE_V4L2_VID_ENC_PROFILE, DEFAULT_PROFILE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_INSERT_VUI,
g_param_spec_boolean ("insert-vui",
"Insert H.264 VUI",
"Insert H.264 VUI(Video Usability Information) in SPS",
#if !defined(USE_V4L2_TARGET_NV_X86) && !defined(AARCH64_IS_SBSA)
FALSE,
#else
TRUE,
#endif
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INSERT_SPS_PPS,
g_param_spec_boolean ("insert-sps-pps",
"Insert H.264 SPS, PPS",
"Insert H.264 SPS, PPS at every IDR frame",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INSERT_AUD,
g_param_spec_boolean ("insert-aud",
"Insert H.264 AUD",
"Insert H.264 Access Unit Delimiter(AUD)",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_NUM_BFRAMES,
g_param_spec_uint ("num-B-Frames",
"B Frames between two reference frames",
"Number of B Frames between two reference frames (not recommended)",
0, MAX_NUM_B_FRAMES, DEFAULT_NUM_B_FRAMES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_ENTROPY_CODING,
g_param_spec_boolean ("disable-cabac",
"Set Entropy Coding",
"Set Entropy Coding Type CAVLC(TRUE) or CABAC(FALSE)",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BIT_PACKETIZATION,
g_param_spec_boolean ("bit-packetization", "Bit Based Packetization",
"Whether or not Packet size is based upon Number Of bits",
DEFAULT_BIT_PACKETIZATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_SLICE_HEADER_SPACING,
g_param_spec_uint64 ("slice-header-spacing", "Slice Header Spacing",
"Slice Header Spacing number of macroblocks/bits in one packet",
0, G_MAXUINT64, DEFAULT_SLICE_HEADER_SPACING,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_NUM_REFERENCE_FRAMES,
g_param_spec_uint ("num-Ref-Frames",
"Sets the number of reference frames for encoder",
"Number of Reference Frames for encoder",
0, MAX_NUM_REFERENCE_FRAMES, (is_cuvid == TRUE) ? 0 : DEFAULT_NUM_REFERENCE_FRAMES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_ENABLE_LOSSLESS_ENC,
g_param_spec_boolean ("enable-lossless",
"Enable Lossless encoding",
"Enable lossless encoding for YUV444",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_SLICE_INTRA_REFRESH_INTERVAL,
g_param_spec_uint ("SliceIntraRefreshInterval",
"SliceIntraRefreshInterval", "Set SliceIntraRefreshInterval", 0,
G_MAXUINT, DEFAULT_INTRA_REFRESH_FRAME_INTERVAL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
if (is_cuvid == TRUE) {
g_object_class_install_property (gobject_class, PROP_EXTENDED_COLORFORMAT,
g_param_spec_boolean ("extended-colorformat",
"Set Extended ColorFormat",
"Set Extended ColorFormat pixel values 0 to 255 in VUI Info",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} else if (is_cuvid == FALSE) {
g_object_class_install_property (gobject_class, PROP_PIC_ORDER_CNT_TYPE,
g_param_spec_uint ("poc-type",
"Picture Order Count type",
"Set Picture Order Count type value",
0, 2, DEFAULT_PIC_ORDER_CNT_TYPE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_ENABLE_MV_META,
g_param_spec_boolean ("EnableMVBufferMeta",
"Enable Motion Vector Meta data",
"Enable Motion Vector Meta data for encoding",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_TWO_PASS_CBR,
g_param_spec_boolean ("EnableTwopassCBR",
"Enable Two pass CBR",
"Enable two pass CBR while encoding",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
}
#endif
baseclass->codec_name = "H264";
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
baseclass->profile_to_string = v4l2_profile_to_string;
baseclass->profile_from_string = v4l2_profile_from_string;
baseclass->level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
baseclass->level_to_string = v4l2_level_to_string;
baseclass->level_from_string = v4l2_level_from_string;
#ifdef USE_V4L2_TARGET_NV
baseclass->set_encoder_properties = set_v4l2_h264_encoder_properties;
#endif
}
/* Probing functions */
gboolean
gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps)
{
return gst_v4l2_is_video_enc (sink_caps, src_caps,
gst_static_caps_get (&src_template_caps));
}
void
gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
{
gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H264_ENC,
"h264", basename, device_path, sink_caps,
gst_static_caps_get (&src_template_caps), src_caps);
}
#ifdef USE_V4L2_TARGET_NV
static GType
gst_v4l2_videnc_profile_get_type (void)
{
static GType profile = 0;
static const GEnumValue profile_type[] = {
{V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
"GST_V4L2_H264_VIDENC_BASELINE_PROFILE",
"Baseline"},
{V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE,
"GST_V4L2_H264_VIDENC_CONSTRAINED_BASELINE_PROFILE",
"Constrained-Baseline"},
{V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, "GST_V4L2_H264_VIDENC_MAIN_PROFILE",
"Main"},
{V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, "GST_V4L2_H264_VIDENC_HIGH_PROFILE",
"High"},
{V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, "GST_V4L2_H264_VIDENC_CONSTRAINED_HIGH_PROFILE",
"Constrained-High"},
{V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE, "GST_V4L2_H264_VIDENC_HIGH_444_PREDICTIVE_PROFILE",
"High444"},
{0, NULL, NULL}
};
if (g_once_init_enter (&profile)) {
GType tmp =
g_enum_register_static ("GstV4l2VideoEncProfileType", profile_type);
g_once_init_leave (&profile, tmp);
}
return (GType) profile;
}
gboolean
gst_v4l2_h264_enc_slice_header_spacing (GstV4l2Object * v4l2object,
guint32 slice_header_spacing, enum v4l2_enc_slice_length_type slice_length_type)
{
struct v4l2_ext_control control;
struct v4l2_ext_controls ctrls;
gint ret;
v4l2_enc_slice_length_param param =
{ slice_length_type, slice_header_spacing };
memset (&control, 0, sizeof (control));
memset (&ctrls, 0, sizeof (ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_ENABLE_SLICE_LEVEL_ENCODE;
control.value = TRUE;
ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0) {
g_print ("Error while setting spacing and packetization\n");
return FALSE;
}
memset (&control, 0, sizeof (control));
memset (&ctrls, 0, sizeof (ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_SLICE_LENGTH_PARAM;
control.string = (gchar *) &param;
ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0) {
g_print ("Error while setting spacing and packetization\n");
return FALSE;
}
if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) {
v4l2object->format.fmt.pix_mp.plane_fmt[0].sizeimage = slice_header_spacing;
} else {
v4l2object->format.fmt.pix.sizeimage = slice_header_spacing;
}
return TRUE;
}
gboolean
gst_v4l2_h264_enc_slice_intrarefresh (GstV4l2Object * v4l2object,
guint32 slice_count, guint32 slice_interval)
{
struct v4l2_ext_control control;
struct v4l2_ext_controls ctrls;
gint ret;
v4l2_ctrl_intra_refresh cuvid_param = {1, slice_interval, slice_count};
v4l2_enc_slice_intrarefresh_param param = {slice_count};
memset (&control, 0, sizeof (control));
memset (&ctrls, 0, sizeof (ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_SLICE_INTRAREFRESH_PARAM;
if (is_cuvid)
control.string = (gchar *)&cuvid_param;
else
control.string = (gchar *)&param;
ret = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0)
{
g_print("Error while setting slice intrarefresh params\n");
return FALSE;
}
return TRUE;
}
gboolean
set_v4l2_h264_encoder_properties (GstVideoEncoder * encoder)
{
GstV4l2H264Enc *self = GST_V4L2_H264_ENC (encoder);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (encoder);
if (!GST_V4L2_IS_OPEN (video_enc->v4l2output)) {
g_print ("V4L2 device is not open\n");
return FALSE;
}
if (self->profile) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
self->profile)) {
g_print ("S_EXT_CTRLS for H264_PROFILE failed\n");
return FALSE;
}
}
if (self->nBFrames) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_NUM_BFRAMES,
self->nBFrames)) {
g_print ("S_EXT_CTRLS for NUM_BFRAMES failed\n");
return FALSE;
}
}
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_VUI, self->insert_vui)) {
g_print ("S_EXT_CTRLS for INSERT_VUI failed\n");
return FALSE;
}
if (is_cuvid == TRUE) {
if (self->extended_colorformat) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_EXTEDED_COLORFORMAT, 1)) {
g_print ("S_EXT_CTRLS for EXTENDED_COLORFORMAT failed\n");
return FALSE;
}
}
}
if (self->insert_aud) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_AUD, 1)) {
g_print ("S_EXT_CTRLS for INSERT_AUD failed\n");
return FALSE;
}
}
if (self->insert_sps_pps) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_SPS_PPS_AT_IDR, 1)) {
g_print ("S_EXT_CTRLS for SPS_PPS_AT_IDR failed\n");
return FALSE;
}
}
if (self->disable_cabac_entropy_coding) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC)) {
g_print ("S_EXT_CTRLS for ENTROPY_MODE failed\n");
return FALSE;
}
}
if (self->slice_header_spacing) {
enum v4l2_enc_slice_length_type slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_MBLK;
if (self->bit_packetization) {
slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_BITS;
}
if (!gst_v4l2_h264_enc_slice_header_spacing (video_enc->v4l2capture,
self->slice_header_spacing,
slice_length_type)) {
g_print ("S_EXT_CTRLS for SLICE_LENGTH_PARAM failed\n");
return FALSE;
}
}
if (self->EnableMVBufferMeta) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_ENABLE_METADATA_MV,
self->EnableMVBufferMeta)) {
g_print ("S_EXT_CTRLS for ENABLE_METADATA_MV failed\n");
return FALSE;
}
}
if (self->SliceIntraRefreshInterval) {
if (!gst_v4l2_h264_enc_slice_intrarefresh (video_enc->v4l2output,
self->SliceIntraRefreshInterval,
video_enc->idrinterval)) {
g_print ("S_EXT_CTRLS for SLICE_INTRAREFRESH_PARAM failed\n");
return FALSE;
}
}
if (self->EnableTwopassCBR) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_TWO_PASS_CBR, 1)) {
g_print ("S_EXT_CTRLS for TWO_PASS_CBR failed\n");
return FALSE;
}
}
if (self->nRefFrames) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_NUM_REFERENCE_FRAMES,
self->nRefFrames)) {
g_print ("S_EXT_CTRLS for NUM_REFERENCE_FRAMES failed\n");
return FALSE;
}
}
if (self->poc_type) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_POC_TYPE, self->poc_type)) {
g_print ("S_EXT_CTRLS for POC_TYPE failed\n");
return FALSE;
}
}
if (self->enableLossless) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_ENABLE_LOSSLESS, self->enableLossless)) {
g_print ("S_EXT_CTRLS for ENABLE_LOSSLESS failed\n");
return FALSE;
}
}
return TRUE;
}
#endif

79
gst-v4l2/gstv4l2h264enc.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2014 SUMOMO Computer Association.
* Author: ayaka <ayaka@soulik.info>
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#ifndef __GST_V4L2_H264_ENC_H__
#define __GST_V4L2_H264_ENC_H__
#include <gst/gst.h>
#include "gstv4l2videoenc.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_H264_ENC \
(gst_v4l2_h264_enc_get_type())
#define GST_V4L2_H264_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_H264_ENC,GstV4l2H264Enc))
#define GST_V4L2_H264_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_H264_ENC,GstV4l2H264EncClass))
#define GST_IS_V4L2_H264_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_H264_ENC))
#define GST_IS_V4L2_H264_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_H264_ENC))
typedef struct _GstV4l2H264Enc GstV4l2H264Enc;
typedef struct _GstV4l2H264EncClass GstV4l2H264EncClass;
struct _GstV4l2H264Enc
{
GstV4l2VideoEnc parent;
#ifdef USE_V4L2_TARGET_NV
guint profile;
guint nBFrames;
guint nRefFrames;
gboolean insert_sps_pps;
gboolean insert_aud;
gboolean insert_vui;
gboolean extended_colorformat;
gboolean EnableTwopassCBR;
gboolean SliceIntraRefreshEnable;
guint SliceIntraRefreshInterval;
gboolean disable_cabac_entropy_coding;
gboolean bit_packetization;
guint32 slice_header_spacing;
gboolean EnableMVBufferMeta;
guint poc_type;
gboolean enableLossless;
#endif
};
struct _GstV4l2H264EncClass
{
GstV4l2VideoEncClass parent_class;
};
GType gst_v4l2_h264_enc_get_type (void);
gboolean gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps);
void gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_H264_ENC_H__ */

750
gst-v4l2/gstv4l2h265enc.c Normal file
View File

@@ -0,0 +1,750 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "gstv4l2object.h"
#include "gstv4l2h265enc.h"
#include <string.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_v4l2_h265_enc_debug);
#define GST_CAT_DEFAULT gst_v4l2_h265_enc_debug
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-h265, stream-format=(string) byte-stream, "
"alignment=(string) au");
static GType
gst_v4l2_videnc_profile_get_type (void);
#define GST_TYPE_V4L2_VID_ENC_PROFILE (gst_v4l2_videnc_profile_get_type ())
/* prototypes */
gboolean set_v4l2_h265_encoder_properties(GstVideoEncoder * encoder);
gboolean gst_v4l2_h265_enc_slice_header_spacing (GstV4l2Object * v4l2object,
guint32 slice_header_spacing, enum v4l2_enc_slice_length_type slice_length_type);
void set_h265_video_enc_property (GstV4l2Object * v4l2object, guint label,
gint param);
gboolean gst_v4l2_h265_enc_slice_intrarefresh (GstV4l2Object * v4l2object,
guint32 slice_count, guint32 slice_interval);
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
PROP_INSERT_SPS_PPS,
PROP_PROFILE,
PROP_INSERT_VUI,
PROP_EXTENDED_COLORFORMAT,
PROP_INSERT_AUD,
PROP_BIT_PACKETIZATION,
PROP_SLICE_HEADER_SPACING,
PROP_SLICE_INTRA_REFRESH_INTERVAL,
PROP_TWO_PASS_CBR,
PROP_ENABLE_MV_META,
PROP_NUM_BFRAMES,
PROP_NUM_REFERENCE_FRAMES,
PROP_ENABLE_LOSSLESS_ENC
};
#define DEFAULT_PROFILE V4L2_MPEG_VIDEO_H265_PROFILE_MAIN
#define DEFAULT_BIT_PACKETIZATION FALSE
#define DEFAULT_SLICE_HEADER_SPACING 0
#define DEFAULT_INTRA_REFRESH_FRAME_INTERVAL 0
#define DEFAULT_NUM_B_FRAMES 0
#define MAX_NUM_B_FRAMES 2
#define DEFAULT_NUM_REFERENCE_FRAMES 1
#define MAX_NUM_REFERENCE_FRAMES 8
#define gst_v4l2_h265_enc_parent_class parent_class
G_DEFINE_TYPE (GstV4l2H265Enc, gst_v4l2_h265_enc, GST_TYPE_V4L2_VIDEO_ENC);
static void
gst_v4l2_h265_enc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstV4l2H265Enc *self = GST_V4L2_H265_ENC (object);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (object);
switch (prop_id) {
case PROP_INSERT_SPS_PPS:
self->insert_sps_pps = g_value_get_boolean (value);
break;
case PROP_PROFILE:
self->profile = g_value_get_enum (value);
if (GST_V4L2_IS_OPEN(video_enc->v4l2output)) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEO_H265_PROFILE, self->profile)) {
g_print ("S_EXT_CTRLS for H265_PROFILE failed\n");
}
}
break;
case PROP_INSERT_AUD:
self->insert_aud = g_value_get_boolean (value);
break;
case PROP_INSERT_VUI:
self->insert_vui = g_value_get_boolean (value);
break;
/* extended-colorformat property is available for cuvid path only*/
case PROP_EXTENDED_COLORFORMAT:
self->extended_colorformat = g_value_get_boolean (value);
break;
case PROP_BIT_PACKETIZATION:
self->bit_packetization = g_value_get_boolean (value);
break;
case PROP_SLICE_HEADER_SPACING:
self->slice_header_spacing = g_value_get_uint64 (value);
break;
case PROP_SLICE_INTRA_REFRESH_INTERVAL:
self->SliceIntraRefreshInterval = g_value_get_uint (value);
break;
case PROP_TWO_PASS_CBR:
self->EnableTwopassCBR = g_value_get_boolean (value);
break;
case PROP_ENABLE_MV_META:
self->EnableMVBufferMeta = g_value_get_boolean (value);
video_enc->v4l2capture->enableMVBufferMeta = g_value_get_boolean (value);
break;
case PROP_NUM_BFRAMES:
self->nBFrames = g_value_get_uint (value);
if (self->nBFrames && (self->nRefFrames == DEFAULT_NUM_REFERENCE_FRAMES)) {
// Minimum 2 Ref-Frames are required for B-frames encoding
self->nRefFrames = 2;
}
break;
case PROP_NUM_REFERENCE_FRAMES:
self->nRefFrames = g_value_get_uint (value);
break;
case PROP_ENABLE_LOSSLESS_ENC:
self->enableLossless = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_v4l2_h265_enc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstV4l2H265Enc *self = GST_V4L2_H265_ENC (object);
switch (prop_id) {
case PROP_INSERT_SPS_PPS:
g_value_set_boolean (value, self->insert_sps_pps);
break;
case PROP_PROFILE:
g_value_set_enum (value, self->profile);
break;
case PROP_INSERT_AUD:
g_value_set_boolean (value, self->insert_aud);
break;
case PROP_INSERT_VUI:
g_value_set_boolean (value, self->insert_vui);
break;
/* extended-colorformat property is available for cuvid path only*/
case PROP_EXTENDED_COLORFORMAT:
g_value_set_boolean (value, self->extended_colorformat);
break;
case PROP_BIT_PACKETIZATION:
g_value_set_boolean (value, self->bit_packetization);
break;
case PROP_SLICE_HEADER_SPACING:
g_value_set_uint64 (value, self->slice_header_spacing);
break;
case PROP_SLICE_INTRA_REFRESH_INTERVAL:
g_value_set_uint (value, self->SliceIntraRefreshInterval);
break;
case PROP_TWO_PASS_CBR:
g_value_set_boolean (value, self->EnableTwopassCBR);
break;
case PROP_ENABLE_MV_META:
g_value_set_boolean (value, self->EnableMVBufferMeta);
break;
case PROP_NUM_BFRAMES:
g_value_set_uint (value, self->nBFrames);
break;
case PROP_NUM_REFERENCE_FRAMES:
g_value_set_uint (value, self->nRefFrames);
break;
case PROP_ENABLE_LOSSLESS_ENC:
g_value_set_boolean (value, self->enableLossless);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gint
v4l2_profile_from_string (const gchar * profile)
{
gint v4l2_profile = -1;
if (g_str_equal (profile, "main")) {
v4l2_profile = V4L2_MPEG_VIDEO_H265_PROFILE_MAIN;
} else if (g_str_equal (profile, "main10")) {
v4l2_profile = V4L2_MPEG_VIDEO_H265_PROFILE_MAIN10;
} else if (g_str_equal (profile, "mainstillpicture")) {
v4l2_profile = V4L2_MPEG_VIDEO_H265_PROFILE_MAINSTILLPICTURE;
} else if (g_str_equal (profile, "frext")) {
v4l2_profile = V4L2_MPEG_VIDEO_H265_PROFILE_FREXT;
} else {
GST_WARNING ("Unsupported profile string '%s'", profile);
}
return v4l2_profile;
}
static const gchar *
v4l2_profile_to_string (gint v4l2_profile)
{
switch (v4l2_profile) {
case V4L2_MPEG_VIDEO_H265_PROFILE_MAIN:
return "main";
case V4L2_MPEG_VIDEO_H265_PROFILE_MAIN10:
return "main10";
case V4L2_MPEG_VIDEO_H265_PROFILE_MAINSTILLPICTURE:
return "mainstillpicture";
case V4L2_MPEG_VIDEO_H265_PROFILE_FREXT:
return "frext";
default:
GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
break;
}
return NULL;
}
static gint
v4l2_level_from_string (const gchar * level)
{
gint v4l2_level = -1;
#ifdef USE_V4L2_TARGET_NV
if (g_str_equal(level, "main_1.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_1_0_MAIN_TIER;
} else if (g_str_equal(level, "high_1.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_1_0_HIGH_TIER;
} else if (g_str_equal(level, "main_2.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_2_0_MAIN_TIER;
} else if (g_str_equal(level, "high_2.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_2_0_HIGH_TIER;
} else if (g_str_equal(level, "main_2.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_2_1_MAIN_TIER;
} else if (g_str_equal(level, "high_2.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_2_1_HIGH_TIER;
} else if (g_str_equal(level, "main_3.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_3_0_MAIN_TIER;
} else if (g_str_equal(level, "high_3.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_3_0_HIGH_TIER;
} else if (g_str_equal(level, "main_3.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_3_1_MAIN_TIER;
} else if (g_str_equal(level, "high_3.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_3_1_HIGH_TIER;
} else if (g_str_equal(level, "main_4.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_4_0_MAIN_TIER;
} else if (g_str_equal(level, "high_4.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_4_0_HIGH_TIER;
} else if (g_str_equal(level, "main_4.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_4_1_MAIN_TIER;
} else if (g_str_equal(level, "high_4.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_4_1_HIGH_TIER;
} else if (g_str_equal(level, "main_5.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_0_MAIN_TIER;
} else if (g_str_equal(level, "high_5.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_0_HIGH_TIER;
} else if (g_str_equal(level, "main_5.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_1_MAIN_TIER;
} else if (g_str_equal(level, "high_5.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_1_HIGH_TIER;
} else if (g_str_equal(level, "main_5.2")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_2_MAIN_TIER;
} else if (g_str_equal(level, "high_5.2")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_5_2_HIGH_TIER;
} else if (g_str_equal(level, "main_6.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_0_MAIN_TIER;
} else if (g_str_equal(level, "high_6.0")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_0_HIGH_TIER;
} else if (g_str_equal(level, "main_6.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_1_MAIN_TIER;
} else if (g_str_equal(level, "high_6.1")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_1_HIGH_TIER;
} else if (g_str_equal(level, "main_6.2")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_2_MAIN_TIER;
} else if (g_str_equal(level, "high_6.2")) {
v4l2_level = V4L2_MPEG_VIDEO_H265_LEVEL_6_2_HIGH_TIER;
} else
{
GST_WARNING("Unsupported level string '%s'", level);
}
#endif
return v4l2_level;
}
static const gchar *
v4l2_level_to_string (gint v4l2_level)
{
#ifdef USE_V4L2_TARGET_NV
switch (v4l2_level)
{
case V4L2_MPEG_VIDEO_H265_LEVEL_1_0_MAIN_TIER:
return "main_1.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_1_0_HIGH_TIER:
return "high_1.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_2_0_MAIN_TIER:
return "main_2.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_2_0_HIGH_TIER:
return "high_2.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_2_1_MAIN_TIER:
return "main_2.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_2_1_HIGH_TIER:
return "high_2.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_3_0_MAIN_TIER:
return "main_3.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_3_0_HIGH_TIER:
return "high_3.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_3_1_MAIN_TIER:
return "main_3.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_3_1_HIGH_TIER:
return "high_3.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_4_0_MAIN_TIER:
return "main_4.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_4_0_HIGH_TIER:
return "high_4.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_4_1_MAIN_TIER:
return "main_4.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_4_1_HIGH_TIER:
return "high_4.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_0_MAIN_TIER:
return "main_5.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_0_HIGH_TIER:
return "high_5.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_1_MAIN_TIER:
return "main_5.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_1_HIGH_TIER:
return "high_5.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_2_MAIN_TIER:
return "main_5.2";
case V4L2_MPEG_VIDEO_H265_LEVEL_5_2_HIGH_TIER:
return "high_5.2";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_0_MAIN_TIER:
return "main_6.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_0_HIGH_TIER:
return "high_6.0";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_1_MAIN_TIER:
return "main_6.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_1_HIGH_TIER:
return "high_6.1";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_2_MAIN_TIER:
return "main_6.2";
case V4L2_MPEG_VIDEO_H265_LEVEL_6_2_HIGH_TIER:
return "high_6.2";
default:
GST_WARNING("Unsupported V4L2 level %i", v4l2_level);
break;
}
#endif
return NULL;
}
static void
gst_v4l2_h265_enc_init (GstV4l2H265Enc * self)
{
self->insert_sps_pps = FALSE;
self->profile = DEFAULT_PROFILE;
self->insert_aud = FALSE;
self->extended_colorformat = FALSE;
self->bit_packetization = DEFAULT_BIT_PACKETIZATION;
self->slice_header_spacing = DEFAULT_SLICE_HEADER_SPACING;
self->nRefFrames = 1;
self->nBFrames = 0;
self->enableLossless = FALSE;
if (is_cuvid == TRUE)
{
self->extended_colorformat = FALSE;
self->nRefFrames = 0;
self->insert_vui = TRUE;
}
#if !defined(USE_V4L2_TARGET_NV_X86) && !defined(AARCH64_IS_SBSA)
self->insert_vui = FALSE;
#endif
}
static void
gst_v4l2_h265_enc_class_init (GstV4l2H265EncClass * klass)
{
GstElementClass *element_class;
GObjectClass *gobject_class;
GstV4l2VideoEncClass *baseclass;
parent_class = g_type_class_peek_parent (klass);
element_class = (GstElementClass *) klass;
gobject_class = (GObjectClass *) klass;
baseclass = (GstV4l2VideoEncClass *) (klass);
GST_DEBUG_CATEGORY_INIT (gst_v4l2_h265_enc_debug, "v4l2h265enc", 0,
"V4L2 H.265 Encoder");
gst_element_class_set_static_metadata (element_class,
"V4L2 H.265 Encoder",
"Codec/Encoder/Video",
"Encode H.265 video streams via V4L2 API",
"Viranjan Pagar <vpagar@nvidia.com>, Amit Pandya <apandya@nvidia.com>");
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_v4l2_h265_enc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_v4l2_h265_enc_get_property);
#ifdef USE_V4L2_TARGET_NV
g_object_class_install_property (gobject_class, PROP_PROFILE,
g_param_spec_enum ("profile", "profile",
"Set profile for v4l2 encode",
GST_TYPE_V4L2_VID_ENC_PROFILE, DEFAULT_PROFILE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_INSERT_SPS_PPS,
g_param_spec_boolean ("insert-sps-pps",
"Insert H.265 SPS, PPS",
"Insert H.265 SPS, PPS at every IDR frame",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INSERT_VUI,
g_param_spec_boolean ("insert-vui",
"Insert H.265 VUI",
"Insert H.265 VUI(Video Usability Information) in SPS",
(is_cuvid == TRUE) ? TRUE : FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INSERT_AUD,
g_param_spec_boolean ("insert-aud",
"Insert H.265 AUD",
"Insert H.265 Access Unit Delimiter(AUD)",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BIT_PACKETIZATION,
g_param_spec_boolean ("bit-packetization", "Bit Based Packetization",
"Whether or not Packet size is based upon Number Of bits",
DEFAULT_BIT_PACKETIZATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_SLICE_HEADER_SPACING,
g_param_spec_uint64 ("slice-header-spacing", "Slice Header Spacing",
"Slice Header Spacing number of macroblocks/bits in one packet",
0, G_MAXUINT64, DEFAULT_SLICE_HEADER_SPACING,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_NUM_BFRAMES,
g_param_spec_uint ("num-B-Frames",
"B Frames between two reference frames",
"Number of B Frames between two reference frames (not recommended)(Supported only on Xavier)",
0, MAX_NUM_B_FRAMES, DEFAULT_NUM_B_FRAMES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_NUM_REFERENCE_FRAMES,
g_param_spec_uint ("num-Ref-Frames",
"Sets the number of reference frames for encoder",
"Number of Reference Frames for encoder",
0, MAX_NUM_REFERENCE_FRAMES, (is_cuvid == TRUE) ? 0 : DEFAULT_NUM_REFERENCE_FRAMES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_ENABLE_LOSSLESS_ENC,
g_param_spec_boolean ("enable-lossless",
"Enable Lossless encoding",
"Enable lossless encoding for YUV444",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_SLICE_INTRA_REFRESH_INTERVAL,
g_param_spec_uint ("SliceIntraRefreshInterval",
"SliceIntraRefreshInterval", "Set SliceIntraRefreshInterval", 0,
G_MAXUINT, DEFAULT_INTRA_REFRESH_FRAME_INTERVAL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
if (is_cuvid == TRUE) {
g_object_class_install_property (gobject_class, PROP_EXTENDED_COLORFORMAT,
g_param_spec_boolean ("extended-colorformat",
"Set Extended ColorFormat",
"Set Extended ColorFormat pixel values 0 to 255 in VUI info",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} else if (is_cuvid == FALSE) {
g_object_class_install_property (gobject_class, PROP_ENABLE_MV_META,
g_param_spec_boolean ("EnableMVBufferMeta",
"Enable Motion Vector Meta data",
"Enable Motion Vector Meta data for encoding",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
g_object_class_install_property (gobject_class, PROP_TWO_PASS_CBR,
g_param_spec_boolean ("EnableTwopassCBR",
"Enable Two pass CBR",
"Enable two pass CBR while encoding",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
}
#endif
baseclass->codec_name = "H265";
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_H265_PROFILE;
baseclass->profile_to_string = v4l2_profile_to_string;
baseclass->profile_from_string = v4l2_profile_from_string;
baseclass->level_cid = V4L2_CID_MPEG_VIDEOENC_H265_LEVEL;
baseclass->level_to_string = v4l2_level_to_string;
baseclass->level_from_string = v4l2_level_from_string;
baseclass->set_encoder_properties = set_v4l2_h265_encoder_properties;
}
/* Probing functions */
gboolean
gst_v4l2_is_h265_enc (GstCaps * sink_caps, GstCaps * src_caps)
{
return gst_v4l2_is_video_enc (sink_caps, src_caps,
gst_static_caps_get (&src_template_caps));
}
void
gst_v4l2_h265_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
{
gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H265_ENC,
"h265", basename, device_path, sink_caps,
gst_static_caps_get (&src_template_caps), src_caps);
}
static GType
gst_v4l2_videnc_profile_get_type (void)
{
static GType profile = 0;
static const GEnumValue profile_type[] = {
{V4L2_MPEG_VIDEO_H265_PROFILE_MAIN,
"GST_V4L2_H265_VIDENC_MAIN_PROFILE", "Main"},
{V4L2_MPEG_VIDEO_H265_PROFILE_MAIN10,
"GST_V4L2_H265_VIDENC_MAIN10_PROFILE", "Main10"},
{V4L2_MPEG_VIDEO_H265_PROFILE_FREXT,
"GST_V4L2_H265_VIDENC_FREXT_PROFILE", "FREXT"},
{0, NULL, NULL}
};
if (g_once_init_enter (&profile)) {
GType tmp =
g_enum_register_static ("GstV4L2VideoEncProfileType", profile_type);
g_once_init_leave (&profile, tmp);
}
return (GType) profile;
}
gboolean
gst_v4l2_h265_enc_slice_header_spacing (GstV4l2Object * v4l2object,
guint32 slice_header_spacing, enum v4l2_enc_slice_length_type slice_length_type)
{
struct v4l2_ext_control control;
struct v4l2_ext_controls ctrls;
gint ret;
v4l2_enc_slice_length_param param =
{ slice_length_type, slice_header_spacing };
memset (&control, 0, sizeof (control));
memset (&ctrls, 0, sizeof (ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_SLICE_LENGTH_PARAM;
control.string = (gchar *) &param;
ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0) {
g_print ("Error while setting spacing and packetization\n");
return FALSE;
}
return TRUE;
}
gboolean
gst_v4l2_h265_enc_slice_intrarefresh(GstV4l2Object *v4l2object,
guint32 slice_count, guint32 slice_interval)
{
struct v4l2_ext_control control;
struct v4l2_ext_controls ctrls;
gint ret;
v4l2_ctrl_intra_refresh cuvid_param = {1, slice_interval, slice_count};
v4l2_enc_slice_intrarefresh_param param = {slice_count};
memset(&control, 0, sizeof(control));
memset(&ctrls, 0, sizeof(ctrls));
ctrls.count = 1;
ctrls.controls = &control;
ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
control.id = V4L2_CID_MPEG_VIDEOENC_SLICE_INTRAREFRESH_PARAM;
if (is_cuvid)
control.string = (gchar *)&cuvid_param;
else
control.string = (gchar *)&param;
ret = v4l2object->ioctl(v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
if (ret < 0)
{
g_print("Error while setting slice intrarefresh params\n");
return FALSE;
}
return TRUE;
}
gboolean
set_v4l2_h265_encoder_properties (GstVideoEncoder * encoder)
{
GstV4l2H265Enc *self = GST_V4L2_H265_ENC (encoder);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (encoder);
if (!GST_V4L2_IS_OPEN (video_enc->v4l2output)) {
g_print ("V4L2 device is not open\n");
return FALSE;
}
if (self->insert_sps_pps) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_SPS_PPS_AT_IDR, 1)) {
g_print ("S_EXT_CTRLS for INSERT_SPS_PPS_AT_IDR failed\n");
return FALSE;
}
}
if (self->profile) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEO_H265_PROFILE, self->profile)) {
g_print ("S_EXT_CTRLS for H265_PROFILE failed\n");
return FALSE;
}
}
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_VUI, self->insert_vui)) {
g_print ("S_EXT_CTRLS for INSERT_VUI failed\n");
return FALSE;
}
if (self->extended_colorformat) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_EXTEDED_COLORFORMAT, 1)) {
g_print ("S_EXT_CTRLS for EXTENDED_COLORFORMAT failed\n");
return FALSE;
}
}
if (self->insert_aud) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_INSERT_AUD, 1)) {
g_print ("S_EXT_CTRLS for INSERT_AUD failed\n");
return FALSE;
}
}
if (self->slice_header_spacing) {
enum v4l2_enc_slice_length_type slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_MBLK;
if (self->bit_packetization) {
slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_BITS;
}
if (!gst_v4l2_h265_enc_slice_header_spacing (video_enc->v4l2output,
self->slice_header_spacing, slice_length_type)) {
g_print ("S_EXT_CTRLS for SLICE_LENGTH_PARAM failed\n");
return FALSE;
}
}
if (self->EnableMVBufferMeta) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_ENABLE_METADATA_MV,
self->EnableMVBufferMeta)) {
g_print ("S_EXT_CTRLS for ENABLE_METADATA_MV failed\n");
return FALSE;
}
}
if (self->SliceIntraRefreshInterval) {
if (!gst_v4l2_h265_enc_slice_intrarefresh (video_enc->v4l2output,
self->SliceIntraRefreshInterval,
video_enc->idrinterval)) {
g_print ("S_EXT_CTRLS for SLICE_INTRAREFRESH_PARAM failed\n");
return FALSE;
}
}
if (self->EnableTwopassCBR) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_TWO_PASS_CBR, 1)) {
g_print ("S_EXT_CTRLS for TWO_PASS_CBR failed\n");
return FALSE;
}
}
if (self->nBFrames) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_NUM_BFRAMES,
self->nBFrames)) {
g_print ("S_EXT_CTRLS for NUM_BFRAMES failed\n");
return FALSE;
}
}
if (self->nRefFrames) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_NUM_REFERENCE_FRAMES,
self->nRefFrames)) {
g_print ("S_EXT_CTRLS for NUM_REFERENCE_FRAMES failed\n");
return FALSE;
}
}
if (self->enableLossless) {
if (!set_v4l2_video_mpeg_class (video_enc->v4l2output,
V4L2_CID_MPEG_VIDEOENC_ENABLE_LOSSLESS, self->enableLossless)) {
g_print ("S_EXT_CTRLS for ENABLE_LOSSLESS failed\n");
return FALSE;
}
}
return TRUE;
}

73
gst-v4l2/gstv4l2h265enc.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#ifndef __GST_V4L2_H265_ENC_H__
#define __GST_V4L2_H265_ENC_H__
#include <gst/gst.h>
#include "gstv4l2videoenc.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_H265_ENC \
(gst_v4l2_h265_enc_get_type())
#define GST_V4L2_H265_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_H265_ENC,GstV4l2H265Enc))
#define GST_V4L2_H265_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_H265_ENC,GstV4l2H265EncClass))
#define GST_IS_V4L2_H265_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_H265_ENC))
#define GST_IS_V4L2_H265_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_H265_ENC))
typedef struct _GstV4l2H265Enc GstV4l2H265Enc;
typedef struct _GstV4l2H265EncClass GstV4l2H265EncClass;
struct _GstV4l2H265Enc
{
GstV4l2VideoEnc parent;
gboolean insert_sps_pps;
guint profile;
guint level;
guint nBFrames;
guint nRefFrames;
gboolean insert_aud;
gboolean insert_vui;
gboolean extended_colorformat;
guint SliceIntraRefreshInterval;
gboolean EnableTwopassCBR;
gboolean bit_packetization;
guint32 slice_header_spacing;
gboolean EnableMVBufferMeta;
gboolean enableLossless;
};
struct _GstV4l2H265EncClass
{
GstV4l2VideoEncClass parent_class;
};
GType gst_v4l2_h265_enc_get_type (void);
gboolean gst_v4l2_is_h265_enc (GstCaps * sink_caps, GstCaps * src_caps);
void gst_v4l2_h265_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_H265_ENC_H__ */

View File

@@ -0,0 +1,896 @@
/*
* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
*
* 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
#include "nalutils.h"
#include "gstv4l2h26xparser.h"
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbitreader.h>
#include <string.h>
#include <math.h>
GST_DEBUG_CATEGORY_STATIC (h26x_parser_debug);
#define GST_CAT_DEFAULT h26x_parser_debug
static gboolean initialized = FALSE;
#define INITIALIZE_DEBUG_CATEGORY \
if (!initialized) { \
GST_DEBUG_CATEGORY_INIT (h26x_parser_debug, "codecparsers_h26x", 0, \
"h26x parser library"); \
initialized = TRUE; \
}
/**** Default scaling_lists according to Table 7-2 *****/
static const guint8 default_4x4_intra[16] = {
6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32,
32, 37, 37, 42
};
static const guint8 default_4x4_inter[16] = {
10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27,
27, 30, 30, 34
};
static const guint8 default_8x8_intra[64] = {
6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18,
18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27,
27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33,
33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42
};
static const guint8 default_8x8_inter[64] = {
9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19,
19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24,
24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28,
28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35
};
/***** Utils ****/
#define EXTENDED_SAR 255
static gboolean
h264_parse_nalu_header (H264NalUnit * nalu)
{
guint8 *data = nalu->data + nalu->offset;
if (nalu->size < 1)
return FALSE;
nalu->type = (data[0] & 0x1f);
nalu->ref_idc = (data[0] & 0x60) >> 5;
nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0);
nalu->header_bytes = 1;
nalu->extension_type = H264_NAL_EXTENSION_NONE;
GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc);
return TRUE;
}
static gboolean
h264_parser_parse_scaling_list (NalReader * nr,
guint8 scaling_lists_4x4[6][16], guint8 scaling_lists_8x8[6][64],
const guint8 fallback_4x4_inter[16], const guint8 fallback_4x4_intra[16],
const guint8 fallback_8x8_inter[64], const guint8 fallback_8x8_intra[64],
guint8 n_lists)
{
guint i;
static const guint8 *default_lists[12] = {
default_4x4_intra, default_4x4_intra, default_4x4_intra,
default_4x4_inter, default_4x4_inter, default_4x4_inter,
default_8x8_intra, default_8x8_inter,
default_8x8_intra, default_8x8_inter,
default_8x8_intra, default_8x8_inter
};
GST_DEBUG ("parsing scaling lists");
for (i = 0; i < 12; i++) {
gboolean use_default = FALSE;
if (i < n_lists) {
guint8 scaling_list_present_flag;
READ_UINT8 (nr, scaling_list_present_flag, 1);
if (scaling_list_present_flag) {
guint8 *scaling_list;
guint size;
guint j;
guint8 last_scale, next_scale;
if (i < 6) {
scaling_list = scaling_lists_4x4[i];
size = 16;
} else {
scaling_list = scaling_lists_8x8[i - 6];
size = 64;
}
last_scale = 8;
next_scale = 8;
for (j = 0; j < size; j++) {
if (next_scale != 0) {
gint32 delta_scale;
READ_SE (nr, delta_scale);
next_scale = (last_scale + delta_scale) & 0xff;
}
if (j == 0 && next_scale == 0) {
/* Use default scaling lists (7.4.2.1.1.1) */
memcpy (scaling_list, default_lists[i], size);
break;
}
last_scale = scaling_list[j] =
(next_scale == 0) ? last_scale : next_scale;
}
} else
use_default = TRUE;
} else
use_default = TRUE;
if (use_default) {
switch (i) {
case 0:
memcpy (scaling_lists_4x4[0], fallback_4x4_intra, 16);
break;
case 1:
memcpy (scaling_lists_4x4[1], scaling_lists_4x4[0], 16);
break;
case 2:
memcpy (scaling_lists_4x4[2], scaling_lists_4x4[1], 16);
break;
case 3:
memcpy (scaling_lists_4x4[3], fallback_4x4_inter, 16);
break;
case 4:
memcpy (scaling_lists_4x4[4], scaling_lists_4x4[3], 16);
break;
case 5:
memcpy (scaling_lists_4x4[5], scaling_lists_4x4[4], 16);
break;
case 6:
memcpy (scaling_lists_8x8[0], fallback_8x8_intra, 64);
break;
case 7:
memcpy (scaling_lists_8x8[1], fallback_8x8_inter, 64);
break;
case 8:
memcpy (scaling_lists_8x8[2], scaling_lists_8x8[0], 64);
break;
case 9:
memcpy (scaling_lists_8x8[3], scaling_lists_8x8[1], 64);
break;
case 10:
memcpy (scaling_lists_8x8[4], scaling_lists_8x8[2], 64);
break;
case 11:
memcpy (scaling_lists_8x8[5], scaling_lists_8x8[3], 64);
break;
default:
break;
}
}
}
return TRUE;
error:
GST_WARNING ("error parsing scaling lists");
return FALSE;
}
H264NalParser *
h264_nal_parser_new (void)
{
H264NalParser *nalparser;
nalparser = g_slice_new0 (H264NalParser);
INITIALIZE_DEBUG_CATEGORY;
return nalparser;
}
void
h264_nal_parser_free (H264NalParser * nalparser)
{
guint i;
for (i = 0; i < H264_MAX_SPS_COUNT; i++)
h264_sps_clear (&nalparser->sps[i]);
g_slice_free (H264NalParser, nalparser);
nalparser = NULL;
}
H264ParserResult
h264_parser_identify_nalu_unchecked (H264NalParser * nalparser,
const guint8 * data, guint offset, gsize size, H264NalUnit * nalu)
{
gint off1;
memset (nalu, 0, sizeof (*nalu));
if (size < offset + 4) {
GST_DEBUG ("Can't parse, buffer has too small size %" G_GSIZE_FORMAT
", offset %u", size, offset);
return H264_PARSER_ERROR;
}
off1 = scan_for_start_codes (data + offset, size - offset);
if (off1 < 0) {
GST_DEBUG ("No start code prefix in this buffer");
return H264_PARSER_NO_NAL;
}
if (offset + off1 == size - 1) {
GST_DEBUG ("Missing data to identify nal unit");
return H264_PARSER_ERROR;
}
nalu->sc_offset = offset + off1;
nalu->offset = offset + off1 + 3;
nalu->data = (guint8 *) data;
nalu->size = size - nalu->offset;
if (!h264_parse_nalu_header (nalu)) {
GST_WARNING ("error parsing \"NAL unit header\"");
nalu->size = 0;
return H264_PARSER_BROKEN_DATA;
}
nalu->valid = TRUE;
/* sc might have 2 or 3 0-bytes */
if (nalu->sc_offset > 0 && data[nalu->sc_offset - 1] == 00
&& (nalu->type == H264_NAL_SPS || nalu->type == H264_NAL_PPS
|| nalu->type == H264_NAL_AU_DELIMITER))
nalu->sc_offset--;
if (nalu->type == H264_NAL_SEQ_END ||
nalu->type == H264_NAL_STREAM_END) {
GST_DEBUG ("end-of-seq or end-of-stream nal found");
nalu->size = 1;
return H264_PARSER_OK;
}
return H264_PARSER_OK;
}
H264ParserResult
h264_parser_identify_nalu (H264NalParser * nalparser,
const guint8 * data, guint offset, gsize size, H264NalUnit * nalu)
{
H264ParserResult res;
gint off2;
res =
h264_parser_identify_nalu_unchecked (nalparser, data, offset, size,
nalu);
if (res != H264_PARSER_OK)
goto beach;
/* The two NALs are exactly 1 byte size and are placed at the end of an AU,
* there is no need to wait for the following */
if (nalu->type == H264_NAL_SEQ_END ||
nalu->type == H264_NAL_STREAM_END)
goto beach;
off2 = scan_for_start_codes (data + nalu->offset, size - nalu->offset);
if (off2 < 0) {
GST_DEBUG ("Nal start %d, No end found", nalu->offset);
return H264_PARSER_NO_NAL_END;
}
/* Mini performance improvement:
* We could have a way to store how many 0s were skipped to avoid
* parsing them again on the next NAL */
while (off2 > 0 && data[nalu->offset + off2 - 1] == 00)
off2--;
nalu->size = off2;
if (nalu->size < 2)
return H264_PARSER_BROKEN_DATA;
GST_DEBUG ("Complete nal found. Off: %d, Size: %d", nalu->offset, nalu->size);
beach:
return res;
}
H264ParserResult
h264_parser_parse_sps (H264NalUnit * nalu,
H264SPS * sps, gboolean parse_vui_params)
{
H264ParserResult res = h264_parse_sps (nalu, sps, parse_vui_params);
return res;
}
/* Parse seq_parameter_set_data() */
static gboolean
h264_parse_sps_data (NalReader * nr, H264SPS * sps,
gboolean parse_vui_params)
{
gint width, height;
guint subwc[] = { 1, 2, 2, 1 };
guint subhc[] = { 1, 2, 1, 1 };
memset (sps, 0, sizeof (*sps));
/* set default values for fields that might not be present in the bitstream
and have valid defaults */
sps->extension_type = H264_NAL_EXTENSION_NONE;
sps->chroma_format_idc = 1;
memset (sps->scaling_lists_4x4, 16, 96);
memset (sps->scaling_lists_8x8, 16, 384);
READ_UINT8 (nr, sps->profile_idc, 8);
READ_UINT8 (nr, sps->constraint_set0_flag, 1);
READ_UINT8 (nr, sps->constraint_set1_flag, 1);
READ_UINT8 (nr, sps->constraint_set2_flag, 1);
READ_UINT8 (nr, sps->constraint_set3_flag, 1);
READ_UINT8 (nr, sps->constraint_set4_flag, 1);
READ_UINT8 (nr, sps->constraint_set5_flag, 1);
/* skip reserved_zero_2bits */
if (!_skip (nr, 2))
goto error;
READ_UINT8 (nr, sps->level_idc, 8);
READ_UE_MAX (nr, sps->id, H264_MAX_SPS_COUNT - 1);
if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
sps->profile_idc == 122 || sps->profile_idc == 244 ||
sps->profile_idc == 44 || sps->profile_idc == 83 ||
sps->profile_idc == 86 || sps->profile_idc == 118 ||
sps->profile_idc == 128) {
READ_UE_MAX (nr, sps->chroma_format_idc, 3);
if (sps->chroma_format_idc == 3)
READ_UINT8 (nr, sps->separate_colour_plane_flag, 1);
READ_UE_MAX (nr, sps->bit_depth_luma_minus8, 6);
READ_UE_MAX (nr, sps->bit_depth_chroma_minus8, 6);
READ_UINT8 (nr, sps->qpprime_y_zero_transform_bypass_flag, 1);
READ_UINT8 (nr, sps->scaling_matrix_present_flag, 1);
if (sps->scaling_matrix_present_flag) {
guint8 n_lists;
n_lists = (sps->chroma_format_idc != 3) ? 8 : 12;
if (!h264_parser_parse_scaling_list (nr,
sps->scaling_lists_4x4, sps->scaling_lists_8x8,
default_4x4_inter, default_4x4_intra,
default_8x8_inter, default_8x8_intra, n_lists))
goto error;
}
}
READ_UE_MAX (nr, sps->log2_max_frame_num_minus4, 12);
sps->max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
READ_UE_MAX (nr, sps->pic_order_cnt_type, 2);
if (sps->pic_order_cnt_type == 0) {
READ_UE_MAX (nr, sps->log2_max_pic_order_cnt_lsb_minus4, 12);
} else if (sps->pic_order_cnt_type == 1) {
guint i;
READ_UINT8 (nr, sps->delta_pic_order_always_zero_flag, 1);
READ_SE (nr, sps->offset_for_non_ref_pic);
READ_SE (nr, sps->offset_for_top_to_bottom_field);
READ_UE_MAX (nr, sps->num_ref_frames_in_pic_order_cnt_cycle, 255);
for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
READ_SE (nr, sps->offset_for_ref_frame[i]);
}
READ_UE (nr, sps->num_ref_frames);
READ_UINT8 (nr, sps->gaps_in_frame_num_value_allowed_flag, 1);
READ_UE (nr, sps->pic_width_in_mbs_minus1);
READ_UE (nr, sps->pic_height_in_map_units_minus1);
READ_UINT8 (nr, sps->frame_mbs_only_flag, 1);
if (!sps->frame_mbs_only_flag)
READ_UINT8 (nr, sps->mb_adaptive_frame_field_flag, 1);
READ_UINT8 (nr, sps->direct_8x8_inference_flag, 1);
READ_UINT8 (nr, sps->frame_cropping_flag, 1);
if (sps->frame_cropping_flag) {
READ_UE (nr, sps->frame_crop_left_offset);
READ_UE (nr, sps->frame_crop_right_offset);
READ_UE (nr, sps->frame_crop_top_offset);
READ_UE (nr, sps->frame_crop_bottom_offset);
}
/* calculate ChromaArrayType */
if (!sps->separate_colour_plane_flag)
sps->chroma_array_type = sps->chroma_format_idc;
/* Calculate width and height */
width = (sps->pic_width_in_mbs_minus1 + 1);
width *= 16;
height = (sps->pic_height_in_map_units_minus1 + 1);
height *= 16 * (2 - sps->frame_mbs_only_flag);
GST_LOG ("initial width=%d, height=%d", width, height);
if (width < 0 || height < 0) {
GST_WARNING ("invalid width/height in SPS");
goto error;
}
sps->width = width;
sps->height = height;
if (sps->frame_cropping_flag) {
const guint crop_unit_x = subwc[sps->chroma_format_idc];
const guint crop_unit_y =
subhc[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag);
width -= (sps->frame_crop_left_offset + sps->frame_crop_right_offset)
* crop_unit_x;
height -= (sps->frame_crop_top_offset + sps->frame_crop_bottom_offset)
* crop_unit_y;
sps->crop_rect_width = width;
sps->crop_rect_height = height;
sps->crop_rect_x = sps->frame_crop_left_offset * crop_unit_x;
sps->crop_rect_y = sps->frame_crop_top_offset * crop_unit_y;
GST_LOG ("crop_rectangle x=%u y=%u width=%u, height=%u", sps->crop_rect_x,
sps->crop_rect_y, width, height);
}
sps->fps_num_removed = 0;
sps->fps_den_removed = 1;
return TRUE;
error:
return FALSE;
}
H264ParserResult
h264_parse_sps (H264NalUnit * nalu, H264SPS * sps,
gboolean parse_vui_params)
{
NalReader nr;
INITIALIZE_DEBUG_CATEGORY;
GST_DEBUG ("parsing SPS");
init_nal (&nr, nalu->data + nalu->offset + nalu->header_bytes,
nalu->size - nalu->header_bytes);
if (!h264_parse_sps_data (&nr, sps, parse_vui_params))
goto error;
sps->valid = TRUE;
return H264_PARSER_OK;
error:
GST_WARNING ("error parsing \"Sequence parameter set\"");
sps->valid = FALSE;
return H264_PARSER_ERROR;
}
void
h264_sps_clear (H264SPS * sps)
{
g_return_if_fail (sps != NULL);
}
/************************** H265 *****************************/
static gboolean
h265_parse_nalu_header (H265NalUnit * nalu)
{
guint8 *data = nalu->data + nalu->offset;
GstBitReader br = {0};
if (nalu->size < 2)
return FALSE;
gst_bit_reader_init (&br, data, nalu->size - nalu->offset);
/* skip the forbidden_zero_bit */
gst_bit_reader_skip_unchecked (&br, 1);
nalu->type = gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
nalu->layer_id = gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
nalu->temporal_id_plus1 = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
nalu->header_bytes = 2;
return TRUE;
}
/****** Parsing functions *****/
static gboolean
h265_parse_profile_tier_level (H265ProfileTierLevel * ptl,
NalReader * nr, guint8 maxNumSubLayersMinus1)
{
guint i, j;
GST_DEBUG ("parsing \"ProfileTierLevel parameters\"");
READ_UINT8 (nr, ptl->profile_space, 2);
READ_UINT8 (nr, ptl->tier_flag, 1);
READ_UINT8 (nr, ptl->profile_idc, 5);
for (j = 0; j < 32; j++)
READ_UINT8 (nr, ptl->profile_compatibility_flag[j], 1);
READ_UINT8 (nr, ptl->progressive_source_flag, 1);
READ_UINT8 (nr, ptl->interlaced_source_flag, 1);
READ_UINT8 (nr, ptl->non_packed_constraint_flag, 1);
READ_UINT8 (nr, ptl->frame_only_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_12bit_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_10bit_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_8bit_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_422chroma_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_420chroma_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_monochrome_constraint_flag, 1);
READ_UINT8 (nr, ptl->intra_constraint_flag, 1);
READ_UINT8 (nr, ptl->one_picture_only_constraint_flag, 1);
READ_UINT8 (nr, ptl->lower_bit_rate_constraint_flag, 1);
READ_UINT8 (nr, ptl->max_14bit_constraint_flag, 1);
/* skip the reserved zero bits */
if (!_skip (nr, 34))
goto error;
READ_UINT8 (nr, ptl->level_idc, 8);
for (j = 0; j < maxNumSubLayersMinus1; j++) {
READ_UINT8 (nr, ptl->sub_layer_profile_present_flag[j], 1);
READ_UINT8 (nr, ptl->sub_layer_level_present_flag[j], 1);
}
if (maxNumSubLayersMinus1 > 0) {
for (i = maxNumSubLayersMinus1; i < 8; i++)
if (!_skip (nr, 2))
goto error;
}
for (i = 0; i < maxNumSubLayersMinus1; i++) {
if (ptl->sub_layer_profile_present_flag[i]) {
READ_UINT8 (nr, ptl->sub_layer_profile_space[i], 2);
READ_UINT8 (nr, ptl->sub_layer_tier_flag[i], 1);
READ_UINT8 (nr, ptl->sub_layer_profile_idc[i], 5);
for (j = 0; j < 32; j++)
READ_UINT8 (nr, ptl->sub_layer_profile_compatibility_flag[i][j], 1);
READ_UINT8 (nr, ptl->sub_layer_progressive_source_flag[i], 1);
READ_UINT8 (nr, ptl->sub_layer_interlaced_source_flag[i], 1);
READ_UINT8 (nr, ptl->sub_layer_non_packed_constraint_flag[i], 1);
READ_UINT8 (nr, ptl->sub_layer_frame_only_constraint_flag[i], 1);
if (!_skip (nr, 44))
goto error;
}
if (ptl->sub_layer_level_present_flag[i])
READ_UINT8 (nr, ptl->sub_layer_level_idc[i], 8);
}
return TRUE;
error:
GST_WARNING ("error parsing \"ProfileTierLevel Parameters\"");
return FALSE;
}
H265Parser *
h265_parser_new (void)
{
H265Parser *parser;
parser = g_slice_new0 (H265Parser);
INITIALIZE_DEBUG_CATEGORY;
return parser;
}
void
h265_parser_free (H265Parser * parser)
{
g_slice_free (H265Parser, parser);
parser = NULL;
}
H265ParserResult
h265_parser_identify_nalu_unchecked (H265Parser * parser,
const guint8 * data, guint offset, gsize size, H265NalUnit * nalu)
{
gint off1;
memset (nalu, 0, sizeof (*nalu));
if (size < offset + 4) {
GST_DEBUG ("Can't parse, buffer has too small size %" G_GSIZE_FORMAT
", offset %u", size, offset);
return H265_PARSER_ERROR;
}
off1 = scan_for_start_codes (data + offset, size - offset);
if (off1 < 0) {
GST_DEBUG ("No start code prefix in this buffer");
return H265_PARSER_NO_NAL;
}
if (offset + off1 == size - 1) {
GST_DEBUG ("Missing data to identify nal unit");
return H265_PARSER_ERROR;
}
nalu->sc_offset = offset + off1;
/* sc might have 2 or 3 0-bytes */
if (nalu->sc_offset > 0 && data[nalu->sc_offset - 1] == 00)
nalu->sc_offset--;
nalu->offset = offset + off1 + 3;
nalu->data = (guint8 *) data;
nalu->size = size - nalu->offset;
if (!h265_parse_nalu_header (nalu)) {
GST_WARNING ("error parsing \"NAL unit header\"");
nalu->size = 0;
return H265_PARSER_BROKEN_DATA;
}
nalu->valid = TRUE;
if (nalu->type == H265_NAL_EOS || nalu->type == H265_NAL_EOB) {
GST_DEBUG ("end-of-seq or end-of-stream nal found");
nalu->size = 2;
return H265_PARSER_OK;
}
return H265_PARSER_OK;
}
H265ParserResult
h265_parser_identify_nalu (H265Parser * parser,
const guint8 * data, guint offset, gsize size, H265NalUnit * nalu)
{
H265ParserResult res;
gint off2;
res =
h265_parser_identify_nalu_unchecked (parser, data, offset, size,
nalu);
if (res != H265_PARSER_OK)
goto beach;
/* The two NALs are exactly 2 bytes size and are placed at the end of an AU,
* there is no need to wait for the following */
if (nalu->type == H265_NAL_EOS || nalu->type == H265_NAL_EOB)
goto beach;
off2 = scan_for_start_codes (data + nalu->offset, size - nalu->offset);
if (off2 < 0) {
GST_DEBUG ("Nal start %d, No end found", nalu->offset);
return H265_PARSER_NO_NAL_END;
}
/* Mini performance improvement:
* We could have a way to store how many 0s were skipped to avoid
* parsing them again on the next NAL */
while (off2 > 0 && data[nalu->offset + off2 - 1] == 00)
off2--;
nalu->size = off2;
if (nalu->size < 3)
return H265_PARSER_BROKEN_DATA;
GST_DEBUG ("Complete nal found. Off: %d, Size: %d", nalu->offset, nalu->size);
beach:
return res;
}
H265ParserResult
h265_parser_identify_nalu_hevc (H265Parser * parser,
const guint8 * data, guint offset, gsize size, guint8 nal_length_size,
H265NalUnit * nalu)
{
GstBitReader br = {0};
memset (nalu, 0, sizeof (*nalu));
if (size < offset + nal_length_size) {
GST_DEBUG ("Can't parse, buffer has too small size %" G_GSIZE_FORMAT
", offset %u", size, offset);
return H265_PARSER_ERROR;
}
size = size - offset;
gst_bit_reader_init (&br, data + offset, size);
nalu->size = gst_bit_reader_get_bits_uint32_unchecked (&br,
nal_length_size * 8);
nalu->sc_offset = offset;
nalu->offset = offset + nal_length_size;
if (size < nalu->size + nal_length_size) {
nalu->size = 0;
return H265_PARSER_NO_NAL_END;
}
nalu->data = (guint8 *) data;
if (!h265_parse_nalu_header (nalu)) {
GST_WARNING ("error parsing \"NAL unit header\"");
nalu->size = 0;
return H265_PARSER_BROKEN_DATA;
}
if (nalu->size < 2)
return H265_PARSER_BROKEN_DATA;
nalu->valid = TRUE;
return H265_PARSER_OK;
}
H265ParserResult
h265_parser_parse_sps (H265Parser * parser, H265NalUnit * nalu,
H265SPS * sps, gboolean parse_vui_params)
{
H265ParserResult res =
h265_parse_sps (parser, nalu, sps, parse_vui_params);
return res;
}
H265ParserResult
h265_parse_sps (H265Parser * parser, H265NalUnit * nalu,
H265SPS * sps, gboolean parse_vui_params)
{
NalReader nr;
guint8 vps_id;
guint i;
guint subwc[] = { 1, 2, 2, 1, 1 };
guint subhc[] = { 1, 2, 1, 1, 1 };
INITIALIZE_DEBUG_CATEGORY;
GST_DEBUG ("parsing SPS");
init_nal (&nr, nalu->data + nalu->offset + nalu->header_bytes,
nalu->size - nalu->header_bytes);
memset (sps, 0, sizeof (*sps));
READ_UINT8 (&nr, vps_id, 4);
READ_UINT8 (&nr, sps->max_sub_layers_minus1, 3);
READ_UINT8 (&nr, sps->temporal_id_nesting_flag, 1);
if (!h265_parse_profile_tier_level (&sps->profile_tier_level, &nr,
sps->max_sub_layers_minus1))
goto error;
READ_UE_MAX (&nr, sps->id, H265_MAX_SPS_COUNT - 1);
READ_UE_MAX (&nr, sps->chroma_format_idc, 3);
if (sps->chroma_format_idc == 3)
READ_UINT8 (&nr, sps->separate_colour_plane_flag, 1);
READ_UE_ALLOWED (&nr, sps->pic_width_in_luma_samples, 1, 16888);
READ_UE_ALLOWED (&nr, sps->pic_height_in_luma_samples, 1, 16888);
READ_UINT8 (&nr, sps->conformance_window_flag, 1);
if (sps->conformance_window_flag) {
READ_UE (&nr, sps->conf_win_left_offset);
READ_UE (&nr, sps->conf_win_right_offset);
READ_UE (&nr, sps->conf_win_top_offset);
READ_UE (&nr, sps->conf_win_bottom_offset);
}
READ_UE_MAX (&nr, sps->bit_depth_luma_minus8, 6);
READ_UE_MAX (&nr, sps->bit_depth_chroma_minus8, 6);
READ_UE_MAX (&nr, sps->log2_max_pic_order_cnt_lsb_minus4, 12);
READ_UINT8 (&nr, sps->sub_layer_ordering_info_present_flag, 1);
for (i =
(sps->sub_layer_ordering_info_present_flag ? 0 :
sps->max_sub_layers_minus1); i <= sps->max_sub_layers_minus1; i++) {
READ_UE_MAX (&nr, sps->max_dec_pic_buffering_minus1[i], 16);
READ_UE_MAX (&nr, sps->max_num_reorder_pics[i],
sps->max_dec_pic_buffering_minus1[i]);
READ_UE_MAX (&nr, sps->max_latency_increase_plus1[i], G_MAXUINT32 - 1);
}
/* setting default values if sps->sub_layer_ordering_info_present_flag is zero */
if (!sps->sub_layer_ordering_info_present_flag && sps->max_sub_layers_minus1) {
for (i = 0; i <= (guint)(sps->max_sub_layers_minus1 - 1); i++) {
sps->max_dec_pic_buffering_minus1[i] =
sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1];
sps->max_num_reorder_pics[i] =
sps->max_num_reorder_pics[sps->max_sub_layers_minus1];
sps->max_latency_increase_plus1[i] =
sps->max_latency_increase_plus1[sps->max_sub_layers_minus1];
}
}
/* The limits are calculted based on the profile_tier_level constraint
* in Annex-A: CtbLog2SizeY = 4 to 6 */
READ_UE_MAX (&nr, sps->log2_min_luma_coding_block_size_minus3, 3);
READ_UE_MAX (&nr, sps->log2_diff_max_min_luma_coding_block_size, 6);
READ_UE_MAX (&nr, sps->log2_min_transform_block_size_minus2, 3);
READ_UE_MAX (&nr, sps->log2_diff_max_min_transform_block_size, 3);
READ_UE_MAX (&nr, sps->max_transform_hierarchy_depth_inter, 4);
READ_UE_MAX (&nr, sps->max_transform_hierarchy_depth_intra, 4);
/* Calculate width and height */
sps->width = sps->pic_width_in_luma_samples;
sps->height = sps->pic_height_in_luma_samples;
if (sps->width < 0 || sps->height < 0) {
GST_WARNING ("invalid width/height in SPS");
goto error;
}
if (sps->conformance_window_flag) {
const guint crop_unit_x = subwc[sps->chroma_format_idc];
const guint crop_unit_y = subhc[sps->chroma_format_idc];
sps->crop_rect_width = sps->width -
(sps->conf_win_left_offset + sps->conf_win_right_offset) * crop_unit_x;
sps->crop_rect_height = sps->height -
(sps->conf_win_top_offset + sps->conf_win_bottom_offset) * crop_unit_y;
sps->crop_rect_x = sps->conf_win_left_offset * crop_unit_x;
sps->crop_rect_y = sps->conf_win_top_offset * crop_unit_y;
GST_LOG ("crop_rectangle x=%u y=%u width=%u, height=%u", sps->crop_rect_x,
sps->crop_rect_y, sps->crop_rect_width, sps->crop_rect_height);
}
sps->fps_num = 0;
sps->fps_den = 1;
sps->valid = TRUE;
return H265_PARSER_OK;
error:
GST_WARNING ("error parsing \"Sequence parameter set\"");
sps->valid = FALSE;
return H265_PARSER_ERROR;
}

View File

@@ -0,0 +1,462 @@
/*
* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#ifndef __H26X_PARSER_H__
#define __H26X_PARSER_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define H264_MAX_SPS_COUNT 32
typedef enum
{
H264_NAL_UNKNOWN = 0,
H264_NAL_SLICE = 1,
H264_NAL_SLICE_DPA = 2,
H264_NAL_SLICE_DPB = 3,
H264_NAL_SLICE_DPC = 4,
H264_NAL_SLICE_IDR = 5,
H264_NAL_SEI = 6,
H264_NAL_SPS = 7,
H264_NAL_PPS = 8,
H264_NAL_AU_DELIMITER = 9,
H264_NAL_SEQ_END = 10,
H264_NAL_STREAM_END = 11,
H264_NAL_FILLER_DATA = 12,
H264_NAL_SPS_EXT = 13,
H264_NAL_PREFIX_UNIT = 14,
H264_NAL_SUBSET_SPS = 15,
H264_NAL_DEPTH_SPS = 16,
H264_NAL_SLICE_AUX = 19,
H264_NAL_SLICE_EXT = 20,
H264_NAL_SLICE_DEPTH = 21
} H264NalUnitType;
typedef enum
{
H264_NAL_EXTENSION_NONE = 0,
H264_NAL_EXTENSION_SVC,
H264_NAL_EXTENSION_MVC,
} H264NalUnitExtensionType;
typedef enum
{
H264_PARSER_OK,
H264_PARSER_BROKEN_DATA,
H264_PARSER_BROKEN_LINK,
H264_PARSER_ERROR,
H264_PARSER_NO_NAL,
H264_PARSER_NO_NAL_END
} H264ParserResult;
typedef enum
{
H264_FRAME_PACKING_NONE = 6,
H264_FRAME_PACKING_CHECKERBOARD_INTERLEAVING = 0,
H264_FRAME_PACKING_COLUMN_INTERLEAVING = 1,
H264_FRAME_PACKING_ROW_INTERLEAVING = 2,
H264_FRAME_PACKING_SIDE_BY_SIDE = 3,
H264_FRMAE_PACKING_TOP_BOTTOM = 4,
H264_FRAME_PACKING_TEMPORAL_INTERLEAVING = 5
} H264FramePackingType;
typedef enum
{
H264_P_SLICE = 0,
H264_B_SLICE = 1,
H264_I_SLICE = 2,
H264_SP_SLICE = 3,
H264_SI_SLICE = 4,
H264_S_P_SLICE = 5,
H264_S_B_SLICE = 6,
H264_S_I_SLICE = 7,
H264_S_SP_SLICE = 8,
H264_S_SI_SLICE = 9
} H264SliceType;
typedef enum
{
H264_CT_TYPE_PROGRESSIVE = 0,
H264_CT_TYPE_INTERLACED = 1,
H264_CT_TYPE_UNKNOWN = 2,
} CtType;
typedef struct _H264NalParser H264NalParser;
typedef struct _H264NalUnit H264NalUnit;
typedef struct _H264SPS H264SPS;
struct _H264NalUnit
{
guint16 ref_idc;
guint16 type;
/* calculated values */
guint8 idr_pic_flag;
guint size;
guint offset;
guint sc_offset;
gboolean valid;
guint8 *data;
guint8 header_bytes;
guint8 extension_type;
};
struct _H264SPS
{
gint id;
guint8 profile_idc;
guint8 constraint_set0_flag;
guint8 constraint_set1_flag;
guint8 constraint_set2_flag;
guint8 constraint_set3_flag;
guint8 constraint_set4_flag;
guint8 constraint_set5_flag;
guint8 level_idc;
guint8 chroma_format_idc;
guint8 separate_colour_plane_flag;
guint8 bit_depth_luma_minus8;
guint8 bit_depth_chroma_minus8;
guint8 qpprime_y_zero_transform_bypass_flag;
guint8 scaling_matrix_present_flag;
guint8 scaling_lists_4x4[6][16];
guint8 scaling_lists_8x8[6][64];
guint8 log2_max_frame_num_minus4;
guint8 pic_order_cnt_type;
/* if pic_order_cnt_type == 0 */
guint8 log2_max_pic_order_cnt_lsb_minus4;
/* else if pic_order_cnt_type == 1 */
guint8 delta_pic_order_always_zero_flag;
gint32 offset_for_non_ref_pic;
gint32 offset_for_top_to_bottom_field;
guint8 num_ref_frames_in_pic_order_cnt_cycle;
gint32 offset_for_ref_frame[255];
guint32 num_ref_frames;
guint8 gaps_in_frame_num_value_allowed_flag;
guint32 pic_width_in_mbs_minus1;
guint32 pic_height_in_map_units_minus1;
guint8 frame_mbs_only_flag;
guint8 mb_adaptive_frame_field_flag;
guint8 direct_8x8_inference_flag;
guint8 frame_cropping_flag;
/* if frame_cropping_flag */
guint32 frame_crop_left_offset;
guint32 frame_crop_right_offset;
guint32 frame_crop_top_offset;
guint32 frame_crop_bottom_offset;
guint8 vui_parameters_present_flag;
/* calculated values */
guint8 chroma_array_type;
guint32 max_frame_num;
gint width, height;
gint crop_rect_width, crop_rect_height;
gint crop_rect_x, crop_rect_y;
gint fps_num_removed, fps_den_removed; /* FIXME: remove */
gboolean valid;
/* Subset SPS extensions */
guint8 extension_type;
};
struct _H264NalParser
{
/*< private >*/
H264SPS sps[H264_MAX_SPS_COUNT];
H264SPS *last_sps;
};
H264NalParser *h264_nal_parser_new (void);
H264ParserResult h264_parser_identify_nalu (H264NalParser *nalparser,
const guint8 *data, guint offset,
gsize size, H264NalUnit *nalu);
H264ParserResult h264_parser_identify_nalu_unchecked (H264NalParser *nalparser,
const guint8 *data, guint offset,
gsize size, H264NalUnit *nalu);
H264ParserResult h264_parser_parse_sps (H264NalUnit *nalu,
H264SPS *sps, gboolean parse_vui_params);
void h264_nal_parser_free (H264NalParser *nalparser);
H264ParserResult h264_parse_sps (H264NalUnit *nalu,
H264SPS *sps, gboolean parse_vui_params);
void h264_sps_clear (H264SPS *sps);
#define H265_MAX_SUB_LAYERS 8
#define H265_MAX_SPS_COUNT 16
typedef enum
{
H265_NAL_SLICE_TRAIL_N = 0,
H265_NAL_SLICE_TRAIL_R = 1,
H265_NAL_SLICE_TSA_N = 2,
H265_NAL_SLICE_TSA_R = 3,
H265_NAL_SLICE_STSA_N = 4,
H265_NAL_SLICE_STSA_R = 5,
H265_NAL_SLICE_RADL_N = 6,
H265_NAL_SLICE_RADL_R = 7,
H265_NAL_SLICE_RASL_N = 8,
H265_NAL_SLICE_RASL_R = 9,
H265_NAL_SLICE_BLA_W_LP = 16,
H265_NAL_SLICE_BLA_W_RADL = 17,
H265_NAL_SLICE_BLA_N_LP = 18,
H265_NAL_SLICE_IDR_W_RADL = 19,
H265_NAL_SLICE_IDR_N_LP = 20,
H265_NAL_SLICE_CRA_NUT = 21,
H265_NAL_VPS = 32,
H265_NAL_SPS = 33,
H265_NAL_PPS = 34,
H265_NAL_AUD = 35,
H265_NAL_EOS = 36,
H265_NAL_EOB = 37,
H265_NAL_FD = 38,
H265_NAL_PREFIX_SEI = 39,
H265_NAL_SUFFIX_SEI = 40
} H265NalUnitType;
typedef enum
{
H265_PARSER_OK,
H265_PARSER_BROKEN_DATA,
H265_PARSER_BROKEN_LINK,
H265_PARSER_ERROR,
H265_PARSER_NO_NAL,
H265_PARSER_NO_NAL_END
} H265ParserResult;
typedef struct _H265Parser H265Parser;
typedef struct _H265NalUnit H265NalUnit;
typedef struct _H265SPS H265SPS;
typedef struct _H265ProfileTierLevel H265ProfileTierLevel;
struct _H265NalUnit
{
guint8 type;
guint8 layer_id;
guint8 temporal_id_plus1;
/* calculated values */
guint size;
guint offset;
guint sc_offset;
gboolean valid;
guint8 *data;
guint8 header_bytes;
};
struct _H265ProfileTierLevel {
guint8 profile_space;
guint8 tier_flag;
guint8 profile_idc;
guint8 profile_compatibility_flag[32];
guint8 progressive_source_flag;
guint8 interlaced_source_flag;
guint8 non_packed_constraint_flag;
guint8 frame_only_constraint_flag;
guint8 max_12bit_constraint_flag;
guint8 max_10bit_constraint_flag;
guint8 max_8bit_constraint_flag;
guint8 max_422chroma_constraint_flag;
guint8 max_420chroma_constraint_flag;
guint8 max_monochrome_constraint_flag;
guint8 intra_constraint_flag;
guint8 one_picture_only_constraint_flag;
guint8 lower_bit_rate_constraint_flag;
guint8 max_14bit_constraint_flag;
guint8 level_idc;
guint8 sub_layer_profile_present_flag[6];
guint8 sub_layer_level_present_flag[6];
guint8 sub_layer_profile_space[6];
guint8 sub_layer_tier_flag[6];
guint8 sub_layer_profile_idc[6];
guint8 sub_layer_profile_compatibility_flag[6][32];
guint8 sub_layer_progressive_source_flag[6];
guint8 sub_layer_interlaced_source_flag[6];
guint8 sub_layer_non_packed_constraint_flag[6];
guint8 sub_layer_frame_only_constraint_flag[6];
guint8 sub_layer_level_idc[6];
};
struct _H265SPS
{
guint8 id;
guint8 max_sub_layers_minus1;
guint8 temporal_id_nesting_flag;
H265ProfileTierLevel profile_tier_level;
guint8 chroma_format_idc;
guint8 separate_colour_plane_flag;
guint16 pic_width_in_luma_samples;
guint16 pic_height_in_luma_samples;
guint8 conformance_window_flag;
/* if conformance_window_flag */
guint32 conf_win_left_offset;
guint32 conf_win_right_offset;
guint32 conf_win_top_offset;
guint32 conf_win_bottom_offset;
guint8 bit_depth_luma_minus8;
guint8 bit_depth_chroma_minus8;
guint8 log2_max_pic_order_cnt_lsb_minus4;
guint8 sub_layer_ordering_info_present_flag;
guint8 max_dec_pic_buffering_minus1[H265_MAX_SUB_LAYERS];
guint8 max_num_reorder_pics[H265_MAX_SUB_LAYERS];
guint8 max_latency_increase_plus1[H265_MAX_SUB_LAYERS];
guint8 log2_min_luma_coding_block_size_minus3;
guint8 log2_diff_max_min_luma_coding_block_size;
guint8 log2_min_transform_block_size_minus2;
guint8 log2_diff_max_min_transform_block_size;
guint8 max_transform_hierarchy_depth_inter;
guint8 max_transform_hierarchy_depth_intra;
guint8 scaling_list_enabled_flag;
/* if scaling_list_enabled_flag */
guint8 scaling_list_data_present_flag;
guint8 amp_enabled_flag;
guint8 sample_adaptive_offset_enabled_flag;
guint8 pcm_enabled_flag;
/* if pcm_enabled_flag */
guint8 pcm_sample_bit_depth_luma_minus1;
guint8 pcm_sample_bit_depth_chroma_minus1;
guint8 log2_min_pcm_luma_coding_block_size_minus3;
guint8 log2_diff_max_min_pcm_luma_coding_block_size;
guint8 pcm_loop_filter_disabled_flag;
guint8 num_short_term_ref_pic_sets;
guint8 long_term_ref_pics_present_flag;
/* if long_term_ref_pics_present_flag */
guint8 num_long_term_ref_pics_sps;
guint16 lt_ref_pic_poc_lsb_sps[32];
guint8 used_by_curr_pic_lt_sps_flag[32];
guint8 temporal_mvp_enabled_flag;
guint8 strong_intra_smoothing_enabled_flag;
guint8 vui_parameters_present_flag;
/* if vui_parameters_present_flat */
guint8 sps_extension_flag;
/* calculated values */
guint8 chroma_array_type;
gint width, height;
gint crop_rect_width, crop_rect_height;
gint crop_rect_x, crop_rect_y;
gint fps_num, fps_den;
gboolean valid;
};
struct _H265Parser
{
/*< private >*/
H265SPS sps[H265_MAX_SPS_COUNT];
H265SPS *last_sps;
};
H265Parser * h265_parser_new (void);
H265ParserResult h265_parser_identify_nalu (H265Parser * parser,
const guint8 * data,
guint offset,
gsize size,
H265NalUnit * nalu);
H265ParserResult h265_parser_identify_nalu_unchecked (H265Parser * parser,
const guint8 * data,
guint offset,
gsize size,
H265NalUnit * nalu);
H265ParserResult h265_parser_identify_nalu_hevc (H265Parser * parser,
const guint8 * data,
guint offset,
gsize size,
guint8 nal_length_size,
H265NalUnit * nalu);
H265ParserResult h265_parser_parse_sps (H265Parser * parser,
H265NalUnit * nalu,
H265SPS * sps,
gboolean parse_vui_params);
void h265_parser_free (H265Parser * parser);
H265ParserResult h265_parse_sps (H265Parser * parser,
H265NalUnit * nalu,
H265SPS * sps,
gboolean parse_vui_params);
G_END_DECLS
#endif

5189
gst-v4l2/gstv4l2object.c Normal file
View File

File diff suppressed because it is too large Load Diff

386
gst-v4l2/gstv4l2object.h Normal file
View File

@@ -0,0 +1,386 @@
/* 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
*
* gstv4l2object.h: base class 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.
*/
#ifndef __GST_V4L2_OBJECT_H__
#define __GST_V4L2_OBJECT_H__
#include "linux/videodev2.h"
#ifdef HAVE_LIBV4L2
# include <libv4l2.h>
#endif
#include "v4l2-utils.h"
#ifdef USE_V4L2_TARGET_NV
#include "nvbufsurface.h"
#include "v4l2_nv_extensions.h"
#endif
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <gst/video/video.h>
typedef struct _GstV4l2Object GstV4l2Object;
typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
#include <gstv4l2bufferpool.h>
/* size of v4l2 buffer pool in streaming case */
#define GST_V4L2_MIN_BUFFERS 2
#ifdef USE_V4L2_TARGET_NV
#define V4L2_DEVICE_BASENAME_NVDEC "nvdec"
#define V4L2_DEVICE_BASENAME_NVENC "msenc"
#define V4L2_DEVICE_PATH_NVDEC "/dev/nvhost-nvdec"
#define V4L2_DEVICE_PATH_NVDEC_ALT "/dev/v4l2-nvdec"
#define V4L2_DEVICE_PATH_NVDEC_MCCOY "/dev/nvidia0"
#define V4L2_DEVICE_PATH_NVENC "/dev/nvhost-msenc"
#define V4L2_DEVICE_PATH_NVENC_ALT "/dev/v4l2-nvenc"
#define V4L2_DEVICE_PATH_TEGRA_INFO "/sys/firmware/devicetree/base/compatible"
#define V4L2_DEVICE_INFO_SOM_EEPROM "/sys/firmware/devicetree/base/chosen/ids"
#endif
/* max frame width/height */
#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */
G_BEGIN_DECLS
#define GST_TYPE_V4L2_IO_MODE (gst_v4l2_io_mode_get_type ())
GType gst_v4l2_io_mode_get_type (void);
#ifdef USE_V4L2_TARGET_NV
#define GST_TYPE_V4L2_DEC_OUTPUT_IO_MODE (gst_v4l2_dec_output_io_mode_get_type ())
GType gst_v4l2_dec_output_io_mode_get_type (void);
#define GST_TYPE_V4L2_DEC_CAPTURE_IO_MODE (gst_v4l2_dec_capture_io_mode_get_type ())
GType gst_v4l2_dec_capture_io_mode_get_type (void);
#define GST_TYPE_V4L2_ENC_OUTPUT_IO_MODE (gst_v4l2_enc_output_io_mode_get_type ())
GType gst_v4l2_enc_output_io_mode_get_type (void);
#define GST_TYPE_V4L2_ENC_CAPTURE_IO_MODE (gst_v4l2_enc_capture_io_mode_get_type ())
GType gst_v4l2_enc_capture_io_mode_get_type (void);
#endif
#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj)
extern gboolean is_cuvid;
typedef enum {
GST_V4L2_IO_AUTO = 0,
GST_V4L2_IO_RW = 1,
GST_V4L2_IO_MMAP = 2,
GST_V4L2_IO_USERPTR = 3,
GST_V4L2_IO_DMABUF = 4,
GST_V4L2_IO_DMABUF_IMPORT = 5
} GstV4l2IOMode;
typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input);
typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input);
typedef gboolean (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object);
#define GST_V4L2_WIDTH(o) (GST_VIDEO_INFO_WIDTH (&(o)->info))
#define GST_V4L2_HEIGHT(o) (GST_VIDEO_INFO_HEIGHT (&(o)->info))
#define GST_V4L2_PIXELFORMAT(o) ((o)->fmtdesc->pixelformat)
#define GST_V4L2_FPS_N(o) (GST_VIDEO_INFO_FPS_N (&(o)->info))
#define GST_V4L2_FPS_D(o) (GST_VIDEO_INFO_FPS_D (&(o)->info))
/* simple check whether the device is open */
#define GST_V4L2_IS_OPEN(o) ((o)->video_fd > 0)
/* check whether the device is 'active' */
#define GST_V4L2_IS_ACTIVE(o) ((o)->active)
#define GST_V4L2_SET_ACTIVE(o) ((o)->active = TRUE)
#define GST_V4L2_SET_INACTIVE(o) ((o)->active = FALSE)
/* checks whether the current v4lv4l2object has already been open()'ed or not */
#define GST_V4L2_CHECK_OPEN(v4l2object) \
if (!GST_V4L2_IS_OPEN(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(_("Device is not open.")), (NULL)); \
return FALSE; \
}
/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */
#define GST_V4L2_CHECK_NOT_OPEN(v4l2object) \
if (GST_V4L2_IS_OPEN(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(_("Device is open.")), (NULL)); \
return FALSE; \
}
/* checks whether we're out of capture mode or not */
#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object) \
if (GST_V4L2_IS_ACTIVE(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(NULL), ("Device is in streaming mode")); \
return FALSE; \
}
struct _GstV4l2Object {
GstElement * element;
GstObject * dbg_obj;
enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
/* the video device */
char *videodev;
#ifdef USE_V4L2_TARGET_NV
gboolean is_encode;
#endif
/* the video-device's file descriptor */
gint video_fd;
GstV4l2IOMode mode;
gboolean active;
gboolean streaming;
/* the current format */
struct v4l2_fmtdesc *fmtdesc;
struct v4l2_format format;
GstVideoInfo info;
GstVideoAlignment align;
/* Features */
gboolean need_video_meta;
gboolean has_alpha_component;
/* only used if the device supports MPLANE
* nb planes is meaning of v4l2 planes
* the gstreamer equivalent is gst_buffer_n_memory
*/
gint n_v4l2_planes;
/* We cache the frame duration if known */
GstClockTime duration;
/* if the MPLANE device support both contiguous and non contiguous
* it allows to select which one we want. But we prefered_non_contiguous
* non contiguous mode.
*/
gboolean prefered_non_contiguous;
/* This will be set if supported in decide_allocation. It can be used to
* calculate the minimum latency. */
guint32 min_buffers;
/* wanted mode */
GstV4l2IOMode req_mode;
/* optional pool */
GstBufferPool *pool;
/* the video device's capabilities */
struct v4l2_capability vcap;
/* opened device specific capabilities */
guint32 device_caps;
/* lists... */
GSList *formats; /* list of available capture formats */
GstCaps *probed_caps;
GList *colors;
GList *norms;
GList *channels;
GData *controls;
/* properties */
v4l2_std_id tv_norm;
gchar *channel;
gulong frequency;
GstStructure *extra_controls;
gboolean keep_aspect;
GValue *par;
#ifdef USE_V4L2_TARGET_NV
gboolean enableMVBufferMeta;
gboolean Enable_frame_type_reporting;
gboolean Enable_error_check;
gboolean Enable_headers;
gint ProcessedFrames;
gboolean open_mjpeg_block;
gboolean capture_plane_stopped;
GCond cplane_stopped_cond;
GMutex cplane_stopped_lock;
guint sei_payload_size;
void* sei_payload;
gchar *sei_uuid;
#endif
/* funcs */
GstV4l2GetInOutFunction get_in_out_func;
GstV4l2SetInOutFunction set_in_out_func;
GstV4l2UpdateFpsFunction update_fps_func;
/* syscalls */
gint (*fd_open) (gint fd, gint v4l2_flags);
gint (*close) (gint fd);
gint (*dup) (gint fd);
gint (*ioctl) (gint fd, gulong request, ...);
gssize (*read) (gint fd, gpointer buffer, gsize n);
gpointer (*mmap) (gpointer start, gsize length, gint prot, gint flags,
gint fd, off_t offset);
gint (*munmap) (gpointer _start, gsize length);
/* Quirks */
/* Skips interlacing probes */
gboolean never_interlaced;
/* Allow to skip reading initial format through G_FMT. Some devices
* just fails if you don't call S_FMT first. (ex: M2M decoders) */
gboolean no_initial_format;
/* Avoid any try_fmt probe. This is used by v4l2src to speedup start up time
* on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify
* the caps to reflect what was negotiated during fixation */
gboolean skip_try_fmt_probes;
};
struct _GstV4l2ObjectClassHelper {
/* probed devices */
GList *devices;
};
GType gst_v4l2_object_get_type (void);
#define V4L2_STD_OBJECT_PROPS \
PROP_DEVICE, \
PROP_DEVICE_NAME, \
PROP_DEVICE_FD, \
PROP_FLAGS, \
PROP_BRIGHTNESS, \
PROP_CONTRAST, \
PROP_SATURATION, \
PROP_HUE, \
PROP_TV_NORM, \
PROP_IO_MODE, \
PROP_OUTPUT_IO_MODE, \
PROP_CAPTURE_IO_MODE, \
PROP_EXTRA_CONTROLS, \
PROP_PIXEL_ASPECT_RATIO, \
PROP_FORCE_ASPECT_RATIO
/* create/destroy */
GstV4l2Object* gst_v4l2_object_new (GstElement * element,
GstObject * dbg_obj,
enum v4l2_buf_type type,
const char * default_device,
GstV4l2GetInOutFunction get_in_out_func,
GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func);
void gst_v4l2_object_destroy (GstV4l2Object * v4l2object);
/* properties */
void gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
const char * default_device);
void gst_v4l2_object_install_m2m_properties_helper (GObjectClass * gobject_class);
#ifdef USE_V4L2_TARGET_NV
void gst_v4l2_object_install_m2m_dec_iomode_properties_helper (GObjectClass * gobject_class);
void gst_v4l2_object_install_m2m_enc_iomode_properties_helper (GObjectClass * gobject_class);
#endif
gboolean gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
guint prop_id,
const GValue * value,
GParamSpec * pspec);
gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2object,
guint prop_id, GValue * value,
GParamSpec * pspec);
/* open/close */
gboolean gst_v4l2_object_open (GstV4l2Object * v4l2object);
gboolean gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other);
gboolean gst_v4l2_object_close (GstV4l2Object * v4l2object);
/* probing */
GstCaps* gst_v4l2_object_get_all_caps (void);
GstCaps* gst_v4l2_object_get_raw_caps (void);
GstCaps* gst_v4l2_object_get_codec_caps (void);
gint gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
gint plane, gint stride);
gboolean gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
gboolean gst_v4l2_object_try_format (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
gboolean gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps);
gboolean gst_v4l2_object_unlock (GstV4l2Object * v4l2object);
gboolean gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object);
gboolean gst_v4l2_object_stop (GstV4l2Object * v4l2object);
GstCaps * gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter);
GstCaps * gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter);
gboolean gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info);
gboolean gst_v4l2_object_set_crop (GstV4l2Object * obj);
gboolean gst_v4l2_object_decide_allocation (GstV4l2Object * v4l2object, GstQuery * query);
gboolean gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query);
GstStructure * gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
/* TODO Move to proper namespace */
/* open/close the device */
gboolean gst_v4l2_open (GstV4l2Object * v4l2object);
gboolean gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other);
gboolean gst_v4l2_close (GstV4l2Object * v4l2object);
/* norm/input/output */
gboolean gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm);
gboolean gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm);
gboolean gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input);
gboolean gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input);
gboolean gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output);
gboolean gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output);
/* frequency control */
gboolean gst_v4l2_get_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong * frequency);
gboolean gst_v4l2_set_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong frequency);
gboolean gst_v4l2_signal_strength (GstV4l2Object * v4l2object, gint tunernum, gulong * signal);
/* attribute control */
gboolean gst_v4l2_get_attribute (GstV4l2Object * v4l2object, int attribute, int * value);
gboolean gst_v4l2_set_attribute (GstV4l2Object * v4l2object, int attribute, const int value);
gboolean gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls);
void post_error_to_bus(GstElement *element, const gchar *error_message);
#ifdef USE_V4L2_TARGET_NV
gboolean set_v4l2_video_mpeg_class (GstV4l2Object * v4l2object, guint label,
gint params);
#endif
G_END_DECLS
#endif /* __GST_V4L2_OBJECT_H__ */

3033
gst-v4l2/gstv4l2videodec.c Normal file
View File

File diff suppressed because it is too large Load Diff

134
gst-v4l2/gstv4l2videodec.h Normal file
View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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.
*
*/
#ifndef __GST_V4L2_VIDEO_DEC_H__
#define __GST_V4L2_VIDEO_DEC_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideodecoder.h>
#include <gst/video/gstvideometa.h>
#include <gstv4l2object.h>
#include <gstv4l2bufferpool.h>
G_BEGIN_DECLS
#define GST_TYPE_V4L2_VIDEO_DEC \
(gst_v4l2_video_dec_get_type())
#define GST_V4L2_VIDEO_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VIDEO_DEC,GstV4l2VideoDec))
#define GST_V4L2_VIDEO_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VIDEO_DEC,GstV4l2VideoDecClass))
#define GST_IS_V4L2_VIDEO_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VIDEO_DEC))
#define GST_IS_V4L2_VIDEO_DEC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VIDEO_DEC))
/* The structures are renamed as the name conflicts with the
* OSS v4l2 library structures. */
#ifdef USE_V4L2_TARGET_NV
#define GstV4l2VideoDec GstNvV4l2VideoDec
#define GstV4l2VideoDecClass GstNvV4l2VideoDecClass
#define LOOP_COUNT_TO_WAIT_FOR_DQEVENT 10
#define WAIT_TIME_PER_LOOP_FOR_DQEVENT 100*1000
#define VP8_START_BYTE_0 0x9D
#define VP8_START_BYTE_1 0x01
#define VP9_START_BYTE_0 0x49
#define VP9_START_BYTE_1 0x83
#define VP9_START_BYTE_2 0x42
#endif
typedef struct _GstV4l2VideoDec GstV4l2VideoDec;
typedef struct _GstV4l2VideoDecClass GstV4l2VideoDecClass;
struct _GstV4l2VideoDec
{
GstVideoDecoder parent;
/* < private > */
GstV4l2Object *v4l2output;
GstV4l2Object *v4l2capture;
/* pads */
GstCaps *probed_srccaps;
GstCaps *probed_sinkcaps;
/* State */
GstVideoCodecState *input_state;
gboolean active;
GstFlowReturn output_flow;
guint64 frame_num;
#ifdef USE_V4L2_TARGET_NV
GHashTable* hash_pts_systemtime;
guint64 decoded_picture_cnt;
guint32 skip_frames;
gboolean idr_received;
guint32 drop_frame_interval;
guint32 num_extra_surfaces;
gboolean is_drc;
gboolean disable_dpb;
gboolean enable_full_frame;
gboolean enable_frame_type_reporting;
gboolean enable_error_check;
gboolean enable_max_performance;
gboolean set_format;
gboolean is_gdr_stream;
guint32 cudadec_mem_type;
guint32 cudadec_gpu_id;
guint32 cudadec_num_surfaces;
gboolean cudadec_low_latency;
gboolean extract_sei_type5_data;
gchar *sei_uuid_string;
gdouble rate;
guint32 cap_buf_dynamic_allocation;
guint32 current_width;
guint32 current_height;
guint32 old_width;
guint32 old_height;
gboolean valid_vpx;
GMutex pts_hashtable_lock;
#endif
};
struct _GstV4l2VideoDecClass
{
GstVideoDecoderClass parent_class;
gchar *default_device;
};
GType gst_v4l2_video_dec_get_type (void);
gboolean gst_v4l2_is_video_dec (GstCaps * sink_caps, GstCaps * src_caps);
#ifdef USE_V4L2_TARGET_NV
gboolean set_v4l2_controls (GstV4l2VideoDec *self);
#endif
void gst_v4l2_video_dec_register (GstPlugin * plugin,
const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_VIDEO_DEC_H__ */

3229
gst-v4l2/gstv4l2videoenc.c Normal file
View File

File diff suppressed because it is too large Load Diff

168
gst-v4l2/gstv4l2videoenc.h Normal file
View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2014 SUMOMO Computer Association.
* Author: ayaka <ayaka@soulik.info>
* SPDX-FileCopyrightText: Copyright (c) 2018-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LGPL-2.0-only
*
* 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.
*
*/
#ifndef __GST_V4L2_VIDEO_ENC_H__
#define __GST_V4L2_VIDEO_ENC_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideoencoder.h>
#include <gst/video/gstvideometa.h>
#include <gstv4l2object.h>
#include <gstv4l2bufferpool.h>
G_BEGIN_DECLS
#define GST_TYPE_V4L2_VIDEO_ENC \
(gst_v4l2_video_enc_get_type())
#define GST_V4L2_VIDEO_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VIDEO_ENC,GstV4l2VideoEnc))
#define GST_V4L2_VIDEO_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VIDEO_ENC,GstV4l2VideoEncClass))
#define GST_IS_V4L2_VIDEO_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VIDEO_ENC))
#define GST_IS_V4L2_VIDEO_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VIDEO_ENC))
#define GST_V4L2_VIDEO_ENC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_VIDEO_ENC, GstV4l2VideoEncClass))
typedef struct _GstV4l2VideoEnc GstV4l2VideoEnc;
typedef struct _GstV4l2VideoEncClass GstV4l2VideoEncClass;
struct _GstV4l2VideoEnc
{
GstVideoEncoder parent;
#ifdef USE_V4L2_TARGET_NV
guint32 ratecontrol;
guint32 bitrate;
guint32 maxbitrate;
guint32 vbvbufsize;
guint32 vbvinit;
guint32 peak_bitrate;
guint32 idrinterval;
guint32 iframeinterval;
guint32 quant_i_frames;
guint32 quant_p_frames;
guint32 quant_b_frames;
guint32 MinQpI;
guint32 MaxQpI;
guint32 MinQpP;
guint32 MaxQpP;
guint32 MinQpB;
guint32 MaxQpB;
guint32 constQpI;
guint32 constQpP;
guint32 constQpB;
guint32 IInitQP;
guint32 PInitQP;
guint32 BInitQP;
gboolean set_qpRange;
gboolean set_intrarefresh;
guint32 enableIntraRefresh;
guint32 intraRefreshPeriod;
guint32 intraRefreshCnt;
gboolean enableTemporalAQ;
guint32 aqStrength;
guint32 targetQuality;
guint32 hw_preset_level;
guint virtual_buffer_size;
gboolean measure_latency;
gboolean ratecontrol_enable;
gboolean force_idr;
gboolean force_intra;
gchar *sei_uuid;
gboolean maxperf_enable;
gboolean copy_timestamp;
FILE *tracing_file_enc;
GQueue *got_frame_pt;
guint32 cudaenc_mem_type;
guint32 cudaenc_gpu_id;
guint32 cudaenc_preset_id;
guint32 cudaenc_tuning_info_id;
gboolean slice_output;
GstVideoCodecFrame *best_prev;
GstClockTime buf_pts_prev;
gdouble buffer_in_time;
GHashTable* hash_pts_systemtime;
gboolean copy_meta;
gboolean enable_hwpreset;
#endif
/* < private > */
GstV4l2Object *v4l2output;
GstV4l2Object *v4l2capture;
/* pads */
GstCaps *probed_srccaps;
GstCaps *probed_sinkcaps;
/* State */
GstVideoCodecState *input_state;
gboolean active;
gboolean processing;
GstFlowReturn output_flow;
};
struct _GstV4l2VideoEncClass
{
GstVideoEncoderClass parent_class;
gchar *default_device;
const char *codec_name;
guint32 profile_cid;
const gchar *(*profile_to_string) (gint v4l2_profile);
gint (*profile_from_string) (const gchar * profile);
#ifdef USE_V4L2_TARGET_NV
gboolean (*set_encoder_properties) (GstVideoEncoder * encoder);
gboolean (*set_video_encoder_properties) (GstVideoEncoder * encoder);
#endif
guint32 level_cid;
const gchar *(*level_to_string) (gint v4l2_level);
gint (*level_from_string) (const gchar * level);
#ifdef USE_V4L2_TARGET_NV
void (*force_IDR) (GstV4l2VideoEnc *);
#endif
};
GType gst_v4l2_video_enc_get_type (void);
gboolean gst_v4l2_is_video_enc (GstCaps * sink_caps, GstCaps * src_caps,
GstCaps * codec_caps);
void gst_v4l2_video_enc_register (GstPlugin * plugin, GType type,
const char *codec, const gchar * basename, const gchar * device_path,
GstCaps * sink_caps, GstCaps * codec_caps, GstCaps * src_caps);
#ifdef USE_V4L2_TARGET_NV
void set_encoder_src_caps (GstVideoEncoder *encoder, GstCaps *input_caps);
gboolean is_drc (GstVideoEncoder *encoder, GstCaps *input_caps);
gboolean reconfigure_fps (GstVideoEncoder *encoder, GstCaps *input_caps, guint label);
#endif
G_END_DECLS
#endif /* __GST_V4L2_VIDEO_ENC_H__ */

198
gst-v4l2/gstv4l2vp8enc.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* Copyright (C) 2017 Collabora Inc.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* 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
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "gstv4l2object.h"
#include "gstv4l2vp8enc.h"
#include <string.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_v4l2_vp8_enc_debug);
#define GST_CAT_DEFAULT gst_v4l2_vp8_enc_debug
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-vp8, profile=(string) { 0, 1, 2, 3 }");
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
#ifdef USE_V4L2_TARGET_NV
PROP_ENABLE_HEADER,
#endif
/* TODO */
};
#define gst_v4l2_vp8_enc_parent_class parent_class
G_DEFINE_TYPE (GstV4l2Vp8Enc, gst_v4l2_vp8_enc, GST_TYPE_V4L2_VIDEO_ENC);
static void
gst_v4l2_vp8_enc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2Vp8Enc *self = GST_V4L2_VP8_ENC (object);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
self->EnableHeaders = g_value_get_boolean (value);
video_enc->v4l2capture->Enable_headers = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static void
gst_v4l2_vp8_enc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2Vp8Enc *self = GST_V4L2_VP8_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
g_value_set_boolean (value, self->EnableHeaders);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static gint
v4l2_profile_from_string (const gchar * profile)
{
gint v4l2_profile = -1;
if (g_str_equal (profile, "0"))
v4l2_profile = 0;
else if (g_str_equal (profile, "1"))
v4l2_profile = 1;
else if (g_str_equal (profile, "2"))
v4l2_profile = 2;
else if (g_str_equal (profile, "3"))
v4l2_profile = 3;
else
GST_WARNING ("Unsupported profile string '%s'", profile);
return v4l2_profile;
}
static const gchar *
v4l2_profile_to_string (gint v4l2_profile)
{
switch (v4l2_profile) {
case 0:
return "0";
case 1:
return "1";
case 2:
return "2";
case 3:
return "3";
default:
GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
break;
}
return NULL;
}
static void
gst_v4l2_vp8_enc_init (GstV4l2Vp8Enc * self)
{
}
static void
gst_v4l2_vp8_enc_class_init (GstV4l2Vp8EncClass * klass)
{
GstElementClass *element_class;
GObjectClass *gobject_class;
GstV4l2VideoEncClass *baseclass;
parent_class = g_type_class_peek_parent (klass);
element_class = (GstElementClass *) klass;
gobject_class = (GObjectClass *) klass;
baseclass = (GstV4l2VideoEncClass *) (klass);
GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp8_enc_debug, "v4l2vp8enc", 0,
"V4L2 VP8 Encoder");
gst_element_class_set_static_metadata (element_class,
"V4L2 VP8 Encoder",
"Codec/Encoder/Video",
"Encode VP8 video streams via V4L2 API",
"Nicolas Dufresne <nicolas.dufresne@collabora.com");
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_get_property);
#ifdef USE_V4L2_TARGET_NV
g_object_class_install_property (gobject_class, PROP_ENABLE_HEADER,
g_param_spec_boolean ("enable-headers",
"Enable VP8 headers",
"Enable VP8 file and frame headers, if enabled, dump elementary stream",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
#endif
baseclass->codec_name = "VP8";
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
baseclass->profile_to_string = v4l2_profile_to_string;
baseclass->profile_from_string = v4l2_profile_from_string;
}
/* Probing functions */
gboolean
gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps)
{
return gst_v4l2_is_video_enc (sink_caps, src_caps,
gst_static_caps_get (&src_template_caps));
}
void
gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
{
gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP8_ENC,
"vp8", basename, device_path, sink_caps,
gst_static_caps_get (&src_template_caps), src_caps);
}

63
gst-v4l2/gstv4l2vp8enc.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2017 Collabora Inc.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* 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.
*
*/
#ifndef __GST_V4L2_VP8_ENC_H__
#define __GST_V4L2_VP8_ENC_H__
#include <gst/gst.h>
#include "gstv4l2videoenc.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_VP8_ENC \
(gst_v4l2_vp8_enc_get_type())
#define GST_V4L2_VP8_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VP8_ENC,GstV4l2Vp8Enc))
#define GST_V4L2_VP8_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VP8_ENC,GstV4l2Vp8EncClass))
#define GST_IS_V4L2_VP8_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VP8_ENC))
#define GST_IS_V4L2_VP8_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VP8_ENC))
typedef struct _GstV4l2Vp8Enc GstV4l2Vp8Enc;
typedef struct _GstV4l2Vp8EncClass GstV4l2Vp8EncClass;
struct _GstV4l2Vp8Enc
{
GstV4l2VideoEnc parent;
#ifdef USE_V4L2_TARGET_NV
gboolean EnableHeaders;
#endif
};
struct _GstV4l2Vp8EncClass
{
GstV4l2VideoEncClass parent_class;
};
GType gst_v4l2_vp8_enc_get_type (void);
gboolean gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps);
void gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_VP8_ENC_H__ */

197
gst-v4l2/gstv4l2vp9enc.c Normal file
View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2017 Collabora Inc.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* 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
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "gstv4l2object.h"
#include "gstv4l2vp9enc.h"
#include <string.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_v4l2_vp9_enc_debug);
#define GST_CAT_DEFAULT gst_v4l2_vp9_enc_debug
static GstStaticCaps src_template_caps =
GST_STATIC_CAPS ("video/x-vp9, profile=(string) { 0, 1, 2, 3 }");
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
#ifdef USE_V4L2_TARGET_NV
PROP_ENABLE_HEADER,
#endif
/* TODO */
};
#define gst_v4l2_vp9_enc_parent_class parent_class
G_DEFINE_TYPE (GstV4l2Vp9Enc, gst_v4l2_vp9_enc, GST_TYPE_V4L2_VIDEO_ENC);
static void
gst_v4l2_vp9_enc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2Vp9Enc *self = GST_V4L2_VP9_ENC (object);
GstV4l2VideoEnc *video_enc = GST_V4L2_VIDEO_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
self->EnableHeaders = g_value_get_boolean (value);
video_enc->v4l2capture->Enable_headers = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static void
gst_v4l2_vp9_enc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
/* TODO */
#ifdef USE_V4L2_TARGET_NV
GstV4l2Vp9Enc *self = GST_V4L2_VP9_ENC (object);
switch (prop_id) {
case PROP_ENABLE_HEADER:
g_value_set_boolean (value, self->EnableHeaders);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#endif
}
static gint
v4l2_profile_from_string (const gchar * profile)
{
gint v4l2_profile = -1;
if (g_str_equal (profile, "0"))
v4l2_profile = 0;
else if (g_str_equal (profile, "1"))
v4l2_profile = 1;
else if (g_str_equal (profile, "2"))
v4l2_profile = 2;
else if (g_str_equal (profile, "3"))
v4l2_profile = 3;
else
GST_WARNING ("Unsupported profile string '%s'", profile);
return v4l2_profile;
}
static const gchar *
v4l2_profile_to_string (gint v4l2_profile)
{
switch (v4l2_profile) {
case 0:
return "0";
case 1:
return "1";
case 2:
return "2";
case 3:
return "3";
default:
GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
break;
}
return NULL;
}
static void
gst_v4l2_vp9_enc_init (GstV4l2Vp9Enc * self)
{
}
static void
gst_v4l2_vp9_enc_class_init (GstV4l2Vp9EncClass * klass)
{
GstElementClass *element_class;
GObjectClass *gobject_class;
GstV4l2VideoEncClass *baseclass;
parent_class = g_type_class_peek_parent (klass);
element_class = (GstElementClass *) klass;
gobject_class = (GObjectClass *) klass;
baseclass = (GstV4l2VideoEncClass *) (klass);
GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp9_enc_debug, "v4l2vp9enc", 0,
"V4L2 VP9 Encoder");
gst_element_class_set_static_metadata (element_class,
"V4L2 VP9 Encoder",
"Codec/Encoder/Video",
"Encode VP9 video streams via V4L2 API",
"Nicolas Dufresne <nicolas.dufresne@collabora.com");
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_get_property);
#ifdef USE_V4L2_TARGET_NV
g_object_class_install_property (gobject_class, PROP_ENABLE_HEADER,
g_param_spec_boolean ("enable-headers",
"Enable VP9 headers",
"Enable VP9 file and frame headers, if enabled, dump elementary stream",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
#endif
baseclass->codec_name = "VP9";
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
baseclass->profile_to_string = v4l2_profile_to_string;
baseclass->profile_from_string = v4l2_profile_from_string;
}
/* Probing functions */
gboolean
gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps)
{
return gst_v4l2_is_video_enc (sink_caps, src_caps,
gst_static_caps_get (&src_template_caps));
}
void
gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
{
gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP9_ENC,
"vp9", basename, device_path, sink_caps,
gst_static_caps_get (&src_template_caps), src_caps);
}

63
gst-v4l2/gstv4l2vp9enc.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2017 Collabora Inc.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* 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.
*
*/
#ifndef __GST_V4L2_VP9_ENC_H__
#define __GST_V4L2_VP9_ENC_H__
#include <gst/gst.h>
#include "gstv4l2videoenc.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_VP9_ENC \
(gst_v4l2_vp9_enc_get_type())
#define GST_V4L2_VP9_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VP9_ENC,GstV4l2Vp9Enc))
#define GST_V4L2_VP9_ENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VP9_ENC,GstV4l2Vp9EncClass))
#define GST_IS_V4L2_VP9_ENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VP9_ENC))
#define GST_IS_V4L2_VP9_ENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VP9_ENC))
typedef struct _GstV4l2Vp9Enc GstV4l2Vp9Enc;
typedef struct _GstV4l2Vp9EncClass GstV4l2Vp9EncClass;
struct _GstV4l2Vp9Enc
{
GstV4l2VideoEnc parent;
#ifdef USE_V4L2_TARGET_NV
gboolean EnableHeaders;
#endif
};
struct _GstV4l2Vp9EncClass
{
GstV4l2VideoEncClass parent_class;
};
GType gst_v4l2_vp9_enc_get_type (void);
gboolean gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps);
void gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
G_END_DECLS
#endif /* __GST_V4L2_VP9_ENC_H__ */

296
gst-v4l2/nalutils.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
*
* 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
#include "nalutils.h"
/* Compute Ceil(Log2(v)) */
/* Derived from branchless code for integer log2(v) from:
<http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */
guint
ceil_log2 (guint32 v)
{
guint r, shift;
v--;
r = (v > 0xFFFF) << 4;
v >>= r;
shift = (v > 0xFF) << 3;
v >>= shift;
r |= shift;
shift = (v > 0xF) << 2;
v >>= shift;
r |= shift;
shift = (v > 0x3) << 1;
v >>= shift;
r |= shift;
r |= (v >> 1);
return r + 1;
}
/****** Nal parser ******/
void
init_nal (NalReader * nr, const guint8 * data, guint size)
{
nr->data = data;
nr->size = size;
nr->n_epb = 0;
nr->byte = 0;
nr->bits_in_cache = 0;
/* fill with something other than 0 to detect emulation prevention bytes */
nr->first_byte = 0xff;
nr->cache = 0xff;
}
gboolean
_read (NalReader * nr, guint nbits)
{
if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) {
GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in "
"bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8);
return FALSE;
}
while (nr->bits_in_cache < nbits) {
guint8 byte;
gboolean check_three_byte;
check_three_byte = TRUE;
next_byte:
if (G_UNLIKELY (nr->byte >= nr->size))
return FALSE;
byte = nr->data[nr->byte++];
/* check if the byte is a emulation_prevention_three_byte */
if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 &&
((nr->cache & 0xff) == 0)) {
/* next byte goes unconditionally to the cache, even if it's 0x03 */
check_three_byte = FALSE;
nr->n_epb++;
goto next_byte;
}
nr->cache = (nr->cache << 8) | nr->first_byte;
nr->first_byte = byte;
nr->bits_in_cache += 8;
}
return TRUE;
}
/* Skips the specified amount of bits. This is only suitable to a
cacheable number of bits */
gboolean
_skip (NalReader * nr, guint nbits)
{
g_assert (nbits <= 8 * sizeof (nr->cache));
if (G_UNLIKELY (!_read (nr, nbits)))
return FALSE;
nr->bits_in_cache -= nbits;
return TRUE;
}
/* Generic version to skip any number of bits */
gboolean
_skip_long (NalReader * nr, guint nbits)
{
/* Leave out enough bits in the cache once we are finished */
const guint skip_size = 4 * sizeof (nr->cache);
guint remaining = nbits;
nbits %= skip_size;
while (remaining > 0) {
if (!_skip (nr, nbits))
return FALSE;
remaining -= nbits;
nbits = skip_size;
}
return TRUE;
}
guint
_get_pos (const NalReader * nr)
{
return nr->byte * 8 - nr->bits_in_cache;
}
guint
_get_remaining (const NalReader * nr)
{
return (nr->size - nr->byte) * 8 + nr->bits_in_cache;
}
guint
_get_epb_count (const NalReader * nr)
{
return nr->n_epb;
}
#define _READ_BITS(bits) \
gboolean \
_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \
{ \
guint shift; \
\
if (!_read (nr, nbits)) \
return FALSE; \
\
/* bring the required bits down and truncate */ \
shift = nr->bits_in_cache - nbits; \
*val = nr->first_byte >> shift; \
\
*val |= nr->cache << (8 - shift); \
/* mask out required bits */ \
if (nbits < bits) \
*val &= ((guint##bits)1 << nbits) - 1; \
\
nr->bits_in_cache = shift; \
\
return TRUE; \
} \
_READ_BITS (8);
_READ_BITS (16);
_READ_BITS (32);
#define _PEEK_BITS(bits) \
gboolean \
_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) \
{ \
NalReader tmp; \
\
tmp = *nr; \
return _get_bits_uint##bits (&tmp, val, nbits); \
}
_PEEK_BITS (8);
gboolean
_get_ue (NalReader * nr, guint32 * val)
{
guint i = 0;
guint8 bit;
guint32 value;
if (G_UNLIKELY (!_get_bits_uint8 (nr, &bit, 1)))
return FALSE;
while (bit == 0) {
i++;
if (G_UNLIKELY (!_get_bits_uint8 (nr, &bit, 1)))
return FALSE;
}
if (G_UNLIKELY (i > 31))
return FALSE;
if (G_UNLIKELY (!_get_bits_uint32 (nr, &value, i)))
return FALSE;
*val = (1 << i) - 1 + value;
return TRUE;
}
gboolean
_get_se (NalReader * nr, gint32 * val)
{
guint32 value;
if (G_UNLIKELY (!_get_ue (nr, &value)))
return FALSE;
if (value % 2)
*val = (value / 2) + 1;
else
*val = -(value / 2);
return TRUE;
}
gboolean
_is_byte_aligned (NalReader * nr)
{
if (nr->bits_in_cache != 0)
return FALSE;
return TRUE;
}
gboolean
_has_more_data (NalReader * nr)
{
NalReader nr_tmp;
guint remaining, nbits;
guint8 rbsp_stop_one_bit, zero_bits;
remaining = _get_remaining (nr);
if (remaining == 0)
return FALSE;
nr_tmp = *nr;
nr = &nr_tmp;
/* The spec defines that more_rbsp_data() searches for the last bit
equal to 1, and that it is the rbsp_stop_one_bit. Subsequent bits
until byte boundary is reached shall be zero.
This means that more_rbsp_data() is FALSE if the next bit is 1
and the remaining bits until byte boundary are zero. One way to
be sure that this bit was the very last one, is that every other
bit after we reached byte boundary are also set to zero.
Otherwise, if the next bit is 0 or if there are non-zero bits
afterwards, then then we have more_rbsp_data() */
if (!_get_bits_uint8 (nr, &rbsp_stop_one_bit, 1))
return FALSE;
if (!rbsp_stop_one_bit)
return TRUE;
nbits = --remaining % 8;
while (remaining > 0) {
if (!_get_bits_uint8 (nr, &zero_bits, nbits))
return FALSE;
if (zero_bits != 0)
return TRUE;
remaining -= nbits;
nbits = 8;
}
return FALSE;
}
/*********** end of nal parser ***************/
gint
scan_for_start_codes (const guint8 * data, guint size)
{
GstByteReader br;
gst_byte_reader_init (&br, data, size);
/* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
0, size);
}

170
gst-v4l2/nalutils.h Normal file
View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
*
* 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
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbitreader.h>
#include <string.h>
guint ceil_log2 (guint32 v);
typedef struct
{
const guint8 *data;
guint size;
guint n_epb; /* Number of emulation prevention bytes */
guint byte; /* Byte position */
guint bits_in_cache; /* bitpos in the cache of next bit */
guint8 first_byte;
guint64 cache; /* cached bytes */
} NalReader;
G_GNUC_INTERNAL
void init_nal (NalReader * nr, const guint8 * data, guint size);
G_GNUC_INTERNAL
gboolean _read (NalReader * nr, guint nbits);
G_GNUC_INTERNAL
gboolean _skip (NalReader * nr, guint nbits);
G_GNUC_INTERNAL
gboolean _skip_long (NalReader * nr, guint nbits);
G_GNUC_INTERNAL
guint _get_pos (const NalReader * nr);
G_GNUC_INTERNAL
guint _get_remaining (const NalReader * nr);
G_GNUC_INTERNAL
guint _get_epb_count (const NalReader * nr);
G_GNUC_INTERNAL
gboolean _is_byte_aligned (NalReader * nr);
G_GNUC_INTERNAL
gboolean _has_more_data (NalReader * nr);
#define _READ_BITS_H(bits) \
G_GNUC_INTERNAL \
gboolean _get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits)
_READ_BITS_H (8);
_READ_BITS_H (16);
_READ_BITS_H (32);
#define _PEEK_BITS_H(bits) \
G_GNUC_INTERNAL \
gboolean _peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits)
_PEEK_BITS_H (8);
G_GNUC_INTERNAL
gboolean _get_ue (NalReader * nr, guint32 * val);
G_GNUC_INTERNAL
gboolean _get_se (NalReader * nr, gint32 * val);
#define CHECK_ALLOWED_MAX(val, max) { \
if (val > max) { \
GST_WARNING ("value greater than max. value: %d, max %d", \
val, max); \
goto error; \
} \
}
#define CHECK_ALLOWED(val, min, max) { \
if (val < min || val > max) { \
GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \
val, min, max); \
goto error; \
} \
}
#define READ_UINT8(nr, val, nbits) { \
if (!_get_bits_uint8 (nr, &val, nbits)) { \
GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
goto error; \
} \
}
#define READ_UINT16(nr, val, nbits) { \
if (!_get_bits_uint16 (nr, &val, nbits)) { \
GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
goto error; \
} \
}
#define READ_UINT32(nr, val, nbits) { \
if (!_get_bits_uint32 (nr, &val, nbits)) { \
GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
goto error; \
} \
}
#define READ_UINT64(nr, val, nbits) { \
if (!_get_bits_uint64 (nr, &val, nbits)) { \
GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
goto error; \
} \
}
#define READ_UE(nr, val) { \
if (!_get_ue (nr, &val)) { \
GST_WARNING ("failed to read UE"); \
goto error; \
} \
}
#define READ_UE_ALLOWED(nr, val, min, max) { \
guint32 tmp; \
READ_UE (nr, tmp); \
CHECK_ALLOWED (tmp, min, max); \
val = tmp; \
}
#define READ_UE_MAX(nr, val, max) { \
guint32 tmp; \
READ_UE (nr, tmp); \
CHECK_ALLOWED_MAX (tmp, max); \
val = tmp; \
}
#define READ_SE(nr, val) { \
if (!_get_se (nr, &val)) { \
GST_WARNING ("failed to read SE"); \
goto error; \
} \
}
#define READ_SE_ALLOWED(nr, val, min, max) { \
gint32 tmp; \
READ_SE (nr, tmp); \
CHECK_ALLOWED (tmp, min, max); \
val = tmp; \
}
G_GNUC_INTERNAL
gint scan_for_start_codes (const guint8 * data, guint size);

168
gst-v4l2/sei_parse.c Normal file
View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*
*/
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "gstv4l2object.h"
#define UUID_SIZE 16
#define USER_DATA_UNREGISTERED_TYPE 5
gboolean check_uuid(uint8_t *stream, char *sei_uuid_string);
uint8_t* parse_sei_unit(uint8_t * bs_ptr, guint *size, char *sei_uuid_string);
uint8_t *parse_sei_data (uint8_t *bs, uint32_t size, uint32_t *payload_size,
char *sei_uuid_string, guint32 pixelformat);
gboolean check_uuid(uint8_t *stream, char *sei_uuid_string)
{
char uuid_string[UUID_SIZE] = {0};
uint32_t size = snprintf (uuid_string, UUID_SIZE, "%s", stream);
if (size == (UUID_SIZE-1))
{
if (!strncmp (uuid_string, sei_uuid_string, (UUID_SIZE-1)))
return TRUE;
else
return FALSE;
}
else
return FALSE;
}
uint8_t* parse_sei_unit(uint8_t * bs_ptr, guint *size, char *sei_uuid_string)
{
int payload_type = 0;
int payload_size = 0;
uint8_t* payload = NULL;
int i;
/* printf("found a SEI NAL unit!\n"); */
payload_type = *bs_ptr++;
while (payload_size % 0xFF == 0)
{
payload_size += *bs_ptr++;
}
//printf("payload_type = %i payload_size = %i\n", payload_type, payload_size);
if (!check_uuid (bs_ptr, sei_uuid_string))
{
//printf ("Expected UUID not found\n");
bs_ptr += (payload_size - UUID_SIZE);
return NULL;
}
else
{
bs_ptr += UUID_SIZE;
}
*size = payload_size;
if (payload_type == USER_DATA_UNREGISTERED_TYPE)
{
payload = (uint8_t*)malloc((payload_size - UUID_SIZE)*sizeof(uint8_t));
for (i = 0; i < (payload_size - UUID_SIZE); i++)
{
payload[i] = *bs_ptr;
if (strncmp (sei_uuid_string, "VST_CUSTOM_META", (UUID_SIZE-1)) != 0)
{
// drop emulation prevention bytes
if ((*(bs_ptr) == 0x03)
&& (*(bs_ptr - 1) == 0x00)
&& (*(bs_ptr - 2) == 0x00))
{
i--;
}
}
bs_ptr++;
}
return payload;
}
else
{
return NULL;
}
}
/*************************************************************
+------H264-----+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
+------------H265---------------+
|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| Type | LayerId | TID |
+-------------+-----------------+
*************************************************************/
uint8_t *parse_sei_data (uint8_t *bs, uint32_t size, uint32_t *payload_size,
char *sei_uuid_string, guint32 pixelformat)
{
if (sei_uuid_string == NULL)
return NULL;
int checklen = 0;
unsigned int sei_payload_size = 0;
uint8_t *bs_ptr = bs;
uint8_t *bs_ptr_end = bs + size;
uint8_t *payload = NULL;
while (bs_ptr_end > bs_ptr)
{
if (checklen < 2 && *bs_ptr++ == 0x00)
checklen++;
else if (checklen == 2 && *bs_ptr++ == 0x00)
checklen++;
else if (checklen == 3 && *bs_ptr++ == 0x01)
checklen++;
else if (checklen == 4 && ((pixelformat == V4L2_PIX_FMT_H264) ? *bs_ptr == 0x06 : (((*bs_ptr >> 1) & 0x3f) == 0x27)))
{
bs_ptr++;
if (pixelformat == V4L2_PIX_FMT_H265)
bs_ptr++;
payload = parse_sei_unit(bs_ptr, &sei_payload_size, sei_uuid_string);
checklen = 0;
if (payload != NULL)
{
*payload_size = (sei_payload_size - 16);
return payload;
}
else
{
continue;
}
}
else
checklen = 0;
}
return NULL;
}

202
gst-v4l2/v4l2-utils.c Normal file
View File

@@ -0,0 +1,202 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
*
* 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
#include "v4l2-utils.h"
/**************************/
/* Common device iterator */
/**************************/
#ifdef HAVE_GUDEV
#include <gudev/gudev.h>
struct _GstV4l2GUdevIterator
{
GstV4l2Iterator parent;
GList *devices;
GUdevDevice *device;
GUdevClient *client;
};
GstV4l2Iterator *
gst_v4l2_iterator_new (void)
{
static const gchar *subsystems[] = { "video4linux", NULL };
struct _GstV4l2GUdevIterator *it;
it = g_slice_new0 (struct _GstV4l2GUdevIterator);
it->client = g_udev_client_new (subsystems);
it->devices = g_udev_client_query_by_subsystem (it->client, "video4linux");
return (GstV4l2Iterator *) it;
}
gboolean
gst_v4l2_iterator_next (GstV4l2Iterator * _it)
{
struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it;
const gchar *device_name;
if (it->device)
g_object_unref (it->device);
it->device = NULL;
it->parent.device_path = NULL;
it->parent.device_name = NULL;
if (it->devices == NULL)
return FALSE;
it->device = it->devices->data;
it->devices = g_list_delete_link (it->devices, it->devices);
device_name = g_udev_device_get_property (it->device, "ID_V4L_PRODUCT");
if (!device_name)
device_name = g_udev_device_get_property (it->device, "ID_MODEL_ENC");
if (!device_name)
device_name = g_udev_device_get_property (it->device, "ID_MODEL");
it->parent.device_path = g_udev_device_get_device_file (it->device);
it->parent.device_name = device_name;
it->parent.sys_path = g_udev_device_get_sysfs_path (it->device);
return TRUE;
}
void
gst_v4l2_iterator_free (GstV4l2Iterator * _it)
{
struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it;
g_list_free_full (it->devices, g_object_unref);
gst_object_unref (it->client);
g_slice_free (struct _GstV4l2GUdevIterator, it);
}
#else /* No GUDEV */
struct _GstV4l2FsIterator
{
GstV4l2Iterator parent;
gint base_idx;
gint video_idx;
gchar *device;
};
GstV4l2Iterator *
gst_v4l2_iterator_new (void)
{
struct _GstV4l2FsIterator *it;
it = g_slice_new0 (struct _GstV4l2FsIterator);
it->base_idx = 0;
it->video_idx = -1;
it->device = NULL;
return (GstV4l2Iterator *) it;
}
gboolean
gst_v4l2_iterator_next (GstV4l2Iterator * _it)
{
struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it;
static const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL };
gchar *device = NULL;
g_free ((gchar *) it->parent.device_path);
it->parent.device_path = NULL;
while (device == NULL) {
it->video_idx++;
if (it->video_idx >= 64) {
it->video_idx = 0;
it->base_idx++;
}
if (dev_base[it->base_idx] == NULL) {
it->video_idx = 0;
break;
}
device = g_strdup_printf ("%s%d", dev_base[it->base_idx], it->video_idx);
if (g_file_test (device, G_FILE_TEST_EXISTS)) {
it->parent.device_path = device;
break;
}
g_free (device);
device = NULL;
}
return it->parent.device_path != NULL;
}
void
gst_v4l2_iterator_free (GstV4l2Iterator * _it)
{
struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it;
g_free ((gchar *) it->parent.device_path);
g_slice_free (struct _GstV4l2FsIterator, it);
}
#endif
void
gst_v4l2_clear_error (GstV4l2Error * v4l2err)
{
if (v4l2err) {
g_clear_error (&v4l2err->error);
g_free (v4l2err->dbg_message);
v4l2err->dbg_message = NULL;
}
}
void
gst_v4l2_error (gpointer element, GstV4l2Error * v4l2err)
{
GError *error;
if (!v4l2err || !v4l2err->error)
return;
error = v4l2err->error;
if (error->message)
GST_WARNING_OBJECT (element, "error: %s", error->message);
if (v4l2err->dbg_message)
GST_WARNING_OBJECT (element, "error: %s", v4l2err->dbg_message);
gst_element_message_full (GST_ELEMENT (element), GST_MESSAGE_ERROR,
error->domain, error->code, error->message, v4l2err->dbg_message,
v4l2err->file, v4l2err->func, v4l2err->line);
error->message = NULL;
v4l2err->dbg_message = NULL;
gst_v4l2_clear_error (v4l2err);
}

78
gst-v4l2/v4l2-utils.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2014 Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
*
* 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.
*
*/
#ifndef __V4L2_UTILS_H__
#define __V4L2_UTILS_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_V4L2_ERROR_INIT { NULL, NULL }
#define GST_V4L2_ERROR(v4l2err,domain,code,msg,dbg) \
{\
if (v4l2err) { \
gchar *_msg = _gst_element_error_printf msg; \
v4l2err->error = g_error_new_literal (GST_##domain##_ERROR, \
GST_##domain##_ERROR_##code, _msg); \
g_free (_msg); \
v4l2err->dbg_message = _gst_element_error_printf dbg; \
v4l2err->file = __FILE__; \
v4l2err->func = GST_FUNCTION; \
v4l2err->line = __LINE__; \
} \
}
typedef struct _GstV4l2Iterator GstV4l2Iterator;
typedef struct _GstV4l2Error GstV4l2Error;
struct _GstV4l2Iterator
{
const gchar *device_path;
const gchar *device_name;
const gchar *sys_path;
};
struct _GstV4l2Error
{
GError *error;
gchar *dbg_message;
const gchar *file;
const gchar *func;
gint line;
};
GstV4l2Iterator * gst_v4l2_iterator_new (void);
gboolean gst_v4l2_iterator_next (GstV4l2Iterator *it);
void gst_v4l2_iterator_free (GstV4l2Iterator *it);
const gchar * gst_v4l2_iterator_get_device_path (GstV4l2Iterator *it);
const gchar * gst_v4l2_iterator_get_device_name (GstV4l2Iterator *it);
const gchar * gst_v4l2_iterator_get_sys_path (GstV4l2Iterator *it);
void gst_v4l2_clear_error (GstV4l2Error *error);
void gst_v4l2_error (gpointer element, GstV4l2Error *error);
G_END_DECLS
#endif /* __V4L2_UTILS_H__ */

1186
gst-v4l2/v4l2_calls.c Normal file
View File

File diff suppressed because it is too large Load Diff

41
gst-v4l2/wsl_utils.c Normal file
View File

@@ -0,0 +1,41 @@
/**
* SPDX-FileCopyrightText: Copyright (c) 2024-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include "wsl_utils.h"
bool is_running_in_WSL(void)
{
static volatile bool verified = false;
static volatile bool ret = false;
if (!verified) {
verified = true;
FILE *versionFile = fopen("/proc/version", "r");
if (versionFile != NULL) {
char versionInfo[512];
if (fgets(versionInfo, sizeof(versionInfo), versionFile) != NULL) {
for (int i=0; versionInfo[i] != '\0'; i++) {
versionInfo[i] = tolower((unsigned char)versionInfo[i]);
}
if (strstr(versionInfo, "microsoft") != NULL) {
/* Yes, Running inside WSL */
ret = true;
}
}
fclose(versionFile);
} else {
printf("ERROR: opening /proc/version failed\n");
}
}
return ret;
}

24
gst-v4l2/wsl_utils.h Normal file
View File

@@ -0,0 +1,24 @@
/**
* SPDX-FileCopyrightText: Copyright (c) 2024-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#ifndef _WSL_UTILS_
#define _WSL_UTILS_
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
/* Function to check if running inside Windows Subsystem For Linux (WSL) */
bool is_running_in_WSL(void);
#endif //_WSL_UTILS_

1075
nvbufsurface.h Normal file
View File

File diff suppressed because it is too large Load Diff

1
push_info.txt Normal file
View File

@@ -0,0 +1 @@
jetson_38.2

3438
v4l2_nv_extensions.h Normal file
View File

File diff suppressed because it is too large Load Diff