Encoding Stream Video

Update:

To make things easier I have made some Command Prompt / Bash scripts that use all the best practices and commands described on this guide but way better, click here to see the BinKit 2.0 and how can simplify your life.

Guide:

This is a deep study and a guide on how to encode video for pseudo-streming on the web, I’m following the same specs that YouTube use doing some reverse engineering and analyzing the video encoded by YouTube today.

Fisrt of all you have to know that a video online has many many versions and many files, each version is encoded to fit the needs of different bandwidths and devices, in this case I’ll show the most common video versions and files used in a YouTube video:

240p – A video version designed to fit a bandwidth of 256Kbps aprox, it has 432x240px for widescreen video (16:9) and 320x240px for standard video (4:3) aspect ratio.

360p – A video version designed to fit a bandwidth of 768kbps to 1Mbps, it has 640x368px for widescreen video and 480x368px for standard video, it is the default format that YouTube gives today.

480p – A video version designed to deliver DVD like quality to de web, it became popular on the web when YouTube realize that HD format was not really ready for everyone on the web, it has 848x480px for widescreen video and 640x480px for standard video and uses an average bitrate of 768Kbps to 1768Kbps.

720p – The typical HD version, it has 1280x720px for widescreen and it doesn’t exist in the standard video size, it use an average bitrate of 2Mbps and a max bitrate of 6 to 8Mbps.

iPhone/iPad/iPod Touch – A video version designed to run on modern mobile devices, it is encoded in a way that doesn’t require huge CPU power to be decoded, it has 480x272px for widescreen video and 480x368px for standard video and an average bitrate of 400Kbps to 800Kbps.

Thumbnails – Youtube generate some JPG images from the video in order to appear as thumbnails for the video.

Captions – A file that contains the captions or subtitles for the video, the common format for JW Player is an XML file and there are several utilities online to convert an SRT subtitle format to this XML format.

The Strem Video Player plug-in for WordPress use the JW Player where you can switch between only two formats, a low bandwidth format and a high quality format, you have to decide which low and high quality formats fit your audience, on the following example I’ll use the 240p version to reach more users, the 480p to give good quality but be able to fit a flawless playback on 1Mbps connections, I will also make 10 snapshots of the video and will convert a SRT captions file to XML format.

Notice that you can encode your video using any tool available for encoding to FLV and MP4, but also notice that you have to encode your video to get H.264 video and AAC audio on a FLV or MP4 file AND for the pseudo-streming technique the FLV video file has to have his metadata included and a key frame each second or each 3 seconds at most, this is mandatory for the pseudo-streaming.

For this guide I use FFmpeg which is a command line video encoding software, the main reasons to use FFmpeg are quite simple, it runs on Windows, Linux and Macintoch, it’s fast and the most important, it is Free Software (free = libre).

FFmpeg team only deliver the source code of the project so you need to compile it before using it or find a place online to download a compiled version, because I know it is not that easy I have done some compilations that run on Windows, Linux and Macintoch, you can download and install them here, also NOTICE that I use an X264 video encoding preset called iphone that it’s only available on my custom FFmpeg build, if you are not using my custom version you have to download and put it inside the folder where are your other “.ffpreset” files, typically on “C:usrlocalshareffmpeg” for Windows or “/usr/local/share/ffmpeg” for Linux and Macintosh, you can download the iphone preset here.

I’ll use a pice of video of the computer animated film by the Blender Institute, Big Buck Bunny as the input for this encoding; you can download the source here:

You can put your video on a folder for the encoding, I’ll make a folder called “encoding” on my desktop, then I use my “Terminal” or “Command Prompt” and get to my folder, if you don’t know how to do this I’m sorry to tell you this guide isn’t for you.

The most important thing is to know your input frame rate and aspect ratio, you have to encode your video trying to get the closest to your source specs, also notice that to achieve very good quality and low bitrate it is a best practice to ensure that the width and height of your video is evenly divisible by 16, to know your source specs you can use FFmpeg by only giving the input flag:

You can see that the input has streams, the audio and video stream have some specs as codec, format, size and frame rate and the audio have codec, hertz, number of channels and bits.

