Introduction to Stream Output

The stream output chain (also called the sout chain) can be used to process and output any file that the VLC media player can read. This output can then either be saved as a new file, or it can be streamed over a network. The sout chain can include various modules which help in completing specific tasks.

Some of the most commonly used modules are,

  • std - to save the file locally or to stream it over a network.

  • transcode - to encode raw streams using various codecs.

  • gather - to combine multiple similar elementary streams into a single one.

  • duplicate - to fork pipelines (and each one is handled in an independent manner).

  • display - to display the output file locally.

Stream out as a pipeline

When we combine different modules of stream-out, they work as a pipeline - where the output of one becomes the input for another. In the CLI, this is done by the colon : operator. For those familiar with unix, they can think of the : as the | (pipe command).

Following are a few examples to demonstrate the behavior as a pipeline.

Example 1 (Combining transcode and std)

For example, when converting a file from MP4 to OGG and saving the converted file locally, the flow of control will be:

digraph example_one_block { rankdir=LR; node [shape=box]; "Input" -> "Convert (transcode)"; "Convert (transcode)" -> "Output (standard)"; }


The code for this operation is as follow:

$ vlc sample.mp4 --sout="#transcode{vcodec=h265, acodec=aac, scodec=ssa}:std{access=file, mux=mkv, dst=sample.mkv}"

In the above code snippet,

  • sample.mp4 is the input file.

  • The transcode block encodes the elementary streams of the file using the specified codecs (h265 video codec, aac audio codec, and ssa subtitle codec).

  • The std block combines the elementary streams into a single output stream and saves it in the mkv muxer (container) at the specified destination.

Following is how the pipeline elements correspond to the code:

