{"record":{"id":"237a40c6bcdee5bb","repo":"microsoft/autogen","slug":"failed-to-capture-frame-at-timestamp-2f-s","errorCode":null,"errorMessage":"Failed to capture frame at {timestamp:.2f}s","messagePattern":"Failed to capture frame at (.+?)s","errorType":"exception","errorClass":"IOError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py","lineNumber":102,"sourceCode":"def save_screenshot(video_path: str, timestamp: float, output_path: str) -> None:\n    \"\"\"\n    Captures a screenshot at the specified timestamp and saves it to the output path.\n\n    :param video_path: Path to the video file.\n    :param timestamp: Timestamp in seconds.\n    :param output_path: Path to save the screenshot. The file format is determined by the extension in the path.\n    \"\"\"\n    cap = cv2.VideoCapture(video_path)\n    if not cap.isOpened():\n        raise IOError(f\"Cannot open video file {video_path}\")\n    fps = cap.get(cv2.CAP_PROP_FPS)\n    frame_number = int(timestamp * fps)\n    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)\n    ret, frame = cap.read()\n    if ret:\n        cv2.imwrite(output_path, frame)\n    else:\n        raise IOError(f\"Failed to capture frame at {timestamp:.2f}s\")\n    cap.release()\n\n\nasync def transcribe_video_screenshot(video_path: str, timestamp: float, model_client: ChatCompletionClient) -> str:\n    \"\"\"\n    Transcribes the content of a video screenshot captured at the specified timestamp using OpenAI API.\n\n    :param video_path: Path to the video file.\n    :param timestamp: Timestamp in seconds.\n    :param model_client: ChatCompletionClient instance.\n    :return: Description of the screenshot content.\n    \"\"\"\n    screenshots = get_screenshot_at(video_path, [timestamp])\n    if not screenshots:\n        return \"Failed to capture screenshot.\"\n\n    _, frame = screenshots[0]\n    # Convert the frame to bytes and then to base64 encoding","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py#L84-L120","documentation":"Raised by save_screenshot() when the video opened successfully and the capture position was set to int(timestamp * fps), but cap.read() returned ret=False — no frame came back at that position. Common causes: timestamp beyond the actual (vs. reported) stream length, a variable-frame-rate file where CAP_PROP_POS_FRAMES seeks imprecisely, or a truncated/corrupt file whose header frame count is wrong.","triggerScenarios":"Calling save_screenshot(video, timestamp) with a timestamp at or near the reported duration (e.g. duration exactly), seeking in a variable-frame-rate video, or reading a partially downloaded file whose metadata over-reports frame count.","commonSituations":"Agents computing a timestamp from get_video_length() output (frame_count/fps can overestimate), taking a screenshot of the final frame, handling webcam/DVR streams with unreliable CAP_PROP_FRAME_COUNT.","solutions":["Use a timestamp strictly less than the duration, e.g. min(timestamp, duration - 1.0/fps)","Clamp the frame number: frame_number = min(int(timestamp * fps), int(frame_count) - 1)","Re-encode the video to constant frame rate with ffmpeg -vsync cfr to make seeks reliable","Verify the file is fully downloaded/uncorrupted (ffprobe reports no errors)"],"exampleFix":"// before\nsave_screenshot(video_path, duration, 'last.png')  # seek past end -> IOError\n\n// after\nfps = cv2.VideoCapture(video_path).get(cv2.CAP_PROP_FPS)\nframes = cv2.VideoCapture(video_path).get(cv2.CAP_PROP_FRAME_COUNT)\nsafe_ts = min(timestamp, (frames - 1) / fps)\nsave_screenshot(video_path, safe_ts, 'last.png')","handlingStrategy":"validation","validationCode":"import cv2\ndef clamp_timestamp(video: str, ts: float) -> float:\n    cap = cv2.VideoCapture(video)\n    fps = cap.get(cv2.CAP_PROP_FPS) or 30.0\n    frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)\n    cap.release()\n    return max(0.0, min(ts, (frames - 1) / fps))","typeGuard":null,"tryCatchPattern":"try:\n    save_screenshot(video, ts, out)\nexcept IOError:\n    save_screenshot(video, max(0.0, ts - 0.5), out)  # retry slightly earlier frame","preventionTips":["Never request a timestamp equal to the full duration","Transcode VFR recordings to CFR for reliable seeking","Treat repeated read failures as a corrupt-file signal, not a timestamp problem"],"tags":["opencv","video","seek","screenshot","video-surfer"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}