]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::codecs::*; | |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_codec_support::codecs::imaadpcm::*; | |
4 | use std::str::FromStr; | |
5 | ||
6 | struct IMAADPCMDecoder { | |
7 | ainfo: NAAudioInfo, | |
8 | chmap: NAChannelMap, | |
9 | ch_state: [IMAState; 2], | |
10 | block_len: usize, | |
11 | } | |
12 | ||
13 | impl IMAADPCMDecoder { | |
14 | fn new() -> Self { | |
15 | Self { | |
16 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0), | |
17 | chmap: NAChannelMap::new(), | |
18 | ch_state: [IMAState::new(), IMAState::new()], | |
19 | block_len: 0, | |
20 | } | |
21 | } | |
22 | } | |
23 | ||
24 | impl NADecoder for IMAADPCMDecoder { | |
25 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
26 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { | |
27 | self.block_len = ainfo.get_block_len(); | |
28 | let channels = ainfo.get_channels() as usize; | |
29 | validate!(channels == 2 || channels == 1); | |
30 | validate!(self.block_len >= 8 * channels); | |
31 | validate!((self.block_len & 3) == 0); | |
32 | let len = (self.block_len / channels - 4) * 2 + 1; | |
33 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, len); | |
34 | self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap(); | |
35 | Ok(()) | |
36 | } else { | |
37 | Err(DecoderError::InvalidData) | |
38 | } | |
39 | } | |
40 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
41 | let info = pkt.get_stream().get_info(); | |
42 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
43 | let pktbuf = pkt.get_buffer(); | |
44 | let channels = self.chmap.num_channels(); | |
45 | validate!(pktbuf.len() >= 8 * channels); | |
46 | let nsamples = (pktbuf.len() / channels - 4) * 2 + 1; | |
47 | let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?; | |
48 | let mut adata = abuf.get_abuf_i16().unwrap(); | |
49 | let mut off = [adata.get_offset(0), adata.get_offset(1)]; | |
50 | let dst = adata.get_data_mut().unwrap(); | |
51 | ||
52 | let mut mr = MemoryReader::new_read(pktbuf.as_slice()); | |
53 | let mut br = ByteReader::new(&mut mr); | |
54 | for ch in 0..channels { | |
55 | let pred = br.read_u16le()? as i16; | |
56 | let step = br.read_byte()?; | |
57 | br.read_skip(1)?; | |
58 | validate!(step <= IMA_MAX_STEP); | |
59 | self.ch_state[ch].reset(pred, step); | |
60 | dst[off[ch]] = pred; | |
61 | off[ch] += 1; | |
62 | } | |
63 | while br.left() > 0 { | |
64 | for ch in 0..channels { | |
65 | let mut cw = br.read_u32le()?; | |
66 | for _ in 0..8 { | |
67 | dst[off[ch]] = self.ch_state[ch].expand_sample((cw & 0xF) as u8); | |
68 | off[ch] += 1; | |
69 | cw >>= 4; | |
70 | } | |
71 | } | |
72 | } | |
73 | let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf); | |
74 | frm.set_duration(Some(nsamples as u64)); | |
75 | frm.set_keyframe(false); | |
76 | Ok(frm.into_ref()) | |
77 | } else { | |
78 | Err(DecoderError::InvalidData) | |
79 | } | |
80 | } | |
81 | fn flush(&mut self) { | |
82 | } | |
83 | } | |
84 | ||
85 | impl NAOptionHandler for IMAADPCMDecoder { | |
86 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
87 | fn set_options(&mut self, _options: &[NAOption]) { } | |
88 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
89 | } | |
90 | ||
91 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
92 | Box::new(IMAADPCMDecoder::new()) | |
93 | } | |
94 | ||
95 | #[cfg(test)] | |
96 | mod test { | |
97 | use nihav_core::codecs::RegisteredDecoders; | |
98 | use nihav_core::demuxers::RegisteredDemuxers; | |
99 | use nihav_codec_support::test::dec_video::*; | |
100 | use crate::ms_register_all_decoders; | |
101 | use nihav_commonfmt::generic_register_all_demuxers; | |
102 | #[test] | |
103 | fn test_ima_adpcm_ms() { | |
104 | let mut dmx_reg = RegisteredDemuxers::new(); | |
105 | generic_register_all_demuxers(&mut dmx_reg); | |
106 | let mut dec_reg = RegisteredDecoders::new(); | |
107 | ms_register_all_decoders(&mut dec_reg); | |
108 | ||
109 | // sample: https://samples.mplayerhq.hu/A-codecs/ima-adpcm/ima-adpcm-stutter/IMAG0006.AVI | |
110 | test_decoding("avi", "ima-adpcm-ms", "assets/MS/IMAG0006.AVI", None, &dmx_reg, &dec_reg, | |
111 | ExpectedTestResult::MD5([0x0cdc640f, 0xb00df235, 0x1ec4a280, 0x065b5e9e])); | |
112 | } | |
113 | } |