2013-05-31 40 views
4

我想從HttpHandler流式傳輸大型文件。它似乎不工作,因爲它沒有流式傳輸文件。相反,它將文件讀入內存,然後將其發送回客戶端。我期待所有的解決方案,並且解決方案告訴我,他們在做同樣的事情時會傳輸文件。我的解決方案,流是這樣的:流式傳輸大型視頻文件.net

using (Stream fileStream = File.OpenRead(path)) 
{ 
    context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(360.0)); 
    context.Response.Cache.SetCacheability(HttpCacheability.Public); 
    context.Response.AppendHeader("Content-Type", "video/mp4"); 
    context.Response.AppendHeader("content-length", file.Length); 
    byte[] buffer = new byte[1024]; 
    while (true) 
    { 
     if (context.Response.IsClientConnected) 
    { 
     int bytesRead = fileStream.Read(buffer, 0, buffer.Length); 
     if (bytesRead == 0) break; 
     context.Response.OutputStream.Write(buffer, 0, bytesRead); 
     context.Response.Flush(); 
    } 
    else 
    { 
     break; 
    } 

    } 
    context.Response.End(); 
} 

正在發生的事情是對小文件,如果我調試的代碼,它會播放視頻,但直到它到達context.Respond.End()線。但對於大文件,這不起作用,因爲它將整個文件存儲在內存中,這會帶來問題。

+0

您可能希望與['IHttpAsyncHandler'](http://msdn.microsoft.com/en-us/library/system.web.ihttpasynchandler.aspx)異步實現此操作,並異步讀取磁盤。 – vcsjones

+0

@ vcsjones-我不確定Async是如何工作的,但只是做了一個快速谷歌,我不知道如何解決這個問題。這似乎釋放了一個線程返回到客戶端異步從磁盤讀取,但會返回內容,因爲它仍然從磁盤讀取? – Jake

回答

9

我有一個類似的問題,其中的視頻必須完全下載之前播放。

我可以看到你想流式傳輸視頻,更具體。 你必須小心編碼(確保它是流式傳輸),不要只依賴擴展名,因爲創建該文件的人可能會以更奇怪的方式構建視頻,但99%的時間你應該很好。我使用mediainfo。 在你的情況應該是H.264。

它也取決於瀏覽器和你用什麼流(除了後端代碼)。就我而言,我使用了Chrome/Html5和.webm(VP8/Ogg Vorbis)。它正在爲超過1G的文件工作。沒有測試超過4G ...

我用視頻的下載代碼:

public void Video(string folder, string name) { 
     string filepath = Server.MapPath(String.Format("{0}{1}", HttpUtility.UrlDecode(folder), name)); 
     string filename = name; 

     System.IO.Stream iStream = null; 
     byte[] buffer = new Byte[4096]; 
     int length; 
     long dataToRead; 

     try { 
      // Open the file. 
      iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, 
         System.IO.FileAccess.Read, System.IO.FileShare.Read); 


      // Total bytes to read: 
      dataToRead = iStream.Length; 

      Response.AddHeader("Accept-Ranges", "bytes"); 
      Response.ContentType = MimeType.GetMIMEType(name); 

      int startbyte = 0; 

      if (!String.IsNullOrEmpty(Request.Headers["Range"])) { 
       string[] range = Request.Headers["Range"].Split(new char[] { '=', '-' }); 
       startbyte = Int32.Parse(range[1]); 
       iStream.Seek(startbyte, SeekOrigin.Begin); 

       Response.StatusCode = 206; 
       Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", startbyte, dataToRead - 1, dataToRead)); 
      } 

      while (dataToRead > 0) { 
       // Verify that the client is connected. 
       if (Response.IsClientConnected) { 
        // Read the data in buffer. 
        length = iStream.Read(buffer, 0, buffer.Length); 

        // Write the data to the current output stream. 
        Response.OutputStream.Write(buffer, 0, buffer.Length); 
        // Flush the data to the HTML output. 
        Response.Flush(); 

        buffer = new Byte[buffer.Length]; 
        dataToRead = dataToRead - buffer.Length; 
       } else { 
        //prevent infinite loop if user disconnects 
        dataToRead = -1; 
       } 
      } 
     } catch (Exception ex) { 
      // Trap the error, if any. 
      Response.Write("Error : " + ex.Message); 
     } finally { 
      if (iStream != null) { 
       //Close the file. 
       iStream.Close(); 
      } 
      Response.Close(); 
     } 
    } 

確保您的響應報頭包含了你所需要的一切。

+0

該文件編碼容易,沒有問題。如果直接進入瀏覽器,我可以在瀏覽器中播放該文件。什麼是mediainfo?它對這個問題有什麼好處。我也使用html 5,它似乎仍然不能播放大文件。我正在測試的文件大約是150 MB,它通過一個處理程序發回給瀏覽器html5標記的源代碼,但從不播放,但如果我發送較小的文件6 MB,它沒有問題 – Jake

+0

請確保httpRuntime具有maxRequestLength足夠大以發送文件。 Mediainfo只是爲了看視頻的細節(編解碼器和比特率) – Maxad

+0

我知道視頻的細節。我用ffmpeg自己編碼。它在瀏覽器中運行良好,如果我直接去它,maxRequestLength是2000000000和文件只有150MB – Jake