mirror of
https://github.com/unclshura/ABStemPlayer.git
synced 2026-08-07 00:43:38 +00:00
105 lines
2.5 KiB
C#
105 lines
2.5 KiB
C#
using System.Diagnostics;
|
|
using System.Globalization;
|
|
|
|
namespace AudioCore.Impl;
|
|
|
|
public sealed class FfmpegAudioReader : IAudioReader, IDisposable
|
|
{
|
|
private readonly string _path;
|
|
|
|
private Lazy<FfmpegProcess> _process;
|
|
|
|
private long _pendingSeekSample = 0;
|
|
|
|
// NEW: internal position tracking (in floats)
|
|
private long _pos = 0;
|
|
|
|
public int SampleRate { get; }
|
|
public int Channels { get; }
|
|
public long TotalSamples { get; }
|
|
public TimeSpan Duration { get; }
|
|
|
|
public FfmpegAudioReader(string path)
|
|
{
|
|
_path = path;
|
|
|
|
var probe = FfprobeProcess.ProbeAudio(path);
|
|
|
|
SampleRate = probe.SampleRate;
|
|
Channels = probe.Channels;
|
|
TotalSamples = probe.TotalSamples;
|
|
Duration = probe.Duration;
|
|
|
|
_process = CreateLazyProcess();
|
|
}
|
|
|
|
private Lazy<FfmpegProcess> CreateLazyProcess() =>
|
|
new Lazy<FfmpegProcess>(() =>
|
|
{
|
|
var startSeconds = (double)_pendingSeekSample / SampleRate;
|
|
|
|
var cmd =
|
|
"-hide_banner -loglevel error " +
|
|
"-nostdin " +
|
|
$"-i \"{_path}\" " + // input first
|
|
$"-ss {startSeconds.ToString(CultureInfo.InvariantCulture)} " + // output seek
|
|
$"-f f32le -ac {Channels} -ar {SampleRate} pipe:1";
|
|
|
|
|
|
var p = new FfmpegProcess(
|
|
name: $"pipe:{_path}",
|
|
commandLine: cmd,
|
|
redirectOutput: true,
|
|
redirectInput: false);
|
|
|
|
p.StartProcess();
|
|
return p;
|
|
});
|
|
|
|
/// <summary>
|
|
/// Async float reader using new FfmpegProcess.ReadAsync
|
|
/// </summary>
|
|
public async Task<int> ReadAsync(Memory<float> buffer, CancellationToken token)
|
|
{
|
|
var proc = _process.Value;
|
|
if (proc.Stdout is null)
|
|
return 0;
|
|
|
|
int readFloats = await proc.ReadAsync(buffer, token).ConfigureAwait(false);
|
|
|
|
// NEW: update internal position
|
|
_pos += readFloats;
|
|
|
|
return readFloats;
|
|
}
|
|
|
|
public void Seek(long sampleIndex)
|
|
{
|
|
_pendingSeekSample = sampleIndex;
|
|
|
|
// NEW: update internal position (floats)
|
|
_pos = sampleIndex * Channels;
|
|
|
|
DisposeProcessOnly();
|
|
_process = CreateLazyProcess();
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
Seek(0);
|
|
}
|
|
|
|
private void DisposeProcessOnly()
|
|
{
|
|
if (_process.IsValueCreated)
|
|
{
|
|
try { _process.Value.Dispose(); } catch { }
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
DisposeProcessOnly();
|
|
}
|
|
}
|