From 1b48a48075e46ae79d6860f10cd74c4c1bdc50b0 Mon Sep 17 00:00:00 2001
From: Eloi BAIL <eloi.bail@savoirfairelinux.com>
Date: Wed, 21 Jan 2015 15:01:52 -0500
Subject: [PATCH] daemon: handle libav opus native decoder

Since libavcodec56 libav native opus decoder is used instead of libopus
decoder.
This decoder only ouput float planar audio data (AV_SAMPLE_FMT_FLTP)
This commit detect the output format and convert it to signed 16bits
in case of float planar.

Refs #64245

Change-Id: Idb8240a1158a0add446d7df3b4a1ed51089e2781
---
 daemon/src/media/audio/audiobuffer.cpp | 20 ++++++++++++++++++++
 daemon/src/media/audio/audiobuffer.h   |  6 ++++++
 daemon/src/media/media_decoder.cpp     |  9 +++++++--
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/daemon/src/media/audio/audiobuffer.cpp b/daemon/src/media/audio/audiobuffer.cpp
index 40d11e1087..5310536e9e 100644
--- a/daemon/src/media/audio/audiobuffer.cpp
+++ b/daemon/src/media/audio/audiobuffer.cpp
@@ -214,6 +214,26 @@ void AudioBuffer::deinterleave(const std::vector<ring::AudioSample>& in, AudioFo
     deinterleave(in.data(), in.size()/format.nb_channels, format.nb_channels);
 }
 
+void AudioBuffer::convertFloatPlanarToSigned16(uint8_t** extended_data, size_t frame_num, unsigned nb_channels)
+{
+    if (extended_data == nullptr)
+        return;
+
+    // Resize buffer
+    setChannelNum(nb_channels);
+    resize(frame_num);
+
+    for (unsigned j = 0, c = channels(); j < c; j++){
+        float* inputChannel = (float*)extended_data[j];
+        for (unsigned i=0, f=frames(); i < f; i++){
+            float inputChannelVal = *inputChannel++;
+            // avoid saturation: limit val between -1 and 1
+            inputChannelVal = std::max(-1.0f, std::min(inputChannelVal, 1.0f));
+            samples_[j][i] = (int16_t) (inputChannelVal * 32768.0f);
+        }
+    }
+}
+
 size_t AudioBuffer::mix(const AudioBuffer& other, bool up /* = true */)
 {
     const bool upmix = up && (other.samples_.size() < samples_.size());
diff --git a/daemon/src/media/audio/audiobuffer.h b/daemon/src/media/audio/audiobuffer.h
index 3d22eb9e47..fffd5c2c7e 100644
--- a/daemon/src/media/audio/audiobuffer.h
+++ b/daemon/src/media/audio/audiobuffer.h
@@ -288,6 +288,12 @@ class AudioBuffer {
          */
         void deinterleave(const std::vector<ring::AudioSample>& in, AudioFormat format);
 
+        /**
+         * convert float planar data to signed 16
+         */
+        void convertFloatPlanarToSigned16(uint8_t** extended_data, size_t frame_num, unsigned nb_channels = 1);
+
+
         /**
          * In-place gain transformation.
          *
diff --git a/daemon/src/media/media_decoder.cpp b/daemon/src/media/media_decoder.cpp
index 4a14fef788..2b8a517da7 100644
--- a/daemon/src/media/media_decoder.cpp
+++ b/daemon/src/media/media_decoder.cpp
@@ -432,8 +432,13 @@ void MediaDecoder::writeToRingBuffer(AVFrame* decoded_frame,
 
     ring::AudioBuffer out(decoded_frame->nb_samples, decoderFormat);
 
-    out.deinterleave(reinterpret_cast<const ring::AudioSample*>(decoded_frame->data[0]),
-                     decoded_frame->nb_samples, decoderCtx_->channels);
+    if ( decoderCtx_->sample_fmt == AV_SAMPLE_FMT_FLTP ) {
+        out.convertFloatPlanarToSigned16(decoded_frame->extended_data,
+                         decoded_frame->nb_samples, decoderCtx_->channels);
+    } else if ( decoderCtx_->sample_fmt == AV_SAMPLE_FMT_S16 ) {
+        out.deinterleave(reinterpret_cast<const ring::AudioSample*>(decoded_frame->data[0]),
+                         decoded_frame->nb_samples, decoderCtx_->channels);
+    }
     if ((unsigned)decoded_frame->sample_rate != outFormat.sample_rate) {
         if (!resampler_) {
             RING_DBG("Creating audio resampler");
-- 
GitLab