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
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223

media / base / pipeline_impl.h [blame]

// Copyright 2016 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_BASE_PIPELINE_IMPL_H_
#define MEDIA_BASE_PIPELINE_IMPL_H_

#include <memory>
#include <optional>

#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
#include "media/base/pipeline.h"
#include "media/base/renderer.h"
#include "media/base/renderer_factory_selector.h"

namespace base {
class SingleThreadTaskRunner;
}

namespace media {

class MediaLog;

// Callbacks used for Renderer creation. When the RendererType is nullopt, the
// current base one will be created.
using CreateRendererCB = base::RepeatingCallback<std::unique_ptr<Renderer>(
    std::optional<RendererType>)>;
using RendererCreatedCB = base::OnceCallback<void(std::unique_ptr<Renderer>)>;
using AsyncCreateRendererCB =
    base::RepeatingCallback<void(std::optional<RendererType>,
                                 RendererCreatedCB)>;

// Pipeline runs the media pipeline.  Filters are created and called on the
// task runner injected into this object. Pipeline works like a state
// machine to perform asynchronous initialization, pausing, seeking and playing.
//
// Here's a state diagram that describes the lifetime of this object.
//
//   [ *Created ]                       [ Any State ]
//         | Start()                         | Stop()
//         V                                 V
//   [ Starting ]                       [ Stopping ]
//         |                                 |
//         V                                 V
//   [ Playing ] <---------.            [ Stopped ]
//     |  |  | Seek()      |
//     |  |  V             |
//     |  | [ Seeking ] ---'
//     |  |                ^
//     |  | *TrackChange() |
//     |  V                |
//     | [ Switching ] ----'
//     |                   ^
//     | Suspend()         |
//     V                   |
//   [ Suspending ]        |
//     |                   |
//     V                   |
//   [ Suspended ]         |
//     | Resume()          |
//     V                   |
//   [ Resuming ] ---------'
//
// Initialization is a series of state transitions from "Created" through each
// filter initialization state.  When all filter initialization states have
// completed, we simulate a Seek() to the beginning of the media to give filters
// a chance to preroll. From then on the normal Seek() transitions are carried
// out and we start playing the media.
//
// If Stop() is ever called, this object will transition to "Stopped" state.
// Pipeline::Stop() is never called from within PipelineImpl. It's |client_|'s
// responsibility to call stop when appropriate.
//
// TODO(sandersd): It should be possible to pass through Suspended when going
// from InitDemuxer to InitRenderer, thereby eliminating the Resuming state.
// Some annoying differences between the two paths need to be removed first.
class MEDIA_EXPORT PipelineImpl : public Pipeline {
 public:
  // Constructs a pipeline that will execute media tasks on |media_task_runner|.
  // |create_renderer_cb|: to create renderers when starting and resuming.
  PipelineImpl(scoped_refptr<base::SequencedTaskRunner> media_task_runner,
               scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
               CreateRendererCB create_renderer_cb,
               MediaLog* media_log);

  PipelineImpl(const PipelineImpl&) = delete;
  PipelineImpl& operator=(const PipelineImpl&) = delete;

  ~PipelineImpl() override;

  // Pipeline implementation.
  void Start(StartType start_type,
             Demuxer* demuxer,
             Client* client,
             PipelineStatusCallback seek_cb) override;
  void Stop() override;
  void Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) override;
  void Suspend(PipelineStatusCallback suspend_cb) override;
  void Resume(base::TimeDelta time, PipelineStatusCallback seek_cb) override;
  bool IsRunning() const override;
  bool IsSuspended() const override;
  double GetPlaybackRate() const override;
  void SetPlaybackRate(double playback_rate) override;
  float GetVolume() const override;
  void SetVolume(float volume) override;
  void SetLatencyHint(std::optional<base::TimeDelta> latency_hint) override;
  void SetPreservesPitch(bool preserves_pitch) override;
  void SetWasPlayedWithUserActivationAndHighMediaEngagement(
      bool was_played_with_user_activation_and_high_media_engagement) override;
  base::TimeDelta GetMediaTime() const override;
  Ranges<base::TimeDelta> GetBufferedTimeRanges() const override;
  base::TimeDelta GetMediaDuration() const override;
  bool DidLoadingProgress() override;
  PipelineStatistics GetStatistics() const override;
  void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override;

