首页 > PHP> PHP返回视频流给IOS播放-2014-07-18更新

PHP返回视频流给IOS播放-2014-07-18更新

2014-04-24 14:43:38 发表评论 阅读评论 1435 人阅读    

通过手机上传视频,然后返回URL给IOS进行播放,因为播放地址是通过PHP读取然后返回的,在网页上正常播放,但是在IOS就无法播放。

以下是header头部信息:

HTTP/1.1 200 OK
Server: nginx/1.2.7
Date: Thu, 24 Apr 2014 02:20:29 GMT
Content-Type: video/mp4
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.26
Accept-Ranges: bytes


通过抓包发现IOS请求是通过断点续传的方式。
HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下: 
  1.客户端下载一个1024K的文件,已经下载了其中512K 
  2. 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段: 
       Range:bytes=512000- 
    这个头通知服务端从文件的512K位置开始传输文件 
  3. 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加: 
    Content-Range:bytes 512000-/1024000 
    并且此时服务端返回的HTTP状态码应该是206,而不是200。 


因为之前我是直接一次性返回的,所以IOS无法播放,好了,修改代码如下:

<?php
	$fp = @fopen($file, 'rb');

	$size   = filesize($file); // File size
	$length = $size;           // Content length
	$start  = 0;               // Start byte
	$end    = $size - 1;       // End byte

	// header("Accept-Ranges: 0-$length");
	header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');

	if (isset($_SERVER['HTTP_RANGE'])) {

	  $c_start = $start;
	  $c_end   = $end;
	  // Extract the range string
	  list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
	  // Make sure the client hasn't sent us a multibyte range
	  if (strpos($range, ',') !== false) {
		header('HTTP/1.1 416 Requested Range Not Satisfiable');
		header("Content-Range: bytes $start-$end/$size");
		exit;
	  }

	   
		$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;
	   // Validate the requested range and return 
	   // an error if it's not correct.
	   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");
		// (?) Echo some info to the client?
		exit;
	   }
	  $start  = $c_start;
	  $end    = $c_end;
	  $length = $end - $start + 1; // Calculate new content length
	  fseek($fp, $start);
	  header('HTTP/1.1 206 Partial Content');

	  header("Content-Range: bytes $start-$end/$size");
	  header("Content-Length: $length");

	  // Start buffered download
	  $buffer = 1024 * 8;
	  while(!feof($fp) && ($p = ftell($fp)) <= $end) { 		  				
               if ($p + $buffer > $end) {
		    $buffer = $end - $p + 1;
		}
		set_time_limit(0); // Reset time limit for big files
		echo fread($fp, $buffer);
		// Free up memory. 
		//Otherwise large files will trigger PHP's memory limit.
		flush(); 
	   }

	   fclose($fp);
	} else {
	   header("Content-Range: bytes $start-$end/$size");
	   header("Content-Length: $length");

	   readfile($file);
	}
}

?>


2014-07-18更新:

代码中有一个小问题,虽然不影响播放。

修改之前的代码:if ($range0== '-') {
修改之后的代码:if ($range{0}== '-') {

range有三种状态:

100-200 // 第100到第200字节

500-    // 第500字节到文件末尾

-1000   // 最后的1000个字节


这里的判断明显是第三种,所以代码需要将$range0改为$range{0}判断第一个字符串。


参考地址:
http://stackoverflow.com/questions/5924061/using-php-to-output-an-mp4-video
http://mobiforge.com/design-development/content-delivery-mobile-devices

分类: PHP 标签: 视频流 断点传输
comments powered by Disqus