• 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/cli/codec/flac_encoder.h"
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <cstring>
17 #include <list>
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/functional/any_invocable.h"
23 #include "absl/log/log.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/synchronization/mutex.h"
27 #include "absl/types/span.h"
28 #include "iamf/cli/audio_frame_with_data.h"
29 #include "iamf/cli/proto/codec_config.pb.h"
30 #include "iamf/common/utils/macros.h"
31 #include "iamf/common/utils/sample_processing_utils.h"
32 #include "iamf/obu/decoder_config/flac_decoder_config.h"
33 #include "include/FLAC/format.h"
34 #include "include/FLAC/ordinals.h"
35 #include "include/FLAC/stream_encoder.h"
36 
37 namespace iamf_tools {
38 
39 namespace {
40 
Configure(const iamf_tools_cli_proto::FlacEncoderMetadata & encoder_metadata,const FlacDecoderConfig & decoder_config,int num_channels,uint32_t num_samples_per_frame,uint32_t output_sample_rate,uint8_t input_pcm_bit_depth_,FLAC__StreamEncoder * const encoder)41 absl::Status Configure(
42     const iamf_tools_cli_proto::FlacEncoderMetadata& encoder_metadata,
43     const FlacDecoderConfig& decoder_config, int num_channels,
44     uint32_t num_samples_per_frame, uint32_t output_sample_rate,
45     uint8_t input_pcm_bit_depth_, FLAC__StreamEncoder* const encoder) {
46   FLAC__bool ok = true;
47   // Configure values based on the associated Codec Config OBU.
48 
49   ok &= FLAC__stream_encoder_set_channels(encoder, num_channels);
50 
51   ok &= FLAC__stream_encoder_set_bits_per_sample(
52       encoder, static_cast<uint32_t>(input_pcm_bit_depth_));
53 
54   ok &= FLAC__stream_encoder_set_sample_rate(encoder, output_sample_rate);
55 
56   // IAMF requires a constant block size.
57   ok &= FLAC__stream_encoder_set_blocksize(encoder, num_samples_per_frame);
58 
59   uint64_t total_samples_in_stream;
60   RETURN_IF_NOT_OK(
61       decoder_config.GetTotalSamplesInStream(total_samples_in_stream));
62 
63   ok &= FLAC__stream_encoder_set_total_samples_estimate(
64       encoder, total_samples_in_stream);
65 
66   // Set arguments configured by the user-provided `encoder_metadata_`.
67   ok &= FLAC__stream_encoder_set_compression_level(
68       encoder, encoder_metadata.compression_level());
69 
70   ok &= FLAC__stream_encoder_set_verify(encoder, true);
71 
72   if (!ok) {
73     return absl::UnknownError("Failed to configure Flac encoder.");
74   }
75 
76   return absl::OkStatus();
77 }
78 }  // namespace
79 
LibFlacWriteCallback(const FLAC__StreamEncoder *,const FLAC__byte buffer[],size_t bytes,unsigned int samples,unsigned int current_frame,void * client_data)80 FLAC__StreamEncoderWriteStatus LibFlacWriteCallback(
81     const FLAC__StreamEncoder* /*encoder*/, const FLAC__byte buffer[],
82     size_t bytes, unsigned int samples, unsigned int current_frame,
83     void* client_data) {
84   const unsigned int kLibFlacMetadataSentinel = 0;
85   if (samples == kLibFlacMetadataSentinel) {
86     // `libflac` uses a value of `0` to indicate this callback is for metadata.
87     LOG(INFO) << "`iamf_tools` currently ignores all additional FLAC metadata.";
88     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
89   }
90 
91   auto flac_encoder = static_cast<FlacEncoder*>(client_data);
92 
93   absl::MutexLock lock(&flac_encoder->mutex_);
94 
95   auto flac_frame_iter =
96       flac_encoder->frame_index_to_frame_.find(current_frame);
97   if (flac_frame_iter == flac_encoder->frame_index_to_frame_.end()) {
98     LOG(ERROR) << "Failed to find a frame with index " << current_frame
99                << " in Flac encoder. Data may be lost or corrupted.";
100     return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
101   }
102 
103   // Append to `audio_frame_` and track how many samples it represents. It will
104   // be finalized later to ensure frames are finalized in chronological order.
105   FlacFrame& flac_frame = flac_frame_iter->second;
106   flac_frame.audio_frame_with_data->obu.audio_frame_.insert(
107       flac_frame.audio_frame_with_data->obu.audio_frame_.end(), buffer,
108       buffer + bytes);
109   flac_frame.num_samples += samples;
110 
111   if (flac_frame.num_samples == flac_encoder->num_samples_per_frame_) {
112     // A frame has been completed; move to the finalized frames.
113     flac_encoder->finalized_audio_frames_.emplace_back(
114         std::move(*flac_frame_iter->second.audio_frame_with_data));
115 
116     // The frame is fully processed and no longer needed.
117     flac_encoder->frame_index_to_frame_.erase(flac_frame_iter);
118   }
119 
120   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
121 }
122 
LibFlacMetadataCallback(const FLAC__StreamEncoder *,const FLAC__StreamMetadata * metadata,void * client_data)123 void LibFlacMetadataCallback(const FLAC__StreamEncoder* /*encoder*/,
124                              const FLAC__StreamMetadata* metadata,
125                              void* client_data) {
126   LOG_FIRST_N(INFO, 1) << "Begin `LibFlacMetadataCallback`.";
127 
128   if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
129     LOG(INFO) << "Received `STREAMINFO` metadata.";
130     // Just validate we got the `STREAMINFO` metadata at some point. IAMF
131     // requires some fields to be set constant and different from what will be
132     // returned by `libflac`.
133     auto flac_encoder = static_cast<FlacEncoder*>(client_data);
134 
135     absl::MutexLock lock(&flac_encoder->mutex_);
136     flac_encoder->finished_ = true;
137   }
138 }
139 
~FlacEncoder()140 FlacEncoder::~FlacEncoder() {
141   FLAC__stream_encoder_delete(encoder_);
142 
143   absl::MutexLock lock(&mutex_);
144   if (!frame_index_to_frame_.empty()) {
145     LOG(ERROR) << "Some frames were not fully processed. Maybe `Finalize()` "
146                   "was not called.";
147   }
148 }
149 
EncodeAudioFrame(int input_bit_depth,const std::vector<std::vector<int32_t>> & samples,std::unique_ptr<AudioFrameWithData> partial_audio_frame_with_data)150 absl::Status FlacEncoder::EncodeAudioFrame(
151     int input_bit_depth, const std::vector<std::vector<int32_t>>& samples,
152     std::unique_ptr<AudioFrameWithData> partial_audio_frame_with_data) {
153   RETURN_IF_NOT_OK(ValidateNotFinalized());
154   RETURN_IF_NOT_OK(ValidateInputSamples(samples));
155   const int num_samples_per_channel = static_cast<int>(num_samples_per_frame_);
156 
157   LOG_FIRST_N(INFO, 1) << "num_samples_per_channel: "
158                        << num_samples_per_channel;
159   LOG_FIRST_N(INFO, 1) << "num_channels: " << num_channels_;
160 
161   // FLAC requires a right-justified sign extended value. Calculate what the
162   // mask is to sign extend a `input_bit_depth`-bit value.
163   uint32_t base_sign_extension_mask = 0;
164   for (int i = 31; i > input_bit_depth - 1; --i) {
165     base_sign_extension_mask |= 1 << i;
166   }
167 
168   const absl::AnyInvocable<absl::Status(int32_t, int32_t&) const>
169       kLeftJustifiedToRightJustified =
170           [base_sign_extension_mask, input_bit_depth](int32_t input,
171                                                       int32_t& output) {
172             // Only apply the sign extension mask when the left-justified value
173             // has '1' in the MSB.
174             const uint32_t sign_extension_mask =
175                 (input & 0x80000000) ? base_sign_extension_mask : 0;
176             // Shift the input value to be right-justified.
177             output = static_cast<uint32_t>(input) >> (32 - input_bit_depth) |
178                      sign_extension_mask;
179             return absl::OkStatus();
180           };
181 
182   // Convert input to the array that will be passed to `flac_encode`.
183   std::vector<FLAC__int32> encoder_input_pcm;
184   RETURN_IF_NOT_OK(ConvertTimeChannelToInterleaved(
185       absl::MakeConstSpan(samples), kLeftJustifiedToRightJustified,
186       encoder_input_pcm));
187 
188   LOG_FIRST_N(INFO, 1) << "Encoding " << encoder_input_pcm.size() * 4
189                        << " bytes representing " << num_samples_per_channel
190                        << " x " << num_channels_ << " samples.";
191 
192   if (!FLAC__stream_encoder_process_interleaved(
193           encoder_, encoder_input_pcm.data(), num_samples_per_channel)) {
194     return absl::UnknownError("Flac failed to encode.");
195   }
196 
197   absl::MutexLock lock(&mutex_);
198 
199   // Transfer ownership of the partial audio frame so it can be finalized later.
200   frame_index_to_frame_[next_frame_index_++].audio_frame_with_data =
201       std::move(partial_audio_frame_with_data);
202   return absl::OkStatus();
203 }
204 
Finalize()205 absl::Status FlacEncoder::Finalize() {
206   // Signal to `libflac` the encoder is finished.
207   if (!FLAC__stream_encoder_finish(encoder_)) {
208     return absl::UnknownError("Failed to finalize Flac encoder.");
209   }
210 
211   return absl::OkStatus();
212 }
213 
InitializeEncoder()214 absl::Status FlacEncoder::InitializeEncoder() {
215   // Initialize the encoder.
216   encoder_ = FLAC__stream_encoder_new();
217   if (encoder_ == nullptr) {
218     return absl::UnknownError("Failed to initialize Flac encoder.");
219   }
220 
221   // Configure the FLAC encoder based on user input data.
222   RETURN_IF_NOT_OK(Configure(encoder_metadata_, decoder_config_, num_channels_,
223                              num_samples_per_frame_, output_sample_rate_,
224                              input_pcm_bit_depth_, encoder_));
225 
226   // Initialize the FLAC encoder.
227   FLAC__StreamEncoderInitStatus init_status = FLAC__stream_encoder_init_stream(
228       encoder_, LibFlacWriteCallback, /*seek_callback=*/nullptr,
229       /*tell_callback=*/nullptr, LibFlacMetadataCallback,
230       static_cast<void*>(this));
231 
232   if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
233     return absl::UnknownError(
234         absl::StrCat("Failed to initialize Flac stream: ", init_status));
235   }
236 
237   return absl::OkStatus();
238 }
239 
240 }  // namespace iamf_tools
241