Modular ScreencastOptions

This commit is contained in:
mcored 2014-05-08 21:28:46 +08:00
parent ca6c61fe8e
commit 5d4533523c
17 changed files with 126 additions and 68 deletions

View file

@ -10,7 +10,7 @@ namespace HelpersLib
{
public abstract class ExternalCLIManager : IDisposable
{
protected Process CLI = new Process();
private Process CLI = new Process();
public StringBuilder Output = new StringBuilder();
public StringBuilder Errors = new StringBuilder();
@ -18,7 +18,7 @@ public abstract class ExternalCLIManager : IDisposable
public delegate void ErrorDataReceivedHandler();
public event ErrorDataReceivedHandler ErrorDataReceived;
public virtual void Run(string cliPath, string args = "")
public virtual void Open(string cliPath)
{
ProcessStartInfo psi = new ProcessStartInfo(cliPath);
psi.UseShellExecute = false;
@ -26,7 +26,8 @@ public virtual void Run(string cliPath, string args = "")
psi.RedirectStandardInput = true;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.Arguments = args;
psi.WorkingDirectory = Path.GetDirectoryName(cliPath);
psi.WindowStyle = ProcessWindowStyle.Normal;
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
@ -58,9 +59,6 @@ public virtual void Run(string cliPath, string args = "")
CLI.StartInfo = psi;
CLI.Start();
CLI.BeginOutputReadLine();
CLI.WaitForExit();
}
}

View file

@ -44,4 +44,18 @@ public enum NodePosition
BottomLeft,
Left
}
public enum VideoCodec
{
Default = -1,
MPEG4 = 0,
WMV1 = 1,
WMV2 = 2,
MSMPEG4v2 = 3,
MSMPEG4v3 = 4,
H263P = 5,
FLV1 = 6,
MPEG2 = 7,
Raw = 8,
}
}

View file

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

View file

