如何优雅地关闭后台运行的 ffmpeg 进程而不损坏编码的视频文件?

问题描述 投票:0回答:4

我需要能够按需停止它。我试图用

taskkill /im ffmpeg.exe
优雅地终止该进程,但它不起作用。如果我用
/f
强制执行,那么视频文件就会损坏。

我认为替代方案可能是:

  • 获取进程句柄,然后将
    q
    击键发送到在后台运行的该进程的标准输入。
  • 再次恢复控制台,以便我可以从控制台发送输入。
  • 使用 PyHooks 和/或 Win32Api 读取按键,如果按下组合,则写入进程的标准输入。

这是我用来创建ffmpeg.exe进程的代码(

rec.pyw
),隐藏:

import subprocess
import sys
import os

# Creation flags
DETACHED_PROCESS = 0x00000008
CREATE_NO_WINDOW = 0x08000000
CREATE_NEW_PROCESS_GROUP = 0x00000200

cmd = sys._MEIPASS + os.sep + 'ffmpeg.exe -f dshow -i video=screen-capture-recorder -vcodec libx264 -qp 0 -crf 0 -vf scale=1280x720 -preset ultrafast -an -y out.mp4'
r = subprocess.call(cmd.split(), shell=True) #creationflags=

然后我使用 pyinstaller 创建了一个

exe
文件,并捆绑了
ffmpeg

pyinstaller --onefile --noconsole --add-binary ffmpeg.exe;. rec.pyw

我使用了

creationflags
参数,因为我已经读到,通过独立的进程,我可以再次创建窗口。但我还没找到怎么办。

解决方法

我发现,如果我使用

.mkv
而不是
.mp4
,当从任务管理器杀死 ffmpeg 进程时,文件不会被损坏。

python winapi subprocess
4个回答
2
投票

以下链接的帖子教我通过模拟“q”按键来从 python 中干净地停止 ffmpeg:

如何远程停止ffmpeg?

您创建一个空文件,当您准备停止它时,在其中写入“q”。

要使用 python 代码启动 ffmpeg 流,请执行以下操作:

os.system("<stop /usr/bin/ffmpeg ...") 

准备好在 Python 代码中停止 ffmpeg 时,请执行以下操作:

os.system("echo 'q' >stop") 

1
投票

问题

ffmpeg 不会彻底关闭,因为 ffmpeg 在 Windows 上不使用窗口句柄运行,只有具有窗口句柄的程序才能捕获

WM_CLOSE
命令发送的
taskkill
事件。 事实上,ffmpeg 根本就不是为了捕获
WM_CLOSE
事件而设计的,因此,即使您使用
start
命令为 ffmpeg 创建窗口句柄,当您发送
taskkill
时,它也不会正常关闭

解决方案

唯一真正的解决方案是修改 ffmpeg 本身,或者创建一个具有窗口句柄并可以捕获

WM_CLOSE
事件的包装程序。

我遇到了同样的问题,并创建了一个包装程序来处理

WM_CLOSE
事件并正常关闭 ffmpeg。 它是用
nim
编写的,所以你必须编译它,或者你可以从发布页面获取一个版本:

https://github.com/Wykleph/ffmpeg_wrapper

您可以使用包装器启动 ffmpeg 并使用

taskkill
终止包装器的 PID。 当包装器收到
WM_CLOSE
事件时,它会正常关闭 ffmpeg 进程。 您可以使用
mp4
或任何您需要的编码。

ffmpeg_wrap.exe ffmpeg.exe -rtbufsize 150M -f gdigrab -framerate 30 -offset_x 448 -offset_y 240 -video_size 1024x600 -draw_mouse 1 -show_region 1 -i desktop -r 30 -preset ultrafast -tune zerolatency -movflags +faststart screen-recording.mp4

运行该程序并打开任务管理器,获取

pid
进程的
ffmpeg_wrap.exe
并发送
taskkill

要在

python
中使用它,只需启动
ffmpeg_wrap
进程并获取 PID,然后在您希望它正常关闭 ffmpeg 时在 PID 上运行
taskkill
(您可以在同一个脚本中执行此操作)。

捕获

该程序依赖于 python dll 文件。 我是

nim
的新手,我知道如何保持 ffmpeg 进程打开而不挂起的唯一方法是使用 python
subprocess
模块。 任何具有
subprocess
模块的 python dll 文件都应该可以工作。 我使用
python3.8.dll
,所以这肯定有效。 该文件应位于:

C:/Users/username/AppData/Local/Microsoft/WindowsApps


0
投票

在 python 脚本中,您需要使用 except 语句捕获信号。我不是 Windows 用户,所以我不知道 unix 信号如何准确转换为您发送的内容,

taskkill
,但是快速谷歌一下如何在 python 中处理它,然后在 except 块中处理您'我想要调用一个函数,该函数可以完成当前帧的写入,并知道在该帧写入后结束,然后进行清理,这可能涉及也可能不涉及向文件写入更多标头/元数据,然后关闭文件句柄。


0
投票

对于 Windows,最好找到 ffmpeg 进程的父进程,然后使用 Win32 用户交互向其发送 Ctrl+C。

这样,它就可以真正优雅地停止,而不会以损坏的 MP4 文件结束。

我在这里为Windows制定了一个解决方案:https://github.com/Apivan/ffmpeg_stopper_win32

© www.soinside.com 2019 - 2024. All rights reserved.