Live video streaming with PHP


Picture this. We want to stream live video. In fact don’t need PHP. We only need a flash player (or HTML5) and our live feed. The problem appear when we need to offer some kind of security. For example we want to show videos only to registered users based on our authentication system. Imagine we’re using sessions for validate users. That’s means we cannot put the media in a public folder and point our media player to those files. We can obfuscate the file name but it’ll remain public. In this small tutorial We’re going to see how to implement it with PHP. Let’s start.

First we are going to forget for a while video files. We are going to think in pictures.

If we don’t need to protect the file we can place the image in public folder:

<image href=’/path/to/image.png’ alt=’image’ width=’10’ height=’10’/>

But if we want to protect the picture we cannot place it on a public folder. We need to place it on a server folder and flush it with a code like this:

// here you can chech your sessions
header("Content-Type: image/jpeg");
readfile(‘/path/of/image’);

That’s easy. Isn’t it?.
Video files are similar than pictures. We cannot use image tag but the behaviour is the same. With HTML5 we can show them with HTML tags and without HTML5 we need to use a client viewer (generally a flash viewer).

We can use the same technique than the previous example with video files but the problem now is the size of the file. Live video feeds are never ends. If we use the previous code our server must read the live feed forever, and our browser will be waiting forever too. We can easily change this behaviour. Instead to read the entire video file and flush it to the browser we can read small pieces of the file and flush them without waiting until the end of the file.

<?php
// here you can chech your sessions

function flush_buffers(){
    ob_end_flush();
    ob_flush();
    flush();
    ob_start();
}

$filename = "/path/of/fideofeed.flv";
if (is_file($filename)) {
    header('Content-Type: video/x-flv');
    header("Content-Disposition: attachment; filename=video.flv");
    $fd = fopen($filename, "r");
    while(!feof($fd)) {
        echo fread($fd, 1024 * 5);
        flush_buffers();
        }
    fclose ($fd);
    exit();
}

If we want to stream static video files we also need to take into account the start of the video. When someone want to move across the video going forward and backward within the video client, our server script will retrieve a variable with the start time. That’s means we need to use this start time to open the file from this byte instead from the beggining.

