星火微课系统客户端
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

FFMpeg.cs 64KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606
  1. using AForge.Video.DirectShow;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using VisioForge.Shared.NAudio.CoreAudioApi;
  10. using VisioForge.Shared.NAudio.Wave;
  11. namespace Common.system
  12. {
  13. /// <summary>
  14. /// ffmpeg帮助类 创建人:赵耀 创建时间::2020年8月22日 需要安装\SSCR\Setup Screen Capturer Recorder v0.12.10.exe
  15. /// 本地调试需要配置环境变量 将ffmpeg.exe位置配置到环境变量的path中
  16. /// </summary>
  17. public class FFMpeg
  18. {
  19. #region 变量
  20. public Process myProcess = null;
  21. /// <summary>
  22. /// 是否输出录课录屏日志
  23. /// </summary>
  24. public bool OutputVideoLog = FileToolsCommon.GetConfigValue("OutputVideoLog") != "0";
  25. /// <summary>
  26. /// ffmpeg输出日志文件地址 每个文件2MB左右
  27. /// </summary>
  28. private string LogPath = "";
  29. /// <summary>
  30. /// 是否可以录制扬声器
  31. /// </summary>
  32. private bool IsRecordSpeaker = true;
  33. /// <summary>
  34. /// 是否可以录制麦克风
  35. /// </summary>
  36. private bool IsRecordMicrophone = true;
  37. private string ffmpegPath = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg.exe");
  38. #endregion 变量
  39. /// <summary>
  40. /// 录制屏幕
  41. /// </summary>
  42. /// <param name="FilePath">文件存储路径</param>
  43. /// <param name="size">大小</param>
  44. /// <param name="RecordingSound">录制音频</param>
  45. /// <param name="RecordingMicrophone">录制麦克风</param>
  46. /// <param name="ErrMessage">错误信息</param>
  47. /// <param name="MicrophoneName">麦克风名</param>
  48. /// <returns></returns>
  49. public bool StartRecordingVideo(string FilePath, Size size, bool RecordingSound, bool RecordingMicrophone, out string ErrMessage, string MicrophoneName = null)
  50. {
  51. while (myProcess != null)
  52. {
  53. Thread.Sleep(100);
  54. }
  55. ErrMessage = null;
  56. //路径
  57. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  58. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  59. //文件保存路径
  60. string PathName = GetRSFilePathName(FilePath);
  61. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  62. foreach (Process KillProcess in KillProcessArray)
  63. {
  64. KillProcess.Kill();
  65. }
  66. myProcess = new Process();
  67. LogPath = CreateffmpegLog();
  68. if (string.IsNullOrWhiteSpace(MicrophoneName))
  69. {
  70. MicrophoneName = GetMicrophoneName();
  71. }
  72. #region 检测麦克风扬声器
  73. string AudioPath = FileToolsCommon.GetFileAbsolutePath("/temp/audio/");
  74. FileToolsCommon.CreateDirectory(AudioPath);
  75. string audioSpeakerPath = AudioPath + "adoS" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".m";//FileToolsCommon.GetFileAbsolutePath("adoS.m");
  76. string audioMicrophonePath = AudioPath + "adoM" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".m";//FileToolsCommon.GetFileAbsolutePath("adoM.m");
  77. try
  78. {
  79. FileToolsCommon.DeleteFile(audioSpeakerPath);
  80. FileToolsCommon.DeleteFile(audioMicrophonePath);
  81. }
  82. catch (Exception)
  83. {
  84. }
  85. //是否录制音频
  86. if (RecordingSound)
  87. {
  88. if (StartRecordSpeakerAudio(audioSpeakerPath))
  89. {
  90. IsRecordSpeaker = true;
  91. }
  92. else
  93. {
  94. //无法录制扬声器音频
  95. IsRecordSpeaker = false;
  96. }
  97. StopRecordAudio(2);
  98. Thread.Sleep(100);
  99. }
  100. //是否录制麦克风
  101. if (RecordingMicrophone)
  102. {
  103. if (StartRecordAudio(audioMicrophonePath))
  104. {
  105. IsRecordMicrophone = true;
  106. }
  107. else
  108. {
  109. //无法录制麦克风
  110. IsRecordMicrophone = false;
  111. }
  112. StopRecordAudio(1);
  113. }
  114. #endregion 检测麦克风扬声器
  115. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  116. string SpeakerStr = "";
  117. string MicrophoneStr = "";
  118. if (IsRecordSpeaker && RecordingSound)
  119. {
  120. SpeakerStr = "-f dshow -i audio=\"virtual-audio-capturer\" ";
  121. }
  122. if (IsRecordMicrophone && RecordingMicrophone)
  123. {
  124. if (!string.IsNullOrWhiteSpace(MicrophoneName))
  125. {
  126. MicrophoneStr = "-f dshow -i audio=\"" + MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ";
  127. }
  128. }
  129. switch (Extension.ToUpper())
  130. {
  131. case ".MP4":
  132. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -framerate 6 -offset_x 0 -offset_y 0 -video_size " + size.Width + "x" + size.Height + " -i desktop -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac " + PathName;
  133. break;
  134. case ".AVI":
  135. case ".FLV":
  136. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -framerate 6 -offset_x 0 -offset_y 0 -video_size " + size.Width + "x" + size.Height + " -i desktop -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac -f " + Extension.ToLower().Replace(".", "") + " " + PathName;
  137. break;
  138. default:
  139. myProcess.StartInfo.Arguments = SpeakerStr + MicrophoneStr + " -f gdigrab -framerate 6 -offset_x 0 -offset_y 0 -video_size " + size.Width + "x" + size.Height + " -i desktop -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec aac " + PathName;
  140. break;
  141. }
  142. if (OutputVideoLog)
  143. {
  144. LogHelper.WriteInfoLog("【录屏】:" + myProcess.StartInfo.Arguments);
  145. }
  146. FileToolsCommon.AppendText(LogPath, "【录屏】:" + myProcess.StartInfo.Arguments + "\r\n");
  147. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  148. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  149. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  150. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  151. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  152. try
  153. {
  154. myProcess.Start();
  155. myProcess.BeginErrorReadLine();
  156. }
  157. catch (Exception ex)
  158. {
  159. if (ex.Message.Contains("访问"))
  160. {
  161. ErrMessage = "访问被拒绝,请关闭杀毒软件或新任此软件后重试!";
  162. }
  163. else
  164. {
  165. ErrMessage = ex.Message + " 请关闭杀毒软件或信任此软件后重试!";
  166. }
  167. LogHelper.WriteErrLog("【录音】(StartRecordingAudio)" + ErrMessage, ex);
  168. myProcess.Dispose();
  169. myProcess = null;
  170. return false;
  171. }
  172. return true;
  173. }
  174. /// <summary>
  175. /// 录制音频
  176. /// </summary>
  177. /// <param name="Mp3Path">MP3音频位置</param>
  178. /// <param name="ErrMessage">错误信息</param>
  179. /// <param name="RecordingSound">录制音频</param>
  180. /// <param name="RecordingMicrophone">录制麦克风</param>
  181. /// <param name="MicrophoneName">麦克风名</param>
  182. public bool StartRecordingAudio(string Mp3Path, out string ErrMessage, bool RecordingSound, bool RecordingMicrophone, string MicrophoneName = null)
  183. {
  184. ErrMessage = null;
  185. while (myProcess != null)
  186. {
  187. Thread.Sleep(100);
  188. }
  189. //路径
  190. string Path = FileToolsCommon.GetDirectoryName(Mp3Path);
  191. //文件保存路径
  192. string PathName = GetFilePathName(Mp3Path);
  193. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  194. foreach (Process KillProcess in KillProcessArray)
  195. {
  196. KillProcess.Kill();
  197. }
  198. if (string.IsNullOrWhiteSpace(MicrophoneName))
  199. {
  200. MicrophoneName = GetMicrophoneName();
  201. }
  202. #region 检测麦克风扬声器
  203. string AudioPath = FileToolsCommon.GetFileAbsolutePath("/temp/audio/");
  204. FileToolsCommon.CreateDirectory(AudioPath);
  205. string audioSpeakerPath = AudioPath + "adoS" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".m";
  206. string audioMicrophonePath = AudioPath + "adoM" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".m";
  207. try
  208. {
  209. FileToolsCommon.DeleteFile(audioSpeakerPath);
  210. FileToolsCommon.DeleteFile(audioMicrophonePath);
  211. }
  212. catch (Exception)
  213. {
  214. }
  215. if (RecordingSound)
  216. {
  217. if (StartRecordSpeakerAudio(audioSpeakerPath))
  218. {
  219. IsRecordSpeaker = true;
  220. }
  221. else
  222. {
  223. //无法录制扬声器音频
  224. IsRecordSpeaker = false;
  225. }
  226. StopRecordAudio(2);
  227. Thread.Sleep(100);
  228. if (!IsRecordSpeaker)
  229. {
  230. ErrMessage = "无法录制声音,请关闭杀毒软件,确保扬声器处于可用状态!";
  231. //return false;
  232. }
  233. }
  234. if (RecordingMicrophone)
  235. {
  236. if (StartRecordAudio(audioMicrophonePath))
  237. {
  238. IsRecordMicrophone = true;
  239. }
  240. else
  241. {
  242. //无法录制麦克风
  243. IsRecordMicrophone = false;
  244. }
  245. StopRecordAudio(1);
  246. if (!IsRecordMicrophone)
  247. {
  248. ErrMessage = "无法录制麦克风,请关闭杀毒软件,确保麦克风处于可用状态!";
  249. //return false;
  250. }
  251. }
  252. #endregion 检测麦克风扬声器
  253. myProcess = new Process();
  254. LogPath = CreateffmpegLog();
  255. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  256. if (IsRecordSpeaker && IsRecordMicrophone && RecordingSound && RecordingMicrophone)
  257. {
  258. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
  259. MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + PathName;
  260. }
  261. else if (IsRecordSpeaker && RecordingSound)
  262. {
  263. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" " + PathName;
  264. }
  265. else if (IsRecordMicrophone && RecordingMicrophone)
  266. {
  267. //录制麦克风
  268. if (!string.IsNullOrWhiteSpace(MicrophoneName))
  269. {
  270. myProcess.StartInfo.Arguments = "-f dshow -i audio=\"" +
  271. MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + PathName;
  272. }
  273. }
  274. if (OutputVideoLog)
  275. {
  276. LogHelper.WriteInfoLog("【录音】:" + myProcess.StartInfo.Arguments);
  277. }
  278. FileToolsCommon.AppendText(LogPath, "【录音】:" + myProcess.StartInfo.Arguments + "\r\n");
  279. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  280. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  281. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  282. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  283. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  284. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  285. try
  286. {
  287. myProcess.Start(); //启动线程
  288. myProcess.BeginErrorReadLine(); //开始异步读取
  289. }
  290. catch (Exception ex)
  291. {
  292. if (ex.Message.Contains("访问"))
  293. {
  294. ErrMessage = "无法录制声音,访问被拒绝,请关闭杀毒软件或信任此软件后重试!";
  295. }
  296. else
  297. {
  298. ErrMessage = ex.Message + " 请关闭杀毒软件或信任此软件后重试!";
  299. }
  300. LogHelper.WriteErrLog("【录音】(StartRecordingAudio)" + ErrMessage, ex);
  301. myProcess.Dispose();
  302. myProcess = null;
  303. return false;
  304. }
  305. return true;
  306. }
  307. /// <summary>
  308. /// 暂停录制
  309. /// </summary>
  310. public bool SuspendFFmpeg()
  311. {
  312. if (myProcess != null)
  313. {
  314. myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
  315. myProcess.Close();//关闭进程
  316. myProcess.Dispose();//释放资源
  317. }
  318. #region 进程是否已经释放
  319. bool IsRunning = true;
  320. while (IsRunning)
  321. {
  322. IsRunning = false;
  323. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  324. foreach (Process KillProcess in ProcessArray)
  325. {
  326. IsRunning = true;
  327. Thread.Sleep(100);
  328. }
  329. }
  330. #endregion 进程是否已经释放
  331. myProcess = null;
  332. return true;
  333. //myProcess.Kill();
  334. }
  335. /// <summary>
  336. /// 停止录制并合成文件
  337. /// </summary>
  338. /// <param name="FilePath">文件存储路径 必须与开始时的路径完全一致</param>
  339. public bool StopFFmpeg(string FilePath)
  340. {
  341. try
  342. {
  343. //文件完整路径
  344. if (myProcess != null)
  345. {
  346. myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
  347. myProcess.Close();//关闭进程
  348. myProcess.Dispose();//释放资源
  349. }
  350. }
  351. catch (Exception)
  352. {
  353. myProcess = null;
  354. }
  355. #region 进程是否已经释放
  356. bool IsRunning = true;
  357. while (IsRunning)
  358. {
  359. IsRunning = false;
  360. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  361. foreach (Process KillProcess in ProcessArray)
  362. {
  363. IsRunning = true;
  364. Thread.Sleep(100);
  365. }
  366. }
  367. #endregion 进程是否已经释放
  368. try
  369. {
  370. myProcess = null;
  371. Thread t1 = new Thread(MergeVideoOrAudio);
  372. t1.Start(FilePath);
  373. return true;
  374. }
  375. catch (Exception ex)
  376. {
  377. LogHelper.WriteErrLog("【合成文件】:" + FilePath + "合成失败," + ex.Message, ex);
  378. return false;
  379. }
  380. //文件合成
  381. }
  382. /// <summary>
  383. /// 图片音频合成视频
  384. /// </summary>
  385. /// <param name="ImageListPath">图片列表位置 命名为1.png 2.png</param>
  386. /// <param name="Mp3Path">MP3音频位置</param>
  387. /// <param name="VideoSavePath">视频保存位置</param>
  388. /// <param name="Frequency">每秒帧率</param>
  389. /// <param name="VideoWidth">视频宽度</param>
  390. /// <param name="VideoHeight">视频高度</param>
  391. public bool SynthesisVideo(string ImageListPath, string Mp3Path, string VideoSavePath, int Frequency, int VideoWidth, int VideoHeight, out string ErrMessage)
  392. {
  393. while (myProcess != null)
  394. {
  395. Thread.Sleep(100);
  396. }
  397. ErrMessage = null;
  398. string Extension = FileToolsCommon.GetIOExtension(VideoSavePath);//扩展名
  399. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  400. foreach (Process KillProcess in KillProcessArray)
  401. {
  402. KillProcess.Kill();
  403. }
  404. myProcess = new Process();
  405. try
  406. {
  407. LogPath = CreateffmpegLog();
  408. string mp3Str = "";
  409. #region 判断音频是否存在
  410. if (!string.IsNullOrWhiteSpace(Mp3Path))
  411. {
  412. if (FileToolsCommon.IsExistFile(Mp3Path))
  413. {
  414. mp3Str = "-i " + Mp3Path;
  415. }
  416. }
  417. #endregion 判断音频是否存在
  418. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  419. switch (Extension.ToUpper())
  420. {
  421. case ".MP4":
  422. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  423. ImageListPath + @"%d.png " +
  424. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
  425. VideoSavePath;
  426. break;
  427. case ".AVI":
  428. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  429. ImageListPath + @"%d.png " +
  430. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -f AVI " +
  431. VideoSavePath;
  432. break;
  433. case ".FLV":
  434. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  435. ImageListPath + @"%d.png " +
  436. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -f FLV " +
  437. VideoSavePath;
  438. break;
  439. default:
  440. myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
  441. ImageListPath + @"%d.png " +
  442. mp3Str + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
  443. VideoSavePath;
  444. break;
  445. }
  446. if (OutputVideoLog)
  447. {
  448. LogHelper.WriteInfoLog("【图片音频合成视频】:" + myProcess.StartInfo.Arguments);
  449. }
  450. FileToolsCommon.AppendText(LogPath, "【图片音频合成视频】:" + myProcess.StartInfo.Arguments + "\r\n");
  451. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  452. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  453. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  454. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  455. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  456. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  457. try
  458. {
  459. myProcess.Start(); //启动线程
  460. myProcess.BeginErrorReadLine(); //开始异步读取
  461. myProcess.WaitForExit(); //阻塞等待进程结束
  462. myProcess.Close(); //关闭进程
  463. }
  464. catch (Exception ex)
  465. {
  466. if (ex.Message.Contains("访问"))
  467. {
  468. ErrMessage = "访问被拒绝,请关闭杀毒软件或新任此软件后重试!";
  469. }
  470. else
  471. {
  472. ErrMessage = ex.Message + " 请关闭杀毒软件或信任此软件后重试!";
  473. }
  474. LogHelper.WriteErrLog("【录音】(StartRecordingAudio)" + ErrMessage, ex);
  475. myProcess.Dispose();
  476. myProcess = null;
  477. return false;
  478. }
  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. //生成视频后删除图片和音频保存列表
  495. //FileToolsCommon.DeleteDirectory(ImageListPath);
  496. //FileToolsCommon.DeleteDirectory(FileToolsCommon.GetDirectoryName(Mp3Path));
  497. Thread.Sleep(100);
  498. FileToolsCommon.DeleteDirectory(FileToolsCommon.GetDirectoryName(VideoSavePath) + "temp");
  499. return true;
  500. }
  501. catch (Exception ex)
  502. {
  503. LogHelper.WriteErrLog("【视频合成】(SynthesisVideo)视频生成失败," + ex.Message, ex);
  504. ErrMessage = ex.Message;
  505. return false;
  506. }
  507. //Dispatcher.Invoke(() =>
  508. //{
  509. //});
  510. //// 允许不同线程间的调用
  511. //Control.CheckForIllegalCrossThreadCalls = false;
  512. }
  513. /// <summary>
  514. /// 视频音频合成
  515. /// </summary>
  516. /// <param name="FilePath">存储路径</param>
  517. public void MergeVideoOrAudio(object FilePathobj)
  518. {
  519. while (myProcess != null)
  520. {
  521. Thread.Sleep(100);
  522. }
  523. //路径
  524. string FilePath = (string)FilePathobj;
  525. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  526. //扩展名
  527. string Extension = FileToolsCommon.GetIOExtension(FilePath);
  528. //Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  529. //foreach (var KillProcess in KillProcessArray)
  530. //{
  531. // KillProcess.Kill();
  532. //}
  533. #region 判断文件是否存在
  534. if (Extension.ToUpper() == ".MP3")
  535. {
  536. if (!FileToolsCommon.IsExistFile(Path + "temp/filelist.d"))
  537. {
  538. return;
  539. }
  540. }
  541. else
  542. {
  543. if (!FileToolsCommon.IsExistFile(Path + "temprs/filelist.d"))
  544. {
  545. return;
  546. }
  547. }
  548. #endregion 判断文件是否存在
  549. myProcess = new Process();
  550. LogPath = CreateffmpegLog();
  551. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  552. if (Extension.ToUpper() == ".MP3")
  553. {
  554. myProcess.StartInfo.Arguments = "-f concat -safe 0 -i " + Path + "temp/filelist.d -c copy " + FilePath;
  555. }
  556. else
  557. {
  558. myProcess.StartInfo.Arguments = "-f concat -safe 0 -i " + Path + "temprs/filelist.d -c copy " + FilePath;
  559. }
  560. if (OutputVideoLog)
  561. {
  562. LogHelper.WriteInfoLog("【音视频合成】:" + myProcess.StartInfo.Arguments);
  563. }
  564. FileToolsCommon.AppendText(LogPath, "【音视频合成】:" + myProcess.StartInfo.Arguments + "\r\n");
  565. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  566. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  567. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  568. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  569. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  570. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  571. myProcess.Start(); //启动线程
  572. myProcess.BeginErrorReadLine(); //开始异步读取
  573. myProcess.WaitForExit(); //阻塞等待进程结束
  574. myProcess.Close(); //关闭进程
  575. myProcess.Dispose(); //释放资源
  576. #region 进程是否已经释放
  577. bool IsRunning = true;
  578. while (IsRunning)
  579. {
  580. IsRunning = false;
  581. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  582. foreach (Process KillProcess in ProcessArray)
  583. {
  584. IsRunning = true;
  585. Thread.Sleep(100);
  586. }
  587. }
  588. #endregion 进程是否已经释放
  589. myProcess = null;
  590. if (Extension.ToUpper() == ".MP3")
  591. {
  592. FileToolsCommon.DeleteDirectory(Path + "temp/");
  593. }
  594. else
  595. {
  596. FileToolsCommon.DeleteDirectory(Path + "temprs/");
  597. }
  598. }
  599. /// <summary>
  600. /// 视频剪辑
  601. /// </summary>
  602. /// <param name="VideoFilePath">视频路径</param>
  603. /// <param name="StartTime">开始时间 格式 HH:mm:ss</param>
  604. /// <param name="EndTime">结束时间 格式 HH:mm:ss</param>
  605. /// <param name="SaveFilePath">保存文件路径</param>
  606. public void ClipVideo(string VideoFilePath, string StartTime, string EndTime, string SaveFilePath)
  607. {
  608. while (myProcess != null)
  609. {
  610. Thread.Sleep(100);
  611. }
  612. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  613. foreach (var KillProcess in KillProcessArray)
  614. {
  615. KillProcess.Kill();
  616. }
  617. myProcess = new Process();
  618. LogPath = CreateffmpegLog();
  619. this.myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  620. //ffmpeg -ss 开始时间 -to 结束时间 -accurate_seek -i mp4输入路径 -c:v libx264 -c:a aac -strict experimental -vf scale = 宽:高 -b 500k 输出路径.mp4
  621. myProcess.StartInfo.Arguments = "-i " + VideoFilePath + " -vcodec copy -acodec copy -ss " + StartTime + " -to " + EndTime + " " + SaveFilePath; //-filter:a "volume=0.5"
  622. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  623. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  624. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  625. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  626. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  627. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  628. myProcess.Start(); //启动线程
  629. myProcess.BeginErrorReadLine(); //开始异步读取
  630. myProcess.WaitForExit(); //阻塞等待进程结束
  631. myProcess.Close(); //关闭进程
  632. myProcess.Dispose(); //释放资源
  633. #region 进程是否已经释放
  634. bool IsRunning = true;
  635. while (IsRunning)
  636. {
  637. IsRunning = false;
  638. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  639. foreach (var KillProcess in ProcessArray)
  640. {
  641. IsRunning = true;
  642. Thread.Sleep(100);
  643. }
  644. }
  645. #endregion 进程是否已经释放
  646. myProcess = null;
  647. }
  648. /// <summary>
  649. /// 获取文件完整路径 音频
  650. /// </summary>
  651. /// <param name="FilePath">文件路径</param>
  652. /// <returns></returns>
  653. private string GetFilePathName(string FilePath)
  654. {
  655. //路径
  656. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  657. //Path.GetFileName(FilePath);//获取文件名
  658. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  659. string tempFilePath = Path + "temp/";
  660. //创建临时目录
  661. FileToolsCommon.CreateDirectory(tempFilePath);
  662. //创建记录文件
  663. if (!FileToolsCommon.IsExistFile(tempFilePath + "filelist.d"))
  664. {
  665. FileToolsCommon.CreateFile(tempFilePath + "filelist.d");
  666. }
  667. int num = 1;
  668. string CompleteFilePath = tempFilePath + num + Extension;
  669. while (FileToolsCommon.IsExistFile(CompleteFilePath))
  670. {
  671. num++;
  672. CompleteFilePath = tempFilePath + num + Extension;
  673. }
  674. FileToolsCommon.AppendText(tempFilePath + "filelist.d", "file ./" + num + Extension + "\r\n");
  675. return CompleteFilePath;
  676. }
  677. /// <summary>
  678. /// 获取文件完整路径 录屏
  679. /// </summary>
  680. /// <param name="FilePath">文件路径</param>
  681. /// <returns></returns>
  682. private string GetRSFilePathName(string FilePath)
  683. {
  684. //路径
  685. string Path = FileToolsCommon.GetDirectoryName(FilePath);
  686. //Path.GetFileName(FilePath);//获取文件名
  687. string Extension = FileToolsCommon.GetIOExtension(FilePath);//扩展名
  688. string tempFilePath = Path + "temprs/";
  689. //创建临时目录
  690. FileToolsCommon.CreateDirectory(tempFilePath);
  691. //创建记录文件
  692. if (!FileToolsCommon.IsExistFile(tempFilePath + "filelist.d"))
  693. {
  694. FileToolsCommon.CreateFile(tempFilePath + "filelist.d");
  695. }
  696. int num = 1;
  697. string CompleteFilePath = tempFilePath + num + Extension;
  698. while (FileToolsCommon.IsExistFile(CompleteFilePath))
  699. {
  700. num++;
  701. CompleteFilePath = tempFilePath + num + Extension;
  702. }
  703. FileToolsCommon.AppendText(tempFilePath + "filelist.d", "file ./" + num + Extension + "\r\n");
  704. return CompleteFilePath;
  705. }
  706. /// <summary>
  707. /// 生成缩略图
  708. /// </summary>
  709. /// <param name="VideoPath">视频地址</param>
  710. /// <param name="ImagePath">图片地址</param>
  711. /// <param name="Width">图片大小</param>
  712. /// <param name="Height">图片大小</param>
  713. public bool GenerateThumbnails(string VideoPath, string ImagePath, int Width = 0, int Height = 0)
  714. {
  715. while (myProcess != null)
  716. {
  717. Thread.Sleep(100);
  718. }
  719. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  720. foreach (Process KillProcess in KillProcessArray)
  721. {
  722. KillProcess.Kill();
  723. }
  724. string WHStr = "";
  725. if (Width > 0)
  726. {
  727. WHStr = " -s " + Width + "x" + Height;
  728. }
  729. try
  730. {
  731. myProcess = new Process();
  732. LogPath = CreateffmpegLog();
  733. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  734. //myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -s " + thubWidth + "*" + thubHeight + " -f image2 \"" + ImagePath + "\"";
  735. myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2" + WHStr + " -f image2 \"" + ImagePath + "\"";
  736. if (OutputVideoLog)
  737. {
  738. LogHelper.WriteInfoLog("【生成缩略图】:" + myProcess.StartInfo.Arguments);
  739. }
  740. FileToolsCommon.AppendText(LogPath, "【生成缩略图】:" + myProcess.StartInfo.Arguments + "\r\n");
  741. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  742. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  743. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  744. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  745. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  746. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  747. myProcess.Start(); //启动线程
  748. myProcess.BeginErrorReadLine(); //开始异步读取
  749. myProcess.WaitForExit(); //阻塞等待进程结束
  750. myProcess.Close(); //关闭进程
  751. myProcess.Dispose(); //释放资源
  752. #region 进程是否已经释放
  753. bool IsRunning = true;
  754. while (IsRunning)
  755. {
  756. IsRunning = false;
  757. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  758. foreach (Process KillProcess in ProcessArray)
  759. {
  760. IsRunning = true;
  761. Thread.Sleep(100);
  762. }
  763. }
  764. #endregion 进程是否已经释放
  765. myProcess = null;
  766. return true;
  767. }
  768. catch (Exception ex)
  769. {
  770. LogHelper.WriteErrLog("【生成缩略图】(GenerateThumbnails)缩略图生成失败," + ex.Message, ex);
  771. return false;
  772. }
  773. }
  774. /// <summary>
  775. /// 视频转码
  776. /// </summary>
  777. /// <param name="VideoPathName">源视频</param>
  778. /// <param name="VideoSavePathName">目标视频存储路径</param>
  779. /// <param name="Width">宽</param>
  780. /// <param name="Height">高</param>
  781. /// <returns></returns>
  782. public bool VideoTranscode(string VideoPathName, string VideoSavePathName, int Width, int Height)
  783. {
  784. while (myProcess != null)
  785. {
  786. Thread.Sleep(100);
  787. }
  788. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  789. foreach (Process KillProcess in KillProcessArray)
  790. {
  791. KillProcess.Kill();
  792. }
  793. try
  794. {
  795. myProcess = new Process();
  796. LogPath = CreateffmpegLog();
  797. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  798. myProcess.StartInfo.Arguments = "-i " + VideoPathName + " -acodec copy -vcodec libx264 -s " + Width + "*" + Height + " " + VideoSavePathName;
  799. if (OutputVideoLog)
  800. {
  801. LogHelper.WriteInfoLog("【视频转码】:" + myProcess.StartInfo.Arguments);
  802. }
  803. FileToolsCommon.AppendText(LogPath, "【视频转码】:" + myProcess.StartInfo.Arguments + "\r\n");
  804. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  805. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  806. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  807. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  808. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  809. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  810. myProcess.Start(); //启动线程
  811. myProcess.BeginErrorReadLine(); //开始异步读取
  812. myProcess.WaitForExit(); //阻塞等待进程结束
  813. myProcess.Close(); //关闭进程
  814. myProcess.Dispose(); //释放资源
  815. #region 进程是否已经释放
  816. bool IsRunning = true;
  817. while (IsRunning)
  818. {
  819. IsRunning = false;
  820. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  821. foreach (Process KillProcess in ProcessArray)
  822. {
  823. IsRunning = true;
  824. Thread.Sleep(100);
  825. }
  826. }
  827. #endregion 进程是否已经释放
  828. myProcess = null;
  829. Thread.Sleep(200);
  830. FileToolsCommon.DeleteFile(VideoPathName);
  831. return true;
  832. }
  833. catch (Exception ex)
  834. {
  835. LogHelper.WriteErrLog("【视频转码】(VideoTranscode)视频转码失败," + ex.Message, ex);
  836. return false;
  837. }
  838. }
  839. public bool VideoAudioMerge(string VideoPathName, string mp3path,string VideoSavePathName, int Width, int Height)
  840. {
  841. while (myProcess != null)
  842. {
  843. Thread.Sleep(100);
  844. }
  845. Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
  846. foreach (Process KillProcess in KillProcessArray)
  847. {
  848. KillProcess.Kill();
  849. }
  850. try
  851. {
  852. myProcess = new Process();
  853. LogPath = CreateffmpegLog();
  854. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  855. myProcess.StartInfo.Arguments = "-i " + VideoPathName + " -i " + mp3path + " -acodec copy -vcodec libx264 " + "-s " + Width + "*" + Height + " " + VideoSavePathName;
  856. if (OutputVideoLog)
  857. {
  858. LogHelper.WriteInfoLog("【视频转码】:" + myProcess.StartInfo.Arguments);
  859. }
  860. FileToolsCommon.AppendText(LogPath, "【视频转码】:" + myProcess.StartInfo.Arguments + "\r\n");
  861. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  862. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  863. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  864. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  865. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  866. myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
  867. myProcess.Start(); //启动线程
  868. myProcess.BeginErrorReadLine(); //开始异步读取
  869. myProcess.WaitForExit(); //阻塞等待进程结束
  870. myProcess.Close(); //关闭进程
  871. myProcess.Dispose(); //释放资源
  872. #region 进程是否已经释放
  873. bool IsRunning = true;
  874. while (IsRunning)
  875. {
  876. IsRunning = false;
  877. Process[] ProcessArray = Process.GetProcessesByName("ffmpeg");
  878. foreach (Process KillProcess in ProcessArray)
  879. {
  880. IsRunning = true;
  881. Thread.Sleep(100);
  882. }
  883. }
  884. #endregion 进程是否已经释放
  885. myProcess = null;
  886. Thread.Sleep(200);
  887. FileToolsCommon.DeleteFile(VideoPathName);
  888. return true;
  889. }
  890. catch (Exception ex)
  891. {
  892. LogHelper.WriteErrLog("【视频转码】(VideoTranscode)视频转码失败," + ex.Message, ex);
  893. return false;
  894. }
  895. }
  896. /// <summary>
  897. /// 创建日志文件
  898. /// </summary>
  899. /// <returns></returns>
  900. private string CreateffmpegLog()
  901. {
  902. string LogFileName = DateTime.Now.ToString("yyyyMMdd");
  903. string LogFilePath = FileToolsCommon.GetFileAbsolutePath("/Log/FFMpegLog/");
  904. FileToolsCommon.CreateDirectory(LogFilePath);
  905. string LogName = LogFilePath + LogFileName + ".log";
  906. try
  907. {
  908. if (!FileToolsCommon.IsExistFile(LogName))
  909. {
  910. FileToolsCommon.CreateFile(LogName);
  911. FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
  912. "****************************************************************************************************\r\n");
  913. return LogName;
  914. }
  915. else
  916. {
  917. int num = 0;
  918. while (FileToolsCommon.GetFileSizeByMB(LogName) > 2)
  919. {
  920. num++;
  921. LogName = LogFilePath + LogFileName + "_" + num + ".log";
  922. FileToolsCommon.CreateFile(LogName);
  923. }
  924. FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
  925. "****************************************************************************************************\r\n");
  926. return LogName;
  927. }
  928. }
  929. catch (Exception)
  930. {
  931. return LogName;
  932. }
  933. }
  934. /// <summary>
  935. /// 输出结果
  936. /// </summary>
  937. /// <param name="sendProcess"></param>
  938. /// <param name="output"></param>
  939. private void Output(object sendProcess, DataReceivedEventArgs output)
  940. {
  941. if (!string.IsNullOrEmpty(output.Data))
  942. {
  943. FileToolsCommon.AppendText(LogPath, "【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "】:");
  944. FileToolsCommon.AppendText(LogPath, output.Data + "\r\n");
  945. }
  946. }
  947. #region 麦克风声卡检测
  948. #region 获取麦克风
  949. private bool IsMicrophone = false;
  950. /// <summary>
  951. /// 使用FFmpeg获取的麦克风名
  952. /// </summary>
  953. private string MicrophoneNameInfo = "";
  954. /// <summary>
  955. /// 获取麦克风名称
  956. /// </summary>
  957. /// <returns></returns>
  958. public string GetMicrophoneName()
  959. {
  960. return GetAudioInDevices();
  961. //string FullName = GetInDeviceFull();
  962. //if(string.IsNullOrWhiteSpace(MicrophoneNameInfo))
  963. //{
  964. // return FullName;
  965. //}
  966. ////byte[] bufferASCII = Encoding.Default.GetBytes(MicrophoneNameInfo);
  967. ////string str = Encoding.UTF8.GetString(bufferASCII);
  968. ////str = str.Replace("?", " ");
  969. ////int num = str.Length;
  970. ////int num1 = FullName.Length;
  971. //if (FullName.Contains("(") || FullName.Contains("("))
  972. //{
  973. // string EName = FullName.Substring(FullName.IndexOf("(")+1);
  974. // if(string.IsNullOrEmpty(EName))
  975. // {
  976. // EName = FullName.Substring(FullName.IndexOf("(") + 1);
  977. // EName = EName.Substring(0, EName.LastIndexOf(")"));
  978. // }
  979. // else
  980. // {
  981. // //EName = EName.Substring(0, EName.LastIndexOf(")"));
  982. // }
  983. // if(MicrophoneNameInfo.Contains(EName))
  984. // {
  985. // return FullName;
  986. // }
  987. // else
  988. // {
  989. // return GetInDeviceName();
  990. // }
  991. //}
  992. //else
  993. //{
  994. // return FullName;
  995. //}
  996. }
  997. /// <summary>
  998. /// 获取麦克风列表
  999. /// </summary>
  1000. /// <returns></returns>
  1001. public List<string> GetMicrophoneNameList()
  1002. {
  1003. return GetAudioInDevicesList();
  1004. }
  1005. /// <summary>
  1006. /// 使用FFmpeg获取设备名称--待定
  1007. /// </summary>
  1008. public void GetMToFFmpeg()
  1009. {
  1010. //return;
  1011. new Thread(new ThreadStart(new Action(() =>
  1012. {
  1013. try
  1014. {
  1015. while (myProcess != null)
  1016. {
  1017. Thread.Sleep(100);
  1018. }
  1019. myProcess = new Process();
  1020. LogPath = CreateffmpegLog();
  1021. myProcess.StartInfo.FileName = ffmpegPath; //ffmpeg.exe的绝对路径
  1022. myProcess.StartInfo.Arguments = " -list_devices true -f dshow -i dummy";
  1023. if (OutputVideoLog)
  1024. {
  1025. LogHelper.WriteInfoLog("【获取设备信息】:" + myProcess.StartInfo.Arguments);
  1026. }
  1027. FileToolsCommon.AppendText(LogPath, "【获取设备信息】:" + myProcess.StartInfo.Arguments + "\r\n");
  1028. myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
  1029. myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
  1030. myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
  1031. myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
  1032. //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
  1033. myProcess.ErrorDataReceived += GetDevInfoData;
  1034. myProcess.Start(); //启动线程
  1035. myProcess.BeginErrorReadLine(); //开始异步读取
  1036. myProcess.WaitForExit(); //阻塞等待进程结束
  1037. myProcess.Close(); //关闭进程
  1038. myProcess.Dispose(); //释放资源
  1039. myProcess = null;
  1040. }
  1041. catch (Exception ex)
  1042. {
  1043. LogHelper.WriteErrLog("【获取设备信息】(GetMToFFmpeg)信息获取失败:" + ex.Message, ex);
  1044. }
  1045. }))).Start();
  1046. }
  1047. /// <summary>
  1048. /// 使用FFmpeg获取设备名称--待定
  1049. /// </summary>
  1050. /// <param name="sender"></param>
  1051. /// <param name="e"></param>
  1052. private void GetDevInfoData(object sender, DataReceivedEventArgs e)
  1053. {
  1054. if (!string.IsNullOrEmpty(e.Data))
  1055. {
  1056. if (IsMicrophone)
  1057. {
  1058. try
  1059. {
  1060. MicrophoneNameInfo = e.Data;
  1061. MicrophoneNameInfo = MicrophoneNameInfo.Substring(MicrophoneNameInfo.IndexOf("]") + 1);
  1062. MicrophoneNameInfo = MicrophoneNameInfo.Replace("\"", "");
  1063. MicrophoneNameInfo = MicrophoneNameInfo.Trim();
  1064. #region 测试
  1065. //byte[] bufferASCII = Encoding.Default.GetBytes(MicrophoneNameInfo);
  1066. //MicrophoneNameInfo = Encoding.UTF8.GetString(bufferASCII); // 统一使用UTF-8
  1067. ////System.Text.Encoding GB2312 = System.Text.Encoding.GetEncoding("GB2312");
  1068. ////byte[] gb = GB2312.GetBytes(MicrophoneNameInfo);
  1069. ////MicrophoneNameInfo = Encoding.UTF8.GetString(gb);
  1070. #endregion 测试
  1071. IsMicrophone = false;
  1072. FileToolsCommon.AppendText(LogPath, e.Data);
  1073. //FileToolsCommon.AppendText(LogPath, "\r\n***************************************************\r\n");
  1074. }
  1075. catch (Exception ex)
  1076. {
  1077. LogHelper.WriteErrLog("【获取设备信息】(GetDevInfoData)信息获取失败:" + ex.Message, ex);
  1078. }
  1079. }
  1080. else
  1081. {
  1082. if (e.Data.Contains("DirectShow audio devices"))
  1083. {
  1084. //FileToolsCommon.AppendText(LogPath, "\r\n***************************************************\r\n");
  1085. IsMicrophone = true;
  1086. }
  1087. FileToolsCommon.AppendText(LogPath, e.Data);
  1088. FileToolsCommon.AppendText(LogPath, "\r\n");
  1089. }
  1090. }
  1091. }
  1092. /// <summary>
  1093. /// AForge获取麦克风
  1094. /// </summary>
  1095. /// <returns></returns>
  1096. public static string GetAudioInDevices()
  1097. {
  1098. List<string> devicesList = new List<string>();
  1099. try
  1100. {
  1101. FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.AudioInputDevice);
  1102. foreach (FilterInfo device in videoDevices)
  1103. {
  1104. devicesList.Add(device.Name);
  1105. }
  1106. }
  1107. catch (ApplicationException)
  1108. {
  1109. //Console.WriteLine("No local capture devices");
  1110. }
  1111. if (devicesList.Count > 1)
  1112. {
  1113. return devicesList[1];
  1114. }
  1115. else
  1116. {
  1117. return "";
  1118. }
  1119. }
  1120. /// <summary>
  1121. /// AForge获取麦克风列表
  1122. /// </summary>
  1123. /// <returns></returns>
  1124. public static List<string> GetAudioInDevicesList()
  1125. {
  1126. List<string> devicesList = new List<string>();
  1127. try
  1128. {
  1129. FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.AudioInputDevice);
  1130. foreach (FilterInfo device in videoDevices)
  1131. {
  1132. if (device.Name == "virtual-audio-capturer")
  1133. {
  1134. continue;
  1135. }
  1136. devicesList.Add(device.Name);
  1137. }
  1138. }
  1139. catch (ApplicationException)
  1140. {
  1141. //Console.WriteLine("No local capture devices");
  1142. }
  1143. return devicesList;
  1144. }
  1145. /// <summary>
  1146. /// 获取声音输入设备名称 不完整
  1147. /// </summary>
  1148. /// <returns></returns>
  1149. public static string GetInDeviceName()
  1150. {
  1151. List<WaveInCapabilities> devices = new List<WaveInCapabilities>();
  1152. int waveInDevices = WaveIn.DeviceCount;
  1153. for (int i = 0; i < waveInDevices; i++)
  1154. {
  1155. devices.Add(WaveIn.GetCapabilities(i));
  1156. }
  1157. List<string> devs = new List<string>();
  1158. devs = devices.Select(item => item.ProductName).ToList();
  1159. if (devs.Count > 0)
  1160. {
  1161. byte[] buffer = Encoding.UTF8.GetBytes(devs[0]);
  1162. string MicrophoneName = Encoding.UTF8.GetString(buffer); // 统一使用UTF-8
  1163. return MicrophoneName;
  1164. }
  1165. else
  1166. {
  1167. return "";
  1168. }
  1169. }
  1170. /// <summary>
  1171. /// 获取声音输入设备完整名称
  1172. /// </summary>
  1173. /// <returns></returns>
  1174. public static string GetInDeviceFull()
  1175. {
  1176. List<string> devices = new List<string>();
  1177. MMDeviceEnumerator enumberator = new MMDeviceEnumerator();
  1178. MMDeviceCollection deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  1179. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  1180. {
  1181. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  1182. foreach (MMDevice device in deviceCollection)
  1183. {
  1184. try
  1185. {
  1186. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  1187. {
  1188. devices.Add(device.FriendlyName);
  1189. break;
  1190. }
  1191. }
  1192. catch (Exception)
  1193. {
  1194. continue;
  1195. }
  1196. }
  1197. }
  1198. if (devices.Count > 0)
  1199. {
  1200. byte[] buffer = Encoding.UTF8.GetBytes(devices[0]);
  1201. string MicrophoneName = Encoding.UTF8.GetString(buffer); // 统一使用UTF-8
  1202. return MicrophoneName;
  1203. }
  1204. else
  1205. {
  1206. return "";
  1207. }
  1208. }
  1209. /// <summary>
  1210. /// 获取声音输入设备完整名称列表
  1211. /// </summary>
  1212. /// <returns></returns>
  1213. public List<string> GetInDeviceListFull()
  1214. {
  1215. List<string> devices = new List<string>();
  1216. MMDeviceEnumerator enumberator = new MMDeviceEnumerator();
  1217. MMDeviceCollection deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  1218. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  1219. {
  1220. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  1221. foreach (MMDevice device in deviceCollection)
  1222. {
  1223. try
  1224. {
  1225. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  1226. {
  1227. devices.Add(device.FriendlyName);
  1228. break;
  1229. }
  1230. }
  1231. catch (Exception)
  1232. {
  1233. continue;
  1234. }
  1235. }
  1236. }
  1237. return devices;
  1238. }
  1239. /// <summary>
  1240. /// 获取麦克风---废弃
  1241. /// </summary>
  1242. private string GetMicrophone()
  1243. {
  1244. List<string> devs = new List<string>();
  1245. MMDeviceEnumerator enumberator = new MMDeviceEnumerator();
  1246. MMDeviceCollection deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
  1247. for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
  1248. {
  1249. WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
  1250. foreach (MMDevice device in deviceCollection)
  1251. {
  1252. try
  1253. {
  1254. if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
  1255. {
  1256. devs.Add(device.FriendlyName);
  1257. break;
  1258. }
  1259. }
  1260. catch (Exception)
  1261. {
  1262. }
  1263. }
  1264. }
  1265. if (devs.Count > 0)
  1266. {
  1267. return devs[0];
  1268. }
  1269. else
  1270. {
  1271. return "";
  1272. }
  1273. }
  1274. #endregion 获取麦克风
  1275. #region 录音
  1276. /// <summary>
  1277. /// 开始录制麦克风
  1278. /// </summary>
  1279. public bool StartAudio(string audioFile, string DeviceName = "")
  1280. {
  1281. try
  1282. {
  1283. int deviceIndex = 0;
  1284. waveIn = new WaveInEvent();
  1285. List<string> InDeviceList = GetInDeviceListFull();
  1286. if (InDeviceList.Exists(x => DeviceName.Contains(x)))
  1287. {
  1288. deviceIndex = InDeviceList.FindIndex(x => DeviceName.Contains(x));
  1289. }
  1290. waveIn.DeviceNumber = deviceIndex;
  1291. //waveIn.DeviceNumber = 1;
  1292. //生成音频文件的对象
  1293. WaveFileWriter writer = new WaveFileWriter(audioFile, waveIn.WaveFormat);
  1294. //开始录音,写数据
  1295. waveIn.DataAvailable += (s, a) =>
  1296. {
  1297. writer.Write(a.Buffer, 0, a.BytesRecorded);
  1298. };
  1299. return true;
  1300. }
  1301. catch (Exception ex)
  1302. {
  1303. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  1304. return false;
  1305. }
  1306. }
  1307. //public bool StopAudio()
  1308. //{
  1309. // try
  1310. // {
  1311. // //结束录音
  1312. // waveIn.RecordingStopped += (s, a) =>
  1313. // {
  1314. // writer.Dispose();
  1315. // writer = null;
  1316. // waveIn.Dispose();
  1317. // waveIn = null;
  1318. // try
  1319. // {
  1320. // FileToolsCommon.DeleteFile(audioFile);
  1321. // }
  1322. // catch (Exception)
  1323. // {
  1324. // }
  1325. // };
  1326. // waveIn.StartRecording();
  1327. // }
  1328. // catch (Exception ex)
  1329. // {
  1330. // throw;
  1331. // }
  1332. //}
  1333. #endregion 录音
  1334. #region 检测是否可用
  1335. /// <summary>
  1336. /// 录制麦克风的声音
  1337. /// </summary>
  1338. private WaveInEvent waveIn = null; //new WaveInEvent();
  1339. /// <summary>
  1340. /// 开始录制麦克风
  1341. /// </summary>
  1342. public bool StartRecordAudio(string audioFile, string DeviceName = "", bool IsStopDelFile = true)
  1343. {
  1344. try
  1345. {
  1346. int deviceIndex = 0;
  1347. waveIn = new WaveInEvent();
  1348. List<string> InDeviceList = GetInDeviceListFull();
  1349. if (InDeviceList.Exists(x => DeviceName.Contains(x)))
  1350. {
  1351. deviceIndex = InDeviceList.FindIndex(x => DeviceName.Contains(x));
  1352. }
  1353. waveIn.DeviceNumber = deviceIndex;
  1354. //waveIn.DeviceNumber = 1;
  1355. //生成音频文件的对象
  1356. WaveFileWriter writer = new WaveFileWriter(audioFile, waveIn.WaveFormat);
  1357. //开始录音,写数据
  1358. waveIn.DataAvailable += (s, a) =>
  1359. {
  1360. writer.Write(a.Buffer, 0, a.BytesRecorded);
  1361. };
  1362. //结束录音
  1363. waveIn.RecordingStopped += (s, a) =>
  1364. {
  1365. writer.Dispose();
  1366. writer = null;
  1367. waveIn.Dispose();
  1368. waveIn = null;
  1369. try
  1370. {
  1371. if (IsStopDelFile)
  1372. {
  1373. FileToolsCommon.DeleteFile(audioFile);
  1374. }
  1375. }
  1376. catch (Exception)
  1377. {
  1378. }
  1379. };
  1380. waveIn.StartRecording();
  1381. return true;
  1382. }
  1383. catch (Exception ex)
  1384. {
  1385. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  1386. return false;
  1387. }
  1388. }
  1389. /// <summary>
  1390. /// 结束录制音频
  1391. /// </summary>
  1392. /// <param name="type">1麦克风 2扬声器</param>
  1393. public void StopRecordAudio(int type)
  1394. {
  1395. try
  1396. {
  1397. if (type == 1)
  1398. {
  1399. if (waveIn != null)
  1400. {
  1401. try
  1402. {
  1403. waveIn.StopRecording();
  1404. }
  1405. catch (Exception)
  1406. {
  1407. waveIn = null;
  1408. }
  1409. }
  1410. }
  1411. else if (type == 2)
  1412. {
  1413. if (capture != null)
  1414. {
  1415. try
  1416. {
  1417. capture.StopRecording();
  1418. }
  1419. catch (Exception)
  1420. {
  1421. capture = null;
  1422. }
  1423. }
  1424. }
  1425. }
  1426. catch (Exception ex)
  1427. {
  1428. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  1429. }
  1430. }
  1431. /// <summary>
  1432. /// 录制扬声器的声音
  1433. /// </summary>
  1434. private WasapiLoopbackCapture capture = null; //new WasapiLoopbackCapture();
  1435. /// <summary>
  1436. /// 开始录制扬声器
  1437. /// </summary>
  1438. public bool StartRecordSpeakerAudio(string audioFile)
  1439. {
  1440. try
  1441. {
  1442. capture = new WasapiLoopbackCapture();
  1443. //生成音频文件的对象
  1444. WaveFileWriter writer = new WaveFileWriter(audioFile, capture.WaveFormat);
  1445. capture.DataAvailable += (s, a) =>
  1446. {
  1447. writer.Write(a.Buffer, 0, a.BytesRecorded);
  1448. };
  1449. //结束录音
  1450. capture.RecordingStopped += (s, a) =>
  1451. {
  1452. writer.Dispose();
  1453. writer = null;
  1454. capture.Dispose();
  1455. capture = null;
  1456. try
  1457. {
  1458. FileToolsCommon.DeleteFile(audioFile);
  1459. }
  1460. catch (Exception)
  1461. {
  1462. }
  1463. };
  1464. capture.StartRecording();
  1465. return true;
  1466. }
  1467. catch (Exception ex)
  1468. {
  1469. LogHelper.WriteErrLog("【麦克风】麦克风不可用:" + ex.Message, ex);
  1470. return false;
  1471. }
  1472. }
  1473. #endregion 检测是否可用
  1474. #endregion 麦克风声卡检测
  1475. }
  1476. }