diff options
Diffstat (limited to 'remuxer/src/demuxers/flac.rs')
-rw-r--r-- | remuxer/src/demuxers/flac.rs | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/remuxer/src/demuxers/flac.rs b/remuxer/src/demuxers/flac.rs new file mode 100644 index 0000000..04d15e0 --- /dev/null +++ b/remuxer/src/demuxers/flac.rs @@ -0,0 +1,250 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin <metamuffin.org> +*/ + +use crate::demuxers::{Demuxer, DemuxerNew, ReadSeek}; +use anyhow::{Result, anyhow, bail}; +use std::io::{BufReader, Read, Seek, SeekFrom}; +use winter_matroska::{Audio, Cluster, TrackEntry, TrackType, Tracks}; + +pub struct FlacDemuxer { + reader: BufReader<Box<dyn ReadSeek>>, + metadata: Option<Vec<MetadataBlock>>, + first_frame_offset: u64, +} +impl DemuxerNew for FlacDemuxer { + fn new(reader: Box<dyn ReadSeek>) -> Self { + Self { + reader: BufReader::new(reader), + metadata: None, + first_frame_offset: 0, + } + } +} + +struct MetadataBlock { + r#type: u8, + data: Vec<u8>, +} +impl MetadataBlock { + const TY_STREAMINFO: u8 = 0; + const TY_PADDING: u8 = 1; + const TY_APPLICATION: u8 = 2; + const TY_SEEK_TABLE: u8 = 3; + const TY_VORBIS_COMMENT: u8 = 4; + const TY_CUESHEET: u8 = 5; + const TY_PICTURE: u8 = 6; +} + +struct StreamInfo { + min_block_size: u16, + max_block_size: u16, + min_frame_size: u32, + max_frame_size: u32, + sample_rate: u32, + num_channels: u8, + bit_depth: u8, +} +impl StreamInfo { + pub fn parse(d: &[u8; 22]) -> Self { + let k = u64::from_be_bytes([d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17]]); + Self { + min_block_size: u16::from_be_bytes([d[0], d[1]]), + max_block_size: u16::from_be_bytes([d[2], d[3]]), + min_frame_size: u32::from_be_bytes([0, d[4], d[5], d[6]]), + max_frame_size: u32::from_be_bytes([0, d[7], d[8], d[9]]), + sample_rate: (k >> (64 - 20)) as u32, + num_channels: ((k >> (64 - 20 - 3)) & 0b111) as u8 + 1, + bit_depth: ((k >> (64 - 20 - 3 - 5)) & 0b11111) as u8 + 1, + } + } +} + +impl FlacDemuxer { + fn read_metadata(&mut self) -> Result<&Vec<MetadataBlock>> { + if self.metadata.is_some() { + return Ok(self.metadata.as_ref().unwrap()); + } + self.reader.seek(SeekFrom::Start(0))?; + + let mut magic = [0u8; 4]; + self.reader.read_exact(&mut magic)?; + if magic != *b"fLaC" { + bail!("incorrect magic bytes") + } + + let mut blocks = Vec::new(); + loop { + let mut header = [0u8; 4]; + self.reader.read_exact(&mut header)?; + let last = header[0] & 0x80 != 0; + let r#type = header[0] & 0x7f; + let size = u32::from_be_bytes(header) & 0x00FFFFFF; + + let mut data = vec![0u8; size as usize]; + self.reader.read_exact(&mut data)?; + blocks.push(MetadataBlock { r#type, data }); + + if last { + break; + } + } + + self.first_frame_offset = self.reader.stream_position()?; + + self.metadata = Some(blocks); + return Ok(self.metadata.as_ref().unwrap()); + } + fn stream_info(&mut self) -> Result<StreamInfo> { + let m = self.read_metadata()?; + if m[0].r#type == MetadataBlock::TY_STREAMINFO { + Ok(StreamInfo::parse(m[0].data.as_slice().try_into().map_err( + |_| anyhow!("Streaminfo block is not 22 bytes"), + )?)) + } else { + bail!("first metadata block is not Streaminfo") + } + } +} +impl Demuxer for FlacDemuxer { + fn tracks(&mut self) -> Result<Option<Tracks>> { + let si = self.stream_info()?; + let mut buf = Vec::new(); + buf.extend(b"fLaC"); + let meta = self.read_metadata()?; + for (i, mb) in meta.iter().enumerate() { + buf.push(if i == meta.len() - 1 { 0x80 } else { 0 } | mb.r#type); + buf.extend(&u32::to_be_bytes(0)[1..]); + buf.extend(&mb.data); + } + let te = TrackEntry { + codec_id: "A_FLAC".to_string(), + codec_private: Some(buf), + track_number: 1, + track_type: TrackType::Audio, + audio: Some(Audio { + bit_depth: Some(si.bit_depth as u64), + channels: si.num_channels as u64, + sampling_frequency: si.sample_rate as f64, + ..Default::default() + }), + ..Default::default() + }; + Ok(Some(Tracks { entries: vec![te] })) + } + + fn seek_cluster(&mut self, position: Option<u64>) -> Result<()> { + if let Some(position) = position { + self.reader.seek(SeekFrom::Start(position))?; + } else { + if self.first_frame_offset == 0 { + self.read_metadata()?; + } + self.reader.seek(SeekFrom::Start(self.first_frame_offset))?; + } + Ok(()) + } + fn read_cluster(&mut self) -> Result<Option<(u64, Cluster)>> { + let mut header = [0u8; 5]; + self.reader.read_exact(&mut header)?; + + let sync_and_blocking = u16::from_be_bytes([header[0], header[1]]); + let fixed_blocking = match sync_and_blocking { + 0xfff8 => true, + 0xfff9 => false, + _ => bail!("invalid frame sync code"), + }; + + let block_size_bits = header[2] >> 4; + let sample_rate_bits = header[2] & 0x0f; + + let channel_count = match header[3] >> 4 { + x @ 0..8 => x + 1, + 8..11 => 2, + _ => bail!("reserved channel bits used"), + }; + let bit_depth = match (header[3] >> 1) & 0b111 { + 0b000 => 0, // TODO streaminfo + 0b001 => 8, + 0b010 => 12, + 0b011 => bail!("reserved bit depth used"), + 0b100 => 16, + 0b101 => 20, + 0b110 => 24, + 0b111 => 32, + _ => unreachable!(), + }; + if header[3] & 1 != 0 { + bail!("reserveed bit set") + } + + let coded_num_length = match header[4].leading_ones() { + 0 => 0, + 1 => bail!("invalid coded number vint length (loc=1)"), + x @ 2..8 => x - 1, + 8 => bail!("invalid coded number vint length (loc=8)"), + _ => unreachable!(), + }; + let mut coded_num_buf = [0u8; 6]; + self.reader.read_exact(&mut coded_num_buf)?; + + let block_size = match block_size_bits { + 0b0000 => bail!("reserved block size used"), + 0b0001 => 192, + x @ 0b0010..=0b0101 => 144 * 2u32.pow(x as u32), + 0b0110 => { + let mut buf = [0u8; 1]; + self.reader.read_exact(&mut buf)?; + buf[0] as u32 + 1 + } + 0b0111 => { + let mut buf = [0u8; 2]; + self.reader.read_exact(&mut buf)?; + u16::from_be_bytes(buf) as u32 + 1 + } + x @ 0b1000..=0b1111 => 2u32.pow(x as u32), + _ => unreachable!(), + }; + + let sample_rate = match sample_rate_bits { + 0b0000 => 0, // TODO streaminfo, + 0b0001 => 88200, + 0b0010 => 176400, + 0b0011 => 192000, + 0b0100 => 8000, + 0b0101 => 16000, + 0b0110 => 22050, + 0b0111 => 24000, + 0b1000 => 32000, + 0b1001 => 44100, + 0b1010 => 48000, + 0b1011 => 96000, + 0b1100 => { + let mut buf = [0u8; 1]; + self.reader.read_exact(&mut buf)?; + buf[0] as u32 * 1000 + } + 0b1101 => { + let mut buf = [0u8; 2]; + self.reader.read_exact(&mut buf)?; + u16::from_be_bytes(buf) as u32 + } + 0b1110 => { + let mut buf = [0u8; 2]; + self.reader.read_exact(&mut buf)?; + u16::from_be_bytes(buf) as u32 * 10 + } + 0b1111 => bail!("forbidden sample rate bits used"), + _ => unreachable!(), + }; + + let mut crc_buf = [0u8; 1]; + self.reader.read_exact(&mut crc_buf)?; + + + + Ok(None) + } +} |