如何在不破坏编码视频文件的情况下优雅地关闭在后台运行的ffmpeg进程?

时间:2017-07-25 04:40:42

标签: python winapi subprocess

我需要能够按需停止它。我尝试使用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进程时,该文件不会被破坏。

3 个答案:

答案 0 :(得分:0)

在python脚本中,您需要使用except语句捕获信号。我不是一个Windows用户,所以我不知道unix信号如何准确地转换为你发送的内容taskkill,但是快速谷歌如何在python中处理它,然后在except块中你想要调用一个函数来完成当前帧的写入并知道在写入该帧之后结束,然后进行清理,这可能涉及或不涉及将更多的头文件/元数据写入文件,然后关闭文件句柄。 / p>

答案 1 :(得分:0)

问题

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,然后在需要时对PID运行taskkill(可以在同一脚本中执行此操作)可以正常关闭ffmpeg。

抓住

此程序依赖python dll文件。我是nim的新手,我知道如何保持ffmpeg进程打开而不会挂起的唯一方法是使用python subprocess模块。具有subprocess模块的任何python dll文件均应正常工作。我使用python3.8.dll,所以绝对可以。该文件应位于:

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

答案 2 :(得分:0)

下面的链接文章教我通过模拟“ q”的按键来彻底停止ffmpeg的运行:

How to stop ffmpeg remotely?

您创建了一个空文件,当您准备停止该文件时会写“ q”。

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

setState()

准备在您的python代码中停止ffmpeg时,请执行以下操作:

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