using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Web.Configuration;
using System.Web.Http;
namespace Fw.WebAPI.Controllers.FileAPI
{
[RoutePrefix("api/file/media")]
public class MediaAPIController : ApiController
{
#region Fields // This will be used in copying input stream to output stream.
public const int ReadStreamBufferSize = 1024 * 1024;
// We have a read-only dictionary for mapping file extensions and MIME names.
public static readonly IReadOnlyDictionary<string, string> MimeNames;
// We will discuss this later.
public static readonly IReadOnlyCollection<char> InvalidFileNameChars;
// Where are your videos located at? Change the value to any folder you want.
public static readonly string InitialDirectory; #endregion #region Constructors static MediaAPIController()
{
var mimeNames = new Dictionary<string, string>(); mimeNames.Add(".mp3", "audio/mpeg"); // List all supported media types;
mimeNames.Add(".mp4", "video/mp4");
mimeNames.Add(".ogg", "application/ogg");
mimeNames.Add(".ogv", "video/ogg");
mimeNames.Add(".oga", "audio/ogg");
mimeNames.Add(".wav", "audio/x-wav");
mimeNames.Add(".webm", "video/webm"); MimeNames = new ReadOnlyDictionary<string, string>(mimeNames); InvalidFileNameChars = Array.AsReadOnly(Path.GetInvalidFileNameChars());
InitialDirectory = WebConfigurationManager.AppSettings["InitialDirectory"];
} #endregion #region Actions
[Route("Play/{id}")]
[HttpGet]
public HttpResponseMessage Play(string id)
{
//从Gridfs中取文件流
IDFSHandle dsfHandle = new GridFSHandle();
Stream stream=dsfHandle.GetFile(id); // This can prevent some unnecessary accesses.
// These kind of file names won't be existing at all.
if (stream==null)
throw new HttpResponseException(HttpStatusCode.NotFound); long totalLength = stream.Length; RangeHeaderValue rangeHeader = base.Request.Headers.Range;
HttpResponseMessage response = new HttpResponseMessage(); response.Headers.AcceptRanges.Add("bytes"); // The request will be treated as normal request if there is no Range header.
if (rangeHeader == null || !rangeHeader.Ranges.Any())
{
response.StatusCode = HttpStatusCode.OK;
response.Content = new PushStreamContent((outputStream, httpContent, transpContext)
=>
{
using (outputStream) // Copy the file to output stream straightforward. try
{
stream.CopyTo(outputStream, ReadStreamBufferSize);
}
catch (Exception error)
{
Debug.WriteLine(error);
} }, GetMimeNameFromExt("mp4")); response.Content.Headers.ContentLength = totalLength;
return response;
} long start = 0, end = 0; // 1. If the unit is not 'bytes'.
// 2. If there are multiple ranges in header value.
// 3. If start or end position is greater than file length.
if (rangeHeader.Unit != "bytes" || rangeHeader.Ranges.Count > 1 ||
!TryReadRangeItem(rangeHeader.Ranges.First(), totalLength, out start, out end))
{
response.StatusCode = HttpStatusCode.RequestedRangeNotSatisfiable;
response.Content = new StreamContent(Stream.Null); // No content for this status.
response.Content.Headers.ContentRange = new ContentRangeHeaderValue(totalLength);
response.Content.Headers.ContentType = GetMimeNameFromExt("mp4"); return response;
} var contentRange = new ContentRangeHeaderValue(start, end, totalLength); // We are now ready to produce partial content.
response.StatusCode = HttpStatusCode.PartialContent;
response.Content = new PushStreamContent((outputStream, httpContent, transpContext)
=>
{
using (outputStream) // Copy the file to output stream in indicated range. CreatePartialContent(stream, outputStream, start, end); }, GetMimeNameFromExt("mp4")); response.Content.Headers.ContentLength = end - start + 1;
response.Content.Headers.ContentRange = contentRange; return response;
} #endregion #region Others private static bool AnyInvalidFileNameChars(string fileName)
{
return InvalidFileNameChars.Intersect(fileName).Any();
} private static MediaTypeHeaderValue GetMimeNameFromExt(string ext)
{
string value; if (MimeNames.TryGetValue(ext.ToLowerInvariant(), out value))
return new MediaTypeHeaderValue(value);
else
return new MediaTypeHeaderValue(MediaTypeNames.Application.Octet);
} private static bool TryReadRangeItem(RangeItemHeaderValue range, long contentLength,
out long start, out long end)
{
if (range.From != null)
{
start = range.From.Value;
if (range.To != null)
end = range.To.Value;
else
end = contentLength - 1;
}
else
{
end = contentLength - 1;
if (range.To != null)
start = contentLength - range.To.Value;
else
start = 0;
}
return (start < contentLength && end < contentLength);
} private static void CreatePartialContent(Stream inputStream, Stream outputStream,
long start, long end)
{
int count = 0;
long remainingBytes = end - start + 1;
long position = start;
byte[] buffer = new byte[ReadStreamBufferSize]; inputStream.Position = start;
do
{
try
{
if (remainingBytes > ReadStreamBufferSize)
count = inputStream.Read(buffer, 0, ReadStreamBufferSize);
else
count = inputStream.Read(buffer, 0, (int)remainingBytes);
outputStream.Write(buffer, 0, count);
}
catch (Exception error)
{
Debug.WriteLine(error);
break;
}
position = inputStream.Position;
remainingBytes = end - position + 1;
} while (position <= end);
} #endregion
}
}

  

MediaAPIController的更多相关文章

随机推荐

  1. How to appraise Hearthstone card values

    https://elie.net/blog/hearthstone/how-to-appraise-hearthstone-card-values/ In 2014, I became an avid ...

  2. Vue UI组件库

    1. iView UI组件库  iView官网:https://www.iviewui.com/ 2.Vux UI组件库   Vux官网:https://vux.li/ 3.Element UI组件库 ...

  3. 监控查询慢sql

    mysql:--查询慢sql:业务db用户 select b.time, b.host, b.id, b.state, b.user, b.db, b.info  from information_s ...

  4. 修改Eclipse启动时的选择工作空间

    对于eclipse的默认的工作空间,如果不需要正常切换workspace的用户很方便,打开eclipse便自动进入默认的工作空间.而如果用户经常在多个workspace之间切换的话,启动eclipse ...

  5. 打印Linq生成的SQL语句

    var t1 = source.OrderBy<T>(orderby).Skip<T>(_skip).Take<T>(_take); var t2 = t1.ToO ...

  6. JAVA 基础编程练习题50 【程序 50 文件 IO】

    50 [程序 50 文件 IO] 题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩), 计算出平均成绩,将原有的数据和计算出的平均分数存放在磁盘文件&qu ...

  7. AppCode 2016.3 注册码

    43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  8. ubuntu默认root密码问题,第一次使用ubuntu需要设置root密码

    http://www.voidcn.com/article/p-yvnoogkc-ng.html 新接触ubuntu(baseondebian)的人,大多会因为安装中没有提示root密码而不太清楚为什 ...

  9. 在Windows操作系统中安装MongoDB

    如何在Windows操作系统中安装MongoDB: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/ 启动Mon ...

  10. html table设置成强制不换行

    在html文件中添加如下代码: <style type="text/css"> table td{word-break: keep-all;white-space:no ...