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