OpenCV VideoWriter – A Practical Guide

1. Introduction

“Video is the closest thing we have to teleportation.” – Steve Jobs once said that about FaceTime, but in the world of AI and Data Science, video processing is what bridges raw visual data to intelligent automation.

Why Video Processing Matters

I’ve worked with video data in multiple real-world applications—whether it was training AI models for autonomous vehicles or optimizing surveillance footage for motion detection. Video isn’t just a sequence of images; it’s a high-dimensional data stream that requires careful handling.

Here’s the thing: If you’re dealing with object detection, tracking, action recognition, or even simple video preprocessing for deep learning models, you need a reliable way to read, modify, and write video files efficiently. And that’s where OpenCV VideoWriter comes in.

What This Guide Covers

This isn’t going to be one of those “hello world” style tutorials. I’m skipping the fluff and jumping straight into practical applications of OpenCV VideoWriter—the how, why, and what of writing videos using Python.

Here’s what you’ll learn:
✔️ How to set up and use OpenCV VideoWriter like a pro
✔️ The best codecs and formats for speed vs. quality trade-offs
✔️ Advanced techniques like adding overlays, timestamps, and multi-threading for performance

If you’ve ever struggled with incorrect frame sizes, codec mismatches, or massive file sizes, I’ve been there too. This guide will walk you through every challenge and solution I’ve discovered over time.


2. Prerequisites

Before we start, let’s make sure your setup is ready. You don’t want to troubleshoot dependency issues while deep into the code.

Installing Dependencies

Here’s the minimal setup you need:

pip install opencv-python numpy

That’s it. No need for OpenCV-contrib unless you’re using advanced modules.

Understanding Codecs & Formats

Now, let’s talk codecs. If you’ve ever saved a video and noticed weird artifacts, incorrect colors, or absurdly large file sizes, chances are you picked the wrong codec.

Lossy vs. Lossless Codecs

  • Lossy (H.264, VP9, MPEG-4) → Great for reducing file size, but at the cost of slight quality loss.
  • Lossless (FFV1, HuffYUV, Lagarith) → Maintains perfect quality but results in massive files.

From my experience, H.264 (AVC) is your best bet for a balance between quality and compression. If you need extreme compression while maintaining decent quality, H.265 (HEVC) is worth exploring.

Choosing the Right Video Format (.avi, .mp4, .mov, etc.)

The file format isn’t just a name—it dictates how your video is stored and played across different platforms.

FormatBest ForDrawbacks
AVIHigh quality, lossless encodingHuge file sizes
MP4Best for web and storage efficiencyMay have compression artifacts
MOVHigh-quality Apple-friendly formatNot as widely supported as MP4

💡 Pro Tip: If you’re writing videos for deep learning applications, stick to MP4 with H.264—it’s widely supported and compresses well without much loss.

GPU-Accelerated Encoding (H.264, H.265)

This is where things get really interesting. If you’re dealing with high-resolution videos (1080p, 4K), software encoding will choke your CPU. Instead, you can offload encoding to your GPU using FFmpeg with OpenCV:

fourcc = cv2.VideoWriter_fourcc(*'H264')  # Hardware-accelerated encoding
out = cv2.VideoWriter('output.mp4', fourcc, 30.0, (1280, 720))

If you have an NVIDIA GPU, you can supercharge encoding with NVENC (NVIDIA Encoder):

ffmpeg -hwaccel nvdec -i input.mp4 -c:v h264_nvenc output.mp4

This can speed up encoding 10x compared to CPU-based encoding.


3. OpenCV VideoWriter – Quick Setup

“If you can’t explain it simply, you don’t understand it well enough.” – Einstein’s words apply to video processing too. If you’ve ever struggled to save videos in OpenCV, I’ve been there. But once you understand how VideoWriter works, it’s actually pretty straightforward.

Basic Usage – Creating a Simple Video from Images

Let’s start with the bare minimum—writing a video from randomly generated frames.

import cv2
import numpy as np

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')  # 'XVID' codec for AVI files
out = cv2.VideoWriter('output.avi', fourcc, 30.0, (640, 480))

# Generate 100 random frames and write to video
for i in range(100):
    frame = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8)  # Random noise frame
    out.write(frame)

