From 32dfb34724cb881e40f7808eeea1a880bf303393 Mon Sep 17 00:00:00 2001 From: Julien Loir Date: Mon, 12 Apr 2021 13:50:27 +0200 Subject: [PATCH] Add simple support for PCM audio source wrapping Former-commit-id: d8810682efdfc63aa194d16f39211736cd3a514d --- FFMpegCore/Extend/PcmAudioSampleWrapper.cs | 27 +++++++++++ FFMpegCore/FFMpeg/Pipes/IAudioSample.cs | 16 +++++++ FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs | 45 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 FFMpegCore/Extend/PcmAudioSampleWrapper.cs create mode 100644 FFMpegCore/FFMpeg/Pipes/IAudioSample.cs create mode 100644 FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs diff --git a/FFMpegCore/Extend/PcmAudioSampleWrapper.cs b/FFMpegCore/Extend/PcmAudioSampleWrapper.cs new file mode 100644 index 0000000..d67038b --- /dev/null +++ b/FFMpegCore/Extend/PcmAudioSampleWrapper.cs @@ -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); + } +} diff --git a/FFMpegCore/FFMpeg/Pipes/IAudioSample.cs b/FFMpegCore/FFMpeg/Pipes/IAudioSample.cs new file mode 100644 index 0000000..c7dea65 --- /dev/null +++ b/FFMpegCore/FFMpeg/Pipes/IAudioSample.cs @@ -0,0 +1,16 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace FFMpegCore.Pipes +{ + /// + /// Interface for Audio sample + /// + public interface IAudioSample + { + void Serialize(Stream stream); + + Task SerializeAsync(Stream stream, CancellationToken token); + } +} diff --git a/FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs b/FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs new file mode 100644 index 0000000..40b964c --- /dev/null +++ b/FFMpegCore/FFMpeg/Pipes/RawAudioPipeSource.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace FFMpegCore.Pipes +{ + /// + /// Implementation of for a raw audio stream that is gathered from + /// + public class RawAudioPipeSource : IPipeSource + { + private readonly IEnumerator _sampleEnumerator; + + public string Format { get; set; } = "s16le"; + public uint SampleRate { get; set; } = 8000; + public uint Channels { get; set; } = 1; + + public RawAudioPipeSource(IEnumerator sampleEnumerator) + { + _sampleEnumerator = sampleEnumerator; + } + + public RawAudioPipeSource(IEnumerable 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); + } + } + } +}