Pseudo-streaming MP4/H264 video from PHP
After struggling for a while I managed to put together a PHP extension for (pseudo-)streaming video files encoded with the all-new H264 codec, based on the wonderful work of these guys , thus giving people the ability to seek into MP4 files by using PHP and any webserver they like (like Apache, NGINX etc.). Anyone who knows anything about this will know what a pain it can be. [Sorry, the demo server is no longer available since I’m currently using it in a separate context to develop an improved version of this package].
I will not waste time here with explaining the concept of pseudo-streaming and I will also assume that you know a bit of PHP and what this whole thing is about. So I’ll dive right in:
Here it is: download version 1.0 (beta).
This is basically a PHP extension. You decompress it into a directory of your choice and then compile it as follows:
phpize ./configure --enable-psstream make sudo make install sudo cp psstream.ini /etc/php5/conf.d sudo /etc/init.d/apache2 restart
The last two lines might differ for you depending on your Linux distribution and webserver of choice.
After this you take the psstream.php file and put it on the webserver path (wherever you desire) and use it from your player of choice (only JW FLV Media Player 4.2 supports MP4 streaming as of yet AFAIK).
PSSTREAM offers two functions:
psstream_flv($video_file_path [, $seek_offset_position]);
and
psstream_mp4($video_file_path [, $seek_time_position]);
The seek offset for FLV is a numeric position iside the FLV file while for MP4 it is a specific time value specified in (float) seconds. The psstream.php file is meant to be a simple interface for these functions.
Attention: The JW FLV Media Player must be properly called (using the flashvar streamer=lighttpd) in order for it to correctly send (h264) seek requests to psstream.php. These are the flashvar values needed to play mp4 files using PSSTREAM and JW player (this is the actual flashvars line in the SWFObject script):
s1.addParam("flashvars","image=preview.jpg&file=http://mydomain.com/psstream.php&type=video&id=video.mp4&streamer=lighttpd");
The id parameter is also required to properly transmit the actual filename to the streaming script since the file variable is used by the path to psstream.php (the player also sends the id variable when seeking). The type is needed since the file variable has a php extension and which confuses the player aboutit real type.
To stream regular FLV files you would use:
s1.addParam("flashvars","image=preview.jpg&file=video.flv&id=video.flv&streamer=http://mydomain.com/psstream.php");
The id is also used here as well since psstream.php (currently) ignores the file variable because the problem mentioned above (this behavior can be changed from psstream.php). I hope this inconsistency will go away in the near future.
Note that if your videos happen to be out-of-sync with the audio when seeking into h264 files then most likely your encoding process is the problem. See here for a procedure that seems to produce good results.
Hope this stuff helps and let me know how it works out for you.
Enjoyed this post?, why not subscribe to the RSS feed!
February 5th, 2009 at 2:36 am
Hi Valeriu,
Nice to see that the code is being picked up and used. :)
Just to keep you updated, there are now also plugins available for Apache and Nginx (next to Lighttpd).
Let me know if you have any feature requests, we’re always looking to improve on things.
Regards,
Arjen
http://h264.code-shop.com
February 6th, 2009 at 4:58 pm
Many thanks for sharing this!
February 6th, 2009 at 5:15 pm
@Joe: Glad to hear it :)
@Arjen: The code is excellent and is essential for a website I’m working on so, thank you!
February 9th, 2009 at 6:12 pm
For me, it works only if I disable the bandwidth limit functionality
ini_set(’psstream.bandwidth_limit’,0);
Tested on CentOS5 with apache 2.2 and lighttpd 1.4.20.
Anyway, it this extension is extremely usefull, since it allows you to “pseudo-stream” both flv and mp4 files from any webserver software on linux with PHP.
Thanks and keep up the good work!
Doru.
February 11th, 2009 at 5:44 pm
Do you now how it can be compiled for windows?
April 4th, 2009 at 10:44 pm
Hi there. I think I got everything installed properly but when I try to run the movie from the link below, I get a movie cannot be found message? I tried a direct url and a local reference but nothing seems to work? Argh… Can you take a look at see if you can see what I am doing wrong? Thanks so much for posting this. I hope I can get it working.
Hans
http://www.listingsmagic.com/jw_player2/mp4_player_test.php
April 5th, 2009 at 9:50 pm
@Hans Guts:
Hello, the problem is in your flashvars line (the script that I used at the demo site could not have worked for you since it uses a slightly modified version of the original player).
In the original form of the player (the SWF you have on your site) the player only sends the correct requests to psstream if it has the “streamer=lighttpd” parameter passed in the flashvars; the mp4 file path is then sent through the id parameter (i.e. “streamer=lighttpd&id=video.mp4″).
Please see the section marked above in red (in the post) to understand the issue, it is all explained there in detail.
Please tell me if you need more help, I’ll be glad to pitch in :D.
April 6th, 2009 at 1:22 pm
Great extension, quick question does it support duration? I have the extension working well but could not find the support for duration. Would be very useful?
April 14th, 2009 at 3:08 pm
[…] Pseudo-streaming MP4/H264 video from PHP | Paloş::Code.Blog() - This PHP extension allows you to start downloading a video file from a given offset time. This means you can jump to a point halfway through a movie without having to wait for the first half to load. […]
April 16th, 2009 at 2:04 pm
@Bryan: What exactly do you mean by duration? You mean to actually serve only a part of the file (limiting the length served)? This is not implemented, maybe when I make a bit of time I could look into it.
April 22nd, 2009 at 12:06 pm
Hi Valeriu,
many thanks for your work!
Can I ask you if the parameter settings for mp4 pseudostreaming (as given above) is still deemed to be correct:
s1.addParam(”flashvars”,”image=preview.jpg&file=http://mydomain.com/psstream.php&type=video&id=video.mp4&streamer=lighttpd”); ?
I tried many different combinations of this bunch of parameters but I never got it to work properly (with version 1.0 (beta) downloaded yesterday). Sometimes the video started but the pseudostreaming seek functionality never worked.
I then had a look at the source code of your demo and with some minor changes I managed to get it to work both with the JWPlayer embedded in Flex and the standalone version (embedded in HTML via swfobject):
Flex:
private var file:String = “player.swf?file=kanea_maa.mp4&” +
“streamer=http://192.168.193.129/psstream.php?id=kanea_maa.mp4&” +
“controlbar=over&” +
“resizing=false”;
HTML:
var s1 = new SWFObject(’flash/player.swf’,'player’,'400′,’300′,’9′);
s1.addParam(’allowfullscreen’,'false’);
s1.addParam(’allowscriptaccess’,'always’);
s1.addParam(”flashvars”,”file=kanea_maa.mp4&streamer=http://192.168.193.129/psstream.php?id=kanea_maa.mp4&image=img/annex-icon.gif”);
s1.write(’preview’);
I’m using XAMPP (-> Apache 2) in an ubuntu vmware image as pseudostreaming solution.
Cheers, Thomas
April 22nd, 2009 at 12:09 pm
Unfortunately all the tags in my code snippets were eaten up in my previous post. I’ll have another try:
Flex:
private var file:String = “player.swf?file=kanea_maa.mp4&” +
“streamer=http://192.168.193.129/psstream.php?id=kanea_maa.mp4&” +
“controlbar=over&” +
“resizing=false”;
<mx:SWFLoader id=”player” source=”{file}”
maintainAspectRatio=”false” scaleContent=”false”
width=”320″ height=”240″ minHeight=”200″
init=”loaderFinished(event);”
resize=”resizePlayer();”>
</mx:SWFLoader>
HTML:
<script type=’text/javascript’>
var s1 = new SWFObject(’flash/player.swf’,'player’,'400′,’300′,’9′);
s1.addParam(’allowfullscreen’,'false’);
s1.addParam(’allowscriptaccess’,'always’);
s1.addParam(”flashvars”,”file=kanea_maa.mp4&streamer=http://192.168.193.129/psstream.php?id=kanea_maa.mp4&image=img/annex-icon.gif”);
s1.write(’preview’);
</script>
April 22nd, 2009 at 12:15 pm
A question to everybody: has anyone ever managed to get mp4 pseudostreaming with this PHP module properly up and running with FlowPlayer (FlowPlayer manages to do mp4 pseudostreaming with the original h264.code-shop module)? If so, would you mind to share the code snippets to make the correct call to FlowPlayer?
Thanks, Thomas
April 22nd, 2009 at 5:15 pm
[…] Оригинальный пост в блоге Palos. […]
April 27th, 2009 at 10:09 pm
Thomas,
It seems only JW FLV Player supports this type of h264 pseudo-streaming.
June 6th, 2009 at 11:33 pm
FYI TO ALL
psstream_flv and psstream_mp4 do not work when attempting to load the files through Internet Explorer over SSL (https).
I am guessing its a header issue. Presuming that these plugins output headers? I’ve tried using PHP to output proper headers before calling psstream plugins, but to no avail.
I can use xmoov-php pseudo-streaming script (basically php file-seeker) for FLV files and it works fine over SSL in IE. As soon as I switch to psstream_flv, IE fails to work over SSL. In JW Player, error comes back as “video not found”
June 7th, 2009 at 12:05 am
@Grey:
Did you try using psstream_flv without SSL? Have you made sure the player send the correct parameters to psstream? Read the section in red displayed above carefully.
June 7th, 2009 at 1:04 am
What about the license restrictions for this extension?
Is it fine to use it in commercial environment?
June 7th, 2009 at 1:19 am
The main restriction for this extension is that it can *not* be used to stream pornographic or erotic material! I can not agree with that! Aside of that, you are completely free to use it in commercial environment.
June 8th, 2009 at 5:52 pm
Hi
I tried to install your script and it seemed to go all fine, but when I try to load a video I get this error : “Video stream not found : ”
I also tried run_tests.php and got this error :
ERROR: environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!
June 12th, 2009 at 2:20 pm
I got some problems …
I have this structure:
myhost.com/mediaplayer/psstream.php
myhost.com/mediaplayer/predator.mp4
myhost.com/mediaplayer/index.php (where the player actually is running)
I’ve check and everything is reachable from the outside (internet) and the psstream module is working !
Refering to the demo and the howto, I tried the following configurations :
s1.addParam(”flashvars”,”file=predator.mp4&streamer=http://myhost.com/mediaplayer/psstream.php”);
-> ERROR: Video not found predator.mp4
s1.addParam(”flashvars”,”image=predator.jpg&file=http://myhost.com/mediaplayer/psstream.php&type=video&id=predator.mp4&streamer=lighttpd”);
- > ERROR: Video not found http://myhost.com/mediaplayer/psstream.php
Can you help me please ?
July 11th, 2009 at 4:30 pm
Hi,
Thanks for the script.
I run into few problem, the script was working great with apache-prefork but then I needed to switch to apache-worker.
The problem with worker is that various macro TSRMLS are set. (They remain unset with prefork).
And two functions used in your script are prototyped this way in SAPI.C:
SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC);
SAPI_API int sapi_send_headers(TSRMLS_D);
So I modified psstream.c adding the variable tsrm_ls.
line 123 : sapi_header_op(SAPI_HEADER_ADD, &psstream_sapi_header_line, tsrm_ls);
line 128 : sapi_header_op(SAPI_HEADER_REPLACE, &psstream_sapi_header_line, tsrm_ls);
line 130 : #define SEND_HEADERS sapi_send_headers(tsrm_ls);
And now it compile fine, spend couple hours so if it can help anyone.
August 17th, 2009 at 2:00 pm
Veleriu,
This looks like a great piece of work and I would like to modify it so that I can use it with my cutom Flash Player and shared windows hosting account.
The shared hosting thing means I suspect that I can’t instal it as an extension as per your process.
What I think I can do is create an extension as a .dll and store it in a an extensions path on my server (and point to this path in my PHP.ini).
I am about to embark on this voyage of discovery .. any help would be appreciated (and If I get there I will post the results back here).
First peice of help would be .. Am I on the right track, and is it possible?
If so what aspects of the current code should be dropped?
What will have to be added?
Thanks
Jim
August 18th, 2009 at 9:37 am
Hello Jim, the way I build this extension is actually pretty much the generic way one would do it under any Linux distro, and at least in theory, I think you could build psstream on Windows following “the generic way of building a PHP extension under Windows” (whatever that may be - I’m sure there are plenty of tutorials on the net for that).
There is a problem though, as far as I can tell, the real issues that usually make code incompatible between Windows and Linux are things like low/level routines, I/O, access to hardware and so on.
The problem is that psstream uses moov.c (from Cinelarra project) which is the really the smart bit of the whole thing, and which does a lot of complex file I/O.
So, although I am unfamiliar with porting PHP extensions to Windows, I don’t think this is the real problem. You should first check if the moov.c file contains any operations that are incompatible with Windows (or maybe missing).
I’m really sorry I can’t help further with this.
August 25th, 2009 at 12:06 am
Thanks,
i have been really busy on other stuff of late, but hope to get back to this next week and will check out windows moov.c
Thanks again for the heads up.
Jim
August 29th, 2009 at 1:03 pm
The Demo Link is dead :-/
August 30th, 2009 at 9:11 am
Yup, I’m sorry about that, I actually forgot about the demo. I use that server to develop a new version of this lib. If a demo is still really needed, I’ll install a new one somewhere more stable.
September 1st, 2009 at 7:24 pm
Hi,
Thanks a lot for your excellent work firstly, I have tried to find this kind of library for several days. But I still have some problem when playing flv or mp4 files, it reports “file not found” error. Besides, I also want to confirm whether this library can support streaming of both normal FLV and FLV with H264?
Thank you again!
November 9th, 2009 at 9:17 pm
Hi,
Thanks for this php extension but,
Can you write this directly in a php class (without ext) ?
Regards, bernedef.
November 9th, 2009 at 10:45 pm
@Fabien: That might be possible but the fact is that the part that does the actual parsing of the movies is written in C and is quite sizable. Porting that to PHP would be not only hard but I would suppose also unrecommended, since the PHP version would be slower and would use up more memory.
I think the best scenario would be to have a separate streaming micro-server that would wrap the h264 parsing functionality and would only serve mp4/flv files. This is quite doable, and I intend to make it happen quite soon (because I need it).
I agree that the PHP extension is a bit awkward to compile and use; it also uses more memory and is slower since it implies that the whole PHP virtual machine must be started for streaming to be done. The micro-server would be faster, lighter and a lot safer to use.
November 10th, 2009 at 8:43 pm
Can you compile me your extension (.so and .dll) ?
Thanks.
November 24th, 2009 at 7:39 pm
Salut :)
Do you know if peteava.ro is using your extension or.. something else?
i like how it’s working on big files so i’m wondering what are they using because personally on my tests the code-shop method in nginx/lighttpd gave me few times the i/o wait of usual downloads under some load..
multumesc.
November 25th, 2009 at 12:54 am
Yeah, http://peteava.ro does use this extension! However in a few days they will move from using this extension (which must use apache2+mod_php or nginx+php-fastcgi) to using a standalone streaming micro-server that yields much higher performance! I will return with information here when the streaming server will be ready (should be a few days) so everyone can use it too!
December 17th, 2009 at 12:44 pm
Hi, I am trying with JW Player 5, and it dont do streaming, too, i must write:
so.addVariable(”file”, “‘http://myurl/psstream.php?id=/mypath/video.mp4″); for that it work.
I have tried too with:
so.addVariable(”file”, “‘http://myurl/psstream.php?id=/mypath/video.mp4″);
and
so.addVariable(”id”, “/mypath/video.mp4″);
and nothing… it dont work.
Yes, I have added:
so.addVariable(”streamer”, “lighttpd”);
Any help? Very thank for this script, i will can protect access to my video files now! :)
December 17th, 2009 at 12:59 pm
Ok, it yes work with version 4, thanks you!!!
January 5th, 2010 at 2:27 pm
halooo
i want to ask
if i want to make web server video streaming mp4 h264 with ubuntu what packet i must install???and what script php must i change…
thx..
January 19th, 2010 at 11:10 pm
Hi,
I installed the module and is working fine with mp4 video files. Then I tried with an AAC file and the resulting data is not recognized by VLC player.
This is how I tested it:
1) Test original AAC file (40 seconds long) with VLC in my workstation
2) Upload file to my test web server
3) wget “http://192.168.0.41/test/psstream.php?id=music.mp4&start=10″
4) Download resulting file to my workstation and test with VLC. VLC does not play it
File was converted from WAV with Nero AAC Encoder in variable bit rate mode (-q 0.15)
Is it possible to use this fantastic module with AAC files?
January 20th, 2010 at 11:08 pm
I found the solution. The AAC file encoded by Nero should be muxed. I used ffmpeg:
ffmpeg -i music.aac -acodec copy -f mp4 music.mp4
Then, change the MOOV position with
qt-faststart music.mp4 musicOK.mp4
Now, you can access musicOK.mp4 via http pseudostream.
January 27th, 2010 at 6:10 pm
Thank you so much for this extension ! you saved my stream ;-)
January 30th, 2010 at 10:48 pm
[…] yes! I am sure that many of you already know about psstream (the PHP streaming extension I made a while back). Well, many things happened since then and I came […]
January 30th, 2010 at 10:57 pm
Hi everybody, please see my latest post regarding your issues. The problems you had with psstream (or around it) are all too familiar to me.
Thanks!
June 2nd, 2010 at 3:18 pm
Man, you are indeed awsome :)
i will soon make this thing ready for ClipBucket ;)
June 2nd, 2010 at 3:51 pm
@Arslan: awesome! In about 2 or 3 weeks Loomiere/Stream 2.0 will be ready. It will pack a HUGE lot of ass-kicking sweetness! :)
Maybe you could then provide your users with a professional/commercial version of the ClipBucket services based on L/S-2.0.
June 5th, 2010 at 1:02 am
[…] unless you have shell access to your Linux server and wish to try compiling a PHP module like this or you are using lighttpd as your web […]
August 20th, 2010 at 8:57 am
This article helps me better understand the mechanism of portable video players. Thanks.
November 6th, 2010 at 6:55 pm
how to compile it on windows ?
November 6th, 2010 at 11:21 pm
@nero: Well that would need some porting actually. It’s definitely not a straight-forward job :(. Do you really need this to run under Windows? I’m curious…
January 10th, 2011 at 2:04 pm
Damn this works good. Amazing.
February 9th, 2011 at 9:53 pm
Just wanted to say a big thanks for your work. I’m starting to play with it as I write this.
Cheers,
Andrei
July 5th, 2011 at 11:45 pm
Hi Valeriu,
do you know if your php extension also works together with flowplayer (www.flowplayer.org) and the flowplayer pseudostreaming plugin? http://flowplayer.org/plugins/streaming/pseudostreaming.html
and what would then be the correct syntax to call your php extension?
thanks very much!
Tom
July 27th, 2011 at 3:16 am
I’m starting to play with it as I write this.
November 16th, 2011 at 11:56 pm
Hello,
everthing works fine for me, but if I jump to a certain position via “&start=” there’s no sound. Without offset sound is fine. I’m using h264 with ACC. Any ideas?
Alex