OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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/blink/webmediaplayer_impl.h" | 5 #include "media/blink/webmediaplayer_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <limits> | 9 #include <limits> |
10 #include <string> | 10 #include <string> |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 media_task_runner_(params.media_task_runner()), | 193 media_task_runner_(params.media_task_runner()), |
194 worker_task_runner_(params.worker_task_runner()), | 194 worker_task_runner_(params.worker_task_runner()), |
195 media_log_(params.media_log()), | 195 media_log_(params.media_log()), |
196 pipeline_(media_task_runner_, media_log_.get()), | 196 pipeline_(media_task_runner_, media_log_.get()), |
197 pipeline_controller_( | 197 pipeline_controller_( |
198 &pipeline_, | 198 &pipeline_, |
199 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | 199 base::Bind(&WebMediaPlayerImpl::CreateRenderer, |
200 base::Unretained(this)), | 200 base::Unretained(this)), |
201 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), | 201 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), |
202 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), | 202 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), |
203 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()), | |
204 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()), | |
203 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())), | 205 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())), |
204 load_type_(LoadTypeURL), | 206 load_type_(LoadTypeURL), |
205 opaque_(false), | 207 opaque_(false), |
206 playback_rate_(0.0), | 208 playback_rate_(0.0), |
207 paused_(true), | 209 paused_(true), |
208 paused_when_hidden_(false), | 210 paused_when_hidden_(false), |
209 seeking_(false), | 211 seeking_(false), |
210 pending_suspend_resume_cycle_(false), | 212 pending_suspend_resume_cycle_(false), |
211 ended_(false), | 213 ended_(false), |
212 should_notify_time_changed_(false), | 214 should_notify_time_changed_(false), |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 // incorrectly discard what it thinks is a seek to the existing time. | 469 // incorrectly discard what it thinks is a seek to the existing time. |
468 paused_time_ = | 470 paused_time_ = |
469 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | 471 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); |
470 | 472 |
471 if (observer_) | 473 if (observer_) |
472 observer_->OnPaused(); | 474 observer_->OnPaused(); |
473 | 475 |
474 DCHECK(watch_time_reporter_); | 476 DCHECK(watch_time_reporter_); |
475 watch_time_reporter_->OnPaused(); | 477 watch_time_reporter_->OnPaused(); |
476 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 478 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
479 | |
477 UpdatePlayState(); | 480 UpdatePlayState(); |
478 } | 481 } |
479 | 482 |
480 bool WebMediaPlayerImpl::supportsSave() const { | 483 bool WebMediaPlayerImpl::supportsSave() const { |
481 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 484 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
482 return supports_save_; | 485 return supports_save_; |
483 } | 486 } |
484 | 487 |
485 void WebMediaPlayerImpl::seek(double seconds) { | 488 void WebMediaPlayerImpl::seek(double seconds) { |
486 DVLOG(1) << __func__ << "(" << seconds << "s)"; | 489 DVLOG(1) << __func__ << "(" << seconds << "s)"; |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
664 << "]"; | 667 << "]"; |
665 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds); | 668 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds); |
666 } | 669 } |
667 | 670 |
668 void WebMediaPlayerImpl::selectedVideoTrackChanged( | 671 void WebMediaPlayerImpl::selectedVideoTrackChanged( |
669 blink::WebMediaPlayer::TrackId* selectedTrackId) { | 672 blink::WebMediaPlayer::TrackId* selectedTrackId) { |
670 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 673 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
671 | 674 |
672 std::ostringstream logstr; | 675 std::ostringstream logstr; |
673 std::vector<MediaTrack::Id> selectedVideoMediaTrackId; | 676 std::vector<MediaTrack::Id> selectedVideoMediaTrackId; |
674 bool canAddVideoTrack = | 677 if (selectedTrackId && !video_track_disabled_) { |
675 !IsBackgroundVideoTrackOptimizationEnabled() || !IsHidden(); | |
676 if (selectedTrackId && canAddVideoTrack) { | |
677 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data()); | 678 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data()); |
678 logstr << selectedVideoMediaTrackId[0]; | 679 logstr << selectedVideoMediaTrackId[0]; |
679 } | 680 } |
680 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str() | 681 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str() |
681 << "]"; | 682 << "]"; |
682 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId); | 683 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId); |
683 } | 684 } |
684 | 685 |
685 blink::WebSize WebMediaPlayerImpl::naturalSize() const { | 686 blink::WebSize WebMediaPlayerImpl::naturalSize() const { |
686 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 687 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1057 set_cdm_result_->completeWithError( | 1058 set_cdm_result_->completeWithError( |
1058 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 1059 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
1059 "Unable to set ContentDecryptionModule object"); | 1060 "Unable to set ContentDecryptionModule object"); |
1060 set_cdm_result_.reset(); | 1061 set_cdm_result_.reset(); |
1061 } | 1062 } |
1062 } | 1063 } |
1063 | 1064 |
1064 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { | 1065 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
1065 seeking_ = false; | 1066 seeking_ = false; |
1066 seek_time_ = base::TimeDelta(); | 1067 seek_time_ = base::TimeDelta(); |
1068 | |
1067 if (paused_) { | 1069 if (paused_) { |
1068 #if defined(OS_ANDROID) // WMPI_CAST | 1070 #if defined(OS_ANDROID) // WMPI_CAST |
1069 if (isRemote()) { | 1071 if (isRemote()) { |
1070 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime()); | 1072 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime()); |
1071 } else { | 1073 } else { |
1072 paused_time_ = pipeline_.GetMediaTime(); | 1074 paused_time_ = pipeline_.GetMediaTime(); |
1073 } | 1075 } |
1074 #else | 1076 #else |
1075 paused_time_ = pipeline_.GetMediaTime(); | 1077 paused_time_ = pipeline_.GetMediaTime(); |
1076 #endif | 1078 #endif |
1077 } else { | 1079 } else { |
1078 DCHECK(watch_time_reporter_); | 1080 DCHECK(watch_time_reporter_); |
1079 watch_time_reporter_->OnPlaying(); | 1081 watch_time_reporter_->OnPlaying(); |
1080 } | 1082 } |
1081 if (time_updated) | 1083 if (time_updated) |
1082 should_notify_time_changed_ = true; | 1084 should_notify_time_changed_ = true; |
1083 | 1085 |
1084 // Reset underflow count upon seek; this prevents looping videos and user | 1086 // Reset underflow count upon seek; this prevents looping videos and user |
1085 // actions from artificially inflating the underflow count. | 1087 // actions from artificially inflating the underflow count. |
1086 underflow_count_ = 0; | 1088 underflow_count_ = 0; |
1089 | |
1090 // Apply optimizations for the hidden videos if hidden. | |
1091 if (IsHidden()) | |
1092 OnHidden(); | |
sandersd (OOO until July 31)
2017/01/10 21:34:37
OnHidden() does a bit more than what is requested,
whywhat
2017/01/11 19:41:30
I think that's the point of it, no? We initialize
sandersd (OOO until July 31)
2017/01/11 21:54:51
The target state for this code is that OnHidden()
| |
1087 } | 1093 } |
1088 | 1094 |
1089 void WebMediaPlayerImpl::OnPipelineSuspended() { | 1095 void WebMediaPlayerImpl::OnPipelineSuspended() { |
1090 #if defined(OS_ANDROID) | 1096 #if defined(OS_ANDROID) |
1091 if (isRemote()) { | 1097 if (isRemote()) { |
1092 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1098 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
1093 if (frame) | 1099 if (frame) |
1094 compositor_->PaintSingleFrame(frame); | 1100 compositor_->PaintSingleFrame(frame); |
1095 } | 1101 } |
1096 #endif | 1102 #endif |
1097 | 1103 |
1098 // If we're not in an aggressive buffering state, tell the data source we have | 1104 // If we're not in an aggressive buffering state, tell the data source we have |
1099 // enough data so that it may release the connection. | 1105 // enough data so that it may release the connection. |
1100 if (buffering_strategy_ != | 1106 if (buffering_strategy_ != |
1101 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { | 1107 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { |
1102 if (data_source_) | 1108 if (data_source_) |
1103 data_source_->OnBufferingHaveEnough(true); | 1109 data_source_->OnBufferingHaveEnough(true); |
1104 } | 1110 } |
1105 | 1111 |
1106 ReportMemoryUsage(); | 1112 ReportMemoryUsage(); |
1107 | 1113 |
1108 if (pending_suspend_resume_cycle_) { | 1114 if (pending_suspend_resume_cycle_) { |
1109 pending_suspend_resume_cycle_ = false; | 1115 pending_suspend_resume_cycle_ = false; |
1110 UpdatePlayState(); | 1116 UpdatePlayState(); |
1111 } | 1117 } |
1112 } | 1118 } |
1113 | 1119 |
1120 void WebMediaPlayerImpl::OnBeforePipelineResume() { | |
1121 // Enable video track if we disabled it in the background - this way the new | |
1122 // renderer will attach its callbacks to the video stream properly. | |
1123 // TODO(avayvod): Remove this when disabling and enabling video tracks in | |
1124 // non-playing state works correctly. See https://crbug.com/678374. | |
1125 EnableVideoTrackIfNeeded(); | |
1126 is_pipeline_resuming_ = true; | |
1127 } | |
1128 | |
1129 void WebMediaPlayerImpl::OnPipelineResumed() { | |
1130 is_pipeline_resuming_ = false; | |
1131 | |
1132 if (IsHidden()) { | |
1133 DisableVideoTrackIfNeeded(); | |
1134 return; | |
sandersd (OOO until July 31)
2017/01/10 21:34:37
Nit: This may be a case where early return is more
whywhat
2017/01/11 19:41:30
Done. For some reason, I expect lint to complain t
| |
1135 } | |
1136 | |
1137 EnableVideoTrackIfNeeded(); | |
1138 } | |
1139 | |
1114 void WebMediaPlayerImpl::OnDemuxerOpened() { | 1140 void WebMediaPlayerImpl::OnDemuxerOpened() { |
1115 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1141 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1116 client_->mediaSourceOpened( | 1142 client_->mediaSourceOpened( |
1117 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); | 1143 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); |
1118 } | 1144 } |
1119 | 1145 |
1120 void WebMediaPlayerImpl::OnError(PipelineStatus status) { | 1146 void WebMediaPlayerImpl::OnError(PipelineStatus status) { |
1121 DVLOG(1) << __func__; | 1147 DVLOG(1) << __func__; |
1122 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1148 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1123 DCHECK_NE(status, PIPELINE_OK); | 1149 DCHECK_NE(status, PIPELINE_OK); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1346 if (video_weblayer_) | 1372 if (video_weblayer_) |
1347 video_weblayer_->layer()->SetContentsOpaque(opaque_); | 1373 video_weblayer_->layer()->SetContentsOpaque(opaque_); |
1348 } | 1374 } |
1349 | 1375 |
1350 void WebMediaPlayerImpl::OnHidden() { | 1376 void WebMediaPlayerImpl::OnHidden() { |
1351 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1377 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1352 | 1378 |
1353 if (watch_time_reporter_) | 1379 if (watch_time_reporter_) |
1354 watch_time_reporter_->OnHidden(); | 1380 watch_time_reporter_->OnHidden(); |
1355 | 1381 |
1356 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) { | 1382 if (!paused_when_hidden_ && ShouldPauseWhenHidden()) { |
sandersd (OOO until July 31)
2017/01/10 21:34:37
As a matter of style, I prefer idempotency whereve
whywhat
2017/01/11 19:41:30
I think it won't because ShouldPauseWhenHidden and
| |
1357 if (ShouldPauseWhenHidden()) { | 1383 // OnPause() will set |paused_when_hidden_| to false and call |
1358 // OnPause() will set |paused_when_hidden_| to false and call | 1384 // UpdatePlayState(), so set the flag to true after and then return. |
1359 // UpdatePlayState(), so set the flag to true after and then return. | 1385 OnPause(); |
1360 OnPause(); | 1386 paused_when_hidden_ = true; |
1361 paused_when_hidden_ = true; | 1387 return; |
1362 return; | 1388 } |
1363 } | |
1364 | 1389 |
1365 selectedVideoTrackChanged(nullptr); | 1390 DisableVideoTrackIfNeeded(); |
1366 } | |
1367 | 1391 |
1368 UpdatePlayState(); | 1392 UpdatePlayState(); |
1369 | 1393 |
1370 // Schedule suspended playing media to be paused if the user doesn't come back | 1394 // Schedule suspended playing media to be paused if the user doesn't come back |
1371 // to it within some timeout period to avoid any autoplay surprises. | 1395 // to it within some timeout period to avoid any autoplay surprises. |
1372 ScheduleIdlePauseTimer(); | 1396 ScheduleIdlePauseTimer(); |
1373 } | 1397 } |
1374 | 1398 |
1375 void WebMediaPlayerImpl::OnShown() { | 1399 void WebMediaPlayerImpl::OnShown() { |
1376 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1400 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1377 if (watch_time_reporter_) | 1401 if (watch_time_reporter_) |
1378 watch_time_reporter_->OnShown(); | 1402 watch_time_reporter_->OnShown(); |
1379 | 1403 |
1380 compositor_task_runner_->PostTask( | 1404 compositor_task_runner_->PostTask( |
1381 FROM_HERE, | 1405 FROM_HERE, |
1382 base::Bind(&VideoFrameCompositor::SetForegroundTime, | 1406 base::Bind(&VideoFrameCompositor::SetForegroundTime, |
1383 base::Unretained(compositor_), base::TimeTicks::Now())); | 1407 base::Unretained(compositor_), base::TimeTicks::Now())); |
1384 | 1408 |
1385 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) { | 1409 if (paused_when_hidden_) { |
sandersd (OOO until July 31)
2017/01/10 21:34:37
By the same reasoning, this should go right before
whywhat
2017/01/11 19:41:30
Moved the state update above the new logic.
I don
| |
1386 if (paused_when_hidden_) { | 1410 paused_when_hidden_ = false; |
1387 paused_when_hidden_ = false; | 1411 OnPlay(); // Calls UpdatePlayState() so return afterwards. |
1388 OnPlay(); // Calls UpdatePlayState() so return afterwards. | 1412 return; |
1389 return; | 1413 } |
1390 } | |
1391 | 1414 |
1392 if (client_->hasSelectedVideoTrack()) { | 1415 EnableVideoTrackIfNeeded(); |
1393 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); | |
1394 selectedVideoTrackChanged(&trackId); | |
1395 } | |
1396 } | |
1397 | 1416 |
1398 must_suspend_ = false; | 1417 must_suspend_ = false; |
1399 background_pause_timer_.Stop(); | 1418 background_pause_timer_.Stop(); |
1400 | 1419 |
1401 UpdatePlayState(); | 1420 UpdatePlayState(); |
1402 } | 1421 } |
1403 | 1422 |
1404 bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { | 1423 bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { |
1405 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1424 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1406 | 1425 |
(...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2073 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; | 2092 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; |
2074 } | 2093 } |
2075 | 2094 |
2076 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { | 2095 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { |
2077 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 2096 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
2078 | 2097 |
2079 client_->activateViewportIntersectionMonitoring(activate); | 2098 client_->activateViewportIntersectionMonitoring(activate); |
2080 } | 2099 } |
2081 | 2100 |
2082 bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const { | 2101 bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const { |
2102 DCHECK(IsHidden()); | |
2103 // Don't pause videos being Cast (Android only) or if the background video | |
2104 // optimizations are off (desktop only). | |
2083 #if defined(OS_ANDROID) // WMPI_CAST | 2105 #if defined(OS_ANDROID) // WMPI_CAST |
2084 if (isRemote()) | 2106 if (isRemote()) |
2085 return false; | 2107 return false; |
2086 #endif // defined(OS_ANDROID) // WMPI_CAST | 2108 #else // defined(OS_ANDROID) |
2109 if (!IsBackgroundVideoTrackOptimizationEnabled()) | |
2110 return false; | |
2111 #endif // defined(OS_ANDROID) | |
2087 | 2112 |
2088 return hasVideo() && !hasAudio(); | 2113 return hasVideo() && !hasAudio(); |
sandersd (OOO until July 31)
2017/01/10 21:34:37
Probably worth a comment somewhere: these conditio
whywhat
2017/01/11 19:41:30
Should I make an even stronger comment that they w
sandersd (OOO until July 31)
2017/01/11 21:54:51
OnMetadata is called after demuxer initialization,
| |
2089 } | 2114 } |
2090 | 2115 |
2116 bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const { | |
2117 DCHECK(IsHidden()); | |
2118 return IsBackgroundVideoTrackOptimizationEnabled() && hasVideo() && | |
2119 hasAudio() && !IsStreaming(); | |
2120 } | |
2121 | |
2122 void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() { | |
2123 DCHECK(!IsHidden()); | |
2124 | |
2125 // Don't change video track while the pipeline is resuming or seeking. | |
2126 if (is_pipeline_resuming_ || seeking_) | |
2127 return; | |
2128 | |
2129 if (video_track_disabled_) { | |
2130 video_track_disabled_ = false; | |
2131 if (client_->hasSelectedVideoTrack()) { | |
2132 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); | |
2133 selectedVideoTrackChanged(&trackId); | |
2134 } | |
2135 } | |
2136 } | |
2137 | |
2138 void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() { | |
2139 DCHECK(IsHidden()); | |
2140 | |
2141 // Don't change video track while the pipeline is resuming or seeking. | |
2142 if (is_pipeline_resuming_ || seeking_) | |
2143 return; | |
2144 | |
2145 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) { | |
2146 video_track_disabled_ = true; | |
2147 selectedVideoTrackChanged(nullptr); | |
2148 } | |
2149 } | |
2150 | |
2091 } // namespace media | 2151 } // namespace media |
OLD | NEW |