]>
Commit | Line | Data |
---|---|---|
92d9fb69 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::bitreader::*; | |
3 | use nihav_codec_support::codecs::imaadpcm::*; | |
4 | use std::str::FromStr; | |
5 | ||
6 | const STEPS: [&[i8]; 4] = [ | |
7 | &[ -1, 2], | |
8 | &[ -1, -1, 2, 4], | |
9 | &[ -1, -1, -1, -1, 2, 4, 6, 8], | |
10 | &[ -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 ] | |
11 | ]; | |
12 | ||
13 | #[derive(Clone,Copy)] | |
14 | struct State { | |
15 | predictor: i32, | |
16 | step: usize, | |
17 | smask: u8, | |
18 | steps: &'static [i8], | |
19 | } | |
20 | ||
21 | impl State { | |
22 | fn new() -> Self { | |
23 | Self { | |
24 | predictor: 0, | |
25 | step: 0, | |
26 | smask: 0, | |
27 | steps: STEPS[2], | |
28 | } | |
29 | } | |
30 | fn expand_sample(&mut self, nibble: u8) -> i16 { | |
31 | let istep = (self.step as isize) + isize::from(self.steps[(nibble & !self.smask) as usize]); | |
32 | let sign = (nibble & self.smask) != 0; | |
33 | let diff = (i32::from(2 * (nibble & !self.smask) + 1) * IMA_STEP_TABLE[self.step]) >> 3; | |
34 | let sample = if !sign { self.predictor + diff } else { self.predictor - diff }; | |
35 | self.predictor = sample.max(i32::from(std::i16::MIN)).min(i32::from(std::i16::MAX)); | |
36 | self.step = istep.max(0).min(IMA_MAX_STEP as isize) as usize; | |
37 | self.predictor as i16 | |
38 | } | |
39 | } | |
40 | ||
41 | const BLOCK_LEN: usize = 4096; | |
42 | ||
43 | struct ADPCMDecoder { | |
44 | ainfo: NAAudioInfo, | |
45 | chmap: NAChannelMap, | |
46 | ch_state: [State; 2], | |
47 | } | |
48 | ||
49 | impl ADPCMDecoder { | |
50 | fn new() -> Self { | |
51 | Self { | |
52 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, BLOCK_LEN), | |
53 | chmap: NAChannelMap::new(), | |
54 | ch_state: [State::new(), State::new()], | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
59 | impl NADecoder for ADPCMDecoder { | |
60 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
61 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { | |
62 | let channels = ainfo.get_channels() as usize; | |
63 | validate!(channels == 2 || channels == 1); | |
64 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, 0); | |
65 | self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap(); | |
66 | Ok(()) | |
67 | } else { | |
68 | Err(DecoderError::InvalidData) | |
69 | } | |
70 | } | |
71 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
72 | let info = pkt.get_stream().get_info(); | |
73 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
74 | let src = pkt.get_buffer(); | |
75 | let channels = self.chmap.num_channels(); | |
76 | let mut br = BitReader::new(&src, BitReaderMode::BE); | |
77 | let step_size = br.read(2)? as usize + 2; | |
78 | ||
79 | let pkt_size = (16 + 6 + (BLOCK_LEN - 1) * step_size) * channels; | |
80 | let num_pkts = ((br.left() as usize) / pkt_size).max(1); | |
81 | let nsamples = num_pkts * BLOCK_LEN; | |
82 | let mut abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?; | |
83 | let mut adata = abuf.get_abuf_i16().unwrap(); | |
84 | let mut off = [adata.get_offset(0), adata.get_offset(1)]; | |
85 | let dst = adata.get_data_mut().unwrap(); | |
86 | ||
87 | let mut tot_samples = 0; | |
88 | for _pkt in 0..num_pkts { | |
89 | for (ch, state) in self.ch_state[..channels].iter_mut().enumerate() { | |
90 | state.predictor = br.read_s(16)?; | |
91 | state.step = br.read(6)? as usize; | |
92 | state.steps = STEPS[step_size - 2]; | |
93 | state.smask = 1 << (step_size - 1); | |
94 | dst[off[ch]] = state.predictor as i16; | |
95 | off[ch] += 1; | |
96 | } | |
97 | tot_samples += 1; | |
98 | let cur_samples = ((br.left() as usize) / step_size / channels).min(BLOCK_LEN - 1); | |
99 | for _ in 0..cur_samples { | |
100 | for (ch, state) in self.ch_state[..channels].iter_mut().enumerate() { | |
101 | let idx = br.read(step_size as u8)? as u8; | |
102 | dst[off[ch]] = state.expand_sample(idx); | |
103 | off[ch] += 1; | |
104 | } | |
105 | } | |
106 | tot_samples += cur_samples; | |
107 | } | |
108 | abuf.truncate_audio(tot_samples); | |
109 | ||
110 | let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf); | |
111 | frm.set_duration(Some(tot_samples as u64)); | |
112 | frm.set_keyframe(true); | |
113 | Ok(frm.into_ref()) | |
114 | } else { | |
115 | Err(DecoderError::InvalidData) | |
116 | } | |
117 | } | |
118 | fn flush(&mut self) { | |
119 | } | |
120 | } | |
121 | ||
122 | impl NAOptionHandler for ADPCMDecoder { | |
123 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
124 | fn set_options(&mut self, _options: &[NAOption]) { } | |
125 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
126 | } | |
127 | ||
128 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
129 | Box::new(ADPCMDecoder::new()) | |
130 | } | |
131 | ||
132 | #[cfg(test)] | |
133 | mod test { | |
134 | use nihav_core::codecs::RegisteredDecoders; | |
135 | use nihav_core::demuxers::RegisteredDemuxers; | |
136 | use nihav_codec_support::test::dec_video::*; | |
137 | use crate::flash_register_all_decoders; | |
138 | use crate::flash_register_all_demuxers; | |
139 | #[test] | |
140 | fn test_flv_adpcm_mono() { | |
141 | let mut dmx_reg = RegisteredDemuxers::new(); | |
142 | flash_register_all_demuxers(&mut dmx_reg); | |
143 | let mut dec_reg = RegisteredDecoders::new(); | |
144 | flash_register_all_decoders(&mut dec_reg); | |
145 | ||
886cde48 | 146 | // sample: https://samples.mplayerhq.hu/FLV/flash_flv_adpcm_testfiles/mono_11k.flv |
92d9fb69 KS |
147 | test_decoding("flv", "flv-adpcm", "assets/Flash/mono_11k.flv", Some(3000), &dmx_reg, &dec_reg, |
148 | ExpectedTestResult::MD5([0x4cf30e71, 0x4360c85b, 0x21c52863, 0x1782160e])); | |
149 | } | |
150 | #[test] | |
151 | fn test_flv_adpcm_stereo() { | |
152 | let mut dmx_reg = RegisteredDemuxers::new(); | |
153 | flash_register_all_demuxers(&mut dmx_reg); | |
154 | let mut dec_reg = RegisteredDecoders::new(); | |
155 | flash_register_all_decoders(&mut dec_reg); | |
156 | ||
886cde48 | 157 | // sample: https://samples.mplayerhq.hu/FLV/flash_flv_adpcm_testfiles/stereo_44k.flv |
92d9fb69 KS |
158 | test_decoding("flv", "flv-adpcm", "assets/Flash/stereo_44k.flv", Some(3000), &dmx_reg, &dec_reg, |
159 | ExpectedTestResult::MD5([0xae108d38, 0xb36236f8, 0x2bc18d31, 0xac600424])); | |
160 | } | |
161 | } |