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 // 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |