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.

Update 2 (2021): This information is outdated, really outdated, please, read the quite useful FFmpeg documentation on AVC/H.264 video encoding: https://trac.ffmpeg.org/wiki/Encode/H.264

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:

http://v1.rodrigopolo.com/wp-content/uploads/video/BigBuckBunny/Input-For-Encoding.mp4

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:

Ffmpeg -i Input-For-Encoding.mp4

You will get something like the following


Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Input-For-Encoding.mp4':
Duration: 00:01:19.04, start: 0.000000, bitrate: 6109 kb/s
Stream #0.0(eng): Video: h264, yuv420p, 1280x720, 24.00 tb(r)
Stream #0.1(eng): Audio: aac, 48000 Hz, stereo, s16
At least one output file must be specified

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:

ffmpeg -i Input-For-Encoding.mp4 -ss 10 -vframes 1 -an -f image2 snapshot.png

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:

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 480x272 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 448k -maxrate 752k -bufsize 1504k -g 24 -vpre iphone -f mp4 -an 01-iPhone.mp4

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 480x272 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 448k -maxrate 752k -bufsize 1504k -g 24 -vpre iphone -acodec libfaac -ac 2 -ar 44100 -ab 96k -f mp4 01-iPhone.mp4

And for the 240p, 360p, 480p and 720p encoding I use this commands:

# 01-iPhone
ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 480x272 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 448k -maxrate 752k -bufsize 1504k -g 24 -vpre iphone -f mp4 -an 01-iPhone.mp4

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 480x272 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 448k -maxrate 752k -bufsize 1504k -g 24 -vpre iphone -f mp4 -acodec libfaac -ac 2 -ar 44100 -ab 96k 01-iPhone.mp4

240

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 432x240 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 224k -maxrate 704k -bufsize 1408k -g 24 -vpre fastfirstpass -an 02-240.flv

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 432x240 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 224k -maxrate 704k -bufsize 1408k -g 24 -vpre hq -acodec libfaac -ac 2 -ar 44100 -ab 32k 02-240.flv

# 360
ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 640x368 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 480k -maxrate 768k -bufsize 1536k -g 30 -vpre fastfirstpass -an 03-360.flv

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 640x368 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 480k -maxrate 768k -bufsize 1536k -g 30 -vpre hq -acodec libfaac -ac 2 -ar 44100 -ab 128k 03-360.flv

# 480
ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 848x480 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 1072k -maxrate 1616k -bufsize 3232k -g 24 -vpre fastfirstpass -an 04-480.flv

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 848x480 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 1072k -maxrate 1616k -bufsize 3232k -g 24 -vpre hq -acodec libfaac -ac 2 -ar 44100 -ab 128k 04-480.flv

# 720
ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 1280x720 -aspect 16:9 -r 24 -vcodec libx264 -pass 1 -b 1904k -maxrate 3088k -bufsize 6176k -g 24 -vpre fastfirstpass -an 05-720.flv

ffmpeg -y -threads 8 -i Input-For-Encoding.mp4 -s 1280x720 -aspect 16:9 -r 24 -vcodec libx264 -pass 2 -b 1904k -maxrate 3088k -bufsize 6176k -g 24 -vpre hq -acodec libfaac -ac 2 -ar 44100 -ab 128k 05-720.flv

IMPORTANT: in order to use this FLV videos with the pseudo-stream technique you have to inject the video metadata on the FLV, for this task I recommend FLVMeta which is included in the FFmpeg installation on this site, you can also download from the official FLVMeta site by clicking here.

The command for inject the FLV Metadata is very very easy, it requires only two parameters, the input and the output file without any flag, here is the command:

flvmeta input.flv injected_output.flv

I’ll inject the metadata in all my encoded files:

flvmeta 02-240.flv 02-240in.flv
flvmeta 03-360.flv 03-360in.flv
flvmeta 04-480.flv 04-480in.flv
flvmeta 05-720.flv 05-720in.flv

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:

# PNG
ffmpeg -i Input-For-Encoding.mp4 -r 0.1315097317201473 -s 480x270 -an -f image2 thumb_%d.png

# JPG
ffmpeg -i Input-For-Encoding.mp4 -r 0.1315097317201473 -s 480x270 -an -f image2 thumb_%d.jpg

Now, for the SRT captions (subtitles) you can make your own captions with Subtitle Workshop for Windows or this other tools for Linux an Macintosh and save your captions as SRT format, then you can use my SRT2XML conversion utility online http://tools.v1.rodrigopolo.com/srt2xml/ to make it compatible for JW Player.

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:

svpsvp

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:

http://code.google.com/p/subler/

http://www.jubler.org/

Do you have your video/s already encoded using H.264 and AAC but in MP4? Don’t worry, can change the video encapsulator with FFmpeg without reencoding your video using the following command:

ffmpeg -i input_video.mp4 -vcodec copy -acodec copy output_video.flv

Then just add the metadata with FLVMeta

flvmeta input.flv output.flv

So this is it, hope this little guide help you encode and share your videos online with the Stream Video Player!


Back to Top ↑