Advantages and disadvantages of using PHP Video Stream?

Asked

Viewed 1,996 times

3

Researching a little about the performance of videos for stream, I found a solution that fits me well, that would use a PHP script to send the video in parts to the player, and such method would not force me to use protocols like RTSP or Websocket, but there is the doubt:

  • I would have some advantage or disadvantage by uploading the videos of this form?
  • The standard protocols for this type of use are more recommended?

  • These are rather large explanations to be given in response by here, but if anyone could indicate me good points, and tutorials to respect for this type of page display, would be of great help.

Update: Below is the PHP code to stream; Link to the tutorial: http://codesamplez.com/programming/php-html5-video-streaming-tutorial

class VideoStream
{
    private $path = "";
    private $stream = "";
    private $buffer = 102400;
    private $start  = -1;
    private $end    = -1;
    private $size   = 0;

    function __construct($filePath) 
    {
        $this->path = $filePath;
    }

    /**
     * Open stream
     */
    private function open()
    {
        if (!($this->stream = fopen($this->path, 'rb'))) {
            die('Could not open stream for reading');
        }

    }

    /**
     * Set proper header to serve the video content
     */
    private function setHeader()
    {
        ob_get_clean();
        header("Content-Type: video/mp4");
        header("Cache-Control: max-age=604800, public");
        header("Expires: ".gmdate('D, d M Y H:i:s', time()+604800) . ' GMT');
        header("Last-Modified: ".gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT' );
        $this->start = 0;
        $this->size  = filesize($this->path);
        $this->end   = $this->size - 1;
        header("Accept-Ranges: 0-".$this->end);

        if (isset($_SERVER['HTTP_RANGE'])) {

            $c_start = $this->start;
            $c_end = $this->end;

            list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
            if (strpos($range, ',') !== false) {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
                header("Content-Range: bytes $this->start-$this->end/$this->size");
                exit;
            }
            if ($range == '-') {
                $c_start = $this->size - substr($range, 1);
            }else{
                $range = explode('-', $range);
                $c_start = $range[0];

                $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
            }
            $c_end = ($c_end > $this->end) ? $this->end : $c_end;
            if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
                header("Content-Range: bytes $this->start-$this->end/$this->size");
                exit;
            }
            $this->start = $c_start;
            $this->end = $c_end;
            $length = $this->end - $this->start + 1;
            fseek($this->stream, $this->start);
            header('HTTP/1.1 206 Partial Content');
            header("Content-Length: ".$length);
            header("Content-Range: bytes $this->start-$this->end/".$this->size);
        }
        else
        {
            header("Content-Length: ".$this->size);
        }  

    }

    /**
     * close curretly opened stream
     */
    private function end()
    {
        fclose($this->stream);
        exit;
    }

    /**
     * perform the streaming of calculated range
     */
    private function stream()
    {
        $i = $this->start;
        set_time_limit(0);
        while(!feof($this->stream) && $i <= $this->end) {
            $bytesToRead = $this->buffer;
            if(($i+$bytesToRead) > $this->end) {
                $bytesToRead = $this->end - $i + 1;
            }
            $data = fread($this->stream, $bytesToRead);
            echo $data;
            flush();
            $i += $bytesToRead;
        }
    }

    /**
     * Start streaming video content
     */
    function start()
    {
        $this->open();
        $this->setHeader();
        $this->stream();
        $this->end();
    }
}

/*chamo a classe*/
    $filePath = "caminho-para-o-video.mp4";
    $stream = new VideoStream($filePath);
    $stream->start();

1 answer

3


HTTP Header Range (Download split files)

PHP allows not only for videos, but for any kind of download, to put together a script for managing the delivery of parts of files. This is how sites like Mega or other specialized in Download manage the band used, speed and any other limitation that the service has for free account users.

One of the main problems of PHP when used for stream, websocket or anything like that is that it is terrible to manage memory, PHP must die sometime. It is not healthy for the server to let a PHP script run for centuries. This must be the biggest problem when using this medium that is wanting.

Once again, PHP is by no means an ideal language to implement stream, websocket or anything like that. Can you implement it? Of course, but the result will not be very satisfactory when placing in production environment.

From what I saw there is no HTTP header to limit the size of a range, so I would have to resort to Javascript or Flash implementations for this. Otherwise you won’t have much control, which can be a huge problem, because while the video is loading, the PHP script will be running.

What you can do is try to separate into several requests by requesting different parts of the file.

Using this way of delivering the file in parts can be an interesting solution, but you need to be careful about the amount of memory your script will use or the number of threads used.

To illustrate, you made your system and it delivers a percentage of the file to each request, let’s assume, every 10%.

If you have an average file size, the delivery might not generate any problems, the download time will be good, and there will be many consecutive requests to the server.

If you have a small file, the delivery can start to generate problems with a larger number of user using, because as the delivered parts of the file is very small, the answer will be very fast and the need for a new part of the file will appear as fast. Therefore, the number of consecutive requests can increase too much, and if you have multiple users requesting the same file, will be several threads created and as a consequence a very auto processing use.

If you have a very large file, PHP will take a long time to execute the entire request delivery, and PHP was not made to process scripts for a long time, PHP must die sometime.

Controlling the size of ranges

I haven’t found anything on how to control the HTML5 player buffer, but it’s certainly possible, since Youtube does this, but I don’t think much that it works using PHP as a stream service, but a specific system for this.

In the meantime, if you want to take a chance, some possible solutions:

But by solving this problem with the range size limit, with tests and more tests you can reach a better solution of the optimal maximum size.

To set a range size I suggest using a fixed maximum size or a range table.

Fixed maximum size

Setting a maximum size for the delivered range is like saying that each request will deliver for example 100kb. then all requests delivered at most 100 Kb. But why "at most"? When you reach the end of the file and have less than 100 kb to deliver, then the range value has to be lower, so at most.

In the case of video delivery, the good use of the range can be an interesting download by allowing you to set things like, the video will always be loaded X seconds ahead.

The advantage is that it will always be a constant value and maybe decrease the complexity of the code.

The downside is that if a file is smaller than the set range will be fully loaded, and if it is larger, maybe the amount will have too many requests.

Table range

Using a range table of delivery bytes can be interesting as you will set ranges according to the size of the file being delivered. That is, for a small file is a range, for the medium is another and for a giant a third range.

For example:

Arquivo                    | Tamanho        | range máximo
pequeno 01                 | 10 bytes       | 100 kb
pequeno 02                 | 50 kb          | 100 kb
pequeno 03                 | 200kb          | 100 kb
médio 04                   | 1 Mb           | 200 kb
gigante                    | 1 Gb           | 1 Mb

References

  • I was really interested in this idea of limiting the ranges, problem is that I have no idea how to do it, currently running the videos by php I have the impression that they start loading faster than accessing the file directly

Browser other questions tagged

You are not signed in. Login or sign up in order to post.