2015-12-02 6 views
10

अब मैं FileStreamResult का उपयोग कर रहा हूं और यह एक वीडियो स्ट्रीम करने के लिए काम करता है, लेकिन इसे खोज नहीं सकता है। यह हमेशा शुरुआत से फिर से शुरू होता है।अनुरोध और प्रतिक्रिया रेंज हेडर पर विचार करने वाले वीडियो या फ़ाइल को स्ट्रीम कैसे करें?

मैं ByteRangeStreamContent का उपयोग कर रहा था लेकिन ऐसा लगता है कि यह अब dnxcore50 के साथ उपलब्ध नहीं है।

तो कैसे आगे बढ़ना है?

मैं स्वयं अनुरोध रेंज हेडर पार्स और एक कस्टम FileResult कि प्रतिक्रिया Content-Range और हेडर के बाकी सेट करता है और प्रतिक्रिया शरीर के लिए बफर सीमा लिखते हैं या लिखने की ज़रूरत है कि वहाँ कुछ पहले से ही लागू किया है और मैं ' मैं इसे याद कर रहा हूँ?

उत्तर

15

यहाँ, एक VideoStreamResult के एक अनुभवहीन कार्यान्वयन है मैं (बहुखण्डीय सामग्री भाग का परीक्षण नहीं किया गया है) इस समय का उपयोग कर रहा:

public class VideoStreamResult : FileStreamResult 
{ 
    // default buffer size as defined in BufferedStream type 
    private const int BufferSize = 0x1000; 
    private string MultipartBoundary = "<qwe123>"; 

    public VideoStreamResult(Stream fileStream, string contentType) 
     : base(fileStream, contentType) 
    { 

    } 

    public VideoStreamResult(Stream fileStream, MediaTypeHeaderValue contentType) 
     : base(fileStream, contentType) 
    { 

    } 

    private bool IsMultipartRequest(RangeHeaderValue range) 
    { 
     return range != null && range.Ranges != null && range.Ranges.Count > 1; 
    } 

    private bool IsRangeRequest(RangeHeaderValue range) 
    { 
     return range != null && range.Ranges != null && range.Ranges.Count > 0; 
    } 

    protected async Task WriteVideoAsync(HttpResponse response) 
    { 
     var bufferingFeature = response.HttpContext.Features.Get<IHttpBufferingFeature>(); 
     bufferingFeature?.DisableResponseBuffering(); 

     var length = FileStream.Length; 

     var range = response.HttpContext.GetRanges(length); 

     if (IsMultipartRequest(range)) 
     { 
      response.ContentType = $"multipart/byteranges; boundary={MultipartBoundary}"; 
     } 
     else 
     { 
      response.ContentType = ContentType.ToString(); 
     } 

     response.Headers.Add("Accept-Ranges", "bytes"); 

     if (IsRangeRequest(range)) 
     { 
      response.StatusCode = (int)HttpStatusCode.PartialContent; 

      if (!IsMultipartRequest(range)) 
      { 
       response.Headers.Add("Content-Range", $"bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}"); 
      } 

      foreach (var rangeValue in range.Ranges) 
      { 
       if (IsMultipartRequest(range)) // dunno if multipart works 
       { 
        await response.WriteAsync($"--{MultipartBoundary}"); 
        await response.WriteAsync(Environment.NewLine); 
        await response.WriteAsync($"Content-type: {ContentType}"); 
        await response.WriteAsync(Environment.NewLine); 
        await response.WriteAsync($"Content-Range: bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}"); 
        await response.WriteAsync(Environment.NewLine); 
       } 

       await WriteDataToResponseBody(rangeValue, response); 

       if (IsMultipartRequest(range)) 
       { 
        await response.WriteAsync(Environment.NewLine); 
       } 
      } 

      if (IsMultipartRequest(range)) 
      { 
       await response.WriteAsync($"--{MultipartBoundary}--"); 
       await response.WriteAsync(Environment.NewLine); 
      } 
     } 
     else 
     { 
      await FileStream.CopyToAsync(response.Body); 
     } 
    } 

