From 9164b2c9f691ae9b865d0c845c61b8f6bb7fd4f9 Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Thu, 21 Jul 2022 20:59:05 +1000 Subject: [PATCH] use python-ffmpeg (run external ffmpeg) to generate video thumb as it also auto-rotates --- BUGs | 2 +- pa_job_manager.py | 53 ++++++++++++++++++----------------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/BUGs b/BUGs index d33f840..eea6205 100644 --- a/BUGs +++ b/BUGs @@ -1,4 +1,4 @@ -### Next: 99 +### Next: 100 BUG-97: if restart a job, we reset start time too (debatable) - prob. better making a job have anull start time rather than now() as default, then if its null set it when we run the job (this would set it at actual run time not create time, and if we restart, it would leave orig start time correct) diff --git a/pa_job_manager.py b/pa_job_manager.py index f8c5b49..745453d 100644 --- a/pa_job_manager.py +++ b/pa_job_manager.py @@ -45,6 +45,7 @@ import face_recognition import re import sys import json +import ffmpeg # global debug setting @@ -1694,41 +1695,27 @@ def GenImageThumbnail(job, file): # GenVideoThumbnail(): log and then generate the thumb for a video (this grabs the width/height of a frame from the video, # and then reads the first few frames until the mean() fo the frame indicates its not just black frame, then make the thumbnail #################################################################################################################################### -def GenVideoThumbnail(job, file): - ProcessFileForJob( job, "Generate Thumbnail from Video file: {}".format( file ), file ) +def GenVideoThumbnail( job, fname): + ProcessFileForJob( job, f"Generate Thumbnail from Video file: {fname}", fname ) + height = THUMBSIZE try: - vcap = cv2.VideoCapture(file) - res, frame = vcap.read() - first_res = res - first_frame = frame - frame_cnt=0 - # if the mean pixel value is > 15, we have something worth making a sshot of (no black frame at start being the sshot) - # limit it to 1000 frames jic - while res and frame.mean() < 15 and frame_cnt < 1000: - res, frame = vcap.read() - frame_cnt += 1 - # if we never got a frame that is not dark, then use first frame - if not res: - res = first_res - frame = first_frame - - w = vcap.get(cv2.CAP_PROP_FRAME_WIDTH) - h = vcap.get(cv2.CAP_PROP_FRAME_HEIGHT) - if w > h: - factor = w / THUMBSIZE - else: - factor = h / THUMBSIZE - new_h = int(h / factor) - new_w = int(w / factor) - frame = cv2.resize(frame, (new_w, new_h), 0, 0, cv2.INTER_LINEAR) - - res, thumb_buf = cv2.imencode('.jpeg', frame) - bt = thumb_buf.tobytes() - thumbnail = base64.b64encode(bt) - thumbnail = str(thumbnail)[2:-1] - except Exception as e: - AddLogForJob( job, f"ERROR: Failed to Generate thumbnail for video file: {file} - error={e}" ) + probe = ffmpeg.probe(fname) + time = float(probe['streams'][0]['duration']) // 2 + tmp_fname='/tmp/pa_tmp_'+os.path.basename(fname.split('.')[0])+'.jpg' + ( + ffmpeg + .input(fname, ss=time) + .filter('scale', -1, height) + .output(tmp_fname, vframes=1) + .overwrite_output() + .run(capture_stdout=True, capture_stderr=True) + ) + except ffmpeg.Error as e: + AddLogForJob( job, f"ERROR: Failed to Generate thumbnail for video file: {fname} - error={e}" ) return None + + thumbnail, w, h = GenThumb( tmp_fname, False ) + os.remove( tmp_fname ) return thumbnail ####################################################################################################################################