]> git.nihav.org Git - nihav.git/commitdiff
add FLAC packetiser and raw stream demuxer
authorKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 16 Nov 2021 17:20:40 +0000 (18:20 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 16 Nov 2021 17:20:40 +0000 (18:20 +0100)
nihav-allstuff/src/lib.rs
nihav-llaudio/src/codecs/flac.rs
nihav-llaudio/src/codecs/mod.rs
nihav-llaudio/src/demuxers/flacraw.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/mod.rs
nihav-llaudio/src/lib.rs

index f48deeee1fbe26787f433884255a15a2a7bf60c1..233238a9836e418b342292ba75681c45f1a8a01b 100644 (file)
@@ -16,6 +16,7 @@ use nihav_core::codecs::RegisteredDecoders;
 use nihav_core::codecs::RegisteredPacketisers;
 use nihav_core::codecs::RegisteredEncoders;
 use nihav_core::demuxers::RegisteredDemuxers;
+use nihav_core::demuxers::RegisteredRawDemuxers;
 use nihav_core::muxers::RegisteredMuxers;
 
 use nihav_commonfmt::*;
@@ -51,6 +52,7 @@ pub fn nihav_register_all_decoders(rd: &mut RegisteredDecoders) {
 
 /// Registers all known packetisers.
 pub fn nihav_register_all_packetisers(rp: &mut RegisteredPacketisers) {
+    llaudio_register_all_packetisers(rp);
     mpeg_register_all_packetisers(rp);
 }
 
@@ -66,6 +68,11 @@ pub fn nihav_register_all_demuxers(rd: &mut RegisteredDemuxers) {
     vivo_register_all_demuxers(rd);
 }
 
+/// Registers all known raw stream demuxers.
+pub fn nihav_register_all_raw_demuxers(rd: &mut RegisteredRawDemuxers) {
+    llaudio_register_all_raw_demuxers(rd);
+}
+
 /// Registers all known encoders.
 pub fn nihav_register_all_encoders(re: &mut RegisteredEncoders) {
     flash_register_all_encoders(re);
index 0ca80aab48bcb1d0ca3a12ccf05b60110e657a20..a3145ac4e732ae95011ca7eb89e55d5962112808 100644 (file)
@@ -429,10 +429,209 @@ pub fn get_decoder() -> Box<dyn NADecoder + Send> {
     Box::new(FlacDecoder::new())
 }
 
+#[derive(Clone,Copy,Default)]
+struct FrameHeader {
+    blocksize:      u32,
+    srate:          u32,
+    channels:       u8,
+    bits:           u8,
+    time:           u64,
+    blk_strat:      bool,
+}
+
+#[derive(Default)]
+struct FLACPacketiser {
+    hdr:        FrameHeader,
+    buf:        Vec<u8>,
+    ref_crc:    u16,
+    cur_crc:    u16,
+    end:        usize,
+    hdr_ok:     bool,
+}
+
+fn read_utf8(br: &mut BitReader) -> DecoderResult<u64> {
+    let byte                    = br.read(8)? as u8;
+    let len = (!byte).leading_zeros();
+    if (len == 1) || (len > 5) {
+        return Err(DecoderError::InvalidData);
+    }
+    if len > 1 {
+        let mut val = u64::from(byte << len >> len);
+        for _ in 1..len {
+            let byte            = br.read(8)?;
+            if (byte & 0xC0) != 0x80 {
+                return Err(DecoderError::InvalidData);
+            }
+            val = (val << 6) | u64::from(byte & 0x3F);
+        }
+        Ok(val)
+    } else {
+        Ok(u64::from(byte))
+    }
+}
+
+impl FLACPacketiser {
+    fn new() -> Self { Self::default() }
+    fn parse_header(&self) -> DecoderResult<FrameHeader> {
+        if self.buf.len() < 5 {
+            return Err(DecoderError::ShortData);
+        }
+        let mut br = BitReader::new(&self.buf, BitReaderMode::BE);
+        let sync_code                   = br.read(14)?;
+        if sync_code != 0x3FFE {
+            return Err(DecoderError::InvalidData);
+        }
+        let marker                      = br.read(1)?;
+        if marker != 0 {
+            return Err(DecoderError::InvalidData);
+        }
+        let blk_strat                   = br.read_bool()?;
+        let bsize                       = br.read(4)?;
+        let srate_idx                   = br.read(4)? as u8;
+        let chan_idx                    = br.read(4)? as u8;
+        let bits = match br.read(3)? {
+                0 => 0,
+                1 => 8,
+                2 => 12,
+                4 => 16,
+                5 => 20,
+                6 => 24,
+                _ => return Err(DecoderError::InvalidData),
+            };
+        let marker                      = br.read(1)?;
+        if marker != 0 {
+            return Err(DecoderError::InvalidData);
+        }
+
+        let time = read_utf8(&mut br)?;
+
+        let blocksize = match bsize {
+                1 => 192,
+                2..=5 => 576 << (bsize - 2),
+                6 => br.read(8)? + 1,
+                7 => br.read(16)? + 1,
+                8..=15 => 256 << (bsize - 8),
+                _ => return Err(DecoderError::InvalidData),
+            };
+        let srate = match srate_idx {
+                0 => 0,
+                1 => 88200,
+                2 => 176400,
+                3 => 192000,
+                4 => 8000,
+                5 => 16000,
+                6 => 22050,
+                7 => 24000,
+                8 => 32000,
+                9 => 44100,
+                10 => 48000,
+                11 => 96000,
+                12 => br.read(8)? * 1000,
+                13 => br.read(16)?,
+                14 => br.read(16)? * 10,
+                _ => return Err(DecoderError::InvalidData),
+            };
+        let channels = match chan_idx {
+                0..=7 => chan_idx + 1,
+                8 | 9 | 10 => 2,
+                _ => return Err(DecoderError::InvalidData),
+            };
+
+        let hdr_size = br.tell() / 8;
+        let ref_crc                     = br.read(8)? as u8;
+        let mut crc = 0;
+        for &b in self.buf[..hdr_size].iter() {
+            crc = update_crc8(crc, b);
+        }
+        if crc != ref_crc {
+            return Err(DecoderError::ChecksumError);
+        }
+
+        Ok(FrameHeader{ blk_strat, time, srate, channels, bits, blocksize })
+    }
+}
+
+impl NAPacketiser for FLACPacketiser {
+    fn add_data(&mut self, src: &[u8]) -> bool {
+        self.buf.extend_from_slice(src);
+        self.buf.len() < 4096
+    }
+    fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
+        let hdr = self.parse_header()?;
+        let ainfo = NAAudioInfo::new(hdr.srate, hdr.channels, if hdr.bits <= 16 { SND_S16P_FORMAT } else { SND_S32P_FORMAT }, hdr.blocksize as usize);
+        let info = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ainfo), None);
+        Ok(NAStream::new(StreamType::Audio, id, info, 1, hdr.srate, 0).into_ref())
+    }
+    fn skip_junk(&mut self) -> DecoderResult<usize> {
+        Err(DecoderError::NotImplemented)
+    }
+    fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
+        if self.end == self.buf.len() || self.buf.len() < 5 {
+            return Err(DecoderError::ShortData);
+        }
+        if !self.hdr_ok {
+            self.hdr = self.parse_header()?;
+            self.hdr_ok = true;
+            self.cur_crc = 0;
+            for i in 0..5 {
+                self.cur_crc = update_crc16(self.cur_crc, self.buf[i]);
+            }
+            self.end = 5;
+        }
+        while self.end < self.buf.len() {
+            let b = self.buf[self.end];
+            self.end += 1;
+            match self.end {
+                0..=5 => unreachable!(),
+                6 => self.ref_crc = u16::from(b),
+                7 => self.ref_crc = (self.ref_crc << 8) | u16::from(b),
+                _ => {
+                    let bbb = (self.ref_crc >> 8) as u8;
+                    self.ref_crc = (self.ref_crc << 8) | u16::from(b);
+                    self.cur_crc = update_crc16(self.cur_crc, bbb);
+                    let mut found = self.ref_crc == self.cur_crc;
+                    if self.end + 2 < self.buf.len() {
+                        let b1 = self.buf[self.end];
+                        let b2 = self.buf[self.end + 1];
+                        if b1 != 0xFF || (b2 & 0xFC) != 0xF8 {
+                            found = false;
+                        }
+                    }
+                    if found {
+                        let mut data = Vec::with_capacity(self.end);
+                        data.extend_from_slice(&self.buf[..self.end]);
+                        self.buf.drain(..self.end);
+                        let mut ts = NATimeInfo::new(None, None, Some(u64::from(self.hdr.blocksize)), 1, self.hdr.srate);
+                        ts.pts = if self.hdr.blk_strat {
+                                Some(self.hdr.time)
+                            } else {
+                                Some(self.hdr.time * u64::from(self.hdr.blocksize))
+                            };
+                        self.end = 0;
+                        self.hdr_ok = false;
+
+                        return Ok(Some(NAPacket::new(stream, ts, true, data)));
+                    }
+                },
+            }
+        }
+        Ok(None)
+    }
+    fn reset(&mut self) {
+        self.buf.clear();
+        self.end = 0;
+        self.hdr_ok = false;
+    }
+}
+
+pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
+    Box::new(FLACPacketiser::new())
+}
+
 #[cfg(test)]
 mod test {
-    use nihav_core::codecs::RegisteredDecoders;
-    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_core::codecs::*;
+    use nihav_core::demuxers::*;
     use nihav_codec_support::test::dec_video::*;
     use crate::llaudio_register_all_decoders;
     use crate::llaudio_register_all_demuxers;
@@ -446,6 +645,90 @@ mod test {
         test_decoding("flac", "flac", "assets/LLaudio/luckynight.flac", Some(6), &dmx_reg, &dec_reg,
                       ExpectedTestResult::MD5([0xe689787a, 0x032a98f7, 0xeb6e64f4, 0xfa652132]));
     }
+    use std::io::{Read, Seek, SeekFrom};
+    #[test]
+    fn test_flac_packetiser() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let dmx_f = dmx_reg.find_demuxer("flac").unwrap();
+        let mut file = std::fs::File::open("assets/LLaudio/luckynight.flac").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
+
+        let mut pkt_sizes = Vec::new();
+        while let Ok(pkt) = dmx.get_frame() {
+            pkt_sizes.push(pkt.get_buffer().len());
+        }
+
+        let mut file = std::fs::File::open("assets/LLaudio/luckynight.flac").unwrap();
+        file.seek(SeekFrom::Start(0x115E)).unwrap();
+
+        let mut pkts = super::FLACPacketiser::new();
+        let mut buf = [0; 8192];
+        for _ in 0..16 {
+            file.read_exact(&mut buf).unwrap();
+            pkts.add_data(&buf);
+        }
+        let stream = pkts.parse_stream(0).unwrap();
+        let mut pkt_sizes2 = Vec::new();
+        let mut piter = pkt_sizes.iter();
+        loop {
+            let res = pkts.get_packet(stream.clone());
+            match res {
+                Ok(Some(pkt)) => {
+                    assert_eq!(*piter.next().unwrap(), pkt.get_buffer().len());
+                    pkt_sizes2.push(pkt.get_buffer().len());
+                    continue;
+                },
+                Ok(None) | Err(DecoderError::ShortData) => {},
+                Err(err) => {
+                    println!("error {:?}", err);
+                    panic!("packetising error");
+                },
+            };
+            let ret = file.read(&mut buf);
+            match ret {
+                Ok(0) => {
+                    let res = pkts.get_packet(stream.clone());
+                    match res {
+                        Ok(Some(pkt)) => {
+                            assert_eq!(*piter.next().unwrap(), pkt.get_buffer().len());
+                            pkt_sizes2.push(pkt.get_buffer().len());
+                            continue;
+                        },
+                        Ok(None) | Err(DecoderError::ShortData) => break,
+                        Err(err) => {
+                            println!("error {:?}", err);
+                            panic!("packetising error");
+                        },
+                    };
+                },
+                Ok(size) => pkts.add_data(&buf[..size]),
+                Err(err) => {
+                    if err.kind() == std::io::ErrorKind::UnexpectedEof {
+                        let res = pkts.get_packet(stream.clone());
+                        match res {
+                            Ok(Some(pkt)) => {
+                                assert_eq!(*piter.next().unwrap(), pkt.get_buffer().len());
+                                pkt_sizes2.push(pkt.get_buffer().len());
+                                continue;
+                            },
+                            Ok(None) | Err(DecoderError::ShortData) => break,
+                            Err(err) => {
+                                println!("error {:?}", err);
+                                panic!("packetising error");
+                            },
+                        };
+                    } else {
+                        println!(" {:?}", err.kind());
+                        panic!("i/o error!");
+                    }
+                },
+            };
+        }
+        assert_eq!(pkt_sizes.len(), pkt_sizes2.len());
+    }
 }
 
 fn update_crc8(crc: u8, byte: u8) -> u8 {
index ed253c88d707387dcec3858aa4117f608c3632ad..a0e92bb320e528d1ae1cd04b61127ce393b1f91e 100644 (file)
@@ -38,6 +38,18 @@ pub fn llaudio_register_all_decoders(rd: &mut RegisteredDecoders) {
     }
 }
 
