Skip to content

Instantly share code, notes, and snippets.

@BackFront
Last active May 27, 2023 16:04
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save BackFront/3908f6a4810b4440d05daf7b100cd7a8 to your computer and use it in GitHub Desktop.
Save BackFront/3908f6a4810b4440d05daf7b100cd7a8 to your computer and use it in GitHub Desktop.
Pseudo Streaming MP4’s with PHP

So I’ve been working on a video hosting project for most of the year and ran into issues while trying to push all storage files thru a PHP script. For proper tracking of embedded videos this was/is a must. If you’re having this problem and can’t find a solution, maybe this will help…

The below code will pseudo stream any MP4 file on any browser (including iPads/tablets) with all functionality working properly (seek forward, seek backwards and displays correct time). This code has also been tested with Longtail JWPlayer 6 and HTML5 players.

If you’re interested in an advanced version of this script, I currently have an unreleased version which includes automatic rate limiting (buffer rate). I’m also playing with other ideas to further enhance it. If you have any suggestions or questions either contact us or leave a comment at the bottom.

I have added the script to GITHub so everyone can contribute to ehance this code. Please feel free to contact me if you have any questions. https://github.com/tuxxin/MP4Streaming

<video controls="" width="400">
<source src="http://66.128.61.175/reel/1cc976948e74aa62f7a7fde16e64fb6b/360p" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<?php
$file = 'video360p.mp4';
$fp = @fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
//header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $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 $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
?>
@geri777
Copy link

geri777 commented May 16, 2018

Genius! Really great.
Why did you comment out "Accept-Ranges" ?

@toxiicdev
Copy link

Can I advice you to use fstat and read blocks count & block size instead of doing that kind of buffer?

@hackstarsj
Copy link

Brilliant Thank you very much :) 👍

@dungla2011
Copy link

it's really great!!!
how it's simple like that :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment