| 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 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "media/base/media_log.h" | 22 #include "media/base/media_log.h" |
| 23 #include "media/base/media_switches.h" | 23 #include "media/base/media_switches.h" |
| 24 #include "media/base/renderer.h" | 24 #include "media/base/renderer.h" |
| 25 #include "media/base/renderer_client.h" | 25 #include "media/base/renderer_client.h" |
| 26 #include "media/base/serial_runner.h" | 26 #include "media/base/serial_runner.h" |
| 27 #include "media/base/text_renderer.h" | 27 #include "media/base/text_renderer.h" |
| 28 #include "media/base/text_track_config.h" | 28 #include "media/base/text_track_config.h" |
| 29 #include "media/base/timestamp_constants.h" | 29 #include "media/base/timestamp_constants.h" |
| 30 #include "media/base/video_decoder_config.h" | 30 #include "media/base/video_decoder_config.h" |
| 31 | 31 |
| 32 namespace { |
| 32 static const double kDefaultPlaybackRate = 0.0; | 33 static const double kDefaultPlaybackRate = 0.0; |
| 33 static const float kDefaultVolume = 1.0f; | 34 static const float kDefaultVolume = 1.0f; |
| 34 | 35 |
| 36 base::TimeDelta CurrentMediaTime(base::TimeDelta min_time, |
| 37 base::TimeDelta max_time, |
| 38 base::TimeTicks ref_time, |
| 39 base::TimeTicks curr_time, |
| 40 double playback_rate) { |
| 41 DCHECK(!ref_time.is_null()); |
| 42 return std::min(min_time + (curr_time - ref_time) * playback_rate, max_time); |
| 43 } |
| 44 |
| 45 } // namespace |
| 46 |
| 35 namespace media { | 47 namespace media { |
| 36 | 48 |
| 37 class PipelineImpl::RendererWrapper : public DemuxerHost, | 49 class PipelineImpl::RendererWrapper : public DemuxerHost, |
| 38 public RendererClient { | 50 public RendererClient { |
| 39 public: | 51 public: |
| 40 RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, | 52 RendererWrapper(scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
| 41 scoped_refptr<MediaLog> media_log); | 53 scoped_refptr<MediaLog> media_log); |
| 42 ~RendererWrapper() final; | 54 ~RendererWrapper() final; |
| 43 | 55 |
| 44 void Start(Demuxer* demuxer, | 56 void Start(Demuxer* demuxer, |
| 45 std::unique_ptr<Renderer> renderer, | 57 std::unique_ptr<Renderer> renderer, |
| 46 std::unique_ptr<TextRenderer> text_renderer, | 58 std::unique_ptr<TextRenderer> text_renderer, |
| 47 base::WeakPtr<PipelineImpl> weak_pipeline); | 59 base::WeakPtr<PipelineImpl> weak_pipeline); |
| 48 void Stop(const base::Closure& stop_cb); | 60 void Stop(const base::Closure& stop_cb); |
| 49 void Seek(base::TimeDelta time); | 61 void Seek(base::TimeDelta time); |
| 50 void Suspend(); | 62 void Suspend(); |
| 51 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time); | 63 void Resume(std::unique_ptr<Renderer> renderer, base::TimeDelta time); |
| 52 void SetPlaybackRate(double playback_rate); | 64 void SetPlaybackRate(double playback_rate); |
| 53 void SetVolume(float volume); | 65 void SetVolume(float volume); |
| 54 base::TimeDelta GetMediaTime() const; | 66 void GetMediaTimeExtents(base::TimeDelta* time_min, |
| 67 base::TimeDelta* time_max, |
| 68 base::TimeTicks* time_reference) const; |
| 55 Ranges<base::TimeDelta> GetBufferedTimeRanges() const; | 69 Ranges<base::TimeDelta> GetBufferedTimeRanges() const; |
| 56 bool DidLoadingProgress(); | 70 bool DidLoadingProgress(); |
| 57 PipelineStatistics GetStatistics() const; | 71 PipelineStatistics GetStatistics() const; |
| 58 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); | 72 void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); |
| 59 | 73 |
| 60 // |enabledTrackIds| contains track ids of enabled audio tracks. | 74 // |enabledTrackIds| contains track ids of enabled audio tracks. |
| 61 void OnEnabledAudioTracksChanged( | 75 void OnEnabledAudioTracksChanged( |
| 62 const std::vector<MediaTrack::Id>& enabledTrackIds); | 76 const std::vector<MediaTrack::Id>& enabledTrackIds); |
| 63 | 77 |
| 64 // |trackId| either empty, which means no video track is selected, or contain | 78 // |trackId| either empty, which means no video track is selected, or contain |
| 65 // one element - the selected video track id. | 79 // one element - the selected video track id. |
| 66 void OnSelectedVideoTrackChanged( | 80 void OnSelectedVideoTrackChanged( |
| 67 const std::vector<MediaTrack::Id>& selectedTrackId); | 81 const std::vector<MediaTrack::Id>& selectedTrackId); |
| 68 | 82 |
| 69 private: | 83 private: |
| 70 // Contains state shared between main and media thread. | 84 // Contains state shared between main and media thread. |
| 71 // Main thread can only read. Media thread can both - read and write. | 85 // Main thread can only read. Media thread can both - read and write. |
| 72 // So it is not necessary to lock when reading from the media thread. | 86 // So it is not necessary to lock when reading from the media thread. |
| 73 // This struct should only contain state that is not immediately needed by | 87 // This struct should only contain state that is not immediately needed by |
| 74 // PipelineClient and can be cached on the media thread until queried. | 88 // PipelineClient and can be cached on the media thread until queried. |
| 75 // Alternatively we could cache it on the main thread by posting the | 89 // Alternatively we could cache it on the main thread by posting the |
| 76 // notification to the main thread. But some of the state change notifications | 90 // notification to the main thread. But some of the state change notifications |
| 77 // (OnStatisticsUpdate and OnBufferedTimeRangesChanged) arrive much more | 91 // (OnStatisticsUpdate and OnBufferedTimeRangesChanged) arrive much more |
| 78 // frequently than needed. Posting all those notifications to the main thread | 92 // frequently than needed. Posting all those notifications to the main thread |
| 79 // causes performance issues: crbug.com/619975. | 93 // causes performance issues: crbug.com/619975. |
| 80 struct SharedState { | 94 struct SharedState { |
| 81 // TODO(scherkus): Enforce that Renderer is only called on a single thread, | |
| 82 // even for accessing media time http://crbug.com/370634 | |
| 83 std::unique_ptr<Renderer> renderer; | |
| 84 | |
| 85 // True when OnBufferedTimeRangesChanged() has been called more recently | 95 // True when OnBufferedTimeRangesChanged() has been called more recently |
| 86 // than DidLoadingProgress(). | 96 // than DidLoadingProgress(). |
| 87 bool did_loading_progress = false; | 97 bool did_loading_progress = false; |
| 88 | 98 |
| 89 // Amount of available buffered data as reported by Demuxer. | 99 // Amount of available buffered data as reported by Demuxer. |
| 90 Ranges<base::TimeDelta> buffered_time_ranges; | 100 Ranges<base::TimeDelta> buffered_time_ranges; |
| 91 | 101 |
| 92 // Accumulated statistics reported by the renderer. | 102 // Accumulated statistics reported by the renderer. |
| 93 PipelineStatistics statistics; | 103 PipelineStatistics statistics; |
| 94 | 104 |
| 95 // The media timestamp to return while the pipeline is suspended. | 105 // Media time extents reported by the renderer. |
| 96 // Otherwise set to kNoTimestamp. | 106 base::TimeDelta media_time_min; |
| 97 base::TimeDelta suspend_timestamp = kNoTimestamp; | 107 base::TimeDelta media_time_max; |
| 108 base::TimeTicks media_time_reference; |
| 98 }; | 109 }; |
| 99 | 110 |
| 100 // DemuxerHost implementaion. | 111 // DemuxerHost implementaion. |
| 101 void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final; | 112 void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final; |
| 102 void SetDuration(base::TimeDelta duration) final; | 113 void SetDuration(base::TimeDelta duration) final; |
| 103 void OnDemuxerError(PipelineStatus error) final; | 114 void OnDemuxerError(PipelineStatus error) final; |
| 104 void AddTextStream(DemuxerStream* text_stream, | 115 void AddTextStream(DemuxerStream* text_stream, |
| 105 const TextTrackConfig& config) final; | 116 const TextTrackConfig& config) final; |
| 106 void RemoveTextStream(DemuxerStream* text_stream) final; | 117 void RemoveTextStream(DemuxerStream* text_stream) final; |
| 107 | 118 |
| 108 // RendererClient implementation. | 119 // RendererClient implementation. |
| 109 void OnError(PipelineStatus error) final; | 120 void OnError(PipelineStatus error) final; |
| 110 void OnEnded() final; | 121 void OnEnded() final; |
| 111 void OnStatisticsUpdate(const PipelineStatistics& stats) final; | 122 void OnStatisticsUpdate(const PipelineStatistics& stats) final; |
| 112 void OnBufferingStateChange(BufferingState state) final; | 123 void OnBufferingStateChange(BufferingState state) final; |
| 113 void OnWaitingForDecryptionKey() final; | 124 void OnWaitingForDecryptionKey() final; |
| 114 void OnVideoNaturalSizeChange(const gfx::Size& size) final; | 125 void OnVideoNaturalSizeChange(const gfx::Size& size) final; |
| 115 void OnVideoOpacityChange(bool opaque) final; | 126 void OnVideoOpacityChange(bool opaque) final; |
| 127 void OnTimeUpdate(base::TimeDelta curr_time, |
| 128 base::TimeDelta max_time, |
| 129 base::TimeTicks capture_time) final; |
| 116 | 130 |
| 117 // TextRenderer tasks and notifications. | 131 // TextRenderer tasks and notifications. |
| 118 void OnTextRendererEnded(); | 132 void OnTextRendererEnded(); |
| 119 void AddTextStreamTask(DemuxerStream* text_stream, | 133 void AddTextStreamTask(DemuxerStream* text_stream, |
| 120 const TextTrackConfig& config); | 134 const TextTrackConfig& config); |
| 121 void RemoveTextStreamTask(DemuxerStream* text_stream); | 135 void RemoveTextStreamTask(DemuxerStream* text_stream); |
| 122 | 136 |
| 123 // Common handlers for notifications from renderers and demuxer. | 137 // Common handlers for notifications from renderers and demuxer. |
| 124 void OnPipelineError(PipelineStatus error); | 138 void OnPipelineError(PipelineStatus error); |
| 125 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, | 139 void OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, |
| 126 CdmContext* cdm_context, | 140 CdmContext* cdm_context, |
| 127 bool success); | 141 bool success); |
| 128 void CheckPlaybackEnded(); | 142 void CheckPlaybackEnded(); |
| 129 | 143 |
| 130 // State transition tasks. | 144 // State transition tasks. |
| 131 void SetState(State next_state); | 145 void SetState(State next_state); |
| 132 void CompleteSeek(base::TimeDelta seek_time, PipelineStatus status); | 146 void CompleteSeek(base::TimeDelta seek_time, PipelineStatus status); |
| 133 void CompleteSuspend(PipelineStatus status); | 147 void CompleteSuspend(PipelineStatus status); |
| 134 void InitializeDemuxer(const PipelineStatusCB& done_cb); | 148 void InitializeDemuxer(const PipelineStatusCB& done_cb); |
| 135 void InitializeRenderer(const PipelineStatusCB& done_cb); | 149 void InitializeRenderer(const PipelineStatusCB& done_cb); |
| 136 void DestroyRenderer(); | |
| 137 void ReportMetadata(); | 150 void ReportMetadata(); |
| 138 | 151 |
| 139 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; | 152 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; |
| 140 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 153 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 141 const scoped_refptr<MediaLog> media_log_; | 154 const scoped_refptr<MediaLog> media_log_; |
| 142 | 155 |
| 143 base::WeakPtr<PipelineImpl> weak_pipeline_; | 156 base::WeakPtr<PipelineImpl> weak_pipeline_; |
| 144 Demuxer* demuxer_; | 157 Demuxer* demuxer_; |
| 158 std::unique_ptr<Renderer> renderer_; |
| 145 std::unique_ptr<TextRenderer> text_renderer_; | 159 std::unique_ptr<TextRenderer> text_renderer_; |
| 146 double playback_rate_; | 160 double playback_rate_; |
| 147 float volume_; | 161 float volume_; |
| 148 CdmContext* cdm_context_; | 162 CdmContext* cdm_context_; |
| 149 | 163 |
| 150 // Lock used to serialize |shared_state_|. | 164 // Lock used to serialize |shared_state_|. |
| 151 mutable base::Lock shared_state_lock_; | 165 mutable base::Lock shared_state_lock_; |
| 152 | 166 |
| 153 // State shared between main and media thread. | 167 // State shared between main and media thread. |
| 154 SharedState shared_state_; | 168 SharedState shared_state_; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 std::unique_ptr<Renderer> renderer, | 223 std::unique_ptr<Renderer> renderer, |
| 210 std::unique_ptr<TextRenderer> text_renderer, | 224 std::unique_ptr<TextRenderer> text_renderer, |
| 211 base::WeakPtr<PipelineImpl> weak_pipeline) { | 225 base::WeakPtr<PipelineImpl> weak_pipeline) { |
| 212 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 226 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 213 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: " | 227 DCHECK_EQ(kCreated, state_) << "Received start in unexpected state: " |
| 214 << state_; | 228 << state_; |
| 215 | 229 |
| 216 SetState(kStarting); | 230 SetState(kStarting); |
| 217 | 231 |
| 218 DCHECK(!demuxer_); | 232 DCHECK(!demuxer_); |
| 219 DCHECK(!shared_state_.renderer); | 233 DCHECK(!renderer_); |
| 220 DCHECK(!text_renderer_); | 234 DCHECK(!text_renderer_); |
| 221 DCHECK(!renderer_ended_); | 235 DCHECK(!renderer_ended_); |
| 222 DCHECK(!text_renderer_ended_); | 236 DCHECK(!text_renderer_ended_); |
| 223 DCHECK(!weak_pipeline_); | 237 DCHECK(!weak_pipeline_); |
| 224 demuxer_ = demuxer; | 238 demuxer_ = demuxer; |
| 225 { | 239 renderer_ = std::move(renderer); |
| 226 base::AutoLock auto_lock(shared_state_lock_); | |
| 227 shared_state_.renderer = std::move(renderer); | |
| 228 } | |
| 229 text_renderer_ = std::move(text_renderer); | 240 text_renderer_ = std::move(text_renderer); |
| 230 if (text_renderer_) { | 241 if (text_renderer_) { |
| 231 text_renderer_->Initialize( | 242 text_renderer_->Initialize( |
| 232 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_)); | 243 base::Bind(&RendererWrapper::OnTextRendererEnded, weak_this_)); |
| 233 } | 244 } |
| 234 weak_pipeline_ = weak_pipeline; | 245 weak_pipeline_ = weak_pipeline; |
| 235 | 246 |
| 236 // Queue asynchronous actions required to start. | 247 // Queue asynchronous actions required to start. |
| 237 DCHECK(!pending_callbacks_); | 248 DCHECK(!pending_callbacks_); |
| 238 SerialRunner::Queue fns; | 249 SerialRunner::Queue fns; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 263 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", | 274 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", |
| 264 shared_state_.statistics.video_frames_dropped); | 275 shared_state_.statistics.video_frames_dropped); |
| 265 } | 276 } |
| 266 | 277 |
| 267 // If we stop during starting/seeking/suspending/resuming we don't want to | 278 // If we stop during starting/seeking/suspending/resuming we don't want to |
| 268 // leave outstanding callbacks around. The callbacks also do not get run if | 279 // leave outstanding callbacks around. The callbacks also do not get run if |
| 269 // the pipeline is stopped before it had a chance to complete outstanding | 280 // the pipeline is stopped before it had a chance to complete outstanding |
| 270 // tasks. | 281 // tasks. |
| 271 pending_callbacks_.reset(); | 282 pending_callbacks_.reset(); |
| 272 | 283 |
| 273 DestroyRenderer(); | 284 renderer_.reset(); |
| 274 text_renderer_.reset(); | 285 text_renderer_.reset(); |
| 275 | |
| 276 if (demuxer_) { | 286 if (demuxer_) { |
| 277 demuxer_->Stop(); | 287 demuxer_->Stop(); |
| 278 demuxer_ = NULL; | 288 demuxer_ = NULL; |
| 279 } | 289 } |
| 280 | 290 |
| 281 SetState(kStopped); | 291 SetState(kStopped); |
| 282 | 292 |
| 283 // Post the stop callback to enqueue it after the tasks that may have been | 293 // Post the stop callback to enqueue it after the tasks that may have been |
| 284 // posted by Demuxer and Renderer during stopping. Note that in theory the | 294 // posted by Demuxer and Renderer during stopping. Note that in theory the |
| 285 // tasks posted by Demuxer/Renderer may post even more tasks that will get | 295 // tasks posted by Demuxer/Renderer may post even more tasks that will get |
| 286 // enqueued after |stop_cb|. This may be problematic because Demuxer may | 296 // enqueued after |stop_cb|. This may be problematic because Demuxer may |
| 287 // get destroyed as soon as |stop_cb| is run. In practice this is not a | 297 // get destroyed as soon as |stop_cb| is run. In practice this is not a |
| 288 // problem, but ideally Demuxer should be destroyed on the media thread. | 298 // problem, but ideally Demuxer should be destroyed on the media thread. |
| 289 media_task_runner_->PostTask(FROM_HERE, stop_cb); | 299 media_task_runner_->PostTask(FROM_HERE, stop_cb); |
| 290 } | 300 } |
| 291 | 301 |
| 292 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { | 302 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) { |
| 293 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 303 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 294 | 304 |
| 295 // Suppress seeking if we're not fully started. | 305 // Suppress seeking if we're not fully started. |
| 296 if (state_ != kPlaying) { | 306 if (state_ != kPlaying) { |
| 297 DCHECK(state_ == kStopping || state_ == kStopped) | 307 DCHECK(state_ == kStopping || state_ == kStopped) |
| 298 << "Receive seek in unexpected state: " << state_; | 308 << "Receive seek in unexpected state: " << state_; |
| 299 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); | 309 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); |
| 300 return; | 310 return; |
| 301 } | 311 } |
| 302 | 312 |
| 303 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); | |
| 304 | |
| 305 SetState(kSeeking); | 313 SetState(kSeeking); |
| 306 renderer_ended_ = false; | 314 renderer_ended_ = false; |
| 307 text_renderer_ended_ = false; | 315 text_renderer_ended_ = false; |
| 308 | 316 |
| 309 // Queue asynchronous actions required to start. | 317 // Queue asynchronous actions required to start. |
| 310 DCHECK(!pending_callbacks_); | 318 DCHECK(!pending_callbacks_); |
| 311 SerialRunner::Queue bound_fns; | 319 SerialRunner::Queue bound_fns; |
| 312 | 320 |
| 313 // Pause. | 321 // Pause. |
| 314 if (text_renderer_) { | 322 if (text_renderer_) { |
| 315 bound_fns.Push(base::Bind(&TextRenderer::Pause, | 323 bound_fns.Push(base::Bind(&TextRenderer::Pause, |
| 316 base::Unretained(text_renderer_.get()))); | 324 base::Unretained(text_renderer_.get()))); |
| 317 } | 325 } |
| 318 | 326 |
| 319 // Flush. | 327 // Flush. |
| 320 DCHECK(shared_state_.renderer); | 328 DCHECK(renderer_); |
| 321 bound_fns.Push(base::Bind(&Renderer::Flush, | 329 bound_fns.Push( |
| 322 base::Unretained(shared_state_.renderer.get()))); | 330 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
| 323 | 331 |
| 324 if (text_renderer_) { | 332 if (text_renderer_) { |
| 325 bound_fns.Push(base::Bind(&TextRenderer::Flush, | 333 bound_fns.Push(base::Bind(&TextRenderer::Flush, |
| 326 base::Unretained(text_renderer_.get()))); | 334 base::Unretained(text_renderer_.get()))); |
| 327 } | 335 } |
| 328 | 336 |
| 329 // Seek demuxer. | 337 // Seek demuxer. |
| 338 base::TimeDelta seek_time = std::max(time, demuxer_->GetStartTime()); |
| 330 bound_fns.Push( | 339 bound_fns.Push( |
| 331 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 340 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_time)); |
| 332 | 341 |
| 333 // Run tasks. | 342 // Run tasks. |
| 334 pending_callbacks_ = SerialRunner::Run( | 343 pending_callbacks_ = SerialRunner::Run( |
| 335 bound_fns, | 344 bound_fns, |
| 336 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, seek_timestamp)); | 345 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, seek_time)); |
| 337 } | 346 } |
| 338 | 347 |
| 339 void PipelineImpl::RendererWrapper::Suspend() { | 348 void PipelineImpl::RendererWrapper::Suspend() { |
| 340 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 349 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 341 | 350 |
| 342 // Suppress suspending if we're not playing. | 351 // Suppress suspending if we're not playing. |
| 343 if (state_ != kPlaying) { | 352 if (state_ != kPlaying) { |
| 344 DCHECK(state_ == kStopping || state_ == kStopped) | 353 DCHECK(state_ == kStopping || state_ == kStopped) |
| 345 << "Receive suspend in unexpected state: " << state_; | 354 << "Receive suspend in unexpected state: " << state_; |
| 346 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); | 355 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); |
| 347 return; | 356 return; |
| 348 } | 357 } |
| 349 DCHECK(shared_state_.renderer); | 358 DCHECK(renderer_); |
| 350 DCHECK(!pending_callbacks_.get()); | 359 DCHECK(!pending_callbacks_.get()); |
| 351 | 360 |
| 352 SetState(kSuspending); | 361 SetState(kSuspending); |
| 353 | 362 |
| 354 // Freeze playback and record the media time before flushing. (Flushing clears | 363 // Freeze playback and record the media time before flushing. (Flushing clears |
| 355 // the value.) | 364 // the value.) |
| 356 shared_state_.renderer->SetPlaybackRate(0.0); | 365 renderer_->SetPlaybackRate(0.0); |
| 366 base::TimeDelta media_time = renderer_->GetMediaTime(); |
| 357 { | 367 { |
| 358 base::AutoLock auto_lock(shared_state_lock_); | 368 base::AutoLock auto_lock(shared_state_lock_); |
| 359 shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime(); | 369 shared_state_.media_time_min = media_time; |
| 360 DCHECK(shared_state_.suspend_timestamp != kNoTimestamp); | 370 shared_state_.media_time_max = media_time; |
| 371 shared_state_.media_time_reference = base::TimeTicks(); |
| 361 } | 372 } |
| 362 | 373 |
| 363 // Queue the asynchronous actions required to stop playback. | 374 // Queue the asynchronous actions required to stop playback. |
| 364 SerialRunner::Queue fns; | 375 SerialRunner::Queue fns; |
| 365 | 376 |
| 366 if (text_renderer_) { | 377 if (text_renderer_) { |
| 367 fns.Push(base::Bind(&TextRenderer::Pause, | 378 fns.Push(base::Bind(&TextRenderer::Pause, |
| 368 base::Unretained(text_renderer_.get()))); | 379 base::Unretained(text_renderer_.get()))); |
| 369 } | 380 } |
| 370 | 381 |
| 371 fns.Push(base::Bind(&Renderer::Flush, | 382 fns.Push(base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
| 372 base::Unretained(shared_state_.renderer.get()))); | |
| 373 | 383 |
| 374 if (text_renderer_) { | 384 if (text_renderer_) { |
| 375 fns.Push(base::Bind(&TextRenderer::Flush, | 385 fns.Push(base::Bind(&TextRenderer::Flush, |
| 376 base::Unretained(text_renderer_.get()))); | 386 base::Unretained(text_renderer_.get()))); |
| 377 } | 387 } |
| 378 | 388 |
| 379 pending_callbacks_ = SerialRunner::Run( | 389 pending_callbacks_ = SerialRunner::Run( |
| 380 fns, base::Bind(&RendererWrapper::CompleteSuspend, weak_this_)); | 390 fns, base::Bind(&RendererWrapper::CompleteSuspend, weak_this_)); |
| 381 } | 391 } |
| 382 | 392 |
| 383 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer, | 393 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer, |
| 384 base::TimeDelta timestamp) { | 394 base::TimeDelta timestamp) { |
| 385 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 395 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 386 | 396 |
| 387 // Suppress resuming if we're not suspended. | 397 // Suppress resuming if we're not suspended. |
| 388 if (state_ != kSuspended) { | 398 if (state_ != kSuspended) { |
| 389 DCHECK(state_ == kStopping || state_ == kStopped) | 399 DCHECK(state_ == kStopping || state_ == kStopped) |
| 390 << "Receive resume in unexpected state: " << state_; | 400 << "Receive resume in unexpected state: " << state_; |
| 391 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); | 401 OnPipelineError(PIPELINE_ERROR_INVALID_STATE); |
| 392 return; | 402 return; |
| 393 } | 403 } |
| 394 DCHECK(!shared_state_.renderer); | 404 DCHECK(!renderer_); |
| 395 DCHECK(!pending_callbacks_.get()); | 405 DCHECK(!pending_callbacks_.get()); |
| 396 | 406 |
| 397 SetState(kResuming); | 407 SetState(kResuming); |
| 398 | 408 |
| 399 { | 409 renderer_ = std::move(renderer); |
| 400 base::AutoLock auto_lock(shared_state_lock_); | |
| 401 shared_state_.renderer = std::move(renderer); | |
| 402 } | |
| 403 | |
| 404 renderer_ended_ = false; | 410 renderer_ended_ = false; |
| 405 text_renderer_ended_ = false; | 411 text_renderer_ended_ = false; |
| 406 base::TimeDelta start_timestamp = | 412 base::TimeDelta start_timestamp = |
| 407 std::max(timestamp, demuxer_->GetStartTime()); | 413 std::max(timestamp, demuxer_->GetStartTime()); |
| 408 | 414 |
| 409 // Queue the asynchronous actions required to start playback. | 415 // Queue the asynchronous actions required to start playback. |
| 410 SerialRunner::Queue fns; | 416 SerialRunner::Queue fns; |
| 411 | 417 |
| 412 fns.Push( | 418 fns.Push( |
| 413 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp)); | 419 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp)); |
| 414 | 420 |
| 415 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); | 421 fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_)); |
| 416 | 422 |
| 417 pending_callbacks_ = SerialRunner::Run( | 423 pending_callbacks_ = SerialRunner::Run( |
| 418 fns, | 424 fns, |
| 419 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, start_timestamp)); | 425 base::Bind(&RendererWrapper::CompleteSeek, weak_this_, start_timestamp)); |
| 420 } | 426 } |
| 421 | 427 |
| 422 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { | 428 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) { |
| 423 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 429 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 424 | 430 |
| 431 if (!shared_state_.media_time_reference.is_null()) { |
| 432 base::AutoLock auto_lock(shared_state_lock_); |
| 433 base::TimeTicks now_time = base::TimeTicks::Now(); |
| 434 shared_state_.media_time_min = CurrentMediaTime( |
| 435 shared_state_.media_time_min, shared_state_.media_time_max, |
| 436 shared_state_.media_time_reference, now_time, playback_rate_); |
| 437 shared_state_.media_time_reference = now_time; |
| 438 } |
| 439 |
| 425 playback_rate_ = playback_rate; | 440 playback_rate_ = playback_rate; |
| 426 if (state_ == kPlaying) | 441 if (state_ == kPlaying) |
| 427 shared_state_.renderer->SetPlaybackRate(playback_rate_); | 442 renderer_->SetPlaybackRate(playback_rate_); |
| 428 } | 443 } |
| 429 | 444 |
| 430 void PipelineImpl::RendererWrapper::SetVolume(float volume) { | 445 void PipelineImpl::RendererWrapper::SetVolume(float volume) { |
| 431 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 446 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 432 | 447 |
| 433 volume_ = volume; | 448 volume_ = volume; |
| 434 if (state_ == kPlaying) | 449 if (state_ == kPlaying) |
| 435 shared_state_.renderer->SetVolume(volume_); | 450 renderer_->SetVolume(volume_); |
| 436 } | 451 } |
| 437 | 452 |
| 438 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() const { | 453 void PipelineImpl::RendererWrapper::GetMediaTimeExtents( |
| 439 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 454 base::TimeDelta* time_min, |
| 455 base::TimeDelta* time_max, |
| 456 base::TimeTicks* time_reference) const { |
| 457 base::AutoLock auto_lock(shared_state_lock_); |
| 440 | 458 |
| 441 base::AutoLock auto_lock(shared_state_lock_); | 459 *time_min = shared_state_.media_time_min; |
| 442 if (shared_state_.suspend_timestamp != kNoTimestamp) | 460 *time_max = shared_state_.media_time_max; |
| 443 return shared_state_.suspend_timestamp; | 461 *time_reference = shared_state_.media_time_reference; |
| 444 return shared_state_.renderer ? shared_state_.renderer->GetMediaTime() | |
| 445 : base::TimeDelta(); | |
| 446 } | 462 } |
| 447 | 463 |
| 448 Ranges<base::TimeDelta> PipelineImpl::RendererWrapper::GetBufferedTimeRanges() | 464 Ranges<base::TimeDelta> PipelineImpl::RendererWrapper::GetBufferedTimeRanges() |
| 449 const { | 465 const { |
| 450 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 466 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 451 | 467 |
| 452 base::AutoLock auto_lock(shared_state_lock_); | 468 base::AutoLock auto_lock(shared_state_lock_); |
| 453 return shared_state_.buffered_time_ranges; | 469 return shared_state_.buffered_time_ranges; |
| 454 } | 470 } |
| 455 | 471 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 467 | 483 |
| 468 base::AutoLock auto_lock(shared_state_lock_); | 484 base::AutoLock auto_lock(shared_state_lock_); |
| 469 return shared_state_.statistics; | 485 return shared_state_.statistics; |
| 470 } | 486 } |
| 471 | 487 |
| 472 void PipelineImpl::RendererWrapper::SetCdm( | 488 void PipelineImpl::RendererWrapper::SetCdm( |
| 473 CdmContext* cdm_context, | 489 CdmContext* cdm_context, |
| 474 const CdmAttachedCB& cdm_attached_cb) { | 490 const CdmAttachedCB& cdm_attached_cb) { |
| 475 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 491 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 476 | 492 |
| 477 if (!shared_state_.renderer) { | 493 if (!renderer_) { |
| 478 cdm_context_ = cdm_context; | 494 cdm_context_ = cdm_context; |
| 479 cdm_attached_cb.Run(true); | 495 cdm_attached_cb.Run(true); |
| 480 return; | 496 return; |
| 481 } | 497 } |
| 482 | 498 |
| 483 shared_state_.renderer->SetCdm( | 499 renderer_->SetCdm(cdm_context, |
| 484 cdm_context, base::Bind(&RendererWrapper::OnCdmAttached, weak_this_, | 500 base::Bind(&RendererWrapper::OnCdmAttached, weak_this_, |
| 485 cdm_attached_cb, cdm_context)); | 501 cdm_attached_cb, cdm_context)); |
| 486 } | 502 } |
| 487 | 503 |
| 488 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged( | 504 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged( |
| 489 const Ranges<base::TimeDelta>& ranges) { | 505 const Ranges<base::TimeDelta>& ranges) { |
| 490 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer | 506 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer |
| 491 // implementations call DemuxerHost on the media thread. | 507 // implementations call DemuxerHost on the media thread. |
| 492 base::AutoLock auto_lock(shared_state_lock_); | 508 base::AutoLock auto_lock(shared_state_lock_); |
| 493 shared_state_.did_loading_progress = true; | 509 shared_state_.did_loading_progress = true; |
| 494 shared_state_.buffered_time_ranges = ranges; | 510 shared_state_.buffered_time_ranges = ranges; |
| 495 } | 511 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 const std::vector<MediaTrack::Id>& enabledTrackIds) { | 591 const std::vector<MediaTrack::Id>& enabledTrackIds) { |
| 576 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 592 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 577 | 593 |
| 578 // Track status notifications might be delivered asynchronously. If we receive | 594 // Track status notifications might be delivered asynchronously. If we receive |
| 579 // a notification when pipeline is stopped/shut down, it's safe to ignore it. | 595 // a notification when pipeline is stopped/shut down, it's safe to ignore it. |
| 580 if (state_ == kStopping || state_ == kStopped) { | 596 if (state_ == kStopping || state_ == kStopped) { |
| 581 return; | 597 return; |
| 582 } | 598 } |
| 583 | 599 |
| 584 DCHECK(demuxer_); | 600 DCHECK(demuxer_); |
| 585 DCHECK(shared_state_.renderer); | 601 DCHECK(renderer_); |
| 586 | 602 |
| 587 base::TimeDelta currTime = (state_ == kPlaying) | 603 base::TimeDelta currTime = (state_ == kPlaying) ? renderer_->GetMediaTime() |
| 588 ? shared_state_.renderer->GetMediaTime() | 604 : demuxer_->GetStartTime(); |
| 589 : demuxer_->GetStartTime(); | |
| 590 demuxer_->OnEnabledAudioTracksChanged(enabledTrackIds, currTime); | 605 demuxer_->OnEnabledAudioTracksChanged(enabledTrackIds, currTime); |
| 591 } | 606 } |
| 592 | 607 |
| 593 void PipelineImpl::RendererWrapper::OnSelectedVideoTrackChanged( | 608 void PipelineImpl::RendererWrapper::OnSelectedVideoTrackChanged( |
| 594 const std::vector<MediaTrack::Id>& selectedTrackId) { | 609 const std::vector<MediaTrack::Id>& selectedTrackId) { |
| 595 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 610 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 596 | 611 |
| 597 // Track status notifications might be delivered asynchronously. If we receive | 612 // Track status notifications might be delivered asynchronously. If we receive |
| 598 // a notification when pipeline is stopped/shut down, it's safe to ignore it. | 613 // a notification when pipeline is stopped/shut down, it's safe to ignore it. |
| 599 if (state_ == kStopping || state_ == kStopped) { | 614 if (state_ == kStopping || state_ == kStopped) { |
| 600 return; | 615 return; |
| 601 } | 616 } |
| 602 | 617 |
| 603 DCHECK(demuxer_); | 618 DCHECK(demuxer_); |
| 604 DCHECK(shared_state_.renderer); | 619 DCHECK(renderer_); |
| 605 | 620 |
| 606 base::TimeDelta currTime = (state_ == kPlaying) | 621 base::TimeDelta currTime = (state_ == kPlaying) ? renderer_->GetMediaTime() |
| 607 ? shared_state_.renderer->GetMediaTime() | 622 : demuxer_->GetStartTime(); |
| 608 : demuxer_->GetStartTime(); | |
| 609 demuxer_->OnSelectedVideoTrackChanged(selectedTrackId, currTime); | 623 demuxer_->OnSelectedVideoTrackChanged(selectedTrackId, currTime); |
| 610 } | 624 } |
| 611 | 625 |
| 612 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( | 626 void PipelineImpl::RendererWrapper::OnStatisticsUpdate( |
| 613 const PipelineStatistics& stats) { | 627 const PipelineStatistics& stats) { |
| 614 DVLOG(3) << __func__; | 628 DVLOG(3) << __func__; |
| 615 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 629 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 616 | 630 |
| 617 base::AutoLock auto_lock(shared_state_lock_); | 631 base::AutoLock auto_lock(shared_state_lock_); |
| 618 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded; | 632 shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 } | 665 } |
| 652 | 666 |
| 653 void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) { | 667 void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) { |
| 654 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 668 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 655 | 669 |
| 656 main_task_runner_->PostTask( | 670 main_task_runner_->PostTask( |
| 657 FROM_HERE, | 671 FROM_HERE, |
| 658 base::Bind(&PipelineImpl::OnVideoOpacityChange, weak_pipeline_, opaque)); | 672 base::Bind(&PipelineImpl::OnVideoOpacityChange, weak_pipeline_, opaque)); |
| 659 } | 673 } |
| 660 | 674 |
| 675 void PipelineImpl::RendererWrapper::OnTimeUpdate(base::TimeDelta curr_time, |
| 676 base::TimeDelta max_time, |
| 677 base::TimeTicks capture_time) { |
| 678 DVLOG(4) << __func__ << "(" << curr_time.InMicroseconds() << ", " |
| 679 << max_time.InMicroseconds() << ", " << capture_time << ")"; |
| 680 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 681 |
| 682 base::AutoLock auto_lock(shared_state_lock_); |
| 683 shared_state_.media_time_min = curr_time; |
| 684 shared_state_.media_time_max = max_time; |
| 685 shared_state_.media_time_reference = capture_time; |
| 686 } |
| 687 |
| 661 void PipelineImpl::RendererWrapper::OnTextRendererEnded() { | 688 void PipelineImpl::RendererWrapper::OnTextRendererEnded() { |
| 662 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 689 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 663 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); | 690 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); |
| 664 | 691 |
| 665 if (state_ != kPlaying) | 692 if (state_ != kPlaying) |
| 666 return; | 693 return; |
| 667 | 694 |
| 668 DCHECK(!text_renderer_ended_); | 695 DCHECK(!text_renderer_ended_); |
| 669 text_renderer_ended_ = true; | 696 text_renderer_ended_ = true; |
| 670 CheckPlaybackEnded(); | 697 CheckPlaybackEnded(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 747 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 721 | 748 |
| 722 if (success) | 749 if (success) |
| 723 cdm_context_ = cdm_context; | 750 cdm_context_ = cdm_context; |
| 724 cdm_attached_cb.Run(success); | 751 cdm_attached_cb.Run(success); |
| 725 } | 752 } |
| 726 | 753 |
| 727 void PipelineImpl::RendererWrapper::CheckPlaybackEnded() { | 754 void PipelineImpl::RendererWrapper::CheckPlaybackEnded() { |
| 728 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 755 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 729 | 756 |
| 730 if (shared_state_.renderer && !renderer_ended_) | 757 if (renderer_ && !renderer_ended_) |
| 731 return; | 758 return; |
| 732 | 759 |
| 733 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) | 760 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) |
| 734 return; | 761 return; |
| 735 | 762 |
| 736 DCHECK_EQ(status_, PIPELINE_OK); | 763 DCHECK_EQ(status_, PIPELINE_OK); |
| 737 main_task_runner_->PostTask( | 764 main_task_runner_->PostTask( |
| 738 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_)); | 765 FROM_HERE, base::Bind(&PipelineImpl::OnEnded, weak_pipeline_)); |
| 739 } | 766 } |
| 740 | 767 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 753 DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming); | 780 DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming); |
| 754 | 781 |
| 755 DCHECK(pending_callbacks_); | 782 DCHECK(pending_callbacks_); |
| 756 pending_callbacks_.reset(); | 783 pending_callbacks_.reset(); |
| 757 | 784 |
| 758 if (status != PIPELINE_OK) { | 785 if (status != PIPELINE_OK) { |
| 759 OnPipelineError(status); | 786 OnPipelineError(status); |
| 760 return; | 787 return; |
| 761 } | 788 } |
| 762 | 789 |
| 763 shared_state_.renderer->StartPlayingFrom( | 790 seek_time = std::max(seek_time, demuxer_->GetStartTime()); |
| 764 std::max(seek_time, demuxer_->GetStartTime())); | 791 renderer_->StartPlayingFrom(seek_time); |
| 765 { | 792 renderer_->SetPlaybackRate(playback_rate_); |
| 766 base::AutoLock auto_lock(shared_state_lock_); | 793 renderer_->SetVolume(volume_); |
| 767 shared_state_.suspend_timestamp = kNoTimestamp; | |
| 768 } | |
| 769 | 794 |
| 770 if (text_renderer_) | 795 if (text_renderer_) |
| 771 text_renderer_->StartPlaying(); | 796 text_renderer_->StartPlaying(); |
| 772 | 797 |
| 773 shared_state_.renderer->SetPlaybackRate(playback_rate_); | 798 { |
| 774 shared_state_.renderer->SetVolume(volume_); | 799 base::AutoLock auto_lock(shared_state_lock_); |
| 800 shared_state_.media_time_min = seek_time; |
| 801 shared_state_.media_time_max = seek_time; |
| 802 shared_state_.media_time_reference = base::TimeTicks(); |
| 803 } |
| 775 | 804 |
| 776 SetState(kPlaying); | 805 SetState(kPlaying); |
| 777 main_task_runner_->PostTask( | 806 main_task_runner_->PostTask( |
| 778 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_)); | 807 FROM_HERE, base::Bind(&PipelineImpl::OnSeekDone, weak_pipeline_)); |
| 779 } | 808 } |
| 780 | 809 |
| 781 void PipelineImpl::RendererWrapper::CompleteSuspend(PipelineStatus status) { | 810 void PipelineImpl::RendererWrapper::CompleteSuspend(PipelineStatus status) { |
| 782 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 811 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 783 DCHECK_EQ(kSuspending, state_); | 812 DCHECK_EQ(kSuspending, state_); |
| 784 | 813 |
| 785 DCHECK(pending_callbacks_); | 814 DCHECK(pending_callbacks_); |
| 786 pending_callbacks_.reset(); | 815 pending_callbacks_.reset(); |
| 787 | 816 |
| 788 // In case we are suspending or suspended, the error may be recoverable, | 817 // In case we are suspending or suspended, the error may be recoverable, |
| 789 // so don't propagate it now, instead let the subsequent seek during resume | 818 // so don't propagate it now, instead let the subsequent seek during resume |
| 790 // propagate it if it's unrecoverable. | 819 // propagate it if it's unrecoverable. |
| 791 LOG_IF(WARNING, status != PIPELINE_OK) | 820 LOG_IF(WARNING, status != PIPELINE_OK) |
| 792 << "Encountered pipeline error while suspending: " << status; | 821 << "Encountered pipeline error while suspending: " << status; |
| 793 | 822 |
| 794 DestroyRenderer(); | 823 renderer_.reset(); |
| 795 { | 824 { |
| 796 base::AutoLock auto_lock(shared_state_lock_); | 825 base::AutoLock auto_lock(shared_state_lock_); |
| 797 shared_state_.statistics.audio_memory_usage = 0; | 826 shared_state_.statistics.audio_memory_usage = 0; |
| 798 shared_state_.statistics.video_memory_usage = 0; | 827 shared_state_.statistics.video_memory_usage = 0; |
| 799 } | 828 } |
| 800 | 829 |
| 801 SetState(kSuspended); | 830 SetState(kSuspended); |
| 802 main_task_runner_->PostTask( | 831 main_task_runner_->PostTask( |
| 803 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_)); | 832 FROM_HERE, base::Bind(&PipelineImpl::OnSuspendDone, weak_pipeline_)); |
| 804 } | 833 } |
| 805 | 834 |
| 806 void PipelineImpl::RendererWrapper::InitializeDemuxer( | 835 void PipelineImpl::RendererWrapper::InitializeDemuxer( |
| 807 const PipelineStatusCB& done_cb) { | 836 const PipelineStatusCB& done_cb) { |
| 808 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 837 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 809 | 838 |
| 810 demuxer_->Initialize(this, done_cb, !!text_renderer_); | 839 demuxer_->Initialize(this, done_cb, !!text_renderer_); |
| 811 } | 840 } |
| 812 | 841 |
| 813 void PipelineImpl::RendererWrapper::InitializeRenderer( | 842 void PipelineImpl::RendererWrapper::InitializeRenderer( |
| 814 const PipelineStatusCB& done_cb) { | 843 const PipelineStatusCB& done_cb) { |
| 815 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 844 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 816 | 845 |
| 817 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && | 846 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && |
| 818 !demuxer_->GetStream(DemuxerStream::VIDEO)) { | 847 !demuxer_->GetStream(DemuxerStream::VIDEO)) { |
| 819 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); | 848 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 820 return; | 849 return; |
| 821 } | 850 } |
| 822 | 851 |
| 823 if (cdm_context_) | 852 if (cdm_context_) |
| 824 shared_state_.renderer->SetCdm(cdm_context_, | 853 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); |
| 825 base::Bind(&IgnoreCdmAttached)); | |
| 826 | 854 |
| 827 shared_state_.renderer->Initialize(demuxer_, this, done_cb); | 855 renderer_->Initialize(demuxer_, this, done_cb); |
| 828 } | |
| 829 | |
| 830 void PipelineImpl::RendererWrapper::DestroyRenderer() { | |
| 831 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 832 | |
| 833 // Destroy the renderer outside the lock scope to avoid holding the lock | |
| 834 // while renderer is being destroyed (in case Renderer destructor is costly). | |
| 835 std::unique_ptr<Renderer> renderer; | |
| 836 { | |
| 837 base::AutoLock auto_lock(shared_state_lock_); | |
| 838 renderer.swap(shared_state_.renderer); | |
| 839 } | |
| 840 } | 856 } |
| 841 | 857 |
| 842 void PipelineImpl::RendererWrapper::ReportMetadata() { | 858 void PipelineImpl::RendererWrapper::ReportMetadata() { |
| 843 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 859 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 844 | 860 |
| 845 PipelineMetadata metadata; | 861 PipelineMetadata metadata; |
| 846 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 862 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
| 847 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 863 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 848 if (stream) { | 864 if (stream) { |
| 849 metadata.has_video = true; | 865 metadata.has_video = true; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 DCHECK(thread_checker_.CalledOnValidThread()); | 988 DCHECK(thread_checker_.CalledOnValidThread()); |
| 973 DCHECK(!seek_cb.is_null()); | 989 DCHECK(!seek_cb.is_null()); |
| 974 | 990 |
| 975 if (!IsRunning()) { | 991 if (!IsRunning()) { |
| 976 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 992 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; |
| 977 return; | 993 return; |
| 978 } | 994 } |
| 979 | 995 |
| 980 DCHECK(seek_cb_.is_null()); | 996 DCHECK(seek_cb_.is_null()); |
| 981 seek_cb_ = seek_cb; | 997 seek_cb_ = seek_cb; |
| 998 media_time_last_ = base::TimeDelta(); |
| 999 |
| 982 media_task_runner_->PostTask( | 1000 media_task_runner_->PostTask( |
| 983 FROM_HERE, base::Bind(&RendererWrapper::Seek, | 1001 FROM_HERE, base::Bind(&RendererWrapper::Seek, |
| 984 base::Unretained(renderer_wrapper_.get()), time)); | 1002 base::Unretained(renderer_wrapper_.get()), time)); |
| 985 } | 1003 } |
| 986 | 1004 |
| 987 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { | 1005 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { |
| 988 DVLOG(2) << __func__; | 1006 DVLOG(2) << __func__; |
| 989 DCHECK(!suspend_cb.is_null()); | 1007 DCHECK(!suspend_cb.is_null()); |
| 990 | 1008 |
| 991 DCHECK(IsRunning()); | 1009 DCHECK(IsRunning()); |
| 992 DCHECK(suspend_cb_.is_null()); | 1010 DCHECK(suspend_cb_.is_null()); |
| 993 suspend_cb_ = suspend_cb; | 1011 suspend_cb_ = suspend_cb; |
| 994 | 1012 |
| 995 media_task_runner_->PostTask( | 1013 media_task_runner_->PostTask( |
| 996 FROM_HERE, base::Bind(&RendererWrapper::Suspend, | 1014 FROM_HERE, base::Bind(&RendererWrapper::Suspend, |
| 997 base::Unretained(renderer_wrapper_.get()))); | 1015 base::Unretained(renderer_wrapper_.get()))); |
| 998 } | 1016 } |
| 999 | 1017 |
| 1000 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer, | 1018 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer, |
| 1001 base::TimeDelta time, | 1019 base::TimeDelta time, |
| 1002 const PipelineStatusCB& seek_cb) { | 1020 const PipelineStatusCB& seek_cb) { |
| 1003 DVLOG(2) << __func__; | 1021 DVLOG(2) << __func__; |
| 1004 DCHECK(thread_checker_.CalledOnValidThread()); | 1022 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1005 DCHECK(renderer); | 1023 DCHECK(renderer); |
| 1006 DCHECK(!seek_cb.is_null()); | 1024 DCHECK(!seek_cb.is_null()); |
| 1007 | 1025 |
| 1008 DCHECK(IsRunning()); | 1026 DCHECK(IsRunning()); |
| 1009 DCHECK(seek_cb_.is_null()); | 1027 DCHECK(seek_cb_.is_null()); |
| 1010 seek_cb_ = seek_cb; | 1028 seek_cb_ = seek_cb; |
| 1029 media_time_last_ = base::TimeDelta(); |
| 1011 | 1030 |
| 1012 media_task_runner_->PostTask( | 1031 media_task_runner_->PostTask( |
| 1013 FROM_HERE, base::Bind(&RendererWrapper::Resume, | 1032 FROM_HERE, base::Bind(&RendererWrapper::Resume, |
| 1014 base::Unretained(renderer_wrapper_.get()), | 1033 base::Unretained(renderer_wrapper_.get()), |
| 1015 base::Passed(&renderer), time)); | 1034 base::Passed(&renderer), time)); |
| 1016 } | 1035 } |
| 1017 | 1036 |
| 1018 bool PipelineImpl::IsRunning() const { | 1037 bool PipelineImpl::IsRunning() const { |
| 1019 DCHECK(thread_checker_.CalledOnValidThread()); | 1038 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1020 return !!client_; | 1039 return !!client_; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 | 1072 |
| 1054 volume_ = volume; | 1073 volume_ = volume; |
| 1055 media_task_runner_->PostTask( | 1074 media_task_runner_->PostTask( |
| 1056 FROM_HERE, | 1075 FROM_HERE, |
| 1057 base::Bind(&RendererWrapper::SetVolume, | 1076 base::Bind(&RendererWrapper::SetVolume, |
| 1058 base::Unretained(renderer_wrapper_.get()), volume_)); | 1077 base::Unretained(renderer_wrapper_.get()), volume_)); |
| 1059 } | 1078 } |
| 1060 | 1079 |
| 1061 base::TimeDelta PipelineImpl::GetMediaTime() const { | 1080 base::TimeDelta PipelineImpl::GetMediaTime() const { |
| 1062 DCHECK(thread_checker_.CalledOnValidThread()); | 1081 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1063 return renderer_wrapper_->GetMediaTime(); | 1082 |
| 1083 base::TimeDelta time_min, time_max; |
| 1084 base::TimeTicks time_ref; |
| 1085 renderer_wrapper_->GetMediaTimeExtents(&time_min, &time_max, &time_ref); |
| 1086 |
| 1087 // Return the current time based on the known extents of media data plus an |
| 1088 // estimate based on the last time those values were calculated. |
| 1089 base::TimeDelta media_time = |
| 1090 time_ref.is_null() |
| 1091 ? time_min |
| 1092 : CurrentMediaTime(time_min, time_max, time_ref, |
| 1093 base::TimeTicks::Now(), playback_rate_); |
| 1094 |
| 1095 // Clamp current media time to the last reported value, this prevents higher |
| 1096 // level clients from seeing time go backwards based on inaccurate or spurious |
| 1097 // delay values reported to the AudioClock. |
| 1098 // |
| 1099 // It is expected that such events are transient and will be recovered as |
| 1100 // rendering continues over time. |
| 1101 if (media_time < media_time_last_) { |
| 1102 DVLOG(2) << __func__ << ": " << media_time_last_ |
| 1103 << " (clamped), actual: " << media_time; |
| 1104 return media_time_last_; |
| 1105 } |
| 1106 |
| 1107 DVLOG(2) << __func__ << ": " << media_time; |
| 1108 media_time_last_ = media_time; |
| 1109 return media_time; |
| 1064 } | 1110 } |
| 1065 | 1111 |
| 1066 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { | 1112 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { |
| 1067 DCHECK(thread_checker_.CalledOnValidThread()); | 1113 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1068 return renderer_wrapper_->GetBufferedTimeRanges(); | 1114 return renderer_wrapper_->GetBufferedTimeRanges(); |
| 1069 } | 1115 } |
| 1070 | 1116 |
| 1071 base::TimeDelta PipelineImpl::GetMediaDuration() const { | 1117 base::TimeDelta PipelineImpl::GetMediaDuration() const { |
| 1072 DCHECK(thread_checker_.CalledOnValidThread()); | 1118 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1073 return duration_; | 1119 return duration_; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 void PipelineImpl::OnSuspendDone() { | 1275 void PipelineImpl::OnSuspendDone() { |
| 1230 DVLOG(3) << __func__; | 1276 DVLOG(3) << __func__; |
| 1231 DCHECK(thread_checker_.CalledOnValidThread()); | 1277 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1232 DCHECK(IsRunning()); | 1278 DCHECK(IsRunning()); |
| 1233 | 1279 |
| 1234 DCHECK(!suspend_cb_.is_null()); | 1280 DCHECK(!suspend_cb_.is_null()); |
| 1235 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK); | 1281 base::ResetAndReturn(&suspend_cb_).Run(PIPELINE_OK); |
| 1236 } | 1282 } |
| 1237 | 1283 |
| 1238 } // namespace media | 1284 } // namespace media |
| OLD | NEW |