123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// found in the LICENSE file. 423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/bind.h" 646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/callback_helpers.h" 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/message_loop/message_loop.h" 846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/run_loop.h" 923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/child/child_process.h" 1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/renderer/media_stream_video_sink.h" 1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/renderer/media/media_stream_video_capturer_source.h" 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/renderer/media/media_stream_video_track.h" 1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/renderer/media/mock_media_constraint_factory.h" 1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "media/base/bind_to_current_loop.h" 1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h" 1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace content { 2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class MockVideoCapturerDelegate : public VideoCapturerDelegate { 2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public: 2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) explicit MockVideoCapturerDelegate(const StreamDeviceInfo& device_info) 2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) : VideoCapturerDelegate(device_info) {} 2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu MOCK_METHOD3(StartCapture, 2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void(const media::VideoCaptureParams& params, 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const VideoCaptureDeliverFrameCB& new_frame_callback, 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const RunningCallback& running_callback)); 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MOCK_METHOD0(StopCapture, void()); 3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private: 3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) virtual ~MockVideoCapturerDelegate() {} 3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}; 3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class MediaStreamVideoCapturerSourceTest : public testing::Test { 3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public: 38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) MediaStreamVideoCapturerSourceTest() 39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) : child_process_(new ChildProcess()), 40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) source_(NULL) { 41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void InitWithDeviceInfo(const StreamDeviceInfo& device_info) { 4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) delegate_ = new MockVideoCapturerDelegate(device_info); 4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) source_ = new MediaStreamVideoCapturerSource( 4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) device_info, 4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) MediaStreamSource::SourceStoppedCallback(), 480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch delegate_); 4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"), 5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) blink::WebMediaStreamSource::TypeVideo, 5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::UTF8ToUTF16("dummy_source_name")); 5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) webkit_source_.setExtraData(source_); 5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch blink::WebMediaStreamTrack StartSource() { 5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) MockMediaConstraintFactory factory; 58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bool enabled = true; 590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // CreateVideoTrack will trigger OnConstraintsApplied. 600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return MediaStreamVideoTrack::CreateVideoTrack( 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch source_, factory.CreateWebMediaConstraints(), 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind( 63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch &MediaStreamVideoCapturerSourceTest::OnConstraintsApplied, 64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Unretained(this)), 650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch enabled); 6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MockVideoCapturerDelegate& mock_delegate() { 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return *static_cast<MockVideoCapturerDelegate*>(delegate_.get()); 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) protected: 7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void OnConstraintsApplied(MediaStreamSource* source, bool success) { 7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::MessageLoopForUI message_loop_; 77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scoped_ptr<ChildProcess> child_process_; 7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) blink::WebMediaStreamSource webkit_source_; 7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) MediaStreamVideoCapturerSource* source_; // owned by webkit_source. 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_refptr<VideoCapturerDelegate> delegate_; 8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}; 8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) { 8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) StreamDeviceInfo device_info; 8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE; 8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) InitWithDeviceInfo(device_info); 8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_CALL(mock_delegate(), StartCapture( 8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::Field(&media::VideoCaptureParams::allow_resolution_change, true), 9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::_, 9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::_)).Times(1); 920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch blink::WebMediaStreamTrack track = StartSource(); 930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // When the track goes out of scope, the source will be stopped. 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_CALL(mock_delegate(), StopCapture()); 9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, 9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DesktopCaptureAllowResolutionChange) { 9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) StreamDeviceInfo device_info; 10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE; 10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) InitWithDeviceInfo(device_info); 10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_CALL(mock_delegate(), StartCapture( 10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::Field(&media::VideoCaptureParams::allow_resolution_change, true), 10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::_, 10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) testing::_)).Times(1); 1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch blink::WebMediaStreamTrack track = StartSource(); 1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // When the track goes out of scope, the source will be stopped. 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_CALL(mock_delegate(), StopCapture()); 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, Ended) { 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StreamDeviceInfo device_info; 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE; 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delegate_ = new VideoCapturerDelegate(device_info); 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_ = new MediaStreamVideoCapturerSource( 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) device_info, 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaStreamSource::SourceStoppedCallback(), 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delegate_); 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"), 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) blink::WebMediaStreamSource::TypeVideo, 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::UTF8ToUTF16("dummy_source_name")); 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webkit_source_.setExtraData(source_); 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) blink::WebMediaStreamTrack track = StartSource(); 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) message_loop_.RunUntilIdle(); 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED); 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) message_loop_.RunUntilIdle(); 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webkit_source_.readyState()); 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR); 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) message_loop_.RunUntilIdle(); 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webkit_source_.readyState()); 13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class FakeMediaStreamVideoSink : public MediaStreamVideoSink { 13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public: 14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FakeMediaStreamVideoSink(base::TimeTicks* capture_time, 14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Closure got_frame_cb) 14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) : capture_time_(capture_time), 14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) got_frame_cb_(got_frame_cb) { 14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame, 14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const media::VideoCaptureFormat& format, 14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::TimeTicks& capture_time) { 14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) *capture_time_ = capture_time; 15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::ResetAndReturn(&got_frame_cb_).Run(); 15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private: 15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeTicks* capture_time_; 15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Closure got_frame_cb_; 15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}; 15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTime) { 15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) StreamDeviceInfo device_info; 16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE; 16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) InitWithDeviceInfo(device_info); 16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) VideoCaptureDeliverFrameCB deliver_frame_cb; 16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) VideoCapturerDelegate::RunningCallback running_cb; 16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) EXPECT_CALL(mock_delegate(), StartCapture( 16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) testing::_, 16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) testing::_, 16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) testing::_)) 17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) .Times(1) 17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) .WillOnce(testing::DoAll(testing::SaveArg<1>(&deliver_frame_cb), 17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) testing::SaveArg<2>(&running_cb))); 17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) EXPECT_CALL(mock_delegate(), StopCapture()); 17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) blink::WebMediaStreamTrack track = StartSource(); 17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) running_cb.Run(true); 17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::RunLoop run_loop; 17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeTicks reference_capture_time = 17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeTicks::FromInternalValue(60013); 18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeTicks capture_time; 18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FakeMediaStreamVideoSink fake_sink( 18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) &capture_time, 18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) media::BindToCurrentLoop(run_loop.QuitClosure())); 18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FakeMediaStreamVideoSink::AddToVideoTrack( 18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) &fake_sink, 18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame, 18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Unretained(&fake_sink)), 18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) track); 18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) child_process_->io_message_loop()->PostTask( 19046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FROM_HERE, 19146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(deliver_frame_cb, 19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)), 19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) media::VideoCaptureFormat(), 19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) reference_capture_time)); 19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) run_loop.Run(); 19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink, track); 19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) EXPECT_EQ(reference_capture_time, capture_time); 19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 20023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} // namespace content 201