Created FFmpegCLIHelper

ffmpeg.exe quits as soon as it starts!
This commit is contained in:
McoreD 2014-05-08 17:06:53 +08:00
parent 58cd9990b4
commit ca6c61fe8e
14 changed files with 266 additions and 70 deletions

View file

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace HelpersLib
{
public abstract class ExternalCLIManager : IDisposable
{
protected Process CLI = new Process();
public StringBuilder Output = new StringBuilder();
public StringBuilder Errors = new StringBuilder();
public delegate void ErrorDataReceivedHandler();
public event ErrorDataReceivedHandler ErrorDataReceived;
public virtual void Run(string cliPath, string args = "")
{
ProcessStartInfo psi = new ProcessStartInfo(cliPath);
psi.UseShellExecute = false;
psi.ErrorDialog = false;
psi.RedirectStandardInput = true;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.Arguments = args;
psi.WindowStyle = ProcessWindowStyle.Normal;
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
CLI.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
Output.AppendLine(e.Data);
}
};
CLI.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
Errors.AppendLine(e.Data);
}
};
CLI.StartInfo = psi;
CLI.Start();
CLI.BeginOutputReadLine();
CLI.WaitForExit();
}
}
public void SendCommand(string command)
{
if (CLI != null)
{
CLI.StandardInput.WriteLine(command);
}
}
public virtual void Close()
{
CLI.CloseMainWindow();
}
public virtual void OnErrorDataReceived()
{
if (ErrorDataReceived != null)
{
ErrorDataReceived();
}
}
public void Dispose()
{
if (CLI != null)
{
CLI.Dispose();
}
}
}
}

View file

@ -87,6 +87,7 @@
<Compile Include="ConvolutionMatrix.cs" />
<Compile Include="ConvolutionMatrixManager.cs" />
<Compile Include="EncoderProgram.cs" />
<Compile Include="CLI\ExternalCLIManager.cs" />
<Compile Include="FontSafe.cs" />
<Compile Include="Helpers\MathHelpers.cs" />
<Compile Include="MimeTypes.cs" />

View file

@ -0,0 +1,13 @@
using HelpersLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ScreenCaptureLib
{
public abstract class CLIEncoder : ExternalCLIManager
{
public abstract void Record();
}
}

View file

@ -63,9 +63,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CLIEncoder.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Screencast\FFmpegOptions.cs" />
<Compile Include="Screencast\ScreencastOptions.cs" />
<Compile Include="Screencast\FFmpegCLIHelper.cs" />
<Compile Include="Screencast\AVIOptions.cs" />
<Compile Include="Screencast\AviWriter.cs" />
<Compile Include="Screencast\FFmpegCache.cs" />

View file

@ -32,10 +32,19 @@ You should have received a copy of the GNU General Public License
namespace ScreenCaptureLib
{
public class AVIOptions : ScreencastOptions
public class AVIOptions
{
public string OutputPath;
public int FPS;
public Size Size;
// AVI
public AVICOMPRESSOPTIONS CompressOptions;
public bool ShowOptionsDialog;
public IntPtr ParentWindow;
// FFmpeg
public string CLIPath { get; set; }
public int BitRate { get; set; }
}
}

View file

@ -0,0 +1,78 @@
#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
Copyright (C) 2008-2014 ShareX Developers
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at <http://www.gnu.org/licenses/>.
*/
#endregion License Information (GPL v3)
using HelpersLib;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ScreenCaptureLib
{
public class FFmpegCLIHelper : CLIEncoder
{
public AVIOptions Options { get; private set; }
public FFmpegCLIHelper(AVIOptions options)
{
Options = options;
if (string.IsNullOrEmpty(options.CLIPath))
{
options.CLIPath = Path.Combine(Application.StartupPath, "ffmpeg.exe");
}
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);
this.ErrorDataReceived += Close;
}
public override void Record()
{
StringBuilder args = new StringBuilder();
args.Append("-f dshow -i video=\"screen-capture-recorder\"");
if (Options.FPS > 0)
{
args.Append(string.Format(" -r {0}", Options.FPS));
}
args.Append(string.Format(" -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -y \"{0}\"", Options.OutputPath));
Run(Options.CLIPath, args.ToString());
}
public void ListDevices()
{
SendCommand("-list_devices true -f dshow -i dummy");
}
public override void Close()
{
CLI.StandardInput.WriteLine("q");
}
}
}

View file

@ -43,7 +43,7 @@ public class FFmpegCache : ImageCache
private VideoFileWriter ffmpegWriter;
public FFmpegCache(FFmpegOptions options)
public FFmpegCache(AVIOptions options)
{
Options = options;
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);

View file

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ScreenCaptureLib
{
public class FFmpegOptions : ScreencastOptions
{
public int BitRate { get; set; }
}
}

View file

