Red5: A video-on-demand Flash Server

Plone does not provide a responsive user experience out of the box. This is not because the system is slow, but because it simply does (too) much. It does a lot of security checks and workflow operations, handles the content rules, does content validation, and so on. Still, there are some high-traffic sites running with the popular Content Management System. How do they manage?

"All Plone integrators are caching experts." This saying is commonly heard and read in the Plone community. And it is true. If we want a fast and responsive system, we have to use caching and load-balancing applications to spread the load.

The article discusses a practical example. We will set up a protected video-on-demand solution with Plone and a Red5 server. We will see how to integrate it with Plone for an effective and secure video-streaming solution.

The Red5 server is an open source Flash server. It is written in Java and is very extensible via plugins. There are plugins for transcoding, different kinds of streaming, and several other manipulations we might want to do with video or audio content. What we want to investigate here is how to integrate video streams protected by Plone permissions.

(For more resources on Plone, see here.)

Requirements for setting up a Red5 server

The requirement for running a Red5 Flash server is Java 6. We can check the Java version by running this:

$ java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-9M3125)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)

The version needs to be 1.6 at least. The earlier versions of the Red5 server run with 1.5, but the plugin for protecting the media files needs Java 6. To get Java 6, if we do not have it already, we can download it from the Sun home page. There are packages available for Windows and Linux.

Some Linux distributions have different implementations of Java because of licensing issues. You may check the corresponding documentation if this is the case for you.

Mac OS X ships with its own Java bundled. To set the Java version to 1.6 on Mac OS X, we need to do the following:

$ cd /System/Library/Frameworks/JavaVM.framework/Versions
$ rm Current*
$ ln -s 1.6 Current
$ ln -s 1.6 CurrentJDK

After doing so, we should double-check the Java version with the command shown before.

The Red5 server is available as a package for various operating systems. In the next section, we will see how we can integrate a Red5 server into a Plone buildout.

A Red5 buildout

Red5 can be downloaded in several different ways. As it is open source, even the sources are available as a tarball from the product home page. For the buildout, we use the bundle of ready compiled Java libraries. This bundle comes with everything needed to run a standalone Red5 server. There are startup scripts provided for Windows and Bash (usable with Linux and Mac OS X). Let's see how to configure our buildout.

The buildout needs the usual common elements for a Plone 3.3.3 installation. Apart from the application and the instance, the Red5-specific parts are also present: a fss storage part and a part for setting up the supervisor.

newest = false
parts =
extends =
versions = versions
find-links =

There is nothing special in the zope2 application part.

recipe = plone.recipe.zope2install
fake-zope-eggs = true
url = ${versions:zope2-url}

On the Plone side, we need—despite of the fss eggs—a package called unimr.red5.protectedvod. This package with the rather complicated name creates rather complicated one-time URLs for the communication with Red5.

recipe = plone.recipe.zope2instance
zope2-location = ${zope2:location}
user = admin:admin
http-address = 8080
eggs =
zcml =

First, we need to configure FileSystemStorage.FileSystemStorage is used for sharing the videos between Plone and Red5. The videos are uploaded via the Plone UI and they are put on the filesystem. The storage strategy needs to be either site1 or site2. These two strategies store the binary data with its original filename and file extension. The extension is needed for the Red5 server to recognize the file.

recipe = iw.recipe.fss
zope-instances =
storages =
global /
site /site site2

The red5 part downloads and extracts the Red5 application. We have to envision that everything is placed into the parts directory. This includes configurations, plugins, logs, and even content. We need to be extra careful with changing the recipe in the buildout if running in production mode. The content we share with Plone is symlinked, so this is not a problem. For the logs, we might change the position to outside the parts directory and symlink them back.

recipe =
url =

The next part adds our custom application, which handles the temporary links used for protection, to the Red5 application. The plugin is shipped together with the unimr.red5.protectedvod egg we use on the Plone side. It is easier to get it from the Subversion repository directly.