digraph example_one { rankdir=BT; node [shape=box]; splines=ortho //Non-bordered nodes "Input file" [shape=plaintext] "Transcode module for conversion" [shape=plaintext] "Standard module for saving the file" [shape=plaintext] //Description blocks to code blocks "Input file" -> "$ vlc sample.mp4" "Transcode module for conversion" -> "\"#transcode{vcodec=h265,\nacodec=aac, scodec=ssa}" "Standard module for saving the file" -> ":std{access=file, mux=mkv, dst=sample.mkv}\"" subgraph code_blocks { rank = same; "$ vlc sample.mp4" -> "--sout=" -> "\"#transcode{vcodec=h265,\nacodec=aac, scodec=ssa}" -> ":std{access=file, mux=mkv, dst=sample.mkv}\"" [style=invis]; } subgraph description_blocks { rank = same; "Input file" -> "Transcode module for conversion" -> "Standard module for saving the file"; } }


To understand how transcoding works and how transcode and std modules interact in more detail, refer to Combining Transcoding and Standard Output.

Example 2 (Combining gather and std)

Suppose you want to combine multiple audio songs (all in mp3 format) to make a playlist, and stream it over the local network. In this case, the flow of control between the modules would will be:

digraph example_two_block { rankdir=LR; node [shape=box]; { node [width=0, shape=point] a, b; } "File 1" -> a [arrowhead=none] [label="Audio stream 1"] a -> "\nCombine (gather)\n " "File 2" -> "\nCombine (gather)\n " [label="Audio stream 2"] "File 3" -> b [arrowhead=none] [label="Audio stream 3"] "\nCombine (gather)\n " -> b [dir=back] "\nCombine (gather)\n " -> "\nOutput (standard)\n " [label="The three streams\nconcatenated into an\nuninterrupted stream"] subgraph name { rank=same; a, b, "\nCombine (gather)\n "; } }


The code for this operation will be:

$ vlc sample1.mp3 sample2.mp3 sample3.mp3 --sout="#gather:std{access=http, mux=ts, dst=:8090/sample_stream}" --sout-keep

In this code,

  • sample1.mp3, sample2.mp3, sample3.mp3 are the input files.

  • The gather module combines them one after another to make a single stream.

  • The standard module takes the stream and streams it over HTTP at port 8090. (To understand how streaming over HTTP works in more detail, refer to Stream Over HTTP.)

We use the sout-keep option so that the stream is kept open when one song ends, and the next song is streamed to the same destination. If we do not write sout-keep, we will have to reconnect everytime a song ends.

In this example, following is how the pipeline is implemented through the code:

digraph example_two { rankdir=BT; node [shape=box]; splines=ortho //Non-bordered nodes "Input files" [shape=plaintext] "Gather module for combining" [shape=plaintext] "Standard module for streaming" [shape=plaintext] //Description blocks to code blocks "Input files" -> "$ vlc sample1.mp3\nsample2.mp3 sample3.mp3" "Gather module for combining" -> "\"#gather" "Standard module for streaming" -> ":std{access=http, mux=ts, dst=:8090/sample_stream}\"" subgraph code_blocks { rank = same; "$ vlc sample1.mp3\nsample2.mp3 sample3.mp3" -> "--sout=" -> "\"#gather" -> ":std{access=http, mux=ts, dst=:8090/sample_stream}\"" [style=invis]; } subgraph description_blocks { rank = same; "Input files" -> "Gather module for combining" -> "Standard module for streaming"; } }


Example 3 (Combining transcode, gather, and std)

Consider that the audio files from the last example are in different formats - one file is in MP3, second one in OGG and the third in FLAC. In this case, the gather module will not work as it needs all the original files to be in the same format.

To solve this problem, we can use the transcode module to first convert all the files to a common format and then pass them to gather.

Hence, the flow of control will be:

digraph example_three_block { rankdir=LR; node [shape=box]; { node [width=0, shape=point] a, b; } "File 1" -> a [arrowhead=none] [label="Audio from\nMP3 file"] a -> "\nConvert (transcode)\n " "File 2" -> "\nConvert (transcode)\n " [label="Audio from\nOGG file"] "File 3" -> b [arrowhead=none] [label="Audio from\nFLAC file"] "\nConvert (transcode)\n " -> b [dir=back] "\nConvert (transcode)\n " -> "\nCombine (gather)\n " [label="All the three audio\nstreams encoded in\na common format"] "\nConvert (transcode)\n " -> "\nCombine (gather)\n " "\nConvert (transcode)\n " -> "\nCombine (gather)\n " "\nCombine (gather)\n " -> "\nOutput (standard)\n " [label="The three streams\nconcatenated into an\nuninterrupted stream"] subgraph name { rank=same; a, b, "\nConvert (transcode)\n "; } }


The code for this scenario will be:

$ vlc sample1.mp3 sample2.ogg sample3.flac --sout="#transcode{vcodec=none, acodec=vorb}:gather:std{access=http, mux=mkv, dst=:8090/stream}" --sout-keep

In the above code,

  • sample1.mp3, sample2.ogg, and sample3.flac are the input files.

  • The transcode block re-encodes all of them using the vorb acodec.

  • The gather module combines them and sends an uninterrupted stream.

  • The std module streams it over the local network.

Graphically, this is how the code implements the pipeline flow:

digraph example_three { rankdir=BT; node [shape=box]; splines=ortho //Non-bordered nodes "Input files" [shape=plaintext] "Transcode module for\nconverting to common type" [shape=plaintext] "Gather module for\ncombining" [shape=plaintext] "Standard module for\nstreaming" [shape=plaintext] //Description blocks to code blocks "Input files" -> "$ vlc sample1.mp3\nsample2.ogg sample3.flac" "Transcode module for\nconverting to common type" -> "\"#transcode{vcodec=none,\nacodec=vorb}" "Gather module for\ncombining" -> ":gather" "Standard module for\nstreaming" -> ":std{access=http, mux=mkv,\ndst=:8090/sample_stream}\"" subgraph code_blocks { rank = same; "$ vlc sample1.mp3\nsample2.ogg sample3.flac" -> "--sout=" -> "\"#transcode{vcodec=none,\nacodec=vorb}" -> ":gather" -> ":std{access=http, mux=mkv,\ndst=:8090/sample_stream}\"" [style=invis]; } subgraph description_blocks { rank = same; "Input files" -> "Transcode module for\nconverting to common type" -> "Gather module for\ncombining" -> "Standard module for\nstreaming"; } }


Notice how the output at each stage is the input for the next one.