zoukankan      html  css  js  c++  java
  • 转贴: A Simple c# Wrapper for ffMpeg

    原帖地址:http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/

    A Simple c# Wrapper for ffMpeg

    Converting video in .Net is a pain in the butt. The .Net framework, as of 2/8/2010 does not have a nice, simple, conversion process that will take a file in the many different formats out there and drop it into a nicely formatted .flv file for easy slideshowpro (or other flash based package) streaming.

    The alternative, that I have most often seen, is using ffMpeg to convert source video into .flv format. Unfortunately, this process can a bit arcane. While there are other libraries out there that wrap up ffMpeg with a nice shiny, albeit complex, bow. I figured there might be some use for a simple c# library that does a couple simple, but very useful processes.

    The following class will convert your input file to a .flv file and create a preview image from 1/3 of the way into the movie. By getting the preview image from 1/3 into the movie, we can avoid a completely black preview image that can come from a video that fades in.

    Getting Started:

    Create a directory in your project that contains the ffMpeg.exe file, this file will be referenced by the class below. This class is also going to use the web.config or app.config to store the location of our ffMpeg.exe file and a couple key settings. To do this, you will need to import system.configuration into your project and include the following line:

    1
    using System.Configuration;

    To start with, we have a couple properties that expose the working path that ffMpeg will need while it is processing our video file along with a property that exposes the location of our exe file.

    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
    private string _ffExe;
    public string ffExe
    {
        get
        {
            return _ffExe;
        }
        set
        {
            _ffExe = value;
        }
    }
     
    private string _WorkingPath;
    public string WorkingPath
    {
        get
        {
            return _WorkingPath;
        }
        set
        {
            _WorkingPath = value;
        }
    }

    In our constructors, we will call an initialize method that will attempt to grab our exepath from web.config, assuming that one has not been entered into our second constructor.

    Note: In this example, the class is name “Converter”

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public Converter()
    {
        Initialize();
    }
    public Converter(string ffmpegExePath)
    {
        _ffExe = ffmpegExePath;
        Initialize();
    }

    Initialization

    You will note that the we are testing to see if the ffmpeg.exe file location exists before attempting to pull it from web.config.

    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
    //Make sure we have valid ffMpeg.exe file and working directory to do our dirty work.
    private void Initialize()
    {
        //first make sure we have a value for the ffexe file setting
        if (string.IsNullOrEmpty(_ffExe))
        {
            object o = ConfigurationManager.AppSettings["ffmpeg:ExeLocation"];
            if (o == null)
            {
                throw new Exception("Could not find the location of the ffmpeg exe file.  The path for ffmpeg.exe " +
                "can be passed in via a constructor of the ffmpeg class (this class) or by setting in the app.config or web.config file.  " +
                "in the appsettings section, the correct property name is: ffmpeg:ExeLocation");
            }
            else
            {
                if (string.IsNullOrEmpty(o.ToString()))
                {
                    throw new Exception("No value was found in the app setting for ffmpeg:ExeLocation");
                }
                _ffExe = o.ToString();
            }
        }
     
        //Now see if ffmpeg.exe exists
        string workingpath = GetWorkingFile();
        if (string.IsNullOrEmpty(workingpath))
        {
            //ffmpeg doesn't exist at the location stated.
            throw new Exception("Could not find a copy of ffmpeg.exe");
        }
        _ffExe = workingpath;
     
        //now see if we have a temporary place to work
        if (string.IsNullOrEmpty(_WorkingPath))
        {
            object o = ConfigurationManager.AppSettings["ffmpeg:WorkingPath"];
            if (o != null)
            {
                _WorkingPath = o.ToString();
            }
            else
            {
                _WorkingPath = string.Empty;
            }
        }
    }
     
    private string GetWorkingFile()
    {
        //try the stated directory
        if (File.Exists(_ffExe))
        {
            return _ffExe;
        }
     
        //oops, that didn't work, try the base directory
        if (File.Exists(Path.GetFileName(_ffExe)))
        {
            return Path.GetFileName(_ffExe);
        }
     
        //well, now we are really unlucky, let's just return null
        return null;
    }

    Loading Files Without Creating Locks

    These subs might be a bit out of place but are useful as they create our memory resident objects without throwing a lock on the source file. This means that we can run more than one process at once, or delete our file without screwing things up for another process.

    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
    public static System.Drawing.Image LoadImageFromFile(string fileName)
    {
        System.Drawing.Image theImage = null;
        using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
        FileAccess.Read))
        {
            byte[] img;
            img = new byte[fileStream.Length];
            fileStream.Read(img, 0, img.Length);
            fileStream.Close();
            theImage = System.Drawing.Image.FromStream(new MemoryStream(img));
            img = null;
        }
        GC.Collect();
        return theImage;
    }
     
    public static MemoryStream LoadMemoryStreamFromFile(string fileName)
    {
        MemoryStream ms = null;
        using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
        FileAccess.Read))
        {
            byte[] fil;
            fil = new byte[fileStream.Length];
            fileStream.Read(fil, 0, fil.Length);
            fileStream.Close();
            ms = new MemoryStream(fil);
        }
        GC.Collect();
        return ms;
    }

    Running the ffMpeg Process

    Now that we have setup our class and have some basic helper subs to get us going, we need to actually have a method that will run the ffMpeg process.

    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
    //Note the private call here and the argument for Parameters.  The private call is
    //being made here because, in this class, we don't really want to have this method
    //called from outside of the class -- this, however flies in the face of allowing the
    //parameters argument (why not just allow out the public call so that a developer can
    //put in the parameters from their own code?  I guess one could do it and it would probably
    //work fine but, for this implementation, I chose to leave it private.
    private string RunProcess(string Parameters)
    {
        //create a process info object so we can run our app
        ProcessStartInfo oInfo = new ProcessStartInfo(this._ffExe, Parameters);
        oInfo.UseShellExecute = false;
        oInfo.CreateNoWindow = true;
     
        //so we are going to redirect the output and error so that we can parse the return
        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;
    }

    Now let’s make some functional stuff

    Now that we have called the ffMpeg process, we need to get some video info, get a video file, and a preview image. So, with that being said, onto more source code.

    Getting the Details

    So, we need to now parse the details of our ffMpeg.exe output and read some details about the video file.

    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
    //We are going to take in memory stream for this file to allow for different input options.
    //Unfortunately, this means that we also need the file extension to pass it out to ffMpeg.
    public VideoFile GetVideoInfo(MemoryStream inputFile, string Filename)
    {
        //Create a temporary file for our use in ffMpeg
        string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
        FileStream fs = File.Create(tempfile);
     
        //write the memory stream to a file and close our the stream so it can be used again.
        inputFile.WriteTo(fs);
        fs.Flush();
        fs.Close();
        GC.Collect();
     
        //Video File is a class you will see further down this post.  It has some basic information about the video
        VideoFile vf = null;
        try
        {
            vf = new VideoFile(tempfile);
        }
        catch (Exception ex)
        {
            throw ex;
        }
     
        //And, without adieu, a call to our main method for this functionality.
        GetVideoInfo(vf);
     
        try
        {
            File.Delete(tempfile);
        }
        catch (Exception)
        {
     
        }
     
        return vf;
    }
     
    //This sub is just another overload to allow input of a direct path, we are just
    //using the videofile class to send in.  More on the video file class further down
    //the article.
    public VideoFile GetVideoInfo(string inputPath)
    {
        VideoFile vf = null;
        try
        {
            vf = new VideoFile(inputPath);
        }
        catch (Exception ex)
        {
            throw ex;
        }
        GetVideoInfo(vf);
        return vf;
    }
     
    //And now the important code for the GetVideoInfo
    public void GetVideoInfo(VideoFile input)
    {
        //set up the parameters for video info -- these will be passed into ffMpeg.exe
        string Params = string.Format("-i {0}", input.Path);
        string output = RunProcess(Params);
        input.RawInfo = output;
     
        //Use a regular expression to get the different properties from the video parsed out.
        Regex re = new Regex("[D|d]uration:.((\d|:|\.)*)");
        Match m = re.Match(input.RawInfo);
     
        if (m.Success)
        {
            string duration = m.Groups[1].Value;
            string[] timepieces = duration.Split(new char[] { ':', '.' });
            if (timepieces.Length == 4)
            {
                input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
            }
        }
     
        //get audio bit rate
        re = new Regex("[B|b]itrate:.((\d|:)*)");
        m = re.Match(input.RawInfo);
        double kb = 0.0;
        if (m.Success)
        {
            Double.TryParse(m.Groups[1].Value, out kb);
        }
        input.BitRate = kb;
     
        //get the audio format
        re = new Regex("[A|a]udio:.*");
        m = re.Match(input.RawInfo);
        if (m.Success)
        {
            input.AudioFormat = m.Value;
        }
     
        //get the video format
        re = new Regex("[V|v]ideo:.*");
        m = re.Match(input.RawInfo);
        if (m.Success)
        {
            input.VideoFormat = m.Value;
        }
     
        //get the video format
        re = new Regex("(\d{2,3})x(\d{2,3})");
        m = re.Match(input.RawInfo);
        if (m.Success)
        {
            int width = 0; int height = 0;
            int.TryParse(m.Groups[1].Value, out width);
            int.TryParse(m.Groups[2].Value, out height);
            input.Width = width;
            input.Height = height;
        }
        input.infoGathered = true;
    }

    Finally, do the conversion

    So, here is the conversion meat and preview imaging.

    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
    //Note the ouputpackage object output.  The output package class is detailed below.
    //this overload does much the same as the one above does, in that, it offers the ability
    //to input a memory stream vs. a filename or our videofile input class.
    public OutputPackage ConvertToFLV(MemoryStream inputFile, string Filename)
    {
        string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
        FileStream fs = File.Create(tempfile);
        inputFile.WriteTo(fs);
        fs.Flush();
        fs.Close();
        GC.Collect();
     
        VideoFile vf = null;
        try
        {
            vf = new VideoFile(tempfile);
        }
        catch (Exception ex)
        {
            throw ex;
        }
     
        OutputPackage oo = ConvertToFLV(vf);
     
        try{
            File.Delete(tempfile);
        } catch(Exception) {
     
        }
     
        return oo;
    }
    public OutputPackage ConvertToFLV(string inputPath)
    {
        VideoFile vf = null;
        try
        {
            vf = new VideoFile(inputPath);
        }
        catch (Exception ex)
        {
            throw ex;
        }
     
        OutputPackage oo = ConvertToFLV(vf);
        return oo;
    }
     
    //The actually important code, rather than an overload.
    public OutputPackage ConvertToFLV(VideoFile input)
    {
        //check to see if we have already gathered our info so we know
        //where to get our preview image from.
        if (!input.infoGathered)
        {
            GetVideoInfo(input);
        }
     
        //Create our output object
        OutputPackage ou = new OutputPackage();
     
        //set up the parameters for getting a previewimage
        string filename = System.Guid.NewGuid().ToString() + ".jpg";
        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 finalpath = Path.Combine(this.WorkingPath, filename);
     
        //These are the parameters for setting up a preview image that must be passed to ffmpeg.
        //Note that we are asking for a jpeg image at our specified seconds.
        string Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, secs);
        string output = RunProcess(Params);
     
        ou.RawOutput = output;
     
        //Ok, so hopefully we now have a preview file.  If the file
        //did not get created properly, try again at the first frame.
        if (File.Exists(finalpath))
        {
            //load that file into our output package and attempt to delete the file
            //since we no longer need it.
            ou.PreviewImage = LoadImageFromFile(finalpath);
            try
            {
                File.Delete(finalpath);
            }
            catch (Exception) { }
        } 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, finalpath, 1);
            output = RunProcess(Params);
     
            ou.RawOutput = output;
     
            if (File.Exists(finalpath)) {
                ou.PreviewImage = LoadImageFromFile(finalpath);
                try
                {
                    File.Delete(finalpath);
                }
                catch (Exception) { }
            }
        }
     
        finalpath = Path.Combine(this.WorkingPath, filename);
        filename = System.Guid.NewGuid().ToString() + ".flv";
     
        //Now we are going to actually create the converted file.  Note that we are asking for
        //a video at 22khz 64bit.  This can be changed by a couple quick alterations to this line,
        //or by extending out this class to offer multiple different conversions.
        Params = string.Format("-i {0} -y -ar 22050 -ab 64 -f flv {1}", input.Path, finalpath);
        output = RunProcess(Params);
     
        //Check to see if our conversion file exists and then load the converted
        //file into our output package.  If the file does exist and we are able to
        //load it into our output package, we can delete the work file.
        if (File.Exists(finalpath))
        {
            ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
            try
            {
                File.Delete(finalpath);
            }
            catch (Exception) { }
        }
        return ou;
    }

    Supplementary Classes

    Throughout this article, you will have noticed the use of “VideoFile” and “OutputPackage”. These classes are just informational classes that provide simple ways of accessing everything.
    Here they are:

    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
    public class VideoFile
    {
        #region Properties
        private string _Path;
        public string Path
        {
            get
            {
                return _Path;
            }
            set
            {
                _Path = value;
            }
        }
     
        public TimeSpan Duration { get; set; }
        public double BitRate { get; set; }
        public string AudioFormat { 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;}
        #endregion
     
        #region Constructors
        public VideoFile(string path)
        {
            _Path = path;
            Initialize();
        }
        #endregion
     
        #region Initialization
        private void Initialize()
        {
            this.infoGathered = false;
            //first make sure we have a value for the video file setting
            if (string.IsNullOrEmpty(_Path))
            {
                throw new Exception("Could not find the location of the video file");
            }
     
            //Now see if the video file exists
            if (!File.Exists(_Path))
            {
                throw new Exception("The video file " + _Path + " does not exist.");
            }
        }
        #endregion
    }
     
    public class OutputPackage
    {
        public MemoryStream VideoStream { get; set; }
        public System.Drawing.Image PreviewImage { get; set; }
        public string RawOutput { get; set; }
        public bool Success { get; set; }
    }

    Full Code for the class:

    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
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.IO;
    using System.Diagnostics;
    using System.Configuration;
    using System.Text.RegularExpressions;
     
    namespace ffMpeg
    {
        public class Converter
        {
            #region Properties
            private string _ffExe;
            public string ffExe
            {
                get
                {
                    return _ffExe;
                }
                set
                {
                    _ffExe = value;
                }
            }
     
            private string _WorkingPath;
            public string WorkingPath
            {
                get
                {
                    return _WorkingPath;
                }
                set
                {
                    _WorkingPath = value;
                }
            }
     
            #endregion
     
            #region Constructors
            public Converter()
            {
                Initialize();
            }
            public Converter(string ffmpegExePath)
            {
                _ffExe = ffmpegExePath;
                Initialize();
            }
            #endregion
     
            #region Initialization
            private void Initialize()
            {
                //first make sure we have a value for the ffexe file setting
                if (string.IsNullOrEmpty(_ffExe))
                {
                    object o = ConfigurationManager.AppSettings["ffmpeg:ExeLocation"];
                    if (o == null)
                    {
                        throw new Exception("Could not find the location of the ffmpeg exe file.  The path for ffmpeg.exe " +
                        "can be passed in via a constructor of the ffmpeg class (this class) or by setting in the app.config or web.config file.  " +
                        "in the appsettings section, the correct property name is: ffmpeg:ExeLocation");
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(o.ToString()))
                        {
                            throw new Exception("No value was found in the app setting for ffmpeg:ExeLocation");
                        }
                        _ffExe = o.ToString();
                    }
                }
     
                //Now see if ffmpeg.exe exists
                string workingpath = GetWorkingFile();
                if (string.IsNullOrEmpty(workingpath))
                {
                    //ffmpeg doesn't exist at the location stated.
                    throw new Exception("Could not find a copy of ffmpeg.exe");
                }
                _ffExe = workingpath;
     
                //now see if we have a temporary place to work
                if (string.IsNullOrEmpty(_WorkingPath))
                {
                    object o = ConfigurationManager.AppSettings["ffmpeg:WorkingPath"];
                    if (o != null)
                    {
                        _WorkingPath = o.ToString();
                    }
                    else
                    {
                        _WorkingPath = string.Empty;
                    }
                }
            }
     
            private string GetWorkingFile()
            {
                //try the stated directory
                if (File.Exists(_ffExe))
                {
                    return _ffExe;
                }
     
                //oops, that didn't work, try the base directory
                if (File.Exists(Path.GetFileName(_ffExe)))
                {
                    return Path.GetFileName(_ffExe);
                }
     
                //well, now we are really unlucky, let's just return null
                return null;
            }
            #endregion
     
            #region Get the File without creating a file lock
            public static System.Drawing.Image LoadImageFromFile(string fileName)
            {
                System.Drawing.Image theImage = null;
                using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
                FileAccess.Read))
                {
                    byte[] img;
                    img = new byte[fileStream.Length];
                    fileStream.Read(img, 0, img.Length);
                    fileStream.Close();
                    theImage = System.Drawing.Image.FromStream(new MemoryStream(img));
                    img = null;
                }
                GC.Collect();
                return theImage;
            }
     
            public static MemoryStream LoadMemoryStreamFromFile(string fileName)
            {
                MemoryStream ms = null;
                using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
                FileAccess.Read))
                {
                    byte[] fil;
                    fil = new byte[fileStream.Length];
                    fileStream.Read(fil, 0, fil.Length);
                    fileStream.Close();
                    ms = new MemoryStream(fil);
                }
                GC.Collect();
                return ms;
            }
            #endregion
     
            #region Run the process
            private string RunProcess(string Parameters)
            {
                //create a process info
                ProcessStartInfo oInfo = new ProcessStartInfo(this._ffExe, 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;
            }
            #endregion
     
            #region GetVideoInfo
            public VideoFile GetVideoInfo(MemoryStream inputFile, string Filename)
            {
                string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
                FileStream fs = File.Create(tempfile);
                inputFile.WriteTo(fs);
                fs.Flush();
                fs.Close();
                GC.Collect();
     
                VideoFile vf = null;
                try
                {
                    vf = new VideoFile(tempfile);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
     
                GetVideoInfo(vf);
     
                try
                {
                    File.Delete(tempfile);
                }
                catch (Exception)
                {
     
                }
     
                return vf;
            }
            public VideoFile GetVideoInfo(string inputPath)
            {
                VideoFile vf = null;
                try
                {
                    vf = new VideoFile(inputPath);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                GetVideoInfo(vf);
                return vf;
            }
            public void GetVideoInfo(VideoFile input)
            {
                //set up the parameters for video info
                string Params = string.Format("-i {0}", input.Path);
                string output = RunProcess(Params);
                input.RawInfo = output;
     
                //get duration
                Regex re = new Regex("[D|d]uration:.((\d|:|\.)*)");
                Match m = re.Match(input.RawInfo);
     
                if (m.Success)
                {
                    string duration = m.Groups[1].Value;
                    string[] timepieces = duration.Split(new char[] { ':', '.' });
                    if (timepieces.Length == 4)
                    {
                        input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
                    }
                }
     
                //get audio bit rate
                re = new Regex("[B|b]itrate:.((\d|:)*)");
                m = re.Match(input.RawInfo);
                double kb = 0.0;
                if (m.Success)
                {
                    Double.TryParse(m.Groups[1].Value, out kb);
                }
                input.BitRate = kb;
     
                //get the audio format
                re = new Regex("[A|a]udio:.*");
                m = re.Match(input.RawInfo);
                if (m.Success)
                {
                    input.AudioFormat = m.Value;
                }
     
                //get the video format
                re = new Regex("[V|v]ideo:.*");
                m = re.Match(input.RawInfo);
                if (m.Success)
                {
                    input.VideoFormat = m.Value;
                }
     
                //get the video format
                re = new Regex("(\d{2,3})x(\d{2,3})");
                m = re.Match(input.RawInfo);
                if (m.Success)
                {
                    int width = 0; int height = 0;
                    int.TryParse(m.Groups[1].Value, out width);
                    int.TryParse(m.Groups[2].Value, out height);
                    input.Width = width;
                    input.Height = height;
                }
                input.infoGathered = true;
            }
            #endregion
     
            #region Convert to FLV
            public OutputPackage ConvertToFLV(MemoryStream inputFile, string Filename)
            {
                string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
                FileStream fs = File.Create(tempfile);
                inputFile.WriteTo(fs);
                fs.Flush();
                fs.Close();
                GC.Collect();
     
                VideoFile vf = null;
                try
                {
                    vf = new VideoFile(tempfile);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
     
                OutputPackage oo = ConvertToFLV(vf);
     
                try{
                    File.Delete(tempfile);
                } catch(Exception) {
     
                }
     
                return oo;
            }
            public OutputPackage ConvertToFLV(string inputPath)
            {
                VideoFile vf = null;
                try
                {
                    vf = new VideoFile(inputPath);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
     
                OutputPackage oo = ConvertToFLV(vf);
                return oo;
            }
            public OutputPackage ConvertToFLV(VideoFile input)
            {
                if (!input.infoGathered)
                {
                    GetVideoInfo(input);
                }
                OutputPackage ou = new OutputPackage();
     
                //set up the parameters for getting a previewimage
                string filename = System.Guid.NewGuid().ToString() + ".jpg";
                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 finalpath = Path.Combine(this.WorkingPath, filename);
                string Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, secs);
                string output = RunProcess(Params);
     
                ou.RawOutput = output;
     
                if (File.Exists(finalpath))
                {
                    ou.PreviewImage = LoadImageFromFile(finalpath);
                    try
                    {
                        File.Delete(finalpath);
                    }
                    catch (Exception) { }
                } 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, finalpath, 1);
                    output = RunProcess(Params);
     
                    ou.RawOutput = output;
     
                    if (File.Exists(finalpath)) {
                        ou.PreviewImage = LoadImageFromFile(finalpath);
                        try
                        {
                            File.Delete(finalpath);
                        }
                        catch (Exception) { }
                    }
                }
     
                finalpath = Path.Combine(this.WorkingPath, filename);
                filename = System.Guid.NewGuid().ToString() + ".flv";
                Params = string.Format("-i {0} -y -ar 22050 -ab 64 -f flv {1}", input.Path, finalpath);
                output = RunProcess(Params);
     
                if (File.Exists(finalpath))
                {
                    ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
                    try
                    {
                        File.Delete(finalpath);
                    }
                    catch (Exception) { }
                }
                return ou;
            }
            #endregion
        }
     
        public class VideoFile
        {
            #region Properties
            private string _Path;
            public string Path
            {
                get
                {
                    return _Path;
                }
                set
                {
                    _Path = value;
                }
            }
     
            public TimeSpan Duration { get; set; }
            public double BitRate { get; set; }
            public string AudioFormat { 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;}
            #endregion
     
            #region Constructors
            public VideoFile(string path)
            {
                _Path = path;
                Initialize();
            }
            #endregion
     
            #region Initialization
            private void Initialize()
            {
                this.infoGathered = false;
                //first make sure we have a value for the video file setting
                if (string.IsNullOrEmpty(_Path))
                {
                    throw new Exception("Could not find the location of the video file");
                }
     
                //Now see if the video file exists
                if (!File.Exists(_Path))
                {
                    throw new Exception("The video file " + _Path + " does not exist.");
                }
            }
            #endregion
        }
     
        public class OutputPackage
        {
            public MemoryStream VideoStream { get; set; }
            public System.Drawing.Image PreviewImage { get; set; }
            public string RawOutput { get; set; }
            public bool Success { get; set; }
        }
    }
  • 相关阅读:
    第十二讲 Web 服务的创建和使用
    第十七讲 ASP.NET安全性
    第九讲 水晶报表的使用
    第十五讲 数据集的使用方法和技巧
    第十六讲 调试和跟踪ASP.NET应用程序
    第十讲 ASP.NET程序的部署
    第十四讲 ADO.NET数据操作
    第十八讲 Web服务器控件使用
    【笔记】java多线程 2 五种状态
    【笔记】数据库模式
  • 原文地址:https://www.cnblogs.com/findcaiyzh/p/3513114.html
Copyright © 2011-2022 走看看