星火微课系统客户端
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

FFMpeg.cs 42KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using System.Threading;
  6. using VisioForge.Shared.NAudio.CoreAudioApi;
  7. using VisioForge.Shared.NAudio.Wave;
  8. namespace Common.system
  9. {
  10. /// <summary>
  11. /// ffmpeg帮助类
  12. /// 创建人:赵耀
  13. /// 创建时间::2020年8月22日
  14. /// 需要安装\ffmpeg\bin\Setup Screen Capturer Recorder v0.12.10.exe
  15. /// 本地调试需要配置环境变量 将ffmpeg.exe位置配置到环境变量的path中
  16. /// </summary>
  17. public class FFMpeg
  18. {
  19. public Process myProcess = null;
  20. /// <summary>
  21. /// 是否输出录课录屏日志
  22. /// </summary>
  23. public bool OutputVideoLog = FileToolsCommon.GetConfigValue("OutputVideoLog") != "0";
  24. /// <summary>
  25. /// ffmpeg输出日志文件地址 每个文件2MB左右
  26. /// </summary>
  27. private string LogPath = "";
  28. /// <summary>
  29. /// 是否可以录制扬声器
  30. /// </summary>
  31. private bool IsRecordSpeaker = true;
  32. /// <summary>
  33. /// 是否可以录制麦克风
  34. /// </summary>
  35. private bool IsRecordMicrophone = true;
  36. /// <summary>
  37. /// 录制屏幕
  38. /// </summary>
  39. /// <param name="FilePath">文件存储路径</param>
  40. public void StartRecordingVideo(string FilePath)
  41. {
  42. while (myProcess != null)
  43. {
  44. Thread.Sleep(100);
  45. }
  46. //路径
  47. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  48. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  49. //文件保存路径
  50. string PathName = GetRSFilePathName(FilePath);
  51. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  52. foreach (Process KillProcess in KillProcessArray)
  53. {
  54. KillProcess.Kill();
  55. }
  56. myProcess = new Process();
  57. LogPath = CreateffmpegLog();
  58. string MicrophoneName = null;
  59. #region 检测麦克风扬声器
  60. string audioSpeakerPath = FileToolsCommon.GetFileAbsolutePath("adoS.m");
  61. string audioMicrophonePath = FileToolsCommon.GetFileAbsolutePath("adoM.m");
  62. try
  63. {
  64. FileToolsCommon.DeleteFile(audioSpeakerPath);
  65. FileToolsCommon.DeleteFile(audioMicrophonePath);
  66. }
  67. catch (Exception)
  68. {
  69. }
  70. if (StartRecordSpeakerAudio(audioSpeakerPath))
  71. {
  72. IsRecordSpeaker = true;
  73. }
  74. else
  75. {
  76. //无法录制扬声器音频
  77. IsRecordSpeaker = false;
  78. }
  79. StopRecordAudio(2);
  80. Thread.Sleep(100);
  81. if (StartRecordAudio(audioMicrophonePath))
  82. {
  83. IsRecordMicrophone = true;
  84. }
  85. else
  86. {
  87. //无法录制麦克风
  88. IsRecordMicrophone = false;
  89. }
  90. StopRecordAudio(1);
  91. #endregion
  92. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  93. string SpeakerStr = "";
  94. string MicrophoneStr = "";
  95. if (IsRecordSpeaker)
  96. {
  97. SpeakerStr = "-f dshow -i audio=\"virtual-audio-capturer\" ";
  98. }
  99. if (IsRecordMicrophone)
  100. {
  101. MicrophoneName = GetInDeviceFull();
  102. if (!string.IsNullOrWhiteSpace(MicrophoneName))
  103. {
  104. MicrophoneStr = "-f dshow -i audio=\"" + MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ";
  105. }
  106. }
  107. switch (Extension.ToUpper())
  108. {
  109. case ".MP4":
  110. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac " + PathName;
  111. //myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f dshow -i video=\"screen-capture-recorder\" -pix_fmt yuv420p -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac " + PathName;
  112. //if (string.IsNullOrWhiteSpace(MicrophoneName))
  113. //{
  114. // 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 " + PathName; //ffmpeg的参数
  115. //}
  116. //else
  117. //{
  118. // myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
  119. // 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的参数
  120. //}
  121. break;
  122. case ".AVI":
  123. case ".FLV":
  124. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac -f " + Extension.ToLower().Replace(".", "") + " " + PathName;
  125. //if (string.IsNullOrWhiteSpace(MicrophoneName))
  126. //{
  127. // 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 " + Extension.ToLower() + " " + PathName; //ffmpeg的参数
  128. //}
  129. //else
  130. //{
  131. // myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
  132. // 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 " + Extension.ToLower() + " " + PathName; //ffmpeg的参数
  133. //}
  134. break;
  135. default:
  136. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac " + PathName;
  137. break;
  138. }
  139. if (OutputVideoLog)
  140. {
  141. LogHelper.WriteInfoLog("【录屏】:" + myProcess.StartInfo.Arguments);
  142. }
  143. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  144. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  145. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  146. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  147. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  148. myProcess.Start();
  149. myProcess.BeginErrorReadLine();
  150. }
  151. /// <summary>
  152. /// 录制音频
  153. /// </summary>
  154. /// <param name="Mp3Path">MP3音频位置</param>
  155. public bool StartRecordingAudio(string Mp3Path)
  156. {
  157. while (myProcess != null)
  158. {
  159. Thread.Sleep(100);
  160. }
  161. //路径
  162. string Path = FileToolsCommon.GetDirectoryName(Mp3Path);
  163. //文件保存路径
  164. string PathName = GetFilePathName(Mp3Path);
  165. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  166. foreach (Process KillProcess in KillProcessArray)
  167. {
  168. KillProcess.Kill();
  169. }
  170. string MicrophoneName = null;
  171. #region 检测麦克风扬声器
  172. string audioSpeakerPath = FileToolsCommon.GetFileAbsolutePath("adoS.m");
  173. string audioMicrophonePath = FileToolsCommon.GetFileAbsolutePath("adoM.m");
  174. try
  175. {
  176. FileToolsCommon.DeleteFile(audioSpeakerPath);
  177. FileToolsCommon.DeleteFile(audioMicrophonePath);
  178. }
  179. catch (Exception)
  180. {
  181. }
  182. if (StartRecordSpeakerAudio(audioSpeakerPath))
  183. {
  184. IsRecordSpeaker = true;
  185. }
  186. else
  187. {
  188. //无法录制扬声器音频
  189. IsRecordSpeaker = false;
  190. }
  191. StopRecordAudio(2);
  192. Thread.Sleep(100);
  193. if (StartRecordAudio(audioMicrophonePath))
  194. {
  195. IsRecordMicrophone = true;
  196. MicrophoneName = GetInDeviceFull();
  197. }
  198. else
  199. {
  200. //无法录制麦克风
  201. IsRecordMicrophone = false;
  202. }
  203. StopRecordAudio(1);
  204. if (!IsRecordSpeaker && !IsRecordMicrophone)
  205. {
  206. return false;
  207. }
  208. #endregion
  209. myProcess = new Process();
  210. LogPath = CreateffmpegLog();
  211. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  212. if (IsRecordSpeaker && IsRecordMicrophone)
  213. {
  214. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
  215. MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + PathName;
  216. }
  217. else if (IsRecordSpeaker)
  218. {
  219. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" " + PathName;
  220. }
  221. else if (IsRecordMicrophone)
  222. {
  223. //录制麦克风
  224. if (!string.IsNullOrWhiteSpace(MicrophoneName))
  225. {
  226. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"" +
  227. MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + PathName;
  228. }
  229. }
  230. if (OutputVideoLog)
  231. LogHelper.WriteInfoLog("【录音】:" + myProcess.StartInfo.Arguments);
  232. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  233. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  234. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  235. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  236. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  237. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  238. myProcess.Start(); //启动线程
  239. myProcess.BeginErrorReadLine(); //开始异步读取
  240. return true;
  241. }
  242. /// <summary>
  243. /// 暂停录制
  244. /// </summary>
  245. public bool SuspendFFmpeg()
  246. {
  247. if (myProcess != null)
  248. {
  249. myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
  250. myProcess.Close();//关闭进程
  251. myProcess.Dispose();//释放资源
  252. }
  253. #region 进程是否已经释放
  254. bool IsRunning = true;
  255. while (IsRunning)
  256. {
  257. IsRunning = false;
  258. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  259. foreach (Process KillProcess in ProcessArray)
  260. {
  261. IsRunning = true;
  262. Thread.Sleep(100);
  263. }
  264. }
  265. #endregion
  266. myProcess = null;
  267. return true;
  268. //myProcess.Kill();
  269. }
  270. /// <summary>
  271. /// 停止录制并合成文件
  272. /// </summary>
  273. /// <param name="FilePath">文件存储路径 必须与开始时的路径完全一致</param>
  274. public bool StopFFmpeg(string FilePath)
  275. {
  276. //文件完整路径
  277. if (myProcess != null)
  278. {
  279. myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
  280. myProcess.Close();//关闭进程
  281. myProcess.Dispose();//释放资源
  282. }
  283. #region 进程是否已经释放
  284. bool IsRunning = true;
  285. while (IsRunning)
  286. {
  287. IsRunning = false;
  288. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  289. foreach (Process KillProcess in ProcessArray)
  290. {
  291. IsRunning = true;
  292. Thread.Sleep(100);
  293. }
  294. }
  295. #endregion
  296. myProcess = null;
  297. Thread t1 = new Thread(MergeVideoOrAudio);
  298. t1.Start(FilePath);
  299. return true;
  300. //文件合成
  301. }
  302. /// <summary>
  303. /// 图片音频合成视频
  304. /// </summary>
  305. /// <param name="ImageListPath">图片列表位置 命名为1.png 2.png</param>
  306. /// <param name="Mp3Path">MP3音频位置</param>
  307. /// <param name="VideoSavePath">视频保存位置</param>
  308. /// <param name="Frequency">每秒帧率</param>
  309. /// <param name="VideoWidth">视频宽度</param>
  310. /// <param name="VideoHeight">视频高度</param>
  311. public bool SynthesisVideo(string ImageListPath, string Mp3Path, string VideoSavePath, int Frequency, int VideoWidth, int VideoHeight)
  312. {
  313. //new Thread(new ThreadStart(new Action(() =>
  314. //{
  315. //}))).Start();
  316. while (myProcess != null)
  317. {
  318. Thread.Sleep(100);
  319. }
  320. string Extension = FileToolsCommon.GetIOExtension(VideoSavePath);//扩展名
  321. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  322. //Debug.WriteLine(KillProcessArray.Length.ToString());
  323. foreach (Process KillProcess in KillProcessArray)
  324. {
  325. KillProcess.Kill();
  326. }
  327. myProcess = new Process();
  328. try
  329. {
  330. LogPath = CreateffmpegLog();
  331. string mp3Str = "";
  332. #region 判断音频是否存在
  333. if (!string.IsNullOrWhiteSpace(Mp3Path))
  334. {
  335. if (FileToolsCommon.IsExistFile(Mp3Path))
  336. {
  337. mp3Str = "-i " + Mp3Path;
  338. }
  339. }
  340. #endregion
  341. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  342. switch (Extension.ToUpper())
  343. {
  344. case ".MP4":
  345. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  346. ImageListPath + @"%d.png " +
  347. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
  348. VideoSavePath;
  349. break;
  350. case ".AVI":
  351. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  352. ImageListPath + @"%d.png " +
  353. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -f AVI " +
  354. VideoSavePath;
  355. break;
  356. case ".FLV":
  357. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  358. ImageListPath + @"%d.png " +
  359. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -f FLV " +
  360. VideoSavePath;
  361. break;
  362. default:
  363. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  364. ImageListPath + @"%d.png " +
  365. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
  366. VideoSavePath;
  367. break;
  368. }
  369. if (OutputVideoLog)
  370. LogHelper.WriteInfoLog("【图片音频合成视频】:" + myProcess.StartInfo.Arguments);
  371. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  372. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  373. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  374. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  375. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  376. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  377. myProcess.Start(); //启动线程
  378. myProcess.BeginErrorReadLine(); //开始异步读取
  379. myProcess.WaitForExit(); //阻塞等待进程结束
  380. myProcess.Close(); //关闭进程
  381. myProcess.Dispose(); //释放资源
  382. #region 进程是否已经释放
  383. bool IsRunning = true;
  384. while (IsRunning)
  385. {
  386. IsRunning = false;
  387. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  388. foreach (Process KillProcess in ProcessArray)
  389. {
  390. IsRunning = true;
  391. Thread.Sleep(100);
  392. }
  393. }
  394. #endregion
  395. myProcess = null;
  396. //生成视频后删除图片和音频保存列表
  397. //FileToolsCommon.DeleteDirectory(ImageListPath);
  398. //FileToolsCommon.DeleteDirectory(FileToolsCommon.GetDirectoryName(Mp3Path));
  399. Thread.Sleep(100);
  400. FileToolsCommon.DeleteDirectory(FileToolsCommon.GetDirectoryName(VideoSavePath) + "temp");
  401. return true;
  402. }
  403. catch (Exception ex)
  404. {
  405. LogHelper.WriteErrLog("【视频合成】(SynthesisVideo)视频生成失败," + ex.Message, ex);
  406. return false;
  407. }
  408. //Dispatcher.Invoke(() =>
  409. //{
  410. //});
  411. //// 允许不同线程间的调用
  412. //Control.CheckForIllegalCrossThreadCalls = false;
  413. }
  414. /// <summary>
  415. /// 视频音频合成
  416. /// </summary>
  417. /// <param name="FilePath">存储路径</param>
  418. public void MergeVideoOrAudio(object FilePathobj)
  419. {
  420. //new Thread(new ThreadStart(new Action(() =>
  421. //{
  422. //Dispatcher.Invoke(() =>
  423. //{
  424. //});
  425. //}))).Start();
  426. while (myProcess != null)
  427. {
  428. Thread.Sleep(100);
  429. }
  430. //路径
  431. string FilePath = (string)FilePathobj;
  432. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  433. //扩展名
  434. string Extension = FileToolsCommon.GetIOExtension(FilePath);
  435. //Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  436. //foreach (var KillProcess in KillProcessArray)
  437. //{
  438. // KillProcess.Kill();
  439. //}
  440. #region 判断文件是否存在
  441. if (Extension.ToUpper() == ".MP3")
  442. {
  443. if (!FileToolsCommon.IsExistFile(Path + "temp/filelist.d"))
  444. {
  445. return;
  446. }
  447. }
  448. else
  449. {
  450. if (!FileToolsCommon.IsExistFile(Path + "temprs/filelist.d"))
  451. {
  452. return;
  453. }
  454. }
  455. #endregion
  456. myProcess = new Process();
  457. LogPath = CreateffmpegLog();
  458. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  459. if (Extension.ToUpper() == ".MP3")
  460. {
  461. myProcess.StartInfo.Arguments = "-f concat -safe 0 -i " + Path + "temp/filelist.d -c copy " + FilePath;
  462. }
  463. else
  464. {
  465. myProcess.StartInfo.Arguments = "-f concat -safe 0 -i " + Path + "temprs/filelist.d -c copy " + FilePath;
  466. }
  467. if (OutputVideoLog)
  468. LogHelper.WriteInfoLog("【音视频合成】:" + myProcess.StartInfo.Arguments);
  469. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  470. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  471. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  472. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  473. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  474. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  475. myProcess.Start(); //启动线程
  476. myProcess.BeginErrorReadLine(); //开始异步读取
  477. myProcess.WaitForExit(); //阻塞等待进程结束
  478. myProcess.Close(); //关闭进程
  479. myProcess.Dispose(); //释放资源
  480. #region 进程是否已经释放
  481. bool IsRunning = true;
  482. while (IsRunning)
  483. {
  484. IsRunning = false;
  485. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  486. foreach (Process KillProcess in ProcessArray)
  487. {
  488. IsRunning = true;
  489. Thread.Sleep(100);
  490. }
  491. }
  492. #endregion
  493. myProcess = null;
  494. if (Extension.ToUpper() == ".MP3")
  495. {
  496. FileToolsCommon.DeleteDirectory(Path + "temp/");
  497. }
  498. else
  499. {
  500. FileToolsCommon.DeleteDirectory(Path + "temprs/");
  501. }
  502. }
  503. /// <summary>
  504. /// 获取文件完整路径 音频
  505. /// </summary>
  506. /// <param name="FilePath">文件路径</param>
  507. /// <returns></returns>
  508. private string GetFilePathName(string FilePath)
  509. {
  510. //路径
  511. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  512. //Path.GetFileName(FilePath);//获取文件名
  513. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  514. string tempFilePath = Path + "temp/";
  515. //创建临时目录
  516. FileToolsCommon.CreateDirectory(tempFilePath);
  517. //创建记录文件
  518. if (!FileToolsCommon.IsExistFile(tempFilePath + "filelist.d"))
  519. {
  520. FileToolsCommon.CreateFile(tempFilePath + "filelist.d");
  521. }
  522. int num = 1;
  523. string CompleteFilePath = tempFilePath + num + Extension;
  524. while (FileToolsCommon.IsExistFile(CompleteFilePath))
  525. {
  526. num++;
  527. CompleteFilePath = tempFilePath + num + Extension;
  528. }
  529. FileToolsCommon.AppendText(tempFilePath + "filelist.d", "file ./" + num + Extension + "\r\n");
  530. return CompleteFilePath;
  531. }
  532. /// <summary>
  533. /// 获取文件完整路径 录屏
  534. /// </summary>
  535. /// <param name="FilePath">文件路径</param>
  536. /// <returns></returns>
  537. private string GetRSFilePathName(string FilePath)
  538. {
  539. //路径
  540. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  541. //Path.GetFileName(FilePath);//获取文件名
  542. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  543. string tempFilePath = Path + "temprs/";
  544. //创建临时目录
  545. FileToolsCommon.CreateDirectory(tempFilePath);
  546. //创建记录文件
  547. if (!FileToolsCommon.IsExistFile(tempFilePath + "filelist.d"))
  548. {
  549. FileToolsCommon.CreateFile(tempFilePath + "filelist.d");
  550. }
  551. int num = 1;
  552. string CompleteFilePath = tempFilePath + num + Extension;
  553. while (FileToolsCommon.IsExistFile(CompleteFilePath))
  554. {
  555. num++;
  556. CompleteFilePath = tempFilePath + num + Extension;
  557. }
  558. FileToolsCommon.AppendText(tempFilePath + "filelist.d", "file ./" + num + Extension + "\r\n");
  559. return CompleteFilePath;
  560. }
  561. /// <summary>
  562. /// 生成缩略图
  563. /// </summary>
  564. /// <param name="VideoPath">视频地址</param>
  565. /// <param name="ImagePath">图片地址</param>
  566. /// <param name="Width">图片大小</param>
  567. /// <param name="Height">图片大小</param>
  568. public bool GenerateThumbnails(string VideoPath, string ImagePath,int Width=0,int Height=0)
  569. {
  570. while (myProcess != null)
  571. {
  572. Thread.Sleep(100);
  573. }
  574. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  575. foreach (Process KillProcess in KillProcessArray)
  576. {
  577. KillProcess.Kill();
  578. }
  579. string WHStr = "";
  580. if(Width>0)
  581. {
  582. WHStr = " -s "+ Width + "x"+ Height;
  583. }
  584. try
  585. {
  586. myProcess = new Process();
  587. LogPath = CreateffmpegLog();
  588. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  589. //myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -s " + thubWidth + "*" + thubHeight + " -f image2 \"" + ImagePath + "\"";
  590. myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2"+ WHStr + " -f image2 \"" + ImagePath + "\"";
  591. if (OutputVideoLog)
  592. LogHelper.WriteInfoLog("【生成缩略图】:" + myProcess.StartInfo.Arguments);
  593. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  594. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  595. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  596. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  597. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  598. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  599. myProcess.Start(); //启动线程
  600. myProcess.BeginErrorReadLine(); //开始异步读取
  601. myProcess.WaitForExit(); //阻塞等待进程结束
  602. myProcess.Close(); //关闭进程
  603. myProcess.Dispose(); //释放资源
  604. #region 进程是否已经释放
  605. bool IsRunning = true;
  606. while (IsRunning)
  607. {
  608. IsRunning = false;
  609. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  610. foreach (Process KillProcess in ProcessArray)
  611. {
  612. IsRunning = true;
  613. Thread.Sleep(100);
  614. }
  615. }
  616. #endregion
  617. myProcess = null;
  618. return true;
  619. }
  620. catch (Exception ex)
  621. {
  622. LogHelper.WriteErrLog("【生成缩略图】(GenerateThumbnails)缩略图生成失败," + ex.Message, ex);
  623. return false;
  624. }
  625. }
  626. /// <summary>
  627. /// 视频转码
  628. /// </summary>
  629. /// <param name="VideoPathName">源视频</param>
  630. /// <param name="VideoSavePathName">目标视频存储路径</param>
  631. /// <param name="Width">宽</param>
  632. /// <param name="Height">高</param>
  633. /// <returns></returns>
  634. public bool VideoTranscode(string VideoPathName, string VideoSavePathName, int Width, int Height)
  635. {
  636. while (myProcess != null)
  637. {
  638. Thread.Sleep(100);
  639. }
  640. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  641. foreach (Process KillProcess in KillProcessArray)
  642. {
  643. KillProcess.Kill();
  644. }
  645. try
  646. {
  647. myProcess = new Process();
  648. LogPath = CreateffmpegLog();
  649. myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
  650. myProcess.StartInfo.Arguments = "-i " + VideoPathName + " -acodec copy -vcodec libx264 -s " + Width + "*" + Height + " " + VideoSavePathName;
  651. if (OutputVideoLog)
  652. LogHelper.WriteInfoLog("【视频转码】:" + myProcess.StartInfo.Arguments);
  653. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  654. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  655. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  656. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  657. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  658. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  659. myProcess.Start(); //启动线程
  660. myProcess.BeginErrorReadLine(); //开始异步读取
  661. myProcess.WaitForExit(); //阻塞等待进程结束
  662. myProcess.Close(); //关闭进程
  663. myProcess.Dispose(); //释放资源
  664. #region 进程是否已经释放
  665. bool IsRunning = true;
  666. while (IsRunning)
  667. {
  668. IsRunning = false;
  669. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  670. foreach (Process KillProcess in ProcessArray)
  671. {
  672. IsRunning = true;
  673. Thread.Sleep(100);
  674. }
  675. }
  676. #endregion
  677. myProcess = null;
  678. Thread.Sleep(200);
  679. FileToolsCommon.DeleteFile(VideoPathName);
  680. return true;
  681. }
  682. catch (Exception ex)
  683. {
  684. LogHelper.WriteErrLog("【视频转码】(VideoTranscode)视频转码失败," + ex.Message, ex);
  685. return false;
  686. }
  687. }
  688. /// <summary>
  689. /// 创建日志文件
  690. /// </summary>
  691. /// <returns></returns>
  692. private string CreateffmpegLog()
  693. {
  694. string LogFileName = DateTime.Now.ToString("yyyyMMdd");
  695. string LogFilePath = FileToolsCommon.GetFileAbsolutePath("/Log/FFMpegLog/");
  696. FileToolsCommon.CreateDirectory(LogFilePath);
  697. string LogName = LogFilePath + LogFileName + ".log";
  698. try
  699. {
  700. if (!FileToolsCommon.IsExistFile(LogName))
  701. {
  702. FileToolsCommon.CreateFile(LogName);
  703. FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
  704. "****************************************************************************************************\r\n");
  705. return LogName;
  706. }
  707. else
  708. {
  709. int num = 0;
  710. while (FileToolsCommon.GetFileSizeByMB(LogName) > 2)
  711. {
  712. num++;
  713. LogName = LogFilePath + LogFileName + "_" + num + ".log";
  714. FileToolsCommon.CreateFile(LogName);
  715. }
  716. FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
  717. "****************************************************************************************************\r\n");
  718. return LogName;
  719. }
  720. }
  721. catch (Exception)
  722. {
  723. return LogName;
  724. }
  725. }
  726. /// <summary>
  727. /// 输出结果
  728. /// </summary>
  729. /// <param name="sendProcess"></param>
  730. /// <param name="output"></param>
  731. private void Output(object sendProcess, DataReceivedEventArgs output)
  732. {
  733. if (!string.IsNullOrEmpty(output.Data))
  734. {
  735. FileToolsCommon.AppendText(LogPath, output.Data);
  736. }
  737. }
  738. /// <summary>
  739. /// 获取麦克风
  740. /// </summary>
  741. private string GetMicrophone()
  742. {
  743. List<string> devs = new List<string>();
  744. MMDeviceEnumerator enumberator = new MMDeviceEnumerator();
  745. MMDeviceCollection deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  746. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  747. {
  748. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  749. foreach (MMDevice device in deviceCollection)
  750. {
  751. try
  752. {
  753. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  754. {
  755. devs.Add(device.FriendlyName);
  756. break;
  757. }
  758. }
  759. catch (Exception)
  760. {
  761. }
  762. }
  763. }
  764. if (devs.Count > 0)
  765. {
  766. return devs[0];
  767. }
  768. else
  769. {
  770. return "";
  771. }
  772. }
  773. /// <summary>
  774. /// 获取声音输入设备完整名称
  775. /// </summary>
  776. /// <returns></returns>
  777. public static string GetInDeviceFull()
  778. {
  779. List<string> devices = new List<string>();
  780. var enumberator = new MMDeviceEnumerator();
  781. var deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  782. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  783. {
  784. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  785. foreach (MMDevice device in deviceCollection)
  786. {
  787. try
  788. {
  789. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  790. {
  791. devices.Add(device.FriendlyName);
  792. break;
  793. }
  794. }
  795. catch (Exception ex)
  796. {
  797. continue;
  798. }
  799. }
  800. }
  801. if (devices.Count > 0)
  802. {
  803. byte[] buffer = Encoding.UTF8.GetBytes(devices[0]);
  804. string MicrophoneName = Encoding.UTF8.GetString(buffer); // 统一使用UTF-8
  805. return MicrophoneName;
  806. }
  807. else
  808. {
  809. return "";
  810. }
  811. }
  812. /// <summary>
  813. /// 获取声音输入设备完整名称
  814. /// </summary>
  815. /// <returns></returns>
  816. public List<string> GetInDeviceListFull()
  817. {
  818. List<string> devices = new List<string>();
  819. var enumberator = new MMDeviceEnumerator();
  820. var deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  821. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  822. {
  823. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  824. foreach (MMDevice device in deviceCollection)
  825. {
  826. try
  827. {
  828. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  829. {
  830. devices.Add(device.FriendlyName);
  831. break;
  832. }
  833. }
  834. catch (Exception ex)
  835. {
  836. continue;
  837. }
  838. }
  839. }
  840. return devices;
  841. }
  842. /// <summary>
  843. /// 录制麦克风的声音
  844. /// </summary>
  845. private WaveInEvent waveIn = null; //new WaveInEvent();
  846. /// <summary>
  847. /// 开始录制麦克风
  848. /// </summary>
  849. public bool StartRecordAudio(string audioFile)
  850. {
  851. try
  852. {
  853. waveIn = new WaveInEvent();
  854. //生成音频文件的对象
  855. WaveFileWriter writer = new WaveFileWriter(audioFile, waveIn.WaveFormat);
  856. //开始录音,写数据
  857. waveIn.DataAvailable += (s, a) =>
  858. {
  859. writer.Write(a.Buffer, 0, a.BytesRecorded);
  860. };
  861. //结束录音
  862. waveIn.RecordingStopped += (s, a) =>
  863. {
  864. writer.Dispose();
  865. writer = null;
  866. waveIn.Dispose();
  867. waveIn = null;
  868. try
  869. {
  870. FileToolsCommon.DeleteFile(audioFile);
  871. }
  872. catch (Exception)
  873. {
  874. }
  875. };
  876. waveIn.StartRecording();
  877. return true;
  878. }
  879. catch (Exception ex)
  880. {
  881. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  882. return false;
  883. }
  884. }
  885. /// <summary>
  886. /// 结束录制音频
  887. /// </summary>
  888. /// <param name="type">1麦克风 2扬声器</param>
  889. public void StopRecordAudio(int type)
  890. {
  891. try
  892. {
  893. if (type == 1)
  894. {
  895. if (waveIn != null)
  896. {
  897. try
  898. {
  899. waveIn.StopRecording();
  900. }
  901. catch (Exception)
  902. {
  903. waveIn = null;
  904. }
  905. }
  906. }
  907. else if (type == 2)
  908. {
  909. if (capture != null)
  910. {
  911. try
  912. {
  913. capture.StopRecording();
  914. }
  915. catch (Exception)
  916. {
  917. capture = null;
  918. }
  919. }
  920. }
  921. }
  922. catch (Exception ex)
  923. {
  924. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  925. }
  926. }
  927. /// <summary>
  928. /// 录制扬声器的声音
  929. /// </summary>
  930. private WasapiLoopbackCapture capture = null; //new WasapiLoopbackCapture();
  931. /// <summary>
  932. /// 开始录制扬声器
  933. /// </summary>
  934. public bool StartRecordSpeakerAudio(string audioFile)
  935. {
  936. try
  937. {
  938. capture = new WasapiLoopbackCapture();
  939. //生成音频文件的对象
  940. WaveFileWriter writer = new WaveFileWriter(audioFile, capture.WaveFormat);
  941. capture.DataAvailable += (s, a) =>
  942. {
  943. writer.Write(a.Buffer, 0, a.BytesRecorded);
  944. };
  945. //结束录音
  946. capture.RecordingStopped += (s, a) =>
  947. {
  948. writer.Dispose();
  949. writer = null;
  950. capture.Dispose();
  951. capture = null;
  952. try
  953. {
  954. FileToolsCommon.DeleteFile(audioFile);
  955. }
  956. catch (Exception)
  957. {
  958. }
  959. };
  960. capture.StartRecording();
  961. return true;
  962. }
  963. catch (Exception ex)
  964. {
  965. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  966. return false;
  967. }
  968. }
  969. }
  970. }