Last active
June 15, 2021 03:28
-
-
Save velovix/b6021e72737228944b784978b97d0584 to your computer and use it in GitHub Desktop.
Reproduces a segment seeking bug and memory leak in nvcodec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM nvidia/cuda:11.2.1-devel-ubuntu18.04 AS gstreamer | |
# Adds NVCODEC libraries to the environment for use in building NVDEC support | |
ENV NVIDIA_DRIVER_CAPABILITIES=all | |
ARG FFMPEG_VERSION=n4.3.1 | |
WORKDIR /ffmpeg | |
# Get FFmpeg dependencies | |
RUN apt-get update && \ | |
apt-get -y --no-install-recommends install \ | |
autoconf automake build-essential libtool libxcb1-dev \ | |
libxcb-shm0-dev libxcb-xfixes0-dev texinfo zlib1g-dev yasm git \ | |
ca-certificates \ | |
&& \ | |
rm -rf /var/lib/apt/lists/* | |
RUN update-ca-certificates && \ | |
git clone --depth=1 --branch=$FFMPEG_VERSION https://github.com/FFmpeg/FFmpeg . | |
# Build | |
RUN ./configure \ | |
--enable-shared \ | |
--extra-libs="-lpthread -lm" \ | |
--disable-static | |
RUN make -j $(($(nproc) + 1)) | |
RUN make install | |
# Get GStreamer build dependencies | |
RUN apt-get update && \ | |
apt-get -y --no-install-recommends install \ | |
# Generic build dependencies | |
pkg-config autopoint libglib2.0-dev gettext wget \ | |
ca-certificates git g++ yasm ninja-build flex bison \ | |
libgirepository1.0-dev gobject-introspection \ | |
# gst-plugins-base dependencies | |
libogg0 libopus0 libtheora0 libvorbis0a libvorbisenc2 \ | |
# gst-plugins-good dependencies | |
libv4l-dev libjpeg-dev libmp3lame-dev libmpg123-dev \ | |
libtag1-dev libvpx-dev nettle-dev \ | |
# gst-libav dependencies | |
libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavresample-dev libavutil-dev \ | |
# gst-plugins-bad dependencies | |
libsoup2.4-dev \ | |
# Pip, so we can install Meson | |
python3-pip python3-setuptools \ | |
# For JIT acceleration | |
liborc-0.4-dev \ | |
&& \ | |
rm -rf /var/lib/apt/lists/* | |
RUN pip3 install --no-cache-dir meson==0.55.3 | |
ARG GSTREAMER_VERSION=1.19.1 | |
# Build GStreamer core | |
WORKDIR /gstreamer | |
RUN update-ca-certificates && \ | |
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gstreamer | |
WORKDIR /gstreamer/gstreamer | |
RUN meson builddir | |
RUN ninja -C builddir install | |
# Build base GStreamer plugins | |
WORKDIR /gstreamer | |
RUN update-ca-certificates && \ | |
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gst-plugins-base | |
WORKDIR /gstreamer/gst-plugins-base | |
RUN meson builddir | |
RUN ninja -C builddir install | |
# Build good GStreamer plugins | |
WORKDIR /gstreamer | |
RUN update-ca-certificates && \ | |
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gst-plugins-good | |
WORKDIR /gstreamer/gst-plugins-good | |
RUN meson builddir | |
RUN ninja -C builddir install | |
# Build only a few "bad" GStreamer plugins | |
WORKDIR /gstreamer | |
RUN update-ca-certificates && \ | |
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad | |
WORKDIR /gstreamer/gst-plugins-bad | |
RUN meson builddir | |
RUN meson configure \ | |
# Disable all plugins by default | |
-Dauto_features=disabled \ | |
# h264parse, required for NVDEC to work | |
-Dvideoparsers=enabled \ | |
# NVDEC hardware decoding | |
-Dnvcodec=enabled \ | |
builddir | |
RUN ninja -C builddir install | |
# Build GStreamer libav support | |
WORKDIR /gstreamer | |
RUN update-ca-certificates && \ | |
git clone --depth 1 --branch $GSTREAMER_VERSION https://gitlab.freedesktop.org/gstreamer/gst-libav | |
WORKDIR /gstreamer/gst-libav | |
RUN meson builddir | |
RUN ninja -C builddir install | |
WORKDIR /project | |
RUN apt-get update && \ | |
apt-get -y --no-install-recommends install \ | |
python3-dev python3-wheel libcairo-dev libgirepository1.0-dev \ | |
&& \ | |
rm -rf /var/lib/apt/lists/* | |
RUN pip3 install pygobject | |
ENV GI_TYPELIB_PATH="/usr/local/lib/x86_64-linux-gnu/girepository-1.0" | |
ENV GST_DEBUG=3 | |
COPY reproducer.py . | |
COPY test_video.mp4 . | |
CMD [ "python3", "/project/reproducer.py", "/project/test_video.mp4" ] | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from threading import Thread | |
from time import sleep | |
import sys | |
import gi | |
gi.require_version("Gst", "1.0") | |
gi.require_version("GstApp", "1.0") | |
from gi.repository import Gst, GLib, GstApp | |
def main(): | |
if len(sys.argv) < 2: | |
print("Usage: python3 reproducer.py {video file}") | |
sys.exit(1) | |
Gst.init() | |
main_loop = GLib.MainLoop.new(context=None, is_running=False) | |
main_loop_thread = Thread( | |
target=main_loop.run, name="GObjectInitThread", daemon=True | |
) | |
main_loop_thread.start() | |
pipeline = Gst.parse_launch( | |
f"filesrc location={sys.argv[1]} " | |
"! qtdemux " | |
"! h264parse " | |
"! nvh264dec " | |
"! fakesink " | |
) | |
segment_seeking_on = False | |
def watch(_bus, message): | |
nonlocal segment_seeking_on | |
if message.type == Gst.MessageType.STATE_CHANGED: | |
_, new_state, _ = message.parse_state_changed() | |
if ( | |
message.src == pipeline | |
and new_state == Gst.State.PLAYING | |
and not segment_seeking_on | |
): | |
print("Enabling segment seeking") | |
_segment_seek_to_start(pipeline, flush=True) | |
segment_seeking_on = True | |
elif message.type == Gst.MessageType.SEGMENT_DONE: | |
print("Seeking back to the start of the video") | |
_segment_seek_to_start(pipeline, flush=False) | |
return True | |
pipeline.get_bus().add_watch(GLib.PRIORITY_DEFAULT, watch) | |
pipeline.set_state(Gst.State.PLAYING) | |
print("Requested the PLAYING state") | |
try: | |
while True: | |
sleep(0.1) | |
except KeyboardInterrupt: | |
pass | |
print("Done") | |
def _segment_seek_to_start(pipeline, flush): | |
"""Seeks the given pipeline to the start of the video stream. This should | |
be done as a response to a SEGMENT_DONE event. | |
""" | |
flags = Gst.SeekFlags.SEGMENT | |
if flush: | |
flags |= Gst.SeekFlags.FLUSH | |
seek_result = pipeline.seek( | |
rate=1.0, | |
format=Gst.Format.TIME, | |
flags=flags, | |
start_type=Gst.SeekType.SET, | |
start=0, | |
stop_type=Gst.SeekType.NONE, | |
stop=-1, | |
) | |
if not seek_result: | |
raise RuntimeError(f"Failed to send seek event") | |
if __name__ == "__main__": | |
main() | |
_ = GstApp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment