• FFmpeg的C#.Net封装


    After reading below article do not forget to checkout Important Update to Another Simple C# Wrapper For FFmpeg

    When you want to encode uploaded videos to your website you are in luck if you use PHP, encoding uploaded videos to your web site on the fly quite easy on Linux based servers. Install FFmpeg and get a PHP wrapper for FFmpeg and you are good to go.

    Story is a little bit different on Windows servers. There is no support from .Net framework; although there are couple of open source C# .Net wrappers for FFmpeg that encodes video on the fly, they are mostly incomplete. There are also commercial ones such as Mediahandler are not free/open-source.

    In short, I couldn't get what i wanted from open-source ones so I've decided to write my own C# wrapper for FFmpeg.

    My .Net skills are no where near good but here what i ended up with.

    See usage in the example at the bottom of this post. Download whole project VideoEncoder.rar (48.54 kb) or download changes made by Anders (see comments) VideoEncoderAsync.rar (6.79 kb)

    Don't forget to download FFmpeg win32 build and put in to FFmpeg folder in the project

    My solution has 5 classes;

    Encoder.cs, does the main job and gets FFmpegPath as input.

    It has 3 methods :

    •  EncodeVideo: Encodes video with FFmpeg according to commands
    •  GetVideoThumbnail: Gets video thumbnail image without encoding video
    •  GetVideoInfo: Gets information about source video and assigns it to VideoFile class such as Duration, BitRate, AudioFormat, VideoFormat, Height, Width 

    To do: Implement a class to insert logo on to the video with ffmpeg -vhook

    Source of Encoder.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Text.RegularExpressions;
     
     
    namespace VideoEncoder
    {
        public class Encoder
        {
     
            public EncodedVideo EncodeVideo(VideoFile input, string encodingCommand, string outputFile, bool getVideoThumbnail)
            {
                EncodedVideo encoded = new EncodedVideo();
     
                Params = string.Format("-i {0} {1} {2}", input.Path, encodingCommand, outputFile);
                string output = RunProcess(Params);
                encoded.EncodingLog = output;
                encoded.EncodedVideoPath = outputFile;
                 
     
     
     
     
                if (File.Exists(outputFile))
                {
                    encoded.Success = true;
     
                    //get thumbnail?
                    if (getVideoThumbnail)
                    {
                        string saveThumbnailTo = outputFile + "_thumb.jpg";
     
                        if (GetVideoThumbnail(input, saveThumbnailTo))
                        {
                            encoded.ThumbnailPath = saveThumbnailTo;
                        }
                    }
                }
                else
                {
                    encoded.Success = false;
                }
     
     
                return encoded;
     
            }
            public bool GetVideoThumbnail(VideoFile input, string saveThumbnailTo)
            {
                if (!input.infoGathered)
                {
                    GetVideoInfo(input);
                }
                int secs;
                //divide the duration in 3 to get a preview image in the middle of the clip
                //instead of a black image from the beginning.
                secs = (int)Math.Round(TimeSpan.FromTicks(input.Duration.Ticks / 3).TotalSeconds, 0);
                string Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, saveThumbnailTo, secs);
                string output = RunProcess(Params);
     
                if (File.Exists(saveThumbnailTo))
                {
                    return true;
                }
                else
                {
                    //try running again at frame 1 to get something
                    Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, saveThumbnailTo, 1);
                    output = RunProcess(Params);
     
                    if (File.Exists(saveThumbnailTo))
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
     
     
            }
            public void GetVideoInfo(VideoFile input)
            {
                string Params = string.Format("-i {0}", input.Path);
                string output = RunProcess(Params);
                input.RawInfo = output;
                input.Duration = ExtractDuration(input.RawInfo);
                input.BitRate = ExtractBitrate(input.RawInfo);
                input.RawAudioFormat = ExtractRawAudioFormat(input.RawInfo);
                input.AudioFormat = ExtractAudioFormat(input.RawAudioFormat);
                input.RawVideoFormat = ExtractRawVideoFormat(input.RawInfo);
                input.VideoFormat = ExtractVideoFormat(input.RawVideoFormat);
                input.Width = ExtractVideoWidth(input.RawInfo);
                input.Height = ExtractVideoHeight(input.RawInfo);
                input.infoGathered = true;
            }
            private string RunProcess(string Parameters)
            {
                //create a process info
                ProcessStartInfo oInfo = new ProcessStartInfo(this.FFmpegPath, Parameters);
                oInfo.UseShellExecute = false;
                oInfo.CreateNoWindow = true;
                oInfo.RedirectStandardOutput = true;
                oInfo.RedirectStandardError = true;
     
                //Create the output and streamreader to get the output
                string output = null; StreamReader srOutput = null;
     
                //try the process
                try
                {
                    //run the process
                    Process proc = System.Diagnostics.Process.Start(oInfo);
     
                    proc.WaitForExit();
     
                    //get the output
                    srOutput = proc.StandardError;
     
                    //now put it in a string
                    output = srOutput.ReadToEnd();
     
                    proc.Close();
                }
                catch (Exception)
                {
                    output = string.Empty;
                }
                finally
                {
                    //now, if we succeded, close out the streamreader
                    if (srOutput != null)
                    {
                        srOutput.Close();
                        srOutput.Dispose();
                    }
                }
                return output;
            }
            public string FFmpegPath { get; set; }
            private string Params { get; set; }
            private TimeSpan ExtractDuration(string rawInfo)
            {
                TimeSpan t = new TimeSpan(0);
                Regex re = new Regex("[D|d]uration:.((\d|:|\.)*)", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
     
                if (m.Success)
                {
                    string duration = m.Groups[1].Value;
                    string[] timepieces = duration.Split(new char[] { ':', '.' });
                    if (timepieces.Length == 4)
                    {
                        t = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
                    }
                }
     
                return t;
            }
            private double ExtractBitrate(string rawInfo)
            {
                Regex re = new Regex("[B|b]itrate:.((\d|:)*)", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
                double kb = 0.0;
                if (m.Success)
                {
                    Double.TryParse(m.Groups[1].Value, out kb);
                }
                return kb;
            }
            private string ExtractRawAudioFormat(string rawInfo)
            {
                string a = string.Empty;
                Regex re = new Regex("[A|a]udio:.*", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
                if (m.Success)
                {
                    a = m.Value;
                }
                return a.Replace("Audio: ", "");
            }
            private string ExtractAudioFormat(string rawAudioFormat)
            {
                string[] parts = rawAudioFormat.Split(new string[] { ", " }, StringSplitOptions.None);
                return parts[0].Replace("Audio: ", "");
            }
            private string ExtractRawVideoFormat(string rawInfo)
            {
                string v = string.Empty;
                Regex re = new Regex("[V|v]ideo:.*", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
                if (m.Success)
                {
                    v = m.Value;
                }
                return v.Replace("Video: ", ""); ;
            }
            private string ExtractVideoFormat(string rawVideoFormat)
            {
                string[] parts = rawVideoFormat.Split(new string[] { ", " }, StringSplitOptions.None);
                return parts[0].Replace("Video: ", "");
            }
            private int ExtractVideoWidth(string rawInfo)
            {
                int width = 0;
                Regex re = new Regex("(\d{2,4})x(\d{2,4})", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
                if (m.Success)
                {
                    int.TryParse(m.Groups[1].Value, out width);
                }
                return width;
            }
            private int ExtractVideoHeight(string rawInfo)
            {
                int height = 0;
                Regex re = new Regex("(\d{2,4})x(\d{2,4})", RegexOptions.Compiled);
                Match m = re.Match(rawInfo);
                if (m.Success)
                {
                    int.TryParse(m.Groups[2].Value, out height);
                }
                return height;
            }
        }
    }

     

    EncodedVideo.cs is output package for Encode method

    Source of EncodedVideo.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    namespace VideoEncoder
    {
        public class EncodedVideo
        {
            public string EncodedVideoPath { get; set; }
            public string ThumbnailPath {get; set; }
            public string EncodingLog { get; set; }
            public bool Success { get; set; }
        }
     
    }

     

    VideoFile.cs holds properties of input/source video

    Source of VideoFile.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    using System;
    using System.IO;
     
    namespace VideoEncoder
    {
     
        public class VideoFile
        {
            private string _Path;
            public string Path
            {
                get
                {
                    return _Path;
                }
                set
                {
                    _Path = value;
                }
            }
            public TimeSpan Duration { get; set; }
            public double BitRate { get; set; }
            public string RawAudioFormat { get; set; }
            public string AudioFormat { get; set; }
            public string RawVideoFormat { get; set; }
            public string VideoFormat { get; set; }
            public int Height { get; set; }
            public int Width { get; set; }
            public string RawInfo { get; set; }
            public bool infoGathered { get; set; }
     
            public VideoFile(string path)
            {
                _Path = path;
                Initialize();
            }
            private void Initialize()
            {
                this.infoGathered = false;
                if (string.IsNullOrEmpty(_Path))
                {
                    throw new Exception("Video file Path not set or empty.");
                }
                if (!File.Exists(_Path))
                {
                    throw new Exception("The video file " + _Path + " does not exist.");
                }
            }
        }
    }

     

    Project also have two helper classes QuickAudioEncodingCommands.cs and QuickVideoEncodingCommands.cs to make video encoding easier. I simple created FFmpeg command-line snippets for easy encoding

    Source of QuickAudioEncodingCommands.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ///
    ///
    /// Ready made encoding commands for FFmpeg
    /// Use when calling EncodeVideo commands as string encodingCommand
    /// Add remove as you like
    ///
    ///
    ///
    public class QuickAudioEncodingCommands
    {
            //mp3
        public static string MP3128Kbps = "-y -ab 128k -ar 44100";
        public static string MP396Kbps = "-y -ab 96k -ar 44100";
        public static string MP364Kbps = "-y -ab 64k -ar 44100";
        public static string MP332Kbps = "-y -ab 32k -ar 44100";
     }

    Source of  QuickVideoEncodingCommands.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    ///
    ///
    /// Ready made encoding commands for FFmpeg
    /// Use when calling EncodeVideo commands as string encodingCommand
    /// Add remove as you like
    ///
    ///
    ///
    namespace VideoEncoder
    {
        public class QuickVideoEncodingCommands
        {
            //-b
            static string LQVideoBitrate = "256k";
            static string MQVideoBitrate = "512k";
            static string HQVideoBitrate = "756k";
            static string VHQVideoBitrate = "1024k";
            //-ab
            static string LQAudioBitrate = "32k";
            static string MQAudioBitrate = "64k";
            static string HQAudioBitrate = "96k";
            static string VHQAudioBitrate = "128k";
            //-ar
            static string LQAudioSamplingFrequency = "22050";
            static string MQAudioSamplingFrequency = "44100";
            static string HQAudioSamplingFrequency = "44100";
            //-s
            static string SQCIF = "sqcif"; //128x96
            static string QCIF = "qcif"; //176x144
            static string QVGA = "qvga"; //320x240
            static string CIF = "cif"; //352x288
            static string VGA = "vga"; //640x480
            static string SVGA = "svga"; //800x600
     
        
            // todo
            //insert logo
            //
            //string LogoPath ="/Path/to/transparent/png";
            //string PositionX ="0";
            //string PositionY ="0";
            //string.Format("-vhook "vhook/imlib2.dll -x {0} -y {1}  -i {2}"", PositionX,PositionY,LogoPath);
     
     
     
            //flv
            public static string FLVLowQualityQCIF = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f flv", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string FLVMediumQualityCIF = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f flv", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string FLVHighQualityVGA = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f flv", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
            public static string FLVVeryHighQualitySVGA = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f flv", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA);
     
            public static string FLVLowQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string FLVMediumQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string FLVHighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
            public static string FLVVeryHighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA);
     
            //3gp
            public static string THREEGPLowQualitySQCIF = string.Format("-y -acodec aac -ac 1 -b {0} -ab {1} -ar {2} -s {3} -f 3gp", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, SQCIF);
            public static string THREEGPMediumQualityQCIF = string.Format("-y -acodec aac -b {0} -ab {1} -ar {2} -s {3} -f 3gp", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, QCIF);
            public static string THREEGPHighQualityCIF = string.Format("-y -acodec aac -b {0} -ab {1} -ar {2} -s {3} -f 3gp", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, CIF);
            //mp4
            public static string MP4LowQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string MP4MediumQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string MP4HighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
     
            public static string MP4LowQualityQVGA = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f mp4", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string MP4MediumQualityCIF = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f mp4", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string MP4HighQualityVGA = string.Format("-y -b {0} -ab {1} -ar {2} -s {3} -f mp4", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
     
            //WMV
            public static string WMVLowQualityQVGA = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2} -s {3}", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string WMVMediumQualityCIF = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2} -s {3}", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string WMVHighQualityVGA = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2} -s {3}", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
            public static string WMVVeryHighQualitySVGA = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2} -s {3}", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA);
     
            public static string WMVLowQualityKeepOriginalSize = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2}", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA);
            public static string WMVMediumQualityKeepOriginalSize = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2}", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF);
            public static string WMVHighQualityKeepOriginalSize = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2}", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA);
            public static string WMVVeryHighQualityKeepOriginalSize = string.Format("-y -vcodec wmv2  -acodec wmav2 -b {0} -ab {1} -ar {2}", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA);
     
        }
    }

    Sample Usage

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    using System;
    using VideoEncoder;
     
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Encoder enc = new Encoder();
            enc.FFmpegPath = Server.MapPath("~/FFmpeg/ffmpeg.exe");
            VideoFile inputv = new VideoFile(Server.MapPath("~/WorkingFolder/SourceVideo.wmv"));
            string outputVPath = Server.MapPath("~/WorkingFolder/OutputVideo.flv");
            string saveThumbnailTo = Server.MapPath("~/WorkingFolder/OutputVideoThumbnail.jpg");
             
            // to get video thumbnail call
            enc.GetVideoThumbnail(inputv,saveThumbnailTo);
     
     
            // to encode video call
            EncodedVideo encoded = enc.EncodeVideo(inputv, QuickVideoEncodingCommands.FLVVeryHighQualityKeepOriginalSize, outputVPath, true);
            if (encoded.Success)
            {
                Response.Write(encoded.ThumbnailPath);
                Response.Write("<br>");
                Response.Write(encoded.EncodedVideoPath);
                Response.Write("<br>");
                Response.Write(encoded.EncodingLog);
            }
            else
            {
                Response.Write(encoded.EncodingLog);
            }
     
        }
    }

    This project borrowed some code from http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/

  • 相关阅读:
    js的一些总结
    模型矩阵, 视图矩阵, 投影矩阵
    深入理解Three.js(WebGL)贴图(纹理映射)和UV映射
    Cesium学习笔记(四)Camera
    Node.js 命令行程序开发教程 ---------http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html
    node 模块 fs-extra
    Object.keys() https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
    Object.create() __https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
    JavaScript停止冒泡和阻止浏览器默认行为
    js创建对象的最佳方式
  • 原文地址:https://www.cnblogs.com/cjxiao/p/3232345.html
Copyright © 2020-2023  润新知