using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using VisioForge.Shared.NAudio.CoreAudioApi;
using VisioForge.Shared.NAudio.Wave;
namespace Common.system
{
///
/// ffmpeg帮助类
/// 需要安装\ffmpeg\bin\Setup Screen Capturer Recorder v0.12.10.exe
/// 本地调试需要配置环境变量 将ffmpeg.exe位置配置到环境变量的path中
///
public class FFMpeg
{
Process myProcess = null;
///
/// ffmpeg输出日志文件地址 每个文件2MB左右
///
string LogPath = "";
///
/// 录制屏幕
///
/// 文件存储路径
/// 视频类型
public void StartRecordingVideo(string PathName, string VideoType)
{
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
Debug.WriteLine(KillProcessArray.Length.ToString());
foreach (var KillProcess in KillProcessArray)
{
KillProcess.Kill();
}
myProcess = new Process();
LogPath = CreateffmpegLog();
string MicrophoneName = GetMicrophone();
myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
switch (VideoType.ToUpper())
{
case "MP4":
if (string.IsNullOrWhiteSpace(MicrophoneName))
{
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 avi " + PathName; //ffmpeg的参数
}
else
{
myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
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的参数
}
break;
case "AVI":
case "FLV":
if (string.IsNullOrWhiteSpace(MicrophoneName))
{
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 "+ VideoType.ToLower() + " " + PathName; //ffmpeg的参数
}
else
{
myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
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 " + VideoType.ToLower() + " " + PathName; //ffmpeg的参数
}
break;
default:
if (string.IsNullOrWhiteSpace(MicrophoneName))
{
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 avi " + PathName; //ffmpeg的参数
}
else
{
myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
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的参数
}
break;
}
myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
myProcess.Start();
myProcess.BeginErrorReadLine();
}
///
/// 录制音频
///
/// MP3音频位置
private void StartRecordingAudio(string Mp3Path)
{
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
Debug.WriteLine(KillProcessArray.Length.ToString());
foreach (var KillProcess in KillProcessArray)
{
KillProcess.Kill();
}
myProcess = new Process();
LogPath = CreateffmpegLog();
this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
string MicrophoneName = GetMicrophone();
if (string.IsNullOrWhiteSpace(MicrophoneName))
{
myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" " + Mp3Path;
}
else
{
myProcess.StartInfo.Arguments = "-f dshow -i audio=\"virtual-audio-capturer\" -f dshow -i audio=\"" +
MicrophoneName + "\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2 " + Mp3Path;
}
myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
myProcess.Start(); //启动线程
myProcess.BeginErrorReadLine(); //开始异步读取
}
///
/// 停止录制
///
public void StopFFmpeg()
{
//Thread.Sleep(3000);
if (myProcess == null)
return;
myProcess.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
myProcess.Close();//关闭进程
myProcess.Dispose();//释放资源
myProcess = null;
//myProcess.Kill();
}
///
/// 合成视频
///
/// 图片列表位置 命名为1.png 2.png
/// MP3音频位置
/// 视频保存位置
/// 每秒帧率
/// 视频宽度
/// 视频高度
/// 视频类型 MP4 FLV AVI
private void SynthesisVideo(string ImageListPath, string Mp3Path, string VideoSavePath, int Frequency, int VideoWidth, int VideoHeight, string VideoType)
{
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
Debug.WriteLine(KillProcessArray.Length.ToString());
foreach (var KillProcess in KillProcessArray)
{
KillProcess.Kill();
}
myProcess = new Process();
LogPath=CreateffmpegLog();
this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
switch (VideoType.ToUpper())
{
case "MP4":
myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
ImageListPath + @"%d.png -i " +
Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
VideoSavePath;
break;
case "AVI":
myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
ImageListPath + @"%d.png -i " +
Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -f AVI " +
VideoSavePath;
break;
case "FLV":
myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
ImageListPath + @"%d.png -i " +
Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -f FLV " +
VideoSavePath;
break;
default:
myProcess.StartInfo.Arguments = @"-y -r " + Frequency + " -i " +
ImageListPath + @"%d.png -i " +
Mp3Path + @" -s " + VideoWidth + "x" + VideoHeight + " -vcodec mpeg4 " +
VideoSavePath;
break;
}
myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
myProcess.Start(); //启动线程
myProcess.BeginErrorReadLine(); //开始异步读取
myProcess.WaitForExit(); //阻塞等待进程结束
myProcess.Close(); //关闭进程
myProcess.Dispose(); //释放资源
//生成视频后删除图片保存列表
FileToolsCommon.DeleteDirectory(ImageListPath);
}
///
/// 生成缩略图
///
/// 视频地址
/// 图片地址
void GenerateThumbnails(string VideoPath,string ImagePath)
{
Process[] KillProcessArray = Process.GetProcessesByName("ffmpeg");
Debug.WriteLine(KillProcessArray.Length.ToString());
foreach (var KillProcess in KillProcessArray)
{
KillProcess.Kill();
}
myProcess = new Process();
LogPath = CreateffmpegLog();
this.myProcess.StartInfo.FileName = FileToolsCommon.GetFileAbsolutePath(@"/ffmpeg/bin/ffmpeg.exe"); //ffmpeg.exe的绝对路径
//myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -s " + thubWidth + "*" + thubHeight + " -f image2 \"" + ImagePath + "\"";
myProcess.StartInfo.Arguments = "-i \"" + VideoPath + "\" -ss 1 -vframes 1 -r 1 -ac 1 -ab 2 -f image2 \"" + ImagePath + "\"";
myProcess.StartInfo.UseShellExecute = false; //不使用操作系统外壳程序启动
myProcess.StartInfo.RedirectStandardError = true; //重定向标准错误输出
myProcess.StartInfo.CreateNoWindow = true; //不显示程序窗口
myProcess.StartInfo.RedirectStandardInput = true; //用于模拟该进程控制台的输入
//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
myProcess.ErrorDataReceived += new DataReceivedEventHandler(Output);
myProcess.Start(); //启动线程
myProcess.BeginErrorReadLine(); //开始异步读取
myProcess.WaitForExit(); //阻塞等待进程结束
myProcess.Close(); //关闭进程
myProcess.Dispose(); //释放资源
}
///
/// 创建日志文件
///
///
string CreateffmpegLog()
{
string LogFileName = DateTime.Now.ToString("yyyyMMdd");
string LogFilePath = FileToolsCommon.GetFileAbsolutePath("/Log/FFMpegLog/");
FileToolsCommon.CreateDirectory(LogFilePath);
string LogName = LogFilePath + LogFileName + ".log";
try
{
if (!FileToolsCommon.IsExistFile(LogName))
{
FileToolsCommon.CreateFile(LogName);
FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
"****************************************************************************************************\r\n");
return LogName;
}
else
{
int num = 0;
while (FileToolsCommon.GetFileSizeByMB(LogName) > 2)
{
num++;
LogName = LogFilePath + LogFileName + "_" + num + ".log";
FileToolsCommon.CreateFile(LogName);
}
FileToolsCommon.AppendText(LogName, "\r\n****************************************************************************************************" +
"****************************************************************************************************\r\n");
return LogName;
}
}
catch (Exception)
{
return LogName;
}
}
///
/// 输出结果
///
///
///
private void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!String.IsNullOrEmpty(output.Data))
{
FileToolsCommon.AppendText(LogPath, output.Data);
}
}
//private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e)
//{
// //+= new DataReceivedEventHandler((s, message) => { Console.WriteLine(message.Data); })
// using (StreamWriter fs = new StreamWriter("E:\\项目\\测试\\Wpf测试\\bin\\Debug\\ffmpeg\\log.txt", true))
// {
// fs.WriteLine(e.Data);
// Debug.WriteLine(output.Data.ToString());
// }
//}
///
/// 获取麦克风
///
string GetMicrophone()
{
List devs = new List();
MMDeviceEnumerator enumberator = new MMDeviceEnumerator();
MMDeviceCollection deviceCollection = enumberator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
for (int waveInDevice = 0; waveInDevice < WaveIn.DeviceCount; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
foreach (MMDevice device in deviceCollection)
{
try
{
if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
{
devs.Add(device.FriendlyName);
break;
}
}
catch (Exception)
{
}
}
}
if (devs.Count > 0)
{
return devs[0];
}
else
{
return "";
}
}
}
}