1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#[cfg(feature = "flac")]
use flac_sys::{FLAC__stream_encoder_new, FLAC__stream_encoder_get_state, FLAC__stream_encoder_get_verify_decoder_state, FLAC__stream_encoder_finish,
               FLAC__stream_encoder_process, FLAC__stream_encoder_process_interleaved};

#[cfg(feature = "libflac")]
use libflac_sys::{FLAC__stream_encoder_new, FLAC__stream_encoder_get_state, FLAC__stream_encoder_get_verify_decoder_state, FLAC__stream_encoder_finish,
    FLAC__stream_encoder_process, FLAC__stream_encoder_process_interleaved};

use super::{StreamEncoderContainer, FlacEncoderConfig, FlacEncoderState};
use std::marker::PhantomData;
use std::convert::TryFrom;
use std::os::raw::c_uint;
use std::{mem, ptr};


/// The [stream encoder](https://xiph.org/flac/api/group__flac__stream__encoder.html) can encode to native FLAC,
/// and optionally Ogg FLAC (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
///
/// The basic usage of this encoder is as follows:
///   * The program creates an instance of an encoder using
///     [`FlacEncoder::new()`](#method.new).
///   * The program overrides the default settings using functions in
///     [`FlacEncoderConfig`](struct.FlacEncoderConfig.html). At a minimum, the following
///     functions should be called:
///       * [`FlacEncoderConfig::channels()`](struct.FlacEncoderConfig.html#method.channels)
///       * [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample)
///       * [`FlacEncoderConfig::sample_rate()`](struct.FlacEncoderConfig.html#method.sample_rate)
///       * [`FlacEncoderConfig::ogg_serial_number()`](struct.FlacEncoderConfig.html#method.ogg_serial_number)
///         (if encoding to Ogg FLAC)
///       * [`FlacEncoderConfig::total_samples_estimate()`](struct.FlacEncoderConfig.html#method.total_samples_estimate)
///         (if known)
///   * If the application wants to control the compression level or set its own
///     metadata, then the following should also be called:
///     * [`FlacEncoderConfig::compression_level()`](struct.FlacEncoderConfig.html#method.compression_level)
///     * [`FlacEncoderConfig::verify()`](struct.FlacEncoderConfig.html#method.verify)
///     * [`FlacEncoderConfig::metadata()`](struct.FlacEncoderConfig.html#method.metadata)
///   * The rest of the set functions should only be called if the client needs
///     exact control over how the audio is compressed; thorough understanding
///     of the FLAC format is necessary to achieve good results.
///   * The program initializes the instance to validate the settings and
///     prepare for encoding using
///       * [`FlacEncoderConfig::init_write()`](struct.FlacEncoderConfig.html#method.init_write), or
///         [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file), or
///         [`FlacEncoderConfig::init_stdout()`](struct.FlacEncoderConfig.html#method.init_stdout) for native FLAC
///       * [`FlacEncoderConfig::init_write_ogg()`](struct.FlacEncoderConfig.html#method.init_write_ogg), or
///         [`FlacEncoderConfig::init_file_ogg()`](struct.FlacEncoderConfig.html#method.init_file_ogg), or
///         [`FlacEncoderConfig::init_stdout_ogg()`](struct.FlacEncoderConfig.html#method.init_stdout_ogg) for Ogg FLAC
///   * The program calls [`FlacEncoder::process()`](#method.process) or
///     [`FlacEncoder::process_interleaved()`](#method.process_interleaved) to encode data, which
///     subsequently calls the callbacks when there is encoder data ready
///     to be written.
///   * The program finishes the encoding with [`FlacEncoder::finish()`](#method.finish),
///     which causes the encoder to encode any data still in its input pipe,
///     update the metadata with the final encoding statistics if output
///     seeking is possible, and finally reset the encoder to the
///     uninitialized state.
///     Note: the stream is `finish()`ed when it's dropped, and any potential error is ignored.
///   * The instance may be used again or deleted with
///     [`FlacEncoder::delete()`](#method.delete).
///     Note: the stream is `delete()`ed when it's dropped.
///
/// In more detail, the stream encoder functions similarly to the
/// stream decoder, but has fewer
/// callbacks and more options. Typically the client will create a new
/// instance by calling [`FlacEncoder::new()`](#method.new), then set the necessary
/// parameters with functions on [`FlacEncoderConfig`](struct.FlacEncoderConfig.html), and initialize it by
/// calling one of the [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) functions.
///
/// Unlike the decoders, the stream encoder has many options that can
/// affect the speed and compression ratio. When setting these parameters
/// you should have some basic knowledge of the format (see the
/// user-level documentation or the formal description). The functions on
/// [`FlacEncoderConfig`](struct.FlacEncoderConfig.html) themselves do not validate the
/// values as many are interdependent. The [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write)
/// functions will do this, so make sure to pay attention to the result
/// returned by [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) to make sure that it is
/// `Ok()`. Any parameters that are not set
/// before [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) will take on the defaults from
/// the constructor.
///
/// There are three initialization functions for native FLAC, one for
/// setting up the encoder to encode FLAC data to the client via
/// a `Write` stream, and two for encoding directly to a file.
///
/// For encoding via a `Write` stream, use [`FlacEncoderConfig::init_write()`](struct.FlacEncoderConfig.html#method.init_write).
/// You must also supply a `std::io::Write` stream which will be called anytime
/// there is raw encoded data to write. The client cannot seek the output due to
/// [RFC 2035](https://github.com/rust-lang/rfcs/issues/2035), so the
/// encoder cannot go back after encoding is finished to write back
/// information that was collected while encoding, like seek point offsets,
/// frame sizes, etc.
///
/// For encoding directly to a file, use [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file).
/// Then you must only supply a UTF-8 filename; the encoder will handle all the callbacks
/// internally. You may also supply a progress callback for periodic
/// notification of the encoding progress.
///
/// There are three similarly-named init functions for encoding to Ogg
/// FLAC streams.
///
/// The call to [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write) currently will also immediately
/// call write to the sink several times, once with the `fLaC` signature,
/// and once for each encoded metadata block. Note that for Ogg FLAC
/// encoding you will usually get at least twice the number of callbacks than
/// with native FLAC, one for the Ogg page header and one for the page body.
///
/// After initializing the instance, the client may feed audio data to the
/// encoder in one of two ways:
///
///   * Channel separate, through [`FlacEncoder::process()`](#method.process) - The client
///     will pass an slice of buffer slices, one for each channel, to
///     the encoder, each of the same length. The samples need not be
///     block-aligned, but each channel should have the same number of samples.
///     This function will allocate if the user supplies more than 8 channels.
///   * Channel interleaved, through
///     [`FlacEncoder::process_interleaved()`](#method.process_interleaved) - The client will pass a single
///     slice to data that is channel-interleaved (i.e. `channel0_sample0`,
///     `channel1_sample0`, ... , `channelN_sample0`, `channel0_sample1`, ...).
///     Again, the samples need not be block-aligned but they must be
///     sample-aligned, i.e. the first value should be `channel0_sample0` and
///     the last value `channelN_sampleM`.
///
/// Note that for either process call, each sample in the buffers should be a
/// signed integer, right-justified to the resolution set by
/// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample).
/// For example, if the resolution is 16 bits per sample, the samples should all be in the range [-32768,32767].
///
/// When the client is finished encoding data, it calls
/// [`FlacEncoder::finish()`](#method.finish), either explicitly or by dropping the encoder,
/// which causes the encoder to encode any
/// data still in its input pipe, and call the metadata callback with the
/// final encoding statistics. Then the instance may be deleted with
/// [`FlacEncoder::delete()`](#method.delete) by dropping the encoder, or initialized again to encode another
/// stream.
///
/// For programs that write their own metadata, but that do not know the
/// actual metadata until after encoding, it is advantageous to instruct
/// the encoder to write a PADDING block of the correct size, so that
/// instead of rewriting the whole stream after encoding, the program can
/// just overwrite the PADDING block. If only the maximum size of the
/// metadata is known, the program can write a slightly larger padding
/// block, then split it after encoding.
///
/// Make sure you understand how lengths are calculated. All FLAC metadata
/// blocks have a 4 byte header which contains the type and length. This
/// length does not include the 4 bytes of the header. See the format page
/// for the specification of metadata blocks and their lengths.
///
/// **Note**:<br />
/// If you are writing the FLAC data to a file via callbacks, make sure it
/// is open for update (e.g. mode "w+" for stdio streams). This is because
/// after the first encoding pass, the encoder will try to seek back to the
/// beginning of the stream, to the STREAMINFO block, to write some data
/// there. (If using [`FlacEncoderConfig::init_file()`](struct.FlacEncoderConfig.html#method.init_file), the file is managed internally.)
///
/// **Note**:<br />
/// [`FlacEncoder::finish()`](#method.finish) resets all settings to the constructor defaults.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct FlacEncoder<'out>(pub(super) StreamEncoderContainer, pub(super) PhantomData<&'out mut ()>);

