mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
parent
d948867396
commit
17c9db52dd
12 changed files with 42 additions and 49 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace FFMpegCore.Pipes
|
||||
{
|
||||
public interface IPipeDataReader
|
||||
public interface IPipeSink
|
||||
{
|
||||
Task CopyAsync(System.IO.Stream inputStream, CancellationToken cancellationToken);
|
||||
string GetFormat();
|
|
@ -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);
|
|
@ -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()
|
||||
{
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue