C#視頻開發相關 ffmpeg

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.IO;
using System.Web;
namespace AUV5.Common
{
    public class FormatConverter
    {
        //FFmpeg配置信息
        private string ffmpegpath = "/FFmpeg/ffmpeg.exe";//FFmpeg的服務器路徑
        private string imgsize = "400*300";     //視頻截圖大小
        private string videosize = "480*360"; //視頻大小
        #region 也可將信息添加到配置文件中
        //public static string ffmpegpath = ConfigurationManager.AppSettings["ffmpeg"];
        //public static string imgsize = ConfigurationManager.AppSettings["imgsize"];
        //public static string videosize = ConfigurationManager.AppSettings["videoize"];
        #endregion
 
        private string destVideo = "";
 
        /// <summary>
        /// 視頻路徑
        /// </summary>
        public string DestVideo
        {
            get { return destVideo; }
            set { destVideo = value; }
        }
        private string destImage = "";
 
        /// <summary>
        /// 圖片路徑
        /// </summary>
        public string DestImage
        {
            get { return destImage; }
            set { destImage = value; }
        }
 
        /// <summary>
        /// 視頻長度
        /// </summary>
        public string VideoLength { get; set; }
 
        //文件類型
        public enum VideoType
        {
            [Description(".avi")]
            AVI,
            [Description(".mov")]
            MOV,
            [Description(".mpg")]
            MPG,
            [Description(".mp4")]
            MP4,
            [Description(".flv")]
            FLV
        }
        /// <summary>
        /// 返回枚舉類型的描述信息
        /// </summary>
        /// <param name="myEnum"></param>
        /// <returns></returns>
        private string GetDiscription(System.Enum myEnum)
        {
 
            System.Reflection.FieldInfo fieldInfo = myEnum.GetType().GetField(myEnum.ToString());
            object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
            if (attrs != null && attrs.Length > 0)
            {
                DescriptionAttribute desc = attrs[0] as DescriptionAttribute;
                if (desc != null)
                {
                    return desc.Description.ToLower();
                }
            }
            return myEnum.ToString();
        }
        //將GetDesCription定義爲擴展方法,需.net3.5
        //public static string Description(this Enum myEnum)
        //{
        //    return GetDiscription(myEnum);
        //}
 
        //構造函數
        //創建目錄
        public FormatConverter()
        {
        }
 
        #region 使用FFmpeg進行格式轉換
 
        /// <summary>
        /// 運行格式轉換
        /// </summary>
        /// <param name="sourceFile">要轉換文件絕對路徑</param>
        /// <param name="destPath">轉換結果存儲的相對路徑</param>
        /// <param name="videotype">要轉換成的文件類型</param>
        /// <param name="createImage">是否生成截圖</param>
        /// <returns>
        /// 執行成功返回空,否則返回錯誤信息
        /// </returns>
        public string Convert(string sourceFile, string destPath,string uniquename, VideoType videotype, bool createImage,bool getDuration)
        {
            //取得ffmpeg.exe的物理路徑
            string ffmpeg = System.Web.HttpContext.Current.Server.MapPath(ffmpegpath);
            if (!File.Exists(ffmpeg))
            {
                return "找不到格式轉換程序!";
            }
            if (!File.Exists(sourceFile))
            {
                return "找不到源文件!";
            }
            //string uniquename = FileHelper.GetUniqueFileName();
            string filename = uniquename + GetDiscription(videotype);
            string destFile = HttpContext.Current.Server.MapPath(destPath + filename);
            //if (Path.GetExtension(sourceFile).ToLower() != GetDiscription(videotype).ToLower())
            //{
            System.Diagnostics.ProcessStartInfo FilestartInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg);
            FilestartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            /*ffmpeg參數說明
             * -i 1.avi   輸入文件
             * -ab/-ac <比特率> 設定聲音比特率,前面-ac設爲立體聲時要以一半比特率來設置,比如192kbps的就設成96,轉換 
                均默認比特率都較小,要聽到較高品質聲音的話建議設到160kbps(80)以上
             * -ar <採樣率> 設定聲音採樣率,PSP只認24000
             * -b <比特率> 指定壓縮比特率,似乎ffmpeg是自動VBR的,指定了就大概是平均比特率,比如768,1500這樣的   --加了以後轉換不正常
             * -r 29.97 楨速率(可以改,確認非標準楨率會導致音畫不同步,所以只能設定爲15或者29.97)
             * s 320x240 指定分辨率
             * 最後的路徑爲目標文件
             */
            FilestartInfo.Arguments = " -i " + sourceFile + " -ab 80 -ar 22050 -r 29.97 -s " + videosize + " " + destFile;
            //FilestartInfo.Arguments = "-y -i " + sourceFile + " -s 320x240 -vcodec h264 -qscale 4  -ar 24000 -f psp -muxvb 768 " + destFile;
            try
            {
                //轉換
                System.Diagnostics.Process.Start(FilestartInfo);
                destVideo = destPath + filename;
            }
            catch
            {
                return "格式轉換失敗!";
            }
            //}
            //格式不需要轉換則直接複製文件到目錄
            //else
            //{
            //    File.Copy(sourceFile, destFile,true);
            //    destVideo = destPath + filename;
            //}
            //提取視頻長度
            if (getDuration)
            {
                VideoLength = GetVideoDuration(ffmpeg, sourceFile);
            }
            //提取圖片
            if (createImage)
            {
                //定義進程
                System.Diagnostics.ProcessStartInfo ImgstartInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg);
 