impl<'out> FlacEncoder<'out> {
    /// Create a new stream encoder, in a configuration wrapper, or `None` if one couldn't be allocated.
    #[allow(clippy::new_ret_no_self)]
    pub fn new() -> Option<FlacEncoderConfig> {
        let enc = unsafe { FLAC__stream_encoder_new() };
        if !enc.is_null() {
            Some(FlacEncoderConfig(StreamEncoderContainer(enc)))
        } else {
            None
        }
    }

    /// Get the current encoder state.
    pub fn state(&self) -> FlacEncoderState {
        FlacEncoderState::try_from(unsafe { FLAC__stream_encoder_get_state((self.0).0) }).unwrap()
    }

    /// Get the state of the verify stream decoder.
    ///
    /// Useful when the stream encoder state is
    /// [`VerifyDecoderError`](enum.FlacEncoderState.html#variant.VerifyDecoderError).
    pub fn verify_decoder_state(&self) -> FlacEncoderState {
        FlacEncoderState::try_from(unsafe { FLAC__stream_encoder_get_verify_decoder_state((self.0).0) }).unwrap()
    }

    /// Submit data for encoding.
    ///
    /// This version allows you to supply the input data via a slice of
    /// slices, each slice consisting of the same amount of samples as the first one,
    /// representing one channel. The samples need not be block-aligned,
    /// but each channel should have the same number of samples. Each sample
    /// should be a signed integer, right-justified to the resolution set by
    /// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample). For example, if the
    /// resolution is 16 bits per sample, the samples should all be in the
    /// range [-32768,32767].
    ///
    /// For applications where channel order is important, channels must
    /// follow the order as described in the
    /// [frame header](https://xiph.org/flac/format.html#frame_header).
    ///
    /// Requires encoder instance to be in OK state.
    pub fn process(&mut self, buffers: &[&[i32]]) -> Result<(), ()> {
        if buffers.len() <= 8 {
            let mut buffer = [ptr::null(); 8];
            self.process_impl(&mut buffer, buffers)
        } else {
            let mut buffer = vec![ptr::null(); buffers.len()];
            self.process_impl(&mut buffer, buffers)
        }
    }

