Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / media_stream_video_source_unittest.cc
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
3 // found in the LICENSE file.
4
5 #include <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/child/child_process.h"
14 #include "content/renderer/media/media_stream_video_source.h"
15 #include "content/renderer/media/media_stream_video_track.h"
16 #include "content/renderer/media/mock_media_constraint_factory.h"
17 #include "content/renderer/media/mock_media_stream_video_sink.h"
18 #include "content/renderer/media/mock_media_stream_video_source.h"
19 #include "media/base/video_frame.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace content {
23
24 ACTION_P(RunClosure, closure) {
25   closure.Run();
26 }
27
28 class MediaStreamVideoSourceTest
29     : public ::testing::Test {
30  public:
31   MediaStreamVideoSourceTest()
32       : child_process_(new ChildProcess()),
33         number_of_successful_constraints_applied_(0),
34         number_of_failed_constraints_applied_(0),
35         mock_source_(new MockMediaStreamVideoSource(true)) {
36     media::VideoCaptureFormats formats;
37     formats.push_back(media::VideoCaptureFormat(
38         gfx::Size(1280, 720), 30, media::PIXEL_FORMAT_I420));
39     formats.push_back(media::VideoCaptureFormat(
40         gfx::Size(640, 480), 30, media::PIXEL_FORMAT_I420));
41     formats.push_back(media::VideoCaptureFormat(
42         gfx::Size(352, 288), 30, media::PIXEL_FORMAT_I420));
43     formats.push_back(media::VideoCaptureFormat(
44         gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420));
45     mock_source_->SetSupportedFormats(formats);
46     webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
47                               blink::WebMediaStreamSource::TypeVideo,
48                               base::UTF8ToUTF16("dummy_source_name"));
49     webkit_source_.setExtraData(mock_source_);
50   }
51
52  protected:
53   // Create a track that's associated with |webkit_source_|.
54   blink::WebMediaStreamTrack CreateTrack(
55       const std::string& id,
56       const blink::WebMediaConstraints& constraints) {
57     bool enabled = true;
58     return MediaStreamVideoTrack::CreateVideoTrack(
59         mock_source_, constraints,
60         base::Bind(
61             &MediaStreamVideoSourceTest::OnConstraintsApplied,
62             base::Unretained(this)),
63         enabled);
64   }
65
66   blink::WebMediaStreamTrack CreateTrackAndStartSource(
67       const blink::WebMediaConstraints& constraints,
68       int expected_width,
69       int expected_height,
70       int expected_frame_rate) {
71     blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
72
73     mock_source_->CompleteGetSupportedFormats();
74     const media::VideoCaptureParams& format = mock_source()->start_params();
75     EXPECT_EQ(expected_width, format.requested_format.frame_size.width());
76     EXPECT_EQ(expected_height, format.requested_format.frame_size.height());
77     EXPECT_EQ(expected_frame_rate, format.requested_format.frame_rate);
78
79     EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks());
80     mock_source_->StartMockedSource();
81     // Once the source has started successfully we expect that the
82     // ConstraintsCallback in MediaStreamSource::AddTrack completes.
83     EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
84     return track;
85   }
86
87   int NumberOfSuccessConstraintsCallbacks() const {
88     return number_of_successful_constraints_applied_;
89   }
90
91   int NumberOfFailedConstraintsCallbacks() const {
92     return number_of_failed_constraints_applied_;
93   }
94
95   MockMediaStreamVideoSource* mock_source() { return mock_source_; }
96
97   // Test that the source crops to the requested max width and
98   // height even though the camera delivers a larger frame.
99   void TestSourceCropFrame(int capture_width,
100                            int capture_height,
101                            const blink::WebMediaConstraints& constraints,
102                            int expected_width,
103                            int expected_height) {
104     // Expect the source to start capture with the supported resolution.
105     blink::WebMediaStreamTrack track =
106         CreateTrackAndStartSource(constraints, capture_width, capture_height,
107                                   30);
108
109     MockMediaStreamVideoSink sink;
110     MediaStreamVideoSink::AddToVideoTrack(
111         &sink, sink.GetDeliverFrameCB(), track);
112     DeliverVideoFrameAndWaitForRenderer(capture_width, capture_height, &sink);
113     EXPECT_EQ(1, sink.number_of_frames());
114
115     // Expect the delivered frame to be cropped.
116     EXPECT_EQ(expected_height, sink.frame_size().height());
117     EXPECT_EQ(expected_width, sink.frame_size().width());
118     MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
119   }
120
121   void DeliverVideoFrameAndWaitForRenderer(int width, int height,
122                                            MockMediaStreamVideoSink* sink) {
123     base::RunLoop run_loop;
124     base::Closure quit_closure = run_loop.QuitClosure();
125     EXPECT_CALL(*sink, OnVideoFrame()).WillOnce(
126         RunClosure(quit_closure));
127     scoped_refptr<media::VideoFrame> frame =
128               media::VideoFrame::CreateBlackFrame(gfx::Size(width, height));
129     mock_source()->DeliverVideoFrame(frame);
130     run_loop.Run();
131   }
132
133
134   void ReleaseTrackAndSourceOnAddTrackCallback(
135       const blink::WebMediaStreamTrack& track_to_release) {
136     track_to_release_ = track_to_release;
137   }
138
139  private:
140   void OnConstraintsApplied(MediaStreamSource* source, bool success) {
141     ASSERT_EQ(source, webkit_source_.extraData());
142
143     if (success)
144       ++number_of_successful_constraints_applied_;
145     else
146       ++number_of_failed_constraints_applied_;
147
148     if (!track_to_release_.isNull()) {
149       mock_source_ = NULL;
150       webkit_source_.reset();
151       track_to_release_.reset();
152     }
153   }
154   scoped_ptr<ChildProcess> child_process_;
155   base::MessageLoopForUI message_loop_;
156   blink::WebMediaStreamTrack track_to_release_;
157   int number_of_successful_constraints_applied_;
158   int number_of_failed_constraints_applied_;
159   blink::WebMediaStreamSource webkit_source_;
160   // |mock_source_| is owned by |webkit_source_|.
161   MockMediaStreamVideoSource* mock_source_;
162 };
163
164 TEST_F(MediaStreamVideoSourceTest, AddTrackAndStartSource) {
165   blink::WebMediaConstraints constraints;
166   constraints.initialize();
167   blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
168   mock_source()->CompleteGetSupportedFormats();
169   mock_source()->StartMockedSource();
170   EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
171 }
172
173 TEST_F(MediaStreamVideoSourceTest, AddTwoTracksBeforeSourceStarts) {
174   blink::WebMediaConstraints constraints;
175   constraints.initialize();
176   blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
177   mock_source()->CompleteGetSupportedFormats();
178   blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
179   EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks());
180   mock_source()->StartMockedSource();
181   EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
182 }
183
184 TEST_F(MediaStreamVideoSourceTest, AddTrackAfterSourceStarts) {
185   blink::WebMediaConstraints constraints;
186   constraints.initialize();
187   blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
188   mock_source()->CompleteGetSupportedFormats();
189   mock_source()->StartMockedSource();
190   EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
191   blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
192   EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
193 }
194
195 TEST_F(MediaStreamVideoSourceTest, AddTrackAndFailToStartSource) {
196   blink::WebMediaConstraints constraints;
197   constraints.initialize();
198   blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
199   mock_source()->CompleteGetSupportedFormats();
200   mock_source()->FailToStartMockedSource();
201   EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
202 }
203
204 TEST_F(MediaStreamVideoSourceTest, AddTwoTracksBeforeGetSupportedFormats) {
205   blink::WebMediaConstraints constraints;
206   constraints.initialize();
207   blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
208   blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
209   mock_source()->CompleteGetSupportedFormats();
210   mock_source()->StartMockedSource();
211   EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
212 }
213
214 // Test that the capture output is CIF if we set max constraints to CIF.
215 // and the capture device support CIF.
216 TEST_F(MediaStreamVideoSourceTest, MandatoryConstraintCif5Fps) {
217   MockMediaConstraintFactory factory;
218   factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 352);
219   factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 288);
220   factory.AddMandatory(MediaStreamVideoSource::kMaxFrameRate, 5);
221
222   CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 352, 288, 5);
223 }
224
225 // Test that the capture output is 720P if the camera support it and the
226 // optional constraint is set to 720P.
227 TEST_F(MediaStreamVideoSourceTest, MandatoryMinVgaOptional720P) {
228   MockMediaConstraintFactory factory;
229   factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 640);
230   factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
231   factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
232   factory.AddOptional(MediaStreamVideoSource::kMinAspectRatio,
233                       1280.0 / 720);
234
235   CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 1280, 720, 30);
236 }
237
238 // Test that the capture output have aspect ratio 4:3 if a mandatory constraint
239 // require it even if an optional constraint request a higher resolution
240 // that don't have this aspect ratio.
241 TEST_F(MediaStreamVideoSourceTest, MandatoryAspectRatio4To3) {
242   MockMediaConstraintFactory factory;
243   factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 640);
244   factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
245   factory.AddMandatory(MediaStreamVideoSource::kMaxAspectRatio,
246                        640.0 / 480);
247   factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
248
249   CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 640, 480, 30);
250 }
251
252 // Test that AddTrack fail if the mandatory aspect ratio
253 // is set higher than supported.
254 TEST_F(MediaStreamVideoSourceTest, MandatoryAspectRatioTooHigh) {
255   MockMediaConstraintFactory factory;
256   factory.AddMandatory(MediaStreamVideoSource::kMinAspectRatio, 2);
257   blink::WebMediaStreamTrack track = CreateTrack(
258       "123", factory.CreateWebMediaConstraints());
259   mock_source()->CompleteGetSupportedFormats();
260   EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
261 }
262
263 // Test that its safe to release the last reference of a blink track and the
264 // source during the callback if adding a track succeeds.
265 TEST_F(MediaStreamVideoSourceTest, ReleaseTrackAndSourceOnSuccessCallBack) {
266   MockMediaConstraintFactory factory;
267   {
268     blink::WebMediaStreamTrack track =
269         CreateTrack("123", factory.CreateWebMediaConstraints());
270     ReleaseTrackAndSourceOnAddTrackCallback(track);
271   }
272   mock_source()->CompleteGetSupportedFormats();
273   mock_source()->StartMockedSource();
274   EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
275 }
276
277 // Test that its safe to release the last reference of a blink track and the
278 // source during the callback if adding a track fails.
279 TEST_F(MediaStreamVideoSourceTest, ReleaseTrackAndSourceOnFailureCallBack) {
280   MockMediaConstraintFactory factory;
281   factory.AddMandatory(MediaStreamVideoSource::kMinAspectRatio, 2);
282   {
283     blink::WebMediaStreamTrack track =
284         CreateTrack("123", factory.CreateWebMediaConstraints());
285     ReleaseTrackAndSourceOnAddTrackCallback(track);
286   }
287   mock_source()->CompleteGetSupportedFormats();
288   EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
289 }
290
291 // Test that the source ignores an optional aspect ratio that is higher than
292 // supported.
293 TEST_F(MediaStreamVideoSourceTest, OptionalAspectRatioTooHigh) {
294   MockMediaConstraintFactory factory;
295   factory.AddOptional(MediaStreamVideoSource::kMinAspectRatio, 2);
296   blink::WebMediaStreamTrack track = CreateTrack(
297       "123", factory.CreateWebMediaConstraints());
298   mock_source()->CompleteGetSupportedFormats();
299
300   const media::VideoCaptureParams& params = mock_source()->start_params();
301   double aspect_ratio =
302       static_cast<double>(params.requested_format.frame_size.width()) /
303       params.requested_format.frame_size.height();
304   EXPECT_LT(aspect_ratio, 2);
305 }
306
307 // Test that the source starts video with the default resolution if the
308 // that is the only supported.
309 TEST_F(MediaStreamVideoSourceTest, DefaultCapability) {
310   media::VideoCaptureFormats formats;
311   formats.push_back(media::VideoCaptureFormat(
312       gfx::Size(MediaStreamVideoSource::kDefaultWidth,
313                 MediaStreamVideoSource::kDefaultHeight),
314       MediaStreamVideoSource::kDefaultFrameRate,
315       media::PIXEL_FORMAT_I420));
316   mock_source()->SetSupportedFormats(formats);
317
318   blink::WebMediaConstraints constraints;
319   constraints.initialize();
320   CreateTrackAndStartSource(constraints,
321                             MediaStreamVideoSource::kDefaultWidth,
322                             MediaStreamVideoSource::kDefaultHeight,
323                             30);
324 }
325
326 TEST_F(MediaStreamVideoSourceTest, InvalidMandatoryConstraint) {
327   MockMediaConstraintFactory factory;
328   factory.AddMandatory("weird key", 640);
329   blink::WebMediaStreamTrack track = CreateTrack(
330       "123", factory.CreateWebMediaConstraints());
331   mock_source()->CompleteGetSupportedFormats();
332   EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
333 }
334
335 // Test that the source ignores an unknown optional constraint.
336 TEST_F(MediaStreamVideoSourceTest, InvalidOptionalConstraint) {
337   MockMediaConstraintFactory factory;
338   factory.AddOptional("weird key", 640);
339
340   CreateTrackAndStartSource(factory.CreateWebMediaConstraints(),
341                             MediaStreamVideoSource::kDefaultWidth,
342                             MediaStreamVideoSource::kDefaultHeight,
343                             30);
344 }
345
346 // Tests that the source starts video with the max width and height set by
347 // constraints for screencast.
348 TEST_F(MediaStreamVideoSourceTest, ScreencastResolutionWithConstraint) {
349   media::VideoCaptureFormats formats;
350       formats.push_back(media::VideoCaptureFormat(
351           gfx::Size(480, 270), 30, media::PIXEL_FORMAT_I420));
352   mock_source()->SetSupportedFormats(formats);
353   MockMediaConstraintFactory factory;
354   factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 480);
355   factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 270);
356
357   blink::WebMediaStreamTrack track = CreateTrackAndStartSource(
358       factory.CreateWebMediaConstraints(), 480, 270, 30);
359   EXPECT_EQ(480, mock_source()->max_requested_height());
360   EXPECT_EQ(270, mock_source()->max_requested_width());
361 }
362
363 // Test that optional constraints are applied in order.
364 TEST_F(MediaStreamVideoSourceTest, OptionalConstraints) {
365   MockMediaConstraintFactory factory;
366   // Min width of 2056 pixels can not be fulfilled.
367   factory.AddOptional(MediaStreamVideoSource::kMinWidth, 2056);
368   factory.AddOptional(MediaStreamVideoSource::kMinWidth, 641);
369   // Since min width is set to 641 pixels, max width 640 can not be fulfilled.
370   factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
371   CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 1280, 720, 30);
372 }
373
374 // Test that the source crops to the requested max width and
375 // height even though the camera delivers a larger frame.
376 TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameOptional640360) {
377   MockMediaConstraintFactory factory;
378   factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
379   factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 360);
380   TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 640, 360);
381 }
382
383 TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameMandatory640360) {
384   MockMediaConstraintFactory factory;
385   factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 640);
386   factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 360);
387   TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 640, 360);
388 }
389
390 TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameMandatory732489) {
391   MockMediaConstraintFactory factory;
392   factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 732);
393   factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 489);
394   factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 732);
395   factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 489);
396   TestSourceCropFrame(1280, 720, factory.CreateWebMediaConstraints(), 732, 489);
397 }
398
399 // Test that the source crops to the requested max width and
400 // height even though the requested frame has odd size.
401 TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrame637359) {
402   MockMediaConstraintFactory factory;
403   factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 637);
404   factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 359);
405   TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 637, 359);
406 }
407
408 TEST_F(MediaStreamVideoSourceTest, DeliverSmallerSizeWhenTooLargeMax) {
409   MockMediaConstraintFactory factory;
410   factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 1920);
411   factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 1080);
412   factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
413   factory.AddOptional(MediaStreamVideoSource::kMinHeight, 720);
414   TestSourceCropFrame(1280, 720, factory.CreateWebMediaConstraints(),
415                       1280, 720);
416 }
417
418 // Test that a source can change the frame resolution on the fly and that
419 // tracks sinks get the new frame size unless constraints force the frame to be
420 // cropped.
421 TEST_F(MediaStreamVideoSourceTest, SourceChangeFrameSize) {
422   MockMediaConstraintFactory factory;
423   factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 800);
424   factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 700);
425
426   // Expect the source to start capture with the supported resolution.
427   blink::WebMediaStreamTrack track =
428       CreateTrackAndStartSource(factory.CreateWebMediaConstraints(),
429                                 640, 480, 30);
430
431   MockMediaStreamVideoSink sink;
432   MediaStreamVideoSink::AddToVideoTrack(
433       &sink, sink.GetDeliverFrameCB(), track);
434   EXPECT_EQ(0, sink.number_of_frames());
435   DeliverVideoFrameAndWaitForRenderer(320, 240, &sink);
436   EXPECT_EQ(1, sink.number_of_frames());
437   // Expect the delivered frame to be passed unchanged since its smaller than
438   // max requested.
439   EXPECT_EQ(320, sink.frame_size().width());
440   EXPECT_EQ(240, sink.frame_size().height());
441
442   DeliverVideoFrameAndWaitForRenderer(640, 480, &sink);
443   EXPECT_EQ(2, sink.number_of_frames());
444   // Expect the delivered frame to be passed unchanged since its smaller than
445   // max requested.
446   EXPECT_EQ(640, sink.frame_size().width());
447   EXPECT_EQ(480, sink.frame_size().height());
448
449   DeliverVideoFrameAndWaitForRenderer(1280, 720, &sink);
450
451   EXPECT_EQ(3, sink.number_of_frames());
452   // Expect a frame to be cropped since its larger than max requested.
453   EXPECT_EQ(800, sink.frame_size().width());
454   EXPECT_EQ(700, sink.frame_size().height());
455
456   MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
457 }
458
459 TEST_F(MediaStreamVideoSourceTest, IsConstraintSupported) {
460   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
461           MediaStreamVideoSource::kMaxFrameRate));
462   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
463         MediaStreamVideoSource::kMinFrameRate));
464   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
465       MediaStreamVideoSource::kMaxWidth));
466   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
467         MediaStreamVideoSource::kMinWidth));
468   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
469         MediaStreamVideoSource::kMaxHeight));
470   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
471       MediaStreamVideoSource::kMinHeight));
472   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
473         MediaStreamVideoSource::kMaxAspectRatio));
474   EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
475       MediaStreamVideoSource::kMinAspectRatio));
476
477   EXPECT_FALSE(MediaStreamVideoSource::IsConstraintSupported(
478       "something unsupported"));
479 }
480
481 }  // namespace content