out.release()
cv2.destroyAllWindows()

Breaking it Down:

VideoWriter_fourcc(*'XVID') – Defines the codec (XVID for AVI).
VideoWriter('output.avi', fourcc, 30.0, (640, 480)) – Creates a video file with 30 FPS and 640×480 resolution.
✅ The loop generates 100 random frames and writes them to the file.

At this point, you should have a random noise video saved as output.avi. It’s not pretty, but it proves that VideoWriter is working.

Common Pitfalls & Debugging

Here’s where most people mess up (and trust me, I’ve made these mistakes myself):

Video not saving?

  • Double-check that frame size in VideoWriter exactly matches the frame you’re writing.
  • AVI format may require XVID or MJPG codecs, while MP4 often needs MP4V.

Codec issues?

  • Try different fourcc codes:
fourcc = cv2.VideoWriter_fourcc(*'MJPG')  # Another common codec
  • If MP4V doesn’t work for .mp4, use H264 (requires FFmpeg).

Huge file size?

  • Switch to H.264 or H.265 for better compression.
  • Lower FPS if your application doesn’t need ultra-smooth playback.

4. Advanced Video Writing Techniques

Now that we have the basics down, let’s get into real-world applications.

Recording from a Webcam & Writing to a File

I’ve often needed to capture live video and save it in real-time—whether for data collection, surveillance, or just debugging. Here’s how you can do it:

import cv2

