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的更多相关文章
随机推荐
- 转:C++何时调用构造函数,何时调用析构函数
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wjf1997/article/detai ...
- jquery - 定义二维数组
var products = []; products.push({product_id: '1',count: 3},{product_id:'2',count: 6})
- JMeter-jp@gc - PerfMon Metrics Collector-CPU监控工具的配置及使用(win版本)
服务器端放这个 如果端口号被占用,默认报这个错: 如果默认的4444端口被占用的修改: C:\Users\Administrator>CD E:\E:\apache-jmeter-4.0\Ser ...
- MySQL 创建删除和选择数据库
使用 create 命令创建数据库,语法如下: CREATE DATABASE 数据库名; 删除数据库 drop database <数据库名>; 选择数据库 use 数据库名 Datab ...
- 查看进程的命令ps
查看进程的命令:ps aux strace -p pid(进程id) 杀死进程:kill pid(进程id)强制杀死进程:kill -9 pid(进程id) linux ps 命令查看进程状态linu ...
- Flutter打包release版本安卓apk包真机安装无法请求网络的解决方法
今天flutter build apk打包了一个release.apk包,在真机上安装后网络数据都不显示,但是在模拟器上没问题,然后又连接真机开debug各种测试,一切都正常!那这会是什么问题呢? 查 ...
- Lua实现简单的类,继承,多态 实例
-- 类的例子,长方形的类,具备一个打印面积方法和一个设置长宽的方法 --lua实现类的思路,定义出来的对象在lua中可以访问自己有的成员,访问成员函数实际上是通过元表的__index方法实现的,具体 ...
- C/C++笔试基础知识
1. int *a[10] :指向int类型的指针数组a[10] int (*a)[10]:指向有10个int类型数组的指针a int (*a)(int):函数指针,指向有一个参数并且返回类型均为in ...
- ffmpeg学习笔记-初识ffmpeg
ffmpeg用来对音视频进行处理,那么在使用ffmpeg前就需要ffmpeg有一个大概的了解,这里使用雷神的ppt素材进行整理,以便于复习 音视频基础知识 视频播放器的原理 播放视频的流程大致如下: ...
- 如何编写spring mvc 项目
src/main/resources/static 目录里放资源文件css js jpg src/main/resources/templates 目录里放模板,html模板/这里是内容的展示页面 s ...