- 获取访问令牌(直接使用AZURE ACS URL,不要去通过301解析最新的ACS URL)
- 生成资产,获得资产ID
- 预创建资产包含的资产文件,获得资产文件ID
- 创建访问策略
- 生成上传URL
- 启用AZURE存储服务的跨站点访问CORS策略
- 上传视频
- 更新媒体信息
参考:
https://blogs.msdn.microsoft.com/lj/2014/10/07/windows-azure-media-service-rest-api-windows-storewindows-phone-part-2/
https://blogs.msdn.microsoft.com/hanxia/2014/09/30/windows-storeazure-3/
https://www.azure.cn/documentation/articles/media-services-rest-upload-files
using HtmlAgilityPack;
using Newtonsoft.Json.Linq;
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Hnop.Azure
{
static public class MediaServiceHelper
{
public static string acsToken;
public static string mediaServicesAccountName;
public static string mediaServicesAccountKey;
/// <summary>
/// 判断令牌是否即将内过期
/// </summary>
/// <param name="token">令牌</param>
/// <param name="minute">即将过去的时间</param>
/// <returns></returns>
public static bool IsTokenExpiring(string token,int minute)
{
if (!string.IsNullOrEmpty(token))
{
var arrTemp = token.Split('&');
DateTime t1970 = new DateTime(1970, 1, 1);
for (int i = 0; i < arrTemp.Length; i++)
{
if (arrTemp[i].StartsWith("ExpiresOn"))
{
long t = (DateTime.UtcNow.Ticks - t1970.Ticks) / 10000000;
if (Convert.ToInt64(arrTemp[i].Remove(0,10)) - t > minute)
return false;
else
{
return true;
}
}
}
return false;
}
else
{
return true;
}
}
/// <summary>
/// 获得访问AZURE媒体服务的accessToken
/// </summary>
/// <returns>令牌</returns>
public static string GetAccessToken(string acsEndpoint)
{
if (string.IsNullOrEmpty(mediaServicesAccountName) || string.IsNullOrEmpty(mediaServicesAccountKey))
throw new Exception("未设置媒体服务账户名称或访问密钥。");
if (string.IsNullOrEmpty(acsEndpoint))
throw new Exception("未设置授权服务器URI");
//请求令牌RequestBody
string acsRequestBodyFormat = "grant_type=client_credentials&client_id={0}&client_secret={1}&scope=urn%3aWindowsAzureMediaServices";
HttpWebResponse response = null;
HttpWebRequest request = null;
Stream receiveStream = null;
string acsToken = null;
//HttpClient httpClient = new HttpClient();
request = WebRequest.Create(acsEndpoint) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "application/json;odata=verbose";
string requestBody = string.Format(
System.Globalization.CultureInfo.InvariantCulture,
acsRequestBodyFormat,
mediaServicesAccountName,
System.Net.WebUtility.UrlEncode(mediaServicesAccountKey)
);
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
var content = reader.ReadToEnd();
JObject jsonObject = JObject.Parse(content);
acsToken = jsonObject.Value<string>("access_token");
}
else
{
acsToken = null;
}
}
catch
{
acsToken = null;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
if (null == receiveStream)
receiveStream.Close();
}
return acsToken;
}
/// <summary>
/// 创建媒体资产
/// </summary>
/// <param name="wamsEndPoint">媒体服务处理端点</param>
/// <param name="mediaName"></param>
/// <returns>媒体资产ID</returns>
public static string CreateAsset(string wamsEndPoint, string mediaName)
{
HttpWebResponse response = null;
HttpWebRequest request = null;
Stream receiveStream = null;
string assetId = null;
request = WebRequest.Create(wamsEndPoint + "Assets") as HttpWebRequest;
SetRequestHeaders(ref request);
request.Method = "POST";
string assetCreateRequestPayloadFormat = @"{0}""Name"":{1}{2}{3}{4}";
string requestBody = string.Format(
CultureInfo.InvariantCulture,
assetCreateRequestPayloadFormat,
"{", "\"", mediaName, "\"", "}"
);
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
var content = reader.ReadToEnd();
JObject jsonObject = JObject.Parse(content);
assetId = jsonObject.Value<string>("Id");
}
else
{
assetId =null;
}
}
catch
{
assetId =null;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
if (null == receiveStream)
receiveStream.Close();
}
return assetId;
}
/// <summary>
/// 预创建需要上传的媒体文件
/// </summary>
/// <param name="acsToken">媒体服务访问令牌</param>
/// <param name="wamsEndPoint">媒体服务处理端点</param>
/// <param name="assetId">媒体资产ID</param>
/// <param name="mediaFileName">媒体文件名称</param>
/// <param name="mediaType">媒体类型</param>
/// <returns></returns>
public static string CreateAssetFiles(string acsToken, string wamsEndPoint, string assetId, string mediaFileName, MediaType mediaType)
{
HttpWebResponse response = null;
HttpWebRequest request = null;
Stream receiveStream = null;
string assetFileId = null;
request = WebRequest.Create(wamsEndPoint + "Files") as HttpWebRequest;
SetRequestHeaders(ref request);
request.Method = "POST";
//string mineType = Enum.GetName(typeof(MediaType), mediaType).Replace('_','/');
string mineType = mediaType.ToString().Replace('_', '/');
String requestBody = "{\"Name\":\"" + mediaFileName + "\"," +
"\"ParentAssetId\": \"" + assetId + "\"," +
"\"MimeType\":\"" + mineType + "\"}";
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
var content = reader.ReadToEnd();
JObject jsonObject = JObject.Parse(content);
assetFileId = jsonObject.Value<string>("Id");
}
else
{
assetFileId = null;
}
}
catch
{
assetFileId = null;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
if (null == receiveStream)
receiveStream.Close();
}
return assetFileId;
}
/// <summary>
/// 创建媒体资产访问策略
/// </summary>
/// <param name="acsToken"></param>
/// <param name="wamsEndPoint"></param>
/// <param name="policeName"></param>
/// <param name="accessType"></param>
/// <returns></returns>
private static string CreateAccessPolicy(string acsToken, string wamsEndPoint, string policeName, AccessType accessType)
{
HttpWebResponse response = null;
HttpWebRequest request = null;
Stream receiveStream = null;
string policyId = null;
request = WebRequest.Create(wamsEndPoint + "AccessPolicies") as HttpWebRequest;
SetRequestHeaders(ref request);
request.Method = "POST";
String requestBody = "{\"Name\":\"" + policeName + "\"," +
"\"DurationInMinutes\":\"" + "300" + "\"," +
"\"Permissions\":" + (int)accessType + "}";
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
var content = reader.ReadToEnd();
JObject jsonObject = JObject.Parse(content);
policyId = jsonObject.Value<string>("Id");
}
else
{
policyId = null;
}
}
catch
{
policyId = null;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
if (null == receiveStream)
receiveStream.Close();
}
return policyId;
}
/// <summary>
/// 获得媒体文件上传URL
/// </summary>
/// <param name="acsToken"></param>
/// <param name="wamsEndPoint"></param>
/// <param name="accessPolicyId"></param>
/// <param name="assetId"></param>
/// <returns></returns>
public static string CreateUploadURL(string acsToken, string wamsEndPoint, string accessPolicyId, string assetId)
{
HttpWebResponse response = null;
HttpWebRequest request = null;
Stream receiveStream = null;
string uploadUrl = null;
request = WebRequest.Create(wamsEndPoint + "Locators") as HttpWebRequest;
SetRequestHeaders(ref request);
request.Method = "POST";
String requestBody = "{\"AccessPolicyId\":\"" + accessPolicyId + "\"," +
" \"AssetId\":\"" + assetId + "\"," +
" \"StartTime\":\"" + DateTime.UtcNow.AddMinutes(-5).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + "\"," +
" \"Type\":" + "1" + "}";
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
var content = reader.ReadToEnd();
JObject jsonObject = JObject.Parse(content);
string baseUri = jsonObject.Value<string>("BaseUri");
string contentAccessComponent = jsonObject.Value<string>("ContentAccessComponent");
uploadUrl = baseUri + "/@NAME/" + contentAccessComponent;
}
else
{
uploadUrl = null;
}
}
catch
{
uploadUrl = null;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
if (null == receiveStream)
receiveStream.Close();
}
return uploadUrl;
}
private static bool MergeAssetFilesAsync(string acsToken, string wamsEndPoint, string assetId, string assetFileId, string mediaFileName, string contentSize, MediaType mediaType)
{
HttpWebResponse response = null;
HttpWebRequest request = null;
bool jobDone = false;
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
string mineType = mediaType.ToString().Replace('_', '/');
String requestBody = "{\"Name\":\"" + mediaFileName + "\"," +
"\"ContentFileSize\":\"" + contentSize + "\"," +
"\"ParentAssetId\":\"" + assetId + "\"," +
"\"Id\":\"" + assetFileId + "\"," +
"\"MimeType\":\"" + mineType + "\"}";
request = (HttpWebRequest)HttpWebRequest.Create(wamsEndPoint + "Files('" + assetFileId + "')");
request.Method = "MERGE";
request.ContentType = "application/json;odata=verbose";
request.Accept = "application/json;odata=verbose";
request.Headers["DataServiceVersion"] = "1.0"; //3.0
request.Headers["MaxDataServiceVersion"] = "3.0";
request.Headers["x-ms-version"] = "2.11";//2.7
request.Headers["Authorization"] = header.ToString();
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Flush();
try
{
response = request.GetResponse() as HttpWebResponse;
if (response.ContentLength == 0)
jobDone = true;
}
catch
{
jobDone = false;
}
finally
{
if (null == request)
request.Abort();
if (null == requestStream)
requestStream.Close();
if (null == response)
response.Close();
}
return jobDone;
}
/// <summary>
/// 设置HttpWebRequest的头部信息
/// </summary>
/// <param name="request"></param>
static void SetRequestHeaders(ref HttpWebRequest request)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
request.Headers.Add("Authorization", header.ToString());
request.Headers.Add("x-ms-version", "2.11");//2.7
request.Headers.Add("DataServiceVersion", "1.0"); //3.0
request.Headers.Add("MaxDataServiceVersion", "3.0");
request.Accept = "application/json";
}
/// <summary>
/// 获得媒体服务的最新的处理端点
/// </summary>
/// <param name="acsToken"></param>
/// <returns></returns>
private static async Task<string> ConnectMediaServiceAsync(string acsToken)
{
string WAMSEndpoint = "media.chinacloudapi.cn";
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false
};
HttpClient httpClient = new HttpClient(handler);
httpClient.MaxResponseContentBufferSize = int.MaxValue;
httpClient.DefaultRequestHeaders.Add("Authorization", header.ToString());
httpClient.DefaultRequestHeaders.Add("x-ms-version", "2.7");
httpClient.DefaultRequestHeaders.Add("DataServiceVersion", "3.0");
httpClient.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, WAMSEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.SendAsync(request);
//after connecting to https://media.windows.net, you will receive a 301 redirect specifying another Media Services URI.
// You must make subsequent calls to the new URI.
string wamsEndPointFinal = WAMSEndpoint;
if (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.MovedPermanently)
{
var htmlcontent = await response.Content.ReadAsStringAsync();
HtmlDocument htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(htmlcontent);
var inputs_a = htmlDocument.DocumentNode.Descendants("a");
string newLocation = null;
foreach (var input in inputs_a)
{
newLocation = input.Attributes["href"].Value;
}
if (newLocation != null)
{
wamsEndPointFinal = newLocation;
}
}
return wamsEndPointFinal;
}
/// <summary>
/// 设置媒体服务Post请求头部验证信息
/// </summary>
/// <param name="acsToken"></param>
/// <returns></returns>
private static AuthenticationHeaderValue CreateBasicAuthenticationHeader(string acsToken)
{
return new AuthenticationHeaderValue("Bearer", acsToken);
}
}
public class AcsToken
{
public string token_type { get; set; }
public string access_token { get; set; }
public int expires_in { get; set; }
public string scope { get; set; }
}
public enum MediaType
{
video_mp4,
video_avi,
video_wmv
}
public enum AccessType
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
List = 8
}
}
上传HTML(HTML5)
<!DOCTYPE html>
<html>
<head>
<title>Upload Files using XMLHttpRequest - Minimal</title>
<script type="text/javascript">
function fileSelected() {
var file = document.getElementById('fileToUpload').files[0];
if (file) {
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
}
}
function uploadFile() {
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var file = document.getElementById('fileToUpload').files[0];
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
xhr.open("PUT", "https://mediasvctest01.blob.core.chinacloudapi.cn/asset-021d4878-e32e-48ef-accf-fda84d5538f0/5test.avi?sv=2012-02-12&sr=c&si=ccdd6610-36e8-40ce-b3dc-98bfa65cc0cb&sig=AkM2X6uWHs%2BPHaKPcXz4E45M%2FeKjs5Usq1KMSV2hUy4%3D&st=2016-06-23T02%3A14%3A57Z&se=2016-06-23T07%3A14%3A57Z");
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('x-ms-blob-content-type', file.type);
//xhr.setRequestHeader('x-ms-meta-uploadvia', 'CORS Demo');
xhr.setRequestHeader('Content-Length', file.length);
xhr.send(fd);
}
function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
}
else {
document.getElementById('progressNumber').innerHTML = 'unable to compute';
}
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText);
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.");
}
</script>
</head>
<body>
<form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
<div class="row">
<label for="fileToUpload">Select a File to Upload</label>
<input type="file" name="fileToUpload" id="fileToUpload" οnchange="fileSelected();" />
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="button" οnclick="uploadFile()" value="Upload" />
</div>
<div id="progressNumber"></div>
</form>
</body>
</html>