C++程序  |  125行  |  4.88 KB

// Copyright (c) 2012 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.

#ifndef MEDIA_BASE_AUDIO_SPLICER_H_
#define MEDIA_BASE_AUDIO_SPLICER_H_

#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "media/audio/audio_parameters.h"
#include "media/base/buffers.h"
#include "media/base/media_export.h"

namespace media {

class AudioBuffer;
class AudioBus;
class AudioStreamSanitizer;

// Helper class that handles filling gaps and resolving overlaps.
class MEDIA_EXPORT AudioSplicer {
 public:
  explicit AudioSplicer(int samples_per_second);
  ~AudioSplicer();

  enum {
    // The number of ms to crossfade before trimming when buffers overlap.
    kCrossfadeDurationInMilliseconds = 5,

    // Largest gap or overlap allowed between buffers.  Anything larger than
    // this will trigger an error.  This is an arbitrary value, but the initial
    // selection of 50ms roughly represents the duration of 2 compressed AAC or
    // MP3 frames.
    kMaxTimeDeltaInMilliseconds = 50,
  };

  // Resets the splicer state by clearing the output buffers queue and resetting
  // the timestamp helper.
  void Reset();

  // Adds a new buffer full of samples or end of stream buffer to the splicer.
  // Returns true if the buffer was accepted.  False is returned if an error
  // occurred.
  bool AddInput(const scoped_refptr<AudioBuffer>& input);

  // Returns true if the splicer has a buffer to return.
  bool HasNextBuffer() const;

  // Removes the next buffer from the output buffer queue and returns it; this
  // should only be called if HasNextBuffer() returns true.
  scoped_refptr<AudioBuffer> GetNextBuffer();

  // Indicates an upcoming splice point.  All buffers overlapping or after the
  // |splice_timestamp| will be considered as "before the splice."  Clients must
  // then call SetSpliceTimestamp(kNoTimestamp()) to signal that future buffers
  // should be considered as "after the splice."
  //
  // Once |kCrossfadeDurationInMilliseconds| of buffers "after the splice" or
  // end of stream has been received, the "after" buffers will be crossfaded
  // with all "before" buffers which overlap them.  "before" buffers outside
  // of the overlap range will be discarded.
  void SetSpliceTimestamp(base::TimeDelta splice_timestamp);

 private:
  friend class AudioSplicerTest;

  // Extracts frames to be crossfaded from |pre_splice_sanitizer_|.  Transfers
  // all frames before |splice_timestamp_| into |output_sanitizer_| and drops
  // frames outside of the crossfade duration.
  //
  // The size of the returned AudioBus is the crossfade duration in frames.
  // Crossfade duration is calculated based on the number of frames available
  // after |splice_timestamp_| in each sanitizer and capped by
  // |max_crossfade_duration_|.
  //
  // |pre_splice_sanitizer_| will be empty after this operation.
  scoped_ptr<AudioBus> ExtractCrossfadeFromPreSplice(
      scoped_refptr<AudioBuffer>* crossfade_buffer);

  // Crossfades |pre_splice_bus->frames()| frames from
  // |post_splice_sanitizer_|
  // with those from |pre_splice_bus|.  Adds the crossfaded buffer to
  // |output_sanitizer_| along with all buffers in |post_splice_sanitizer_|.
  //
  // |post_splice_sanitizer_| will be empty after this operation.
  void CrossfadePostSplice(scoped_ptr<AudioBus> pre_splice_bus,
                           scoped_refptr<AudioBuffer> crossfade_buffer);

  // Reset the splice and splice end timestamps.
  void reset_splice_timestamps() {
    splice_timestamp_ = max_splice_end_timestamp_ = kNoTimestamp();
  }

  const base::TimeDelta max_crossfade_duration_;
  base::TimeDelta splice_timestamp_;
  base::TimeDelta max_splice_end_timestamp_;

  // The various sanitizers for each stage of the crossfade process.  Buffers in
  // |output_sanitizer_| are immediately available for consumption by external
  // callers.
  //
  // Overlapped buffers go into the |pre_splice_sanitizer_| while overlapping
  // buffers go into the |post_splice_sanitizer_|.  Once enough buffers for
  // crossfading are received the pre and post sanitizers are drained into
  // |output_sanitizer_| by the two ExtractCrossfadeFromXXX methods above.
  //
  // |pre_splice_sanitizer_| is not constructed until the first splice frame is
  // encountered.  At which point it is constructed based on the timestamp state
  // of |output_sanitizer_|.  It is destructed once the splice is finished.
  scoped_ptr<AudioStreamSanitizer> output_sanitizer_;
  scoped_ptr<AudioStreamSanitizer> pre_splice_sanitizer_;
  scoped_ptr<AudioStreamSanitizer> post_splice_sanitizer_;

  // Whether all buffers which should go into |pre_splice_sanitizer_| have been
  // received.  If true, buffers should now be put in |post_splice_sanitizer_|.
  bool have_all_pre_splice_buffers_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSplicer);
};

}  // namespace media

#endif