Compare commits

..

1 Commits

Author SHA1 Message Date
svcmobrel-release
554cdfd85f Updating prebuilts and/or headers
6913ed4a984b2247d1373f0e1b395c582fefb2bd - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/LICENSE
bead485f1fb0d1861545916d7fb63d633c9ec872 - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/nvgstipctestapp.c
7152d9928416f55c6879ec0170a495f71eabf80d - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/Makefile.public
582a142d1a3098aed3bb4c8f7329e8cdac7b0ed8 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.c
d3dee823127d19bcf050cb35c5e0962e9130d789 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.c
c028fa403772288daf002520356e8e18cce5cb06 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.h
aaafd7fd4c0214a52bf73dd2a0ba0af08c675b85 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.h
33a285339d714d5546cddb92a710e418853470aa - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.c
6bafa48f47ad43d33ee446cf86f2b1da134f7868 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.h
a5bdf6935960973677a005d9d28a04c023f5ec6f - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgst_x11_common.c
bd149086ce2fd243a4f2ef669945ed673aa459b9 - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.h
ec4e84387d8e0e16529f7c8bcd7fee48c16c769c - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.c
87556b6e7da0ec3865546f10b7a58959cd8c6bfc - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgst_x11_common.h

Change-Id: I8370c6e4de7d08081f8762b117676ada366bbc66
2024-05-02 11:24:57 -07:00
11 changed files with 1363 additions and 69 deletions

View File

@@ -1,12 +1,15 @@
Updating prebuilts and/or headers
9b47978b5f3b6672dd4d6ad5ebe80c9b945a7eba - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.c
6913ed4a984b2247d1373f0e1b395c582fefb2bd - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/LICENSE
bead485f1fb0d1861545916d7fb63d633c9ec872 - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/nvgstipctestapp.c
7152d9928416f55c6879ec0170a495f71eabf80d - nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/Makefile.public
582a142d1a3098aed3bb4c8f7329e8cdac7b0ed8 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.c
d3dee823127d19bcf050cb35c5e0962e9130d789 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.c
c028fa403772288daf002520356e8e18cce5cb06 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.h
aaafd7fd4c0214a52bf73dd2a0ba0af08c675b85 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.h
33a285339d714d5546cddb92a710e418853470aa - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.c
6bafa48f47ad43d33ee446cf86f2b1da134f7868 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.h
599544266262509705c60ca9e8d2c8ade3bdfc30 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.c
aaafd7fd4c0214a52bf73dd2a0ba0af08c675b85 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.h
c028fa403772288daf002520356e8e18cce5cb06 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.h
a5bdf6935960973677a005d9d28a04c023f5ec6f - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgst_x11_common.c
6380a3e21b43fdc01c6de7d3934c602af38c3d12 - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.c
bd149086ce2fd243a4f2ef669945ed673aa459b9 - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.h
ec4e84387d8e0e16529f7c8bcd7fee48c16c769c - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.c
87556b6e7da0ec3865546f10b7a58959cd8c6bfc - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgst_x11_common.h
4048ce41fcd68ca284bf6146d2d32608fe69ca8a - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.h

View File

