user3657114 user3657114 - 1 month ago 19
Linux Question

Pipe ffmpeg output to named pipe

I'm trying to get ffmpegs output to a named pipe, where I could read from another shell. I do not need the video stream piped, just the informations below to get a state of the conversion process back. I am not able to achieve the piping behavior in any way, but I can write the data to a file with the following command:

ffmpeg -i vid.mov -vcodec h264 -acodec aac -strict -2 -y vid.mp4 > fflog.txt 2>&1


This leads to the following output in fflog.txt

Stream mapping:
Stream #0:1 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:0 -> #0:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
frame= 50 fps=0.0 q=0.0 size= 0kB time=00:00:03.20 bitrate= 0.1kbits/s
frame= 73 fps= 70 q=28.0 size= 230kB time=00:00:04.05 bitrate= 465.4kbits/s
frame= 100 fps= 65 q=28.0 size= 462kB time=00:00:05.44 bitrate= 695.3kbits/s


Afterwards I can get lines via

tail -f -1 fflog.txt


out of the file. But the lines are not escaped correctly, I think. Vi shows me the following:

frame= 50 fps=0.0 q=0.0 size= 0kB time=00:00:03.20 bitrate= 0.1kbits/s
^Mframe= 73 fps= 70 q=28.0 size= 230kB time=00:00:04.05 bitrate= 465.4kbits/s
^Mframe= 100 fps= 65 q=28.0 size= 462kB time=00:00:05.44 bitrate= 695.3kbits/s
^Mframe= 125 fps= 61 q=28.0 size= 608kB time=00:00:06.48 bitrate= 767.5kbits/s


So the questions are:


  1. How to convert the CRLF to UNIX like LF to return data correctly via tail -n?

  2. Or even better: How to pipe the ffmpeg results correctly to a mkfifo named pipe?

  3. Or the most general: Is there a different way to achieve my goal in a more clever manner?


Answer

Let's tackle the line endings first. ffmpeg uses carriage return ('\r') to send the cursor back to the start of the line so it doesn't fill up the terminal with progress messages. With tr, the fix is simple.

ffmpeg -i input.mov output.webm 2>&1 | tr '\r' '\n'

Now you should see each progress line separately. Things get more interesting if we pipe or redirect somewhere else.

ffmpeg -i input.mov output.webm 2>&1 | tr '\r' '\n' | cat

Notice that the output appears as chunks rather than line-by-line. If that's not acceptable for your purposes, you can use stdbuf to disable tr's output buffering.

ffmpeg -i input.mov video.webm 2>&1 | stdbuf -o0 tr '\r' '\n' | cat

For reading the output from a different shell, a named pipe might work. However, the pipe won't end until ffmpeg finishes, so tail won't print anything until then. You can read a pipe in progress with other tools like cat or grep, but it's probably easier to just use a plain file.

# shell 1
ffmpeg -i input.mov output.webm 2>&1 | stdbuf -o0 tr '\r' '\n' > fflog.txt

# shell 2
tail -f fflog.txt