星火微课系统客户端
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.

FFMpeg.cs 55KB

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