  // |enabled_track_ids| contains track ids of enabled audio tracks.
  void OnEnabledAudioTracksChanged(
      const std::vector<MediaTrack::Id>& enabled_track_ids,
      base::OnceClosure change_completed_cb) override;

  // |selected_track_id| is either empty, which means no video track is
  // selected, or contains the selected video track id.
  void OnSelectedVideoTrackChanged(
      std::optional<MediaTrack::Id> selected_track_id,
      base::OnceClosure change_completed_cb) override;

  void OnExternalVideoFrameRequest() override;

 private:
  friend class MediaLog;
  class RendererWrapper;

  // Create a Renderer asynchronously. Must be called on the main task runner
  // and the callback will be called on the main task runner as well.
  void AsyncCreateRenderer(std::optional<RendererType> renderer_type,
                           RendererCreatedCB renderer_created_cb);

  // Notifications from RendererWrapper.
  void OnError(PipelineStatus error);
  void OnFallback(PipelineStatus fallback);
  void OnEnded();
  void OnMetadata(const PipelineMetadata& metadata);
  void OnBufferingStateChange(BufferingState state,
                              BufferingStateChangeReason reason);
  void OnDurationChange(base::TimeDelta duration);
  void OnWaiting(WaitingReason reason);
  void OnAudioConfigChange(const AudioDecoderConfig& config);
  void OnVideoConfigChange(const VideoDecoderConfig& config);
  void OnVideoNaturalSizeChange(const gfx::Size& size);
  void OnVideoOpacityChange(bool opaque);
  void OnVideoAverageKeyframeDistanceUpdate();
  void OnAudioPipelineInfoChange(const AudioPipelineInfo& info);
  void OnVideoPipelineInfoChange(const VideoPipelineInfo& info);
  void OnRemotePlayStateChange(MediaStatus::State state);
  void OnVideoFrameRateChange(std::optional<int> fps);

  // Task completion callbacks from RendererWrapper.
  void OnSeekDone(bool is_suspended);
  void OnSuspendDone();

  // Parameters passed in the constructor.
  const scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
  CreateRendererCB create_renderer_cb_;
  const raw_ptr<MediaLog> media_log_;

  // Pipeline client. Valid only while the pipeline is running.
  raw_ptr<Client> client_;

  // RendererWrapper instance that runs on the media thread.
  std::unique_ptr<RendererWrapper> renderer_wrapper_;

  // Temporary callback used for Start(), Seek(), and Resume().
  PipelineStatusCallback seek_cb_;

  // Temporary callback used for Suspend().
  PipelineStatusCallback suspend_cb_;

  // Current playback rate (>= 0.0). This value is set immediately via
  // SetPlaybackRate() and a task is dispatched on the task runner to notify
  // the filters.
  double playback_rate_;

  // Current volume level (from 0.0f to 1.0f). This value is set immediately
  // via SetVolume() and a task is dispatched on the task runner to notify the
  // filters.
  float volume_;

  // Current duration as reported by Demuxer.
  base::TimeDelta duration_;

  // Set by GetMediaTime(), used to prevent the current media time value as
  // reported to JavaScript from going backwards in time.
  mutable base::TimeDelta last_media_time_;

  // Set by Seek(), used in place of asking the renderer for current media time
  // while a seek is pending. Renderer's time cannot be trusted until the seek
  // has completed.
  base::TimeDelta seek_time_;

  // Cached suspension state for the RendererWrapper.
  bool is_suspended_;

  // 'external_video_frame_request_signaled_' tracks whether we've called
  // OnExternalVideoFrameRequest on the current renderer. Calls which may
  // create a new renderer in the RendererWrapper (Start, Resume, SetCdm) will
  // reset this member. There is no guarantee to the client that
  // OnExternalVideoFrameRequest will be called only once.
  bool external_video_frame_request_signaled_ = false;

  base::ThreadChecker thread_checker_;
  base::WeakPtrFactory<PipelineImpl> weak_factory_{this};
};

}  // namespace media

#endif  // MEDIA_BASE_PIPELINE_IMPL_H_