blob: 54af84af413bfa2b6fc7d8e77657c4ea7b9a44a7 [file] [log] [blame]
/*
* 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_