OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/android/media_source_player.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 #include <limits> | |
10 #include <utility> | |
11 | |
12 #include "base/android/jni_android.h" | |
13 #include "base/android/jni_string.h" | |
14 #include "base/barrier_closure.h" | |
15 #include "base/bind.h" | |
16 #include "base/bind_helpers.h" | |
17 #include "base/callback_helpers.h" | |
18 #include "base/location.h" | |
19 #include "base/logging.h" | |
20 #include "base/macros.h" | |
21 #include "base/single_thread_task_runner.h" | |
22 #include "base/strings/string_number_conversions.h" | |
23 #include "base/threading/thread_task_runner_handle.h" | |
24 #include "base/trace_event/trace_event.h" | |
25 #include "media/base/android/audio_decoder_job.h" | |
26 #include "media/base/android/media_player_manager.h" | |
27 #include "media/base/android/video_decoder_job.h" | |
28 #include "media/base/bind_to_current_loop.h" | |
29 #include "media/base/timestamp_constants.h" | |
30 | |
31 namespace media { | |
32 | |
33 MediaSourcePlayer::MediaSourcePlayer( | |
34 int player_id, | |
35 MediaPlayerManager* manager, | |
36 const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb, | |
37 std::unique_ptr<DemuxerAndroid> demuxer, | |
38 const GURL& frame_url) | |
39 : MediaPlayerAndroid(player_id, | |
40 manager, | |
41 on_decoder_resources_released_cb, | |
42 frame_url), | |
43 demuxer_(std::move(demuxer)), | |
44 pending_event_(NO_EVENT_PENDING), | |
45 playing_(false), | |
46 interpolator_(&default_tick_clock_), | |
47 doing_browser_seek_(false), | |
48 pending_seek_(false), | |
49 cdm_registration_id_(0), | |
50 is_waiting_for_key_(false), | |
51 key_added_while_decode_pending_(false), | |
52 is_waiting_for_audio_decoder_(false), | |
53 is_waiting_for_video_decoder_(false), | |
54 prerolling_(true), | |
55 weak_factory_(this) { | |
56 media_stat_.reset(new MediaStatistics()); | |
57 | |
58 audio_decoder_job_.reset(new AudioDecoderJob( | |
59 base::Bind(&DemuxerAndroid::RequestDemuxerData, | |
60 base::Unretained(demuxer_.get()), | |
61 DemuxerStream::AUDIO), | |
62 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, | |
63 weak_factory_.GetWeakPtr()))); | |
64 video_decoder_job_.reset(new VideoDecoderJob( | |
65 base::Bind(&DemuxerAndroid::RequestDemuxerData, | |
66 base::Unretained(demuxer_.get()), | |
67 DemuxerStream::VIDEO), | |
68 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, | |
69 weak_factory_.GetWeakPtr()))); | |
70 | |
71 demuxer_->Initialize(this); | |
72 interpolator_.SetPlaybackRate(1.0); | |
73 interpolator_.SetUpperBound(base::TimeDelta()); | |
74 weak_this_ = weak_factory_.GetWeakPtr(); | |
75 } | |
76 | |
77 MediaSourcePlayer::~MediaSourcePlayer() { | |
78 Release(); | |
79 DCHECK_EQ(!cdm_, !cdm_registration_id_); | |
80 if (cdm_) { | |
81 // Cancel previously registered callback (if any). | |
82 static_cast<MediaDrmBridge*>(cdm_.get()) | |
83 ->SetMediaCryptoReadyCB(MediaDrmBridge::MediaCryptoReadyCB()); | |
84 | |
85 static_cast<MediaDrmBridge*>(cdm_.get()) | |
86 ->UnregisterPlayer(cdm_registration_id_); | |
87 cdm_registration_id_ = 0; | |
88 } | |
89 } | |
90 | |
91 void MediaSourcePlayer::SetVideoSurface(gl::ScopedJavaSurface surface) { | |
92 DVLOG(1) << __FUNCTION__; | |
93 if (!video_decoder_job_->SetVideoSurface(std::move(surface))) | |
94 return; | |
95 // Retry video decoder creation. | |
96 RetryDecoderCreation(false, true); | |
97 } | |
98 | |
99 void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding( | |
100 base::TimeDelta seek_time) { | |
101 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ")"; | |
102 DCHECK(!IsEventPending(SEEK_EVENT_PENDING)); | |
103 | |
104 pending_seek_ = false; | |
105 | |
106 interpolator_.SetBounds(seek_time, seek_time, default_tick_clock_.NowTicks()); | |
107 | |
108 if (audio_decoder_job_->is_decoding()) | |
109 audio_decoder_job_->StopDecode(); | |
110 if (video_decoder_job_->is_decoding()) | |
111 video_decoder_job_->StopDecode(); | |
112 | |
113 SetPendingEvent(SEEK_EVENT_PENDING); | |
114 ProcessPendingEvents(); | |
115 } | |
116 | |
117 void MediaSourcePlayer::BrowserSeekToCurrentTime() { | |
118 DVLOG(1) << __FUNCTION__; | |
119 | |
120 DCHECK(!IsEventPending(SEEK_EVENT_PENDING)); | |
121 doing_browser_seek_ = true; | |
122 ScheduleSeekEventAndStopDecoding(GetCurrentTime()); | |
123 } | |
124 | |
125 bool MediaSourcePlayer::Seekable() { | |
126 // If the duration TimeDelta, converted to milliseconds from microseconds, | |
127 // is >= 2^31, then the media is assumed to be unbounded and unseekable. | |
128 // 2^31 is the bound due to java player using 32-bit integer for time | |
129 // values at millisecond resolution. | |
130 return duration_ < | |
131 base::TimeDelta::FromMilliseconds(std::numeric_limits<int32_t>::max()); | |
132 } | |
133 | |
134 void MediaSourcePlayer::Start() { | |
135 DVLOG(1) << __FUNCTION__; | |
136 | |
137 playing_ = true; | |
138 | |
139 StartInternal(); | |
140 } | |
141 | |
142 void MediaSourcePlayer::Pause(bool is_media_related_action) { | |
143 DVLOG(1) << __FUNCTION__; | |
144 | |
145 // Since decoder jobs have their own thread, decoding is not fully paused | |
146 // until all the decoder jobs call MediaDecoderCallback(). It is possible | |
147 // that Start() is called while the player is waiting for | |
148 // MediaDecoderCallback(). In that case, decoding will continue when | |
149 // MediaDecoderCallback() is called. | |
150 playing_ = false; | |
151 start_time_ticks_ = base::TimeTicks(); | |
152 } | |
153 | |
154 bool MediaSourcePlayer::IsPlaying() { | |
155 return playing_; | |
156 } | |
157 | |
158 bool MediaSourcePlayer::HasVideo() const { | |
159 return video_decoder_job_->HasStream(); | |
160 } | |
161 | |
162 bool MediaSourcePlayer::HasAudio() const { | |
163 return audio_decoder_job_->HasStream(); | |
164 } | |
165 | |
166 int MediaSourcePlayer::GetVideoWidth() { | |
167 return video_decoder_job_->output_width(); | |
168 } | |
169 | |
170 int MediaSourcePlayer::GetVideoHeight() { | |
171 return video_decoder_job_->output_height(); | |
172 } | |
173 | |
174 void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { | |
175 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")"; | |
176 | |
177 if (IsEventPending(SEEK_EVENT_PENDING)) { | |
178 DCHECK(doing_browser_seek_) << "SeekTo while SeekTo in progress"; | |
179 DCHECK(!pending_seek_) << "SeekTo while SeekTo pending browser seek"; | |
180 | |
181 // There is a browser seek currently in progress to obtain I-frame to feed | |
182 // a newly constructed video decoder. Remember this real seek request so | |
183 // it can be initiated once OnDemuxerSeekDone() occurs for the browser seek. | |
184 pending_seek_ = true; | |
185 pending_seek_time_ = timestamp; | |
186 return; | |
187 } | |
188 | |
189 doing_browser_seek_ = false; | |
190 ScheduleSeekEventAndStopDecoding(timestamp); | |
191 } | |
192 | |
193 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { | |
194 return std::min(interpolator_.GetInterpolatedTime(), duration_); | |
195 } | |
196 | |
197 base::TimeDelta MediaSourcePlayer::GetDuration() { | |
198 return duration_; | |
199 } | |
200 | |
201 void MediaSourcePlayer::Release() { | |
202 DVLOG(1) << __FUNCTION__; | |
203 | |
204 media_stat_->StopAndReport(GetCurrentTime()); | |
205 | |
206 audio_decoder_job_->ReleaseDecoderResources(); | |
207 video_decoder_job_->ReleaseDecoderResources(); | |
208 | |
209 // Prevent player restart, including job re-creation attempts. | |
210 playing_ = false; | |
211 | |
212 decoder_starvation_callback_.Cancel(); | |
213 | |
214 DetachListener(); | |
215 on_decoder_resources_released_cb_.Run(player_id()); | |
216 } | |
217 | |
218 void MediaSourcePlayer::UpdateEffectiveVolumeInternal(double effective_volume) { | |
219 audio_decoder_job_->SetVolume(effective_volume); | |
220 } | |
221 | |
222 bool MediaSourcePlayer::CanPause() { | |
223 return Seekable(); | |
224 } | |
225 | |
226 bool MediaSourcePlayer::CanSeekForward() { | |
227 return Seekable(); | |
228 } | |
229 | |
230 bool MediaSourcePlayer::CanSeekBackward() { | |
231 return Seekable(); | |
232 } | |
233 | |
234 bool MediaSourcePlayer::IsPlayerReady() { | |
235 return HasAudio() || HasVideo(); | |
236 } | |
237 | |
238 void MediaSourcePlayer::StartInternal() { | |
239 DVLOG(1) << __FUNCTION__; | |
240 // If there are pending events, wait for them finish. | |
241 if (pending_event_ != NO_EVENT_PENDING) | |
242 return; | |
243 | |
244 if (!manager()->RequestPlay(player_id(), duration_, HasAudio())) { | |
245 Pause(true); | |
246 return; | |
247 } | |
248 | |
249 // When we start, we could have new demuxed data coming in. This new data | |
250 // could be clear (not encrypted) or encrypted with different keys. So key | |
251 // related info should all be cleared. | |
252 is_waiting_for_key_ = false; | |
253 key_added_while_decode_pending_ = false; | |
254 AttachListener(nullptr); | |
255 | |
256 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | |
257 ProcessPendingEvents(); | |
258 } | |
259 | |
260 void MediaSourcePlayer::OnDemuxerConfigsAvailable( | |
261 const DemuxerConfigs& configs) { | |
262 DVLOG(1) << __FUNCTION__; | |
263 DCHECK(!HasAudio() && !HasVideo()); | |
264 | |
265 duration_ = configs.duration; | |
266 | |
267 audio_decoder_job_->SetDemuxerConfigs(configs); | |
268 video_decoder_job_->SetDemuxerConfigs(configs); | |
269 OnDemuxerConfigsChanged(); | |
270 } | |
271 | |
272 void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) { | |
273 DVLOG(1) << __FUNCTION__ << "(" << data.type << ")"; | |
274 DCHECK_LT(0u, data.access_units.size()); | |
275 CHECK_GE(1u, data.demuxer_configs.size()); | |
276 | |
277 if (data.type == DemuxerStream::AUDIO) | |
278 audio_decoder_job_->OnDataReceived(data); | |
279 else if (data.type == DemuxerStream::VIDEO) | |
280 video_decoder_job_->OnDataReceived(data); | |
281 } | |
282 | |
283 void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) { | |
284 duration_ = duration; | |
285 } | |
286 | |
287 void MediaSourcePlayer::OnMediaCryptoReady( | |
288 MediaDrmBridge::JavaObjectPtr media_crypto, | |
289 bool /* needs_protected_surface */) { | |
290 DCHECK(media_crypto); | |
291 DCHECK(static_cast<MediaDrmBridge*>(cdm_.get())->GetMediaCrypto()); | |
292 | |
293 if (media_crypto->is_null()) { | |
294 // TODO(xhwang): Fail playback nicely here if needed. Note that we could get | |
295 // here even though the stream to play is unencrypted and therefore | |
296 // MediaCrypto is not needed. In that case, we may ignore this error and | |
297 // continue playback, or fail the playback. | |
298 LOG(ERROR) << "MediaCrypto creation failed!"; | |
299 return; | |
300 } | |
301 | |
302 // Retry decoder creation if the decoders are waiting for MediaCrypto. | |
303 RetryDecoderCreation(true, true); | |
304 } | |
305 | |
306 void MediaSourcePlayer::SetCdm(const scoped_refptr<MediaKeys>& cdm) { | |
307 DCHECK(cdm); | |
308 | |
309 // Currently we don't support DRM change during the middle of playback, even | |
310 // if the player is paused. | |
311 // TODO(qinmin): support DRM change after playback has started. | |
312 // http://crbug.com/253792. | |
313 if (GetCurrentTime() > base::TimeDelta()) { | |
314 VLOG(0) << "Setting DRM bridge after playback has started. " | |
315 << "This is not well supported!"; | |
316 } | |
317 | |
318 if (cdm_) { | |
319 NOTREACHED() << "Currently we do not support resetting CDM."; | |
320 return; | |
321 } | |
322 | |
323 cdm_ = cdm; | |
324 | |
325 // Only MediaDrmBridge will be set on MediaSourcePlayer. | |
326 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get()); | |
327 | |
328 // No need to set |cdm_unset_cb| since |this| holds a reference to the |cdm_|. | |
329 cdm_registration_id_ = drm_bridge->RegisterPlayer( | |
330 base::Bind(&MediaSourcePlayer::OnKeyAdded, weak_this_), | |
331 base::Bind(&base::DoNothing)); | |
332 | |
333 audio_decoder_job_->SetDrmBridge(drm_bridge); | |
334 video_decoder_job_->SetDrmBridge(drm_bridge); | |
335 | |
336 // Use BindToCurrentLoop to avoid reentrancy. | |
337 drm_bridge->SetMediaCryptoReadyCB(BindToCurrentLoop( | |
338 base::Bind(&MediaSourcePlayer::OnMediaCryptoReady, weak_this_))); | |
339 } | |
340 | |
341 void MediaSourcePlayer::OnDemuxerSeekDone( | |
342 base::TimeDelta actual_browser_seek_time) { | |
343 DVLOG(1) << __FUNCTION__; | |
344 | |
345 ClearPendingEvent(SEEK_EVENT_PENDING); | |
346 if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) | |
347 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | |
348 | |
349 if (pending_seek_) { | |
350 DVLOG(1) << __FUNCTION__ << "processing pending seek"; | |
351 DCHECK(doing_browser_seek_); | |
352 pending_seek_ = false; | |
353 SeekTo(pending_seek_time_); | |
354 return; | |
355 } | |
356 | |
357 // It is possible that a browser seek to I-frame had to seek to a buffered | |
358 // I-frame later than the requested one due to data removal or GC. Update | |
359 // player clock to the actual seek target. | |
360 if (doing_browser_seek_) { | |
361 DCHECK(actual_browser_seek_time != kNoTimestamp); | |
362 base::TimeDelta seek_time = actual_browser_seek_time; | |
363 // A browser seek must not jump into the past. Ideally, it seeks to the | |
364 // requested time, but it might jump into the future. | |
365 DCHECK(seek_time >= GetCurrentTime()); | |
366 DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: " | |
367 << seek_time.InSecondsF(); | |
368 interpolator_.SetBounds(seek_time, seek_time, | |
369 default_tick_clock_.NowTicks()); | |
370 audio_decoder_job_->SetBaseTimestamp(seek_time); | |
371 } else { | |
372 DCHECK(actual_browser_seek_time == kNoTimestamp); | |
373 } | |
374 | |
375 base::TimeDelta current_time = GetCurrentTime(); | |
376 // TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_| | |
377 // to preroll media decoder jobs. Currently |start_presentation_timestamp_| | |
378 // is calculated from decoder output, while preroll relies on the access | |
379 // unit's timestamp. There are some differences between the two. | |
380 preroll_timestamp_ = current_time; | |
381 if (HasAudio()) | |
382 audio_decoder_job_->BeginPrerolling(preroll_timestamp_); | |
383 if (HasVideo()) | |
384 video_decoder_job_->BeginPrerolling(preroll_timestamp_); | |
385 prerolling_ = true; | |
386 | |
387 if (!doing_browser_seek_) | |
388 manager()->OnSeekComplete(player_id(), current_time); | |
389 | |
390 ProcessPendingEvents(); | |
391 } | |
392 | |
393 void MediaSourcePlayer::UpdateTimestamps( | |
394 base::TimeDelta current_presentation_timestamp, | |
395 base::TimeDelta max_presentation_timestamp) { | |
396 base::TimeTicks now_ticks = default_tick_clock_.NowTicks(); | |
397 interpolator_.SetBounds(current_presentation_timestamp, | |
398 max_presentation_timestamp, now_ticks); | |
399 manager()->OnTimeUpdate(player_id(), GetCurrentTime(), now_ticks); | |
400 } | |
401 | |
402 void MediaSourcePlayer::ProcessPendingEvents() { | |
403 DVLOG(1) << __FUNCTION__ << " : 0x" << std::hex << pending_event_; | |
404 // Wait for all the decoding jobs to finish before processing pending tasks. | |
405 if (video_decoder_job_->is_decoding()) { | |
406 DVLOG(1) << __FUNCTION__ << " : A video job is still decoding."; | |
407 return; | |
408 } | |
409 | |
410 if (audio_decoder_job_->is_decoding()) { | |
411 DVLOG(1) << __FUNCTION__ << " : An audio job is still decoding."; | |
412 return; | |
413 } | |
414 | |
415 if (IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { | |
416 DVLOG(1) << __FUNCTION__ << " : PREFETCH_DONE still pending."; | |
417 return; | |
418 } | |
419 | |
420 if (IsEventPending(SEEK_EVENT_PENDING)) { | |
421 DVLOG(1) << __FUNCTION__ << " : Handling SEEK_EVENT"; | |
422 ClearDecodingData(); | |
423 audio_decoder_job_->SetBaseTimestamp(GetCurrentTime()); | |
424 demuxer_->RequestDemuxerSeek(GetCurrentTime(), doing_browser_seek_); | |
425 return; | |
426 } | |
427 | |
428 if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) { | |
429 // Don't continue if one of the decoder is not created. | |
430 if (is_waiting_for_audio_decoder_ || is_waiting_for_video_decoder_) | |
431 return; | |
432 ClearPendingEvent(DECODER_CREATION_EVENT_PENDING); | |
433 } | |
434 | |
435 if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) { | |
436 DVLOG(1) << __FUNCTION__ << " : Handling PREFETCH_REQUEST_EVENT."; | |
437 | |
438 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); | |
439 | |
440 // It is possible that all streams have finished decode, yet starvation | |
441 // occurred during the last stream's EOS decode. In this case, prefetch is a | |
442 // no-op. | |
443 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | |
444 if (count == 0) | |
445 return; | |
446 | |
447 SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); | |
448 base::Closure barrier = BarrierClosure( | |
449 count, base::Bind(&MediaSourcePlayer::OnPrefetchDone, weak_this_)); | |
450 | |
451 if (!AudioFinished()) | |
452 audio_decoder_job_->Prefetch(barrier); | |
453 | |
454 if (!VideoFinished()) | |
455 video_decoder_job_->Prefetch(barrier); | |
456 | |
457 return; | |
458 } | |
459 | |
460 DCHECK_EQ(pending_event_, NO_EVENT_PENDING); | |
461 | |
462 // Now that all pending events have been handled, resume decoding if we are | |
463 // still playing. | |
464 if (playing_) | |
465 StartInternal(); | |
466 } | |
467 | |
468 void MediaSourcePlayer::MediaDecoderCallback( | |
469 bool is_audio, | |
470 MediaCodecStatus status, | |
471 bool is_late_frame, | |
472 base::TimeDelta current_presentation_timestamp, | |
473 base::TimeDelta max_presentation_timestamp) { | |
474 DVLOG(1) << __FUNCTION__ << ": " << is_audio << ", " << status; | |
475 | |
476 // TODO(xhwang): Drop IntToString() when http://crbug.com/303899 is fixed. | |
477 if (is_audio) { | |
478 TRACE_EVENT_ASYNC_END1("media", | |
479 "MediaSourcePlayer::DecodeMoreAudio", | |
480 audio_decoder_job_.get(), | |
481 "MediaCodecStatus", | |
482 base::IntToString(status)); | |
483 } else { | |
484 TRACE_EVENT_ASYNC_END1("media", | |
485 "MediaSourcePlayer::DecodeMoreVideo", | |
486 video_decoder_job_.get(), | |
487 "MediaCodecStatus", | |
488 base::IntToString(status)); | |
489 } | |
490 | |
491 // Let tests hook the completion of this decode cycle. | |
492 if (!decode_callback_for_testing_.is_null()) | |
493 base::ResetAndReturn(&decode_callback_for_testing_).Run(); | |
494 | |
495 bool is_clock_manager = is_audio || !HasAudio(); | |
496 | |
497 if (is_clock_manager) | |
498 decoder_starvation_callback_.Cancel(); | |
499 | |
500 if (status == MEDIA_CODEC_ERROR) { | |
501 DVLOG(1) << __FUNCTION__ << " : decode error"; | |
502 Release(); | |
503 manager()->OnError(player_id(), MEDIA_ERROR_DECODE); | |
504 if (is_clock_manager) | |
505 media_stat_->StopAndReport(GetCurrentTime()); | |
506 return; | |
507 } | |
508 | |
509 // Increment frame counts for UMA. | |
510 if (current_presentation_timestamp != kNoTimestamp) { | |
511 FrameStatistics& frame_stats = is_audio ? media_stat_->audio_frame_stats() | |
512 : media_stat_->video_frame_stats(); | |
513 frame_stats.IncrementFrameCount(); | |
514 if (is_late_frame) | |
515 frame_stats.IncrementLateFrameCount(); | |
516 } | |
517 | |
518 DCHECK(!IsEventPending(PREFETCH_DONE_EVENT_PENDING)); | |
519 | |
520 // Let |SEEK_EVENT_PENDING| (the highest priority event outside of | |
521 // |PREFETCH_DONE_EVENT_PENDING|) preempt output EOS detection here. Process | |
522 // any other pending events only after handling EOS detection. | |
523 if (IsEventPending(SEEK_EVENT_PENDING)) { | |
524 ProcessPendingEvents(); | |
525 // In case of Seek GetCurrentTime() already tells the time to seek to. | |
526 if (is_clock_manager && !doing_browser_seek_) | |
527 media_stat_->StopAndReport(current_presentation_timestamp); | |
528 return; | |
529 } | |
530 | |
531 if ((status == MEDIA_CODEC_OK || status == MEDIA_CODEC_INPUT_END_OF_STREAM) && | |
532 is_clock_manager && current_presentation_timestamp != kNoTimestamp) { | |
533 UpdateTimestamps(current_presentation_timestamp, | |
534 max_presentation_timestamp); | |
535 } | |
536 | |
537 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | |
538 PlaybackCompleted(is_audio); | |
539 if (is_clock_manager) | |
540 interpolator_.StopInterpolating(); | |
541 } | |
542 | |
543 if (pending_event_ != NO_EVENT_PENDING) { | |
544 ProcessPendingEvents(); | |
545 return; | |
546 } | |
547 | |
548 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | |
549 if (is_clock_manager) | |
550 media_stat_->StopAndReport(GetCurrentTime()); | |
551 return; | |
552 } | |
553 | |
554 if (!playing_) { | |
555 if (is_clock_manager) | |
556 interpolator_.StopInterpolating(); | |
557 | |
558 if (is_clock_manager) | |
559 media_stat_->StopAndReport(GetCurrentTime()); | |
560 return; | |
561 } | |
562 | |
563 if (status == MEDIA_CODEC_NO_KEY) { | |
564 if (key_added_while_decode_pending_) { | |
565 DVLOG(2) << __FUNCTION__ << ": Key was added during decoding."; | |
566 ResumePlaybackAfterKeyAdded(); | |
567 } else { | |
568 is_waiting_for_key_ = true; | |
569 manager()->OnWaitingForDecryptionKey(player_id()); | |
570 if (is_clock_manager) | |
571 media_stat_->StopAndReport(GetCurrentTime()); | |
572 } | |
573 return; | |
574 } | |
575 | |
576 // If |key_added_while_decode_pending_| is true and both audio and video | |
577 // decoding succeeded, we should clear |key_added_while_decode_pending_| here. | |
578 // But that would add more complexity into this function. If we don't clear it | |
579 // here, the worst case would be we call ResumePlaybackAfterKeyAdded() when | |
580 // we don't really have a new key. This should rarely happen and the | |
581 // performance impact should be pretty small. | |
582 // TODO(qinmin/xhwang): This class is complicated because we handle both audio | |
583 // and video in one file. If we separate them, we should be able to remove a | |
584 // lot of duplication. | |
585 | |
586 // If the status is MEDIA_CODEC_ABORT, stop decoding new data. The player is | |
587 // in the middle of a seek or stop event and needs to wait for the IPCs to | |
588 // come. | |
589 if (status == MEDIA_CODEC_ABORT) { | |
590 return; | |
591 } | |
592 | |
593 if (prerolling_ && IsPrerollFinished(is_audio)) { | |
594 if (IsPrerollFinished(!is_audio)) { | |
595 prerolling_ = false; | |
596 StartInternal(); | |
597 } | |
598 return; | |
599 } | |
600 | |
601 if (is_clock_manager) { | |
602 // If we have a valid timestamp, start the starvation callback. Otherwise, | |
603 // reset the |start_time_ticks_| so that the next frame will not suffer | |
604 // from the decoding delay caused by the current frame. | |
605 if (current_presentation_timestamp != kNoTimestamp) | |
606 StartStarvationCallback(current_presentation_timestamp, | |
607 max_presentation_timestamp); | |
608 else | |
609 start_time_ticks_ = base::TimeTicks::Now(); | |
610 } | |
611 | |
612 if (is_audio) | |
613 DecodeMoreAudio(); | |
614 else | |
615 DecodeMoreVideo(); | |
616 } | |
617 | |
618 bool MediaSourcePlayer::IsPrerollFinished(bool is_audio) const { | |
619 if (is_audio) | |
620 return !HasAudio() || !audio_decoder_job_->prerolling(); | |
621 return !HasVideo() || !video_decoder_job_->prerolling(); | |
622 } | |
623 | |
624 void MediaSourcePlayer::DecodeMoreAudio() { | |
625 DVLOG(1) << __FUNCTION__; | |
626 DCHECK(!audio_decoder_job_->is_decoding()); | |
627 DCHECK(!AudioFinished()); | |
628 | |
629 MediaDecoderJob::MediaDecoderJobStatus status = audio_decoder_job_->Decode( | |
630 start_time_ticks_, | |
631 start_presentation_timestamp_, | |
632 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, true)); | |
633 | |
634 switch (status) { | |
635 case MediaDecoderJob::STATUS_SUCCESS: | |
636 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreAudio", | |
637 audio_decoder_job_.get()); | |
638 break; | |
639 case MediaDecoderJob::STATUS_KEY_FRAME_REQUIRED: | |
640 NOTREACHED(); | |
641 break; | |
642 case MediaDecoderJob::STATUS_FAILURE: | |
643 is_waiting_for_audio_decoder_ = true; | |
644 if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) | |
645 SetPendingEvent(DECODER_CREATION_EVENT_PENDING); | |
646 break; | |
647 } | |
648 } | |
649 | |
650 void MediaSourcePlayer::DecodeMoreVideo() { | |
651 DVLOG(1) << __FUNCTION__; | |
652 DCHECK(!video_decoder_job_->is_decoding()); | |
653 DCHECK(!VideoFinished()); | |
654 | |
655 MediaDecoderJob::MediaDecoderJobStatus status = video_decoder_job_->Decode( | |
656 start_time_ticks_, | |
657 start_presentation_timestamp_, | |
658 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, weak_this_, | |
659 false)); | |
660 | |
661 switch (status) { | |
662 case MediaDecoderJob::STATUS_SUCCESS: | |
663 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourcePlayer::DecodeMoreVideo", | |
664 video_decoder_job_.get()); | |
665 break; | |
666 case MediaDecoderJob::STATUS_KEY_FRAME_REQUIRED: | |
667 BrowserSeekToCurrentTime(); | |
668 break; | |
669 case MediaDecoderJob::STATUS_FAILURE: | |
670 is_waiting_for_video_decoder_ = true; | |
671 if (!IsEventPending(DECODER_CREATION_EVENT_PENDING)) | |
672 SetPendingEvent(DECODER_CREATION_EVENT_PENDING); | |
673 break; | |
674 } | |
675 } | |
676 | |
677 void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { | |
678 DVLOG(1) << __FUNCTION__ << "(" << is_audio << ")"; | |
679 | |
680 if (AudioFinished() && VideoFinished()) { | |
681 playing_ = false; | |
682 start_time_ticks_ = base::TimeTicks(); | |
683 manager()->OnPlaybackComplete(player_id()); | |
684 } | |
685 } | |
686 | |
687 void MediaSourcePlayer::ClearDecodingData() { | |
688 DVLOG(1) << __FUNCTION__; | |
689 audio_decoder_job_->Flush(); | |
690 video_decoder_job_->Flush(); | |
691 start_time_ticks_ = base::TimeTicks(); | |
692 } | |
693 | |
694 bool MediaSourcePlayer::AudioFinished() { | |
695 return audio_decoder_job_->OutputEOSReached() || !HasAudio(); | |
696 } | |
697 | |
698 bool MediaSourcePlayer::VideoFinished() { | |
699 return video_decoder_job_->OutputEOSReached() || !HasVideo(); | |
700 } | |
701 | |
702 void MediaSourcePlayer::OnDecoderStarved() { | |
703 DVLOG(1) << __FUNCTION__; | |
704 | |
705 media_stat_->AddStarvation(); | |
706 | |
707 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | |
708 ProcessPendingEvents(); | |
709 } | |
710 | |
711 void MediaSourcePlayer::StartStarvationCallback( | |
712 base::TimeDelta current_presentation_timestamp, | |
713 base::TimeDelta max_presentation_timestamp) { | |
714 // 20ms was chosen because it is the typical size of a compressed audio frame. | |
715 // Anything smaller than this would likely cause unnecessary cycling in and | |
716 // out of the prefetch state. | |
717 const base::TimeDelta kMinStarvationTimeout = | |
718 base::TimeDelta::FromMilliseconds(20); | |
719 | |
720 base::TimeDelta current_timestamp = GetCurrentTime(); | |
721 base::TimeDelta timeout; | |
722 if (HasAudio()) { | |
723 timeout = max_presentation_timestamp - current_timestamp; | |
724 } else { | |
725 DCHECK(current_timestamp <= current_presentation_timestamp); | |
726 | |
727 // For video only streams, fps can be estimated from the difference | |
728 // between the previous and current presentation timestamps. The | |
729 // previous presentation timestamp is equal to current_timestamp. | |
730 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
731 // video frame timeout. | |
732 timeout = 2 * (current_presentation_timestamp - current_timestamp); | |
733 } | |
734 | |
735 timeout = std::max(timeout, kMinStarvationTimeout); | |
736 | |
737 decoder_starvation_callback_.Reset( | |
738 base::Bind(&MediaSourcePlayer::OnDecoderStarved, weak_this_)); | |
739 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
740 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | |
741 } | |
742 | |
743 void MediaSourcePlayer::OnPrefetchDone() { | |
744 DVLOG(1) << __FUNCTION__; | |
745 DCHECK(!audio_decoder_job_->is_decoding()); | |
746 DCHECK(!video_decoder_job_->is_decoding()); | |
747 | |
748 // A previously posted OnPrefetchDone() could race against a Release(). If | |
749 // Release() won the race, we should no longer have decoder jobs. | |
750 // TODO(qinmin/wolenetz): Maintain channel state to not double-request data | |
751 // or drop data received across Release()+Start(). See http://crbug.com/306314 | |
752 // and http://crbug.com/304234. | |
753 if (!IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { | |
754 DVLOG(1) << __FUNCTION__ << " : aborting"; | |
755 return; | |
756 } | |
757 | |
758 ClearPendingEvent(PREFETCH_DONE_EVENT_PENDING); | |
759 | |
760 if (pending_event_ != NO_EVENT_PENDING) { | |
761 ProcessPendingEvents(); | |
762 return; | |
763 } | |
764 | |
765 if (!playing_) | |
766 return; | |
767 | |
768 start_time_ticks_ = base::TimeTicks::Now(); | |
769 start_presentation_timestamp_ = GetCurrentTime(); | |
770 if (!interpolator_.interpolating()) | |
771 interpolator_.StartInterpolating(); | |
772 | |
773 if (!AudioFinished() || !VideoFinished()) | |
774 media_stat_->Start(start_presentation_timestamp_); | |
775 | |
776 if (!AudioFinished()) | |
777 DecodeMoreAudio(); | |
778 | |
779 if (!VideoFinished()) | |
780 DecodeMoreVideo(); | |
781 } | |
782 | |
783 void MediaSourcePlayer::OnDemuxerConfigsChanged() { | |
784 manager()->OnMediaMetadataChanged( | |
785 player_id(), duration_, GetVideoWidth(), GetVideoHeight(), true); | |
786 } | |
787 | |
788 const char* MediaSourcePlayer::GetEventName(PendingEventFlags event) { | |
789 // Please keep this in sync with PendingEventFlags. | |
790 static const char* kPendingEventNames[] = { | |
791 "PREFETCH_DONE", | |
792 "SEEK", | |
793 "DECODER_CREATION", | |
794 "PREFETCH_REQUEST", | |
795 }; | |
796 | |
797 int mask = 1; | |
798 for (size_t i = 0; i < arraysize(kPendingEventNames); ++i, mask <<= 1) { | |
799 if (event & mask) | |
800 return kPendingEventNames[i]; | |
801 } | |
802 | |
803 return "UNKNOWN"; | |
804 } | |
805 | |
806 bool MediaSourcePlayer::IsEventPending(PendingEventFlags event) const { | |
807 return pending_event_ & event; | |
808 } | |
809 | |
810 void MediaSourcePlayer::SetPendingEvent(PendingEventFlags event) { | |
811 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; | |
812 DCHECK_NE(event, NO_EVENT_PENDING); | |
813 DCHECK(!IsEventPending(event)); | |
814 | |
815 pending_event_ |= event; | |
816 } | |
817 | |
818 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { | |
819 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; | |
820 DCHECK_NE(event, NO_EVENT_PENDING); | |
821 DCHECK(IsEventPending(event)) << GetEventName(event); | |
822 | |
823 pending_event_ &= ~event; | |
824 } | |
825 | |
826 void MediaSourcePlayer::RetryDecoderCreation(bool audio, bool video) { | |
827 if (audio) | |
828 is_waiting_for_audio_decoder_ = false; | |
829 if (video) | |
830 is_waiting_for_video_decoder_ = false; | |
831 if (IsEventPending(DECODER_CREATION_EVENT_PENDING)) | |
832 ProcessPendingEvents(); | |
833 } | |
834 | |
835 void MediaSourcePlayer::OnKeyAdded() { | |
836 DVLOG(1) << __FUNCTION__; | |
837 | |
838 if (is_waiting_for_key_) { | |
839 ResumePlaybackAfterKeyAdded(); | |
840 return; | |
841 } | |
842 | |
843 if ((audio_decoder_job_->is_content_encrypted() && | |
844 audio_decoder_job_->is_decoding()) || | |
845 (video_decoder_job_->is_content_encrypted() && | |
846 video_decoder_job_->is_decoding())) { | |
847 DVLOG(1) << __FUNCTION__ << ": " << "Key added during pending decode."; | |
848 key_added_while_decode_pending_ = true; | |
849 } | |
850 } | |
851 | |
852 void MediaSourcePlayer::ResumePlaybackAfterKeyAdded() { | |
853 DVLOG(1) << __FUNCTION__; | |
854 DCHECK(is_waiting_for_key_ || key_added_while_decode_pending_); | |
855 | |
856 is_waiting_for_key_ = false; | |
857 key_added_while_decode_pending_ = false; | |
858 | |
859 // StartInternal() will trigger a prefetch, where in most cases we'll just | |
860 // use previously received data. | |
861 if (playing_) | |
862 StartInternal(); | |
863 } | |
864 | |
865 } // namespace media | |
OLD | NEW |