128 lines
4.5 KiB
Python
128 lines
4.5 KiB
Python
import logging
|
|
import os
|
|
import subprocess
|
|
from datetime import datetime
|
|
from typing import Optional, IO
|
|
|
|
from entity.ffmpeg import FfmpegTask
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def to_annexb(file):
|
|
if not os.path.exists(file):
|
|
return file
|
|
logger.info("ToAnnexb: %s", file)
|
|
ffmpeg_process = subprocess.run(["ffmpeg.exe", "-y", "-hide_banner", "-i", file, "-c", "copy", "-bsf:v", "h264_mp4toannexb",
|
|
"-f", "mpegts", file+".ts"])
|
|
logger.info("ToAnnexb: %s, returned: %s", file, ffmpeg_process.returncode)
|
|
if ffmpeg_process.returncode == 0:
|
|
os.remove(file)
|
|
return file+".ts"
|
|
else:
|
|
return file
|
|
|
|
def start_render(ffmpeg_task: FfmpegTask):
|
|
logger.info(ffmpeg_task)
|
|
logger.info(ffmpeg_task.get_ffmpeg_args())
|
|
if not ffmpeg_task.need_run():
|
|
ffmpeg_task.set_output_file(ffmpeg_task.input_file[0])
|
|
return True
|
|
ffmpeg_args = ffmpeg_task.get_ffmpeg_args()
|
|
if len(ffmpeg_args) == 0:
|
|
ffmpeg_task.set_output_file(ffmpeg_task.input_file[0])
|
|
return True
|
|
ffmpeg_process = subprocess.run(["ffmpeg.exe", "-progress", "-", "-loglevel", "error", *ffmpeg_args], **subprocess_args(True))
|
|
logger.info("FINISH TASK, OUTPUT IS %s", handle_ffmpeg_output(ffmpeg_process.stdout))
|
|
code = ffmpeg_process.returncode
|
|
return code == 0
|
|
|
|
def handle_ffmpeg_output(stdout: Optional[bytes]) -> str:
|
|
out_time = "0:0:0.0"
|
|
if stdout is None:
|
|
print("[!]STDOUT is null")
|
|
return out_time
|
|
speed = "0"
|
|
for line in stdout.split(b"\n"):
|
|
if line == b"":
|
|
break
|
|
if line.strip() == b"progress=end":
|
|
# 处理完毕
|
|
break
|
|
if line.startswith(b"out_time="):
|
|
out_time = line.replace(b"out_time=", b"").decode().strip()
|
|
if line.startswith(b"speed="):
|
|
speed = line.replace(b"speed=", b"").decode().strip()
|
|
print("[ ]Speed:", out_time, "@", speed)
|
|
return out_time+"@"+speed
|
|
|
|
|
|
def duration_str_to_float(duration_str: str) -> float:
|
|
_duration = datetime.strptime(duration_str, "%H:%M:%S.%f") - datetime(1900, 1, 1)
|
|
return _duration.total_seconds()
|
|
|
|
|
|
def probe_video_info(video_file):
|
|
# 获取宽度和高度
|
|
result = subprocess.run(
|
|
["ffprobe.exe", '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height:format=duration', '-of',
|
|
'csv=s=x:p=0', video_file],
|
|
stderr=subprocess.STDOUT,
|
|
**subprocess_args(True)
|
|
)
|
|
all_result = result.stdout.decode('utf-8').strip()
|
|
wh, duration = all_result.split('\n')
|
|
width, height = wh.strip().split('x')
|
|
|
|
return int(width), int(height), float(duration)
|
|
|
|
|
|
# Create a set of arguments which make a ``subprocess.Popen`` (and
|
|
# variants) call work with or without Pyinstaller, ``--noconsole`` or
|
|
# not, on Windows and Linux. Typical use::
|
|
#
|
|
# subprocess.call(['program_to_run', 'arg_1'], **subprocess_args())
|
|
#
|
|
# When calling ``check_output``::
|
|
#
|
|
# subprocess.check_output(['program_to_run', 'arg_1'],
|
|
# **subprocess_args(False))
|
|
def subprocess_args(include_stdout=True):
|
|
# The following is true only on Windows.
|
|
if hasattr(subprocess, 'STARTUPINFO'):
|
|
# On Windows, subprocess calls will pop up a command window by default
|
|
# when run from Pyinstaller with the ``--noconsole`` option. Avoid this
|
|
# distraction.
|
|
si = subprocess.STARTUPINFO()
|
|
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
# Windows doesn't search the path by default. Pass it an environment so
|
|
# it will.
|
|
env = os.environ
|
|
else:
|
|
si = None
|
|
env = None
|
|
|
|
# ``subprocess.check_output`` doesn't allow specifying ``stdout``::
|
|
#
|
|
# Traceback (most recent call last):
|
|
# File "test_subprocess.py", line 58, in <module>
|
|
# **subprocess_args(stdout=None))
|
|
# File "C:\Python27\lib\subprocess.py", line 567, in check_output
|
|
# raise ValueError('stdout argument not allowed, it will be overridden.')
|
|
# ValueError: stdout argument not allowed, it will be overridden.
|
|
#
|
|
# So, add it only if it's needed.
|
|
if include_stdout:
|
|
ret = {'stdout': subprocess.PIPE}
|
|
else:
|
|
ret = {}
|
|
|
|
# On Windows, running this from the binary produced by Pyinstaller
|
|
# with the ``--noconsole`` option requires redirecting everything
|
|
# (stdin, stdout, stderr) to avoid an OSError exception
|
|
# "[Error 6] the handle is invalid."
|
|
ret.update({'stdin': subprocess.PIPE,
|
|
'startupinfo': si,
|
|
'env': env})
|
|
return ret
|
|
|