Bug 1431810 - Disable Opus phase inversion on stereo to mono downmix. r?rillian
MozReview-Commit-ID: 5eaSPQzUu9o
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -157,16 +157,29 @@ void DownmixStereoToMono(mozilla::AudioD
int sample = 0;
#endif
// The sample of the buffer would be interleaved.
sample = (aBuffer[fIdx*channels] + aBuffer[fIdx*channels + 1]) * 0.5;
aBuffer[fIdx*channels] = aBuffer[fIdx*channels + 1] = sample;
}
}
+uint32_t DecideAudioPlaybackChannels(const AudioInfo& info)
+{
+ if (MediaPrefs::MonoAudio()) {
+ return 1;
+ }
+
+ if (MediaPrefs::AudioSinkForceStereo()) {
+ return 2;
+ }
+
+ return info.mChannels;
+}
+
bool
IsVideoContentType(const nsCString& aContentType)
{
NS_NAMED_LITERAL_CSTRING(video, "video");
if (FindInReadable(video, aContentType)) {
return true;
}
return false;
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -153,16 +153,20 @@ nsresult SecondsToUsecs(double aSeconds,
void
ScaleDisplayByAspectRatio(gfx::IntSize& aDisplay, float aAspectRatio);
// Downmix Stereo audio samples to Mono.
// Input are the buffer contains stereo data and the number of frames.
void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer,
uint32_t aFrames);
+// Decide the number of playback channels according to the
+// given AudioInfo and the prefs that are being set.
+uint32_t DecideAudioPlaybackChannels(const AudioInfo& info);
+
bool IsVideoContentType(const nsCString& aContentType);
// Returns true if it's safe to use aPicture as the picture to be
// extracted inside a frame of size aFrame, and scaled up to and displayed
// at a size of aDisplay. You should validate the frame, picture, and
// display regions before using them to display video frames.
bool
IsValidVideoRegion(const gfx::IntSize& aFrame,
--- a/dom/media/mediasink/AudioSink.cpp
+++ b/dom/media/mediasink/AudioSink.cpp
@@ -59,22 +59,17 @@ AudioSink::AudioSink(AbstractThread* aTh
// content provider want change from those rates mid-stream.
mOutputRate = mInfo.mRate;
} else {
// We will resample all data to match cubeb's preferred sampling rate.
mOutputRate = AudioStream::GetPreferredRate();
}
MOZ_DIAGNOSTIC_ASSERT(mOutputRate, "output rate can't be 0.");
- bool monoAudioEnabled = MediaPrefs::MonoAudio();
-
- mOutputChannels =
- monoAudioEnabled
- ? 1
- : (MediaPrefs::AudioSinkForceStereo() ? 2 : mInfo.mChannels);
+ mOutputChannels = DecideAudioPlaybackChannels(mInfo);
}
AudioSink::~AudioSink()
{
}
RefPtr<GenericPromise>
AudioSink::Init(const PlaybackParams& aParams)
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -88,16 +88,27 @@ OpusDataDecoder::Init()
int r;
mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
mOpusParser->mChannels,
mOpusParser->mStreams,
mOpusParser->mCoupledStreams,
mMappingTable,
&r);
+
+ // Opus has a special feature for stereo coding where it represent wide
+ // stereo channels by 180-degree out of phase. This improves quality, but
+ // needs to be disabled when the output is downmixed to mono. Playback number
+ // of channels are set in AudioSink, using the same method
+ // `DecideAudioPlaybackChannels()`, and triggers downmix if needed.
+ if (mOpusDecoder && mOpusParser->mChannels == 2 &&
+ DecideAudioPlaybackChannels(mInfo) == 1) {
+ opus_multistream_decoder_ctl(mOpusDecoder, OPUS_SET_PHASE_INVERSION_DISABLED(1));
+ }
+
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(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}