mirror of
git://nv-tegra.nvidia.com/tegra/gst-src/nvgstapps.git
synced 2025-12-25 03:35:41 +03:00
Compare commits
1 Commits
jetson_35.
...
jetson_36.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
554cdfd85f |
@@ -1,12 +1,15 @@
|
||||
Updating prebuilts and/or headers
|
||||
|
||||
6bafa48f47ad43d33ee446cf86f2b1da134f7868 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.h
|
||||
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
|
||||
33a285339d714d5546cddb92a710e418853470aa - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_asound_common.c
|
||||
9b47978b5f3b6672dd4d6ad5ebe80c9b945a7eba - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.c
|
||||
599544266262509705c60ca9e8d2c8ade3bdfc30 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgstplayer.c
|
||||
aaafd7fd4c0214a52bf73dd2a0ba0af08c675b85 - nvgstapps_src/nvgst_sample_apps/nvgstplayer-1.0/nvgst_x11_common.h
|
||||
8531d3b2fb38ae84efeaadf6cc177e1e2b07a90b - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.h
|
||||
39d7bace9939d38f221edd9f87dc8e8dab2c2365 - nvgstapps_src/nvgst_sample_apps/nvgstcapture-1.0/nvgstcapture.c
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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);
|
||||
@@ -2040,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)) {
|
||||
@@ -3278,7 +3279,7 @@ create_vid_enc_bin (void)
|
||||
}
|
||||
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) {
|
||||
@@ -4589,16 +4590,13 @@ main (int argc, char *argv[])
|
||||
if(app->encset.bitrate != 0)
|
||||
is_user_bitrate = 1;
|
||||
|
||||
FILE *fp;
|
||||
fp = fopen(NVGST_DEFAULT_V4L2_NVENC_DEVICE_PATH, "r");
|
||||
if (fp == NULL)
|
||||
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;
|
||||
}
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
g_option_context_free (ctx);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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
|
||||
@@ -94,6 +95,7 @@ int dummy_func ()
|
||||
#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
|
||||
|
||||
|
||||
20
nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/LICENSE
Normal file
20
nvgstapps_src/nvgst_sample_apps/nvgstipctestapp-1.0/LICENSE
Normal 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.
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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, ¬hing, ¬hing)) {
|
||||
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, ¬hing, ¬hing)) {
|
||||
BOOL enabled;
|
||||
BOOL enabled = false;
|
||||
CARD16 powerLevel;
|
||||
|
||||
DPMSInfo (dpyCtx->mDisplay, &powerLevel, &enabled);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
jetson_35.6
|
||||
jetson_36.3
|
||||
|
||||
Reference in New Issue
Block a user