feat: handle large video files

This commit is contained in:
Stevan Freeborn
2026-01-06 14:15:46 -06:00
parent 75faf89a97
commit b4ccda00b5
+38 -26
View File
@@ -6,7 +6,6 @@
using FFMpegCore; using FFMpegCore;
using FFMpegCore.Enums; using FFMpegCore.Enums;
using FFMpegCore.Pipes;
using NAudio.Wave; using NAudio.Wave;
using Whisper.net; using Whisper.net;
using Whisper.net.Ggml; using Whisper.net.Ggml;
@@ -25,44 +24,41 @@ if (File.Exists(videoPath) is false)
return; return;
} }
using var mp4Stream = File.OpenRead(videoPath); var tempWavPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.wav");
using var mp3Stream = new MemoryStream();
await FFMpegArguments try
.FromPipeInput(new StreamPipeSource(mp4Stream)) {
.OutputToPipe( await FFMpegArguments
new StreamPipeSink(mp3Stream), .FromFileInput(videoPath)
static o => o.DisableChannel(Channel.Video).ForceFormat("mp3") .OutputToFile(tempWavPath, true, options => options
.DisableChannel(Channel.Video)
.ForceFormat("wav")
.WithAudioSamplingRate(16000)
) )
.ProcessAsynchronously(); .ProcessAsynchronously();
mp3Stream.Position = 0; using var waveReader = new WaveFileReader(tempWavPath);
using var reader = new Mp3FileReader(mp3Stream);
var outFormat = new WaveFormat(16000, reader.WaveFormat.Channels);
using var resampler = new MediaFoundationResampler(reader, outFormat);
using var waveStream = new MemoryStream();
WaveFileWriter.WriteWavFileToStream(waveStream, resampler);
waveStream.Position = 0; var segmentDuration = TimeSpan.FromMinutes(2);
using var waveReader = new WaveFileReader(waveStream); var totalDuration = waveReader.TotalTime;
var segmentDuration = TimeSpan.FromMinutes(2); var numOfSegments = (int)Math.Ceiling(totalDuration.TotalSeconds / segmentDuration.TotalSeconds);
var totalDuration = waveReader.TotalTime;
var numOfSegments = (int)Math.Ceiling(totalDuration.TotalSeconds / segmentDuration.TotalSeconds); using var processor = await GetProcessor();
foreach (var i in Enumerable.Range(0, numOfSegments))
{
using var segmentReader = new WaveFileReader(tempWavPath);
foreach (var i in Enumerable.Range(0, numOfSegments))
{
waveStream.Position = 0;
using var segmentReader = new WaveFileReader(waveStream);
var segment = segmentReader.ToSampleProvider() var segment = segmentReader.ToSampleProvider()
.Skip(i * segmentDuration) .Skip(i * segmentDuration)
.Take(segmentDuration); .Take(segmentDuration);
var segmentProvider = segment.ToWaveProvider16(); var segmentProvider = segment.ToWaveProvider16();
var segmentStream = new MemoryStream(); using var segmentStream = new MemoryStream();
WaveFileWriter.WriteWavFileToStream(segmentStream, segmentProvider); WaveFileWriter.WriteWavFileToStream(segmentStream, segmentProvider);
segmentStream.Position = 0; segmentStream.Position = 0;
using var processor = await GetProcessor();
var durationOffset = TimeSpan.FromSeconds(i * segmentDuration.TotalSeconds); var durationOffset = TimeSpan.FromSeconds(i * segmentDuration.TotalSeconds);
await foreach (var result in processor.ProcessAsync(segmentStream)) await foreach (var result in processor.ProcessAsync(segmentStream))
@@ -71,12 +67,28 @@ foreach (var i in Enumerable.Range(0, numOfSegments))
var endTime = result.End + durationOffset; var endTime = result.End + durationOffset;
Console.WriteLine($"[{startTime:hh\\:mm\\:ss} - {endTime:hh\\:mm\\:ss}]: {result.Text}"); Console.WriteLine($"[{startTime:hh\\:mm\\:ss} - {endTime:hh\\:mm\\:ss}]: {result.Text}");
} }
}
}
finally
{
// Cleanup temporary file
if (File.Exists(tempWavPath))
{
try
{
File.Delete(tempWavPath);
}
catch
{
// Best effort cleanup
}
}
} }
static async Task<WhisperProcessor> GetProcessor() static async Task<WhisperProcessor> GetProcessor()
{ {
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
var model = await WhisperGgmlDownloader.Default.GetGgmlModelAsync(GgmlType.TinyEn); var model = await WhisperGgmlDownloader.Default.GetGgmlModelAsync(GgmlType.BaseEn);
await model.CopyToAsync(memoryStream); await model.CopyToAsync(memoryStream);
var whisperFactory = WhisperFactory.FromBuffer(memoryStream.ToArray()); var whisperFactory = WhisperFactory.FromBuffer(memoryStream.ToArray());
return whisperFactory.CreateBuilder() return whisperFactory.CreateBuilder()