1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141

media / muxers / muxer_timestamp_adapter.h [blame]

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_MUXERS_MUXER_TIMESTAMP_ADAPTER_H_
#define MEDIA_MUXERS_MUXER_TIMESTAMP_ADAPTER_H_

#include <memory>
#include <string>

#include "base/containers/circular_deque.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "media/base/audio_parameters.h"
#include "media/base/media_export.h"
#include "media/muxers/muxer.h"

namespace media {

// Adapter for muxers that emits incoming samples in monotonically increasing
// timestamp order, and covers MediaRecorder pause/resume behavior as well as
// tracks ending and enabledness.
// This class is thread-compatible.
class MEDIA_EXPORT MuxerTimestampAdapter {
 public:
  MuxerTimestampAdapter(std::unique_ptr<Muxer> muxer,
                        bool has_video,
                        bool has_audio);
  MuxerTimestampAdapter(const MuxerTimestampAdapter&) = delete;
  MuxerTimestampAdapter& operator=(const MuxerTimestampAdapter&) = delete;
  ~MuxerTimestampAdapter();

  // Functions to add video and audio frames with `encoded_data.data()`.
  // `encoded_alpha` represents the encode output of alpha channel when
  // available, can be empty otherwise.
  // Returns true if the data is accepted by the muxer, false otherwise.
  bool OnEncodedVideo(
      const Muxer::VideoParameters& params,
      scoped_refptr<DecoderBuffer> encoded_data,
      std::optional<media::VideoEncoder::CodecDescription> codec_description,
      base::TimeTicks timestamp);
  bool OnEncodedAudio(
      const AudioParameters& params,
      scoped_refptr<DecoderBuffer> encoded_data,
      std::optional<media::AudioEncoder::CodecDescription> codec_description,
      base::TimeTicks timestamp);

  // Call to handle mute and tracks getting disabled. If the track is not live
  // and enabled, input data will be ignored and black frames or silence will
  // be output instead.
  void SetLiveAndEnabled(bool track_live_and_enabled, bool is_video);

  // Calling `Pause()` will cause the muxer to modify the timestamps of inputs,
  // setting them to the last received value before the pause. This effectively
  // removes the input data from the presentation, while still preserving it.
  // Once `Resume()` is called, new inputs will have muxer timestamps starting
  // from the time that `Pause()` was called.
  void Pause();
  void Resume();

  // Drains and writes out all buffered frames and finalizes the output.
  // Returns true on success, false otherwise.
  bool Flush();

  Muxer* GetMuxerForTesting() const { return muxer_.get(); }

 private:
  friend class MuxerTimestampAdapterTestBase;

  // Structure for keeping encoded frames in internal queues.
  struct EncodedFrame {
    EncodedFrame();
    EncodedFrame(Muxer::EncodedFrame frame,
                 base::TimeTicks timestamp_minus_paused);
    EncodedFrame(EncodedFrame&&);
    ~EncodedFrame();
    Muxer::EncodedFrame frame;
    // Timestamp of frame minus the total time in pause at the time.
    base::TimeTicks timestamp_minus_paused;
  };

  // Adds all currently buffered frames to the muxer in timestamp order,
  // until the queues are depleted.
  void FlushQueues();
  // Flushes out frames to the muxer while ensuring monotonically increasing
  // timestamps.
  // Note that frames may still be around in the queues after this call. The
  // method stops flushing when timestamp monotonicity can't be guaranteed
  // anymore.
  bool PartiallyFlushQueues();
  // Flushes out the next frame in timestamp order from the queues. Returns true
  // on success and false on muxer failure.
  // Note: it's assumed that at least one video or audio frame is queued.
  bool FlushNextFrame();
  // Ensures a monotonically increasing timestamp sequence, despite
  // incoming non-monotonically increasing timestamps.
  base::TimeTicks UpdateLastTimestampAndGetNext(
      std::optional<base::TimeTicks>& last_timestamp,
      base::TimeTicks incoming_timestamp);

  // TODO(ajose): Change these when support is added for multiple tracks.
  // http://crbug.com/528523
  const bool has_video_;
  const bool has_audio_;
  bool has_seen_video_ = false;
  bool has_seen_audio_ = false;

  std::unique_ptr<Muxer> muxer_;
  std::optional<base::TimeTicks> last_video_timestamp_;
  std::optional<base::TimeTicks> last_audio_timestamp_;

  // The timestamp of the lowest timestamp audio or video sample, compensated
  // for the total time in pause at the time.
  base::TimeTicks first_timestamp_;

  // Variables to measure and accumulate, respectively, the time in pause state.
  std::optional<base::ElapsedTimer> elapsed_time_in_pause_;
  base::TimeDelta total_time_in_pause_;

  // Variables to track live and enabled state of audio and video.
  bool video_track_live_and_enabled_ = true;
  bool audio_track_live_and_enabled_ = true;

  // Maximum interval between data output callbacks (given frames arriving)
  base::TimeDelta max_data_output_interval_;

  // Last timestamp written into the muxer.
  base::TimeDelta last_timestamp_written_;

  // The following two queues hold frames to ensure that monotonically
  // increasing timestamps are stored in the resulting file without modifying
  // the timestamps.
  base::circular_deque<EncodedFrame> audio_frames_;
  // If muxing audio and video, this queue holds frames until the first audio
  // frame appears.
  base::circular_deque<EncodedFrame> video_frames_;
};

}  // namespace media

#endif  // MEDIA_MUXERS_MUXER_TIMESTAMP_ADAPTER_H_