Some video sources are interlaced, the encoding we are using doesn’t work well if the video is interlaced so we have to deinterlace the video if it’s necessary, to know if a video it’s interlaced the most practical way it’s to make an snapshot of your video, this is the command I use to take a PNG snapshot of a video:

You can change the “-ss” flag to change the point in time where you want to take the snapshot, after seeing your snapshot check if it has some lines on it, this lines are more visible when the video has something moving fast, if it is interlaced you have to add the “-deinterlace” flag to your encoding command.

The first encoding I’ll do is the iPhone encoding, to achieve very good quality I’ll use a two pass encoding with the same X264 preset, notice that the input video has 24fps but in some cases you’ll see 29.97fps or 23.976fps, to achieve frame rate accuracy and avoid audio sync issues it is recommended to use type “30000/1001” for 29.97fps and “24000/1001” for 29.976fps in your “-r” frame rate flag.

Also notice that I’m using 480x272px dimension to fit on the iPhone screen, a 16:9 video with the max width of 480px have a video dimension of 480x270px BUT this size doesn’t fit the evenly divisible by 16 rule, that’s why it is mandatory to use the aspect ratio flag so when the iPhone playback the video it change automatically the size of the video from 480x272px to 480x270p.

Another important flag is the “keyframe flag” which I always try to fit the frame per second, in this case 24.

WARNING: A flag I use many times is the Threads flag, be careful with this flag, I have an Intel i7 procesor so I decided to use 16 threads but with a Intel Quad Core I can only achieve 8 threads, the more threads the faster you get your encoding done, if you put more threads than your CPU can handle FFmpeg will return an error.

Because I’m using a “two pass” encoding I have to encode the video twice and of course typing two different encoding commands, you can “concatenate” both lines using “&&” between the two encoding commands, something like “ls && clear” or “dir && cls“, here are my two encoding lines for iPhone encoding:

Now let’s make 10 snapshot of the video, a very easy way to do this it’s to use FFmpeg to export the video to an image sequence AND change the frame rate to a very low bitrate, I have done an equation to get a low frame rate that make the amount of snapshot I want, I divided the length of the video in seconds into the amount of frames I want and then I divided 1 into that result, the result of that it’s the frame rate for the input, so for this video I have a duration of “00:01:19.04” which are 76.04 seconds, so 76.04/10 = 7.604 and 1 / 7.604 = 0.1315097317201473… here is the equation:

1/(76.04/10) = 0.1315097317201473

Here is the command for the snapshots, notice that you can choose between JPG or PNG by just changing the file extension on the command:

Ok, so we have the needed files for a video publishing with the Stream Video Encoder, as I said before I’ll only publish the iPhone version with the 240p and the 480p version of the video, this are the file I’m going to upload to my server via FTP:

thumb_5.jpg – the thumbnail or image preview of the video.

01-iPhone.mp4 – the Android, iPhone/iPad/iPod Touch version of the video.

02-240in.flv – the injected 240p version of the FLV video.

04-480in.flv – the injected 240p version of the FLV video.

captions.xml – the captions file

Notice that WordPress can’t handle some uploads because the file types so I use FTP for the uploading, I recommend to use a folder for each video you upload, now that you have all your video files on your server create or edit any post or page on WordPress and with the Stream-Video-Player tag generator browse for your files until you have something like this:

So that’s it, now you have a video that can run on an iPhone/iPad/iPod Touch and also on any computer, it has subtitles (captions) and you can go to any time on the video random because the pseudo-streming.

If you want to embed subtitles for the iPhone you can use Subler which works great for me, the only issue is that only runs on OS X, there is also Jubler which is a multiplatform solution but I haven’t tasted yet, here are the links:

Is there any way to get the logo in the player to stay “on” during entire video? I see it as a feature in the JW Player, but can’t figure out where this would go in your scripts. They have a call like: logo.hide (“false”).

I did not edit any of my .flv files and they work perfectly with the plugin, which is just wonderful.

Although when attempting to play on an iphone/ipod/ipad, the video just appears with a ‘grey’ quicktime skin that has a cross through the play button. I have even uploaded an .mp4 video in the ‘iphone video’ part when inserting the video.

I spent 2 hours looking for a solution and have not seen any others with the same issue.