PHP输出视频流 本地and在线视频
废话不多说 直接上代码 这个是支持在线读取远程视频文件的,分段读取 已测试支持ios 及ios uc浏览器,代码中的算法还可以优化,需要的朋友 请自行修改,视频地址可能会失效,到时候换成你需要的就行了。
该带码经过测试,在2h2g 的服务器上支持多人在线观看,同时不消化内存(具体多少人自行测试吧。免得说我忽悠你)。
这里小小的说明一下 代码中是通过 curl 携带请求头 Range:bytes={$start}-{$end} 去分段读取视频流的,而并非一次性读取,这样服务器内存会炸掉。同时在输出视频流的前提下 header 要对,否则浏览器无法正确读取,这里无法正确读取主要是ios uc 浏览器标准严格,一旦有一个错了就会播放不出来。
每次加载大小为5M 支持随意快进,当然加载速度快慢取决于你的服务器,我用的是国外的服务器做的测试
1.读取线上视频文件
1 <?php 2 #作者:APan 3 #时间:2020-09-15 4 #文章地址:https://blog.csdn.net/qq_40729514 5 #转载请注明版权,尊重作者成果 6 7 ini_set('memory_limit', '1024M'); //修改脚本的最大运行内存 8 set_time_limit(600); //设置超时限制为 10分钟 9 10 //输出视频流 11 function outPutStream($videoUrl) { 12 13 if(!$videoUrl){ 14 header('HTTP/1.1 500 Internal Server Error'); 15 echo "Error: Video cannot be played !"; 16 exit(); 17 } 18 19 //获取视频大小 20 $header_array = get_headers($videoUrl, true); 21 $sizeTemp = $header_array['Content-Length']; 22 if (is_array($sizeTemp)) { 23 $size = $sizeTemp[count($sizeTemp) - 1]; 24 } else { 25 $size = $sizeTemp; 26 } 27 28 //初始参数 29 $start = 0; 30 $end = $size - 1; 31 $length = $size; 32 $buffer = 1024 * 1024 * 5; // 输出的流大小 5m 33 34 //计算 Range 35 $ranges_arr = array(); 36 if (isset($_SERVER['HTTP_RANGE'])) { 37 38 if (!preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/i', $_SERVER['HTTP_RANGE'])) { 39 header('HTTP/1.1 416 Requested Range Not Satisfiable'); 40 } 41 $ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6)); 42 foreach ($ranges as $range) { 43 $parts = explode('-', $range); 44 $ranges_arr[] = array($parts[0], $parts[1]); 45 } 46 $ranges = $ranges_arr[0]; 47 $start = (int)$ranges[0]; 48 if ($ranges[1] != '') { 49 $end = (int)$ranges[1]; 50 } 51 $length = min($end - $start + 1, $buffer); 52 $end = $start + $length - 1; 53 }else{ 54 55 // php 文件第一次浏览器请求不会携带 RANGE 为了提升加载速度 默认请求 1 个字节的数据 56 $start=0; 57 $end=1; 58 $length=2; 59 } 60 61 //添加 Range 分段请求 62 $header = array("Range:bytes={$start}-{$end}"); 63 #发起请求 64 $ch2 = curl_init(); 65 curl_setopt($ch2, CURLOPT_URL, $videoUrl); 66 curl_setopt($ch2, CURLOPT_TIMEOUT, 60); 67 curl_setopt($ch2, CURLOPT_HTTPHEADER, $header); 68 //设置读取的缓存区大小 69 curl_setopt($ch2, CURLOPT_BUFFERSIZE, $buffer); 70 // 关闭安全认证 71 curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false); 72 curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false); 73 //追踪返回302状态码,继续抓取 74 curl_setopt($ch2, CURLOPT_HEADER, false); 75 curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); 76 curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); 77 curl_setopt($ch2, CURLOPT_CONNECTTIMEOUT, 60); 78 curl_setopt($ch2, CURLOPT_NOBODY, false); 79 curl_setopt($ch2, CURLOPT_REFERER, $videoUrl); 80 //模拟来路 81 curl_setopt($ch2, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44"); 82 $content = curl_exec($ch2); 83 curl_close($ch2); 84 #设置响应头 85 header('HTTP/1.1 206 PARTIAL CONTENT'); 86 header("Accept-Ranges: bytes"); 87 header("Connection: keep-alive"); 88 header("Content-Type: video/mp4"); 89 header("Access-Control-Allow-Origin: *"); 90 //为了兼容 ios UC这类浏览器 这里加个判断 UC的 Content-Range 是 起始值-总大小减一 91 if($end!=1){ 92 $end=$size-1; 93 } 94 header("Content-Range: bytes {$start}-{$end}/{$size}"); 95 //设置流的实际大小 96 header("Content-Length: ".strlen($content)); 97 //清空缓存区 98 ob_clean(); 99 //输出视频流 100 echo $content; 101 //销毁内存 102 unset($content); 103 } 104 105 #输出视频流 视频地址可能失效,您可以换成你的来测试 106 outPutStream("https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4"); 107 die(); 108 ?>
2.读取本地视频
通过php直接输出的文件通常不被html5的<video>标签支持,尤其是ios设备。为了完美支持html5的视频播放,php必须支持byte-range请求。因为html5播放视频之前会发送一个只需文件少数字节的请求,确认服务端是否支持byte-range请求,支持才会继续发送请求剩余的文件数据。
具体的问题就是 byte-range ,相信遇到这个问题的朋友也在网上搜索到了许多相关的问题,接下来下面是整理后的代码,经测试苹果端可支持播放,代码如下:
————————————————
1 <?php 2 3 $localfile = "test.mp4"; 4 5 $size = filesize($localfile); 6 7 $start = 0; 8 $end = $size - 1; 9 $length = $size; 10 11 header("Accept-Ranges: 0-$size"); 12 header("Content-Type: video/mp4"); 13 14 $ranges_arr = array(); 15 if (isset($_SERVER['HTTP_RANGE'])) { 16 if (!preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/i', $_SERVER['HTTP_RANGE'])) { 17 header('HTTP/1.1 416 Requested Range Not Satisfiable'); 18 } 19 $ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6)); 20 foreach ($ranges as $range) { 21 $parts = explode('-', $range); 22 $ranges_arr[] = array($parts[0],$parts[1]); 23 } 24 25 $ranges = $ranges_arr[0]; 26 if($ranges[0]==''){ 27 if($ranges[1]!=''){ 28 //Range: bytes=-n 表示取文件末尾的n个字节 29 $length = (int)$ranges[1]; 30 $start = $size - $length; 31 }else{ 32 //Range: bytes=- 这种形式不合法 33 header('HTTP/1.1 416 Requested Range Not Satisfiable'); 34 } 35 }else{ 36 $start = (int)$ranges[0]; 37 if($ranges[1]!=''){ 38 //Range: bytes=n-m 表示从文件的n偏移量读到m偏移量 39 $end = (int)$ranges[1]; 40 } 41 //Range: bytes=n- 表示从文件的n偏移量读到末尾 42 $length = $end - $start + 1; 43 } 44 header('HTTP/1.1 206 PARTIAL CONTENT'); 45 } 46 47 header("Content-Range: bytes {$start}-{$end}/{$size}"); 48 header("Content-Length: $length"); 49 50 $buffer = 8096; 51 $file = fopen($localfile, 'rb'); 52 if($file){ 53 fseek($file, $start); 54 while (!feof($file) && ($p = ftell($file)) <= $end){ 55 if ($p + $buffer > $end) { 56 $buffer = $end - $p + 1; 57 } 58 set_time_limit(0); 59 echo fread($file, $buffer); 60 flush(); 61 } 62 fclose($file); 63 } 64 die; 65 66 ?>
————————————————
版权声明:本文为CSDN博主「Syspan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40729514/article/details/108600666
本文来自博客园,作者:火知火味,转载请注明原文链接:https://www.cnblogs.com/whwa/p/17253143.html