Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
在文章 基于Windows Azure Media Service REST API 进行Windows Store/Windows Phone 应用开发系列-Part 1 简介中介绍了基于Windows Azure Media Service(Windows Azure 媒体服务,简称WAMS)进行应用开发的相关信息及包含的基本流程,紧接着在文章基于Windows Azure Media Service REST API 进行Windows Store/Windows Phone 应用开发系列-Part 2初始设置链接到WAMS中介绍了如何使用REST API链接到媒体服务,本文将基于此对如何上传媒体到媒体服务进行详细讲解。
使用REST API将媒体文件上传到媒体服务包含许多步骤,主要流程是:
- 创建资产(ASSET)
- 对资产进行加密(可选项)—本文暂时不予以考虑
- 将媒体文件上传到blob storage
请注意,在使用REST API时访问媒体服务时,必须在HTTP请求中添加如下必须的header;WAMS 的根 URI 为https://media.windows.net/,成功连接到此 URI后,会收到一个“301 重定向”响应并提取出新的媒体服务URI,随后调用新都是基于该 URI,详细内容参见Part2内容。
根据文档媒体服务 REST API 开发的设置可知,每次调用WAMS时,客户端必须在请求中包括必需的标头,列表如下:
Header |
Type |
Value |
Authorization |
Bearer |
Bearer 是唯一接受的授权机制。 该值还必须包括由 ACS 提供的访问令牌。 |
x-ms-version |
Decimal |
2.7 |
DataServiceVersion |
Decimal |
3.0 |
MaxDataServiceVersion |
Decimal |
3.0 |
如Part 1中描述:资产(ASSET)是包含媒体信息的逻辑实体,可能包含了一个或多个需要处理的数字文件如audio,video等。资产实体是对资产的抽象,包含了一系列的属性如Id, State等,为便于处理,我们定义Asset类用于表示媒体服务中的一个资产:
创建资产:在媒体服务中创建一个新的资产
EndPoint |
https://media.windows.net/API/Assets 或redirection后的新的URI/Assets |
HTTP Method |
POST |
Request Headers |
DataServiceVersion: 3.0MaxDataServiceVersion: 3.0x-ms-version: 2.7Authorization: Bear + ACSToken |
Request Content Type |
application/json;odata=verbose |
Request Body Format |
{ "Name": "<Asset Name>", (通常使用媒体文件名,本文省略加密操作)format>"}e.g.{ "Name": "<filename>", (此处常用媒体文件的名字)} |
通常根据媒体文件名创建asset, 如下代码根据文件名在媒体服务中创建相应的资产实体,代码执行成功后可以提取相应的Id值(做为AssetId)如nb:cid:UUID:636363d9-7c66-42ca-add4-0a8c4d4464f6。
(为便于描述,本文先假设上传位于媒体库中名为interview3.wmv的文件,以Part2链接媒体服务的内容为基础)
private string AssetId;
private string AccessPolicyId;
private string UploadUrl;
private string UploadEndpoint;
private static readonly string mediaFileName = "interview3.wmv";
private async Task<string> CreateAssetAsync(string acsToken, string wamsEndPoint, string mediaName)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
HttpClient httpClient = new HttpClient();
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.Post, wamsEndPoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string assetCreateRequestPayloadFormat = @"{0} ""Name"": {1} {2} {3} {4}";
string requestBody = string.Format(CultureInfo.InvariantCulture, assetCreateRequestPayloadFormat, "{","\"", mediaName,"\"", "}");
HttpContent body = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(wamsEndPoint + "Assets", body);
string assetId = null;
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(content);
XmlNodeList elemList = xmlDoc.GetElementsByTagName("d:Id");
foreach (var ele in elemList)
{
assetId = ele.InnerText;
}
}
return assetId;
}
此时再去创建该资产下的资产文件,获取资产实体下对应的资产文件的ID, 以便后续过程中将上传的媒体文件更新到该ID下(MergeAssetFilesAsync):
private async Task<string> CreateAssetFilesAsync(string acsToken, string wamsEndPoint, string assetId, string mediaFileName)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
HttpClient httpClient = new HttpClient();
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");
String requestBody = "{ \"Name\" : \"" + mediaFileName + "\"," +
" \"ContentFileSize\" : \"" + "0" + "\", " +
" \"ParentAssetId\" : \"" + assetId + "\", " +
" \"MimeType\" : \"" + "video/x-ms-wmv" + "\"}";
HttpContent body = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(wamsEndPoint + "Files", body);
string assetFileId = null;
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(content);
XmlNodeList elemList = xmlDoc.GetElementsByTagName("d:Id");
foreach (var ele in elemList)
{
assetFileId = ele.InnerText;
}
}
return assetFileId;
}
如Part 1中描述,每个WAMS 账户都有一个或多个相关联的Azure Storage 账户,用于存储关联的WAMS 账户控制的媒体内容,在将媒体文件上传至Blob Storage时要求对资产设置相应的写入权限,然后提取用于上传的Storage URL,最后使用 Azure Storage REST APIs进行传输。
将任何文件上载到 BLOB 存储之前,需要设置用于对资产执行写入操作的访问策略权限。为此,需要向 AccessPolicy 实体集发送一个 HTTP POST 请求,创建AccessPolicy 请求简要总结如下:
EndPoint |
或redirection后的新的URI/AccessPolicies |
HTTP Method |
POST |
Request Headers |
DataServiceVersion: 3.0MaxDataServiceVersion: 3.0x-ms-version: 2.7Authorization: Bear + ACSToken |
Request Content Type |
application/json;odata=verbose |
Request Body Format |
{ "Name": "NewUploadPolicy", "DurationInMinutes" : "300",
format>"} |
执行过程可参考如下代码, 此处是写的权限(Permissions=”2”),在 文章5媒体的发布过程中,同样需要指定资产“读”的权限(Permissions=”1”),执行成功后,根据返回内容获得相应的AccessPolicyId, 如:"nb:pid:UUID:58fcf51e-5219-4fea-8536-6c295d2c388a"。
/// <summary>
///apName
/// for upload-NewUploadPolicy
/// for download - DownloadPolicy
/// accessType 2- upload(write), 1- read
/// </summary>
/// <param name="acsToken"></param>
/// <param name="wamsEndPoint"></param>
/// <param name="policyName"></param>
/// <returns></returns>
private async Task<string> CreateAccessPolicyAsync(string acsToken, string wamsEndPoint, string apName, int accessType)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
HttpClient httpClient = new HttpClient();
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.Post, wamsEndPoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
String requestBody = "{ \"Name\" : \"" + apName + "\"," +
" \"DurationInMinutes\" : \"" + "300" + "\", " +
" \"Permissions\" : " + accessType.ToString() + "}";
HttpContent body = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(wamsEndPoint + "AccessPolicies", body);
string accessPolicyId = null;
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(content);
XmlNodeList elemList = xmlDoc.GetElementsByTagName("d:Id");
foreach (var ele in elemList)
{
accessPolicyId = ele.InnerText;
}
}
return accessPolicyId;
}
创建 AccessPolicy 后,将该Id链接到某个定位符实体,该实体将为你提供用于将文件上载到 BLOB 存储的 URL 路径,创建上传URL的请求简要总结如下:
EndPoint |
或redirection后的新的URI/Locators |
HTTP Method |
POST |
Request Headers |
DataServiceVersion: 3.0MaxDataServiceVersion: 3.0x-ms-version: 2.7Authorization: Bear + ACSToken |
Request Content Type |
application/json;odata=verbose |
Request Body Format |
"AssetId" : “<AssetId>”,
format>"} e.g: {"AccessPolicyId" : "nb:pid:UUID:58fcf51e-5219-4fea-8536-6c295d2c388a", "AssetId" : "nb:cid:UUID:636363d9-7c66-42ca-add4-0a8c4d4464f6", "StartTime" : "2014-11-28T10:39:58", "Type" : 1 } |
执行过程可参考如下代码,执行成功后,根据返回内容构造相应的上传URL,注意必须将要上载的文件的文件名添加到在获取得到的URL中,如:https://myappsstorage.blob.core.windows.net/asset-636363d9-7c66-42ca-add4-0a8c4d4464f6/azure.wmv?sv=2012-02-12&sr=c&si=8561f64e-0392-47f6-a178-8397f6ee4352&sig=JjDaBdvxHqWsA%2FWrLMLkAqQjl92v03vwdOrqVIAjkV8%3D&st=2014-11-28T10%3A39%3A58Z&se=2014-11-28T15%3A39%3A58Z。
private async Task CreateUploadURLAsync(string acsToken, string wamsEndPoint, string accessPolicyId, string assetId)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
HttpClient httpClient = new HttpClient();
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.Post, wamsEndPoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
String requestBody = "{ \"AccessPolicyId\" : \"" + accessPolicyId + "\"," +
" \"AssetId\" : \"" + assetId+ "\", " +
" \"StartTime\" : \"" + DateTime.UtcNow.AddMinutes(-5).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + "\", " +
" \"Type\" : " + "1" + "}";
HttpContent body = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(wamsEndPoint + "Locators", body);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(content);
XmlNodeList elemListBase = xmlDoc.GetElementsByTagName("d:BaseUri");
XmlNodeList elemListSV = xmlDoc.GetElementsByTagName("d:ContentAccessComponent");
string baseUrl=null;
string sv=null;
foreach (var ele in elemListBase)
{
baseUrl = ele.InnerText;
}
foreach (var ele in elemListSV)
{
sv = ele.InnerText;
}
UploadUrl = baseUrl + "/" +Path.GetFileName(MediaFileName) + sv;
UploadEndpoint = baseUrl.Substring(0, baseUrl.IndexOf("/asset"));
}
}
获得上传地址且设置好访问权限后,即可使用存储 REST API 将具体的文件上载到 Azure BLOB 存储容器,上传文件请求简要总结如下:
EndPoint |
上传地址(blob storage SAS 定位符) |
HTTP Method |
PUT |
Request Headers |
|
Request Content Type |
|
Request Body Format |
{ 媒体文件二进制数据 } |
执行过程可参考如下代码,需要注意的是二进制文件的添加,此处仅以本地Video库(Windows.Storage.KnownFolders.VideosLibrary)中的一个名为interview3.wmv媒体文件为例,可以做相应修改,如让用户选择要上传的文件(OpenFilePicker)或自带摄像头拍摄的视频,执行成功返回201创建成功。
private async Task<bool> UploadFileAsync(string acsToken, string uploadEndPoint,string uploadUrl)
{
HttpClientHandler handler = new HttpClientHandler { MaxRequestContentBufferSize = 10000000 };
HttpClient httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Add("x-ms-version", "2011-08-18");
httpClient.DefaultRequestHeaders.Add("x-ms-date", "2011-01-17");
httpClient.DefaultRequestHeaders.Add("x-ms-blob-type", "BlockBlob");
StorageFolder library = Windows.Storage.KnownFolders.VideosLibrary;
var videoFile = await library.GetFileAsync(MediaFileName);
var props = await videoFile.GetBasicPropertiesAsync();
var stream = await videoFile.OpenStreamForReadAsync();
ContentSize = props.Size;
StreamContent streamContent = new StreamContent(stream, (int)props.Size);
HttpResponseMessage response = await httpClient.PutAsync(uploadUrl, streamContent);
if (response.IsSuccessStatusCode)
{
return true;
}
else
{
return false;
}
}
请注意到这一步为止,媒体文件已经上传至Blob Storage,但是还没有更新到我们的资产实体中,需要再发送一个更新请求才能完成整个媒体文件的上传工作,相应的执行过程可参考如下代码。
private async Task MergeAssetFilesAsync(string acsToken, string wamsEndPoint,string assetId, string assetFileId, string mediaFileName)
{
AuthenticationHeaderValue header = CreateBasicAuthenticationHeader(acsToken);
String requestBody = "{ \"Name\" : \"" + mediaFileName + "\"," +
" \"ContentFileSize\" : \"" + ContentSize + "\", " +
" \"ParentAssetId\" : \"" + assetId + "\", " +
" \"Id\" : \"" + assetFileId + "\", " +
" \"MimeType\" : \"" + "video/x-ms-wmv" + "\"}";
var 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"] = "3.0";
request.Headers["MaxDataServiceVersion"] = "3.0";
request.Headers["x-ms-version"] = "2.7";
request.Headers["Authorization"] = header.ToString();
var requestBytes = Encoding.UTF8.GetBytes(requestBody);
var requestStream = await request.GetRequestStreamAsync();
await requestStream.WriteAsync(requestBytes, 0, requestBytes.Length);
await requestStream.FlushAsync();
var response = await request.GetResponseAsync();
}
完成文件的上传后,我们可以在Portal上看到该文件的大小,同时在页面底部的Encode按钮现在也可以使用了,之后便可以进行后续媒体的操作如编码,将在后续文章中详细讲述,敬请期待。
