add FFmpeg.probe()

This commit is contained in:
Pavel Muhortov 2023-06-18 07:55:58 +03:00
parent c700997ed3
commit 3e938f20cc

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import json
import logging
import urllib.request
from argparse import ArgumentParser
@ -1204,7 +1205,7 @@ class Proc:
return execlist
@classmethod
def list(cls) -> list:
def list_all(cls) -> list:
"""Find all running process.
Returns:
@ -1230,7 +1231,7 @@ class Proc:
"""
proc_found = []
try:
for proc in cls.list():
for proc in cls.list_all():
if exclude and (
exclude in proc['execpid'] or
exclude in proc['exename'] or
@ -1272,34 +1273,43 @@ class FFmpeg:
@classmethod
def run(
cls,
src: str,
src: (str, type(None)) = None,
dst: str = None,
fps: int = None,
preset: str = None,
raw: (str, type(None)) = None,
ffpath: str = None,
watchdog: bool = False,
watchsec: int = None,
onlyonce: bool = False
) -> None:
"""Running the installed ffmpeg
) -> int:
"""Running the installed ffmpeg.
Args:
src (str): sources urls (example: "rtsp://user:pass@host:554/Streaming/Channels/101, anull").
dst (str, optional): destination url (example: rtp://239.0.0.1:5554). Defaults to None.
src (str, type, optional): sources urls, example:
'rtsp://user:pass@host:554/Streaming/Channels/101, anull'. Defaults to None.
dst (str, optional): destination url, example: 'rtp://239.0.0.1:5554'. Defaults to None.
fps (int, optional): frame per second encoding output. Defaults to None.
preset (str, optional): 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p. Defaults to None.
ffpath (str, optional): alternative path to bin (example: /usr/bin/ffmpeg). Defaults to None.
raw (str, type, optional): custom ffmpeg parameters string. Defaults to None.
ffpath (str, optional): custom path to bin, example: /usr/bin/ffmpeg. Defaults to None.
watchdog (bool, optional): detect ffmpeg freeze and terminate. Defaults to False.
watchsec (int, optional): seconds to wait before the watchdog terminates. Defaults to None.
watchsec (int, optional): seconds to wait before watchdog terminates. Defaults to None.
onlyonce (bool, optional): detect ffmpeg running copy and terminate. Defaults to False.
"""
process = (
cls._bin(ffpath).split() +
cls._src(src).split() +
cls._preset(preset, fps).split() +
cls._dst(dst).split()
Returns:
int: ffmpeg return code
"""
if not raw:
process = (''
+ cls._bin(ffpath).split()
+ cls._src(src).split()
+ cls._preset(preset, fps).split()
+ cls._dst(dst).split()
)
else:
process = cls._bin(ffpath).split() + raw.split()
if onlyonce and Proc.search(' '.join(process)):
print('Process already exist, exit...')
else:
@ -1318,17 +1328,18 @@ class FFmpeg:
print(line, flush=True)
else:
que.put(line)
exit()
return proc.returncode
@classmethod
def _bin(cls, path_ffmpeg: str) -> str:
"""Returns the path to the ffmpeg depending on the OS.
def _bin(cls, ffpath: str, tool: str = 'ffmpeg') -> str:
"""Returns the path to the bin depending on the OS.
Args:
path_ffmpeg (str): alternative path to bin.
ffpath (str): custom path to bin.
tool (str, optional): 'ffmpeg', 'ffprobe'. Defaults to 'ffmpeg'.
Returns:
str: path to ffmpeg.
str: path to bin or None, if path does not exist.
"""
faq = (
'\n'
@ -1346,15 +1357,21 @@ class FFmpeg:
'\tDownload and extract archive from: https://evermeet.cx/ffmpeg/\n'
'\tTarget: /usr/bin/ffmpeg\n'
)
if not path_ffmpeg:
if not ffpath:
if platform.startswith('linux') or platform.startswith('darwin'):
path_ffmpeg = '/usr/bin/ffmpeg'
elif platform.startswith('win32'):
path_ffmpeg = environ['PROGRAMFILES'] + "\\ffmpeg\\bin\\ffmpeg.exe"
if path.exists(path_ffmpeg):
return path_ffmpeg
if tool == 'ffprobe':
ffpath = '/usr/bin/ffprobe'
else:
print('ON', platform, 'PLATFORM', 'not found ffmpeg', faq)
ffpath = '/usr/bin/ffmpeg'
elif platform.startswith('win32'):
if tool == 'ffprobe':
ffpath = environ['PROGRAMFILES'] + "\\ffmpeg\\bin\\ffprobe.exe"
else:
ffpath = environ['PROGRAMFILES'] + "\\ffmpeg\\bin\\ffmpeg.exe"
if path.exists(ffpath):
return ffpath
else:
print('ON', platform, 'PLATFORM', 'not found', tool, faq)
return None
@classmethod
@ -1471,6 +1488,41 @@ class FFmpeg:
break
exit()
@classmethod
def probe(
cls,
target: (str, type(None)) = None,
raw: (str, type(None)) = None,
ffpath: str = None
) -> (dict, bytes, None):
"""Running the installed ffprobe.
Args:
target (str, type, optional): media file path to probe. Defaults to None.
raw (str, type, optional): custom ffprobe parameters string. Defaults to None.
ffpath (str, optional): custom path to bin, example: /usr/bin/ffprobe. Defaults to None.
Returns:
dict, bytes, None: ffprobe response or None.
"""
if not raw:
command = ([]
+ cls._bin(ffpath=ffpath, tool='ffprobe').split()
+ ('-i ' + target
+ ' -v quiet -print_format json -show_format -show_programs -show_streams').split()
)
else:
command = cls._bin(ffpath=ffpath, tool='ffprobe').split() + raw.split()
with Popen(command, stdout=PIPE, stderr=STDOUT) as process:
result = process.communicate()
if process.returncode == 0 and not raw:
return json.loads(result[0].decode('utf-8'))
elif process.returncode == 0 and raw:
return result[0]
else:
return None
if __name__ == "__main__":
time_start = datetime.now()
@ -1556,7 +1608,7 @@ if __name__ == "__main__":
watchsec = None
if 'watchsec' in broadcast_config:
watchsec = int(broadcast_config['watchsec'])
monopoly = None
onlyonce = None
if 'onlyonce' in broadcast_config:
onlyonce = broadcast_config['onlyonce']
FFmpeg.run(