DotNet 使用阿里云媒体转码服务
程序员文章站
2022-07-04 23:04:15
公司项目中一部分文件放到了阿里云 OSS 上,其中有些音频文件是 amr 类型的,在后期使用的时候比较麻烦,所以需要转换成 mp3 的文件,方便以后使用。本来想使用 ffmpeg 处理,但由于文件都存放在阿里云 OSS 上,使用 ffmpeg 就需要把文件从远程下载下来,转码之后再重新传回阿里云上,... ......
公司项目中一部分文件放到了阿里云 oss 上,其中有些音频文件是 amr 类型的,在后期使用的时候比较麻烦,所以需要转换成 mp3 的文件,方便以后使用。本来想使用 ffmpeg 处理,但由于文件都存放在阿里云 oss 上,使用 ffmpeg 就需要把文件从远程下载下来,转码之后再重新传回阿里云上,还需要使用消息组件进行通知,而且转码对服务器的压力也会很大。不如直接使用阿里云的媒体转码服务来的快,阿里云只提供了 oss 的 dotnet 类库,并没有提供 mts 的,所以只能自己参考 api 和其他语言的类库来开发,还好 mts 的 api 并不是很复杂,几次尝试之后就搞定了。
相关参数需要从阿里云的控制台获取。
阿里云媒体转码服务类:
/// <summary>
/// 阿里云媒体转码服务助手类。
/// </summary>
public class mediatranscodehelper
{
private static readonly encoding encode_type = encoding.utf8;
private static readonly string algorithm = "hmacsha1";
private static readonly string http_method = "get";
private static readonly string separator = "&";
private static readonly string equal = "=";
private static readonly string iso8601_date_format = "yyyy-mm-dd't'hh:mm:ss'z'";
private static readonly string regionid = "cn-beijing";
private static readonly string version = "2014-06-18";
private static readonly string action = "submitjobs";
private static readonly string format = "json";
private static readonly string mtsdomain = "mts.cn-beijing.aliyuncs.com";
private static readonly int maxretrynumber = 3;
private static readonly bool autoretry = true;
private static readonly int timeoutinmilliseconds = 100000;
private static readonly string accesskeyid = "you accesskeyid";
private static readonly string accesskeysecret = "you accesskeysecret";
private static readonly string pipelineid = "you pipelineid";
/// <summary>
/// 提交转码任务。
/// </summary>
/// <param name="inputfile">输入文件。</param>
/// <returns>输出文件。</returns>
public static string submittranscodejob(string inputfile, string osslocation)
{
string outputjob = string.empty;
return outputjob;
}
/// <summary>
/// 提交转码任务。
/// </summary>
public async task<(bool success, string response)> submittranscodejob()
{
string signaturenonce = guid.newguid().tostring();
var paramers = new dictionary<string, string>
{
{ "action", action },
{ "version", "2014-06-18" },
{ "accesskeyid", accesskeyid },
{ "timestamp", formatiso8601date(datetime.now) },
{ "signaturemethod", "hmac-sha1" },
{ "signatureversion", "1.0" },
{ "signaturenonce", signaturenonce },
{ "format", format },
{ "pipelineid", pipelineid },
{ "input", "{\"bucket\":\"charlesbeijng\",\"location\":\"oss-cn-beijing\",\"object\":\"3.amr\"}" },
{ "outputbucket", "charlesbeijng" },
{ "outputlocation", "oss-cn-beijing" },
{ "outputs", " [{\"outputobject\":\"" + guid.newguid().tostring() + ".mp3\",\"templateid\":\"1a94dc364cec44708f00367938a0122f\",\"location\":\"oss-cn-beijing\",\"watermarks\":[{\"inputfile\":{\"bucket\":\"charlesbeijng\",\"location\":\"oss-cn-beijing\",\"object\":\"1.png\"},\"watermarktemplateid\":\"c473de87d0504f44be7ebdac1667ab13\"}]}]" }
};
try
{
string url = getsignurl(paramers, accesskeysecret);
int retrytimes = 1;
var reply = await httpgetasync(url);
while (500 <= reply.statuscode && autoretry && retrytimes < maxretrynumber)
{
url = getsignurl(paramers, accesskeysecret);
reply = await httpgetasync(url);
retrytimes++;
}
if (!string.isnullorempty(reply.response))
{
var res = jsonconvert.deserializeobject<dictionary<string, string>>(reply.response);
if (res != null && res.containskey("code") && "ok".equals(res["code"]))
{
return (true, reply.response);
}
}
return (false, reply.response);
}
catch (exception ex)
{
return (false, response: ex.message);
}
}
/// <summary>
/// 同步请求。
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private static string httpget(string url)
{
httpwebrequest req = (httpwebrequest)webrequest.create(url);
req.method = http_method;
req.keepalive = true;
req.useragent = "idui1";
req.timeout = timeoutinmilliseconds;
req.contenttype = "application/x-www-form-urlencoded;charset=utf-8";
httpwebresponse rsp = null;
try
{
rsp = (httpwebresponse)req.getresponse();
}
catch (webexception webex)
{
if (webex.status == webexceptionstatus.timeout)
{
rsp.close();
}
}
if (rsp != null)
{
if (rsp.characterset != null)
{
encoding encoding = encoding.getencoding(rsp.characterset);
return getresponseasstring(rsp, encoding);
}
else
{
return string.empty;
}
}
else
{
return string.empty;
}
}
/// <summary>
/// 异步请求。
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private async task<(int statuscode, string response)> httpgetasync(string url)
{
httpclienthandler handler = new httpclienthandler();
handler.proxy = null;
handler.automaticdecompression = decompressionmethods.gzip;
using (var http = new httpclient(handler))
{
http.timeout = new timespan(timespan.tickspermillisecond * timeoutinmilliseconds);
httpresponsemessage response = await http.getasync(url);
return ((int)response.statuscode, await response.content.readasstringasync());
}
}
/// <summary>
/// 把响应流转换为文本。
/// </summary>
/// <param name="rsp">响应流对象</param>
/// <param name="encoding">编码方式</param>
/// <returns>响应文本</returns>
private static string getresponseasstring(httpwebresponse rsp, encoding encoding)
{
stringbuilder result = new stringbuilder();
stream stream = null;
streamreader reader = null;
try
{
// 以字符流的方式读取http响应
stream = rsp.getresponsestream();
//rsp.close();
reader = new streamreader(stream, encoding);
// 每次读取不大于256个字符,并写入字符串
char[] buffer = new char[256];
int readbytes = 0;
while ((readbytes = reader.read(buffer, 0, buffer.length)) > 0)
{
result.append(buffer, 0, readbytes);
}
}
catch (webexception webex)
{
if (webex.status == webexceptionstatus.timeout)
{
result = new stringbuilder();
}
}
finally
{
// 释放资源
if (reader != null) reader.close();
if (stream != null) stream.close();
if (rsp != null) rsp.close();
}
return result.tostring();
}
/// <summary>
/// 处理消息。
/// </summary>
/// <param name="message">消息内容。</param>
public static void handlingmessage(string message)
{
}
/// <summary>
///
/// </summary>
/// <param name="datetime"></param>
/// <returns></returns>
private static string formatiso8601date(datetime datetime)
{
return datetime.touniversaltime().tostring("yyyy-mm-dd't'hh:mm:ss'z'", cultureinfo.createspecificculture("en-us"));
}
/// <summary>
/// 签名
/// </summary>
public static string signstring(string source, string accesssecret)
{
using (var algorithm = new hmacsha1(encoding.utf8.getbytes(accesssecret.tochararray())))
{
return convert.tobase64string(algorithm.computehash(encoding.utf8.getbytes(source.tochararray())));
}
}
private string getsignurl(dictionary<string, string> parameters, string accesssecret)
{
var imutablemap = new dictionary<string, string>(parameters)
{
//{ "timestamp", formatiso8601date(datetime.now) },
//{ "signaturemethod", "hmac-sha1" },
//{ "signatureversion", "1.0" },
//{ "signaturenonce", guid.newguid().tostring() },
//{ "action", action },
//{ "version", version },
//{ "format", format },
//{ "regionid", regionid }
};
idictionary<string, string> sorteddictionary = new sorteddictionary<string, string>(imutablemap, stringcomparer.ordinal);
stringbuilder canonicalizedquerystring = new stringbuilder();
foreach (var p in sorteddictionary)
{
canonicalizedquerystring.append("&")
.append(percentencode(p.key)).append("=")
.append(percentencode(p.value));
}
stringbuilder stringtosign = new stringbuilder();
stringtosign.append(http_method);
stringtosign.append(separator);
stringtosign.append(percentencode("/"));
stringtosign.append(separator);
stringtosign.append(percentencode(canonicalizedquerystring.tostring().substring(1)));
string signature = signstring(stringtosign.tostring(), accesssecret + "&");
imutablemap.add("signature", signature);
return composeurl(mtsdomain, imutablemap);
}
private static string composeurl(string endpoint, dictionary<string, string> parameters)
{
stringbuilder urlbuilder = new stringbuilder("");
urlbuilder.append("http://").append(endpoint);
if (-1 == urlbuilder.tostring().indexof("?"))
{
urlbuilder.append("/?");
}
string query = concatquerystring(parameters);
return urlbuilder.append(query).tostring();
}
private static string concatquerystring(dictionary<string, string> parameters)
{
if (null == parameters)
{
return null;
}
stringbuilder sb = new stringbuilder();
foreach (var entry in parameters)
{
string key = entry.key;
string val = entry.value;
sb.append(httputility.urlencode(key, encoding.utf8));
if (val != null)
{
sb.append("=").append(httputility.urlencode(val, encoding.utf8));
}
sb.append("&");
}
int strindex = sb.length;
if (parameters.count > 0)
sb.remove(strindex - 1, 1);
return sb.tostring();
}
public static string percentencode(string value)
{
stringbuilder stringbuilder = new stringbuilder();
string text = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789-_.~";
byte[] bytes = encoding.getencoding("utf-8").getbytes(value);
foreach (char c in bytes)
{
if (text.indexof(c) >= 0)
{
stringbuilder.append(c);
}
else
{
stringbuilder.append("%").append(
string.format(cultureinfo.invariantculture, "{0:x2}", (int)c));
}
}
return stringbuilder.tostring();
}
/// <summary>
/// hmac-sha1加密算法
/// </summary>
/// <param name="key">密钥</param>
/// <param name="input">要加密的串</param>
/// <returns></returns>
public static string hmacsha1(string key, string input)
{
byte[] keybytes = encoding.utf8.getbytes(key);
byte[] inputbytes = encoding.utf8.getbytes(input);
hmacsha1 hmac = new hmacsha1(keybytes);
byte[] hashbytes = hmac.computehash(inputbytes);
return convert.tobase64string(hashbytes);
}
/// <summary>
/// aes 算法加密(ecb模式) 将明文加密,加密后进行base64编码,返回密文
/// </summary>
/// <param name="encryptstr">明文</param>
/// <param name="key">密钥</param>
/// <returns>加密后base64编码的密文</returns>
public static string encrypt(string encryptstr, string key)
{
try
{
//byte[] keyarray = encoding.utf8.getbytes(key);
byte[] keyarray = convert.frombase64string(key);
byte[] toencryptarray = encoding.utf8.getbytes(encryptstr);
rijndaelmanaged rdel = new rijndaelmanaged
{
key = keyarray,
mode = ciphermode.ecb,
padding = paddingmode.pkcs7
};
icryptotransform ctransform = rdel.createencryptor();
byte[] resultarray = ctransform.transformfinalblock(toencryptarray, 0, toencryptarray.length);
return convert.tobase64string(resultarray, 0, resultarray.length);
}
catch (exception)
{
return null;
}
}
public static string decrypt(string todecrypt, string key)
{
byte[] keyarray = convert.frombase64string(key); // 将 testgenaesbytekey 类输出的字符串转为 byte 数组
byte[] toencryptarray = convert.frombase64string(todecrypt);
rijndaelmanaged rdel = new rijndaelmanaged
{
key = keyarray,
mode = ciphermode.ecb, // 必须设置为 ecb
padding = paddingmode.pkcs7 // 必须设置为 pkcs7
};
icryptotransform ctransform = rdel.createdecryptor();
byte[] resultarray = ctransform.transformfinalblock(toencryptarray, 0, toencryptarray.length);
return encoding.utf8.getstring(resultarray);
}
private static string buildcanonicalizedquerystring(dictionary<string, string> parameters)
{
// 对参数进行排序
list<string> sortedkeys = new list<string>(parameters.keys);
sortedkeys.sort();
stringbuilder temp = new stringbuilder();
foreach (var key in sortedkeys)
{
// 此处需要对 key 和 value 进行编码
string value = parameters[key];
temp.append(separator).append(percentencode(key)).append(equal).append(percentencode(value));
}
return temp.tostring().substring(1);
}
private static string buildrequesturl(string signature, dictionary<string, string> parameters)
{
// 生成请求 url
stringbuilder temp = new stringbuilder("mts.cn-beijing.aliyuncs.com");
temp.append(httputility.urlencode("signature", encode_type)).append("=").append(signature);
foreach (var item in parameters)
{
temp.append("&").append(percentencode(item.key)).append("=").append(percentencode(item.value));
}
return temp.tostring();
}
}
使用的时候直接调用 submittranscodejob 方法就可以了。