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

如何在Python中通过ffmpeg更快向stdin写入字节生成帧处理后新视频

核心问题分析

  1. 异步实现无效的原因:你使用的ffmpeg-python的run_async返回的是标准同步子进程对象,stdout.read、stdin.write都是阻塞IO操作,套async壳子不会实现非阻塞调度,反而额外增加协程调度开销,所以性能更差。
  2. 写入耗时远高于读取的核心原因:你没有给输出的FFmpeg进程指定编码参数,默认使用的编码预设优先级偏向压缩率而非速度,编码耗时占了绝大多数时间。你观测到的process2.stdin.write耗时高,本质是FFmpeg编码速度慢导致管道缓冲区被占满,write操作被阻塞等待缓冲区释放,不是Python侧写入本身的性能问题。

优化方案

  • 调整FFmpeg编码参数

给输出的FFmpeg进程指定H.264编码器、极速编码预设,合理设置画质参数,这是最有效的优化手段:

process2 = (
    ffmpeg
    .input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height))
    .output('new2.mp4', 
            vcodec='libx264',
            pix_fmt='yuv420p',
            preset='ultrafast', # 编码速度最快的预设,压缩率最低
            crf=23) # 画质参数,范围0-51,数值越小画质越好、文件越大
    .overwrite_output()
    .run_async(pipe_stdin=True)
)

如果对压缩率没有要求,可以进一步降低crf数值提升编码速度。

  • 移除冗余的numpy操作

你翻转得到的out_frame本身就是uint8类型,不需要额外调用astype(np.uint8)。另外翻转后的numpy数组是非连续内存,直接转bytes会有额外拷贝,先转成连续内存再输出:

# 替换原来的循环内处理逻辑
out_frame = np.ascontiguousarray(in_frame[:, ::-1], dtype=np.uint8)
process2.stdin.write(out_frame.tobytes())
  • 合并音频处理流程

不需要单独抽取音频再后续混流,可以直接在输出进程中指定输入原视频的音频流,减少一次文件IO开销:

input_video = ffmpeg.input(video_path)
audio_stream = input_video.audio

process2 = (
    ffmpeg
    .input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height))
    .output(audio_stream, 'new2.mp4', 
            vcodec='libx264',
            pix_fmt='yuv420p',
            preset='ultrafast',
            crf=23,
            acodec='aac')
    .overwrite_output()
    .run_async(pipe_stdin=True)
)
  • 异步实现的正确姿势

如果要使用异步优化,必须使用asyncio原生的create_subprocess_exec异步子进程接口,替换同步的子进程读写操作,避免阻塞事件循环。原异步实现只是给同步操作套了协程壳,不会带来任何性能收益。


内容的提问来源于stack exchange,提问作者A.K.M. Adib

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:45:03