A graph description consists of two major parts. The first part is an (optional) comment introduced by the character %.
The second part specifies the flow graph which describes how to connect the nodes. The following example describes
a simple graph to play an MP3 audio file.
To run this graph description, copy it into a file, e.g. mp3play.gd, and start clic with the following command:
The option -i is used to specify the input file. To exit the application, enter q at the command line.
For detailed information about all options simply type:
describes the location of the graph descriptions that are included in
the current NMM release. The rest of this section describes this example in detail.
The flow graph section of a graph description describes how to connect the nodes. A node
is identified by its name, which is (normally) the C++ class name. The exclamation mark (!)
is used to denote a connection between two nodes as seen in the graph description for MP3
files.
In this example the statement
MP3ReadNode ! MPEGAudioDecodeNode ! PlaybackNode
|
causes
the clic-application to request the nodes MP3ReadNode, MPEGAudioDecodeNode and PlaybackNode.
If all nodes can be successfully requested, the MP3ReadNode is connected to the MPEGAudioDecodeNode,
and the MPEGAudioDecodeNode to the PlaybackNode. After this clic sets the specified parameters
from the command line, like an input file, and starts the entire flow graph.
To specify a more complex flow graph that includes a a demultiplexer we need an additional syntax to describe
the different input- or output jacks which a (de)multiplexer can provide. Therefore, a unique
string which is called jack tag is associated with each jack to identify it. For example these
jack tags are used to distinguish between audio and video in/output of a multiplexer or a
demultiplexer node. If a node provides only a single input or output jack the string "default"
is used as jack tag and it is used in graph description if no other jack tag is specified.
To use a specific input jack that should be used for a connection, the corresponding jack
tag must be written before the node name, and behind the node name to specify an output
jack respectively. The following example shows the MP3 player graph description with
specified "default" jack tags:
% This graph description realizes a simple MP3 player and specifies the
% input and output jacks using their jack tags.
% Use the -i option of clic to specify the MP3 file
MP3ReadNode "default"
! "default" MPEGAudioDecodeNode "default"
! "default" PlaybackNode
|
In this example the specification of jack tags is not required because clic uses the
jack "default" to connect nodes if no one is specified. Furthermore, we need a syntax
to describe branches of nodes that must be connected to
a specific output jack of the demultiplexer. To describe a branch in a flow graph, the
corresponding nodes are encapsulated in braces ({}) as seen in the following example,
for reading mpeg files.
% This graph description realizes a simple mpeg video player with ac3 audio.
% Use the -i option of clic to specify the mpeg video file.
MPEGReadNode ! MPEGDemuxNode
{
{ ["mpeg_video0"] ! MPEGVideoDecodeNode ! XDisplayNode }
{ ["ac3_audio0"] ! AC3DecodeNode ! PlaybackNode }
}
|
The MPEGDemuxNode demultiplexes incoming messages and forwards audio buffer to
the "ac3_audio0" output jack and video buffer to the "mpeg_video0" output jack
respectively. After the MPEGDemuxNode, braces encapsulates all branches
connected to this node. Each branch itself is encapsulated in braces too and starts
with the output jack tag of the MPEGDemuxNode, encapsulated in square brackets. This
output jack is connected to the leading node of the branch. So in this example we have
two branches. The first one consist in the MPEGVideoDecodeNode, connected to the
XDisplayNode. The MPEGVideoDecodeNode is the leading node of this branch and is connected
to output jack of the MPEGDemuxNode with jack tag "mpeg_video0". The second branch consist
in the AC3DecodeNode connected to the PlaybackNode. The leading node of this branch is
the AC3DecodeNode which is connected to the output jack of the MPEGDemuxNode with jack tag
"mpeg_audio0".
To add a multiplexer node is very similar to a demultiplexer, as seen in the
following example.
% This graph description converts an mpeg video file with ac3
% audio into an avi file.
% Unfortunately the flow graph doesn't work because the FFMpegEncodeNode
% requires a bitrate.
MPEGReadNode ! MPEGDemuxNode
{
{
["mpeg_video0"] !
MPEGVideoDecodeNode !
FFMpegEncodeNode !
["video"]
}
{
["ac3_audio0"] !
["audio"]
}
} AVMuxNode ! AVIWriteNode
|
This example can be used to convert an mpeg file into an avi file with DivX-video
and ac3 audio. So the first branch consist in an MPEGVideoDecodeNode which is connected
to the FFMpegEncodeNode. The input of the first node in this branch, the MPEGVideoDecodeNode,
is connected to the output jack of the MPEGDemuxNode with jack tag "mpeg_video0". The output
of the last node in this branch, the FFMpegVideoEncodeNode, is connected to the
input jack of the AVMuxNode with jack tag "video". The second branch has no nodes. In this
branch output of the MPEGDemuxNode jack with jack tag "ac3_audio0" is connected to
the input jack of AVmuxNode with jack tag "audio". So the audio buffers are directly passed
through from the MPEGDemuxNode to the AVMuxNode without any conversion.
The syntax of this example is correct but the flow graph can not run because the
FFMpegEncodeNode needs the encoding bitrate which is specified in the connection format.
So we need a possibility to
(partially) specify a connection format that is used between two nodes. The statement
Format prefaced by the character '@' is used to specify the connection
format. This statement expects a comma separated list of format types, which are defined
in the Format.hpp followed by a corresponding value. A sole exception is the format type
which is written as a single string. Note: The connection format must be specified in front
of the connection symbol (!). The following example shows how to define the connection
format including the format type and the bitrate of the FFMpegEncodeNode.
% This graph description converts an mpeg video file with ac3 audio
% into an avi file. Furthermore the desired bitrate of the video is
% specified using the connection format.
% Use the -i option of clic to specify the mpeg video file and -o option
% to specify the name of the output file.
MPEGReadNode ! MPEGDemuxNode
{
{
["mpeg_video0"] !
MPEGVideoDecodeNode !
FFMpegEncodeNode @ Format ("video/mpeg4", bitrate = 1200000) !
["video"]
}
{
["ac3_audio0"] !
["audio"]
}
} AVMuxNode ! AVIWriteNode
|
To run this flow graph, copy the graph description into a file, e.g.mpeg_to_avi.gd, an enter
./clic mpeg_to_avi.gd -i /home/bob/video/movie.mpeg -o /home/bob/video/movie.avi
|
whereas the option -i specifies the input file and -o the output file.
Furthermore you can specify two additional parameters to set the transport protocol used to
transmit data between two nodes, which is especially useful if they are running on different
hosts. Both parameters are prefaced by the character '@' as well. To configure
a specific transport protocol used for instream communication the parameter
setBufferStrategy and setEventStrategy
can be used, as seen in the following graph description.
% This graph description describes a simple MP3 player which specifies the
% used transport protocols between the nodes.
% Use the -i option of clic to specify the MP3 file
MP3ReadNode @ setEventStrategy("TCPStrategy")
@ setBufferStrategy("RTPStrategy") !
MPEGAudioDecodeNode @ setBufferStrategy("RTPStrategy") !
PlaybackNode
|
The parameter
setBufferStrategy specifies the transport protocol used to transmit
multimedia buffers and the parameter
setEventStrategy how to transport instream
events. In this example the multimedia protocol RTP is used to transmit the MP3 buffers and the
reliable TCP protocol to transmit instream events. To transport buffers between the
MPEGAudioDecodeNode and PlaybackNode, the RTP protocol is used, but no protocol for instream events
is specified. If one of these parameters or both are not set, the default transport strategy
proposed by the NMM middleware is used, which is a
LocalStrategy to transport
buffers and events between nodes in the same address space efficiently via pointer forwarding
and
TCPStrategy between nodes running on different hosts or address spaces.