Утечка памяти при использовании gsteramer appsink (привязки python) - PullRequest
0 голосов
/ 04 июля 2018

Я пытаюсь построить конвейер с appsink, и он потребляет много памяти:

#!/usr/bin/env python

import sys

import gi


gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst


def main():
    GObject.threads_init()
    Gst.init(None)
    # pipeline = Gst.parse_launch('fakesrc ! fakesink')
    pipeline = Gst.parse_launch('fakesrc ! appsink')

    loop = GObject.MainLoop()

    pipeline.set_state(Gst.State.PLAYING)
    try:
        loop.run()
    except:
        pass

    pipeline.set_state(Gst.State.NULL)


if __name__ == '__main__':
    sys.exit(main())

Даже без настройки соединения память постоянно увеличивается. Я попытался подключить функцию, используя sink.connect("new-sample", handler, sink) - она ​​также утечка памяти. Также пытался добавить обработчик к шине (где-то читал, что gst может ставить в очередь сообщения, которые не были доставлены в python и сохраняют их навсегда) - тоже не помогает.

Нужно ли где-нибудь освобождать память? Я нашел вызовы gst_object_unref в коде C, но я не уверен, стоит ли использовать unref в коде Python.

Также простой конвейер 'fakesrc ! fakesink' не пропускает память.

Сценарий выполняется внутри Docker (не уверен, что это важно, к сожалению, я не могу проверить вне Docker):

FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN mkdir -p /code
WORKDIR /code
ADD Pipfile Pipfile.lock /code/
RUN apt-get update && apt-get install -y software-properties-common cmake \
    gobject-introspection libgirepository1.0-dev libcairo2-dev \
    libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools \
    python-gst-1.0
RUN pip install pipenv && pipenv install --system
ADD . /code/
WORKDIR /code/src
EXPOSE 8181
CMD python main.py

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Appsink имеет очередь, в которой хранятся входящие сэмплы. По умолчанию этот размер не ограничен. Вы можете управлять этим с помощью свойств приложения max-buffers и drop, чтобы оно не росло бесконечно.

Но на самом деле вам нужно активно извлечь эти образцы из приложения и обработать их - или, по крайней мере, просто отбросить их.

Сигнал new-sample - хорошее начало. Если этот сигнал сработал, новый образец прибыл и готов к обработке. Я не могу вспомнить Python конкретно здесь, но вы хотите вызвать pull_sample метод объекта appsink, чтобы получить право собственности на образец из appsink для себя. Как только вы выйдете из области видимости, этот образец должен быть выпущен должным образом - я думаю.

РЕДАКТИРОВАТЬ: убедитесь, что сигнал излучается. Есть свойство appsink emit-signals, которое по умолчанию отключено. Но я обычно делаю C, поэтому я не уверен, что Python переключает некоторые переключатели, так что он работает "из коробки".

0 голосов
/ 04 июля 2018

Ну, решение (по крайней мере, исправление) простое: вручную позвоните gc.collect()

Я не совсем уверен, почему он не вызывает (или не освобождает) автоматически, но простой вызов gc.collect() для каждого обработчика sink решает проблему. Вызывать gc для каждого кадра не очень эффективно, и я обязательно проведу некоторые исследования, когда у меня будет свободное время.

Решение было найдено путем переписывания на Java (оно также потребляет много памяти), но в Java вы можете указать -Xmx, что уменьшает объем памяти, доступный для JVM

...