OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/renderer/media/video_track_recorder.h" | 5 #include "content/renderer/media/video_track_recorder.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
(...skipping 22 matching lines...) Expand all Loading... | |
33 using ::testing::SaveArg; | 33 using ::testing::SaveArg; |
34 using ::testing::TestWithParam; | 34 using ::testing::TestWithParam; |
35 using ::testing::ValuesIn; | 35 using ::testing::ValuesIn; |
36 | 36 |
37 namespace content { | 37 namespace content { |
38 | 38 |
39 ACTION_P(RunClosure, closure) { | 39 ACTION_P(RunClosure, closure) { |
40 closure.Run(); | 40 closure.Run(); |
41 } | 41 } |
42 | 42 |
43 // VideoFrame holding ARGB memory-backed pixels (VideoFrame has no public API | |
44 // surface for creating this type of frames nor their storage). | |
45 class ARGBVideoFrame : public media::VideoFrame { | |
46 public: | |
47 ARGBVideoFrame(const gfx::Size& size) | |
48 : VideoFrame(media::PIXEL_FORMAT_ARGB, | |
49 STORAGE_OWNED_MEMORY, | |
50 size, | |
51 gfx::Rect(size), | |
52 size, | |
53 base::TimeDelta()), | |
54 buffer_(size.GetArea()) { | |
55 set_data(kARGBPlane, buffer_.data()); | |
56 set_stride(kARGBPlane, size.GetArea()); | |
57 } | |
58 | |
59 private: | |
60 ~ARGBVideoFrame() final {} | |
61 | |
62 std::vector<uint8_t> buffer_; | |
63 DISALLOW_COPY_AND_ASSIGN(ARGBVideoFrame); | |
64 }; | |
65 | |
43 const VideoTrackRecorder::CodecId kTrackRecorderTestCodec[] = { | 66 const VideoTrackRecorder::CodecId kTrackRecorderTestCodec[] = { |
44 VideoTrackRecorder::CodecId::VP8, | 67 VideoTrackRecorder::CodecId::VP8, |
45 VideoTrackRecorder::CodecId::VP9 | 68 VideoTrackRecorder::CodecId::VP9 |
46 #if BUILDFLAG(RTC_USE_H264) | 69 #if BUILDFLAG(RTC_USE_H264) |
47 , VideoTrackRecorder::CodecId::H264 | 70 , VideoTrackRecorder::CodecId::H264 |
48 #endif | 71 #endif |
49 }; | 72 }; |
50 | 73 |
74 // Typical frame size; cannot be arbitrarily small, should be reasonable. | |
75 static const gfx::Size kFrameSize(80,40); | |
76 | |
77 static void DummyReleaseMailboxCB(const gpu::SyncToken& sync_token) {} | |
78 | |
51 class VideoTrackRecorderTest | 79 class VideoTrackRecorderTest |
52 : public TestWithParam<VideoTrackRecorder::CodecId> { | 80 : public TestWithParam<VideoTrackRecorder::CodecId> { |
53 public: | 81 public: |
54 VideoTrackRecorderTest() | 82 VideoTrackRecorderTest() |
55 : mock_source_(new MockMediaStreamVideoSource(false)) { | 83 : mock_source_(new MockMediaStreamVideoSource(false)) { |
56 const blink::WebString webkit_track_id(base::UTF8ToUTF16("dummy")); | 84 const blink::WebString webkit_track_id(base::UTF8ToUTF16("dummy")); |
57 blink_source_.initialize(webkit_track_id, | 85 blink_source_.initialize(webkit_track_id, |
58 blink::WebMediaStreamSource::TypeVideo, | 86 blink::WebMediaStreamSource::TypeVideo, |
59 webkit_track_id); | 87 webkit_track_id); |
60 blink_source_.setExtraData(mock_source_); | 88 blink_source_.setExtraData(mock_source_); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 DISALLOW_COPY_AND_ASSIGN(VideoTrackRecorderTest); | 149 DISALLOW_COPY_AND_ASSIGN(VideoTrackRecorderTest); |
122 }; | 150 }; |
123 | 151 |
124 // Construct and destruct all objects, in particular |video_track_recorder_| and | 152 // Construct and destruct all objects, in particular |video_track_recorder_| and |
125 // its inner object(s). This is a non trivial sequence. | 153 // its inner object(s). This is a non trivial sequence. |
126 TEST_P(VideoTrackRecorderTest, ConstructAndDestruct) {} | 154 TEST_P(VideoTrackRecorderTest, ConstructAndDestruct) {} |
127 | 155 |
128 // Creates the encoder and encodes 2 frames of the same size; the encoder should | 156 // Creates the encoder and encodes 2 frames of the same size; the encoder should |
129 // be initialised and produce a keyframe, then a non-keyframe. Finally a frame | 157 // be initialised and produce a keyframe, then a non-keyframe. Finally a frame |
130 // of larger size is sent and is expected to be encoded as a keyframe. | 158 // of larger size is sent and is expected to be encoded as a keyframe. |
131 TEST_P(VideoTrackRecorderTest, VideoEncoding) { | 159 TEST_P(VideoTrackRecorderTest, Encoding) { |
132 // |frame_size| cannot be arbitrarily small, should be reasonable. | |
133 const gfx::Size frame_size(160, 80); | |
134 const scoped_refptr<VideoFrame> video_frame = | 160 const scoped_refptr<VideoFrame> video_frame = |
135 VideoFrame::CreateBlackFrame(frame_size); | 161 VideoFrame::CreateBlackFrame(kFrameSize); |
136 const double kFrameRate = 60.0f; | 162 const double kFrameRate = 60.0f; |
137 video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, | 163 video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, |
138 kFrameRate); | 164 kFrameRate); |
139 | 165 |
140 InSequence s; | 166 InSequence s; |
141 const base::TimeTicks timeticks_now = base::TimeTicks::Now(); | 167 const base::TimeTicks timeticks_now = base::TimeTicks::Now(); |
142 base::StringPiece first_frame_encoded_data; | 168 base::StringPiece first_frame_encoded_data; |
143 EXPECT_CALL(*this, DoOnEncodedVideo(video_frame, _, timeticks_now, true)) | 169 EXPECT_CALL(*this, DoOnEncodedVideo(video_frame, _, timeticks_now, true)) |
144 .Times(1) | 170 .Times(1) |
145 .WillOnce(SaveArg<1>(&first_frame_encoded_data)); | 171 .WillOnce(SaveArg<1>(&first_frame_encoded_data)); |
(...skipping 25 matching lines...) Expand all Loading... | |
171 run_loop.Run(); | 197 run_loop.Run(); |
172 | 198 |
173 const size_t kEncodedSizeThreshold = 14; | 199 const size_t kEncodedSizeThreshold = 14; |
174 EXPECT_GE(first_frame_encoded_data.size(), kEncodedSizeThreshold); | 200 EXPECT_GE(first_frame_encoded_data.size(), kEncodedSizeThreshold); |
175 EXPECT_GE(second_frame_encoded_data.size(), kEncodedSizeThreshold); | 201 EXPECT_GE(second_frame_encoded_data.size(), kEncodedSizeThreshold); |
176 EXPECT_GE(third_frame_encoded_data.size(), kEncodedSizeThreshold); | 202 EXPECT_GE(third_frame_encoded_data.size(), kEncodedSizeThreshold); |
177 | 203 |
178 Mock::VerifyAndClearExpectations(this); | 204 Mock::VerifyAndClearExpectations(this); |
179 } | 205 } |
180 | 206 |
207 // Verifies that a Mappable ARGB Video Frame can be correctly encoded. | |
208 TEST_P(VideoTrackRecorderTest, EncodingARGBFrame) { | |
209 const scoped_refptr<VideoFrame> video_frame(new ARGBVideoFrame(kFrameSize)); | |
210 | |
211 InSequence s; | |
212 base::RunLoop run_loop; | |
213 base::Closure quit_closure = run_loop.QuitClosure(); | |
214 scoped_refptr<VideoFrame> encoded_frame; | |
215 base::StringPiece encoded_data; | |
216 EXPECT_CALL(*this, DoOnEncodedVideo(_, _, _, true)) | |
217 .Times(1) | |
218 .WillOnce(DoAll(SaveArg<0>(&encoded_frame), | |
219 SaveArg<1>(&encoded_data), | |
220 RunClosure(quit_closure))); | |
221 Encode(video_frame, base::TimeTicks::Now()); | |
222 run_loop.Run(); | |
223 | |
224 EXPECT_EQ(media::PIXEL_FORMAT_I420, encoded_frame->format()); | |
225 EXPECT_EQ(video_frame->coded_size(), encoded_frame->coded_size()); | |
226 | |
227 const size_t kEncodedSizeThreshold = 14; | |
228 EXPECT_GE(encoded_data.size(), kEncodedSizeThreshold); | |
229 | |
230 Mock::VerifyAndClearExpectations(this); | |
231 } | |
232 | |
233 // Tests that a not IsMappable() frame is encoded as a full black one. | |
234 TEST_P(VideoTrackRecorderTest, EncodingNonMappableFrame) { | |
235 gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes] = {}; | |
236 const scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapNativeTextures( | |
237 media::PIXEL_FORMAT_ARGB, mailbox_holders, | |
238 base::Bind(&DummyReleaseMailboxCB), kFrameSize, gfx::Rect(kFrameSize), | |
239 kFrameSize, base::TimeDelta()); | |
240 ASSERT_FALSE(video_frame->IsMappable()); | |
241 | |
242 InSequence s; | |
243 base::RunLoop run_loop; | |
244 base::Closure quit_closure = run_loop.QuitClosure(); | |
245 scoped_refptr<VideoFrame> encoded_frame; | |
246 EXPECT_CALL(*this, DoOnEncodedVideo(_, _, _, true)) | |
247 .Times(1) | |
248 .WillOnce(DoAll(SaveArg<0>(&encoded_frame), RunClosure(quit_closure))); | |
249 Encode(video_frame, base::TimeTicks::Now()); | |
250 run_loop.Run(); | |
251 | |
252 // |encoded_frame| should be full-black, since |video_frame| is not mappable. | |
253 ASSERT_EQ(media::PIXEL_FORMAT_YV12, encoded_frame->format()); | |
254 EXPECT_EQ(video_frame->coded_size(), encoded_frame->coded_size()); | |
255 const uint8_t* y_plane = encoded_frame->data(media::VideoFrame::kYPlane); | |
emircan
2016/07/12 22:57:00
Can we have this in a for loop?
mcasas
2016/07/13 00:45:31
Do you mean:
for (int i = 0; i < y_plane_size; ++
| |
256 const int y_plane_size = encoded_frame->row_bytes(media::VideoFrame::kYPlane); | |
257 for (int i = 0; i < y_plane_size; ++i) | |
258 EXPECT_EQ(0u, y_plane[i]); | |
259 const uint8_t* u_plane = encoded_frame->data(media::VideoFrame::kUPlane); | |
260 const int u_plane_size = encoded_frame->row_bytes(media::VideoFrame::kUPlane); | |
261 for (int i = 0; i < u_plane_size; ++i) | |
262 EXPECT_EQ(0x80, u_plane[i]); | |
263 const uint8_t* v_plane = encoded_frame->data(media::VideoFrame::kVPlane); | |
264 const int v_plane_size = encoded_frame->row_bytes(media::VideoFrame::kVPlane); | |
265 for (int i = 0; i < v_plane_size; ++i) | |
266 EXPECT_EQ(0x80, v_plane[i]); | |
267 | |
268 Mock::VerifyAndClearExpectations(this); | |
269 } | |
270 | |
181 INSTANTIATE_TEST_CASE_P(, | 271 INSTANTIATE_TEST_CASE_P(, |
182 VideoTrackRecorderTest, | 272 VideoTrackRecorderTest, |
183 ValuesIn(kTrackRecorderTestCodec)); | 273 ValuesIn(kTrackRecorderTestCodec)); |
184 | 274 |
185 } // namespace content | 275 } // namespace content |
OLD | NEW |