Bug 1542097 - Directly downmix to mono. r=bryce a=lizzard
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 22 Apr 2019 13:27:42 +0000
changeset 526433 a6d52faaa77c3c7be1e3614157eb2bc15d7b488f
parent 526432 c30959fc3dfaa06dcc16e4e2bb57ea30f3fda44e
child 526434 327f82eb58800f2432c453e0df2604ce290fce10
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce, lizzard
bugs1542097
milestone67.0
Bug 1542097 - Directly downmix to mono. r=bryce a=lizzard 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;