 |
<!–
–>
|
Level: Intermediate
Jack D Herrington (jherr@pobox.com), Senior Software Engineer, Leverage Software Inc.
23 Oct 2007
With the advent of widely available broadband, media, movies, images, and sound drive the Web 2.0 revolution. Learn to combine media with technologies such as PHP and Asynchronous JavaScript™ + XML (Ajax) to create a compelling experience for your customers.
Ask people which site is most representative of the new wave of applications on the Web, and most will answer YouTube. It’s a site that has not only embraced new technology in a compelling way but changed how we view media and our relationship to it. Major stories can break on YouTube well before they appear on traditional media outlets, and when they don’t, YouTube acts like one big TiVo for the world.
Media sharing is changing the world, and from a technology standpoint, it’s not hard to do. This article shows how to put an Ajax front end on a simple Web video-hosting application.
Simple video selection
I start with a Web site that holds a movie list and uses that list to select from one of several movies—a site on which you can change movies without actually moving from one page to another. Listing 1 shows the code for the page.
Listing 1. index.html
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<div id="movieHost">
</div>
<div id="movieList">
</div>
<script>
function setMovie( url )
{
$('movieHost').innerHTML = '';
var elEmbed = document.createElement( 'embed' );
elEmbed.src = url;
$('movieHost').appendChild( elEmbed );
}
new Ajax.Request( 'movies.xml', {
method: 'get',
onSuccess: function( transport ) {
var movieTags = transport.responseXML.getElementsByTagName( 'movie' );
$('movieList').innerHTML = '';
var bFirst = true;
for( var b = 0; b < movieTags.length; b++ ) {
var url = movieTags[b].getAttribute('url');
var title = movieTags[b].getAttribute('title');
if ( bFirst )
{
setMovie( url );
bFirst = false;
}
var html = '<a href="javascript:void setMovie(\''+url+'\');">';
html += title+'</a><br/>';
$('movieList').innerHTML += html;
}
}
} );
</script>
</body>
</html>
|
This page uses the excellent Prototype.js JavaScript library to make an Ajax request of the movies.xml data source. When the data is returned, the code finds all the movie tags using the getElementsByTagName() method. Then, for each movie tag, the code retrieves both the URL and the title. If the retrieved tag is for the first movie in the list, the script starts to play that movie right away. Otherwise, it adds an anchor tag, which acts as a movie selector to the movieList <div> tag.
This movie selector anchor calls the setMovie() function to start a particular movie. To start a movie, I simply set the contents of the movieHost <div> tag to empty, which removes any previous movie. Then, I set the contents to an <embed> tag whose URL is specified by the movie list.
The <embed> tag is the simplest way to get a movie onto a page, but it can have issues between browsers. Another option is to use both an <object> and an <embed> tag. (Yet another method is to use Macromedia Flash Player: I get into that a little later in the article.)
In this simple example, the movies.xml file is just a flat file with some references to short home movies of mine. Listing 2 shows the file.
Listing 2. movies.xml
<movies>
<movie url="spider.mov" title="Spider" />
<movie url="swing.mov" title="Swing Set" />
<movie url="water.mov" title="Water Splash" />
</movies>
|
When I navigate to the page, I see the something like Figure 1.
Figure 1. The simple movie list page

The movie is at the top of the page, being played by the <embed> tag, and a list of available movies appears below it. If I click any of those links, the movie changes to the one I clicked.
Obviously, this system isn’t going to scale particularly well to large video repositories, so I need a way to do some searching on the movie list.
Searchable movie lists
To add search functionality, I need to add a search box, which you can see in Listing 3. I’ve also added a search input field named q.
Listing 3. Add search functionality
<html>
<head>
<script src="prototype.js"></script>
</head>
<body>
<table><tr><td valign="top">
<input type="text" id="q" onkeyup="search()">
<div id="movieList">
</div>
</td><td valign="top">
<div id="movieHost">
</div>
</td>
</tr></table>
<script>
function setMovie( url )
{
$('movieHost').innerHTML = '';
var elEmbed = document.createElement( 'embed' );
elEmbed.src = url;
$('movieHost').appendChild( elEmbed );
}
function search()
{
new Ajax.Request( 'search.php?q='+escape($('q').value), {
method: 'get',
onSuccess: function( transport ) {
var movieTags = transport.responseXML.getElementsByTagName( 'movie' );
$('movieList').innerHTML = '';
var bFirst = true;
for( var b = 0; b < movieTags.length; b++ ) {
var url = movieTags[b].getAttribute('url');
var title = movieTags[b].getAttribute('title');
if ( bFirst )
{
setMovie( url );
bFirst = false;
}
var html = '<a href="javascript:void setMovie(\''+url+'\');">';
html += title+'</a><br/>';
$('movieList').innerHTML += html;
}
}
} );
}
</script>
</body>
</html>
|
On the key-up event, I specified that the search() method should be called. That search() method is like the Ajax.Request call, with the exception that it now passes along the query string to a page called search.php. The search.php script returns the same XML format as the original, so the code that does the XML parsing doesn’t need to change.
I admit that a search() function on key-up is a bit too responsive for my taste. Ideally, the system would wait for a second or so before running the search so that I could finish a complete search text without having the list flicker in the meantime. You can easily implement such behavior by using the window.setTimeout() method.
Listing 4 shows the revised search.php script.
Listing 4. search.php
<?php
header( 'content-type: text/xml' );
$movies = array();
$movies['spider.mov'] = 'Spider';
$movies['swing.mov'] = 'Swing Set';
$movies['water.mov'] = 'Water Splash';
?>
<movies>
<?php
foreach( $movies as $k => $v ) {
if ( strlen( $_GET['q'] ) > 0 &&
preg_match( '/'.$_GET['q'].'/i', $v ) ) {
?>
<movie url="<?php echo($k) ?>" title="<?php echo($v) ?>" />
<?php
} }
?>
</movies>
|
At the top of the script, I create an array that holds all the movies. For simplicity’s sake, I hard-coded the movies. But in reality, these elements are likely to come from a database of movie listings.
The code then iterates through the list and applies a regular expression of the search query to each movie title. When they match, a <movie> tag is output with the URL and the name.
When I start the page and type s, I get the page shown in Figure 2.
Figure 2. The movie query page with a simple query

