decoder/opus: support chained streams
This commit is contained in:
parent
ba6f2b0467
commit
c98cb1d6f9
1
NEWS
1
NEWS
|
@ -10,6 +10,7 @@ ver 0.19.3 (not yet released)
|
||||||
- audiofile: fix bit rate calculation
|
- audiofile: fix bit rate calculation
|
||||||
- ffmpeg: support opus
|
- ffmpeg: support opus
|
||||||
- opus: fix bogus duration on streams
|
- opus: fix bogus duration on streams
|
||||||
|
- opus: support chained streams
|
||||||
- opus: improved error logging
|
- opus: improved error logging
|
||||||
* fix distorted audio with soxr resampler
|
* fix distorted audio with soxr resampler
|
||||||
* fix build failure on Mac OS X with non-Apple compilers
|
* fix build failure on Mac OS X with non-Apple compilers
|
||||||
|
|
|
@ -77,6 +77,14 @@ class MPDOpusDecoder {
|
||||||
OpusDecoder *opus_decoder;
|
OpusDecoder *opus_decoder;
|
||||||
opus_int16 *output_buffer;
|
opus_int16 *output_buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If non-zero, then a previous Opus stream has been found
|
||||||
|
* already with this number of channels. If opus_decoder is
|
||||||
|
* nullptr, then its end-of-stream packet has been found
|
||||||
|
* already.
|
||||||
|
*/
|
||||||
|
unsigned previous_channels;
|
||||||
|
|
||||||
bool os_initialized;
|
bool os_initialized;
|
||||||
|
|
||||||
int opus_serialno;
|
int opus_serialno;
|
||||||
|
@ -91,6 +99,7 @@ public:
|
||||||
:decoder(_decoder), input_stream(_input_stream),
|
:decoder(_decoder), input_stream(_input_stream),
|
||||||
opus_decoder(nullptr),
|
opus_decoder(nullptr),
|
||||||
output_buffer(nullptr),
|
output_buffer(nullptr),
|
||||||
|
previous_channels(0),
|
||||||
os_initialized(false) {}
|
os_initialized(false) {}
|
||||||
~MPDOpusDecoder();
|
~MPDOpusDecoder();
|
||||||
|
|
||||||
|
@ -245,7 +254,14 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(opus_decoder == nullptr);
|
assert(opus_decoder == nullptr);
|
||||||
assert(output_buffer == nullptr);
|
assert((previous_channels == 0) == (output_buffer == nullptr));
|
||||||
|
|
||||||
|
if (previous_channels != 0 && channels != previous_channels) {
|
||||||
|
FormatWarning(opus_domain,
|
||||||
|
"Next stream has different channels (%u -> %u)",
|
||||||
|
previous_channels, channels);
|
||||||
|
return DecoderCommand::STOP;
|
||||||
|
}
|
||||||
|
|
||||||
opus_serialno = os.serialno;
|
opus_serialno = os.serialno;
|
||||||
|
|
||||||
|
@ -261,6 +277,13 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
|
||||||
return DecoderCommand::STOP;
|
return DecoderCommand::STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previous_channels != 0) {
|
||||||
|
/* decoder was already initialized by the previous
|
||||||
|
stream; skip the rest of this method */
|
||||||
|
LogDebug(opus_domain, "Found another stream");
|
||||||
|
return decoder_get_command(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
eos_granulepos = LoadEOSGranulePos(input_stream, &decoder,
|
eos_granulepos = LoadEOSGranulePos(input_stream, &decoder,
|
||||||
opus_serialno);
|
opus_serialno);
|
||||||
const auto duration = eos_granulepos >= 0
|
const auto duration = eos_granulepos >= 0
|
||||||
|
@ -268,6 +291,7 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
|
||||||
opus_sample_rate)
|
opus_sample_rate)
|
||||||
: SignedSongTime::Negative();
|
: SignedSongTime::Negative();
|
||||||
|
|
||||||
|
previous_channels = channels;
|
||||||
const AudioFormat audio_format(opus_sample_rate,
|
const AudioFormat audio_format(opus_sample_rate,
|
||||||
SampleFormat::S16, channels);
|
SampleFormat::S16, channels);
|
||||||
decoder_initialized(decoder, audio_format,
|
decoder_initialized(decoder, audio_format,
|
||||||
|
@ -283,6 +307,17 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
|
||||||
inline DecoderCommand
|
inline DecoderCommand
|
||||||
MPDOpusDecoder::HandleEOS()
|
MPDOpusDecoder::HandleEOS()
|
||||||
{
|
{
|
||||||
|
if (eos_granulepos < 0 && previous_channels != 0) {
|
||||||
|
/* allow chaining of (unseekable) streams */
|
||||||
|
assert(opus_decoder != nullptr);
|
||||||
|
assert(output_buffer != nullptr);
|
||||||
|
|
||||||
|
opus_decoder_destroy(opus_decoder);
|
||||||
|
opus_decoder = nullptr;
|
||||||
|
|
||||||
|
return decoder_get_command(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
return DecoderCommand::STOP;
|
return DecoderCommand::STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue