A single FLV stream contains at most one audio stream and at most one video stream. Flash supports uncompressed sound and various compressed formats like MP3 and ADPCM as well as the proprietary Nellymoser audio codec. With flash version 6 Macromedia also introduced video support for flash. In version 6 only the Sorenson H.263 video codec was supported which is a slightly modified version of the open H.263 standard. The latest flash version 7 introduced a second video format "Screen Video", which is a simple, loss less video format, especially developed for screen capturing.
ffmpeg -i infile.[avi|mpeg] stream.flv
Another project dealing with FLV streams is called libflv [libflv.sourceforge.net]. While FFmpeg is a general audio and video converting suite, libflv is focused on working with FLV streams. The project is still in a very early stage, but is able encoding videos in the Screen Video format and allows simple FLV stream manipulations like (de-)multiplexing of audio and video streams. A simple GTK-based screen capturing application can be found in the example directory.
MING is an open source library which is able to create flash files with almost all recent flash features, including Action Script, sound and video support. The library also has language bindings for a bunch of script and programming languages. The examples presented in this article are written in PHP4. Porting the examples to other supported languages like C/C++, Java, Python or Perl should be trivial.
To run the following example a current CVS snapshot of MING is needed. It is available either via Sourceforges anonymous CVS service or pre-packaged at klaus.geekserver.net/ming/.
First we create a new move instance and set dimension and background color:
The new flash move can now be filled with flash objects called characters. For the
multimedia player example we create a video canvas object and add it to the movie. The
add() method takes a character and inserts it to the current frame and
returns a handle to the object. This can be used to move, rotate, resize or
remove an object. If the object is going to be used with ActionScript, a name can be
assigned to it.
$stream = new SWFVideoStream();
$item = $movie->add($stream);
SWFVideoStream() constructor can also take a FLV file as argument. In
this case the video stream will be embedded to the flash file. However this approach
has some drawbacks. First of all the resulting flash movie will get as least as big as
the stream. But also the stream's frame rate must not exceed the flash movies frame rate
and each flash file is limited to 16000 frames, which means that the embedded stream can
contain at most 16000 frames.
A multimedia player application should be able to load and play streams dynamically.
SWFVideoStream() constructor is called with no arguments. Thus
only an empty video canvas will be created, which will be controlled by the following
connection = new NetConnection();
stream = new NetStream(connection);
The ActionScript first creates a pseudo connection by passing
connect() method of the
NetConnection object. In contrast,
a real connection to a Macromedia streaming server can be made by passing a valid
url to the method. Having a
NetConnection instance a new
NetStream object can be created and attached to the empty video canvas.
This object handles streaming and provides methods for controlling the stream. The
above example loads a FLV stream from the local web server with a downloadbuffer of
10 seconds. The ActionScript code can be compiled and added to the movie with:
$action = new SWFAction($action_string);
Until now the flash movie just loads and plays a certain FLV stream. To control its
behavior, a simple user interface consisting of some buttons and a seek-slider is missing.
Flash has its own compressed loss less bitmap format called DBL. MING provides a small
png2dbl to convert PNG images to DBL. Such images are used for
the player's control buttons:
$button = new SWFButton();
$flags = (SWFBUTTON_UP | SWFBUTTON_HIT | SWFBUTTON_OVER | SWFBUTTON_DOWN);
$action = new SWFAction("stream.pause();");
$button_ref = $movie->add($button);
The above example creates a pause button for the multimedia player. An interactive button
is created in two steps. First its look has to be defined by adding shapes for certain
mouse events. In flash a shape is the basic representation for graphic objects. For
each mouse event a different shape object can be assigned to the button. In the above
example the button looks always the same.
In the second step the buttons action can be defined by assigning ActionScript to a special event.
One drawback using progressive download streaming without server support is that there is no possibility to get the stream's total length. Therefore the seek-sliders functionality is limited to seeking within the already loaded parts of the stream.
The dragable part of the seek-slider is realized as a movie-clip object. A movie-clip is running as an independent movie in the flash movie. It has an independent time line, can handles scripts and handles external events itself.
$mc = new SWFSprite();
$shape = new SWFShape();
$slider = $movie->add($mc);
A movie clip (SWFSprite) has similar methods like a movie object. The
method inserts a flash object to the current frame,
the current frame and creates a new one. The movie clip is also a normal flash object
which can be added to a movie and placed on the stage.
The functionality of the seek-slider is defined by three small scripts. The first two
actions make the movie-clip dragable:
$a = new SWFAction("startDrag(this, $xMin, $y, $xMax, $y, 1); drag = true;");
$a = new SWFAction("stopDrag(); drag=flase;");
The third more lengthy script sets the stream position depending on sliders x-position if the slider is actually moved by the user or sets the sliders x-position depending on the streams current time:
// width in px
width = xMax - xMin;
paused = false;
// pause stream while seeking
paused = true;
x = _root._xmouse - xMin;
seekTo = (_global.streamLen / width) * x;
pos = (_global.stream.time * (width / _global.streamLen)) + xMin;
this._x = pos;
this._y = y;
// restart paused stream
$slider-handle with the
After having added all elements to the flash movie the first frame has to be closed
nextFrame() call. Since we don not need another frame the movie
can also be finished:
The resulting multimedia player