Php: iPad Does Not Play Mp4 Videos Delivered by PHP, But If Accessed Directly It Does

PHP: iPad does not play MP4 videos delivered by PHP, but if accessed directly it does

Wow, that was tough!



**1. First major Problem**

It turned out to be no encoding problem but a problem with the mp4 container header set during the video conversion process - iPad has obviously a problem with MP4 videos that are prepared for progressive streaming.

First I discovered that in a conversation here. After converting a video I always used the tool MP4 Fast Start to prepare the video file for progressive stream. This was necessary to stream the video file to the Flash Player in pieces (progressively), so it did not load the entire file (and the user had to wait).

With Handbrake there is a similar setting, that is called Web Optimized. It does the same:

Web Optimized
Also known as "Fast Start"
This places the container header at the start of the file, optimizing it for streaming across the web.

If you enable this and convert your video, the iPad will not play the video file! Instead you get the error "The operation could not be completed".

ipad strikedthrough play button

Check out and test it yourself: video test resources.



**2. Second Problem**

In production environment I always used PHP to check the referer. As I found out, the iPad does not send the referer information. This also prevents the streaming and you will also see the cannot-play-symbol (striked-through play icon).



**3. Third Problem**

I could not find out why, but the iPad only accepts the video streaming from this script http://ideone.com/NPSlw5

<?php
// disable zlib so that progress bar of player shows up correctly
if(ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'Off');
}

$folder = '.';
$filename = 'video.mp4';
$path = $folder.'/'.$filename;

// from: http://licson.net/post/stream-videos-php/
if (file_exists($path)) {
// Clears the cache and prevent unwanted output
ob_clean();

$mime = "video/mp4"; // The MIME type of the file, this should be replaced with your own.
$size = filesize($path); // The size of the file

// Send the content type header
header('Content-type: ' . $mime);

// Check if it's a HTTP range request
if(isset($_SERVER['HTTP_RANGE'])){
// Parse the range header to get the byte offset
$ranges = array_map(
'intval', // Parse the parts into integer
explode(
'-', // The range separator
substr($_SERVER['HTTP_RANGE'], 6) // Skip the `bytes=` part of the header
)
);

// If the last range param is empty, it means the EOF (End of File)
if(!$ranges[1]){
$ranges[1] = $size - 1;
}

// Send the appropriate headers
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header('Content-Length: ' . ($ranges[1] - $ranges[0])); // The size of the range

// Send the ranges we offered
header(
sprintf(
'Content-Range: bytes %d-%d/%d', // The header format
$ranges[0], // The start range
$ranges[1], // The end range
$size // Total size of the file
)
);

// It's time to output the file
$f = fopen($path, 'rb'); // Open the file in binary mode
$chunkSize = 8192; // The size of each chunk to output

// Seek to the requested start range
fseek($f, $ranges[0]);

// Start outputting the data
while(true){
// Check if we have outputted all the data requested
if(ftell($f) >= $ranges[1]){
break;
}

// Output the data
echo fread($f, $chunkSize);

// Flush the buffer immediately
@ob_flush();
flush();
}
}
else {
// It's not a range request, output the file anyway
header('Content-Length: ' . $size);

// Read the file
@readfile($path);

// and flush the buffer
@ob_flush();
flush();
}

}
die();

?>

I hope this information will help others to cope with the problem.


Update: Three months later in production environment, some of my users still reported playback issues. There seems to be another problem with Safari. I advised them to use Chrome for iPad, this fixed it.




PS: A couple of days of research and hassle only to play a video file that, by the way, runs on all other devices. This again proves to me that Apple got successful just because of great marketing, not because of great software.

MP4 plays when accessed directly, but not when read through PHP, on iOS

If you are handling it yourself like that, then you will need to handle byte-range requests yourself as well.

mp4 file through php not playing as html5 video

Finally I've found a way to make it work

header("Content-Type: $mediatype");

if ( empty($_SERVER['HTTP_RANGE']) )
{
header("Content-Length: $filesize");

$fh = fopen($file, "rb") or die("Could not open file: " .$file);

# output file
while(!feof($fh))
{
# output file without bandwidth limiting
echo fread($fh, $filesize);
}
fclose($fh);
}
else //violes rfc2616, which requires ignoring the header if it's invalid
{
rangeDownload($file);
}

It is working in direct link of the php file and inside html5 video tag.

But in order to work in Flowplayer (and maybe in other flash/html5 players) you need to add a mp4 extension (eg. view.php?id=XXX&file=type.mp4)

HTML5 audio with PHP script does not work on iPad/Iphone

Try remove header("Accept-Ranges: bytes"); as your not sending a portion of the file.
Remove the header("X-Powered-By: "); as Apache serves that anyway

$etag = md5(serialize(fstat($fp))); 
fclose($fp);
header('Etag: '.$etag);

^^ Add an Electronic Tag

And give it a go!

Import Video from URL and directly pass to visitor for download

Try this in your download-video.php maybe?

<?php

$vidFile=$_GET["file"];

$videoURL = "https://another-hosting.org/$vidFile";

header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=video.mp4");
header("Content-Type: video/mp4");

readfile($videoURL);


Related Topics



Leave a reply



Submit