deepinsight/insightface · error · ValueError

NV21 data size is not enough: expected {expected_size} bytes

Error message

NV21 data size is not enough: expected {expected_size} bytes, actual {len(yuv)} bytes

What it means

read_nv21 validates that the raw file holds at least width*height*3/2 bytes (Y plane + interleaved VU plane) before reshape and cv2.cvtColor(COLOR_YUV2BGR_NV21). If the buffer is smaller, conversion is impossible, so it raises this ValueError instead of producing garbage.

Source

Thrown at cpp-package/inspireface/python/read_nv21.py:15

import cv2
import numpy as np
from inspireface import ImageStream
import inspireface as isf


def read_nv21(file_path, width, height, rotate=0):
    with open(file_path, 'rb') as f:
        nv21_data = f.read()
    
    yuv = np.frombuffer(nv21_data, dtype=np.uint8)
    
    expected_size = width * height * 3 // 2
    if len(yuv) < expected_size:
        raise ValueError(f"NV21 data size is not enough: expected {expected_size} bytes, actual {len(yuv)} bytes")
    
    yuv_mat = np.zeros((height * 3 // 2, width), dtype=np.uint8)
    yuv_mat[:] = yuv[:height * width * 3 // 2].reshape(height * 3 // 2, width)
    
    bgr_mat = cv2.cvtColor(yuv_mat, cv2.COLOR_YUV2BGR_NV21)
    
    # add reverse rotate
    if rotate != 0:
        # calculate reverse rotate angle
        reverse_angle = (360 - rotate) % 360
        
        # select rotate method by angle
        if reverse_angle == 90:
            bgr_mat = cv2.rotate(bgr_mat, cv2.ROTATE_90_CLOCKWISE)
        elif reverse_angle == 180:
            bgr_mat = cv2.rotate(bgr_mat, cv2.ROTATE_180)
        elif reverse_angle == 270:
            bgr_mat = cv2.rotate(bgr_mat, cv2.ROTATE_90_COUNTERCLOCKWISE)

View on GitHub (pinned to 7fadd420c2)

Solutions

  1. Check the file size equals width*height*3//2 and fix width/height to match the actual capture resolution.
  2. Confirm the data really is NV21 (Y plane then interleaved V/U), not NV12, RGB, or compressed.
  3. If the file is truncated, re-capture the frame — do not pad, fix the producer side.

Example fix

# before
bgr = read_nv21('frame.nv21', 1080, 1920)  # ValueError: expected 3110400 bytes, actual 2073600

# after
import os
w, h = 1080, 1920
assert os.path.getsize('frame.nv21') >= w * h * 3 // 2, 'truncated NV21 file'
bgr = read_nv21('frame.nv21', w, h)
Defensive patterns

Strategy: validation

Validate before calling

import os
w, h = 1080, 1920
assert os.path.getsize(path) >= w * h * 3 // 2, 'NV21 file too small for given width/height'

Type guard

def is_valid_nv21(buf: bytes, w: int, h: int) -> bool:
    return isinstance(buf, (bytes, bytearray)) and len(buf) >= w * h * 3 // 2

Try / catch

try:
    bgr = read_nv21(p, w, h)
except ValueError as e:
    if 'NV21 data size' in str(e):
        raise RuntimeError(f'bad frame {p}: {e}') from e
    raise

Prevention

When it happens

Trigger: Calling read_nv21(path, width, height) where the file has fewer bytes than width*height*3//2 — wrong width/height passed for the file, a truncated capture, or a file that is actually NV12/RGB/JPEG rather than NV21.

Common situations: Mismatch between camera capture resolution and the reader arguments, feeding an RGB or grayscale dump into the NV21 reader, truncated camera-HAL dumps, or buffers that lost the chroma planes during copy.

Related errors


AI-assisted analysis of deepinsight/insightface@7fadd420c2 (2026-08-28). Data as JSON: /api/errors/b98d1bed37802b2c. Report an issue: GitHub.