Shaka Player Embedded
source_buffer.cc
Go to the documentation of this file.
1 // Copyright 2016 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 <cmath>
18 #include <utility>
19 
20 #include "src/js/events/event.h"
22 #include "src/js/js_error.h"
24 #include "src/js/mse/time_ranges.h"
25 #include "src/media/media_utils.h"
26 
27 namespace shaka {
28 namespace js {
29 namespace mse {
30 
31 SourceBuffer::SourceBuffer(const std::string& mime,
32  RefPtr<MediaSource> media_source)
33  : mode(AppendMode::SEGMENTS),
34  updating(false),
35  demuxer_(mime, media_source.get(), &frames_),
36  media_source_(media_source),
37  timestamp_offset_(0),
38  append_window_start_(0),
39  append_window_end_(HUGE_VAL /* Infinity */) {
40  AddListenerField(EventType::UpdateStart, &on_update_start);
41  AddListenerField(EventType::Update, &on_update);
42  AddListenerField(EventType::UpdateEnd, &on_update_end);
43  AddListenerField(EventType::Error, &on_error);
44  AddListenerField(EventType::Abort, &on_abort);
45 }
46 
47 // \cond Doxygen_Skip
48 SourceBuffer::~SourceBuffer() {}
49 // \endcond Doxygen_Skip
50 
53  tracer->Trace(&append_buffer_);
54  tracer->Trace(&media_source_);
55 }
56 
57 bool SourceBuffer::Attach(const std::string& mime, media::MediaPlayer* player,
58  bool is_video) {
59  return player->AddMseBuffer(mime, is_video, &frames_);
60 }
61 
63  demuxer_.Stop();
64  media_source_ = nullptr;
65 }
66 
68  if (!media_source_) {
69  return JsError::DOMException(
70  InvalidStateError, "SourceBuffer has been detached from the <video>.");
71  }
72  if (updating) {
74  "Already performing an update.");
75  }
76 
77  if (media_source_->ready_state == MediaSourceReadyState::ENDED) {
78  media_source_->ready_state = MediaSourceReadyState::OPEN;
79  media_source_->ScheduleEvent<events::Event>(EventType::SourceOpen);
80  }
81 
82  append_buffer_ = std::move(data);
83  demuxer_.AppendData(
84  timestamp_offset_, append_window_start_, append_window_end_,
85  append_buffer_.data(), append_buffer_.size(),
86  std::bind(&SourceBuffer::OnAppendComplete, this, std::placeholders::_1));
87 
88  updating = true;
89  return {};
90 }
91 
93  // TODO:
94 }
95 
96 ExceptionOr<void> SourceBuffer::Remove(double start, double end) {
97  if (!media_source_) {
98  return JsError::DOMException(
99  InvalidStateError, "SourceBuffer has been detached from the <video>.");
100  }
101  if (updating) {
103  "Already performing an update.");
104  }
105 
106  // TODO: Consider running this on a background thread.
107  frames_.Remove(start, end);
108 
109  ScheduleEvent<events::Event>(EventType::UpdateEnd);
110  return {};
111 }
112 
114  return frames_.GetBufferedRanges();
115 }
116 
118  if (!media_source_) {
119  return JsError::DOMException(
121  "SourceBuffer is detached from the <video> element.");
122  }
123  return new TimeRanges(frames_.GetBufferedRanges());
124 }
125 
127  return timestamp_offset_;
128 }
129 
131  if (!std::isfinite(offset)) {
132  return JsError::TypeError("timestampOffset cannot be NaN or +/-Infinity.");
133  }
134 
135  if (!media_source_) {
136  return JsError::DOMException(
138  "SourceBuffer is detached from the <video> element.");
139  }
140  if (updating) {
142  "Already performing an update.");
143  }
144 
145  timestamp_offset_ = offset;
146  return {};
147 }
148 
150  return append_window_start_;
151 }
152 
154  if (!std::isfinite(window_start)) {
155  return JsError::TypeError(
156  "appendWindowStart cannot be NaN or +/-Infinity.");
157  }
158 
159  if (!media_source_) {
160  return JsError::DOMException(
162  "SourceBuffer is detached from the <video> element.");
163  }
164  if (updating) {
166  "Already performing an update.");
167  }
168  if (window_start < 0) {
169  return JsError::TypeError("appendWindowStart cannot be negative.");
170  }
171  if (window_start >= append_window_end_) {
172  return JsError::TypeError(
173  "appendWindowStart cannot be greater than appendWindowEnd.");
174  }
175 
176  append_window_start_ = window_start;
177  return {};
178 }
179 
181  return append_window_end_;
182 }
183 
185  if (!media_source_) {
186  return JsError::DOMException(
188  "SourceBuffer is detached from the <video> element.");
189  }
190  if (updating) {
192  "Already performing an update.");
193  }
194  if (std::isnan(window_end)) {
195  return JsError::TypeError("appendWindowEnd cannot be NaN.");
196  }
197  if (window_end <= append_window_start_) {
198  return JsError::TypeError(
199  "appendWindowEnd cannot be less than appendWindowStart.");
200  }
201 
202  append_window_end_ = window_end;
203  return {};
204 }
205 
206 void SourceBuffer::OnAppendComplete(bool success) {
207  VLOG(1) << "Finish appending media segment: "
208  << (success ? "success" : "error");
209  updating = false;
210  append_buffer_.Clear();
211  if (!success) {
212  Abort();
213  ScheduleEvent<events::Event>(EventType::Error);
214  }
215  ScheduleEvent<events::Event>(EventType::UpdateEnd);
216 }
217 
218 
220  AddListenerField(EventType::UpdateStart, &SourceBuffer::on_update_start);
221  AddListenerField(EventType::Update, &SourceBuffer::on_update);
222  AddListenerField(EventType::UpdateEnd, &SourceBuffer::on_update_end);
223  AddListenerField(EventType::Error, &SourceBuffer::on_error);
224  AddListenerField(EventType::Abort, &SourceBuffer::on_abort);
225 
226  AddGenericProperty("buffered", &SourceBuffer::GetBuffered);
227 
228  AddGenericProperty("timestampOffset", &SourceBuffer::TimestampOffset,
230  AddGenericProperty("appendWindowStart", &SourceBuffer::AppendWindowStart,
232  AddGenericProperty("appendWindowEnd", &SourceBuffer::AppendWindowEnd,
234 
235  AddReadWriteProperty("mode", &SourceBuffer::mode);
236  AddReadOnlyProperty("updating", &SourceBuffer::updating);
237 
238  AddMemberFunction("appendBuffer", &SourceBuffer::AppendBuffer);
239  AddMemberFunction("abort", &SourceBuffer::Abort);
240  AddMemberFunction("remove", &SourceBuffer::Remove);
241 
242  NotImplemented("audioTracks");
243  NotImplemented("videoTracks");
244  NotImplemented("textTracks");
245 }
246 
247 } // namespace mse
248 } // namespace js
249 } // namespace shaka
virtual bool AddMseBuffer(const std::string &mime, bool is_video, const ElementaryStream *stream)=0
SourceBuffer(const std::string &mime, RefPtr< MediaSource > media_source)
ExceptionOr< void > SetTimestampOffset(double offset)
ExceptionOr< void > SetAppendWindowEnd(double window_end)
void Trace(memory::HeapTracer *tracer) const override
bool Attach(const std::string &mime, media::MediaPlayer *player, bool is_video)
void Trace(const Traceable *ptr)
Definition: heap_tracer.cc:43
ExceptionOr< void > Remove(double start, double end)
media::BufferedRanges GetBufferedRanges() const
impl::get_const_reference_at_t< I, Choices... > get(const variant< Choices... > &variant)
Definition: variant.h:456
void AppendData(double timestamp_offset, double window_start, double window_end, const uint8_t *data, size_t data_size, std::function< void(bool)> on_complete)
std::vector< BufferedRange > BufferedRanges
Definition: types.h:26
void Trace(memory::HeapTracer *tracer) const override
Definition: event_target.cc:31
ExceptionOr< void > SetAppendWindowStart(double window_start)
ExceptionOr< void > AppendBuffer(ByteBuffer data)
static JsError TypeError(const std::string &message)
Definition: js_error.cc:81
static JsError DOMException(ExceptionCode code)
Definition: js_error.cc:115
std::vector< BufferedRange > GetBufferedRanges() const
Definition: streams.cc:225
ExceptionOr< RefPtr< TimeRanges > > GetBuffered() const
void Remove(double start, double end)
Definition: streams.cc:270
void AddListenerField(EventType type, Listener *on_field)
Definition: event_target.h:138