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