recipe = infrae.subversion
urls = red5-webapp

The red5-protectedVOD part configures the protectedVOD plugin. Basically, the WAR archive we checked out in the previous step is extracted. If the location of the fss storage does not exist already, it is symlinked into the streams directory of the plugin. The streams directory is the usual place for media files for Red5.

recipe = iw.recipe.cmd
on_install = true
on_update = false
cmds =
mkdir -p ${red5:location}/webapps/protectedVOD
cd ${red5:location}/webapps/protectedVOD
jar xvf ${red5-webapp:location}/
cd streams
if [ ! -L ${red5:location}
/webapps/protectedVOD/streams/fss_storage_site ];
then ln -s ${buildout:directory}/var/fss_storage_site .;

The commands used above are Unix/Linux centric. Until Vista/ Server 2008, Windows didn't understand symbolic links. That's why the whole idea of the recipe doesn't work. The recipe might work with Windows Vista, Windows Server 2008, or Windows 7; but the commands look different

Finally, we add the Red5 server to our supervisor configuration. We need to set the RED5_HOME environment variable, so that the startup script can find the necessary libraries of Red5.

recipe = collective.recipe.supervisor
programs =
30 instance2 ${instance2:location}/bin/runzope ${instance2:location}
40 red5 env [RED5_HOME=${red5:location} ${red5:location}/]
${red5:location} true

After running the buildout, we can start the supervisor by issuing the following command:


The supervisor will take care of running all the subprocesses. To find out more on the supervisor, we may visit its website. To check if everything worked, we can request a status report by issuing this:

bin/supervisorctl status
instance RUNNING pid 2176, uptime 3:00:23
red5 RUNNING pid 7563, uptime 0:51:25

(For more resources on Plone, see here.)

Using Red5

To use Plone together with the Red5 server, we have to install two add-ons in our site: iw.fss (FileSystemStorage) and unimr.red5.protectedvod setup. The FileSystemStorage product allows Plone to store binary data on the filesystemrather than in the ZODB. The protectedvod product does two things. It provides an API to create temporary media links accessing the Red5 server, and it provides a simple content type. This content type Red5Stream is similar to the File content type of Plone. It has a title, a description, and a binary component. This binary component is stored on the filesystem with the help of the FileSystemStorage. The directory of the filesystem where the data is put is accessible from Plone and Red5. If a Red5Stream content object is viewed, the data doesn't come from Plone or the FileSystemstorage, but is streamed from the Red5 server with a specially created temporary link.

On the Plone side, the Red5 plugin can be configured with the following values:

  • red5_server_url: The complete URL of the protectedVOD plugin. The default setting assumes the Zope server and the Red5 server run on the same machine—rtmp://localhost/protectedVOD.
  • ttl: The time to live in seconds. This value sets how long a generated video link is valid. The default value is 60.
  • secret: The password that is shared between Plone and the Red5 server. Defaults to top_secret.

The secret on the Red5 side is set in the file, which is stored in the WEB-INF directory of the protectedVOD plugin. The full path starting from the buildout base is parts/red5/webapps/protectedVOD/WEB-INF/ The password is set with the sharedSecret property like this:

webapp.virtualHosts=*, localhost, localhost:5080,

The temporary URL

The dynamically signed streaming URL takes the following format:


The first part, rtmp://<red5_hostname>/protectedVOD, is defined by the red5_server_url property of the Plone configuration. The other parts are added as follows:

  • The rtmp protocol (Real Time Messaging Protocol) is a proprietary network protocol developed by Adobe systems to transfer audio, video, and other data to a Flash player over the Internet.
  • The baseURL is the relative path of the media content in the FileSystemStorage.
  • The signature is calculated as follows: + baseUrl + streamName + client ip + expires).hexdigest(). The secret is specified in the configuration of Plone and must match the value on the Red5 server. More information on the hmac format can be found in the documentation of the corresponding Python module.
  • expires is a timestamp given as a hex string. This is the number of seconds since January 1, 1970, 00:00:00 in hexadecimal notation plus the time to live (ttl) configured in Plone.
  • The streamName is the name of the video file, for example: dancing_clouds.flv, funmovie.flv, or rocknroll.mp4. This part of the URL is optional.