About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on September 20, 2010, in php, Technology, tips. Bookmark the permalink. 42 Comments.

  1. 1) On Windows you need to use “rb” instead of “r” with fopen() (but you should always use “rb”)
    2) If you stream a live feed or a static file (but not from the start) you need to send those string before the feed :
    print(“FLV”);
    print(pack(‘C’, 1 ));
    print(pack(‘C’, 1 ));
    print(pack(‘N’, 9 ));
    print(pack(‘N’, 9 ));
    3) Reading large file may hang futur request from the same user currently streaming from the php script.
    4) You don’t need to call ob_flush(); after ob_end_flush(); ( ob_end_flush() is an alias of ob_flush(); and ob_clean();)

    • By the way, why do you open the output buffering and not just use “ob_flush(); flush();” ? The only reason I see why you may use it is to reduct the HTTP header cost (which will not work because you flush the buffer after every read…) from multi-part.

      • What’s Windows? (it’s a joke).

        I know the way I use to flush buffers is a bit redundant. Why I use it? The answer is because it works for me in all situations. Under web environment and even on CLI mode. I know there are slight differences between them and as you say some of them are simply alias.

        After my regret list (they’re good isn’t it?) I will read a bit more about them. What do you recommend in this case? Do you think use this function always “without thinking” is a good solution? (I know it sounds bad but as far I know there aren’t any significant performance problem)

        Thanks for 2) Probably is the solution for a problem I have in another project. I didn’t know it. (knowledge updated :))

        point 3): correct. Normally I don’t have this kind of problems with videos files (my videos are not very big and I don’t have too many concurrent users). What do you recommend in this case? I’ve been playing storing files in a CouchDb Database to avoid this kind of locks (CouchDb is great reading data)

      • [quote]The answer is because it works for me in all situations. Under web environment and even on CLI mode.[/quote]
        Kinda wierd, the method I suggest should work for CLI and web environment. (Except a warning for the CLI, I think I just add a “if ( ob_get_length() )” before ob_flush()) Maybe I should test a little more :O

        When I wrote “always use rb” I was talking only about your PHP sample. In my case, if I know i deal with binary files (like this case) I add “b” otherwise I just don’t add it. About performance, I’m almost sure that “b” will be faster. (Just read documentation from fopen(), they are talking about translation stuff without “b” mode ;)) On a linux system “r” is “rb” anyways.

        The idea of private/public image is good, people should also read about the rewrite mod for apache so there’s no need to write 1 php file per image.

        However, I think many things about the php streaming part is not 100% true.
        I only see one major error : [quote]the entire video file [is flushed] to the browser [...] [at] the end of the file.[/quote] This will almost never happen. PHP will automatically call flush() when it reach a level of data waiting to be send. (For binary medium/large file at least PHP seem to call it often). The only way to change this behavior is to enable the output buffering without a memory limit. (Here, user need to call ob_flush()) Your script may be usefull just to make sure we send data as soon they are available and for extra actions. (Bandwith limitation (I know there is some apache mod too), session validation,…) This may be usefull for any live stream because time is important. (like you explained, just remove the part which say you receive the file only at the end of the file…)
        So you could use readfile() too.

        (I’m not sure about this part, this is just some theory) For a live feed just make sure the fread() param ( here 1024 * 5 ) is not more than the minimum length of your feed for 1sec. (I think it should be half of this minimum) (The lower is the value, the better frame per seconds you should get, of course the upload bandwidth from your server or the camera FPS may be the problem)

        3) Well… I’m looking for an anwser too. Actually my problem isn’t about concurrent (but I didn’t test about that) but “multiple” request from the same PHPSESSID. If you run a PHP streaming script any futur request (from the same PHPSESSID and only to a php file) is in a queue until your PHP streaming is done… this may be a huge problem.

  2. 3) I had a similar problem with sessions and long time scripts. Not a live video. It was a comet script. I’d a post about it here:

    http://gonzalo123.wordpress.com/2010/04/13/sessions-comet-and-php/

    session_write_close() is your friend. Now I use couchDb as session storage and I don’t have this kind problem but session_write_close was a great discover when I faced that problem. When I discovered that closing session as soon as possible the problem was solved

    I can’t live without memory limit. It’s my lifeguard. Sometimes I change it to a higher value, but I never remove it. Without it it’s easy to use all the resources of the server (with an error in a for loop for example) And believe me without reading the file into small chunks and flushing buffers my browser never start to play the live feed. But I will test it. Now that code works like a charm (if it works, don’t touch it :) ) but I will test it without time limit (added to my to-do list).

    Finally I decided 1024 * 5 because it worked fine with different cameras. The biggest nightmare was the frameset of the live feed. Wrong values means flash player work different under different browsers. FF was great even with wrong FPS flowplayer (the client I use) worked fluently but IE and Chrome not

    • Adrian Harding

      Thank you for posting about session_write_close(), I was going crazy trying to figure out why the user could not perform any other actions until the stream had finished.

  3. 3) Why I never think about session_write_close… thanks ! (anyways I will check about couchDb too :))

    You are not alone to like memory limitation ;)
    Thing may be different from the last time I tested without ob_flush/flush() or i may crazy too. Now (from some years) I always use ob_flush()/flush() for any binary file. (You have the control and you are sure of the behavior, also I guess this is less memory heavy)

    5ko you said, I will write it somwhere it may be usefull

  4. How would you use this on the client side? I have pointed JW Player at a similar php script i created and the file is definitely coming across the wire. However the flash player is not rendering it.

    • I ended up figuring this issue out (Had to adjust some JW Player parameters. Flowplayer worked right out of the box). Thanks for this tutorial. I have been able to modify this to live stream H.264 encoded FLVs. Pretty much solves everything I have been trying to do for weeks!

      • I’m new to php and i’m encountering a problem that when i paste the code into my php file and give the links to the video on my computer, it opens the page and downloads the video, video is in some distorted format and i can’t even play it on my local media players like window media, flv etc.

  5. Hello,
    Sorry I can make a query.
    look at your issue with PHP Live streaming video
    and was wondering if there is a possibility.
    a sequence of images could lead to video.flv

    • Gonzalo Ayuso

      take a look to ffmpeg.
      I use the following command to convert a secuence of png into a flv video:
      ffmpeg -f image2 -r 1 -i image_%d.png video.flv

  6. hello, I think this is what I’m trying to do. May I explain my problem ?
    I have a remote location that can only use port 80 (all other ports are blocked)
    I have 10 IP cams that I want to be able to view at the remote location. How can I do this?
    I think using your suggestion above should do it but I’m not sure how I could include thsi in a web page to show my cameras at the remote location. If need be I don’t mind only seeing one camera at a time and switching between them. Anyhelp would be most apreciated.
    Thanks.

    • Gonzalo Ayuso

      First: the most easy way to to that is convert all IP cams into flv live streams (flv can be viewed within all browsers). Normally IP cams don’t serve flv by default, but you can use ffserver to convert the live streams of the IP cams into flv live streams. ffserver creates a live stream on the port we’ve selected. As you said you can use only port 80, so you will need to create a proxypass on your apache server to redirect your ffserver feeds to your port 80.

      Summarizing. Is perfectly posible what you say. I’ve worked in project doing something similar. We had an extra problem to protect the live feeds with a legacy sso (because of that I wrote the article). It was a bit hard the part of create the flv streams of all the IP cams (different models, and not a great background knowledge of video processing)

      Here you are a link about ffserver: http://goo.gl/frqpQ

      I hope this idea works for you

  7. Thanks for the nice article .. I think i am nearly to do my code with the help of this article, anyone just let me know that how to point my cctv cameras to my website

  8. I want to restream a flash streaming which is stream from another server using php . Please suggest me

    • This post was about restream flv content. Maybe first you need to ask yourself why you want to use PHP. My answer was to add a security layer. Original flv stream was public (in LAN) and I wanted to show it in the internet with user/pass. If you’ve got similar needs, go ahead, but if not, consider using a simple alias or redirect in the web server.

  9. hello, I am a cemaraman. I want to make presence of live streaming of function which I capture. For this I have a site and host. I am somewhat familiar with PHP,JAVAScripts, But no with Flash. Suggest me how to do this?

  10. I think that from a networking perspective, from a classic End-User -> Streamer scenario (which is probably very efficient because of a streamer’s design, network speed etc) using that method you’re switching to End-User -> Web Server -> Streamer.

    Something like that could be a bottleneck for “real-life” high traffic streaming scenarios.

    But nonetheless, you proved a point here for not so demanding applications (just noticed the local flv file on the code).

    Thanks for your post!

    • Gonzalo Ayuso

      I agree with you. This solution is only correct if we don’t have so many users. If we need to stream media to a big group of users we need to use on streaming solution (End-User -> Streamer) instead of End-User -> Web Server -> Streamer.

      But if we are working in a intranet solution (without hight traffic demand), this simple solution is enought. Anyway it doesn’t scale

  11. hi Gonzalo,thanks for your script but it don’t works for me when i open the page it download the video which i expected to streamed,i want to know what am supposed to add in that code to get the streamed video and not being downloaded?…
    thanks in advance

    • You cannot open the page with a browser. You need a video player that support live streaming such as vlc or embeded video player

      • Hi
        I’m encountering the same problem as Kuliga,
        I’ve downloaded a jwplayer. and placed it into my website folder. Now i am able to call it and it shows up on my website page. But As i’m new to php development i’m unable to figure out the next step.

        Browser still downloads the video and video is in some distorted format and doesn’t even play on the local players like flv or windows media player.

  12. how to let users stream their live video into server?

  13. hi i’ve a online tv script from worldtvpc its open source php script and call windows player to stream how can i add more player to it ,i’m not a coder but if i have the code and some instruction i’ll do it thank you in advance CHEERS

  14. Hi, thanks for this great discussion by the way, i try embeding flash player to load the streaming video but it didn’t work. below is the code.

    video.php contain the php code

    Thanks

  15. hi i am new to php and live streaming and in my new project requires me to stream live webcam on internet. so is it possible to this using php only including getting video feed from webcam and writing on the website? any kind of help is appreciated

    • Probably your webcam is not able to stream data to more than 5 or 10 users. Because of that you will one extra software to serve the content. This post explains how to do it with PHP. But maybe you will need to use one encoder to convert your media to flv (ffmpeg for example)

  16. I’ve got a blog similar to this niche and you have provided me a wonderful idea for a brand new article. Appreciate it.

  17. hi!
    Why does your code force the file to download instead of playing on browser live…?

    function flush_buffers(){
    ob_end_flush();
    //ob_flush();
    flush();
    ob_start();
    }

    //$filename = “/path/of/fideofeed.flv”;
    if (is_file($fullPath)) {
    header(‘Content-Type: video/mp4′);
    header(“Content-Disposition: attachment; filename=”.”K2013″.$file_name);
    $fd = fopen($fullPath, “rb”);
    while(!feof($fd)) {
    echo fread($fd, 1024 * 5);
    flush_buffers();
    }
    fclose ($fd);
    exit();
    }

    • Gonzalo Ayuso

      If our file is very big we need to send small pieces of file to the browser if we don’t want to wait until the browser downloads the whole file. When we are working with live feeds those files never ends so we need this small hack to send them to the browser.

  18. Hi Gonzalo
    thanks for your useful website
    im going to showing webcam or other camera live stream in my php project
    please help me
    thanks alot

  19. if u don’t mind please give me complete script file to test. thanks

  20. Hi,

    I’ve got a problem with your script, I basically copy it, and under your script I put a video player code, and I link $fd as a link to the file, but it looks like $fd is empty, when I test it on the browser and when I looked into the source of website it doesn’t show any link to the file.

    Do I used your script correctly ? does $fd should contain link to the file ?

  21. i want full details to setup a camera and view it in my web page with the PHP

  1. Pingback: Protect files within public folders with mod_rewrite and PHP « Gonzalo Ayuso | Web Architect

  2. Pingback: Live video streaming with PHP ← Bookmarks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 972 other followers

%d bloggers like this: