Lasso Soft Inc. > Home

  • Articles

Displaying Video with Lasso and FFmpeg

The methods described on this page are based on a blog entry by Daniel Tietze, who uses Django and FFmpeg to play Video files on his web pages.

PassThru or OS_Process

Handling video files as outlined in this document can only be done through the use of command line applications. These were accessed by installing and using Steffan Clines PassThru tag for older versions of Lasso, or alternatively by using OS_Process in Lasso version 8.5 and newer.

Installing LAME encoder

This section on the installation of the LAME MP3 encoder has been reproduced with kind permission by Stephen Jungels from his article on FFmpeg on Mac OS X How-to.

Although it's not documented anywhere, FFmpeg will silently ignore audio streams when converting to Flash Video, if you do not have the LAME MP3 encoder installed. Other codecs, like mp2, just don't work. I don't know if this is a limitation of FFmpeg or of Flash Video, but it is easy enough to fix by installing LAME. In this case FFmpeg is going to need include files, so it is not enough to install a prebuilt binary.

Start by creating a working directory:

mkdir ~/lame
cd ~/lame

 

On a good day you can get the latest source code release of LAME from Sourceforge. The file you want will be named lame-3.97.tar.gz or something similar. If you download the tar file, you need to unpack it as follows:

tar xvzf lame-3.97.tar.gz

 

After downloading and unpacking the source, change to the main directory and do the usual install procedure:

cd lame-3.97
./configure
make
sudo make install

Install faad encoder
Quicktime movies, such as the ones produced by iMovie, may cause problems with ffmpeg reporting errors about "negative ctts". As it happens, the "negative ctts" is not actually a problem - the real error lies in the codec ffmpeg is trying to use. Having previously compiled ffmpeg with the LAME mp3 libraries, it turns out that we need another library to deal with these Quicktime files. Thanks to Rich Fortnum for pointing this out!

This problem is addressed by installing the faad libraries, which are available from http://packages.debian.org/unstable/sound/faad. Personally, I simply downloaded the package "faad2_2.6.orig.tar.gz" and unpacked it. Once you've done that, cd into the resulting directory and perform the usual install procedure from the Terminal:

./configure
make
sudo make install

That should be it, libfaad is ready to be included in your ffmpeg build.

Building FFmpeg

As of July 24, 2006, the latest version of FFmpeg from the Subversion repository builds and runs on OS X 10.4 as well as OS X 10.3 (tested by yours truly). However, I recently (November 2007) found that building on OSX 10.3 Server reported several errors, notably an error about "ffmpeg-doc.html". Fortunately, this did not stop the build from being successful, so I decided to ignore the errors, which appear to relate to the installation of the docs. Who reads them, anyway?

In January 2008, while trying to build on OS X Server 10.5 on my new Intel Xserve, the build failed miserably. Chris Waltham on the Apple macosx-server List supplied the solution - we need to add the --disable-mmx flag to ./configure in order to, you guessed it, disable MMX support.

FFmpeg is available from http://ffmpeg.mplayerhq.hu/download.html. I prefer to fetch the source with Subversion. First create a working directory:

mkdir ~/ffmpeg
cd ~/ffmpeg

 

Use Subversion to retrieve the source and cd into the main directory:

svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg
cd ffmpeg

 

It is of course possible that an earlier version of FFmpeg is already installed on your system. This may well cause problems, such as unsupported codec errors. The solution is to perform a clean recompile to ensure that FFmpeg will work with LAME and faad. The --enable-gpl parameter is there to keep the faad libraries happy.

./configure --enable-libmp3lame --enable-static --disable-vhook --enable-libfaad --enable-gpl --disable-mmx
make clean
make
sudo make install

Note that various instructions online refer to --enable-mp3lame but this no longer works - make sure to use --enable-libmp3lame instead.

Retrieving Info from Video Files

