For the purposes of this tutorial I will assume you have installed:
I will also assume a basic understanding of shell scripting, though the examples should be fairly self explanatory.
ppmfilter is a command line video effects processing utility.
Simply put, it applies video effects on streams of uncompressed images received on stdin and produces uncompressed images on stdout. Input can be delivered in any of the Portable Anymap/PNM formats and output is produced in the PNM PPM (Portable Pixmap) format.
The motivation behind the development of this tool was simply that most graphic editing tools in the open source world operate on discrete files or pre-rendered file sequences, making them awkward and inefficient to apply to video.
The very powerful ImageMagick suite provides a good example of such a tool. While their convert utility does accept PNM on stdin and can produce results on stdout, it doesn't start outputing until all the input is processed - obviously, this only works with very small inputs.
Others, such as the very interesting effectv project are locked in on specific capabilities of linux (video4linux and the video loopback in their case), making them non-portable. There is also some very interesting work going on in this area in the gstreamer project.
I wanted a framework that was small and not locked in on a particular API, language or platform. Other factors were friendliness towards openMosix and a desire to produce a component which is compatible with the existing kino plug-in effects. During the development, I provided a means to integrate the tool with ffmpeg.
You'll find a few examples of mpegs produced with ppmfilter and ffmpeg here.
The following takes an arbitrary collection of images in a directory and its sub-directories, scales to full PAL sized frames, repeats each 25 times and presents the results for you to look at:
dir2ppm -a -r 25 /usr/share/pixmaps | ppmplay
NB: Both dir2ppm and ppmplay are scripts defined in smilscripts.
The next example shows provides a simple spiral transition between the frames:
dir2ppm -a -r 25 /usr/share/pixmaps | ppmfilter --spiraltv | ppmplay
The following example takes a video as input and makes it look old:
ffmpeg2ppm video.mpeg | ppmfilter --black-and-white --agingtv | ppmplay
To allow you to play with effects, a nice tool to use is launchfilter:
ffmpeg2ppm video.mpeg | launchfilter | ppmplay
The launchfilter app is a simple GTK program which provides a drop down with a sample selection of filters - you can change the filter and click on Run.
These examples shows the 3 stages of usage:
producer | filter | consumer
Some more examples of producers and consumers can be found in smilscripts. The majority of the remainder of this document will concentrate only on the filter stage.
You will receive a complete list of all effects available by running:
Generally, the syntax of ppmfilter is:
ppmfilter [ --effect [ [property=]value ] ]*
The default property of any given effect is the first one listed from the --help output.
Additionally, all effects have 3 unlisted properties - start, end and cycle. The start property denotes the first frame to begin the effect and end denotes the frame to end with.
ppmfilter --radioactv start=0 end=100
would apply the radioactive effect from effectv for the first 100 frames (frames 0 to 99). The cycle property allows an effect to be reused:
ppmfilter --radioactv start=0 end=100 cycle=500
would run the radioactive effect as before, but at frame 500, the effect will run again (from frames 500 to 599) and it will start again at 1000, 1500 etc.
Let's say you want to overlay one video on top of another, say with the second video appearing in the top right hand corner:
ffmpeg2ppm bottom.mpeg | ppmfilter --stack-video top.mpeg --overlay position=60,10:30x30 | ppmplay
The output of this will be as long as bottom.mpeg and top.mpeg will repeat and/or be truncated to match the time period. The overlay position is determined by the property provided - the syntax is X,Y:WxH where each component is expressed as a percentage of the size of the frames from bottom.mpeg.
If this is a common requirement, you may want to create a script to save on typing it out each time.
Typically, the scripts I develop using ppmfilter don't include the producer or the consumer, so I would write that script as a file called 'toprightvideo':
#!/bin/bash ppmfilter --stack-video "$1" --overlay position=60,10:30x30
You will have to save this somewhere on your path and make it executable with 'chmod +x' or similar. It can be used as follows:
ffmpeg2ppm bottom.mpeg | toprightvideo top.mpeg | ppmplay
To use this is conjunction with other effects, then the following would work:
ffmpeg2ppm bottom.mpeg | ppmfilter --black-and-white | toprightvideo top.mpeg | ppmplay
In this case, the contents of bottom.mpeg would be made black and white, while the top would remain in colour.
The most powerful aspect of ppmfilter is it's stacking capabilities - for those of you familiar with Reverse Polish Notation, the concept should be second nature.
For those others, a quick explaination follows, though it's generally easier to use than it sounds.
"Reverse Polish Notation is a way of expressing arithmetic expressions that avoids the use of brackets to define priorities for evaluation of operators".
For example, instead of writing 1 + 3 * 2, you would express it as 1 3 2 * +. As you read from left to right, the numbers are stacked until an operator appears - the * would remove the top two numbers (3 and 2) and return 6 to the stack. The + would remove the top two numbers (1 and 6) and return 7.
The concept in ppmfilter is similar - instead of numbers being placed on the stack, we place video frames. Our operators use 0 or more existing frames and place a new frame on the stack.
Important to note - as we process each frame from the input, we always place two frames on the stack - the bottom of the stack is the previous output (or a black frame in the case of the first frame) and the top of the stack is the current frame. If you do no operations at all, then the current frame, being the top of the stack, is output. All items other than the top of the stack are deleted before the next frame is read from the input.
Many effects take the top two stack frames to produce effects - for example, chroma, luma, motion-blur, plugin-transition and overlay. Other filters provide only stack manipulations, such as stack-dupe, stack-swap, stack-copy and stack-remove.
Plug-ins can be introduced to the filter via the plugin-producer, plugin-consumer, plugin-filter and plugin-transition effects.
A plugin-filter can simply be scripts which use ppmfilter:
ffmpeg2ppm bottom.mpeg | ppmfilter --plugin-filter putintv | ppmplay
Similarly, producers can be anything that produces pnm on stdout, consumers can be anything that reads ppm on stdin and a transition is any process which reads two ppms on stdin and produces a pnm on stdout.
When developing a filter, you must ensure that for every frame read, there is one frame output. When developing a transition, you must ensure that for every two frames read there is one output. For all filters, transitions and producers, it is imperatitve that stdout is flushed after writing each frame. Consumers provide no feedback into ppmfilter so it can do what it likes.
The current release only has very rudimentary support for animating properties.
The best example are the position properties. Consider inandout from smilscripts:
#!/bin/bash ppmfilter --group colour=0x000000 \ --border start=0 end=25 position=0,0:100x100 position=+40,40:20x20 \ --border start=25 end=50 position=40,40:20x20 position=+0,0:100x100
In this example, our filter runs for 50 frames, with the first 25 frames rescaling the image into the middle, and the following 25 rescaling it back out.
More work will go into this area in future releases, and the syntax is likely to change...
So now we have our fx, how do we produce mpeg, dv or divx with full audio?
smilutils provides ffmpeg2raw which will transcode all ffmpeg supported formats to raw dv. The -vhook switch there will allow you to pop in your video fx:
ffmpeg2raw -a -vhook "ppmfilter --black-and-white" input.mpeg > output.dv
If you're using ffmpeg to transcode kino projects, then the syntax is similar:
smil2raw project.smil | ffmpeg -f dv -i - -f mpeg -qscale 3 -s 320x240 -vhook "ppm.so ppmfilter --black-and-white" output.mpeg
Although ppmfilter is in its early stages of development, it already provides a flexible framework to build on. The hope is that ppmfilter will encourage other graphics projects to work in a similar manner and thus become plug-ins or even replacements for ppmfilter. Many existing libraries and tools can be adapted with little effort.