1 /*
2 * Copyright (c) 2023, Alliance for Open Media. All rights reserved.
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 #include <cstddef>
13 #include <cstdint>
14 #include <vector>
15
16 #include "aom/aomcx.h"
17 #include "aom/aom_codec.h"
18 #include "aom/aom_encoder.h"
19 #include "aom/aom_image.h"
20 #include "config/aom_config.h"
21 #include "gtest/gtest.h"
22
23 namespace {
24
25 /*
26 Reproduces https://crbug.com/aomedia/3376. Emulates the command line:
27
28 ./aomenc --cpu-used=6 --threads=10 --cq-level=14 --passes=1 --limit=1 \
29 --lag-in-frames=0 --end-usage=q --deltaq-mode=3 --min-q=0 --max-q=63 \
30 -o output.av1 niklas_1280_720_30.y4m
31 */
TEST(DeltaqModeTest,DeltaqMode3MultiThread)32 TEST(DeltaqModeTest, DeltaqMode3MultiThread) {
33 constexpr int kWidth = 1280;
34 constexpr int kHeight = 720;
35 // Dummy buffer of neutral gray samples.
36 constexpr size_t kBufferSize = kWidth * kHeight + kWidth * kHeight / 2;
37 std::vector<unsigned char> buffer(kBufferSize,
38 static_cast<unsigned char>(128));
39
40 aom_image_t img;
41 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
42 buffer.data()));
43
44 aom_codec_iface_t *iface = aom_codec_av1_cx();
45 aom_codec_enc_cfg_t cfg;
46 EXPECT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY),
47 AOM_CODEC_OK);
48 cfg.g_w = kWidth;
49 cfg.g_h = kHeight;
50 cfg.g_threads = 10;
51 cfg.rc_end_usage = AOM_Q;
52 cfg.g_profile = 0;
53 cfg.g_bit_depth = AOM_BITS_8;
54 cfg.g_input_bit_depth = 8;
55 cfg.g_lag_in_frames = 0;
56 cfg.rc_min_quantizer = 0;
57 cfg.rc_max_quantizer = 63;
58 cfg.g_pass = AOM_RC_ONE_PASS;
59 cfg.g_limit = 1;
60 aom_codec_ctx_t enc;
61 EXPECT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
62 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 6), AOM_CODEC_OK);
63 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 14), AOM_CODEC_OK);
64 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 3), AOM_CODEC_OK);
65 EXPECT_EQ(aom_codec_set_option(&enc, "passes", "1"), AOM_CODEC_OK);
66 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_STUDIO_RANGE),
67 AOM_CODEC_OK);
68
69 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK);
70 aom_codec_iter_t iter = nullptr;
71 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
72 ASSERT_NE(pkt, nullptr);
73 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
74 // pkt->data.frame.flags is 0x1f0011.
75 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
76 pkt = aom_codec_get_cx_data(&enc, &iter);
77 EXPECT_EQ(pkt, nullptr);
78
79 // Flush encoder
80 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
81 iter = nullptr;
82 pkt = aom_codec_get_cx_data(&enc, &iter);
83 EXPECT_EQ(pkt, nullptr);
84
85 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
86 }
87
88 // The implementation of multi-threading for deltaq-mode=3 in allintra
89 // mode is based on row multi-threading.
90 // The test ensures that When row mt is turned off,
91 // deltaq-mode = 3 can still properly encode and decode.
TEST(DeltaqModeTest,DeltaqMode3MultiThreadNoRowMT)92 TEST(DeltaqModeTest, DeltaqMode3MultiThreadNoRowMT) {
93 constexpr int kWidth = 1280;
94 constexpr int kHeight = 720;
95 // Dummy buffer of neutral gray samples.
96 constexpr size_t kBufferSize = kWidth * kHeight + kWidth * kHeight / 2;
97 std::vector<unsigned char> buffer(kBufferSize,
98 static_cast<unsigned char>(128));
99
100 aom_image_t img;
101 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
102 buffer.data()));
103
104 aom_codec_iface_t *iface = aom_codec_av1_cx();
105 aom_codec_enc_cfg_t cfg;
106 EXPECT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY),
107 AOM_CODEC_OK);
108 cfg.g_w = kWidth;
109 cfg.g_h = kHeight;
110 cfg.g_threads = 10;
111 cfg.rc_end_usage = AOM_Q;
112 cfg.g_profile = 0;
113 cfg.g_bit_depth = AOM_BITS_8;
114 cfg.g_input_bit_depth = 8;
115 cfg.g_lag_in_frames = 0;
116 cfg.rc_min_quantizer = 0;
117 cfg.rc_max_quantizer = 63;
118 cfg.g_pass = AOM_RC_ONE_PASS;
119 cfg.g_limit = 1;
120 aom_codec_ctx_t enc;
121 EXPECT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
122 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_ROW_MT, 0), AOM_CODEC_OK);
123 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 6), AOM_CODEC_OK);
124 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 14), AOM_CODEC_OK);
125 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 3), AOM_CODEC_OK);
126 EXPECT_EQ(aom_codec_set_option(&enc, "passes", "1"), AOM_CODEC_OK);
127 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_STUDIO_RANGE),
128 AOM_CODEC_OK);
129
130 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK);
131 aom_codec_iter_t iter = nullptr;
132 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
133 ASSERT_NE(pkt, nullptr);
134 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
135 // pkt->data.frame.flags is 0x1f0011.
136 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
137 pkt = aom_codec_get_cx_data(&enc, &iter);
138 EXPECT_EQ(pkt, nullptr);
139
140 // Flush encoder
141 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
142 iter = nullptr;
143 pkt = aom_codec_get_cx_data(&enc, &iter);
144 EXPECT_EQ(pkt, nullptr);
145
146 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
147 }
148
149 #if CONFIG_AV1_HIGHBITDEPTH
150 // 10-bit version of the DeltaqMode3MultiThread test.
TEST(DeltaqModeTest,DeltaqMode3MultiThreadHighbd)151 TEST(DeltaqModeTest, DeltaqMode3MultiThreadHighbd) {
152 constexpr int kWidth = 1280;
153 constexpr int kHeight = 720;
154 // Dummy buffer of 10-bit neutral gray samples.
155 constexpr size_t kBufferSize = kWidth * kHeight + kWidth * kHeight / 2;
156 std::vector<uint16_t> buffer(kBufferSize, 512);
157
158 aom_image_t img;
159 EXPECT_EQ(&img,
160 aom_img_wrap(&img, AOM_IMG_FMT_I42016, kWidth, kHeight, 1,
161 reinterpret_cast<unsigned char *>(buffer.data())));
162
163 aom_codec_iface_t *iface = aom_codec_av1_cx();
164 aom_codec_enc_cfg_t cfg;
165 EXPECT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY),
166 AOM_CODEC_OK);
167 cfg.g_w = kWidth;
168 cfg.g_h = kHeight;
169 cfg.g_threads = 10;
170 cfg.rc_end_usage = AOM_Q;
171 cfg.g_profile = 0;
172 cfg.g_bit_depth = AOM_BITS_10;
173 cfg.g_input_bit_depth = 10;
174 cfg.g_lag_in_frames = 0;
175 cfg.rc_min_quantizer = 0;
176 cfg.rc_max_quantizer = 63;
177 cfg.g_pass = AOM_RC_ONE_PASS;
178 cfg.g_limit = 1;
179 aom_codec_ctx_t enc;
180 EXPECT_EQ(aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH),
181 AOM_CODEC_OK);
182 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 6), AOM_CODEC_OK);
183 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 14), AOM_CODEC_OK);
184 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 3), AOM_CODEC_OK);
185 EXPECT_EQ(aom_codec_set_option(&enc, "passes", "1"), AOM_CODEC_OK);
186 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_STUDIO_RANGE),
187 AOM_CODEC_OK);
188
189 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK);
190 aom_codec_iter_t iter = nullptr;
191 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
192 ASSERT_NE(pkt, nullptr);
193 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
194 // pkt->data.frame.flags is 0x1f0011.
195 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
196 pkt = aom_codec_get_cx_data(&enc, &iter);
197 EXPECT_EQ(pkt, nullptr);
198
199 // Flush encoder
200 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
201 iter = nullptr;
202 pkt = aom_codec_get_cx_data(&enc, &iter);
203 EXPECT_EQ(pkt, nullptr);
204
205 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
206 }
207 #endif // CONFIG_AV1_HIGHBITDEPTH
208
209 } // namespace
210