转贴: 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
Posted February 9, 2010 by jasonjano in Asset Management, cSharp, ffMpeg. Tagged: cSharp, ffMpeg.77 Comments
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 ; } } } |
转贴: A Simple c# Wrapper for ffMpeg的更多相关文章
- .NET读取视频信息、视频截图
在.NET中处理视频是一件痛苦的事情,.NET并没有提供视频处理的类.于是咱们只能找一些第三方的类库或者自己实现,在项目时间比较赶的情况下,自己实现是不可能的了,而且说不定会留下很多坑.所以一般情况下 ...
- .NET 读取视频文件
该篇文章 复制别人的文章 在.NET中处理视频是一件痛苦的事情,.NET并没有提供视频处理的类.于是咱们只能找一些第三方的类库或者自己实现,在项目时间比较赶的情况下,自己实现是不可能的了,而且说不定会 ...
- Java Service Wrapper配置详解
#encoding=UTF-8 # Configuration files must begin with a line specifying the encoding # of the the fi ...
- 基于最简单的FFmpeg包封过程:视频和音频分配器启动(demuxer-simple)
===================================================== 基于最简单的FFmpeg封装工艺的系列文章上市: 最简单的基于FFmpeg的封装格式处理:视 ...
- wrapper x64 版本发布到centos
背景: 项目需要在spark任务提交服务器节点上自动提交任务到spark集群上.因此创建了一个固定时间监控任务项目,使用timer定时监控oracle数据库中是否有spark提交任务,如果有spark ...
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- 试写foxit reader的ConvertToPDF功能的wrapper
相比于直接fuzzing大型程序本身,针对程序的某一特定功能写wrapper后再fuzzing则要高效的多.网上搜了下,仅有两篇关于foxit reader的wrapper文章,一个用python,另 ...
- Java Service Wrapper将java程序设置为服务
有时候我们希望我们java写的程序作为服务注册到系统中,Java Service Wrapper(下面简称wrapper)是目前较为流行的将Java程序部署成Windows服务的解决方案, 本文将讨论 ...
- Java Service Wrapper 发布Java程序为Windows服务
下载Windows版本:https://www.krenger.ch/blog/java-service-wrapper-3-5-37-for-windows-x64/ 转自:F:\java\bhGe ...
随机推荐
- php生成圆形图片
http://files.cnblogs.com/files/adtuu/circle_image.zip
- Mysql 正则获取字段的交集【转】
问题描述 比如table1中有两条记录 name no a 2,9 b 8,10 然后有一串字符串,是0,1,2,3,4 然后通过一条sql,找出no为2,9的记录来``` 因为字符串中有 ...
- Java方法重载
Java允许一个类中定义多个方法,只要参数列表不同就行了.如果同一个类中包含了两个或者两个以上的方法的方法名相同,但形参列表不同,则被称为方法重载. /* 参数类型不同的重载 */ public cl ...
- return *this和return this的区别
别跟我说, return *this返回当前对象, return this返回当前对象的地址(指向当前对象的指针). 正确答案为:return *this返回的是当前对象的克隆(当然, 这里仅考虑返回 ...
- 【python】 web开发入门
进入Web开发 现在你完成了Python忍者训练,准备深入Ptyhon的Web开发,但现在的问题是有很多的框架,从中选择最好的框架非常困难,但从初学者的角度出发,Flask基本Web框架将非常适合We ...
- iOS 进阶 第十天(0410)
0410 在tableViewCell之间添加一根线,通栏 iOS应用数据存储的常用方式 plist存储文件 plist读取文件 下面是plist存储读取的图解: 注意:plist只能存储常见的属性. ...
- 把NodeJS注册成Windows服务
为了让NodeJS开发的网站能在服务器端正常运行,最好把NodeJS需要运行的代码注册成Windows服务,服务器如果重启也不需要重新去启动NodeJS. 1.编写一个执行NodeJS脚本的bat文件 ...
- Linux课本第一二章
一.第一章:Linux内核简介 1.操作系统和内核:操作系统是指在整个系统中负责完成最基本功能和系统管理的那些部分,包括内核.设备驱动程序.启动引导程序.命令行shall等. 内核就是操作系统的核心, ...
- Android SDK Android NDK 官方下载地址
Android NDK r6b Windows http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip Mac OS X(intel) ...
- 不同的source control下配置DiffMerge
TFS: 1. 打开Option -> Source Control -> Visual Studio TFS -> Configure User Tools; 2. 添加 .*, ...