hwopus: Implement DecodeInterleaved
This functions almost identically to DecodeInterleavedWithPerfOld, however this function also has the ability to reset the decoder context. This is documented as a potentially desirable thing in the libopus manual in some circumstances as it says for the OPUS_RESET_STATE ctl: "This should be called when switching streams in order to prevent the back to back decoding from giving different result from one at a time decoding."
This commit is contained in:
parent
07b86dc28c
commit
a897feb21e
|
@ -37,7 +37,7 @@ public:
|
||||||
{3, nullptr, "SetContextForMultiStream"},
|
{3, nullptr, "SetContextForMultiStream"},
|
||||||
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
|
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
|
||||||
{5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
|
{5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
|
||||||
{6, nullptr, "DecodeInterleaved"},
|
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
||||||
{7, nullptr, "DecodeInterleavedForMultiStream"},
|
{7, nullptr, "DecodeInterleavedForMultiStream"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -46,24 +46,49 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Describes extra behavior that may be asked of the decoding context.
|
||||||
|
enum class ExtraBehavior {
|
||||||
|
/// No extra behavior.
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// Resets the decoder context back to a freshly initialized state.
|
||||||
|
ResetContext,
|
||||||
|
};
|
||||||
|
|
||||||
void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) {
|
void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Audio, "called");
|
LOG_DEBUG(Audio, "called");
|
||||||
|
|
||||||
DecodeInterleavedHelper(ctx, nullptr);
|
DecodeInterleavedHelper(ctx, nullptr, ExtraBehavior::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) {
|
void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Audio, "called");
|
LOG_DEBUG(Audio, "called");
|
||||||
|
|
||||||
u64 performance = 0;
|
u64 performance = 0;
|
||||||
DecodeInterleavedHelper(ctx, &performance);
|
DecodeInterleavedHelper(ctx, &performance, ExtraBehavior::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecodeInterleavedHelper(Kernel::HLERequestContext& ctx, u64* performance) {
|
void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Audio, "called");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto extra_behavior =
|
||||||
|
rp.Pop<bool>() ? ExtraBehavior::ResetContext : ExtraBehavior::None;
|
||||||
|
|
||||||
|
u64 performance = 0;
|
||||||
|
DecodeInterleavedHelper(ctx, &performance, extra_behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecodeInterleavedHelper(Kernel::HLERequestContext& ctx, u64* performance,
|
||||||
|
ExtraBehavior extra_behavior) {
|
||||||
u32 consumed = 0;
|
u32 consumed = 0;
|
||||||
u32 sample_count = 0;
|
u32 sample_count = 0;
|
||||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||||
|
|
||||||
|
if (extra_behavior == ExtraBehavior::ResetContext) {
|
||||||
|
ResetDecoderContext();
|
||||||
|
}
|
||||||
|
|
||||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
|
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
|
||||||
performance)) {
|
performance)) {
|
||||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||||
|
@ -136,6 +161,12 @@ private:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResetDecoderContext() {
|
||||||
|
ASSERT(decoder != nullptr);
|
||||||
|
|
||||||
|
opus_decoder_ctl(decoder.get(), OPUS_RESET_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
struct OpusHeader {
|
struct OpusHeader {
|
||||||
u32_be sz; // Needs to be BE for some odd reason
|
u32_be sz; // Needs to be BE for some odd reason
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
|
|
Reference in New Issue