Felipe Weckx

Streaming videos with PHP

Videos for the Web

With the recent support for HTML5 in most modern browsers, nearly all of them can understand the <video> tag which allows to place a video in a webpage. However, not any video format can be used for there are limitations between browsers and their versions, so before serving a video on the web it has to be converted to a supported format.

Supported Formats

MP4 is the most widely supported video format on the web today, however it is possible to specify several sources in the <video> tag which allows the browser to choose format it supports best. According to W3Schools the supported formats  in each of the most common browsers are:


Browser MP4 WebM Ogg
Internet Explorer SIM NÃO NÃO

For this example this video in the Quicktime (.mov) format will be used. The FFmpeg, available for Linux, Windows and MAC will be used.

Converting to MP4

To convert the video into the MP4 format use the following command line:

ffmpeg -i Rain_Fire.mov -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset slower -crf 23 -vf "scale=trunc(in_w/2)*2:trunc(in_h/2)*2" -movflags +faststart rain.mp4

Some important parameters of the command above:

  • -c:v libx264 – Use the x264 codec, very importante since its the most widely supported
  • -pix_fmt yuv420p – Pixel format to use
  • -profile:v baseline – Video profile. The baseline profile makes it easy for Androi devices to support
  • – preset slower – Determines the size/encoding time ratio.  Can be (faster, fast, medium, slow
  • -crf 23 – Quality encoding level. 0 means lossless and 51 the worst quality possible. The default is 23 which is a good value.
  • -vf “scale=trunc(in_w/2)*2:trunc(in_h/2)*2” – For some reasons MP4 movies using this encoding need even width and height. This parameter adjusts these values.
  • -movflags +faststart – Places the video information headers on the beggining of the file, this allows the browser to download the video information first.  This parameter is essential to allow the streaming of the video.

For more information see FFmpeg documentation on H.264 video encoding.

Converting to WebM

Another possibile video format is WebM which uses the VP8 codec , a royalty free video codec purchased by Google. To convert to this format use the following command:

ffmpeg -i Rain_Fire.mov -c:v libvpx -c:a libvorbis -pix_fmt yuv420p -b:v 2M -crf 5 rain.webm

The parameters are

  • -c:v libvpx – The video codec to use (VP8)
  • -c:a libvorbis – The audio codec
  • -pix_fmt yuv420p – pixel format
  • -b:v 2M – desired bitrate. It is important to set this parameter as the default creates poor quality videos
  • -crf 5 – Video quality. Ranges from 4 – 63. The smaller the better.

More info on the FFmpeg VP8 documentation.

Serving the file

With the correct format files let’s create a simple site to serve it. The following directory structure will be used:

Estrutura de diretórios

Estrutura de diretórios

In the public directory are the files that are visible by the webserver and in the resource directory the video files which we will serve. The index.php file has the HTML and stream.php is where we will read the video files using PHP to serve them.


Streaming is a data distribution method in which the content is served to the client as needed, in a way that it is not necessary to have the full content before acessing it. That is the best way to serve video files because it allows quick visualization by the user and also lowers bandwidth usage. The web browsers use the HTTP Range header to indicate which bytes of the video it wants.

Handling the Range header

According to the RFC2616 which specifies the  HTTP protocol version 1.1 the Range header specifies the portion of the content to be served on the request and format of the header is one of the following:

  • The first 500 bytes: bytes=0-499
  • The second 500 bytes: bytes=500-999
  • The last 500 bytes: bytes=-500
  • All bytes since 9500: bytes=9500-

The header value is available on the $_SERVER[‘HTTP_RANGE’] variable, the code below for the file stream.php uses the PHP filesystem functions  to read a video file and serve it.

It is essential to handle the Range header when streaming video files otherwise the forward, reverse and seek player options will not work. Also, without that the video would have to be completely downloaded before watching, which gives a bad user experience.

The web page

Moving on to the web page the file index.php  will have the HTML with the <video> tag and will be the one acessed by the user:

The file can be tested using a webserver o the PHP built-in webserver executing:

php -S localhost:8000 index.php

And on the browser access http://localhost:8000

The <video> tag

The <video> tag is used to add the video element to the page. Inside the tag there may be any number of <source> elements, each one with a video or audio URL. So it is possible, for example, to specify a video and an audio file that will be combined by the browser on playback. In our case we specify two video sources, on for the MP4 file and the other for the WebM file and the browser will decide which one to use. The attributes for the tag are:

  • controls – Wheter the video controls should be displayed
  • preload – If the video will be loaded with the webpage or not. The value can be auto to load, , metadata to load only the metadata or none to not load the video util it is clicked (played) by the user. Internet Explorer does not respect this parameter.
  • width height – The video width and height if it is not the same as the file the video will be resized by the browser
  • poster – URL for an image that will be displayed in the video container util the video is loaded or played. It is possible to create it using FFmpeg as we will see below.
  • autoplay – if specified the video will start playing as soon as possible

There are several other parameters available.

Creating the poster

The poster image can be created using FFmpeg with the following command:

ffmpeg -i Rain_Fire.mov -r 1 -vframes 1 -ss 0:05 poster.png

The most important parameter is -ss 0:05 which specifies the time where the image will be extracted.

Using video.js

The page works on any modern browser that supports HTML5. But what about older, but still used, browsers such as Internet Explorer 7 or 8? For those we can use the video.js javascript library. It automatically detects if the <video> tag is supported and if it isn’t it is replaced with a flash video player automatically. The update index.php is shown below:


HTML5’s <video> tag allows for easy video embedding in web pages, but it is necessary to take care with the video format and make the necessary convertions. It is essential that the files be served via streaming to reduce network usage and enhance user experience. PHP allows easy handling of streaming by the use of its file system functions and the Range HTTP header. The code developed here is very basic and can be improved in many ways.

The example code is available at Github: https://github.com/weckx/wcx-video-stream