@ -37,7 +37,7 @@ namespace ScreenCaptureLib
{
public partial class FFmpegOptionsForm : Form
{
public FFmpegOptionsForm(FFmpegOptions options)
public FFmpegOptionsForm(AVIOptions options)
{
InitializeComponent();
this.Text = string.Format("{0} - FFmpeg Options", Application.ProductName);

View file

@ -37,7 +37,7 @@ namespace ScreenCaptureLib
public abstract class ImageCache : IDisposable
{
public bool IsWorking { get; protected set; }
public ScreencastOptions Options { get; set; }
public AVIOptions Options { get; set; }
protected Task task;
protected BlockingCollection<Image> imageQueue;

View file

@ -88,7 +88,7 @@ private set
public ScreenRecordOutput OutputType { get; private set; }
public ScreencastOptions Options { get; set; }
public AVIOptions Options { get; set; }
public delegate void ProgressEventHandler(int progress);
@ -98,6 +98,7 @@ private set
private float durationSeconds;
private Rectangle captureRectangle;
private ImageCache imgCache;
private FFmpegCLIHelper ffMpegCli;
private bool stopRequest;
public ScreenRecorder(int fps, float durationSeconds, Rectangle captureRectangle, string cachePath, ScreenRecordOutput outputType, AVICOMPRESSOPTIONS compressOptions)
@ -113,27 +114,24 @@ public ScreenRecorder(int fps, float durationSeconds, Rectangle captureRectangle
CachePath = cachePath;
OutputType = outputType;
Options = new ScreencastOptions()
Options = new AVIOptions()
{
FPS = FPS,
OutputPath = CachePath,
Size = CaptureRectangle.Size
Size = CaptureRectangle.Size,
CompressOptions = compressOptions
};
switch (OutputType)
{
case ScreenRecordOutput.AVI:
AVIOptions aviOptions = Options as AVIOptions;
aviOptions.CompressOptions = compressOptions;
imgCache = new AVICache(aviOptions);
imgCache = new AVICache(Options);
break;
case ScreenRecordOutput.FFmpegNet:
FFmpegOptions ffMpegOptions = Options as FFmpegOptions;
ffMpegOptions.BitRate = 1000;
imgCache = new FFmpegCache(ffMpegOptions);
imgCache = new FFmpegCache(Options);
break;
case ScreenRecordOutput.GIF:
imgCache = new HardDiskCache(Options as AVIOptions);
imgCache = new HardDiskCache(Options);
break;
}
}
@ -151,44 +149,68 @@ public void StartRecording()
IsRecording = true;
stopRequest = false;
try
if (OutputType == ScreenRecordOutput.FFmpegCLI)
{
for (int i = 0; !stopRequest && (frameCount == 0 || i < frameCount); i++)
{
Stopwatch timer = Stopwatch.StartNew();
Image img = Screenshot.CaptureRectangle(CaptureRectangle);
//DebugHelper.WriteLine("Screen capture: " + (int)timer.ElapsedMilliseconds);
imgCache.AddImageAsync(img);
if (!stopRequest && (frameCount == 0 || i + 1 < frameCount))
{
int sleepTime = delay - (int)timer.ElapsedMilliseconds;
if (sleepTime > 0)
{
Thread.Sleep(sleepTime);
}
else if (sleepTime < 0)
{
// Need to handle FPS drops
}
}
}
RecordUsingFFmpegCLI();
}
finally
else
{
imgCache.Finish();
RecordUsingCache();
}
}
IsRecording = false;
}
private void RecordUsingFFmpegCLI()
{
ffMpegCli = new FFmpegCLIHelper(Options);
ffMpegCli.Record();
ffMpegCli.ListDevices();
}
private void RecordUsingCache()
{
try
{
for (int i = 0; !stopRequest && (frameCount == 0 || i < frameCount); i++)
{
Stopwatch timer = Stopwatch.StartNew();
Image img = Screenshot.CaptureRectangle(CaptureRectangle);
//DebugHelper.WriteLine("Screen capture: " + (int)timer.ElapsedMilliseconds);
imgCache.AddImageAsync(img);
if (!stopRequest && (frameCount == 0 || i + 1 < frameCount))
{
int sleepTime = delay - (int)timer.ElapsedMilliseconds;
if (sleepTime > 0)
{
Thread.Sleep(sleepTime);
}
else if (sleepTime < 0)
{
// Need to handle FPS drops
}
}
}
}
finally
{
imgCache.Finish();
}
}
public void StopRecording()
{
stopRequest = true;
if (ffMpegCli != null)
{
ffMpegCli.Close();
}
}
public void SaveAsGIF(string path, GIFQuality quality)

View file

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace ScreenCaptureLib
{
public class ScreencastOptions
{
public string OutputPath;
public int FPS;
public Size Size;
}
}

View file

@ -145,6 +145,10 @@ await TaskEx.Run(() =>
{
path = Path.Combine(TaskSettings.CaptureFolder, TaskHelpers.GetFilename(TaskSettings, "avi"));
}
else if (TaskSettings.CaptureSettings.ScreenRecordOutput == ScreenRecordOutput.FFmpegCLI)
{
path = Path.Combine(TaskSettings.CaptureFolder, TaskHelpers.GetFilename(TaskSettings, "mp4"));
}
else
{
path = Program.ScreenRecorderCacheFilePath;

View file

@ -279,7 +279,7 @@ public class TaskSettingsCapture
public ScreenRecordOutput ScreenRecordOutput = ScreenRecordOutput.GIF;
public AVICOMPRESSOPTIONS ScreenRecordCompressOptions = new AVICOMPRESSOPTIONS();
public FFmpegOptions FFmpegOptions = new FFmpegOptions();
public AVIOptions FFmpegOptions = new AVIOptions();
public int ScreenRecordFPS = 5;
public bool ScreenRecordFixedDuration = true;
public float ScreenRecordDuration = 3f;