Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes attempting to use disposed decoders #72

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class FFmpegAudioDecoder
private byte[] _decodedFrameBuffer = new byte[0];
private bool _disposed;

// Lock object to ensure this object remains disposed (or not) for the duration of a action
private readonly object disposalLock = new object();

public int BitsPerCodedSample { get; }

private FFmpegAudioDecoder(FFmpegAudioCodecId audioCodecId, int bitsPerCodedSample, IntPtr decoderHandle)
Expand Down Expand Up @@ -72,27 +75,33 @@ public unsafe bool TryDecode(RawAudioFrame rawAudioFrame)

fixed (byte* rawBufferPtr = &rawAudioFrame.FrameSegment.Array[rawAudioFrame.FrameSegment.Offset])
{
int resultCode = FFmpegAudioPInvoke.DecodeFrame(_decoderHandle, (IntPtr)rawBufferPtr,
lock (disposalLock) {
if (_disposed) {
Console.WriteLine("Skipped decoding audio frame, as decoder was disposed. (Therefore the frame probably wasn't wanted)");
return false;
}

int resultCode = FFmpegAudioPInvoke.DecodeFrame(_decoderHandle, (IntPtr)rawBufferPtr,
rawAudioFrame.FrameSegment.Count, out int sampleRate, out int bitsPerSample, out int channels);

_currentRawFrameTimestamp = rawAudioFrame.Timestamp;
_currentRawFrameTimestamp = rawAudioFrame.Timestamp;

if (resultCode != 0)
return false;
if (resultCode != 0)
return false;

if (rawAudioFrame is RawG711Frame g711Frame)
{
sampleRate = g711Frame.SampleRate;
channels = g711Frame.Channels;
}
if (rawAudioFrame is RawG711Frame g711Frame) {
sampleRate = g711Frame.SampleRate;
channels = g711Frame.Channels;
}

if (_currentFrameFormat.SampleRate != sampleRate || _currentFrameFormat.BitPerSample != bitsPerSample ||
_currentFrameFormat.Channels != channels)
{
_currentFrameFormat = new AudioFrameFormat(sampleRate, bitsPerSample, channels);

if (_resamplerHandle != IntPtr.Zero)
FFmpegAudioPInvoke.RemoveAudioResampler(_resamplerHandle);
if (_currentFrameFormat.SampleRate != sampleRate || _currentFrameFormat.BitPerSample != bitsPerSample ||
_currentFrameFormat.Channels != channels) {
_currentFrameFormat = new AudioFrameFormat(sampleRate, bitsPerSample, channels);

if (_resamplerHandle != IntPtr.Zero)
FFmpegAudioPInvoke.RemoveAudioResampler(_resamplerHandle);
}
}
}

Expand All @@ -109,38 +118,41 @@ public IDecodedAudioFrame GetDecodedFrame(AudioConversionParameters optionalAudi

int resultCode;

if (optionalAudioConversionParameters == null ||
lock (disposalLock) {
if (_disposed) {
Console.WriteLine("Skipped retrieving decoded audio frame, as decoder was disposed. (Therefore the frame probably wasn't wanted)");
return null;
}

if (optionalAudioConversionParameters == null ||
(optionalAudioConversionParameters.OutSampleRate == 0 || optionalAudioConversionParameters.OutSampleRate == _currentFrameFormat.SampleRate) &&
(optionalAudioConversionParameters.OutBitsPerSample == 0 || optionalAudioConversionParameters.OutBitsPerSample == _currentFrameFormat.BitPerSample) &&
(optionalAudioConversionParameters.OutChannels == 0 || optionalAudioConversionParameters.OutChannels == _currentFrameFormat.Channels))
{
resultCode = FFmpegAudioPInvoke.GetDecodedFrame(_decoderHandle, out outBufferPtr, out dataSize);
(optionalAudioConversionParameters.OutChannels == 0 || optionalAudioConversionParameters.OutChannels == _currentFrameFormat.Channels)) {
resultCode = FFmpegAudioPInvoke.GetDecodedFrame(_decoderHandle, out outBufferPtr, out dataSize);

if (resultCode != 0)
throw new DecoderException($"An error occurred while getting decoded audio frame, {_audioCodecId} codec, code: {resultCode}");
if (resultCode != 0)
throw new DecoderException($"An error occurred while getting decoded audio frame, {_audioCodecId} codec, code: {resultCode}");

format = _currentFrameFormat;
}
else
{
if (_resamplerHandle == IntPtr.Zero)
{
resultCode = FFmpegAudioPInvoke.CreateAudioResampler(_decoderHandle,
optionalAudioConversionParameters.OutSampleRate, optionalAudioConversionParameters.OutBitsPerSample,
optionalAudioConversionParameters.OutChannels, out _resamplerHandle);
format = _currentFrameFormat;
} else {
if (_resamplerHandle == IntPtr.Zero) {
resultCode = FFmpegAudioPInvoke.CreateAudioResampler(_decoderHandle,
optionalAudioConversionParameters.OutSampleRate, optionalAudioConversionParameters.OutBitsPerSample,
optionalAudioConversionParameters.OutChannels, out _resamplerHandle);

if (resultCode != 0)
throw new DecoderException($"An error occurred while creating audio resampler, code: {resultCode}");
}
if (resultCode != 0)
throw new DecoderException($"An error occurred while creating audio resampler, code: {resultCode}");
}

resultCode = FFmpegAudioPInvoke.ResampleDecodedFrame(_decoderHandle, _resamplerHandle, out outBufferPtr, out dataSize);
resultCode = FFmpegAudioPInvoke.ResampleDecodedFrame(_decoderHandle, _resamplerHandle, out outBufferPtr, out dataSize);

if (resultCode != 0)
throw new DecoderException($"An error occurred while converting audio frame, code: {resultCode}");
if (resultCode != 0)
throw new DecoderException($"An error occurred while converting audio frame, code: {resultCode}");

format = new AudioFrameFormat(optionalAudioConversionParameters.OutSampleRate != 0 ? optionalAudioConversionParameters.OutSampleRate : _currentFrameFormat.SampleRate,
optionalAudioConversionParameters.OutBitsPerSample != 0 ? optionalAudioConversionParameters.OutBitsPerSample : _currentFrameFormat.BitPerSample,
optionalAudioConversionParameters.OutChannels != 0 ? optionalAudioConversionParameters.OutChannels : _currentFrameFormat.Channels);
format = new AudioFrameFormat(optionalAudioConversionParameters.OutSampleRate != 0 ? optionalAudioConversionParameters.OutSampleRate : _currentFrameFormat.SampleRate,
optionalAudioConversionParameters.OutBitsPerSample != 0 ? optionalAudioConversionParameters.OutBitsPerSample : _currentFrameFormat.BitPerSample,
optionalAudioConversionParameters.OutChannels != 0 ? optionalAudioConversionParameters.OutChannels : _currentFrameFormat.Channels);
}
}

if (_decodedFrameBuffer.Length < dataSize)
Expand All @@ -152,16 +164,18 @@ public IDecodedAudioFrame GetDecodedFrame(AudioConversionParameters optionalAudi

public void Dispose()
{
if (_disposed)
return;
lock (disposalLock) {
if (_disposed)
return;

_disposed = true;
FFmpegAudioPInvoke.RemoveAudioDecoder(_decoderHandle);
_disposed = true;
FFmpegAudioPInvoke.RemoveAudioDecoder(_decoderHandle);

if (_resamplerHandle != IntPtr.Zero)
FFmpegAudioPInvoke.RemoveAudioResampler(_resamplerHandle);
if (_resamplerHandle != IntPtr.Zero)
FFmpegAudioPInvoke.RemoveAudioResampler(_resamplerHandle);

GC.SuppressFinalize(this);
GC.SuppressFinalize(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class FFmpegVideoDecoder
private readonly Dictionary<TransformParameters, FFmpegDecodedVideoScaler> _scalersMap =
new Dictionary<TransformParameters, FFmpegDecodedVideoScaler>();

// Lock object to ensure this object remains disposed (or not) for the duration of a action
private readonly object disposalLock = new object();

private byte[] _extraData = new byte[0];
private bool _disposed;

Expand Down Expand Up @@ -72,18 +75,24 @@ public unsafe IDecodedVideoFrame TryDecode(RawVideoFrame rawVideoFrame)
}
}

resultCode = FFmpegVideoPInvoke.DecodeFrame(_decoderHandle, (IntPtr)rawBufferPtr,
lock (disposalLock) {
if (_disposed) {
Console.WriteLine("Skipped decoding video frame, as decoder was disposed. (Therefore the frame probably wasn't wanted)");
return null;
}

resultCode = FFmpegVideoPInvoke.DecodeFrame(_decoderHandle, (IntPtr)rawBufferPtr,
rawVideoFrame.FrameSegment.Count,
out int width, out int height, out FFmpegPixelFormat pixelFormat);

if (resultCode != 0)
return null;
if (resultCode != 0)
return null;

if (_currentFrameParameters.Width != width || _currentFrameParameters.Height != height ||
_currentFrameParameters.PixelFormat != pixelFormat)
{
_currentFrameParameters = new DecodedVideoFrameParameters(width, height, pixelFormat);
DropAllVideoScalers();
if (_currentFrameParameters.Width != width || _currentFrameParameters.Height != height ||
_currentFrameParameters.PixelFormat != pixelFormat) {
_currentFrameParameters = new DecodedVideoFrameParameters(width, height, pixelFormat);
DropAllVideoScalers();
}
}

return new DecodedVideoFrame(TransformTo);
Expand All @@ -92,13 +101,15 @@ public unsafe IDecodedVideoFrame TryDecode(RawVideoFrame rawVideoFrame)

public void Dispose()
{
if (_disposed)
return;

_disposed = true;
FFmpegVideoPInvoke.RemoveVideoDecoder(_decoderHandle);
DropAllVideoScalers();
GC.SuppressFinalize(this);
lock (disposalLock) {
if (_disposed)
return;

_disposed = true;
FFmpegVideoPInvoke.RemoveVideoDecoder(_decoderHandle);
DropAllVideoScalers();
GC.SuppressFinalize(this);
}
}

private void DropAllVideoScalers()
Expand All @@ -117,10 +128,17 @@ private void TransformTo(IntPtr buffer, int bufferStride, TransformParameters pa
_scalersMap.Add(parameters, videoScaler);
}

int resultCode = FFmpegVideoPInvoke.ScaleDecodedVideoFrame(_decoderHandle, videoScaler.Handle, buffer, bufferStride);
lock (disposalLock) {
if (_disposed) {
Console.WriteLine("Skipped scaling video frame, as decoder was disposed. (Therefore the frame probably wasn't wanted)");
return;
}

if (resultCode != 0)
throw new DecoderException($"An error occurred while converting decoding video frame, {_videoCodecId} codec, code: {resultCode}");
int resultCode = FFmpegVideoPInvoke.ScaleDecodedVideoFrame(_decoderHandle, videoScaler.Handle, buffer, bufferStride);

if (resultCode != 0)
throw new DecoderException($"An error occurred while converting decoding video frame, {_videoCodecId} codec, code: {resultCode}");
}
}
}
}