An example URL is:


In this example, the Zope server and the Red5 server are on the same machine. The host in the URL points to localhost. The FileSystemStorage path is the standard path for a Plone site called site fss_storage_site and the Flash video is called kleinesvideo.flv. The hmac signature is 27d8cbebbb446e95d158018e0e9d9c2f and the expires timestamp is 4b264f22. This timestamp corresponds to the date: "Mon Dec 14 15:43:46 2009".

The Red5Stream content type

The unimr.red5.protctedvod package comes with its own content type. The content type is called Red5Stream, but there is nothing special about it. It inherits the schema and the class from ATFile of ATContentTypes. All it does is override the storage of the file field to make use of the FileSystemStorage. Also, it protects the default and the download view with a custom permission DownloadRed5Stream. This has the following effect: Users with a "view" permission can view the content by the streaming technique of the Red5 server, but are not allowed to download the content. By default, only clients with an owner or a manager role have the Download Red5Stream permission to download the content from Plone.

Red5StreamSchema = ATFileSchema.copy()
file_field = Red5StreamSchema['file'] = FileSystemStorage()
file_field.read_permission = DownloadRed5Stream
class Red5Stream(ATFile):
portal_type = 'Red5Stream'
archetype_name = 'Red5Stream'
inlineMimetypes= tuple()
schema = Red5StreamSchema
security = ClassSecurityInfo()
security.declareProtected(DownloadRed5Stream, 'index_html')
security.declareProtected(DownloadRed5Stream, 'download')

The content type comes with a custom view—red5stream_view. This view includes an instance of the flowplayer used for playing the stream fetchedfrom the Red5 server.

With the Flowplayer, it is possible to play FLV, H.264, and MP4-encoded video files, as well as MP3-encoded audio files.

Visual editor integration

To make it easier to present Red5Streams within a Plone content item, unimr.red5.protectedvod comes with a dedicated Kupu paragraph style for video integration into rich text. The technique is similar to that we have seen for collective.flowplayer.

  • We insert the image we want to use as a splash image. We insert this "inline" (rather than left/right floating), preferably in its own paragraph. Alternatively, we can also enter some text as a placeholder.
  • We select the image (or placeholder text) and make it an internal link to a red5stream content object we want to play.
  • We select the Red5 Stream style from the styles dropdown.

We use this feature as shown in this screenshot:

Troubleshooting Red5

There are some problems we might run into while setting up a Red5 server.

Java version issues

First, the Java version has to be at least 1.6.0. We have discussed already how to check the Java version and how to upgrade it, if our dependency is not fulfilled.

Checking the logs

A good starting point for troubleshooting is always the logs. In our buildout environment, the logs are located in parts/red5/log. There are two access logs, an error log, a general log, and a log of our protectedVOD plugin. A successful request of a video from Plone to Red5 looks like this in the protectedVOD.log:

2009-12-18 14:38:37,167 [main] DEBUG root -
Starting up context protectedVOD
2009-12-18 14:40:05,911 [NioProcessor-1] INFO unimr.vod.hmac.
PlaybackSecurityHmac - getSignMap - {expires=
4b2b866e, name=kleinesvideo.flv, path=/fss_storage_site/kleinesvideo.
e5004b8946, ip=}
2009-12-18 14:40:06,689 [NioProcessor-1] DEBUG unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - localSignature
2009-12-18 14:40:06,690 [NioProcessor-1] DEBUG unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - remoteSignature
2009-12-18 14:40:06,690 [NioProcessor-1] DEBUG unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - true

Network and time issues

