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

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