    private async Task WriteDataToResponseBody(RangeItemHeaderValue rangeValue, HttpResponse response) 
    { 
     var startIndex = rangeValue.From ?? 0; 
     var endIndex = rangeValue.To ?? 0; 

     byte[] buffer = new byte[BufferSize]; 
     long totalToSend = endIndex - startIndex; 
     int count = 0; 

     long bytesRemaining = totalToSend + 1; 
     response.ContentLength = bytesRemaining; 

     FileStream.Seek(startIndex, SeekOrigin.Begin); 

     while (bytesRemaining > 0) 
     { 
      try 
      { 
       if (bytesRemaining <= buffer.Length) 
        count = FileStream.Read(buffer, 0, (int)bytesRemaining); 
       else 
        count = FileStream.Read(buffer, 0, buffer.Length); 

       if (count == 0) 
        return; 

       await response.Body.WriteAsync(buffer, 0, count); 

       bytesRemaining -= count; 
      } 
      catch (IndexOutOfRangeException) 
      { 
       await response.Body.FlushAsync(); 
       return; 
      } 
      finally 
      { 
       await response.Body.FlushAsync(); 
      } 
     } 
    } 

    public override async Task ExecuteResultAsync(ActionContext context) 
    { 
     await WriteVideoAsync(context.HttpContext.Response); 
    } 
} 

और पार्स अनुरोध हेडर लेकर:

public static RangeHeaderValue GetRanges(this HttpContext context, long contentSize) 
     { 
      RangeHeaderValue rangesResult = null; 

      string rangeHeader = context.Request.Headers["Range"]; 

      if (!string.IsNullOrEmpty(rangeHeader)) 
      { 
       // rangeHeader contains the value of the Range HTTP Header and can have values like: 
       //  Range: bytes=0-1   * Get bytes 0 and 1, inclusive 
       //  Range: bytes=0-500   * Get bytes 0 to 500 (the first 501 bytes), inclusive 
       //  Range: bytes=400-1000  * Get bytes 500 to 1000 (501 bytes in total), inclusive 
       //  Range: bytes=-200   * Get the last 200 bytes 
       //  Range: bytes=500-   * Get all bytes from byte 500 to the end 
       // 
       // Can also have multiple ranges delimited by commas, as in: 
       //  Range: bytes=0-500,600-1000 * Get bytes 0-500 (the first 501 bytes), inclusive plus bytes 600-1000 (401 bytes) inclusive 

       // Remove "Ranges" and break up the ranges 
       string[] ranges = rangeHeader.Replace("bytes=", string.Empty).Split(",".ToCharArray()); 

       rangesResult = new RangeHeaderValue(); 

       for (int i = 0; i < ranges.Length; i++) 
       { 
        const int START = 0, END = 1; 

        long endByte, startByte; 

        long parsedValue; 

        string[] currentRange = ranges[i].Split("-".ToCharArray()); 

        if (long.TryParse(currentRange[END], out parsedValue)) 
         endByte = parsedValue; 
        else 
         endByte = contentSize - 1; 


        if (long.TryParse(currentRange[START], out parsedValue)) 
         startByte = parsedValue; 
        else 
        { 
         // No beginning specified, get last n bytes of file 
         // We already parsed end, so subtract from total and 
         // make end the actual size of the file 
         startByte = contentSize - endByte; 
         endByte = contentSize - 1; 
        } 

        rangesResult.Ranges.Add(new RangeItemHeaderValue(startByte, endByte)); 
       } 
      } 

      return rangesResult; 
     } 
+0

क्या यह इंटरनेट एक्सप्लोरर के साथ काम करता है? –

+0

पूरी तरह से काम करता है। अच्छा काम! – gisek

+0

आपको फ़ंक्शंस का उपयोग करने वाले कार्यों (WriteVideoAsync, WriteDataToResponseBody) के लिए उपयोग करने की आवश्यकता है। जो filestream का निपटान करने की अनुमति देगा। – drewex

संबंधित मुद्दे