Bug 1431810 - Disable Opus phase inversion on stereo to mono downmix. r=rillian
☠☠ backed out by 422ce7e85434 ☠ ☠
authorAlex Chronopoulos <achronop@gmail.com>
Thu, 15 Mar 2018 18:28:14 +0200
changeset 409912 3fe9d85d684a63cbdcae20508f0db318005fd5c0
parent 409911 d83bf99d438d2f0edd7873d9f6fffc077d9deaf9
child 409913 43eb1c01c67f86d1a2b0531434a53b15f80592d9
push id61670
push userachronop@gmail.com
push dateMon, 26 Mar 2018 07:07:05 +0000
treeherderautoland@a01c1941a829 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs1431810
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1431810 - Disable Opus phase inversion on stereo to mono downmix. r=rillian MozReview-Commit-ID: 5eaSPQzUu9o
dom/media/VideoUtils.cpp
dom/media/VideoUtils.h
dom/media/mediasink/AudioSink.cpp
dom/media/platforms/agnostic/OpusDecoder.cpp
--- 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
@@ -90,16 +90,27 @@ OpusDataDecoder::Init()
   MOZ_ASSERT(mMappingTable.Length() >= uint32_t(mOpusParser->mChannels));
   int r;
   mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
                                                  mOpusParser->mChannels,
                                                  mOpusParser->mStreams,
                                                  mOpusParser->mCoupledStreams,
                                                  mMappingTable.Elements(),
                                                  &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__);
   }