1 /*
2 * Copyright (c) 2020 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 "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
12
13 #include <limits>
14 #include <memory>
15 #include <vector>
16
17 #include "absl/types/optional.h"
18 #include "api/video_codecs/video_codec.h"
19 #include "api/video_codecs/video_encoder.h"
20 #include "modules/video_coding/codecs/test/encoded_video_frame_producer.h"
21 #include "modules/video_coding/include/video_error_codes.h"
22 #include "test/gmock.h"
23 #include "test/gtest.h"
24
25 namespace webrtc {
26 namespace {
27
28 using ::testing::ElementsAre;
29 using ::testing::Eq;
30 using ::testing::Field;
31 using ::testing::IsEmpty;
32 using ::testing::SizeIs;
33
DefaultCodecSettings()34 VideoCodec DefaultCodecSettings() {
35 VideoCodec codec_settings;
36 codec_settings.width = 320;
37 codec_settings.height = 180;
38 codec_settings.maxFramerate = 30;
39 codec_settings.maxBitrate = 1000;
40 codec_settings.qpMax = 63;
41 return codec_settings;
42 }
43
DefaultEncoderSettings()44 VideoEncoder::Settings DefaultEncoderSettings() {
45 return VideoEncoder::Settings(
46 VideoEncoder::Capabilities(/*loss_notification=*/false),
47 /*number_of_cores=*/1, /*max_payload_size=*/1200);
48 }
49
TEST(LibaomAv1EncoderTest,CanCreate)50 TEST(LibaomAv1EncoderTest, CanCreate) {
51 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
52 EXPECT_TRUE(encoder);
53 }
54
TEST(LibaomAv1EncoderTest,InitAndRelease)55 TEST(LibaomAv1EncoderTest, InitAndRelease) {
56 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
57 ASSERT_TRUE(encoder);
58 VideoCodec codec_settings = DefaultCodecSettings();
59 EXPECT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
60 WEBRTC_VIDEO_CODEC_OK);
61 EXPECT_EQ(encoder->Release(), WEBRTC_VIDEO_CODEC_OK);
62 }
63
TEST(LibaomAv1EncoderTest,NoBitrateOnTopLayerRefecltedInActiveDecodeTargets)64 TEST(LibaomAv1EncoderTest, NoBitrateOnTopLayerRefecltedInActiveDecodeTargets) {
65 // Configure encoder with 2 temporal layers.
66 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
67 VideoCodec codec_settings = DefaultCodecSettings();
68 codec_settings.SetScalabilityMode(ScalabilityMode::kL1T2);
69 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
70 WEBRTC_VIDEO_CODEC_OK);
71
72 VideoEncoder::RateControlParameters rate_parameters;
73 rate_parameters.framerate_fps = 30;
74 rate_parameters.bitrate.SetBitrate(0, /*temporal_index=*/0, 300'000);
75 rate_parameters.bitrate.SetBitrate(0, /*temporal_index=*/1, 0);
76 encoder->SetRates(rate_parameters);
77
78 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
79 EncodedVideoFrameProducer(*encoder).SetNumInputFrames(1).Encode();
80 ASSERT_THAT(encoded_frames, SizeIs(1));
81 ASSERT_NE(encoded_frames[0].codec_specific_info.generic_frame_info,
82 absl::nullopt);
83 // Assuming L1T2 structure uses 1st decode target for T0 and 2nd decode target
84 // for T0+T1 frames, expect only 1st decode target is active.
85 EXPECT_EQ(encoded_frames[0]
86 .codec_specific_info.generic_frame_info->active_decode_targets,
87 0b01);
88 }
89
TEST(LibaomAv1EncoderTest,SpatialScalabilityInTemporalUnitReportedAsDeltaFrame)90 TEST(LibaomAv1EncoderTest,
91 SpatialScalabilityInTemporalUnitReportedAsDeltaFrame) {
92 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
93 VideoCodec codec_settings = DefaultCodecSettings();
94 codec_settings.SetScalabilityMode(ScalabilityMode::kL2T1);
95 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
96 WEBRTC_VIDEO_CODEC_OK);
97
98 VideoEncoder::RateControlParameters rate_parameters;
99 rate_parameters.framerate_fps = 30;
100 rate_parameters.bitrate.SetBitrate(/*spatial_index=*/0, 0, 300'000);
101 rate_parameters.bitrate.SetBitrate(/*spatial_index=*/1, 0, 300'000);
102 encoder->SetRates(rate_parameters);
103
104 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
105 EncodedVideoFrameProducer(*encoder).SetNumInputFrames(1).Encode();
106 ASSERT_THAT(encoded_frames, SizeIs(2));
107 EXPECT_THAT(encoded_frames[0].encoded_image._frameType,
108 Eq(VideoFrameType::kVideoFrameKey));
109 EXPECT_THAT(encoded_frames[1].encoded_image._frameType,
110 Eq(VideoFrameType::kVideoFrameDelta));
111 }
112
TEST(LibaomAv1EncoderTest,NoBitrateOnTopSpatialLayerProduceDeltaFrames)113 TEST(LibaomAv1EncoderTest, NoBitrateOnTopSpatialLayerProduceDeltaFrames) {
114 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
115 VideoCodec codec_settings = DefaultCodecSettings();
116 codec_settings.SetScalabilityMode(ScalabilityMode::kL2T1);
117 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
118 WEBRTC_VIDEO_CODEC_OK);
119
120 VideoEncoder::RateControlParameters rate_parameters;
121 rate_parameters.framerate_fps = 30;
122 rate_parameters.bitrate.SetBitrate(/*spatial_index=*/0, 0, 300'000);
123 rate_parameters.bitrate.SetBitrate(/*spatial_index=*/1, 0, 0);
124 encoder->SetRates(rate_parameters);
125
126 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
127 EncodedVideoFrameProducer(*encoder).SetNumInputFrames(2).Encode();
128 ASSERT_THAT(encoded_frames, SizeIs(2));
129 EXPECT_THAT(encoded_frames[0].encoded_image._frameType,
130 Eq(VideoFrameType::kVideoFrameKey));
131 EXPECT_THAT(encoded_frames[1].encoded_image._frameType,
132 Eq(VideoFrameType::kVideoFrameDelta));
133 }
134
TEST(LibaomAv1EncoderTest,SetsEndOfPictureForLastFrameInTemporalUnit)135 TEST(LibaomAv1EncoderTest, SetsEndOfPictureForLastFrameInTemporalUnit) {
136 VideoBitrateAllocation allocation;
137 allocation.SetBitrate(0, 0, 30000);
138 allocation.SetBitrate(1, 0, 40000);
139 allocation.SetBitrate(2, 0, 30000);
140
141 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
142 VideoCodec codec_settings = DefaultCodecSettings();
143 // Configure encoder with 3 spatial layers.
144 codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1);
145 codec_settings.maxBitrate = allocation.get_sum_kbps();
146 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
147 WEBRTC_VIDEO_CODEC_OK);
148
149 encoder->SetRates(VideoEncoder::RateControlParameters(
150 allocation, codec_settings.maxFramerate));
151
152 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
153 EncodedVideoFrameProducer(*encoder).SetNumInputFrames(2).Encode();
154 ASSERT_THAT(encoded_frames, SizeIs(6));
155 EXPECT_FALSE(encoded_frames[0].codec_specific_info.end_of_picture);
156 EXPECT_FALSE(encoded_frames[1].codec_specific_info.end_of_picture);
157 EXPECT_TRUE(encoded_frames[2].codec_specific_info.end_of_picture);
158 EXPECT_FALSE(encoded_frames[3].codec_specific_info.end_of_picture);
159 EXPECT_FALSE(encoded_frames[4].codec_specific_info.end_of_picture);
160 EXPECT_TRUE(encoded_frames[5].codec_specific_info.end_of_picture);
161 }
162
TEST(LibaomAv1EncoderTest,CheckOddDimensionsWithSpatialLayers)163 TEST(LibaomAv1EncoderTest, CheckOddDimensionsWithSpatialLayers) {
164 VideoBitrateAllocation allocation;
165 allocation.SetBitrate(0, 0, 30000);
166 allocation.SetBitrate(1, 0, 40000);
167 allocation.SetBitrate(2, 0, 30000);
168 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
169 VideoCodec codec_settings = DefaultCodecSettings();
170 // Configure encoder with 3 spatial layers.
171 codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1);
172 // Odd width and height values should not make encoder crash.
173 codec_settings.width = 623;
174 codec_settings.height = 405;
175 codec_settings.maxBitrate = allocation.get_sum_kbps();
176 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
177 WEBRTC_VIDEO_CODEC_OK);
178 encoder->SetRates(VideoEncoder::RateControlParameters(
179 allocation, codec_settings.maxFramerate));
180 EncodedVideoFrameProducer evfp(*encoder);
181 evfp.SetResolution(RenderResolution{623, 405});
182 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
183 evfp.SetNumInputFrames(2).Encode();
184 ASSERT_THAT(encoded_frames, SizeIs(6));
185 }
186
TEST(LibaomAv1EncoderTest,EncoderInfoProvidesFpsAllocation)187 TEST(LibaomAv1EncoderTest, EncoderInfoProvidesFpsAllocation) {
188 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
189 VideoCodec codec_settings = DefaultCodecSettings();
190 codec_settings.SetScalabilityMode(ScalabilityMode::kL3T3);
191 codec_settings.maxFramerate = 60;
192 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
193 WEBRTC_VIDEO_CODEC_OK);
194
195 const auto& encoder_info = encoder->GetEncoderInfo();
196 EXPECT_THAT(encoder_info.fps_allocation[0], ElementsAre(15, 30, 60));
197 EXPECT_THAT(encoder_info.fps_allocation[1], ElementsAre(15, 30, 60));
198 EXPECT_THAT(encoder_info.fps_allocation[2], ElementsAre(15, 30, 60));
199 EXPECT_THAT(encoder_info.fps_allocation[3], IsEmpty());
200 }
201
TEST(LibaomAv1EncoderTest,PopulatesEncodedFrameSize)202 TEST(LibaomAv1EncoderTest, PopulatesEncodedFrameSize) {
203 VideoBitrateAllocation allocation;
204 allocation.SetBitrate(0, 0, 30000);
205 allocation.SetBitrate(1, 0, 40000);
206 allocation.SetBitrate(2, 0, 30000);
207 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
208 VideoCodec codec_settings = DefaultCodecSettings();
209 codec_settings.maxBitrate = allocation.get_sum_kbps();
210 ASSERT_GT(codec_settings.width, 4);
211 // Configure encoder with 3 spatial layers.
212 codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1);
213 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
214 WEBRTC_VIDEO_CODEC_OK);
215 encoder->SetRates(VideoEncoder::RateControlParameters(
216 allocation, codec_settings.maxFramerate));
217 using Frame = EncodedVideoFrameProducer::EncodedFrame;
218 std::vector<Frame> encoded_frames =
219 EncodedVideoFrameProducer(*encoder).SetNumInputFrames(1).Encode();
220 EXPECT_THAT(
221 encoded_frames,
222 ElementsAre(
223 Field(&Frame::encoded_image,
224 AllOf(Field(&EncodedImage::_encodedWidth,
225 codec_settings.width / 4),
226 Field(&EncodedImage::_encodedHeight,
227 codec_settings.height / 4))),
228 Field(&Frame::encoded_image,
229 AllOf(Field(&EncodedImage::_encodedWidth,
230 codec_settings.width / 2),
231 Field(&EncodedImage::_encodedHeight,
232 codec_settings.height / 2))),
233 Field(&Frame::encoded_image,
234 AllOf(Field(&EncodedImage::_encodedWidth, codec_settings.width),
235 Field(&EncodedImage::_encodedHeight,
236 codec_settings.height)))));
237 }
238
TEST(LibaomAv1EncoderTest,RtpTimestampWrap)239 TEST(LibaomAv1EncoderTest, RtpTimestampWrap) {
240 std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder();
241 VideoCodec codec_settings = DefaultCodecSettings();
242 codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1);
243 ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
244 WEBRTC_VIDEO_CODEC_OK);
245
246 VideoEncoder::RateControlParameters rate_parameters;
247 rate_parameters.framerate_fps = 30;
248 rate_parameters.bitrate.SetBitrate(/*spatial_index=*/0, 0, 300'000);
249 encoder->SetRates(rate_parameters);
250
251 std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
252 EncodedVideoFrameProducer(*encoder)
253 .SetNumInputFrames(2)
254 .SetRtpTimestamp(std::numeric_limits<uint32_t>::max())
255 .Encode();
256 ASSERT_THAT(encoded_frames, SizeIs(2));
257 EXPECT_THAT(encoded_frames[0].encoded_image._frameType,
258 Eq(VideoFrameType::kVideoFrameKey));
259 EXPECT_THAT(encoded_frames[1].encoded_image._frameType,
260 Eq(VideoFrameType::kVideoFrameDelta));
261 }
262
263 } // namespace
264 } // namespace webrtc
265