Posts Tagged ‘Video’

Using Drupal to deliver video

Colin Calnan | Tuesday, December 22nd, 2009

There are many ways to skin the cat when it comes to putting video on a Drupal site. I’ve tried and tested quite a few methods since my first introduction to Drupal 2 years ago. I’ve used Embedded Media Field as well as Video Filter but finally settled on the combination of FileField with JWPlayer or Flowplayer and in some cases the Media Mover Module for moving files to Amazon S3 storage. I’m going to use our recent launch of the CCPA website as a case study for how we currently handle video delivery. So let’s dissect this a little.

Uploading files

The video files need to be uploaded before we display them. This is best achieved using the wonderful Filefield Module. This is quite a simple yet powerful module developed/maintained by Lullabot, Nate Haug (quicksketch), whom I’ve had the pleasure of being trained by at one of their excellent Drupal Theming workshops. Once you install and enable the module you then add a new CCK field, of type “filefield”. In our case we have a content type called “Multimedia”. We add the field to this content type. You then need to configure the following:

1. Permitted upload file extensions

In most cases this is relatively straightforward, it’s just one file type. If you’re using JWPlayer or Flowplayer it will be FLV. Both these players are built to play Flash Video files (FLV). If you have Quicktime MOV’s or AVI’s that you want to upload then you’ll need to consider different options for playing video. For the purpose of this case study we’re just uploading FLV files.

2. File size restrictions

It’s very important that you set these, otherwise you may end up with users trying to upload 200MB videos, not a very good idea. I set this low as a learning feature for clients. Any reasonably long FLV file that is over 40MB is probably not optimized as well as it should be.

3. Path Settings

I like to keep all files that admin/editor users upload in a folder called uploads so that it’s easy to manage them later if they need to be exported etc.

File Field

Multimedia File Field Settings

Create a placeholder image

Most video players require some sort of poster/placeholder image to display before the video plays. In this case I created another FileField for the placeholder image. We’ll use that later on in conjunction with the ImageCache module to achieve our desired results.

Moving Files to Amazon S3

We’ve been using Amazon S3 for storing video files on quite a number of sites recently. One reason is that we were looking for a location off the webserver that could deliver the video, without impacting the performance of the server, so that in the event of a traffic spike the webserver wouldn’t fall over. We could also have used Amazon EC2 or another CDN service for this, however as most of our clients have a very regional (BC) audience. Most CDN’s have nodes in various locations across the US and Europe and this would have served no real improvement as the nearest cached version will always be in the same place for everyone.

So if they’re uploading the files directly to the Drupal site, how to the files get delivered from Amazon S3. That’s where the Media Mover module comes in. This module has many purposes, but for our needs it simply harvests all the files uploaded via the “Multimedia” content type and moves those files to Amazon S3 so that we can deliver them from there.

Download, install and enable the Media Mover module. You’ll also need an S3 account and will need to set that up via the module setting page. You then need to add a Configuration via https://www.yoursite.ca/admin/build/media_mover/add.

Media Mover has 4 actions which it performs on your files:

  • Harvest – Define/collect the files you want to perform actions on
  • Process – Perform certain actions on the files
  • Storage – Where to store files once the actions have been carried out
  • Complete – Final actions to perform on the files

So in this case we just want to harvest all Multimedia files and store them on Amazon S3.

So for clarification here Media Mover does NOT MOVE the files to Amazon S3, it simply COPIES them over to S3 and the original files remain on your server.

Media Mover Settings

Media Mover Settings

Delivering the moved Video files

So this is where the Drupal theming trickery comes in. Flowplayer and JWPlayer are both Flash based FLV video players than can be called using Javascript and that’s exactly what I do on this site. In plain english this is what happens:

  1. Output the placeholder image to screen as a link.
  2. Use Javascript so that when the user clicks on the image the video plays.
  3. Deliver the video from the file on Amazon S3 rather than the file on the webserver (Drupal site).

We need to modify three files to achive the above:

  • template.php
  • multimedia.js (a newly created JS file)
  • node-multimedia.tpl.php (a custom template file for all multimedia types)

template.php file

Setting up all the variables we’re going to need to use as well as making the javascript available

