1 #include "iamf/cli/codec/lpcm_decoder.h"
2
3 #include <cstdint>
4 #include <vector>
5
6 #include "absl/log/log.h"
7 #include "absl/status/status_matchers.h"
8 #include "gmock/gmock.h"
9 #include "gtest/gtest.h"
10 #include "iamf/obu/codec_config.h"
11 #include "iamf/obu/decoder_config/lpcm_decoder_config.h"
12 #include "iamf/obu/obu_header.h"
13
14 namespace iamf_tools {
15 namespace {
16
17 using ::absl_testing::IsOk;
18
19 constexpr bool kOverrideAudioRollDistance = true;
20 constexpr uint32_t kNumSamplesPerFrame = 1024;
21 constexpr uint8_t kSampleSize16 = 16;
22 constexpr bool kLittleEndian = true;
23
CreateCodecConfigObu(LpcmDecoderConfig lpcm_decoder_config,uint32_t num_samples_per_frame)24 CodecConfigObu CreateCodecConfigObu(LpcmDecoderConfig lpcm_decoder_config,
25 uint32_t num_samples_per_frame) {
26 const CodecConfig codec_config = {
27 .codec_id = CodecConfig::kCodecIdLpcm,
28 .num_samples_per_frame = num_samples_per_frame,
29 .decoder_config = lpcm_decoder_config};
30
31 CodecConfigObu codec_config_obu(ObuHeader(), 0, codec_config);
32 return codec_config_obu;
33 };
34
TEST(LpcmDecoderTest,Construct)35 TEST(LpcmDecoderTest, Construct) {
36 LpcmDecoderConfig lpcm_decoder_config;
37 lpcm_decoder_config.sample_rate_ = 48000;
38 lpcm_decoder_config.sample_size_ = 16;
39 lpcm_decoder_config.sample_format_flags_bitmask_ =
40 LpcmDecoderConfig::LpcmFormatFlagsBitmask::kLpcmLittleEndian;
41 CodecConfigObu codec_config_obu =
42 CreateCodecConfigObu(lpcm_decoder_config, kNumSamplesPerFrame);
43 ASSERT_THAT(codec_config_obu.Initialize(kOverrideAudioRollDistance), IsOk());
44 int number_of_channels = 11; // Arbitrary.
45
46 LpcmDecoder lpcm_decoder(codec_config_obu, number_of_channels);
47 }
48
TEST(LpcmDecoderTest,Initialize_InvalidConfigFails)49 TEST(LpcmDecoderTest, Initialize_InvalidConfigFails) {
50 LpcmDecoderConfig lpcm_decoder_config;
51 // The sample rate and bit depth are validated with CodecConfigObu::Initialize
52 // so if we want to test the validation in LpcmDecoderConfig::Initialize we
53 // will give an invalid sample_format_flags_bitmask_.
54 lpcm_decoder_config.sample_rate_ = 48000;
55 lpcm_decoder_config.sample_size_ = 16;
56 lpcm_decoder_config.sample_format_flags_bitmask_ =
57 LpcmDecoderConfig::LpcmFormatFlagsBitmask::kLpcmBeginReserved;
58 CodecConfigObu codec_config_obu =
59 CreateCodecConfigObu(lpcm_decoder_config, kNumSamplesPerFrame);
60 ASSERT_THAT(codec_config_obu.Initialize(kOverrideAudioRollDistance), IsOk());
61 int number_of_channels = 11; // Arbitrary.
62
63 LpcmDecoder lpcm_decoder(codec_config_obu, number_of_channels);
64 auto status = lpcm_decoder.Initialize();
65
66 EXPECT_FALSE(status.ok());
67 }
68
CreateDecoderForDecodingTest(uint8_t sample_size,bool little_endian,uint32_t num_samples_per_frame)69 LpcmDecoder CreateDecoderForDecodingTest(uint8_t sample_size,
70 bool little_endian,
71 uint32_t num_samples_per_frame) {
72 LpcmDecoderConfig lpcm_decoder_config;
73 // The sample rate and bit depth are validated with CodecConfigObu::Initialize
74 // so if we want to test the validation in LpcmDecoderConfig::Initialize we
75 // will give an invalid sample_format_flags_bitmask_.
76 lpcm_decoder_config.sample_rate_ = 48000;
77 lpcm_decoder_config.sample_size_ = sample_size;
78 using enum LpcmDecoderConfig::LpcmFormatFlagsBitmask;
79 lpcm_decoder_config.sample_format_flags_bitmask_ =
80 little_endian ? kLpcmLittleEndian : kLpcmBigEndian;
81 CodecConfigObu codec_config_obu =
82 CreateCodecConfigObu(lpcm_decoder_config, num_samples_per_frame);
83 if (!codec_config_obu.Initialize(kOverrideAudioRollDistance).ok()) {
84 LOG(ERROR) << "Failed to initialize codec config OBU";
85 }
86 constexpr int kTwoChannels = 2; // Keep the amount of test data reasonable.
87
88 LpcmDecoder lpcm_decoder(codec_config_obu, kTwoChannels);
89 auto status = lpcm_decoder.Initialize();
90 return lpcm_decoder;
91 }
92
TEST(LpcmDecoderTest,DecodeAudioFrame_FailsWhenFrameIsLargerThanExpected)93 TEST(LpcmDecoderTest, DecodeAudioFrame_FailsWhenFrameIsLargerThanExpected) {
94 constexpr uint32_t kShortNumberOfSamplesPerFrame = 1;
95 LpcmDecoder lpcm_decoder = CreateDecoderForDecodingTest(
96 kSampleSize16, kLittleEndian, kShortNumberOfSamplesPerFrame);
97 const std::vector<uint8_t>& kEncodedFrameWithOneSamplesPerFrame = {
98 0x00, 0x00, // 0
99 0x01, 0x00, // 1
100 };
101 // The decoder is configured correctly. One sample per frame decodes fine.
102 ASSERT_THAT(
103 lpcm_decoder.DecodeAudioFrame(kEncodedFrameWithOneSamplesPerFrame),
104 IsOk());
105
106 // But decoding two samples per frame fails, since the decoder was configured
107 // for at most one sample per frame.
108 const std::vector<uint8_t>& kEncodedFrameWithTwoSamplesPerFrame = {
109 0x00, 0x00, // 0
110 0x01, 0x00, // 1
111 0x00, 0x01, // 256
112 0x80, 0xff, // -128
113 };
114 EXPECT_FALSE(
115 lpcm_decoder.DecodeAudioFrame(kEncodedFrameWithTwoSamplesPerFrame).ok());
116 }
117
TEST(LpcmDecoderTest,DecodeAudioFrame_LittleEndian16BitSamples)118 TEST(LpcmDecoderTest, DecodeAudioFrame_LittleEndian16BitSamples) {
119 uint8_t sample_size = 16;
120 bool little_endian = true;
121 LpcmDecoder lpcm_decoder = CreateDecoderForDecodingTest(
122 sample_size, little_endian, kNumSamplesPerFrame);
123 const std::vector<uint8_t>& encoded_frame = {
124 0x00, 0x00, // 0
125 0x01, 0x00, // 1
126 0x00, 0x01, // 256
127 0x80, 0xff, // -128
128 };
129
130 auto status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
131 const auto& decoded_samples = lpcm_decoder.ValidDecodedSamples();
132
133 EXPECT_THAT(status, IsOk());
134 // We have two channels and four samples, so we expect two time ticks of two
135 // samples each.
136 EXPECT_EQ(decoded_samples.size(), 2);
137 EXPECT_EQ(decoded_samples[0].size(), 2);
138 EXPECT_EQ(decoded_samples[0][0], 0);
139 EXPECT_EQ(decoded_samples[0][1], 0x00010000);
140 EXPECT_EQ(decoded_samples[1].size(), 2);
141 EXPECT_EQ(decoded_samples[1][0], 0x01000000);
142 EXPECT_EQ(decoded_samples[1][1], 0xff800000);
143 }
144
TEST(LpcmDecoderTest,DecodeAudioFrame_BigEndian24BitSamples)145 TEST(LpcmDecoderTest, DecodeAudioFrame_BigEndian24BitSamples) {
146 uint8_t sample_size = 24;
147 bool little_endian = false;
148 LpcmDecoder lpcm_decoder = CreateDecoderForDecodingTest(
149 sample_size, little_endian, kNumSamplesPerFrame);
150 const std::vector<uint8_t>& encoded_frame = {
151 0x00, 0x00, 0x00, // 0
152 0x00, 0x00, 0x01, // 1
153 0x00, 0x00, 0x03, // 3
154 0x00, 0x00, 0x04, // 4
155 0x7f, 0xff, 0xff, // 8388607
156 0x80, 0x00, 0x00, // -8388608
157 };
158
159 auto status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
160 const auto& decoded_samples = lpcm_decoder.ValidDecodedSamples();
161
162 EXPECT_THAT(status, IsOk());
163 // We have two channels and six samples, so we expect three time ticks of two
164 // samples each.
165 EXPECT_EQ(decoded_samples.size(), 3);
166 EXPECT_EQ(decoded_samples[0].size(), 2);
167 EXPECT_EQ(decoded_samples[0][0], 0);
168 EXPECT_EQ(decoded_samples[0][1], 0x00000100);
169 EXPECT_EQ(decoded_samples[1].size(), 2);
170 EXPECT_EQ(decoded_samples[1][0], 0x00000300);
171 EXPECT_EQ(decoded_samples[1][1], 0x00000400);
172 EXPECT_EQ(decoded_samples[2].size(), 2);
173 EXPECT_EQ(decoded_samples[2][0], 0x7fffff00);
174 EXPECT_EQ(decoded_samples[2][1], 0x80000000);
175 }
176
TEST(LpcmDecoderTest,DecodeAudioFrame_WillNotDecodeWrongSize)177 TEST(LpcmDecoderTest, DecodeAudioFrame_WillNotDecodeWrongSize) {
178 uint8_t sample_size = 16;
179 bool little_endian = true;
180 LpcmDecoder lpcm_decoder = CreateDecoderForDecodingTest(
181 sample_size, little_endian, kNumSamplesPerFrame);
182 // If we have 6 bytes, 16-bit samples, and two channels, we only have 3
183 // samples which doesn't divide evenly into the number of channels.
184 const std::vector<uint8_t>& encoded_frame = {0x00, 0x00, 0x00,
185 0x00, 0x00, 0x00};
186
187 auto status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
188 EXPECT_FALSE(status.ok());
189 EXPECT_THAT(lpcm_decoder.ValidDecodedSamples(), ::testing::IsEmpty());
190 }
191
TEST(LpcmDecoderTest,DecodeAudioFrame_OverwritesExistingSamples)192 TEST(LpcmDecoderTest, DecodeAudioFrame_OverwritesExistingSamples) {
193 uint8_t sample_size = 16;
194 bool little_endian = true;
195 LpcmDecoder lpcm_decoder = CreateDecoderForDecodingTest(
196 sample_size, little_endian, kNumSamplesPerFrame);
197 const std::vector<uint8_t>& encoded_frame = {0x00, 0x00, 0x01, 0x00};
198
199 auto status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
200 EXPECT_THAT(status, IsOk());
201 EXPECT_EQ(lpcm_decoder.ValidDecodedSamples().size(), 1);
202
203 status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
204 EXPECT_THAT(status, IsOk());
205 EXPECT_EQ(lpcm_decoder.ValidDecodedSamples().size(), 1);
206
207 status = lpcm_decoder.DecodeAudioFrame(encoded_frame);
208 EXPECT_THAT(status, IsOk());
209 EXPECT_EQ(lpcm_decoder.ValidDecodedSamples().size(), 1);
210 }
211
212 } // namespace
213 } // namespace iamf_tools
214