Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: media/base/pipeline_impl.cc

Issue 1904793002: Move Pipeline permanent callbacks into Pipeline::Client interface. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: restored lock during stop Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/pipeline_impl.h" 5 #include "media/base/pipeline_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/callback_helpers.h" 13 #include "base/callback_helpers.h"
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/compiler_specific.h" 15 #include "base/compiler_specific.h"
16 #include "base/location.h" 16 #include "base/location.h"
17 #include "base/memory/ptr_util.h" 17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/histogram.h" 18 #include "base/metrics/histogram.h"
19 #include "base/single_thread_task_runner.h" 19 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h" 20 #include "base/stl_util.h"
21 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h" 22 #include "base/strings/string_util.h"
23 #include "base/synchronization/condition_variable.h" 23 #include "base/synchronization/waitable_event.h"
24 #include "base/thread_task_runner_handle.h"
25 #include "media/base/bind_to_current_loop.h"
24 #include "media/base/media_log.h" 26 #include "media/base/media_log.h"
25 #include "media/base/media_switches.h" 27 #include "media/base/media_switches.h"
26 #include "media/base/renderer.h" 28 #include "media/base/renderer.h"
27 #include "media/base/text_renderer.h" 29 #include "media/base/text_renderer.h"
28 #include "media/base/text_track_config.h" 30 #include "media/base/text_track_config.h"
29 #include "media/base/timestamp_constants.h" 31 #include "media/base/timestamp_constants.h"
30 #include "media/base/video_decoder_config.h" 32 #include "media/base/video_decoder_config.h"
31 33
32 using base::TimeDelta; 34 using base::TimeDelta;
33 35
34 namespace media { 36 namespace media {
35 37
36 PipelineImpl::PipelineImpl( 38 PipelineImpl::PipelineImpl(
37 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 39 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
38 MediaLog* media_log) 40 MediaLog* media_log)
39 : task_runner_(task_runner), 41 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
sandersd (OOO until July 31) 2016/05/02 18:37:47 Perhaps this should be explicitly passed, since |c
xhwang 2016/05/02 20:58:35 +1
alokp 2016/05/02 22:25:17 I disagree. IMO passing a task runner makes sense
sandersd (OOO until July 31) 2016/05/02 22:45:52 This is reasonable, although I would feel better a
alokp 2016/05/02 23:00:59 I agree. In fact initial patches passed client in
sandersd (OOO until July 31) 2016/05/02 23:20:47 That's true, but the reason to do so was also remo
alokp 2016/05/03 05:22:18 How do you propose doing that? It will be weird to
sandersd (OOO until July 31) 2016/05/03 19:28:55 A fair point, I'll accept that.
alokp 2016/05/03 20:15:23 One way to add Client in the base class interface
42 media_task_runner_(media_task_runner),
40 media_log_(media_log), 43 media_log_(media_log),
41 running_(false), 44 running_(false),
42 did_loading_progress_(false), 45 did_loading_progress_(false),
43 volume_(1.0f), 46 volume_(1.0f),
44 playback_rate_(0.0), 47 playback_rate_(0.0),
45 status_(PIPELINE_OK), 48 status_(PIPELINE_OK),
46 state_(kCreated), 49 state_(kCreated),
47 suspend_timestamp_(kNoTimestamp()), 50 suspend_timestamp_(kNoTimestamp()),
48 renderer_ended_(false), 51 renderer_ended_(false),
49 text_renderer_ended_(false), 52 text_renderer_ended_(false),
50 demuxer_(NULL), 53 demuxer_(NULL),
54 client_(nullptr),
51 cdm_context_(nullptr), 55 cdm_context_(nullptr),
52 weak_factory_(this) { 56 weak_factory_(this) {
57 DVLOG(2) << __FUNCTION__;
53 weak_this_ = weak_factory_.GetWeakPtr(); 58 weak_this_ = weak_factory_.GetWeakPtr();
54 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 59 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
55 } 60 }
56 61
57 PipelineImpl::~PipelineImpl() { 62 PipelineImpl::~PipelineImpl() {
58 DCHECK(thread_checker_.CalledOnValidThread()) 63 DVLOG(2) << __FUNCTION__;
64 DCHECK(main_task_runner_->BelongsToCurrentThread())
59 << "Pipeline must be destroyed on same thread that created it"; 65 << "Pipeline must be destroyed on same thread that created it";
60 DCHECK(!running_) << "Stop() must complete before destroying object"; 66 DCHECK(!running_) << "Stop() must complete before destroying object";
61 DCHECK(stop_cb_.is_null());
62 DCHECK(seek_cb_.is_null()); 67 DCHECK(seek_cb_.is_null());
63 } 68 }
64 69
65 void PipelineImpl::Start(Demuxer* demuxer, 70 void PipelineImpl::Start(Demuxer* demuxer,
66 std::unique_ptr<Renderer> renderer, 71 std::unique_ptr<Renderer> renderer,
67 const base::Closure& ended_cb, 72 Client* client,
68 const PipelineStatusCB& error_cb, 73 const PipelineStatusCB& seek_cb) {
69 const PipelineStatusCB& seek_cb, 74 DCHECK(main_task_runner_->BelongsToCurrentThread());
70 const PipelineMetadataCB& metadata_cb, 75 DCHECK(client);
71 const BufferingStateCB& buffering_state_cb,
72 const base::Closure& duration_change_cb,
73 const AddTextTrackCB& add_text_track_cb,
74 const base::Closure& waiting_for_decryption_key_cb) {
75 DCHECK(!ended_cb.is_null());
76 DCHECK(!error_cb.is_null());
77 DCHECK(!seek_cb.is_null()); 76 DCHECK(!seek_cb.is_null());
78 DCHECK(!metadata_cb.is_null());
79 DCHECK(!buffering_state_cb.is_null());
80 77
81 base::AutoLock auto_lock(lock_); 78 base::AutoLock auto_lock(lock_);
82 CHECK(!running_) << "Media pipeline is already running"; 79 CHECK(!running_) << "Media pipeline is already running";
83 running_ = true; 80 running_ = true;
84 81
85 demuxer_ = demuxer; 82 demuxer_ = demuxer;
86 renderer_ = std::move(renderer); 83 renderer_ = std::move(renderer);
87 ended_cb_ = ended_cb; 84 client_ = client;
88 error_cb_ = error_cb; 85 seek_cb_ = media::BindToCurrentLoop(seek_cb);
89 seek_cb_ = seek_cb; 86 media_task_runner_->PostTask(
90 metadata_cb_ = metadata_cb; 87 FROM_HERE, base::Bind(&PipelineImpl::StartTask, weak_this_));
91 buffering_state_cb_ = buffering_state_cb;
92 duration_change_cb_ = duration_change_cb;
93 add_text_track_cb_ = add_text_track_cb;
94 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
95
96 task_runner_->PostTask(FROM_HERE,
97 base::Bind(&PipelineImpl::StartTask, weak_this_));
98 } 88 }
99 89
100 void PipelineImpl::Stop(const base::Closure& stop_cb) { 90 void PipelineImpl::Stop() {
91 DCHECK(main_task_runner_->BelongsToCurrentThread());
101 DVLOG(2) << __FUNCTION__; 92 DVLOG(2) << __FUNCTION__;
102 task_runner_->PostTask( 93
103 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)); 94 if (media_task_runner_ != main_task_runner_) {
95 // This path is executed by production code where the two task runners -
96 // main and media - live on different threads.
97 base::WaitableEvent waiter(false, false);
98 media_task_runner_->PostTask(
99 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, &waiter));
sandersd (OOO until July 31) 2016/05/02 18:37:47 I'm not a fan of this pattern; it was bad in WMPI
xhwang 2016/05/02 20:58:35 We already have a waiter in WMPI when Pipeline::St
alokp 2016/05/02 22:25:17 This is not a new waiter. The one in WMPI is simpl
100 waiter.Wait();
101 } else {
102 // This path is executed by unittests that share media and main threads.
103 StopTask(nullptr);
104 }
105 client_ = nullptr;
104 } 106 }
105 107
106 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { 108 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) {
107 base::AutoLock auto_lock(lock_); 109 DCHECK(main_task_runner_->BelongsToCurrentThread());
108 if (!running_) { 110
111 if (!IsRunning()) {
109 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; 112 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
110 return; 113 return;
111 } 114 }
112 115
113 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SeekTask, 116 media_task_runner_->PostTask(
114 weak_this_, time, seek_cb)); 117 FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_this_, time,
118 media::BindToCurrentLoop(seek_cb)));
115 } 119 }
116 120
117 bool PipelineImpl::IsRunning() const { 121 bool PipelineImpl::IsRunning() const {
122 // TODO(alokp): Add thread DCHECK after removing the internal usage on
123 // media thread.
118 base::AutoLock auto_lock(lock_); 124 base::AutoLock auto_lock(lock_);
119 return running_; 125 return running_;
120 } 126 }
121 127
122 double PipelineImpl::GetPlaybackRate() const { 128 double PipelineImpl::GetPlaybackRate() const {
129 // TODO(alokp): Add thread DCHECK after removing the internal usage on
130 // media thread.
123 base::AutoLock auto_lock(lock_); 131 base::AutoLock auto_lock(lock_);
124 return playback_rate_; 132 return playback_rate_;
125 } 133 }
126 134
127 void PipelineImpl::SetPlaybackRate(double playback_rate) { 135 void PipelineImpl::SetPlaybackRate(double playback_rate) {
136 DCHECK(main_task_runner_->BelongsToCurrentThread());
137
128 if (playback_rate < 0.0) 138 if (playback_rate < 0.0)
129 return; 139 return;
130 140
131 base::AutoLock auto_lock(lock_); 141 base::AutoLock auto_lock(lock_);
132 playback_rate_ = playback_rate; 142 playback_rate_ = playback_rate;
133 if (running_) { 143 if (running_) {
134 task_runner_->PostTask(FROM_HERE, 144 media_task_runner_->PostTask(
135 base::Bind(&PipelineImpl::PlaybackRateChangedTask, 145 FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask,
136 weak_this_, playback_rate)); 146 weak_this_, playback_rate));
137 } 147 }
138 } 148 }
139 149
140 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { 150 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
141 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, 151 DCHECK(main_task_runner_->BelongsToCurrentThread());
142 weak_this_, suspend_cb)); 152
153 media_task_runner_->PostTask(
154 FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, weak_this_,
155 media::BindToCurrentLoop(suspend_cb)));
143 } 156 }
144 157
145 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer, 158 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer,
146 base::TimeDelta timestamp, 159 base::TimeDelta timestamp,
147 const PipelineStatusCB& seek_cb) { 160 const PipelineStatusCB& seek_cb) {
148 task_runner_->PostTask( 161 DCHECK(main_task_runner_->BelongsToCurrentThread());
149 FROM_HERE, base::Bind(&PipelineImpl::ResumeTask, weak_this_, 162
150 base::Passed(&renderer), timestamp, seek_cb)); 163 media_task_runner_->PostTask(
164 FROM_HERE,
165 base::Bind(&PipelineImpl::ResumeTask, weak_this_, base::Passed(&renderer),
166 timestamp, media::BindToCurrentLoop(seek_cb)));
151 } 167 }
152 168
153 float PipelineImpl::GetVolume() const { 169 float PipelineImpl::GetVolume() const {
170 // TODO(alokp): Add thread DCHECK after removing the internal usage on
171 // media thread.
154 base::AutoLock auto_lock(lock_); 172 base::AutoLock auto_lock(lock_);
155 return volume_; 173 return volume_;
156 } 174 }
157 175
158 void PipelineImpl::SetVolume(float volume) { 176 void PipelineImpl::SetVolume(float volume) {
177 DCHECK(main_task_runner_->BelongsToCurrentThread());
178
159 if (volume < 0.0f || volume > 1.0f) 179 if (volume < 0.0f || volume > 1.0f)
160 return; 180 return;
161 181
162 base::AutoLock auto_lock(lock_); 182 base::AutoLock auto_lock(lock_);
163 volume_ = volume; 183 volume_ = volume;
164 if (running_) { 184 if (running_) {
165 task_runner_->PostTask( 185 media_task_runner_->PostTask(
166 FROM_HERE, 186 FROM_HERE,
167 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume)); 187 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume));
168 } 188 }
169 } 189 }
170 190
171 TimeDelta PipelineImpl::GetMediaTime() const { 191 TimeDelta PipelineImpl::GetMediaTime() const {
192 DCHECK(main_task_runner_->BelongsToCurrentThread());
193
172 base::AutoLock auto_lock(lock_); 194 base::AutoLock auto_lock(lock_);
173 if (suspend_timestamp_ != kNoTimestamp()) 195 if (suspend_timestamp_ != kNoTimestamp())
174 return suspend_timestamp_; 196 return suspend_timestamp_;
175 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) 197 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_)
176 : TimeDelta(); 198 : TimeDelta();
177 } 199 }
178 200
179 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { 201 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
202 DCHECK(main_task_runner_->BelongsToCurrentThread());
203
180 base::AutoLock auto_lock(lock_); 204 base::AutoLock auto_lock(lock_);
181 return buffered_time_ranges_; 205 return buffered_time_ranges_;
182 } 206 }
183 207
184 TimeDelta PipelineImpl::GetMediaDuration() const { 208 TimeDelta PipelineImpl::GetMediaDuration() const {
209 DCHECK(main_task_runner_->BelongsToCurrentThread());
210
185 base::AutoLock auto_lock(lock_); 211 base::AutoLock auto_lock(lock_);
186 return duration_; 212 return duration_;
187 } 213 }
188 214
189 bool PipelineImpl::DidLoadingProgress() { 215 bool PipelineImpl::DidLoadingProgress() {
216 DCHECK(main_task_runner_->BelongsToCurrentThread());
217
190 base::AutoLock auto_lock(lock_); 218 base::AutoLock auto_lock(lock_);
191 bool ret = did_loading_progress_; 219 bool ret = did_loading_progress_;
192 did_loading_progress_ = false; 220 did_loading_progress_ = false;
193 return ret; 221 return ret;
194 } 222 }
195 223
196 PipelineStatistics PipelineImpl::GetStatistics() const { 224 PipelineStatistics PipelineImpl::GetStatistics() const {
225 // TODO(alokp): Add thread DCHECK after removing the internal usage on
226 // media thread.
197 base::AutoLock auto_lock(lock_); 227 base::AutoLock auto_lock(lock_);
198 return statistics_; 228 return statistics_;
199 } 229 }
200 230
201 void PipelineImpl::SetCdm(CdmContext* cdm_context, 231 void PipelineImpl::SetCdm(CdmContext* cdm_context,
202 const CdmAttachedCB& cdm_attached_cb) { 232 const CdmAttachedCB& cdm_attached_cb) {
203 task_runner_->PostTask( 233 DCHECK(main_task_runner_->BelongsToCurrentThread());
234
235 media_task_runner_->PostTask(
204 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context, 236 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context,
205 cdm_attached_cb)); 237 cdm_attached_cb));
206 } 238 }
207 239
208 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { 240 void PipelineImpl::SetErrorForTesting(PipelineStatus status) {
209 OnError(status); 241 OnError(status);
210 } 242 }
211 243
212 bool PipelineImpl::HasWeakPtrsForTesting() const { 244 bool PipelineImpl::HasWeakPtrsForTesting() const {
213 DCHECK(task_runner_->BelongsToCurrentThread()); 245 DCHECK(media_task_runner_->BelongsToCurrentThread());
214 return weak_factory_.HasWeakPtrs(); 246 return weak_factory_.HasWeakPtrs();
215 } 247 }
216 248
217 void PipelineImpl::SetState(State next_state) { 249 void PipelineImpl::SetState(State next_state) {
250 DCHECK(media_task_runner_->BelongsToCurrentThread());
218 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); 251 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state);
219 252
220 state_ = next_state; 253 state_ = next_state;
221 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); 254 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
222 } 255 }
223 256
224 #define RETURN_STRING(state) \ 257 #define RETURN_STRING(state) \
225 case state: \ 258 case state: \
226 return #state; 259 return #state;
227 260
(...skipping 10 matching lines...) Expand all
238 RETURN_STRING(kSuspended); 271 RETURN_STRING(kSuspended);
239 RETURN_STRING(kResuming); 272 RETURN_STRING(kResuming);
240 } 273 }
241 NOTREACHED(); 274 NOTREACHED();
242 return "INVALID"; 275 return "INVALID";
243 } 276 }
244 277
245 #undef RETURN_STRING 278 #undef RETURN_STRING
246 279
247 PipelineImpl::State PipelineImpl::GetNextState() const { 280 PipelineImpl::State PipelineImpl::GetNextState() const {
248 DCHECK(task_runner_->BelongsToCurrentThread()); 281 DCHECK(media_task_runner_->BelongsToCurrentThread());
249 DCHECK(stop_cb_.is_null()) << "State transitions don't happen when stopping";
250 DCHECK_EQ(status_, PIPELINE_OK) 282 DCHECK_EQ(status_, PIPELINE_OK)
251 << "State transitions don't happen when there's an error: " << status_; 283 << "State transitions don't happen when there's an error: " << status_;
252 284
253 switch (state_) { 285 switch (state_) {
254 case kCreated: 286 case kCreated:
255 return kInitDemuxer; 287 return kInitDemuxer;
256 288
257 case kInitDemuxer: 289 case kInitDemuxer:
258 return kInitRenderer; 290 return kInitRenderer;
259 291
(...skipping 13 matching lines...) Expand all
273 case kPlaying: 305 case kPlaying:
274 case kStopping: 306 case kStopping:
275 case kStopped: 307 case kStopped:
276 break; 308 break;
277 } 309 }
278 NOTREACHED() << "State has no transition: " << state_; 310 NOTREACHED() << "State has no transition: " << state_;
279 return state_; 311 return state_;
280 } 312 }
281 313
282 void PipelineImpl::OnDemuxerError(PipelineStatus error) { 314 void PipelineImpl::OnDemuxerError(PipelineStatus error) {
283 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, 315 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
284 weak_this_, error)); 316 // implementations call DemuxerHost on the media thread.
317 media_task_runner_->PostTask(
318 FROM_HERE,
319 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error));
285 } 320 }
286 321
287 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, 322 void PipelineImpl::AddTextStream(DemuxerStream* text_stream,
288 const TextTrackConfig& config) { 323 const TextTrackConfig& config) {
289 task_runner_->PostTask( 324 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
325 // implementations call DemuxerHost on the media thread.
326 media_task_runner_->PostTask(
290 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_, 327 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_,
291 text_stream, config)); 328 text_stream, config));
292 } 329 }
293 330
294 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { 331 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) {
295 task_runner_->PostTask( 332 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
333 // implementations call DemuxerHost on the media thread.
334 media_task_runner_->PostTask(
296 FROM_HERE, 335 FROM_HERE,
297 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream)); 336 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream));
298 } 337 }
299 338
300 void PipelineImpl::OnError(PipelineStatus error) { 339 void PipelineImpl::OnError(PipelineStatus error) {
301 DCHECK(task_runner_->BelongsToCurrentThread()); 340 DCHECK(media_task_runner_->BelongsToCurrentThread());
302 DCHECK(IsRunning()); 341 DCHECK(IsRunning());
303 DCHECK_NE(PIPELINE_OK, error); 342 DCHECK_NE(PIPELINE_OK, error);
304 VLOG(1) << "Media pipeline error: " << error; 343 VLOG(1) << "Media pipeline error: " << error;
305 344
306 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, 345 media_task_runner_->PostTask(
307 weak_this_, error)); 346 FROM_HERE,
347 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error));
308 } 348 }
309 349
310 void PipelineImpl::SetDuration(TimeDelta duration) { 350 void PipelineImpl::SetDuration(TimeDelta duration) {
351 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
352 // implementations call DemuxerHost on the media thread.
311 DCHECK(IsRunning()); 353 DCHECK(IsRunning());
312 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, 354 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET,
313 "duration", duration)); 355 "duration", duration));
314 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); 356 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
315 357
316 base::AutoLock auto_lock(lock_); 358 base::AutoLock auto_lock(lock_);
317 duration_ = duration; 359 duration_ = duration;
318 if (!duration_change_cb_.is_null()) 360 main_task_runner_->PostTask(FROM_HERE,
319 duration_change_cb_.Run(); 361 base::Bind(&Pipeline::Client::OnDurationChange,
362 base::Unretained(client_)));
xhwang 2016/05/02 20:58:35 Could you explain why base::Unretained is safe her
alokp 2016/05/02 22:25:17 It is not safe. The latest patch uses weak pointer
320 } 363 }
321 364
322 void PipelineImpl::StateTransitionTask(PipelineStatus status) { 365 void PipelineImpl::StateTransitionTask(PipelineStatus status) {
323 DCHECK(task_runner_->BelongsToCurrentThread()); 366 DCHECK(media_task_runner_->BelongsToCurrentThread());
324 367
325 // No-op any state transitions if we're stopping. 368 // No-op any state transitions if we're stopping.
326 if (state_ == kStopping || state_ == kStopped) 369 if (state_ == kStopping || state_ == kStopped)
327 return; 370 return;
328 371
329 // Preserve existing abnormal status, otherwise update based on the result of 372 // Report error from the previous operation.
330 // the previous operation. 373 if (status != PIPELINE_OK) {
331 status_ = (status_ != PIPELINE_OK ? status_ : status); 374 ErrorChangedTask(status);
332
333 if (status_ != PIPELINE_OK) {
334 ErrorChangedTask(status_);
335 return; 375 return;
336 } 376 }
337 377
338 // Guard against accidentally clearing |pending_callbacks_| for states that 378 // Guard against accidentally clearing |pending_callbacks_| for states that
339 // use it as well as states that should not be using it. 379 // use it as well as states that should not be using it.
340 DCHECK_EQ(pending_callbacks_.get() != NULL, 380 DCHECK_EQ(pending_callbacks_.get() != NULL,
341 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); 381 state_ == kSeeking || state_ == kSuspending || state_ == kResuming);
342 382
343 pending_callbacks_.reset(); 383 pending_callbacks_.reset();
344 384
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 } 437 }
398 } 438 }
399 439
400 // Note that the usage of base::Unretained() with the renderers is considered 440 // Note that the usage of base::Unretained() with the renderers is considered
401 // safe as they are owned by |pending_callbacks_| and share the same lifetime. 441 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
402 // 442 //
403 // That being said, deleting the renderers while keeping |pending_callbacks_| 443 // That being said, deleting the renderers while keeping |pending_callbacks_|
404 // running on the media thread would result in crashes. 444 // running on the media thread would result in crashes.
405 void PipelineImpl::DoSeek(TimeDelta seek_timestamp, 445 void PipelineImpl::DoSeek(TimeDelta seek_timestamp,
406 const PipelineStatusCB& done_cb) { 446 const PipelineStatusCB& done_cb) {
407 DCHECK(task_runner_->BelongsToCurrentThread()); 447 DCHECK(media_task_runner_->BelongsToCurrentThread());
408 DCHECK(!pending_callbacks_.get()); 448 DCHECK(!pending_callbacks_.get());
409 DCHECK_EQ(state_, kSeeking); 449 DCHECK_EQ(state_, kSeeking);
410 SerialRunner::Queue bound_fns; 450 SerialRunner::Queue bound_fns;
411 451
412 // Pause. 452 // Pause.
413 if (text_renderer_) { 453 if (text_renderer_) {
414 bound_fns.Push(base::Bind(&TextRenderer::Pause, 454 bound_fns.Push(base::Bind(&TextRenderer::Pause,
415 base::Unretained(text_renderer_.get()))); 455 base::Unretained(text_renderer_.get())));
416 } 456 }
417 457
418 // Flush. 458 // Flush.
419 DCHECK(renderer_); 459 DCHECK(renderer_);
420 bound_fns.Push( 460 bound_fns.Push(
421 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 461 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
422 462
423 if (text_renderer_) { 463 if (text_renderer_) {
424 bound_fns.Push(base::Bind(&TextRenderer::Flush, 464 bound_fns.Push(base::Bind(&TextRenderer::Flush,
425 base::Unretained(text_renderer_.get()))); 465 base::Unretained(text_renderer_.get())));
426 } 466 }
427 467
428 // Seek demuxer. 468 // Seek demuxer.
429 bound_fns.Push( 469 bound_fns.Push(
430 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 470 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
431 471
432 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 472 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
433 } 473 }
434 474
435 void PipelineImpl::DoStop(const PipelineStatusCB& done_cb) { 475 void PipelineImpl::DoStop(base::WaitableEvent* waiter) {
436 DVLOG(2) << __FUNCTION__; 476 DVLOG(2) << __FUNCTION__;
437 DCHECK(task_runner_->BelongsToCurrentThread()); 477 DCHECK(media_task_runner_->BelongsToCurrentThread());
478 DCHECK_EQ(state_, kStopping);
438 DCHECK(!pending_callbacks_.get()); 479 DCHECK(!pending_callbacks_.get());
439 480
440 // TODO(scherkus): Enforce that Renderer is only called on a single thread, 481 // TODO(scherkus): Enforce that Renderer is only called on a single thread,
441 // even for accessing media time http://crbug.com/370634 482 // even for accessing media time http://crbug.com/370634
442 std::unique_ptr<Renderer> renderer; 483 std::unique_ptr<Renderer> renderer;
443 { 484 {
444 base::AutoLock auto_lock(lock_); 485 base::AutoLock auto_lock(lock_);
445 renderer.swap(renderer_); 486 renderer.swap(renderer_);
446 } 487 }
447 renderer.reset(); 488 renderer.reset();
448 text_renderer_.reset(); 489 text_renderer_.reset();
449 490
450 if (demuxer_) { 491 if (demuxer_) {
451 demuxer_->Stop(); 492 demuxer_->Stop();
452 demuxer_ = NULL; 493 demuxer_ = NULL;
453 } 494 }
454 495
455 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 496 // If we stop during initialization/seeking/suspending we don't want to leave
456 } 497 // outstanding callbacks around. The callbacks also do not get run if the
498 // pipeline is stopped before it had a chance to complete outstanding tasks.
499 seek_cb_.Reset();
500 suspend_cb_.Reset();
457 501
458 void PipelineImpl::OnStopCompleted(PipelineStatus status) { 502 SetState(kStopped);
459 DVLOG(2) << __FUNCTION__;
460 DCHECK(task_runner_->BelongsToCurrentThread());
461 DCHECK_EQ(state_, kStopping);
462 DCHECK(!renderer_);
463 DCHECK(!text_renderer_);
464
465 { 503 {
466 base::AutoLock auto_lock(lock_); 504 base::AutoLock auto_lock(lock_);
467 running_ = false; 505 running_ = false;
468 } 506 }
507 weak_factory_.InvalidateWeakPtrs();
469 508
470 SetState(kStopped); 509 if (waiter)
471 demuxer_ = NULL; 510 waiter->Signal();
472
473 // If we stop during initialization/seeking/suspending we don't want to leave
474 // outstanding callbacks around.
475 if (!seek_cb_.is_null()) {
476 base::ResetAndReturn(&seek_cb_).Run(status_);
477 error_cb_.Reset();
478 }
479 if (!suspend_cb_.is_null()) {
480 base::ResetAndReturn(&suspend_cb_).Run(status_);
481 error_cb_.Reset();
482 }
483 if (!stop_cb_.is_null()) {
484 error_cb_.Reset();
485
486 // Invalid all weak pointers so it's safe to destroy |this| on the render
487 // main thread.
488 weak_factory_.InvalidateWeakPtrs();
489
490 base::ResetAndReturn(&stop_cb_).Run();
491
492 // NOTE: pipeline may be deleted at this point in time as a result of
493 // executing |stop_cb_|.
494 return;
495 }
496 if (!error_cb_.is_null()) {
497 DCHECK_NE(status_, PIPELINE_OK);
498 base::ResetAndReturn(&error_cb_).Run(status_);
499 }
500 } 511 }
501 512
502 void PipelineImpl::OnBufferedTimeRangesChanged( 513 void PipelineImpl::OnBufferedTimeRangesChanged(
503 const Ranges<base::TimeDelta>& ranges) { 514 const Ranges<base::TimeDelta>& ranges) {
515 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
516 // implementations call DemuxerHost on the media thread.
504 base::AutoLock auto_lock(lock_); 517 base::AutoLock auto_lock(lock_);
505 buffered_time_ranges_ = ranges; 518 buffered_time_ranges_ = ranges;
506 did_loading_progress_ = true; 519 did_loading_progress_ = true;
507 } 520 }
508 521
509 // Called from any thread. 522 // Called from any thread.
510 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { 523 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) {
511 base::AutoLock auto_lock(lock_); 524 base::AutoLock auto_lock(lock_);
512 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; 525 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded;
513 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; 526 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded;
514 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; 527 statistics_.video_frames_decoded += stats_delta.video_frames_decoded;
515 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; 528 statistics_.video_frames_dropped += stats_delta.video_frames_dropped;
516 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; 529 statistics_.audio_memory_usage += stats_delta.audio_memory_usage;
517 statistics_.video_memory_usage += stats_delta.video_memory_usage; 530 statistics_.video_memory_usage += stats_delta.video_memory_usage;
518 } 531 }
519 532
533 void PipelineImpl::OnWaitingForDecryptionKey() {
534 DCHECK(media_task_runner_->BelongsToCurrentThread());
535
536 main_task_runner_->PostTask(
537 FROM_HERE, base::Bind(&Pipeline::Client::OnWaitingForDecryptionKey,
538 base::Unretained(client_)));
539 }
540
520 void PipelineImpl::StartTask() { 541 void PipelineImpl::StartTask() {
521 DCHECK(task_runner_->BelongsToCurrentThread()); 542 DCHECK(media_task_runner_->BelongsToCurrentThread());
522 543
523 CHECK_EQ(kCreated, state_) 544 CHECK_EQ(kCreated, state_)
524 << "Media pipeline cannot be started more than once"; 545 << "Media pipeline cannot be started more than once";
525 546
526 text_renderer_ = CreateTextRenderer(); 547 text_renderer_ = CreateTextRenderer();
527 if (text_renderer_) { 548 if (text_renderer_) {
528 text_renderer_->Initialize( 549 text_renderer_->Initialize(
529 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); 550 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_));
530 } 551 }
531 552
532 StateTransitionTask(PIPELINE_OK); 553 StateTransitionTask(PIPELINE_OK);
533 } 554 }
534 555
535 void PipelineImpl::StopTask(const base::Closure& stop_cb) { 556 void PipelineImpl::StopTask(base::WaitableEvent* waiter) {
536 DCHECK(task_runner_->BelongsToCurrentThread()); 557 DCHECK(media_task_runner_->BelongsToCurrentThread());
537 DCHECK(stop_cb_.is_null());
538 558
539 if (state_ == kStopped) { 559 // We may already be stopping due to a runtime error.
540 // Invalid all weak pointers so it's safe to destroy |this| on the render 560 if (state_ == kStopped || state_ == kStopping) {
541 // main thread. 561 if (waiter)
542 weak_factory_.InvalidateWeakPtrs(); 562 waiter->Signal();
543
544 // NOTE: pipeline may be deleted at this point in time as a result of
545 // executing |stop_cb|.
546 stop_cb.Run();
547
548 return; 563 return;
549 } 564 }
550 565
551 stop_cb_ = stop_cb;
552
553 // We may already be stopping due to a runtime error.
554 if (state_ == kStopping)
555 return;
556
557 // Do not report statistics if the pipeline is not fully initialized. 566 // Do not report statistics if the pipeline is not fully initialized.
558 if (state_ == kSeeking || state_ == kPlaying || state_ == kSuspending || 567 if (state_ == kSeeking || state_ == kPlaying || state_ == kSuspending ||
559 state_ == kSuspended || state_ == kResuming) { 568 state_ == kSuspended || state_ == kResuming) {
560 PipelineStatistics stats = GetStatistics(); 569 PipelineStatistics stats = GetStatistics();
561 if (stats.video_frames_decoded > 0) { 570 if (stats.video_frames_decoded > 0) {
562 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", 571 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
563 stats.video_frames_dropped); 572 stats.video_frames_dropped);
564 } 573 }
565 } 574 }
566 575
567 SetState(kStopping); 576 SetState(kStopping);
568 pending_callbacks_.reset(); 577 pending_callbacks_.reset();
569 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); 578 DoStop(waiter);
570 } 579 }
571 580
572 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { 581 void PipelineImpl::ErrorChangedTask(PipelineStatus error) {
573 DCHECK(task_runner_->BelongsToCurrentThread()); 582 DCHECK(media_task_runner_->BelongsToCurrentThread());
574 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 583 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
575 584
585 // Preserve existing abnormal status.
586 if (status_ != PIPELINE_OK)
587 return;
588
576 // Don't report pipeline error events to the media log here. The embedder will 589 // Don't report pipeline error events to the media log here. The embedder will
577 // log this when |error_cb_| is called. If the pipeline is already stopped or 590 // log this when |error_cb_| is called. If the pipeline is already stopped or
578 // stopping we also don't want to log any event. In case we are suspending or 591 // stopping we also don't want to log any event. In case we are suspending or
579 // suspended, the error may be recoverable, so don't propagate it now, instead 592 // suspended, the error may be recoverable, so don't propagate it now, instead
580 // let the subsequent seek during resume propagate it if it's unrecoverable. 593 // let the subsequent seek during resume propagate it if it's unrecoverable.
581
582 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || 594 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending ||
583 state_ == kSuspended) { 595 state_ == kSuspended) {
584 return; 596 return;
585 } 597 }
586 598
587 SetState(kStopping); 599 // Once we enter |kStopping| state, nothing is reported back to the client.
588 pending_callbacks_.reset(); 600 // If we encounter an error during initialization/seeking/suspending,
601 // report the error using the completion callbacks for those tasks.
589 status_ = error; 602 status_ = error;
603 bool status_reported = false;
604 if (!seek_cb_.is_null()) {
605 base::ResetAndReturn(&seek_cb_).Run(status_);
sandersd (OOO until July 31) 2016/05/02 18:37:47 Are we sure it's safe to drop these from the Stop(
alokp 2016/05/02 22:25:17 It is not possible to call these since Stop is blo
sandersd (OOO until July 31) 2016/05/02 22:45:51 That's fair, but we also can't commit this without
alokp 2016/05/02 23:00:59 PipelineImpl::Seek/Suspend is only called from Pip
sandersd (OOO until July 31) 2016/05/02 23:20:47 PipelineController binds them all to OnPipelineSta
alokp 2016/05/03 05:22:18 Right. I am sorry I do not see a problem there. Ca
sandersd (OOO until July 31) 2016/05/03 19:28:55 I'm not sure if it's a problem, it's probably not,
alokp 2016/05/03 20:15:23 SGTM
606 status_reported = true;
607 }
608 if (!suspend_cb_.is_null()) {
609 base::ResetAndReturn(&suspend_cb_).Run(status_);
610 status_reported = true;
611 }
612 if (!status_reported) {
613 DCHECK_NE(status_, PIPELINE_OK);
614 main_task_runner_->PostTask(FROM_HERE,
615 base::Bind(&Pipeline::Client::OnError,
616 base::Unretained(client_), status_));
617 }
590 618
591 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); 619 // Stop the pipeline.
620 StopTask(nullptr);
592 } 621 }
593 622
594 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { 623 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) {
595 DCHECK(task_runner_->BelongsToCurrentThread()); 624 DCHECK(media_task_runner_->BelongsToCurrentThread());
596 625
597 // Playback rate changes are only carried out while playing. 626 // Playback rate changes are only carried out while playing.
598 if (state_ != kPlaying) 627 if (state_ != kPlaying)
599 return; 628 return;
600 629
601 renderer_->SetPlaybackRate(playback_rate); 630 renderer_->SetPlaybackRate(playback_rate);
602 } 631 }
603 632
604 void PipelineImpl::VolumeChangedTask(float volume) { 633 void PipelineImpl::VolumeChangedTask(float volume) {
605 DCHECK(task_runner_->BelongsToCurrentThread()); 634 DCHECK(media_task_runner_->BelongsToCurrentThread());
606 635
607 // Volume changes are only carried out while playing. 636 // Volume changes are only carried out while playing.
608 if (state_ != kPlaying) 637 if (state_ != kPlaying)
609 return; 638 return;
610 639
611 renderer_->SetVolume(volume); 640 renderer_->SetVolume(volume);
612 } 641 }
613 642
614 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { 643 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
615 DCHECK(task_runner_->BelongsToCurrentThread()); 644 DCHECK(media_task_runner_->BelongsToCurrentThread());
616 DCHECK(stop_cb_.is_null());
617 645
618 // Suppress seeking if we're not fully started. 646 // Suppress seeking if we're not fully started.
619 if (state_ != kPlaying) { 647 if (state_ != kPlaying) {
620 DCHECK(state_ == kStopping || state_ == kStopped) 648 DCHECK(state_ == kStopping || state_ == kStopped)
621 << "Receive seek in unexpected state: " << state_; 649 << "Receive seek in unexpected state: " << state_;
622 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); 650 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
623 return; 651 return;
624 } 652 }
625 653
626 DCHECK(seek_cb_.is_null()); 654 DCHECK(seek_cb_.is_null());
627 655
628 const base::TimeDelta seek_timestamp = 656 const base::TimeDelta seek_timestamp =
629 std::max(time, demuxer_->GetStartTime()); 657 std::max(time, demuxer_->GetStartTime());
630 658
631 SetState(kSeeking); 659 SetState(kSeeking);
632 seek_cb_ = seek_cb; 660 seek_cb_ = seek_cb;
633 renderer_ended_ = false; 661 renderer_ended_ = false;
634 text_renderer_ended_ = false; 662 text_renderer_ended_ = false;
635 start_timestamp_ = seek_timestamp; 663 start_timestamp_ = seek_timestamp;
636 664
637 DoSeek(seek_timestamp, 665 DoSeek(seek_timestamp,
638 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); 666 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_));
639 } 667 }
640 668
641 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { 669 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) {
642 DCHECK(task_runner_->BelongsToCurrentThread()); 670 DCHECK(media_task_runner_->BelongsToCurrentThread());
643 671
644 // Suppress suspending if we're not playing. 672 // Suppress suspending if we're not playing.
645 if (state_ != kPlaying) { 673 if (state_ != kPlaying) {
646 DCHECK(state_ == kStopping || state_ == kStopped) 674 DCHECK(state_ == kStopping || state_ == kStopped)
647 << "Receive suspend in unexpected state: " << state_; 675 << "Receive suspend in unexpected state: " << state_;
648 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); 676 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE);
649 return; 677 return;
650 } 678 }
651 DCHECK(renderer_); 679 DCHECK(renderer_);
652 DCHECK(!pending_callbacks_.get()); 680 DCHECK(!pending_callbacks_.get());
(...skipping 27 matching lines...) Expand all
680 base::Unretained(text_renderer_.get()))); 708 base::Unretained(text_renderer_.get())));
681 } 709 }
682 710
683 pending_callbacks_ = SerialRunner::Run( 711 pending_callbacks_ = SerialRunner::Run(
684 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); 712 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_));
685 } 713 }
686 714
687 void PipelineImpl::ResumeTask(std::unique_ptr<Renderer> renderer, 715 void PipelineImpl::ResumeTask(std::unique_ptr<Renderer> renderer,
688 base::TimeDelta timestamp, 716 base::TimeDelta timestamp,
689 const PipelineStatusCB& seek_cb) { 717 const PipelineStatusCB& seek_cb) {
690 DCHECK(task_runner_->BelongsToCurrentThread()); 718 DCHECK(media_task_runner_->BelongsToCurrentThread());
691 719
692 // Suppress resuming if we're not suspended. 720 // Suppress resuming if we're not suspended.
693 if (state_ != kSuspended) { 721 if (state_ != kSuspended) {
694 DCHECK(state_ == kStopping || state_ == kStopped) 722 DCHECK(state_ == kStopping || state_ == kStopped)
695 << "Receive resume in unexpected state: " << state_; 723 << "Receive resume in unexpected state: " << state_;
696 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); 724 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
697 return; 725 return;
698 } 726 }
699 DCHECK(!renderer_); 727 DCHECK(!renderer_);
700 DCHECK(!pending_callbacks_.get()); 728 DCHECK(!pending_callbacks_.get());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 } 762 }
735 763
736 renderer_->SetCdm(cdm_context, 764 renderer_->SetCdm(cdm_context,
737 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_, 765 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_,
738 cdm_attached_cb, cdm_context)); 766 cdm_attached_cb, cdm_context));
739 } 767 }
740 768
741 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, 769 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb,
742 CdmContext* cdm_context, 770 CdmContext* cdm_context,
743 bool success) { 771 bool success) {
744 DCHECK(task_runner_->BelongsToCurrentThread()); 772 DCHECK(media_task_runner_->BelongsToCurrentThread());
745 if (success) 773 if (success)
746 cdm_context_ = cdm_context; 774 cdm_context_ = cdm_context;
747 cdm_attached_cb.Run(success); 775 cdm_attached_cb.Run(success);
748 } 776 }
749 777
750 void PipelineImpl::OnRendererEnded() { 778 void PipelineImpl::OnRendererEnded() {
751 DCHECK(task_runner_->BelongsToCurrentThread()); 779 DCHECK(media_task_runner_->BelongsToCurrentThread());
752 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); 780 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED));
753 781
754 if (state_ != kPlaying) 782 if (state_ != kPlaying)
755 return; 783 return;
756 784
757 DCHECK(!renderer_ended_); 785 DCHECK(!renderer_ended_);
758 renderer_ended_ = true; 786 renderer_ended_ = true;
759 787
760 RunEndedCallbackIfNeeded(); 788 RunEndedCallbackIfNeeded();
761 } 789 }
762 790
763 void PipelineImpl::OnTextRendererEnded() { 791 void PipelineImpl::OnTextRendererEnded() {
764 DCHECK(task_runner_->BelongsToCurrentThread()); 792 DCHECK(media_task_runner_->BelongsToCurrentThread());
765 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 793 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
766 794
767 if (state_ != kPlaying) 795 if (state_ != kPlaying)
768 return; 796 return;
769 797
770 DCHECK(!text_renderer_ended_); 798 DCHECK(!text_renderer_ended_);
771 text_renderer_ended_ = true; 799 text_renderer_ended_ = true;
772 800
773 RunEndedCallbackIfNeeded(); 801 RunEndedCallbackIfNeeded();
774 } 802 }
775 803
776 void PipelineImpl::RunEndedCallbackIfNeeded() { 804 void PipelineImpl::RunEndedCallbackIfNeeded() {
777 DCHECK(task_runner_->BelongsToCurrentThread()); 805 DCHECK(media_task_runner_->BelongsToCurrentThread());
778 806
779 if (renderer_ && !renderer_ended_) 807 if (renderer_ && !renderer_ended_)
780 return; 808 return;
781 809
782 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 810 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
783 return; 811 return;
784 812
785 DCHECK_EQ(status_, PIPELINE_OK); 813 DCHECK_EQ(status_, PIPELINE_OK);
786 ended_cb_.Run(); 814 main_task_runner_->PostTask(FROM_HERE, base::Bind(&Pipeline::Client::OnEnded,
815 base::Unretained(client_)));
787 } 816 }
788 817
789 std::unique_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { 818 std::unique_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() {
790 DCHECK(task_runner_->BelongsToCurrentThread()); 819 DCHECK(media_task_runner_->BelongsToCurrentThread());
791 820
792 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); 821 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
793 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) 822 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks))
794 return nullptr; 823 return nullptr;
795 824
796 return base::WrapUnique(new media::TextRenderer( 825 return base::WrapUnique(new media::TextRenderer(
797 task_runner_, base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_))); 826 media_task_runner_,
827 base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_)));
798 } 828 }
799 829
800 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, 830 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream,
801 const TextTrackConfig& config) { 831 const TextTrackConfig& config) {
802 DCHECK(task_runner_->BelongsToCurrentThread()); 832 DCHECK(media_task_runner_->BelongsToCurrentThread());
803 // TODO(matthewjheaney): fix up text_ended_ when text stream 833 // TODO(matthewjheaney): fix up text_ended_ when text stream
804 // is added (http://crbug.com/321446). 834 // is added (http://crbug.com/321446).
805 if (text_renderer_) 835 if (text_renderer_)
806 text_renderer_->AddTextStream(text_stream, config); 836 text_renderer_->AddTextStream(text_stream, config);
807 } 837 }
808 838
809 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { 839 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) {
810 DCHECK(task_runner_->BelongsToCurrentThread()); 840 DCHECK(media_task_runner_->BelongsToCurrentThread());
841
811 if (text_renderer_) 842 if (text_renderer_)
812 text_renderer_->RemoveTextStream(text_stream); 843 text_renderer_->RemoveTextStream(text_stream);
813 } 844 }
814 845
815 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, 846 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config,
816 const AddTextTrackDoneCB& done_cb) { 847 const AddTextTrackDoneCB& done_cb) {
817 DCHECK(task_runner_->BelongsToCurrentThread()); 848 DCHECK(media_task_runner_->BelongsToCurrentThread());
818 add_text_track_cb_.Run(config, done_cb); 849
850 main_task_runner_->PostTask(
851 FROM_HERE, base::Bind(&Pipeline::Client::OnAddTextTrack,
852 base::Unretained(client_), config, done_cb));
819 } 853 }
820 854
821 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { 855 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) {
822 DCHECK(task_runner_->BelongsToCurrentThread()); 856 DCHECK(media_task_runner_->BelongsToCurrentThread());
857
823 demuxer_->Initialize(this, done_cb, !!text_renderer_); 858 demuxer_->Initialize(this, done_cb, !!text_renderer_);
824 } 859 }
825 860
826 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { 861 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) {
827 DCHECK(task_runner_->BelongsToCurrentThread()); 862 DCHECK(media_task_runner_->BelongsToCurrentThread());
828 863
829 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && 864 if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
830 !demuxer_->GetStream(DemuxerStream::VIDEO)) { 865 !demuxer_->GetStream(DemuxerStream::VIDEO)) {
831 { 866 {
832 base::AutoLock auto_lock(lock_); 867 base::AutoLock auto_lock(lock_);
833 renderer_.reset(); 868 renderer_.reset();
834 } 869 }
835 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); 870 OnError(PIPELINE_ERROR_COULD_NOT_RENDER);
836 return; 871 return;
837 } 872 }
838 873
839 if (cdm_context_) 874 if (cdm_context_)
840 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); 875 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached));
841 876
842 renderer_->Initialize( 877 renderer_->Initialize(
843 demuxer_, done_cb, 878 demuxer_, done_cb,
844 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), 879 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_),
845 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), 880 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_),
846 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), 881 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_),
847 base::Bind(&PipelineImpl::OnError, weak_this_), 882 base::Bind(&PipelineImpl::OnError, weak_this_),
848 waiting_for_decryption_key_cb_); 883 base::Bind(&PipelineImpl::OnWaitingForDecryptionKey, weak_this_));
849 } 884 }
850 885
851 void PipelineImpl::ReportMetadata() { 886 void PipelineImpl::ReportMetadata() {
852 DCHECK(task_runner_->BelongsToCurrentThread()); 887 DCHECK(media_task_runner_->BelongsToCurrentThread());
888
853 PipelineMetadata metadata; 889 PipelineMetadata metadata;
854 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 890 metadata.timeline_offset = demuxer_->GetTimelineOffset();
855 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 891 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
856 if (stream) { 892 if (stream) {
857 metadata.has_video = true; 893 metadata.has_video = true;
858 metadata.natural_size = stream->video_decoder_config().natural_size(); 894 metadata.natural_size = stream->video_decoder_config().natural_size();
859 metadata.video_rotation = stream->video_rotation(); 895 metadata.video_rotation = stream->video_rotation();
860 } 896 }
861 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { 897 if (demuxer_->GetStream(DemuxerStream::AUDIO)) {
862 metadata.has_audio = true; 898 metadata.has_audio = true;
863 } 899 }
864 metadata_cb_.Run(metadata); 900
901 main_task_runner_->PostTask(FROM_HERE,
902 base::Bind(&Pipeline::Client::OnMetadata,
903 base::Unretained(client_), metadata));
865 } 904 }
866 905
867 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { 906 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) {
907 DCHECK(media_task_runner_->BelongsToCurrentThread());
868 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; 908 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") ";
869 DCHECK(task_runner_->BelongsToCurrentThread()); 909
870 buffering_state_cb_.Run(new_buffering_state); 910 main_task_runner_->PostTask(
911 FROM_HERE, base::Bind(&Pipeline::Client::OnBufferingStateChange,
912 base::Unretained(client_), new_buffering_state));
871 } 913 }
872 914
873 } // namespace media 915 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698