Skip to main content

shine_rs/
mp3_encoder.rs

1//! 高级MP3编码器接口
2//!
3//! 这个模块提供了一个简单易用的高级接口,封装了底层的shine编码器实现。
4//! 它提供了Rust风格的API,同时保留了对底层低级接口的完全访问。
5
6use crate::encoder::{
7    shine_encode_buffer_interleaved, shine_flush, shine_initialise, shine_set_config_mpeg_defaults,
8    ShineConfig, ShineMpeg, ShineWave, NONE,
9};
10use crate::error::{ConfigError, EncoderError, InputDataError};
11use crate::types::ShineGlobalConfig;
12use std::collections::VecDeque;
13
14/// 支持的采样率 (Hz)
15pub const SUPPORTED_SAMPLE_RATES: &[u32] = &[
16    8000, 11025, 12000, // MPEG 2.5
17    16000, 22050, 24000, // MPEG 2
18    32000, 44100, 48000, // MPEG 1
19];
20
21/// 支持的比特率 (kbps)
22pub const SUPPORTED_BITRATES: &[u32] = &[
23    8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320,
24];
25
26/// 立体声模式
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum StereoMode {
29    /// 立体声
30    Stereo = 0,
31    /// 联合立体声
32    JointStereo = 1,
33    /// 双声道
34    DualChannel = 2,
35    /// 单声道
36    Mono = 3,
37}
38
39/// MP3编码器配置
40#[derive(Debug, Clone)]
41pub struct Mp3EncoderConfig {
42    /// 采样率 (Hz)
43    pub sample_rate: u32,
44    /// 比特率 (kbps)
45    pub bitrate: u32,
46    /// 声道数 (1 = 单声道, 2 = 立体声)
47    pub channels: u8,
48    /// 立体声模式
49    pub stereo_mode: StereoMode,
50    /// 版权标志
51    pub copyright: bool,
52    /// 原创标志
53    pub original: bool,
54}
55
56impl Default for Mp3EncoderConfig {
57    fn default() -> Self {
58        Self {
59            sample_rate: 44100,
60            bitrate: 128,
61            channels: 2,
62            stereo_mode: StereoMode::Stereo,
63            copyright: false,
64            original: true,
65        }
66    }
67}
68
69impl Mp3EncoderConfig {
70    /// 创建新的配置
71    pub fn new() -> Self {
72        Self::default()
73    }
74
75    /// 设置采样率
76    pub fn sample_rate(mut self, sample_rate: u32) -> Self {
77        self.sample_rate = sample_rate;
78        self
79    }
80
81    /// 设置比特率
82    pub fn bitrate(mut self, bitrate: u32) -> Self {
83        self.bitrate = bitrate;
84        self
85    }
86
87    /// 设置声道数
88    pub fn channels(mut self, channels: u8) -> Self {
89        self.channels = channels;
90        self
91    }
92
93    /// 设置立体声模式
94    pub fn stereo_mode(mut self, mode: StereoMode) -> Self {
95        self.stereo_mode = mode;
96        self
97    }
98
99    /// 设置版权标志
100    pub fn copyright(mut self, copyright: bool) -> Self {
101        self.copyright = copyright;
102        self
103    }
104
105    /// 设置原创标志
106    pub fn original(mut self, original: bool) -> Self {
107        self.original = original;
108        self
109    }
110
111    /// 验证配置的有效性
112    pub fn validate(&self) -> Result<(), ConfigError> {
113        // 检查采样率
114        if !SUPPORTED_SAMPLE_RATES.contains(&self.sample_rate) {
115            return Err(ConfigError::UnsupportedSampleRate(self.sample_rate));
116        }
117
118        // 检查比特率
119        if !SUPPORTED_BITRATES.contains(&self.bitrate) {
120            return Err(ConfigError::UnsupportedBitrate(self.bitrate));
121        }
122
123        // 检查声道数
124        if self.channels == 0 || self.channels > 2 {
125            return Err(ConfigError::InvalidChannels);
126        }
127
128        // 检查立体声模式与声道数的兼容性
129        match (self.channels, self.stereo_mode) {
130            (1, StereoMode::Mono) => {}
131            (2, StereoMode::Stereo | StereoMode::JointStereo | StereoMode::DualChannel) => {}
132            (channels, mode) => {
133                return Err(ConfigError::InvalidStereoMode {
134                    mode: format!("{:?}", mode),
135                    channels,
136                });
137            }
138        }
139
140        // 使用shine的验证逻辑检查采样率和比特率组合
141        let shine_result =
142            crate::encoder::shine_check_config(self.sample_rate as i32, self.bitrate as i32);
143
144        if shine_result < 0 {
145            // 确定MPEG版本以提供更详细的错误信息
146            let mpeg_version = if self.sample_rate <= 12000 {
147                "MPEG-2.5"
148            } else if self.sample_rate <= 24000 {
149                "MPEG-2"
150            } else {
151                "MPEG-1"
152            };
153
154            let reason = match mpeg_version {
155                "MPEG-2.5" => format!(
156                    "MPEG-2.5 ({}Hz) only supports bitrates up to 64 kbps",
157                    self.sample_rate
158                ),
159                "MPEG-2" => format!(
160                    "MPEG-2 ({}Hz) only supports bitrates up to 160 kbps",
161                    self.sample_rate
162                ),
163                "MPEG-1" => format!(
164                    "MPEG-1 ({}Hz) only supports bitrates from 32 to 320 kbps",
165                    self.sample_rate
166                ),
167                _ => "Invalid combination".to_string(),
168            };
169
170            return Err(ConfigError::IncompatibleRateCombination {
171                sample_rate: self.sample_rate,
172                bitrate: self.bitrate,
173                reason,
174            });
175        }
176
177        Ok(())
178    }
179}
180
181/// 高级MP3编码器
182#[derive(Debug)]
183pub struct Mp3Encoder {
184    /// 底层shine配置
185    config: Box<ShineGlobalConfig>,
186    /// 编码器配置
187    encoder_config: Mp3EncoderConfig,
188    /// 每次编码需要的样本数
189    samples_per_frame: usize,
190    /// 输入缓冲区
191    input_buffer: VecDeque<i16>,
192    /// 是否已完成编码
193    finished: bool,
194}
195
196impl Mp3Encoder {
197    /// 创建新的MP3编码器
198    pub fn new(config: Mp3EncoderConfig) -> Result<Self, EncoderError> {
199        // 验证配置
200        config.validate()?;
201
202        // 转换为shine配置
203        let shine_config = Self::create_shine_config(&config)?;
204
205        // 初始化shine编码器
206        let global_config = shine_initialise(&shine_config).map_err(EncoderError::Encoding)?;
207
208        // 计算每帧需要的样本数(交错格式的总样本数)
209        let samples_per_channel = crate::encoder::shine_samples_per_pass(&global_config) as usize;
210        let samples_per_frame = samples_per_channel * config.channels as usize;
211
212        Ok(Self {
213            config: global_config,
214            encoder_config: config,
215            samples_per_frame,
216            input_buffer: VecDeque::new(),
217            finished: false,
218        })
219    }
220
221    /// 获取编码器配置
222    pub fn config(&self) -> &Mp3EncoderConfig {
223        &self.encoder_config
224    }
225
226    /// 获取每帧需要的样本数
227    pub fn samples_per_frame(&self) -> usize {
228        self.samples_per_frame
229    }
230
231    /// 获取底层shine配置(用于高级用户直接访问)
232    pub fn shine_config(&mut self) -> &mut ShineGlobalConfig {
233        &mut self.config
234    }
235
236    /// 编码PCM音频数据(交错格式)
237    ///
238    /// # 参数
239    /// - `pcm_data`: 交错格式的PCM数据 (左右声道交替)
240    ///
241    /// # 返回值
242    /// 返回编码后的MP3数据块的向量
243    pub fn encode_interleaved(&mut self, pcm_data: &[i16]) -> Result<Vec<Vec<u8>>, EncoderError> {
244        if self.finished {
245            return Err(EncoderError::InternalState(
246                "Encoder has been finished".to_string(),
247            ));
248        }
249
250        // 验证输入数据
251        if pcm_data.is_empty() {
252            return Err(EncoderError::InputData(InputDataError::EmptyInput));
253        }
254
255        // 将数据添加到缓冲区
256        self.input_buffer.extend(pcm_data);
257
258        let mut output_frames = Vec::new();
259
260        // 处理完整的帧
261        while self.input_buffer.len() >= self.samples_per_frame {
262            let frame_data: Vec<i16> = self.input_buffer.drain(..self.samples_per_frame).collect();
263
264            // 调用底层编码函数
265            let (mp3_data, written) =
266                unsafe { shine_encode_buffer_interleaved(&mut self.config, frame_data.as_ptr()) }
267                    .map_err(EncoderError::Encoding)?;
268
269            if written > 0 {
270                output_frames.push(mp3_data[..written].to_vec());
271            }
272        }
273
274        Ok(output_frames)
275    }
276
277    /// 编码PCM音频数据(分离声道格式)
278    ///
279    /// # 参数
280    /// - `left_channel`: 左声道数据
281    /// - `right_channel`: 右声道数据(单声道时可为None)
282    ///
283    /// # 返回值
284    /// 返回编码后的MP3数据块的向量
285    pub fn encode_separate_channels(
286        &mut self,
287        left_channel: &[i16],
288        right_channel: Option<&[i16]>,
289    ) -> Result<Vec<Vec<u8>>, EncoderError> {
290        if self.finished {
291            return Err(EncoderError::InternalState(
292                "Encoder has been finished".to_string(),
293            ));
294        }
295
296        // 验证输入数据
297        if left_channel.is_empty() {
298            return Err(EncoderError::InputData(InputDataError::EmptyInput));
299        }
300
301        // 验证声道数据一致性
302        match (self.encoder_config.channels, right_channel) {
303            (1, None) => {
304                // 单声道,只使用左声道
305                self.encode_interleaved(left_channel)
306            }
307            (2, Some(right)) => {
308                if left_channel.len() != right.len() {
309                    return Err(EncoderError::InputData(
310                        InputDataError::InvalidChannelCount {
311                            expected: left_channel.len(),
312                            actual: right.len(),
313                        },
314                    ));
315                }
316
317                // 交错合并左右声道
318                let mut interleaved = Vec::with_capacity(left_channel.len() * 2);
319                for (l, r) in left_channel.iter().zip(right.iter()) {
320                    interleaved.push(*l);
321                    interleaved.push(*r);
322                }
323
324                self.encode_interleaved(&interleaved)
325            }
326            (1, Some(_)) => Err(EncoderError::InputData(
327                InputDataError::InvalidChannelCount {
328                    expected: 1,
329                    actual: 2,
330                },
331            )),
332            (2, None) => Err(EncoderError::InputData(
333                InputDataError::InvalidChannelCount {
334                    expected: 2,
335                    actual: 1,
336                },
337            )),
338            _ => unreachable!(),
339        }
340    }
341
342    /// 完成编码并获取剩余数据
343    ///
344    /// # 返回值
345    /// 返回最后的MP3数据块
346    pub fn finish(&mut self) -> Result<Vec<u8>, EncoderError> {
347        if self.finished {
348            return Ok(Vec::new());
349        }
350
351        self.finished = true;
352
353        // 处理剩余的不完整帧(用零填充)
354        let mut final_output = Vec::new();
355
356        if !self.input_buffer.is_empty() {
357            // 用零填充到完整帧大小
358            while self.input_buffer.len() < self.samples_per_frame {
359                self.input_buffer.push_back(0);
360            }
361
362            let frame_data: Vec<i16> = self.input_buffer.drain(..).collect();
363
364            let (mp3_data, written) =
365                unsafe { shine_encode_buffer_interleaved(&mut self.config, frame_data.as_ptr()) }
366                    .map_err(EncoderError::Encoding)?;
367
368            if written > 0 {
369                final_output.extend_from_slice(&mp3_data[..written]);
370            }
371        }
372
373        // 刷新编码器缓冲区
374        let (flush_data, flush_written) = shine_flush(&mut self.config);
375        if flush_written > 0 {
376            final_output.extend_from_slice(&flush_data[..flush_written]);
377        }
378
379        Ok(final_output)
380    }
381
382    /// 获取缓冲区中剩余的样本数
383    pub fn buffered_samples(&self) -> usize {
384        self.input_buffer.len()
385    }
386
387    /// 检查编码器是否已完成
388    pub fn is_finished(&self) -> bool {
389        self.finished
390    }
391
392    /// 创建shine配置
393    fn create_shine_config(config: &Mp3EncoderConfig) -> Result<ShineConfig, ConfigError> {
394        let mut mpeg = ShineMpeg {
395            mode: config.stereo_mode as i32,
396            bitr: config.bitrate as i32,
397            emph: NONE,
398            copyright: if config.copyright { 1 } else { 0 },
399            original: if config.original { 1 } else { 0 },
400        };
401
402        // 设置默认值
403        shine_set_config_mpeg_defaults(&mut mpeg);
404
405        // 应用用户配置
406        mpeg.mode = config.stereo_mode as i32;
407        mpeg.bitr = config.bitrate as i32;
408        mpeg.copyright = if config.copyright { 1 } else { 0 };
409        mpeg.original = if config.original { 1 } else { 0 };
410
411        let wave = ShineWave {
412            channels: config.channels as i32,
413            samplerate: config.sample_rate as i32,
414        };
415
416        Ok(ShineConfig { wave, mpeg })
417    }
418}
419
420impl Drop for Mp3Encoder {
421    fn drop(&mut self) {
422        // 注意:这里我们不能调用shine_close,因为它需要获取Box的所有权
423        // 但是Rust的Drop trait只提供&mut self
424        // 幸运的是,Rust的自动内存管理会处理清理工作
425    }
426}
427
428/// 便利函数:一次性编码整个PCM数据
429///
430/// # 参数
431/// - `config`: 编码器配置
432/// - `pcm_data`: 交错格式的PCM数据
433///
434/// # 返回值
435/// 返回完整的MP3数据
436pub fn encode_pcm_to_mp3(
437    config: Mp3EncoderConfig,
438    pcm_data: &[i16],
439) -> Result<Vec<u8>, EncoderError> {
440    let mut encoder = Mp3Encoder::new(config)?;
441
442    let mut mp3_data = Vec::new();
443
444    // 编码所有数据
445    let frames = encoder.encode_interleaved(pcm_data)?;
446    for frame in frames {
447        mp3_data.extend(frame);
448    }
449
450    // 完成编码
451    let final_data = encoder.finish()?;
452    mp3_data.extend(final_data);
453
454    Ok(mp3_data)
455}