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

Side by Side Diff: content/browser/renderer_host/media/web_contents_video_capture_device.cc

Issue 11565052: Log statistics of TabCapture API through UMA (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: view size Created 8 years 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Implementation notes: This needs to work on a variety of hardware 5 // Implementation notes: This needs to work on a variety of hardware
6 // configurations where the speed of the CPU and GPU greatly affect overall 6 // configurations where the speed of the CPU and GPU greatly affect overall
7 // performance. Therefore, the process of capturing has been split up into a 7 // performance. Therefore, the process of capturing has been split up into a
8 // pipeline of three stages. Each stage executes on its own thread: 8 // pipeline of three stages. Each stage executes on its own thread:
9 // 9 //
10 // 1. Capture: A bitmap is snapshotted/copied from the RenderView's backing 10 // 1. Capture: A bitmap is snapshotted/copied from the RenderView's backing
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 #include <algorithm> 43 #include <algorithm>
44 #include <string> 44 #include <string>
45 45
46 #include "base/basictypes.h" 46 #include "base/basictypes.h"
47 #include "base/bind.h" 47 #include "base/bind.h"
48 #include "base/bind_helpers.h" 48 #include "base/bind_helpers.h"
49 #include "base/callback_forward.h" 49 #include "base/callback_forward.h"
50 #include "base/debug/trace_event.h" 50 #include "base/debug/trace_event.h"
51 #include "base/logging.h" 51 #include "base/logging.h"
52 #include "base/memory/scoped_ptr.h" 52 #include "base/memory/scoped_ptr.h"
53 #include "base/metrics/histogram.h"
53 #include "base/stringprintf.h" 54 #include "base/stringprintf.h"
54 #include "base/synchronization/lock.h" 55 #include "base/synchronization/lock.h"
55 #include "base/threading/thread.h" 56 #include "base/threading/thread.h"
56 #include "base/time.h" 57 #include "base/time.h"
57 #include "content/browser/renderer_host/media/web_contents_capture_util.h" 58 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
58 #include "content/public/browser/browser_thread.h" 59 #include "content/public/browser/browser_thread.h"
59 #include "content/public/browser/render_process_host.h" 60 #include "content/public/browser/render_process_host.h"
60 #include "content/public/browser/render_view_host.h" 61 #include "content/public/browser/render_view_host.h"
61 #include "content/public/browser/render_widget_host_view.h" 62 #include "content/public/browser/render_widget_host_view.h"
62 #include "content/public/browser/web_contents.h" 63 #include "content/public/browser/web_contents.h"
(...skipping 22 matching lines...) Expand all
85 } \ 86 } \
86 } 87 }
87 88
88 namespace content { 89 namespace content {
89 90
90 namespace { 91 namespace {
91 92
92 const int kMinFrameWidth = 2; 93 const int kMinFrameWidth = 2;
93 const int kMinFrameHeight = 2; 94 const int kMinFrameHeight = 2;
94 95
96 // Report % of frame drop for the following frame interval. That accounts for
97 // about 5 minutes of frames.
98 const int kFrameDropReportInterval = 9000;
miu 2012/12/14 23:28:35 I think you can remove this (see comments below).
Alpha Left Google 2013/01/04 00:00:38 Done.
99
95 // Returns the nearest even integer closer to zero. 100 // Returns the nearest even integer closer to zero.
96 template<typename IntType> 101 template<typename IntType>
97 IntType MakeEven(IntType x) { 102 IntType MakeEven(IntType x) {
98 return x & static_cast<IntType>(-2); 103 return x & static_cast<IntType>(-2);
99 } 104 }
100 105
101 // Determine a |fitted_size| that would fit within a video frame with the same 106 // Determine a |fitted_size| that would fit within a video frame with the same
102 // aspect ratio as the given source_width/height. 107 // aspect ratio as the given source_width/height.
103 void CalculateFittedSize(int source_width, int source_height, 108 void CalculateFittedSize(int source_width, int source_height,
104 int frame_width, int frame_height, 109 int frame_width, int frame_height,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 void LookUpAndObserveWebContents(); 175 void LookUpAndObserveWebContents();
171 176
172 void CopyFromBackingStoreComplete(int frame_number, 177 void CopyFromBackingStoreComplete(int frame_number,
173 scoped_ptr<skia::PlatformBitmap> capture, 178 scoped_ptr<skia::PlatformBitmap> capture,
174 const DoneCB& done_cb, bool success); 179 const DoneCB& done_cb, bool success);
175 180
176 // The "starting point" to find the capture source. 181 // The "starting point" to find the capture source.
177 const int render_process_id_; 182 const int render_process_id_;
178 const int render_view_id_; 183 const int render_view_id_;
179 184
185 // Last known RenderView size.
186 gfx::Size last_view_size_;
187
180 // If the following is NULL (normal behavior), the implementation should 188 // If the following is NULL (normal behavior), the implementation should
181 // access RenderWidgetHost via web_contents(). 189 // access RenderWidgetHost via web_contents().
182 RenderWidgetHost* rwh_for_testing_; 190 RenderWidgetHost* rwh_for_testing_;
183 191
184 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); 192 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier);
185 }; 193 };
186 194
187 // Renders captures (from the backing store) into video frame buffers on a 195 // Renders captures (from the backing store) into video frame buffers on a
188 // separate thread. Manages use of internally-owned video frame buffers. 196 // separate thread. Manages use of internally-owned video frame buffers.
189 class VideoFrameRenderer { 197 class VideoFrameRenderer {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 const base::Time& frame_timestamp, 266 const base::Time& frame_timestamp,
259 const base::Closure& done_cb); 267 const base::Closure& done_cb);
260 268
261 base::Thread deliver_thread_; 269 base::Thread deliver_thread_;
262 SynchronizedConsumer* const consumer_; 270 SynchronizedConsumer* const consumer_;
263 271
264 // The following keep track of and log the effective frame rate (from the 272 // The following keep track of and log the effective frame rate (from the
265 // deliver stage) whenever verbose logging is turned on. 273 // deliver stage) whenever verbose logging is turned on.
266 base::Time last_frame_rate_log_time_; 274 base::Time last_frame_rate_log_time_;
267 int count_frames_rendered_; 275 int count_frames_rendered_;
276 int count_frames_missed_;
277 int last_frame_number_;
268 278
269 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); 279 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer);
270 }; 280 };
271 281
272 BackingStoreCopier::BackingStoreCopier(int render_process_id, 282 BackingStoreCopier::BackingStoreCopier(int render_process_id,
273 int render_view_id) 283 int render_view_id)
274 : render_process_id_(render_process_id), render_view_id_(render_view_id), 284 : render_process_id_(render_process_id), render_view_id_(render_view_id),
275 rwh_for_testing_(NULL) {} 285 rwh_for_testing_(NULL) {}
276 286
277 void BackingStoreCopier::LookUpAndObserveWebContents() { 287 void BackingStoreCopier::LookUpAndObserveWebContents() {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 } 342 }
333 343
334 gfx::Size fitted_size; 344 gfx::Size fitted_size;
335 if (RenderWidgetHostView* const view = rwh->GetView()) { 345 if (RenderWidgetHostView* const view = rwh->GetView()) {
336 const gfx::Size& view_size = view->GetViewBounds().size(); 346 const gfx::Size& view_size = view->GetViewBounds().size();
337 if (!view_size.IsEmpty()) { 347 if (!view_size.IsEmpty()) {
338 CalculateFittedSize(view_size.width(), view_size.height(), 348 CalculateFittedSize(view_size.width(), view_size.height(),
339 desired_width, desired_height, 349 desired_width, desired_height,
340 &fitted_size); 350 &fitted_size);
341 } 351 }
352 if (view_size != last_view_size_) {
353 last_view_size_ = view_size;
354
355 // Measure the number of kilopixels.
356 UMA_HISTOGRAM_COUNTS_10000(
357 "TabCapture.ViewKiloPixels",
miu 2012/12/14 23:28:35 Since a sample is only recorded when the size chan
Alpha Left Google 2013/01/04 00:00:38 Done.
358 view_size.width() * view_size.height() / 1024);
359 }
342 } 360 }
343 361
344 // TODO(miu): Look into tweaking the interface to CopyFromBackingStore, since 362 // TODO(miu): Look into tweaking the interface to CopyFromBackingStore, since
345 // it seems poor to have to allocate a new skia::PlatformBitmap as an output 363 // it seems poor to have to allocate a new skia::PlatformBitmap as an output
346 // buffer for each successive frame (rather than reuse buffers). Perhaps 364 // buffer for each successive frame (rather than reuse buffers). Perhaps
347 // PlatformBitmap itself should only re-Allocate when necessary? 365 // PlatformBitmap itself should only re-Allocate when necessary?
348 skia::PlatformBitmap* const bitmap = new skia::PlatformBitmap(); 366 skia::PlatformBitmap* const bitmap = new skia::PlatformBitmap();
349 scoped_ptr<skia::PlatformBitmap> capture(bitmap); 367 scoped_ptr<skia::PlatformBitmap> capture(bitmap);
350 rwh->CopyFromBackingStore( 368 rwh->CopyFromBackingStore(
351 gfx::Rect(), 369 gfx::Rect(),
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 556
539 void SynchronizedConsumer::OnIncomingCapturedFrame( 557 void SynchronizedConsumer::OnIncomingCapturedFrame(
540 const uint8* pixels, int size, const base::Time& timestamp) { 558 const uint8* pixels, int size, const base::Time& timestamp) {
541 base::AutoLock guard(consumer_lock_); 559 base::AutoLock guard(consumer_lock_);
542 if (wrapped_consumer_) { 560 if (wrapped_consumer_) {
543 wrapped_consumer_->OnIncomingCapturedFrame(pixels, size, timestamp); 561 wrapped_consumer_->OnIncomingCapturedFrame(pixels, size, timestamp);
544 } 562 }
545 } 563 }
546 564
547 VideoFrameDeliverer::VideoFrameDeliverer(SynchronizedConsumer* consumer) 565 VideoFrameDeliverer::VideoFrameDeliverer(SynchronizedConsumer* consumer)
548 : deliver_thread_("WebContentsVideo_DeliverThread"), consumer_(consumer) { 566 : deliver_thread_("WebContentsVideo_DeliverThread"),
567 consumer_(consumer),
568 count_frames_missed_(0),
569 last_frame_number_(0) {
549 DCHECK(consumer_); 570 DCHECK(consumer_);
550 deliver_thread_.Start(); 571 deliver_thread_.Start();
551 } 572 }
552 573
553 void VideoFrameDeliverer::Deliver( 574 void VideoFrameDeliverer::Deliver(
554 int frame_number, 575 int frame_number,
555 const SkBitmap& frame_buffer, const base::Time& frame_timestamp, 576 const SkBitmap& frame_buffer, const base::Time& frame_timestamp,
556 const base::Closure& done_cb) { 577 const base::Closure& done_cb) {
557 deliver_thread_.message_loop()->PostTask( 578 deliver_thread_.message_loop()->PostTask(
558 FROM_HERE, 579 FROM_HERE,
559 base::Bind(&VideoFrameDeliverer::DeliverOnDeliverThread, 580 base::Bind(&VideoFrameDeliverer::DeliverOnDeliverThread,
560 base::Unretained(this), 581 base::Unretained(this),
561 frame_number, base::ConstRef(frame_buffer), frame_timestamp, 582 frame_number, base::ConstRef(frame_buffer), frame_timestamp,
562 done_cb)); 583 done_cb));
563 } 584 }
564 585
565 void VideoFrameDeliverer::DeliverOnDeliverThread( 586 void VideoFrameDeliverer::DeliverOnDeliverThread(
566 int frame_number, 587 int frame_number,
567 const SkBitmap& frame_buffer, const base::Time& frame_timestamp, 588 const SkBitmap& frame_buffer, const base::Time& frame_timestamp,
568 const base::Closure& done_cb) { 589 const base::Closure& done_cb) {
569 DCHECK_EQ(deliver_thread_.message_loop(), MessageLoop::current()); 590 DCHECK_EQ(deliver_thread_.message_loop(), MessageLoop::current());
570 591
592 // Count the number of frame drops based on non-consecutive frame numbers.
593 if (frame_number > last_frame_number_)
594 count_frames_missed_ += frame_number - last_frame_number_ - 1;
595
596 if (frame_number % kFrameDropReportInterval ==
miu 2012/12/14 23:28:35 Rather than do this mod kFrameDropReportInterval s
Alpha Left Google 2013/01/04 00:00:38 Done.
597 kFrameDropReportInterval - 1) {
598 // Count the percentage of frames dropped in the last period.
599 UMA_HISTOGRAM_PERCENTAGE(
600 "TabCapture.FrameDropPercentage",
601 count_frames_missed_ * 100 / kFrameDropReportInterval);
miu 2012/12/14 23:28:35 What if the frames missed is 0.9%? It seems we'd
Alpha Left Google 2013/01/04 00:00:38 Done.
602 count_frames_missed_ = 0;
603 }
604 last_frame_number_ = frame_number;
605
571 TRACE_EVENT1("mirroring", "DeliverFrame", "frame_number", frame_number); 606 TRACE_EVENT1("mirroring", "DeliverFrame", "frame_number", frame_number);
572 607
573 // Send the frame to the consumer. 608 // Send the frame to the consumer.
574 // Note: The consumer will do an ARGB-->YUV conversion in this callback, 609 // Note: The consumer will do an ARGB-->YUV conversion in this callback,
575 // blocking the current thread for a bit. 610 // blocking the current thread for a bit.
576 SkAutoLockPixels frame_buffer_locker(frame_buffer); 611 SkAutoLockPixels frame_buffer_locker(frame_buffer);
577 consumer_->OnIncomingCapturedFrame( 612 consumer_->OnIncomingCapturedFrame(
578 static_cast<const uint8*>(frame_buffer.getPixels()), 613 static_cast<const uint8*>(frame_buffer.getPixels()),
579 frame_buffer.getSize(), 614 frame_buffer.getSize(),
580 frame_timestamp); 615 frame_timestamp);
581 616
582 // Log frame rate, if verbose logging is turned on. 617 // Log frame rate, if verbose logging is turned on.
583 if (VLOG_IS_ON(1)) { 618 static const base::TimeDelta kFrameRateLogInterval =
584 static const base::TimeDelta kFrameRateLogInterval = 619 base::TimeDelta::FromSeconds(10);
585 base::TimeDelta::FromSeconds(5); 620 const base::Time& now = base::Time::Now();
586 const base::Time& now = base::Time::Now(); 621 if (last_frame_rate_log_time_.is_null()) {
587 if (last_frame_rate_log_time_.is_null()) { 622 last_frame_rate_log_time_ = now;
623 count_frames_rendered_ = 0;
624 } else {
625 ++count_frames_rendered_;
626 const base::TimeDelta elapsed = now - last_frame_rate_log_time_;
627 if (elapsed >= kFrameRateLogInterval) {
628 const int measured_fps =
miu 2012/12/14 23:28:35 IMHO, you're going to want more precision here. S
Alpha Left Google 2013/01/04 00:00:38 I think a rough number is enough, 29 or 30 are bot
629 count_frames_rendered_ / elapsed.InSecondsF();
630 UMA_HISTOGRAM_COUNTS("TabCapture.FrameRate", measured_fps);
miu 2012/12/14 23:28:35 Ditto on considering rounding the value (assuming
631 VLOG(1) << "Current measured frame rate for CaptureMachine@" << this
632 << " is " << measured_fps << " FPS.";
588 last_frame_rate_log_time_ = now; 633 last_frame_rate_log_time_ = now;
589 count_frames_rendered_ = 0; 634 count_frames_rendered_ = 0;
590 } else {
591 ++count_frames_rendered_;
592 const base::TimeDelta elapsed = now - last_frame_rate_log_time_;
593 if (elapsed >= kFrameRateLogInterval) {
594 const double measured_fps =
595 count_frames_rendered_ / elapsed.InSecondsF();
596 VLOG(1) << "Current measured frame rate for CaptureMachine@" << this
597 << " is " << measured_fps << " FPS.";
598 last_frame_rate_log_time_ = now;
599 count_frames_rendered_ = 0;
600 }
601 } 635 }
602 } 636 }
603 637
604 // All done. 638 // All done.
605 done_cb.Run(); 639 done_cb.Run();
606 } 640 }
607 641
608 } // namespace 642 } // namespace
609 643
610 // The "meat" of the video capture implementation, which is a ref-counted class. 644 // The "meat" of the video capture implementation, which is a ref-counted class.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 // Stops capturing and notifies consumer_ of an error state. 691 // Stops capturing and notifies consumer_ of an error state.
658 void Error(); 692 void Error();
659 693
660 // Schedules the next frame capture off of the system clock, skipping frames 694 // Schedules the next frame capture off of the system clock, skipping frames
661 // to catch-up if necessary. 695 // to catch-up if necessary.
662 void ScheduleNextFrameCapture(); 696 void ScheduleNextFrameCapture();
663 697
664 // The glue between the pipeline stages. 698 // The glue between the pipeline stages.
665 void StartSnapshot(); 699 void StartSnapshot();
666 void SnapshotComplete(int frame_number, 700 void SnapshotComplete(int frame_number,
701 base::Time start_time,
miu 2012/12/14 23:28:35 Should be const ref type.
Alpha Left Google 2013/01/04 00:00:38 Done.
667 BackingStoreCopier::Result result, 702 BackingStoreCopier::Result result,
668 scoped_ptr<skia::PlatformBitmap> capture, 703 scoped_ptr<skia::PlatformBitmap> capture,
669 const base::Time& capture_time); 704 const base::Time& capture_time);
670 void RenderComplete(int frame_number, 705 void RenderComplete(int frame_number,
671 const base::Time& capture_time, 706 const base::Time& capture_time,
672 const SkBitmap* frame_buffer); 707 const SkBitmap* frame_buffer);
673 void DeliverComplete(const SkBitmap* frame_buffer); 708 void DeliverComplete(const SkBitmap* frame_buffer);
674 709
675 // Specialized RefCounted traits for CaptureMachine, so that operator delete 710 // Specialized RefCounted traits for CaptureMachine, so that operator delete
676 // is called from an "outside" thread. See comments for "traits" in 711 // is called from an "outside" thread. See comments for "traits" in
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 if (state_ != kCapturing) { 936 if (state_ != kCapturing) {
902 return; 937 return;
903 } 938 }
904 939
905 if (!is_snapshotting_) { 940 if (!is_snapshotting_) {
906 is_snapshotting_ = true; 941 is_snapshotting_ = true;
907 942
908 const BackingStoreCopier::DoneCB& done_cb = 943 const BackingStoreCopier::DoneCB& done_cb =
909 media::BindToLoop(manager_thread_.message_loop_proxy(), 944 media::BindToLoop(manager_thread_.message_loop_proxy(),
910 base::Bind(&CaptureMachine::SnapshotComplete, this, 945 base::Bind(&CaptureMachine::SnapshotComplete, this,
911 frame_number_)); 946 frame_number_, base::Time::Now()));
912 const base::Closure& start_cb = 947 const base::Closure& start_cb =
913 base::Bind(&BackingStoreCopier::StartCopy, 948 base::Bind(&BackingStoreCopier::StartCopy,
914 base::Unretained(&copier_), 949 base::Unretained(&copier_),
915 frame_number_, settings_.width, settings_.height, done_cb); 950 frame_number_, settings_.width, settings_.height, done_cb);
916 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, start_cb); 951 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, start_cb);
917 } 952 }
918 953
919 ScheduleNextFrameCapture(); 954 ScheduleNextFrameCapture();
920 } 955 }
921 956
922 void CaptureMachine::SnapshotComplete(int frame_number, 957 void CaptureMachine::SnapshotComplete(int frame_number,
958 base::Time start_time,
923 BackingStoreCopier::Result result, 959 BackingStoreCopier::Result result,
924 scoped_ptr<skia::PlatformBitmap> capture, 960 scoped_ptr<skia::PlatformBitmap> capture,
925 const base::Time& capture_time) { 961 const base::Time& capture_time) {
926 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current()); 962 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current());
927 963
928 DCHECK(is_snapshotting_); 964 DCHECK(is_snapshotting_);
929 is_snapshotting_ = false; 965 is_snapshotting_ = false;
930 966
931 if (state_ != kCapturing) { 967 if (state_ != kCapturing) {
932 return; 968 return;
933 } 969 }
934 970
935 switch (result) { 971 switch (result) {
936 case BackingStoreCopier::OK: 972 case BackingStoreCopier::OK:
973 UMA_HISTOGRAM_TIMES("TabCapture.SnapshotTime",
974 base::Time::Now() - start_time);
937 if (num_renders_pending_ <= 1) { 975 if (num_renders_pending_ <= 1) {
938 ++num_renders_pending_; 976 ++num_renders_pending_;
939 DCHECK(capture); 977 DCHECK(capture);
940 DCHECK(!capture_time.is_null()); 978 DCHECK(!capture_time.is_null());
941 renderer_.Render( 979 renderer_.Render(
942 frame_number, 980 frame_number,
943 capture.Pass(), 981 capture.Pass(),
944 settings_.width, settings_.height, 982 settings_.width, settings_.height,
945 media::BindToLoop(manager_thread_.message_loop_proxy(), 983 media::BindToLoop(manager_thread_.message_loop_proxy(),
946 base::Bind(&CaptureMachine::RenderComplete, this, 984 base::Bind(&CaptureMachine::RenderComplete, this,
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1050 capturer_->SetConsumer(NULL); 1088 capturer_->SetConsumer(NULL);
1051 capturer_->DeAllocate(); 1089 capturer_->DeAllocate();
1052 } 1090 }
1053 1091
1054 const media::VideoCaptureDevice::Name& 1092 const media::VideoCaptureDevice::Name&
1055 WebContentsVideoCaptureDevice::device_name() { 1093 WebContentsVideoCaptureDevice::device_name() {
1056 return device_name_; 1094 return device_name_;
1057 } 1095 }
1058 1096
1059 } // namespace content 1097 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698