summaryrefslogtreecommitdiffstats
path: root/media/cast/sender/vp8_quantizer_parser_unittest.cc
blob: 260dd79b22ebc09b729e107a38eacb1c1eead293 (plain)
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
149
150
151
152
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>

#include <cstdlib>

#include "base/macros.h"
#include "base/time/time.h"
#include "media/cast/cast_config.h"
#include "media/cast/receiver/video_decoder.h"
#include "media/cast/sender/sender_encoded_frame.h"
#include "media/cast/sender/vp8_encoder.h"
#include "media/cast/sender/vp8_quantizer_parser.h"
#include "media/cast/test/utility/default_config.h"
#include "media/cast/test/utility/video_utility.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {
namespace cast {

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

VideoSenderConfig GetVideoConfigForTest() {
  VideoSenderConfig config = GetDefaultVideoSenderConfig();
  config.codec = CODEC_VIDEO_VP8;
  config.use_external_encoder = false;
  config.max_frame_rate = kFrameRate;
  config.min_qp = kQp;
  config.max_qp = kQp;
  config.max_cpu_saver_qp = kQp;
  return config;
}
}  // unnamed namespace

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

  // Call vp8 software encoder to encode one randomly generated frame.
  void EncodeOneFrame(SenderEncodedFrame* encoded_frame) {
    const gfx::Size frame_size = gfx::Size(kWidth, kHeight);
    const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
        PIXEL_FORMAT_YV12, 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::TimeDelta::FromSeconds(1) / kFrameRate;
    PopulateVideoFrameWithNoise(video_frame.get());
    vp8_encoder_->Encode(video_frame, reference_time, encoded_frame);
  }

  // Update the vp8 encoder with the new quantizer.
  void UpdateQuantizer(int qp) {
    DCHECK((qp > 3) && (qp < 64));
    video_config_.min_qp = qp;
    video_config_.max_qp = qp;
    video_config_.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_.reset(new Vp8Encoder(video_config_));
    vp8_encoder_->Initialize();
  }

  base::TimeDelta next_frame_timestamp_;
  VideoSenderConfig video_config_;
  scoped_ptr<Vp8Encoder> vp8_encoder_;

  DISALLOW_COPY_AND_ASSIGN(Vp8QuantizerParserTest);
};

// Encode 3 frames to test the cases with insufficient data input.
TEST_F(Vp8QuantizerParserTest, InsufficientData) {
  for (int i = 0; i < 3; ++i) {
    scoped_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame());
    const uint8_t* encoded_data =
        reinterpret_cast<const uint8_t*>(encoded_frame->data.data());
    // Null input.
    int decoded_quantizer =
        ParseVp8HeaderQuantizer(encoded_data, encoded_frame->data.size());
    EXPECT_EQ(-1, decoded_quantizer);
    EncodeOneFrame(encoded_frame.get());
    encoded_data = reinterpret_cast<const uint8_t*>(encoded_frame->data.data());
    // Zero bytes should not be enough to decode the quantizer value.
    decoded_quantizer = ParseVp8HeaderQuantizer(encoded_data, 0);
    EXPECT_EQ(-1, decoded_quantizer);
    // Three bytes should not be enough to decode the quantizer value..
    decoded_quantizer = ParseVp8HeaderQuantizer(encoded_data, 3);
    EXPECT_EQ(-1, decoded_quantizer);
    unsigned int first_partition_size =
        (encoded_data[0] | (encoded_data[1] << 8) | (encoded_data[2] << 16)) >>
        5;
    if (encoded_frame->dependency == EncodedFrame::KEY) {
      // Ten bytes should not be enough to decode the quanitizer value
      // for a Key frame.
      decoded_quantizer = ParseVp8HeaderQuantizer(encoded_data, 10);
      EXPECT_EQ(-1, decoded_quantizer);
      // One byte less than needed to decode the quantizer value.
      decoded_quantizer =
          ParseVp8HeaderQuantizer(encoded_data, 10 + first_partition_size - 1);
      EXPECT_EQ(-1, decoded_quantizer);
      // Minimum number of bytes to decode the quantizer value.
      decoded_quantizer =
          ParseVp8HeaderQuantizer(encoded_data, 10 + first_partition_size);
      EXPECT_EQ(kQp, decoded_quantizer);
    } else {
      // One byte less than needed to decode the quantizer value.
      decoded_quantizer =
          ParseVp8HeaderQuantizer(encoded_data, 3 + first_partition_size - 1);
      EXPECT_EQ(-1, decoded_quantizer);
      // Minimum number of bytes to decode the quantizer value.
      decoded_quantizer =
          ParseVp8HeaderQuantizer(encoded_data, 3 + first_partition_size);
      EXPECT_EQ(kQp, decoded_quantizer);
    }
  }
}

// Encode 3 fames for every quantizer value in the range of [4,63].
TEST_F(Vp8QuantizerParserTest, VariedQuantizer) {
  int decoded_quantizer = -1;
  for (int qp = 4; qp <= 63; qp += 10) {
    UpdateQuantizer(qp);
    for (int i = 0; i < 3; ++i) {
      scoped_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame());
      EncodeOneFrame(encoded_frame.get());
      decoded_quantizer = ParseVp8HeaderQuantizer(
          reinterpret_cast<const uint8_t*>(encoded_frame->data.data()),
          encoded_frame->data.size());
      EXPECT_EQ(qp, decoded_quantizer);
    }
  }
}

}  // namespace cast
}  // namespace media