Skip to content

Instantly share code, notes, and snippets.

@ranacseruet
Last active February 19, 2024 17:10
Star You must be signed in to star a gist
Save ranacseruet/9826293 to your computer and use it in GitHub Desktop.
PHP VideoStream class for HTML5 video streaming
<?php
/**
* Description of VideoStream
*
* @author Rana
* @link 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=2592000, public");
header("Expires: ".gmdate('D, d M Y H:i:s', time()+2592000) . ' 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();
}
}
@DJ1TJOO
Copy link

DJ1TJOO commented Mar 19, 2019

I want to stream a .mp4 but it wont work and gives no error messages

I have this code:
index.php:
<video controls preload="auto" src="http://localhost/videostream/test.php" width="100%"></video>
test.php:

<?php
include_once 'videostream.php';
$stream = new VideoStream("video.mp4");
$stream->start();exit();

videostream.php:
is the lib

Already solved it the mp4 file was to big

@juliogancino
Copy link

Thank you that was so helpfull, but it's possible to play the video in a <\video> element ?

http://demo.codesamplez.com/html5/video

@vtuykom
Copy link

vtuykom commented Nov 5, 2019

Thank you for this script
I am looking for a solution to can start and stop de streaming like I would decide.
If I have a video of 50s and I would see a piece of this video
For example between the 30de second and de 33de second.
Can somebody my help please ?
Thank you
Alain

@ericol
Copy link

ericol commented Nov 16, 2019

A while ago, I was looking for a stream server. I really did try to find a solution for that, to no avail.

Lo and behold, today it occurred to me that "may be" there was a script available that would cover my needs. So, I did search for one first in PHP (I can handle python, but I'm a lot more proficient in PHP) and I found this.

I gotta say, man. What a surprise.

This one works flawlessly, and covered completely my needs (that happen to be quite special).

Dude, I'm incredible grateful for this.

@Emilio2233
Copy link

Emilio2233 commented Mar 4, 2020

Dear Ranacseruet

If the streaming starts i cannot leave the page until the video has loaded completely. Is there a way to stop the streaming if a visitor wants to leave the page ? (It happens in chrome, in firefox you can leave the page)

@BlackIQ
Copy link

BlackIQ commented Apr 21, 2020

Very useful. Thank you.

how did you use that ?
I have this script in a folder name "live" .
So when I open it -> 127.0.0.1/live , it does not show anything !
where should I put video ?
my video is in that folder too .
Please help me !

@dragona
Copy link

dragona commented May 5, 2020

Very useful. Thank you.

how did you use that ?
I have this script in a folder name "live" .
So when I open it -> 127.0.0.1/live , it does not show anything !
where should I put video ?
my video is in that folder too .
Please help me !

1- Download the DownloadStream.php
2- Save it in the root of your server (online or local)
3- Create a second file and name it "index.php"
4- Copy the following code in your "index.php"
<?php include "VideoStream.php"; $filePath = "demo.mp4"; $stream = new VideoStream($filePath); $stream->start();

5- Copy and paste the video you would like to stream in the same root (same location as your VideoStream and index files)
6- Rename the video file to be "demo.mp4"

@kezern
Copy link

kezern commented May 20, 2020

I'm having some issues.
Allowed memory size of 134217728 bytes exhausted (tried to allocate 307971432 bytes)
I have already increased the memory_limit parameter, but it still does not work....

@saikatstutorial
Copy link

Can someone put an example on how to stream aws S3 video using this VideoStreamer class?

@carcinocron
Copy link

carcinocron commented Sep 22, 2020

I am using the <video> tag (only test chrome so far) and my videos keep getting stuck "buffering" randomly starting around 40s up to 3 minutes. My sample video isn't much longer. I've never been able to finish watching a video. Manual seeking works (in general and when stuck buffering) but if I try to watch it straight through it always gets stuck buffering.

@rorenzo
Copy link

rorenzo commented Dec 15, 2020

hi, I'm using your code, I made just a little mod. It work very well on windows (all browser), but in MACOS (all browser) the video does not play. any idea? thanks

@lizardpeter
Copy link

Is there a way to use this and prevent users from downloading the video? The video can be downloaded by just right clicking after the entire video has been played. I am looking for a way to prevent it from being downloaded (like streaming services use).

@korosh-abbasy
Copy link

thank you so much
the things I did

add the first line in part setHeader()
session_write_close();


line 110
print( $data ) ;


@marlon33
Copy link

Has anyone managed to block downloads?
I made this code, but it only works in chrome and Opera, firefox does not work, anyone to help?

if(isset($_SERVER["HTTP_REFERER"]) && $_SERVER['HTTP_SEC_FETCH_SITE'] == 'same-origin'){
  $filePath ="videos/depoimentos/".$filePath.".mp4";
  if(file_exists($filePath)){
    $stream = new VideoStream($filePath);
    $stream->start();
  }else{
    echo "Error!";
  }
}

@mathe42
Copy link

mathe42 commented Jul 28, 2021

Is there some simple changes to use it with http2=http/2=h2 ?

I changed for example

header('HTTP/1.1 416 Requested Range Not Satisfiable');

to

header('', false, 416);

So no HTTP/1.1 in my code...

The class always responsed with a 416...

@mathe42
Copy link

mathe42 commented Jul 28, 2021

Never mind now it works maybe some strange caching...

@rayj00
Copy link

rayj00 commented Oct 13, 2021

I have an existing Webrtc one2many broadcasting application working. I also have a php based social website that is working. I need to integrate the Webrtc into the social website. Any recommendations how to go about implementing this?

@David263
Copy link

Doesn't work for me when I use the default video player of the browser. In Firefox, it won't change position. In Chrome, it won't enable the player. Your published example, http://demo.codesamplez.com/html5/video, seems to work everywhere because the player doesn't use the library code. It has the video path specified explicitly.

@marlon33
Copy link

Whta are you try to do??

the code work for me

@David263
Copy link

David263 commented Jul 15, 2022

I gave up on this library and experimented and created my own code that works. I have no idea what the problem was. Thanks anyway. Maybe I didn't understand exactly how and where to use this code.

@marlon33
Copy link

It's awesome, can you share your code??

@David263
Copy link

David263 commented Jul 15, 2022

It's still under development. It works great, but fails on Safari/MacOS. I am having great difficulty figuring out how to debug it on Safari, which seems to not have Dev Tools. It is an app that asks the user for a password, then provides a list of video files as buttons. Clicking a button plays the file, with repositioning, using the default browser video player. The entire app is a bit lengthy for simply posting, but eventually I can release it as a repository.

@marlon33
Copy link

Understand, if you need some help, just put here

@bondan20
Copy link

bondan20 commented Sep 1, 2022

for mp4 work sir
how to play m3u8 Sir?

@marlon33
Copy link

marlon33 commented Sep 2, 2022

for mp4 work sir how to play m3u8 Sir?

It's note possible, becouse the file m3u8 is a stream file

@bondan20
Copy link

bondan20 commented Sep 8, 2022

for mp4 work sir how to play m3u8 Sir?

It's note possible, becouse the file m3u8 is a stream file

not work sir,
please create streaming for m3u8 sir :D heheheh

@himadrisaha89
Copy link

Working fine for me for small size video file but for big size file I am getting net::ERR_CONTENT_LENGTH_MISMATCH 206 (Partial Content) in chrome console and of course the status is failed in chrome network tab.
Any Help !!!

@David263
Copy link

David263 commented Sep 8, 2022

himadrisaha89, this usually means that the software that is sending the streaming file is either calculating or formatting the size information that it sends to the client player incorrectly. If you look at the network information in a browser developer tool, you might be able to see the problem.

@michalcz17
Copy link

Is it possible for the controls not to be displayed on that page? Or at least not be able to download the video? or do you need a script for that?

@micilini
Copy link

micilini commented Nov 16, 2022

This code need UPDATE, he cannot read EXTERNAL URL VIDEO, only local videos, for solve this problem I create a new package that works with laravel, check it out: https://github.com/micilini/video-stream.

My Package can handle local and external video files 👯

@WordpressArtist
Copy link

I got an error please help

filesize(): stat failed for http://laraveltest.test/ElephantsDream.mp4

got error here. from class VideoStream
$this->size = filesize($this->path);

where code

$a = 'http://laraveltest.test/ElephantsDream.mp4'; // public folder video
$stream = new VideoStream($a);
return response()->stream(function() use ($stream) {
$stream->start();
});

Any help please using laravel 9

@carcinocron
Copy link

trying to access a file using http:// does not look valid to me, probably you want something like one of these:

$a = storage_path('ElephantsDream.mp4');
$a = public_path('ElephantsDream.mp4');
$a = asset('ElephantsDream.mp4');

depending on where the file is physically in your laravel directory.

@WordpressArtist
Copy link

@carcinocron thanks so external url not supported right ?

@jackbaron
Copy link

Is there a way to do this same process but with AJAX?

@vincentckk
Copy link

Here is my code. For sure require to check URL and File. Just assume file path / URL is correct.
// Check starting string
if (substr($this->path, 0, 3) == 'htt' || substr($this->path, 0, 3) == 'ftp') { /* External URL - allow_url_fopen=On /
$headers = get_headers($this->path, 1);
$this->size = $headers["Content-Length"];
}else{ /
Internal file */
$this->size = filesize($this->path);
}
:
//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);
// Use stream_get_contents instead of fseek
echo stream_get_contents($this->stream, -1, $this->start);

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