欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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 方法就可以了。