If I press Delete and type water, I get the page shown in Figure 3.
Figure 3. The movie query page looking for “water” movies

While the point of this article is mainly to show how you could create a front end using Dynamic HTML (DHTML) and Ajax, there’s a lot more to creating a video sharing site.
Video sharing basics
Jumping from the practical to the more theoretical for a moment, let me talk about how to handle some of the trickier video-sharing issues. There are three main issues to cover:
- How to store and stream the video
- How to handle different video formats
- How to get thumbnail images and video information from the uploaded files
Video storage is a real problem—particularly for small applications. Video files are large, so expensive hardware is required to store them. And there are bandwidth charges for feeding them down the wire to your customers. You could buy your own equipment and put it in a hosting facility. Or you could use a service such as S3 from Amazon, which allows you to upload any material (database backups, images, movies, and so on) and feed them out of the Amazon datacenters for a reasonable cost. It’s probably worth looking into one of these services before bankrolling a datacenter roll-out.
The next issue—video formats—presents an interesting challenge. Many video formats exist, and not all players handle all formats. In fact, most players handle just their video format of choice. To make it easier on the customer, it’s probably best to standardize on a particular format, and then convert all the incoming video into that format. One particularly handy tool for doing that is a command-line application called FFmpeg. Not only can it convert from one video format to another, but it can also take frame snapshots and thus provide a thumbnail of the video before customers view it.
The choice of which video format to standardize on can be complex. Flash video is the clear winner at the moment, but Windows Media®, particularly with the release of Microsoft Silverlight (formerly WPF/Everywhere), is gaining ground. FFmpeg can export almost any movie to the Flash video format, which is compelling. And there are several free and open source Flash movie players that you can easily embed in your site. You can combine those players with the code above to make a complete end-to-end video-sharing solution with an Ajax front end.
But video isn’t the only thing going on with the Web: Image sharing is also important.
Slide shows
Listing 5 shows a simple DHTML-based slide show that sources its data from an XML file.
Listing 5. index.html
<html>
<head>
<script src="prototype.js"></script>
</head>
<body bgcolor="black">
<div style="text-align:center;">
<img id="imgItem" src="" style="display:none;"><br>
<div id="imgTitle" style="color:white;font-family:arial;font-size:24pt;">
</div>
</div>
<script>
var g_images = [];
var g_slideIndex = 0;
function showSlide()
{
$('imgTitle').hide();
$('imgItem').hide();
var height = 600;
var width = ( height / g_images[ g_slideIndex ].height ) *
g_images[ g_slideIndex ].width;
$('imgItem').src = g_images[ g_slideIndex ].src;
$('imgItem').width = width;
$('imgItem').height = height;
$('imgTitle').innerHTML = g_images[ g_slideIndex ].title;
$('imgTitle').show();
$('imgItem').show();
g_slideIndex++;
if ( g_slideIndex >= g_images.length )
g_slideIndex = 0;
}
new Ajax.Request( 'images.xml', {
method: 'get',
onSuccess: function( transport ) {
var imageTags = transport.responseXML.getElementsByTagName( 'image' );
for( var b = 0; b < imageTags.length; b++ ) {
g_images.push( {
src: imageTags[b].getAttribute('src'),
title: imageTags[b].getAttribute('title'),
width: imageTags[b].getAttribute('width'),
height: imageTags[b].getAttribute('height')
} );
}
showSlide();
window.setInterval( showSlide, 5000 );
}
} );
</script>
</body>
</html>
|
 |
|
The code is based on the Prototype.js JavaScript library. It uses the Ajax.Request object to get the list of images to show. The returned XML code is then parsed to get the URL as well as the width, height, and title of each image. The showSlide() function is then called to get the slide show ball rolling. A timer is set to go off every five seconds to move the show onto the next slide.
The slide show is implemented by having one <image> tag for the current image and one <div> tag for the title. The slide show simply hides the current image and title, sets the source of the image and the text of the title to the new slide contents, and then shows them. If you want something that fades in and out, I recommend using the Effects classes in the Scriptaculous library, which is built on Prototype.js.
Listing 6 shows the data images file.
Listing 6. images.xml
<images>
<image src="images/megan1_875_700.jpg" title="Megan" width="875" height="700" />
<image src="images/oso1_875_700.jpg" title="Oso 1" width="875" height="700" />
<image src="images/oso2_873_700.jpg" title="Oso 2" width="873" height="700" />
</images>
|
This one is hard-coded, but you can just as easily generate the XML code using a PHP script. The slide show is shown in progress in Figure 4.
Figure 4. The simple slide show

Note: I previously published a much more elaborate version of the slide show (see Resources for a link). This one differs in that it uses the Prototype.js library and is much simpler in its transitions between slides.
Conclusion
Sites like Flikr and YouTube show just the tip of the full potential for media on the Web. This article provides some easy implementations of video and image browsing that you can use in your own project. If it works for you, please let me know by joining the developerWorks Ajax forum (see Resources) to talk about your success.
Download
| Description |
Name |
Size |
Download method |
| Sample code |
x-ajaxxml7-media.zip |
1090KB |
HTTP |
About the author
|
Trackback this post | Subscribe to the comments via RSS Feed