Description: Learn how to create a reusable VideoReader service in Python using OpenCV to read video files frame-by-frame and access FPS, frame count, width, and height.

In the previous part, we looked at how to get basic video file metadata using OpenCV.

As video-processing applications become more complex, directly using cv2.VideoCapture throughout your application can make the code harder to maintain and reuse.

A better approach is to create a small, reusable service class that handles video reading in one place.

In this part, we will create a VideoReader class that can:

  • Open and validate a video file
  • Read video frames one by one
  • Get the video FPS
  • Get the total frame count
  • Get the video width and height
  • Release the video resource properly


Create a Reusable VideoReader

We can create a simple VideoReader service using OpenCV, pathlib, Python type hints, and NumPy.

"""
Helper video reader functions
Service layer for reading video files frame-by-frame using OpenCV.
"""

from pathlib import Path
from urllib.parse import urlparse
from typing import Generator

import cv2
import numpy as np


class VideoReader:
    def __init__(self, video_path: str):
        """
            compatible with local files and URLs
        """
        self.video_path = video_path

        parsed = urlparse(video_path)
        is_url = parsed.scheme in ("http", "https")

        if not is_url:
            path = Path(video_path)

            if not path.exists():
                raise FileNotFoundError(video_path)

        self.cap = cv2.VideoCapture(video_path)

        if not self.cap.isOpened():
            raise RuntimeError(f"Unable to open video: {video_path}")


    @property
    def fps(self) -> float:
        return self.cap.get(cv2.CAP_PROP_FPS)

    @property
    def frame_count(self) -> int:
        return int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))

    @property
    def width(self) -> int:
        return int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))

    @property
    def height(self) -> int:
        return int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    def frames(self) -> Generator[tuple[int, np.ndarray], None, None]:
        """
        Yield:
            frame_index,
            frame (numpy array)
        """

        frame_index = 0

        while True:
            success, frame = self.cap.read()

            if not success:
                break

            yield frame_index, frame

            frame_index += 1

    def release(self):
        self.cap.release()

here we first check it is url or not, then checking whether the file exists or not, if not then prevents the application from trying to open a file that does not exist. after that we verify that OpenCV successfully opened the video. This is important because a file can exist but still be unsupported, corrupted, or inaccessible.

let’s wait for next part.