Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: media/blink/webmediaplayer_impl.cc

Issue 2160963002: Add watch time metrics for HTML5 media playback. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments, couple more tests. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 19 matching lines...) Expand all
30 #include "media/audio/null_audio_sink.h" 30 #include "media/audio/null_audio_sink.h"
31 #include "media/base/bind_to_current_loop.h" 31 #include "media/base/bind_to_current_loop.h"
32 #include "media/base/cdm_context.h" 32 #include "media/base/cdm_context.h"
33 #include "media/base/limits.h" 33 #include "media/base/limits.h"
34 #include "media/base/media_log.h" 34 #include "media/base/media_log.h"
35 #include "media/base/media_switches.h" 35 #include "media/base/media_switches.h"
36 #include "media/base/text_renderer.h" 36 #include "media/base/text_renderer.h"
37 #include "media/base/timestamp_constants.h" 37 #include "media/base/timestamp_constants.h"
38 #include "media/base/video_frame.h" 38 #include "media/base/video_frame.h"
39 #include "media/blink/texttrack_impl.h" 39 #include "media/blink/texttrack_impl.h"
40 #include "media/blink/watch_time_reporter.h"
40 #include "media/blink/webaudiosourceprovider_impl.h" 41 #include "media/blink/webaudiosourceprovider_impl.h"
41 #include "media/blink/webcontentdecryptionmodule_impl.h" 42 #include "media/blink/webcontentdecryptionmodule_impl.h"
42 #include "media/blink/webinbandtexttrack_impl.h" 43 #include "media/blink/webinbandtexttrack_impl.h"
43 #include "media/blink/webmediaplayer_delegate.h" 44 #include "media/blink/webmediaplayer_delegate.h"
44 #include "media/blink/webmediaplayer_util.h" 45 #include "media/blink/webmediaplayer_util.h"
45 #include "media/blink/webmediasource_impl.h" 46 #include "media/blink/webmediasource_impl.h"
46 #include "media/filters/chunk_demuxer.h" 47 #include "media/filters/chunk_demuxer.h"
47 #include "media/filters/ffmpeg_demuxer.h" 48 #include "media/filters/ffmpeg_demuxer.h"
48 #include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h" 49 #include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
49 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" 50 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result); 123 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result);
123 return result; 124 return result;
124 } 125 }
125 126
126 gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) { 127 gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
127 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270) 128 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
128 return gfx::Size(natural_size.height(), natural_size.width()); 129 return gfx::Size(natural_size.height(), natural_size.width());
129 return natural_size; 130 return natural_size;
130 } 131 }
131 132
133 base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) {
134 // We wrap currentTime() instead of using pipeline_.GetMediaTime() since there
135 // are a variety of cases in which that time is not accurate; e.g., while
136 // remoting and during a pause or seek.
137 return base::TimeDelta::FromSecondsD(p_this->currentTime());
138 }
139
132 } // namespace 140 } // namespace
133 141
134 class BufferedDataSourceHostImpl; 142 class BufferedDataSourceHostImpl;
135 143
136 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, 144 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified,
137 UrlData::CORS_UNSPECIFIED); 145 UrlData::CORS_UNSPECIFIED);
138 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); 146 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS);
139 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, 147 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials,
140 UrlData::CORS_USE_CREDENTIALS); 148 UrlData::CORS_USE_CREDENTIALS);
141 149
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 is_cdm_attached_(false), 214 is_cdm_attached_(false),
207 #if defined(OS_ANDROID) // WMPI_CAST 215 #if defined(OS_ANDROID) // WMPI_CAST
208 cast_impl_(this, client_, params.context_3d_cb()), 216 cast_impl_(this, client_, params.context_3d_cb()),
209 #endif 217 #endif
210 volume_(1.0), 218 volume_(1.0),
211 volume_multiplier_(1.0), 219 volume_multiplier_(1.0),
212 renderer_factory_(std::move(renderer_factory)), 220 renderer_factory_(std::move(renderer_factory)),
213 surface_manager_(params.surface_manager()), 221 surface_manager_(params.surface_manager()),
214 overlay_surface_id_(SurfaceManager::kNoSurfaceID), 222 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
215 suppress_destruction_errors_(false), 223 suppress_destruction_errors_(false),
216 can_suspend_state_(CanSuspendState::UNKNOWN) { 224 can_suspend_state_(CanSuspendState::UNKNOWN),
225 is_encrypted_(false) {
217 DCHECK(!adjust_allocated_memory_cb_.is_null()); 226 DCHECK(!adjust_allocated_memory_cb_.is_null());
218 DCHECK(renderer_factory_); 227 DCHECK(renderer_factory_);
219 DCHECK(client_); 228 DCHECK(client_);
220 229
221 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch( 230 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kForceVideoOverlays); 231 switches::kForceVideoOverlays);
223 232
224 if (delegate_) 233 if (delegate_)
225 delegate_id_ = delegate_->AddObserver(this); 234 delegate_id_ = delegate_->AddObserver(this);
226 235
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 } 396 }
388 #endif 397 #endif
389 398
390 paused_ = false; 399 paused_ = false;
391 is_idle_ = false; 400 is_idle_ = false;
392 pipeline_.SetPlaybackRate(playback_rate_); 401 pipeline_.SetPlaybackRate(playback_rate_);
393 402
394 if (data_source_) 403 if (data_source_)
395 data_source_->MediaIsPlaying(); 404 data_source_->MediaIsPlaying();
396 405
406 watch_time_reporter_->OnPlaying();
397 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); 407 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
398 UpdatePlayState(); 408 UpdatePlayState();
399 } 409 }
400 410
401 void WebMediaPlayerImpl::pause() { 411 void WebMediaPlayerImpl::pause() {
402 DVLOG(1) << __func__; 412 DVLOG(1) << __func__;
403 DCHECK(main_task_runner_->BelongsToCurrentThread()); 413 DCHECK(main_task_runner_->BelongsToCurrentThread());
404 414
405 // We update the paused state even when casting, since we expect pause() to be 415 // We update the paused state even when casting, since we expect pause() to be
406 // called when casting begins, and when we exit casting we should end up in a 416 // called when casting begins, and when we exit casting we should end up in a
407 // paused state. 417 // paused state.
408 paused_ = true; 418 paused_ = true;
409 419
410 #if defined(OS_ANDROID) // WMPI_CAST 420 #if defined(OS_ANDROID) // WMPI_CAST
411 if (isRemote()) { 421 if (isRemote()) {
412 cast_impl_.pause(); 422 cast_impl_.pause();
413 return; 423 return;
414 } 424 }
415 #endif 425 #endif
416 426
417 pipeline_.SetPlaybackRate(0.0); 427 pipeline_.SetPlaybackRate(0.0);
418 428
419 // pause() may be called after playback has ended and the HTMLMediaElement 429 // pause() may be called after playback has ended and the HTMLMediaElement
420 // requires that currentTime() == duration() after ending. We want to ensure 430 // requires that currentTime() == duration() after ending. We want to ensure
421 // |paused_time_| matches currentTime() in this case or a future seek() may 431 // |paused_time_| matches currentTime() in this case or a future seek() may
422 // incorrectly discard what it thinks is a seek to the existing time. 432 // incorrectly discard what it thinks is a seek to the existing time.
423 paused_time_ = 433 paused_time_ =
424 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); 434 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
425 435
436 watch_time_reporter_->OnPaused();
426 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); 437 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
427 UpdatePlayState(); 438 UpdatePlayState();
428 } 439 }
429 440
430 bool WebMediaPlayerImpl::supportsSave() const { 441 bool WebMediaPlayerImpl::supportsSave() const {
431 DCHECK(main_task_runner_->BelongsToCurrentThread()); 442 DCHECK(main_task_runner_->BelongsToCurrentThread());
432 return supports_save_; 443 return supports_save_;
433 } 444 }
434 445
435 void WebMediaPlayerImpl::seek(double seconds) { 446 void WebMediaPlayerImpl::seek(double seconds) {
(...skipping 30 matching lines...) Expand all
466 // completed just by restoring it. Otherwise we will just wait for the real 477 // completed just by restoring it. Otherwise we will just wait for the real
467 // ready state change to eventually happen. 478 // ready state change to eventually happen.
468 if (old_state == ReadyStateHaveEnoughData) { 479 if (old_state == ReadyStateHaveEnoughData) {
469 main_task_runner_->PostTask( 480 main_task_runner_->PostTask(
470 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange, 481 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
471 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); 482 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
472 } 483 }
473 return; 484 return;
474 } 485 }
475 486
487 // Call this before setting |seeking_| so that the current media time can be
488 // recorded by the reporter.
489 watch_time_reporter_->OnSeeking(time);
sandersd (OOO until July 31) 2016/08/04 23:06:26 Since the actual seek time may differ from the req
DaleCurtis 2016/08/08 23:16:42 Reworked to avoid needing seek time and just call
490
476 // TODO(sandersd): Ideally we would not clear the idle state if 491 // TODO(sandersd): Ideally we would not clear the idle state if
477 // |pipeline_controller_| can elide the seek. 492 // |pipeline_controller_| can elide the seek.
478 is_idle_ = false; 493 is_idle_ = false;
479 ended_ = false; 494 ended_ = false;
480 495
481 seeking_ = true; 496 seeking_ = true;
482 seek_time_ = time; 497 seek_time_ = time;
483 if (paused_) 498 if (paused_)
484 paused_time_ = time; 499 paused_time_ = time;
485 pipeline_controller_.Seek(time, time_updated); 500 pipeline_controller_.Seek(time, time_updated);
(...skipping 26 matching lines...) Expand all
512 if (data_source_) 527 if (data_source_)
513 data_source_->MediaPlaybackRateChanged(rate); 528 data_source_->MediaPlaybackRateChanged(rate);
514 } 529 }
515 } 530 }
516 531
517 void WebMediaPlayerImpl::setVolume(double volume) { 532 void WebMediaPlayerImpl::setVolume(double volume) {
518 DVLOG(1) << __func__ << "(" << volume << ")"; 533 DVLOG(1) << __func__ << "(" << volume << ")";
519 DCHECK(main_task_runner_->BelongsToCurrentThread()); 534 DCHECK(main_task_runner_->BelongsToCurrentThread());
520 volume_ = volume; 535 volume_ = volume;
521 pipeline_.SetVolume(volume_ * volume_multiplier_); 536 pipeline_.SetVolume(volume_ * volume_multiplier_);
537 if (watch_time_reporter_)
538 watch_time_reporter_->OnVolumeChange(volume);
522 } 539 }
523 540
524 void WebMediaPlayerImpl::setSinkId( 541 void WebMediaPlayerImpl::setSinkId(
525 const blink::WebString& sink_id, 542 const blink::WebString& sink_id,
526 const blink::WebSecurityOrigin& security_origin, 543 const blink::WebSecurityOrigin& security_origin,
527 blink::WebSetSinkIdCallbacks* web_callback) { 544 blink::WebSetSinkIdCallbacks* web_callback) {
528 DCHECK(main_task_runner_->BelongsToCurrentThread()); 545 DCHECK(main_task_runner_->BelongsToCurrentThread());
529 DVLOG(1) << __func__; 546 DVLOG(1) << __func__;
530 547
531 media::OutputDeviceStatusCB callback = 548 media::OutputDeviceStatusCB callback =
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
864 } 881 }
865 882
866 void WebMediaPlayerImpl::OnEncryptedMediaInitData( 883 void WebMediaPlayerImpl::OnEncryptedMediaInitData(
867 EmeInitDataType init_data_type, 884 EmeInitDataType init_data_type,
868 const std::vector<uint8_t>& init_data) { 885 const std::vector<uint8_t>& init_data) {
869 DCHECK(init_data_type != EmeInitDataType::UNKNOWN); 886 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
870 887
871 // TODO(xhwang): Update this UMA name. https://crbug.com/589251 888 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
872 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1); 889 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
873 890
891 is_encrypted_ = true;
874 encrypted_client_->encrypted( 892 encrypted_client_->encrypted(
875 ConvertToWebInitDataType(init_data_type), init_data.data(), 893 ConvertToWebInitDataType(init_data_type), init_data.data(),
876 base::saturated_cast<unsigned int>(init_data.size())); 894 base::saturated_cast<unsigned int>(init_data.size()));
877 } 895 }
878 896
879 void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated( 897 void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
880 std::unique_ptr<MediaTracks> tracks) { 898 std::unique_ptr<MediaTracks> tracks) {
881 // For MSE/chunk_demuxer case the media track updates are handled by 899 // For MSE/chunk_demuxer case the media track updates are handled by
882 // WebSourceBufferImpl. 900 // WebSourceBufferImpl.
883 DCHECK(demuxer_.get()); 901 DCHECK(demuxer_.get());
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 // expected to be a no-op. 1034 // expected to be a no-op.
1017 UpdatePlayState(); 1035 UpdatePlayState();
1018 } 1036 }
1019 1037
1020 void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) { 1038 void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
1021 DVLOG(1) << __func__; 1039 DVLOG(1) << __func__;
1022 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1040 DCHECK(main_task_runner_->BelongsToCurrentThread());
1023 1041
1024 pipeline_metadata_ = metadata; 1042 pipeline_metadata_ = metadata;
1025 1043
1044 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
1026 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation, 1045 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
1027 VIDEO_ROTATION_MAX + 1); 1046 VIDEO_ROTATION_MAX + 1);
1028 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
1029 1047
1030 if (hasVideo()) { 1048 if (hasVideo()) {
1031 pipeline_metadata_.natural_size = GetRotatedVideoSize( 1049 pipeline_metadata_.natural_size = GetRotatedVideoSize(
1032 pipeline_metadata_.video_rotation, pipeline_metadata_.natural_size); 1050 pipeline_metadata_.video_rotation, pipeline_metadata_.natural_size);
1033 1051
1034 if (overlay_enabled_ && surface_manager_) 1052 if (overlay_enabled_ && surface_manager_)
1035 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size); 1053 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1036 1054
1037 DCHECK(!video_weblayer_); 1055 DCHECK(!video_weblayer_);
1038 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create( 1056 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1039 compositor_, pipeline_metadata_.video_rotation))); 1057 compositor_, pipeline_metadata_.video_rotation)));
1040 video_weblayer_->layer()->SetContentsOpaque(opaque_); 1058 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1041 video_weblayer_->SetContentsOpaqueIsFixed(true); 1059 video_weblayer_->SetContentsOpaqueIsFixed(true);
1042 client_->setWebLayer(video_weblayer_.get()); 1060 client_->setWebLayer(video_weblayer_.get());
1043 } 1061 }
1044 1062
1063 // Create the watch time reporter and synchronize its initial state.
1064 watch_time_reporter_.reset(
1065 new WatchTimeReporter(hasAudio(), hasVideo(), !!chunk_demuxer_,
1066 is_encrypted_, pipeline_metadata_.natural_size,
1067 base::Bind(&GetCurrentTimeInternal, this)));
1068 watch_time_reporter_->OnVolumeChange(volume_);
1069 if (delegate_ && delegate_->IsHidden())
1070 watch_time_reporter_->OnHidden();
1071 else
1072 watch_time_reporter_->OnShown();
1073
1045 UpdatePlayState(); 1074 UpdatePlayState();
1046 } 1075 }
1047 1076
1048 void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) { 1077 void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1049 DVLOG(1) << __func__ << "(" << state << ")"; 1078 DVLOG(1) << __func__ << "(" << state << ")";
1050 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1079 DCHECK(main_task_runner_->BelongsToCurrentThread());
1051 1080
1052 // Ignore buffering state changes until we've completed all outstanding 1081 // Ignore buffering state changes until we've completed all outstanding
1053 // operations. 1082 // operations.
1054 if (!pipeline_controller_.IsStable()) 1083 if (!pipeline_controller_.IsStable())
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 1182
1154 opaque_ = opaque; 1183 opaque_ = opaque;
1155 // Modify content opaqueness of cc::Layer directly so that 1184 // Modify content opaqueness of cc::Layer directly so that
1156 // SetContentsOpaqueIsFixed is ignored. 1185 // SetContentsOpaqueIsFixed is ignored.
1157 if (video_weblayer_) 1186 if (video_weblayer_)
1158 video_weblayer_->layer()->SetContentsOpaque(opaque_); 1187 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1159 } 1188 }
1160 1189
1161 void WebMediaPlayerImpl::OnHidden() { 1190 void WebMediaPlayerImpl::OnHidden() {
1162 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1191 DCHECK(main_task_runner_->BelongsToCurrentThread());
1192 if (watch_time_reporter_)
1193 watch_time_reporter_->OnHidden();
1194
1163 UpdatePlayState(); 1195 UpdatePlayState();
1164 1196
1165 // Schedule suspended playing media to be paused if the user doesn't come back 1197 // Schedule suspended playing media to be paused if the user doesn't come back
1166 // to it within some timeout period to avoid any autoplay surprises. 1198 // to it within some timeout period to avoid any autoplay surprises.
1167 ScheduleIdlePauseTimer(); 1199 ScheduleIdlePauseTimer();
1168 } 1200 }
1169 1201
1170 void WebMediaPlayerImpl::OnShown() { 1202 void WebMediaPlayerImpl::OnShown() {
1171 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1203 DCHECK(main_task_runner_->BelongsToCurrentThread());
1204 if (watch_time_reporter_)
1205 watch_time_reporter_->OnShown();
1206
1172 must_suspend_ = false; 1207 must_suspend_ = false;
1173 background_pause_timer_.Stop(); 1208 background_pause_timer_.Stop();
1174 UpdatePlayState(); 1209 UpdatePlayState();
1175 } 1210 }
1176 1211
1177 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { 1212 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
1178 DCHECK(main_task_runner_->BelongsToCurrentThread()); 1213 DCHECK(main_task_runner_->BelongsToCurrentThread());
1179 1214
1180 if (must_suspend) { 1215 if (must_suspend) {
1181 must_suspend_ = true; 1216 must_suspend_ = true;
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
1726 if (isRemote()) 1761 if (isRemote())
1727 return; 1762 return;
1728 #endif 1763 #endif
1729 1764
1730 // Idle timeout chosen arbitrarily. 1765 // Idle timeout chosen arbitrarily.
1731 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), 1766 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
1732 this, &WebMediaPlayerImpl::OnPause); 1767 this, &WebMediaPlayerImpl::OnPause);
1733 } 1768 }
1734 1769
1735 } // namespace media 1770 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698