flac_bound/encoder/
encoder.rs

1#[cfg(feature = "flac")]
2use flac_sys::{FLAC__stream_encoder_new, FLAC__stream_encoder_get_state, FLAC__stream_encoder_get_verify_decoder_state, FLAC__stream_encoder_finish,
3               FLAC__stream_encoder_process, FLAC__stream_encoder_process_interleaved};
4
5#[cfg(feature = "libflac-nobuild")]
6use libflac_sys::{FLAC__stream_encoder_new, FLAC__stream_encoder_get_state, FLAC__stream_encoder_get_verify_decoder_state, FLAC__stream_encoder_finish,
7    FLAC__stream_encoder_process, FLAC__stream_encoder_process_interleaved};
8
9use super::{StreamEncoderContainer, FlacEncoderConfig, FlacEncoderState};
10use std::marker::PhantomData;
11use std::convert::TryFrom;
12use std::os::raw::c_uint;
13use std::{mem, ptr};
14
15
16/// The [stream encoder](https://xiph.org/flac/api/group__flac__stream__encoder.html) can encode to native FLAC,
17/// and optionally Ogg FLAC (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
18///
19/// The basic usage of this encoder is as follows:
20///   * The program creates an instance of an encoder using
21///     [`FlacEncoder::new()`](#method.new).
22///   * The program overrides the default settings using functions in
23///     [`FlacEncoderConfig`](struct.FlacEncoderConfig.html). At a minimum, the following
24///     functions should be called:
25///       * [`FlacEncoderConfig::channels()`](struct.FlacEncoderConfig.html#method.channels)
26///       * [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample)
27///       * [`FlacEncoderConfig::sample_rate()`](struct.FlacEncoderConfig.html#method.sample_rate)
28///       * [`FlacEncoderConfig::ogg_serial_number()`](struct.FlacEncoderConfig.html#method.ogg_serial_number)
29///         (if encoding to Ogg FLAC)
30///       * [`FlacEncoderConfig::total_samples_estimate()`](struct.FlacEncoderConfig.html#method.total_samples_estimate)
31///         (if known)
32///   * If the application wants to control the compression level or set its own
33///     metadata, then the following should also be called:
34///     * [`FlacEncoderConfig::compression_level()`](struct.FlacEncoderConfig.html#method.compression_level)
35///     * [`FlacEncoderConfig::verify()`](struct.FlacEncoderConfig.html#method.verify)
36///     * [`FlacEncoderConfig::metadata()`](struct.FlacEncoderConfig.html#method.metadata)
37///   * The rest of the set functions should only be called if the client needs
38///     exact control over how the audio is compressed; thorough understanding
39///     of the FLAC format is necessary to achieve good results.
40///   * The program initializes the instance to validate the settings and
41///     prepare for encoding using
42///       * [`FlacEncoderConfig::init_write()`](struct.FlacEncoderConfig.html#method.init_write), or
43///         [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file), or
44///         [`FlacEncoderConfig::init_stdout()`](struct.FlacEncoderConfig.html#method.init_stdout) for native FLAC
45///       * [`FlacEncoderConfig::init_write_ogg()`](struct.FlacEncoderConfig.html#method.init_write_ogg), or
46///         [`FlacEncoderConfig::init_file_ogg()`](struct.FlacEncoderConfig.html#method.init_file_ogg), or
47///         [`FlacEncoderConfig::init_stdout_ogg()`](struct.FlacEncoderConfig.html#method.init_stdout_ogg) for Ogg FLAC
48///   * The program calls [`FlacEncoder::process()`](#method.process) or
49///     [`FlacEncoder::process_interleaved()`](#method.process_interleaved) to encode data, which
50///     subsequently calls the callbacks when there is encoder data ready
51///     to be written.
52///   * The program finishes the encoding with [`FlacEncoder::finish()`](#method.finish),
53///     which causes the encoder to encode any data still in its input pipe,
54///     update the metadata with the final encoding statistics if output
55///     seeking is possible, and finally reset the encoder to the
56///     uninitialized state.
57///     Note: the stream is `finish()`ed when it's dropped, and any potential error is ignored.
58///   * The instance may be used again or deleted with
59///     [`FlacEncoder::delete()`](#method.delete).
60///     Note: the stream is `delete()`ed when it's dropped.
61///
62/// In more detail, the stream encoder functions similarly to the
63/// stream decoder, but has fewer
64/// callbacks and more options. Typically the client will create a new
65/// instance by calling [`FlacEncoder::new()`](#method.new), then set the necessary
66/// parameters with functions on [`FlacEncoderConfig`](struct.FlacEncoderConfig.html), and initialize it by
67/// calling one of the [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) functions.
68///
69/// Unlike the decoders, the stream encoder has many options that can
70/// affect the speed and compression ratio. When setting these parameters
71/// you should have some basic knowledge of the format (see the
72/// user-level documentation or the formal description). The functions on
73/// [`FlacEncoderConfig`](struct.FlacEncoderConfig.html) themselves do not validate the
74/// values as many are interdependent. The [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write)
75/// functions will do this, so make sure to pay attention to the result
76/// returned by [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) to make sure that it is
77/// `Ok()`. Any parameters that are not set
78/// before [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) will take on the defaults from
79/// the constructor.
80///
81/// There are three initialization functions for native FLAC, one for
82/// setting up the encoder to encode FLAC data to the client via
83/// a `Write` stream, and two for encoding directly to a file.
84///
85/// For encoding via a `Write` stream, use [`FlacEncoderConfig::init_write()`](struct.FlacEncoderConfig.html#method.init_write).
86/// You must also supply a `std::io::Write` stream which will be called anytime
87/// there is raw encoded data to write. The client cannot seek the output due to
88/// [RFC 2035](https://github.com/rust-lang/rfcs/issues/2035), so the
89/// encoder cannot go back after encoding is finished to write back
90/// information that was collected while encoding, like seek point offsets,
91/// frame sizes, etc.
92///
93/// For encoding directly to a file, use [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file).
94/// Then you must only supply a UTF-8 filename; the encoder will handle all the callbacks
95/// internally. You may also supply a progress callback for periodic
96/// notification of the encoding progress.
97///
98/// There are three similarly-named init functions for encoding to Ogg
99/// FLAC streams.
100///
101/// The call to [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) currently will also immediately
102/// call write to the sink several times, once with the `fLaC` signature,
103/// and once for each encoded metadata block. Note that for Ogg FLAC
104/// encoding you will usually get at least twice the number of callbacks than
105/// with native FLAC, one for the Ogg page header and one for the page body.
106///
107/// After initializing the instance, the client may feed audio data to the
108/// encoder in one of two ways:
109///
110///   * Channel separate, through [`FlacEncoder::process()`](#method.process) - The client
111///     will pass an slice of buffer slices, one for each channel, to
112///     the encoder, each of the same length. The samples need not be
113///     block-aligned, but each channel should have the same number of samples.
114///     This function will allocate if the user supplies more than 8 channels.
115///   * Channel interleaved, through
116///     [`FlacEncoder::process_interleaved()`](#method.process_interleaved) - The client will pass a single
117///     slice to data that is channel-interleaved (i.e. `channel0_sample0`,
118///     `channel1_sample0`, ... , `channelN_sample0`, `channel0_sample1`, ...).
119///     Again, the samples need not be block-aligned but they must be
120///     sample-aligned, i.e. the first value should be `channel0_sample0` and
121///     the last value `channelN_sampleM`.
122///
123/// Note that for either process call, each sample in the buffers should be a
124/// signed integer, right-justified to the resolution set by
125/// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample).
126/// For example, if the resolution is 16 bits per sample, the samples should all be in the range [-32768,32767].
127///
128/// When the client is finished encoding data, it calls
129/// [`FlacEncoder::finish()`](#method.finish), either explicitly or by dropping the encoder,
130/// which causes the encoder to encode any
131/// data still in its input pipe, and call the metadata callback with the
132/// final encoding statistics. Then the instance may be deleted with
133/// [`FlacEncoder::delete()`](#method.delete) by dropping the encoder, or initialized again to encode another
134/// stream.
135///
136/// For programs that write their own metadata, but that do not know the
137/// actual metadata until after encoding, it is advantageous to instruct
138/// the encoder to write a PADDING block of the correct size, so that
139/// instead of rewriting the whole stream after encoding, the program can
140/// just overwrite the PADDING block. If only the maximum size of the
141/// metadata is known, the program can write a slightly larger padding
142/// block, then split it after encoding.
143///
144/// Make sure you understand how lengths are calculated. All FLAC metadata
145/// blocks have a 4 byte header which contains the type and length. This
146/// length does not include the 4 bytes of the header. See the format page
147/// for the specification of metadata blocks and their lengths.
148///
149/// **Note**:<br />
150/// If you are writing the FLAC data to a file via callbacks, make sure it
151/// is open for update (e.g. mode "w+" for stdio streams). This is because
152/// after the first encoding pass, the encoder will try to seek back to the
153/// beginning of the stream, to the STREAMINFO block, to write some data
154/// there. (If using [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file), the file is managed internally.)
155///
156/// **Note**:<br />
157/// [`FlacEncoder::finish()`](#method.finish) resets all settings to the constructor defaults.
158#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
159#[repr(transparent)]
160pub struct FlacEncoder<'out>(pub(super) StreamEncoderContainer, pub(super) PhantomData<&'out mut ()>);
161
162impl<'out> FlacEncoder<'out> {
163    /// Create a new stream encoder, in a configuration wrapper, or `None` if one couldn't be allocated.
164    #[allow(clippy::new_ret_no_self)]
165    pub fn new() -> Option<FlacEncoderConfig> {
166        let enc = unsafe { FLAC__stream_encoder_new() };
167        if !enc.is_null() {
168            Some(FlacEncoderConfig(StreamEncoderContainer(enc)))
169        } else {
170            None
171        }
172    }
173
174    /// Get the current encoder state.
175    pub fn state(&self) -> FlacEncoderState {
176        FlacEncoderState::try_from(unsafe { FLAC__stream_encoder_get_state((self.0).0) }).unwrap()
177    }
178
179    /// Get the state of the verify stream decoder.
180    ///
181    /// Useful when the stream encoder state is
182    /// [`VerifyDecoderError`](enum.FlacEncoderState.html#variant.VerifyDecoderError).
183    pub fn verify_decoder_state(&self) -> FlacEncoderState {
184        FlacEncoderState::try_from(unsafe { FLAC__stream_encoder_get_verify_decoder_state((self.0).0) }).unwrap()
185    }
186
187    /// Submit data for encoding.
188    ///
189    /// This version allows you to supply the input data via a slice of
190    /// slices, each slice consisting of the same amount of samples as the first one,
191    /// representing one channel. The samples need not be block-aligned,
192    /// but each channel should have the same number of samples. Each sample
193    /// should be a signed integer, right-justified to the resolution set by
194    /// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample). For example, if the
195    /// resolution is 16 bits per sample, the samples should all be in the
196    /// range [-32768,32767].
197    ///
198    /// For applications where channel order is important, channels must
199    /// follow the order as described in the
200    /// [frame header](https://xiph.org/flac/format.html#frame_header).
201    ///
202    /// Requires encoder instance to be in OK state.
203    pub fn process(&mut self, buffers: &[&[i32]]) -> Result<(), ()> {
204        if buffers.len() <= 8 {
205            let mut buffer = [ptr::null(); 8];
206            self.process_impl(&mut buffer, buffers)
207        } else {
208            let mut buffer = vec![ptr::null(); buffers.len()];
209            self.process_impl(&mut buffer, buffers)
210        }
211    }
212
213    fn process_impl(&mut self, buffer: &mut [*const i32], buffers: &[&[i32]]) -> Result<(), ()> {
214        let samples = buffers.iter().next().map(|b| b.len()).unwrap_or(0) as c_uint;
215
216        for (pbfr, sbfr) in buffer.iter_mut().zip(buffers) {
217            *pbfr = sbfr.as_ptr();
218        }
219
220        if unsafe { FLAC__stream_encoder_process((self.0).0, buffer.as_ptr(), samples) } != 0 {
221            Ok(())
222        } else {
223            Err(())
224        }
225    }
226
227    /// Submit data for encoding.
228    ///
229    /// This version allows you to supply the input data where the channels
230    /// are interleaved into a single array (i.e. `channel0_sample0`,
231    /// `channel1_sample0`, ... , `channelN_sample0`, `channel0_sample1`, ...).
232    /// The samples need not be block-aligned but they must be
233    /// sample-aligned, i.e. the first value should be `channel0_sample0`
234    /// and the last value `channelN_sampleM`. Each sample should be a signed
235    /// integer, right-justified to the resolution set by
236    /// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample).
237    /// For example, if the resolution is 16 bits per sample, the samples should all be in the
238    /// range [-32768,32767].
239    ///
240    /// For applications where channel order is important, channels must
241    /// follow the order as described in the
242    /// [frame header](https://xiph.org/flac/format.html#frame_header).
243    ///
244    /// Requires encoder instance to be in OK state.
245    pub fn process_interleaved(&mut self, buffer: &[i32], samples_per_channel: u32) -> Result<(), ()> {
246        if unsafe { FLAC__stream_encoder_process_interleaved((self.0).0, buffer.as_ptr(), samples_per_channel) } != 0 {
247            Ok(())
248        } else {
249            Err(())
250        }
251    }
252
253    /// Finish the encoding process.
254    ///
255    /// Flushes the encoding buffer, releases resources, resets the encoder
256    /// settings to their defaults, and returns the encoder state to
257    /// `FLAC__STREAM_ENCODER_UNINITIALIZED`. Note that this can generate
258    /// one or more write callbacks before returning, and will generate
259    /// a metadata callback.
260    ///
261    /// Note that in the course of processing the last frame, errors can
262    /// occur, so the caller should be sure to check the return value to
263    /// ensure the file was encoded properly.
264    ///
265    /// In the event of a prematurely-terminated encode, it is not strictly
266    /// necessary to call this immediately before [`FlacEncoder::delete()`](#method.delete)
267    /// but it is good practice to match every [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write)
268    /// with a [`FlacEncoder::finish()`](#method.finish).
269    ///
270    /// This is also called by `drop()`.
271    ///
272    /// Returns `Err(self)` if an error occurred processing the last frame, or, if verify
273    /// mode is set (see [`FlacEncoderConfig::verify()`](struct.FlacEncoderConfig.html#method.verify)), there was a
274    /// verify mismatch; else the config wrapper.
275    ///
276    /// If `Err()`, caller should check the state with [`state()`](#method.state) for more information about the error.
277    pub fn finish(mut self) -> Result<FlacEncoderConfig, FlacEncoder<'out>> {
278        if unsafe { FLAC__stream_encoder_finish((self.0).0) } != 0 {
279            Ok(FlacEncoderConfig(mem::replace(&mut self.0, StreamEncoderContainer(ptr::null_mut()))))
280        } else {
281            Err(self)
282        }
283    }
284}
285
286impl<'out> Drop for FlacEncoder<'out> {
287    fn drop(&mut self) {
288        if !(self.0).0.is_null() {
289            unsafe { FLAC__stream_encoder_finish((self.0).0) };
290        }
291    }
292}