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 13 #ifndef CLI_ENCODER_BASE_H_ 14 #define CLI_ENCODER_BASE_H_ 15 16 #include <cstdint> 17 #include <list> 18 #include <memory> 19 #include <vector> 20 21 #include "absl/base/thread_annotations.h" 22 #include "absl/status/status.h" 23 #include "absl/synchronization/mutex.h" 24 #include "iamf/cli/audio_frame_with_data.h" 25 #include "iamf/obu/codec_config.h" 26 27 namespace iamf_tools { 28 29 class EncoderBase { 30 public: 31 /*!\brief Constructor. 32 * 33 * After constructing `Initialize()` MUST be called and return successfully 34 * before using most functionality of the encoder. 35 * 36 * - Call `EncodeAudioFrame()` to encode an audio frame. The encoding may 37 * happen asynchronously. 38 * - Call `FramesAvailable()` to see if there is any finished frame. 39 * - Call `Pop()` to retrieve finished frames one at a time, in the order 40 * they were received by `EncodeAudioFrame()`. 41 * - Call `Finalize()` to close the encoder, telling it to finish encoding 42 * any remaining frames, which can be retrieved via subsequent `Pop()`s. 43 * After calling `Finalize()`, any subsequent call to `EncodeAudioFrame()` 44 * will fail. 45 * 46 * \param codec_config Codec Config OBU for the encoder. 47 * \num_channels Number of channels for the encoder. 48 */ EncoderBase(const CodecConfigObu & codec_config,int num_channels)49 EncoderBase(const CodecConfigObu& codec_config, int num_channels) 50 : num_samples_per_frame_(codec_config.GetNumSamplesPerFrame()), 51 input_sample_rate_(codec_config.GetInputSampleRate()), 52 output_sample_rate_(codec_config.GetOutputSampleRate()), 53 input_pcm_bit_depth_(codec_config.GetBitDepthToMeasureLoudness()), 54 num_channels_(num_channels) {} 55 56 /*!\brief Destructor. */ 57 virtual ~EncoderBase() = 0; 58 59 /*!\brief Initializes `EncoderBase`. 60 * 61 * \param validate_codec_delay If true, validates the Codec Config OBU fields 62 * related to codec delay agree with the encoder. 63 * \return `absl::OkStatus()` on success. A specific status on failure. 64 */ 65 absl::Status Initialize(bool validate_codec_delay); 66 67 /*!\brief Encodes an audio frame. 68 * 69 * \param input_bit_depth Bit-depth of the input data. 70 * \param samples Samples arranged in (time x channel) axes. The samples are 71 * left-justified and stored in the upper `input_bit_depth` bits. 72 * \param partial_audio_frame_with_data Unique pointer to take ownership of. 73 * The underlying `audio_frame_` is modified. All other fields are 74 * blindly passed along. 75 * \return `absl::OkStatus()` on success. Success does not necessarily mean 76 * the frame was finished. A specific status on failure. 77 */ 78 virtual absl::Status EncodeAudioFrame( 79 int input_bit_depth, const std::vector<std::vector<int32_t>>& samples, 80 std::unique_ptr<AudioFrameWithData> partial_audio_frame_with_data) = 0; 81 82 /*!\brief Gets whether there are frames available. 83 * 84 * Available frames can be retrieved by `Pop()`. 85 * 86 * \return True if there is any finished audio frame. 87 */ FramesAvailable()88 bool FramesAvailable() const { 89 absl::MutexLock lock(&mutex_); 90 return !finalized_audio_frames_.empty(); 91 } 92 93 /*!\brief Pop the first finished audio frame (if any). 94 * 95 * \param audio_frames List to append the first finished frame to. 96 * \return `absl::OkStatus()` on success. A specific status on failure. 97 */ Pop(std::list<AudioFrameWithData> & audio_frames)98 absl::Status Pop(std::list<AudioFrameWithData>& audio_frames) { 99 absl::MutexLock lock(&mutex_); 100 if (!finalized_audio_frames_.empty()) { 101 audio_frames.splice(audio_frames.end(), finalized_audio_frames_, 102 finalized_audio_frames_.begin()); 103 } 104 return absl::OkStatus(); 105 } 106 107 /*!\brief Finalizes the encoder, signaling it to finish any remaining frames. 108 * 109 * This function MUST be called at most once before popping the last batch 110 * of encoded audio frames. 111 * 112 * \return `absl::OkStatus()` on success. A specific status on failure. 113 */ Finalize()114 virtual absl::Status Finalize() { 115 absl::MutexLock lock(&mutex_); 116 finished_ = true; 117 return absl::OkStatus(); 118 } 119 120 /*!\brief Gets whether the encoder has been closed. 121 * 122 * \return True if the encoder has been closed. 123 */ Finished()124 bool Finished() const { 125 absl::MutexLock lock(&mutex_); 126 return finished_ && finalized_audio_frames_.empty(); 127 } 128 129 /*!\brief Gets the required number of samples to delay at the start. 130 * 131 * Sometimes this is called "pre-skip". This represents the number of initial 132 * "junk" samples output from the encoder. In IAMF this represents the 133 * recommended amount of samples to trim at the start of a substream. 134 * 135 * \return Number of samples to delay at the start of the substream. 136 */ GetNumberOfSamplesToDelayAtStart()137 uint32_t GetNumberOfSamplesToDelayAtStart() const { 138 return required_samples_to_delay_at_start_; 139 } 140 141 const uint32_t num_samples_per_frame_; 142 const uint32_t input_sample_rate_; 143 const uint32_t output_sample_rate_; 144 const uint8_t input_pcm_bit_depth_; 145 const int num_channels_; 146 147 protected: 148 /*!\brief Initializes the child class. 149 * 150 * \return `absl::OkStatus()` on success. A specific status on failure. 151 */ 152 virtual absl::Status InitializeEncoder() = 0; 153 154 /*!\brief Initializes `required_samples_to_delay_at_start_`. 155 * 156 * \param validate_codec_delay If true, validates the Codec Config OBU fields 157 * related to codec delay agree with the encoder. 158 * \return `absl::OkStatus()` on success. A specific status on failure. 159 */ SetNumberOfSamplesToDelayAtStart(bool)160 virtual absl::Status SetNumberOfSamplesToDelayAtStart( 161 bool /*validate_codec_delay*/) { 162 required_samples_to_delay_at_start_ = 0; 163 return absl::OkStatus(); 164 } 165 166 /*!\brief Validates `Finalize()` has not yet been called. 167 * 168 * \return `absl::OkStatus()` on success. A specific status on failure. 169 */ ValidateNotFinalized()170 absl::Status ValidateNotFinalized() { 171 if (Finished()) { 172 return absl::InvalidArgumentError( 173 "Encoding is disallowed after `Finalize()` has been called"); 174 } 175 return absl::OkStatus(); 176 } 177 178 /*!\brief Validates `samples` has the correct number of ticks and channels. 179 * 180 * \return `absl::OkStatus()` on success. A specific status on failure. 181 */ 182 absl::Status ValidateInputSamples( 183 const std::vector<std::vector<int32_t>>& samples) const; 184 185 uint32_t required_samples_to_delay_at_start_ = 0; 186 187 // Mutex to guard simultaneous access to data members. 188 mutable absl::Mutex mutex_; 189 190 std::list<AudioFrameWithData> finalized_audio_frames_ 191 ABSL_GUARDED_BY(mutex_) = {}; 192 193 // Whether the encoding has been closed. 194 bool finished_ ABSL_GUARDED_BY(mutex_) = false; 195 }; 196 197 } // namespace iamf_tools 198 199 #endif // CLI_ENCODER_BASE_H_ 200