星火直播PC
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

FFMpeg.cs 60KB

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