{"record":{"id":"9cc9094c7e60a9ba","repo":"commaai/openpilot","slug":"unsupported-pixel-format-pix-fmt","errorCode":null,"errorMessage":"Unsupported pixel format: {pix_fmt}","messagePattern":"Unsupported pixel format: (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"openpilot/tools/lib/framereader.py","lineNumber":66,"sourceCode":"          \"-threads\", threads,\n          \"-hwaccel\", hwaccel,\n          \"-c:v\", \"hevc\",\n          \"-vsync\", \"0\",\n          \"-f\", vid_fmt,\n          \"-flags2\", \"showall\",\n          \"-i\", \"pipe:0\",\n          \"-f\", \"rawvideo\",\n          \"-pix_fmt\", pix_fmt,\n          \"pipe:1\"]\n  dat = subprocess.check_output(args, input=rawdat)\n\n  ret: np.ndarray\n  if pix_fmt == \"rgb24\":\n    ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, h, w, 3)\n  elif pix_fmt in [\"nv12\", \"yuv420p\"]:\n    ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, (h*w*3//2))\n  else:\n    raise NotImplementedError(f\"Unsupported pixel format: {pix_fmt}\")\n  return ret\n\ndef ffprobe(fn, fmt=None):\n  fn = resolve_name(fn)\n  cmd = [\"ffprobe\", \"-v\", \"quiet\", \"-print_format\", \"json\", \"-show_format\", \"-show_streams\"]\n  if fmt:\n    cmd += [\"-f\", fmt]\n  cmd += [\"-i\", \"pipe:0\"]\n\n  try:\n    with FileReader(fn) as f:\n      ffprobe_output = subprocess.check_output(cmd, input=f.read(4096))\n  except subprocess.CalledProcessError as e:\n    raise DataUnreadableError(fn) from e\n  return json.loads(ffprobe_output)\n\ndef get_index_data(fn: str, index_data: dict|None = None):\n  if index_data is None:","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/lib/framereader.py#L48-L84","documentation":"decompress_video_data() only reshapes ffmpeg's raw output for three pixel formats: rgb24, nv12, and yuv420p. Any other pix_fmt string reaches the else-branch and raises NotImplementedError. The restriction exists because the output numpy shape (h,w,3 vs h*w*3//2) is hardcoded per format.","triggerScenarios":"Calling decompress_video_data(..., pix_fmt='gray') or 'bgr24', 'yuv444p', etc. Also calling FrameReader with an unsupported pix_fmt since it forwards the argument.","commonSituations":"Wanting grayscale frames for a model and passing 'gray'; copying ffmpeg filter names into pix_fmt; typo like 'NV12' (uppercase) which misses the exact-match list.","solutions":["Use one of the supported formats: 'rgb24', 'nv12', or 'yuv420p'","For grayscale, decode as nv12/yuv420p and take the Y plane: frames[:, :h, :w] instead of pix_fmt='gray'","For bgr24, decode rgb24 then do frames[..., ::-1]"],"exampleFix":"# before\nframes = decompress_video_data(raw, w, h, pix_fmt='gray')\n\n# after\nframes = decompress_video_data(raw, w, h, pix_fmt='nv12').reshape(-1, h*3//2, w)\ngray = frames[:, :h, :]","handlingStrategy":"validation","validationCode":"SUPPORTED_PIX_FMTS = {'rgb24', 'nv12', 'yuv420p'}\nassert pix_fmt in SUPPORTED_PIX_FMTS, f'pass one of {SUPPORTED_PIX_FMTS}'","typeGuard":"def is_supported_pix_fmt(p: str) -> bool:\n    return p in ('rgb24', 'nv12', 'yuv420p')","tryCatchPattern":null,"preventionTips":["Whitelist pix_fmt at your API boundary instead of passing user strings through","Derive grayscale from nv12's Y plane rather than asking ffmpeg for 'gray'","Watch case-sensitivity: only lowercase format names match"],"tags":["video","ffmpeg","pixel-format","framereader"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}