天天看點

php safari播放mp4,修複video标簽在safari中無法播放mp4視訊的問題

前言

近期一個站長聯系我,向我求救解決一個bug,該問題在網絡上很多遇到,但是沒有正常的解決方案。

特此記錄下。

問題

該站長有一個discuz論壇,其中在文章中釋出視訊時,如果添加的視訊位址是其他站點的位址或者圖檔下的視訊路徑,可以正常播放。

如果使用附件中位址,則異常。

php safari播放mp4,修複video标簽在safari中無法播放mp4視訊的問題

image.png

其中無法播放的位址的代碼如下

原因

safari浏覽器,在打開視訊的時候,他不是一次性請求全部檔案的,一般首先會請求0-1位元組,這個寫在request header的"range"字段中:range:'bytes=0-1'

php safari播放mp4,修複video标簽在safari中無法播放mp4視訊的問題

image.png

chrome也會發送range,隻不過它是這樣的: 'bytes=0-',表示可以一次性加載整個視訊檔案。

php safari播放mp4,修複video标簽在safari中無法播放mp4視訊的問題

image.png

如果是想要傳輸視訊,必須要解析range字段,然後按照range字段的要求傳回對應的資料,同時response header至少要包含三個字段:"Content-Type", "Content-Range", "Content-Length"

"Content-Type"必需明确指定視訊格式,有"video/mp4", "video/ogg", "video/mov"等等。

"Content-Range"格式是 "bytes -/",其中start和end必需對應request header裡的range字段,total是檔案總大小,不是傳回的資料長度

"Content-Length"指定傳回的二進制長度

這裡需要注意:所有的end是指inclusive end,意味着檔案長度如果是245,傳回"Content-Range"就是"bytes 0-244/245",錯一點視訊就放不出來了。

如果你的視訊檔案可以被直接通路,則以上解析工作是由nginx來處理的。你無需處理,通常可以正常播放。

如果你的視訊是編碼輸出的,例如需要php或者java等讀取二進制流,則需要手動處理。

解決

php針對range解析視訊流的代碼如下:

$total = filesize($filename);

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

$range = str_replace('=','-',$_SERVER['HTTP_RANGE']);

$range = explode('-',$range);

if (isset($range[2]) && intval($range[2]) >0){

$end = trim($range[2]);

}else{

$end = $total-1;

}

$start = trim($range[1]);

$size = $end-$start+1;

header('Content-Length:'.$size);

header('Content-Range: bytes '.$start.'-'.$end.'/'.$total);

} else {

$size = $total;

header('Content-Length:'.$size);

header('Content-Range: bytes 0-'.($total-1).'/'.$total);

}

header('Accenpt-Ranges: bytes');

header('Content-Type: video/mpeg4');

$fp = fopen($filename,'rb+');

fseek($fp,$start);

while(!feof($fp)) {

print(fread($fp,$size));

flush();

ob_flush();

}

fclose($fp);