14

I'm running ffmpeg on another machine for screen capture. I'd like to be able to stop it recording remotely. FFMPEG requires that q is pressed to stop encoding as it has to do some finalization to finish the file cleanly. I know I could kill it with kill/killall however this can lead to corrupt videos.

Press [q] to stop encoding

I can't find anything on google specifically for this, but some there is suggestion that echoing into /proc//fd/0 will work.

I've tried this but it does not stop ffmpeg. The q is however shown in the terminal in which ffmpeg is running.

echo -n q > /proc/16837/fd/0

So how can I send a character to another existing process in such a way it is as if it were typed locally? Or is there another way of remotely stopping ffmpeg cleanly.

Adam
  • 35,919
  • 9
  • 100
  • 137
  • 1
    Newer versions of ffmpeg don't use 'q' anymore, at least on Ubuntu Oneiric, instead they say to press Ctrl+C to stop them. So with a newer version you can simply use 'killall -INT' to send them SIGINT instead of SIGTERM, and they should exit cleanly. – sashoalm Mar 15 '12 at 16:33
  • @satuon: That version of Ubuntu is likely using avconv (part of the forked Libav project). That utility has removed 'q' as an option; main FFmpeg still has it. – Multimedia Mike Mar 15 '12 at 16:44
  • I've since discovered that I can used kill -2 to stop ffmpeg cleanly. I'm still interested in how to simulate key pressed into other applications though. – Adam Mar 15 '12 at 21:45
  • @satuon Do you want to add your suggestion of Ctrl+C as an answer so I can accept it? – Adam Apr 18 '12 at 07:36
  • OK, I'll just paste it as an answer. – sashoalm Apr 18 '12 at 07:41

5 Answers5

21

Here's a neat trick I discovered when I was faced with this problem: Make an empty file (it doesn't have to be a named pipe or anything), then write 'q' to it when it's time to stop recording.

  1. $ touch stop
  2. $ <./stop ffmpeg -i ... output.ext >/dev/null 2>>Capture.log &
  3. $ wait for stopping time
  4. $ echo 'q' > stop

FFmpeg stops as though it got 'q' from the terminal STDIN.

Doran
  • 4,051
  • 2
  • 27
  • 41
TheHelper
  • 211
  • 2
  • 2
17

Newer versions of ffmpeg don't use 'q' anymore, at least on Ubuntu Oneiric, instead they say to press Ctrl+C to stop them. So with a newer version you can simply use 'killall -INT' to send them SIGINT instead of SIGTERM, and they should exit cleanly.

sashoalm
  • 75,001
  • 122
  • 434
  • 781
4

Elaborating on the answer from sashoalm, i have tested both scenarios, and here are the results:

My experiments shows that doing

killall --user $USER  --ignore-case  --signal INT  ffmpeg

Produces the following on the console where ffmpeg was running

Exiting normally, received signal 2.

While doing

killall --user $USER --ignore-case --signal SIGTERM  ffmpeg

Produces

Exiting normally, received signal 15.

So it looks that ffmpeg is fine with both signals.

System: Debian GNU/Linux 9 (stretch), 2020-02-28

Rub
  • 2,071
  • 21
  • 37
1

The question has already been answered for Linux, but it came up when I was looking for the windows equivalent, so I'm gonna add that to the answers:

On powershell, you start the process like this:

$((Start-Process ffmpeg -passthru -argument "FFMPEG_ARGS").ID)

This sends back the PID of the FFMPEG process that you can store in a variable, or echo, and then you send the windows equivalent of sigint (Ctrl + C) using taskkill

taskkill /pid FFMPEG_PID

I tried with Stop-Process (which is what comes up when looking how to do this on Google) but it actually kills the process. (And yes, taskkill doesn't kill it, it gently asks the process to stop... good naming :D)

Skymen
  • 115
  • 1
  • 11
0

You can also try to use "expect" to automate the execution and stop of the program. You would have to start it using some virtual shell like screen, tmux or byobu and then start the ffmpeg inside of it. This way you would be able to get again the virtual shell screen and give the "q" option.

  1. Locally or remotely start a virtual shell session, lets say with "screen". Name the session with -S option, like screen -S recvideo Then you can start the ffmpeg as you like. You can, optionally, detach from this session with a Ctrl+a + d.

  2. Connect to the machine where the ffmpeg is running inside the screen (or tmux or whatever) and reconnect to it: screen -d -RR recvideo and then send the "q"

To do that from inside a script you can then use expect, like:

prompt="> "
expect << EOF
set timeout 20
spawn screen -S recvideo
expect "$prompt"
send -- "ffmpeg xxxxx\r"
set timeout 1
expect eof
EOF

Then, in another moment or script point or in another script you recover it:

expect << EOF
set timeout 30
spawn screen -d -RR recvideo
expect "$prompt"
send -- "q"
expect "$prompt"
send -- "exit\r"
expect eof
EOF

You can also automate the whole ssh session with expect, passing a sequence of commands and "expects" to do what you want.