]>
Commit | Line | Data |
---|---|---|
2cd9d8a6 KS |
1 | use nihav_core::frame::*; |
2 | use nihav_core::demuxers::*; | |
3 | ||
4 | struct FLACDemuxer<'a> { | |
5 | src: &'a mut ByteReader<'a>, | |
6 | data_start: u64, | |
7 | tot_samples: u64, | |
8 | cur_samples: u64, | |
9 | blk_samples: u16, | |
10 | min_samples: u16, | |
11 | min_size: usize, | |
12 | max_size: usize, | |
13 | srate: u32, | |
14 | build_index: bool, | |
15 | } | |
16 | ||
17 | impl<'a> FLACDemuxer<'a> { | |
18 | fn new(io: &'a mut ByteReader<'a>) -> Self { | |
19 | Self { | |
20 | src: io, | |
21 | data_start: 0, | |
22 | tot_samples: 0, | |
23 | cur_samples: 0, | |
24 | blk_samples: 0, | |
25 | min_samples: 0, | |
26 | min_size: 0, | |
27 | max_size: 0, | |
28 | srate: 0, | |
29 | build_index: false, | |
30 | } | |
31 | } | |
32 | } | |
33 | ||
34 | impl<'a> RawDemuxCore<'a> for FLACDemuxer<'a> { | |
35 | fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { | |
36 | let tag = self.src.read_tag()?; | |
37 | validate!(&tag == b"fLaC"); | |
38 | let mut streaminfo: Vec<u8> = Vec::new(); | |
39 | let mut srate = 0u32; | |
40 | let mut channels = 0u8; | |
41 | loop { | |
42 | let id1 = self.src.read_byte()?; | |
43 | let len = self.src.read_u24be()? as usize; | |
44 | let id = id1 & 0x7F; | |
45 | ||
46 | match id { | |
47 | 0x00 => { | |
48 | validate!(len >= 34); | |
49 | streaminfo = vec![0u8; len]; | |
50 | self.src.read_buf(&mut streaminfo)?; | |
51 | let min_bs = read_u16be(&streaminfo[0..])?; | |
52 | let max_bs = read_u16be(&streaminfo[2..])?; | |
53 | if min_bs == max_bs { | |
54 | self.blk_samples = max_bs; | |
55 | } | |
56 | self.min_samples = min_bs; | |
57 | self.min_size = read_u24be(&streaminfo[4..])? as usize; | |
58 | self.max_size = read_u24be(&streaminfo[7..])? as usize; | |
59 | let word = read_u24be(&streaminfo[10..])?; | |
60 | srate = word >> 4; | |
61 | channels = (((word >> 1) & 7) + 1) as u8; | |
62 | self.tot_samples = (u64::from(streaminfo[13] & 0xF) << 32) | u64::from(read_u32be(&streaminfo[14..])?); | |
63 | }, | |
64 | 0x03 => { | |
65 | validate!((len % 18) == 0); | |
66 | seek_index.mode = SeekIndexMode::Present; | |
67 | for _ in 0..len / 18 { | |
68 | let sample = self.src.read_u64be()?; | |
69 | let offset = self.src.read_u64be()?; | |
70 | let _nsamps = self.src.read_u16be()?; | |
71 | let time = sample * 1000 / u64::from(srate.max(1000)); | |
72 | seek_index.add_entry(0, SeekEntry { time, pts: sample, pos: offset }); | |
73 | } | |
74 | }, | |
75 | _ => self.src.read_skip(len)?, | |
76 | }; | |
77 | ||
78 | if (id1 & 0x80) != 0 { | |
79 | break; | |
80 | } | |
81 | } | |
82 | if seek_index.mode != SeekIndexMode::Present { | |
83 | seek_index.mode = SeekIndexMode::Automatic; | |
84 | self.build_index = true; | |
85 | } else { | |
86 | self.build_index = false; | |
87 | } | |
88 | self.data_start = self.src.tell(); | |
89 | validate!(srate != 0); | |
90 | self.srate = srate; | |
91 | ||
92 | let base = if self.blk_samples != 0 { u32::from(self.blk_samples) } else { 1 }; | |
e6aaad5c | 93 | let ahdr = NAAudioInfo::new(srate, channels, SND_S16P_FORMAT, base as usize); |
2cd9d8a6 KS |
94 | let ainfo = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ahdr), Some(streaminfo)); |
95 | strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate, 0)).unwrap(); | |
96 | ||
97 | Ok(()) | |
98 | } | |
99 | fn get_data(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NARawData> { | |
100 | let stream = strmgr.get_stream(0).unwrap(); | |
101 | let mut buf = vec![0; 8192]; | |
102 | let size = self.src.read_buf_some(&mut buf)?; | |
103 | buf.truncate(size); | |
104 | Ok(NARawData::new(stream, buf)) | |
105 | } | |
106 | fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> { | |
107 | if seek_index.mode == SeekIndexMode::Present { | |
108 | let ret = seek_index.find_pos(time); | |
109 | if ret.is_none() { | |
110 | return Err(DemuxerError::SeekError); | |
111 | } | |
112 | let seek_info = ret.unwrap(); | |
113 | self.cur_samples = seek_info.pts; | |
114 | self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?; | |
115 | Ok(()) | |
116 | } else { | |
117 | Err(DemuxerError::NotPossible) | |
118 | } | |
119 | } | |
120 | fn get_duration(&self) -> u64 { self.tot_samples * 1000 / u64::from(self.srate) } | |
121 | } | |
122 | ||
123 | impl<'a> NAOptionHandler for FLACDemuxer<'a> { | |
124 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
125 | fn set_options(&mut self, _options: &[NAOption]) { } | |
126 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
127 | } | |
128 | ||
129 | pub struct FLACDemuxerCreator { } | |
130 | ||
131 | impl RawDemuxerCreator for FLACDemuxerCreator { | |
132 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn RawDemuxCore<'a> + 'a> { | |
133 | Box::new(FLACDemuxer::new(br)) | |
134 | } | |
135 | fn get_name(&self) -> &'static str { "flac" } | |
136 | fn check_format(&self, br: &mut ByteReader) -> bool { | |
137 | if br.seek(SeekFrom::Start(0)).is_err() { | |
138 | return false; | |
139 | } | |
6f263099 | 140 | matches!(br.read_tag(), Ok([b'f', b'L', b'a', b'C'])) |
2cd9d8a6 KS |
141 | } |
142 | } | |
143 | ||
144 | #[cfg(test)] | |
145 | mod test { | |
146 | use nihav_core::codecs::*; | |
147 | use super::*; | |
148 | use crate::llaudio_register_all_packetisers; | |
149 | use std::fs::File; | |
150 | ||
151 | #[test] | |
152 | fn test_flac_raw_demux() { | |
886cde48 | 153 | // sample: https://samples.mplayerhq.hu/A-codecs/lossless/luckynight.flac |
2cd9d8a6 KS |
154 | let mut file = File::open("assets/LLaudio/luckynight.flac").unwrap(); |
155 | let mut fr = FileReader::new_read(&mut file); | |
156 | let mut br = ByteReader::new(&mut fr); | |
157 | let mut dmx = FLACDemuxer::new(&mut br); | |
158 | let mut sm = StreamManager::new(); | |
159 | let mut si = SeekIndex::new(); | |
160 | dmx.open(&mut sm, &mut si).unwrap(); | |
161 | let stream = sm.get_stream(0).unwrap(); | |
162 | let mut pkt_reg = RegisteredPacketisers::new(); | |
163 | llaudio_register_all_packetisers(&mut pkt_reg); | |
164 | let creator = pkt_reg.find_packetiser("flac").unwrap(); | |
165 | let mut pkts = (creator)(); | |
166 | let mut tot_size = 0; | |
167 | while let Ok(pkt) = dmx.get_data(&mut sm) { | |
168 | tot_size += pkt.get_buffer().len(); | |
169 | pkts.add_data(&pkt.get_buffer()); | |
170 | } | |
171 | let mut tot_size2 = 0; | |
172 | let mut npkts = 0; | |
173 | while let Ok(Some(pkt)) = pkts.get_packet(stream.clone()) { | |
174 | tot_size2 += pkt.get_buffer().len(); | |
175 | npkts += 1; | |
176 | } | |
177 | assert_eq!(npkts, 579); | |
178 | assert_eq!(tot_size, tot_size2); | |
179 | } | |
180 | } |