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 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12 #include "iamf/cli/codec/lpcm_encoder.h"
13
14 #include <cstdint>
15 #include <memory>
16 #include <vector>
17
18 #include "absl/status/status_matchers.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "iamf/cli/codec/tests/encoder_test_base.h"
22 #include "iamf/obu/codec_config.h"
23 #include "iamf/obu/decoder_config/lpcm_decoder_config.h"
24 #include "iamf/obu/obu_header.h"
25
26 namespace iamf_tools {
27 namespace {
28
29 using ::absl_testing::IsOk;
30
31 constexpr bool kOverrideAudioRollDistance = true;
32
33 class LpcmEncoderTest : public EncoderTestBase, public testing::Test {
34 public:
LpcmEncoderTest()35 LpcmEncoderTest() { input_sample_size_ = 32; }
36 ~LpcmEncoderTest() = default;
37
38 protected:
ConstructEncoder()39 void ConstructEncoder() override {
40 // Construct a Codec Config OBU. The only fields that should affect the
41 // output are `num_samples_per_frame` and `decoder_config`.
42 const CodecConfig temp = {.codec_id = CodecConfig::kCodecIdLpcm,
43 .num_samples_per_frame = num_samples_per_frame_,
44 .decoder_config = lpcm_decoder_config_};
45 CodecConfigObu codec_config(ObuHeader(), 0, temp);
46 EXPECT_THAT(codec_config.Initialize(kOverrideAudioRollDistance), IsOk());
47
48 encoder_ = std::make_unique<LpcmEncoder>(codec_config, num_channels_);
49 }
50
51 LpcmDecoderConfig lpcm_decoder_config_ = {
52 .sample_format_flags_bitmask_ = LpcmDecoderConfig::kLpcmLittleEndian,
53 .sample_size_ = 32,
54 .sample_rate_ = 48000};
55 }; // namespace iamf_tools
56
TEST_F(LpcmEncoderTest,LittleEndian32bit)57 TEST_F(LpcmEncoderTest, LittleEndian32bit) {
58 InitExpectOk();
59
60 EncodeAudioFrame({{0x01234567}});
61 expected_audio_frames_.push_back({0x67, 0x45, 0x23, 0x01});
62 FinalizeAndValidate();
63 }
64
TEST_F(LpcmEncoderTest,BigEndian32bit)65 TEST_F(LpcmEncoderTest, BigEndian32bit) {
66 lpcm_decoder_config_.sample_format_flags_bitmask_ =
67 LpcmDecoderConfig::kLpcmBigEndian;
68 InitExpectOk();
69
70 EncodeAudioFrame({{0x01234567}});
71 expected_audio_frames_.push_back({0x01, 0x23, 0x45, 0x67});
72 FinalizeAndValidate();
73 }
74
TEST_F(LpcmEncoderTest,MultipleFrames)75 TEST_F(LpcmEncoderTest, MultipleFrames) {
76 InitExpectOk();
77
78 EncodeAudioFrame({{0x01234567}});
79 expected_audio_frames_.push_back({0x67, 0x45, 0x23, 0x01});
80 EncodeAudioFrame({{0x77665544}});
81 expected_audio_frames_.push_back({0x44, 0x55, 0x66, 0x77});
82 FinalizeAndValidate();
83 }
84
TEST_F(LpcmEncoderTest,LittleEndian16bit)85 TEST_F(LpcmEncoderTest, LittleEndian16bit) {
86 lpcm_decoder_config_.sample_size_ = 16;
87 input_sample_size_ = 16;
88 InitExpectOk();
89
90 EncodeAudioFrame({{0x12340000}});
91 expected_audio_frames_.push_back({0x34, 0x12});
92 FinalizeAndValidate();
93 }
94
TEST_F(LpcmEncoderTest,BigEndian16bit)95 TEST_F(LpcmEncoderTest, BigEndian16bit) {
96 lpcm_decoder_config_.sample_size_ = 16;
97 lpcm_decoder_config_.sample_format_flags_bitmask_ =
98 LpcmDecoderConfig::kLpcmBigEndian;
99
100 input_sample_size_ = 16;
101 InitExpectOk();
102
103 EncodeAudioFrame({{0x12340000}});
104 expected_audio_frames_.push_back({0x12, 0x34});
105 FinalizeAndValidate();
106 }
107
TEST_F(LpcmEncoderTest,LittleEndian24bit)108 TEST_F(LpcmEncoderTest, LittleEndian24bit) {
109 lpcm_decoder_config_.sample_size_ = 24;
110 input_sample_size_ = 24;
111 InitExpectOk();
112
113 EncodeAudioFrame({{0x12345600}});
114 expected_audio_frames_.push_back({0x56, 0x34, 0x12});
115 FinalizeAndValidate();
116 }
117
TEST_F(LpcmEncoderTest,BigEndian24bit)118 TEST_F(LpcmEncoderTest, BigEndian24bit) {
119 lpcm_decoder_config_.sample_size_ = 24;
120 lpcm_decoder_config_.sample_format_flags_bitmask_ =
121 LpcmDecoderConfig::kLpcmBigEndian;
122 input_sample_size_ = 24;
123 InitExpectOk();
124
125 EncodeAudioFrame({{0x12345600}});
126 expected_audio_frames_.push_back({0x12, 0x34, 0x56});
127 FinalizeAndValidate();
128 }
129
TEST_F(LpcmEncoderTest,MultipleSamplesPerFrame)130 TEST_F(LpcmEncoderTest, MultipleSamplesPerFrame) {
131 num_samples_per_frame_ = 3;
132 InitExpectOk();
133
134 EncodeAudioFrame({{0x11111111}, {0x22222222}, {0x33333333}});
135 expected_audio_frames_.push_back(
136 {0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33});
137 FinalizeAndValidate();
138 }
139
TEST_F(LpcmEncoderTest,EncodeAudioFrameFailsWhenThereAreNoSamples)140 TEST_F(LpcmEncoderTest, EncodeAudioFrameFailsWhenThereAreNoSamples) {
141 InitExpectOk();
142 const std::vector<std::vector<int32_t>> kInputFrameWithNoSamples = {};
143
144 EncodeAudioFrame(kInputFrameWithNoSamples,
145 /*expected_encode_frame_is_ok=*/false);
146 }
147
TEST_F(LpcmEncoderTest,DoesNotSupportPartialFrames)148 TEST_F(LpcmEncoderTest, DoesNotSupportPartialFrames) {
149 constexpr bool kExpectEncodeFrameIsNotOk = false;
150 num_samples_per_frame_ = 3;
151 InitExpectOk();
152
153 EncodeAudioFrame({{0x11111111}, {0x22222222}}, kExpectEncodeFrameIsNotOk);
154 }
155
TEST_F(LpcmEncoderTest,TwoChannels)156 TEST_F(LpcmEncoderTest, TwoChannels) {
157 num_channels_ = 2;
158 InitExpectOk();
159
160 EncodeAudioFrame({{0x11111111, 0x22222222}});
161 expected_audio_frames_.push_back(
162 {0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22});
163 FinalizeAndValidate();
164 }
165
TEST_F(LpcmEncoderTest,EncodeAudioFrameFailsWhenNumChannelsIsInconsitentWithInputFrame)166 TEST_F(LpcmEncoderTest,
167 EncodeAudioFrameFailsWhenNumChannelsIsInconsitentWithInputFrame) {
168 num_channels_ = 1;
169 const std::vector<std::vector<int32_t>> kInputFrameWithTwoChannels = {
170 {0x11111111, 0x22222222}};
171 InitExpectOk();
172
173 EncodeAudioFrame(kInputFrameWithTwoChannels,
174 /*expected_encode_frame_is_ok=*/false);
175 }
176
TEST_F(LpcmEncoderTest,FramesAreInOrder)177 TEST_F(LpcmEncoderTest, FramesAreInOrder) {
178 InitExpectOk();
179
180 // Encode several frames and ensure the correct number of frames are output in
181 // the same order as the input.
182 const int kNumFrames = 100;
183 for (int i = 0; i < kNumFrames; i++) {
184 EncodeAudioFrame(std::vector<std::vector<int32_t>>(
185 num_samples_per_frame_, std::vector<int32_t>(num_channels_, i)));
186 }
187 FinalizeAndValidateOrderOnly(kNumFrames);
188 }
189
190 } // namespace
191 } // namespace iamf_tools
192