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

Python subprocess调用ffmpeg流式输出时异常处理与进程终止问题问询

问题根因

你的代码存在两个核心问题导致异常场景下卡死、CPU升高:

  1. 未消费stderr管道:ffmpeg报错时会向stderr写入大量日志,管道缓冲区满后ffmpeg会被阻塞挂起,既不退出也不输出stdout,导致你的循环永久等待。
  2. stdout读取终止条件错误:subprocess的stdout是二进制模式,readline读完返回的是空字节b"",而非空字符串"",你原来的终止条件永远无法触发,ffmpeg退出后循环会一直空转,CPU占用持续升高。

communicate不适用的原因是它会等待子进程完全退出后再一次性返回所有输出,无法满足流式返回的需求。


解决方案

通过后台daemon线程单独消费stderr避免阻塞,同时修改读取逻辑,主动检测进程状态,异常时及时清理资源,修改后代码如下:

import subprocess
import threading

def stream(link):
    ffmpegcmd = [
        "ffmpeg",
        # "-loglevel",
        # "panic",
        "-i",
        link,
        "-vcodec",
        "copy",
        "-f",
        "mp4",
        "-movflags",
        "frag_keyframe+empty_moov",
        "pipe:",
    ]
    ffmpeg_sb = None

    def drain_stderr():
        """后台线程消费stderr,避免缓冲区满阻塞进程"""
        while ffmpeg_sb and ffmpeg_sb.poll() is None:
            # 不需要stderr日志可直接丢弃,也可写入日志文件用于排查问题
            ffmpeg_sb.stderr.read(1024)

    try:
        ffmpeg_sb = subprocess.Popen(
            ffmpegcmd, 
            stdin=subprocess.DEVNULL, 
            stdout=subprocess.PIPE, 
            stderr=subprocess.PIPE
        )
        # 启动daemon线程,主进程退出时自动销毁
        threading.Thread(target=drain_stderr, daemon=True).start()

        # 修复终止条件,用空字节作为结束标识
        for stdout_line in iter(ffmpeg_sb.stdout.readline, b""):
            # 每次输出前检查进程是否异常退出
            if ffmpeg_sb.poll() is not None and ffmpeg_sb.returncode != 0:
                raise RuntimeError(f"ffmpeg异常退出,返回码:{ffmpeg_sb.returncode}")
            yield stdout_line
    except Exception as e:
        print("Exception:", str(e))
        if ffmpeg_sb and ffmpeg_sb.poll() is None:
            ffmpeg_sb.kill()
    finally:
        # 回收子进程资源,避免僵尸进程
        if ffmpeg_sb:
            ffmpeg_sb.wait()
            ffmpeg_sb.stdout.close()
            ffmpeg_sb.stderr.close()
    print("Finished")

优化说明

  • 后台daemon线程会持续消费stderr的内容,不会让缓冲区满导致ffmpeg阻塞
  • 修复了readline的终止条件,ffmpeg正常退出后循环会自动结束
  • 每次yield前都检查进程状态,一旦ffmpeg异常退出就主动抛异常,走清理逻辑
  • 用finally块保证不管是正常结束还是异常退出,都会回收子进程资源,不会残留僵尸进程导致CPU升高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 22:24:06