Platform documentation & tutorials

Integrate Panda with your web app

Integrating Panda with Ruby on Rails

The following is a guide to integrating Panda into your Ruby on Rails application. However the instructions here can easily be adapted to any Ruby-based web framework or web application.

Before continuing you must have a Panda account.

If you want to use the Heroku addon, then start with the Heroku add-on documentation, and then continue with implementation. Otherwise you just need to sign up here.

Free accounts are available, great for playing around. For more info on the gem, check out the documentation or github.

The example application

This documentation will talk you through the process of integrating Panda with a basic Ruby on Rails application. It will use the libraries linked above.

You can view the code of the complete Ruby on Rails example.

Checkout the branch rails2 if you want to use Rails 2.X

Configuration

First you must log in to your account, where you can find your credentials as follows:

  • Under Api Access: Access key, Secret key, API URL
  • After selecting your Cloud: Cloud ID

If you haven’t yet created an encoding cloud you should do so before continuing.

PRO TIP: you may want to create two different clouds, one for development and one for production. Note that each cloud will have a different Cloud ID, but the other credentials will be shared across all clouds.

Once equipped with this information, you can create a Panda config file on config/panda.yml. Just copy the following example and fill it out with your own credentials where appropriate:

development:
  access_key: Your Panda access key
  secret_key: Your Panda secret key
  cloud_id: Your Panda cloud id
  # Uncomment the line below if your account is in the EU
  # api_host: api-eu.pandastream.com

In your Gemfile, add the following line:

gem 'panda', '~> 1.5.0'

If you are going to deploy your app to Heroku Bamboo stack add the following line:

gem 'typhoeus', '~> 0.2.4'
gem 'panda', '~> 1.5.0'

Now install the gem:

$ bundle install

Next create the file initializers/panda.rb and then add the line below to connect to Panda when your app starts. If you’re using the Panda Heroku Add-on you will need to set the PANDASTREAM_URL environment variable on your local system. Read the Panda Heroku Add-on docs for further details.

Panda.configure((ENV['PANDASTREAM_URL'] || YAML::load_file(File.join(File.dirname(__FILE__),"..", "panda.yml"))[RAILS_ENV]))

Checking that everything is working

Fire up a console. Your initialiser should run and connect you to Panda. You should be able to list all your encoding profiles.

>> Panda::Profile.all
=> [<Panda::Profile preset_name: h264, ...>]

Now, upload a sample video. You can use any URL; this is the URL of a sample we’ve made available:

>> video = Panda::Video.create!(:source_url => "http://panda-test-harness-videos.s3.amazonaws.com/panda.mp4")

Or use a local file:

>> video = Panda::Video.create!(:file => File.new("/home/me/panda.mp4"))

Now wait until the video has finished encoding (which could be several minutes). You can check by doing:

>> video.reload.status
=> "success"

Your input video has been uploaded to s3

>> video.encodings['h264'].reload
>> video.encodings['h264'].encoding_progress
=> 100
>> video.encodings['h264'].status
=> "success"

Now you can get the URL of a re-encoded version:

>> video.encodings['h264'].url
=> http://s3.amazonaws.com/S3_BUCKET/e40c1f68fbc1c4db46.mp4

Open this URL in your browser, and you’ll see that Panda has received, re-encoded, and stored your video into your S3 bucket.

Everything’s working great - time to write some application code! If you’d like to play with the console some more, the full set of resources are listed in the API Documentation or Gem Docucmentation.

Implementing video uploads in your application

Upload example

The simplest way to begin uploading videos directly to Panda is using the panda_uploader jQuery plugin. The plugin will automatically detect the user’s browser and provide the user with the best upload method supported. On modern browsers (Safari, Firefox or Chrome), the upload will be done using several advanced features of HTML5. If the browser doesn’t support these, the uploader will automatically fallback to a Flash-based solution using SWFUpload.

Both methods provide the same UI for upload progress, however the upload button will be slightly different. HTML5 uses a native file select form element, and SWFUpload uses an image.

In summary, the plugin renders a widget next to a hidden form element. Once an upload is complete, the ID of the new video will be inserted into this hidden field. This ID can then be saved in your application, and will be used to reference the video in Panda later.

Setup models and controllers

Create a Video model to save the ID of the video from Panda, we’ll call it panda_video_id:

rails g model Video title:string panda_video_id:string
rake db:migrate

Panda provides its own Panda::Video model, which we’ll wrap with our ActiveRecord model. Edit app/models/video.rb:

class Video < ActiveRecord::Base
  validates_presence_of :panda_video_id

  def panda_video
    @panda_video ||= Panda::Video.find(panda_video_id)
  end
end

Now you can access the wrapped object with myvideo.panda_video, or go directly to the encodings with myvideo.panda_video.encodings. This call requires a call to the Panda API, so we cache it with an instance variable to save time.

We’ll use a simple VideosController following the REST pattern. Create app/controllers/videos_controller.rb:

class VideosController < ApplicationController
  def show
    @video = Video.find(params[:id])
    @original_video = @video.panda_video
    @h264_encoding = @original_video.encodings["h264"]
  end

  def new
    @video = Video.new
  end

  def create
    @video = Video.create!(params[:video])
    redirect_to :action => :show, :id => @video.id 
  end
end

In the show action, we’re first getting a reference to our ActiveRecord object, as normal. Then we’re getting a reference to the wrapped Panda::Video, as @original_video. This object has methods defined in the Panda gem to manipulate the video encodings.

Finally, we’re getting a reference to the actual encoding of the video that’s been performed by Panda, so that we can pass it to the View. When a video is uploaded, one Encoding will be created for each Profile that’s defined. A shiny-new Panda account comes with a single Profile created, called “h264”, but you can create more in your account.

