Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/media/webmediaplayer_impl.h" | 5 #include "webkit/media/webmediaplayer_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 // the time bar. For really high speeds, audio becomes a bottleneck and we just | 74 // the time bar. For really high speeds, audio becomes a bottleneck and we just |
| 75 // use up the data we have, which may not achieve the speed requested, but will | 75 // use up the data we have, which may not achieve the speed requested, but will |
| 76 // not crash the tab. | 76 // not crash the tab. |
| 77 // | 77 // |
| 78 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems | 78 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems |
| 79 // like a busy loop). It gets unresponsive, although its not completely dead. | 79 // like a busy loop). It gets unresponsive, although its not completely dead. |
| 80 // | 80 // |
| 81 // Also our timers are not very accurate (especially for ogg), which becomes | 81 // Also our timers are not very accurate (especially for ogg), which becomes |
| 82 // evident at low speeds and on Vista. Since other speeds are risky and outside | 82 // evident at low speeds and on Vista. Since other speeds are risky and outside |
| 83 // the norms, we think 1/16x to 16x is a safe and useful range for now. | 83 // the norms, we think 1/16x to 16x is a safe and useful range for now. |
| 84 const float kMinRate = 0.0625f; | 84 const double kMinRate = 0.0625; |
| 85 const float kMaxRate = 16.0f; | 85 const double kMaxRate = 16.0; |
| 86 | 86 |
| 87 // Prefix for histograms related to Encrypted Media Extensions. | 87 // Prefix for histograms related to Encrypted Media Extensions. |
| 88 const char* kMediaEme = "Media.EME."; | 88 const char* kMediaEme = "Media.EME."; |
| 89 } // namespace | 89 } // namespace |
| 90 | 90 |
| 91 namespace webkit_media { | 91 namespace webkit_media { |
| 92 | 92 |
| 93 #define COMPILE_ASSERT_MATCHING_ENUM(name) \ | 93 #define COMPILE_ASSERT_MATCHING_ENUM(name) \ |
| 94 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \ | 94 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \ |
| 95 static_cast<int>(BufferedResourceLoader::k ## name), \ | 95 static_cast<int>(BufferedResourceLoader::k ## name), \ |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 | 368 |
| 369 bool WebMediaPlayerImpl::supportsSave() const { | 369 bool WebMediaPlayerImpl::supportsSave() const { |
| 370 DCHECK(main_loop_->BelongsToCurrentThread()); | 370 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 371 return supports_save_; | 371 return supports_save_; |
| 372 } | 372 } |
| 373 | 373 |
| 374 void WebMediaPlayerImpl::seekFloat(float seconds) { | 374 void WebMediaPlayerImpl::seekFloat(float seconds) { |
| 375 seek(seconds); | 375 seek(seconds); |
| 376 } | 376 } |
| 377 | 377 |
| 378 void WebMediaPlayerImpl::seek(float seconds) { | 378 void WebMediaPlayerImpl::seek(double seconds) { |
| 379 DCHECK(main_loop_->BelongsToCurrentThread()); | 379 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 380 | 380 |
| 381 if (starting_ || seeking_) { | 381 if (starting_ || seeking_) { |
| 382 pending_seek_ = true; | 382 pending_seek_ = true; |
| 383 pending_seek_seconds_ = seconds; | 383 pending_seek_seconds_ = seconds; |
| 384 if (chunk_demuxer_) | 384 if (chunk_demuxer_) |
| 385 chunk_demuxer_->CancelPendingSeek(); | 385 chunk_demuxer_->CancelPendingSeek(); |
| 386 return; | 386 return; |
| 387 } | 387 } |
| 388 | 388 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 402 // Kick off the asynchronous seek! | 402 // Kick off the asynchronous seek! |
| 403 pipeline_->Seek( | 403 pipeline_->Seek( |
| 404 seek_time, | 404 seek_time, |
| 405 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek)); | 405 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek)); |
| 406 } | 406 } |
| 407 | 407 |
| 408 void WebMediaPlayerImpl::setEndTimeFloat(float seconds) { | 408 void WebMediaPlayerImpl::setEndTimeFloat(float seconds) { |
| 409 setEndTime(seconds); | 409 setEndTime(seconds); |
| 410 } | 410 } |
| 411 | 411 |
| 412 void WebMediaPlayerImpl::setEndTime(float seconds) { | 412 void WebMediaPlayerImpl::setEndTime(double seconds) { |
| 413 DCHECK(main_loop_->BelongsToCurrentThread()); | 413 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 414 | 414 |
| 415 // TODO(hclam): add method call when it has been implemented. | 415 // TODO(hclam): add method call when it has been implemented. |
| 416 return; | 416 return; |
| 417 } | 417 } |
| 418 | 418 |
| 419 void WebMediaPlayerImpl::setRateFloat(float rate) { | 419 void WebMediaPlayerImpl::setRateFloat(float rate) { |
| 420 setRate(rate); | 420 setRate(rate); |
| 421 } | 421 } |
| 422 | 422 |
| 423 void WebMediaPlayerImpl::setRate(float rate) { | 423 void WebMediaPlayerImpl::setRate(double rate) { |
| 424 DCHECK(main_loop_->BelongsToCurrentThread()); | 424 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 425 | 425 |
| 426 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 426 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
| 427 // following checks so rewind uses reasonable values also. | 427 // following checks so rewind uses reasonable values also. |
| 428 if (rate < 0.0f) | 428 if (rate < 0.0) |
| 429 return; | 429 return; |
| 430 | 430 |
| 431 // Limit rates to reasonable values by clamping. | 431 // Limit rates to reasonable values by clamping. |
| 432 if (rate != 0.0f) { | 432 if (rate != 0.0) { |
| 433 if (rate < kMinRate) | 433 if (rate < kMinRate) |
| 434 rate = kMinRate; | 434 rate = kMinRate; |
| 435 else if (rate > kMaxRate) | 435 else if (rate > kMaxRate) |
| 436 rate = kMaxRate; | 436 rate = kMaxRate; |
| 437 } | 437 } |
| 438 | 438 |
| 439 playback_rate_ = rate; | 439 playback_rate_ = rate; |
| 440 if (!paused_) { | 440 if (!paused_) { |
| 441 pipeline_->SetPlaybackRate(rate); | 441 pipeline_->SetPlaybackRate(rate); |
| 442 } | 442 } |
| 443 } | 443 } |
| 444 | 444 |
| 445 void WebMediaPlayerImpl::setVolumeFloat(float volume) { | 445 void WebMediaPlayerImpl::setVolumeFloat(float volume) { |
| 446 setVolume(volume); | 446 setVolume(volume); |
| 447 } | 447 } |
| 448 | 448 |
| 449 void WebMediaPlayerImpl::setVolume(float volume) { | 449 void WebMediaPlayerImpl::setVolume(double volume) { |
| 450 DCHECK(main_loop_->BelongsToCurrentThread()); | 450 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 451 | 451 |
| 452 pipeline_->SetVolume(volume); | 452 pipeline_->SetVolume(volume); |
| 453 } | 453 } |
| 454 | 454 |
| 455 void WebMediaPlayerImpl::setVisible(bool visible) { | 455 void WebMediaPlayerImpl::setVisible(bool visible) { |
| 456 DCHECK(main_loop_->BelongsToCurrentThread()); | 456 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 457 | 457 |
| 458 // TODO(hclam): add appropriate method call when pipeline has it implemented. | 458 // TODO(hclam): add appropriate method call when pipeline has it implemented. |
| 459 return; | 459 return; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 bool WebMediaPlayerImpl::seeking() const { | 510 bool WebMediaPlayerImpl::seeking() const { |
| 511 DCHECK(main_loop_->BelongsToCurrentThread()); | 511 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 512 | 512 |
| 513 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) | 513 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
| 514 return false; | 514 return false; |
| 515 | 515 |
| 516 return seeking_; | 516 return seeking_; |
| 517 } | 517 } |
| 518 | 518 |
| 519 float WebMediaPlayerImpl::durationFloat() const { | 519 float WebMediaPlayerImpl::durationFloat() const { |
| 520 return duration(); | |
| 521 } | |
| 522 | |
| 523 float WebMediaPlayerImpl::duration() const { | |
| 524 DCHECK(main_loop_->BelongsToCurrentThread()); | |
| 525 | |
| 526 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) | 520 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
| 527 return std::numeric_limits<float>::quiet_NaN(); | 521 return std::numeric_limits<float>::quiet_NaN(); |
| 528 | 522 |
| 529 double duration; | 523 double result = duration(); |
| 530 if (chunk_demuxer_) { | |
| 531 duration = chunk_demuxer_->GetDuration(); | |
| 532 } else { | |
| 533 duration = GetPipelineDuration(); | |
| 534 } | |
| 535 | 524 |
| 536 // Make sure super small durations don't get truncated to 0 and | 525 // Make sure super small durations don't get truncated to 0 and |
| 537 // large durations don't get converted to infinity by the double -> float | 526 // large durations don't get converted to infinity by the double -> float |
| 538 // conversion. | 527 // conversion. |
| 539 // | 528 // |
| 540 // TODO(acolwell): Remove when WebKit is changed to report duration as a | 529 // TODO(acolwell): Remove when WebKit is changed to report duration as a |
| 541 // double. | 530 // double. |
| 542 if (duration > 0.0 && duration < std::numeric_limits<double>::infinity()) { | 531 if (result > 0.0 && result < std::numeric_limits<double>::infinity()) { |
| 543 duration = std::max(duration, | 532 result = std::max(result, |
| 544 static_cast<double>(std::numeric_limits<float>::min())); | 533 static_cast<double>(std::numeric_limits<float>::min())); |
| 545 duration = std::min(duration, | 534 result = std::min(result, |
| 546 static_cast<double>(std::numeric_limits<float>::max())); | 535 static_cast<double>(std::numeric_limits<float>::max())); |
| 547 } | 536 } |
| 548 | 537 |
| 549 return static_cast<float>(duration); | 538 return static_cast<float>(result); |
| 539 | |
| 540 } | |
| 541 | |
| 542 double WebMediaPlayerImpl::duration() const { | |
| 543 DCHECK(main_loop_->BelongsToCurrentThread()); | |
| 544 | |
| 545 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) | |
| 546 return std::numeric_limits<double>::quiet_NaN(); | |
| 547 | |
| 548 if (chunk_demuxer_) | |
| 549 return chunk_demuxer_->GetDuration(); | |
| 550 | |
| 551 return GetPipelineDuration(); | |
| 550 } | 552 } |
| 551 | 553 |
| 552 float WebMediaPlayerImpl::currentTimeFloat() const { | 554 float WebMediaPlayerImpl::currentTimeFloat() const { |
| 553 return currentTime(); | 555 return static_cast<float>(currentTime()); |
| 554 } | 556 } |
| 555 | 557 |
| 556 float WebMediaPlayerImpl::currentTime() const { | 558 double WebMediaPlayerImpl::currentTime() const { |
| 557 DCHECK(main_loop_->BelongsToCurrentThread()); | 559 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 558 if (paused_) | 560 if (paused_) |
| 559 return static_cast<float>(paused_time_.InSecondsF()); | 561 return paused_time_.InSecondsF(); |
|
DaleCurtis
2013/04/16 01:19:48
If you're so inclined:
return (paused_ ? paused_t
acolwell GONE FROM CHROMIUM
2013/04/16 16:58:15
Done.
| |
| 560 return static_cast<float>(pipeline_->GetMediaTime().InSecondsF()); | 562 return pipeline_->GetMediaTime().InSecondsF(); |
| 561 } | 563 } |
| 562 | 564 |
| 563 int WebMediaPlayerImpl::dataRate() const { | 565 int WebMediaPlayerImpl::dataRate() const { |
| 564 DCHECK(main_loop_->BelongsToCurrentThread()); | 566 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 565 | 567 |
| 566 // TODO(hclam): Add this method call if pipeline has it in the interface. | 568 // TODO(hclam): Add this method call if pipeline has it in the interface. |
| 567 return 0; | 569 return 0; |
| 568 } | 570 } |
| 569 | 571 |
| 570 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { | 572 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { |
| 571 DCHECK(main_loop_->BelongsToCurrentThread()); | 573 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 572 return network_state_; | 574 return network_state_; |
| 573 } | 575 } |
| 574 | 576 |
| 575 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { | 577 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { |
| 576 DCHECK(main_loop_->BelongsToCurrentThread()); | 578 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 577 return ready_state_; | 579 return ready_state_; |
| 578 } | 580 } |
| 579 | 581 |
| 580 const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() { | 582 const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() { |
| 581 DCHECK(main_loop_->BelongsToCurrentThread()); | 583 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 582 WebKit::WebTimeRanges web_ranges( | 584 WebKit::WebTimeRanges web_ranges( |
| 583 ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges())); | 585 ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges())); |
| 584 buffered_.swap(web_ranges); | 586 buffered_.swap(web_ranges); |
| 585 return buffered_; | 587 return buffered_; |
| 586 } | 588 } |
| 587 | 589 |
| 588 float WebMediaPlayerImpl::maxTimeSeekableFloat() const { | 590 float WebMediaPlayerImpl::maxTimeSeekableFloat() const { |
| 589 return maxTimeSeekable(); | |
|
DaleCurtis
2013/04/16 01:19:48
How come?
acolwell GONE FROM CHROMIUM
2013/04/16 16:58:15
durationFloat() needs to be used in this version n
| |
| 590 } | |
| 591 | |
| 592 float WebMediaPlayerImpl::maxTimeSeekable() const { | |
| 593 DCHECK(main_loop_->BelongsToCurrentThread()); | 591 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 594 | 592 |
| 595 // If we haven't even gotten to ReadyStateHaveMetadata yet then just | 593 // If we haven't even gotten to ReadyStateHaveMetadata yet then just |
| 596 // return 0 so that the seekable range is empty. | 594 // return 0 so that the seekable range is empty. |
| 597 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) | 595 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) |
| 598 return 0.0f; | 596 return 0.0f; |
| 599 | 597 |
| 600 // We don't support seeking in streaming media. | 598 // We don't support seeking in streaming media. |
| 601 if (data_source_ && data_source_->IsStreaming()) | 599 if (data_source_ && data_source_->IsStreaming()) |
| 602 return 0.0f; | 600 return 0.0f; |
| 601 return durationFloat(); | |
| 602 } | |
| 603 | |
| 604 double WebMediaPlayerImpl::maxTimeSeekable() const { | |
| 605 DCHECK(main_loop_->BelongsToCurrentThread()); | |
| 606 | |
| 607 // If we haven't even gotten to ReadyStateHaveMetadata yet then just | |
| 608 // return 0 so that the seekable range is empty. | |
| 609 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) | |
| 610 return 0.0; | |
| 611 | |
| 612 // We don't support seeking in streaming media. | |
| 613 if (data_source_ && data_source_->IsStreaming()) | |
| 614 return 0.0; | |
| 603 return duration(); | 615 return duration(); |
| 604 } | 616 } |
| 605 | 617 |
| 606 bool WebMediaPlayerImpl::didLoadingProgress() const { | 618 bool WebMediaPlayerImpl::didLoadingProgress() const { |
| 607 DCHECK(main_loop_->BelongsToCurrentThread()); | 619 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 608 return pipeline_->DidLoadingProgress(); | 620 return pipeline_->DidLoadingProgress(); |
| 609 } | 621 } |
| 610 | 622 |
| 611 unsigned long long WebMediaPlayerImpl::totalBytes() const { | 623 unsigned long long WebMediaPlayerImpl::totalBytes() const { |
| 612 DCHECK(main_loop_->BelongsToCurrentThread()); | 624 DCHECK(main_loop_->BelongsToCurrentThread()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 // Disable seeking while streaming. | 676 // Disable seeking while streaming. |
| 665 if (data_source_ && data_source_->IsStreaming()) | 677 if (data_source_ && data_source_->IsStreaming()) |
| 666 return WebMediaPlayer::MovieLoadTypeLiveStream; | 678 return WebMediaPlayer::MovieLoadTypeLiveStream; |
| 667 return WebMediaPlayer::MovieLoadTypeUnknown; | 679 return WebMediaPlayer::MovieLoadTypeUnknown; |
| 668 } | 680 } |
| 669 | 681 |
| 670 float WebMediaPlayerImpl::mediaTimeForTimeValueFloat(float timeValue) const { | 682 float WebMediaPlayerImpl::mediaTimeForTimeValueFloat(float timeValue) const { |
| 671 return mediaTimeForTimeValue(timeValue); | 683 return mediaTimeForTimeValue(timeValue); |
| 672 } | 684 } |
| 673 | 685 |
| 674 float WebMediaPlayerImpl::mediaTimeForTimeValue(float timeValue) const { | 686 double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const { |
| 675 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); | 687 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); |
| 676 } | 688 } |
| 677 | 689 |
| 678 unsigned WebMediaPlayerImpl::decodedFrameCount() const { | 690 unsigned WebMediaPlayerImpl::decodedFrameCount() const { |
| 679 DCHECK(main_loop_->BelongsToCurrentThread()); | 691 DCHECK(main_loop_->BelongsToCurrentThread()); |
| 680 | 692 |
| 681 media::PipelineStatistics stats = pipeline_->GetStatistics(); | 693 media::PipelineStatistics stats = pipeline_->GetStatistics(); |
| 682 return stats.video_frames_decoded; | 694 return stats.video_frames_decoded; |
| 683 } | 695 } |
| 684 | 696 |
| (...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1270 | 1282 |
| 1271 if (pending_repaint_) | 1283 if (pending_repaint_) |
| 1272 return; | 1284 return; |
| 1273 | 1285 |
| 1274 pending_repaint_ = true; | 1286 pending_repaint_ = true; |
| 1275 main_loop_->PostTask(FROM_HERE, base::Bind( | 1287 main_loop_->PostTask(FROM_HERE, base::Bind( |
| 1276 &WebMediaPlayerImpl::Repaint, AsWeakPtr())); | 1288 &WebMediaPlayerImpl::Repaint, AsWeakPtr())); |
| 1277 } | 1289 } |
| 1278 | 1290 |
| 1279 } // namespace webkit_media | 1291 } // namespace webkit_media |
| OLD | NEW |