Bug 1248861: P10. Ensure opus decoder channel layout is always in SMPTE order. r?rillian
MozReview-Commit-ID: BDZ25pXJQWa
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -2,17 +2,19 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OpusDecoder.h"
#include "TimeUnits.h"
#include "VorbisUtils.h"
+#include "VorbisDecoder.h" // For VorbisLayout
#include "mozilla/Endian.h"
+#include "mozilla/PodOperations.h"
#include <stdint.h>
#include <inttypes.h> // For PRId64
extern mozilla::LogModule* GetPDMLog();
#define OPUS_DEBUG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, \
("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
@@ -61,17 +63,17 @@ OpusDataDecoder::Init()
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
int r;
mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
mOpusParser->mChannels,
mOpusParser->mStreams,
mOpusParser->mCoupledStreams,
- mOpusParser->mMappingTable,
+ mMappingTable,
&r);
mSkip = mOpusParser->mPreSkip;
mPaddingDiscarded = false;
if (codecDelay != FramesToUsecs(mOpusParser->mPreSkip,
mOpusParser->mRate).value()) {
NS_WARNING("Invalid Opus header: CodecDelay and pre-skip do not match!");
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
@@ -95,23 +97,40 @@ OpusDataDecoder::DecodeHeader(const unsi
MOZ_ASSERT(!mOpusDecoder);
MOZ_ASSERT(!mDecodedHeader);
mDecodedHeader = true;
mOpusParser = new OpusParser;
if (!mOpusParser->DecodeHeader(const_cast<unsigned char*>(aData), aLength)) {
return NS_ERROR_FAILURE;
}
+ int channels = mOpusParser->mChannels;
// No channel mapping for more than 8 channels.
- if (mOpusParser->mChannels > 8) {
+ if (channels > 8) {
OPUS_DEBUG("No channel mapping for more than 8 channels. Source is %d channels",
- mOpusParser->mChannels);
+ channels);
return NS_ERROR_FAILURE;
}
+ AudioConfig::ChannelLayout vorbisLayout(
+ channels, VorbisDataDecoder::VorbisLayout(channels));
+ AudioConfig::ChannelLayout smpteLayout(channels);
+ static_assert(sizeof(mOpusParser->mMappingTable) / sizeof(mOpusParser->mMappingTable[0]) >= MAX_AUDIO_CHANNELS,
+ "Invalid size set");
+ uint8_t map[sizeof(mOpusParser->mMappingTable) / sizeof(mOpusParser->mMappingTable[0])];
+ if (vorbisLayout.MappingTable(smpteLayout, map)) {
+ for (int i = 0; i < channels; i++) {
+ mMappingTable[i] = mOpusParser->mMappingTable[map[i]];
+ }
+ } else {
+ // Should never get here as vorbis layout is always convertible to SMPTE
+ // default layout.
+ PodCopy(mMappingTable, mOpusParser->mMappingTable, MAX_AUDIO_CHANNELS);
+ }
+
return NS_OK;
}
nsresult
OpusDataDecoder::Input(MediaRawData* aSample)
{
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableMethodWithArg<RefPtr<MediaRawData>>(
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -54,12 +54,13 @@ private:
bool mDecodedHeader;
// Opus padding should only be discarded on the final packet. Once this
// is set to true, if the reader attempts to decode any further packets it
// will raise an error so we can indicate that the file is invalid.
bool mPaddingDiscarded;
int64_t mFrames;
Maybe<int64_t> mLastFrameTime;
+ uint8_t mMappingTable[MAX_AUDIO_CHANNELS]; // Channel mapping table.
};
} // namespace mozilla
#endif