PHP输出视频流 本地and在线视频

发布时间 2023-03-24 19:43:50作者: 火知火味

废话不多说 直接上代码 这个是支持在线读取远程视频文件的,分段读取 已测试支持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 ?>
读取在线视频 输出视频流的php代码

 

 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 ?>
读取本地视频 输出视频流的php代码

————————————————

 


版权声明:本文为CSDN博主「Syspan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40729514/article/details/108600666