• 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 #ifndef CLI_FLAC_ENCODER_DECODER_H_
13 #define CLI_FLAC_ENCODER_DECODER_H_
14 
15 #include <cstddef>
16 #include <cstdint>
17 #include <memory>
18 #include <vector>
19 
20 #include "absl/base/thread_annotations.h"
21 #include "absl/container/btree_map.h"
22 #include "absl/status/status.h"
23 #include "iamf/cli/audio_frame_with_data.h"
24 #include "iamf/cli/codec/encoder_base.h"
25 #include "iamf/cli/proto/codec_config.pb.h"
26 #include "iamf/obu/codec_config.h"
27 #include "iamf/obu/decoder_config/flac_decoder_config.h"
28 #include "include/FLAC/format.h"
29 #include "include/FLAC/ordinals.h"
30 #include "include/FLAC/stream_encoder.h"
31 
32 namespace iamf_tools {
33 
34 struct FlacFrame {
35   // Partial audio frame with data associated with this FLAC frame. Its
36   // `audio_frame_` is built up in the call(s) to `LibFlacWriteCallback`.
37   std::unique_ptr<AudioFrameWithData> audio_frame_with_data;
38 
39   // Number of samples represented by raw data.
40   unsigned int num_samples = 0;
41 };
42 
43 /*!\brief Encodes FLAC frames `FlacEncoder` using `libflac`.
44  *
45  * The `libflac` encoder works asynchronously. `EncodeAudioFrame()` passes data
46  * to `libflac` to start encoding a frame. `libflac` calls the callback
47  * functions (i.e. `LibFlacWriteCallback` and `LibFlacMetadataCallback`) as the
48  * data is processed. The callback functions track the state of the frames in
49  * various member variables of this class.
50  *
51  * Data associated with the frames are stored in `frame_index_to_frame_`
52  * until they are fully encoded. Any finished frame will be moved to
53  * `EncoderBase::finalized_audio_frames_` and can be moved into the output
54  * list provided to `Pop()`.
55  *
56  * `Finalize()` function closes the encoder. When the `STREAMINFO` metadata
57  * block is produced, the last batch of Audio Frame OBUs are encoded and
58  * available to be popped.
59  */
60 class FlacEncoder : public EncoderBase {
61  public:
FlacEncoder(const iamf_tools_cli_proto::FlacEncoderMetadata & flac_encoder_metadata,const CodecConfigObu & codec_config,int num_channels)62   FlacEncoder(
63       const iamf_tools_cli_proto::FlacEncoderMetadata& flac_encoder_metadata,
64       const CodecConfigObu& codec_config, int num_channels)
65       : EncoderBase(codec_config, num_channels),
66         encoder_metadata_(flac_encoder_metadata),
67         decoder_config_(std::get<FlacDecoderConfig>(
68             codec_config.GetCodecConfig().decoder_config)) {}
69 
70   ~FlacEncoder() override;
71 
72   /*!\brief Encodes an audio frame.
73    *
74    * \param input_bit_depth Bit-depth of the input data.
75    * \param samples Samples arranged in (time x channel) axes. The samples are
76    *        left-justified and stored in the upper `input_bit_depth` bits.
77    * \param partial_audio_frame_with_data Unique pointer to take ownership of.
78    *        The underlying `audio_frame_` is modified. All other fields are
79    *        blindly passed along.
80    * \return `absl::OkStatus()` on success. Success does not necessarily mean
81    *         the frame was finished. A specific status on failure.
82    */
83   absl::Status EncodeAudioFrame(
84       int input_bit_depth, const std::vector<std::vector<int32_t>>& samples,
85       std::unique_ptr<AudioFrameWithData> partial_audio_frame_with_data)
86       override;
87 
88   /*!\brief Finalizes the encoder.
89    *
90    * This function MUST be called to ensure all audio frames are popped from
91    * the encoder.
92    *
93    * \return `absl::OkStatus()` on success. A specific status on failure.
94    */
95   absl::Status Finalize() override;
96 
97  private:
98   // `libflac` uses callbacks to signal the frames are done. Let the callback
99   // functions be friends so they can update state information in
100   // `next_frame_index_`, frame_index_to_frame_`, and `finished_`.
101   friend FLAC__StreamEncoderWriteStatus LibFlacWriteCallback(
102       const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[],
103       size_t bytes, unsigned int samples, unsigned int current_frame,
104       void* client_data);
105   friend void LibFlacMetadataCallback(const FLAC__StreamEncoder* encoder,
106                                       const FLAC__StreamMetadata* metadata,
107                                       void* client_data);
108 
109   /*!\brief Initializes the underlying encoder.
110    *
111    * \return `absl::OkStatus()` on success. A specific status on failure.
112    */
113   absl::Status InitializeEncoder() override;
114 
115   const iamf_tools_cli_proto::FlacEncoderMetadata encoder_metadata_;
116   const FlacDecoderConfig decoder_config_;
117 
118   // A pointer to the `libflac` encoder.
119   FLAC__StreamEncoder* encoder_ = nullptr;
120 
121   // Tracks the next frame index to use. This data is associated with the
122   // `current_frame` argument to `flac_write_callback`.
123   unsigned int next_frame_index_ = 0;
124 
125   // The buffer of any unfinished frames, keyed and sorted by the frame
126   // index.
127   absl::btree_map<unsigned int, FlacFrame> frame_index_to_frame_
128       ABSL_GUARDED_BY(mutex_) = {};
129 };
130 
131 }  // namespace iamf_tools
132 
133 #endif  // CLI_FLAC_ENCODER_DECODER_H_
134