DotNet 使用阿裡雲媒體轉碼服務

来源:https://www.cnblogs.com/weisenz/archive/2019/08/06/11308806.html
-Advertisement-
Play Games

公司項目中一部分文件放到了阿裡雲 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 方法就可以了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 資料庫基礎 資料庫系統的組成:由資料庫,資料庫管理軟體,資料庫管理員DBA,支持資料庫系統的硬體和軟體組成,其中資料庫管理員是對資料庫進行規劃、設計、維護、和監視的專業管理人員,在資料庫系統中起著非常重要的作用 資料庫系統的三級模式解構分為: 內模式(唯一):主要描述資料庫系統的物理結構和儲存方式, ...
  • GAC 全稱是 Global Assembly Cache 作用是可以存放一些有很多程式都要用到的公共 Assembly ,例如 System.Data 、System.Windows.Form 等等。這樣,很多程式就可以從GAC 裡面取得 Assembly ,而不需要再把所有要 用到的 Assem ...
  • 演示用遞歸的方法複製指定文件夾下所有文件(包括子文件夾)到指定位置,涉及位元組流讀取寫入位元組操作 ...
  • 測試頁面foo.html 在Startup.cs內使用middleware 代碼如下: 或者: 運行結果: Static Files in ASP.NET Core By default an ASP.NET Core application will not serve static files; ...
  • 介紹 本文章發佈於博客園:https://www.cnblogs.com/fallstar/p/11310749.html 作者:fallstar 本文章適用於:ASP.NET Core 2.1 + 今天想給一個asp.net core 的項目加上許可權驗證,於是研究了一下怎麼加, 折騰了好一陣,發現 ...
  • 寫在前面 Dapper 是一款輕量級ORM架構。為解決網站訪問流量極高而產生的性能問題而構造,主要通過執行TSQL表達式而實現資料庫的CQRS。 如果在項目中遇到性能訪問問題,選擇Dapper作為ORM框架可能是明智之舉,當然也可以使用Entity Framework或NHibernate來處理大數 ...
  • 恢復內容開始 1.delegate 一般用法 delegate void WriteValue(string vale);//申明一個委托,參數是string類型,無返回值 static void Main(string[] args) { WriteValue write = new WriteV ...
  • 淺拷貝和深拷貝之間的區別: 淺拷貝是指將對象中的數值類型的欄位拷貝到新的對象中,而對象中的引用型欄位則指複製它的一個引用到目標對象。如果改變目標對象中引用型欄位的值他將反映在原始對象中,也就是說原始對象中對應的欄位也會發生變化。 深拷貝與淺拷貝不同的是對於引用的處理,深拷貝將會在新對象中創建一個新的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...