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   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
    441