text: // Copyright 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "media/base/audio_buffer.h"
  
  #include <cmath>
  
  #include "base/logging.h"
  #include "media/base/audio_bus.h"
  #include "media/base/limits.h"
  #include "media/base/timestamp_constants.h"
  
  namespace media {
  
  static base::TimeDelta CalculateDuration(int frames, double sample_rate) {
    DCHECK_GT(sample_rate, 0);
    return base::TimeDelta::FromMicroseconds(
        frames * base::Time::kMicrosecondsPerSecond / sample_rate);
  }
  
  AudioBuffer::AudioBuffer(SampleFormat sample_format,
                           ChannelLayout channel_layout,
                           int channel_count,
                           int sample_rate,
                           int frame_count,
                           bool create_buffer,
                           const uint8_t* const* data,
                           const base::TimeDelta timestamp)
      : sample_format_(sample_format),
        channel_layout_(channel_layout),
        channel_count_(channel_count),
        sample_rate_(sample_rate),
        adjusted_frame_count_(frame_count),
        trim_start_(0),
        end_of_stream_(!create_buffer && data == NULL && frame_count == 0),
        timestamp_(timestamp),
        duration_(end_of_stream_
                      ? base::TimeDelta()
                      : CalculateDuration(adjusted_frame_count_, sample_rate_)),
        data_size_(0) {
    CHECK_GE(channel_count_, 0);
    CHECK_LE(channel_count_, limits::kMaxChannels);
    CHECK_GE(frame_count, 0);
    DCHECK(channel_layout == CHANNEL_LAYOUT_DISCRETE ||
           ChannelLayoutToChannelCount(channel_layout) == channel_count);
  
    int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format);
    DCHECK_LE(bytes_per_channel, kChannelAlignment);
  
    // Empty buffer?
    if (!create_buffer)
      return;
  
    int data_size_per_channel = frame_count * bytes_per_channel;
    if (IsPlanar(sample_format)) {
      // Planar data, so need to allocate buffer for each channel.
      // Determine per channel data size, taking into account alignment.
      int block_size_per_channel =
          (data_size_per_channel + kChannelAlignment - 1) &
          ~(kChannelAlignment - 1);
      DCHECK_GE(block_size_per_channel, data_size_per_channel);
  
      // Allocate a contiguous buffer for all the channel data.
      data_size_ = channel_count_ * block_size_per_channel;
      data_.reset(static_cast<uint8_t*>(
          base::AlignedAlloc(data_size_, kChannelAlignment)));
      channel_data_.reserve(channel_count_);
  
      // Copy each channel's data into the appropriate spot.
      for (int i = 0; i < channel_count_; ++i) {
        channel_data_.push_back(data_.get() + i * block_size_per_channel);
        if (data)
          memcpy(channel_data_[i], data[i], data_size_per_channel);
      }
      return;
    }
  
    // Remaining formats are interleaved data.
    DCHECK(IsInterleaved(sample_format)) << sample_format_;
    // Allocate our own buffer and copy the supplied data into it. Buffer must
    // contain the data for all channels.
    data_size_ = data_size_per_channel * channel_count_;
    data_.reset(
        static_cast<uint8_t*>(base::AlignedAlloc(data_size_, kChannelAlignment)));
    channel_data_.reserve(1);
    channel_data_.push_back(data_.get());
    if (data)
      memcpy(data_.get(), data[0], data_size_);
  }
  
  AudioBuffer::~AudioBuffer() {}
  
  // static
  scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom(
      SampleFormat sample_format,
      ChannelLayout channel_layout,
      int channel_count,
      int sample_rate,
      int frame_count,
      const uint8_t* const* data,
      const base::TimeDelta timestamp) {
    // If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
    CHECK_GT(frame_count, 0);  // Otherwise looks like an EOF buffer.
    CHECK(data[0]);
    return make_scoped_refptr(new AudioBuffer(sample_format,
                                              channel_layout,
                                              channel_count,
                                              sample_rate,
                                              frame_count,
                                              true,
                                              data,
                                              timestamp));
  }
  
  // static
  scoped_refptr<AudioBuffer> AudioBuffer::CreateBuffer(
      SampleFormat sample_format,
      ChannelLayout channel_layout,
      int channel_count,
      int sample_rate,
      int frame_count) {
    CHECK_GT(frame_count, 0);  // Otherwise looks like an EOF buffer.
    return make_scoped_refptr(new AudioBuffer(sample_format,
                                              channel_layout,
                                              channel_count,
                                              sample_rate,
                                              frame_count,
                                              true,
                                              NULL,
                                              kNoTimestamp()));
  }
  
  // static
  scoped_refptr<AudioBuffer> AudioBuffer::CreateEmptyBuffer(
      ChannelLayout channel_layout,
      int channel_count,
      int sample_rate,
      int frame_count,
      const base::TimeDelta timestamp) {
    CHECK_GT(frame_count, 0);  // Otherwise looks like an EOF buffer.
    // Since data == NULL, format doesn't matter.
    return make_scoped_refptr(new AudioBuffer(kSampleFormatF32,
                                              channel_layout,
                                              channel_count,
                                              sample_rate,
                                              frame_count,
                                              false,
                                              NULL,
                                              timestamp));
  }
  
  // static
  scoped_refptr<AudioBuffer> AudioBuffer::CreateEOSBuffer() {
    return make_scoped_refptr(new AudioBuffer(kUnknownSampleFormat,
                                              CHANNEL_LAYOUT_NONE,
                                              0,
                                              0,
                                              0,
                                              false,
                                              NULL,
                                              kNoTimestamp()));
  }
  
  template <typename Target, typename Dest>
  static inline Dest ConvertSample(Target value);
  
  // Convert int16_t values in the range [INT16_MIN, INT16_MAX] to [-1.0, 1.0].
  template <>
  inline float ConvertSample<int16_t, float>(int16_t value) {
    return value * (value < 0 ? -1.0f / std::numeric_limits<int16_t>::min()
                              : 1.0f / std::numeric_limits<int16_t>::max());
  }
  
  // Specializations for int32_t
  template <>
  inline int32_t ConvertSample<int16_t, int32_t>(int16_t value) {
    return static_cast<int32_t>(value) << 16;
  }
  
  template <>
  inline int32_t ConvertSample<int32_t, int32_t>(int32_t value) {
    return value;
  }
  
  template <>
  inline int32_t ConvertSample<float, int32_t>(float value) {
    return static_cast<int32_t>(
        value < 0 ? (-value) * std::numeric_limits<int32_t>::min()
                  : value * std::numeric_limits<int32_t>::max());
  }
  
  // Specializations for int16_t
  template <>
  inline int16_t ConvertSample<int16_t, int16_t>(int16_t sample) {
    return sample;
  }
  
  template <>
  inline int16_t ConvertSample<int32_t, int16_t>(int32_t sample) {
    return sample >> 16;
  }
  
  template <>
  inline int16_t ConvertSample<float, int16_t>(float sample) {
    return static_cast<int16_t>(
        nearbyint(sample < 0 ? (-sample) * std::numeric_limits<int16_t>::min()
                             : sample * std::numeric_limits<int16_t>::max()));
  }
  
  void AudioBuffer::AdjustSampleRate(int sample_rate) {
    DCHECK(!end_of_stream_);
    sample_rate_ = sample_rate;
    duration_ = CalculateDuration(adjusted_frame_count_, sample_rate_);
  }
  
  void AudioBuffer::ReadFrames(int frames_to_copy,
                               int source_frame_offset,
                               int dest_frame_offset,
                               AudioBus* dest) {
    // Deinterleave each channel (if necessary) and convert to 32bit
    // floating-point with nominal range -1.0 -> +1.0 (if necessary).
  
    // |dest| must have the same number of channels, and the number of frames
    // specified must be in range.
    DCHECK(!end_of_stream());
    DCHECK_EQ(dest->channels(), channel_count_);
    DCHECK_LE(source_frame_offset + frames_to_copy, adjusted_frame_count_);
    DCHECK_LE(dest_frame_offset + frames_to_copy, dest->frames());
  
    // Move the start past any frames that have been trimmed.
    source_frame_offset += trim_start_;
  
    if (!data_) {
      // Special case for an empty buffer.
      dest->ZeroFramesPartial(dest_frame_offset, frames_to_copy);
      return;
    }
  
    if (sample_format_ == kSampleFormatPlanarF32) {
      // Format is planar float32. Copy the data from each channel as a block.
      for (int ch = 0; ch < channel_count_; ++ch) {
        const float* source_data =
            reinterpret_cast<const float*>(channel_data_[ch]) +
            source_frame_offset;
        memcpy(dest->channel(ch) + dest_frame_offset,
               source_data,
               sizeof(float) * frames_to_copy);
      }
      return;
    }
  
    if (sample_format_ == kSampleFormatPlanarS16) {
      // Format is planar signed16. Convert each value into float and insert into
      // output channel data.
      for (int ch = 0; ch < channel_count_; ++ch) {
        const int16_t* source_data =
            reinterpret_cast<const int16_t*>(channel_data_[ch]) +
            source_frame_offset;
        float* dest_data = dest->channel(ch) + dest_frame_offset;
        for (int i = 0; i < frames_to_copy; ++i) {
          dest_data[i] = ConvertSample<int16_t, float>(source_data[i]);
        }
      }
      return;
    }
  
    if (sample_format_ == kSampleFormatF32) {
      // Format is interleaved float32. Copy the data into each channel.
      const float* source_data = reinterpret_cast<const float*>(data_.get()) +
                                 source_frame_offset * channel_count_;
      for (int ch = 0; ch < channel_count_; ++ch) {
        float* dest_data = dest->channel(ch) + dest_frame_offset;
        for (int i = 0, offset = ch; i < frames_to_copy;
             ++i, offset += channel_count_) {
          dest_data[i] = source_data[offset];
        }
      }
      return;
    }
  
    // Remaining formats are integer interleaved data. Use the deinterleaving code
    // in AudioBus to copy the data.
    DCHECK(
        sample_format_ == kSampleFormatU8 || sample_format_ == kSampleFormatS16 ||
        sample_format_ == kSampleFormatS24 || sample_format_ == kSampleFormatS32);
    int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format_);
    int frame_size = channel_count_ * bytes_per_channel;
    const uint8_t* source_data = data_.get() + source_frame_offset * frame_size;
    dest->FromInterleavedPartial(
        source_data, dest_frame_offset, frames_to_copy, bytes_per_channel);
  }
  
  template <class Target, typename Dest>
  void InterleaveAndConvert(const std::vector<uint8_t*>& channel_data,
                            size_t frames_to_copy,
                            int trim_start,
                            Dest* dest_data) {
    for (size_t ch = 0; ch < channel_data.size(); ++ch) {
      const Target* source_data =
          reinterpret_cast<const Target*>(channel_data[ch]) + trim_start;
      for (size_t i = 0, offset = ch; i < frames_to_copy;
           ++i, offset += channel_data.size()) {
        dest_data[offset] = ConvertSample<Target, Dest>(source_data[i]);
      }
    }
  }
  
  template <typename Dest>
  void ReadFramesInterleaved(const std::vector<uint8_t*>& channel_data,
                             int channel_count,
                             SampleFormat sample_format,
                             int frames_to_copy,
                             int trim_start,
                             Dest* dest_data) {
    switch (sample_format) {
      case kSampleFormatU8:
        NOTREACHED();
        break;
      case kSampleFormatS16:
        InterleaveAndConvert<int16_t, Dest>(
            channel_data, frames_to_copy * channel_count, trim_start, dest_data);
        break;
      case kSampleFormatS24:
      case kSampleFormatS32:
        InterleaveAndConvert<int32_t, Dest>(
            channel_data, frames_to_copy * channel_count, trim_start, dest_data);
        break;
      case kSampleFormatF32:
        InterleaveAndConvert<float, Dest>(
            channel_data, frames_to_copy * channel_count, trim_start, dest_data);
        break;
      case kSampleFormatPlanarS16:
        InterleaveAndConvert<int16_t, Dest>(channel_data, frames_to_copy,
                                            trim_start, dest_data);
        break;
      case kSampleFormatPlanarF32:
        InterleaveAndConvert<float, Dest>(channel_data, frames_to_copy,
                                          trim_start, dest_data);
        break;
      case kSampleFormatPlanarS32:
        InterleaveAndConvert<int32_t, Dest>(channel_data, frames_to_copy,
                                            trim_start, dest_data);
        break;
      case kUnknownSampleFormat:
        NOTREACHED();
        break;
    }
  }
  
  void AudioBuffer::ReadFramesInterleavedS32(int frames_to_copy,
                                             int32_t* dest_data) {
    DCHECK_LE(frames_to_copy, adjusted_frame_count_);
    ReadFramesInterleaved<int32_t>(channel_data_, channel_count_, sample_format_,
                                   frames_to_copy, trim_start_, dest_data);
  }
  
  void AudioBuffer::ReadFramesInterleavedS16(int frames_to_copy,
                                             int16_t* dest_data) {
    DCHECK_LE(frames_to_copy, adjusted_frame_count_);
    ReadFramesInterleaved<int16_t>(channel_data_, channel_count_, sample_format_,
                                   frames_to_copy, trim_start_, dest_data);
  }
  
  void AudioBuffer::TrimStart(int frames_to_trim) {
    CHECK_GE(frames_to_trim, 0);
    CHECK_LE(frames_to_trim, adjusted_frame_count_);
  
    // Adjust the number of frames in this buffer and where the start really is.
    adjusted_frame_count_ -= frames_to_trim;
    trim_start_ += frames_to_trim;
  
    // Adjust timestamp_ and duration_ to reflect the smaller number of frames.
    const base::TimeDelta old_duration = duration_;
    duration_ = CalculateDuration(adjusted_frame_count_, sample_rate_);
    timestamp_ += old_duration - duration_;
  }
  
  void AudioBuffer::TrimEnd(int frames_to_trim) {
    CHECK_GE(frames_to_trim, 0);
    CHECK_LE(frames_to_trim, adjusted_frame_count_);
  
    // Adjust the number of frames and duration for this buffer.
    adjusted_frame_count_ -= frames_to_trim;
    duration_ = CalculateDuration(adjusted_frame_count_, sample_rate_);
  }
  
  void AudioBuffer::TrimRange(int start, int end) {
    CHECK_GE(start, 0);
    CHECK_LE(end, adjusted_frame_count_);
  
    const int frames_to_trim = end - start;
    CHECK_GE(frames_to_trim, 0);
    CHECK_LE(frames_to_trim, adjusted_frame_count_);
  
    const int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format_);
    const int frames_to_copy = adjusted_frame_count_ - end;
    if (frames_to_copy > 0) {
      switch (sample_format_) {
        case kSampleFormatPlanarS16:
        case kSampleFormatPlanarF32:
        case kSampleFormatPlanarS32:
          // Planar data must be shifted per channel.
          for (int ch = 0; ch < channel_count_; ++ch) {
            memmove(channel_data_[ch] + (trim_start_ + start) * bytes_per_channel,
                    channel_data_[ch] + (trim_start_ + end) * bytes_per_channel,
                    bytes_per_channel * frames_to_copy);
          }
          break;
        case kSampleFormatU8:
        case kSampleFormatS16:
        case kSampleFormatS24:
        case kSampleFormatS32:
        case kSampleFormatF32: {
          // Interleaved data can be shifted all at once.
          const int frame_size = channel_count_ * bytes_per_channel;
          memmove(channel_data_[0] + (trim_start_ + start) * frame_size,
                  channel_data_[0] + (trim_start_ + end) * frame_size,
                  frame_size * frames_to_copy);
          break;
        }
        case kUnknownSampleFormat:
          NOTREACHED() << "Invalid sample format!";
      }
    } else {
      CHECK_EQ(frames_to_copy, 0);
    }
  
    // Trim the leftover data off the end of the buffer and update duration.
    TrimEnd(frames_to_trim);
  }
  
  }  // namespace media
  