How to gracefully close an ffmpeg process running in background without corrupting the encoded video file?

1

I need to be able to stop it on demand. I tried to gracefully terminate the process with taskkill /im ffmpeg.exe but it doesn't work. If I force it with /f then the video file gets corrupted.

I think the alternatives could be:

  • To get the process handle and then send a q keystroke to the stdin of that process running in background.
  • To get the console back again so I can sent the input from the console.
  • To use PyHooks and/or Win32Api to read keypresses, if a combination is pressed, then write to the stdin of the process.

This is the code (rec.pyw) I used to create the ffmpeg.exe process, hidden:

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=

Then I used pyinstaller to create an exe file with ffmpeg bundled:

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

I used the creationflags parameters because I've read that with a detached process I could create the window again. But I haven't found how.

Workaround

I've found that if I use .mkv instead of .mp4 the file doesn't get corrupted when killing the ffmpeg process from the task manager.

python
winapi
subprocess
asked on Stack Overflow Jul 25, 2017 by Jeflopo • edited Jul 25, 2017 by Jeflopo

3 Answers

0

In your python script you'll need to catch the signal with an except statement. I'm not a windows person, so I don't know how unix signals translate exactly to what you're sending, taskkill, but do a quick google on how to handle that in python and then in the except block you'll want to call a function that can finish writing the current frame and know to end after that frame is written and then do cleanup which may or may not involve writing more header/metadata to your file and then closing the file handle.

answered on Stack Overflow Jul 25, 2017 by B Rad C
0

The Problem

ffmpeg won't shut down cleanly because ffmpeg doesn't run with a window handle on windows, and only programs with a window handle can catch the WM_CLOSE event that the taskkill command sends. In fact, ffmpeg isn't even designed to catch a WM_CLOSE event at all, so even if you create a window handle for ffmpeg with the start command, it's not going to shut down gracefully when you send the taskkill

The Solution

The only real solution is to modify ffmpeg itself, or create a wrapper program that has a window handle and can catch the WM_CLOSE event.

I ran into the same issues and created a wrapper program to handle the WM_CLOSE event and shut down ffmpeg gracefully. It's written in nim so you'll have to compile it or you can grab a release from the releases page:

https://github.com/Wykleph/ffmpeg_wrapper

You can launch ffmpeg with the wrapper and kill the wrapper's PID with taskkill. When the wrapper gets the WM_CLOSE event it shuts down the ffmpeg process gracefully. You can use mp4 or whatever encoding you need.

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

Run that and open up task manager, get the pid for the ffmpeg_wrap.exe process and send the taskkill

To use it in python, just start the ffmpeg_wrap process and get the PID, then run taskkill on the PID (you can do this in the same script) when you want it to shut down ffmpeg gracefully.

The Catch

This program relies on a python dll file. I'm new to nim and the only way I know how to keep an ffmpeg process open without hanging is with the python subprocess module. Any of the python dll files that have the subprocess module should work. I use python3.8.dll, so that should definitely work. This file should be located at:

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

answered on Stack Overflow Aug 30, 2020 by DuckPuncher • edited Aug 30, 2020 by DuckPuncher
0

The following linked post taught me to cleanly stop ffmpeg from python by simulating a keypress of 'q':

How to stop ffmpeg remotely?

You create an empty file that you write 'q' to when you are ready to stop it.

To start the ffmpeg stream with python code, do this:

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

When ready to stop ffmpeg in your python code, do this:

os.system("echo 'q' >stop") 
answered on Stack Overflow Sep 12, 2020 by Sean Miller

User contributions licensed under CC BY-SA 3.0