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

使用FFmpeg提取小尺寸测试视频帧时出现「Invalid data found when processing input」错误的排查求助

问题分析与修复方案

我看到你遇到的问题是小尺寸测试视频提取帧时FFmpeg报错,但大尺寸视频能正常运行,这主要有两个关键问题需要修复:

  1. 临时文件写入后未重置读取指针:写入视频字节到临时文件后,文件指针停在末尾,FFmpeg读取时会从这个位置开始,自然读不到有效数据。
  2. 测试视频生成的兼容性不足:小尺寸视频用默认参数生成时,编码格式的兼容性较差,导致FFmpeg解析异常。

下面是修复后的完整代码及细节说明:


修复后的创建测试视频代码

import subprocess
import shlex
import os
from dataclasses import dataclass

def create_dummy_mp4_video(w: int, h: int, fps: int, sec: int, filename: str) -> None:
    cmd = (
        f"ffmpeg -y "  # 覆盖已有文件
        f"-f lavfi -i color=size={w}x{h}:rate={fps}:color=black "  # 生成纯色视频源
        f"-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 "  # 生成静音音频源
        f"-t {sec} "  # 视频时长(秒)
        f"-c:v libx264 -profile:v baseline -pix_fmt yuv420p "  # 指定兼容的H.264编码参数
        f"-movflags +faststart "  # 将moov原子移到文件开头,提升读取兼容性
        f"{filename}"
    )
    proc = subprocess.run(
        shlex.split(cmd),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        shell=False,
    )
    if proc.returncode != 0:
        raise Exception(f"FFmpeg生成视频失败: {proc.stderr.decode()}")

@dataclass(frozen=True)
class FakeVideo:
    body: bytes
    width: int
    height: int
    fps: int
    size: int
    frames: int
    length_s: int

def video() -> FakeVideo:
    w, h, fps, sec, filename = 100, 100, 10, 1, "output.mp4"
    create_dummy_mp4_video(w, h, fps, sec, filename)
    video_path = os.path.join(os.getcwd(), filename)
    with open(video_path, "rb") as file:
        body = file.read()
    size = len(body)
    frames = fps * sec  # 修复帧数量计算错误(原代码为fps//sec,逻辑错误)
    return FakeVideo(
        body=body,
        width=w,
        height=h,
        fps=fps,
        size=size,
        frames=frames,
        length_s=sec,
    )

修复后的异步提取帧代码

import asyncio
import aiofiles
import logging
import imghdr

LOGGER = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)

async def run_shell_command(frame_millisecond, data: bytes) -> bytes:
    async with aiofiles.tempfile.NamedTemporaryFile("wb") as file:
        await file.write(data)
        await file.seek(0)  # 关键修复:将文件指针重置到开头,确保FFmpeg能读取完整内容
        proc = await asyncio.create_subprocess_exec(
            "ffmpeg",
            "-i", file.name,
            "-ss", f"{frame_millisecond}ms",  # 定位到指定毫秒位置
            "-vframes", "1",  # 只提取一帧
            "-c:v", "png",  # 指定输出为PNG格式
            "-f", "image2pipe", "-",  # 将输出定向到标准输出
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await proc.communicate()
        level = logging.DEBUG if proc.returncode == 0 else logging.WARN
        LOGGER.log(level, f"[命令退出码] {proc.returncode}")
        if stderr:
            LOGGER.log(level, f"[错误输出] {stderr.decode()}")
        return stdout

async def runner():
    v = video()
    time = int(v.length_s / 2 * 1000)
    res = await run_shell_command(time, v.body)
    assert isinstance(res, bytes)
    assert imghdr.what(h=res, file=None) == "png"
    print("帧提取成功!")

if __name__ == "__main__":
    asyncio.run(runner())  # 使用Python 3.7+推荐的异步运行方式

关键修复点说明

  1. 临时文件指针重置:
    在写入视频字节后添加await file.seek(0),确保FFmpeg读取文件时从开头开始,而不是从写入后的末尾位置。这是导致你报错的最直接原因。

  2. 测试视频编码兼容性优化:

    • 明确指定libx264编码器、baseline编码 profile 和yuv420p像素格式,这些参数确保生成的MP4具有广泛的兼容性,尤其是小尺寸视频场景。
    • 添加-movflags +faststart将视频的moov原子(存储元数据的部分)移到文件开头,让FFmpeg无需读取到文件末尾就能解析视频信息。
  3. 其他细节修复:

    • 修复了帧数量计算错误:原代码frames = fps // sec逻辑错误,正确应为frames = fps * sec(总帧数=帧率×时长)。
    • 使用asyncio.run()替代旧的get_event_loop().run_until_complete(),符合Python 3.7+的异步代码规范。

现在你可以测试任意尺寸的视频(包括100x100),都能正常提取帧了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 23:52:37