Make sure you have set a name to your profile, in this case “h264” (it could be something else), otherwise @original_video.encodings["h264"] will return nil. (You can update your profile name using the api or the web interface)

Finally, add the videos resource to config/routes.rb.

resources :videos
root :to => "videos#new"

Create the video upload form

Create the layout views/layouts/application.html.erb, and include jQuery (version 1.3 or later) and the uploader javascript library:

<html>
<head>
  <%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js' %>  
  <%= javascript_include_tag 'http://cdn.pandastream.com/u/1.4/jquery.panda-uploader.min.js' %>
</head>
<body>
  <%= yield %>
</body>
</html>

Now create a view which will be the video upload form: /app/views/videos/new.html.erb.

<%= form_for @video do |f| %>
  <p>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </p>

  <!-- the control will appear next to this, and the video ID will be stored here after the upload -->
  <input type="hidden" name="video[panda_video_id]" id="returned_video_id" />

  <!-- upload progress bar (optional) -->
  <div id="upload_progress" class="panda_upload_progress"></div>


  <%= f.submit "Upload video" %>
<% end %>

<script>
  <% auth_params = Panda.signed_params('post', "/videos.json") %>
  jQuery("#returned_video_id").pandaUploader(<%=raw auth_params.to_json %>, {
    // Uncomment the line below if your account is in the EU
    // api_host: 'api-eu.pandastream.com',
    upload_progress_id: 'upload_progress'
  });
</script>

The script block obtains a signature from the Panda gem and passes it over to the Flash object so that it can correctly sign the video it is uploading.

For more options, see the panda_uploader documentation.

The Panda Uploader will use HTML5 upload if the browser supports it, and will fall back to Flash upload if necessary:

BrowserUpload Supported?Method Used
IE 6-9YesFlash
OperaYesFlash
SafariYesHTML5
ChromeYesHTML5
Firefox >= 3.5YesHTML5
OthersYesFlash

Set up routes

Now create a basic view to show the video data once it has been uploaded. Edit app/views/videos/show.html.erb:

<h2><%= @video.title %></h2>
<p><%= h @video.panda_video.inspect %></p>

Test video uploading

Start Rails application with rails s and visit http://localhost:3000/videos/new where you will see the video upload form. Choose a video (download this splendid video of a sneezing panda if you need a test one) and hit submit. The video will be uploaded directly to Panda, and once complete the form will be submitted to your Rails app, with the upload’s panda_video_id included.

You should now be looking at /videos/1, which will show the detail of the video object. The status should be “processing”. Refresh this page and you will see it change to “success” when the video has finished encoding.

If there is an error when uploading, it’s most likely because the signature is incorrect. Double check you have entered the correct values for the access key, secret key and cloud id. If you can’t solve the issue, don’t hesitate to submit a support ticket and we’ll be able to help you out right away.

Embedding your videos

There are a few options for video playback. Read the Video Players documentation for detailed information. The examples below should be enough to get you started though.

Using HTML5

If you don’t have to support older browsers, the simplest is to use the new HTML5 <video> tag. To support Firefox you’ll also need to add in an OGG source. See the Video Players documentation for details.

Edit your show page in app/views/videos/show.html.erb:

<% if @video.panda.status == "success" %>
  <video id="movie" width="<%= @h264_encoding.width %>" height="<%= @h264_encoding.height %>" preload="none" 
    poster="<%= @h264_encoding.screenshots.first %>" controls>
    <source src="<%= @h264_encoding.url %>" type="video/mp4">
  </video>
<% end %>

If you refresh the show page you’ll see the encoded video!

Using a Flash player

If you need to support older browsers, you can also offer a Flash player. There are several options including JW Player and Flowplayer. The instructions below are for using JW Player.

Download JW Player, unzip it, and copy player.swf to the public/ in your Rails app. Also copy swfobject.js to public/javascripts/.

Edit your layout in app/views/layouts/application.html.erb and include swfobject.js:

<%= javascript_include_tag 'swfobject' %>

Now, edit app/views/videos/show.html.erb:

<div id='flash_player'>Flash player will appear here</div>

<script type='text/javascript'>
  var so = new SWFObject('/player.swf','mpl','<%= @h264_encoding.width %>','<%= @h264_encoding.height %>','9');
  so.addParam('allowfullscreen','true');
  so.addParam('allowscriptaccess','always');
  so.addParam('wmode','opaque');
  so.addVariable('file','<%= @h264_encoding.url %>');
  so.addVariable('image','<%= @h264_encoding.screenshots.first %>');
  so.write('flash_player');
</script>

If you refresh the show page you’ll see the encoded video inside JW Player. This will work on almost any browser with a recent installation of Flash.

Advanced topics

Encoding Profiles

You can change the formats that Panda encodes videos into by logging in to your Panda account. Each Cloud has its own set of Profiles. You can select from preconfigured presets, or create your own by entering the ffmpeg command. To learn more, see the sections on Encoding Profiles and Advanced Profiles. We highly recommend that you use our presets. They use the most updated tools and we make them evolve. Most of encoding options are available for presets.

It’s possible to define several profiles and then decide on a per-video basis which ones to use. When creating your signed params for the panda_uploader, you can specify each profile name that you want to use, separated by a comma:

<% auth_params = Panda.signed_params('POST', "/videos.json", { 
    :profiles => "h264,webm" 
}) %>

Learn more

Now that you have a basic implementation, you might want to check out the Panda Gem Documentation or the full API Documentation for more ideas.