Skip to content
Merged
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
12 changes: 4 additions & 8 deletions plugins/soundsourcem4a/soundsourcem4a.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,18 +367,12 @@ void SoundSourceM4A::restartDecoding(MP4SampleId sampleBlockId) {
SINT SoundSourceM4A::seekSampleFrame(SINT frameIndex) {
DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));

DEBUG_ASSERT_AND_HANDLE(isValidFrameIndex(frameIndex)) {
// EOF reached
if (frameIndex >= getMaxFrameIndex()) {
// EOF
m_curFrameIndex = getMaxFrameIndex();
return m_curFrameIndex;
}

// Handle trivial case
if (frameIndex == m_curFrameIndex) {
// Nothing to do
return m_curFrameIndex;
}

// NOTE(uklotzde): Resetting the decoder near to the beginning
// of the stream when seeking backwards produces invalid sample
// values! As a consequence the seeking test fails.
Expand All @@ -388,6 +382,8 @@ SINT SoundSourceM4A::seekSampleFrame(SINT frameIndex) {
// of the stream while decoding.
reopenDecoder();
skipSampleFrames(frameIndex);
}
if (frameIndex == m_curFrameIndex) {
return m_curFrameIndex;
}

Expand Down
24 changes: 14 additions & 10 deletions plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,15 @@ void SoundSourceMediaFoundation::close() {

SINT SoundSourceMediaFoundation::seekSampleFrame(
SINT frameIndex) {
DEBUG_ASSERT(isValidFrameIndex(frameIndex));
DEBUG_ASSERT(isValidFrameIndex(m_currentFrameIndex));

if (m_currentFrameIndex < frameIndex) {
if (frameIndex >= getMaxFrameIndex()) {
// EOF
m_currentFrameIndex = getMaxFrameIndex();
return m_currentFrameIndex;
}

if (frameIndex > m_currentFrameIndex) {
// seeking forward
SINT skipFramesCount = frameIndex - m_currentFrameIndex;
// When to prefer skipping over seeking:
Expand All @@ -151,23 +157,21 @@ SINT SoundSourceMediaFoundation::seekSampleFrame(
skipSampleFrames(skipFramesCount);
}
}

if (m_currentFrameIndex == frameIndex) {
// already there
if (frameIndex == m_currentFrameIndex) {
return m_currentFrameIndex;
}

if (m_pSourceReader == nullptr) {
// reader is dead -> jump to end of stream
return getMaxFrameIndex();
}

// Discard decoded samples
m_sampleBuffer.reset();

// Invalidate current position (end of stream)
m_currentFrameIndex = getMaxFrameIndex();

if (m_pSourceReader == nullptr) {
// reader is dead
return m_currentFrameIndex;
}

// Jump to a position before the actual seeking position.
// Prefetching a certain number of frames is necessary for
// sample accurate decoding. The decoder needs to decode
Expand Down
33 changes: 31 additions & 2 deletions plugins/soundsourcewv/soundsourcewv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ SoundSourceWV::SoundSourceWV(const QUrl& url)
m_wpc(nullptr),
m_sampleScaleFactor(CSAMPLE_ZERO),
m_pWVFile(nullptr),
m_pWVCFile(nullptr) {
m_pWVCFile(nullptr),
m_curFrameIndex(getMinFrameIndex()) {
}

SoundSourceWV::~SoundSourceWV() {
Expand Down Expand Up @@ -86,11 +87,24 @@ void SoundSourceWV::close() {
delete m_pWVCFile;
m_pWVCFile = nullptr;
}
m_curFrameIndex = getMinFrameIndex();
}

SINT SoundSourceWV::seekSampleFrame(SINT frameIndex) {
DEBUG_ASSERT(isValidFrameIndex(frameIndex));
DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));

if (frameIndex >= getMaxFrameIndex()) {
// EOF reached
m_curFrameIndex = getMaxFrameIndex();
return m_curFrameIndex;
}

if (frameIndex == m_curFrameIndex) {
return m_curFrameIndex;
}

if (WavpackSeekSample(m_wpc, frameIndex) == true) {
m_curFrameIndex = frameIndex;
return frameIndex;
} else {
qDebug() << "SSWV::seek : could not seek to frame #" << frameIndex;
Expand All @@ -100,9 +114,23 @@ SINT SoundSourceWV::seekSampleFrame(SINT frameIndex) {

SINT SoundSourceWV::readSampleFrames(
SINT numberOfFrames, CSAMPLE* sampleBuffer) {
if (sampleBuffer == nullptr) {
// NOTE(uklotzde): The WavPack API does not provide any
// functions for skipping samples in the audio stream. Calling
// API functions with a nullptr buffer does not return. Since
// we don't want to read samples into a temporary buffer that
// has to be allocated we are seeking to the position after
// the skipped samples.
SINT curFrameIndexBefore = m_curFrameIndex;
SINT curFrameIndexAfter = seekSampleFrame(m_curFrameIndex + numberOfFrames);
DEBUG_ASSERT(curFrameIndexBefore <= curFrameIndexAfter);
DEBUG_ASSERT(m_curFrameIndex == curFrameIndexAfter);
return curFrameIndexAfter - curFrameIndexBefore;
}
// static assert: sizeof(CSAMPLE) == sizeof(int32_t)
SINT unpackCount = WavpackUnpackSamples(m_wpc,
reinterpret_cast<int32_t*>(sampleBuffer), numberOfFrames);
DEBUG_ASSERT(unpackCount >= 0);
if (!(WavpackGetMode(m_wpc) & MODE_FLOAT)) {
// signed integer -> float
const SINT sampleCount = frames2samples(unpackCount);
Expand All @@ -112,6 +140,7 @@ SINT SoundSourceWV::readSampleFrames(
sampleBuffer[i] = CSAMPLE(sampleValue) * m_sampleScaleFactor;
}
}
m_curFrameIndex += unpackCount;
return unpackCount;
}

Expand Down
2 changes: 2 additions & 0 deletions plugins/soundsourcewv/soundsourcewv.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class SoundSourceWV: public SoundSourcePlugin {
CSAMPLE m_sampleScaleFactor;
QFile* m_pWVFile;
QFile* m_pWVCFile;

SINT m_curFrameIndex;
};

class SoundSourceProviderWV: public SoundSourceProvider {
Expand Down
22 changes: 20 additions & 2 deletions src/sources/soundsourcecoreaudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,27 @@ SINT SoundSourceCoreAudio::seekSampleFrame(SINT frameIndex) {

SINT SoundSourceCoreAudio::readSampleFrames(
SINT numberOfFrames, CSAMPLE* sampleBuffer) {
//if (!m_decoder) return 0;
SINT numFramesRead = 0;
DEBUG_ASSERT(numberOfFrames >= 0);
if (numberOfFrames <= 0) {
return 0;
}

// Handle special case: Skipping instead of reading
if (sampleBuffer == nullptr) {
SInt64 frameOffset = 0;
const OSStatus osErr = ExtAudioFileTell(m_audioFile, &frameOffset);
if (osErr == noErr) {
const SINT frameIndexBefore = getMinFrameIndex() + frameOffset;
const SINT frameIndexAfter = seekSampleFrame(frameIndexBefore + numberOfFrames);
DEBUG_ASSERT(frameIndexBefore <= frameIndexAfter);
return frameIndexAfter - frameIndexBefore;
} else {
qWarning() << "SSCA: Error to determine the current position for skipping sample frames" << osErr;
return 0; // abort
}
}

SINT numFramesRead = 0;
while (numFramesRead < numberOfFrames) {
SINT numFramesToRead = numberOfFrames - numFramesRead;

Expand Down
69 changes: 33 additions & 36 deletions src/sources/soundsourcemp3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audio
// Abort
return OpenResult::FAILED;
}
DEBUG_ASSERT(m_seekFrameList.front().frameIndex == getMinFrameIndex());

int mostCommonSamplingRateIndex = kSamplingRateCount; // invalid
int mostCommonSamplingRateCount = 0;
Expand Down Expand Up @@ -351,13 +352,12 @@ SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audio

// Terminate m_seekFrameList
addSeekFrame(m_curFrameIndex, 0);

// Reset positions
m_curFrameIndex = getMinFrameIndex();
DEBUG_ASSERT(m_seekFrameList.back().frameIndex == getMaxFrameIndex());

// Restart decoding at the beginning of the audio stream
m_curFrameIndex = restartDecoding(m_seekFrameList.front());
if (m_curFrameIndex != m_seekFrameList.front().frameIndex) {
restartDecoding(m_seekFrameList.front());

if (m_curFrameIndex != getMinFrameIndex()) {
qWarning() << "Failed to start decoding:" << m_file.fileName();
// Abort
return OpenResult::FAILED;
Expand All @@ -383,7 +383,7 @@ void SoundSourceMp3::close() {
initDecoding();
}

SINT SoundSourceMp3::restartDecoding(
void SoundSourceMp3::restartDecoding(
const SeekFrameType& seekFrame) {
qDebug() << "restartDecoding @" << seekFrame.frameIndex;

Expand Down Expand Up @@ -415,14 +415,13 @@ SINT SoundSourceMp3::restartDecoding(
mad_synth_mute(&m_madSynth);
}

if (!decodeFrameHeader(&m_madFrame.header, &m_madStream, false)) {
if (!isStreamValid(m_madStream)) {
// Failure -> Seek to EOF
return getFrameCount();
}
if (decodeFrameHeader(&m_madFrame.header, &m_madStream, false)
&& isStreamValid(m_madStream)) {
m_curFrameIndex = seekFrame.frameIndex;
} else {
// Failure -> Seek to EOF
m_curFrameIndex = getMaxFrameIndex();
}

return seekFrame.frameIndex;
}

void SoundSourceMp3::addSeekFrame(
Expand Down Expand Up @@ -485,20 +484,17 @@ SINT SoundSourceMp3::findSeekFrameIndex(

SINT SoundSourceMp3::seekSampleFrame(SINT frameIndex) {
DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));
DEBUG_ASSERT(isValidFrameIndex(frameIndex));

// Handle trivial case
if (m_curFrameIndex == frameIndex) {
// Nothing to do
return m_curFrameIndex;
}
// Handle edge case
if (getMaxFrameIndex() <= frameIndex) {
if (frameIndex >= getMaxFrameIndex()) {
// EOF reached
m_curFrameIndex = getMaxFrameIndex();
return m_curFrameIndex;
}

if (frameIndex == m_curFrameIndex) {
return m_curFrameIndex;
}

SINT seekFrameIndex = findSeekFrameIndex(
frameIndex);
DEBUG_ASSERT(SINT(m_seekFrameList.size()) > seekFrameIndex);
Expand All @@ -513,8 +509,6 @@ SINT SoundSourceMp3::seekSampleFrame(SINT frameIndex) {
(seekFrameIndex > (curSeekFrameIndex + kMp3SeekFramePrefetchCount))) { // jump forward

// Adjust the seek frame index for prefetching
// Implementation note: The type SINT is unsigned so
// need to be careful when subtracting!
if (kMp3SeekFramePrefetchCount < seekFrameIndex) {
// Restart decoding kMp3SeekFramePrefetchCount seek frames
// before the expected sync position
Expand All @@ -524,24 +518,22 @@ SINT SoundSourceMp3::seekSampleFrame(SINT frameIndex) {
seekFrameIndex = 0;
}

m_curFrameIndex = restartDecoding(m_seekFrameList[seekFrameIndex]);
if (getMaxFrameIndex() <= m_curFrameIndex) {
// out of range -> abort
return m_curFrameIndex;
}
restartDecoding(m_seekFrameList[seekFrameIndex]);

DEBUG_ASSERT(findSeekFrameIndex(m_curFrameIndex) == seekFrameIndex);
}

// Decoding starts before the actual target position
// Decoding starts at or before the actual target position
DEBUG_ASSERT(m_curFrameIndex <= frameIndex);

// Skip (= decode and discard) all samples up to the target position
const SINT prefetchFrameCount = frameIndex - m_curFrameIndex;
const SINT skipFrameCount = skipSampleFrames(prefetchFrameCount);
DEBUG_ASSERT(skipFrameCount <= prefetchFrameCount);
if (skipFrameCount < prefetchFrameCount) {
qWarning() << "Failed to prefetch sample data while seeking"
<< skipFrameCount << "<" << prefetchFrameCount;
if (m_curFrameIndex < frameIndex) {
skipSampleFrames(frameIndex - m_curFrameIndex);
DEBUG_ASSERT(m_curFrameIndex <= frameIndex);
if (m_curFrameIndex < frameIndex) {
qWarning() << "Failed to prefetch sample data while seeking:"
<< m_curFrameIndex << "<" << frameIndex;
}
}

DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));
Expand Down Expand Up @@ -590,7 +582,12 @@ SINT SoundSourceMp3::readSampleFrames(
if (mad_frame_decode(&m_madFrame, &m_madStream)) {
// Something went wrong when decoding the frame...
if (MAD_ERROR_BUFLEN == m_madStream.error) {
// Abort
// Abort when reaching the end of the stream
DEBUG_ASSERT(isUnrecoverableError(m_madStream));
if (m_curFrameIndex < getMaxFrameIndex()) {
qWarning() << "End of MP3 stream is unreachable:"
<< m_curFrameIndex << "<" << getMaxFrameIndex();
}
break;
}
if (isUnrecoverableError(m_madStream)) {
Expand Down
7 changes: 2 additions & 5 deletions src/sources/soundsourcemp3.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ class SoundSourceMp3: public SoundSource {
SINT m_curFrameIndex;

// NOTE(uklotzde): Each invocation of initDecoding() must be
// followed by an invocation of finishDecoding(). In between
// 2 matching invocations restartDecoding() might invoked any
// number of times, but only if the files has been opened
// successfully.
// followed by an invocation of finishDecoding().
void initDecoding();
SINT restartDecoding(const SeekFrameType& seekFrame);
void restartDecoding(const SeekFrameType& seekFrame);
void finishDecoding();

// MAD decoder
Expand Down
Loading