15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/debugger.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/run_loop.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/test/test_timeouts.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/browser_thread_impl.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_oracle.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/web_contents_capture_util.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/render_view_host_factory.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_widget_host_impl.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/test_render_view_host.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/port/browser/render_widget_host_view_frame_subscriber.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_service.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_types.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/mock_render_process_host.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_browser_context.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/test/test_browser_thread_bundle.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/test/test_utils.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/test/test_web_contents.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_util.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/yuv_convert.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/video/capture/video_capture_types.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/platform_canvas.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTestWidth = 320;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTestHeight = 240;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTestFramesPerSecond = 20;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kNothingYet = 0xdeadbeef;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kNotInterested = ~kNothingYet;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeadlineExceeded(base::Closure quit_closure) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::debug::BeingDebugged()) {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    quit_closure.Run();
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAIL() << "Deadline exceeded while waiting, quitting";
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << "attached.";
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RunCurrentLoopWithDeadline() {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Timer deadline(false, false);
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  deadline.Start(FROM_HERE, TestTimeouts::action_max_timeout(), base::Bind(
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &DeadlineExceeded, base::MessageLoop::current()->QuitClosure()));
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop::current()->Run();
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deadline.Stop();
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SkColor ConvertRgbToYuv(SkColor rgb) {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 yuv[3];
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  media::ConvertRGB32ToYUV(reinterpret_cast<uint8*>(&rgb),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           yuv, yuv + 1, yuv + 2, 1, 1, 1, 1, 1);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SkColorSetRGB(yuv[0], yuv[1], yuv[2]);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Thread-safe class that controls the source pattern to be captured by the
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// system under test. The lifetime of this class is greater than the lifetime
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of all objects that reference it, so it does not need to be reference
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// counted.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class CaptureTestSourceController {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController()
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : color_(SK_ColorMAGENTA),
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        copy_result_size_(kTestWidth, kTestHeight),
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        can_copy_to_video_frame_(false),
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        use_frame_subscriber_(false) {}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetSolidColor(SkColor color) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock guard(lock_);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    color_ = color;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkColor GetSolidColor() {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return color_;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetCopyResultSize(int width, int height) {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    copy_result_size_ = gfx::Size(width, height);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size GetCopyResultSize() {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return copy_result_size_;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SignalCopy() {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(nick): This actually should always be happening on the UI thread.
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!copy_done_.is_null()) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, copy_done_);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      copy_done_.Reset();
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetCanCopyToVideoFrame(bool value) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    can_copy_to_video_frame_ = value;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool CanCopyToVideoFrame() {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return can_copy_to_video_frame_;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetUseFrameSubscriber(bool value) {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    use_frame_subscriber_ = value;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool CanUseFrameSubscriber() {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock guard(lock_);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return use_frame_subscriber_;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForNextCopy() {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock guard(lock_);
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      copy_done_ = base::MessageLoop::current()->QuitClosure();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunCurrentLoopWithDeadline();
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Lock lock_;  // Guards changes to all members.
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkColor color_;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size copy_result_size_;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool can_copy_to_video_frame_;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool use_frame_subscriber_;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Closure copy_done_;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A stub implementation which returns solid-color bitmaps in calls to
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CopyFromCompositingSurfaceToVideoFrame(), and which allows the video-frame
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// readback path to be switched on and off. The behavior is controlled by a
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CaptureTestSourceController.
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class CaptureTestView : public TestRenderWidgetHostView {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit CaptureTestView(RenderWidgetHostImpl* rwh,
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           CaptureTestSourceController* controller)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : TestRenderWidgetHostView(rwh),
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        controller_(controller) {}
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~CaptureTestView() {}
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TestRenderWidgetHostView overrides.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual gfx::Rect GetViewBounds() const OVERRIDE {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool CanCopyToVideoFrame() const OVERRIDE {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return controller_->CanCopyToVideoFrame();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void CopyFromCompositingSurfaceToVideoFrame(
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const gfx::Rect& src_subrect,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<media::VideoFrame>& target,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const base::Callback<void(bool)>& callback) OVERRIDE {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkColor c = ConvertRgbToYuv(controller_->GetSolidColor());
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    media::FillYUV(
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        target.get(), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(true);
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    controller_->SignalCopy();
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void BeginFrameSubscription(
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    subscriber_.reset(subscriber.release());
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void EndFrameSubscription() OVERRIDE {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    subscriber_.reset();
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate a compositor paint event for our subscriber.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SimulateUpdate() {
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Time present_time = base::Time::Now();
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<media::VideoFrame> target;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (subscriber_ && subscriber_->ShouldCaptureFrame(present_time,
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       &target, &callback)) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SkColor c = ConvertRgbToYuv(controller_->GetSolidColor());
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      media::FillYUV(
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          target.get(), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      BrowserThread::PostTask(BrowserThread::UI,
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              FROM_HERE,
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              base::Bind(callback, present_time, true));
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      controller_->SignalCopy();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController* const controller_;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(COMPILER_MSVC)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// MSVC warns on diamond inheritance. See comment for same warning on
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RenderViewHostImpl.
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma warning(push)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma warning(disable: 4250)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A stub implementation which returns solid-color bitmaps in calls to
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CopyFromBackingStore(). The behavior is controlled by a
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CaptureTestSourceController.
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class CaptureTestRenderViewHost : public TestRenderViewHost {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestRenderViewHost(SiteInstance* instance,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            RenderViewHostDelegate* delegate,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            RenderWidgetHostDelegate* widget_delegate,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            int routing_id,
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            int main_frame_routing_id,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            bool swapped_out,
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            CaptureTestSourceController* controller)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : TestRenderViewHost(instance, delegate, widget_delegate, routing_id,
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           main_frame_routing_id, swapped_out),
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        controller_(controller) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Override the default view installed by TestRenderViewHost; we need
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // our special subclass which has mocked-out tab capture support.
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderWidgetHostView* old_view = GetView();
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetView(new CaptureTestView(this, controller));
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete old_view;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TestRenderViewHost overrides.
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void CopyFromBackingStore(
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const gfx::Rect& src_rect,
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const gfx::Size& accelerated_dst_size,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const base::Callback<void(bool, const SkBitmap&)>& callback) OVERRIDE {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Size size = controller_->GetCopyResultSize();
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkColor color = controller_->GetSolidColor();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Although it's not necessary, use a PlatformBitmap here (instead of a
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // regular SkBitmap) to exercise possible threading issues.
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    skia::PlatformBitmap output;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(output.Allocate(size.width(), size.height(), false));
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SkAutoLockPixels locker(output.GetBitmap());
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      output.GetBitmap().eraseColor(color);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(true, output.GetBitmap());
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    controller_->SignalCopy();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController* controller_;
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHost);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(COMPILER_MSVC)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Re-enable warning 4250
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma warning(pop)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class CaptureTestRenderViewHostFactory : public RenderViewHostFactory {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit CaptureTestRenderViewHostFactory(
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CaptureTestSourceController* controller) : controller_(controller) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RegisterFactory(this);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~CaptureTestRenderViewHostFactory() {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UnregisterFactory();
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // RenderViewHostFactory implementation.
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual RenderViewHost* CreateRenderViewHost(
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SiteInstance* instance,
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RenderViewHostDelegate* delegate,
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RenderWidgetHostDelegate* widget_delegate,
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int routing_id,
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int main_frame_routing_id,
295a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      bool swapped_out) OVERRIDE {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return new CaptureTestRenderViewHost(instance, delegate, widget_delegate,
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                         routing_id, main_frame_routing_id,
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                         swapped_out, controller_);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController* controller_;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHostFactory);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A stub consumer of captured video frames, which checks the output of
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WebContentsVideoCaptureDevice.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StubConsumer : public media::VideoCaptureDevice::EventHandler {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StubConsumer()
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : error_encountered_(false),
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        wait_color_yuv_(0xcafe1950) {
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    buffer_pool_ =
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        new VideoCaptureBufferPool(kTestWidth * kTestHeight * 3 / 2, 2);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(buffer_pool_->Allocate());
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~StubConsumer() {}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void QuitIfConditionMet(SkColor color) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock guard(lock_);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (wait_color_yuv_ == color || error_encountered_)
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::MessageLoop::current()->Quit();
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForNextColor(SkColor expected_color) {
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::AutoLock guard(lock_);
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      wait_color_yuv_ = ConvertRgbToYuv(expected_color);
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_encountered_ = false;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunCurrentLoopWithDeadline();
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::AutoLock guard(lock_);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ASSERT_FALSE(error_encountered_);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForError() {
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::AutoLock guard(lock_);
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      wait_color_yuv_ = kNotInterested;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_encountered_ = false;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunCurrentLoopWithDeadline();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock guard(lock_);
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ASSERT_TRUE(error_encountered_);
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool HasError() {
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::AutoLock guard(lock_);
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return error_encountered_;
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual scoped_refptr<media::VideoFrame> ReserveOutputBuffer() OVERRIDE {
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return buffer_pool_->ReserveI420VideoFrame(gfx::Size(kTestWidth,
359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                         kTestHeight),
360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               0);
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnIncomingCapturedFrame(
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const uint8* data,
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int length,
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Time timestamp,
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int rotation,
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool flip_vert,
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool flip_horiz) OVERRIDE {
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAIL();
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnIncomingCapturedVideoFrame(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const scoped_refptr<media::VideoFrame>& frame,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Time timestamp) OVERRIDE {
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->coded_size());
3774311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    EXPECT_EQ(media::VideoFrame::I420, frame->format());
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EXPECT_LE(
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        0,
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        buffer_pool_->RecognizeReservedBuffer(frame->shared_memory_handle()));
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint8 yuv[3];
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int plane = 0; plane < 3; ++plane) {
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      yuv[plane] = frame->data(plane)[0];
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(nick): We just look at the first pixel presently, because if
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the analysis is too slow, the backlog of frames will grow without bound
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // and trouble erupts. http://crbug.com/174519
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PostColorOrError(SkColorSetRGB(yuv[0], yuv[1], yuv[2]));
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void PostColorOrError(SkColor new_color) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &StubConsumer::QuitIfConditionMet, base::Unretained(this), new_color));
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnError() OVERRIDE {
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::AutoLock guard(lock_);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_encountered_ = true;
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PostColorOrError(kNothingYet);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnFrameInfo(const media::VideoCaptureCapability& info) OVERRIDE {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kTestWidth, info.width);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kTestHeight, info.height);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kTestFramesPerSecond, info.frame_rate);
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(media::VideoCaptureCapability::kI420, info.color);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock_;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool error_encountered_;
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkColor wait_color_yuv_;
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StubConsumer);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test harness that sets up a minimal environment with necessary stubs.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebContentsVideoCaptureDeviceTest : public testing::Test {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // This is public because C++ method pointer scoping rules are silly and make
424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // this hard to use with Bind().
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ResetWebContents() {
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_contents_.reset();
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() {
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // eliminated here, if only we could use RenderViewHostTestHarness. The
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // catch is that we need our TestRenderViewHost to support a
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // CopyFromBackingStore operation that we control. To accomplish that,
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // either RenderViewHostTestHarness would have to support installing a
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // custom RenderViewHostFactory, or else we implant some kind of delegated
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // CopyFromBackingStore functionality into TestRenderViewHost itself.
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_process_host_factory_.reset(new MockRenderProcessHostFactory());
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Create our (self-registering) RVH factory, so that when we create a
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // WebContents, it in turn creates CaptureTestRenderViewHosts.
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_view_host_factory_.reset(
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new CaptureTestRenderViewHostFactory(&controller_));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_context_.reset(new TestBrowserContext());
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<SiteInstance> site_instance =
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SiteInstance::Create(browser_context_.get());
449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    SiteInstanceImpl::set_render_process_host_factory(
450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        render_process_host_factory_.get());
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_contents_.reset(
452868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        TestWebContents::Create(browser_context_.get(), site_instance.get()));
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This is actually a CaptureTestRenderViewHost.
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderWidgetHostImpl* rwh =
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        RenderWidgetHostImpl::From(web_contents_->GetRenderViewHost());
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string device_id =
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::StringPrintf("%d:%d", rwh->GetProcess()->GetID(),
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               rwh->GetRoutingID()));
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    device_.reset(WebContentsVideoCaptureDevice::Create(device_id));
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::RunLoop().RunUntilIdle();
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tear down in opposite order of set-up.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The device is destroyed asynchronously, and will notify the
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // CaptureTestSourceController when it finishes destruction.
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Trigger this, and wait.
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (device_) {
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      device_->DeAllocate();
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      device_.reset();
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
479868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::RunLoop().RunUntilIdle();
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Destroy the browser objects.
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_contents_.reset();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_context_.reset();
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
485868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::RunLoop().RunUntilIdle();
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
487868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    SiteInstanceImpl::set_render_process_host_factory(NULL);
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_view_host_factory_.reset();
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_process_host_factory_.reset();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Accessors.
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController* source() { return &controller_; }
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  media::VideoCaptureDevice* device() { return device_.get(); }
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StubConsumer* consumer() { return &consumer_; }
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SimulateDrawEvent() {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (source()->CanUseFrameSubscriber()) {
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Print
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CaptureTestView* test_view = static_cast<CaptureTestView*>(
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          web_contents_->GetRenderViewHost()->GetView());
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      test_view->SimulateUpdate();
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Simulate a non-accelerated paint.
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NotificationService::current()->Notify(
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          Source<RenderWidgetHost>(web_contents_->GetRenderViewHost()),
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NotificationService::NoDetails());
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void DestroyVideoCaptureDevice() { device_.reset(); }
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The consumer is the ultimate recipient of captured pixel data.
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StubConsumer consumer_;
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The controller controls which pixel patterns to produce.
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CaptureTestSourceController controller_;
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Self-registering RenderProcessHostFactory.
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates capture-capable RenderViewHosts whose pixel content production is
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // under the control of |controller_|.
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<CaptureTestRenderViewHostFactory> render_view_host_factory_;
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A mocked-out browser and tab.
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<TestBrowserContext> browser_context_;
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<WebContents> web_contents_;
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Finally, the WebContentsVideoCaptureDevice under test.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<media::VideoCaptureDevice> device_;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TestBrowserThreadBundle thread_bundle_;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, InvalidInitialWebContentsError) {
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Before the installs itself on the UI thread up to start capturing, we'll
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // delete the web contents. This should trigger an error which can happen in
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // practice; we should be able to recover gracefully.
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResetWebContents();
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
544a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
545a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
546a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
547a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
548a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
549a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
550a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
551a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
552a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->Start();
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError());
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->DeAllocate();
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) {
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We'll simulate the tab being closed after the capture pipeline is up and
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // running.
561a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
562a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
563a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
564a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
565a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
566a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
567a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
568a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
569a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->Start();
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Do one capture to prove
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source()->SetSolidColor(SK_ColorRED);
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SimulateDrawEvent();
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
577868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Post a task to close the tab. We should see an error reported to the
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // consumer.
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&WebContentsVideoCaptureDeviceTest::ResetWebContents,
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this)));
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError());
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->DeAllocate();
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest,
589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       StopDeviceBeforeCaptureMachineCreation) {
590a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
591a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
592a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
593a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
594a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
595a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
596a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
597a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
598a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Start();
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Make a point of not running the UI messageloop here.
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Stop();
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->DeAllocate();
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DestroyVideoCaptureDevice();
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Currently, there should be CreateCaptureMachineOnUIThread() and
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // DestroyCaptureMachineOnUIThread() tasks pending on the current (UI) message
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // loop. These should both succeed without crashing, and the machine should
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // wind up in the idle state.
609868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set up the test to use RGB copies and an normal
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetCanCopyToVideoFrame(false);
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetUseFrameSubscriber(false);
616a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
617a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
618a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
619a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
620a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
621a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
622a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
623a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
624a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
625a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Start();
627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Make a point of not running the UI messageloop here.
628868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(ajwong): Why do we care?
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < 10; ++i)
632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SimulateDrawEvent();
633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Stop();
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->DeAllocate();
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Currently, there should be CreateCaptureMachineOnUIThread() and
637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // DestroyCaptureMachineOnUIThread() tasks pending on the current message
638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // loop. These should both succeed without crashing, and the machine should
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // wind up in the idle state.
640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(consumer()->HasError());
641868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(consumer()->HasError());
643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, DeviceRestart) {
646a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
647a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
648a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
649a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
650a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
651a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
652a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
653a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
654a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Start();
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetSolidColor(SK_ColorRED);
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetSolidColor(SK_ColorGREEN);
664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Stop();
667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Device is stopped, but content can still be animating.
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->Start();
674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetSolidColor(SK_ColorBLUE);
675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
676c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLUE));
677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  source()->SetSolidColor(SK_ColorYELLOW);
678c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SimulateDrawEvent();
679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorYELLOW));
680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  device()->DeAllocate();
681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The "happy case" test.  No scaling is needed, so we should be able to change
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the picture emitted from the source and expect to see each delivered to the
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// consumer. The test will alternate between the three capture paths, simulating
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// falling in and out of accelerated compositing.
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
688a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
689a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
690a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
691a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
692a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
693a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
694a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
695a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
696a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device()->Start();
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 6; i++) {
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const char* name = NULL;
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (i % 3) {
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case 0:
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetCanCopyToVideoFrame(true);
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetUseFrameSubscriber(false);
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        name = "VideoFrame";
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case 1:
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetCanCopyToVideoFrame(false);
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetUseFrameSubscriber(true);
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        name = "Subscriber";
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case 2:
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetCanCopyToVideoFrame(false);
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        source()->SetUseFrameSubscriber(false);
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        name = "SkBitmap";
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FAIL();
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    source()->SetSolidColor(SK_ColorRED);
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimulateDrawEvent();
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    source()->SetSolidColor(SK_ColorGREEN);
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimulateDrawEvent();
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    source()->SetSolidColor(SK_ColorBLUE);
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimulateDrawEvent();
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLUE));
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    source()->SetSolidColor(SK_ColorBLACK);
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimulateDrawEvent();
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLACK));
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->DeAllocate();
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) {
744a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
745a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      1280,
746a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      720,
747a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      -2,
748a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
749a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
750a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
751a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
752a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI,
753a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          FROM_HERE,
754a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          base::Bind(&media::VideoCaptureDevice::Allocate,
755a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                     base::Unretained(device()),
756a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                     capture_format,
757a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                     consumer()));
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError());
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
762a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  media::VideoCaptureCapability capture_format(
763a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestWidth,
764a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestHeight,
765a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kTestFramesPerSecond,
766a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::VideoCaptureCapability::kI420,
767a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      0,
768a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      false,
769a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      media::ConstantResolutionVideoCaptureDevice);
770a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  device()->Allocate(capture_format, consumer());
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1x1 is too small to process; we intend for this to result in an error.
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source()->SetCopyResultSize(1, 1);
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source()->SetSolidColor(SK_ColorRED);
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->Start();
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // These frames ought to be dropped during the Render stage. Let
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // several captures to happen.
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Now push some good frames through; they should be processed normally.
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source()->SetCopyResultSize(kTestWidth, kTestHeight);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source()->SetSolidColor(SK_ColorGREEN);
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  source()->SetSolidColor(SK_ColorRED);
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device()->Stop();
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device()->DeAllocate();
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
796c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
797c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace content
798