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

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