Former-commit-id: 39dd390e81
This commit is contained in:
Malte Rosenbjerg 2020-05-24 19:17:14 +02:00
parent d948867396
commit 17c9db52dd
12 changed files with 42 additions and 49 deletions

View file

@ -72,7 +72,7 @@ private void ConvertFromStreamPipe(ContainerFormat type, params IArgument[] inpu
var input = FFProbe.Analyse(VideoLibrary.LocalVideoWebm.FullName);
using (var inputStream = File.OpenRead(input.Path))
{
var pipeSource = new StreamPipeDataWriter(inputStream);
var pipeSource = new StreamPipeSource(inputStream);
var arguments = FFMpegArguments.FromPipe(pipeSource);
foreach (var arg in inputArguments)
arguments.WithArgument(arg);
@ -124,7 +124,7 @@ private void ConvertToStreamPipe(params IArgument[] inputArguments)
foreach (var arg in inputArguments)
arguments.WithArgument(arg);
var streamPipeDataReader = new StreamPipeDataReader(ms);
var streamPipeDataReader = new StreamPipeSink(ms);
var processor = arguments.OutputToPipe(streamPipeDataReader);
var scaling = arguments.Find<ScaleArgument>();
@ -220,7 +220,7 @@ public void ConvertFromPipe(ContainerFormat type, System.Drawing.Imaging.PixelFo
try
{
var videoFramesSource = new RawVideoPipeDataWriter(BitmapSource.CreateBitmaps(128, fmt, 256, 256));
var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, fmt, 256, 256));
var arguments = FFMpegArguments.FromPipe(videoFramesSource);
foreach (var arg in inputArguments)
arguments.WithArgument(arg);
@ -302,7 +302,7 @@ public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
await Assert.ThrowsExceptionAsync<FFMpegException>(async () =>
{
await using var ms = new MemoryStream();
var pipeSource = new StreamPipeDataReader(ms);
var pipeSource = new StreamPipeSink(ms);
await FFMpegArguments
.FromInputFiles(VideoLibrary.LocalVideo)
.ForceFormat("mkv")
@ -322,7 +322,7 @@ public void Video_ToMP4_Args_StreamOutputPipe_Failure()
public void Video_ToMP4_Args_StreamOutputPipe_Async()
{
using var ms = new MemoryStream();
var pipeSource = new StreamPipeDataReader(ms);
var pipeSource = new StreamPipeSink(ms);
FFMpegArguments
.FromInputFiles(VideoLibrary.LocalVideo)
.WithVideoCodec(VideoCodec.LibX264)
@ -622,8 +622,8 @@ public void Video_UpdatesProgress()
public void Video_TranscodeInMemory()
{
using var resStream = new MemoryStream();
var reader = new StreamPipeDataReader(resStream);
var writer = new RawVideoPipeDataWriter(BitmapSource.CreateBitmaps(128, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128));
var reader = new StreamPipeSink(resStream);
var writer = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128));
FFMpegArguments
.FromPipe(writer)
@ -642,8 +642,8 @@ public void Video_TranscodeInMemory()
public async Task Video_Cancel_Async()
{
await using var resStream = new MemoryStream();
var reader = new StreamPipeDataReader(resStream);
var writer = new RawVideoPipeDataWriter(BitmapSource.CreateBitmaps(512, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128));
var reader = new StreamPipeSink(resStream);
var writer = new RawVideoPipeSource(BitmapSource.CreateBitmaps(512, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128));
var task = FFMpegArguments
.FromPipe(writer)

View file

@ -10,9 +10,9 @@ namespace FFMpegCore.Arguments
/// </summary>
public class InputPipeArgument : PipeArgument, IInputArgument
{
public readonly IPipeDataWriter Writer;
public readonly IPipeSource Writer;
public InputPipeArgument(IPipeDataWriter writer) : base(PipeDirection.Out)
public InputPipeArgument(IPipeSource writer) : base(PipeDirection.Out)
{
Writer = writer;
}

View file

@ -7,9 +7,9 @@ namespace FFMpegCore.Arguments
{
public class OutputPipeArgument : PipeArgument, IOutputArgument
{
public readonly IPipeDataReader Reader;
public readonly IPipeSink Reader;
public OutputPipeArgument(IPipeDataReader reader) : base(PipeDirection.In)
public OutputPipeArgument(IPipeSink reader) : base(PipeDirection.In)
{
Reader = reader;
}

View file

@ -59,7 +59,7 @@ public static Bitmap Snapshot(MediaAnalysis source, Size? size = null, TimeSpan?
.Resize(size)
.Seek(captureTime)
.ForceFormat("rawvideo")
.OutputToPipe(new StreamPipeDataReader(ms))
.OutputToPipe(new StreamPipeSink(ms))
.ProcessSynchronously();
ms.Position = 0;

View file

@ -12,7 +12,11 @@ namespace FFMpegCore
{
public class FFMpegArgumentProcessor
{
private static readonly Regex ProgressRegex = new Regex(@"time=(\d\d:\d\d:\d\d.\d\d?)", RegexOptions.Compiled);
private readonly FFMpegArguments _ffMpegArguments;
private Action<double>? _onPercentageProgress;
private Action<TimeSpan>? _onTimeProgress;
private TimeSpan? _totalTimespan;
internal FFMpegArgumentProcessor(FFMpegArguments ffMpegArguments)
{
@ -74,15 +78,20 @@ void OnCancelEvent(object sender, EventArgs args)
_ffMpegArguments.Post();
}
return HandleCompletion(throwOnError, errorCode, instance);
}
private bool HandleCompletion(bool throwOnError, int errorCode, Instance instance)
{
if (throwOnError && errorCode != 0)
throw new FFMpegException(FFMpegExceptionType.Conversion, string.Join("\n", instance.ErrorData));
_onPercentageProgress?.Invoke(100.0);
if (_totalTimespan.HasValue) _onTimeProgress?.Invoke(_totalTimespan.Value);
return errorCode == 0;
}
public async Task<bool> ProcessAsynchronously(bool throwOnError = true)
{
using var instance = PrepareInstance(out var cancellationTokenSource, out var errorCode);
@ -113,13 +122,7 @@ await Task.WhenAll(instance.FinishedRunning().ContinueWith(t =>
_ffMpegArguments.Post();
}
if (throwOnError && errorCode != 0)
throw new FFMpegException(FFMpegExceptionType.Conversion, string.Join("\n", instance.ErrorData));
_onPercentageProgress?.Invoke(100.0);
if (_totalTimespan.HasValue) _onTimeProgress?.Invoke(_totalTimespan.Value);
return errorCode == 0;
return HandleCompletion(throwOnError, errorCode, instance);
}
private Instance PrepareInstance(out CancellationTokenSource cancellationTokenSource, out int errorCode)
@ -146,18 +149,8 @@ private static bool HandleException(bool throwOnError, Exception e, Instance ins
string.Join("\n", instance.ErrorData));
}
private static readonly Regex ProgressRegex = new Regex(@"time=(\d\d:\d\d:\d\d.\d\d?)", RegexOptions.Compiled);
private Action<double>? _onPercentageProgress;
private Action<TimeSpan>? _onTimeProgress;
private TimeSpan? _totalTimespan;
private void OutputData(object sender, (DataType Type, string Data) msg)
{
#if DEBUG
Trace.WriteLine(msg.Data);
#endif
var match = ProgressRegex.Match(msg.Data);
if (!match.Success) return;

View file

@ -32,7 +32,7 @@ private FFMpegArguments(IInputArgument inputArgument)
public static FFMpegArguments FromInputFiles(params FileInfo[] files) => new FFMpegArguments(new InputArgument(false, files));
public static FFMpegArguments FromInputFiles(bool verifyExists, params FileInfo[] files) => new FFMpegArguments(new InputArgument(verifyExists, files));
public static FFMpegArguments FromConcatenation(params string[] files) => new FFMpegArguments(new ConcatArgument(files));
public static FFMpegArguments FromPipe(IPipeDataWriter writer) => new FFMpegArguments(new InputPipeArgument(writer));
public static FFMpegArguments FromPipe(IPipeSource writer) => new FFMpegArguments(new InputPipeArgument(writer));
public FFMpegArguments WithAudioCodec(Codec audioCodec) => WithArgument(new AudioCodecArgument(audioCodec));
@ -87,7 +87,7 @@ private FFMpegArguments(IInputArgument inputArgument)
public FFMpegArgumentProcessor OutputToFile(string file, bool overwrite = false) => ToProcessor(new OutputArgument(file, overwrite));
public FFMpegArgumentProcessor OutputToFile(Uri uri, bool overwrite = false) => ToProcessor(new OutputArgument(uri.AbsolutePath, overwrite));
public FFMpegArgumentProcessor OutputToPipe(IPipeDataReader reader) => ToProcessor(new OutputPipeArgument(reader));
public FFMpegArgumentProcessor OutputToPipe(IPipeSink reader) => ToProcessor(new OutputPipeArgument(reader));
public FFMpegArguments WithArgument(IArgument argument)
{

View file

@ -3,7 +3,7 @@
namespace FFMpegCore.Pipes
{
public interface IPipeDataReader
public interface IPipeSink
{
Task CopyAsync(System.IO.Stream inputStream, CancellationToken cancellationToken);
string GetFormat();

View file

@ -6,7 +6,7 @@ namespace FFMpegCore.Pipes
/// <summary>
/// Interface for ffmpeg pipe source data IO
/// </summary>
public interface IPipeDataWriter
public interface IPipeSource
{
string GetFormat();
Task CopyAsync(System.IO.Stream outputStream, CancellationToken cancellationToken);

View file

@ -7,9 +7,9 @@
namespace FFMpegCore.Pipes
{
/// <summary>
/// Implementation of <see cref="IPipeDataWriter"/> for a raw video stream that is gathered from <see cref="IEnumerator{IVideoFrame}"/>
/// Implementation of <see cref="IPipeSource"/> for a raw video stream that is gathered from <see cref="IEnumerator{IVideoFrame}"/>
/// </summary>
public class RawVideoPipeDataWriter : IPipeDataWriter
public class RawVideoPipeSource : IPipeSource
{
public string StreamFormat { get; private set; } = null!;
public int Width { get; private set; }
@ -18,12 +18,12 @@ public class RawVideoPipeDataWriter : IPipeDataWriter
private bool _formatInitialized;
private readonly IEnumerator<IVideoFrame> _framesEnumerator;
public RawVideoPipeDataWriter(IEnumerator<IVideoFrame> framesEnumerator)
public RawVideoPipeSource(IEnumerator<IVideoFrame> framesEnumerator)
{
_framesEnumerator = framesEnumerator;
}
public RawVideoPipeDataWriter(IEnumerable<IVideoFrame> framesEnumerator) : this(framesEnumerator.GetEnumerator()) { }
public RawVideoPipeSource(IEnumerable<IVideoFrame> framesEnumerator) : this(framesEnumerator.GetEnumerator()) { }
public string GetFormat()
{

View file

@ -3,13 +3,13 @@
namespace FFMpegCore.Pipes
{
public class StreamPipeDataReader : IPipeDataReader
public class StreamPipeSink : IPipeSink
{
public System.IO.Stream Destination { get; }
public int BlockSize { get; set; } = 4096;
public string Format { get; set; } = string.Empty;
public StreamPipeDataReader(System.IO.Stream destination)
public StreamPipeSink(System.IO.Stream destination)
{
Destination = destination;
}

View file

@ -4,15 +4,15 @@
namespace FFMpegCore.Pipes
{
/// <summary>
/// Implementation of <see cref="IPipeDataWriter"/> used for stream redirection
/// Implementation of <see cref="IPipeSource"/> used for stream redirection
/// </summary>
public class StreamPipeDataWriter : IPipeDataWriter
public class StreamPipeSource : IPipeSource
{
public System.IO.Stream Source { get; }
public int BlockSize { get; } = 4096;
public string StreamFormat { get; } = string.Empty;
public StreamPipeDataWriter(System.IO.Stream source)
public StreamPipeSource(System.IO.Stream source)
{
Source = source;
}

View file

@ -20,7 +20,7 @@ public static MediaAnalysis Analyse(string filePath, int outputCapacity = int.Ma
}
public static MediaAnalysis Analyse(System.IO.Stream stream, int outputCapacity = int.MaxValue)
{
var streamPipeSource = new StreamPipeDataWriter(stream);
var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource);
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity);
pipeArgument.Pre();
@ -49,7 +49,7 @@ public static async Task<MediaAnalysis> AnalyseAsync(string filePath, int output
}
public static async Task<MediaAnalysis> AnalyseAsync(System.IO.Stream stream, int outputCapacity = int.MaxValue)
{
var streamPipeSource = new StreamPipeDataWriter(stream);
var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource);
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity);
pipeArgument.Pre();