Shaka Player Embedded
pipeline_monitor.cc
Go to the documentation of this file.
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <utility>
18 
19 #include "shaka/media/streams.h"
20 #include "src/util/utils.h"
21 
22 namespace shaka {
23 namespace media {
24 
25 namespace {
26 
28 constexpr const double kNeedForPlay = 0.3;
30 constexpr const double kEpsilon = 0.1;
31 
32 bool IsBufferedUntil(const BufferedRanges& ranges, double start_time,
33  double end_time, double duration) {
34  for (auto& range : ranges) {
35  if (range.start <= start_time + StreamBase::kMaxGapSize &&
36  (range.end >= end_time || end_time + kEpsilon >= duration)) {
37  return true;
38  }
39  }
40  return false;
41 }
42 
43 bool CanPlay(const BufferedRanges& ranges, double time, double duration) {
44  return IsBufferedUntil(ranges, time, time + kNeedForPlay, duration);
45 }
46 
47 } // namespace
48 
50  std::function<BufferedRanges()> get_buffered,
51  std::function<BufferedRanges()> get_decoded,
52  std::function<void(VideoReadyState)> ready_state_changed,
53  const util::Clock* clock, PipelineManager* pipeline)
54  : mutex_("PipelineMonitor"),
55  start_("PipelineMonitor::Start"),
56  get_buffered_(std::move(get_buffered)),
57  get_decoded_(std::move(get_decoded)),
58  ready_state_changed_(std::move(ready_state_changed)),
59  clock_(clock),
60  pipeline_(pipeline),
61  shutdown_(false),
62  running_(false),
63  ready_state_(VideoReadyState::HaveNothing),
64  thread_("PipelineMonitor",
65  std::bind(&PipelineMonitor::ThreadMain, this)) {}
66 
68  {
69  std::unique_lock<Mutex> lock(mutex_);
70  shutdown_ = true;
71  start_.SignalAllIfNotSet();
72  }
73  thread_.join();
74 }
75 
77  std::unique_lock<Mutex> lock(mutex_);
78  ready_state_ = VideoReadyState::HaveNothing;
79  running_ = true;
80  start_.SignalAllIfNotSet();
81 }
82 
84  std::unique_lock<Mutex> lock(mutex_);
85  running_ = false;
86 }
87 
88 void PipelineMonitor::ThreadMain() {
89  std::unique_lock<Mutex> lock(mutex_);
90  while (!shutdown_) {
91  if (!running_) {
92  start_.ResetAndWaitWhileUnlocked(lock);
93  continue;
94  }
95 
96  const BufferedRanges buffered = get_buffered_();
97  const BufferedRanges decoded = get_decoded_();
98  const double time = pipeline_->GetCurrentTime();
99  const double duration = pipeline_->GetDuration();
100  const auto state = pipeline_->GetPlaybackState();
101  // Don't move playhead until we have decoded at the current time. This
102  // ensures we stop for decryption errors and that we don't blindly move
103  // forward without the correct frames.
104  // If we're already playing, keep playing until the end of the buffered
105  // range; otherwise wait until we have buffered some amount ahead of the
106  // playhead.
107  const bool is_playing = state == VideoPlaybackState::Playing;
108  const bool has_current_frame =
109  IsBufferedUntil(decoded, time, time, duration);
110  const bool can_start =
111  CanPlay(buffered, time, duration) && has_current_frame;
112  const bool can_play = is_playing ? has_current_frame : can_start;
113  if (time >= duration) {
114  pipeline_->OnEnded();
115  } else if (can_play) {
116  pipeline_->CanPlay();
117  } else {
118  pipeline_->Buffering();
119  }
120 
121  if (state == VideoPlaybackState::Initializing) {
122  ChangeReadyState(VideoReadyState::HaveNothing);
123  } else if (can_play) {
124  ChangeReadyState(VideoReadyState::HaveFutureData);
125  } else if (has_current_frame) {
126  ChangeReadyState(VideoReadyState::HaveCurrentData);
127  } else {
128  ChangeReadyState(VideoReadyState::HaveMetadata);
129  }
130 
131  util::Unlocker<Mutex> unlock(&lock);
132  clock_->SleepSeconds(0.01);
133  }
134 }
135 
136 void PipelineMonitor::ChangeReadyState(VideoReadyState new_state) {
137  if (ready_state_ != new_state) {
138  ready_state_ = new_state;
139  ready_state_changed_(new_state);
140  }
141 }
142 
143 } // namespace media
144 } // namespace shaka
virtual VideoPlaybackState GetPlaybackState() const
static constexpr const double kMaxGapSize
Definition: streams.h:76
void join()
Definition: thread.h:56
virtual double GetCurrentTime() const
std::vector< BufferedRange > BufferedRanges
Definition: types.h:26
T ResetAndWaitWhileUnlocked(std::unique_lock< _Mutex > &lock)
Definition: thread_event.h:106
PipelineMonitor(std::function< BufferedRanges()> get_buffered, std::function< BufferedRanges()> get_decoded, std::function< void(VideoReadyState)> ready_state_changed, const util::Clock *clock, PipelineManager *pipeline)
virtual void SleepSeconds(double seconds) const
Definition: clock.cc:39
virtual double GetDuration() const