Christian Heilmann

Posts Tagged ‘conversion’

Making vid.ly conversion and embedding easy

Thursday, December 1st, 2011

I am lucky enough to have a vid.ly pro account to convert videos. Lucky because lately the free service started limiting the amount of times you can watch a video in a month (as they were hammered by a lot of traffic from Asia abusing the service). In case you still haven’t heard about vid.ly – it is a service that converts a video into a few dozen formats for HTML5 embedding and gives you a single URL to redirect devices to the correct format of the video.

Now, to make it easier for my colleagues to convert and embed videos in HTML5, I built a simple interface for converting and embedding a video on our blogs. For this I am using the API, but I wanted to avoid having to give my key out for colleagues to use.

The interface to convert videos is pretty easy:

<header><h1>Vid.ly conversion and embed</h1></header>
<section>
  <?php echo $message; ?>
 
  <p>Simply add the URL of the video to convert below and you get the embed code. 
An email will inform you about the successful conversion. 
Conversion could take up to an hour.</p>
 
  <form method="post">
    <div><label for="email">Email:</label><input type="text" id="email" name="email"></div>
    <div><label for="url">URL:</label><input type="text" id="url" name="url"></div>
    <div><input type="submit" name="send" value="make it so"></div>
  </form>
</section>

One of the cool features of the API is that it allows you to define an email that is not the one connected with the key to be the one that gets notified both of the conversion start, errors and success email. That made my job a lot easier. All I needed to do was assemble the correct XML and send it to the API. As the result is XML, too, I needed to check what came back and give feedback in the form:

<?php
$key = '{add your key here}';
$message = '';
if(isset($_POST['send'])){
 
  if($_POST['email'] !== '' && $_POST['url'] !== '') {
    $query =  '<?xml version="1.0"?>'.
              '<query><action>AddMedia</action><userid>481</userid>'.
              '<userkey>'.$key.'</userkey>'.
              '<notify>'.$_POST['email'].'</notify>'.
              '<Source><SourceFile>'.$_POST['url'].'</SourceFile>'.
              '<CDN>AWS</CDN></Source></query>';
    $url = 'http://m.vid.ly/api/';
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt($ch,CURLOPT_POSTFIELDS,'xml='.urlencode($query));
    $result = curl_exec($ch);
    curl_close($ch);
 
    $xml = simplexml_load_string($result);
 
    if($xml->Success) {
      $vid = $xml->Success->MediaShortLink->ShortLink;
      $video = '<video controls width="100%" controls preload="none"'.
               ' poster="http://cf.cdn.vid.ly/'.$vid.'/poster.jpg">'.
               '<source src="http://cf.cdn.vid.ly/'.$vid.'/mp4.mp4" '.
               'type="video/mp4">'.
               '<source src="http://cf.cdn.vid.ly/'.$vid.'/webm.webm" '.
               'type="video/webm">'.
               '<source src="http://cf.cdn.vid.ly/'.$vid.'/ogv.ogv" '.
               'type="video/ogg">'.
               '<a target="_blank" href="http://vid.ly/'.$vid.'">'.
               '<img src="http://cf.cdn.vid.ly/'.$vid.'/poster.jpg" '.
               'width="500"></a>'.
               '</video>';
      $message = '<div class="success"><h1>Conversion started</h1>'.
                 '<p>The video conversion is under way. '.
                 'You should get an email telling you so and an email when '.
                 'the video URL is ready. The code to copy & paste into '.
                 'the blog is:</p>'.
                 '<textarea>'.htmlspecialchars($video).' </textarea>';
    } else {
        $message = '<div class="error"><h1>Error</h1>'.
                   '<p>Something went wrong in the conversion,'.
                   'please try again.</p></div>';
    }
 
  } else {
    $message = '<div class="error"><h1>Error</h1>'.
               '<p>Please provide a video URL and email</p></div>';
  }
}
?>

Pretty simple, isn’t it. Now my colleagues can add their email, give the form a URL where the video to convert is on the web and will get a copy and paste HTML for the video, for example:

<video controls preload="none" style="width:100%;height:300px;" 
poster="http://cf.cdn.vid.ly/1l5i5m/poster.jpg">
<source src="http://cf.cdn.vid.ly/1l5i5m/mp4.mp4" type="video/mp4">
<source src="http://cf.cdn.vid.ly/1l5i5m/webm.webm" type="video/webm">
<source src="http://cf.cdn.vid.ly/1l5i5m/ogv.ogv" type="video/ogg">
<a target='_blank' href='http://vid.ly/1l5i5m'>
<img   src='http://cf.cdn.vid.ly/1l5i5m/poster.jpg' width="500"></a>
</video>

Which results in:

Giving HTML5 video to the browsers who support it and a link to vid.ly for those who don’t :) The code is on GitHub as a Gist:

Vid.ly Bookmarklet – download different formats

Saturday, February 19th, 2011

If you followed my exploits lately in the realm of HTML5 video you’d know that I am a big fan of the video conversion service vid.ly. This service automatically converts your videos to dozens of different formats and redirects your browsers and mobile devices to the correct format when you call up a single URL.

Being a paranoid developer, I also wanted to have a way to download the browser optimised versions of the videos, so I wrote a bookmarklet to allow you to do that.

Simply drag the following link to your browser toolbar: Vid.ly download

The bookmarklet then adds links to any vid.ly page to download the different versions:

Vid-ly download links

Recording Interviews on Skype and converting to HTML5 friendly formats the easy way

Wednesday, January 5th, 2011

Tomorrow I will start a series of interviews on the Mozilla hacks blog about “People of HTML5”. I thought it is a good idea to introduce some people and ask them a few questions and thus give a face to the awesome you meet on IRC or see on GitHub.

I found myself with a few issues to crack:

  • How do I record a Skype call with good quality?
  • How do I convert the video then to a HTML5 friendly format (as “People of HTML5” with Flash movies would be a bit ironic)

The fun thing I found out is that with a good connection and some web trickery this is dead easy. Check the following screencast for the 150 second version:

The first thing I needed was to record the skype call. I tried using ishowu but that didn’t quite do it.

So I thought I bite the bullet and spend some money. Call recorder for Skype was $20 for my mac and does the job swimmingly – it adds itself to Skype and gives you a record button. It stores the recordings as MOV with an AAC and H.264 encoding.

Once I recorded the videos I wanted to convert them for HTML5 embedding. The easiest thing I found was Miro Video Converter – simply drag your file onto it, select WebM/V8 and it converts and saves the file for you (kids, this is why you use Macs!).

All well and good, but not all HTML5 browsers get WebM yet, right? You also need an MP4 version and a OGG Theora one. Also, I needed a space to put the videos where they get the right MIME type and I don’t pay.

Enter Archive.org. If you release your videos and audio recordings as Creative Commons, you can store them there. They provide an uploader on the page or an FTP access (which strangely enough is only one upload at a time). The really cool thing about Archive.org is though that if you wait for a bit, they will have converted your video to MP4 and OGG for you!

Check the video page on Archive.org of the screencast – I only uploaded the WebM video, the other formats and the animated GIF gets created for me automatically.

The only thing is that it doesn’t give you any information that it is converting so all you can do is wait, go back to the page and see when the magic happened.

Once the Archive.org server pixies did their work, you can use a video tag to show your video, using all the sources from your video page:

Notice that as a fallback I point to a site with the Flash movie (either YouTube or in this case Screenr.com which I used to record this screencast).

And that’s it! A $20 app, and free web services and we have hosting and conversion. We can also add subtitling, if we just add Universal Subtitles. I love the web!

The annoying thing about YQL’s JSON output and the reason for it

Wednesday, September 22nd, 2010

A few days ago, Simon Willison vented on Twitter about one of the things that annoyed me about YQL, too:

Battling YQL's utterly horrible JSON output, where a response with one result is represented completely differently from a response with two

The interesting thing about this is that it is not a YQL bug – instead it is simply a problem of generic code and data conversion.

The problem with YQL JSON results

Let’s have an example. If you use YQL to get for example the geo information about “London” you get several results in XML:

select * from geo.places where text=”london”:

XML output with multiple places

If you use JSON as the output format this becomes an array:

JSON output with multiple places

Cool, so you can loop over query.results.place, right? No, cause when there is only one result, we have a different situation. Instead of being an array, place becomes an object:

select * from geo.places where text=”london,uk”:

Single results in JSON become an object instead of an array

This is what ailed Simon as it means you need to write a function that works around that issue. For example in the Geoplanet Explorer, I use a render() function to show each place result and I use the following to work around the JSON output issue:

function renderlist($p){
if(sizeof($p)>1){
foreach($p as $pp){
$o .= render($pp);
}

} else{
$o = render($p);
}

return $o;
}

In JavaScript you’d have to check the length and either show the results directly or loop over the results.

Generic conversion vs. creating a single API

This is a problem when you convert XML to JSON - as the resulting XML from the GeoPlanet API doesn’t have a places element with place in it but instead repeats the place element for every result the JSON parser must make a decision: if it is only one element, this becomes a property of the results object. If there are more than one place element it becomes a property that is an array (as you cannot repeat the same property name).

If you build your own API and you know the format of the different results you can force this to be an array even when there is only one result. If you do not know the XML schema there is no way of assuming what should be an array and what should not be an array. So the generic solution for XML to JSON conversion of an unknown XML with 1 to n results would be to always create an array. That way you couldn’t get to place.admin1.code for example but you’d always have to do place[0].admin1[0].code[0] – not really a sensible thing to do.

As YQL is an open system and the XML results are provided by anyone in their open table definition the only way around I could think of is to tell YQL in the table that some elements should always be forced to become arrays.

Do you have a solution?

Using YQL to load and convert RSS feeds really, really fast.

Tuesday, December 8th, 2009

My esteemed colleague Stoyan Stefanov is currently running an advent calendar (blog post a day) on performance. Today I have a guest slot on his blog showing how you can use YQL to retrieve five RSS feeds much faster than with any other technology.

Retrieving five RSS feeds speed comparison.

As stated at the end of the article, you could use a YQL open table with embedded JavaScript to move all of the hard conversion work to the YQL server, too.

This table does exactly that. The speed of the retrieval slows down a bit with this (as YQL needs to do another request to pull the table definition):

Retrieving five RSS feeds and converting it on the server with YQL execute by  you.

However, using this table to retrieve multiple feeds as HTML is dead easy:

$data = array(
‘http://code.flickr.com/blog/feed/rss/’,
‘http://feeds.delicious.com/v2/rss/codepo8?count=15’,
‘http://www.stevesouders.com/blog/feed/rss’,
‘http://www.yqlblog.net/blog/feed/’,
‘http://www.quirksmode.org/blog/index.xml’
);
$url =’http://query.yahooapis.com/v1/public/yql?q=’;
$query = “use ‘http://github.com/codepo8/yql-rss-speed-comparison/raw/master/rss.multi.list.xml’ as m;select * from m where feeds=”’”.implode(“’,’”,$data).”’” and html=’true’ and compact=’true’”;
$url.=urlencode($query).’&format=xml&diagnostics=false’;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
$content = preg_replace(‘/.*
$content = preg_replace(‘/div>.*/’,’div>‘,$content);
echo $content;

To use the open table you simply need to give it the list of RSS feeds as the feeds parameter:

use ‘http://github.com/codepo8/yql-rss-speed-comparison/raw/master/rss.multi.list.xml’ as m;
select * from m where feeds=”
‘http://code.flickr.com/blog/feed/rss/’,
‘http://feeds.delicious.com/v2/rss/codepo8?count=15’,
‘http://www.stevesouders.com/blog/feed/rss’,
‘http://www.yqlblog.net/blog/feed/’,
‘http://www.quirksmode.org/blog/index.xml’
” and html=’true’ and compact=’true’

Try it out in the YQL console.

The html parameter defines if you want to get HTML back from the table. Take it out to get a list of feeds instead.

See the results as HTML (with an HTML parameter) or as feeds (without the HTML parameter).

The compact parameter defines if you want to get descriptions back for each entry or not.

See the results as HTML (without descriptions) or as HTML with descriptions.

By using the JSON-P-X output format (xml with callback) you could easily use this in JavaScript:



If you want to compare yourself, get the source code of all the examples from GitHub.