+const LL_PACKETISERS: &[PacketiserInfo] = &[
+#[cfg(feature="decoder_flac")]
+    PacketiserInfo { name: "flac", get_packetiser: flac::get_packetiser },
+];
+
+/// Registers all available packetisers provided by this crate.
+pub fn llaudio_register_all_packetisers(rp: &mut RegisteredPacketisers) {
+    for pkt in LL_PACKETISERS.iter() {
+        rp.add_packetiser(*pkt);
+    }
+}
+
 #[cfg(feature="encoder_flac")]
 pub mod flacenc;
 
diff --git a/nihav-llaudio/src/demuxers/flacraw.rs b/nihav-llaudio/src/demuxers/flacraw.rs
new file mode 100644 (file)
index 0000000..d86d14e
--- /dev/null
@@ -0,0 +1,183 @@
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+struct FLACDemuxer<'a> {
+    src:            &'a mut ByteReader<'a>,
+    data_start:     u64,
+    tot_samples:    u64,
+    cur_samples:    u64,
+    blk_samples:    u16,
+    min_samples:    u16,
+    min_size:       usize,
+    max_size:       usize,
+    srate:          u32,
+    build_index:    bool,
+}
+
+impl<'a> FLACDemuxer<'a> {
+    fn new(io: &'a mut ByteReader<'a>) -> Self {
+        Self {
+            src:            io,
+            data_start:     0,
+            tot_samples:    0,
+            cur_samples:    0,
+            blk_samples:    0,
+            min_samples:    0,
+            min_size:       0,
+            max_size:       0,
+            srate:          0,
+            build_index:    false,
+        }
+    }
+}
+
+impl<'a> RawDemuxCore<'a> for FLACDemuxer<'a> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+        let tag                         = self.src.read_tag()?;
+        validate!(&tag == b"fLaC");
+        let mut streaminfo: Vec<u8> = Vec::new();
+        let mut srate = 0u32;
+        let mut channels = 0u8;
+        loop {
+            let id1                     = self.src.read_byte()?;
+            let len                     = self.src.read_u24be()? as usize;
+            let id = id1 & 0x7F;
+
+            match id {
+                0x00 => {
+                    validate!(len >= 34);
+                    streaminfo = vec![0u8; len];
+                                          self.src.read_buf(&mut streaminfo)?;
+                    let min_bs          = read_u16be(&streaminfo[0..])?;
+                    let max_bs          = read_u16be(&streaminfo[2..])?;
+                    if min_bs == max_bs {
+                        self.blk_samples = max_bs;
+                    }
+                    self.min_samples = min_bs;
+                    self.min_size       = read_u24be(&streaminfo[4..])? as usize;
+                    self.max_size       = read_u24be(&streaminfo[7..])? as usize;
+                    let word            = read_u24be(&streaminfo[10..])?;
+                    srate = word >> 4;
+                    channels = (((word >> 1) & 7) + 1) as u8;
+                    self.tot_samples    = (u64::from(streaminfo[13] & 0xF) << 32) | u64::from(read_u32be(&streaminfo[14..])?);
+                },
+                0x03 => {
+                    validate!((len % 18) == 0);
+                    seek_index.mode = SeekIndexMode::Present;
+                    for _ in 0..len / 18 {
+                        let sample      = self.src.read_u64be()?;
+                        let offset      = self.src.read_u64be()?;
+                        let _nsamps     = self.src.read_u16be()?;
+                        let time = sample * 1000 / u64::from(srate.max(1000));
+                        seek_index.add_entry(0, SeekEntry { time, pts: sample, pos: offset });
+                    }
+                },
+                _ =>                      self.src.read_skip(len)?,
+            };
+
+            if (id1 & 0x80) != 0 {
+                break;
+            }
+        }
+        if seek_index.mode != SeekIndexMode::Present {
+            seek_index.mode = SeekIndexMode::Automatic;
+            self.build_index = true;
+        } else {
+            self.build_index = false;
+        }
+        self.data_start = self.src.tell();
+        validate!(srate != 0);
+        self.srate = srate;
+
+        let base = if self.blk_samples != 0 { u32::from(self.blk_samples) } else { 1 };
+        let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, base as usize);
+        let ainfo = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ahdr), Some(streaminfo));
+        strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate, 0)).unwrap();
+
+        Ok(())
+    }
+    fn get_data(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NARawData> {
+        let stream = strmgr.get_stream(0).unwrap();
+        let mut buf = vec![0; 8192];
+        let size = self.src.read_buf_some(&mut buf)?;
+        buf.truncate(size);
+        Ok(NARawData::new(stream, buf))
+    }
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        if seek_index.mode == SeekIndexMode::Present {
+            let ret = seek_index.find_pos(time);
+            if ret.is_none() {
+                return Err(DemuxerError::SeekError);
+            }
+            let seek_info = ret.unwrap();
+            self.cur_samples = seek_info.pts;
+            self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?;
+            Ok(())
+        } else {
+            Err(DemuxerError::NotPossible)
+        }
+    }
+    fn get_duration(&self) -> u64 { self.tot_samples * 1000 / u64::from(self.srate) }
+}
+
+impl<'a> NAOptionHandler for FLACDemuxer<'a> {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct FLACDemuxerCreator { }
+
+impl RawDemuxerCreator for FLACDemuxerCreator {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn RawDemuxCore<'a> + 'a> {
+        Box::new(FLACDemuxer::new(br))
+    }
+    fn get_name(&self) -> &'static str { "flac" }
+    fn check_format(&self, br: &mut ByteReader) -> bool {
+        if br.seek(SeekFrom::Start(0)).is_err() {
+            return false;
+        }
+        if let Ok([b'f', b'L', b'a', b'C']) = br.read_tag() {
+            true
+        } else {
+            false
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::*;
+    use super::*;
+    use crate::llaudio_register_all_packetisers;
+    use std::fs::File;
+
+    #[test]
+    fn test_flac_raw_demux() {
+        let mut file = File::open("assets/LLaudio/luckynight.flac").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = FLACDemuxer::new(&mut br);
+        let mut sm = StreamManager::new();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
+        let stream = sm.get_stream(0).unwrap();
+        let mut pkt_reg = RegisteredPacketisers::new();
+        llaudio_register_all_packetisers(&mut pkt_reg);
+        let creator = pkt_reg.find_packetiser("flac").unwrap();
+        let mut pkts = (creator)();
+        let mut tot_size = 0;
+        while let Ok(pkt) = dmx.get_data(&mut sm) {
+            tot_size += pkt.get_buffer().len();
+            pkts.add_data(&pkt.get_buffer());
+        }
+        let mut tot_size2 = 0;
+        let mut npkts = 0;
+        while let Ok(Some(pkt)) = pkts.get_packet(stream.clone()) {
+            tot_size2 += pkt.get_buffer().len();
+            npkts += 1;
+        }
+        assert_eq!(npkts, 579);
+        assert_eq!(tot_size, tot_size2);
+    }
+}
index d1d38a203dff62268389f83eed3e781b91127050..41dd9fd5c25e008706f63fbc8cf17501f0d9b5e7 100644 (file)
@@ -9,6 +9,8 @@ macro_rules! validate {
 mod ape;
 #[cfg(feature="demuxer_flac")]
 mod flac;
+#[cfg(feature="demuxer_flac")]
+mod flacraw;
 #[cfg(feature="demuxer_tta")]
 mod tta;
 #[cfg(feature="demuxer_wavpack")]
@@ -31,3 +33,15 @@ pub fn llaudio_register_all_demuxers(rd: &mut RegisteredDemuxers) {
         rd.add_demuxer(*demuxer);
     }
 }
+
+const LL_RAW_AUDIO_DEMUXERS: &[&dyn RawDemuxerCreator] = &[
+#[cfg(feature="demuxer_flac")]
+    &flacraw::FLACDemuxerCreator {},
+];
+
+/// Registers all available raw stream demuxers provided by this crate.
+pub fn llaudio_register_all_raw_demuxers(rd: &mut RegisteredRawDemuxers) {
+    for demuxer in LL_RAW_AUDIO_DEMUXERS.iter() {
+        rd.add_demuxer(*demuxer);
+    }
+}
index 710a22e36d3fed4b911ccc00f76d73651ac2a4fb..d7a2633d04fb7990432f58be1dc70489d8a3c082 100644 (file)
@@ -11,5 +11,7 @@ mod demuxers;
 mod muxers;
 pub use crate::codecs::llaudio_register_all_decoders;
 pub use crate::demuxers::llaudio_register_all_demuxers;
+pub use crate::codecs::llaudio_register_all_packetisers;
+pub use crate::demuxers::llaudio_register_all_raw_demuxers;
 pub use crate::codecs::llaudio_register_all_encoders;
 pub use crate::muxers::llaudio_register_all_muxers;