1

How do you get the size of a portion of a video? I want to get the size of one minute of a video. Is this possible?

I am making a php video streaming script and I realized that you cannot skip forward. This is what I plan to do: If a user skips forward one minute, I calculate the size of one minute of the video. Then I echo out the video, but skip the first minute.

This is my current code:

function readfile_chunked($filename, $retbytes = TRUE) {
    $buffer = "";
    $cnt = 0;
    $handle = fopen($filename, 'rb');
    if ($handle === false) {
        return false;
    }
    while (!feof($handle)) {
        $buffer = fread($handle, CHUNK_SIZE);
        echo $buffer;
        ob_flush();
        flush();
        if ($retbytes) {
            $cnt += strlen($buffer);
        }
    }
    $status = fclose($handle);
    if ($retbytes && $status) {
        return $cnt; // return num. bytes delivered like readfile() does.
    }
    return $status;
}

I also have a content-type header that I didn't include in the code above.

Thanks for all your help!

Nathan
  • 1,321
  • 1
  • 18
  • 32
  • You mean the filesize that comprises a minute of video? Almost impossible to calculate accurately because of the compression methods applied... the number of frames in one minute? so you can jump to frame 1560 if it's 26 fps? – Mark Baker Jul 12 '14 at 22:17
  • @MarkBaker It doesn't have to be exact, but at most a few seconds off. – Nathan Jul 12 '14 at 22:21
  • still not practical, even as an estimate.... compression is typically based on identifying only those pixels that vary from one frame to the next; so certain portions can be highly compressed, others much less so.... you're really better off identifying the framerate, and then stepping forward based on fps – Mark Baker Jul 12 '14 at 22:25

1 Answers1

1

Its not how "skipping" is done.

What you should be doing is looking for the HTTP_RANGE headers that will be sent by the player.

Within your PHP you need to add and then handle the header('Accept-Ranges: bytes'); header.

So when a user clicks to skip forward in the video the player will send a $_SERVER['HTTP_RANGE'] to the server, you then use this to seek to the part of the file for output.

Here is and example (untested):

<?php 
...
...

//check if http_range is sent by browser (or download manager)
if(isset($_SERVER['HTTP_RANGE'])){
    list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
    if ($size_unit == 'bytes'){
        //multiple ranges could be specified at the same time, but for simplicity only serve the first range
        //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
        list($range, $extra_ranges) = explode(',', $range_orig, 2);
    }else{
        $range = '';
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        exit;
    }
}else{
    $range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end   = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1)){
    header('HTTP/1.1 206 Partial Content');
    header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
    header('Content-Length: '.($seek_end - $seek_start + 1));
}else{
    header("Content-Length: $file_size");
}
header('Accept-Ranges: bytes');

...
...
?>

There is also a previous question here you may find usefull, which will be much easyier to implement.

Community
  • 1
  • 1
Lawrence Cherone
  • 46,049
  • 7
  • 62
  • 106
  • Uh... Currently I cannot even skip the video: My php does not receive any request and my player (html5 video) doesn't allow that. I use html5 video by setting the source of the video to my php script. Thanks for your quick response! – Nathan Jul 12 '14 at 22:38
  • So there is no PHP involved yet with your script, just HTML video tag? – Lawrence Cherone Jul 12 '14 at 22:49
  • There is a php script involved: the video tag src is the php script. Also your other link works, digging into it right now :-) Thanks for your help – Nathan Jul 12 '14 at 22:50
  • np, im just abit confused, you want the skipping feature but you think you need to do it your way (by calculation), which is logical.. but its not how its done. Even a single byte thats not expected in the stream and it wont work, the player would just stop. It just sound like an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) now. I can put a working example on github if you like, gimme summing todo for 20mins ;p. – Lawrence Cherone Jul 12 '14 at 22:57
  • It's working now with your stream function (on the other page) but I'm confused about it and don't know what it's doing. Could you please walk me through it? I updated my question to show my current code. Thanks! – Nathan Jul 12 '14 at 23:08
  • I made an example, https://github.com/lcherone/Simple_Video_Stream ... fundementally what happens is that when you set `header('Accept-Ranges: bytes');` it tells your browser its ok to send range headers to the server. It is a range of data that is requested. The actual value will be something like "bytes=0-1023"...this tells you that the browser wants bytes 0 up to and including 1023, so 1KB of data. You then parse these values in PHP to seek to that part of the file and the output from there till the end of file. – Lawrence Cherone Jul 12 '14 at 23:14
  • Thanks for everything, my only regret is that I do not have enough reputation to +1 you. – Nathan Jul 12 '14 at 23:47