1. 程式人生 > >關於動態生成的mp3在audio標籤無法拖動的問題

關於動態生成的mp3在audio標籤無法拖動的問題

html5 audio video不需要外掛即可播放音訊和視訊,currentTime可以用來設定播放的起始時間,使得可以不從檔案開頭開始播放。如果 html5 audio video設定currentTime失效,無法設定開始播放的時間點,audio/video不能拖動進度條調整播放進度,很有可能是使用了php asp jsp等伺服器後端語言動態輸出待播放的媒體檔案內容,如果audio/video播放的媒體資原始檔不是靜態檔案,不經過處理直接通過伺服器語言動態輸出流媒體內容,設定currentTime不會生效。 為什麼直接使用靜態的.mp3 .mp4 .flac等媒體檔案時支援使用 audio | video .currentTime = NUMBERIC; (NUMBERIC是一個數字,可以是整數,也可以是浮點數)來設定播放起始位置呢,而動態輸出流媒體檔案內容時不行呢? 這其中的核心技術就是伺服器端對斷點續傳的支援,斷點續傳允許客戶端從伺服器提取某個檔案指定位元組範圍內的一部分內容,當下載中斷以後再次下載時可以只請求下載原先沒有下載的部分,避免重複傳輸現有內容。當客戶端(瀏覽器)檢測到伺服器支援斷點續傳以後才會傳送相應的區間內容請求給伺服器,伺服器接到請求以後再返回相應範圍內的檔案內容,這樣才能實現流媒體檔案的定點播放。而直接使用靜態檔案做播放資源時,伺服器軟體通常會自動處理斷點續傳請求。 實現動態流媒體檔案支援通過HTML5 audio/video.currentTime設定播放起始時間點,可以使用以下兩種方法。 方法一:使用伺服器模組X-SendFile輸出流媒體檔案內容來解決currentTime失效的問題,以Apache伺服器為例。 首先下載mod_xsendfile,將模組檔案複製到Apache的modules目錄,在Apache配置檔案中新增
  1. LoadModule xsendfile_module modules/mod_xsendfile.so
  2. XSendFile On
  3. XSendFilePath D:/server
複製程式碼其中XSendFilePath意思是將指定的資料夾路徑新增到白名單中,指定資料夾中的檔案可以被Apache直接傳送給客戶端,除了設定的資料夾本身以外,該資料夾包含的各級子目錄也在允許範圍內。配置完伺服器以後重啟Apache伺服器以後X-SendFile模組有效。 安裝了X-SendFile模組以後,PHP輸出媒體檔案變得非常簡單。其中的Content-Type是要輸出檔案的MIME型別,可以不必寫死而通過伺服器語言獲取。可以參見方法二有例項程式碼。
  1. <?php
  2.         header('Content-Type: audio/mp3');
  3.         header('X-Sendfile: D:\server\wuxiancheng.cn\Audio\S.H.E\612xq.mp3');
  4. ?>

複製程式碼 方法二:使用伺服器語言模擬斷點續傳支援讓HTML5 audio/video.currentTime生效,以PHP為例。 如果沒有伺服器配置許可權,可以在動態語言中傳送Accept-Ranges: bytes和Content-Range: bytes S-E/FILESIZE兩個響應頭,告訴客戶端它請求的伺服器資源支援斷點續傳,伺服器端接收到客戶端傳送的請求以後,從請求頭拿到需要傳送的內容區間,然後從檔案中讀取指定起止位置的資料傳送到客戶端即可解決HTML5 audio/video使用後端語言動態輸出媒體檔案內容造成的currentTime失效以及無法手動拖動進度條的問題。其中S和E分別是當次請求的起始位置索引和結束位置索引,FILESIZE為代表檔案尺寸的總位元組數。

    function downloadmp3($file)     {         $fileSize = filesize($file);         $etag = md5(filemtime($file));         $fp = fopen($file, 'rb');         if (!$fp) {             die('Could not open file');         }         $start = 0;         $end = $fileSize - 1;

        if (isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) {             //獲取請求頭中的Range欄位             $range = explode('-', substr($_SERVER['HTTP_RANGE'], strlen('bytes=')));

            $start = $range[0];             if ($range[1] > 0) {                 $end = $range[1];             }

            //構造斷點續傳響應頭             header('HTTP/1.1 206 Partial Content');             header('Status: 206');             header('Accept-Ranges: bytes');             header('Content-Range: bytes ' . $start. '-' . $end . '/' . $fileSize);             header('Content-Length: ' . ($end - $start + 1));         } else {             header('Content-Length: ' . $fileSize);         }

        header('Content-Type: audio/mpeg');         header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T', filemtime($file)));         header('ETag: "' . $etag . '"');         header('Expires: 0');

        if ($start > 0) {             fseek($fp, $start); //移動檔案指標         }

        $bytesPosition = $start;         while (!feof($fp) && $bytesPosition <= $end) {

            $chunk = 1024 * 1024 * 50; //每次讀取50k             if ($bytesPosition + $chunk > $end + 1) {                 $chunk = $end - $bytesPosition + 1;             }

            $chunk = fread($fp, $chunk);             if (!$chunk) {                 die('Could not read file');             }

            print($chunk);             flush();

            $bytesPosition += $chunk;         }

        fclose($fp);     }