| /* |
| * Copyright (c) 2023, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 3-Clause Clear License |
| * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
| * License was not distributed with this source code in the LICENSE file, you |
| * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the |
| * Alliance for Open Media Patent License 1.0 was not distributed with this |
| * source code in the PATENTS file, you can obtain it at |
| * www.aomedia.org/license/patent. |
| */ |
| |
| #ifndef CLI_WAV_WRITER_H_ |
| #define CLI_WAV_WRITER_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdio> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/status/status.h" |
| #include "absl/types/span.h" |
| #include "iamf/cli/sample_processor_base.h" |
| |
| namespace iamf_tools { |
| |
| /*!\brief Write samples to a wav (or pcm) file, then consumes the samples. */ |
| class WavWriter : public SampleProcessorBase { |
| public: |
| /*!\brief Factory function to create a `WavWriter`. |
| * |
| * Creates a `WavWriter` that can be used to write a wav file without knowing |
| * the number of samples in advance. |
| * |
| * \param wav_filename Path of the file to write to. |
| * \param num_channels Number of channels in the wav file. |
| * \param sample_rate_hz Sample rate of the wav file in Hz. |
| * \param bit_depth Bit-depth of the wav file, must be 16, 24, or 32. |
| * \param num_samples_per_frame Number of samples per frame. Subsequent writes |
| * must use at most this number of samples. |
| * \param write_header If true, the wav header is written. |
| * \return Unique pointer to `WavWriter` on success. `nullptr` otherwise. |
| */ |
| static std::unique_ptr<WavWriter> Create(const std::string& wav_filename, |
| int num_channels, int sample_rate_hz, |
| int bit_depth, |
| size_t num_samples_per_frame, |
| bool write_header = true); |
| |
| /*!\brief Finalizes the wav header and closes the underlying file.*/ |
| ~WavWriter(); |
| |
| /*!\brief Returns the bit-depth.*/ |
| int bit_depth() const { return bit_depth_; } |
| |
| /*!\brief Writes samples to the wav file. |
| * |
| * There must be an integer number of samples and the number of samples % |
| * `num_channels()` must equal 0. The number of samples is implicitly |
| * calculated by `buffer.size()` / (bit_depth / 8). |
| * |
| * \param buffer Buffer of raw input PCM with channels interlaced and no |
| * padding. |
| * \return `absl::OkStatus()` on success. A specific status on failure. |
| */ |
| [[deprecated("Use `SampleProcessorBase::PushFrame` instead.")]] |
| absl::Status WritePcmSamples(const std::vector<uint8_t>& buffer); |
| |
| /*!\brief Aborts the write process and deletes the wav file.*/ |
| void Abort(); |
| |
| private: |
| typedef absl::AnyInvocable<int(FILE*, size_t, int, int)> WavHeaderWriter; |
| |
| /*!\brief Private Constructor. Used only by the factory function. |
| * |
| * \param filename_to_remove Path of the file; used to clean up the output |
| * file when aborting. |
| * \param num_channels Number of channels in the wav file, must be 1 or 2. |
| * \param sample_rate_hz Sample rate of the wav file in Hz. |
| * \param num_samples_per_frame Number of samples per frame. Subsequent |
| * writes must use at most this number of samples. |
| * \param bit_depth Bit-depth of the wav file, must be 16, 24, or 32. |
| * \param file Pointer to the file to write to. |
| * \param wav_header_writer Function that writes the header if non-empty. |
| */ |
| WavWriter(const std::string& filename_to_remove, int num_channels, |
| int sample_rate_hz, int bit_depth, size_t num_samples_per_frame, |
| FILE* file, WavHeaderWriter wav_header_writer); |
| |
| /*!\brief Writes samples to the wav file and consumes them. |
| * |
| * Since the samples are consumed, the |
| * `SampleProcessorBase::GetOutputSamplesAsSpan` method will always return an |
| * empty span. |
| * |
| * There must be the same number of samples for each channel. |
| * |
| * \param time_channel_samples Samples to push arranged in (time, channel). |
| * \return `absl::OkStatus()` on success. A specific status on failure. |
| */ |
| absl::Status PushFrameDerived( |
| absl::Span<const std::vector<int32_t>> time_channel_samples) override; |
| |
| /*!\brief Signals that no more samples will be pushed. |
| * |
| * After calling `Flush()`, it is invalid to call `PushFrame()` |
| * or `Flush()` again. |
| * |
| * \return `absl::OkStatus()` on success. A specific status on failure. |
| */ |
| absl::Status FlushDerived() override; |
| |
| const size_t sample_rate_hz_; |
| const size_t bit_depth_; |
| size_t total_samples_written_; |
| FILE* file_; |
| const std::string filename_to_remove_; |
| WavHeaderWriter wav_header_writer_; |
| }; |
| } // namespace iamf_tools |
| |
| #endif // CLI_WAV_WRITER_H_ |