媒体上传--在Windows Store应用中使用Azure媒体服务之一

Windows Azure的媒体服务预览已经于8月15日在中国上线,我已经迫不及待的想在在Windows Store应用中加入媒体服务功能带来的便利了。可是,一个很让人沮丧的事情是,目前的Azure Media的SDK还不支持windows Store应用。不过没关系,我们还有REST API可以使用,这里我就讲解一下如何在Windows store应用中完成媒体文件的上传,编码及发布。在这一篇blog中,我们首先来看一下媒体文件的上传。

为了使用Azure Media,你首先需要在Azure上创建一个媒体服务账号。该账号用以提供访问该媒体服务所需的信息。下面是创建媒体服务账号的步骤:

1.       登录进入Azure管理门户:

https://manage.windowsazure.com/

如果你还没有Windows Azure的账号,那么有两种办法可以免费试用Windows Azure:

a.  因为Windows Azure已经在中国落地,你可以到https://www.windowsazure.cn上去申请试用,这段时间1元试用可是有大礼包送的哦。

b.  你可以登录全球的Windows Azure网站https://www.windowsazure.com来建立一个试用账号。在建立使用账号过程中如果无法进行电话或者短信验证的话,可以到以下网址提交一个问题来要求免去电话和短信验证步骤:

https://support.microsoft.com/oas/default.aspx?prid=14238&ln=en-us&st=1&wfxredirect=1

 

在提交问题的时候,你需要设定如下支持类型

 

然后再后续的邮件中再描述一下你遇到的问题,要求免去电话和短信验证步骤就可以了。

2.  点击新建->应用服务->媒体服务->快速创建,输入所需的名称,选择媒体服务存放的地点以及存储服务的账户。如果你之前没有建立存储服务的账户的话,你也可以选择“新建存储账户”。然后点击“创建媒体服务”就创建了一个媒体服务账号:

 

 

3.       点击新创建的媒体服务账号->管理密钥,你就可以获得访问该媒体服务所需的账户名称以及访问密钥,请将这两个字符串拷贝出来,后面我们会在编程的时候使用到:

    1.  

在配置完Azure Media以后,我们就可以在Windows Store应用程序中通过REST API来传文件了。

首先,我们创建一个新的Windows Store应用,然后为项目添加两个引用:

Microsoft.WindowsAzure.Storage

Newtonsoft.Json

 

为了演示视频文件的上传,我们可以在示例代码中加入一个Button,然后在Button的处理函数中添加相关的代码。我们需要定义两个string来存放前面获得的Account Name和Access Key。另外,我们还需要定义两个string来存放对应的存储账户的Account Name和Access Key以便于后续对存储容器的直接访问。对应的存储账户信息可以从媒体服务的仪表板中获得:

 

接下来就是具体的实现代码了,对于要发送的http报文的内容,下面的MSDN链接已经有详细的描述,我这边就不再重复了:

https://msdn.microsoft.com/en-us/library/azure/jj129593.aspx

根据上述的描述,我们首先要获得一个Access Token,代码如下:

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;}

}

 

private async Task<string> GetAccessToken()

{

    string scope = "urn:WindowsAzureMediaServices";

    string accessControlServiceUri = "https://wamsprodglobal001acs.accesscontrol.windows.net/v2/OAuth2-13";

 

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(accessControlServiceUri);

    request.Method = "POST";

    request.ContentType = "application/x-www-form-urlencoded";

 

    var requestBytes = Encoding.UTF8.GetBytes("grant_type=client_credentials&client_id=" +

        mediaServicesAccountName + "&client_secret=" + System.Net.WebUtility.UrlEncode(mediaServicesAccountKey) +

        "&scope=" + System.Net.WebUtility.UrlEncode(scope));

 

    var requestStream = await request.GetRequestStreamAsync();

    await requestStream.WriteAsync(requestBytes, 0, requestBytes.Length);

    await requestStream.FlushAsync();

 

    WebResponse response = await request.GetResponseAsync();

    Stream responseStream = response.GetResponseStream();

    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(AcsToken));

    var acsToken = (AcsToken)ser.ReadObject(responseStream);

    return acsToken.access_token;

}

  

在得到访问令牌后,就可以创建Asset了:

private async Task<string> CreateAsset(string accessToken)

{

    var request = (HttpWebRequest)HttpWebRequest.Create("https://wamshknclus001rest-hs.cloudapp.net/api/Assets");

    request.Method = "POST";

    request.ContentType = "application/json;odata=verbose";

    request.Accept = "application/json;odata=verbose";

 

    string assertName = "myAssert";

    string requestbody = "{ \"Name\" : \"" + assertName + "\" }";

    request.Headers["DataServiceVersion"] = "3.0";

    request.Headers["MaxDataServiceVersion"] = "3.0";

    request.Headers["x-ms-version"] = "2.5";

    request.Headers["Authorization"] = "Bearer " + accessToken;

 

    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();

    var responseStream = response.GetResponseStream();

    var stream = new StreamReader(responseStream);

 

    var returnBody = stream.ReadToEnd();

    JObject responseJsonObject = JObject.Parse(returnBody);

    var d = responseJsonObject["d"];

    return d.Value<string>("Id");

}

接下来我们需要更新Access Policy,允许对Asset进行写操作:

private async Task<string> UpdateAccessPolicy(string accessToken)

{

    var request = (HttpWebRequest)HttpWebRequest.Create("https://wamshknclus001rest-hs.cloudapp.net/api/AccessPolicies");

    request.Method = "POST";

    request.ContentType = "application/json;odata=verbose";

    request.Accept = "application/json;odata=verbose";

 

    string name = "UploadPolicy" + DateTime.UtcNow.ToString("s") + "Z";

    string dura = "300";

    int permission = 2;

    var requestbody = "{ \"Name\" : \"" + name + "\", \"DurationInMinutes\" : \"" + dura + "\", \"Permissions\" : " + permission + "}";

 

    request.Headers["DataServiceVersion"] = "3.0";

    request.Headers["MaxDataServiceVersion"] = "3.0";

    request.Headers["x-ms-version"] = "2.5";

    request.Headers["Authorization"] = "Bearer " + accessToken;

 

    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();

    var responseStream = response.GetResponseStream();

    var stream = new StreamReader(responseStream);

  

    var returnBody = stream.ReadToEnd();

    var responseJsonObject = JObject.Parse(returnBody);

    var d = responseJsonObject["d"];

    return d.Value<string>("Id");

}

得到了所获得的权限以后,我们就可以通过Assert的存储容器来上传媒体文件了。首先来获得Asset对用的存储容器的名称:

private async Task<string> GetContainerName(string policyId, string assetId, string accessToken)

{

    var request = (HttpWebRequest)HttpWebRequest.Create("https://wamshknclus001rest-hs.cloudapp.net/api/Locators");

    request.Method = "POST";

    request.ContentType = "application/json;odata=verbose";

    request.Accept = "application/json;odata=verbose";

 

    string starttime = DateTime.UtcNow.AddMinutes(-5).ToString("s") + "Z";

    int type = 1;

    var requestbody = "{ \"AccessPolicyId\" : \"" + policyId + "\", \"AssetId\" : \"" + assetId + "\", \"StartTime\" : \"" + starttime + "\", \"Type\" : " + type + "}";

 

    request.Headers["MaxDataServiceVersion"] = "3.0";

    request.Headers["x-ms-version"] = "2.5";

    request.Headers["Authorization"] = "Bearer " + accessToken;

    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();

    var responseStream = response.GetResponseStream();

    var stream = new StreamReader(responseStream);

    var returnBody = stream.ReadToEnd();

    var responseJsonObject = JObject.Parse(returnBody);

    var d = responseJsonObject["d"];

 

    string path = d.Value<string>("Path");

    return (new Uri(path)).Segments[1];

}

接下来就是通过存储服务的API来上传视频文件了,因为存储服务的SDK支持Windows Store应用,所以这里就不用REST API来实现了,直接调用SDK提供的接口,这样整个的Button响应函数代码如下:

private async void Button_Click(object sender, RoutedEventArgs e)

{

    StorageFolder library = Windows.Storage.KnownFolders.VideosLibrary;

    var video = await library.GetFileAsync("Wildlife.wmv");

 

    string accessToken = await GetAccessToken();

 

    string assetId = await CreateAsset(accessToken);

    string policyId = await UpdateAccessPolicy(accessToken);

    string containerName = await GetContainerName(policyId, assetId, accessToken);

   

    StorageCredentials credentials = new StorageCredentials(storageName, storageKey);

 

    var storageAccount = new CloudStorageAccount(credentials, false);

    var cloudBlobClient = storageAccount.CreateCloudBlobClient();

 

    var container = cloudBlobClient.GetContainerReference(containerName);

    await container.CreateIfNotExistsAsync();

 

    CloudBlockBlob blockBlob = container.GetBlockBlobReference("videoblob");

    await blockBlob.UploadFromFileAsync(video);

}

通过以上代码,我们就完成了对视频文件的上传,后续我还将讲述如何对媒体文件进行转码及播放,尽情期待。