Thumbnail Generation Refactoring (#16)

* Fix file_list and convert save_first_frame to use FFMPEG directly

* All thumbnail generation now uses FFMPEG engine
This commit is contained in:
2023-06-15 13:06:46 -05:00
committed by GitHub
parent cae5dbb41c
commit 0a0a228731
4 changed files with 13 additions and 58 deletions

View File

@@ -1,58 +1,19 @@
import subprocess
import ffmpeg # todo: remove all references to ffmpeg library and instead use direct subprocesses
from lib.engines.ffmpeg_engine import FFMPEG
def file_info(path):
try:
return ffmpeg.probe(path)
except Exception as e:
print('Error getting ffmpeg info: ' + str(e))
return None
def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264", pix_fmt="yuv420p"):
def image_sequence_to_video(source_glob_pattern, output_path, framerate=24, encoder="libx264", pix_fmt="yuv420p"):
subprocess.run([FFMPEG.renderer_path(), "-framerate", str(framerate), "-i", f"{source_glob_pattern}",
"-c:v", encoder, "-pix_fmt", pix_fmt, output_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
"-c:v", encoder, "-pix_fmt", pix_fmt, output_path], stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, check=True)
def save_first_frame(source_path, dest_path, max_width=1280, run_async=False):
stream = ffmpeg.input(source_path)
stream = ffmpeg.output(stream, dest_path, **{'vf': f'format=yuv420p,scale={max_width}:trunc(ow/a/2)*2',
'vframes': '1'})
return _run_output(stream, run_async)
def save_first_frame(source_path, dest_path, max_width=1280):
subprocess.run([FFMPEG.renderer_path(), '-i', source_path, '-vf', f'scale={max_width}:-1',
'-vframes', '1', dest_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
def generate_fast_preview(source_path, dest_path, max_width=1280, run_async=False):
stream = ffmpeg.input(source_path)
stream = ffmpeg.output(stream, dest_path, **{'vf': 'format=yuv420p,scale={width}:-2'.format(width=max_width),
'preset': 'ultrafast'})
return _run_output(stream, run_async)
def generate_thumbnail(source_path, dest_path, max_width=240, run_async=False):
stream = ffmpeg.input(source_path).video
stream = ffmpeg.output(stream, dest_path, **{'vf': f'scale={max_width}:trunc(ow/a/2)*2,format=yuv420p',
'preset': 'veryfast',
'r': '15',
'c:v': 'libx265',
'tag:v': 'hvc1'})
return _run_output(stream, run_async)
def generate_prores_trim(source_path, dest_path, start_frame, end_frame, handles=10, run_async=False):
stream = ffmpeg.input(source_path)
stream = stream.trim(**{'start_frame': max(start_frame-handles, 0), 'end_frame': end_frame + handles})
stream = stream.setpts('PTS-STARTPTS') # reset timecode
stream = ffmpeg.output(stream, dest_path, strict='-2', **{'c:v': 'prores_ks', 'profile:v': 4})
return _run_output(stream, run_async)
def _run_output(stream, run_async):
return ffmpeg.run_async(stream, quiet=True, overwrite_output=True) if run_async else \
ffmpeg.run(stream, quiet=True, overwrite_output=True)
if __name__ == '__main__':
x = generate_thumbnail("/Users/brett/Desktop/pexels.mp4", "/Users/brett/Desktop/test-output.mp4", max_width=320)
print(x)
def generate_thumbnail(source_path, dest_path, max_width=240, fps=12):
subprocess.run([FFMPEG.renderer_path(), '-i', source_path, '-vf',
f"scale={max_width}:trunc(ow/a/2)*2,format=yuv420p", '-r', str(fps), '-c:v', 'libx264', '-preset',
'ultrafast', '-an', dest_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)

View File

@@ -1,13 +1,9 @@
import json
import logging
import os
import subprocess
import threading
import requests
from .ffmpeg_helper import generate_thumbnail, save_first_frame
from lib.workers.base_worker import RenderStatus
logger = logging.getLogger()
@@ -21,8 +17,8 @@ def generate_thumbnail_for_job(job, thumb_video_path, thumb_image_path, max_widt
try:
logger.debug(f"Generating video thumbnail for {source}")
generate_thumbnail(source_path=source, dest_path=thumb_video_path, max_width=max_width)
except Exception as e:
logger.error(f"Error generating thumbnail for {source}: {e}")
except subprocess.CalledProcessError as e:
logger.error(f"Error generating video thumbnail for {source}: {e}")
try:
os.remove(in_progress_path)

View File

@@ -5,7 +5,6 @@ import os
import subprocess
import threading
import json
import glob
from datetime import datetime
from enum import Enum
@@ -287,7 +286,7 @@ class BaseRenderWorker(Base):
def file_list(self):
job_dir = os.path.dirname(self.output_path)
file_list = glob.glob(os.path.join(job_dir, '*'))
file_list = [os.path.join(job_dir, file) for file in os.listdir(job_dir)]
file_list.sort()
return file_list

View File

@@ -4,7 +4,6 @@ psutil==5.9.5
PyYAML~=6.0
Flask==2.3.2
rich==13.4.1
ffmpeg-python
Werkzeug==2.3.5
tkinterdnd2~=0.3.0
future==0.18.3