OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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/android/media_source_player.h" | 5 #include "media/base/android/media_source_player.h" |
6 | 6 |
7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
9 #include "base/barrier_closure.h" | 9 #include "base/barrier_closure.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { | 145 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { |
146 return clock_.Elapsed(); | 146 return clock_.Elapsed(); |
147 } | 147 } |
148 | 148 |
149 base::TimeDelta MediaSourcePlayer::GetDuration() { | 149 base::TimeDelta MediaSourcePlayer::GetDuration() { |
150 return duration_; | 150 return duration_; |
151 } | 151 } |
152 | 152 |
153 void MediaSourcePlayer::Release() { | 153 void MediaSourcePlayer::Release() { |
154 DVLOG(1) << __FUNCTION__; | 154 DVLOG(1) << __FUNCTION__; |
155 ClearDecodingData(); | |
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
Not needed since the jobs are getting Release()'ed
| |
156 audio_decoder_job_.reset(); | 155 audio_decoder_job_.reset(); |
157 video_decoder_job_.reset(); | 156 video_decoder_job_.reset(); |
158 reconfig_audio_decoder_ = false; | 157 reconfig_audio_decoder_ = false; |
159 reconfig_video_decoder_ = false; | 158 reconfig_video_decoder_ = false; |
160 playing_ = false; | 159 playing_ = false; |
161 pending_event_ = NO_EVENT_PENDING; | 160 pending_event_ = NO_EVENT_PENDING; |
162 surface_ = gfx::ScopedJavaSurface(); | 161 surface_ = gfx::ScopedJavaSurface(); |
163 ReleaseMediaResourcesFromManager(); | 162 ReleaseMediaResourcesFromManager(); |
164 } | 163 } |
165 | 164 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 return; | 309 return; |
311 | 310 |
312 ClearPendingEvent(SEEK_EVENT_PENDING); | 311 ClearPendingEvent(SEEK_EVENT_PENDING); |
313 | 312 |
314 OnSeekComplete(); | 313 OnSeekComplete(); |
315 ProcessPendingEvents(); | 314 ProcessPendingEvents(); |
316 } | 315 } |
317 | 316 |
318 void MediaSourcePlayer::UpdateTimestamps( | 317 void MediaSourcePlayer::UpdateTimestamps( |
319 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 318 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
319 base::TimeDelta new_max_time = presentation_timestamp; | |
320 | |
320 if (audio_output_bytes > 0) { | 321 if (audio_output_bytes > 0) { |
321 audio_timestamp_helper_->AddFrames( | 322 audio_timestamp_helper_->AddFrames( |
322 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); | 323 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); |
323 clock_.SetMaxTime(audio_timestamp_helper_->GetTimestamp()); | 324 new_max_time = audio_timestamp_helper_->GetTimestamp(); |
324 } else { | |
325 clock_.SetMaxTime(presentation_timestamp); | |
326 } | 325 } |
327 | 326 |
327 clock_.SetMaxTime(new_max_time); | |
328 OnTimeUpdated(); | 328 OnTimeUpdated(); |
329 } | 329 } |
330 | 330 |
331 void MediaSourcePlayer::ProcessPendingEvents() { | 331 void MediaSourcePlayer::ProcessPendingEvents() { |
332 DVLOG(1) << __FUNCTION__ << " : 0x" | 332 DVLOG(1) << __FUNCTION__ << " : 0x" |
333 << std::hex << pending_event_; | 333 << std::hex << pending_event_; |
334 // Wait for all the decoding jobs to finish before processing pending tasks. | 334 // Wait for all the decoding jobs to finish before processing pending tasks. |
335 if ((audio_decoder_job_ && audio_decoder_job_->is_decoding()) || | 335 if ((audio_decoder_job_ && audio_decoder_job_->is_decoding()) || |
336 (video_decoder_job_ && video_decoder_job_->is_decoding())) { | 336 (video_decoder_job_ && video_decoder_job_->is_decoding())) { |
337 DVLOG(1) << __FUNCTION__ << " : A job is still decoding."; | 337 DVLOG(1) << __FUNCTION__ << " : A job is still decoding."; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
389 // Now that all pending events have been handled, resume decoding if we are | 389 // Now that all pending events have been handled, resume decoding if we are |
390 // still playing. | 390 // still playing. |
391 if (playing_) | 391 if (playing_) |
392 StartInternal(); | 392 StartInternal(); |
393 } | 393 } |
394 | 394 |
395 void MediaSourcePlayer::MediaDecoderCallback( | 395 void MediaSourcePlayer::MediaDecoderCallback( |
396 bool is_audio, MediaDecoderJob::DecodeStatus decode_status, | 396 bool is_audio, MediaDecoderJob::DecodeStatus decode_status, |
397 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 397 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
398 DVLOG(1) << __FUNCTION__; | 398 DVLOG(1) << __FUNCTION__; |
399 if (is_audio) | 399 |
400 bool is_clock_manager = is_audio || !HasAudio(); | |
401 | |
402 if (is_clock_manager) | |
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
The starvation callback gets scheduled in the vide
| |
400 decoder_starvation_callback_.Cancel(); | 403 decoder_starvation_callback_.Cancel(); |
401 | 404 |
402 if (decode_status == MediaDecoderJob::DECODE_FAILED) { | 405 if (decode_status == MediaDecoderJob::DECODE_FAILED) { |
403 Release(); | 406 Release(); |
404 OnMediaError(MEDIA_ERROR_DECODE); | 407 OnMediaError(MEDIA_ERROR_DECODE); |
405 return; | 408 return; |
406 } | 409 } |
407 | 410 |
408 if (pending_event_ != NO_EVENT_PENDING) { | 411 if (pending_event_ != NO_EVENT_PENDING) { |
409 ProcessPendingEvents(); | 412 ProcessPendingEvents(); |
410 return; | 413 return; |
411 } | 414 } |
412 | 415 |
413 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED && | |
qinmin
2013/08/30 22:27:43
why changing the order of these 2 if statement?
F
acolwell GONE FROM CHROMIUM
2013/09/06 00:34:55
The blocks are mutually exclusive. decode status c
qinmin
2013/09/06 00:56:33
Looks like this is a bug. When decode status is DE
| |
414 (is_audio || !HasAudio())) { | |
415 UpdateTimestamps(presentation_timestamp, audio_output_bytes); | |
416 } | |
417 | |
418 if (decode_status == MediaDecoderJob::DECODE_OUTPUT_END_OF_STREAM) { | 416 if (decode_status == MediaDecoderJob::DECODE_OUTPUT_END_OF_STREAM) { |
419 PlaybackCompleted(is_audio); | 417 PlaybackCompleted(is_audio); |
420 return; | 418 return; |
421 } | 419 } |
422 | 420 |
421 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED && is_clock_manager) | |
422 UpdateTimestamps(presentation_timestamp, audio_output_bytes); | |
423 | |
423 if (!playing_) { | 424 if (!playing_) { |
424 if (is_audio || !HasAudio()) | 425 if (is_clock_manager) |
425 clock_.Pause(); | 426 clock_.Pause(); |
426 return; | 427 return; |
427 } | 428 } |
428 | 429 |
429 base::TimeDelta current_timestamp = GetCurrentTime(); | 430 if (is_clock_manager && decode_status == MediaDecoderJob::DECODE_SUCCEEDED) |
431 StartStarvationCallback(presentation_timestamp); | |
432 | |
430 if (is_audio) { | 433 if (is_audio) { |
431 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED) { | 434 DecodeMoreAudio(); |
432 base::TimeDelta timeout = | |
433 audio_timestamp_helper_->GetTimestamp() - current_timestamp; | |
434 StartStarvationCallback(timeout); | |
435 } | |
436 DecodeMoreAudio(); | |
437 return; | 435 return; |
438 } | 436 } |
439 | 437 |
440 if (!HasAudio() && decode_status == MediaDecoderJob::DECODE_SUCCEEDED) { | |
441 DCHECK(current_timestamp <= presentation_timestamp); | |
442 // For video only streams, fps can be estimated from the difference | |
443 // between the previous and current presentation timestamps. The | |
444 // previous presentation timestamp is equal to current_timestamp. | |
445 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
446 // video frame timeout. | |
447 StartStarvationCallback(2 * (presentation_timestamp - current_timestamp)); | |
448 } | |
449 | |
450 DecodeMoreVideo(); | 438 DecodeMoreVideo(); |
451 } | 439 } |
452 | 440 |
453 void MediaSourcePlayer::DecodeMoreAudio() { | 441 void MediaSourcePlayer::DecodeMoreAudio() { |
454 DVLOG(1) << __FUNCTION__; | 442 DVLOG(1) << __FUNCTION__; |
455 DCHECK(!audio_decoder_job_->is_decoding()); | 443 DCHECK(!audio_decoder_job_->is_decoding()); |
456 | 444 |
457 if (audio_decoder_job_->Decode( | 445 if (audio_decoder_job_->Decode( |
458 start_time_ticks_, start_presentation_timestamp_, base::Bind( | 446 start_time_ticks_, start_presentation_timestamp_, base::Bind( |
459 &MediaSourcePlayer::MediaDecoderCallback, | 447 &MediaSourcePlayer::MediaDecoderCallback, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 OnMediaMetadataChanged(duration_, width_, height_, true); | 571 OnMediaMetadataChanged(duration_, width_, height_, true); |
584 } | 572 } |
585 | 573 |
586 void MediaSourcePlayer::OnDecoderStarved() { | 574 void MediaSourcePlayer::OnDecoderStarved() { |
587 DVLOG(1) << __FUNCTION__; | 575 DVLOG(1) << __FUNCTION__; |
588 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 576 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
589 ProcessPendingEvents(); | 577 ProcessPendingEvents(); |
590 } | 578 } |
591 | 579 |
592 void MediaSourcePlayer::StartStarvationCallback( | 580 void MediaSourcePlayer::StartStarvationCallback( |
593 const base::TimeDelta& timeout) { | 581 const base::TimeDelta& presentation_timestamp) { |
594 DVLOG(1) << __FUNCTION__ << "(" << timeout.InSecondsF() << ")"; | 582 // 20ms was chosen because it is the typical size of a compressed audio frame. |
583 // Anything smaller than this would likely cause unnecessary cycling in and | |
584 // out of the prefetch state. | |
585 const base::TimeDelta kMinStarvationTimeout = | |
586 base::TimeDelta::FromMilliseconds(20); | |
587 | |
588 base::TimeDelta current_timestamp = GetCurrentTime(); | |
589 base::TimeDelta timeout; | |
590 if (HasAudio()) { | |
591 timeout = audio_timestamp_helper_->GetTimestamp() - current_timestamp; | |
592 } else { | |
593 DCHECK(current_timestamp <= presentation_timestamp); | |
594 | |
595 // For video only streams, fps can be estimated from the difference | |
596 // between the previous and current presentation timestamps. The | |
597 // previous presentation timestamp is equal to current_timestamp. | |
598 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
599 // video frame timeout. | |
600 timeout = 2 * (presentation_timestamp - current_timestamp); | |
601 } | |
602 | |
603 timeout = std::max(timeout, kMinStarvationTimeout); | |
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
This fixes a bug that was in the code where it wou
| |
595 | 604 |
596 decoder_starvation_callback_.Reset( | 605 decoder_starvation_callback_.Reset( |
597 base::Bind(&MediaSourcePlayer::OnDecoderStarved, | 606 base::Bind(&MediaSourcePlayer::OnDecoderStarved, |
598 weak_this_.GetWeakPtr())); | 607 weak_this_.GetWeakPtr())); |
599 base::MessageLoop::current()->PostDelayedTask( | 608 base::MessageLoop::current()->PostDelayedTask( |
600 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | 609 FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
601 } | 610 } |
602 | 611 |
603 void MediaSourcePlayer::SetVolumeInternal() { | 612 void MediaSourcePlayer::SetVolumeInternal() { |
604 if (audio_decoder_job_ && volume_ >= 0) | 613 if (audio_decoder_job_ && volume_ >= 0) |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 | 675 |
667 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { | 676 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { |
668 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; | 677 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; |
669 DCHECK_NE(event, NO_EVENT_PENDING); | 678 DCHECK_NE(event, NO_EVENT_PENDING); |
670 DCHECK(IsEventPending(event)); | 679 DCHECK(IsEventPending(event)); |
671 | 680 |
672 pending_event_ &= ~event; | 681 pending_event_ &= ~event; |
673 } | 682 } |
674 | 683 |
675 } // namespace media | 684 } // namespace media |
OLD | NEW |