|
@@ -1,6 +1,7 @@
|
1
|
1
|
using System;
|
2
|
2
|
using System.Collections.Generic;
|
3
|
3
|
using System.Diagnostics;
|
|
4
|
+using System.IO;
|
4
|
5
|
using System.Linq;
|
5
|
6
|
using System.Text;
|
6
|
7
|
using VisioForge.Shared.NAudio.CoreAudioApi;
|
|
@@ -16,12 +17,16 @@ namespace Common.system
|
16
|
17
|
public class FFMpeg
|
17
|
18
|
{
|
18
|
19
|
Process myProcess = null;
|
19
|
|
-
|
20
|
20
|
/// <summary>
|
21
|
|
- /// 录屏
|
|
21
|
+ /// ffmpeg输出日志文件地址 每个文件2MB左右
|
|
22
|
+ /// </summary>
|
|
23
|
+ string LogPath = "";
|
|
24
|
+ /// <summary>
|
|
25
|
+ /// 录制屏幕
|
22
|
26
|
/// </summary>
|
23
|
27
|
/// <param name="PathName">文件存储路径</param>
|
24
|
|
- public void RunFFmpeg(string PathName)
|
|
28
|
+ /// <param name="VideoType">视频类型</param>
|
|
29
|
+ public void StartRecordingVideo(string PathName, string VideoType)
|
25
|
30
|
{
|
26
|
31
|
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
|
27
|
32
|
Debug.WriteLine(KillProcessArray.Length.ToString());
|
|
@@ -30,25 +35,90 @@ namespace Common.system
|
30
|
35
|
KillProcess.Kill();
|
31
|
36
|
}
|
32
|
37
|
myProcess = new Process();
|
|
38
|
+ LogPath = CreateffmpegLog();
|
33
|
39
|
string MicrophoneName = GetMicrophone();
|
34
|
40
|
myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
|
35
|
|
- if(string.IsNullOrWhiteSpace(MicrophoneName))
|
|
41
|
+ switch (VideoType.ToUpper())
|
36
|
42
|
{
|
37
|
|
- myProcess.StartInfo.Arguments = "-f dshow -i video=\"screen-capture-recorder\" -f dshow -i audio=\"virtual-audio-capturer\" -vcodec libx264 -acodec libmp3lame -r 15 -crf 22 -f avi " + PathName; //ffmpeg的参数
|
|
43
|
+ case "MP4":
|
|
44
|
+ if (string.IsNullOrWhiteSpace(MicrophoneName))
|
|
45
|
+ {
|
|
46
|
+ myProcess.StartInfo.Arguments = "-f dshow -i video=\"screen-capture-recorder\" -f dshow -i audio=\"virtual-audio-capturer\" -vcodec libx264 -acodec libmp3lame -r 15 -crf 22 -f avi " + PathName; //ffmpeg的参数
|
|
47
|
+ }
|
|
48
|
+ else
|
|
49
|
+ {
|
|
50
|
+ myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
|
|
51
|
+ MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -f dshow -i video=\"screen-capture-recorder\" -pix_fmt yuv420p -vcodec h264 -preset:v ultrafast -tune:v zerolatency -acodec aac -ar 44100 -ac 2 " + PathName; //ffmpeg的参数
|
|
52
|
+ }
|
|
53
|
+ break;
|
|
54
|
+ case "AVI":
|
|
55
|
+ case "FLV":
|
|
56
|
+ if (string.IsNullOrWhiteSpace(MicrophoneName))
|
|
57
|
+ {
|
|
58
|
+ myProcess.StartInfo.Arguments = "-f dshow -i video=\"screen-capture-recorder\" -f dshow -i audio=\"virtual-audio-capturer\" -vcodec libx264 -acodec libmp3lame -r 15 -crf 22 -f "+ VideoType.ToLower() + " " + PathName; //ffmpeg的参数
|
|
59
|
+ }
|
|
60
|
+ else
|
|
61
|
+ {
|
|
62
|
+ myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
|
|
63
|
+ MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -f dshow -i video=\"screen-capture-recorder\" -pix_fmt yuv420p -vcodec h264 -preset:v ultrafast -tune:v zerolatency -acodec aac -ar 44100 -ac 2 -f " + VideoType.ToLower() + " " + PathName; //ffmpeg的参数
|
|
64
|
+ }
|
|
65
|
+ break;
|
|
66
|
+ default:
|
|
67
|
+ if (string.IsNullOrWhiteSpace(MicrophoneName))
|
|
68
|
+ {
|
|
69
|
+ myProcess.StartInfo.Arguments = "-f dshow -i video=\"screen-capture-recorder\" -f dshow -i audio=\"virtual-audio-capturer\" -vcodec libx264 -acodec libmp3lame -r 15 -crf 22 -f avi " + PathName; //ffmpeg的参数
|
|
70
|
+ }
|
|
71
|
+ else
|
|
72
|
+ {
|
|
73
|
+ myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
|
|
74
|
+ MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -f dshow -i video=\"screen-capture-recorder\" -pix_fmt yuv420p -vcodec h264 -preset:v ultrafast -tune:v zerolatency -acodec aac -ar 44100 -ac 2 " + PathName; //ffmpeg的参数
|
|
75
|
+ }
|
|
76
|
+ break;
|
|
77
|
+ }
|
|
78
|
+ myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
|
|
79
|
+ myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
|
|
80
|
+ myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
|
|
81
|
+ myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
|
|
82
|
+ myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
|
|
83
|
+ myProcess.Start();
|
|
84
|
+ myProcess.BeginErrorReadLine();
|
|
85
|
+ }
|
|
86
|
+
|
|
87
|
+ /// <summary>
|
|
88
|
+ /// 录制音频
|
|
89
|
+ /// </summary>
|
|
90
|
+ /// <param name="Mp3Path">MP3音频位置</param>
|
|
91
|
+ private void StartRecordingAudio(string Mp3Path)
|
|
92
|
+ {
|
|
93
|
+ Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
|
|
94
|
+ Debug.WriteLine(KillProcessArray.Length.ToString());
|
|
95
|
+ foreach (var KillProcess in KillProcessArray)
|
|
96
|
+ {
|
|
97
|
+ KillProcess.Kill();
|
|
98
|
+ }
|
|
99
|
+ myProcess = new Process();
|
|
100
|
+ LogPath = CreateffmpegLog();
|
|
101
|
+ this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
|
|
102
|
+ string MicrophoneName = GetMicrophone();
|
|
103
|
+ if (string.IsNullOrWhiteSpace(MicrophoneName))
|
|
104
|
+ {
|
|
105
|
+ myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" " + Mp3Path;
|
38
|
106
|
}
|
39
|
107
|
else
|
40
|
108
|
{
|
41
|
|
- myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" + MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -f dshow -i video=\"screen-capture-recorder\" -pix_fmt yuv420p -vcodec h264 -preset:v ultrafast -tune:v zerolatency -acodec aac -ar 44100 -ac 2 -f avi " + PathName; //ffmpeg的参数
|
42
|
|
-
|
|
109
|
+ myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
|
|
110
|
+ MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + Mp3Path;
|
43
|
111
|
}
|
44
|
112
|
myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
|
45
|
113
|
myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
|
46
|
114
|
myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
|
47
|
115
|
myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
|
|
116
|
+ //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
|
48
|
117
|
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
|
49
|
|
- myProcess.Start();
|
50
|
|
- myProcess.BeginErrorReadLine();
|
|
118
|
+ myProcess.Start(); //启动线程
|
|
119
|
+ myProcess.BeginErrorReadLine(); //开始异步读取
|
51
|
120
|
}
|
|
121
|
+
|
52
|
122
|
/// <summary>
|
53
|
123
|
/// 停止录制
|
54
|
124
|
/// </summary>
|
|
@@ -58,30 +128,23 @@ namespace Common.system
|
58
|
128
|
if (myProcess == null)
|
59
|
129
|
return;
|
60
|
130
|
myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
|
61
|
|
- myProcess.Close();
|
62
|
|
- myProcess.Dispose();
|
|
131
|
+ myProcess.Close();//关闭进程
|
|
132
|
+ myProcess.Dispose();//释放资源
|
63
|
133
|
myProcess = null;
|
64
|
134
|
//myProcess.Kill();
|
65
|
135
|
}
|
66
|
|
- /// <summary>
|
67
|
|
- /// 输出结果
|
68
|
|
- /// </summary>
|
69
|
|
- /// <param name="sendProcess"></param>
|
70
|
|
- /// <param name="output"></param>
|
71
|
|
- private void Output(object sendProcess, DataReceivedEventArgs output)
|
72
|
|
- {
|
73
|
|
- if (!String.IsNullOrEmpty(output.Data))
|
74
|
|
- Debug.WriteLine(output.Data.ToString());
|
75
|
|
- }
|
76
|
136
|
|
77
|
137
|
/// <summary>
|
78
|
138
|
/// 合成视频
|
79
|
139
|
/// </summary>
|
80
|
|
- /// <param name="ImageListPath">图片列表位置 命名为1.png</param>
|
|
140
|
+ /// <param name="ImageListPath">图片列表位置 命名为1.png 2.png</param>
|
81
|
141
|
/// <param name="Mp3Path">MP3音频位置</param>
|
82
|
142
|
/// <param name="VideoSavePath">视频保存位置</param>
|
83
|
|
- /// <param name="frequency">每秒帧率</param>
|
84
|
|
- private void SynthesisVideo(string ImageListPath,string Mp3Path,string VideoSavePath,int frequency)
|
|
143
|
+ /// <param name="Frequency">每秒帧率</param>
|
|
144
|
+ /// <param name="VideoWidth">视频宽度</param>
|
|
145
|
+ /// <param name="VideoHeight">视频高度</param>
|
|
146
|
+ /// <param name="VideoType">视频类型 MP4 FLV AVI</param>
|
|
147
|
+ private void SynthesisVideo(string ImageListPath, string Mp3Path, string VideoSavePath, int Frequency, int VideoWidth, int VideoHeight, string VideoType)
|
85
|
148
|
{
|
86
|
149
|
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
|
87
|
150
|
Debug.WriteLine(KillProcessArray.Length.ToString());
|
|
@@ -89,23 +152,133 @@ namespace Common.system
|
89
|
152
|
{
|
90
|
153
|
KillProcess.Kill();
|
91
|
154
|
}
|
92
|
|
- Process myProcess = new Process();
|
|
155
|
+ myProcess = new Process();
|
|
156
|
+ LogPath=CreateffmpegLog();
|
93
|
157
|
this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
|
94
|
|
- myProcess.StartInfo.Arguments = @"-y -r "+ frequency + " -i " +
|
95
|
|
- ImageListPath + @"%d.png -i " +
|
96
|
|
- Mp3Path + @" -s 800x800 -vcodec mpeg4 " +
|
97
|
|
- VideoSavePath;
|
98
|
|
- myProcess.StartInfo.UseShellExecute = false;
|
99
|
|
- myProcess.StartInfo.RedirectStandardError = true;
|
100
|
|
- myProcess.StartInfo.CreateNoWindow = true;
|
|
158
|
+ switch (VideoType.ToUpper())
|
|
159
|
+ {
|
|
160
|
+ case "MP4":
|
|
161
|
+ myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
|
|
162
|
+ ImageListPath + @"%d.png -i " +
|
|
163
|
+ Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
|
|
164
|
+ VideoSavePath;
|
|
165
|
+ break;
|
|
166
|
+ case "AVI":
|
|
167
|
+ myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
|
|
168
|
+ ImageListPath + @"%d.png -i " +
|
|
169
|
+ Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -f AVI " +
|
|
170
|
+ VideoSavePath;
|
|
171
|
+ break;
|
|
172
|
+ case "FLV":
|
|
173
|
+ myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
|
|
174
|
+ ImageListPath + @"%d.png -i " +
|
|
175
|
+ Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -f FLV " +
|
|
176
|
+ VideoSavePath;
|
|
177
|
+ break;
|
|
178
|
+ default:
|
|
179
|
+ myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
|
|
180
|
+ ImageListPath + @"%d.png -i " +
|
|
181
|
+ Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
|
|
182
|
+ VideoSavePath;
|
|
183
|
+ break;
|
|
184
|
+ }
|
|
185
|
+ myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
|
|
186
|
+ myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
|
|
187
|
+ myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
|
|
188
|
+ myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
|
101
|
189
|
//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
|
102
|
190
|
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
|
103
|
|
- //p.ErrorDataReceived += new DataReceivedEventHandler((s, message) => { Console.WriteLine(message.Data); });
|
104
|
|
- myProcess.Start();//启动线程
|
105
|
|
- myProcess.BeginErrorReadLine();//开始异步读取
|
106
|
|
- myProcess.WaitForExit();//阻塞等待进程结束
|
107
|
|
- myProcess.Close();//关闭进程
|
108
|
|
- myProcess.Dispose();//释放资源
|
|
191
|
+ myProcess.Start(); //启动线程
|
|
192
|
+ myProcess.BeginErrorReadLine(); //开始异步读取
|
|
193
|
+ myProcess.WaitForExit(); //阻塞等待进程结束
|
|
194
|
+ myProcess.Close(); //关闭进程
|
|
195
|
+ myProcess.Dispose(); //释放资源
|
|
196
|
+ //生成视频后删除图片保存列表
|
|
197
|
+ FileToolsCommon.DeleteDirectory(ImageListPath);
|
|
198
|
+
|
|
199
|
+ }
|
|
200
|
+
|
|
201
|
+ /// <summary>
|
|
202
|
+ /// 生成缩略图
|
|
203
|
+ /// </summary>
|
|
204
|
+ /// <param name="VideoPath">视频地址</param>
|
|
205
|
+ /// <param name="ImagePath">图片地址</param>
|
|
206
|
+ void GenerateThumbnails(string VideoPath,string ImagePath)
|
|
207
|
+ {
|
|
208
|
+ Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
|
|
209
|
+ Debug.WriteLine(KillProcessArray.Length.ToString());
|
|
210
|
+ foreach (var KillProcess in KillProcessArray)
|
|
211
|
+ {
|
|
212
|
+ KillProcess.Kill();
|
|
213
|
+ }
|
|
214
|
+ myProcess = new Process();
|
|
215
|
+ LogPath = CreateffmpegLog();
|
|
216
|
+ this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
|
|
217
|
+ //myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -s " + thubWidth + "*" + thubHeight + " -f image2 \"" + ImagePath + "\"";
|
|
218
|
+ myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -f image2 \"" + ImagePath + "\"";
|
|
219
|
+ myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
|
|
220
|
+ myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
|
|
221
|
+ myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
|
|
222
|
+ myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
|
|
223
|
+ //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
|
|
224
|
+ myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
|
|
225
|
+ myProcess.Start(); //启动线程
|
|
226
|
+ myProcess.BeginErrorReadLine(); //开始异步读取
|
|
227
|
+ myProcess.WaitForExit(); //阻塞等待进程结束
|
|
228
|
+ myProcess.Close(); //关闭进程
|
|
229
|
+ myProcess.Dispose(); //释放资源
|
|
230
|
+ }
|
|
231
|
+
|
|
232
|
+ /// <summary>
|
|
233
|
+ /// 创建日志文件
|
|
234
|
+ /// </summary>
|
|
235
|
+ /// <returns></returns>
|
|
236
|
+ string CreateffmpegLog()
|
|
237
|
+ {
|
|
238
|
+ string LogFileName = DateTime.Now.ToString("yyyyMMdd");
|
|
239
|
+ string LogFilePath = FileToolsCommon.GetFileAbsolutePath("/Log/FFMpegLog/");
|
|
240
|
+ FileToolsCommon.CreateDirectory(LogFilePath);
|
|
241
|
+ string LogName = LogFilePath + LogFileName + ".log";
|
|
242
|
+ try
|
|
243
|
+ {
|
|
244
|
+ if (!FileToolsCommon.IsExistFile(LogName))
|
|
245
|
+ {
|
|
246
|
+ FileToolsCommon.CreateFile(LogName);
|
|
247
|
+ FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
|
|
248
|
+ "****************************************************************************************************\r\n");
|
|
249
|
+ return LogName;
|
|
250
|
+ }
|
|
251
|
+ else
|
|
252
|
+ {
|
|
253
|
+ int num = 0;
|
|
254
|
+ while (FileToolsCommon.GetFileSizeByMB(LogName) > 2)
|
|
255
|
+ {
|
|
256
|
+ num++;
|
|
257
|
+ LogName = LogFilePath + LogFileName + "_" + num + ".log";
|
|
258
|
+ FileToolsCommon.CreateFile(LogName);
|
|
259
|
+ }
|
|
260
|
+ FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
|
|
261
|
+ "****************************************************************************************************\r\n");
|
|
262
|
+ return LogName;
|
|
263
|
+ }
|
|
264
|
+ }
|
|
265
|
+ catch (Exception)
|
|
266
|
+ {
|
|
267
|
+ return LogName;
|
|
268
|
+ }
|
|
269
|
+ }
|
|
270
|
+
|
|
271
|
+ /// <summary>
|
|
272
|
+ /// 输出结果
|
|
273
|
+ /// </summary>
|
|
274
|
+ /// <param name="sendProcess"></param>
|
|
275
|
+ /// <param name="output"></param>
|
|
276
|
+ private void Output(object sendProcess, DataReceivedEventArgs output)
|
|
277
|
+ {
|
|
278
|
+ if (!String.IsNullOrEmpty(output.Data))
|
|
279
|
+ {
|
|
280
|
+ FileToolsCommon.AppendText(LogPath, output.Data);
|
|
281
|
+ }
|
109
|
282
|
}
|
110
|
283
|
|
111
|
284
|
//private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
|
@@ -114,6 +287,7 @@ namespace Common.system
|
114
|
287
|
// using (StreamWriter fs = new StreamWriter("E:\\项目\\测试\\Wpf测试\\bin\\Debug\\ffmpeg\\log.txt", true))
|
115
|
288
|
// {
|
116
|
289
|
// fs.WriteLine(e.Data);
|
|
290
|
+ // Debug.WriteLine(output.Data.ToString());
|
117
|
291
|
// }
|
118
|
292
|
//}
|
119
|
293
|
|