Skip to content

Commit

Permalink
fix: FFmpeg end-of-stream handling breaks stream contract
Browse files Browse the repository at this point in the history
  • Loading branch information
protyposis committed Jan 30, 2024
1 parent 8d33d6a commit c18b299
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
25 changes: 25 additions & 0 deletions src/Aurio.FFmpeg.UnitTest/FFmpegSourceStreamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,30 @@ out It.Ref<Type>.IsAny
Times.Exactly(3)
);
}

[Fact]
public void SeekBeyondEnd_PositionCanBeSet()
{
var fileInfo = new FileInfo("./Resources/sine440-44100-16-mono-200ms.ts");
var s = new FFmpegSourceStream(fileInfo);
var position = 10000000000 * s.SampleBlockSize;

s.Position = position;

Assert.Equal(position, s.Position);
}

[Fact]
public void SeekBeyondEnd_ReadIndicatesEndOfStream()
{
var fileInfo = new FileInfo("./Resources/sine440-44100-16-mono-200ms.ts");
var s = new FFmpegSourceStream(fileInfo);
var position = 10000000000 * s.SampleBlockSize;

s.Position = position;
var bytesRead = s.Read(new byte[1000], 0, 1000);

Assert.Equal(0, bytesRead);
}
}
}
19 changes: 17 additions & 2 deletions src/Aurio.FFmpeg/FFmpegSourceStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,12 @@ private void ForwardReadUntilTimestamp(long targetTimestamp)
{
ReadFrame();

if (readerPosition == previousReaderPosition)
if (readerPosition == -1)
{
// "Timestamp not found (end of file reached)"
return;
}
else if (readerPosition == previousReaderPosition)
{
// Prevent an endless read-loop in case the reported position does not change.
// I did not encounter this behavior, but who knows how FFmpeg acts on the myriad of supported formats.
Expand Down Expand Up @@ -221,6 +226,16 @@ public long Position
ForwardReadUntilTimestamp(seekTarget);
}

if (sourceBufferLength == -1)
{
// End of stream handling:
// The Aurio stream interface allows seeking beyond the end, so we act
// like the seek was successful. `Read` won't return any samples though.
readerPosition = seekTarget;
sourceBufferPosition = 0;
return;
}

// check if seek ended up at seek target (or earlier because of frame size, depends on file format and stream codec)
if (seekTarget == readerPosition)
{
Expand Down Expand Up @@ -284,7 +299,7 @@ public int Read(byte[] buffer, int offset, int count)
out Type type
);

if (newPosition == -1 || sourceBufferLength == -1)
if (sourceBufferLength == -1)
{
return 0; // end of stream
}
Expand Down

0 comments on commit c18b299

Please sign in to comment.