从节点杀死一个python过程,而不是杀死python的子过程(子过程是ffmpeg.exe)

发布于 2025-01-18 13:48:53 字数 2119 浏览 6 评论 0原文

我正在开发电子应用。在此应用程序中,我正在用文件的路径作为参数来产生Python进程,然后将文件本身传递给FFMPEG(通过FFMPEG-PYTHON模块),然后通过一些TensorFlow函数。

我正在尝试处理用户在整个背景过程中关闭电子应用程序的情况。不过,从我的测试中,无论如何,FFMPEG的过程似乎都保持不变。我在Windows上,正在看任务管理器,但我不确定发生了什么:关闭电子应用程序的窗口时,有时是ffmpeg.exe是一个过程,有时候它将停留在电子中过程组。

我注意到,如果我通过关闭窗口杀死电子的过程,一旦FFMPEG完成了工作,则Python过程也将关闭,所以我想这是半工作的。问题是,FFMPEG正在做密集的事情,如果用户需要关闭窗口,那么FFMPEG过程也需要杀死。但是我无法以任何方式实现这一目标。

我已经尝试了几件事,所以我将粘贴一些代码:

main.js

// retrieve video data
ipcMain.handle('get-games', async (event, arg) => {
    const spawn = require('child_process').spawn;
    const pythonProcess = spawn('python', ["./backend/predict_games.py", arg]);

    // sets pythonProcess as a global variable to be accessed when quitting the app
    global.childProcess = pythonProcess;

    return new Promise((resolve, reject) => {
        let result = "";

        pythonProcess.stdout.on('data', async (data) => {
            data = String(data);

            if (data.startsWith("{"))
                result = JSON.parse(data);
        });

        pythonProcess.on('close', () => {
            resolve(result);
        })

        pythonProcess.on('error', (err) => {
            reject(err);
        });
    })
});

app.on('before-quit', function () {
    global.childProcess.kill('SIGINT');
});

prective_games.py(ffmpeg part)

def convert_video_to_frames(fps, input_file):
    # a few useful directories
    local_dir = os.path.dirname(os.path.abspath(__file__))
    snapshots_dir = fr"{local_dir}/snapshots/{input_file.stem}"

    # creates snapshots folder if it doesn't exist
    Path(snapshots_dir).mkdir(parents=True, exist_ok=True)

print(f"Processing: {Path(fr'{input_file}')}")
try:
    (
        ffmpeg.input(Path(input_file))
        .filter("fps", fps=fps)
        .output(f"{snapshots_dir}/%d.jpg", s="426x240", start_number=0)
        .run(capture_stdout=True, capture_stderr=True)
    )
except ffmpeg.Error as e:
    print("stdout:", e.stdout.decode("utf8"))
    print("stderr:", e.stderr.decode("utf8"))

有人有任何线索吗?

I am developing an Electron application. In this application, I am spawning a Python process with a file's path as an argument, and the file itself is then passed to ffmpeg (through the ffmpeg-python module) and then goes through some Tensorflow functions.

I am trying to handle the case in which the user closes the Electron app while the whole background process is going. From my tests though, it seems like ffmpeg's process stays up no matter what. I'm on Windows and I'm looking at the task manager and I'm not sure what's going on: when closing the Electron app's window, sometimes ffmpeg.exe will be a single process, some other times it will stay in an Electron processes group.

I have noticed that if I kill Electron's process through closing the window, the python process will also close once ffmpeg has done its work, so I guess this is half-working. The problem is, ffmpeg is doing intensive stuff and if the user needs to close the window, then the ffmpeg process also NEEDS to be killed. But I can't achieve that in any way.

I have tried a couple things, so I'll paste some code:

main.js

// retrieve video data
ipcMain.handle('get-games', async (event, arg) => {
    const spawn = require('child_process').spawn;
    const pythonProcess = spawn('python', ["./backend/predict_games.py", arg]);

    // sets pythonProcess as a global variable to be accessed when quitting the app
    global.childProcess = pythonProcess;

    return new Promise((resolve, reject) => {
        let result = "";

        pythonProcess.stdout.on('data', async (data) => {
            data = String(data);

            if (data.startsWith("{"))
                result = JSON.parse(data);
        });

        pythonProcess.on('close', () => {
            resolve(result);
        })

        pythonProcess.on('error', (err) => {
            reject(err);
        });
    })
});

app.on('before-quit', function () {
    global.childProcess.kill('SIGINT');
});

predict_games.py (the ffmpeg part)

def convert_video_to_frames(fps, input_file):
    # a few useful directories
    local_dir = os.path.dirname(os.path.abspath(__file__))
    snapshots_dir = fr"{local_dir}/snapshots/{input_file.stem}"

    # creates snapshots folder if it doesn't exist
    Path(snapshots_dir).mkdir(parents=True, exist_ok=True)

print(f"Processing: {Path(fr'{input_file}')}")
try:
    (
        ffmpeg.input(Path(input_file))
        .filter("fps", fps=fps)
        .output(f"{snapshots_dir}/%d.jpg", s="426x240", start_number=0)
        .run(capture_stdout=True, capture_stderr=True)
    )
except ffmpeg.Error as e:
    print("stdout:", e.stdout.decode("utf8"))
    print("stderr:", e.stderr.decode("utf8"))

Does anyone have any clue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

廻憶裏菂餘溫 2025-01-25 13:48:54

好吧,我终于能够解决这个问题了!由于ffmpeg-python只是良好旧ffmpeg的绑定集,因此可执行文件本身仍然是模块的核心。这也意味着,当FFMPEG运行时,类似于此的屏幕

... 

    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 (h264) -> fps:default
  fps:default -> Stream #0:0 (mjpeg)

...

Press [q] to stop, [?] for help

是幕后发生的事情。一旦我意识到这一点,我所要做的就是找到一种向FFMPEG的stdin发送“ Q”的方法。我做到了这一点,将此摘要添加到窗口插入事件:

app.on('window-all-closed', () => {
    // writes a 'q' in ffmpeg's terminal to quit ffmpeg's process
    // reminder: python gets closed when the Electron app is closed
    global.childProcess.stdin.write("q\n");

    if (process.platform !== 'darwin') app.quit()
})

与摘要相比,Python脚本本身是未接触的,这是我最终修改的唯一一件事。现在,每次我退出电子应用时,ffmpeg都会发送一个“ q”。 Python过程不需要手动杀死,因为电子已经为您做到了。

因此解决了问题。 :)

Alright, I was finally able to fix this! Since ffmpeg-python is just a collection of bindings for good old ffmpeg, the executable itself is still at the core of the module. This also means that when ffmpeg is running, a screen similar to this:

... 

    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 (h264) -> fps:default
  fps:default -> Stream #0:0 (mjpeg)

...

Press [q] to stop, [?] for help

is what's going on behind the scenes. Once I realized this, all I had to do was find a way to send a 'q' to ffmpeg's stdin. And I did it by adding this snippet on the window-all-closed event:

app.on('window-all-closed', () => {
    // writes a 'q' in ffmpeg's terminal to quit ffmpeg's process
    // reminder: python gets closed when the Electron app is closed
    global.childProcess.stdin.write("q\n");

    if (process.platform !== 'darwin') app.quit()
})

The Python script itself is untouched compared to the snippet in the question, and this is the only thing I ended up modifying. Now everytime I quit my Electron app, ffmpeg gets sent a 'q'. The Python process doesn't need to be manually killed because Electron already does that for you.

So problem solved. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文