Create mov,mp4 thumbnails from Python3

I was working on a Gtk 3 project to roll up all my iPhone videos into a flowbox for easy locating and processing since iPhone doesn’t name things in a meaningful way and photo managers dump things into not so meaningful folders, thumbnails was a must to locate videos easily. Plus, I wanted to do some Gtk programming.

I started with GStreamer 1.0, which worked, but not for .mov files. This handles MP4 and MOV. I have not tested other types so it might need further tweaks.

Hope it is helpful to someone. I can provide GStreamer code if you need it. It is also Python and is slightly faster.

#!/usr/bin/python3
import os
import time
import datetime
import getpass
import cv2
from PIL import Image

"""
Requires:
    OpenCV2 
    PIL

Install via pip or apt.
"""


def get_framecv(in_vid, out_vid, w=192, h=108):
    """Generate thumbnail."""
    # Opencv create thumb.
    try:
        cap = cv2.VideoCapture(in_vid)
        video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
        print('length',video_length)
        while cap.isOpened():
            try:
                ret, frame = cap.read()
                cv2.imwrite(out_vid, frame)
                break
            except:
                pass
        cap.release()
        # PIL: resize
        img = Image.open(out_vid) # image extension *.png,*.jpg
        img = img.resize((w, h), Image.ANTIALIAS)
        img.save(out_vid)
    except Exception as e:
        return e

def is_video_file(filename, extensions):
    """Filter videos"""
    return any(filename.lower().endswith(e) for e in extensions)

def scan_vids(base_dir, extensions):
    """Walk path and get all videos in path."""
    for dirpath, dirs, files in os.walk(base_dir):
        for filename in files:
            if is_video_file(filename, extensions):
                full_path = os.path.join(dirpath,filename)
                date_object = datetime.datetime.fromtimestamp(os.path.getctime(full_path))
                yield os.path.join(dirpath,filename),date_object.date()

def gen_thumbs(path,extensions,output=None):
    """Worker function"""
    img_date = datetime.datetime.now().date()
    associations = []

    if output:
        img_store = output
    else:
        #img_store = r'/home/%s/video_thumbs' % getpass.getuser()
        img_store = os.path.join(path, 'thumbnails')

    if not os.path.exists(img_store):
        os.mkdir(img_store)

    for vid_info in scan_vids(path, extensions):
        vid_path,vid_date = vid_info
        vid_name = os.path.split(vid_path)[-1].split('.')[0]
        img_path = os.path.join(img_store,'thumb_%s.png' % vid_name)
        err = get_framecv(vid_path,img_path)

        if err:
            continue # Handle errors.

        associations.append((img_path, img_date, vid_path, vid_date))

    return associations


if __name__ == '__main__':

    filter_extensions = ['.mov', '.mp4']
    local_path = None # Set path to run from program.

    if local_path:
        user_path = local_path
    else:
        # Run from terminal.
        user_path = None

        user_path = input('Path to videos: ')

    if not user_path:
        print('Path required.')
        os._exit(0)
    if not os.path.exists(user_path):
        print('Supplied path %s is invalid.' % user_path)
        os._exit(0)

    # Run...
    results = gen_thumbs(user_path, filter_extensions, output=None)
    # Print results.
    for i in results: print(i)