Is there any way of getting a thumbnail from user-uploaded video?

What I’m trying to do:
Allow the user to upload a video or an image using the File Loader component. Then, show a thumbnail of the video or image uploaded.

What I’ve tried and what’s not working:
It works as expected when it’s an image, but I don’t really know what to show when it’s a video.

Any ideas?

Maybe this can help?

I think all the capability you need can be found in the OpenCV library.
Reference OpenCV video Capture

I would recommend the headless version of OpenCV
opencv-python github

Untested, but something like this:

import cv2

def save_video_frame(video_path: str, frame_path: str, frame_number: int) -> bool:
    """
    Extract a specific frame from a video and save as an image
    
    Args:
         video_path: path to video file
         frame_path: path to frame file
         frame_number: frame number to extract from video
     Returns:
         If the save was successful
    """
    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        print("Cannot open video")
        return False

    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number - 1)
    success, frame = cap.read()
    if success:
        cv2.imwrite(frame_path, frame)
    else:
        print(f"Failed to read frame {frame_number}")

    cap.release()
    return success

Not really. At least, not anymore. I already implemented the player using this exact post before (so thank you).

What I’m looking for is extracting a frame from the video to show as a thumbnail in a Image component.

I’ll look into it! Thank you!

I was laying awake and remembered that cap.release() can be a bit of an issue if you encounter an error. In this case the resource is left open.

I remember creating a context manager for cap so that the resource is always released.

from contextlib import contextmanager

@contextmanager
def VideoCapture(*args, **kwargs):
    cap = cv2.VideoCapture(*args, **kwargs)
    try:
        yield cap
    finally:
        cap.release()

In that case you have this exact code that works with the player. This will set the thumbnail to whatever the video is playing

from anvil.js.window import document

  def set_video_thumbnail_to_frame(self):
    
    canvas = document.createElement('canvas')
    ctx = canvas.getContext('2d')

    canvas.width = self.video_player_1.video_dom.videoWidth
    canvas.height = self.video_player_1.video_dom.videoHeight
    
    ctx.drawImage(self.video_player_1.video_dom, 0, 0, canvas.width, canvas.height)
    self.thumbnail.source = canvas.toDataURL('image/png')
3 Likes

This worked perfectly!

I just did a minimal alteration: to get a better thumbnail, I seeked 15s into the video using video_dom.currentTime = 15 and made the function to generate the thumbnail be inside the onseeked callback of video_dom.

Thanks @divyeshlakhotia and @racersmith !

2 Likes