mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
commit
ef1f40b182
18 changed files with 275 additions and 32 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -18,12 +18,12 @@ jobs:
|
||||||
timeout-minutes: 6
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v2
|
||||||
- name: Prepare .NET
|
- name: Prepare .NET
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: '5.0.x'
|
dotnet-version: '5.0.x'
|
||||||
- name: Prepare FFMpeg
|
- name: Prepare FFMpeg
|
||||||
uses: FedericoCarboni/setup-ffmpeg@v1-beta
|
uses: FedericoCarboni/setup-ffmpeg@v1
|
||||||
- name: Test with dotnet
|
- name: Test with dotnet
|
||||||
run: dotnet test --logger GitHubActions
|
run: dotnet test --logger GitHubActions
|
||||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v2
|
||||||
- name: Prepare .NET
|
- name: Prepare .NET
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using System;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Exceptions;
|
||||||
|
using FFMpegCore.Pipes;
|
||||||
using FFMpegCore.Test.Resources;
|
using FFMpegCore.Test.Resources;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFMpegCore.Pipes;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
|
@ -70,5 +72,155 @@ public void Image_AddAudio()
|
||||||
Assert.IsTrue(analysis.Duration.TotalSeconds > 0);
|
Assert.IsTrue(analysis.Duration.TotalSeconds > 0);
|
||||||
Assert.IsTrue(File.Exists(outputFile));
|
Assert.IsTrue(File.Exists(outputFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToAAC_Args_Pipe()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var samples = new List<IAudioSample>
|
||||||
|
{
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(samples)
|
||||||
|
{
|
||||||
|
Channels = 2,
|
||||||
|
Format = "s8",
|
||||||
|
SampleRate = 8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
var success = FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToLibVorbis_Args_Pipe()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var samples = new List<IAudioSample>
|
||||||
|
{
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(samples)
|
||||||
|
{
|
||||||
|
Channels = 2,
|
||||||
|
Format = "s8",
|
||||||
|
SampleRate = 8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
var success = FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.LibVorbis))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public async Task Audio_ToAAC_Args_Pipe_Async()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var samples = new List<IAudioSample>
|
||||||
|
{
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(samples)
|
||||||
|
{
|
||||||
|
Channels = 2,
|
||||||
|
Format = "s8",
|
||||||
|
SampleRate = 8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
var success = await FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessAsynchronously();
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var samples = new List<IAudioSample>
|
||||||
|
{
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
new PcmAudioSampleWrapper(new byte[] { 0, 0 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(samples);
|
||||||
|
|
||||||
|
var success = FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToAAC_Args_Pipe_InvalidChannels()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
||||||
|
{
|
||||||
|
Channels = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsException<FFMpegException>(() => FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessSynchronously());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToAAC_Args_Pipe_InvalidFormat()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
||||||
|
{
|
||||||
|
Format = "s8le",
|
||||||
|
};
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsException<FFMpegException>(() => FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessSynchronously());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_ToAAC_Args_Pipe_InvalidSampleRate()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
||||||
|
{
|
||||||
|
SampleRate = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsException<FFMpegException>(() => FFMpegArguments
|
||||||
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithAudioCodec(AudioCodec.Aac))
|
||||||
|
.ProcessSynchronously());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
namespace FFMpegCore.Test.Resources
|
||||||
using System.IO;
|
|
||||||
using FFMpegCore.Enums;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test.Resources
|
|
||||||
{
|
{
|
||||||
public enum AudioType
|
public enum AudioType
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -24,7 +25,7 @@ public BitmapVideoFrameWrapper(Bitmap bitmap)
|
||||||
Format = ConvertStreamFormat(bitmap.PixelFormat);
|
Format = ConvertStreamFormat(bitmap.PixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Serialize(System.IO.Stream stream)
|
public void Serialize(Stream stream)
|
||||||
{
|
{
|
||||||
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ public void Serialize(System.IO.Stream stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SerializeAsync(System.IO.Stream stream, CancellationToken token)
|
public async Task SerializeAsync(Stream stream, CancellationToken token)
|
||||||
{
|
{
|
||||||
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
||||||
|
|
||||||
|
@ -67,6 +68,8 @@ private static string ConvertStreamFormat(PixelFormat fmt)
|
||||||
{
|
{
|
||||||
case PixelFormat.Format16bppGrayScale:
|
case PixelFormat.Format16bppGrayScale:
|
||||||
return "gray16le";
|
return "gray16le";
|
||||||
|
case PixelFormat.Format16bppRgb555:
|
||||||
|
return "bgr555le";
|
||||||
case PixelFormat.Format16bppRgb565:
|
case PixelFormat.Format16bppRgb565:
|
||||||
return "bgr565le";
|
return "bgr565le";
|
||||||
case PixelFormat.Format24bppRgb:
|
case PixelFormat.Format24bppRgb:
|
||||||
|
|
27
FFMpegCore/Extend/PcmAudioSampleWrapper.cs
Normal file
27
FFMpegCore/Extend/PcmAudioSampleWrapper.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using FFMpegCore.Pipes;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class PcmAudioSampleWrapper : IAudioSample
|
||||||
|
{
|
||||||
|
//This could actually be short or int, but copies would be inefficient.
|
||||||
|
//Handling bytes lets the user decide on the conversion, and abstract the library
|
||||||
|
//from handling shorts, unsigned shorts, integers, unsigned integers and floats.
|
||||||
|
private readonly byte[] _sample;
|
||||||
|
|
||||||
|
public PcmAudioSampleWrapper(byte[] sample)
|
||||||
|
{
|
||||||
|
_sample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Serialize(Stream stream)
|
||||||
|
{
|
||||||
|
stream.Write(_sample, 0, _sample.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SerializeAsync(Stream stream, CancellationToken token)
|
||||||
|
{
|
||||||
|
await stream.WriteAsync(_sample, 0, _sample.Length, token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ public InputPipeArgument(IPipeSource writer) : base(PipeDirection.Out)
|
||||||
Writer = writer;
|
Writer = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Text => $"-y {Writer.GetStreamArguments()} -i \"{PipePath}\"";
|
public override string Text => $"{Writer.GetStreamArguments()} -i \"{PipePath}\"";
|
||||||
|
|
||||||
protected override async Task ProcessDataAsync(CancellationToken token)
|
protected override async Task ProcessDataAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Enums;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments
|
||||||
{
|
{
|
||||||
|
|
16
FFMpegCore/FFMpeg/Pipes/IAudioSample.cs
Normal file
16
FFMpegCore/FFMpeg/Pipes/IAudioSample.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFMpegCore.Pipes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for Audio sample
|
||||||
|
/// </summary>
|
||||||
|
public interface IAudioSample
|
||||||
|
{
|
||||||
|
void Serialize(Stream stream);
|
||||||
|
|
||||||
|
Task SerializeAsync(Stream stream, CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
using System.Threading;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FFMpegCore.Pipes
|
namespace FFMpegCore.Pipes
|
||||||
{
|
{
|
||||||
public interface IPipeSink
|
public interface IPipeSink
|
||||||
{
|
{
|
||||||
Task ReadAsync(System.IO.Stream inputStream, CancellationToken cancellationToken);
|
Task ReadAsync(Stream inputStream, CancellationToken cancellationToken);
|
||||||
string GetFormat();
|
string GetFormat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Threading;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FFMpegCore.Pipes
|
namespace FFMpegCore.Pipes
|
||||||
|
@ -9,6 +10,6 @@ namespace FFMpegCore.Pipes
|
||||||
public interface IPipeSource
|
public interface IPipeSource
|
||||||
{
|
{
|
||||||
string GetStreamArguments();
|
string GetStreamArguments();
|
||||||
Task WriteAsync(System.IO.Stream outputStream, CancellationToken cancellationToken);
|
Task WriteAsync(Stream outputStream, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Threading;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FFMpegCore.Pipes
|
namespace FFMpegCore.Pipes
|
||||||
|
@ -12,7 +13,7 @@ public interface IVideoFrame
|
||||||
int Height { get; }
|
int Height { get; }
|
||||||
string Format { get; }
|
string Format { get; }
|
||||||
|
|
||||||
void Serialize(System.IO.Stream pipe);
|
void Serialize(Stream pipe);
|
||||||
Task SerializeAsync(System.IO.Stream pipe, CancellationToken token);
|
Task SerializeAsync(Stream pipe, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs
Normal file
46
FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFMpegCore.Pipes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of <see cref="IPipeSource"/> for a raw audio stream that is gathered from <see cref="IEnumerator{IAudioFrame}"/>.
|
||||||
|
/// It is the user's responbility to make sure the enumerated samples match the configuration provided to this pipe.
|
||||||
|
/// </summary>
|
||||||
|
public class RawAudioPipeSource : IPipeSource
|
||||||
|
{
|
||||||
|
private readonly IEnumerator<IAudioSample> _sampleEnumerator;
|
||||||
|
|
||||||
|
public string Format { get; set; } = "s16le";
|
||||||
|
public uint SampleRate { get; set; } = 8000;
|
||||||
|
public uint Channels { get; set; } = 1;
|
||||||
|
|
||||||
|
public RawAudioPipeSource(IEnumerator<IAudioSample> sampleEnumerator)
|
||||||
|
{
|
||||||
|
_sampleEnumerator = sampleEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawAudioPipeSource(IEnumerable<IAudioSample> sampleEnumerator)
|
||||||
|
: this(sampleEnumerator.GetEnumerator()) { }
|
||||||
|
|
||||||
|
public string GetStreamArguments()
|
||||||
|
{
|
||||||
|
return $"-f {Format} -ar {SampleRate} -ac {Channels}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task WriteAsync(Stream outputStream, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (_sampleEnumerator.Current != null)
|
||||||
|
{
|
||||||
|
await _sampleEnumerator.Current.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_sampleEnumerator.MoveNext())
|
||||||
|
{
|
||||||
|
await _sampleEnumerator.Current!.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
@ -46,7 +47,7 @@ public string GetStreamArguments()
|
||||||
return $"-f rawvideo -r {FrameRate.ToString(CultureInfo.InvariantCulture)} -pix_fmt {StreamFormat} -s {Width}x{Height}";
|
return $"-f rawvideo -r {FrameRate.ToString(CultureInfo.InvariantCulture)} -pix_fmt {StreamFormat} -s {Width}x{Height}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteAsync(System.IO.Stream outputStream, CancellationToken cancellationToken)
|
public async Task WriteAsync(Stream outputStream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_framesEnumerator.Current != null)
|
if (_framesEnumerator.Current != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ public StreamPipeSink(Stream destination)
|
||||||
Writer = (inputStream, cancellationToken) => inputStream.CopyToAsync(destination, BlockSize, cancellationToken);
|
Writer = (inputStream, cancellationToken) => inputStream.CopyToAsync(destination, BlockSize, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ReadAsync(System.IO.Stream inputStream, CancellationToken cancellationToken)
|
public Task ReadAsync(Stream inputStream, CancellationToken cancellationToken)
|
||||||
=> Writer(inputStream, cancellationToken);
|
=> Writer(inputStream, cancellationToken);
|
||||||
|
|
||||||
public string GetFormat() => Format;
|
public string GetFormat() => Format;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Threading;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FFMpegCore.Pipes
|
namespace FFMpegCore.Pipes
|
||||||
|
@ -8,17 +9,17 @@ namespace FFMpegCore.Pipes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StreamPipeSource : IPipeSource
|
public class StreamPipeSource : IPipeSource
|
||||||
{
|
{
|
||||||
public System.IO.Stream Source { get; }
|
public Stream Source { get; }
|
||||||
public int BlockSize { get; } = 4096;
|
public int BlockSize { get; } = 4096;
|
||||||
public string StreamFormat { get; } = string.Empty;
|
public string StreamFormat { get; } = string.Empty;
|
||||||
|
|
||||||
public StreamPipeSource(System.IO.Stream source)
|
public StreamPipeSource(Stream source)
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetStreamArguments() => StreamFormat;
|
public string GetStreamArguments() => StreamFormat;
|
||||||
|
|
||||||
public Task WriteAsync(System.IO.Stream outputStream, CancellationToken cancellationToken) => Source.CopyToAsync(outputStream, BlockSize, cancellationToken);
|
public Task WriteAsync(Stream outputStream, CancellationToken cancellationToken) => Source.CopyToAsync(outputStream, BlockSize, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
<Version>3.0.0.0</Version>
|
<Version>3.0.0.0</Version>
|
||||||
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
||||||
<FileVersion>3.0.0.0</FileVersion>
|
<FileVersion>3.0.0.0</FileVersion>
|
||||||
<PackageReleaseNotes>- Added support for mirroring video filter (thanks gorobvictor)</PackageReleaseNotes>
|
<PackageReleaseNotes>- Added support for PCM audio through RawAudioPipeSource (thanks to Namaneo)
|
||||||
|
- Removed -y in InputPipeArgument due to reported problems</PackageReleaseNotes>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>8</LangVersion>
|
||||||
<PackageVersion>4.2.0</PackageVersion>
|
<PackageVersion>4.3.0</PackageVersion>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
|
|
Loading…
Reference in a new issue