                //截大圖
                string imgpath = destPath + uniquename + ".jpg";// FileHelper.GetUniqueFileName(".jpg");
                ConvertImage(sourceFile, imgpath, imgsize, ImgstartInfo);
 
                //截小圖
                imgpath = destPath + uniquename + "_thumb.jpg";
                DestImage = ConvertImage(sourceFile, imgpath, "80*80", ImgstartInfo);
 
            }
            return "";
        }
 
        private string ConvertImage(string sourceFile, string imgpath, string imgsize, System.Diagnostics.ProcessStartInfo ImgstartInfo)
        {
            ImgstartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            /*參數設置
             * -y(覆蓋輸出文件,即如果生成的文件(flv_img)已經存在的話,不經提示就覆蓋掉了)
             * -i 1.avi 輸入文件
             * -f image2 指定輸出格式
             * -ss 8 後跟的單位爲秒,從指定時間點開始轉換任務
             * -vframes
             * -s 指定分辨率
             */
            //duration: 00:00:00.00
            string[] time = VideoLength.Split(':');
            int seconds = int.Parse(time[0]) * 60 * 60 + int.Parse(time[1]) * 60 + int.Parse(time[2]);
            int ss = seconds > 5 ? 5 : seconds - 1;
            ImgstartInfo.Arguments = " -i " + sourceFile + " -y -f image2 -ss " + ss.ToString() + " -vframes 1 -s " + imgsize + " " + HttpContext.Current.Server.MapPath(imgpath);
            try
            {
                System.Diagnostics.Process.Start(ImgstartInfo);
                return imgpath;
            }
            catch
            {
                return "";
            }
        }
 
 
        private string GetVideoDuration(string ffmpegfile, string sourceFile)
        {
            using (System.Diagnostics.Process ffmpeg = new System.Diagnostics.Process())
            {
                String duration;  // soon will hold our video's duration in the form "HH:MM:SS.UU"
                String result;  // temp variable holding a string representation of our video's duration
                StreamReader errorreader;  // StringWriter to hold output from ffmpeg
 
                // we want to execute the process without opening a shell
                ffmpeg.StartInfo.UseShellExecute = false;
                //ffmpeg.StartInfo.ErrorDialog = false;
                ffmpeg.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                // redirect StandardError so we can parse it
                // for some reason the output comes through over StandardError
                ffmpeg.StartInfo.RedirectStandardError = true;
 
                // set the file name of our process, including the full path
                // (as well as quotes, as if you were calling it from the command-line)
                ffmpeg.StartInfo.FileName = ffmpegfile;
 
                // set the command-line arguments of our process, including full paths of any files
                // (as well as quotes, as if you were passing these arguments on the command-line)
                ffmpeg.StartInfo.Arguments = "-i " + sourceFile;
 
                // start the process
                ffmpeg.Start();
 
                // now that the process is started, we can redirect output to the StreamReader we defined
                errorreader = ffmpeg.StandardError;
 
                // wait until ffmpeg comes back
                ffmpeg.WaitForExit();
 
                // read the output from ffmpeg, which for some reason is found in Process.StandardError
                result = errorreader.ReadToEnd();
 
                // a little convoluded, this string manipulation...
                // working from the inside out, it:
                // takes a substring of result, starting from the end of the "Duration: " label contained within,
                // (execute "ffmpeg.exe -i somevideofile" on the command-line to verify for yourself that it is there)
                // and going the full length of the timestamp
 
                duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length);
                return duration;
            }
        }
 
        #endregion
 
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章