Bug 1542097 - Directly downmix to mono. r=bryce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 22 Apr 2019 13:27:42 +0000
changeset 470362 32e046bfdeab2df91e89a584c718346c1a09712c
parent 470361 4bc97c0629fad26ca8739c69bd5fe36e746b18ff
child 470363 d3b41d3190e54ded4fb5c3894042e4d067865c82
push id112868
push useropoprus@mozilla.com
push dateMon, 22 Apr 2019 22:19:22 +0000
treeherdermozilla-inbound@24537856cc88 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce
bugs1542097
milestone68.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 1542097 - Directly downmix to mono. r=bryce No need to first downmix to stereo and then mono. Differential Revision: https://phabricator.services.mozilla.com/D27216
dom/media/AudioConverter.cpp
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "AudioConverter.h"
+#include <speex/speex_resampler.h>
 #include <string.h>
-#include <speex/speex_resampler.h>
 #include <cmath>
 
 /*
  *  Parts derived from MythTV AudioConvert Class
  *  Created by Jean-Yves Avenard.
  *
  *  Copyright (C) Bubblestuff Pty Ltd 2013
  *  Copyright (C) foobum@gmail.com 2010
@@ -146,49 +146,50 @@ static void dumbUpDownMix(TYPE* aOut, in
     for (int32_t j = 0; j < aInChannels - aOutChannels; j++) {
       aOut[i * aOutChannels + j] = 0;
     }
   }
 }
 
 size_t AudioConverter::DownmixAudio(void* aOut, const void* aIn,
                                     size_t aFrames) const {
-  MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
-             mIn.Format() == AudioConfig::FORMAT_FLT);
-  MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
-  MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
-             mOut.Layout() == AudioConfig::ChannelLayout(1));
+  MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
+                        mIn.Format() == AudioConfig::FORMAT_FLT);
+  MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() >= mOut.Channels());
+  MOZ_DIAGNOSTIC_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
+                        mOut.Layout() == AudioConfig::ChannelLayout(1));
 
-  uint32_t channels = mIn.Channels();
+  uint32_t inChannels = mIn.Channels();
+  uint32_t outChannels = mOut.Channels();
 
-  if (channels == 1 && mOut.Channels() == 1) {
+  if (inChannels == outChannels) {
     if (aOut != aIn) {
       memmove(aOut, aIn, FramesOutToBytes(aFrames));
     }
     return aFrames;
   }
 
   if (!mIn.Layout().IsValid() || !mOut.Layout().IsValid()) {
     // Dumb copy dropping extra channels.
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
-      dumbUpDownMix(static_cast<float*>(aOut), mOut.Channels(),
-                    static_cast<const float*>(aIn), mIn.Channels(), aFrames);
+      dumbUpDownMix(static_cast<float*>(aOut), outChannels,
+                    static_cast<const float*>(aIn), inChannels, aFrames);
     } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
-      dumbUpDownMix(static_cast<int16_t*>(aOut), mOut.Channels(),
-                    static_cast<const int16_t*>(aIn), mIn.Channels(), aFrames);
+      dumbUpDownMix(static_cast<int16_t*>(aOut), outChannels,
+                    static_cast<const int16_t*>(aIn), inChannels, aFrames);
     } else {
       MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
     }
     return aFrames;
   }
 
   MOZ_ASSERT(
       mIn.Layout() == AudioConfig::ChannelLayout::SMPTEDefault(mIn.Layout()),
       "Can only downmix input data in SMPTE layout");
-  if (channels > 2) {
+  if (inChannels > 2) {
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
       // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows
       // 5-8.
       static const float dmatrix[6][8][2] = {
           /*3*/ {{0.5858f, 0}, {0, 0.5858f}, {0.4142f, 0.4142f}},
           /*4*/
           {{0.4226f, 0}, {0, 0.4226f}, {0.366f, 0.2114f}, {0.2114f, 0.366f}},
           /*5*/
