Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 |
| OLD | NEW |