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

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

Powered by Google App Engine
This is Rietveld 408576698