You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python OpenCV获取MP4视频最后一帧时ret为False、frame为空问题

问题根源

  • cv2.CAP_PROP_FRAME_COUNT返回值并非对所有视频都100%准确,可变帧率(VFR)视频、带B帧的H.264/H.265封装视频、索引不完整的MP4文件都会出现该值和实际可读取总帧数存在偏差的情况,你遇到的27.75fps非整数帧率视频大概率属于可变帧率范畴,直接减1定位很容易落到实际不存在的帧位置,所以read()返回失败。
  • 部分编码器封装的视频本身不支持精准的单帧步进定位,直接设置CAP_PROP_POS_FRAMES到末尾附近也容易出现定位失效的问题。

修复方案

方案1:带帧位置回退的兼容方案(平衡速度和兼容性,适合绝大多数场景)

不要直接定位到总帧数-1,而是先定位到比总帧数靠前几帧的位置,再逐帧读取直到读取失败,取最后一次成功读取的帧即可,代码示例:

import cv2
def createsample(self, videopath) -> str:
    """Gets the last frame of the video as a sample."""
    cap = cv2.VideoCapture(videopath)
    if not cap.isOpened():
        raise IOError(f"Cannot open video file {videopath}")
    sample = COGSPATH + r"\data\sample.jpg"
    
    # 先获取总帧数,最多往前回退10帧定位(可以根据实际情况调整阈值)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    start_pos = max(total_frames - 10, 0)
    cap.set(cv2.CAP_PROP_POS_FRAMES, start_pos)
    
    last_frame = None
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        last_frame = frame
    
    # 校验是否成功读到帧
    if last_frame is None:
        raise RuntimeError("Cannot read any frame from the video")
    
    cv2.imwrite(sample, last_frame)
    cap.release()
    cv2.destroyAllWindows()
    return sample

方案2:超大视频优化方案(读取速度更快)

可以结合时长属性做定位,先定位到视频总时长前1秒的位置,再逐帧读取,避免遍历过多帧:

import cv2
def createsample(self, videopath) -> str:
    """Gets the last frame of the video as a sample."""
    cap = cv2.VideoCapture(videopath)
    if not cap.isOpened():
        raise IOError(f"Cannot open video file {videopath}")
    sample = COGSPATH + r"\data\sample.jpg"
    
    # 总时长单位为秒,转毫秒
    total_duration = cap.get(cv2.CAP_PROP_DURATION) * 1000
    # 定位到最后1秒的位置
    cap.set(cv2.CAP_PROP_POS_MSEC, max(total_duration - 1000, 0))
    
    last_frame = None
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        last_frame = frame
    
    if last_frame is None:
        raise RuntimeError("Cannot read any frame from the video")
    
    cv2.imwrite(sample, last_frame)
    cap.release()
    cv2.destroyAllWindows()
    return sample

额外说明

如果以上方案还是失效,先检查对应视频的编码格式,部分非常规编码的MP4需要安装额外的解码库,Windows环境可以安装K-Lite Codec Pack,Linux环境可以安装ffmpeg相关解码包解决。

内容的提问来源于stack exchange,提问作者DeepQuantum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:15:03