AzureMediaService REST 上传调用
- 获取访问令牌(直接使用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" onchange="fileSelected();" /> </div> <div id="fileName"></div> <div id="fileSize"></div> <div id="fileType"></div> <div class="row"> <input type="button" onclick="uploadFile()" value="Upload" /> </div> <div id="progressNumber"></div> </form> </body> </html>