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

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: double Created 7 years, 11 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 | 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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 void LookUpAndObserveWebContents(); 166 void LookUpAndObserveWebContents();
166 167
167 void CopyFromBackingStoreComplete(int frame_number, 168 void CopyFromBackingStoreComplete(int frame_number,
168 scoped_ptr<skia::PlatformBitmap> capture, 169 scoped_ptr<skia::PlatformBitmap> capture,
169 const DoneCB& done_cb, bool success); 170 const DoneCB& done_cb, bool success);
170 171
171 // The "starting point" to find the capture source. 172 // The "starting point" to find the capture source.
172 const int render_process_id_; 173 const int render_process_id_;
173 const int render_view_id_; 174 const int render_view_id_;
174 175
176 // Last known RenderView size.
177 gfx::Size last_view_size_;
178
175 // If the following is NULL (normal behavior), the implementation should 179 // If the following is NULL (normal behavior), the implementation should
176 // access RenderWidgetHost via web_contents(). 180 // access RenderWidgetHost via web_contents().
177 RenderWidgetHost* rwh_for_testing_; 181 RenderWidgetHost* rwh_for_testing_;
178 182
179 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); 183 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier);
180 }; 184 };
181 185
182 // Renders captures (from the backing store) into video frame buffers on a 186 // Renders captures (from the backing store) into video frame buffers on a
183 // separate thread. Manages use of internally-owned video frame buffers. 187 // separate thread. Manages use of internally-owned video frame buffers.
184 class VideoFrameRenderer { 188 class VideoFrameRenderer {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 const base::Time& frame_timestamp, 257 const base::Time& frame_timestamp,
254 const base::Closure& done_cb); 258 const base::Closure& done_cb);
255 259
256 base::Thread deliver_thread_; 260 base::Thread deliver_thread_;
257 SynchronizedConsumer* const consumer_; 261 SynchronizedConsumer* const consumer_;
258 262
259 // The following keep track of and log the effective frame rate (from the 263 // The following keep track of and log the effective frame rate (from the
260 // deliver stage) whenever verbose logging is turned on. 264 // deliver stage) whenever verbose logging is turned on.
261 base::Time last_frame_rate_log_time_; 265 base::Time last_frame_rate_log_time_;
262 int count_frames_rendered_; 266 int count_frames_rendered_;
267 int last_frame_number_;
263 268
264 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); 269 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer);
265 }; 270 };
266 271
267 BackingStoreCopier::BackingStoreCopier(int render_process_id, 272 BackingStoreCopier::BackingStoreCopier(int render_process_id,
268 int render_view_id) 273 int render_view_id)
269 : render_process_id_(render_process_id), render_view_id_(render_view_id), 274 : render_process_id_(render_process_id), render_view_id_(render_view_id),
270 rwh_for_testing_(NULL) {} 275 rwh_for_testing_(NULL) {}
271 276
272 void BackingStoreCopier::LookUpAndObserveWebContents() { 277 void BackingStoreCopier::LookUpAndObserveWebContents() {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 } 332 }
328 333
329 gfx::Size fitted_size; 334 gfx::Size fitted_size;
330 if (RenderWidgetHostView* const view = rwh->GetView()) { 335 if (RenderWidgetHostView* const view = rwh->GetView()) {
331 const gfx::Size& view_size = view->GetViewBounds().size(); 336 const gfx::Size& view_size = view->GetViewBounds().size();
332 if (!view_size.IsEmpty()) { 337 if (!view_size.IsEmpty()) {
333 CalculateFittedSize(view_size.width(), view_size.height(), 338 CalculateFittedSize(view_size.width(), view_size.height(),
334 desired_width, desired_height, 339 desired_width, desired_height,
335 &fitted_size); 340 &fitted_size);
336 } 341 }
342 if (view_size != last_view_size_) {
343 last_view_size_ = view_size;
344
345 // Measure the number of kilopixels.
346 UMA_HISTOGRAM_COUNTS_10000(
347 "TabCapture.ViewChangeKiloPixels",
348 view_size.width() * view_size.height() / 1024);
349 }
337 } 350 }
338 351
339 // TODO(miu): Look into tweaking the interface to CopyFromBackingStore, since 352 // TODO(miu): Look into tweaking the interface to CopyFromBackingStore, since
340 // it seems poor to have to allocate a new skia::PlatformBitmap as an output 353 // it seems poor to have to allocate a new skia::PlatformBitmap as an output
341 // buffer for each successive frame (rather than reuse buffers). Perhaps 354 // buffer for each successive frame (rather than reuse buffers). Perhaps
342 // PlatformBitmap itself should only re-Allocate when necessary? 355 // PlatformBitmap itself should only re-Allocate when necessary?
343 skia::PlatformBitmap* const bitmap = new skia::PlatformBitmap(); 356 skia::PlatformBitmap* const bitmap = new skia::PlatformBitmap();
344 scoped_ptr<skia::PlatformBitmap> capture(bitmap); 357 scoped_ptr<skia::PlatformBitmap> capture(bitmap);
345 rwh->CopyFromBackingStore( 358 rwh->CopyFromBackingStore(
346 gfx::Rect(), 359 gfx::Rect(),
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 546
534 void SynchronizedConsumer::OnIncomingCapturedFrame( 547 void SynchronizedConsumer::OnIncomingCapturedFrame(
535 const uint8* pixels, int size, const base::Time& timestamp) { 548 const uint8* pixels, int size, const base::Time& timestamp) {
536 base::AutoLock guard(consumer_lock_); 549 base::AutoLock guard(consumer_lock_);
537 if (wrapped_consumer_) { 550 if (wrapped_consumer_) {
538 wrapped_consumer_->OnIncomingCapturedFrame(pixels, size, timestamp); 551 wrapped_consumer_->OnIncomingCapturedFrame(pixels, size, timestamp);
539 } 552 }
540 } 553 }
541 554
542 VideoFrameDeliverer::VideoFrameDeliverer(SynchronizedConsumer* consumer) 555 VideoFrameDeliverer::VideoFrameDeliverer(SynchronizedConsumer* consumer)
543 : deliver_thread_("WebContentsVideo_DeliverThread"), consumer_(consumer) { 556 : deliver_thread_("WebContentsVideo_DeliverThread"),
557 consumer_(consumer),
558 last_frame_number_(0) {
544 DCHECK(consumer_); 559 DCHECK(consumer_);
545 deliver_thread_.Start(); 560 deliver_thread_.Start();
546 } 561 }
547 562
548 void VideoFrameDeliverer::Deliver( 563 void VideoFrameDeliverer::Deliver(
549 int frame_number, 564 int frame_number,
550 const SkBitmap& frame_buffer, const base::Time& frame_timestamp, 565 const SkBitmap& frame_buffer, const base::Time& frame_timestamp,
551 const base::Closure& done_cb) { 566 const base::Closure& done_cb) {
552 deliver_thread_.message_loop()->PostTask( 567 deliver_thread_.message_loop()->PostTask(
553 FROM_HERE, 568 FROM_HERE,
(...skipping 14 matching lines...) Expand all
568 // Send the frame to the consumer. 583 // Send the frame to the consumer.
569 // Note: The consumer will do an ARGB-->YUV conversion in this callback, 584 // Note: The consumer will do an ARGB-->YUV conversion in this callback,
570 // blocking the current thread for a bit. 585 // blocking the current thread for a bit.
571 SkAutoLockPixels frame_buffer_locker(frame_buffer); 586 SkAutoLockPixels frame_buffer_locker(frame_buffer);
572 consumer_->OnIncomingCapturedFrame( 587 consumer_->OnIncomingCapturedFrame(
573 static_cast<const uint8*>(frame_buffer.getPixels()), 588 static_cast<const uint8*>(frame_buffer.getPixels()),
574 frame_buffer.getSize(), 589 frame_buffer.getSize(),
575 frame_timestamp); 590 frame_timestamp);
576 591
577 // Log frame rate, if verbose logging is turned on. 592 // Log frame rate, if verbose logging is turned on.
578 if (VLOG_IS_ON(1)) { 593 static const base::TimeDelta kFrameRateLogInterval =
579 static const base::TimeDelta kFrameRateLogInterval = 594 base::TimeDelta::FromSeconds(10);
580 base::TimeDelta::FromSeconds(5); 595 const base::Time& now = base::Time::Now();
581 const base::Time& now = base::Time::Now(); 596 if (last_frame_rate_log_time_.is_null()) {
582 if (last_frame_rate_log_time_.is_null()) { 597 last_frame_rate_log_time_ = now;
598 count_frames_rendered_ = 0;
599 last_frame_number_ = frame_number;
600 } else {
601 ++count_frames_rendered_;
602 const base::TimeDelta elapsed = now - last_frame_rate_log_time_;
603 if (elapsed >= kFrameRateLogInterval) {
604 const double measured_fps =
605 count_frames_rendered_ / elapsed.InSecondsF();
606 const int frames_elapsed = frame_number - last_frame_number_;
607 const int count_frames_dropped = frames_elapsed - count_frames_rendered_;
608 DCHECK_LE(0, count_frames_dropped);
609 UMA_HISTOGRAM_PERCENTAGE(
610 "TabCapture.FrameDropPercentage",
611 (count_frames_dropped * 100 + frames_elapsed / 2) / frames_elapsed);
612 UMA_HISTOGRAM_COUNTS(
613 "TabCapture.FrameRate",
614 static_cast<int>(measured_fps));
615 VLOG(1) << "Current measured frame rate for CaptureMachine@" << this
616 << " is " << measured_fps << " FPS.";
583 last_frame_rate_log_time_ = now; 617 last_frame_rate_log_time_ = now;
584 count_frames_rendered_ = 0; 618 count_frames_rendered_ = 0;
585 } else { 619 last_frame_number_ = frame_number;
586 ++count_frames_rendered_;
587 const base::TimeDelta elapsed = now - last_frame_rate_log_time_;
588 if (elapsed >= kFrameRateLogInterval) {
589 const double measured_fps =
590 count_frames_rendered_ / elapsed.InSecondsF();
591 VLOG(1) << "Current measured frame rate for CaptureMachine@" << this
592 << " is " << measured_fps << " FPS.";
593 last_frame_rate_log_time_ = now;
594 count_frames_rendered_ = 0;
595 }
596 } 620 }
597 } 621 }
598 622
599 // All done. 623 // All done.
600 done_cb.Run(); 624 done_cb.Run();
601 } 625 }
602 626
603 } // namespace 627 } // namespace
604 628
605 // The "meat" of the video capture implementation, which is a ref-counted class. 629 // 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
652 // Stops capturing and notifies consumer_ of an error state. 676 // Stops capturing and notifies consumer_ of an error state.
653 void Error(); 677 void Error();
654 678
655 // Schedules the next frame capture off of the system clock, skipping frames 679 // Schedules the next frame capture off of the system clock, skipping frames
656 // to catch-up if necessary. 680 // to catch-up if necessary.
657 void ScheduleNextFrameCapture(); 681 void ScheduleNextFrameCapture();
658 682
659 // The glue between the pipeline stages. 683 // The glue between the pipeline stages.
660 void StartSnapshot(); 684 void StartSnapshot();
661 void SnapshotComplete(int frame_number, 685 void SnapshotComplete(int frame_number,
686 const base::Time& start_time,
662 BackingStoreCopier::Result result, 687 BackingStoreCopier::Result result,
663 scoped_ptr<skia::PlatformBitmap> capture, 688 scoped_ptr<skia::PlatformBitmap> capture,
664 const base::Time& capture_time); 689 const base::Time& capture_time);
665 void RenderComplete(int frame_number, 690 void RenderComplete(int frame_number,
666 const base::Time& capture_time, 691 const base::Time& capture_time,
667 const SkBitmap* frame_buffer); 692 const SkBitmap* frame_buffer);
668 void DeliverComplete(const SkBitmap* frame_buffer); 693 void DeliverComplete(const SkBitmap* frame_buffer);
669 694
670 // Specialized RefCounted traits for CaptureMachine, so that operator delete 695 // Specialized RefCounted traits for CaptureMachine, so that operator delete
671 // is called from an "outside" thread. See comments for "traits" in 696 // is called from an "outside" thread. See comments for "traits" in
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 if (state_ != kCapturing) { 914 if (state_ != kCapturing) {
890 return; 915 return;
891 } 916 }
892 917
893 if (!is_snapshotting_) { 918 if (!is_snapshotting_) {
894 is_snapshotting_ = true; 919 is_snapshotting_ = true;
895 920
896 const BackingStoreCopier::DoneCB& done_cb = 921 const BackingStoreCopier::DoneCB& done_cb =
897 media::BindToLoop(manager_thread_.message_loop_proxy(), 922 media::BindToLoop(manager_thread_.message_loop_proxy(),
898 base::Bind(&CaptureMachine::SnapshotComplete, this, 923 base::Bind(&CaptureMachine::SnapshotComplete, this,
899 frame_number_)); 924 frame_number_, base::Time::Now()));
900 const base::Closure& start_cb = 925 const base::Closure& start_cb =
901 base::Bind(&BackingStoreCopier::StartCopy, 926 base::Bind(&BackingStoreCopier::StartCopy,
902 base::Unretained(&copier_), 927 base::Unretained(&copier_),
903 frame_number_, settings_.width, settings_.height, done_cb); 928 frame_number_, settings_.width, settings_.height, done_cb);
904 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, start_cb); 929 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, start_cb);
905 } 930 }
906 931
907 ScheduleNextFrameCapture(); 932 ScheduleNextFrameCapture();
908 } 933 }
909 934
910 void CaptureMachine::SnapshotComplete(int frame_number, 935 void CaptureMachine::SnapshotComplete(int frame_number,
936 const base::Time& start_time,
911 BackingStoreCopier::Result result, 937 BackingStoreCopier::Result result,
912 scoped_ptr<skia::PlatformBitmap> capture, 938 scoped_ptr<skia::PlatformBitmap> capture,
913 const base::Time& capture_time) { 939 const base::Time& capture_time) {
914 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current()); 940 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current());
915 941
916 DCHECK(is_snapshotting_); 942 DCHECK(is_snapshotting_);
917 is_snapshotting_ = false; 943 is_snapshotting_ = false;
918 944
919 if (state_ != kCapturing) { 945 if (state_ != kCapturing) {
920 return; 946 return;
921 } 947 }
922 948
923 switch (result) { 949 switch (result) {
924 case BackingStoreCopier::OK: 950 case BackingStoreCopier::OK:
951 UMA_HISTOGRAM_TIMES("TabCapture.SnapshotTime",
952 base::Time::Now() - start_time);
925 if (num_renders_pending_ <= 1) { 953 if (num_renders_pending_ <= 1) {
926 ++num_renders_pending_; 954 ++num_renders_pending_;
927 DCHECK(capture); 955 DCHECK(capture);
928 DCHECK(!capture_time.is_null()); 956 DCHECK(!capture_time.is_null());
929 renderer_.Render( 957 renderer_.Render(
930 frame_number, 958 frame_number,
931 capture.Pass(), 959 capture.Pass(),
932 settings_.width, settings_.height, 960 settings_.width, settings_.height,
933 media::BindToLoop(manager_thread_.message_loop_proxy(), 961 media::BindToLoop(manager_thread_.message_loop_proxy(),
934 base::Bind(&CaptureMachine::RenderComplete, this, 962 base::Bind(&CaptureMachine::RenderComplete, this,
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 capturer_->SetConsumer(NULL); 1066 capturer_->SetConsumer(NULL);
1039 capturer_->DeAllocate(); 1067 capturer_->DeAllocate();
1040 } 1068 }
1041 1069
1042 const media::VideoCaptureDevice::Name& 1070 const media::VideoCaptureDevice::Name&
1043 WebContentsVideoCaptureDevice::device_name() { 1071 WebContentsVideoCaptureDevice::device_name() {
1044 return device_name_; 1072 return device_name_;
1045 } 1073 }
1046 1074
1047 } // namespace content 1075 } // 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