From 493c1c5d8a5300b22865573e9e7f327737f43a94 Mon Sep 17 00:00:00 2001 From: Saint_Byte Date: Tue, 19 Jul 2022 09:47:38 +0300 Subject: [PATCH] FfmpegDoubleFrameGenerator --- .flake8 | 5 ++ .pre-commit-config.yaml | 36 +++++++++ constants.py | 4 + frame_generator/ffmpeg_double_fg.py | 116 ++++++++++++++++++++++++++++ frame_generator/ffmpeg_fg.py | 4 +- main.py | 19 ++++- 6 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 .flake8 create mode 100644 .pre-commit-config.yaml create mode 100644 constants.py create mode 100644 frame_generator/ffmpeg_double_fg.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..1666629 --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +max-line-length = 100 +ignore = E203, E402, E266, E501, W503 +# max-complexity = 18 +# select = B,C,E,F,W,T4,B9 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..627d930 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,36 @@ +repos: + - repo: https://github.com/Lucas-C/pre-commit-hooks-safety + rev: v1.2.4 + hooks: + - id: python-safety-dependencies-check + + - repo: 'https://github.com/asottile/reorder_python_imports' + rev: v3.0.1 + hooks: + - id: reorder-python-imports + name: 'Reorder Python imports' + + - repo: https://github.com/ambv/black + rev: 22.3.0 + hooks: + - id: black + language_version: python3.9 + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-merge-conflict + - id: requirements-txt-fixer + + - repo: https://github.com/sondrelg/pep585-upgrade + rev: 'v1' # Use the sha / tag you want to point at + hooks: + - id: upgrade-type-hints + args: [ '--futures=true' ] + + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..bfed6d1 --- /dev/null +++ b/constants.py @@ -0,0 +1,4 @@ +FRAMEGEN_FFMPEG = "FFMPEG" +FRAMEGEN_XWD = "XWD" +FRAMEGEN_SIMPLE = "FRAMEGEN_SIMPLE" +FRAMEGEN_DOUBLE = "FRAMEGEN_DOUBLE" diff --git a/frame_generator/ffmpeg_double_fg.py b/frame_generator/ffmpeg_double_fg.py new file mode 100644 index 0000000..d0dad60 --- /dev/null +++ b/frame_generator/ffmpeg_double_fg.py @@ -0,0 +1,116 @@ +import os +import subprocess +from logging import getLogger +from threading import Thread + +from drop_queue import DropQueue + +log = getLogger(__name__) + + +class FfmpegDoubleFrameGenerator(Thread): + end = False + framebuf: DropQueue + + width = 1366 + height = 768 + + framerate = 30 + optirun = False + vsync = 2 + + buffer_size = 1024 * 10 + + def __init__(self, settings: dict, buf: DropQueue): + super().__init__() + self.framebuf = buf + self.settings = settings + + @property + def size(self): + return f"{self.width}x{self.height}" + + @property + def size2width(self): + return f"{self.width*2}x{self.height}" + + @staticmethod + def api(optirun=False, params=None, **kwargs) -> str: + cmd = "ffmpeg" + if optirun: + cmd = "optirun " + cmd + for i in params: + cmd += f" -{i[0]} {i[1]}" + cmd += " -" + return cmd + + def _get_frame(self, data, start, end): + frame = data[start:end] + return frame + + def _get_display(self): + # Or try :0.0 + # return ":0.0" + return os.getenv("DISPLAY", ":0.0") + "+0,0" + + def run(self): + """ + Run ffmpeg stream video in pipe , should run some like: + ffmpeg -f lavfi -i color=white:s=2732x768\ + -f x11grab -video_size 1366x768 -framerate 30 -i :0.0 \ + -f x11grab -video_size 1366x768 -framerate 30 -i :0.0 \ + -filter_complex "overlay,overlay=1366:0" \ + -vcodec libx264 test.mkv + Ordering of command parametrs IMPOTANT + """ + + self.end = False + params = [ + ("f", "lavfi"), + ("i", f"color=white:s={self.size2width}"), + ("f", "x11grab"), + ("video_size", self.size), + ("framerate", self.framerate), + ("i", self._get_display()), + ("f", "x11grab"), + ("video_size", self.size), + ("framerate", self.framerate), + ("i", self._get_display()), + ("filter_complex", f'"overlay,overlay={self.width}:0"'), + ("loglevel", "error"), + ("nostdin", ""), + ("s", self.size), + ("framerate", self.framerate), + ("f", "mjpeg"), + # ("vsync", self.vsync), + ] + ffmpeg_cmd = self.api(self.optirun, params) + log.info(f"ffmpeg cmd: {ffmpeg_cmd}") + p = subprocess.Popen( + ffmpeg_cmd.split(), + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + + data = bytearray() + start = -1 + cnt = 0 + while not self.end: + data += p.stdout.read(self.buffer_size) + + if start == -1: + start = data.find(b"\xFF\xD8\xFF") + continue + else: + end = data.find(b"\xFF\xD9") + + if end != -1 and start != -1: + frame = data[start : end + 1] + self.framebuf.put(frame) + log.info(f"frame: {cnt}") + cnt = cnt + 1 + data = data[end + 2 :] + start = -1 + log.info("DoubleFrameGenerator end") diff --git a/frame_generator/ffmpeg_fg.py b/frame_generator/ffmpeg_fg.py index 10d7b8c..b818ee0 100644 --- a/frame_generator/ffmpeg_fg.py +++ b/frame_generator/ffmpeg_fg.py @@ -12,8 +12,8 @@ class FfmpegFrameGenerator(Thread): end = False framebuf: DropQueue - width = 800 * 2 - height = 600 + width = 1366 + height = 768 framerate = 30 optirun = False diff --git a/main.py b/main.py index dfde93b..d2a0fd8 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,15 @@ #!/bin/python3 - import logging from time import sleep from callback.open_vr import OpenVR +from constants import FRAMEGEN_DOUBLE +from constants import FRAMEGEN_FFMPEG +from constants import FRAMEGEN_SIMPLE +from constants import FRAMEGEN_XWD from discover import discover +from frame_generator.ffmpeg_double_fg import FfmpegDoubleFrameGenerator +from frame_generator.ffmpeg_fg import FfmpegFrameGenerator from frame_generator.xwd_fg import XwdFrameGenerator from sender import Sender from sensor_client import SensorClient @@ -17,11 +22,19 @@ def main(): server_ip = discover() server_port = 5555 client_port = 7777 - + framegen_type = FRAMEGEN_FFMPEG + framegen_video_type = FRAMEGEN_DOUBLE sender = Sender(server_ip, server_port=server_port, client_port=client_port) # Run frame generator for sender - framegen = XwdFrameGenerator(sender.settings, sender.framebuf) + framegen = None + if framegen_type == FRAMEGEN_FFMPEG: + if framegen_video_type == FRAMEGEN_DOUBLE: + framegen = FfmpegDoubleFrameGenerator(sender.settings, sender.framebuf) + if framegen_video_type == FRAMEGEN_SIMPLE: + framegen = FfmpegFrameGenerator(sender.settings, sender.framebuf) + if framegen_type == FRAMEGEN_XWD: + framegen = XwdFrameGenerator(sender.settings, sender.framebuf) framegen.start() # Start sending frames to client