    fn process_impl(&mut self, buffer: &mut [*const i32], buffers: &[&[i32]]) -> Result<(), ()> {
        let samples = buffers.iter().next().map(|b| b.len()).unwrap_or(0) as c_uint;

        for (pbfr, sbfr) in buffer.iter_mut().zip(buffers) {
            *pbfr = sbfr.as_ptr();
        }

        if unsafe { FLAC__stream_encoder_process((self.0).0, buffer.as_ptr(), samples) } != 0 {
            Ok(())
        } else {
            Err(())
        }
    }

    /// Submit data for encoding.
    ///
    /// This version allows you to supply the input data where the channels
    /// are interleaved into a single array (i.e. `channel0_sample0`,
    /// `channel1_sample0`, ... , `channelN_sample0`, `channel0_sample1`, ...).
    /// The samples need not be block-aligned but they must be
    /// sample-aligned, i.e. the first value should be `channel0_sample0`
    /// and the last value `channelN_sampleM`. Each sample should be a signed
    /// integer, right-justified to the resolution set by
    /// [`FlacEncoderConfig::bits_per_sample()`](struct.FlacEncoderConfig.html#method.bits_per_sample).
    /// For example, if the resolution is 16 bits per sample, the samples should all be in the
    /// range [-32768,32767].
    ///
    /// For applications where channel order is important, channels must
    /// follow the order as described in the
    /// [frame header](https://xiph.org/flac/format.html#frame_header).
    ///
    /// Requires encoder instance to be in OK state.
    pub fn process_interleaved(&mut self, buffer: &[i32], samples_per_channel: u32) -> Result<(), ()> {
        if unsafe { FLAC__stream_encoder_process_interleaved((self.0).0, buffer.as_ptr(), samples_per_channel) } != 0 {
            Ok(())
        } else {
            Err(())
        }
    }

    /// Finish the encoding process.
    ///
    /// Flushes the encoding buffer, releases resources, resets the encoder
    /// settings to their defaults, and returns the encoder state to
    /// `FLAC__STREAM_ENCODER_UNINITIALIZED`. Note that this can generate
    /// one or more write callbacks before returning, and will generate
    /// a metadata callback.
    ///
    /// Note that in the course of processing the last frame, errors can
    /// occur, so the caller should be sure to check the return value to
    /// ensure the file was encoded properly.
    ///
    /// In the event of a prematurely-terminated encode, it is not strictly
    /// necessary to call this immediately before [`FlacEncoder::delete()`](#method.delete)
    /// but it is good practice to match every [`FlacEncoderConfig::init_*()`](struct.FlacEncoderConfig.html#method.init_write)
    /// with a [`FlacEncoder::finish()`](#method.finish).
    ///
    /// This is also called by `drop()`.
    ///
    /// Returns `Err(self)` if an error occurred processing the last frame, or, if verify
    /// mode is set (see [`FlacEncoderConfig::verify()`](struct.FlacEncoderConfig.html#method.verify)), there was a
    /// verify mismatch; else the config wrapper.
    ///
    /// If `Err()`, caller should check the state with [`state()`](#method.state) for more information about the error.
    pub fn finish(mut self) -> Result<FlacEncoderConfig, FlacEncoder<'out>> {
        if unsafe { FLAC__stream_encoder_finish((self.0).0) } != 0 {
            Ok(FlacEncoderConfig(mem::replace(&mut self.0, StreamEncoderContainer(ptr::null_mut()))))
        } else {
            Err(self)
        }
    }
}

impl<'out> Drop for FlacEncoder<'out> {
    fn drop(&mut self) {
        if !(self.0).0.is_null() {
            unsafe { FLAC__stream_encoder_finish((self.0).0) };
        }
    }
}