Flash support
[nihav.git] / nihav-flash / src / codecs / adpcm.rs
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
146 test_decoding("flv", "flv-adpcm", "assets/Flash/mono_11k.flv", Some(3000), &dmx_reg, &dec_reg,
147 ExpectedTestResult::MD5([0x4cf30e71, 0x4360c85b, 0x21c52863, 0x1782160e]));
148 }
149 #[test]
150 fn test_flv_adpcm_stereo() {
151 let mut dmx_reg = RegisteredDemuxers::new();
152 flash_register_all_demuxers(&mut dmx_reg);
153 let mut dec_reg = RegisteredDecoders::new();
154 flash_register_all_decoders(&mut dec_reg);
155
156 test_decoding("flv", "flv-adpcm", "assets/Flash/stereo_44k.flv", Some(3000), &dmx_reg, &dec_reg,
157 ExpectedTestResult::MD5([0xae108d38, 0xb36236f8, 0x2bc18d31, 0xac600424]));
158 }
159 }