@ -35,7 +35,7 @@ public class AVICache : ImageCache
{
private AVIWriter aviWriter;
public AVICache(AVIOptions options)
public AVICache(ScreencastOptions options)
{
Options = options;
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);

View file

@ -32,19 +32,33 @@ You should have received a copy of the GNU General Public License
namespace ScreenCaptureLib
{
public class AVIOptions
public class ScreencastOptions
{
public string OutputPath;
public int FPS;
public Size Size;
// AVI
public AVICOMPRESSOPTIONS CompressOptions;
public bool ShowOptionsDialog;
public IntPtr ParentWindow;
// FFmpeg
public bool ShowAVIOptionsDialog;
public AVIOptions AVI = new AVIOptions();
public FFmpegOptions FFmpeg = new FFmpegOptions();
}
public class AVIOptions
{
public AVICOMPRESSOPTIONS CompressOptions;
}
public class FFmpegOptions
{
public string CLIPath { get; set; }
public VideoCodec VideoCodec { get; set; }
public int BitRate { get; set; }
public FFmpegOptions()
{
VideoCodec = VideoCodec.MPEG4;
}
}
}

View file

@ -89,14 +89,14 @@ public class AVIWriter : IDisposable
// dummy object to lock for synchronization
private readonly object sync = new object();
public AVIOptions Options { get; private set; }
public ScreencastOptions Options { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="AVIWriter"/> class.
/// </summary>
///
/// <remarks>Initializes Video for Windows library.</remarks>
public AVIWriter(AVIOptions options)
public AVIWriter(ScreencastOptions options)
{
NativeMethods.AVIFileInit();
Options = options;
@ -199,27 +199,27 @@ public void Open()
if (NativeMethods.AVIFileCreateStream(file, out stream, ref info) != 0)
throw new Exception("Failed creating stream.");
if (Options.CompressOptions.handler == 0)
if (Options.AVI.CompressOptions.handler == 0)
{
// describe compression options
Options.CompressOptions.handler = NativeMethods.mmioFOURCC("DIB ");
Options.AVI.CompressOptions.handler = NativeMethods.mmioFOURCC("DIB ");
}
if (Options.ShowOptionsDialog)
if (Options.ShowAVIOptionsDialog)
{
AVICOMPRESSOPTIONS options = new AVICOMPRESSOPTIONS();
options.handler = Options.CompressOptions.handler;
options.quality = Options.CompressOptions.quality;
options.handler = Options.AVI.CompressOptions.handler;
options.quality = Options.AVI.CompressOptions.quality;
options.flags = 8; // AVICOMPRESSF_VALID
int result = NativeMethods.AVISaveOptions(stream, ref options, Options.ParentWindow);
if (result == 1)
{
Options.CompressOptions = options;
Options.AVI.CompressOptions = options;
}
}
// create compressed stream
if (NativeMethods.AVIMakeCompressedStream(out streamCompressed, stream, ref Options.CompressOptions, IntPtr.Zero) != 0)
if (NativeMethods.AVIMakeCompressedStream(out streamCompressed, stream, ref Options.AVI.CompressOptions, IntPtr.Zero) != 0)
throw new Exception("Failed creating compressed stream.");
// describe frame format

View file

@ -36,15 +36,16 @@ namespace ScreenCaptureLib
{
public class FFmpegCLIHelper : CLIEncoder
{
public AVIOptions Options { get; private set; }
public string FileName = "ffmpeg.exe";
public ScreencastOptions Options { get; private set; }
public FFmpegCLIHelper(AVIOptions options)
public FFmpegCLIHelper(ScreencastOptions options)
{
Options = options;
if (string.IsNullOrEmpty(options.CLIPath))
if (string.IsNullOrEmpty(options.FFmpeg.CLIPath))
{
options.CLIPath = Path.Combine(Application.StartupPath, "ffmpeg.exe");
options.FFmpeg.CLIPath = Path.Combine(Application.StartupPath, FileName);
}
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);
@ -54,6 +55,8 @@ public FFmpegCLIHelper(AVIOptions options)
public override void Record()
{
Open(Options.FFmpeg.CLIPath);
StringBuilder args = new StringBuilder();
args.Append("-f dshow -i video=\"screen-capture-recorder\"");
if (Options.FPS > 0)
@ -62,7 +65,7 @@ public override void Record()
}
args.Append(string.Format(" -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -y \"{0}\"", Options.OutputPath));
Run(Options.CLIPath, args.ToString());
SendCommand(args.ToString());
}
public void ListDevices()
@ -72,7 +75,7 @@ public void ListDevices()
public override void Close()
{
CLI.StandardInput.WriteLine("q");
SendCommand("q");
}
}
}

View file

@ -43,12 +43,12 @@ public class FFmpegCache : ImageCache
private VideoFileWriter ffmpegWriter;
public FFmpegCache(AVIOptions options)
public FFmpegCache(ScreencastOptions options)
{
Options = options;
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);
ffmpegWriter = new VideoFileWriter();
ffmpegWriter.Open(options.OutputPath, options.Size.Width, options.Size.Height, options.FPS, AForge.Video.FFMPEG.VideoCodec.MPEG4);
ffmpegWriter.Open(options.OutputPath, options.Size.Width, options.Size.Height, options.FPS, (AForge.Video.FFMPEG.VideoCodec)options.FFmpeg.VideoCodec, options.FFmpeg.BitRate * 1000);
}
protected override void WriteFrame(Image img)

View file

@ -39,7 +39,7 @@ private void InitializeComponent()
//
// btnCancel
//
this.btnCancel.Location = new System.Drawing.Point(224, 40);
this.btnCancel.Location = new System.Drawing.Point(224, 44);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 10;
@ -49,7 +49,7 @@ private void InitializeComponent()
//
// btnOK
//
this.btnOK.Location = new System.Drawing.Point(224, 8);
this.btnOK.Location = new System.Drawing.Point(224, 12);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 9;
@ -61,15 +61,16 @@ private void InitializeComponent()
//
this.comboBoxCodecs.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxCodecs.FormattingEnabled = true;
this.comboBoxCodecs.Location = new System.Drawing.Point(56, 8);
this.comboBoxCodecs.Location = new System.Drawing.Point(72, 12);
this.comboBoxCodecs.Name = "comboBoxCodecs";
this.comboBoxCodecs.Size = new System.Drawing.Size(152, 21);
this.comboBoxCodecs.Size = new System.Drawing.Size(136, 21);
this.comboBoxCodecs.TabIndex = 11;
this.comboBoxCodecs.SelectedIndexChanged += new System.EventHandler(this.comboBoxCodecs_SelectedIndexChanged);
//
// lblCodec
//
this.lblCodec.AutoSize = true;
this.lblCodec.Location = new System.Drawing.Point(8, 8);
this.lblCodec.Location = new System.Drawing.Point(8, 16);
this.lblCodec.Name = "lblCodec";
this.lblCodec.Size = new System.Drawing.Size(38, 13);
this.lblCodec.TabIndex = 12;
@ -77,25 +78,31 @@ private void InitializeComponent()
//
// nudBitrate
//
this.nudBitrate.Location = new System.Drawing.Point(56, 40);
this.nudBitrate.Location = new System.Drawing.Point(72, 44);
this.nudBitrate.Maximum = new decimal(new int[] {
9000,
0,
0,
0});
this.nudBitrate.Name = "nudBitrate";
this.nudBitrate.Size = new System.Drawing.Size(152, 20);
this.nudBitrate.Size = new System.Drawing.Size(136, 20);
this.nudBitrate.TabIndex = 13;
this.nudBitrate.ValueChanged += new System.EventHandler(this.nudBitrate_ValueChanged);
//
// lblBitrate
//
this.lblBitrate.AutoSize = true;
this.lblBitrate.Location = new System.Drawing.Point(8, 40);
this.lblBitrate.Location = new System.Drawing.Point(8, 48);
this.lblBitrate.Name = "lblBitrate";
this.lblBitrate.Size = new System.Drawing.Size(40, 13);
this.lblBitrate.Size = new System.Drawing.Size(56, 13);
this.lblBitrate.TabIndex = 14;
this.lblBitrate.Text = "Bit rate";
this.lblBitrate.Text = "Bit rate (K)";
//
// FFmpegOptionsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(304, 90);
this.ClientSize = new System.Drawing.Size(304, 89);
this.Controls.Add(this.lblBitrate);
this.Controls.Add(this.nudBitrate);
this.Controls.Add(this.lblCodec);

View file

@ -37,11 +37,19 @@ namespace ScreenCaptureLib
{
public partial class FFmpegOptionsForm : Form
{
public FFmpegOptionsForm(AVIOptions options)
private FFmpegOptions Options;
public FFmpegOptionsForm(FFmpegOptions options)
{
InitializeComponent();
Options = options;
this.Text = string.Format("{0} - FFmpeg Options", Application.ProductName);
this.Icon = ShareXResources.Icon;
comboBoxCodecs.Items.AddRange(Helpers.GetEnumDescriptions<VideoCodec>());
comboBoxCodecs.SelectedIndex = (int)options.VideoCodec;
nudBitrate.Value = Options.BitRate;
}
private void btnOK_Click(object sender, EventArgs e)
@ -55,5 +63,15 @@ private void btnCancel_Click(object sender, EventArgs e)
DialogResult = DialogResult.Cancel;
Close();
}
private void comboBoxCodecs_SelectedIndexChanged(object sender, EventArgs e)
{
Options.VideoCodec = (VideoCodec)comboBoxCodecs.SelectedIndex;
}
private void nudBitrate_ValueChanged(object sender, EventArgs e)
{
Options.BitRate = (int)nudBitrate.Value;
}
}
}

