feat: extract audio conversion to separate class and refine audio extraction
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
|
||||
using NAudio.Wave;
|
||||
|
||||
namespace StreamShorts.Library.Media.Audio;
|
||||
|
||||
public class AudioConverter : IAudioConverter
|
||||
{
|
||||
public Stream ConvertMp3ToWav16(Stream mp3)
|
||||
{
|
||||
using var reader = new Mp3FileReader(mp3);
|
||||
var outFormat = new WaveFormat(16000, reader.WaveFormat.Channels);
|
||||
using var resampler = new MediaFoundationResampler(reader, outFormat);
|
||||
var waveStream = new MemoryStream();
|
||||
WaveFileWriter.WriteWavFileToStream(waveStream, resampler);
|
||||
waveStream.Position = 0;
|
||||
return waveStream;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
using FFMpegCore;
|
||||
using FFMpegCore.Pipes;
|
||||
|
||||
using Channel = FFMpegCore.Enums.Channel;
|
||||
|
||||
namespace StreamShorts.Library.Media.Audio;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class AudioExtractor : IAudioExtractor
|
||||
{
|
||||
private readonly IFFMpegService _ffmpegService = new FFMpegService();
|
||||
|
||||
public AudioExtractor()
|
||||
{
|
||||
}
|
||||
|
||||
internal AudioExtractor(IFFMpegService ffmpegService)
|
||||
{
|
||||
_ffmpegService = ffmpegService;
|
||||
}
|
||||
|
||||
public async Task<Stream> ExtractMp3FromMp4Async(Stream video)
|
||||
{
|
||||
if (video is null)
|
||||
@@ -29,26 +35,20 @@ public class AudioExtractor : IAudioExtractor
|
||||
|
||||
try
|
||||
{
|
||||
using var mp3Stream = new MemoryStream();
|
||||
var mp3Stream = new MemoryStream();
|
||||
using var mp4Stream = new MemoryStream();
|
||||
|
||||
await video.CopyToAsync(mp4Stream).ConfigureAwait(false);
|
||||
mp4Stream.Position = 0;
|
||||
|
||||
var wasExtracted = await FFMpegArguments
|
||||
.FromPipeInput(new StreamPipeSource(mp4Stream))
|
||||
.OutputToPipe(
|
||||
new StreamPipeSink(mp3Stream),
|
||||
o => o.DisableChannel(Channel.Video).ForceFormat("mp3")
|
||||
)
|
||||
.ProcessAsynchronously()
|
||||
.ConfigureAwait(false);
|
||||
var wasExtracted = await _ffmpegService.ExtractAudioFromVideoAsync(mp4Stream, mp3Stream).ConfigureAwait(false);
|
||||
|
||||
if (wasExtracted is false)
|
||||
{
|
||||
throw new FailedAudioExtractionException("Failed to extract audio from the video stream.");
|
||||
}
|
||||
|
||||
mp3Stream.Position = 0;
|
||||
return mp3Stream;
|
||||
}
|
||||
catch (Exception e) when (e is not FailedAudioExtractionException)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace StreamShorts.Library.Media.Audio;
|
||||
|
||||
public interface IAudioConverter
|
||||
{
|
||||
Stream ConvertMp3ToWav16(Stream mp3);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using FFMpegCore;
|
||||
using FFMpegCore.Enums;
|
||||
using FFMpegCore.Pipes;
|
||||
|
||||
namespace StreamShorts.Library.Media;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal class FFMpegService : IFFMpegService
|
||||
{
|
||||
public async Task<bool> ExtractAudioFromVideoAsync(Stream video, Stream audio)
|
||||
{
|
||||
return await FFMpegArguments
|
||||
.FromPipeInput(new StreamPipeSource(video))
|
||||
.OutputToPipe(
|
||||
new StreamPipeSink(audio),
|
||||
static o => o.DisableChannel(Channel.Video).ForceFormat("mp3")
|
||||
)
|
||||
.ProcessAsynchronously()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace StreamShorts.Library.Media;
|
||||
|
||||
internal interface IFFMpegService
|
||||
{
|
||||
Task<bool> ExtractAudioFromVideoAsync(Stream video, Stream audio);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FFMpegCore" />
|
||||
<PackageReference Include="NAudio" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user