1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148

media / cast / encoding / vpx_quantizer_parser_unittest.cc [blame]

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/cast/encoding/vpx_quantizer_parser.h"

#include <stdint.h>

#include <cstdlib>
#include <memory>

#include "base/time/time.h"
#include "media/base/mock_filters.h"
#include "media/base/video_codecs.h"
#include "media/cast/cast_config.h"
#include "media/cast/common/sender_encoded_frame.h"
#include "media/cast/encoding/vpx_encoder.h"
#include "media/cast/test/utility/default_config.h"
#include "media/cast/test/utility/video_utility.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/openscreen/src/cast/streaming/public/encoded_frame.h"

namespace media::cast {

namespace {
constexpr int kWidth = 32;
constexpr int kHeight = 32;
constexpr int kFrameRate = 10;
constexpr int kQp = 20;

FrameSenderConfig GetVideoConfigForTest() {
  FrameSenderConfig config = GetDefaultVideoSenderConfig();
  config.use_hardware_encoder = false;
  config.max_frame_rate = kFrameRate;

  VideoCodecParams& codec_params = config.video_codec_params.value();
  codec_params.codec = VideoCodec::kVP8;
  codec_params.min_qp = kQp;
  codec_params.max_qp = kQp;
  codec_params.max_cpu_saver_qp = kQp;
  return config;
}
}  // unnamed namespace

class VpxQuantizerParserTest : public ::testing::Test {
 public:
  VpxQuantizerParserTest() : video_config_(GetVideoConfigForTest()) {}

  // Call vp8 software encoder to encode one randomly generated frame.
  void EncodeOneFrame(SenderEncodedFrame* frame) {
    const gfx::Size frame_size = gfx::Size(kWidth, kHeight);
    const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
        PIXEL_FORMAT_I420, frame_size, gfx::Rect(frame_size), frame_size,
        next_frame_timestamp_);
    const base::TimeTicks reference_time =
        base::TimeTicks::UnixEpoch() + next_frame_timestamp_;
    next_frame_timestamp_ += base::Seconds(1) / kFrameRate;
    PopulateVideoFrameWithNoise(video_frame.get());
    vp8_encoder_->Encode(video_frame, reference_time, frame);
  }

  // Update the vp8 encoder with the new quantizer.
  void UpdateQuantizer(int qp) {
    DCHECK((qp > 3) && (qp < 64));
    VideoCodecParams& codec_params = video_config_.video_codec_params.value();
    codec_params.min_qp = qp;
    codec_params.max_qp = qp;
    codec_params.max_cpu_saver_qp = qp;
    RecreateVp8Encoder();
  }

 protected:
  void SetUp() final {
    next_frame_timestamp_ = base::TimeDelta();
    RecreateVp8Encoder();
  }

 private:
  // Reconstruct a vp8 encoder with new config since the Vp8Encoder
  // class has no interface to update the config.
  void RecreateVp8Encoder() {
    vp8_encoder_ = std::make_unique<VpxEncoder>(
        video_config_,
        std::make_unique<media::MockVideoEncoderMetricsProvider>());
    vp8_encoder_->Initialize();
  }

  base::TimeDelta next_frame_timestamp_;
  FrameSenderConfig video_config_;
  std::unique_ptr<VpxEncoder> vp8_encoder_;
};

// Encode 3 frames to test the cases with insufficient data input.
TEST_F(VpxQuantizerParserTest, InsufficientData) {
  for (int i = 0; i < 3; ++i) {
    auto frame = std::make_unique<SenderEncodedFrame>();

    // Null input.
    EXPECT_EQ(-1, ParseVpxHeaderQuantizer(frame->data));
    EncodeOneFrame(frame.get());

    // Zero bytes should not be enough to decode the quantizer value.
    EXPECT_EQ(-1, ParseVpxHeaderQuantizer(frame->data.first(0)));

    // Three bytes should not be enough to decode the quantizer value..
    EXPECT_EQ(-1, ParseVpxHeaderQuantizer(frame->data.first(3)));

    const unsigned int first_partition_size =
        (frame->data[0] | (frame->data[1] << 8) | (frame->data[2] << 16)) >> 5;
    if (frame->is_key_frame) {
      // Ten bytes should not be enough to decode the quantizer value
      // for a Key frame.
      EXPECT_EQ(-1, ParseVpxHeaderQuantizer(frame->data.first(10)));

      // One byte less than needed to decode the quantizer value.
      EXPECT_EQ(-1, ParseVpxHeaderQuantizer(
                        frame->data.first(10 + first_partition_size - 1)));

      // Minimum number of bytes to decode the quantizer value.
      EXPECT_EQ(kQp, ParseVpxHeaderQuantizer(
                         frame->data.first(10 + first_partition_size)));
    } else {
      // One byte less than needed to decode the quantizer value.
      EXPECT_EQ(-1, ParseVpxHeaderQuantizer(
                        frame->data.first(3 + first_partition_size - 1)));

      // Minimum number of bytes to decode the quantizer value.
      EXPECT_EQ(kQp, ParseVpxHeaderQuantizer(
                         frame->data.first(3 + first_partition_size)));
    }
  }
}

// Encode 3 fames for every quantizer value in the range of [4,63].
TEST_F(VpxQuantizerParserTest, VariedQuantizer) {
  int decoded_quantizer = -1;
  for (int qp = 4; qp <= 63; qp += 10) {
    UpdateQuantizer(qp);
    for (int i = 0; i < 3; ++i) {
      auto frame = std::make_unique<SenderEncodedFrame>();
      EncodeOneFrame(frame.get());
      decoded_quantizer = ParseVpxHeaderQuantizer(frame->data);
      EXPECT_EQ(qp, decoded_quantizer);
    }
  }
}

}  // namespace media::cast