MediaAPIController
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的更多相关文章
随机推荐
- Custom Roles Based Access Control (RBAC) in ASP.NET MVC Applications - Part 1 (Framework Introduction)
https://www.codeproject.com/Articles/875547/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NET Introd ...
- 【SpringBoot】转载 springboot使用thymeleaf完成数据的页面展示
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/weixin_36380516/artic ...
- 图解 HTTP 笔记(七)——HTTPS
本章主要讲解 HTTPS 的基本原理,以及如何利用 HTTPS 防范 HTTP 通信过程中存在的伪装.窃听.篡改等问题 一.HTTP 的缺点 HTTP 在通信过程中会面临以下三种安全问题: 通信使用明 ...
- 【401】Python 求合数的所有质数因子
对于这样的一个题目来说,出看来,可能会想到判断是否为质数,但其实并不需要. 只要按照从2开始遍历,只要遇到可以整除的就是想要的质数,理由是,如果遇到合数的话,那么在此之前一定会遇到这个合数的质因子,因 ...
- Python基础-day04
函数基础 目标 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 01. 函数的快速体验 1.1 快速体验 所谓函数,就是把 具有独立功能的代码块 组织为一个 ...
- 查看mycat日志
查看日志: tail -f /usr/local/mycat/logs/wrapper.log
- Spring Cloud(6):保护微服务(Security) - OAuth2.0
OAuth2是一个授权(Authorization)协议.我们要和Spring Security的认证(Authentication)区别开来,认证(Authentication)证明的你是不是这个人 ...
- 微信小程序 左右联动菜单
根据左侧列表,联动跳右侧内容. 效果如图: wxml代码: <view class="page"> <!-- 左侧导航 --> <view class ...
- C#使用MPI进行高性能计算
MPI.NET是用于Microsoft.NET环境的高性能.易于使用的消息传递接口(MPI)实现.mpi是编写在分布式内存系统(如计算集群)上运行的并行程序的事实上的标准,并且得到了广泛的实现.大多数 ...
- 对ysoserial工具及java反序列化的一个阶段性理解【未完成】
经过一段时间的琢磨与反思,以及重读了大量之前看不懂的反序列化文章,目前为止算是对java反序列化这块有了一个阶段性的小理解. 目前为止,发送的所有java反序列化的漏洞中.主要需要两个触发条件: 1. ...