Resolved

4K video rendering causes OOM crashes despite 120GB RAM limit

Video Processing
Memory Management
Multiprocessing
Performance Optimization
Backend
FFmpeg

Video rendering system crashed due to excessive memory usage when processing high-resolution videos | Implemented a dynamic rendering mode that automatically switches between in-memory and streaming based on memory thresholds

In a Python-based video rendering system, processing high-resolution videos (e.g., 4K UHD) resulted in out-of-memory (OOM) crashes despite the system having a 120GB RAM limit. The system was designed for in-memory frame processing, which caused memory spikes exceeding available resources. The solution involved implementing a smart memory-based rendering system that dynamically selects between in-memory and streaming modes based on estimated memory requirements.

Issue

The rendering system consistently crashed when processing:

  • 4K UHD videos: Exceeded memory limits even with 120GB RAM due to frame buffer requirements (e.g., 287GB for 11,558 frames).
  • High-frame-count videos: Systems with lower RAM (e.g., 47GB for 7,500 frames in 1080p) were also prone to crashes.

The root cause was an in-memory-only architecture, where all frames were loaded into memory before encoding, leading to catastrophic memory spikes that triggered OOM kills.

Culprit

The system lacked a dynamic memory management approach, relying exclusively on an in-memory rendering pipeline. Key issues included:

  • No adaptive rendering modes: All frames were forced into memory regardless of system constraints.
  • No fallback mechanism: Although a streaming-capable function existed (write_video_with_ffmpeg_streaming), it was never utilized in production.
  • Memory spikes: The conversion of frame iterators to lists (list(tqdm(...))) caused a single memory allocation equal to the total frames × resolution × color depth.

Solution

1. Configurable Memory Thresholds

Introduced a threshold-based system to automatically switch between rendering modes:

  • In-memory mode: Used for videos with estimated memory usage below a configurable threshold (e.g., 90GB).
  • Streaming mode: Activated for videos exceeding the threshold, preventing OOM crashes.

2. Dual-Mode Rendering Logic

Implemented a conditional rendering approach that:

  • Estimated memory requirements before rendering: (total_frames × width × height × color_depth) / (1024³).
  • Selected rendering mode based on the estimated memory: if above the threshold, streaming mode was activated.
  • Maintained parallel processing: Both modes leveraged multiprocessing for CPU/GPU acceleration.

3. Streaming Integration

Enhanced the system to use existing streaming infrastructure with minimal changes:

  • Direct frame-to-encoder pipeline: Eliminated disk I/O overhead by piping frames directly to FFmpeg.
  • Memory-efficient operation: Frames were processed iteratively, avoiding bulk memory allocation.
  • Configurable safety buffer: The threshold (e.g., 90GB) was set below the OOM kill limit (120GB) to ensure stability.

Impact:

  • Eliminated OOM crashes: All videos, regardless of resolution or length, render successfully.
  • Automatic adaptation: The system dynamically selects the optimal rendering mode without manual intervention.
  • Performance retention: Streaming mode maintains parallel processing capabilities, potentially improving efficiency.
  • Flexibility: Thresholds are configurable via environment variables for different hardware setups.