2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
13 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
14 #include "test/acm_random.h"
16 #include "./aom_config.h"
18 #include "aom_ports/mem.h" // ROUND_POWER_OF_TWO
19 #include "aom/aomcx.h"
20 #include "aom/aomdx.h"
21 #include "aom/aom_encoder.h"
22 #include "aom/aom_decoder.h"
24 using libaom_test::ACMRandom
;
27 class CompressedSource
{
29 explicit CompressedSource(int seed
) : rnd_(seed
), frame_count_(0) {
30 aom_codec_iface_t
*algo
= &aom_codec_av1_cx_algo
;
32 aom_codec_enc_cfg_t cfg
;
33 aom_codec_enc_config_default(algo
, &cfg
, 0);
35 // force the quantizer, to reduce the sensitivity on encoding choices.
36 // e.g, we don't want this test to break when the rate control is modified.
38 const int max_q
= cfg
.rc_max_quantizer
;
39 const int min_q
= cfg
.rc_min_quantizer
;
40 const int q
= rnd_
.PseudoUniform(max_q
- min_q
+ 1) + min_q
;
42 cfg
.rc_end_usage
= AOM_Q
;
43 cfg
.rc_max_quantizer
= q
;
44 cfg
.rc_min_quantizer
= q
;
47 // choose the picture size
49 width_
= rnd_
.PseudoUniform(kWidth
- 8) + 8;
50 height_
= rnd_
.PseudoUniform(kHeight
- 8) + 8;
53 // choose the chroma subsampling
55 const aom_img_fmt_t fmts
[] = {
61 format_
= fmts
[rnd_
.PseudoUniform(NELEMENTS(fmts
))];
66 cfg
.g_lag_in_frames
= 0;
67 if (format_
== AOM_IMG_FMT_I420
)
69 else if (format_
== AOM_IMG_FMT_I444
)
71 else if (format_
== AOM_IMG_FMT_I422
)
74 aom_codec_enc_init(&enc_
, algo
, &cfg
, 0);
77 ~CompressedSource() { aom_codec_destroy(&enc_
); }
79 const aom_codec_cx_pkt_t
*ReadFrame() {
80 uint8_t buf
[kWidth
* kHeight
* 3] = { 0 };
82 // render regular pattern
83 const int period
= rnd_
.Rand8() % 32 + 1;
84 const int phase
= rnd_
.Rand8() % period
;
86 const int val_a
= rnd_
.Rand8();
87 const int val_b
= rnd_
.Rand8();
89 for (int i
= 0; i
< (int)sizeof buf
; ++i
)
90 buf
[i
] = (i
+ phase
) % period
< period
/ 2 ? val_a
: val_b
;
93 aom_img_wrap(&img
, format_
, width_
, height_
, 0, buf
);
94 aom_codec_encode(&enc_
, &img
, frame_count_
++, 1, 0);
96 aom_codec_iter_t iter
= NULL
;
98 const aom_codec_cx_pkt_t
*pkt
= NULL
;
101 pkt
= aom_codec_get_cx_data(&enc_
, &iter
);
102 } while (pkt
&& pkt
->kind
!= AOM_CODEC_CX_FRAME_PKT
);
108 static const int kWidth
= 128;
109 static const int kHeight
= 128;
112 aom_img_fmt_t format_
;
113 aom_codec_ctx_t enc_
;
118 // lowers an aom_image_t to a easily comparable/printable form
119 std::vector
<int16_t> Serialize(const aom_image_t
*img
) {
120 std::vector
<int16_t> bytes
;
121 bytes
.reserve(img
->d_w
* img
->d_h
* 3);
122 for (int plane
= 0; plane
< 3; ++plane
) {
123 const int w
= aom_img_plane_width(img
, plane
);
124 const int h
= aom_img_plane_height(img
, plane
);
126 for (int r
= 0; r
< h
; ++r
) {
127 for (int c
= 0; c
< w
; ++c
) {
128 unsigned char *row
= img
->planes
[plane
] + r
* img
->stride
[plane
];
129 if (img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
)
130 bytes
.push_back(row
[c
* 2]);
132 bytes
.push_back(row
[c
]);
142 explicit Decoder(int allowLowbitdepth
) {
143 aom_codec_iface_t
*algo
= &aom_codec_av1_dx_algo
;
145 aom_codec_dec_cfg_t cfg
= aom_codec_dec_cfg_t();
146 cfg
.allow_lowbitdepth
= allowLowbitdepth
;
148 aom_codec_dec_init(&dec_
, algo
, &cfg
, 0);
151 ~Decoder() { aom_codec_destroy(&dec_
); }
153 std::vector
<int16_t> decode(const aom_codec_cx_pkt_t
*pkt
) {
154 aom_codec_decode(&dec_
, static_cast<uint8_t *>(pkt
->data
.frame
.buf
),
155 static_cast<unsigned int>(pkt
->data
.frame
.sz
), NULL
);
157 aom_codec_iter_t iter
= NULL
;
158 return Serialize(aom_codec_get_frame(&dec_
, &iter
));
162 aom_codec_ctx_t dec_
;
165 // Try to reveal a mismatch between LBD and HBD coding paths.
166 TEST(CodingPathSync
, SearchForHbdLbdMismatch
) {
167 const int count_tests
= 10;
168 for (int i
= 0; i
< count_tests
; ++i
) {
172 CompressedSource
enc(i
);
174 for (int k
= 0; k
< 3; ++k
) {
175 const aom_codec_cx_pkt_t
*frame
= enc
.ReadFrame();
177 std::vector
<int16_t> lbd_yuv
= dec_lbd
.decode(frame
);
178 std::vector
<int16_t> hbd_yuv
= dec_hbd
.decode(frame
);
180 ASSERT_EQ(lbd_yuv
, hbd_yuv
);
185 TEST(CodingPathSyncLarge
, SearchForHbdLbdMismatchLarge
) {
186 const int count_tests
= 100;
187 const int seed
= 1234;
188 for (int i
= 0; i
< count_tests
; ++i
) {
192 CompressedSource
enc(seed
+ i
);
194 for (int k
= 0; k
< 5; ++k
) {
195 const aom_codec_cx_pkt_t
*frame
= enc
.ReadFrame();
197 std::vector
<int16_t> lbd_yuv
= dec_lbd
.decode(frame
);
198 std::vector
<int16_t> hbd_yuv
= dec_hbd
.decode(frame
);
200 ASSERT_EQ(lbd_yuv
, hbd_yuv
);