cap = cv2.VideoCapture(0)  # Open default webcam
fourcc = cv2.VideoWriter_fourcc(*'MP4V')  # MP4 codec
out = cv2.VideoWriter('webcam_output.mp4', fourcc, 30.0, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break  # Stop if no frame is captured

    out.write(frame)  # Save frame to file
    cv2.imshow('Webcam', frame)  # Display video in real-time

    if cv2.waitKey(1) & 0xFF == ord('q'):  # Press 'q' to exit
        break

cap.release()
out.release()
cv2.destroyAllWindows()

What’s Happening Here?

  • cv2.VideoCapture(0) opens your default webcam.
  • while cap.isOpened() keeps reading frames.
  • Frames are saved using VideoWriter and also displayed live.
  • Pressing ‘q’ exits the loop.

Performance Tip: If you’re writing high-resolution videos, consider running frame capture and video writing in separate threads to avoid frame drops.

Adding Text, Overlays & Time Stamps

Here’s where we can get a bit creative. If you’re saving videos for analytics, security footage, or AI training data, adding metadata is a game-changer.

Let’s overlay text on the frames before saving:

import cv2

cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('annotated_output.mp4', fourcc, 30.0, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    # Get current timestamp
    timestamp = cv2.getTextSize('Timestamp', cv2.FONT_HERSHEY_SIMPLEX, 1, 2)[0]

    # Add text overlay
    frame = cv2.putText(frame, 'OpenCV VideoWriter', (50, 50),  
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    frame = cv2.putText(frame, f'Time: {cv2.getTickCount()}', (50, 100),  
                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)

    out.write(frame)
    cv2.imshow('Webcam with Overlay', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

Pro Tip: Instead of cv2.getTickCount(), you can use datetime.now() from Python’s datetime module for an actual timestamp.

Resizing & Converting Color Formats Before Writing

I’ve run into situations where I needed to save grayscale videos or resize frames before writing. If you’re processing high-resolution videos, this can save a lot of storage space.

frame_resized = cv2.resize(frame, (1280, 720))  # Resize to HD
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # Convert to grayscale

And if you want to write a grayscale video, remember to update your VideoWriter:

out = cv2.VideoWriter('gray_output.avi', fourcc, 30.0, (640, 480), isColor=False)

5. Optimizing Video Writing Performance

“Fast is fine, but accuracy is everything.” – Wyatt Earp said this about gunfights, but it applies just as well to video processing. I’ve lost count of the times I’ve struggled with frame drops, lag, and massive file sizes when writing videos in OpenCV. The good news? There are some powerful optimizations you can use to fix these issues.

Let’s go beyond the basics and squeeze every last bit of performance out of OpenCV’s VideoWriter.

Multi-threading with OpenCV Video Capture & Write

Here’s the deal: capturing and writing video frames happen sequentially in most scripts. This means that if your writing process is slow, frames get delayed, leading to laggy or choppy videos. The fix? Multi-threading.

Single-threaded approach (Slow & Inefficient)

This is how most people do it, but it’s not ideal:

import cv2

cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('slow_output.avi', fourcc, 30.0, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    out.write(frame)  # Writing happens in the same thread
    cv2.imshow('Frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

❌ The Problem:

  • Frame Capture & Writing happen in the same thread → If disk writing is slow, frames start buffering, causing lag or dropped frames.

Multi-threaded approach (Faster & Smoother)

I’ve personally used this in real-time video analytics projects, and the difference is night and day.

import cv2
import threading
import queue

frame_queue = queue.Queue()

def writer():
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    out = cv2.VideoWriter('fast_output.avi', fourcc, 30.0, (640, 480))

    while True:
        frame = frame_queue.get()
        if frame is None:
            break
        out.write(frame)

    out.release()

cap = cv2.VideoCapture(0)
threading.Thread(target=writer, daemon=True).start()

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    frame_queue.put(frame)  # Push frames into the queue
    cv2.imshow('Frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

frame_queue.put(None)  # Stop signal for the writer thread
cap.release()
cv2.destroyAllWindows()

✔️ Multi-threading decouples frame capture and writing → Smoother video, no dropped frames!
✔️ Ideal for high-resolution or high-FPS recording.

Writing Video in Chunks to Prevent Memory Overflow

If you’re recording long-duration videos, writing everything into a single file can lead to corruption if something crashes mid-way. I’ve learned this the hard way when hours of data were lost because the process crashed. The fix? Save in smaller chunks.

import cv2
import time

cap = cv2.VideoCapture(0)

chunk_duration = 60  # Save a new file every 60 seconds
start_time = time.time()
file_index = 1

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(f'output_{file_index}.avi', fourcc, 30.0, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    if time.time() - start_time > chunk_duration:
        out.release()
        file_index += 1
        out = cv2.VideoWriter(f'output_{file_index}.avi', fourcc, 30.0, (640, 480))
        start_time = time.time()

    out.write(frame)
    cv2.imshow('Frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

✔️ Creates multiple video files instead of one massive file.
✔️ Prevents data loss if a crash happens.
✔️ Works great for long-term surveillance, sports recording, or time-lapse videos.

Using GPU Acceleration with FFmpeg & OpenCV

Most people ignore hardware acceleration and end up with sluggish video processing. I’ve optimized video pipelines using FFmpeg with OpenCV, and the difference is like going from a bicycle to a sports car.

First, make sure FFmpeg is installed. Then, use H.264 (GPU-accelerated) encoding:

fourcc = cv2.VideoWriter_fourcc(*'H264')  # Requires FFmpeg installed
out = cv2.VideoWriter('gpu_output.mp4', fourcc, 30.0, (1280, 720))

Why H.264?
✔️ 10x smaller file size than raw AVI.
✔️ Better compression without losing quality.
✔️ GPU-accelerated encoding (if supported).

Want even more speed? Use NVIDIA NVENC or Intel Quick Sync Video (QSV) for real-time encoding.

Choosing the Right Codec for Speed vs Quality Trade-offs

Different codecs have different strengths, and choosing the wrong one can kill performance or bloat file sizes. Here’s my go-to reference:

CodecProsCons
XVID (AVI)Fast, widely supportedLarge file size
MJPG (AVI)High quality, less compressionLarge file size
H.264 (MP4)Best compression, small size, GPU-acceleratedNeeds FFmpeg
H.265 (MP4)Even better compressionSlower encoding

Rule of thumb:
👉 Fastest writing → MJPG
👉 Best compression → H.264
👉 Best for low bandwidth → H.265


Conclusion

We’ve covered a lot—from basic VideoWriter usage to multi-threading, chunk-based writing, and GPU acceleration. If you’ve ever struggled with slow, laggy, or oversized videos, these optimizations will make a huge difference.

Final Thoughts & Best Practices

Use multi-threading to separate capture and writing.
Write in chunks to avoid file corruption.
Leverage hardware acceleration for H.264 encoding.
Choose the right codec for your use case.

Further Reading

Leave a Comment