@@ -223,24 +224,26 @@ size_t AudioConverter::DownmixAudio(void
            {0.1943f, 0.3366f}},
       };
       // Re-write the buffer with downmixed data
       const float* in = static_cast<const float*>(aIn);
       float* out = static_cast<float*>(aOut);
       for (uint32_t i = 0; i < aFrames; i++) {
         float sampL = 0.0;
         float sampR = 0.0;
-        for (uint32_t j = 0; j < channels; j++) {
-          sampL +=
-              in[i * mIn.Channels() + j] * dmatrix[mIn.Channels() - 3][j][0];
-          sampR +=
-              in[i * mIn.Channels() + j] * dmatrix[mIn.Channels() - 3][j][1];
+        for (uint32_t j = 0; j < inChannels; j++) {
+          sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0];
+          sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1];
         }
-        *out++ = sampL;
-        *out++ = sampR;
+        if (outChannels == 2) {
+          *out++ = sampL;
+          *out++ = sampR;
+        } else {
+          *out++ = (sampL + sampR) * 0.5;
+        }
       }
     } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
       // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows
       // 5-8. Coefficients in Q14.
       static const int16_t dmatrix[6][8][2] = {
           /*3*/ {{9598, 0}, {0, 9598}, {6786, 6786}},
           /*4*/ {{6925, 0}, {0, 6925}, {5997, 3462}, {3462, 5997}},
           /*5*/
@@ -270,55 +273,56 @@ size_t AudioConverter::DownmixAudio(void
            {5514, 3184},
            {3184, 5514}}};
       // Re-write the buffer with downmixed data
       const int16_t* in = static_cast<const int16_t*>(aIn);
       int16_t* out = static_cast<int16_t*>(aOut);
       for (uint32_t i = 0; i < aFrames; i++) {
         int32_t sampL = 0;
         int32_t sampR = 0;
-        for (uint32_t j = 0; j < channels; j++) {
-          sampL += in[i * channels + j] * dmatrix[channels - 3][j][0];
-          sampR += in[i * channels + j] * dmatrix[channels - 3][j][1];
+        for (uint32_t j = 0; j < inChannels; j++) {
+          sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0];
+          sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1];
         }
-        *out++ = clipTo15((sampL + 8192) >> 14);
-        *out++ = clipTo15((sampR + 8192) >> 14);
+        sampL = clipTo15((sampL + 8192) >> 14);
+        sampR = clipTo15((sampR + 8192) >> 14);
+        if (outChannels == 2) {
+          *out++ = sampL;
+          *out++ = sampR;
+        } else {
+          *out++ = (sampL + sampR) * 0.5;
+        }
       }
     } else {
       MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
     }
-
-    // If we are to continue downmixing to mono, start working on the output
-    // buffer.
-    aIn = aOut;
-    channels = 2;
+    return aFrames;
   }
 
-  if (mOut.Channels() == 1) {
-    if (mIn.Format() == AudioConfig::FORMAT_FLT) {
-      const float* in = static_cast<const float*>(aIn);
-      float* out = static_cast<float*>(aOut);
-      for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
-        float sample = 0.0;
-        // The sample of the buffer would be interleaved.
-        sample = (in[fIdx * channels] + in[fIdx * channels + 1]) * 0.5;
-        *out++ = sample;
-      }
-    } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
-      const int16_t* in = static_cast<const int16_t*>(aIn);
-      int16_t* out = static_cast<int16_t*>(aOut);
-      for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
-        int32_t sample = 0.0;
-        // The sample of the buffer would be interleaved.
-        sample = (in[fIdx * channels] + in[fIdx * channels + 1]) * 0.5;
-        *out++ = sample;
-      }
-    } else {
-      MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
+  MOZ_DIAGNOSTIC_ASSERT(inChannels == 2 && outChannels == 1);
+  if (mIn.Format() == AudioConfig::FORMAT_FLT) {
+    const float* in = static_cast<const float*>(aIn);
+    float* out = static_cast<float*>(aOut);
+    for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
+      float sample = 0.0;
+      // The sample of the buffer would be interleaved.
+      sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5;
+      *out++ = sample;
     }
+  } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
+    const int16_t* in = static_cast<const int16_t*>(aIn);
+    int16_t* out = static_cast<int16_t*>(aOut);
+    for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
+      int32_t sample = 0.0;
+      // The sample of the buffer would be interleaved.
+      sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5;
+      *out++ = sample;
+    }
+  } else {
+    MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
   }
   return aFrames;
 }
 
 size_t AudioConverter::ResampleAudio(void* aOut, const void* aIn,
                                      size_t aFrames) {
   if (!mResampler) {
     return 0;