• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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