vidgear: [Bug]: Memory Leakage with YouTube video
Hi! These days I came across this issue, where it appears that the memory usage keeps increasing as I stream a video. In this example, it increases even more, but in a microserver setting, like launching this script in a REST-API server, there is a steady but small increase over time.
In this scenario, I run the script with docker;
# main.py
from memory_profiler import profile
from vidgear.gears import VideoGear
from typing import Callable
import logging
import time
import cv2
fp = open("/workspace/memory_profiler.log","w+")
class VideoStream:
def __init__(
self,
stream_source: str,
stream_resolution: str = "sd",
stream_framerate: int = 4,
stream_max_frames: int = float("inf"),
stream_backend: int = cv2.CAP_GSTREAMER,
func: Callable = None,
reconnect_frequency: int = 3600,
*args, **kwargs
):
# stream params
self.stream_source = stream_source
self.stream_resolution = stream_resolution
self.stream_framerate = stream_framerate
self.stream_max_frames = stream_max_frames \
if stream_max_frames not in [-1, None] else float("inf")
self.stream_backend = stream_backend
self.reconnect_frequency = reconnect_frequency
self.stream = self.init_stream()
self.func = func
# utils
self.n_frame = 0
self.last_reconnection = time.time()
# For YouTube video, its better to reduced the amount of requests
self.stream_sleep = 0.05 if self.is_stream_mode(self.stream_source) else 0
def get_stream_info(self):
info = {
"height": int(self.stream.stream.get(cv2.CAP_PROP_FRAME_HEIGHT)),
"width": int(self.stream.stream.get(cv2.CAP_PROP_FRAME_WIDTH)),
"total": int(self.stream.stream.get(cv2.CAP_PROP_FRAME_COUNT)),
"fps": self.stream.stream.get(cv2.CAP_PROP_FPS),
}
return info
@staticmethod
def is_stream_mode(source):
return False if str(source).isdigit() else True
def init_stream(self):
stream_mode = self.is_stream_mode(self.stream_source)
if stream_mode:
options = {
"STREAM_RESOLUTION": "best",
"STREAM_PARAMS": {"nocheckcertificate": True},
}
else:
options = {"CAP_PROP_FPS": 30}
stream = VideoGear(
source=self.stream_source,
backend=self.stream_backend,
stream_mode=stream_mode,
logging=False,
**options
)
logging.info(f"Stream with source '{self.stream_source}' initialized.")
return stream
def start_stream(self):
self.stream.start()
logging.info(f"Stream with source '{self.stream_source}' started.")
def stop_stream(self):
self.stream.stop()
logging.info(f"Stream with source '{self.stream_source}' stopped.")
def stop(self):
self.stop_stream()
def fetch_frame(self):
return self.stream.read()
def generator(self):
self.start_stream()
total_frames = 0
while True:
frame = self.fetch_frame()
if frame is None or self.n_frame >= self.stream_max_frames:
break
if total_frames % (30 // self.stream_framerate) == 0:
inputs = {
"id": self.n_frame,
"image": cv2.imencode(".jpg", frame)[1].tobytes(),
"source": str(self.stream_source),
"timestamp": time.time()
}
yield self.func(**inputs) if self.func else inputs
self.n_frame += 1
if self.stream_sleep:
time.sleep(self.stream_sleep)
total_frames += 1
self.stop_stream()
def __iter__(self):
yield from self.generator()
@profile(stream=fp)
def main():
stream = {
"name": "live1",
"stream_source": "http://youtube.com/watch?v=y7QiNgui5Tg",
"stream_framerate": 4,
"stream_resolution": "best",
"stream_max_frames": 100
}
videostreamer = VideoStream(**stream)
for frame in videostreamer:
print(frame["id"], end='\r')
if __name__ == "__main__":
main()
# Dockerfile
FROM python:3.8-slim
# utils -------------------------------------------
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV OPENCV_VERSION="4.5.1"
ENV TZ Europe/Amsterdam
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# init virtualenv ---------------------------------
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
# install OpenCV ----------------------------------
WORKDIR /opt/build
RUN apt-get -qq update \
&& apt-get -qq install -y --no-install-recommends \
build-essential \
cmake \
git \
wget \
unzip \
yasm \
pkg-config \
libswscale-dev \
libtbb2 \
libtbb-dev \
libjpeg-dev \
libpng-dev \
libtiff-dev \
libopenjp2-7-dev \
libavformat-dev \
libpq-dev \
libgstreamer1.0-0 \
ffmpeg \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
gstreamer1.0-tools \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
protobuf-compiler \
libgtk2.0-dev \
ocl-icd-opencl-dev \
&& pip install numpy \
&& wget -q https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip -O opencv.zip \
&& unzip -qq opencv.zip -d /opt \
&& rm -rf opencv.zip \
&& cmake \
-D BUILD_TIFF=ON \
-D BUILD_opencv_python2=OFF \
-D BUILD_opencv_java=OFF \
-D CMAKE_BUILD_TYPE=RELEASE \
-D WITH_CUDA=OFF \
-D WITH_OPENGL=ON \
-D WITH_OPENCL=ON \
-D WITH_TBB=ON \
-D WITH_EIGEN=ON \
-D WITH_V4L=ON \
-D BUILD_TESTS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=$(python -c "import sys; print(sys.prefix)") \
-D PYTHON3_EXECUTABLE=$(which python3) \
-D PYTHON3_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-D PYTHON3_PACKAGES_PATH=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
-D WITH_GSTREAMER=ON \
-D WITH_FFMPEG=ON \
/opt/opencv-${OPENCV_VERSION} \
&& make -j$(nproc) \
&& make install \
&& rm -rf /opt/build/* \
&& rm -rf /opt/opencv-${OPENCV_VERSION} \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get -qq autoremove \
&& apt-get -qq clean
# install pip packages ----------------------------
RUN pip3 install --upgrade pip \
&& pip3 install --no-cache-dir \
vidgear[core]>=0.2.4
RUN pip3 install memory_profiler
# run.sh
docker build . -t venv:latest
docker run \
-v $PWD:/workspace \
venv:latest python3 /workspace/main.py
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 24 (14 by maintainers)
@abhiTronix I think thats a good solution, I’ll take a look at it! Thank you!
@ioangatop Good news is that I’m working on new library that will eliminate use of threading and will produce high performance frames with FFmpeg. Follow issue #148