remotion-dev/remotion · error · std::io::Error

Not enough planes or linesizes

Error message

Not enough planes or linesizes

What it means

Thrown by get_dimensions_from_planes when decoding a YUV420P frame whose plane/linesize arrays have fewer than 3 entries. The function derives width/height from Y/U/V planes, so all three planes and linesizes must be present for any format other than YUV420P (which returns early with the original dimensions). This indicates malformed or truncated decoded frame data passed from ffmpeg.

Source

Thrown at packages/compositor/rust/fix_dimensions.rs:18

use std::io::ErrorKind;

use ffmpeg_next::format::Pixel;

// Calculate dimensions based on linesize, not based on metadata
pub fn get_dimensions_from_planes(
    pixel_format: Pixel,
    planes: &[Vec<u8>],
    linesizes: &[i32; 8],
    original_width: u32,
    original_height: u32,
) -> Result<(u32, u32), std::io::Error> {
    if pixel_format != Pixel::YUV420P {
        return Ok((original_width, original_height));
    }

    if planes.len() < 3 || linesizes.len() < 3 {
        return Err(std::io::Error::new(
            ErrorKind::Other,
            "Not enough planes or linesizes",
        ));
    }

    // Calculate dimensions for each plane based on linesizes
    let y_height = planes[0].len() as u32 / linesizes[0] as u32;
    let y_width = linesizes[0] as u32;

    // Believe the original width, but do not allow overflow
    Ok((y_width.min(original_width), y_height.min(original_height)))
}

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-encode or replace the source media with a valid YUV420P file that ffmpeg can fully decode.
  2. Before calling, assert planes.len() >= 3 and that linesizes[0..3] are non-zero, falling back to original_width/original_height if not.
  3. Upgrade/rematch the ffmpeg-next crate version to one consistent with the linked ffmpeg libraries.

Example fix

// before
let dims = get_dimensions_from_planes(fmt, &planes, &linesizes, w, h)?;

// after
if fmt == Pixel::YUV420P && (planes.len() < 3 || linesizes[0] == 0 || linesizes[1] == 0 || linesizes[2] == 0) {
    return Ok((w, h)); // fall back, do not crash on partial planes
}
let dims = get_dimensions_from_planes(fmt, &planes, &linesizes, w, h)?;
Defensive patterns

Strategy: validation

Validate before calling

fn can_get_dimensions(pixel_format: Pixel, planes: &[Vec<u8>], linesizes: &[i32; 8]) -> bool {
    if pixel_format != Pixel::YUV420P { return true; }
    planes.len() >= 3 && linesizes[0] > 0 && linesizes[1] > 0 && linesizes[2] > 0
}
// call before get_dimensions_from_planes; fall back to (original_width, original_height)

Type guard

null

Try / catch

match get_dimensions_from_planes(fmt, &planes, &linesizes, w, h) {
    Ok(d) => d,
    Err(_) => (w, h), // tolerate partial planes, use declared dims
}

Prevention

When it happens

Trigger: Calling get_dimensions_from_planes with pixel_format == Pixel::YUV420P but planes.len() < 3 or linesizes containing fewer than 3 populated slots (the array is fixed at 8 but only some are set by the decoder). Happens when a hardware/decoded frame surfaces incomplete plane data, or an upstream filter drops subplanes.

Common situations: Corrupt or truncated source media where ffmpeg partially decodes YUV420P; mismatches between the ffmpeg-next version and the planes the decoder emits; feeding manually-constructed plane arrays that omit chroma planes.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/3b3ed5773fceafec. Report an issue: GitHub.