Skip to main content

shine_rs/
bitstream.rs

1//! Bitstream writing functionality for MP3 encoding
2//!
3//! This module implements the bitstream writing functions exactly as defined
4//! in shine's bitstream.c and l3bitstream.c. It provides functions to write
5//! MP3 frame headers, side information, and main data to the output bitstream.
6
7use crate::error::{EncodingError, EncodingResult};
8use crate::huffman::{HuffCodeTab, SHINE_HUFFMAN_TABLE};
9use crate::tables::{SHINE_SCALE_FACT_BAND_INDEX, SHINE_SLEN1_TAB, SHINE_SLEN2_TAB};
10use crate::types::{GrInfo, ShineGlobalConfig, GRANULE_SIZE};
11
12/// Bitstream writer structure (matches shine's bitstream_t exactly)
13/// (ref/shine/src/lib/bitstream.h:4-10)
14#[derive(Debug)]
15pub struct BitstreamWriter {
16    /// Processed data
17    pub data: Box<[u8]>,
18    /// Total data size
19    pub data_size: i32,
20    /// Data position
21    pub data_position: i32,
22    /// Bit stream cache
23    pub cache: u32,
24    /// Free bits in cache
25    pub cache_bits: i32,
26}
27
28impl BitstreamWriter {
29    /// Open the bitstream for writing (matches shine_open_bit_stream)
30    /// (ref/shine/src/lib/bitstream.c:15-22)
31    pub fn new(size: i32) -> Self {
32        Self {
33            data: vec![0u8; size as usize].into_boxed_slice(),
34            data_size: size,
35            data_position: 0,
36            cache: 0,
37            cache_bits: 32,
38        }
39    }
40
41    /// Write N bits into the bit stream (matches shine_putbits exactly)
42    /// (ref/shine/src/lib/bitstream.c:30-58)
43    ///
44    /// # Arguments
45    /// * `val` - value to write into the buffer
46    /// * `n` - number of bits of val
47    pub fn put_bits(&mut self, val: u32, n: i32) -> EncodingResult<()> {
48        #[cfg(debug_assertions)]
49        {
50            if n > 32 {
51                return Err(EncodingError::BitstreamError(
52                    "Cannot write more than 32 bits at a time".to_string(),
53                ));
54            }
55            if n < 0 {
56                return Err(EncodingError::BitstreamError(
57                    "Cannot write negative number of bits".to_string(),
58                ));
59            }
60            if n < 32 && (val >> n) != 0 {
61                return Err(EncodingError::BitstreamError(format!(
62                    "Upper bits are not all zeros: val=0x{:X}, n={}, val>>n=0x{:X}",
63                    val,
64                    n,
65                    val >> n
66                )));
67            }
68        }
69
70        // Handle the special case where n=0 (no bits to write)
71        if n == 0 {
72            return Ok(());
73        }
74
75        if self.cache_bits > n {
76            // Cache has enough space for the new bits
77            self.cache_bits -= n;
78
79            // Add safety check to prevent overflow
80            if self.cache_bits >= 0 && self.cache_bits < 32 {
81                let shifted_val = val << self.cache_bits;
82                self.cache |= shifted_val;
83            } else {
84                return Err(EncodingError::BitstreamError(format!(
85                    "Invalid cache_bits: {}",
86                    self.cache_bits
87                )));
88            }
89        } else {
90            // Cache doesn't have enough space, need to flush and write to buffer
91            // Ensure we have enough space in the buffer
92            if self.data_position + 4 >= self.data_size {
93                let new_size = self.data_size + (self.data_size / 2);
94                let mut new_buffer = vec![0u8; new_size as usize];
95                new_buffer[..self.data_position as usize]
96                    .copy_from_slice(&self.data[..self.data_position as usize]);
97                self.data = new_buffer.into_boxed_slice();
98                self.data_size = new_size;
99            }
100
101            // Match shine's logic exactly
102            let remaining_n = n - self.cache_bits;
103            self.cache |= val >> remaining_n;
104
105            // Write cache to buffer using SWAB32 equivalent (byte swap on little-endian)
106            let cache_bytes = self.cache.to_be_bytes();
107            self.data[self.data_position as usize..self.data_position as usize + 4]
108                .copy_from_slice(&cache_bytes);
109
110            self.data_position += 4;
111            self.cache_bits = 32 - remaining_n;
112
113            // Match Shine's exact logic for setting new cache value
114            // Prevent overflow when remaining_n is 0 or cache_bits is 0
115            if remaining_n != 0 && self.cache_bits > 0 && self.cache_bits < 32 {
116                let new_cache = val << self.cache_bits;
117                self.cache = new_cache;
118            } else {
119                self.cache = 0;
120            }
121        }
122
123        Ok(())
124    }
125
126    /// Get the current bit count (matches shine_get_bits_count exactly)
127    /// (ref/shine/src/lib/bitstream.c:60-62)
128    pub fn get_bits_count(&self) -> i32 {
129        self.data_position * 8 + (32 - self.cache_bits)
130    }
131
132    /// Get the output data
133    pub fn get_data(&self) -> &[u8] {
134        &self.data[..self.data_position as usize]
135    }
136
137    /// Flush any remaining bits in the cache
138    /// This matches shine's behavior when there are remaining bits in cache
139    pub fn flush(&mut self) -> EncodingResult<()> {
140        // Only flush if there are bits in the cache (cache_bits < 32)
141        if self.cache_bits < 32 {
142            // Calculate how many bytes we need to write
143            let bits_in_cache = 32 - self.cache_bits;
144            let bytes_to_write = (bits_in_cache + 7) / 8; // Round up to nearest byte
145
146            // Ensure we have enough space
147            if self.data_position + bytes_to_write >= self.data_size {
148                let new_size = self.data_size + (self.data_size / 2);
149                let mut new_buffer = vec![0u8; new_size as usize];
150                new_buffer[..self.data_position as usize]
151                    .copy_from_slice(&self.data[..self.data_position as usize]);
152                self.data = new_buffer.into_boxed_slice();
153                self.data_size = new_size;
154            }
155
156            // Write the cache bytes in big-endian format (matches shine's SWAB32)
157            let cache_bytes = self.cache.to_be_bytes();
158            self.data[self.data_position as usize
159                ..self.data_position as usize + bytes_to_write as usize]
160                .copy_from_slice(&cache_bytes[..bytes_to_write as usize]);
161            self.data_position += bytes_to_write;
162
163            // Clear the cache
164            self.cache = 0;
165            self.cache_bits = 32;
166        }
167        Ok(())
168    }
169
170    /// Align to byte boundary by flushing partial bytes
171    /// This matches shine's byte alignment behavior
172    pub fn byte_align(&mut self) -> EncodingResult<()> {
173        let bits_in_cache = 32 - self.cache_bits;
174        if bits_in_cache > 0 {
175            let bytes_to_flush = (bits_in_cache + 7) / 8;
176            let bits_to_flush = bytes_to_flush * 8;
177
178            if bits_to_flush > bits_in_cache {
179                // Need to add padding bits to reach byte boundary
180                let padding_bits = bits_to_flush - bits_in_cache;
181                self.put_bits(0, padding_bits)?;
182            }
183
184            // Now flush the cache to align to byte boundary
185            if self.cache_bits < 32 {
186                // Ensure we have enough space
187                if self.data_position + 4 >= self.data_size {
188                    let new_size = self.data_size + (self.data_size / 2);
189                    let mut new_buffer = vec![0u8; new_size as usize];
190                    new_buffer[..self.data_position as usize]
191                        .copy_from_slice(&self.data[..self.data_position as usize]);
192                    self.data = new_buffer.into_boxed_slice();
193                    self.data_size = new_size;
194                }
195
196                let cache_bytes = self.cache.to_be_bytes();
197                self.data[self.data_position as usize..self.data_position as usize + 4]
198                    .copy_from_slice(&cache_bytes);
199                self.data_position += 4;
200                self.cache = 0;
201                self.cache_bits = 32;
202            }
203        }
204        Ok(())
205    }
206}
207
208impl Default for BitstreamWriter {
209    fn default() -> Self {
210        Self::new(8192) // Default buffer size
211    }
212}
213
214/// Format the bitstream for a complete frame (matches shine_format_bitstream exactly)
215/// (ref/shine/src/lib/l3bitstream.c:25-44)
216///
217/// This is called after a frame of audio has been quantized and coded.
218/// It will write the encoded audio to the bitstream.
219pub fn format_bitstream(config: &mut ShineGlobalConfig) -> EncodingResult<()> {
220    // Apply sign correction to quantized values (matches shine exactly)
221    (0..config.wave.channels as usize).for_each(|ch| {
222        (0..config.mpeg.granules_per_frame as usize).for_each(|gr| {
223            let pi = &mut config.l3_enc[ch][gr];
224            let pr = &config.mdct_freq[ch][gr];
225
226            pi.iter_mut()
227                .zip(pr.iter())
228                .take(GRANULE_SIZE)
229                .for_each(|(pi_val, &pr_val)| {
230                    if pr_val < 0 && *pi_val > 0 {
231                        *pi_val *= -1;
232                    }
233                });
234        });
235    });
236
237    encode_side_info(config)?;
238    encode_main_data(config)?;
239
240    Ok(())
241}
242
243/// Encode the main data section (matches encodeMainData exactly)
244/// (ref/shine/src/lib/l3bitstream.c:46-71)
245fn encode_main_data(config: &mut ShineGlobalConfig) -> EncodingResult<()> {
246    for gr in 0..config.mpeg.granules_per_frame as usize {
247        for ch in 0..config.wave.channels as usize {
248            // Extract values we need before borrowing config mutably
249            let scalefac_compress = config.side_info.gr[gr].ch[ch].tt.scalefac_compress;
250            let scfsi = config.side_info.scfsi[ch];
251            let slen1 = SHINE_SLEN1_TAB[scalefac_compress as usize];
252            let slen2 = SHINE_SLEN2_TAB[scalefac_compress as usize];
253
254            // Write scale factors
255            if gr == 0 || scfsi[0] == 0 {
256                (0..6).try_for_each(|sfb| {
257                    let sf_val = config.scalefactor.l[gr][ch][sfb];
258                    config.bs.put_bits(sf_val as u32, slen1)
259                })?;
260            }
261            if gr == 0 || scfsi[1] == 0 {
262                (6..11).try_for_each(|sfb| {
263                    let sf_val = config.scalefactor.l[gr][ch][sfb];
264                    config.bs.put_bits(sf_val as u32, slen1)
265                })?;
266            }
267            if gr == 0 || scfsi[2] == 0 {
268                (11..16).try_for_each(|sfb| {
269                    let sf_val = config.scalefactor.l[gr][ch][sfb];
270                    config.bs.put_bits(sf_val as u32, slen2)
271                })?;
272            }
273            if gr == 0 || scfsi[3] == 0 {
274                (16..21).try_for_each(|sfb| {
275                    let sf_val = config.scalefactor.l[gr][ch][sfb];
276                    config.bs.put_bits(sf_val as u32, slen2)
277                })?;
278            }
279
280            // Copy the granule info to avoid borrowing conflicts
281            let gi = config.side_info.gr[gr].ch[ch].tt.clone();
282            let ix = config.l3_enc[ch][gr];
283            huffman_code_bits(config, &ix, &gi)?;
284        }
285    }
286
287    Ok(())
288}
289
290/// Encode the side information (matches encodeSideInfo exactly)
291/// (ref/shine/src/lib/l3bitstream.c:73-120)
292fn encode_side_info(config: &mut ShineGlobalConfig) -> EncodingResult<()> {
293    let si = &config.side_info;
294
295    // Write frame header
296    config.bs.put_bits(0x7ff, 11)?; // Sync word
297    config.bs.put_bits(config.mpeg.version as u32, 2)?;
298    config.bs.put_bits(config.mpeg.layer as u32, 2)?;
299    config
300        .bs
301        .put_bits(if config.mpeg.crc == 0 { 1 } else { 0 }, 1)?;
302    config.bs.put_bits(config.mpeg.bitrate_index as u32, 4)?;
303    config
304        .bs
305        .put_bits((config.mpeg.samplerate_index % 3) as u32, 2)?;
306    config.bs.put_bits(config.mpeg.padding as u32, 1)?;
307    config.bs.put_bits(config.mpeg.ext as u32, 1)?;
308    config.bs.put_bits(config.mpeg.mode as u32, 2)?;
309    config.bs.put_bits(config.mpeg.mode_ext as u32, 2)?;
310    config.bs.put_bits(config.mpeg.copyright as u32, 1)?;
311    config.bs.put_bits(config.mpeg.original as u32, 1)?;
312    config.bs.put_bits(config.mpeg.emph as u32, 2)?;
313
314    // Write side information
315    if config.mpeg.version == 3 {
316        // MPEG_I = 3
317        config.bs.put_bits(0, 9)?; // Main data begin
318        if config.wave.channels == 2 {
319            config.bs.put_bits(si.private_bits, 3)?;
320        } else {
321            config.bs.put_bits(si.private_bits, 5)?;
322        }
323    } else {
324        config.bs.put_bits(0, 8)?; // Main data begin
325        if config.wave.channels == 2 {
326            config.bs.put_bits(si.private_bits, 2)?;
327        } else {
328            config.bs.put_bits(si.private_bits, 1)?;
329        }
330    }
331
332    // Write SCFSI (only for MPEG-I)
333    if config.mpeg.version == 3 {
334        (0..config.wave.channels as usize).try_for_each(|ch| {
335            (0..4).try_for_each(|scfsi_band| config.bs.put_bits(si.scfsi[ch][scfsi_band], 1))
336        })?;
337    }
338
339    // Write granule information
340    for gr in 0..config.mpeg.granules_per_frame as usize {
341        for ch in 0..config.wave.channels as usize {
342            let gi = &si.gr[gr].ch[ch].tt;
343
344            config.bs.put_bits(gi.part2_3_length, 12)?;
345            config.bs.put_bits(gi.big_values, 9)?;
346            config.bs.put_bits(gi.global_gain, 8)?;
347
348            if config.mpeg.version == 3 {
349                // MPEG_I = 3
350                config.bs.put_bits(gi.scalefac_compress, 4)?;
351            } else {
352                config.bs.put_bits(gi.scalefac_compress, 9)?;
353            }
354
355            config.bs.put_bits(0, 1)?; // Window switching flag (always 0 for long blocks)
356
357            (0..3).try_for_each(|region| config.bs.put_bits(gi.table_select[region], 5))?;
358
359            config.bs.put_bits(gi.region0_count, 4)?;
360            config.bs.put_bits(gi.region1_count, 3)?;
361
362            if config.mpeg.version == 3 {
363                // MPEG_I = 3
364                config.bs.put_bits(gi.preflag, 1)?;
365            }
366            config.bs.put_bits(gi.scalefac_scale, 1)?;
367            config.bs.put_bits(gi.count1table_select, 1)?;
368        }
369    }
370
371    Ok(())
372}
373
374/// Huffman encode the quantized values (matches Huffmancodebits exactly)
375/// (ref/shine/src/lib/l3bitstream.c:123-165)
376fn huffman_code_bits(
377    config: &mut ShineGlobalConfig,
378    ix: &[i32],
379    gi: &GrInfo,
380) -> EncodingResult<()> {
381    let scalefac = &SHINE_SCALE_FACT_BAND_INDEX[config.mpeg.samplerate_index as usize];
382    let bits_start = config.bs.get_bits_count();
383
384    // 1: Write the bigvalues
385    let bigvalues = (gi.big_values << 1) as usize;
386
387    let scalefac_index = gi.region0_count + 1;
388    let region1_start = scalefac[scalefac_index as usize] as usize;
389    let scalefac_index = scalefac_index + gi.region1_count + 1;
390    let region2_start = scalefac[scalefac_index as usize] as usize;
391
392    let mut i = 0;
393    while i < bigvalues {
394        // Get table pointer
395        let idx = if i >= region1_start { 1 } else { 0 } + if i >= region2_start { 1 } else { 0 };
396        let table_index = gi.table_select[idx];
397
398        // Get huffman code
399        if table_index != 0 {
400            let x = ix[i];
401            let y = ix[i + 1];
402
403            huffman_code(&mut config.bs, table_index as usize, x, y)?;
404        }
405        i += 2;
406    }
407
408    // 2: Write count1 area
409    let h = &SHINE_HUFFMAN_TABLE[(gi.count1table_select + 32) as usize];
410    let count1_end = bigvalues + ((gi.count1 << 2) as usize);
411
412    let mut i = bigvalues;
413    while i < count1_end {
414        let v = ix[i];
415        let w = ix[i + 1];
416        let x = ix[i + 2];
417        let y = ix[i + 3];
418
419        huffman_coder_count1(&mut config.bs, h, v, w, x, y)?;
420        i += 4;
421    }
422
423    // 3: Pad with stuffing bits if necessary
424    let bits_used = config.bs.get_bits_count() - bits_start;
425    let bits_available = gi.part2_3_length as i32 - gi.part2_length as i32;
426    let stuffing_bits = bits_available - bits_used;
427
428    if stuffing_bits > 0 {
429        let stuffing_words = stuffing_bits / 32;
430        let remaining_bits = stuffing_bits % 32;
431
432        // Due to the nature of the Huffman code tables, we will pad with ones
433        for _ in 0..stuffing_words {
434            config.bs.put_bits(0xffffffff, 32)?;
435        }
436        if remaining_bits > 0 {
437            config
438                .bs
439                .put_bits((1u32 << remaining_bits) - 1, remaining_bits)?;
440        }
441    }
442
443    Ok(())
444}
445
446/// Huffman encode count1 region (matches shine_huffman_coder_count1 exactly)
447/// (ref/shine/src/lib/l3bitstream.c:174-200)
448fn huffman_coder_count1(
449    bs: &mut BitstreamWriter,
450    h: &HuffCodeTab,
451    v: i32,
452    w: i32,
453    x: i32,
454    y: i32,
455) -> EncodingResult<()> {
456    let mut v = v;
457    let mut w = w;
458    let mut x = x;
459    let mut y = y;
460
461    let signv = abs_and_sign(&mut v);
462    let signw = abs_and_sign(&mut w);
463    let signx = abs_and_sign(&mut x);
464    let signy = abs_and_sign(&mut y);
465
466    let p = v + (w << 1) + (x << 2) + (y << 3);
467
468    if let (Some(table), Some(hlen)) = (h.hb, h.hlen) {
469        bs.put_bits(table[p as usize] as u32, hlen[p as usize] as i32)?;
470
471        let mut code = 0u32;
472        let mut cbits = 0u32;
473
474        if v != 0 {
475            code = signv;
476            cbits = 1;
477        }
478        if w != 0 {
479            code = (code << 1) | signw;
480            cbits += 1;
481        }
482        if x != 0 {
483            code = (code << 1) | signx;
484            cbits += 1;
485        }
486        if y != 0 {
487            code = (code << 1) | signy;
488            cbits += 1;
489        }
490
491        if cbits > 0 {
492            bs.put_bits(code, cbits as i32)?;
493        }
494    }
495
496    Ok(())
497}
498
499/// Huffman encode a pair of values (matches shine_HuffmanCode exactly)
500/// (ref/shine/src/lib/l3bitstream.c:203-250)
501fn huffman_code(
502    bs: &mut BitstreamWriter,
503    table_select: usize,
504    x: i32,
505    y: i32,
506) -> EncodingResult<()> {
507    let mut x = x;
508    let mut y = y;
509
510    let signx = abs_and_sign(&mut x);
511    let signy = abs_and_sign(&mut y);
512
513    let h = &SHINE_HUFFMAN_TABLE[table_select];
514    let ylen = h.ylen as usize;
515
516    if let (Some(table), Some(hlen)) = (h.hb, h.hlen) {
517        if table_select > 15 {
518            // ESC-table is used
519            let mut linbitsx = 0u32;
520            let mut linbitsy = 0u32;
521            let linbits = h.linbits;
522
523            if x > 14 {
524                linbitsx = (x - 15) as u32;
525                x = 15;
526            }
527            if y > 14 {
528                linbitsy = (y - 15) as u32;
529                y = 15;
530            }
531
532            let idx = (x as usize * ylen) + y as usize;
533            let code = table[idx] as u32;
534            let cbits = hlen[idx] as u32;
535
536            let mut ext = 0u32;
537            let mut xbits = 0u32;
538
539            if x > 14 {
540                ext |= linbitsx;
541                xbits += linbits;
542            }
543            if x != 0 {
544                ext <<= 1;
545                ext |= signx;
546                xbits += 1;
547            }
548            if y > 14 {
549                ext <<= linbits;
550                ext |= linbitsy;
551                xbits += linbits;
552            }
553            if y != 0 {
554                ext <<= 1;
555                ext |= signy;
556                xbits += 1;
557            }
558
559            bs.put_bits(code, cbits as i32)?;
560            if xbits > 0 {
561                bs.put_bits(ext, xbits as i32)?;
562            }
563        } else {
564            // No ESC-words
565            let idx = (x as usize * ylen) + y as usize;
566            let mut code = table[idx] as u32;
567            let mut cbits = hlen[idx] as u32;
568
569            if x != 0 {
570                code <<= 1;
571                code |= signx;
572                cbits += 1;
573            }
574            if y != 0 {
575                code <<= 1;
576                code |= signy;
577                cbits += 1;
578            }
579
580            bs.put_bits(code, cbits as i32)?;
581        }
582    }
583
584    Ok(())
585}
586/// Get absolute value and sign bit (matches shine_abs_and_sign exactly)
587/// (ref/shine/src/lib/l3bitstream.c:167-172)
588#[inline]
589pub fn abs_and_sign(x: &mut i32) -> u32 {
590    if *x > 0 {
591        0
592    } else {
593        *x = -*x;
594        1
595    }
596}