chrome瀏覽器mp4視頻流無法進行拖放或者拖放以後要重頭進行播放

適用於mp4視頻流無法通過URL作爲靜態內容返回的場景。

環境:

  1. 服務端 .Net MVC。
  2. 客戶端 Chrome瀏覽器
  3. 播放環境 Video原生標籤
  4. MP4物理路徑無法通過IIS請求到,需通過程序讀取到內存然後返回。(如果這個MP4是靜態內容,不需要程序處理即IIS直接處理,則一般不會有這個問題)

問題:無法進行拖放或者拖放以後要重頭進行播放。

故障原因:與Video標籤適配的請求未被響應。

如何做:

  1. Chrome瀏覽器默認請求會在 Header 添加一個Range如下:服務器要做的就是響應這個Header

      Range:             bytes=0-
    
  2. 服務器接收到這個Header以後,響應的Header如下,同時需要設置狀態碼爲206:

     Accept-Ranges:     bytes
     Content-Length:    2097152
     Content-Range:     bytes 0-2097151/38696534
    

    其中需要說明的是,這裏服務端設置了響應2MB(210241024=2097152字節)的分段加載,返回的數據流則是文件流索引0-2097151的內容,因爲文件流索引是從0開始的。38696534 是視頻文件的總長度。

帖服務器端響應代碼:

public ActionResult Video(Guid id)
 {
     //數據庫存儲的文件路徑
     var archive = ManagerFactory.ArchiveManager.GetVideoArchive(id);
     //物理絕對路徑
     var path = Server.MapPath("~/" + archive.Path);

     //設置響應頭
     HttpContext.Response.Headers.Add("Accept-Ranges", "bytes");
     
     //判定是否響應Chrome中的Range請求
     var rangeQuery = HttpContext.Request.Headers["Range"];
     if (rangeQuery.IsNotNullAndNotEmpty())
     {
         //startIndex 與 endIndex 是索引值,0開始的,注意在與 Length 比較的時候 Length-1
         var startIndex= 0;
         //視頻每節長度爲2MB
         var length = 2 * 1024 * 1024;
         var range = rangeQuery.Split('=')[1].Split('-');
         startIndex= range[0].ParseToInt();
         var endIndex = startIndex + length - 1;
         var fileLength = (int)archive.Length;

         //是否指定了索引終結點
         if (range[1].IsNotNullAndNotEmpty())
         {
             endIndex = range[1].ParseToInt();
         }
         if (endIndex <= startIndex )
         {
             endIndex = startIndex + length - 1;
         }
         if (endIndex > fileLength - 1)
         {
             endIndex = fileLength - 1;
         }
         
         //關鍵設置
         HttpContext.Response.Headers.Add("Content-Range", $"bytes {startIndex}-{endIndex}/{archive.Length}");
         //關鍵設置
         HttpContext.Response.StatusCode = 206;

         //按照索引讀取文件流
         using (var fs = System.IO.File.OpenRead(path))
         {
             var buffer = new byte[endIndex - startIndex + 1];
             fs.Position = startIndex ;
             fs.Read(buffer, 0, buffer.Length);
             return File(buffer, archive.ContentType);
         }
     }
     
     //如果未設置則返回整個文件
     return File(path, archive.ContentType);
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章