The Red5 server binds to the IPv6 interface, if it finds one. Zope binds to an IPv4 interface and uses this information for the hash construction. This may lead to problems because the hash construction will differ on the two systems and the URLs of Plone are not accepted. We can spot this behavior in the protectedVOD.log:

2009-12-18 16:48:01,985 [NioProcessor-1] INFO unimr.vod.
hmac.PlaybackSecurityHmac - getSignMap - {expires=4b2ba46b,
name=kleinesvideo.flv, path=/fss_storage_site/kleinesvideo.flv/, signa
2009-12-18 16:48:02,194 [NioProcessor-1] DEBUG unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - localSignature
2009-12-18 16:48:02,194 [NioProcessor-1] DEBUG unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - remoteSignature
2009-12-18 16:48:02,202 [NioProcessor-1] INFO unimr.vod.hmac.
PlaybackSecurityHmac - isPlaybackAllowed - false: remote signature

Instead of using an IPv4 address ( for example), the Red5 sever uses an IPv6 address (0:0:0:0:0:0:0:1%0 in this case, which is the IPv6 equivalent of There is a solution to this issue, which occurs on a default Mac OS X installation and probably on other Unix systems too. We simply have to deactivate IPv6, which is probably not used anyway. To switch off IPv6 for localhost, we have to comment out the IPv6 addresses in the /etc/hosts configuration file.	                localhost broadcasthost
#::1 localhost
#fe80::1%lo0 localhost

After doing this, we have to restart Red5 server to bind to the IPv4 interface and the hash construction should work as expected. With supervisor, the command is:

bin/supervisorctl restart red5

If we run the Red5 server and the Zope server on different machines, we have to make sure the time of the both servers is in sync. Otherwise, the link may be outdated before it is called. The time on Unix-based systems can be shown with the date command:

$ date
Mo 14 Dez 2009 07:48:15 CET

A good service to keep the time and date in sync over several servers is NTP (Network Time Protocol).

Running Red5 server in the foreground mode

Sometimes it is necessary to run the Red5 server in the foreground mode to check for output or to see if it starts at all. If it is running already, we have to stop it first with the supervisor:

bin/supervisorctl stop red5

The Red5 server needs to be started from the application directory or it needs the environment variable RED5_HOME set to this directory before starting. Let's change the directory now. There are a couple of scripts available for interacting with the Red5 server. The main start script is (for Linux, Mac OS X, and other Unix flavors) and it is red5.bat for Windows operating systems. For debugging purposes, we may use A successful start looks like this (only the relevant parts are shown):

cd parts/red5
Starting Red5
Listening for transport dt_socket at address: 8787
Red5 root: /Users/tom/red5-buildout/parts/red5
Configuation root: /Users/tom/red5-buildout/parts/red5/conf
Root: /Users/tom/red5-buildout/parts/red5
Deploy type: bootstrap
Logger name for context: protectedVOD
Context logger config file: logback-protectedVOD.xml
Adding logger context: protectedVOD to map for context: protectedVOD
[INFO] [Launcher:/protectedVOD] org.springframework.beans.factory.
config.PropertyPlaceholderConfigurer - Loading properties file from
ServletContext resource [/WEB-INF/]
[INFO] [Launcher:/protectedVOD] org.springframework.beans.factory.
support.DefaultListableBeanFactory - Pre-instantiating singletons in org.
7f3: defining beans [placeholderConfig,web.context,web.scope,web.handl
er,streamPlaybackSecurity,streamFilenameGenerator,org.springframework.]; parent: org.
Bootstrap complete


The main purpose of this application is to serve streamed media data. We created a plugin on the Red5 side and on the Plone side, we created a video-on-demand solution that allows the protection of video data by creating temporary links for accessing the streams. in short, we discussed how to install, configure, and use the Red5 Flash server for streaming the protected videos managed by Plone on demand.

Further resources on this subject:





You've been reading an excerpt of:

Plone 3 Multimedia

Explore Title