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 |