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

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

Issue 1999893004: Splits PipelineImpl into main and media thread components. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rearranged code for easier review Created 4 years, 6 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>
9 8
10 #include "base/bind.h" 9 #include "base/bind.h"
11 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
12 #include "base/callback.h" 11 #include "base/callback.h"
13 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
14 #include "base/command_line.h" 13 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/location.h" 14 #include "base/location.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
19 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h" 17 #include "base/synchronization/lock.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/synchronization/waitable_event.h" 18 #include "base/synchronization/waitable_event.h"
24 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
25 #include "media/base/bind_to_current_loop.h" 20 #include "media/base/bind_to_current_loop.h"
21 #include "media/base/demuxer.h"
26 #include "media/base/media_log.h" 22 #include "media/base/media_log.h"
27 #include "media/base/media_switches.h" 23 #include "media/base/media_switches.h"
28 #include "media/base/renderer.h" 24 #include "media/base/renderer.h"
25 #include "media/base/renderer_client.h"
26 #include "media/base/serial_runner.h"
29 #include "media/base/text_renderer.h" 27 #include "media/base/text_renderer.h"
30 #include "media/base/text_track_config.h" 28 #include "media/base/text_track_config.h"
31 #include "media/base/timestamp_constants.h" 29 #include "media/base/timestamp_constants.h"
32 #include "media/base/video_decoder_config.h" 30 #include "media/base/video_decoder_config.h"
33 31
34 using base::TimeDelta; 32 namespace {
33
34 const double kDefaultPlaybackRate = 0.0;
35 const float kDefaultVolume = 1.0f;
36
37 bool TextTracksEnabled() {
38 static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
alokp 2016/06/08 19:59:48 cached here instead of querying the command line f
39 switches::kEnableInbandTextTracks);
40 return enabled;
41 }
42
43 } // namespace
35 44
36 namespace media { 45 namespace media {
37 46
47 class PipelineImpl::RendererWrapper : public DemuxerHost,
48 public RendererClient {
49 public:
50 RendererWrapper(base::WeakPtr<PipelineImpl> weak_pipeline,
51 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
52 scoped_refptr<MediaLog> media_log);
53 ~RendererWrapper() final;
54
55 void Start(Demuxer* demuxer,
56 std::unique_ptr<Renderer> renderer,
57 std::unique_ptr<TextRenderer> text_renderer);
58 void Stop(const base::Closure& stop_cb);
59 void Seek(base::TimeDelta time);
60 void Suspend();
61 void Resume(base::TimeDelta time, std::unique_ptr<Renderer> renderer);
62 void SetPlaybackRate(double playback_rate);
63 void SetVolume(float volume);
64 base::TimeDelta GetMediaTime();
65 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
66
67 private:
68 // DemuxerHost implementaion.
69 void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final;
70 void SetDuration(base::TimeDelta duration) final;
71 void OnDemuxerError(PipelineStatus error) final;
72 void AddTextStream(DemuxerStream* text_stream,
73 const TextTrackConfig& config) final;
74 void RemoveTextStream(DemuxerStream* text_stream) final;
75
76 // RendererClient implementation.
77 void OnError(PipelineStatus error) final;
78 void OnEnded() final;
79 void OnStatisticsUpdate(const PipelineStatistics& stats) final;
80 void OnBufferingStateChange(BufferingState state) final;
81 void OnWaitingForDecryptionKey() final;
82 void OnVideoNaturalSizeChange(const gfx::Size& size) final;
83 void OnVideoOpacityChange(bool opaque) final;
84
85 void OnPipelineError(PipelineStatus error);
86 void OnTextRendererEnded();
87 void RunEndedCallbackIfNeeded();
88 void SetState(State next_state);
89 void OnSeekDone(base::TimeDelta start_time, PipelineStatus status);
90 void OnSuspendDone(base::TimeDelta suspend_time, PipelineStatus status);
91
92 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb,
93 CdmContext* cdm_context,
94 bool success);
95 void AddTextStreamTask(DemuxerStream* text_stream,
96 const TextTrackConfig& config);
97 void RemoveTextStreamTask(DemuxerStream* text_stream);
98 void InitializeDemuxer(const PipelineStatusCB& done_cb);
99 void InitializeRenderer(const PipelineStatusCB& done_cb);
100 void ReportMetadata();
101
102 base::WeakPtr<PipelineImpl> weak_pipeline_;
103 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
104 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
105 const scoped_refptr<MediaLog> media_log_;
106
107 Demuxer* demuxer_;
108 std::unique_ptr<Renderer> renderer_;
109 std::unique_ptr<TextRenderer> text_renderer_;
110 double playback_rate_;
111 float volume_;
112 CdmContext* cdm_context_;
113
114 // Lock used to serialize access for |renderer_|.
115 mutable base::Lock renderer_lock_;
116
117 // Current state of the pipeline.
118 State state_;
119
120 // Last media time reported to the pipeline.
121 base::TimeDelta last_media_time_;
122
123 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
124 // the pipeline is operating correctly. Any other value indicates that the
125 // pipeline is stopped or is stopping. Clients can call the Stop() method to
126 // reset the pipeline state, and restore this to PIPELINE_OK.
127 PipelineStatus status_;
128
129 // Whether we've received the audio/video/text ended events.
130 bool renderer_ended_;
131 bool text_renderer_ended_;
132
133 // Series of tasks to Start(), Seek(), and Resume().
134 std::unique_ptr<SerialRunner> pending_callbacks_;
135
136 base::WeakPtrFactory<RendererWrapper> weak_factory_;
137 DISALLOW_COPY_AND_ASSIGN(RendererWrapper);
138 };
139
38 PipelineImpl::PipelineImpl( 140 PipelineImpl::PipelineImpl(
39 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 141 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
40 MediaLog* media_log) 142 MediaLog* media_log)
41 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), 143 : media_task_runner_(media_task_runner),
42 media_task_runner_(media_task_runner),
43 media_log_(media_log), 144 media_log_(media_log),
44 running_(false), 145 client_(nullptr),
alokp 2016/06/08 19:59:48 no need for running_. We now use client_ != null a
146 playback_rate_(kDefaultPlaybackRate),
147 volume_(kDefaultVolume),
148 suspend_time_(kNoTimestamp()),
45 did_loading_progress_(false), 149 did_loading_progress_(false),
46 volume_(1.0f),
47 playback_rate_(0.0),
48 status_(PIPELINE_OK),
alokp 2016/06/08 19:59:47 state machine has been moved to RendererWrapper.
49 state_(kCreated),
50 suspend_timestamp_(kNoTimestamp()),
51 renderer_ended_(false),
52 text_renderer_ended_(false),
53 demuxer_(NULL),
54 cdm_context_(nullptr),
55 weak_factory_(this) { 150 weak_factory_(this) {
56 weak_this_ = weak_factory_.GetWeakPtr(); 151 DVLOG(2) << __FUNCTION__;
57 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 152 renderer_wrapper_.reset(new RendererWrapper(weak_factory_.GetWeakPtr(),
153 media_task_runner_, media_log_));
58 } 154 }
59 155
60 PipelineImpl::~PipelineImpl() { 156 PipelineImpl::~PipelineImpl() {
61 DCHECK(main_task_runner_->BelongsToCurrentThread()) 157 DVLOG(2) << __FUNCTION__;
62 << "Pipeline must be destroyed on same thread that created it"; 158 DCHECK(thread_checker_.CalledOnValidThread());
63 DCHECK(!running_) << "Stop() must complete before destroying object"; 159 DCHECK(!client_) << "Stop() must complete before destroying object";
64 DCHECK(seek_cb_.is_null()); 160 DCHECK(seek_cb_.is_null());
161 DCHECK(suspend_cb_.is_null());
162
163 // Invalidate self weak pointers effectively canceling all pending
164 // notifications in the message queue.
165 weak_factory_.InvalidateWeakPtrs();
166
167 // RendererWrapper is deleted on the media thread.
168 media_task_runner_->DeleteSoon(FROM_HERE, renderer_wrapper_.release());
65 } 169 }
66 170
67 void PipelineImpl::Start(Demuxer* demuxer, 171 void PipelineImpl::Start(Demuxer* demuxer,
68 std::unique_ptr<Renderer> renderer, 172 std::unique_ptr<Renderer> renderer,
69 Client* client, 173 Client* client,
70 const PipelineStatusCB& seek_cb) { 174 const PipelineStatusCB& seek_cb) {
71 DCHECK(main_task_runner_->BelongsToCurrentThread()); 175 DVLOG(2) << __FUNCTION__;
176 DCHECK(thread_checker_.CalledOnValidThread());
177 DCHECK(demuxer);
178 DCHECK(renderer);
72 DCHECK(client); 179 DCHECK(client);
73 DCHECK(!seek_cb.is_null()); 180 DCHECK(!seek_cb.is_null());
74 181
75 base::AutoLock auto_lock(lock_); 182 DCHECK(!client_);
76 CHECK(!running_) << "Media pipeline is already running"; 183 DCHECK(seek_cb_.is_null());
77 running_ = true; 184 client_ = client;
78 185 seek_cb_ = seek_cb;
79 demuxer_ = demuxer; 186
80 renderer_ = std::move(renderer); 187 std::unique_ptr<TextRenderer> text_renderer;
alokp 2016/06/08 19:59:46 We create TextRenderer on the main thread because:
81 client_weak_factory_.reset(new base::WeakPtrFactory<Client>(client)); 188 if (TextTracksEnabled()) {
82 weak_client_ = client_weak_factory_->GetWeakPtr(); 189 text_renderer.reset(new TextRenderer(
83 seek_cb_ = media::BindToCurrentLoop(seek_cb); 190 media_task_runner_,
84 media_task_runner_->PostTask( 191 BindToCurrentLoop(base::Bind(&PipelineImpl::OnAddTextTrack,
85 FROM_HERE, base::Bind(&PipelineImpl::StartTask, weak_this_)); 192 weak_factory_.GetWeakPtr()))));
193 }
194
195 media_task_runner_->PostTask(
196 FROM_HERE,
197 base::Bind(&RendererWrapper::Start,
198 base::Unretained(renderer_wrapper_.get()), demuxer,
199 base::Passed(&renderer), base::Passed(&text_renderer)));
86 } 200 }
87 201
88 void PipelineImpl::Stop() { 202 void PipelineImpl::Stop() {
89 DCHECK(main_task_runner_->BelongsToCurrentThread()); 203 DVLOG(2) << __FUNCTION__;
90 DVLOG(2) << __FUNCTION__; 204 DCHECK(thread_checker_.CalledOnValidThread());
91 205
92 if (media_task_runner_ != main_task_runner_) { 206 if (!IsRunning()) {
207 DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()";
208 return;
209 }
210
211 if (media_task_runner_->BelongsToCurrentThread()) {
alokp 2016/06/08 19:59:48 no major change here - just swapped the condition
212 // This path is executed by unittests that share media and main threads.
213 base::Closure stop_cb = base::Bind(&base::DoNothing);
214 media_task_runner_->PostTask(
215 FROM_HERE,
216 base::Bind(&RendererWrapper::Stop,
217 base::Unretained(renderer_wrapper_.get()), stop_cb));
218 } else {
93 // This path is executed by production code where the two task runners - 219 // This path is executed by production code where the two task runners -
94 // main and media - live on different threads. 220 // main and media - live on different threads.
95 // TODO(alokp): It may be possible to not have to wait for StopTask by 221 //
96 // moving the members accessed on media thread into a class/struct and 222 // TODO(alokp): We should not have to wait for the RendererWrapper::Stop.
97 // DeleteSoon the instance on the media thread. 223 // RendererWrapper holds a raw reference to Demuxer, which in turn holds a
224 // raw reference to DataSource. Both Demuxer and DataSource need to live
225 // until RendererWrapper is stopped. If RendererWrapper owned Demuxer and
226 // Demuxer owned DataSource, we could simply let RendererWrapper get lazily
227 // destroyed on the media thread.
98 base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC, 228 base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC,
99 base::WaitableEvent::InitialState::NOT_SIGNALED); 229 base::WaitableEvent::InitialState::NOT_SIGNALED);
100 base::Closure stop_cb = 230 base::Closure stop_cb =
101 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter)); 231 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter));
102 // If posting the task fails or the posted task fails to run, 232 media_task_runner_->PostTask(
103 // we will wait here forever. So add a CHECK to make sure we do not run 233 FROM_HERE,
104 // into those situations. 234 base::Bind(&RendererWrapper::Stop,
105 CHECK(weak_factory_.HasWeakPtrs()); 235 base::Unretained(renderer_wrapper_.get()), stop_cb));
106 CHECK(media_task_runner_->PostTask(
107 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)));
108 waiter.Wait(); 236 waiter.Wait();
109 } else {
110 // This path is executed by unittests that share media and main threads.
111 StopTask(base::Bind(&base::DoNothing));
112 } 237 }
113 // Invalidate client weak pointer effectively canceling all pending client 238
114 // notifications in the message queue. 239 // Once the pipeline is stopped, nothing is reported back to the client.
115 client_weak_factory_.reset(); 240 // Reset all callbacks and client handle.
116 } 241 seek_cb_.Reset();
117 242 suspend_cb_.Reset();
118 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { 243 client_ = nullptr;
119 DCHECK(main_task_runner_->BelongsToCurrentThread()); 244 }
245
246 void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) {
247 DVLOG(2) << __FUNCTION__;
alokp 2016/06/08 19:59:47 These functions just post tasks to the media threa
248 DCHECK(thread_checker_.CalledOnValidThread());
249 DCHECK(!seek_cb.is_null());
120 250
121 if (!IsRunning()) { 251 if (!IsRunning()) {
122 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; 252 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
123 return; 253 return;
124 } 254 }
125 255
126 media_task_runner_->PostTask( 256 DCHECK(seek_cb_.is_null());
127 FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_this_, time, 257 seek_cb_ = seek_cb;
128 media::BindToCurrentLoop(seek_cb))); 258 media_task_runner_->PostTask(
259 FROM_HERE, base::Bind(&RendererWrapper::Seek,
260 base::Unretained(renderer_wrapper_.get()), time));
261 }
262
263 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
264 DVLOG(2) << __FUNCTION__;
265 DCHECK(!suspend_cb.is_null());
266
267 DCHECK(IsRunning());
268 DCHECK(suspend_cb_.is_null());
269 suspend_cb_ = suspend_cb;
270
271 media_task_runner_->PostTask(
272 FROM_HERE, base::Bind(&RendererWrapper::Suspend,
273 base::Unretained(renderer_wrapper_.get())));
274 }
275
276 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer,
277 base::TimeDelta time,
278 const PipelineStatusCB& seek_cb) {
279 DVLOG(2) << __FUNCTION__;
280 DCHECK(thread_checker_.CalledOnValidThread());
281 DCHECK(renderer);
282 DCHECK(!seek_cb.is_null());
283
284 DCHECK(IsRunning());
285 DCHECK(seek_cb_.is_null());
286 seek_cb_ = seek_cb;
287
288 media_task_runner_->PostTask(
289 FROM_HERE, base::Bind(&RendererWrapper::Resume,
290 base::Unretained(renderer_wrapper_.get()), time,
291 base::Passed(&renderer)));
129 } 292 }
130 293
131 bool PipelineImpl::IsRunning() const { 294 bool PipelineImpl::IsRunning() const {
132 // TODO(alokp): Add thread DCHECK after removing the internal usage on 295 DCHECK(thread_checker_.CalledOnValidThread());
alokp 2016/06/08 19:59:48 client_ is cleared as soon the pipeline stops. So
133 // media thread. 296 return !!client_;
134 base::AutoLock auto_lock(lock_);
135 return running_;
136 } 297 }
137 298
138 double PipelineImpl::GetPlaybackRate() const { 299 double PipelineImpl::GetPlaybackRate() const {
139 // TODO(alokp): Add thread DCHECK after removing the internal usage on 300 DCHECK(thread_checker_.CalledOnValidThread());
140 // media thread.
141 base::AutoLock auto_lock(lock_);
142 return playback_rate_; 301 return playback_rate_;
143 } 302 }
144 303
145 void PipelineImpl::SetPlaybackRate(double playback_rate) { 304 void PipelineImpl::SetPlaybackRate(double playback_rate) {
146 DCHECK(main_task_runner_->BelongsToCurrentThread()); 305 DVLOG(2) << __FUNCTION__ << "(" << playback_rate << ")";
306 DCHECK(thread_checker_.CalledOnValidThread());
147 307
148 if (playback_rate < 0.0) 308 if (playback_rate < 0.0)
149 return; 309 return;
150 310
151 base::AutoLock auto_lock(lock_);
152 playback_rate_ = playback_rate; 311 playback_rate_ = playback_rate;
153 if (running_) {
154 media_task_runner_->PostTask(
155 FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask,
156 weak_this_, playback_rate));
157 }
158 }
159
160 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
161 DCHECK(main_task_runner_->BelongsToCurrentThread());
162
163 media_task_runner_->PostTask(
164 FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, weak_this_,
165 media::BindToCurrentLoop(suspend_cb)));
166 }
167
168 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer,
169 base::TimeDelta timestamp,
170 const PipelineStatusCB& seek_cb) {
171 DCHECK(main_task_runner_->BelongsToCurrentThread());
172
173 media_task_runner_->PostTask( 312 media_task_runner_->PostTask(
174 FROM_HERE, 313 FROM_HERE,
175 base::Bind(&PipelineImpl::ResumeTask, weak_this_, base::Passed(&renderer), 314 base::Bind(&RendererWrapper::SetPlaybackRate,
176 timestamp, media::BindToCurrentLoop(seek_cb))); 315 base::Unretained(renderer_wrapper_.get()), playback_rate_));
177 } 316 }
178 317
179 float PipelineImpl::GetVolume() const { 318 float PipelineImpl::GetVolume() const {
180 // TODO(alokp): Add thread DCHECK after removing the internal usage on 319 DCHECK(thread_checker_.CalledOnValidThread());
181 // media thread.
182 base::AutoLock auto_lock(lock_);
183 return volume_; 320 return volume_;
184 } 321 }
185 322
186 void PipelineImpl::SetVolume(float volume) { 323 void PipelineImpl::SetVolume(float volume) {
187 DCHECK(main_task_runner_->BelongsToCurrentThread()); 324 DVLOG(2) << __FUNCTION__ << "(" << volume << ")";
325 DCHECK(thread_checker_.CalledOnValidThread());
188 326
189 if (volume < 0.0f || volume > 1.0f) 327 if (volume < 0.0f || volume > 1.0f)
190 return; 328 return;
191 329
192 base::AutoLock auto_lock(lock_);
193 volume_ = volume; 330 volume_ = volume;
194 if (running_) { 331 media_task_runner_->PostTask(
195 media_task_runner_->PostTask( 332 FROM_HERE, base::Bind(&RendererWrapper::SetVolume,
196 FROM_HERE, 333 base::Unretained(renderer_wrapper_.get()), volume));
197 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume)); 334 }
198 } 335
199 } 336 base::TimeDelta PipelineImpl::GetMediaTime() const {
200 337 DCHECK(thread_checker_.CalledOnValidThread());
201 TimeDelta PipelineImpl::GetMediaTime() const { 338
202 DCHECK(main_task_runner_->BelongsToCurrentThread()); 339 return suspend_time_ != kNoTimestamp() ? suspend_time_
203 340 : renderer_wrapper_->GetMediaTime();
204 base::AutoLock auto_lock(lock_); 341 }
205 if (suspend_timestamp_ != kNoTimestamp()) 342
206 return suspend_timestamp_; 343 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
207 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) 344 DCHECK(thread_checker_.CalledOnValidThread());
208 : TimeDelta();
209 }
210
211 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
212 DCHECK(main_task_runner_->BelongsToCurrentThread());
213
214 base::AutoLock auto_lock(lock_);
215 return buffered_time_ranges_; 345 return buffered_time_ranges_;
216 } 346 }
217 347
218 TimeDelta PipelineImpl::GetMediaDuration() const { 348 base::TimeDelta PipelineImpl::GetMediaDuration() const {
219 DCHECK(main_task_runner_->BelongsToCurrentThread()); 349 DCHECK(thread_checker_.CalledOnValidThread());
220
221 base::AutoLock auto_lock(lock_);
222 return duration_; 350 return duration_;
223 } 351 }
224 352
225 bool PipelineImpl::DidLoadingProgress() { 353 bool PipelineImpl::DidLoadingProgress() {
226 DCHECK(main_task_runner_->BelongsToCurrentThread()); 354 DCHECK(thread_checker_.CalledOnValidThread());
227
228 base::AutoLock auto_lock(lock_);
229 bool ret = did_loading_progress_; 355 bool ret = did_loading_progress_;
230 did_loading_progress_ = false; 356 did_loading_progress_ = false;
231 return ret; 357 return ret;
232 } 358 }
233 359
234 PipelineStatistics PipelineImpl::GetStatistics() const { 360 PipelineStatistics PipelineImpl::GetStatistics() const {
235 // TODO(alokp): Add thread DCHECK after removing the internal usage on 361 DCHECK(thread_checker_.CalledOnValidThread());
236 // media thread.
237 base::AutoLock auto_lock(lock_);
238 return statistics_; 362 return statistics_;
239 } 363 }
240 364
241 void PipelineImpl::SetCdm(CdmContext* cdm_context, 365 void PipelineImpl::SetCdm(CdmContext* cdm_context,
242 const CdmAttachedCB& cdm_attached_cb) { 366 const CdmAttachedCB& cdm_attached_cb) {
243 DCHECK(main_task_runner_->BelongsToCurrentThread()); 367 DVLOG(2) << __FUNCTION__;
244 368 DCHECK(thread_checker_.CalledOnValidThread());
245 media_task_runner_->PostTask( 369 DCHECK(cdm_context);
246 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context, 370 DCHECK(!cdm_attached_cb.is_null());
247 cdm_attached_cb)); 371
248 } 372 media_task_runner_->PostTask(
249 373 FROM_HERE,
250 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { 374 base::Bind(&RendererWrapper::SetCdm,
251 OnError(status); 375 base::Unretained(renderer_wrapper_.get()), cdm_context,
252 } 376 media::BindToCurrentLoop(cdm_attached_cb)));
253
254 bool PipelineImpl::HasWeakPtrsForTesting() const {
255 DCHECK(media_task_runner_->BelongsToCurrentThread());
256 return weak_factory_.HasWeakPtrs();
257 }
258
259 void PipelineImpl::SetState(State next_state) {
260 DCHECK(media_task_runner_->BelongsToCurrentThread());
261 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state);
262
263 state_ = next_state;
264 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
265 } 377 }
266 378
267 #define RETURN_STRING(state) \ 379 #define RETURN_STRING(state) \
268 case state: \ 380 case state: \
269 return #state; 381 return #state;
270 382
383 // static
271 const char* PipelineImpl::GetStateString(State state) { 384 const char* PipelineImpl::GetStateString(State state) {
272 switch (state) { 385 switch (state) {
273 RETURN_STRING(kCreated); 386 RETURN_STRING(kCreated);
274 RETURN_STRING(kInitDemuxer); 387 RETURN_STRING(kStarting);
275 RETURN_STRING(kInitRenderer);
276 RETURN_STRING(kSeeking); 388 RETURN_STRING(kSeeking);
277 RETURN_STRING(kPlaying); 389 RETURN_STRING(kPlaying);
278 RETURN_STRING(kStopping); 390 RETURN_STRING(kStopping);
279 RETURN_STRING(kStopped); 391 RETURN_STRING(kStopped);
280 RETURN_STRING(kSuspending); 392 RETURN_STRING(kSuspending);
281 RETURN_STRING(kSuspended); 393 RETURN_STRING(kSuspended);
282 RETURN_STRING(kResuming); 394 RETURN_STRING(kResuming);
283 } 395 }
284 NOTREACHED(); 396 NOTREACHED();
285 return "INVALID"; 397 return "INVALID";
286 } 398 }
287 399
288 #undef RETURN_STRING 400 #undef RETURN_STRING
289 401
290 PipelineImpl::State PipelineImpl::GetNextState() const { 402 void PipelineImpl::OnError(PipelineStatus error) {
291 DCHECK(media_task_runner_->BelongsToCurrentThread()); 403 DVLOG(2) << __FUNCTION__;
292 DCHECK(stop_cb_.is_null()) << "State transitions don't happen when stopping"; 404 DCHECK(thread_checker_.CalledOnValidThread());
293 DCHECK_EQ(status_, PIPELINE_OK) 405 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
294 << "State transitions don't happen when there's an error: " << status_; 406
295 407 if (!IsRunning())
296 switch (state_) { 408 return;
297 case kCreated: 409
298 return kInitDemuxer; 410 // If the error happens during starting/seeking/suspending/resuming,
299 411 // report the error via the completion callback for those tasks.
300 case kInitDemuxer: 412 // Else report error via the client interface.
301 return kInitRenderer; 413 if (!seek_cb_.is_null()) {
302 414 base::ResetAndReturn(&seek_cb_).Run(error);
303 case kInitRenderer: 415 } else if (!suspend_cb_.is_null()) {
304 case kSeeking: 416 base::ResetAndReturn(&suspend_cb_).Run(error);
305 return kPlaying; 417 } else {
306 418 DCHECK(client_);
307 case kSuspending: 419 client_->OnError(error);
308 return kSuspended; 420 }
309 421
310 case kSuspended: 422 // Any kind of error stops the pipeline.
311 return kResuming; 423 Stop();
312 424 }
313 case kResuming: 425
314 return kPlaying; 426 void PipelineImpl::OnEnded() {
315 427 DVLOG(2) << __FUNCTION__;
316 case kPlaying: 428 DCHECK(thread_checker_.CalledOnValidThread());
317 case kStopping: 429
318 case kStopped: 430 if (IsRunning()) {
319 break; 431 DCHECK(client_);
320 } 432 client_->OnEnded();
321 NOTREACHED() << "State has no transition: " << state_; 433 }
322 return state_; 434 }
323 } 435
324 436 void PipelineImpl::OnMetadata(PipelineMetadata metadata) {
325 void PipelineImpl::OnDemuxerError(PipelineStatus error) { 437 DVLOG(2) << __FUNCTION__;
438 DCHECK(thread_checker_.CalledOnValidThread());
439
440 if (IsRunning()) {
441 DCHECK(client_);
442 client_->OnMetadata(metadata);
443 }
444 }
445
446 void PipelineImpl::OnBufferingStateChange(BufferingState state) {
447 DVLOG(2) << __FUNCTION__ << "(" << state << ")";
448 DCHECK(thread_checker_.CalledOnValidThread());
449
450 if (IsRunning()) {
451 DCHECK(client_);
452 client_->OnBufferingStateChange(state);
453 }
454 }
455
456 void PipelineImpl::OnDurationChange(base::TimeDelta duration) {
457 DVLOG(2) << __FUNCTION__;
458 DCHECK(thread_checker_.CalledOnValidThread());
459
460 duration_ = duration;
461
462 if (IsRunning()) {
463 DCHECK(client_);
464 client_->OnDurationChange();
465 }
466 }
467
468 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config,
469 const AddTextTrackDoneCB& done_cb) {
470 DVLOG(2) << __FUNCTION__;
471 DCHECK(thread_checker_.CalledOnValidThread());
472
473 if (IsRunning()) {
474 DCHECK(client_);
475 client_->OnAddTextTrack(config, done_cb);
476 }
477 }
478
479 void PipelineImpl::OnWaitingForDecryptionKey() {
480 DVLOG(2) << __FUNCTION__;
481 DCHECK(thread_checker_.CalledOnValidThread());
482
483 if (IsRunning()) {
484 DCHECK(client_);
485 client_->OnWaitingForDecryptionKey();
486 }
487 }
488
489 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
490 DVLOG(2) << __FUNCTION__;
491 DCHECK(thread_checker_.CalledOnValidThread());
492
493 if (IsRunning()) {
494 DCHECK(client_);
495 client_->OnVideoNaturalSizeChange(size);
496 }
497 }
498
499 void PipelineImpl::OnVideoOpacityChange(bool opaque) {
500 DVLOG(2) << __FUNCTION__;
501 DCHECK(thread_checker_.CalledOnValidThread());
502
503 if (IsRunning()) {
504 DCHECK(client_);
505 client_->OnVideoOpacityChange(opaque);
506 }
507 }
508
509 void PipelineImpl::OnBufferedTimeRangesChange(
510 const Ranges<base::TimeDelta>& ranges) {
511 DVLOG(3) << __FUNCTION__;
512 DCHECK(thread_checker_.CalledOnValidThread());
513
514 buffered_time_ranges_ = ranges;
515 did_loading_progress_ = true;
516 }
517
518 void PipelineImpl::OnStatisticsUpdate(const PipelineStatistics& stats) {
519 DVLOG(3) << __FUNCTION__;
520 DCHECK(thread_checker_.CalledOnValidThread());
521
522 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded;
523 statistics_.video_bytes_decoded += stats.video_bytes_decoded;
524 statistics_.video_frames_decoded += stats.video_frames_decoded;
525 statistics_.video_frames_dropped += stats.video_frames_dropped;
526 statistics_.audio_memory_usage += stats.audio_memory_usage;
527 statistics_.video_memory_usage += stats.video_memory_usage;
528 }
529
530 void PipelineImpl::OnSeekDone(base::TimeDelta start_time) {
531 DVLOG(3) << __FUNCTION__ << "(" << start_time.InMicroseconds() << ")";
532 DCHECK(thread_checker_.CalledOnValidThread());
533
534 // Reset the suspend_time now that the pipeline is playing.
535 // Media time will now be reported by renderer.
536 suspend_time_ = kNoTimestamp();
537
538 if (IsRunning()) {
539 DCHECK(!seek_cb_.is_null());
540 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
541 }
542 }
543
544 void PipelineImpl::OnSuspendDone(base::TimeDelta suspend_time) {
545 DVLOG(3) << __FUNCTION__ << "(" << suspend_time.InMicroseconds() << ")";
546 DCHECK(thread_checker_.CalledOnValidThread());
547
548 // Cache the time at which pipeline was suspended.
549 // It will be used to report media time while the pipeline is suspended.
550 suspend_time_ = suspend_time;
551
552 // Reset audio-video memory usage since renderer has been destroyed.
553 statistics_.audio_memory_usage = 0;
554 statistics_.video_memory_usage = 0;
555
556 if (IsRunning()) {
557 DCHECK(!suspend_cb_.is_null());
558 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK);
559 }
560 }
561
562 PipelineImpl::RendererWrapper::RendererWrapper(
563 base::WeakPtr<PipelineImpl> weak_pipeline,
564 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
565 scoped_refptr<MediaLog> media_log)
566 : weak_pipeline_(weak_pipeline),
567 media_task_runner_(std::move(media_task_runner)),
568 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
569 media_log_(std::move(media_log)),
570 demuxer_(nullptr),
571 playback_rate_(kDefaultPlaybackRate),
572 volume_(kDefaultVolume),
573 cdm_context_(nullptr),
574 state_(kCreated),
575 status_(PIPELINE_OK),
576 renderer_ended_(false),
577 text_renderer_ended_(false),
578 weak_factory_(this) {
579 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
580 }
581
582 PipelineImpl::RendererWrapper::~RendererWrapper() {
583 DCHECK(media_task_runner_->BelongsToCurrentThread());
584 DCHECK(state_ == kCreated || state_ == kStopped);
585 }
586
587 // Note that the usage of base::Unretained() with the renderers and demuxer
588 // is safe as they are owned by |pending_callbacks_| and share the same
589 // lifetime. That said, deleting the renderers while keeping
590 // |pending_callbacks_| running on the media thread would result in crashes.
591
592 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() {
593 // This is the only member function that gets called on the main thread.
594 // TODO(alokp): Enforce that Renderer is only called on a single thread,
595 // even for accessing media time http://crbug.com/370634.
596 DCHECK(main_task_runner_->BelongsToCurrentThread());
597
598 base::AutoLock auto_lock(renderer_lock_);
599 return renderer_ ? renderer_->GetMediaTime() : base::TimeDelta();
600 }
601
602 void PipelineImpl::RendererWrapper::SetState(State next_state) {
603 DCHECK(media_task_runner_->BelongsToCurrentThread());
604 DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> "
605 << PipelineImpl::GetStateString(next_state);
606
607 state_ = next_state;
608 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
609 }
610
611 void PipelineImpl::RendererWrapper::OnDemuxerError(PipelineStatus error) {
612 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
613 // implementations call DemuxerHost on the media thread.
614 media_task_runner_->PostTask(FROM_HERE,
615 base::Bind(&RendererWrapper::OnPipelineError,
616 weak_factory_.GetWeakPtr(), error));
617 }
618
619 void PipelineImpl::RendererWrapper::AddTextStream(
620 DemuxerStream* text_stream,
621 const TextTrackConfig& config) {
326 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 622 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
327 // implementations call DemuxerHost on the media thread. 623 // implementations call DemuxerHost on the media thread.
328 media_task_runner_->PostTask( 624 media_task_runner_->PostTask(
329 FROM_HERE, 625 FROM_HERE, base::Bind(&RendererWrapper::AddTextStreamTask,
330 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error)); 626 weak_factory_.GetWeakPtr(), text_stream, config));
331 } 627 }
332 628
333 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, 629 void PipelineImpl::RendererWrapper::RemoveTextStream(
334 const TextTrackConfig& config) { 630 DemuxerStream* text_stream) {
335 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 631 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
336 // implementations call DemuxerHost on the media thread. 632 // implementations call DemuxerHost on the media thread.
337 media_task_runner_->PostTask( 633 media_task_runner_->PostTask(
338 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_, 634 FROM_HERE, base::Bind(&RendererWrapper::RemoveTextStreamTask,
339 text_stream, config)); 635 weak_factory_.GetWeakPtr(), text_stream));
340 } 636 }
341 637
342 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { 638 void PipelineImpl::RendererWrapper::OnError(PipelineStatus error) {
343 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 639 DCHECK(media_task_runner_->BelongsToCurrentThread());
344 // implementations call DemuxerHost on the media thread. 640
345 media_task_runner_->PostTask( 641 media_task_runner_->PostTask(FROM_HERE,
346 FROM_HERE, 642 base::Bind(&RendererWrapper::OnPipelineError,
347 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream)); 643 weak_factory_.GetWeakPtr(), error));
348 } 644 }
349 645
350 void PipelineImpl::OnError(PipelineStatus error) { 646 void PipelineImpl::RendererWrapper::OnEnded() {
351 DCHECK(media_task_runner_->BelongsToCurrentThread());
352 DCHECK(IsRunning());
353 DCHECK_NE(PIPELINE_OK, error);
354 VLOG(1) << "Media pipeline error: " << error;
355
356 media_task_runner_->PostTask(
357 FROM_HERE,
358 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error));
359 }
360
361 void PipelineImpl::OnEnded() {
362 DCHECK(media_task_runner_->BelongsToCurrentThread()); 647 DCHECK(media_task_runner_->BelongsToCurrentThread());
363 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); 648 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED));
364 649
365 if (state_ != kPlaying) 650 if (state_ != kPlaying)
366 return; 651 return;
367 652
368 DCHECK(!renderer_ended_); 653 DCHECK(!renderer_ended_);
369 renderer_ended_ = true; 654 renderer_ended_ = true;
370
371 RunEndedCallbackIfNeeded(); 655 RunEndedCallbackIfNeeded();
372 } 656 }
373 657
374 void PipelineImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { 658 void PipelineImpl::RendererWrapper::OnStatisticsUpdate(
375 DCHECK(media_task_runner_->BelongsToCurrentThread()); 659 const PipelineStatistics& stats) {
376 660 DCHECK(media_task_runner_->BelongsToCurrentThread());
377 base::AutoLock auto_lock(lock_); 661
378 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; 662 main_task_runner_->PostTask(
379 statistics_.video_bytes_decoded += stats.video_bytes_decoded; 663 FROM_HERE,
380 statistics_.video_frames_decoded += stats.video_frames_decoded; 664 base::Bind(&PipelineImpl::OnStatisticsUpdate, weak_pipeline_, stats));
381 statistics_.video_frames_dropped += stats.video_frames_dropped; 665 }
382 statistics_.audio_memory_usage += stats.audio_memory_usage; 666
383 statistics_.video_memory_usage += stats.video_memory_usage; 667 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
384 } 668 BufferingState state) {
385 669 DCHECK(media_task_runner_->BelongsToCurrentThread());
386 void PipelineImpl::OnBufferingStateChange(BufferingState state) { 670 DVLOG(2) << __FUNCTION__ << "(" << state << ") ";
387 DVLOG(1) << __FUNCTION__ << "(" << state << ") "; 671
388 DCHECK(media_task_runner_->BelongsToCurrentThread()); 672 main_task_runner_->PostTask(
389 673 FROM_HERE,
390 main_task_runner_->PostTask( 674 base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state));
391 FROM_HERE, base::Bind(&Pipeline::Client::OnBufferingStateChange, 675 }
392 weak_client_, state)); 676
393 } 677 void PipelineImpl::RendererWrapper::OnWaitingForDecryptionKey() {
394 678 DCHECK(media_task_runner_->BelongsToCurrentThread());
395 void PipelineImpl::OnWaitingForDecryptionKey() { 679
396 DCHECK(media_task_runner_->BelongsToCurrentThread()); 680 main_task_runner_->PostTask(
397 681 FROM_HERE,
398 main_task_runner_->PostTask( 682 base::Bind(&PipelineImpl::OnWaitingForDecryptionKey, weak_pipeline_));
399 FROM_HERE, 683 }
400 base::Bind(&Pipeline::Client::OnWaitingForDecryptionKey, weak_client_)); 684
401 } 685 void PipelineImpl::RendererWrapper::OnVideoNaturalSizeChange(
402 686 const gfx::Size& size) {
403 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { 687 DCHECK(media_task_runner_->BelongsToCurrentThread());
404 DCHECK(media_task_runner_->BelongsToCurrentThread()); 688
405 689 main_task_runner_->PostTask(
406 main_task_runner_->PostTask( 690 FROM_HERE, base::Bind(&PipelineImpl::OnVideoNaturalSizeChange,
407 FROM_HERE, base::Bind(&Pipeline::Client::OnVideoNaturalSizeChange, 691 weak_pipeline_, size));
408 weak_client_, size)); 692 }
409 } 693
410 694 void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) {
411 void PipelineImpl::OnVideoOpacityChange(bool opaque) { 695 DCHECK(media_task_runner_->BelongsToCurrentThread());
412 DCHECK(media_task_runner_->BelongsToCurrentThread()); 696
413 697 main_task_runner_->PostTask(
414 main_task_runner_->PostTask( 698 FROM_HERE,
415 FROM_HERE, base::Bind(&Pipeline::Client::OnVideoOpacityChange, 699 base::Bind(&PipelineImpl::OnVideoOpacityChange, weak_pipeline_, opaque));
416 weak_client_, opaque)); 700 }
417 } 701
418 702 void PipelineImpl::RendererWrapper::SetDuration(base::TimeDelta duration) {
419 void PipelineImpl::SetDuration(TimeDelta duration) {
420 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 703 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
421 // implementations call DemuxerHost on the media thread. 704 // implementations call DemuxerHost on the media thread.
422 DCHECK(IsRunning());
423 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, 705 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET,
424 "duration", duration)); 706 "duration", duration));
425 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); 707 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
426 708
427 base::AutoLock auto_lock(lock_); 709 main_task_runner_->PostTask(
428 duration_ = duration; 710 FROM_HERE,
429 main_task_runner_->PostTask( 711 base::Bind(&PipelineImpl::OnDurationChange, weak_pipeline_, duration));
430 FROM_HERE, base::Bind(&Pipeline::Client::OnDurationChange, weak_client_)); 712 }
431 } 713
432 714 void PipelineImpl::RendererWrapper::OnSeekDone(base::TimeDelta start_time,
433 void PipelineImpl::StateTransitionTask(PipelineStatus status) { 715 PipelineStatus status) {
434 DCHECK(media_task_runner_->BelongsToCurrentThread()); 716 DCHECK(media_task_runner_->BelongsToCurrentThread());
435 717
436 // No-op any state transitions if we're stopping. 718 DCHECK(pending_callbacks_);
437 if (state_ == kStopping || state_ == kStopped) 719 pending_callbacks_.reset();
720
721 if (status != PIPELINE_OK) {
722 OnPipelineError(status);
438 return; 723 return;
439 724 }
440 // Report error from the previous operation. 725
441 if (status != PIPELINE_OK) { 726 start_time = std::max(start_time, demuxer_->GetStartTime());
442 ErrorChangedTask(status); 727 renderer_->StartPlayingFrom(start_time);
443 return; 728
444 } 729 if (text_renderer_)
445 730 text_renderer_->StartPlaying();
446 // Guard against accidentally clearing |pending_callbacks_| for states that 731
447 // use it as well as states that should not be using it. 732 renderer_->SetPlaybackRate(playback_rate_);
448 DCHECK_EQ(pending_callbacks_.get() != NULL, 733 renderer_->SetVolume(volume_);
449 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); 734
450 735 SetState(kPlaying);
736 main_task_runner_->PostTask(
737 FROM_HERE,
738 base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_, start_time));
739 }
740
741 void PipelineImpl::RendererWrapper::OnSuspendDone(base::TimeDelta suspend_time,
742 PipelineStatus status) {
743 DCHECK(media_task_runner_->BelongsToCurrentThread());
744
745 // In case we are suspending or suspended, the error may be recoverable,
746 // so don't propagate it now, instead let the subsequent seek during resume
747 // propagate it if it's unrecoverable.
748 LOG_IF(WARNING, status != PIPELINE_OK)
749 << "Encountered pipeline error while suspending: " << status;
750
751 DCHECK(pending_callbacks_);
451 pending_callbacks_.reset(); 752 pending_callbacks_.reset();
452 753
453 PipelineStatusCB done_cb =
454 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_);
455
456 // Switch states, performing any entrance actions for the new state as well.
457 SetState(GetNextState());
458 switch (state_) {
459 case kInitDemuxer:
460 return InitializeDemuxer(done_cb);
461
462 case kInitRenderer:
463 // When the state_ transfers to kInitRenderer, it means the demuxer has
464 // finished parsing the init info. It should call ReportMetadata in case
465 // meeting 'decode' error when passing media segment but WebMediaPlayer's
466 // ready_state_ is still ReadyStateHaveNothing. In that case, it will
467 // treat it as NetworkStateFormatError not NetworkStateDecodeError.
468 ReportMetadata();
469 start_timestamp_ = demuxer_->GetStartTime();
470
471 return InitializeRenderer(done_cb);
472
473 case kPlaying:
474 DCHECK(start_timestamp_ >= base::TimeDelta());
475 renderer_->StartPlayingFrom(start_timestamp_);
476 {
477 base::AutoLock auto_lock(lock_);
478 suspend_timestamp_ = kNoTimestamp();
479 }
480
481 if (text_renderer_)
482 text_renderer_->StartPlaying();
483
484 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
485
486 PlaybackRateChangedTask(GetPlaybackRate());
487 VolumeChangedTask(GetVolume());
488 return;
489
490 case kSuspended:
491 renderer_.reset();
492 {
493 base::AutoLock auto_lock(lock_);
494 statistics_.audio_memory_usage = 0;
495 statistics_.video_memory_usage = 0;
496 }
497 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK);
498 return;
499
500 case kStopping:
501 case kStopped:
502 case kCreated:
503 case kSeeking:
504 case kSuspending:
505 case kResuming:
506 NOTREACHED() << "State has no transition: " << state_;
507 return;
508 }
509 }
510
511 // Note that the usage of base::Unretained() with the renderers is considered
512 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
513 //
514 // That being said, deleting the renderers while keeping |pending_callbacks_|
515 // running on the media thread would result in crashes.
516 void PipelineImpl::DoSeek(TimeDelta seek_timestamp,
517 const PipelineStatusCB& done_cb) {
518 DCHECK(media_task_runner_->BelongsToCurrentThread());
519 DCHECK(!pending_callbacks_.get());
520 DCHECK_EQ(state_, kSeeking);
521 SerialRunner::Queue bound_fns;
522
523 // Pause.
524 if (text_renderer_) {
525 bound_fns.Push(base::Bind(&TextRenderer::Pause,
526 base::Unretained(text_renderer_.get())));
527 }
528
529 // Flush.
530 DCHECK(renderer_);
531 bound_fns.Push(
532 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
533
534 if (text_renderer_) {
535 bound_fns.Push(base::Bind(&TextRenderer::Flush,
536 base::Unretained(text_renderer_.get())));
537 }
538
539 // Seek demuxer.
540 bound_fns.Push(
541 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
542
543 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
544 }
545
546 void PipelineImpl::DoStop() {
547 DVLOG(2) << __FUNCTION__;
548 DCHECK(media_task_runner_->BelongsToCurrentThread());
549 DCHECK_EQ(state_, kStopping);
550 DCHECK(!pending_callbacks_.get());
551
552 // TODO(scherkus): Enforce that Renderer is only called on a single thread,
553 // even for accessing media time http://crbug.com/370634
554 std::unique_ptr<Renderer> renderer; 754 std::unique_ptr<Renderer> renderer;
555 { 755 {
556 base::AutoLock auto_lock(lock_); 756 base::AutoLock auto_lock(renderer_lock_);
557 renderer.swap(renderer_); 757 renderer.swap(renderer_);
558 } 758 }
559 renderer.reset(); 759 renderer.reset();
560 text_renderer_.reset(); 760
561 761 SetState(kSuspended);
562 if (demuxer_) { 762 main_task_runner_->PostTask(
563 demuxer_->Stop(); 763 FROM_HERE,
564 demuxer_ = NULL; 764 base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_, suspend_time));
565 } 765 }
566 766
567 { 767 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
568 base::AutoLock auto_lock(lock_);
569 running_ = false;
570 }
571 SetState(kStopped);
572
573 // If we stop during initialization/seeking/suspending we don't want to leave
574 // outstanding callbacks around. The callbacks also do not get run if the
575 // pipeline is stopped before it had a chance to complete outstanding tasks.
576 seek_cb_.Reset();
577 suspend_cb_.Reset();
578
579 if (!stop_cb_.is_null()) {
580 // Invalid all weak pointers so it's safe to destroy |this| on the render
581 // main thread.
582 weak_factory_.InvalidateWeakPtrs();
583
584 // Post the stop callback to enqueue it after the tasks that may have been
585 // Demuxer and Renderer during stopping.
586 media_task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
587 }
588 }
589
590 void PipelineImpl::OnBufferedTimeRangesChanged(
591 const Ranges<base::TimeDelta>& ranges) { 768 const Ranges<base::TimeDelta>& ranges) {
592 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer 769 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
593 // implementations call DemuxerHost on the media thread. 770 // implementations call DemuxerHost on the media thread.
594 base::AutoLock auto_lock(lock_); 771 main_task_runner_->PostTask(
595 buffered_time_ranges_ = ranges; 772 FROM_HERE, base::Bind(&PipelineImpl::OnBufferedTimeRangesChange,
596 did_loading_progress_ = true; 773 weak_pipeline_, ranges));
597 } 774 }
598 775
599 void PipelineImpl::StartTask() { 776 void PipelineImpl::RendererWrapper::Start(
600 DCHECK(media_task_runner_->BelongsToCurrentThread()); 777 Demuxer* demuxer,
601 778 std::unique_ptr<Renderer> renderer,
602 CHECK_EQ(kCreated, state_) 779 std::unique_ptr<TextRenderer> text_renderer) {
603 << "Media pipeline cannot be started more than once"; 780 DCHECK(media_task_runner_->BelongsToCurrentThread());
604 781
605 text_renderer_ = CreateTextRenderer(); 782 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: "
783 << state_;
784 SetState(kStarting);
785
786 DCHECK(!demuxer_);
787 DCHECK(!renderer_);
788 DCHECK(!text_renderer_);
789 DCHECK(!renderer_ended_);
790 DCHECK(!text_renderer_ended_);
791 demuxer_ = demuxer;
792 {
793 base::AutoLock auto_lock(renderer_lock_);
794 renderer_ = std::move(renderer);
795 }
796 text_renderer_ = std::move(text_renderer);
797
798 // Initialize text renderer.
606 if (text_renderer_) { 799 if (text_renderer_) {
607 text_renderer_->Initialize( 800 text_renderer_->Initialize(base::Bind(&RendererWrapper::OnTextRendererEnded,
608 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); 801 weak_factory_.GetWeakPtr()));
609 } 802 }
610 803
611 StateTransitionTask(PIPELINE_OK); 804 // Queue asynchronous actions required to seek.
alokp 2016/06/08 19:59:48 Instead of using StateTransitionTask, we use Seria
612 } 805 DCHECK(!pending_callbacks_);
613 806 SerialRunner::Queue fns;
614 void PipelineImpl::StopTask(const base::Closure& stop_cb) { 807
615 DCHECK(media_task_runner_->BelongsToCurrentThread()); 808 // Initialize demuxer.
616 DCHECK(stop_cb_.is_null()); 809 fns.Push(base::Bind(&RendererWrapper::InitializeDemuxer,
617 810 weak_factory_.GetWeakPtr()));
618 if (state_ == kStopped) { 811
619 // Invalid all weak pointers so it's safe to destroy |this| on the render 812 // Once the demuxer is initialized successfully, media metadata must be
620 // main thread. 813 // available - report the metadata to client.
621 weak_factory_.InvalidateWeakPtrs(); 814 fns.Push(
622 815 base::Bind(&RendererWrapper::ReportMetadata, weak_factory_.GetWeakPtr()));
623 // NOTE: pipeline may be deleted at this point in time as a result of 816
624 // executing |stop_cb|. 817 // Initialize renderer.
625 stop_cb.Run(); 818 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer,
626 819 weak_factory_.GetWeakPtr()));
627 return; 820
628 } 821 // Run tasks.
629 822 pending_callbacks_ = SerialRunner::Run(
630 stop_cb_ = stop_cb; 823 fns, base::Bind(&RendererWrapper::OnSeekDone, weak_factory_.GetWeakPtr(),
631 824 base::TimeDelta()));
632 // We may already be stopping due to a runtime error. 825 }
633 if (state_ == kStopping) 826
634 return; 827 void PipelineImpl::RendererWrapper::Stop(const base::Closure& stop_cb) {
635 828 DCHECK(media_task_runner_->BelongsToCurrentThread());
636 // Do not report statistics if the pipeline is not fully initialized. 829 DCHECK(state_ != kStopping && state_ != kStopped);
637 if (state_ == kSeeking || state_ == kPlaying || state_ == kSuspending ||
638 state_ == kSuspended || state_ == kResuming) {
639 PipelineStatistics stats = GetStatistics();
640 if (stats.video_frames_decoded > 0) {
641 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount",
642 stats.video_frames_dropped);
643 }
644 }
645 830
646 SetState(kStopping); 831 SetState(kStopping);
832
833 // If we stop during starting/seeking/suspending/resuming we don't want to
834 // leave outstanding callbacks around. The callbacks also do not get run if
835 // the pipeline is stopped before it had a chance to complete outstanding
836 // tasks.
647 pending_callbacks_.reset(); 837 pending_callbacks_.reset();
648 DoStop(); 838
649 } 839 std::unique_ptr<Renderer> renderer;
650 840 {
651 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { 841 base::AutoLock auto_lock(renderer_lock_);
842 renderer.swap(renderer_);
843 }
844 renderer.reset();
845 text_renderer_.reset();
846
847 if (demuxer_) {
848 demuxer_->Stop();
849 demuxer_ = nullptr;
850 }
851
852 SetState(kStopped);
853
854 // Post the stop callback to enqueue it after the tasks that may have been
855 // Demuxer and Renderer during stopping.
856 media_task_runner_->PostTask(FROM_HERE, stop_cb);
857 }
858
859 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) {
652 DCHECK(media_task_runner_->BelongsToCurrentThread()); 860 DCHECK(media_task_runner_->BelongsToCurrentThread());
653 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 861 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
654 862
655 // Preserve existing abnormal status. 863 // Preserve existing abnormal status.
656 if (status_ != PIPELINE_OK) 864 if (status_ != PIPELINE_OK)
657 return; 865 return;
658 866
659 // Don't report pipeline error events to the media log here. The embedder will 867 // Don't report pipeline error events to the media log here. The embedder
660 // log this when Client::OnError is called. If the pipeline is already stopped 868 // will log this when Client::OnError is called. If the pipeline is already
661 // or stopping we also don't want to log any event. In case we are suspending 869 // stopped or stopping we also don't want to log any event. In case we are
662 // or suspended, the error may be recoverable, so don't propagate it now, 870 // suspending or suspended, the error may be recoverable, so don't propagate
663 // instead let the subsequent seek during resume propagate it if it's 871 // it now, instead let the subsequent seek during resume propagate it if
664 // unrecoverable. 872 // it's unrecoverable.
665 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || 873 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending ||
666 state_ == kSuspended) { 874 state_ == kSuspended) {
667 return; 875 return;
668 } 876 }
669 877
670 // Once we enter |kStopping| state, nothing is reported back to the client.
671 // If we encounter an error during initialization/seeking/suspending,
672 // report the error using the completion callbacks for those tasks.
673 status_ = error; 878 status_ = error;
674 bool error_reported = false; 879 main_task_runner_->PostTask(
675 if (!seek_cb_.is_null()) { 880 FROM_HERE, base::Bind(&PipelineImpl::OnError, weak_pipeline_, error));
676 base::ResetAndReturn(&seek_cb_).Run(status_);
677 error_reported = true;
678 }
679 if (!suspend_cb_.is_null()) {
680 base::ResetAndReturn(&suspend_cb_).Run(status_);
681 error_reported = true;
682 }
683 if (!error_reported) {
684 DCHECK_NE(status_, PIPELINE_OK);
685 main_task_runner_->PostTask(
686 FROM_HERE,
687 base::Bind(&Pipeline::Client::OnError, weak_client_, status_));
688 }
689
690 SetState(kStopping);
691 pending_callbacks_.reset();
692 DoStop();
693 } 881 }
694 882
695 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { 883 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
696 DCHECK(media_task_runner_->BelongsToCurrentThread()); 884 DCHECK(media_task_runner_->BelongsToCurrentThread());
697 885
698 // Playback rate changes are only carried out while playing. 886 playback_rate_ = playback_rate;
699 if (state_ != kPlaying) 887 if (state_ == kPlaying)
700 return; 888 renderer_->SetPlaybackRate(playback_rate_);
701
702 renderer_->SetPlaybackRate(playback_rate);
703 } 889 }
704 890
705 void PipelineImpl::VolumeChangedTask(float volume) { 891 void PipelineImpl::RendererWrapper::SetVolume(float volume) {
706 DCHECK(media_task_runner_->BelongsToCurrentThread()); 892 DCHECK(media_task_runner_->BelongsToCurrentThread());
707 893
708 // Volume changes are only carried out while playing. 894 volume_ = volume;
709 if (state_ != kPlaying) 895 if (state_ == kPlaying)
710 return; 896 renderer_->SetVolume(volume_);
711
712 renderer_->SetVolume(volume);
713 } 897 }
714 898
715 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { 899 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
716 DCHECK(media_task_runner_->BelongsToCurrentThread()); 900 DCHECK(media_task_runner_->BelongsToCurrentThread());
717 DCHECK(stop_cb_.is_null());
718 901
719 // Suppress seeking if we're not fully started. 902 // Suppress seeking if we're not fully started.
720 if (state_ != kPlaying) { 903 if (state_ != kPlaying) {
721 DCHECK(state_ == kStopping || state_ == kStopped) 904 DCHECK(state_ == kStopping || state_ == kStopped)
722 << "Receive seek in unexpected state: " << state_; 905 << "Receive seek in unexpected state: " << state_;
723 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); 906 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
724 return; 907 return;
725 } 908 }
726 909 DCHECK(renderer_);
727 DCHECK(seek_cb_.is_null()); 910 DCHECK(!pending_callbacks_.get());
728
729 const base::TimeDelta seek_timestamp =
730 std::max(time, demuxer_->GetStartTime());
731 911
732 SetState(kSeeking); 912 SetState(kSeeking);
733 seek_cb_ = seek_cb;
734 renderer_ended_ = false; 913 renderer_ended_ = false;
735 text_renderer_ended_ = false; 914 text_renderer_ended_ = false;
736 start_timestamp_ = seek_timestamp;
737 915
738 DoSeek(seek_timestamp, 916 // Queue asynchronous actions required to seek.
739 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); 917 SerialRunner::Queue bound_fns;
918
919 // Pause.
920 if (text_renderer_) {
921 bound_fns.Push(base::Bind(&TextRenderer::Pause,
922 base::Unretained(text_renderer_.get())));
923 }
924
925 // Flush.
926 bound_fns.Push(
927 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
928 if (text_renderer_) {
929 bound_fns.Push(base::Bind(&TextRenderer::Flush,
930 base::Unretained(text_renderer_.get())));
931 }
932
933 // Seek.
934 bound_fns.Push(base::Bind(&Demuxer::Seek, base::Unretained(demuxer_),
935 std::max(time, demuxer_->GetStartTime())));
936
937 pending_callbacks_ = SerialRunner::Run(
938 bound_fns, base::Bind(&RendererWrapper::OnSeekDone,
939 weak_factory_.GetWeakPtr(), time));
740 } 940 }
741 941
742 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { 942 void PipelineImpl::RendererWrapper::Suspend() {
743 DCHECK(media_task_runner_->BelongsToCurrentThread()); 943 DCHECK(media_task_runner_->BelongsToCurrentThread());
744 944
745 // Suppress suspending if we're not playing. 945 // Suppress suspending if we're not playing.
746 if (state_ != kPlaying) { 946 if (state_ != kPlaying) {
747 DCHECK(state_ == kStopping || state_ == kStopped) 947 DCHECK(state_ == kStopping || state_ == kStopped)
748 << "Receive suspend in unexpected state: " << state_; 948 << "Received suspend in unexpected state: " << state_;
749 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); 949 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
750 return; 950 return;
751 } 951 }
752 DCHECK(renderer_); 952 DCHECK(renderer_);
753 DCHECK(!pending_callbacks_.get()); 953 DCHECK(!pending_callbacks_.get());
754 954
755 SetState(kSuspending); 955 SetState(kSuspending);
756 suspend_cb_ = suspend_cb;
757 956
758 // Freeze playback and record the media time before flushing. (Flushing clears 957 // Freeze playback and record the media time before flushing.
759 // the value.) 958 // (Flushing clears the value.)
760 renderer_->SetPlaybackRate(0.0); 959 renderer_->SetPlaybackRate(0.0);
761 { 960 base::TimeDelta suspend_time = renderer_->GetMediaTime();
762 base::AutoLock auto_lock(lock_); 961 DCHECK(suspend_time != kNoTimestamp());
763 suspend_timestamp_ = renderer_->GetMediaTime();
764 DCHECK(suspend_timestamp_ != kNoTimestamp());
765 }
766 962
767 // Queue the asynchronous actions required to stop playback. (Matches setup in 963 // Queue asynchronous actions required to suspend playback.
768 // DoSeek().)
769 // TODO(sandersd): Share implementation with DoSeek().
770 SerialRunner::Queue fns; 964 SerialRunner::Queue fns;
771 965
966 // Pause.
772 if (text_renderer_) { 967 if (text_renderer_) {
773 fns.Push(base::Bind(&TextRenderer::Pause, 968 fns.Push(base::Bind(&TextRenderer::Pause,
774 base::Unretained(text_renderer_.get()))); 969 base::Unretained(text_renderer_.get())));
775 } 970 }
776 971
972 // Flush.
777 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); 973 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
778
779 if (text_renderer_) { 974 if (text_renderer_) {
780 fns.Push(base::Bind(&TextRenderer::Flush, 975 fns.Push(base::Bind(&TextRenderer::Flush,
781 base::Unretained(text_renderer_.get()))); 976 base::Unretained(text_renderer_.get())));
782 } 977 }
783 978
784 pending_callbacks_ = SerialRunner::Run( 979 pending_callbacks_ = SerialRunner::Run(
785 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); 980 fns, base::Bind(&RendererWrapper::OnSuspendDone,
981 weak_factory_.GetWeakPtr(), suspend_time));
786 } 982 }
787 983
788 void PipelineImpl::ResumeTask(std::unique_ptr<Renderer> renderer, 984 void PipelineImpl::RendererWrapper::Resume(base::TimeDelta time,
789 base::TimeDelta timestamp, 985 std::unique_ptr<Renderer> renderer) {
790 const PipelineStatusCB& seek_cb) {
791 DCHECK(media_task_runner_->BelongsToCurrentThread()); 986 DCHECK(media_task_runner_->BelongsToCurrentThread());
792 987
793 // Suppress resuming if we're not suspended. 988 // Suppress resuming if we're not suspended.
794 if (state_ != kSuspended) { 989 if (state_ != kSuspended) {
795 DCHECK(state_ == kStopping || state_ == kStopped) 990 DCHECK(state_ == kStopping || state_ == kStopped)
796 << "Receive resume in unexpected state: " << state_; 991 << "Received resume in unexpected state: " << state_;
797 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); 992 OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
798 return; 993 return;
799 } 994 }
800 DCHECK(!renderer_); 995 DCHECK(!renderer_);
801 DCHECK(!pending_callbacks_.get()); 996 DCHECK(!pending_callbacks_.get());
802 997
803 SetState(kResuming); 998 SetState(kResuming);
804 renderer_ = std::move(renderer); 999 {
805 1000 base::AutoLock auto_lock(renderer_lock_);
806 // Set up for a seek. (Matches setup in SeekTask().) 1001 renderer_ = std::move(renderer);
807 // TODO(sandersd): Share implementation with SeekTask(). 1002 }
808 seek_cb_ = seek_cb;
809 renderer_ended_ = false; 1003 renderer_ended_ = false;
810 text_renderer_ended_ = false; 1004 text_renderer_ended_ = false;
811 start_timestamp_ = std::max(timestamp, demuxer_->GetStartTime());
812 1005
813 // Queue the asynchronous actions required to start playback. Unlike DoSeek(), 1006 // Queue the asynchronous actions required to resume playback.
814 // we need to initialize the renderer ourselves (we don't want to enter state
815 // kInitDemuxer, and even if we did the current code would seek to the start
816 // instead of |timestamp|).
817 SerialRunner::Queue fns; 1007 SerialRunner::Queue fns;
818 1008
819 fns.Push( 1009 // Seek.
820 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_)); 1010 fns.Push(base::Bind(&Demuxer::Seek, base::Unretained(demuxer_),
1011 std::max(time, demuxer_->GetStartTime())));
821 1012
822 fns.Push(base::Bind(&PipelineImpl::InitializeRenderer, weak_this_)); 1013 // Initialize the new renderer.
1014 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer,
1015 weak_factory_.GetWeakPtr()));
823 1016
824 pending_callbacks_ = SerialRunner::Run( 1017 // Run tasks.
825 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); 1018 pending_callbacks_ =
1019 SerialRunner::Run(fns, base::Bind(&RendererWrapper::OnSeekDone,
1020 weak_factory_.GetWeakPtr(), time));
826 } 1021 }
827 1022
828 void PipelineImpl::SetCdmTask(CdmContext* cdm_context, 1023 void PipelineImpl::RendererWrapper::SetCdm(
829 const CdmAttachedCB& cdm_attached_cb) { 1024 CdmContext* cdm_context,
830 base::AutoLock auto_lock(lock_); 1025 const CdmAttachedCB& cdm_attached_cb) {
1026 DCHECK(media_task_runner_->BelongsToCurrentThread());
1027
831 if (!renderer_) { 1028 if (!renderer_) {
832 cdm_context_ = cdm_context; 1029 cdm_context_ = cdm_context;
833 cdm_attached_cb.Run(true); 1030 cdm_attached_cb.Run(true);
834 return; 1031 return;
835 } 1032 }
836 1033
837 renderer_->SetCdm(cdm_context, 1034 renderer_->SetCdm(cdm_context, base::Bind(&RendererWrapper::OnCdmAttached,
838 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_, 1035 weak_factory_.GetWeakPtr(),
839 cdm_attached_cb, cdm_context)); 1036 cdm_attached_cb, cdm_context));
840 } 1037 }
841 1038
842 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, 1039 void PipelineImpl::RendererWrapper::OnCdmAttached(
843 CdmContext* cdm_context, 1040 const CdmAttachedCB& cdm_attached_cb,
844 bool success) { 1041 CdmContext* cdm_context,
1042 bool success) {
845 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1043 DCHECK(media_task_runner_->BelongsToCurrentThread());
1044
846 if (success) 1045 if (success)
847 cdm_context_ = cdm_context; 1046 cdm_context_ = cdm_context;
848 cdm_attached_cb.Run(success); 1047 cdm_attached_cb.Run(success);
849 } 1048 }
850 1049
851 void PipelineImpl::OnTextRendererEnded() { 1050 void PipelineImpl::RendererWrapper::OnTextRendererEnded() {
852 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1051 DCHECK(media_task_runner_->BelongsToCurrentThread());
853 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 1052 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
854 1053
855 if (state_ != kPlaying) 1054 if (state_ != kPlaying)
856 return; 1055 return;
857 1056
858 DCHECK(!text_renderer_ended_); 1057 DCHECK(!text_renderer_ended_);
859 text_renderer_ended_ = true; 1058 text_renderer_ended_ = true;
860 1059
861 RunEndedCallbackIfNeeded(); 1060 RunEndedCallbackIfNeeded();
862 } 1061 }
863 1062
864 void PipelineImpl::RunEndedCallbackIfNeeded() { 1063 void PipelineImpl::RendererWrapper::RunEndedCallbackIfNeeded() {
865 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1064 DCHECK(media_task_runner_->BelongsToCurrentThread());
866 1065
867 if (renderer_ && !renderer_ended_) 1066 if (renderer_ && !renderer_ended_)
868 return; 1067 return;
869 1068
870 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) 1069 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_)
871 return; 1070 return;
872 1071
873 DCHECK_EQ(status_, PIPELINE_OK); 1072 DCHECK_EQ(status_, PIPELINE_OK);
874 main_task_runner_->PostTask( 1073 main_task_runner_->PostTask(
875 FROM_HERE, base::Bind(&Pipeline::Client::OnEnded, weak_client_)); 1074 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_));
876 } 1075 }
877 1076
878 std::unique_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { 1077 void PipelineImpl::RendererWrapper::AddTextStreamTask(
1078 DemuxerStream* text_stream,
1079 const TextTrackConfig& config) {
879 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1080 DCHECK(media_task_runner_->BelongsToCurrentThread());
880 1081
881 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
882 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks))
883 return nullptr;
884
885 return base::WrapUnique(new media::TextRenderer(
886 media_task_runner_,
887 base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_)));
888 }
889
890 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream,
891 const TextTrackConfig& config) {
892 DCHECK(media_task_runner_->BelongsToCurrentThread());
893 // TODO(matthewjheaney): fix up text_ended_ when text stream 1082 // TODO(matthewjheaney): fix up text_ended_ when text stream
894 // is added (http://crbug.com/321446). 1083 // is added (http://crbug.com/321446).
895 if (text_renderer_) 1084 if (text_renderer_)
896 text_renderer_->AddTextStream(text_stream, config); 1085 text_renderer_->AddTextStream(text_stream, config);
897 } 1086 }
898 1087
899 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { 1088 void PipelineImpl::RendererWrapper::RemoveTextStreamTask(
1089 DemuxerStream* text_stream) {
900 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1090 DCHECK(media_task_runner_->BelongsToCurrentThread());
901 1091
902 if (text_renderer_) 1092 if (text_renderer_)
903 text_renderer_->RemoveTextStream(text_stream); 1093 text_renderer_->RemoveTextStream(text_stream);
904 } 1094 }
905 1095
906 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, 1096 void PipelineImpl::RendererWrapper::InitializeDemuxer(
907 const AddTextTrackDoneCB& done_cb) { 1097 const PipelineStatusCB& done_cb) {
908 DCHECK(media_task_runner_->BelongsToCurrentThread());
909
910 main_task_runner_->PostTask(
911 FROM_HERE, base::Bind(&Pipeline::Client::OnAddTextTrack, weak_client_,
912 config, done_cb));
913 }
914
915 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) {
916 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1098 DCHECK(media_task_runner_->BelongsToCurrentThread());
917 1099
918 demuxer_->Initialize(this, done_cb, !!text_renderer_); 1100 demuxer_->Initialize(this, done_cb, !!text_renderer_);
919 } 1101 }
920 1102
921 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { 1103 void PipelineImpl::RendererWrapper::InitializeRenderer(
1104 const PipelineStatusCB& done_cb) {
922 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1105 DCHECK(media_task_runner_->BelongsToCurrentThread());
923 1106
924 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && 1107 if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
925 !demuxer_->GetStream(DemuxerStream::VIDEO)) { 1108 !demuxer_->GetStream(DemuxerStream::VIDEO)) {
926 { 1109 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
927 base::AutoLock auto_lock(lock_);
928 renderer_.reset();
929 }
930 OnError(PIPELINE_ERROR_COULD_NOT_RENDER);
931 return; 1110 return;
932 } 1111 }
933 1112
934 if (cdm_context_) 1113 if (cdm_context_)
935 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); 1114 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached));
936 1115
937 renderer_->Initialize(demuxer_, this, done_cb); 1116 renderer_->Initialize(demuxer_, this, done_cb);
938 } 1117 }
939 1118
940 void PipelineImpl::ReportMetadata() { 1119 void PipelineImpl::RendererWrapper::ReportMetadata() {
941 DCHECK(media_task_runner_->BelongsToCurrentThread()); 1120 DCHECK(media_task_runner_->BelongsToCurrentThread());
942 1121
943 PipelineMetadata metadata; 1122 PipelineMetadata metadata;
944 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 1123 metadata.timeline_offset = demuxer_->GetTimelineOffset();
945 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 1124 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
946 if (stream) { 1125 if (stream) {
947 metadata.has_video = true; 1126 metadata.has_video = true;
948 metadata.natural_size = stream->video_decoder_config().natural_size(); 1127 metadata.natural_size = stream->video_decoder_config().natural_size();
949 metadata.video_rotation = stream->video_rotation(); 1128 metadata.video_rotation = stream->video_rotation();
950 } 1129 }
951 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { 1130 if (demuxer_->GetStream(DemuxerStream::AUDIO)) {
952 metadata.has_audio = true; 1131 metadata.has_audio = true;
953 } 1132 }
954 1133
955 main_task_runner_->PostTask( 1134 main_task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::OnMetadata,
956 FROM_HERE, 1135 weak_pipeline_, metadata));
957 base::Bind(&Pipeline::Client::OnMetadata, weak_client_, metadata));
958 } 1136 }
959 1137
960 } // namespace media 1138 } // 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