From cfda0fc9ae87ac5aaa398175b9a109b7454b5312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=91=D0=B0=D0=B3?= =?UTF-8?q?=D1=80=D1=8F=D0=BD=D1=86=D0=B5=D0=B2?= Date: Tue, 28 Apr 2020 15:21:48 +0300 Subject: [PATCH] Added ffprobe stream input --- FFMpegCore.Test/FFProbeTests.cs | 25 +++++++++ FFMpegCore.Test/TasksExtensions.cs | 16 ++++++ .../Argument/Atoms/InputPipeArgument.cs | 3 +- FFMpegCore/FFMPEG/FFProbe.cs | 52 +++++++++++++++++++ FFMpegCore/VideoInfo.cs | 18 ++++--- 5 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 FFMpegCore.Test/TasksExtensions.cs diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs index d66d561..5e877ff 100644 --- a/FFMpegCore.Test/FFProbeTests.cs +++ b/FFMpegCore.Test/FFProbeTests.cs @@ -31,5 +31,30 @@ public void Probe_Success() Assert.AreEqual(13, info.Duration.Seconds); } + + [TestMethod] + public void Probe_Success_FromStream() + { + var output = new FFProbe(); + + using (var stream = File.OpenRead(VideoLibrary.LocalVideo.FullName)) + { + var info = output.ParseVideoInfo(stream); + Assert.AreEqual(13, info.Duration.Seconds); + } + } + + [TestMethod] + public void Probe_Success_FromStream_Async() + { + var output = new FFProbe(); + + using (var stream = File.OpenRead(VideoLibrary.LocalVideo.FullName)) + { + var info = output.ParseVideoInfoAsync(stream).WaitForResult(); + + Assert.AreEqual(13, info.Duration.Seconds); + } + } } } \ No newline at end of file diff --git a/FFMpegCore.Test/TasksExtensions.cs b/FFMpegCore.Test/TasksExtensions.cs new file mode 100644 index 0000000..7958ec9 --- /dev/null +++ b/FFMpegCore.Test/TasksExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace FFMpegCore.Test +{ + static class TasksExtensions + { + public static T WaitForResult(this Task task) + { + task.Wait(); + return task.Result; + } + } +} diff --git a/FFMpegCore/FFMPEG/Argument/Atoms/InputPipeArgument.cs b/FFMpegCore/FFMPEG/Argument/Atoms/InputPipeArgument.cs index bed5897..a45937b 100644 --- a/FFMpegCore/FFMPEG/Argument/Atoms/InputPipeArgument.cs +++ b/FFMpegCore/FFMPEG/Argument/Atoms/InputPipeArgument.cs @@ -16,6 +16,7 @@ namespace FFMpegCore.FFMPEG.Argument public class InputPipeArgument : Argument { public string PipeName { get; private set; } + public string PipePath => $@"\\.\pipe\{PipeName}"; public IPipeSource Source { get; private set; } private NamedPipeServerStream pipe; @@ -42,7 +43,7 @@ public void ClosePipe() public override string GetStringValue() { - return $"-y {Source.GetFormat()} -i \\\\.\\pipe\\{PipeName}"; + return $"-y {Source.GetFormat()} -i {PipePath}"; } public void FlushPipe() diff --git a/FFMpegCore/FFMPEG/FFProbe.cs b/FFMpegCore/FFMPEG/FFProbe.cs index 827ea7f..7c683bf 100644 --- a/FFMpegCore/FFMPEG/FFProbe.cs +++ b/FFMpegCore/FFMPEG/FFProbe.cs @@ -5,6 +5,8 @@ using System.Globalization; using System.Threading.Tasks; using Instances; +using FFMpegCore.FFMPEG.Argument; +using FFMpegCore.FFMPEG.Pipes; namespace FFMpegCore.FFMPEG { @@ -65,6 +67,56 @@ public async Task ParseVideoInfoAsync(VideoInfo info) return ParseVideoInfoInternal(info, output); } + public VideoInfo ParseVideoInfo(System.IO.Stream stream) + { + var info = new VideoInfo(); + var streamPipeSource = new StreamPipeSource(stream); + var pipeArgument = new InputPipeArgument(streamPipeSource); + + var instance = new Instance(_ffprobePath, BuildFFProbeArguments(pipeArgument.PipePath)) { DataBufferCapacity = _outputCapacity }; + pipeArgument.OpenPipe(); + + try + { + var task = instance.FinishedRunning(); + pipeArgument.FlushPipe(); + pipeArgument.ClosePipe(); + task.Wait(); + } + finally + { + pipeArgument.ClosePipe(); + } + + var output = string.Join("", instance.OutputData); + return ParseVideoInfoInternal(info, output); + } + + public async Task ParseVideoInfoAsync(System.IO.Stream stream) + { + var info = new VideoInfo(); + var streamPipeSource = new StreamPipeSource(stream); + var pipeArgument = new InputPipeArgument(streamPipeSource); + + var instance = new Instance(_ffprobePath, BuildFFProbeArguments(pipeArgument.PipePath)) { DataBufferCapacity = _outputCapacity }; + pipeArgument.OpenPipe(); + + try + { + var task = instance.FinishedRunning(); + await pipeArgument.FlushPipeAsync(); + pipeArgument.ClosePipe(); + await task; + } + finally + { + pipeArgument.ClosePipe(); + } + + var output = string.Join("", instance.OutputData); + return ParseVideoInfoInternal(info, output); + } + private static string BuildFFProbeArguments(string fullPath) => $"-v quiet -print_format json -show_streams \"{fullPath}\""; diff --git a/FFMpegCore/VideoInfo.cs b/FFMpegCore/VideoInfo.cs index f56145c..4e6c226 100644 --- a/FFMpegCore/VideoInfo.cs +++ b/FFMpegCore/VideoInfo.cs @@ -10,6 +10,10 @@ public class VideoInfo { private FileInfo _file; + internal VideoInfo() + { + + } /// /// Create a video information object from a file information object. /// @@ -76,37 +80,37 @@ public VideoInfo(string path, int outputCapacity = int.MaxValue) : this(new File /// /// Gets the name of the file. /// - public string Name => _file.Name; + public string Name => _file != null ? _file.Name : throw new FileNotFoundException(); /// /// Gets the full path of the file. /// - public string FullName => _file.FullName; + public string FullName => _file != null ? _file.FullName : throw new FileNotFoundException(); /// /// Gets the file extension. /// - public string Extension => _file.Extension; + public string Extension => _file != null ? _file.Extension : throw new FileNotFoundException(); /// /// Gets a flag indicating if the file is read-only. /// - public bool IsReadOnly => _file.IsReadOnly; + public bool IsReadOnly => _file != null ? _file.IsReadOnly : throw new FileNotFoundException(); /// /// Gets a flag indicating if the file exists (no cache, per call verification). /// - public bool Exists => File.Exists(FullName); + public bool Exists => _file != null ? File.Exists(FullName) : false; /// /// Gets the creation date. /// - public DateTime CreationTime => _file.CreationTime; + public DateTime CreationTime => _file != null ? _file.CreationTime : throw new FileNotFoundException(); /// /// Gets the parent directory information. /// - public DirectoryInfo Directory => _file.Directory; + public DirectoryInfo Directory => _file != null ? _file.Directory : throw new FileNotFoundException(); /// /// Create a video information object from a file information object.