if($variables['field_file'][0]['view']) { //If there is a file and there is something to display...
  if ($variables['field_aspect_ratio'][0]['value']) { //Aspect ratio handling
    $variables['aspect_ratio'] = $variables['field_aspect_ratio'][0]['value'];
  } else {
  $variables['aspect_ratio'] = 'normal';
  }
  $variables['multimedia_type'] = 'video'; //Set the type of multimedia - we also have audio and interactive...
  custom_theme_get_media_mover_files($variables['field_file'][0], $variables['media_mover'][3]); //Set the filepath to the media moved filepath...
  drupal_add_js(array('videoplayerpath' => path_to_theme() .'/scripts/plugins/flowplayer/flowplayer-3.1.1.swf'), 'setting'); //Set a JS variable to retrieve later...
  drupal_add_js(path_to_theme() .'/scripts/plugins/flowplayer/example/flowplayer-3.1.1.min.js', 'theme'); //Call the player...
  drupal_add_js(path_to_theme() .'/scripts/multimedia.js', 'theme');//Call the custom JQuery to handle creating the player...
}
 
/**
 * A function that takes a file object and a media_mover element array and set the file path to
 * its media moved path on Amazon S3 or wherever it moved to.
 *
 * It uses the unique file_id identifier to match file with media_mover file.
 *
 * $file = $variables['file_image'][0];
 * $media_mover = $variables['media_mover'][{id of media mover configuration}];
 *
 * @param 		&$file A Drupal file array (by reference)
 * @param 		$media_mover A media_mover file/element array
 */
function custom_theme_get_media_mover_files(&$file, $media_mover) {
  if(module_exists('media_mover_api') && $media_mover) { // If media mover is installed...
    foreach($media_mover as $media) { // Loop through each media_moved file...
      if($media['fid'] == $file['fid']) { // If they match (file id is a unique identifier...
        $file['filepath'] = $media['complete_file']; // Replace the attached file path with the media moved file path...
      }
    }
  }
} // custom_theme_get_media_mover_files()

Let me explain one thing in regards to line 9. I’ve created a custom function and I’m passing

$variables['media_mover'][3]

to my custom function. When you create a Media Mover configuration and map it to a CCK field, it creates an array in $variables to keep track of the Media Mover object. The array is called ‘media_mover’ and the number 3 in this case is the ID of the Media Mover configuration.

node-multimedia.tpl.php

Set up the template. Create a wrapper div with the placeholder image as the background image (this is run through imagecache) and display the play button as a link with the path set to the path of the Amazon S3 file. This link will also have an id attribute of ‘multimedia’. This is necessary as it allows us to attach the player, via Javascript, to this link.

<div id="containing-block">
<div id="video-wrapper" class="<?php print $aspect_ratio;?>">
<div>
     &lt; ?php print l('<img src="/'.path_to_theme().'/images/ccpa-button-play-large.png" alt="Play this video" />', $field_file[0]['filepath'], $options = array('html' => TRUE, 'attributes' => array('id' => 'multimedia', 'class' => $multimedia_type))); ?></div>
</div>
</div>

multimedia.js file

Hook the Flowplayer to the link, with id of ‘multimedia’, that we created in the template.

?View Code JAVASCRIPT
Drupal.behaviors.showMultimedia = function(context) {
  var interactive_path = $('#multimedia').attr('href'); /*Get the path to the video*/
  var interactive_image = $('#multimedia').css('background-image');	/*Get the path to the placeholder image*/
  interactive_image = interactive_image.slice(4,interactive_image.length-1);/*Tidying up the interactive image path*/
 
  if($('#multimedia').hasClass('video')) {/*If the link has a class of video*/
  $('#multimedia').flowplayer( /*Initialize the flowplayer and configure the controls*/
    Drupal.settings.basePath + Drupal.settings.videoplayerpath, /*Path to the player, gotten from temaplate.php*/
    {
      plugins: {
	controls: {
	  stop: true,
	  backgroundColor: '#efefef',
	  backgroundGradient: 'none',
	  borderRadius: '0px',
	  bufferColor: '#d2d6ab',
	  bufferGradient: 'none',
	  buttonColor: '#777777',
	  buttonOverColor: '#99a134',
	  durationColor: '#cccccc',
	  height: 25,
	  opacity: 1.0,
	  progressColor: '#99a134',
	  sliderColor: '#9999999',
	  sliderGradient: 'none',
	  timeBgColor: '#777777',
	  timeColor: '#ffffff',
	  tooltipColor: '#000000',
	  tooltipTextColor: '#ffffff',
	  volumeSliderColor: '#777777',
	  volumeSliderGradient: 'none'
	}
      }
    });
  }
};

I hope that was easy to follow. Now there’s one more thing to cover and that’s Aspect Ratio.

Aspect Ratio

The issue of aspect ratio is very important when figuring out how to display video. Not so recently YouTube switched all video display to the 16:9 ratio thus setting the stage for the proliferation of the widescreen aspect ratio across the web. So how do you allow the user to upload a video and choose it’s aspect ratio. I’m sure there are other ways to do this via Metadata etc, but for our needs on this site I used a CCK field. This is a simple CCK field set with three options:

  1. None (defaults to 4:3)
  2. Normal (4:3)
  3. Widescreen (16:9)
ccpa-aspect-ratio

Aspect Ratio Field Settings

We then check the value of this field in template.php above:

if ($variables['field_aspect_ratio'][0]['value']) { //Aspect ratio handling
    $variables['aspect_ratio'] = $variables['field_aspect_ratio'][0]['value'];
  } else {
  $variables['aspect_ratio'] = 'normal';
  }

and set a variable called ‘aspect_ratio” which we apply as a class to the div wrapping the video in the node-multimedia.tpl.php:

<div id="containing-block">
<div id="video-wrapper" class="<?php print $aspect_ratio;?>">
<div>
     < ?php print l('<img src="/'.path_to_theme().'/images/ccpa-button-play-large.png" alt="Play this video" />', $field_file[0]['filepath'], $options = array('html' => TRUE, 'attributes' => array('id' => 'multimedia', 'class' => $multimedia_type))); ?></div>
</div>
</div>

We have also created image cache presets for the placeholder images to account for both aspect ratios. These are named ‘multimedia_normal’ and ‘multimedia_widescreen’ and these have the appropriate dimensions associated with them:

ccpa-imagecache-presets

Image Cache Presets

So using the amazing article on A List Apart for creating intrinsic ratios for video we use CSS to resize the player based on the aspect ratio chosen by the user.

style.css file

/* -- Multimedia -- */
#containing-block {
  width: 100%;
}
 
#video-wrapper {
  position: relative;
  padding-top: 25px;
  height: 0;
}
 
  #video-wrapper div,
  #video-wrapper embed,
  #video-wrapper object {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
 
  #video-wrapper.normal {
    padding-bottom: 75%;
  }
 
  #video-wrapper.widescreen {
    padding-bottom: 56.25%;
  }
 
  * html #video-wrapper {
    margin-bottom: 45px;
    margin-bot\tom: 0;
  }
 
#video-wrapper #multimedia.audio {
  display:block;
  height:100%;
  margin:1em 0 0 0;
  text-align: center;
  width:100%;
}
 
#video-wrapper #multimedia {
  display:block;
}
 
  #video-wrapper.normal #multimedia img {
    /*margin:118.5px 0 0;*/
    margin:32% 42%;
  }
 
  #video-wrapper.widescreen #multimedia img {
    margin:22% 41%;
  }

And the end result looks something like this http://www.policyalternatives.ca/multimedia/matthew-poverty-and-looking-after-each-other-tough-times. They haven’t added any widescreen content yet, just testing content.

So what are the advantages of doing things this way?

  1. You can easily use any player to play your flash files (all you need to do  is change the path to your player and a few configuration params in multimedia.js)
  2. All your video content is hosted on and delivered from Amazon S3. But there is also a copy on your local server in the event of something going wrong on Amazon S3
  3. You don’t have to worry about your video looking skewed due to aspect ratio problems
  4. You can add many other apsect ratios pretty quickly
  5. The video file is still downloadable when javascript is not present or disabled

I’d love to get feedback on how other do this, please leave a comment or send me an email and let me know how you deliver Video content on your site.

 


t. 604.684.2498 | f. 604.721.4007 | e. turningheads [at] raisedeyebrow.com