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