diff options
author | Jan Holthuis <jan.holthuis@ruhr-uni-bochum.de> | 2021-09-04 00:03:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-04 00:03:18 +0200 |
commit | 40085a377fd4f2ca22d7b32a7ac874b0dea674f6 (patch) | |
tree | 9ccdfef1cbad16de152d823334ae05b678a8aebf /src | |
parent | 6cd39a505c4ee101a5df9a6462d70b57c7950edd (diff) | |
parent | a509808001e9465a55575c2dc2ea301bab5f09d3 (diff) |
Merge pull request #4245 from uklotzde/lp1934785-soundsourceffmpeg
lp1934785 SoundSourceFFmpeg: Ignore inaudible samples before start of stream
Diffstat (limited to 'src')
-rw-r--r-- | src/sources/readaheadframebuffer.cpp | 19 | ||||
-rw-r--r-- | src/sources/soundsourceffmpeg.cpp | 35 |
2 files changed, 50 insertions, 4 deletions
diff --git a/src/sources/readaheadframebuffer.cpp b/src/sources/readaheadframebuffer.cpp index 407074963c..f2db73a920 100644 --- a/src/sources/readaheadframebuffer.cpp +++ b/src/sources/readaheadframebuffer.cpp @@ -3,10 +3,17 @@ #include "util/logger.h" #include "util/sample.h" +// Override or set to `true` to enable verbose debug logging. #if !defined(VERBOSE_DEBUG_LOG) #define VERBOSE_DEBUG_LOG false #endif +// Override or set to `true` to break with a debug assertion +// if an overlap or gap in the audio stream has been detected. +#if !defined(DEBUG_ASSERT_ON_DISCONTINUITIES) +#define DEBUG_ASSERT_ON_DISCONTINUITIES false +#endif + namespace mixxx { namespace { @@ -135,6 +142,9 @@ ReadableSampleFrames ReadAheadFrameBuffer::fillBuffer( << bufferedRange() << "and input buffer" << inputRange; +#if DEBUG_ASSERT_ON_DISCONTINUITIES + DEBUG_ASSERT(!"Unexpected gap"); +#endif switch (discontinuityGapMode) { case DiscontinuityGapMode::Skip: reset(inputRange.start()); @@ -314,6 +324,9 @@ WritableSampleFrames ReadAheadFrameBuffer::consumeAndFillBuffer( << outputRange << "with input buffer" << inputRange; +#if DEBUG_ASSERT_ON_DISCONTINUITIES + DEBUG_ASSERT(!"Unexpected overlap"); +#endif switch (discontinuityOverlapMode) { case DiscontinuityOverlapMode::Ignore: break; @@ -345,6 +358,9 @@ WritableSampleFrames ReadAheadFrameBuffer::consumeAndFillBuffer( << bufferedRange() << "with input buffer" << inputRange; +#if DEBUG_ASSERT_ON_DISCONTINUITIES + DEBUG_ASSERT(!"Unexpected overlap"); +#endif switch (discontinuityOverlapMode) { case DiscontinuityOverlapMode::Ignore: break; @@ -397,6 +413,9 @@ WritableSampleFrames ReadAheadFrameBuffer::consumeAndFillBuffer( << outputRange << "and input buffer" << inputRange; +#if DEBUG_ASSERT_ON_DISCONTINUITIES + DEBUG_ASSERT(!"Unexpected gap"); +#endif switch (discontinuityGapMode) { case DiscontinuityGapMode::Skip: break; diff --git a/src/sources/soundsourceffmpeg.cpp b/src/sources/soundsourceffmpeg.cpp index d76851f585..e1b48196b2 100644 --- a/src/sources/soundsourceffmpeg.cpp +++ b/src/sources/soundsourceffmpeg.cpp @@ -60,7 +60,7 @@ constexpr int64_t kavStreamDecoderFrameDelayAAC = 2112; // Use 0-based sample frame indexing constexpr SINT kMinFrameIndex = 0; -constexpr SINT kSamplesPerMP3Frame = 1152; +constexpr SINT kMaxSamplesPerMP3Frame = 1152; const Logger kLogger("SoundSourceFFmpeg"); @@ -106,7 +106,7 @@ inline int64_t getStreamStartTime(const AVStream& avStream) { // using the default start time. // Not all M4A files encode the start_time correctly, e.g. // the test file cover-test-itunes-12.7.0-aac.m4a has a valid - // start_time of 0. Unfortunately, this special case is cannot + // start_time of 0. Unfortunately, this special case cannot be // detected and compensated. start_time = math_max(kavStreamDefaultStartTime, kavStreamDecoderFrameDelayAAC); break; @@ -135,6 +135,7 @@ inline int64_t getStreamEndTime(const AVStream& avStream) { } inline SINT convertStreamTimeToFrameIndex(const AVStream& avStream, int64_t pts) { + DEBUG_ASSERT(pts != AV_NOPTS_VALUE); // getStreamStartTime(avStream) -> 1st audible frame at kMinFrameIndex return kMinFrameIndex + av_rescale_q( @@ -185,7 +186,7 @@ SINT getStreamSeekPrerollFrameCount(const AVStream& avStream) { // slight deviations from the exact signal! DEBUG_ASSERT(avStream.codecpar->channels <= 2); const SINT mp3SeekPrerollFrameCount = - 9 * (kSamplesPerMP3Frame / avStream.codecpar->channels); + 9 * (kMaxSamplesPerMP3Frame / avStream.codecpar->channels); return math_max(mp3SeekPrerollFrameCount, defaultSeekPrerollFrameCount); } case AV_CODEC_ID_AAC: @@ -1051,12 +1052,33 @@ ReadableSampleFrames SoundSourceFFmpeg::readSampleFramesClamped( #if VERBOSE_DEBUG_LOG avTrace("Received decoded frame", *m_pavDecodedFrame); #endif - DEBUG_ASSERT(m_pavDecodedFrame->pts != AV_NOPTS_VALUE); + VERIFY_OR_DEBUG_ASSERT( + (m_pavDecodedFrame->flags & + (AV_FRAME_FLAG_CORRUPT | + AV_FRAME_FLAG_DISCARD)) == 0) { + av_frame_unref(m_pavDecodedFrame); + continue; + } const auto decodedFrameCount = m_pavDecodedFrame->nb_samples; DEBUG_ASSERT(decodedFrameCount > 0); auto streamFrameIndex = convertStreamTimeToFrameIndex( *m_pavStream, m_pavDecodedFrame->pts); + // Only audible samples are counted, i.e. any inaudible aka + // "priming" samples are not included in nb_samples! + // https://bugs.launchpad.net/mixxx/+bug/1934785 + if (streamFrameIndex < kMinFrameIndex) { +#if VERBOSE_DEBUG_LOG + const auto inaudibleFrameCountUntilStartOfStream = + kMinFrameIndex - streamFrameIndex; + kLogger.debug() + << "Skipping" + << inaudibleFrameCountUntilStartOfStream + << "inaudible sample frames before the start of the stream"; +#endif + streamFrameIndex = kMinFrameIndex; + } + DEBUG_ASSERT(streamFrameIndex >= kMinFrameIndex); decodedFrameRange = IndexRange::forward( streamFrameIndex, decodedFrameCount); @@ -1203,6 +1225,11 @@ ReadableSampleFrames SoundSourceFFmpeg::readSampleFramesClamped( // Housekeeping before next decoding iteration av_frame_unref(m_pavDecodedFrame); av_frame_unref(m_pavResampledFrame); + + // The first loop condition (see below) should always be true + // and has only been added to prevent infinite looping in case + // of unexpected result values. + DEBUG_ASSERT(avcodec_receive_frame_result == 0); } while (avcodec_receive_frame_result == 0 && m_frameBuffer.isValid()); } |