Added support for black detection in video thumbnail generation
Added 3 new conf options: * thumb_video_black_retries = 0 * thumb_video_black_retry_offset = 1 * thumb_video_black_max_colors = 4 They control how many retries a thumbnail generation should run before failure. Each retry seeks the video another N seconds determined by retry_offset in addition to the original thumb_video_delay setting. A 'black' thumbnail is detected when the resulting image has max_colors or less distinct color values in it. This is not exclusive to black, but attempts to avoid any solid color images.
This commit is contained in:
@@ -179,6 +179,9 @@ class Media:
|
||||
s['thumb_video_delay'],
|
||||
fit=s['thumb_fit'],
|
||||
converter=s['video_converter'],
|
||||
black_retries=s['thumb_video_black_retries'],
|
||||
black_offset=s['thumb_video_black_retry_offset'],
|
||||
black_max_colors=s['thumb_video_black_max_colors']
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.error('Failed to generate thumbnail: %s', e)
|
||||
|
||||
@@ -75,7 +75,10 @@ _DEFAULT_CONFIG = {
|
||||
'thumb_prefix': '',
|
||||
'thumb_size': (200, 150),
|
||||
'thumb_suffix': '',
|
||||
'thumb_video_delay': '0',
|
||||
'thumb_video_delay': 0,
|
||||
'thumb_video_black_retries': 0,
|
||||
'thumb_video_black_retry_offset': 1,
|
||||
'thumb_video_black_max_colors': 4,
|
||||
'title': '',
|
||||
'use_orig': False,
|
||||
'user_css': None,
|
||||
|
||||
@@ -119,7 +119,13 @@ thumb_size = (280, 210)
|
||||
# thumb_fit_centering = (0.5, 0.5)
|
||||
|
||||
# Delay in seconds to avoid black thumbnails in videos with fade-in
|
||||
# thumb_video_delay = '0'
|
||||
# thumb_video_delay = 0
|
||||
# Max retries to generate a non-black thumbnail
|
||||
# thumb_video_black_retries = 0
|
||||
# For each retry, advance another N seconds on top of original delay
|
||||
# thumb_video_black_retry_offset = 1
|
||||
# A thumbnail with more than max_colors will not be considered "all black"
|
||||
# thumb_video_black_max_colors = 4
|
||||
|
||||
# Keep original image (default: False)
|
||||
# keep_orig = True
|
||||
|
||||
@@ -27,6 +27,8 @@ import shutil
|
||||
import subprocess
|
||||
from os.path import splitext
|
||||
|
||||
from PIL import Image as PILImage
|
||||
|
||||
from . import image, utils
|
||||
from .utils import is_valid_html5_video
|
||||
|
||||
@@ -172,17 +174,32 @@ def generate_video(source, outname, settings):
|
||||
|
||||
|
||||
def generate_thumbnail(
|
||||
source, outname, box, delay, fit=True, options=None, converter="ffmpeg"
|
||||
source, outname, box, delay, fit=True, options=None, converter="ffmpeg", black_retries=0, black_offset=1, black_max_colors=4
|
||||
):
|
||||
"""Create a thumbnail image for the video source, based on ffmpeg."""
|
||||
logger = logging.getLogger(__name__)
|
||||
tmpfile = outname + ".tmp.jpg"
|
||||
|
||||
# dump an image of the video
|
||||
cmd = [converter, "-i", source, "-an", "-r", "1"]
|
||||
cmd += ["-ss", str(delay), "-vframes", "1", "-y", tmpfile]
|
||||
logger.debug("Create thumbnail for video: %s", " ".join(cmd))
|
||||
check_subprocess(cmd, source, outname)
|
||||
currentTry = 0
|
||||
iDelay = int(delay)
|
||||
while currentTry <= abs(black_retries):
|
||||
# dump an image of the video
|
||||
cmd = [converter, "-i", source, "-an", "-r", "1"]
|
||||
cmd += ["-ss", str(iDelay), "-vframes", "1", "-y", tmpfile]
|
||||
logger.debug("Create thumbnail for video: %s", " ".join(cmd))
|
||||
check_subprocess(cmd, source, outname)
|
||||
if os.path.isfile(tmpfile) and black_retries > 0:
|
||||
img = PILImage.open(tmpfile)
|
||||
colors = img.getcolors(maxcolors=black_max_colors)
|
||||
if colors is None:
|
||||
# There were more colors than maxcolors in the image, it looks suitable for a valid thumbnail
|
||||
break
|
||||
else:
|
||||
# Only found 'maxcolors' unique colors, looks like a solid color, try again with another seek delay
|
||||
currentTry += 1
|
||||
iDelay += abs(black_offset)
|
||||
else:
|
||||
break
|
||||
|
||||
# Sometimes ffmpeg fails with returncode zero but without producing an
|
||||
# output file Thus, we need to check if an output file was created. If
|
||||
@@ -228,6 +245,9 @@ def process_video(media):
|
||||
fit=settings["thumb_fit"],
|
||||
options=settings["jpg_options"],
|
||||
converter=settings["video_converter"],
|
||||
black_retries=s['thumb_video_black_retries'],
|
||||
black_offset=s['thumb_video_black_retry_offset'],
|
||||
black_max_colors=s['thumb_video_black_max_colors']
|
||||
)
|
||||
|
||||
return status.value
|
||||
|
||||
Reference in New Issue
Block a user