Shell – How to pipe a command output to multiple programs

shell

I'm using FFmpeg and I have made a custom application which is a TCP server. I 'm using duplicate output in ffmpeg.

What I want is, for each output I want to start my program to listen on a specific port. For example what I can do now:

ffmpeg -i "stream_link" -codec copy -f mpegts - \
    | myprogram -h 127.0.0.1 -p 12345 -f -

My program takes the data from ffmpeg and stores them inside the server. Now, I CAN'T DO the following

ffmpeg -i "stream_link" -codec copy -f mpegts - -codec copy -f flv - \
    | myprogram -h 127.0.0.1 -p 12345 -f - \
    | myprogram -h 127.0.0.1 -p 12345 -f -

I think you got me. I'm trying to output 2 different containers mpegts, flv and open again 2 instances of my program. So how I am able to do it?

This question is only pipe related. I just gave a real example using FFmpeg.

Best Answer

ffmpeg -i "stream_link" -codec copy -f mpegts - -codec copy -f flv - |  
myprogram -h 127.0.0.1 -p 12345 -f - | 
myprogram -h 127.0.0.1 -p 12345 -f -

So If I understand correctly, you are tryithisng to combine these 2 commands into one.

mpegts format

ffmpeg -i "stream_link" -codec copy -f mpegts - |  
myprogram -h 127.0.0.1 -p 12345 -f - 

flv format

ffmpeg -i "stream_link"  -codec copy -f flv - |  
myprogram -h 127.0.0.1 -p 12345 -f -

So, if my above understanding is correct, I believe you can accomplish it using tee command. You could get more details from this question here.

So, you could rephrase your command as,

 ffmpeg -i "stream_link" -codec copy -f mpegts - -codec copy -f flv - |  
 tee >(myprogram -h 127.0.0.1 -p 12345 -f -) 
     >(myprogram -h 127.0.0.1 -p 12346 -f -) 

However, as user mikeserv points out in his comments,

ffmpeg is writing two streams to one file. Both the mpegts and the flv go to stdout which is the | pipe.

So, the solution would have to involve ffmpeg writing to two distinct files. something like, ffmpeg flv processing -o flvfile, mpegts processing -o mpegtsfile and the two processes reading from the two outputs.

Either that or the process receiving the input would have to parse ffmpeg's output to know at which offset to begin reading their intended streams.

So the problem with the tee approach is that tee could duplicate the ffmpeg's input and two ffmpeg could be used.

So a better solution to this problem would be to use the approach as,

{ { ffmpeg -i "stream_link"            #one input stream
        -codec copy -f flv /dev/fd/3   #duped and processed, out >&3
        -codec copy -f mpegts - |      #duped and processed, out >&1
        myprogram1 >&4                 #receives >&1 on <&0, out >&4
        } 3>&1 | myprogram2            #receives >&3 on <&0, out >&1
} 4>&1                                 #ensures both myprograms write to >&1

When we use the above approach ffmpeg explicitly splits its output. It does depend on being run on a system that understands the /dev/fd/[num] links.