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 |