| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/optional.h" | 8 #include "base/optional.h" |
| 9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
| 10 #include "content/child/child_process.h" | 10 #include "content/child/child_process.h" |
| 11 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" | 11 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" |
| 12 #include "gpu/command_buffer/common/mailbox_holder.h" | 12 #include "gpu/command_buffer/common/mailbox_holder.h" |
| 13 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 static void ReleaseMailboxCB(const gpu::SyncToken& sync_token) {} | 17 static void ReleaseMailboxCB(const gpu::SyncToken& sync_token) {} |
| 18 } // anonymous namespace | 18 } // anonymous namespace |
| 19 | 19 |
| 20 namespace content { | 20 namespace content { |
| 21 | 21 |
| 22 class WebRtcVideoCapturerAdapterTest | 22 class WebRtcVideoCapturerAdapterTest |
| 23 : public rtc::VideoSinkInterface<webrtc::VideoFrame>, | 23 : public rtc::VideoSinkInterface<webrtc::VideoFrame>, |
| 24 public ::testing::Test { | 24 public ::testing::Test { |
| 25 public: | 25 public: |
| 26 WebRtcVideoCapturerAdapterTest() | 26 WebRtcVideoCapturerAdapterTest() |
| 27 : adapter_(false), | 27 : adapter_(new WebRtcVideoCapturerAdapter( |
| 28 false, |
| 29 blink::WebMediaStreamTrack::ContentHintType::None)), |
| 28 output_frame_width_(0), | 30 output_frame_width_(0), |
| 29 output_frame_height_(0) { | 31 output_frame_height_(0) { |
| 30 adapter_.AddOrUpdateSink(this, rtc::VideoSinkWants()); | 32 adapter_->AddOrUpdateSink(this, rtc::VideoSinkWants()); |
| 31 } | 33 } |
| 32 ~WebRtcVideoCapturerAdapterTest() override { | 34 ~WebRtcVideoCapturerAdapterTest() override { adapter_->RemoveSink(this); } |
| 33 adapter_.RemoveSink(this); | |
| 34 } | |
| 35 | 35 |
| 36 void TestSourceCropFrame(int capture_width, | 36 void TestSourceCropFrame(int capture_width, |
| 37 int capture_height, | 37 int capture_height, |
| 38 int cropped_width, | 38 int cropped_width, |
| 39 int cropped_height, | 39 int cropped_height, |
| 40 int natural_width, | 40 int natural_width, |
| 41 int natural_height) { | 41 int natural_height) { |
| 42 const int horiz_crop = ((capture_width - cropped_width) / 2); | 42 const int horiz_crop = ((capture_width - cropped_width) / 2); |
| 43 const int vert_crop = ((capture_height - cropped_height) / 2); | 43 const int vert_crop = ((capture_height - cropped_height) / 2); |
| 44 | 44 |
| 45 gfx::Size coded_size(capture_width, capture_height); | 45 gfx::Size coded_size(capture_width, capture_height); |
| 46 gfx::Size natural_size(natural_width, natural_height); | 46 gfx::Size natural_size(natural_width, natural_height); |
| 47 gfx::Rect view_rect(horiz_crop, vert_crop, cropped_width, cropped_height); | 47 gfx::Rect view_rect(horiz_crop, vert_crop, cropped_width, cropped_height); |
| 48 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::CreateFrame( | 48 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::CreateFrame( |
| 49 media::PIXEL_FORMAT_I420, coded_size, view_rect, natural_size, | 49 media::PIXEL_FORMAT_I420, coded_size, view_rect, natural_size, |
| 50 base::TimeDelta()); | 50 base::TimeDelta()); |
| 51 adapter_.OnFrameCaptured(frame); | 51 adapter_->OnFrameCaptured(frame); |
| 52 EXPECT_EQ(natural_width, output_frame_width_); | 52 EXPECT_EQ(natural_width, output_frame_width_); |
| 53 EXPECT_EQ(natural_height, output_frame_height_); | 53 EXPECT_EQ(natural_height, output_frame_height_); |
| 54 } | 54 } |
| 55 | 55 |
| 56 void TestSourceTextureFrame() { | 56 void TestSourceTextureFrame() { |
| 57 EXPECT_TRUE(message_loop_.IsCurrent()); | 57 EXPECT_TRUE(message_loop_.IsCurrent()); |
| 58 gpu::MailboxHolder holders[media::VideoFrame::kMaxPlanes] = { | 58 gpu::MailboxHolder holders[media::VideoFrame::kMaxPlanes] = { |
| 59 gpu::MailboxHolder(gpu::Mailbox::Generate(), gpu::SyncToken(), 5)}; | 59 gpu::MailboxHolder(gpu::Mailbox::Generate(), gpu::SyncToken(), 5)}; |
| 60 scoped_refptr<media::VideoFrame> frame = | 60 scoped_refptr<media::VideoFrame> frame = |
| 61 media::VideoFrame::WrapNativeTextures( | 61 media::VideoFrame::WrapNativeTextures( |
| 62 media::PIXEL_FORMAT_ARGB, holders, base::Bind(&ReleaseMailboxCB), | 62 media::PIXEL_FORMAT_ARGB, holders, base::Bind(&ReleaseMailboxCB), |
| 63 gfx::Size(10, 10), gfx::Rect(10, 10), gfx::Size(10, 10), | 63 gfx::Size(10, 10), gfx::Rect(10, 10), gfx::Size(10, 10), |
| 64 base::TimeDelta()); | 64 base::TimeDelta()); |
| 65 adapter_.OnFrameCaptured(frame); | 65 adapter_->OnFrameCaptured(frame); |
| 66 ASSERT_TRUE(output_frame_); | 66 ASSERT_TRUE(output_frame_); |
| 67 rtc::scoped_refptr<webrtc::VideoFrameBuffer> texture_frame = | 67 rtc::scoped_refptr<webrtc::VideoFrameBuffer> texture_frame = |
| 68 output_frame_->video_frame_buffer(); | 68 output_frame_->video_frame_buffer(); |
| 69 EXPECT_EQ(media::VideoFrame::STORAGE_OPAQUE, | 69 EXPECT_EQ(media::VideoFrame::STORAGE_OPAQUE, |
| 70 static_cast<media::VideoFrame*>(texture_frame->native_handle()) | 70 static_cast<media::VideoFrame*>(texture_frame->native_handle()) |
| 71 ->storage_type()); | 71 ->storage_type()); |
| 72 | 72 |
| 73 rtc::scoped_refptr<webrtc::VideoFrameBuffer> copied_frame = | 73 rtc::scoped_refptr<webrtc::VideoFrameBuffer> copied_frame = |
| 74 texture_frame->NativeToI420Buffer(); | 74 texture_frame->NativeToI420Buffer(); |
| 75 EXPECT_TRUE(copied_frame); | 75 EXPECT_TRUE(copied_frame); |
| 76 EXPECT_TRUE(copied_frame->DataY()); | 76 EXPECT_TRUE(copied_frame->DataY()); |
| 77 EXPECT_TRUE(copied_frame->DataU()); | 77 EXPECT_TRUE(copied_frame->DataU()); |
| 78 EXPECT_TRUE(copied_frame->DataV()); | 78 EXPECT_TRUE(copied_frame->DataV()); |
| 79 } | 79 } |
| 80 | 80 |
| 81 // rtc::VideoSinkInterface | 81 // rtc::VideoSinkInterface |
| 82 void OnFrame(const webrtc::VideoFrame& frame) override { | 82 void OnFrame(const webrtc::VideoFrame& frame) override { |
| 83 output_frame_ = base::Optional<webrtc::VideoFrame>(frame); | 83 output_frame_ = base::Optional<webrtc::VideoFrame>(frame); |
| 84 output_frame_width_ = frame.width(); | 84 output_frame_width_ = frame.width(); |
| 85 output_frame_height_ = frame.height(); | 85 output_frame_height_ = frame.height(); |
| 86 } | 86 } |
| 87 | 87 |
| 88 void TestContentHintResolutionAdaptation( |
| 89 bool is_screencast, |
| 90 blink::WebMediaStreamTrack::ContentHintType construction_content_hint, |
| 91 bool expect_initial_downscale, |
| 92 blink::WebMediaStreamTrack::ContentHintType set_content_hint, |
| 93 bool expect_final_downscale) { |
| 94 // Reset and configure adapter to the test. |
| 95 adapter_->RemoveSink(this); |
| 96 adapter_.reset(new WebRtcVideoCapturerAdapter(is_screencast, |
| 97 construction_content_hint)); |
| 98 |
| 99 const int kInputWidth = 1280; |
| 100 const int kInputHeight = 720; |
| 101 const gfx::Size kSize(kInputWidth, kInputHeight); |
| 102 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::CreateFrame( |
| 103 media::PIXEL_FORMAT_I420, kSize, gfx::Rect(kSize), kSize, |
| 104 base::TimeDelta()); |
| 105 |
| 106 // Request smaller scale to make sure scaling normally kicks in. |
| 107 rtc::VideoSinkWants wants; |
| 108 wants.max_pixel_count = rtc::Optional<int>(kInputWidth * kInputHeight / 2); |
| 109 adapter_->AddOrUpdateSink(this, wants); |
| 110 |
| 111 adapter_->OnFrameCaptured(frame); |
| 112 if (expect_initial_downscale) { |
| 113 EXPECT_LT(output_frame_width_, kInputWidth); |
| 114 EXPECT_LT(output_frame_height_, kInputHeight); |
| 115 } else { |
| 116 EXPECT_EQ(kInputWidth, output_frame_width_); |
| 117 EXPECT_EQ(kInputHeight, output_frame_height_); |
| 118 } |
| 119 |
| 120 adapter_->SetContentHint(set_content_hint); |
| 121 adapter_->OnFrameCaptured(frame); |
| 122 if (expect_final_downscale) { |
| 123 EXPECT_LT(output_frame_width_, kInputWidth); |
| 124 EXPECT_LT(output_frame_height_, kInputHeight); |
| 125 } else { |
| 126 EXPECT_EQ(kInputWidth, output_frame_width_); |
| 127 EXPECT_EQ(kInputHeight, output_frame_height_); |
| 128 } |
| 129 } |
| 130 |
| 88 private: | 131 private: |
| 89 const base::MessageLoopForIO message_loop_; | 132 const base::MessageLoopForIO message_loop_; |
| 90 const ChildProcess child_process_; | 133 const ChildProcess child_process_; |
| 91 | 134 |
| 92 WebRtcVideoCapturerAdapter adapter_; | 135 std::unique_ptr<WebRtcVideoCapturerAdapter> adapter_; |
| 93 base::Optional<webrtc::VideoFrame> output_frame_; | 136 base::Optional<webrtc::VideoFrame> output_frame_; |
| 94 int output_frame_width_; | 137 int output_frame_width_; |
| 95 int output_frame_height_; | 138 int output_frame_height_; |
| 96 }; | 139 }; |
| 97 | 140 |
| 98 TEST_F(WebRtcVideoCapturerAdapterTest, CropFrameTo640360) { | 141 TEST_F(WebRtcVideoCapturerAdapterTest, CropFrameTo640360) { |
| 99 TestSourceCropFrame(640, 480, 640, 360, 640, 360); | 142 TestSourceCropFrame(640, 480, 640, 360, 640, 360); |
| 100 } | 143 } |
| 101 | 144 |
| 102 TEST_F(WebRtcVideoCapturerAdapterTest, CropFrameTo320320) { | 145 TEST_F(WebRtcVideoCapturerAdapterTest, CropFrameTo320320) { |
| 103 TestSourceCropFrame(640, 480, 480, 480, 320, 320); | 146 TestSourceCropFrame(640, 480, 480, 480, 320, 320); |
| 104 } | 147 } |
| 105 | 148 |
| 106 TEST_F(WebRtcVideoCapturerAdapterTest, Scale720To640360) { | 149 TEST_F(WebRtcVideoCapturerAdapterTest, Scale720To640360) { |
| 107 TestSourceCropFrame(1280, 720, 1280, 720, 640, 360); | 150 TestSourceCropFrame(1280, 720, 1280, 720, 640, 360); |
| 108 } | 151 } |
| 109 | 152 |
| 110 TEST_F(WebRtcVideoCapturerAdapterTest, SendsWithCopyTextureFrameCallback) { | 153 TEST_F(WebRtcVideoCapturerAdapterTest, SendsWithCopyTextureFrameCallback) { |
| 111 TestSourceTextureFrame(); | 154 TestSourceTextureFrame(); |
| 112 } | 155 } |
| 113 | 156 |
| 157 TEST_F(WebRtcVideoCapturerAdapterTest, |
| 158 NonScreencastAdapterDoesNotAdaptContentHintDetail) { |
| 159 // Non-screenshare adapter should not adapt frames when detailed is set. |
| 160 TestContentHintResolutionAdaptation( |
| 161 false, blink::WebMediaStreamTrack::ContentHintType::None, true, |
| 162 blink::WebMediaStreamTrack::ContentHintType::VideoDetailed, false); |
| 163 } |
| 164 |
| 165 TEST_F(WebRtcVideoCapturerAdapterTest, |
| 166 NonScreencastAdapterAdaptsContentHintFluid) { |
| 167 // Non-screenshare adapter should still adapt frames when fluid is set. |
| 168 TestContentHintResolutionAdaptation( |
| 169 false, blink::WebMediaStreamTrack::ContentHintType::None, true, |
| 170 blink::WebMediaStreamTrack::ContentHintType::VideoFluid, true); |
| 171 } |
| 172 |
| 173 TEST_F(WebRtcVideoCapturerAdapterTest, |
| 174 ScreencastAdapterAdaptsContentHintFluid) { |
| 175 // Screenshare adapter should adapt frames when fluid is set. |
| 176 TestContentHintResolutionAdaptation( |
| 177 true, blink::WebMediaStreamTrack::ContentHintType::None, false, |
| 178 blink::WebMediaStreamTrack::ContentHintType::VideoFluid, true); |
| 179 } |
| 180 |
| 181 TEST_F(WebRtcVideoCapturerAdapterTest, |
| 182 ScreencastAdapterDoesNotAdaptContentHintDetailed) { |
| 183 // Screenshare adapter should still not adapt frames when detailed is set. |
| 184 TestContentHintResolutionAdaptation( |
| 185 true, blink::WebMediaStreamTrack::ContentHintType::None, false, |
| 186 blink::WebMediaStreamTrack::ContentHintType::VideoDetailed, false); |
| 187 } |
| 188 |
| 189 TEST_F(WebRtcVideoCapturerAdapterTest, RespectsConstructionTimeContentHint) { |
| 190 // Non-screenshare adapter constructed with detailed content hint should not |
| 191 // adapt before SetContentHint is run. |
| 192 TestContentHintResolutionAdaptation( |
| 193 false, blink::WebMediaStreamTrack::ContentHintType::VideoDetailed, false, |
| 194 blink::WebMediaStreamTrack::ContentHintType::VideoFluid, true); |
| 195 } |
| 196 |
| 114 } // namespace content | 197 } // namespace content |
| OLD | NEW |