Home | History | Annotate | Download | only in source
      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       if (frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx <=
    145           temporal_layer) {
    146         frames++;
    147       }
    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       if (frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx <=
    157           temporal_layer) {
    158         payload_size += frame_data_[i].payload_size;
    159       }
    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
    438