4

I'm writing a web app that serves H.264 encoded MP4 video. In Chrome and Safari, it does this via an HTML5 video tag.

In order to control access to these videos, their contents are served via PHP using a really simply mechanism:

header('Content-type: video/mp4');
readfile($filename);
exit;

No matter what I do, the videos will not stream. Additionally:

  • If I change the source code to serve the files directly, using the same video tag but linking to an Apache-served copy of the video with no PHP pass-through, streaming works fine.
  • Even when streaming doesn't work, I can always right click on the greyed-out HTML5 player and download the file through the PHP pass-through - and it plays great offline.

Any ideas? I'm pulling my hair out!

Ben Werdmuller
  • 185
  • 2
  • 9

3 Answers3

7

Maybe. Try adding also the content length header:

header('Content-length: '.filesize($filename));

If this still doesn't work, check for any output before readfile (echo's or whitespace before <?php). Check also that you don't have whitespace after ?> or simply omit ?> (it's not mandatory if you have nothing after).

As Bruno mentioned, to support streaming, you also need to obey the Range header. Here's a simplified example that respects only the left bound:

if (empty($_SERVER["HTTP_RANGE"])) {
    //do your current stuff...
}
else { //violes rfc2616, which requires ignoring  the header if it's invalid
    preg_match("/^bytes=(\d+)-/i",$_SERVER["HTTP_RANGE"], $matches);
         $offset = (int) $matches[1];
    if ($offset < $filesize && $offset >= 0) {
        if (@fseek($fp, $offset, SEEK_SET) != 0)
            die("err");
        header("HTTP/1.1 206 Partial Content");
        header("Content-Range: bytes $offset-".($filesize - 1)."/$filesize");
    }
    else {
        header("HTTP/1.1 416 Requested Range Not Satisfiable");
        die();
    }
        //fread in loop here
}
Artefacto
  • 96,375
  • 17
  • 202
  • 225
0

See comments!

Using readfile is not recommended for streaming video files since it loads the whole file into memory before outputting. This causes serious problems with memory running out.

Try reading and outputting the file chunk by chunk.

zaf
  • 22,776
  • 12
  • 65
  • 95
  • 1
    That's not true. In fact, this is the most efficient way to do it (using PHP and excluding `virtual`). I don't know where you got that idea. – Artefacto Jul 11 '10 at 11:14
  • Can you point to some references? As there are plenty of references against. Example: http://teddy.fr/blog/how-serve-big-files-through-php – zaf Jul 11 '10 at 13:15
  • And another http://coding.derkeiler.com/Archive/PHP/php.general/2006-10/msg00708.html – zaf Jul 11 '10 at 13:20
  • 1
    @zaf The `readfile` implementation [calls `php_stream_passthru`](http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/file.c?revision=298881&view=markup#l1401), which uses [nmmap](http://en.wikipedia.org/wiki/Mmap) if possible, otherwise loops 8192 bytes at a time (see [here](http://svn.php.net/viewvc/php/php-src/trunk/main/streams/streams.c?revision=299466&view=markup#l1208)). – Artefacto Jul 11 '10 at 14:29
  • @Artefacto Straight to the source! I was mistaken, thanks for enlightening me (and hopefully others). – zaf Jul 12 '10 at 07:04
  • i see that this comment is old, but i want to say that despite all, zaf is saying the right, i had many problems using readfile on big files and i solve using readfilechunk implementation function. – albanx Feb 12 '11 at 00:43
  • @albanx I seriously doubt it. Most likely, you were using output buffering and in your 'readfilechunk' function you were flushing the output buffer and that's why it worked. But it would be more efficient to use `readfile` and disable output buffering before. – Artefacto Feb 23 '12 at 11:34
  • probaly you are right, but the problem was not that, i just can't remember now but the sever must be configurated to support streaming – albanx Feb 23 '12 at 11:38
0

When streaming files to HTML5 Embedded video player you still have to add headers that inform the player with information about the video.

you can't just expect to run a read readfile() command and things will magically work, sorry bud, but programming is not that easy. (Wish it was).

heres a small application you can use to stream properly or just learn from.

http://stream.xmoov.com/download/xmoov-php/

RobertPitt
  • 56,863
  • 21
  • 114
  • 161