Add explicit |forceOnlineSignin| to user pod status
[chromium-blink-merge.git] / media / base / text_renderer.cc
blob63ad27a2ba72bbbb62288ab48626df98e9b7e6b1
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/base/text_renderer.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/stl_util.h"
12 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/demuxer.h"
15 #include "media/base/demuxer_stream.h"
16 #include "media/base/text_cue.h"
18 namespace media {
20 TextRenderer::TextRenderer(
21 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
22 const AddTextTrackCB& add_text_track_cb)
23 : task_runner_(task_runner),
24 weak_factory_(this),
25 add_text_track_cb_(add_text_track_cb),
26 state_(kUninitialized),
27 pending_read_count_(0) {
30 TextRenderer::~TextRenderer() {
31 DCHECK(state_ == kUninitialized ||
32 state_ == kStopped) << "state_ " << state_;
33 DCHECK_EQ(pending_read_count_, 0);
34 STLDeleteValues(&text_track_state_map_);
37 void TextRenderer::Initialize(const base::Closure& ended_cb) {
38 DCHECK(task_runner_->BelongsToCurrentThread());
39 DCHECK(!ended_cb.is_null());
40 DCHECK_EQ(kUninitialized, state_) << "state_ " << state_;
41 DCHECK(text_track_state_map_.empty());
42 DCHECK_EQ(pending_read_count_, 0);
43 DCHECK(pending_eos_set_.empty());
44 DCHECK(ended_cb_.is_null());
46 weak_this_ = weak_factory_.GetWeakPtr();
47 ended_cb_ = ended_cb;
48 state_ = kPaused;
51 void TextRenderer::Play(const base::Closure& callback) {
52 DCHECK(task_runner_->BelongsToCurrentThread());
53 DCHECK_EQ(state_, kPaused) << "state_ " << state_;
55 for (TextTrackStateMap::iterator itr = text_track_state_map_.begin();
56 itr != text_track_state_map_.end(); ++itr) {
57 TextTrackState* state = itr->second;
58 if (state->read_state == TextTrackState::kReadPending) {
59 DCHECK_GT(pending_read_count_, 0);
60 continue;
63 Read(state, itr->first);
66 state_ = kPlaying;
67 callback.Run();
70 void TextRenderer::Pause(const base::Closure& callback) {
71 DCHECK(task_runner_->BelongsToCurrentThread());
72 DCHECK(state_ == kPlaying || state_ == kEnded) << "state_ " << state_;
73 DCHECK_GE(pending_read_count_, 0);
74 pause_cb_ = callback;
76 if (pending_read_count_ == 0) {
77 state_ = kPaused;
78 base::ResetAndReturn(&pause_cb_).Run();
79 return;
82 state_ = kPausePending;
85 void TextRenderer::Flush(const base::Closure& callback) {
86 DCHECK(task_runner_->BelongsToCurrentThread());
87 DCHECK_EQ(pending_read_count_, 0);
88 DCHECK(state_ == kPaused) << "state_ " << state_;
90 for (TextTrackStateMap::iterator itr = text_track_state_map_.begin();
91 itr != text_track_state_map_.end(); ++itr) {
92 pending_eos_set_.insert(itr->first);
94 DCHECK_EQ(pending_eos_set_.size(), text_track_state_map_.size());
95 callback.Run();
98 void TextRenderer::Stop(const base::Closure& cb) {
99 DCHECK(task_runner_->BelongsToCurrentThread());
100 DCHECK(!cb.is_null());
101 DCHECK(state_ == kPlaying ||
102 state_ == kPausePending ||
103 state_ == kPaused ||
104 state_ == kEnded) << "state_ " << state_;
105 DCHECK_GE(pending_read_count_, 0);
107 stop_cb_ = cb;
109 if (pending_read_count_ == 0) {
110 state_ = kStopped;
111 base::ResetAndReturn(&stop_cb_).Run();
112 return;
115 state_ = kStopPending;
118 void TextRenderer::AddTextStream(DemuxerStream* text_stream,
119 const TextTrackConfig& config) {
120 DCHECK(task_runner_->BelongsToCurrentThread());
121 DCHECK(state_ != kUninitialized) << "state_ " << state_;
122 DCHECK_NE(state_, kStopPending);
123 DCHECK_NE(state_, kStopped);
124 DCHECK(text_track_state_map_.find(text_stream) ==
125 text_track_state_map_.end());
126 DCHECK(pending_eos_set_.find(text_stream) ==
127 pending_eos_set_.end());
129 AddTextTrackDoneCB done_cb = BindToCurrentLoop(
130 base::Bind(&TextRenderer::OnAddTextTrackDone, weak_this_, text_stream));
132 add_text_track_cb_.Run(config, done_cb);
135 void TextRenderer::RemoveTextStream(DemuxerStream* text_stream) {
136 DCHECK(task_runner_->BelongsToCurrentThread());
138 TextTrackStateMap::iterator itr = text_track_state_map_.find(text_stream);
139 DCHECK(itr != text_track_state_map_.end());
141 TextTrackState* state = itr->second;
142 DCHECK_EQ(state->read_state, TextTrackState::kReadIdle);
143 delete state;
144 text_track_state_map_.erase(itr);
146 pending_eos_set_.erase(text_stream);
149 bool TextRenderer::HasTracks() const {
150 DCHECK(task_runner_->BelongsToCurrentThread());
151 return !text_track_state_map_.empty();
154 void TextRenderer::BufferReady(
155 DemuxerStream* stream,
156 DemuxerStream::Status status,
157 const scoped_refptr<DecoderBuffer>& input) {
158 DCHECK(task_runner_->BelongsToCurrentThread());
159 DCHECK_NE(status, DemuxerStream::kConfigChanged);
161 if (status == DemuxerStream::kAborted) {
162 DCHECK(!input);
163 DCHECK_GT(pending_read_count_, 0);
164 DCHECK(pending_eos_set_.find(stream) != pending_eos_set_.end());
166 TextTrackStateMap::iterator itr = text_track_state_map_.find(stream);
167 DCHECK(itr != text_track_state_map_.end());
169 TextTrackState* state = itr->second;
170 DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
172 --pending_read_count_;
173 state->read_state = TextTrackState::kReadIdle;
175 switch (state_) {
176 case kPlaying:
177 return;
179 case kPausePending:
180 if (pending_read_count_ == 0) {
181 state_ = kPaused;
182 base::ResetAndReturn(&pause_cb_).Run();
185 return;
187 case kStopPending:
188 if (pending_read_count_ == 0) {
189 state_ = kStopped;
190 base::ResetAndReturn(&stop_cb_).Run();
193 return;
195 case kPaused:
196 case kStopped:
197 case kUninitialized:
198 case kEnded:
199 NOTREACHED();
200 return;
203 NOTREACHED();
204 return;
207 if (input->end_of_stream()) {
208 CueReady(stream, NULL);
209 return;
212 DCHECK_EQ(status, DemuxerStream::kOk);
213 DCHECK_GE(input->side_data_size(), 2);
215 // The side data contains both the cue id and cue settings,
216 // each terminated with a NUL.
217 const char* id_ptr = reinterpret_cast<const char*>(input->side_data());
218 size_t id_len = strlen(id_ptr);
219 std::string id(id_ptr, id_len);
221 const char* settings_ptr = id_ptr + id_len + 1;
222 size_t settings_len = strlen(settings_ptr);
223 std::string settings(settings_ptr, settings_len);
225 // The cue payload is stored in the data-part of the input buffer.
226 std::string text(input->data(), input->data() + input->data_size());
228 scoped_refptr<TextCue> text_cue(
229 new TextCue(input->timestamp(),
230 input->duration(),
232 settings,
233 text));
235 CueReady(stream, text_cue);
238 void TextRenderer::CueReady(
239 DemuxerStream* text_stream,
240 const scoped_refptr<TextCue>& text_cue) {
241 DCHECK(task_runner_->BelongsToCurrentThread());
242 DCHECK(state_ != kUninitialized &&
243 state_ != kStopped) << "state_ " << state_;
244 DCHECK_GT(pending_read_count_, 0);
245 DCHECK(pending_eos_set_.find(text_stream) != pending_eos_set_.end());
247 TextTrackStateMap::iterator itr = text_track_state_map_.find(text_stream);
248 DCHECK(itr != text_track_state_map_.end());
250 TextTrackState* state = itr->second;
251 DCHECK_EQ(state->read_state, TextTrackState::kReadPending);
252 DCHECK(state->text_track);
254 --pending_read_count_;
255 state->read_state = TextTrackState::kReadIdle;
257 switch (state_) {
258 case kPlaying: {
259 if (text_cue)
260 break;
262 const size_t count = pending_eos_set_.erase(text_stream);
263 DCHECK_EQ(count, 1U);
265 if (pending_eos_set_.empty()) {
266 DCHECK_EQ(pending_read_count_, 0);
267 state_ = kEnded;
268 ended_cb_.Run();
269 return;
272 DCHECK_GT(pending_read_count_, 0);
273 return;
275 case kPausePending: {
276 if (text_cue)
277 break;
279 const size_t count = pending_eos_set_.erase(text_stream);
280 DCHECK_EQ(count, 1U);
282 if (pending_read_count_ > 0) {
283 DCHECK(!pending_eos_set_.empty());
284 return;
287 state_ = kPaused;
288 base::ResetAndReturn(&pause_cb_).Run();
290 return;
292 case kStopPending:
293 if (pending_read_count_ == 0) {
294 state_ = kStopped;
295 base::ResetAndReturn(&stop_cb_).Run();
298 return;
300 case kPaused:
301 case kStopped:
302 case kUninitialized:
303 case kEnded:
304 NOTREACHED();
305 return;
308 base::TimeDelta start = text_cue->timestamp();
309 base::TimeDelta end = start + text_cue->duration();
311 state->text_track->addWebVTTCue(start, end,
312 text_cue->id(),
313 text_cue->text(),
314 text_cue->settings());
316 if (state_ == kPlaying) {
317 Read(state, text_stream);
318 return;
321 if (pending_read_count_ == 0) {
322 DCHECK_EQ(state_, kPausePending) << "state_ " << state_;
323 state_ = kPaused;
324 base::ResetAndReturn(&pause_cb_).Run();
328 void TextRenderer::OnAddTextTrackDone(DemuxerStream* text_stream,
329 scoped_ptr<TextTrack> text_track) {
330 DCHECK(task_runner_->BelongsToCurrentThread());
331 DCHECK(state_ != kUninitialized &&
332 state_ != kStopped &&
333 state_ != kStopPending) << "state_ " << state_;
334 DCHECK(text_stream);
335 DCHECK(text_track);
337 scoped_ptr<TextTrackState> state(new TextTrackState(text_track.Pass()));
338 text_track_state_map_[text_stream] = state.release();
339 pending_eos_set_.insert(text_stream);
341 if (state_ == kPlaying)
342 Read(text_track_state_map_[text_stream], text_stream);
345 void TextRenderer::Read(
346 TextTrackState* state,
347 DemuxerStream* text_stream) {
348 DCHECK_NE(state->read_state, TextTrackState::kReadPending);
350 state->read_state = TextTrackState::kReadPending;
351 ++pending_read_count_;
353 text_stream->Read(base::Bind(&TextRenderer::BufferReady,
354 weak_this_,
355 text_stream));
358 TextRenderer::TextTrackState::TextTrackState(scoped_ptr<TextTrack> tt)
359 : read_state(kReadIdle),
360 text_track(tt.Pass()) {
363 TextRenderer::TextTrackState::~TextTrackState() {
366 } // namespace media