mirror of
https://github.com/ShareX/ShareX.git
synced 2024-09-30 01:07:21 +13:00
Added two pass encoding support
This commit is contained in:
parent
64822000be
commit
41ed5a38e2
5 changed files with 111 additions and 80 deletions
|
@ -92,6 +92,15 @@ protected void OnRecordingStarted()
|
|||
}
|
||||
}
|
||||
|
||||
public bool EncodeVideo(string input, string output)
|
||||
{
|
||||
Options.IsRecording = false;
|
||||
Options.IsLossless = false;
|
||||
Options.InputPath = input;
|
||||
Options.OutputPath = output;
|
||||
return Run(Options.FFmpeg.FFmpegPath, Options.GetFFmpegCommands());
|
||||
}
|
||||
|
||||
public bool EncodeGIF(string input, string output, string tempFolder)
|
||||
{
|
||||
bool result;
|
||||
|
|
|
@ -109,7 +109,7 @@ public ScreenRecorder(ScreenRecordOutput outputType, ScreencastOptions options,
|
|||
throw new Exception("Screen recorder cache path is empty.");
|
||||
}
|
||||
|
||||
FPS = outputType == ScreenRecordOutput.GIF ? options.GIFFPS : options.ScreenRecordFPS;
|
||||
FPS = options.FPS;
|
||||
DurationSeconds = options.Duration;
|
||||
CaptureRectangle = captureRectangle;
|
||||
CachePath = options.OutputPath;
|
||||
|
@ -230,6 +230,14 @@ public void SaveAsGIF(string path, GIFQuality quality)
|
|||
}
|
||||
}
|
||||
|
||||
public bool FFmpegEncodeVideo(string input, string output)
|
||||
{
|
||||
Helpers.CreateDirectoryFromFilePath(output);
|
||||
bool result = ffmpegCli.EncodeVideo(input, output);
|
||||
//DebugHelper.WriteLine("Video encoding result:\nInput file size: {0}\nOutput file size: {1}", new FileInfo(input).Length.ToSizeString(), new FileInfo(output).Length.ToSizeString());
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool FFmpegEncodeAsGIF(string sourceFilePath, string targetFilePath, string tempFolder)
|
||||
{
|
||||
Helpers.CreateDirectoryFromFilePath(targetFilePath);
|
||||
|
|
|
@ -34,10 +34,11 @@ namespace ShareX.ScreenCaptureLib
|
|||
{
|
||||
public class ScreencastOptions
|
||||
{
|
||||
public ScreenRecordOutput OutputType { get; set; }
|
||||
public bool IsRecording { get; set; }
|
||||
public bool IsLossless { get; set; }
|
||||
public string InputPath { get; set; }
|
||||
public string OutputPath { get; set; }
|
||||
public int GIFFPS { get; set; }
|
||||
public int ScreenRecordFPS { get; set; }
|
||||
public int FPS { get; set; }
|
||||
public Rectangle CaptureArea { get; set; }
|
||||
public float Duration { get; set; }
|
||||
public bool DrawCursor { get; set; }
|
||||
|
@ -47,7 +48,7 @@ public string GetFFmpegCommands()
|
|||
{
|
||||
string commands;
|
||||
|
||||
if (!string.IsNullOrEmpty(FFmpeg.VideoSource) && FFmpeg.VideoSource.Equals("screen-capture-recorder", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (IsRecording && !string.IsNullOrEmpty(FFmpeg.VideoSource) && FFmpeg.VideoSource.Equals("screen-capture-recorder", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
// https://github.com/rdp/screen-capture-recorder-to-video-windows-free
|
||||
string registryPath = "Software\\screen-capture-recorder";
|
||||
|
@ -59,10 +60,10 @@ public string GetFFmpegCommands()
|
|||
RegistryHelpers.CreateRegistry(registryPath, "capture_mouse_default_1", DrawCursor ? 1 : 0);
|
||||
}
|
||||
|
||||
if (FFmpeg.UseCustomCommands && !string.IsNullOrEmpty(FFmpeg.CustomCommands))
|
||||
if (!IsLossless && FFmpeg.UseCustomCommands && !string.IsNullOrEmpty(FFmpeg.CustomCommands))
|
||||
{
|
||||
commands = FFmpeg.CustomCommands.
|
||||
Replace("$fps$", FFmpeg.VideoCodec == FFmpegVideoCodec.gif ? GIFFPS.ToString() : ScreenRecordFPS.ToString(), StringComparison.InvariantCultureIgnoreCase).
|
||||
Replace("$fps$", FPS.ToString(), StringComparison.InvariantCultureIgnoreCase).
|
||||
Replace("$area_x$", CaptureArea.X.ToString(), StringComparison.InvariantCultureIgnoreCase).
|
||||
Replace("$area_y$", CaptureArea.Y.ToString(), StringComparison.InvariantCultureIgnoreCase).
|
||||
Replace("$area_width$", CaptureArea.Width.ToString(), StringComparison.InvariantCultureIgnoreCase).
|
||||
|
@ -81,7 +82,7 @@ public string GetFFmpegCommands()
|
|||
|
||||
public string GetFFmpegArgs(bool isCustom = false)
|
||||
{
|
||||
if (!FFmpeg.IsVideoSourceSelected && !FFmpeg.IsAudioSourceSelected)
|
||||
if (IsRecording && !FFmpeg.IsVideoSourceSelected && !FFmpeg.IsAudioSourceSelected)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -98,41 +99,48 @@ public string GetFFmpegArgs(bool isCustom = false)
|
|||
}
|
||||
else
|
||||
{
|
||||
fps = FFmpeg.VideoCodec == FFmpegVideoCodec.gif ? GIFFPS.ToString() : ScreenRecordFPS.ToString();
|
||||
fps = FPS.ToString();
|
||||
}
|
||||
|
||||
if (FFmpeg.IsVideoSourceSelected)
|
||||
if (IsRecording)
|
||||
{
|
||||
if (FFmpeg.VideoSource.Equals(FFmpegHelper.SourceGDIGrab, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (FFmpeg.IsVideoSourceSelected)
|
||||
{
|
||||
// http://ffmpeg.org/ffmpeg-devices.html#gdigrab
|
||||
args.AppendFormat("-f gdigrab -framerate {0} -offset_x {1} -offset_y {2} -video_size {3}x{4} -draw_mouse {5} -i desktop ",
|
||||
fps, isCustom ? "$area_x$" : CaptureArea.X.ToString(), isCustom ? "$area_y$" : CaptureArea.Y.ToString(),
|
||||
isCustom ? "$area_width$" : CaptureArea.Width.ToString(), isCustom ? "$area_height$" : CaptureArea.Height.ToString(),
|
||||
isCustom ? "$cursor$" : DrawCursor ? "1" : "0");
|
||||
|
||||
if (FFmpeg.IsAudioSourceSelected)
|
||||
if (FFmpeg.VideoSource.Equals(FFmpegHelper.SourceGDIGrab, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
args.AppendFormat("-f dshow -i audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.AppendFormat("-f dshow -framerate {0} -i video=\"{1}\"", fps, FFmpeg.VideoSource);
|
||||
// http://ffmpeg.org/ffmpeg-devices.html#gdigrab
|
||||
args.AppendFormat("-f gdigrab -framerate {0} -offset_x {1} -offset_y {2} -video_size {3}x{4} -draw_mouse {5} -i desktop ",
|
||||
fps, isCustom ? "$area_x$" : CaptureArea.X.ToString(), isCustom ? "$area_y$" : CaptureArea.Y.ToString(),
|
||||
isCustom ? "$area_width$" : CaptureArea.Width.ToString(), isCustom ? "$area_height$" : CaptureArea.Height.ToString(),
|
||||
isCustom ? "$cursor$" : DrawCursor ? "1" : "0");
|
||||
|
||||
if (FFmpeg.IsAudioSourceSelected)
|
||||
{
|
||||
args.AppendFormat(":audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
if (FFmpeg.IsAudioSourceSelected)
|
||||
{
|
||||
args.AppendFormat("-f dshow -i audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Append(" ");
|
||||
args.AppendFormat("-f dshow -framerate {0} -i video=\"{1}\"", fps, FFmpeg.VideoSource);
|
||||
|
||||
if (FFmpeg.IsAudioSourceSelected)
|
||||
{
|
||||
args.AppendFormat(":audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (FFmpeg.IsAudioSourceSelected)
|
||||
{
|
||||
args.AppendFormat("-f dshow -i audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
}
|
||||
}
|
||||
else if (FFmpeg.IsAudioSourceSelected)
|
||||
else
|
||||
{
|
||||
args.AppendFormat("-f dshow -i audio=\"{0}\" ", FFmpeg.AudioSource);
|
||||
args.Append($"-i \"{InputPath}\" ");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(FFmpeg.UserArgs))
|
||||
|
@ -144,48 +152,51 @@ public string GetFFmpegArgs(bool isCustom = false)
|
|||
{
|
||||
string videoCodec;
|
||||
|
||||
switch (FFmpeg.VideoCodec)
|
||||
if (IsLossless)
|
||||
{
|
||||
default:
|
||||
videoCodec = FFmpeg.VideoCodec.ToString();
|
||||
break;
|
||||
case FFmpegVideoCodec.gif:
|
||||
videoCodec = FFmpegVideoCodec.libx264.ToString();
|
||||
break;
|
||||
videoCodec = FFmpegVideoCodec.libx264.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
videoCodec = FFmpeg.VideoCodec.ToString();
|
||||
}
|
||||
|
||||
args.AppendFormat("-c:v {0} ", videoCodec);
|
||||
args.AppendFormat("-r {0} ", fps); // output FPS
|
||||
|
||||
switch (FFmpeg.VideoCodec)
|
||||
if (IsLossless)
|
||||
{
|
||||
case FFmpegVideoCodec.libx264: // https://trac.ffmpeg.org/wiki/Encode/H.264
|
||||
case FFmpegVideoCodec.libx265: // https://trac.ffmpeg.org/wiki/Encode/H.265
|
||||
args.AppendFormat("-preset {0} ", FFmpeg.x264_Preset);
|
||||
args.AppendFormat("-tune {0} ", FFmpegTune.zerolatency);
|
||||
args.AppendFormat("-crf {0} ", FFmpeg.x264_CRF);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p"); // -pix_fmt yuv420p required otherwise can't stream in Chrome
|
||||
args.AppendFormat("-movflags {0} ", "+faststart"); // This will move some information to the beginning of your file and allow the video to begin playing before it is completely downloaded by the viewer
|
||||
break;
|
||||
case FFmpegVideoCodec.libvpx: // https://trac.ffmpeg.org/wiki/Encode/VP8
|
||||
args.AppendFormat("-deadline {0} ", "realtime");
|
||||
args.AppendFormat("-b:v {0}k ", FFmpeg.VPx_bitrate);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p"); // -pix_fmt yuv420p required otherwise causing issues in Chrome related to WebM transparency support
|
||||
break;
|
||||
case FFmpegVideoCodec.libxvid: // https://trac.ffmpeg.org/wiki/Encode/MPEG-4
|
||||
args.AppendFormat("-qscale:v {0} ", FFmpeg.XviD_qscale);
|
||||
break;
|
||||
case FFmpegVideoCodec.h264_nvenc: // https://trac.ffmpeg.org/wiki/HWAccelIntro#NVENC
|
||||
case FFmpegVideoCodec.hevc_nvenc:
|
||||
args.AppendFormat("-preset {0} ", FFmpeg.NVENC_preset);
|
||||
args.AppendFormat("-b:v {0}k ", FFmpeg.NVENC_bitrate);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p");
|
||||
break;
|
||||
case FFmpegVideoCodec.gif:
|
||||
args.AppendFormat("-preset {0} ", FFmpegPreset.ultrafast);
|
||||
args.AppendFormat("-tune {0} ", FFmpegTune.zerolatency);
|
||||
args.AppendFormat("-qp {0} ", 0);
|
||||
break;
|
||||
args.AppendFormat("-preset {0} ", FFmpegPreset.ultrafast);
|
||||
args.AppendFormat("-tune {0} ", FFmpegTune.zerolatency);
|
||||
args.AppendFormat("-qp {0} ", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (FFmpeg.VideoCodec)
|
||||
{
|
||||
case FFmpegVideoCodec.libx264: // https://trac.ffmpeg.org/wiki/Encode/H.264
|
||||
case FFmpegVideoCodec.libx265: // https://trac.ffmpeg.org/wiki/Encode/H.265
|
||||
args.AppendFormat("-preset {0} ", FFmpeg.x264_Preset);
|
||||
args.AppendFormat("-tune {0} ", FFmpegTune.zerolatency);
|
||||
args.AppendFormat("-crf {0} ", FFmpeg.x264_CRF);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p"); // -pix_fmt yuv420p required otherwise can't stream in Chrome
|
||||
args.AppendFormat("-movflags {0} ", "+faststart"); // This will move some information to the beginning of your file and allow the video to begin playing before it is completely downloaded by the viewer
|
||||
break;
|
||||
case FFmpegVideoCodec.libvpx: // https://trac.ffmpeg.org/wiki/Encode/VP8
|
||||
args.AppendFormat("-deadline {0} ", "realtime");
|
||||
args.AppendFormat("-b:v {0}k ", FFmpeg.VPx_bitrate);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p"); // -pix_fmt yuv420p required otherwise causing issues in Chrome related to WebM transparency support
|
||||
break;
|
||||
case FFmpegVideoCodec.libxvid: // https://trac.ffmpeg.org/wiki/Encode/MPEG-4
|
||||
args.AppendFormat("-qscale:v {0} ", FFmpeg.XviD_qscale);
|
||||
break;
|
||||
case FFmpegVideoCodec.h264_nvenc: // https://trac.ffmpeg.org/wiki/HWAccelIntro#NVENC
|
||||
case FFmpegVideoCodec.hevc_nvenc:
|
||||
args.AppendFormat("-preset {0} ", FFmpeg.NVENC_preset);
|
||||
args.AppendFormat("-b:v {0}k ", FFmpeg.NVENC_bitrate);
|
||||
args.AppendFormat("-pix_fmt {0} ", "yuv420p");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1050,9 +1050,9 @@ private void btnScreenRecorderFFmpegOptions_Click(object sender, EventArgs e)
|
|||
{
|
||||
ScreencastOptions options = new ScreencastOptions
|
||||
{
|
||||
IsRecording = true,
|
||||
FFmpeg = TaskSettings.CaptureSettings.FFmpegOptions,
|
||||
ScreenRecordFPS = TaskSettings.CaptureSettings.ScreenRecordFPS,
|
||||
GIFFPS = TaskSettings.CaptureSettings.GIFFPS,
|
||||
FPS = TaskSettings.CaptureSettings.ScreenRecordFPS,
|
||||
Duration = TaskSettings.CaptureSettings.ScreenRecordFixedDuration ? TaskSettings.CaptureSettings.ScreenRecordDuration : 0,
|
||||
OutputPath = "output.mp4",
|
||||
CaptureArea = Screen.PrimaryScreen.Bounds,
|
||||
|
|
|
@ -88,6 +88,7 @@ private static void StartRecording(ScreenRecordOutput outputType, TaskSettings t
|
|||
else
|
||||
{
|
||||
DebugHelper.WriteLine("Starting screen recording. FPS: {0}", taskSettings.CaptureSettings.GIFFPS);
|
||||
taskSettings.CaptureSettings.FFmpegOptions.VideoCodec = FFmpegVideoCodec.gif;
|
||||
}
|
||||
|
||||
if (taskSettings.CaptureSettings.RunScreencastCLI)
|
||||
|
@ -108,12 +109,6 @@ private static void StartRecording(ScreenRecordOutput outputType, TaskSettings t
|
|||
}
|
||||
}
|
||||
|
||||
if (outputType == ScreenRecordOutput.GIF)
|
||||
{
|
||||
taskSettings.CaptureSettings.FFmpegOptions.VideoCodec = FFmpegVideoCodec.gif;
|
||||
taskSettings.CaptureSettings.FFmpegOptions.UseCustomCommands = false;
|
||||
}
|
||||
|
||||
if (!TaskHelpers.CheckFFmpeg(taskSettings))
|
||||
{
|
||||
return;
|
||||
|
@ -218,9 +213,10 @@ private static void StartRecording(ScreenRecordOutput outputType, TaskSettings t
|
|||
{
|
||||
ScreencastOptions options = new ScreencastOptions()
|
||||
{
|
||||
IsRecording = true,
|
||||
IsLossless = outputType == ScreenRecordOutput.GIF || taskSettings.CaptureSettings.ScreenRecordTwoPassEncoding,
|
||||
FFmpeg = taskSettings.CaptureSettings.FFmpegOptions,
|
||||
ScreenRecordFPS = taskSettings.CaptureSettings.ScreenRecordFPS,
|
||||
GIFFPS = taskSettings.CaptureSettings.GIFFPS,
|
||||
FPS = outputType == ScreenRecordOutput.GIF ? taskSettings.CaptureSettings.GIFFPS : taskSettings.CaptureSettings.ScreenRecordFPS,
|
||||
Duration = duration,
|
||||
OutputPath = path,
|
||||
CaptureArea = captureRectangle,
|
||||
|
@ -253,19 +249,26 @@ private static void StartRecording(ScreenRecordOutput outputType, TaskSettings t
|
|||
{
|
||||
recordForm.ChangeState(ScreenRecordState.AfterStop);
|
||||
|
||||
string sourceFilePath = path;
|
||||
string input = path;
|
||||
|
||||
if (outputType == ScreenRecordOutput.GIF)
|
||||
{
|
||||
path = Path.Combine(taskSettings.CaptureFolder, TaskHelpers.GetFilename(taskSettings, "gif"));
|
||||
screenRecorder.FFmpegEncodeAsGIF(sourceFilePath, path, Program.ToolsFolder);
|
||||
screenRecorder.FFmpegEncodeAsGIF(input, path, Program.ToolsFolder);
|
||||
}
|
||||
else if (taskSettings.CaptureSettings.ScreenRecordTwoPassEncoding)
|
||||
{
|
||||
path = Path.Combine(taskSettings.CaptureFolder, TaskHelpers.GetFilename(taskSettings, taskSettings.CaptureSettings.FFmpegOptions.Extension));
|
||||
screenRecorder.FFmpegEncodeVideo(input, path);
|
||||
DebugHelper.WriteLine("Two pass encoding result:\nInput file size: {0}\nOutput file size: {1}",
|
||||
new FileInfo(input).Length.ToSizeString(), new FileInfo(path).Length.ToSizeString());
|
||||
}
|
||||
|
||||
if (taskSettings.CaptureSettings.RunScreencastCLI)
|
||||
if (taskSettings.CaptureSettings.RunScreencastCLI && !taskSettings.CaptureSettings.ScreenRecordTwoPassEncoding)
|
||||
{
|
||||
VideoEncoder encoder = Program.Settings.VideoEncoders[taskSettings.CaptureSettings.VideoEncoderSelected];
|
||||
path = Path.Combine(taskSettings.CaptureFolder, TaskHelpers.GetFilename(taskSettings, encoder.OutputExtension));
|
||||
screenRecorder.EncodeUsingCommandLine(encoder, sourceFilePath, path);
|
||||
screenRecorder.EncodeUsingCommandLine(encoder, input, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +286,7 @@ private static void StartRecording(ScreenRecordOutput outputType, TaskSettings t
|
|||
|
||||
if (screenRecorder != null)
|
||||
{
|
||||
if ((outputType == ScreenRecordOutput.GIF || taskSettings.CaptureSettings.RunScreencastCLI) &&
|
||||
if ((outputType == ScreenRecordOutput.GIF || taskSettings.CaptureSettings.RunScreencastCLI || taskSettings.CaptureSettings.ScreenRecordTwoPassEncoding) &&
|
||||
!string.IsNullOrEmpty(screenRecorder.CachePath) && File.Exists(screenRecorder.CachePath))
|
||||
{
|
||||
File.Delete(screenRecorder.CachePath);
|
||||
|
|
Loading…
Reference in a new issue