basic cpu encode support
This commit is contained in:
parent
a8abb92b84
commit
9139727dc6
@ -1,3 +1,5 @@
|
||||
import os.path
|
||||
|
||||
from entity.ffmpeg import FfmpegTask
|
||||
import logging
|
||||
|
||||
@ -10,32 +12,32 @@ def parse_ffmpeg_task(task_info, template_info):
|
||||
tasks = []
|
||||
# 中间片段
|
||||
for part in template_info.get("video_parts"):
|
||||
sub_ffmpeg_task = parse_video_part(part, task_info)
|
||||
if not sub_ffmpeg_task:
|
||||
source = select_video_if_needed(part.get('source'), task_info, template_info)
|
||||
if not source:
|
||||
logger.warning("no video found for part: " + str(part))
|
||||
continue
|
||||
sub_ffmpeg_task = FfmpegTask(source)
|
||||
sub_ffmpeg_task.frame_rate = template_info.get("frame_rate", 25)
|
||||
for lut in part.get('filters', []):
|
||||
sub_ffmpeg_task.add_lut(os.path.join(template_info.get("local_path"), lut))
|
||||
for audio in part.get('audios', []):
|
||||
sub_ffmpeg_task.add_audios(os.path.join(template_info.get("local_path"), audio))
|
||||
for overlay in part.get('overlays', []):
|
||||
sub_ffmpeg_task.add_overlay(os.path.join(template_info.get("local_path"), overlay))
|
||||
tasks.append(sub_ffmpeg_task)
|
||||
task = FfmpegTask(tasks, output_file="test.mp4")
|
||||
task.correct_task_type()
|
||||
overall = template_info.get("overall_template")
|
||||
task.add_lut(*overall.get('luts', []))
|
||||
task.add_audios(*overall.get('audios', []))
|
||||
task.add_overlay(*overall.get('overlays', []))
|
||||
task.frame_rate = template_info.get("frame_rate", 25)
|
||||
for lut in overall.get('filters', []):
|
||||
task.add_lut(os.path.join(template_info.get("local_path"), lut))
|
||||
for audio in overall.get('audios', []):
|
||||
task.add_audios(os.path.join(template_info.get("local_path"), audio))
|
||||
for overlay in overall.get('overlays', []):
|
||||
task.add_overlay(os.path.join(template_info.get("local_path"), overlay))
|
||||
return task
|
||||
|
||||
|
||||
def parse_video_part(video_part, task_info):
|
||||
source = select_video_if_needed(video_part.get('source'), task_info)
|
||||
if not source:
|
||||
logger.warning("no video found for part: " + str(video_part))
|
||||
return None
|
||||
task = FfmpegTask(source)
|
||||
task.add_lut(*video_part.get('luts', []))
|
||||
task.add_audios(*video_part.get('audios', []))
|
||||
task.add_overlay(*video_part.get('overlays', []))
|
||||
return task
|
||||
|
||||
|
||||
def select_video_if_needed(source, task_info):
|
||||
def select_video_if_needed(source, task_info, template_info):
|
||||
if source.startswith('PLACEHOLDER_'):
|
||||
placeholder_id = source.replace('PLACEHOLDER_', '')
|
||||
new_sources = task_info.get('user_videos', {}).get(placeholder_id, [])
|
||||
@ -47,7 +49,7 @@ def select_video_if_needed(source, task_info):
|
||||
# TODO: Random Pick / Policy Pick
|
||||
new_sources = new_sources[0]
|
||||
return new_sources
|
||||
return source
|
||||
return os.path.join(template_info.get("local_path"), source)
|
||||
|
||||
|
||||
def start_ffmpeg_task(ffmpeg_task):
|
||||
|
107
entity/ffmpeg.py
107
entity/ffmpeg.py
@ -12,6 +12,7 @@ class FfmpegTask(object):
|
||||
self.output_file = output_file
|
||||
self.mute = True
|
||||
self.speed = 1
|
||||
self.frame_rate = 25
|
||||
self.subtitles = []
|
||||
self.luts = []
|
||||
self.audios = []
|
||||
@ -36,7 +37,7 @@ class FfmpegTask(object):
|
||||
for i in self.input_file:
|
||||
if type(i) is str:
|
||||
continue
|
||||
elif type(i) is FfmpegTask:
|
||||
elif isinstance(i, FfmpegTask):
|
||||
if i.need_run():
|
||||
yield i
|
||||
|
||||
@ -69,7 +70,9 @@ class FfmpegTask(object):
|
||||
|
||||
def get_output_file(self):
|
||||
if self.task_type == 'copy':
|
||||
return self.input_file
|
||||
return self.input_file[0]
|
||||
if self.output_file == '':
|
||||
self.set_output_file()
|
||||
return self.output_file
|
||||
|
||||
def correct_task_type(self):
|
||||
@ -109,3 +112,103 @@ class FfmpegTask(object):
|
||||
def check_audio_track(self):
|
||||
if len(self.audios) > 0:
|
||||
self.mute = False
|
||||
|
||||
def get_ffmpeg_args(self):
|
||||
args = ['-y', '-hide_banner']
|
||||
video_output_str = "[0:v]"
|
||||
if self.task_type == 'encode':
|
||||
input_args = []
|
||||
filter_args = []
|
||||
output_args = []
|
||||
video_output_str = "[0:v]"
|
||||
audio_output_str = "[0:v]"
|
||||
video_input_count = 0
|
||||
audio_input_count = 0
|
||||
for input_file in self.input_file:
|
||||
input_args.append("-i")
|
||||
if type(input_file) is str:
|
||||
input_args.append(input_file)
|
||||
elif isinstance(input_file, FfmpegTask):
|
||||
input_args.append(input_file.get_output_file())
|
||||
for lut in self.luts:
|
||||
filter_args.append("[0:v]lut3d=file=" + lut + "[0:v]")
|
||||
for overlay in self.overlays:
|
||||
input_index = input_args.count("-i")
|
||||
input_args.append("-i")
|
||||
input_args.append(overlay)
|
||||
filter_args.append(f"{video_output_str}[{input_index}:v]scale=rw:rh[v]")
|
||||
filter_args.append(f"[v][{input_index}:v]overlay=1:eof_action=endall[v]")
|
||||
video_output_str = "[v]"
|
||||
output_args.append("-map")
|
||||
output_args.append(video_output_str)
|
||||
output_args.append("-r")
|
||||
output_args.append(f"{self.frame_rate}")
|
||||
if self.mute:
|
||||
output_args.append("-an")
|
||||
else:
|
||||
input_index = 0
|
||||
for audio in self.audios:
|
||||
input_index = input_args.count("-i")
|
||||
input_args.append("-i")
|
||||
input_args.append(audio.replace("\\", "/"))
|
||||
if audio_input_count > 0:
|
||||
filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]")
|
||||
audio_output_str = "[a]"
|
||||
else:
|
||||
audio_output_str = f"[{input_index}:a]"
|
||||
audio_input_count += 1
|
||||
if audio_input_count == 1:
|
||||
audio_output_str = f"{input_index}"
|
||||
output_args.append(f"-map")
|
||||
output_args.append(audio_output_str)
|
||||
return args + input_args + ["-filter_complex", ";".join(filter_args)] + output_args + [self.get_output_file()]
|
||||
elif self.task_type == 'concat':
|
||||
input_args = []
|
||||
output_args = []
|
||||
filter_args = []
|
||||
video_output_str = "[0:v]"
|
||||
audio_output_str = "[0:v]"
|
||||
video_input_count = 0
|
||||
audio_input_count = 0
|
||||
for input_file in self.input_file:
|
||||
input_index = input_args.count("-i")
|
||||
input_args.append("-i")
|
||||
if type(input_file) is str:
|
||||
input_args.append(input_file.replace("\\", "/"))
|
||||
elif isinstance(input_file, FfmpegTask):
|
||||
input_args.append(input_file.get_output_file().replace("\\", "/"))
|
||||
if video_input_count > 0:
|
||||
filter_args.append(f"{video_output_str}[{input_index}:v]concat=n=2:v=1:a=0[v]")
|
||||
video_output_str = "[v]"
|
||||
else:
|
||||
video_output_str = f"[{input_index}:v]"
|
||||
video_input_count += 1
|
||||
output_args.append("-map")
|
||||
output_args.append(video_output_str)
|
||||
if self.mute:
|
||||
output_args.append("-an")
|
||||
else:
|
||||
input_index = 0
|
||||
for audio in self.audios:
|
||||
input_index = input_args.count("-i")
|
||||
input_args.append("-i")
|
||||
input_args.append(audio.replace("\\", "/"))
|
||||
if audio_input_count > 0:
|
||||
filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]")
|
||||
audio_output_str = "[a]"
|
||||
else:
|
||||
audio_output_str = f"[{input_index}:a]"
|
||||
audio_input_count += 1
|
||||
if audio_input_count == 1:
|
||||
audio_output_str = f"{input_index}"
|
||||
output_args.append(f"-map")
|
||||
output_args.append(audio_output_str)
|
||||
return args + input_args + ["-filter_complex", ";".join(filter_args)] + output_args + [self.get_output_file()]
|
||||
|
||||
def set_output_file(self, file=None):
|
||||
if file is None:
|
||||
if self.output_file == '':
|
||||
# TODO: Random Filename
|
||||
self.output_file = "rand.mp4"
|
||||
else:
|
||||
self.output_file = file
|
@ -1,3 +1,5 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Optional, IO
|
||||
|
||||
from entity.ffmpeg import FfmpegTask
|
||||
@ -5,6 +7,8 @@ from entity.ffmpeg import FfmpegTask
|
||||
|
||||
def start_render(ffmpeg_task: FfmpegTask):
|
||||
print(ffmpeg_task)
|
||||
print(ffmpeg_task.get_ffmpeg_args())
|
||||
os.system("ffmpeg.exe "+" ".join(ffmpeg_task.get_ffmpeg_args()))
|
||||
|
||||
def handle_ffmpeg_output(stdout: Optional[IO[bytes]]) -> str:
|
||||
out_time = "0:0:0.0"
|
||||
@ -25,3 +29,7 @@ def handle_ffmpeg_output(stdout: Optional[IO[bytes]]) -> str:
|
||||
speed = line.replace(b"speed=", b"").decode().strip()
|
||||
print("[ ]Speed:", out_time, "@", speed)
|
||||
return out_time
|
||||
|
||||
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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user