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/obu/decoder_config/flac_decoder_config.h"
13
14 #include <cstdint>
15 #include <functional>
16 #include <utility>
17 #include <vector>
18
19 #include "absl/log/log.h"
20 #include "absl/status/status.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/types/span.h"
23 #include "iamf/common/read_bit_buffer.h"
24 #include "iamf/common/utils/macros.h"
25 #include "iamf/common/utils/validation_utils.h"
26 #include "iamf/common/write_bit_buffer.h"
27
28 namespace iamf_tools {
29
30 namespace {
31
GetStreamInfo(const FlacDecoderConfig & decoder_config,const FlacMetaBlockStreamInfo ** stream_info)32 absl::Status GetStreamInfo(const FlacDecoderConfig& decoder_config,
33 const FlacMetaBlockStreamInfo** stream_info) {
34 if (decoder_config.metadata_blocks_.empty() ||
35 decoder_config.metadata_blocks_.front().header.block_type !=
36 FlacMetaBlockHeader::kFlacStreamInfo) {
37 return absl::InvalidArgumentError(
38 "FLAC always requires the first block is present and is a "
39 "`STREAMINFO` block.");
40 }
41
42 *stream_info = &std::get<FlacMetaBlockStreamInfo>(
43 decoder_config.metadata_blocks_.front().payload);
44 return absl::OkStatus();
45 }
46
47 using Cons = FlacStreamInfoConstraints;
48
ValidateSampleRate(uint32_t sample_rate)49 absl::Status ValidateSampleRate(uint32_t sample_rate) {
50 return ValidateInRange(
51 sample_rate, {Cons::kMinSampleRate, Cons::kMaxSampleRate}, "sample_rate");
52 }
53
ValidateBitsPerSample(uint8_t bits_per_sample)54 absl::Status ValidateBitsPerSample(uint8_t bits_per_sample) {
55 // Validate restrictions from the FLAC specification.
56 return ValidateInRange(bits_per_sample,
57 {Cons::kMinBitsPerSample, Cons::kMaxBitsPerSample},
58 "bits_per_sample");
59 }
60
ValidateTotalSamplesInStream(uint64_t total_samples_in_stream)61 absl::Status ValidateTotalSamplesInStream(uint64_t total_samples_in_stream) {
62 // The FLAC specification treats this as a 36-bit value which is always valid,
63 // but in `iamf_tools` it could be out of bounds because it is stored as a
64 // `uint64_t`.
65 return ValidateInRange(
66 total_samples_in_stream,
67 {Cons::kMinTotalSamplesInStream, Cons::kMaxTotalSamplesInStream},
68 "total_samples_in_stream");
69 }
70
71 // Validates the `FlacDecoderConfig`.
ValidatePayload(uint32_t num_samples_per_frame,const FlacDecoderConfig & decoder_config)72 absl::Status ValidatePayload(uint32_t num_samples_per_frame,
73 const FlacDecoderConfig& decoder_config) {
74 for (int i = 0; i < decoder_config.metadata_blocks_.size(); i++) {
75 const bool last_metadata_block_flag =
76 decoder_config.metadata_blocks_[i].header.last_metadata_block_flag;
77
78 const bool last_block = (i == decoder_config.metadata_blocks_.size() - 1);
79
80 if (last_metadata_block_flag != last_block) {
81 return absl::InvalidArgumentError(
82 "There MUST be exactly one FLAC metadata block with "
83 "`last_metadata_block_flag == true` and it MUST be the final block.");
84 }
85 }
86
87 const FlacMetaBlockStreamInfo* stream_info;
88 RETURN_IF_NOT_OK(GetStreamInfo(decoder_config, &stream_info));
89
90 // FLAC restricts some fields.
91 RETURN_IF_NOT_OK(ValidateSampleRate(stream_info->sample_rate));
92 RETURN_IF_NOT_OK(ValidateBitsPerSample(stream_info->bits_per_sample));
93
94 RETURN_IF_NOT_OK(Validate(stream_info->minimum_block_size,
95 std::greater_equal{}, Cons::kMinMinAndMaxBlockSize,
96 "minimum_block_size >="));
97 RETURN_IF_NOT_OK(Validate(stream_info->maximum_block_size,
98 std::greater_equal{}, Cons::kMinMinAndMaxBlockSize,
99 "maximum_block_size >="));
100
101 // IAMF restricts some fields.
102 RETURN_IF_NOT_OK(
103 ValidateEqual(static_cast<uint32_t>(stream_info->maximum_block_size),
104 num_samples_per_frame, "maximum_block_size"));
105 RETURN_IF_NOT_OK(
106 ValidateEqual(static_cast<uint32_t>(stream_info->minimum_block_size),
107 num_samples_per_frame, "minimum_block_size"));
108 RETURN_IF_NOT_OK(ValidateEqual(stream_info->minimum_frame_size,
109 Cons::kMinFrameSize, "minimum_frame_size"));
110 RETURN_IF_NOT_OK(ValidateEqual(stream_info->maximum_frame_size,
111 Cons::kMaxFrameSize, "maximum_frame_size"));
112
113 RETURN_IF_NOT_OK(ValidateEqual(stream_info->number_of_channels,
114 Cons::kNumberOfChannels,
115 "number_of_channels"));
116
117 RETURN_IF_NOT_OK(ValidateTotalSamplesInStream(stream_info->bits_per_sample));
118
119 if (stream_info->md5_signature != Cons::kMd5Signature) {
120 return absl::InvalidArgumentError("Invalid md5_signature.");
121 }
122
123 return absl::OkStatus();
124 }
125
ValidateAudioRollDistance(int16_t audio_roll_distance)126 absl::Status ValidateAudioRollDistance(int16_t audio_roll_distance) {
127 return ValidateEqual(audio_roll_distance,
128 FlacDecoderConfig::GetRequiredAudioRollDistance(),
129 "audio_roll_distance");
130 }
131
WriteStreamInfo(const FlacMetaBlockStreamInfo & stream_info,WriteBitBuffer & wb)132 absl::Status WriteStreamInfo(const FlacMetaBlockStreamInfo& stream_info,
133 WriteBitBuffer& wb) {
134 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.minimum_block_size, 16));
135 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.maximum_block_size, 16));
136 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.minimum_frame_size, 24));
137 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.maximum_frame_size, 24));
138 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.sample_rate, 20));
139 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.number_of_channels, 3));
140 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(stream_info.bits_per_sample, 5));
141 RETURN_IF_NOT_OK(
142 wb.WriteUnsignedLiteral64(stream_info.total_samples_in_stream, 36));
143 RETURN_IF_NOT_OK(
144 wb.WriteUint8Span(absl::MakeConstSpan(stream_info.md5_signature)));
145 return absl::OkStatus();
146 }
147
PrintStreamInfo(const FlacMetaBlockStreamInfo & stream_info)148 void PrintStreamInfo(const FlacMetaBlockStreamInfo& stream_info) {
149 LOG(INFO) << " metadata_block(stream_info):";
150
151 LOG(INFO) << " minimum_block_size= " << stream_info.minimum_block_size;
152 LOG(INFO) << " maximum_block_size= " << stream_info.maximum_block_size;
153 LOG(INFO) << " minimum_frame_size= " << stream_info.minimum_frame_size;
154 LOG(INFO) << " maximum_frame_size= " << stream_info.maximum_frame_size;
155 LOG(INFO) << " sample_rate= " << stream_info.sample_rate;
156 LOG(INFO) << " number_of_channels= "
157 << absl::StrCat(stream_info.number_of_channels);
158 LOG(INFO) << " bits_per_sample= "
159 << absl::StrCat(stream_info.bits_per_sample);
160 LOG(INFO) << " total_samples_in_stream= "
161 << stream_info.total_samples_in_stream;
162 }
163
ReadStreamInfo(FlacMetaBlockStreamInfo & stream_info,ReadBitBuffer & rb)164 absl::Status ReadStreamInfo(FlacMetaBlockStreamInfo& stream_info,
165 ReadBitBuffer& rb) {
166 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(16, stream_info.minimum_block_size));
167 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(16, stream_info.maximum_block_size));
168 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(24, stream_info.minimum_frame_size));
169 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(24, stream_info.maximum_frame_size));
170 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(20, stream_info.sample_rate));
171 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(3, stream_info.number_of_channels));
172 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(5, stream_info.bits_per_sample));
173 RETURN_IF_NOT_OK(
174 rb.ReadUnsignedLiteral(36, stream_info.total_samples_in_stream));
175 return rb.ReadUint8Span(absl::MakeSpan(stream_info.md5_signature));
176 }
177
178 } // namespace
179
ValidateAndWrite(uint32_t num_samples_per_frame,int16_t audio_roll_distance,WriteBitBuffer & wb) const180 absl::Status FlacDecoderConfig::ValidateAndWrite(uint32_t num_samples_per_frame,
181 int16_t audio_roll_distance,
182 WriteBitBuffer& wb) const {
183 MAYBE_RETURN_IF_NOT_OK(ValidateAudioRollDistance(audio_roll_distance));
184
185 RETURN_IF_NOT_OK(ValidatePayload(num_samples_per_frame, *this));
186
187 for (const auto& metadata_block : metadata_blocks_) {
188 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(
189 metadata_block.header.last_metadata_block_flag, 1));
190 RETURN_IF_NOT_OK(
191 wb.WriteUnsignedLiteral(metadata_block.header.block_type, 7));
192 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(
193 metadata_block.header.metadata_data_block_length, 24));
194
195 int64_t expected_end =
196 wb.bit_offset() + metadata_block.header.metadata_data_block_length * 8;
197
198 switch (metadata_block.header.block_type) {
199 case FlacMetaBlockHeader::kFlacStreamInfo:
200 RETURN_IF_NOT_OK(WriteStreamInfo(
201 std::get<FlacMetaBlockStreamInfo>(metadata_block.payload), wb));
202 break;
203 default:
204 RETURN_IF_NOT_OK(wb.WriteUint8Span(absl::MakeConstSpan(
205 std::get<std::vector<uint8_t>>(metadata_block.payload))));
206 break;
207 }
208
209 if (expected_end != wb.bit_offset()) {
210 return absl::UnknownError(
211 absl::StrCat("`FlacDecoderConfig` was expected to be using ",
212 metadata_block.header.metadata_data_block_length,
213 " bytes, but it was not."));
214 }
215 }
216
217 return absl::OkStatus();
218 }
219
ReadAndValidate(uint32_t num_samples_per_frame,int16_t audio_roll_distance,ReadBitBuffer & rb)220 absl::Status FlacDecoderConfig::ReadAndValidate(uint32_t num_samples_per_frame,
221 int16_t audio_roll_distance,
222 ReadBitBuffer& rb) {
223 RETURN_IF_NOT_OK(ValidateAudioRollDistance(audio_roll_distance));
224
225 // We are not given a length field to indicate the number of metadata blocks
226 // to read. Instead, we must look at the `last_metadata_block_flag` to
227 // determine when to stop reading.
228 std::vector<FlacMetadataBlock> metadata_blocks;
229 bool is_last_metadata_block = false;
230 while (!is_last_metadata_block) {
231 FlacMetadataBlock metadata_block;
232 RETURN_IF_NOT_OK(
233 rb.ReadBoolean(metadata_block.header.last_metadata_block_flag));
234 is_last_metadata_block = metadata_block.header.last_metadata_block_flag;
235 uint8_t block_type;
236 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(7, block_type));
237 metadata_block.header.block_type =
238 static_cast<FlacMetaBlockHeader::FlacBlockType>(block_type);
239 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(
240 24, metadata_block.header.metadata_data_block_length));
241
242 switch (metadata_block.header.block_type) {
243 case FlacMetaBlockHeader::kFlacStreamInfo:
244 RETURN_IF_NOT_OK(ReadStreamInfo(
245 std::get<FlacMetaBlockStreamInfo>(metadata_block.payload), rb));
246 break;
247 default: {
248 std::vector<uint8_t> payload;
249 payload.resize(metadata_block.header.metadata_data_block_length);
250 RETURN_IF_NOT_OK(rb.ReadUint8Span(absl::MakeSpan(payload)));
251 metadata_block.payload = std::move(payload);
252 break;
253 }
254 }
255 metadata_blocks_.push_back(std::move(metadata_block));
256 }
257 RETURN_IF_NOT_OK(ValidatePayload(num_samples_per_frame, *this));
258 return absl::OkStatus();
259 }
260
GetOutputSampleRate(uint32_t & output_sample_rate) const261 absl::Status FlacDecoderConfig::GetOutputSampleRate(
262 uint32_t& output_sample_rate) const {
263 const FlacMetaBlockStreamInfo* stream_info;
264 RETURN_IF_NOT_OK(GetStreamInfo(*this, &stream_info));
265
266 output_sample_rate = stream_info->sample_rate;
267 return ValidateSampleRate(output_sample_rate);
268 }
269
GetBitDepthToMeasureLoudness(uint8_t & bit_depth_to_measure_loudness) const270 absl::Status FlacDecoderConfig::GetBitDepthToMeasureLoudness(
271 uint8_t& bit_depth_to_measure_loudness) const {
272 const FlacMetaBlockStreamInfo* stream_info;
273 RETURN_IF_NOT_OK(GetStreamInfo(*this, &stream_info));
274
275 // The raw bit-depth field for FLAC represents bit-depth - 1.
276 bit_depth_to_measure_loudness = stream_info->bits_per_sample + 1;
277 return ValidateBitsPerSample(stream_info->bits_per_sample);
278 }
279
GetTotalSamplesInStream(uint64_t & total_samples_in_stream) const280 absl::Status FlacDecoderConfig::GetTotalSamplesInStream(
281 uint64_t& total_samples_in_stream) const {
282 const FlacMetaBlockStreamInfo* stream_info;
283 RETURN_IF_NOT_OK(GetStreamInfo(*this, &stream_info));
284
285 total_samples_in_stream = stream_info->total_samples_in_stream;
286 return ValidateTotalSamplesInStream(stream_info->total_samples_in_stream);
287 }
288
Print() const289 void FlacDecoderConfig::Print() const {
290 LOG(INFO) << " decoder_config(flac):";
291
292 for (const auto& metadata_block : metadata_blocks_) {
293 LOG(INFO) << " header:";
294 LOG(INFO) << " last_metadata_block_flag= "
295 << metadata_block.header.last_metadata_block_flag;
296 LOG(INFO) << " block_type= "
297 << absl::StrCat(metadata_block.header.block_type);
298 LOG(INFO) << " metadata_data_block_length= "
299 << metadata_block.header.metadata_data_block_length;
300 switch (metadata_block.header.block_type) {
301 case FlacMetaBlockHeader::kFlacStreamInfo:
302 PrintStreamInfo(
303 std::get<FlacMetaBlockStreamInfo>(metadata_block.payload));
304 break;
305 default: {
306 const auto& generic_block =
307 std::get<std::vector<uint8_t>>(metadata_block.payload);
308 LOG(INFO) << " metadata_block(generic_block):";
309 LOG(INFO) << " size= " << generic_block.size();
310 LOG(INFO) << " payload omitted.";
311 }
312 }
313 }
314 }
315
316 } // namespace iamf_tools
317