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_WAV_WRITER_H_ 14 #define CLI_WAV_WRITER_H_ 15 16 #include <cstddef> 17 #include <cstdint> 18 #include <cstdio> 19 #include <memory> 20 #include <string> 21 #include <vector> 22 23 #include "absl/functional/any_invocable.h" 24 #include "absl/status/status.h" 25 #include "absl/types/span.h" 26 #include "iamf/cli/sample_processor_base.h" 27 28 namespace iamf_tools { 29 30 /*!\brief Write samples to a wav (or pcm) file, then consumes the samples. */ 31 class WavWriter : public SampleProcessorBase { 32 public: 33 /*!\brief Factory function to create a `WavWriter`. 34 * 35 * Creates a `WavWriter` that can be used to write a wav file without knowing 36 * the number of samples in advance. 37 * 38 * \param wav_filename Path of the file to write to. 39 * \param num_channels Number of channels in the wav file. 40 * \param sample_rate_hz Sample rate of the wav file in Hz. 41 * \param bit_depth Bit-depth of the wav file, must be 16, 24, or 32. 42 * \param num_samples_per_frame Number of samples per frame. Subsequent writes 43 * must use at most this number of samples. 44 * \param write_header If true, the wav header is written. 45 * \return Unique pointer to `WavWriter` on success. `nullptr` otherwise. 46 */ 47 static std::unique_ptr<WavWriter> Create(const std::string& wav_filename, 48 int num_channels, int sample_rate_hz, 49 int bit_depth, 50 size_t num_samples_per_frame, 51 bool write_header = true); 52 53 /*!\brief Finalizes the wav header and closes the underlying file.*/ 54 ~WavWriter(); 55 56 /*!\brief Returns the bit-depth.*/ bit_depth()57 int bit_depth() const { return bit_depth_; } 58 59 /*!\brief Writes samples to the wav file. 60 * 61 * There must be an integer number of samples and the number of samples % 62 * `num_channels()` must equal 0. The number of samples is implicitly 63 * calculated by `buffer.size()` / (bit_depth / 8). 64 * 65 * \param buffer Buffer of raw input PCM with channels interlaced and no 66 * padding. 67 * \return `absl::OkStatus()` on success. A specific status on failure. 68 */ 69 [[deprecated("Use `SampleProcessorBase::PushFrame` instead.")]] 70 absl::Status WritePcmSamples(const std::vector<uint8_t>& buffer); 71 72 /*!\brief Aborts the write process and deletes the wav file.*/ 73 void Abort(); 74 75 private: 76 typedef absl::AnyInvocable<int(FILE*, size_t, int, int)> WavHeaderWriter; 77 78 /*!\brief Private Constructor. Used only by the factory function. 79 * 80 * \param filename_to_remove Path of the file; used to clean up the output 81 * file when aborting. 82 * \param num_channels Number of channels in the wav file, must be 1 or 2. 83 * \param sample_rate_hz Sample rate of the wav file in Hz. 84 * \param num_samples_per_frame Number of samples per frame. Subsequent 85 * writes must use at most this number of samples. 86 * \param bit_depth Bit-depth of the wav file, must be 16, 24, or 32. 87 * \param file Pointer to the file to write to. 88 * \param wav_header_writer Function that writes the header if non-empty. 89 */ 90 WavWriter(const std::string& filename_to_remove, int num_channels, 91 int sample_rate_hz, int bit_depth, size_t num_samples_per_frame, 92 FILE* file, WavHeaderWriter wav_header_writer); 93 94 /*!\brief Writes samples to the wav file and consumes them. 95 * 96 * Since the samples are consumed, the 97 * `SampleProcessorBase::GetOutputSamplesAsSpan` method will always return an 98 * empty span. 99 * 100 * There must be the same number of samples for each channel. 101 * 102 * \param time_channel_samples Samples to push arranged in (time, channel). 103 * \return `absl::OkStatus()` on success. A specific status on failure. 104 */ 105 absl::Status PushFrameDerived( 106 absl::Span<const std::vector<int32_t>> time_channel_samples) override; 107 108 /*!\brief Signals that no more samples will be pushed. 109 * 110 * After calling `Flush()`, it is invalid to call `PushFrame()` 111 * or `Flush()` again. 112 * 113 * \return `absl::OkStatus()` on success. A specific status on failure. 114 */ 115 absl::Status FlushDerived() override; 116 117 const size_t sample_rate_hz_; 118 const size_t bit_depth_; 119 size_t total_samples_written_; 120 FILE* file_; 121 const std::string filename_to_remove_; 122 WavHeaderWriter wav_header_writer_; 123 }; 124 } // namespace iamf_tools 125 126 #endif // CLI_WAV_WRITER_H_ 127