@@ -6,7 +6,7 @@ ARM architecture.
--------------------------------------------------------------------------------
Prerequisites for nvgst-1.0 applications
--------------------------------------------------------------------------------
For nvgstcapture-1.0 and nvgstplayer-1.0 applications:
For nvgstcapture-1.0, nvgstplayer-1.0 and nvgstipctestapp-1.0 applications:
* You must install GStreamer-1.0 on the target board using apt-get, as follows:
@@ -56,9 +56,22 @@ For nvgstcapture-1.0 and nvgstplayer-1.0 applications:
$(pkg-config --cflags --libs gstreamer-1.0 gstreamer-plugins-base-1.0 \
gstreamer-pbutils-1.0 gstreamer-video-1.0 x11 xext alsa)
--------------------------------------------------------------------------------
Procedure to compile nvgstipctestapp-1.0:
--------------------------------------------------------------------------------
On the target, execute the following commands:
cd nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0
gcc nvgstipctestapp.c -o nvgstipctestapp-1.0 \
$(pkg-config --cflags --libs gstreamer-1.0 gstreamer-plugins-base-1.0 \
gstreamer-pbutils-1.0 gstreamer-video-1.0 x11 gstreamer-video-1.0 gstreamer-app-1.0) -lm
* For nvgstcapture-1.0 usage, refer to
nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture-1.0_README.txt
* For nvgstplayer-1.0 usage, refer to
nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer-1.0_README.txt
* For nvgstipctestapp-1.0 usage, refer to
nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/nvgstipctestapp-1.0_README.txt

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2014-2024 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"),
@@ -13,7 +14,7 @@
*
* 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
* 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
@@ -387,7 +388,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
case GST_MESSAGE_STATE_CHANGED:
{
GstState old, new_state, pending;
GstState old = GST_STATE_NULL, new_state = GST_STATE_NULL, pending = GST_STATE_NULL;
gst_message_parse_state_changed (msg, &old, &new_state, &pending);
@@ -518,7 +519,7 @@ static void
write_vsnap_buffer (GstElement * fsink,
GstBuffer * buffer, GstPad * pad, gpointer udata)
{
GstMapInfo info;
GstMapInfo info = GST_MAP_INFO_INIT;
if (gst_buffer_map (buffer, &info, GST_MAP_READ)) {
if (info.size) {
@@ -1404,13 +1405,13 @@ invalid_input:
void
set_capture_device_node (void)
{
gchar *fname = g_strndup ("/dev/video", 12);
gchar *fname = g_strdup ("/dev/video");
fname = strcat (fname, app->cap_dev_node);
if (app->vidcap_device && access (fname, F_OK) != -1) {
g_free (app->vidcap_device);
app->vidcap_device = NULL;
app->vidcap_device = g_strndup ("/dev/video", 12);
app->vidcap_device = g_strdup ("/dev/video");
app->vidcap_device = strcat (app->vidcap_device, app->cap_dev_node);
} else {
g_print ("%s does not exist\n",fname);
@@ -1481,6 +1482,10 @@ set_encoder_bitrate (guint bitrate)
else if (app->capres.vid_res_index >= VR_3840x2160)
bitrate = NVGST_DEFAULT_2160P_ENCODER_BITRATE;
}
if (app->encset.video_enc == FORMAT_H264_SW)
{
bitrate /= 1000; // x264enc requires kbits/sec
}
app->encset.bitrate = bitrate;
g_print ("bitrate = %u\n", app->encset.bitrate);
g_object_set (G_OBJECT (app->ele.vid_enc), "bitrate", app->encset.bitrate,
@@ -1621,16 +1626,25 @@ get_video_encoder (GstElement ** vencoder)
*vencoder = gst_element_factory_make (NVGST_PRIMARY_V4L2_VP9_VENC, NULL);
set_encoder_bitrate (app->encset.bitrate);
break;
case FORMAT_H264_SW:
*vencoder = gst_element_factory_make(NVGST_SW_H264_ENC, NULL);
set_encoder_bitrate(app->encset.bitrate);
break;
default:
*vencoder = gst_element_factory_make (NVGST_PRIMARY_V4L2_H264_VENC, NULL);
break;
}
g_object_set (*vencoder, "control-rate", app->encset.controlrate, NULL);
if (app->encset.video_enc != FORMAT_H264_SW)
{
g_object_set(*vencoder, "control-rate", app->encset.controlrate, NULL);
g_print("Encoder control-rate = %u\n", app->encset.controlrate);
}
if (app->encset.enabletwopassCBR)
{
g_object_set (*vencoder, "EnableTwopassCBR", app->encset.enabletwopassCBR, NULL);
g_print ("Encoder control-rate = %u\n", app->encset.controlrate);
g_print ("Encoder EnableTwopassCBR = %d\n", app->encset.enabletwopassCBR);
g_print("Encoder EnableTwopassCBR = %d\n", app->encset.enabletwopassCBR);
}
if (!(*vencoder)) {
app->return_value = -1;
@@ -1646,7 +1660,10 @@ get_parser (GstElement ** parser)
{
switch (app->encset.video_enc) {
case FORMAT_H264_HW:
*parser = gst_element_factory_make (NVGST_PRIMARY_H264_PARSER, NULL);
*parser = gst_element_factory_make(NVGST_PRIMARY_H264_PARSER, NULL);
break;
case FORMAT_H264_SW:
*parser = gst_element_factory_make(NVGST_PRIMARY_H264_PARSER, NULL);
break;
case FORMAT_H265_HW:
*parser = gst_element_factory_make (NVGST_PRIMARY_H265_PARSER, NULL);
@@ -2024,7 +2041,7 @@ static void
cam_image_captured (GstElement * fsink,
GstBuffer * buffer, GstPad * pad, gpointer udata)
{
GstMapInfo info;
GstMapInfo info = GST_MAP_INFO_INIT;
if (app->capcount == 0) {
if (gst_buffer_map (buffer, &info, GST_MAP_READ)) {
@@ -2743,8 +2760,11 @@ create_video_scaling_bin (void)
"width", G_TYPE_INT, app->capres.video_cap_width,
"height", G_TYPE_INT, app->capres.video_cap_height, NULL);
feature = gst_caps_features_new ("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
if (app->encset.video_enc != FORMAT_H264_SW)
{
feature = gst_caps_features_new("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
}
/* Set capture caps on capture filter */
g_object_set (app->ele.svc_vidvconv_out_filter, "caps", caps, NULL);
@@ -2875,6 +2895,10 @@ rtsp_video_stream_new (GObject * media)
case FORMAT_VP9_HW:
appsrc_caps = gst_caps_from_string ("video/x-vp9");
break;
case FORMAT_H264_SW:
appsrc_caps =
gst_caps_from_string("video/x-h264, stream-format=byte-stream, alignment=au");
break;
default:
appsrc_caps = gst_caps_from_string ("video/x-h264");
break;
@@ -3014,8 +3038,12 @@ create_streaming_file_src_bin (void)
gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "I420",
"width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
feature = gst_caps_features_new ("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
if (app->encset.video_enc != FORMAT_H264_SW)
{
feature = gst_caps_features_new("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
}
g_object_set (app->ele.cap_filter, "caps", caps, NULL);
gst_caps_unref (caps);
@@ -3083,6 +3111,11 @@ create_streaming_enc_bin (void)
case FORMAT_VP9_HW:
appsink_caps = gst_caps_from_string ("video/x-vp9");
break;
case FORMAT_H264_SW:
appsink_caps =
gst_caps_from_string
("video/x-h264, stream-format=byte-stream, alignment=au");
break;
default:
appsink_caps = gst_caps_from_string ("video/x-h264");
break;
@@ -3145,13 +3178,32 @@ create_vid_enc_bin (void)
caps =
gst_caps_new_simple ("video/x-raw","format", G_TYPE_STRING, "NV12", NULL);
feature = gst_caps_features_new ("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
if (app->encset.video_enc != FORMAT_H264_SW) {
feature = gst_caps_features_new("memory:NVMM", NULL);
gst_caps_set_features(caps, 0, feature);
}
g_object_set (G_OBJECT (app->ele.vid_enc_cap_filter), "caps", caps, NULL);
gst_caps_unref (caps);
}
if ((app->cam_src == NV_CAM_SRC_CSI) && (app->encset.video_enc == FORMAT_H264_SW))
{
app->ele.vid_enc_conv = gst_element_factory_make("nvvidconv", "nvvidconv");
if (!app->ele.vid_enc_conv)
{
NVGST_ERROR_MESSAGE("nvvidconv element could not be created.\n");
goto fail;
}
app->ele.vid_enc_cap_filter =
gst_element_factory_make(NVGST_DEFAULT_CAPTURE_FILTER, NULL);
caps =
gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", NULL);
g_object_set(G_OBJECT(app->ele.vid_enc_cap_filter), "caps", caps, NULL);
gst_caps_unref(caps);
}
app->ele.video_sink =
gst_element_factory_make (NVGST_DEFAULT_VENC_SINK, NULL);
if (!app->ele.video_sink) {
@@ -3193,8 +3245,25 @@ create_vid_enc_bin (void)
}
else
{
gst_bin_add_many (GST_BIN (app->ele.vid_bin), app->ele.vid_enc,
app->ele.parser, app->ele.muxer, app->ele.video_sink, NULL);
if (app->encset.video_enc != FORMAT_H264_SW) {
gst_bin_add_many(GST_BIN(app->ele.vid_bin), app->ele.vid_enc,
app->ele.parser, app->ele.muxer, app->ele.video_sink, NULL);
}
else {
gst_bin_add_many(GST_BIN(app->ele.vid_bin), app->ele.vid_enc_conv,
app->ele.vid_enc_cap_filter, app->ele.vid_enc,
app->ele.parser, app->ele.muxer, app->ele.video_sink, NULL);
if ((gst_element_link(app->ele.vid_enc_conv, app->ele.vid_enc_cap_filter)) != TRUE) {
NVGST_ERROR_MESSAGE("Elements could not link nvvidconv & caps filter\n");
goto fail;
}
if ((gst_element_link(app->ele.vid_enc_cap_filter, app->ele.vid_enc)) != TRUE) {
NVGST_ERROR_MESSAGE("Elements could not link caps filter & encoder \n");
goto fail;
}
}
}
if ((gst_element_link (app->ele.vid_enc, app->ele.parser)) != TRUE) {
@@ -3204,14 +3273,13 @@ create_vid_enc_bin (void)
srcpad = gst_element_get_static_pad (app->ele.parser, "src");
if (app->muxer_is_identity)
{
sinkpad = gst_element_get_static_pad (app->ele.muxer, "sink");
}
else
{
sinkpad = gst_element_get_request_pad (app->ele.muxer, "video_%u");
sinkpad = gst_element_request_pad_simple (app->ele.muxer, "video_%u");
}
if (!sinkpad || !srcpad) {
@@ -3230,7 +3298,7 @@ create_vid_enc_bin (void)
goto fail;
}
if(app->cam_src != NV_CAM_SRC_CSI)
if((app->cam_src != NV_CAM_SRC_CSI) || (app->encset.video_enc == FORMAT_H264_SW))
{
pad = gst_element_get_static_pad (app->ele.vid_enc_conv, "sink");
if (!pad) {
@@ -4099,14 +4167,14 @@ nvgst_handle_xevents ()
static gpointer
nvgst_x_event_thread (gpointer data)
{
gint64 end_time;
g_mutex_lock (app->lock);
while (app->disp.window) {
nvgst_handle_xevents ();
end_time = g_get_monotonic_time () + 1;
g_cond_wait_until (app->x_cond, app->lock, end_time);
g_mutex_unlock(app->lock);
g_usleep(G_USEC_PER_SEC / 20);
g_mutex_lock(app->lock);
}
g_mutex_unlock (app->lock);
g_mutex_unlock(app->lock);
return NULL;
}
#endif
@@ -4295,6 +4363,7 @@ main (int argc, char *argv[])
/* Initialize capture params */
capture_init_params ();
GOptionEntry options_argus[] = {
{"prev-res", 0, 0, G_OPTION_ARG_CALLBACK, parse_spec,
"Preview width & height."
@@ -4320,7 +4389,7 @@ main (int argc, char *argv[])
"Capture mode value (1=still 2=video)", NULL}
,
{"video-enc", 'v', 0, G_OPTION_ARG_INT, &app->encset.video_enc,
"Video encoder type (0=h264[HW] 1=vp8[HW] 2=h265[HW] 3=vp9[HW])",
"Video encoder type (0=h264[HW] 1=vp8[HW] 2=h265[HW] 3=vp9[HW] 4=h264[SW])",
NULL}
,
{"hw-enc-path", 'p', 0, G_OPTION_ARG_INT, &app->encset.hw_enc_type,
@@ -4521,6 +4590,14 @@ main (int argc, char *argv[])
if(app->encset.bitrate != 0)
is_user_bitrate = 1;
if ((access (NVGST_DEFAULT_V4L2_NVENC_DEVICE_PATH, F_OK) != 0) &&
(access (NVGST_DEFAULT_V4L2_NVENC_DEVICE_PATH_ALT, F_OK) != 0))
{
if (app->encset.video_enc != FORMAT_H264_SW)
g_print("Codec not supported. Falling back to opensrc H264 encoder\n");
app->encset.video_enc = FORMAT_H264_SW;
}
g_option_context_free (ctx);
if (!app->aut.automate)
@@ -4576,6 +4653,10 @@ main (int argc, char *argv[])
payloader = "rtpvp9pay";
parser = "identity";
break;
case FORMAT_H264_SW:
payloader = "rtph264pay";
parser = "h264parse";
break;
default:
NVGST_ERROR_MESSAGE ("Unsupported codec for streaming");
goto done;

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2014-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"),
@@ -13,7 +14,7 @@
*
* 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
* 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
@@ -93,6 +94,8 @@ int dummy_func ()
#define NVGST_DEFAULT_CAPTURE_FORMAT "I420"
#define NVGST_DEFAULT_CAPTURE_FPS 30
#define NVGST_DEFAULT_VIDCAP_DEVICE "/dev/video0"
#define NVGST_DEFAULT_V4L2_NVENC_DEVICE_PATH "/dev/nvhost-msenc"
#define NVGST_DEFAULT_V4L2_NVENC_DEVICE_PATH_ALT "/dev/v4l2-nvenc"
#define DEFAULT_LOCATION "/dev/null"
#define SUCCESS 0
@@ -143,6 +146,7 @@ int dummy_func ()
#define NVGST_PRIMARY_V4L2_VP8_VENC "nvv4l2vp8enc"
#define NVGST_PRIMARY_V4L2_VP9_VENC "nvv4l2vp9enc"
#define NVGST_PRIMARY_V4L2_H265_VENC "nvv4l2h265enc"
#define NVGST_SW_H264_ENC "x264enc"
#define NVGST_PRIMARY_H264_PARSER "h264parse"
#define NVGST_PRIMARY_H265_PARSER "h265parse"
#define NVGST_PRIMARY_MP4_MUXER "qtmux"
@@ -419,10 +423,11 @@ typedef enum
FORMAT_H264_HW = 0,
FORMAT_VP8_HW,
FORMAT_H265_HW,
FORMAT_VP9_HW
FORMAT_VP9_HW,
FORMAT_H264_SW
} VideoEncFormatType;
#define VIDEO_ENC_STRINGS {"H.264 (HW)", "VP8 (HW)", "H.265 (HW)", "VP9 (HW)", NULL};
#define VIDEO_ENC_STRINGS {"H.264 (HW)", "VP8 (HW)", "H.265 (HW)", "VP9 (HW)", "H264 (SW)", NULL};
/* H264 ENCODE PROFILE TYPE */
typedef enum
@@ -499,7 +504,7 @@ typedef struct
typedef struct
{
gint image_enc;
gint video_enc;
VideoEncFormatType video_enc;
HardwareEncoderType hw_enc_type;
guint bitrate;
gboolean enabletwopassCBR;

View File

@@ -0,0 +1,20 @@
SPDX-FileCopyrightText: Copyright (c) 2024 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.

View File

@@ -0,0 +1,111 @@
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2024 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.
################################################################################
SRC:=nvgstipctestapp.c
PKGS := gstreamer-1.0 \
gstreamer-base-1.0 \
gstreamer-video-1.0 \
gstreamer-allocators-1.0 \
gstreamer-audio-1.0 \
gstreamer-app-1.0 \
glib-2.0 \
gobject-2.0 \
gthread-2.0 \
gmodule-2.0 \
# Clear the flags from env
CFLAGS :=
LDFLAGS :=
# Verbose flag
ifeq ($(VERBOSE), 1)
AT =
else
AT = @
endif
# ARM ABI of the target platform
ifeq ($(TEGRA_ARMABI),)
TEGRA_ARMABI ?= aarch64-linux-gnu
endif
# Location of the target rootfs
ifeq ($(shell uname -m), aarch64)
TARGET_ROOTFS :=
else
ifeq ($(TARGET_ROOTFS),)
$(error Please specify the target rootfs path if you are cross-compiling)
endif
endif
ifeq ($(shell uname -m), aarch64)
CROSS_COMPILE :=
else
CROSS_COMPILE ?= aarch64-unknown-linux-gnu-
endif
AS = $(AT) $(CROSS_COMPILE)as
LD = $(AT) $(CROSS_COMPILE)ld
CC = $(AT) $(CROSS_COMPILE)gcc
AR = $(AT) $(CROSS_COMPILE)ar
NM = $(AT) $(CROSS_COMPILE)nm
STRIP = $(AT) $(CROSS_COMPILE)strip
OBJCOPY = $(AT) $(CROSS_COMPILE)objcopy
OBJDUMP = $(AT) $(CROSS_COMPILE)objdump
# Specify the logical root directory for headers and libraries.
ifneq ($(TARGET_ROOTFS),)
LDFLAGS += \
-Wl,-rpath-link=$(TARGET_ROOTFS)/usr/lib \
-Wl,-rpath-link=$(TARGET_ROOTFS)/lib/$(TEGRA_ARMABI) \
-Wl,-rpath-link=$(TARGET_ROOTFS)/usr/lib/$(TEGRA_ARMABI)/gstreamer-1.0
endif
# All common dependent libraries
LDFLAGS += \
-lpthread \
-lm \
-ldl \
-L"$(TARGET_ROOTFS)/usr/lib" \
-L"$(TARGET_ROOTFS)/usr/lib/$(TEGRA_ARMABI)" \
-L"$(TARGET_ROOTFS)/usr/lib/$(TEGRA_ARMABI)/gstreamer-1.0"
OBJS := $(SRC:.c=.o)
CFLAGS +=`pkg-config --cflags $(PKGS)`
LDFLAGS +=`pkg-config --libs $(PKGS)`
APP:=nvgstipctestapp-1.0
all: $(APP)
%.o: %.c
@echo "Compiling: $<"
$(CC) -c $< $(CFLAGS) -o $@
$(APP): $(OBJS)
@echo "Linking: $@"
$(CC) -o $@ $(OBJS) $(CFLAGS) $(LDFLAGS)
clean:
$(AT)rm -rf $(APP) $(OBJS)

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
*
* 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.
*/
NvGstIpcTestApp Usage (command: ./nvgstipctestapp --help)
=======
=> PREREQUISITES:
1. You must install GStreamer-1.0 on the target board using apt-get, as follows:
sudo apt-get install gstreamer1.0-tools gstreamer1.0-alsa gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-plugins-bad gstreamer1.0-libav
2. Execute the following commands on the target board's Ubuntu command line before starting the player:
export DISPLAY=:0
xinit &
NvGstIpcTestApp Usage
-----------------------------------------------
Run with the command line.
$ nvgstipctestapp server <rtsp_url> <socket_path>
$ nvgstipctestapp client <socket_path>
e.g.
$ nvgstipctestapp server rtsp://127.0.0.1/video1 /tmp/test1
$ nvgstipctestapp client /tmp/test1
This sample act as either server or client based on command line arguments.
The server accepts H.264/H.265 video stream RTSP URL and IPC socket path
as input. It does the decoding of the stream and listens for the connection
on the IPC socket path. It sends decoded data over IPC to the connected client.
The client accepts IPC socket path as input. It sends connection request to the
server. Once server accepts the request, it starts receiving the decoded data
over IPC which is further pushed into the pipeline.

View File

@@ -0,0 +1,995 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 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.
*/
#include <gst/gst.h>
#include <glib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#define MAX_SOURCE_BINS 8
#define MAX_IPC_SINKS 8
/* NVIDIA Decoder source pad memory feature. This feature signifies that source
* pads having this capability will push GstBuffers containing cuda buffers. */
#define GST_CAPS_FEATURES_NVMM "memory:NVMM"
typedef struct
{
int fd;
guint bus_id;
GstElement *pipeline;
GstElement *appsrc;
GMainLoop *loop;
gboolean quit;
pthread_t thread_id;
void *ipcserver;
} NvIpcSinkPipeline;
typedef struct
{
int fd;
gchar *uri;
gchar *socket_path;
gchar *caps_string;
pthread_t thread_id;
guint bus_id;
GstElement *pipeline;
GQueue *ipc_sink_queue;
GMutex ipc_sink_queue_lock;
GMutex caps_mutex;
GCond caps_cond;
gboolean is_caps;
void *appCtx;
} NvIpcServerPipeline;
typedef struct
{
int fd[MAX_SOURCE_BINS];
gchar *socket_path[MAX_SOURCE_BINS];
guint bus_id;
GstElement *pipeline;
void *appCtx;
} NvIpcClientPipeline;
typedef struct
{
GMainLoop *loop;
NvIpcServerPipeline ipcserver[MAX_SOURCE_BINS];
NvIpcClientPipeline ipcclient;
gboolean quit;
} AppCtx;
static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer user_data)
{
GMainLoop *loop = (GMainLoop *) user_data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_WARNING:
{
gchar *debug;
GError *error;
gst_message_parse_warning (msg, &error, &debug);
g_printerr ("WARNING from element %s: %s\n",
GST_OBJECT_NAME (msg->src), error->message);
g_free (debug);
g_printerr ("Warning: %s\n", error->message);
g_error_free (error);
break;
}
case GST_MESSAGE_ERROR:
{
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_printerr ("ERROR from element %s: %s\n",
GST_OBJECT_NAME (msg->src), error->message);
if (debug)
g_printerr ("Error details: %s\n", debug);
g_free (debug);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_STATE_CHANGED:{
GstState oldstate, newstate;
gst_message_parse_state_changed (msg, &oldstate, &newstate, NULL);
switch (newstate) {
case GST_STATE_PLAYING:
g_print ("Pipeline running\n");
break;
case GST_STATE_PAUSED:
if (oldstate == GST_STATE_PLAYING) {
g_print ("Pipeline paused\n");
}
break;
case GST_STATE_READY:
if (oldstate == GST_STATE_NULL) {
g_print ("Pipeline ready\n");
} else {
g_print ("Pipeline stopped\n");
}
break;
case GST_STATE_NULL:
g_print ("Pipeline Null\n");
g_main_loop_quit (loop);
break;
default:
break;
}
break;
}
default:
break;
}
return TRUE;
}
static void
cb_newpad (GstElement * decodebin, GstPad * decoder_src_pad, gpointer data)
{
GstCaps *caps = gst_pad_get_current_caps (decoder_src_pad);
if (!caps) {
caps = gst_pad_query_caps (decoder_src_pad, NULL);
}
const GstStructure *str = gst_caps_get_structure (caps, 0);
const gchar *name = gst_structure_get_name (str);
GstElement *source_bin = (GstElement *) data;
GstCapsFeatures *features = gst_caps_get_features (caps, 0);
/* Need to check if the pad created by the decodebin is for video and not
* audio. */
if (!strncmp (name, "video", 5)) {
/* Link the decodebin pad only if decodebin has picked nvidia
* decoder plugin nvdec_*. We do this by checking if the pad caps contain
* NVMM memory features. */
if (gst_caps_features_contains (features, GST_CAPS_FEATURES_NVMM)) {
/* Get the source bin ghost pad */
GstPad *bin_ghost_pad = gst_element_get_static_pad (source_bin, "src");
if (!gst_ghost_pad_set_target (GST_GHOST_PAD (bin_ghost_pad),
decoder_src_pad)) {
g_printerr ("Failed to link decoder src pad to source bin ghost pad\n");
}
gst_object_unref (bin_ghost_pad);
} else {
g_printerr ("Error: Decodebin did not pick nvidia decoder plugin.\n");
}
}
}
static void
decodebin_child_added (GstChildProxy * child_proxy, GObject * object,
gchar * name, gpointer user_data)
{
g_print ("Decodebin child added: %s\n", name);
if (g_strrstr (name, "decodebin") == name) {
g_signal_connect (G_OBJECT (object), "child-added",
G_CALLBACK (decodebin_child_added), user_data);
}
}
static GstElement *
create_source_bin (guint index, gchar * uri)
{
GstElement *bin = NULL, *uri_decode_bin = NULL;
gchar bin_name[16] = { };
g_snprintf (bin_name, 15, "source-bin-%02d", index);
/* Create a source GstBin to abstract this bin's content from the rest of the
* pipeline */
bin = gst_bin_new (bin_name);
/* Source element for reading from the uri.
* We will use decodebin and let it figure out the container format of the
* stream and the codec and plug the appropriate demux and decode plugins. */
uri_decode_bin = gst_element_factory_make ("uridecodebin", NULL);
if (!bin || !uri_decode_bin) {
g_printerr ("One element in source bin could not be created.\n");
return NULL;
}
/* We set the input uri to the source element */
g_object_set (G_OBJECT (uri_decode_bin), "uri", uri, NULL);
/* Connect to the "pad-added" signal of the decodebin which generates a
* callback once a new pad for raw data has beed created by the decodebin */
g_signal_connect (G_OBJECT (uri_decode_bin), "pad-added",
G_CALLBACK (cb_newpad), bin);
g_signal_connect (G_OBJECT (uri_decode_bin), "child-added",
G_CALLBACK (decodebin_child_added), bin);
gst_bin_add (GST_BIN (bin), uri_decode_bin);
/* We need to create a ghost pad for the source bin which will act as a proxy
* for the video decoder src pad. The ghost pad will not have a target right
* now. Once the decode bin creates the video decoder and generates the
* cb_newpad callback, we will set the ghost pad target to the video decoder
* src pad. */
if (!gst_element_add_pad (bin, gst_ghost_pad_new_no_target ("src",
GST_PAD_SRC))) {
g_printerr ("Failed to add ghost pad in source bin\n");
return NULL;
}
return bin;
}
static int
UnixSocketConnect(const char *socket_name) {
int sock_fd = -1;
struct sockaddr_un sock_addr;
int wait_loop = 0;
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0) {
g_printerr("%s: socket create failed.\n", __func__);
return -1;
}
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
sock_addr.sun_family = AF_UNIX;
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
while (connect(sock_fd, (const struct sockaddr *)&sock_addr,
sizeof(struct sockaddr_un))) {
/* wait loop runs 60 times after sleep of 100ms each */
if (wait_loop < 60) {
g_print("Waiting for producer count %d\n", wait_loop);
usleep(100000);
wait_loop++;
} else {
g_printerr("\n%s: Waiting timed out\n", __func__);
close (sock_fd);
sock_fd = -1;
return -1;
}
}
return sock_fd;
}
static GstElement *
create_ipc_source_bin (NvIpcClientPipeline *ipcclient, guint index, gchar *socket_path)
{
GstElement *bin = NULL, *ipcpipelinesrc = NULL, *capsfilter = NULL, *queue = NULL;
GstPad *source_pad = NULL, *ghost_sourcepad = NULL;
gchar bin_name[16] = { };
int sock_fd = UnixSocketConnect(socket_path);
if (sock_fd == -1) {
g_printerr ("UnixSocketConnect failed\n");
return NULL;
}
ipcclient->fd[index] = sock_fd;
ipcclient->socket_path[index] = strdup(socket_path);
g_print("client is connected path: %s fd: %d\n",
ipcclient->socket_path[index], ipcclient->fd[index]);
g_snprintf (bin_name, 15, "source-bin-%02d", index);
/* Create a source GstBin to abstract this bin's content from the rest of the
* pipeline */
bin = gst_bin_new (bin_name);
ipcpipelinesrc = gst_element_factory_make ("nvipcpipelinesrc", NULL);
capsfilter = gst_element_factory_make ("capsfilter", NULL);
queue = gst_element_factory_make ("queue", NULL);
if (!bin || !ipcpipelinesrc || !capsfilter || !queue) {
g_printerr ("One element in source bin could not be created.\n");
return NULL;
}
GstCaps* caps = gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "NV12", NULL);
GstCapsFeatures *feature = NULL;
feature = gst_caps_features_new ("memory:NVMM", NULL);
gst_caps_set_features (caps, 0, feature);
g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
g_object_set (ipcpipelinesrc, "ack-time", 10000000, NULL);
g_object_set (ipcpipelinesrc, "fdin", sock_fd, "fdout", sock_fd, NULL);
gst_bin_add_many (GST_BIN (bin), ipcpipelinesrc, capsfilter, queue, NULL);
if (!gst_element_link_many(ipcpipelinesrc, capsfilter, queue, NULL)) {
g_printerr ("Failed to link in source bin\n");
return NULL;
}
source_pad = gst_element_get_static_pad (queue, "src");
ghost_sourcepad = gst_ghost_pad_new ("src", source_pad);
gst_pad_set_active (ghost_sourcepad, TRUE);
if (!gst_element_add_pad (bin, ghost_sourcepad)) {
g_printerr ("Failed to add ghost pad in source bin\n");
return NULL;
}
gst_object_unref (source_pad);
return bin;
}
static int
create_client_pipeline (int argc, char *argv[])
{
AppCtx appCtx;
GMainLoop *loop = NULL;
GstElement *pipeline = NULL, *compositor = NULL, *sink = NULL, *fpssink = NULL;
GstBus *bus = NULL;
guint bus_watch_id;
guint i =0, num_sources = 0;
guint tiler_rows, tiler_columns, tiler_row, tiler_xpos, tiler_ypos,
tiler_column, tiler_width, tiler_height;
gboolean PERF_MODE = g_getenv("NV_IPC_TEST_PERF_MODE") &&
!g_strcmp0(g_getenv("NV_IPC_TEST_PERF_MODE"), "1");
memset(&appCtx, 0, sizeof(AppCtx));
appCtx.loop = loop = g_main_loop_new (NULL, FALSE);
/* Create gstreamer elements */
pipeline = gst_pipeline_new (NULL);
compositor = gst_element_factory_make ("nvcompositor", NULL);
g_object_set (G_OBJECT (compositor), "start-time-selection", 1, NULL);
if (!pipeline || !compositor) {
g_printerr ("One element could not be created. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), compositor);
num_sources = argc - 2;
tiler_row = 0;
tiler_column = 0;
tiler_rows = (guint) round (sqrt (num_sources));
tiler_columns = (guint) ceil (1.0 * num_sources / tiler_rows);
tiler_width = 1920/tiler_columns;
tiler_height = 1080/tiler_columns;
g_print("rows %d columns %d width %d height %d\n", tiler_rows, tiler_columns, tiler_width, tiler_height);
for (i = 0; i < num_sources; i++) {
GstPad *sinkpad, *srcpad;
gchar pad_name[16] = { };
GstElement *source_bin= NULL;
source_bin = create_ipc_source_bin (&appCtx.ipcclient, i, argv[i + 2]);
if (!source_bin) {
g_printerr ("Failed to create source bin. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), source_bin);
g_snprintf (pad_name, 15, "sink_%u", i);
sinkpad = gst_element_request_pad_simple (compositor, pad_name);
if (!sinkpad) {
g_printerr ("Streammux request sink pad failed. Exiting.\n");
return -1;
}
srcpad = gst_element_get_static_pad (source_bin, "src");
if (!srcpad) {
g_printerr ("Failed to get src pad of source bin. Exiting.\n");
return -1;
}
if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) {
g_printerr ("Failed to link source bin to stream muxer. Exiting.\n");
return -1;
}
tiler_xpos = (tiler_column * tiler_width);
tiler_ypos = (tiler_row * tiler_height);
g_print("xpos %d ypos %d width %d height %d\n", tiler_xpos, tiler_ypos, tiler_width, tiler_height);
if (tiler_column < tiler_columns - 1) {
tiler_column++;
} else {
tiler_row++;
tiler_column = 0;
}
g_object_set (sinkpad, "xpos", tiler_xpos, NULL);
g_object_set (sinkpad, "ypos", tiler_ypos, NULL);
g_object_set (sinkpad, "width", tiler_width, NULL);
g_object_set (sinkpad, "height", tiler_height, NULL);
gst_object_unref (srcpad);
gst_object_unref (sinkpad);
}
fpssink = gst_element_factory_make ("fpsdisplaysink", NULL);
if (!fpssink) {
g_printerr ("One element could not be created. Exiting.\n");
return -1;
}
if (PERF_MODE)
sink = gst_element_factory_make ("fakesink", NULL);
else
sink = gst_element_factory_make ("nv3dsink", NULL);
if (!sink) {
g_printerr ("One element could not be created. Exiting.\n");
return -1;
}
g_object_set (G_OBJECT (sink), "sync", FALSE, NULL);
g_object_set (G_OBJECT (fpssink), "text-overlay", FALSE, "sync", FALSE, "video-sink", sink, NULL);
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_bin_add_many (GST_BIN (pipeline), fpssink, NULL);
if (!gst_element_link_many (compositor, fpssink, NULL)) {
g_printerr ("Elements could not be linked. Exiting.\n");
return -1;
}
if (PERF_MODE)
g_signal_connect(pipeline, "deep-notify", G_CALLBACK( gst_object_default_deep_notify ), NULL );
/* Set the pipeline to "playing" state */
g_print ("Now playing:");
for (i = 0; i < num_sources; i++) {
g_print (" %s,", argv[i + 2]);
}
g_print ("\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Wait till pipeline encounters an error or EOS */
g_print ("Running...\n");
g_main_loop_run (loop);
appCtx.quit = TRUE;
for (i = 0; i < num_sources; i++) {
g_print("client is disconnected path: %s fd: %d\n",
appCtx.ipcclient.socket_path[i], appCtx.ipcclient.fd[i]);
close(appCtx.ipcclient.fd[i]);
g_free(appCtx.ipcclient.socket_path[i]);
}
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeline));
g_source_remove (bus_watch_id);
g_main_loop_unref (loop);
return 0;
}
static int
UnixSocketCreate(const char *socket_name) {
int listen_fd;
struct sockaddr_un sock_addr;
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (listen_fd < 0) {
g_printerr("%s: socket create failed", __func__);
return -1;
}
unlink(socket_name);
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
sock_addr.sun_family = AF_UNIX;
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
sock_addr.sun_path[sizeof(sock_addr.sun_path) - 1] = '\0';
if (bind(listen_fd, (const struct sockaddr *)&sock_addr,
sizeof(struct sockaddr_un))) {
g_printerr("%s: bind error", __func__);
close(listen_fd);
return -1;
}
if (listen(listen_fd, 16)) {
g_printerr("%s: listen error", __func__);
close(listen_fd);
return -1;
}
return listen_fd;
}
static int
UnixSocketAccept(int listen_fd) {
/* connect_fd -2 represents timeout */
int connect_fd = -2;
struct sockaddr_un connect_addr;
socklen_t connect_addr_len = 0;
struct timeval timeout;
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(listen_fd, &read_fds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
int activity = select(listen_fd + 1, &read_fds, NULL, NULL, &timeout);
if (activity > 0) {
connect_fd =
accept(listen_fd, (struct sockaddr *)&connect_addr, &connect_addr_len);
if (connect_fd < 0) {
g_printerr("%s: accept failed\n", __func__);
return -1;
}
}
return connect_fd;
}
static void*
client_handler(void *user_data)
{
NvIpcSinkPipeline *ipcsink = (NvIpcSinkPipeline *)user_data;
NvIpcServerPipeline *ipcserver = (NvIpcServerPipeline *)ipcsink->ipcserver;
g_main_loop_run(ipcsink->loop);
ipcsink->quit = TRUE;
gst_element_set_state (ipcsink->pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (ipcsink->pipeline));
g_source_remove (ipcsink->bus_id);
close(ipcsink->fd);
g_main_loop_unref (ipcsink->loop);
g_print("client is disconnected uri: %s path: %s fd: %d\n",
ipcserver->uri, ipcserver->socket_path, ipcsink->fd);
return NULL;
}
static int
create_ipc_sink_pipeline (NvIpcSinkPipeline *ipcsink)
{
GstElement *pipeline = NULL;
GstBus *bus = NULL;
guint bus_watch_id;
GstElement *appsrc=NULL, *capsfilter=NULL, *ipcpipelinesink=NULL;
GstCaps *caps=NULL;
GMainLoop *loop = NULL;
NvIpcServerPipeline *ipcserver = (NvIpcServerPipeline *)ipcsink->ipcserver;
ipcsink->loop = loop = g_main_loop_new (NULL, FALSE);
/* Create gstreamer elements */
ipcsink->pipeline = pipeline = gst_pipeline_new (NULL);
if (!pipeline) {
g_printerr ("Failed to create pipeline. Exiting.\n");
return -1;
}
ipcsink->appsrc = appsrc = gst_element_factory_make ("appsrc", NULL);
if (!appsrc) {
g_printerr ("Failed to create appsrc. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), appsrc);
capsfilter = gst_element_factory_make ("capsfilter", NULL);
if (!capsfilter) {
g_printerr ("Failed to create capsfilter. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), capsfilter);
ipcpipelinesink = gst_element_factory_make ("nvipcpipelinesink", NULL);
if (!ipcpipelinesink) {
g_printerr ("Failed to create ipcpipelinesink. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), ipcpipelinesink);
if (ipcserver->caps_string) {
caps = gst_caps_from_string (ipcserver->caps_string);
} else {
caps = gst_caps_from_string ("video/x-raw(memory:NVMM),format=NV12,width=1920,height=1080,framerate=30/1");
}
g_object_set (G_OBJECT(capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
g_object_set (G_OBJECT(appsrc), "format", 3, NULL);
g_object_set (G_OBJECT(appsrc), "is-live", TRUE, NULL);
g_object_set (G_OBJECT(ipcpipelinesink), "ack-time", 10000000, NULL);
g_object_set (G_OBJECT(ipcpipelinesink), "fdin", ipcsink->fd, "fdout", ipcsink->fd, NULL);
/* link the elements together */
if (!gst_element_link_many (appsrc, capsfilter, ipcpipelinesink, NULL)) {
g_printerr ("Elements could not be linked. Exiting.\n");
return -1;
}
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
ipcsink->bus_id = bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_element_set_state (ipcsink->pipeline, GST_STATE_PLAYING);
pthread_create(&ipcsink->thread_id, NULL,
client_handler, (void*)ipcsink);
return 0;
}
static void*
connection_handler(void *user_data)
{
NvIpcServerPipeline *ipcserver = (NvIpcServerPipeline *)user_data;
AppCtx *appCtx = (AppCtx *)ipcserver->appCtx;
int listen_fd = ipcserver->fd;
int connect_fd;
int ret;
while (!appCtx->quit) {
connect_fd = UnixSocketAccept(listen_fd);
if (connect_fd == -1) {
g_printerr("UnixSocketAccept failed\n");
break;
} else if (connect_fd == -2) {
/*Accept timeout to check if loop quits due to any error */
continue;
}
NvIpcSinkPipeline *ipcsink = g_new0 (NvIpcSinkPipeline, 1);
ipcsink->fd = connect_fd;
ipcsink->ipcserver = (void *)ipcserver;
ret = create_ipc_sink_pipeline(ipcsink);
if (ret == -1) {
g_printerr("create_ipc_sink_pipeline failed\n");
close(connect_fd);
g_free(ipcsink);
break;
}
g_print("client is connected uri: %s path: %s fd: %d\n",
ipcserver->uri, ipcserver->socket_path, connect_fd);
g_mutex_lock (&ipcserver->ipc_sink_queue_lock);
g_queue_push_tail (ipcserver->ipc_sink_queue, ipcsink);
g_mutex_unlock (&ipcserver->ipc_sink_queue_lock);
}
if (!appCtx->quit) {
g_main_loop_quit (appCtx->loop);
}
g_mutex_lock (&ipcserver->ipc_sink_queue_lock);
while (!g_queue_is_empty(ipcserver->ipc_sink_queue))
{
NvIpcSinkPipeline *ipcsink =
(NvIpcSinkPipeline *)g_queue_pop_head (ipcserver->ipc_sink_queue);
if (!ipcsink->quit) {
g_main_loop_quit (ipcsink->loop);
}
pthread_join(ipcsink->thread_id, NULL);
g_free(ipcsink);
}
g_mutex_unlock (&ipcserver->ipc_sink_queue_lock);
return NULL;
}
static void
gst_mem_free_cb(GstSample *sample, GstMiniObject *obj)
{
if (sample) {
gst_sample_unref (sample);
}
}
static GstFlowReturn
on_new_sample (GstElement *appsink, gpointer user_data)
{
NvIpcServerPipeline *ipcserver = (NvIpcServerPipeline *)user_data;
GstSample *sample = NULL;
GstBuffer *srcbuffer = NULL;
GstMapInfo srcmap;
if (gst_app_sink_is_eos((GstAppSink *)appsink)) {
g_printerr("EOS Received on app sink element\n");
return GST_FLOW_EOS;
}
/* Get the sample from appsink */
sample = gst_app_sink_pull_sample (GST_APP_SINK (appsink));
if (sample == NULL) {
g_printerr("Sample NULL received on app sink element\n");
return GST_FLOW_OK;
}
/* Get the buffer from sample */
srcbuffer = gst_sample_get_buffer (sample);
if (srcbuffer == NULL) {
g_printerr("No more buffers available from app sink element\n");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
/* Map the gst buffer */
if (gst_buffer_map (srcbuffer, &srcmap, GST_MAP_READ) == FALSE) {
g_printerr("Map the gst buffer Failed\n");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
g_mutex_lock (&ipcserver->ipc_sink_queue_lock);
if (g_queue_is_empty(ipcserver->ipc_sink_queue)) {
g_mutex_unlock (&ipcserver->ipc_sink_queue_lock);
gst_buffer_unmap (srcbuffer, &srcmap);
gst_sample_unref (sample);
return GST_FLOW_OK;
}
GList *current = ipcserver->ipc_sink_queue->head;
while (current != NULL) {
NvIpcSinkPipeline *ipcsink = (NvIpcSinkPipeline *)(current->data);
if (!ipcsink->quit) {
/* Allocate a new Gst Buffer */
GstBuffer *dstbuffer = gst_buffer_new_allocate (NULL, srcmap.size, NULL);
GstMapInfo dstmap;
/* Map the Gst Buffer to write the data */
gst_buffer_map (dstbuffer, &dstmap, GST_MAP_WRITE);
int copy_flags = (GST_BUFFER_COPY_META | GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
gst_buffer_copy_into (dstbuffer, srcbuffer, (GstBufferCopyFlags)copy_flags, 0, -1);
memcpy (dstmap.data, srcmap.data, srcmap.size);
dstmap.size = srcmap.size;
/* Unmap the Gst Buffer */
gst_buffer_unmap (dstbuffer, &dstmap);
GstMemory *mem = NULL;
mem = gst_buffer_peek_memory (dstbuffer, 0);
gst_mini_object_weak_ref(GST_MINI_OBJECT(mem), (GstMiniObjectNotify)gst_mem_free_cb, sample);
gst_sample_ref(sample);
gst_app_src_push_buffer((GstAppSrc*)ipcsink->appsrc, dstbuffer);
}
current = current->next;
}
g_mutex_unlock (&ipcserver->ipc_sink_queue_lock);
gst_buffer_unmap (srcbuffer, &srcmap);
/* Unref the sample */
gst_sample_unref (sample);
return GST_FLOW_OK;
}
static GstPadProbeReturn
event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
{
NvIpcServerPipeline *ipcserver = (NvIpcServerPipeline *)user_data;
GstEvent *event = NULL;
event = GST_PAD_PROBE_INFO_EVENT(info);
if (event)
{
if (GST_EVENT_CAPS == GST_EVENT_TYPE(event))
{
GstCaps * caps;
gst_event_parse_caps(event, &caps);
if (caps) {
ipcserver->caps_string = gst_caps_to_string (caps);
g_print("uri: %s caps: %s\n", ipcserver->uri, ipcserver->caps_string);
g_mutex_lock (&ipcserver->caps_mutex);
ipcserver->is_caps = TRUE;
g_cond_signal (&ipcserver->caps_cond);
g_mutex_unlock (&ipcserver->caps_mutex);
} else {
ipcserver->caps_string = NULL;
}
}
}
return GST_PAD_PROBE_OK;
}
static int
create_server_pipeline (int argc, char *argv[])
{
AppCtx appCtx;
guint i =0, num_sources = 0;
num_sources = (argc - 2)/2;
GMainLoop *loop = NULL;
gboolean PERF_MODE = g_getenv("NV_IPC_TEST_PERF_MODE") &&
!g_strcmp0(g_getenv("NV_IPC_TEST_PERF_MODE"), "1");
memset(&appCtx, 0, sizeof(AppCtx));
appCtx.loop = loop = g_main_loop_new (NULL, FALSE);
for (i = 0; i < num_sources; i++) {
GstElement *pipeline = NULL;
GstBus *bus = NULL;
guint bus_watch_id;
GstElement *source_bin=NULL, *nvvidconv, *capsfilter=NULL, *appsink= NULL, *fpssink;
GstCaps *caps=NULL;
/* Create gstreamer elements */
appCtx.ipcserver[i].pipeline = pipeline = gst_pipeline_new (NULL);
if (!pipeline) {
g_printerr ("Failed to create pipeline. Exiting.\n");
return -1;
}
source_bin = create_source_bin (i, argv[(i*2) + 2]);
if (!source_bin) {
g_printerr ("Failed to create source bin. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), source_bin);
appCtx.ipcserver[i].uri = strdup(argv[(i*2) + 2]);
GstPad* srcpad = gst_element_get_static_pad (GST_ELEMENT(G_OBJECT(source_bin)), "src");
gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH, event_probe, &appCtx.ipcserver[i], NULL);
gst_object_unref(srcpad);
nvvidconv = gst_element_factory_make ("nvvidconv", NULL);
if (!nvvidconv) {
g_printerr ("Failed to create nvvidconv. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), nvvidconv);
capsfilter = gst_element_factory_make ("capsfilter", NULL);
if (!capsfilter) {
g_printerr ("Failed to create capsfilter. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), capsfilter);
appsink = gst_element_factory_make ("appsink", NULL);
if (!appsink) {
g_printerr ("Failed to create appsink. Exiting.\n");
return -1;
}
fpssink = gst_element_factory_make ("fpsdisplaysink", NULL);
if (!fpssink) {
g_printerr ("Failed to create fpssink. Exiting.\n");
return -1;
}
gst_bin_add (GST_BIN (pipeline), fpssink);
caps = gst_caps_from_string ("video/x-raw(memory:NVMM),format=NV12");
g_object_set (G_OBJECT(capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
g_object_set (G_OBJECT (fpssink), "text-overlay", FALSE, "sync", FALSE, "video-sink", appsink, NULL);
g_object_set (G_OBJECT(appsink), "emit-signals", TRUE, "sync", FALSE, NULL);
g_signal_connect (G_OBJECT(appsink), "new-sample", G_CALLBACK (on_new_sample), &appCtx.ipcserver[i]);
/* link the elements together */
if (!gst_element_link_many (source_bin, nvvidconv, capsfilter, fpssink, NULL)) {
g_printerr ("Elements could not be linked. Exiting.\n");
return -1;
}
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
appCtx.ipcserver[i].bus_id = bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
appCtx.ipcserver[i].appCtx = &appCtx;
if (PERF_MODE)
g_signal_connect(pipeline, "deep-notify", G_CALLBACK(gst_object_default_deep_notify), NULL);
}
/* Set the pipeline to "playing" state */
g_print ("Now playing:");
for (i = 0; i < num_sources; i++) {
g_mutex_init (&appCtx.ipcserver[i].caps_mutex);
g_cond_init (&appCtx.ipcserver[i].caps_cond);
appCtx.ipcserver[i].ipc_sink_queue = g_queue_new ();
g_queue_init (appCtx.ipcserver[i].ipc_sink_queue);
g_mutex_init (&appCtx.ipcserver[i].ipc_sink_queue_lock);
gst_element_set_state (appCtx.ipcserver[i].pipeline, GST_STATE_PLAYING);
g_mutex_lock (&appCtx.ipcserver[i].caps_mutex);
while (!appCtx.ipcserver[i].is_caps)
g_cond_wait (&appCtx.ipcserver[i].caps_cond, &appCtx.ipcserver[i].caps_mutex);
g_mutex_unlock (&appCtx.ipcserver[i].caps_mutex);
}
for (i = 0; i < num_sources; i++) {
appCtx.ipcserver[i].fd = UnixSocketCreate(argv[(i*2) + 3]);
if (appCtx.ipcserver[i].fd == -1) {
g_printerr("UnixSocketCreate failed\n");
return -1;
}
appCtx.ipcserver[i].socket_path = strdup(argv[(i*2) + 3]);
g_print("server is started uri: %s path: %s fd: %d\n",
appCtx.ipcserver[i].uri, appCtx.ipcserver[i].socket_path, appCtx.ipcserver[i].fd);
pthread_create(&appCtx.ipcserver[i].thread_id, NULL,
connection_handler, (void*)&appCtx.ipcserver[i]);
}
/* Wait till pipeline encounters an error or EOS */
g_print ("Running...\n");
g_main_loop_run (loop);
appCtx.quit = TRUE;
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
g_print ("Deleting pipeline\n");
for (i = 0; i < num_sources; i++) {
pthread_join(appCtx.ipcserver[i].thread_id, NULL);
gst_element_set_state (appCtx.ipcserver[i].pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (appCtx.ipcserver[i].pipeline));
g_source_remove (appCtx.ipcserver[i].bus_id);
g_print("server is closed uri: %s path: %s fd: %d\n",
appCtx.ipcserver[i].uri, appCtx.ipcserver[i].socket_path, appCtx.ipcserver[i].fd);
close(appCtx.ipcserver[i].fd);
g_free(appCtx.ipcserver[i].uri);
g_free(appCtx.ipcserver[i].socket_path);
g_free(appCtx.ipcserver[i].caps_string);
g_mutex_clear (&appCtx.ipcserver[i].ipc_sink_queue_lock);
g_queue_clear (appCtx.ipcserver[i].ipc_sink_queue);
g_queue_free(appCtx.ipcserver[i].ipc_sink_queue);
g_mutex_clear (&appCtx.ipcserver[i].caps_mutex);
g_cond_clear (&appCtx.ipcserver[i].caps_cond);
}
g_main_loop_unref (loop);
return 0;
}
int
main (int argc, char *argv[])
{
int ret = 0;
/* Check input arguments */
if (argc < 3) {
g_printerr ("Usage: %s <server> <rtsp_url> <socket_path>\n", argv[0]);
g_printerr ("OR: %s <client> <socket_path> \n", argv[0]);
return -1;
}
/* Standard GStreamer initialization */
gst_init (&argc, &argv);
if (strcmp(argv[1], "client") == 0) {
signal(SIGPIPE, SIG_IGN);
ret = create_client_pipeline(argc, argv);
} else {
signal(SIGPIPE, SIG_IGN);
ret = create_server_pipeline(argc, argv);
}
return ret;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2011-2024 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"),
@@ -13,7 +14,7 @@
*
* 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
* 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
@@ -21,7 +22,7 @@
*/
#include "nvgst_x11_common.h"
#include <stdbool.h>
Display *
nvgst_x11_init (displayCtx * dpyCtx)
@@ -48,7 +49,7 @@ saver_off (displayCtx * dpyCtx)
{
int nothing;
if (DPMSQueryExtension (dpyCtx->mDisplay, &nothing, &nothing)) {
BOOL enabled;
BOOL enabled = false;
CARD16 powerLevel;
DPMSInfo (dpyCtx->mDisplay, &powerLevel, &enabled);
@@ -71,7 +72,7 @@ saver_on (displayCtx * dpyCtx)
{
int nothing;
if (DPMSQueryExtension (dpyCtx->mDisplay, &nothing, &nothing)) {
BOOL enabled;
BOOL enabled = false;
CARD16 powerLevel;
DPMSInfo (dpyCtx->mDisplay, &powerLevel, &enabled);

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2013-2024 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"),
@@ -13,7 +14,7 @@
*
* 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
* 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
@@ -293,8 +294,8 @@ on_video_sink_flow (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
GstEvent *ev = GST_PAD_PROBE_INFO_DATA (info);
if (GST_EVENT_TYPE (ev) == GST_EVENT_QOS) {
GstClockTimeDiff jitter;
GstClockTime ts;
GstClockTimeDiff jitter = 0;
GstClockTime ts = GST_CLOCK_TIME_NONE;
gst_event_parse_qos (ev, 0, NULL, &jitter, &ts);
@@ -559,7 +560,7 @@ on_input (GIOChannel * ichannel, GIOCondition cond, gpointer data)
goto ret;
} else if (g_str_has_prefix (tbuffer, "r") && yes1 && app->pipeline) {
GstState state, pending;
GstState state = GST_STATE_NULL, pending = GST_STATE_NULL;
in->interval = atof (tbuffer + 1) * GST_USECOND;
if (app->buffering) {
@@ -596,7 +597,7 @@ on_input (GIOChannel * ichannel, GIOCondition cond, gpointer data)
}
} else if (g_str_has_prefix (tbuffer, "p") && yes1 && app->pipeline) {
GstState state, pending;
GstState state = GST_STATE_NULL, pending = GST_STATE_NULL;
in->interval = atof (tbuffer + 1) * GST_USECOND;
if (app->buffering) {
@@ -667,12 +668,12 @@ on_input (GIOChannel * ichannel, GIOCondition cond, gpointer data)
res = NVGST_RET_ERR;
}
} else if (g_str_has_prefix (tbuffer, ">")) {
GstClockTimeDiff pos;
GstClockTimeDiff pos = 0;
GstFormat format = GST_FORMAT_TIME;
if (gst_element_query_position (app->pipeline, format, &pos) &&
format == GST_FORMAT_TIME) {
GstClockTimeDiff dur;
GstClockTimeDiff dur = 0;
in->interval = pos + 10000000000ULL;
if (gst_element_query_duration (app->pipeline, format, &dur)
@@ -775,7 +776,7 @@ exec_ops (NvGstOperation operation)
GST_TIME_ARGS (seekPos));
if (GST_CLOCK_TIME_IS_VALID (in->attrs.segment_duration)) {
GstClockTimeDiff pos;
GstClockTimeDiff pos = 0;
GstFormat format = GST_FORMAT_TIME;
if (gst_element_query_position (app->pipeline, format, &pos) &&
@@ -903,8 +904,8 @@ goto_next_track (gpointer data)
destroy_current_track ();
}
if(app->stats)
stats_func(app->pfData.average_fps, app->pfData.frames_rendered, app->pfData.frames_dropped);
if(app->stats)
stats_func(app->pfData.average_fps, app->pfData.frames_rendered, app->pfData.frames_dropped);
NVGST_INFO_MESSAGE_V ("uriCount: %d, uriTotal: %d", (gint) app->uriCount,
(gint) app->uriTotal);
@@ -963,7 +964,7 @@ _tag_info (const GstTagList * list, const gchar * tag, gpointer data)
tagCount = gst_tag_list_get_tag_size (list, tag);
for (index = 0; index < tagCount; index++) {
gchar *pStr;
gchar *pStr = NULL;
if (gst_tag_get_type (tag) == G_TYPE_STRING) {
if (!gst_tag_list_get_string_index (list, tag, index, &pStr))
@@ -1046,7 +1047,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
GstElementFactory *factory = gst_element_get_factory (src);
const gchar *klass = gst_element_factory_get_klass (factory);
if (strstr (klass, "Decode") && strstr (klass, "Video")) {
guint64 frames_dropped;
guint64 frames_dropped = 0;
gst_message_parse_qos_stats (msg, NULL, NULL, &frames_dropped);
if (frames_dropped > app->pfData.frames_dropped_decoder) {
g_atomic_int_inc (&app->pfData.frames_dropped);
@@ -1059,7 +1060,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
break;
case GST_MESSAGE_WARNING:{
GError *gerror;
GError *gerror = NULL;
gchar *debug;
gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (msg));
@@ -1079,7 +1080,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
const GstStructure *str = gst_message_get_structure (msg);
if (gst_structure_has_name (str, "decoder-status")) {
guint DecodedMBs, ConcealedMBs, FrameDecodeTime;
guint DecodedMBs = 0, ConcealedMBs = 0, FrameDecodeTime = 0;
const gchar *decoder_error_str =
gst_structure_get_string (str, "DecodeErrorString");
@@ -1113,7 +1114,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
case GST_MESSAGE_INFO:{
GError *gerror;
gchar *debug;
gchar *debug = NULL;
gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (msg));
gst_message_parse_info (msg, &gerror, &debug);
@@ -1128,7 +1129,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
break;
case GST_MESSAGE_BUFFERING:{
gint percent;
gint percent = 0;
gboolean busy = FALSE;
gst_message_parse_buffering (msg, &percent);
@@ -1160,7 +1161,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
} else {
if (!busy && app->buffering == FALSE) {
GstState state, pending;
GstState state = GST_STATE_NULL, pending = GST_STATE_NULL;
if (gst_element_get_state (app->pipeline, &state, &pending,
GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE) {
@@ -1197,7 +1198,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
break;
case GST_MESSAGE_STATE_CHANGED:{
GstState old, new, pending;
GstState old = GST_STATE_NULL, new = GST_STATE_NULL, pending = GST_STATE_NULL;
inAttrs *in = app->input;
gst_message_parse_state_changed (msg, &old, &new, &pending);
@@ -1267,7 +1268,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
app->running = TRUE;
if (app->stats) {
GstClockTimeDiff duration;
GstClockTimeDiff duration = 0;
GstFormat format = GST_FORMAT_TIME;
fps_init (&app->pfData);
@@ -1517,6 +1518,10 @@ get_keys (GstCaps * caps, gchar * str, gchar * xstr)
}
}
pgp++;
if (val) {
g_free (val);
val = NULL;
}
}
}
}
@@ -1629,7 +1634,8 @@ create_element (GstCaps * caps, gchar * str, gchar * xstr, gchar ** skeys)
NVGST_WARNING_MESSAGE_V
("property %s does not exist in element %s, ignoring", prop[0],
tokens[0]);
g_strfreev (prop);
g_free(prop[0]);
g_free(prop[1]);
vtoken++;
continue;
}
@@ -2933,6 +2939,7 @@ setup_track (void)
if (!g_str_has_prefix (input->uri, "file://")) {
if (!(g_str_has_prefix (input->uri, "rtsp://") ||
g_str_has_prefix (input->uri, "http://") ||
g_str_has_prefix (input->uri, "https://") ||
g_str_has_prefix (input->uri, "udp://"))) {
uri = g_strconcat ("file://", input->uri, NULL);
} else
@@ -2971,6 +2978,8 @@ setup_track (void)
if (g_str_has_prefix (input->uri, "http://")) {
source = create_element (NULL, NVGST_HTTP_SRC, app->shttp, NULL);
} else if (g_str_has_prefix (input->uri, "https://")) {
source = create_element (NULL, NVGST_HTTP_SRC, app->shttp, NULL);
} else if (g_str_has_prefix (input->uri, "rtsp://")) {
source = create_element (NULL, NVGST_RTSP_SRC, app->srtsp, NULL);
} else if (g_str_has_prefix (input->uri, "udp://")) {
@@ -3238,6 +3247,7 @@ static void
nvgst_handle_xevents ()
{
XEvent e;
e.type = 0;
Atom wm_delete;
displayCtx *dpyCtx = &app->disp;
@@ -3278,14 +3288,12 @@ on_input_thread (gpointer data)
GQueue *que = g_queue_new ();
gchar *buffer = NULL;
int i = 0;
changemode (1);
while (!trd_exit) {
if (kbhit ()) {
if (buffer == NULL)
buffer = g_malloc (256);
buffer[i] = getchar ();
if (buffer[i] == 27) {
@@ -3330,8 +3338,10 @@ on_input_thread (gpointer data)
if (g_queue_is_empty (que)) {
g_queue_push_tail (que, buffer);
g_timeout_add (20, on2_input, que);
} else {
/*If queue is not empty then buffer is not pushed to queue, so it needs to be freed explicitly to avoid resource leak */
g_free(buffer);
}
buffer = NULL;
} else

View File

@@ -1 +1 @@
jetson_35.1
jetson_36.3