Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_coding / main / source / video_sender_unittest.cc
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include <vector>
12
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/common.h"
15 #include "webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
17 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
18 #include "webrtc/modules/video_coding/main/interface/mock/mock_vcm_callbacks.h"
19 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
20 #include "webrtc/modules/video_coding/main/source/video_coding_impl.h"
21 #include "webrtc/modules/video_coding/main/test/test_util.h"
22 #include "webrtc/system_wrappers/interface/clock.h"
23 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
24 #include "webrtc/test/frame_generator.h"
25 #include "webrtc/test/testsupport/fileutils.h"
26 #include "webrtc/test/testsupport/gtest_disable.h"
27
28 using ::testing::_;
29 using ::testing::AllOf;
30 using ::testing::ElementsAre;
31 using ::testing::ElementsAreArray;
32 using ::testing::Field;
33 using ::testing::NiceMock;
34 using ::testing::Pointee;
35 using ::testing::Return;
36 using ::testing::FloatEq;
37 using std::vector;
38 using webrtc::test::FrameGenerator;
39
40 namespace webrtc {
41 namespace vcm {
42 namespace {
43 enum {
44   kMaxNumberOfTemporalLayers = 3
45 };
46
47 struct Vp8StreamInfo {
48   float framerate_fps[kMaxNumberOfTemporalLayers];
49   int bitrate_kbps[kMaxNumberOfTemporalLayers];
50 };
51
52 MATCHER_P(MatchesVp8StreamInfo, expected, "") {
53   bool res = true;
54   for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
55     if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
56       *result_listener << " framerate_fps[" << tl
57                        << "] = " << arg.framerate_fps[tl] << " (expected "
58                        << expected.framerate_fps[tl] << ") ";
59       res = false;
60     }
61     if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) {
62       *result_listener << " bitrate_kbps[" << tl
63                        << "] = " << arg.bitrate_kbps[tl] << " (expected "
64                        << expected.bitrate_kbps[tl] << ") ";
65       res = false;
66     }
67   }
68   return res;
69 }
70
71 class EmptyFrameGenerator : public FrameGenerator {
72  public:
73   I420VideoFrame* NextFrame() OVERRIDE { frame_.ResetSize(); return &frame_; }
74
75  private:
76   I420VideoFrame frame_;
77 };
78
79 class PacketizationCallback : public VCMPacketizationCallback {
80  public:
81   PacketizationCallback(Clock* clock)
82       : clock_(clock), start_time_ms_(clock_->TimeInMilliseconds()) {}
83
84   virtual ~PacketizationCallback() {}
85
86   virtual int32_t SendData(FrameType frame_type,
87                            uint8_t payload_type,
88                            uint32_t timestamp,
89                            int64_t capture_time_ms,
90                            const uint8_t* payload_data,
91                            uint32_t payload_size,
92                            const RTPFragmentationHeader& fragmentation_header,
93                            const RTPVideoHeader* rtp_video_header) {
94     assert(rtp_video_header);
95     frame_data_.push_back(FrameData(payload_size, *rtp_video_header));
96     return 0;
97   }
98
99   void Reset() {
100     frame_data_.clear();
101     start_time_ms_ = clock_->TimeInMilliseconds();
102   }
103
104   float FramerateFpsWithinTemporalLayer(int temporal_layer) {
105     return CountFramesWithinTemporalLayer(temporal_layer) *
106            (1000.0 / interval_ms());
107   }
108
109   float BitrateKbpsWithinTemporalLayer(int temporal_layer) {
110     return SumPayloadBytesWithinTemporalLayer(temporal_layer) * 8.0 /
111            interval_ms();
112   }
113
114   Vp8StreamInfo CalculateVp8StreamInfo() {
115     Vp8StreamInfo info;
116     for (int tl = 0; tl < 3; ++tl) {
117       info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl);
118       info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl);
119     }
120     return info;
121   }
122
123  private:
124   struct FrameData {
125     FrameData() {}
126
127     FrameData(uint32_t payload_size, const RTPVideoHeader& rtp_video_header)
128         : payload_size(payload_size), rtp_video_header(rtp_video_header) {}
129
130     uint32_t payload_size;
131     RTPVideoHeader rtp_video_header;
132   };
133
134   int64_t interval_ms() {
135     int64_t diff = (clock_->TimeInMilliseconds() - start_time_ms_);
136     EXPECT_GT(diff, 0);
137     return diff;
138   }
139
140   int CountFramesWithinTemporalLayer(int temporal_layer) {
141     int frames = 0;
142     for (size_t i = 0; i < frame_data_.size(); ++i) {
143       EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
144       const uint8_t temporal_idx =
145           frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
146       if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
147         frames++;
148     }
149     return frames;
150   }
151
152   int SumPayloadBytesWithinTemporalLayer(int temporal_layer) {
153     int payload_size = 0;
154     for (size_t i = 0; i < frame_data_.size(); ++i) {
155       EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec);
156       const uint8_t temporal_idx =
157           frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx;
158       if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx)
159         payload_size += frame_data_[i].payload_size;
160     }
161     return payload_size;
162   }
163
164   Clock* clock_;
165   int64_t start_time_ms_;
166   vector<FrameData> frame_data_;
167 };
168
169 class TestVideoSender : public ::testing::Test {
170  protected:
171   // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as
172   // a special case (e.g. frame rate in media optimization).
173   TestVideoSender() : clock_(1000), packetization_callback_(&clock_) {}
174
175   virtual void SetUp() {
176     sender_.reset(new VideoSender(&clock_, &post_encode_callback_));
177     EXPECT_EQ(0, sender_->InitializeSender());
178     EXPECT_EQ(0, sender_->RegisterTransportCallback(&packetization_callback_));
179   }
180
181   void AddFrame() {
182     assert(generator_.get());
183     sender_->AddVideoFrame(*generator_->NextFrame(), NULL, NULL);
184   }
185
186   SimulatedClock clock_;
187   PacketizationCallback packetization_callback_;
188   MockEncodedImageCallback post_encode_callback_;
189   scoped_ptr<VideoSender> sender_;
190   scoped_ptr<FrameGenerator> generator_;
191 };
192
193 class TestVideoSenderWithMockEncoder : public TestVideoSender {
194  protected:
195   static const int kDefaultWidth = 1280;
196   static const int kDefaultHeight = 720;
197   static const int kNumberOfStreams = 3;
198   static const int kNumberOfLayers = 3;
199   static const int kUnusedPayloadType = 10;
200
201   virtual void SetUp() {
202     TestVideoSender::SetUp();
203     generator_.reset(new EmptyFrameGenerator());
204     EXPECT_EQ(
205         0,
206         sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, false));
207     memset(&settings_, 0, sizeof(settings_));
208     EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &settings_));
209     settings_.numberOfSimulcastStreams = kNumberOfStreams;
210     ConfigureStream(kDefaultWidth / 4,
211                     kDefaultHeight / 4,
212                     100,
213                     &settings_.simulcastStream[0]);
214     ConfigureStream(kDefaultWidth / 2,
215                     kDefaultHeight / 2,
216                     500,
217                     &settings_.simulcastStream[1]);
218     ConfigureStream(
219         kDefaultWidth, kDefaultHeight, 1200, &settings_.simulcastStream[2]);
220     settings_.plType = kUnusedPayloadType;  // Use the mocked encoder.
221     EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
222   }
223
224   virtual void TearDown() { sender_.reset(); }
225
226   void ExpectIntraRequest(int stream) {
227     if (stream == -1) {
228       // No intra request expected.
229       EXPECT_CALL(
230           encoder_,
231           Encode(_,
232                  _,
233                  Pointee(ElementsAre(kDeltaFrame, kDeltaFrame, kDeltaFrame))))
234           .Times(1).WillRepeatedly(Return(0));
235       return;
236     }
237     assert(stream >= 0);
238     assert(stream < kNumberOfStreams);
239     std::vector<VideoFrameType> frame_types(kNumberOfStreams, kDeltaFrame);
240     frame_types[stream] = kKeyFrame;
241     EXPECT_CALL(
242         encoder_,
243         Encode(_,
244                _,
245                Pointee(ElementsAreArray(&frame_types[0], frame_types.size()))))
246         .Times(1).WillRepeatedly(Return(0));
247   }
248
249   static void ConfigureStream(int width,
250                               int height,
251                               int max_bitrate,
252                               SimulcastStream* stream) {
253     assert(stream);
254     stream->width = width;
255     stream->height = height;
256     stream->maxBitrate = max_bitrate;
257     stream->numberOfTemporalLayers = kNumberOfLayers;
258     stream->qpMax = 45;
259   }
260
261   VideoCodec settings_;
262   NiceMock<MockVideoEncoder> encoder_;
263 };
264
265 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequests) {
266   EXPECT_EQ(0, sender_->IntraFrameRequest(0));
267   ExpectIntraRequest(0);
268   AddFrame();
269   ExpectIntraRequest(-1);
270   AddFrame();
271
272   EXPECT_EQ(0, sender_->IntraFrameRequest(1));
273   ExpectIntraRequest(1);
274   AddFrame();
275   ExpectIntraRequest(-1);
276   AddFrame();
277
278   EXPECT_EQ(0, sender_->IntraFrameRequest(2));
279   ExpectIntraRequest(2);
280   AddFrame();
281   ExpectIntraRequest(-1);
282   AddFrame();
283
284   EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
285   ExpectIntraRequest(-1);
286   AddFrame();
287
288   EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
289   ExpectIntraRequest(-1);
290   AddFrame();
291 }
292
293 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequestsInternalCapture) {
294   // De-register current external encoder.
295   EXPECT_EQ(0,
296             sender_->RegisterExternalEncoder(NULL, kUnusedPayloadType, false));
297   // Register encoder with internal capture.
298   EXPECT_EQ(
299       0, sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true));
300   EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200));
301   ExpectIntraRequest(0);
302   EXPECT_EQ(0, sender_->IntraFrameRequest(0));
303   ExpectIntraRequest(1);
304   EXPECT_EQ(0, sender_->IntraFrameRequest(1));
305   ExpectIntraRequest(2);
306   EXPECT_EQ(0, sender_->IntraFrameRequest(2));
307   // No requests expected since these indices are out of bounds.
308   EXPECT_EQ(-1, sender_->IntraFrameRequest(3));
309   EXPECT_EQ(-1, sender_->IntraFrameRequest(-1));
310 }
311
312 class TestVideoSenderWithVp8 : public TestVideoSender {
313  public:
314   TestVideoSenderWithVp8()
315       : codec_bitrate_kbps_(300), available_bitrate_kbps_(1000) {}
316
317   virtual void SetUp() {
318     TestVideoSender::SetUp();
319
320     const char* input_video = "foreman_cif";
321     const int width = 352;
322     const int height = 288;
323     generator_.reset(FrameGenerator::CreateFromYuvFile(
324         test::ResourcePath(input_video, "yuv").c_str(), width, height));
325
326     codec_ = MakeVp8VideoCodec(width, height, 3);
327     codec_.minBitrate = 10;
328     codec_.startBitrate = codec_bitrate_kbps_;
329     codec_.maxBitrate = codec_bitrate_kbps_;
330     EXPECT_EQ(0, sender_->RegisterSendCodec(&codec_, 1, 1200));
331   }
332
333   static VideoCodec MakeVp8VideoCodec(int width,
334                                       int height,
335                                       int temporal_layers) {
336     VideoCodec codec;
337     memset(&codec, 0, sizeof(codec));
338     EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &codec));
339     codec.width = width;
340     codec.height = height;
341     codec.codecSpecific.VP8.numberOfTemporalLayers = temporal_layers;
342     return codec;
343   }
344
345   void InsertFrames(float framerate, float seconds) {
346     for (int i = 0; i < seconds * framerate; ++i) {
347       clock_.AdvanceTimeMilliseconds(1000.0f / framerate);
348       EXPECT_CALL(post_encode_callback_, Encoded(_, NULL, NULL))
349           .WillOnce(Return(0));
350       AddFrame();
351
352       // SetChannelParameters needs to be called frequently to propagate
353       // framerate from the media optimization into the encoder.
354       // Note: SetChannelParameters fails if less than 2 frames are in the
355       // buffer since it will fail to calculate the framerate.
356       if (i != 0) {
357         EXPECT_EQ(VCM_OK,
358                   sender_->SetChannelParameters(
359                       available_bitrate_kbps_ * 1000, 0, 200));
360       }
361     }
362   }
363
364   Vp8StreamInfo SimulateWithFramerate(float framerate) {
365     const float short_simulation_interval = 5.0;
366     const float long_simulation_interval = 10.0;
367     // It appears that this 5 seconds simulation is needed to allow
368     // bitrate and framerate to stabilize.
369     InsertFrames(framerate, short_simulation_interval);
370     packetization_callback_.Reset();
371
372     InsertFrames(framerate, long_simulation_interval);
373     return packetization_callback_.CalculateVp8StreamInfo();
374   }
375
376  protected:
377   VideoCodec codec_;
378   int codec_bitrate_kbps_;
379   int available_bitrate_kbps_;
380 };
381
382 TEST_F(TestVideoSenderWithVp8,
383        DISABLED_ON_ANDROID(FixedTemporalLayersStrategy)) {
384   const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0];
385   const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1];
386   const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2];
387   {
388     Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
389     EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
390   }
391   {
392     Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}};
393     EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
394   }
395 }
396
397 TEST_F(TestVideoSenderWithVp8,
398        DISABLED_ON_ANDROID(RealTimeTemporalLayersStrategy)) {
399   Config extra_options;
400   extra_options.Set<TemporalLayers::Factory>(
401       new RealTimeTemporalLayersFactory());
402   VideoCodec codec = MakeVp8VideoCodec(352, 288, 3);
403   codec.extra_options = &extra_options;
404   codec.minBitrate = 10;
405   codec.startBitrate = codec_bitrate_kbps_;
406   codec.maxBitrate = codec_bitrate_kbps_;
407   EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200));
408
409   const int low_b = codec_bitrate_kbps_ * 0.4;
410   const int mid_b = codec_bitrate_kbps_ * 0.6;
411   const int high_b = codec_bitrate_kbps_;
412
413   {
414     Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
415     EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
416   }
417   {
418     Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}};
419     EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected));
420   }
421   {
422     Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}};
423     EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
424   }
425   {
426     Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}};
427     EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected));
428   }
429   {
430     // TODO(andresp): Find out why this fails with framerate = 7.5
431     Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}};
432     EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected));
433   }
434 }
435 }  // namespace
436 }  // namespace vcm
437 }  // namespace webrtc