View file

@ -52,7 +52,7 @@ public int Count
private FileStream fsCache;
private List<LocationInfo> indexList;
public HardDiskCache(AVIOptions options)
public HardDiskCache(ScreencastOptions options)
{
Options = options;
Helpers.CreateDirectoryIfNotExist(Options.OutputPath);

View file

@ -37,7 +37,7 @@ namespace ScreenCaptureLib
public abstract class ImageCache : IDisposable
{
public bool IsWorking { get; protected set; }
public AVIOptions Options { get; set; }
public ScreencastOptions 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 AVIOptions Options { get; set; }
public ScreencastOptions Options { get; set; }
public delegate void ProgressEventHandler(int progress);
@ -101,26 +101,20 @@ private set
private FFmpegCLIHelper ffMpegCli;
private bool stopRequest;
public ScreenRecorder(int fps, float durationSeconds, Rectangle captureRectangle, string cachePath, ScreenRecordOutput outputType, AVICOMPRESSOPTIONS compressOptions)
public ScreenRecorder(ScreencastOptions options, float durationSeconds, Rectangle captureRectangle, ScreenRecordOutput outputType)
{
if (string.IsNullOrEmpty(cachePath))
if (string.IsNullOrEmpty(options.OutputPath))
{
throw new Exception("Screen recorder cache path is empty.");
}
FPS = fps;
FPS = options.FPS;
DurationSeconds = durationSeconds;
CaptureRectangle = captureRectangle;
CachePath = cachePath;
CachePath = options.OutputPath;
OutputType = outputType;
Options = new AVIOptions()
{
FPS = FPS,
OutputPath = CachePath,
Size = CaptureRectangle.Size,
CompressOptions = compressOptions
};
Options = options;
switch (OutputType)
{

View file

@ -156,8 +156,16 @@ await TaskEx.Run(() =>
float duration = TaskSettings.CaptureSettings.ScreenRecordFixedDuration ? TaskSettings.CaptureSettings.ScreenRecordDuration : 0;
screenRecorder = new ScreenRecorder(TaskSettings.CaptureSettings.ScreenRecordFPS, duration, CaptureRectangle, path,
TaskSettings.CaptureSettings.ScreenRecordOutput, TaskSettings.CaptureSettings.ScreenRecordCompressOptions);
ScreencastOptions options = new ScreencastOptions()
{
Size = CaptureRectangle.Size,
FPS = TaskSettings.CaptureSettings.ScreenRecordFPS,
OutputPath = path,
AVI = TaskSettings.CaptureSettings.AVIOptions,
FFmpeg = TaskSettings.CaptureSettings.FFmpegOptions
};
screenRecorder = new ScreenRecorder(options, duration, CaptureRectangle, TaskSettings.CaptureSettings.ScreenRecordOutput);
int delay = (int)(TaskSettings.CaptureSettings.ScreenRecordStartDelay * 1000);

View file

@ -646,7 +646,8 @@ private void cbCaptureTransparent_CheckedChanged(object sender, EventArgs e)
private void cbScreenRecorderOutput_SelectedIndexChanged(object sender, EventArgs e)
{
TaskSettings.CaptureSettings.ScreenRecordOutput = (ScreenRecordOutput)cbScreenRecorderOutput.SelectedIndex;
btnScreenRecorderOptions.Enabled = TaskSettings.CaptureSettings.ScreenRecordOutput != ScreenRecordOutput.GIF;
btnScreenRecorderOptions.Enabled = TaskSettings.CaptureSettings.ScreenRecordOutput == ScreenRecordOutput.AVI ||
TaskSettings.CaptureSettings.ScreenRecordOutput == ScreenRecordOutput.FFmpegNet;
btnEncoderConfig.Enabled = cboEncoder.Enabled = chkRunScreencastCLI.Enabled && chkRunScreencastCLI.Checked;
}
@ -655,13 +656,13 @@ private void btnScreenRecorderOptions_Click(object sender, EventArgs e)
switch (TaskSettings.CaptureSettings.ScreenRecordOutput)
{
case ScreenRecordOutput.AVI:
AVIOptions options = new AVIOptions
ScreencastOptions options = new ScreencastOptions
{
CompressOptions = TaskSettings.CaptureSettings.ScreenRecordCompressOptions,
AVI = TaskSettings.CaptureSettings.AVIOptions,
ShowAVIOptionsDialog = true,
FPS = 10,
OutputPath = Program.ScreenRecorderCacheFilePath,
ParentWindow = this.Handle,
ShowOptionsDialog = true,
Size = new Size(100, 100)
};
@ -670,13 +671,13 @@ private void btnScreenRecorderOptions_Click(object sender, EventArgs e)
// Ugly workaround for show AVI compression dialog
using (AVICache aviCache = new AVICache(options))
{
TaskSettings.CaptureSettings.ScreenRecordCompressOptions = options.CompressOptions;
TaskSettings.CaptureSettings.AVIOptions.CompressOptions = options.AVI.CompressOptions;
}
}
catch (Exception ex)
{
TaskSettings.CaptureSettings.ScreenRecordCompressOptions = new AVICOMPRESSOPTIONS();
MessageBox.Show(ex.ToString(), "ShareX", MessageBoxButtons.OK, MessageBoxIcon.Error);
TaskSettings.CaptureSettings.AVIOptions.CompressOptions = new AVICOMPRESSOPTIONS();
MessageBox.Show(ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
break;
case ScreenRecordOutput.FFmpegNet:

View file

@ -278,8 +278,9 @@ public class TaskSettingsCapture
#region Capture / Screen recorder
public ScreenRecordOutput ScreenRecordOutput = ScreenRecordOutput.GIF;
public AVICOMPRESSOPTIONS ScreenRecordCompressOptions = new AVICOMPRESSOPTIONS();
public AVIOptions FFmpegOptions = new AVIOptions();
public AVIOptions AVIOptions = new AVIOptions();
public FFmpegOptions FFmpegOptions = new FFmpegOptions();
public int ScreenRecordFPS = 5;
public bool ScreenRecordFixedDuration = true;
public float ScreenRecordDuration = 3f;