From f91c00b4f004c04ce95ff30fb942572d9607ec86 Mon Sep 17 00:00:00 2001 From: Jesper Lodin Date: Mon, 20 May 2024 20:36:12 +0000 Subject: [PATCH 1/3] fix gstreamer hanging and support vaapi --- rootfs/etc/cont-init.d/40-set-env-vars | 6 ++++++ viseron/components/gstreamer/const.py | 16 ++++++++++----- viseron/components/gstreamer/pipeline.py | 13 ++++++++++-- viseron/components/gstreamer/stream.py | 26 +++++++++++------------- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/rootfs/etc/cont-init.d/40-set-env-vars b/rootfs/etc/cont-init.d/40-set-env-vars index 3a1cb7cdb..d6c9dab9a 100644 --- a/rootfs/etc/cont-init.d/40-set-env-vars +++ b/rootfs/etc/cont-init.d/40-set-env-vars @@ -44,6 +44,12 @@ fi export XDG_RUNTIME_DIR=/home/abc printf "/home/abc" > /var/run/environment/XDG_RUNTIME_DIR +# Set XDG_CURRENT_DESKTOP to avoid GStreamer hanging +# Context: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3487 +export XDG_CURRENT_DESKTOP=ubuntu:GNOME +printf "ubuntu:GNOME" > /var/run/environment/XDG_CURRENT_DESKTOP + + # Set HOME to /home/abc export HOME=/home/abc printf "/home/abc" > /var/run/environment/HOME diff --git a/viseron/components/gstreamer/const.py b/viseron/components/gstreamer/const.py index ee55a9b9b..0ab085cc3 100644 --- a/viseron/components/gstreamer/const.py +++ b/viseron/components/gstreamer/const.py @@ -1,4 +1,5 @@ """GStreamer constants.""" +# pyright: reportMissingModuleSource=false from __future__ import annotations import logging @@ -14,13 +15,11 @@ RECORDER = "recorder" -# pylint: disable=useless-suppression -# pylint: disable=wrong-import-position,wrong-import-order,no-name-in-module +# pylint: disable=wrong-import-position,wrong-import-order gi.require_version("Gst", "1.0") -from gi.repository import Gst # pyright: ignore[reportMissingImports] # noqa: E402 +from gi.repository import Gst # noqa: E402 -# pylint: enable=wrong-import-position,wrong-import-order,no-name-in-module -# pylint: enable=useless-suppression +# pylint: enable=wrong-import-position,wrong-import-order class StreamFormat(TypedDict): @@ -71,6 +70,13 @@ class StreamFormat(TypedDict): "mjpeg": "jpegdec", } +VAAPI_DECODER_ELEMENT_MAP = { + "h264": "vaapih264dec", + "h265": "vaapih265dec", + "hevc": "vaapih265dec", + "mjpeg": "vaapimjpegdec", +} + PIXEL_FORMAT = "NV12" CONFIG_LOGLEVEL_TO_GSTREAMER = { diff --git a/viseron/components/gstreamer/pipeline.py b/viseron/components/gstreamer/pipeline.py index 3e12d79f5..6cf183a31 100644 --- a/viseron/components/gstreamer/pipeline.py +++ b/viseron/components/gstreamer/pipeline.py @@ -1,10 +1,12 @@ """GStreamer pipelines.""" from __future__ import annotations +import os from abc import ABC, abstractmethod from typing import TYPE_CHECKING from viseron.components.ffmpeg.const import CAMERA_SEGMENT_DURATION +from viseron.const import ENV_VAAPI_SUPPORTED from .const import ( CONFIG_AUDIO_CODEC, @@ -21,6 +23,7 @@ PARSE_ELEMENT_MAP, PIXEL_FORMAT, STREAM_FORMAT_MAP, + VAAPI_DECODER_ELEMENT_MAP, ) if TYPE_CHECKING: @@ -62,7 +65,6 @@ def input_pipeline(self): + [f"location={self._stream.mainstream.url}"] + [ "name=input_stream", - "do-timestamp=true", ] + STREAM_FORMAT_MAP[self._config[CONFIG_STREAM_FORMAT]]["options"] + ( @@ -132,7 +134,14 @@ def decoder_element(self): Returns decoder element from override map if it exists. Otherwise we assume the decoder element shares name with the codec. """ - decoder_element = DECODER_ELEMENT_MAP.get(self._stream.mainstream.codec, None) + if os.getenv(ENV_VAAPI_SUPPORTED) == "true": + decoder_element = VAAPI_DECODER_ELEMENT_MAP.get( + self._stream.mainstream.codec, None + ) + else: + decoder_element = DECODER_ELEMENT_MAP.get( + self._stream.mainstream.codec, None + ) if decoder_element: return [ diff --git a/viseron/components/gstreamer/stream.py b/viseron/components/gstreamer/stream.py index 58ba29627..180b0b439 100644 --- a/viseron/components/gstreamer/stream.py +++ b/viseron/components/gstreamer/stream.py @@ -1,4 +1,5 @@ """Class to interact with a GStreamer stream.""" +# pyright: reportMissingModuleSource=false from __future__ import annotations import datetime @@ -38,19 +39,12 @@ if TYPE_CHECKING: from viseron.components.gstreamer.camera import Camera -# pylint: disable=useless-suppression -# pylint: disable=wrong-import-position,wrong-import-order,no-name-in-module +# pylint: disable=wrong-import-position,wrong-import-order gi.require_version("Gst", "1.0") gi.require_version("GstApp", "1.0") -from gi.repository import ( # pyright: ignore[reportMissingImports] # noqa: E402 - GLib, - Gst, - GstApp, -) +from gi.repository import GLib, Gst, GstApp # type: ignore[attr-defined] # noqa: E402 -_ = GstApp -# pylint: enable=wrong-import-position,wrong-import-order,no-name-in-module -# pylint: enable=useless-suppression +# pylint: enable=wrong-import-position,wrong-import-order class Stream(FFmpegStream): @@ -151,7 +145,11 @@ def on_new_sample(self, app_sink: GstApp.AppSink) -> Gst.FlowReturn: self._logger.debug("Did not get sample from appsink") return Gst.FlowReturn.ERROR - buffer: Gst.Buffer = sample.get_buffer() + buffer = sample.get_buffer() + if not buffer: + self._logger.debug("Could not get buffer from sample") + return Gst.FlowReturn.ERROR + success, map_info = buffer.map(Gst.MapFlags.READ) if not success: self._logger.debug("Could not map buffer data") @@ -206,14 +204,14 @@ def run_gstreamer(self, process_frames_proc_exit: EventClass) -> None: Gst.debug_add_log_function(self.on_gst_log_message, None) gst_pipeline = Gst.parse_launch(" ".join(self._pipeline.build_pipeline())) - appsink = gst_pipeline.get_by_name( + appsink = gst_pipeline.get_by_name( # type: ignore[attr-defined] "sink", ) - gst_pipeline.set_state(Gst.State.PLAYING) appsink.connect("new-sample", self.on_new_sample) - mux = gst_pipeline.get_by_name("mux") + mux = gst_pipeline.get_by_name("mux") # type: ignore[attr-defined] mux.connect("format-location", self.on_format_location, None) + gst_pipeline.set_state(Gst.State.PLAYING) while not process_frames_proc_exit.is_set(): time.sleep(1) From 52f10cd2e66b0cec3998474bc507f852c34c3cf1 Mon Sep 17 00:00:00 2001 From: Jesper Lodin Date: Mon, 20 May 2024 20:49:57 +0000 Subject: [PATCH 2/3] add pygobject-stubs to requirements_test.txt --- requirements_test.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements_test.txt b/requirements_test.txt index 389b76ed8..58ec10191 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -32,3 +32,4 @@ pyupgrade==3.15.2 # types types-requests types-python-slugify +pygobject-stubs From 6b4011232b48ebd62f4b27f5c8cf08fd90063f51 Mon Sep 17 00:00:00 2001 From: Jesper Lodin Date: Tue, 21 May 2024 08:57:12 +0200 Subject: [PATCH 3/3] ignore pylint errors for gi --- viseron/components/gstreamer/const.py | 6 ++++-- viseron/components/gstreamer/stream.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/viseron/components/gstreamer/const.py b/viseron/components/gstreamer/const.py index 0ab085cc3..5803874cb 100644 --- a/viseron/components/gstreamer/const.py +++ b/viseron/components/gstreamer/const.py @@ -15,11 +15,13 @@ RECORDER = "recorder" -# pylint: disable=wrong-import-position,wrong-import-order +# pylint: disable=useless-suppression +# pylint: disable=wrong-import-position,wrong-import-order,no-name-in-module gi.require_version("Gst", "1.0") from gi.repository import Gst # noqa: E402 -# pylint: enable=wrong-import-position,wrong-import-order +# enable: disable=useless-suppression +# enable: disable=wrong-import-position,wrong-import-order,no-name-in-module class StreamFormat(TypedDict): diff --git a/viseron/components/gstreamer/stream.py b/viseron/components/gstreamer/stream.py index 180b0b439..6cc1356e0 100644 --- a/viseron/components/gstreamer/stream.py +++ b/viseron/components/gstreamer/stream.py @@ -39,12 +39,14 @@ if TYPE_CHECKING: from viseron.components.gstreamer.camera import Camera -# pylint: disable=wrong-import-position,wrong-import-order +# pylint: disable=useless-suppression +# pylint: disable=wrong-import-position,wrong-import-order,no-name-in-module gi.require_version("Gst", "1.0") gi.require_version("GstApp", "1.0") from gi.repository import GLib, Gst, GstApp # type: ignore[attr-defined] # noqa: E402 -# pylint: enable=wrong-import-position,wrong-import-order +# pylint: enable=useless-suppression +# pylint: enable=wrong-import-position,wrong-import-order,no-name-in-module class Stream(FFmpegStream):