It is outside the scope of these instructions to explain how to upload files to your server. Let's just assume that you have a Quicktime movie, MPEG or even .wmv file somewhere on your server.

Using PassThru, FFmpeg and a bit of RegExp, we can retrieve some useful information from such a file:

[PassThru('/usr/local/bin/ffmpeg -i "/path/to/myfile.mov"')]

 

This will return something like the following:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/path/to/myfile.mov':
  Duration: 00:00:24.4, start: 0.000000, bitrate: 991 kb/s
  Stream #0.0(eng): Video: mpeg4, yuv420p, 320x240, 23.95 fps(r)
  Stream #0.1(eng): Audio: pcm_mulaw, 8000 Hz, mono, 64 kb/s
Must supply at least one output file

Note the reference to the video file's frame rate, indicated in the example above as 23.95 fps(r), in other words, 24-ish Frames per Second. In newer versions of ffmpeg, this framerate is referred to less intuitively as 23.95 tb(r).

 
If we stuff this string into a local called movie_info we can retrieve the files dimensions, duration and framerate:
[
//Establish if the file is Video, Audio, or Unsupported:
	if((string_findregexp:#movie_info, -find='Video') -> size > 0);
		local('filetype'='Video');
	else((string_findregexp:#movie_info, -find='Audio') -> size > 0);
		local('filetype'='Audio');
	else;
		local('filetype'='Unknown');
	/if;

//Declare variables for Video-Specific details
	local('dimensions'	= string);
	local('width'		= string);
	local('height'		= string);
	local('fps'		= string);
	
	if:(#filetype [h1] 'Video');
	
		local:'dimensions_temp'	=  (string_findregexp: #movie_info, -find='Video: [^x]*x[^,]*');
		local:'fps_temp'	=  (string_findregexp: #movie_info, -find='Video:[^t]* tb\\(r\\)|Video:[^f]* fps');
		
		#fps = (#fps_temp -> get:1 -> split:' ');
		local:'fps_x'=(#fps -> size);
		#fps = (#fps -> get:(#fps_x - 1));
		
		local:'dimensions_array' = (array);
		
		if:(#dimensions_temp -> size > 0);
			#dimensions_array = (string_findregexp:(#dimensions_temp -> get:1), -find='(\\d+)x(\\d+)');
		/if;
		
		if:(#dimensions_array -> size [h1] 3);
			#dimensions = (#dimensions_array -> get: 1);
			#width = (#dimensions_array -> get: 2);
			#height = (#dimensions_array -> get: 3);
		/if;
	/if;

//Declare variables for general audio/video details
	local:'duration_temp' = (string_findregexp: #movie_info, -find='Duration: [^ ,]*');
	local:'duration_display' = string;
	local:'duration' = decimal;
	local:'seconds' = decimal;
	local:'halftime' = duration;

	if:(#duration_temp -> size > 0);

		#duration_display = (string_removeleading:(#duration_temp -> get:1), -pattern='Duration: ');
		#seconds = #duration_display -> split:':' -> last;
		#duration_display=(duration:#duration_display);

//calculate duration in seconds with decimal value to accurately grab frame interval rate
		#duration = (#duration_display->second);
		#duration = (#duration - (integer:#seconds));
		#duration = (decimal:#duration) + (decimal:#seconds);
		#halftime = (duration(integer(#duration / 2)));

	/if;
]
Using the example, the above code will give us the following locals:

#filetype: 			Video
#duration: 		24.4
#duration_display: 	00:00:24
#seconds: 		24.4
#halftime: 		00:00:12
#dimensions: 		320x240
#width: 			320
#height: 			240
#fps: 			23.95

NOTE: Instead of using PassThru, I have started using OS_Process for some of my cli stuff - but unfortunately OS_Process causes problems when trying to call ffmpeg, in that OS_Process should be explicitly told to retrieve the error, rather than the output, from the ffmpeg command.

Converting Video to Flash (FLV)

The next big requirement will be to display the video in a browser and to that end, we convert it to Flash video format, FLV. Again, PassThru and FFmpeg come to the rescue. Note that we re-use some of the locals from the above example. Also, the .flv file does not exist yet, and you will obviously use vars or locals to set the name of the file.

	local('passthrucommand' = ('/usr/local/bin/ffmpeg -i /path/to/myfile.mov '));
	#passthrucommand += (' -ar 22050 -ab 32 -f flv -s '+#width+'x'+#height);
	#passthrucommand += (/path/to/myfile.flv');
	passthru(#passthrucommand);

 

NOTE: ffmpeg will choke on frame sizes that are not a multiple of 2, so make sure to cast the width and height values (if different from the original) to the nearest even number! You could achive this as follows:

[
#width % 2 > 0 ? #width += 1;
#height % 2 > 0 ? #height += 1;
]

Creating a Thumbnail

FFmpeg can extract single frames from a video stream, storing them in still image format. In our example we calculated a "half-time" value for the video file, and we now use this local to grab a frame from the middle of the clip and turn it into a thumbnail:
 

	Local('PassThruCommand2' =  ('/usr/local/bin/ffmpeg -y -i /path/to/myfile.mov '));
	#PassThruCommand2 += ('-vframes 1 -ss '+(duration(#halftime)));
	#PassThruCommand2 += (' -an -vcodec png -f rawvideo ');
	#PassThruCommand2 += (' -s '+#width+'x'+#height+' /path/to/myfile.png');
	PassThru(#PassThruCommand2);

Make sure to read the note on frame sizes above...!

Playing the Video in a Web Browser

Last but not least, we want to play our video file on a web page similar to YouTube and Google Video. For this, we need to embed a Flash Video player in the webpage. I use FlowPlayer, which is available from http://flowplayer.sourceforge.net/. That page provides ample documentation on how to implement and customise FlowPlayer, all I need to say is that its simplicity itself. The most basic implementation requires no more than the presence of the flowplayer.swf file where it can be accessed by the relevant webpage, plus a chunk of code to embed the object and tell the flowplayer.swf file where to get its video file from:

<object type="application/x-shockwave-flash" data="/path/to/FlowPlayer.swf" width="[#width]" height="[#height]" id="FlowPlayer">
	<param name="allowScriptAccess" value="sameDomain" />
	<param name="movie" value="/path/to/FlowPlayer.swf" />
	<param name="quality" value="high" />
	<param name="scale" value="noScale" />
	<param name="wmode" value="transparent" />
	<param name="flashvars" value="config={ videoFile: '/webroot/path/to/myfile.flv', loop: false, autoPlay: false }" />
</object>

 

Note that the path to the .flv file must be from the website root, whereas the path to FowPlayer may be relative (thanks again, Rich).
 
Thats all there is to it :-)
 

Credits and Links

 
These instructions are basically a compilation of a lot of web crawling to find those bits that work for me. The relevant links are
 
 
 
 
 
The ffmpeg home page is at ffmpeg.mplayerhq.hu.
 
The LAME mp3 encoder is on SourceForge.
 
The faad encoder is on debian.org.
 
 
Many thanks to Rich Fortnum of Viaduct Productions in Toronto, Canada, for addressing the Quicktime/iMovie codec issues.
 
Many thanks also to Chris Waltham on the OS X Server mailing list for supplying the solution to build on OS X Server 10.5.
 

Author: Pier Kuipers
Created: 1 Mar 2007
Last Modified: 16 Mar 2011

Please note that periodically LassoSoft will go through the notes and may incorporate information from them into the documentation. Any submission here gives LassoSoft a non-exclusive license and will be made available in various formats to the Lasso community.

LassoSoft Inc. > Home

 

 

©LassoSoft Inc 2015 | Web Development by Treefrog Inc | PrivacyLegal terms and Shipping | Contact LassoSoft