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/tests/cli_test_utils.h"
13
14 #include <array>
15 #include <cstddef>
16 #include <cstdint>
17 #include <filesystem>
18 #include <fstream>
19 #include <ios>
20 #include <list>
21 #include <numeric>
22 #include <optional>
23 #include <vector>
24
25 #include "absl/status/status.h"
26 #include "absl/status/status_matchers.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/types/span.h"
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 #include "iamf/common/write_bit_buffer.h"
32 #include "iamf/obu/obu_base.h"
33 #include "iamf/obu/obu_header.h"
34 #include "iamf/obu/tests/obu_test_utils.h"
35
36 namespace iamf_tools {
37 namespace {
38
39 using ::absl_testing::IsOk;
40 using ::testing::Not;
41
TEST(GetLogSpectralDistance,ReturnsCorrectValue)42 TEST(GetLogSpectralDistance, ReturnsCorrectValue) {
43 std::vector<double> first_log_spectrum(10);
44 std::iota(first_log_spectrum.begin(), first_log_spectrum.end(), 0);
45 std::vector<double> second_log_spectrum(10);
46 std::iota(second_log_spectrum.begin(), second_log_spectrum.end(), 1);
47 EXPECT_EQ(GetLogSpectralDistance(absl::MakeConstSpan(first_log_spectrum),
48 absl::MakeConstSpan(second_log_spectrum)),
49 10.0);
50 }
51
TEST(ExpectLogSpectralDistanceBelowThreshold,ReturnsZeroWhenEqual)52 TEST(ExpectLogSpectralDistanceBelowThreshold, ReturnsZeroWhenEqual) {
53 std::vector<double> first_log_spectrum(10);
54 std::iota(first_log_spectrum.begin(), first_log_spectrum.end(), 1);
55 std::vector<double> second_log_spectrum(10);
56 std::iota(second_log_spectrum.begin(), second_log_spectrum.end(), 1);
57 EXPECT_EQ(GetLogSpectralDistance(absl::MakeConstSpan(first_log_spectrum),
58 absl::MakeConstSpan(second_log_spectrum)),
59 0.0);
60 }
61
TEST(ReadFileToBytes,FailsIfFileDoesNotExist)62 TEST(ReadFileToBytes, FailsIfFileDoesNotExist) {
63 const std::filesystem::path file_path_does_not_exist(
64 GetAndCleanupOutputFileName(".bin"));
65
66 ASSERT_FALSE(std::filesystem::exists(file_path_does_not_exist));
67
68 std::vector<uint8_t> bytes;
69 EXPECT_FALSE(ReadFileToBytes(file_path_does_not_exist, bytes).ok());
70 }
71
WriteVectorToFile(const std::filesystem::path filename,const std::vector<uint8_t> & bytes)72 void WriteVectorToFile(const std::filesystem::path filename,
73 const std::vector<uint8_t>& bytes) {
74 std::filesystem::remove(filename);
75 WriteBitBuffer wb(0);
76
77 ASSERT_THAT(wb.WriteUint8Span(absl::MakeConstSpan(bytes)), IsOk());
78 auto output_file = std::make_optional<std::fstream>(
79 filename.string(), std::ios::binary | std::ios::out);
80 ASSERT_THAT(wb.FlushAndWriteToFile(output_file), IsOk());
81 output_file->close();
82 }
83
TEST(ReadFileToBytes,ReadsFileContents)84 TEST(ReadFileToBytes, ReadsFileContents) {
85 // Prepare a file to read back.
86 const std::filesystem::path file_to_read(GetAndCleanupOutputFileName(".bin"));
87 const std::vector<uint8_t> kExpectedBytes = {0x01, 0x02, 0x00, 0x03, 0x04};
88 WriteVectorToFile(file_to_read, kExpectedBytes);
89
90 std::vector<uint8_t> bytes;
91 EXPECT_THAT(ReadFileToBytes(file_to_read, bytes), IsOk());
92
93 EXPECT_EQ(bytes, kExpectedBytes);
94 }
95
TEST(ReadFileToBytes,AppendsFileContents)96 TEST(ReadFileToBytes, AppendsFileContents) {
97 // Prepare a file to read back.
98 const std::filesystem::path file_to_read(GetAndCleanupOutputFileName(".bin"));
99 const std::vector<uint8_t> kExpectedBytes = {0x01, 0x02, 0x00, 0x03, 0x04};
100 WriteVectorToFile(file_to_read, kExpectedBytes);
101
102 std::vector<uint8_t> bytes;
103 EXPECT_THAT(ReadFileToBytes(file_to_read, bytes), IsOk());
104 EXPECT_EQ(bytes.size(), kExpectedBytes.size());
105 // The vector grows with each read.
106 EXPECT_THAT(ReadFileToBytes(file_to_read, bytes), IsOk());
107 EXPECT_EQ(bytes.size(), kExpectedBytes.size() * 2);
108 }
109
TEST(ReadFileToBytes,ReadsBinaryFileWithPlatformDependentControlCharacters)110 TEST(ReadFileToBytes, ReadsBinaryFileWithPlatformDependentControlCharacters) {
111 // Prepare a file to read back.
112 const std::filesystem::path file_to_read(GetAndCleanupOutputFileName(".bin"));
113 const std::vector<uint8_t> kBinaryDataWithPlatformDependentControlCharacters =
114 {'\n', '\r', '\n', '\r', '\x1a', '\r', '\n', '\n', ' ', '\n'};
115 WriteVectorToFile(file_to_read,
116 kBinaryDataWithPlatformDependentControlCharacters);
117
118 std::vector<uint8_t> bytes;
119 EXPECT_THAT(ReadFileToBytes(file_to_read, bytes), IsOk());
120
121 EXPECT_THAT(bytes, kBinaryDataWithPlatformDependentControlCharacters);
122 }
123
TEST(SerializeObusExpectOk,SerializesObus)124 TEST(SerializeObusExpectOk, SerializesObus) {
125 MockObu mock_obu(ObuHeader{}, ObuType::kObuIaCodecConfig);
126 constexpr size_t kObuHeaderSize = 2;
127 constexpr std::array<uint8_t, 6> kExpectedBytes = {// OBU header.
128 0x00, 0x04,
129 // OBU payload.
130 0x01, 0x02, 0x00, 0x03};
131
132 ON_CALL(mock_obu, ValidateAndWritePayload)
133 .WillByDefault([&](WriteBitBuffer& wb) {
134 return wb.WriteUint8Span(
135 absl::MakeConstSpan(kExpectedBytes).subspan(kObuHeaderSize));
136 });
137 const std::vector<uint8_t> serialized_obus =
138 SerializeObusExpectOk(std::list<const ObuBase*>{&mock_obu});
139
140 EXPECT_EQ(absl::MakeConstSpan(serialized_obus),
141 absl::MakeConstSpan(kExpectedBytes));
142 }
143
TEST(OneFrameDelayer,ValidatesInputShapeWithTooManyChannels)144 TEST(OneFrameDelayer, ValidatesInputShapeWithTooManyChannels) {
145 // Input shape validation is managed by `SampleProcessorBase`.
146 constexpr uint32_t kNumSamplesPerFrame = 3;
147 constexpr size_t kNumChannels = 1;
148 OneFrameDelayer one_frame_delayer(kNumSamplesPerFrame, kNumChannels);
149 const std::vector<std::vector<int32_t>> kInputFrameWithTooManyChannels(
150 kNumSamplesPerFrame, std::vector<int32_t>(kNumChannels + 1, 0));
151
152 EXPECT_THAT(one_frame_delayer.PushFrame(kInputFrameWithTooManyChannels),
153 Not(IsOk()));
154 }
155
TEST(OneFrameDelayer,ValidatesInputShapeWithTooManySamplesPerFrame)156 TEST(OneFrameDelayer, ValidatesInputShapeWithTooManySamplesPerFrame) {
157 // Input shape validation is managed by `SampleProcessorBase`.
158 constexpr uint32_t kNumSamplesPerFrame = 3;
159 constexpr size_t kNumChannels = 1;
160 OneFrameDelayer one_frame_delayer(kNumSamplesPerFrame, kNumChannels);
161 const std::vector<std::vector<int32_t>> kInputFrameWithTooFewSamples(
162 kNumSamplesPerFrame + 1, std::vector<int32_t>(kNumChannels, 0));
163
164 EXPECT_THAT(one_frame_delayer.PushFrame(kInputFrameWithTooFewSamples),
165 Not(IsOk()));
166 }
167
TEST(OneFrameDelayer,DelaysSamplesByOneFrame)168 TEST(OneFrameDelayer, DelaysSamplesByOneFrame) {
169 constexpr uint32_t kNumSamplesPerFrame = 5;
170 constexpr size_t kNumChannels = 4;
171 const std::vector<std::vector<int32_t>> kFirstInputFrame = {
172 {{1, 2, 3, 4},
173 {5, 6, 7, 8},
174 {9, 10, 11, 12},
175 {13, 14, 15, 16},
176 {17, 18, 19, 20}}};
177 const std::vector<std::vector<int32_t>> kSecondInputFrame = {
178 {{21, 22, 23, 24}}};
179 OneFrameDelayer one_frame_delayer(kNumSamplesPerFrame, kNumChannels);
180 // Nothing is available at the start.
181 EXPECT_TRUE(one_frame_delayer.GetOutputSamplesAsSpan().empty());
182 EXPECT_THAT(one_frame_delayer.PushFrame(kFirstInputFrame), IsOk());
183 // Still nothing is available because the samples are delayed by a frame.
184 EXPECT_TRUE(one_frame_delayer.GetOutputSamplesAsSpan().empty());
185
186 // Pushing in a new frame will cause the first frame to be available.
187 EXPECT_THAT(one_frame_delayer.PushFrame(kSecondInputFrame), IsOk());
188
189 EXPECT_THAT(one_frame_delayer.GetOutputSamplesAsSpan(), kFirstInputFrame);
190 }
191
TEST(OneFrameDelayer,GetOutputSamplesAsSpanReturnsFinalFrameAfterFlush)192 TEST(OneFrameDelayer, GetOutputSamplesAsSpanReturnsFinalFrameAfterFlush) {
193 constexpr uint32_t kNumSamplesPerFrame = 5;
194 constexpr size_t kNumChannels = 4;
195 const std::vector<std::vector<int32_t>> kFirstInputFrame = {
196 {{1, 2, 3, 4},
197 {5, 6, 7, 8},
198 {9, 10, 11, 12},
199 {13, 14, 15, 16},
200 {17, 18, 19, 20}}};
201 OneFrameDelayer one_frame_delayer(kNumSamplesPerFrame, kNumChannels);
202 EXPECT_THAT(one_frame_delayer.PushFrame(kFirstInputFrame), IsOk());
203 // Nothing is available because the samples are delayed by a frame.
204 EXPECT_TRUE(one_frame_delayer.GetOutputSamplesAsSpan().empty());
205
206 // Flushing will allow access to the final delayed frame.
207 EXPECT_THAT(one_frame_delayer.Flush(), IsOk());
208
209 EXPECT_THAT(one_frame_delayer.GetOutputSamplesAsSpan(), kFirstInputFrame);
210 }
211
212 } // namespace
213 } // namespace iamf_tools
214