星火微课系统客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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