introduce a way for encoder to manifest its capabilities
[nihav.git] / nihav-flash / src / codecs / adpcmenc.rs
CommitLineData
92d9fb69
KS
1use nihav_core::codecs::*;
2use nihav_core::io::bitwriter::*;
3use nihav_codec_support::codecs::imaadpcm::*;
4
5#[derive(Default)]
6struct ADPCMEncoder {
7 stream: Option<NAStreamRef>,
8 samples: Vec<i16>,
9 flush: bool,
10 state: [IMAState; 2],
11 channels: usize,
12 srate: u32,
13 pos: u64,
14}
15
16const BLOCK_LEN: usize = 4096;
17
18impl ADPCMEncoder {
19 fn new() -> Self { Self::default() }
20 fn encode_packet(&mut self) -> EncoderResult<NAPacket> {
21 if self.samples.is_empty() {
22 return Err(EncoderError::TryAgain);
23 }
24 let cur_len = (self.samples.len() / self.channels).min(BLOCK_LEN);
25 if cur_len < BLOCK_LEN && !self.flush {
26 return Err(EncoderError::TryAgain);
27 }
28
29 let bsize = (2 + (16 + 6 + (cur_len - 1) * 4) * self.channels + 7) / 8;
30
31 let mut bw = BitWriter::new(Vec::with_capacity(bsize), BitWriterMode::BE);
32
33 bw.write(2, 2);
34
35 for ch in 0..self.channels {
36 self.state[ch].predictor = i32::from(self.samples[ch]);
37 self.state[ch].step = 30;
38
39 bw.write_s(i32::from(self.samples[ch]), 16);
40 bw.write(self.state[ch].step as u32, 6);
41 }
42
43 let mut siter = self.samples[self.channels..].iter();
44 for _ in 1..cur_len {
45 for state in self.state[..self.channels].iter_mut() {
46 let samp = *siter.next().unwrap();
47 let nib = state.compress_sample(samp);
48 state.expand_sample(nib);
49 bw.write(u32::from(nib), 4);
50 }
51 }
52
53 let data = bw.end();
54
55 self.samples.drain(..cur_len * self.channels);
56 let ts = NATimeInfo::new(Some(self.pos), None, Some(cur_len as u64), 1, self.srate);
57 self.pos += cur_len as u64;
58 Ok(NAPacket::new(self.stream.clone().unwrap(), ts, true, data))
59 }
60}
61
62impl NAEncoder for ADPCMEncoder {
63 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
64 match encinfo.format {
65 NACodecTypeInfo::None => {
6f263099
KS
66 Ok(EncodeParameters {
67 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_S16_FORMAT, BLOCK_LEN)),
68 ..Default::default() })
92d9fb69
KS
69 },
70 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
71 NACodecTypeInfo::Audio(ainfo) => {
72 let mut outinfo = ainfo;
73 outinfo.channels = outinfo.channels.max(1).min(2);
74 if outinfo.format != SND_S16P_FORMAT && outinfo.format != SND_S16_FORMAT {
75 outinfo.format = SND_S16_FORMAT;
76 }
77 outinfo.block_len = BLOCK_LEN;
78 let mut ofmt = *encinfo;
79 ofmt.format = NACodecTypeInfo::Audio(outinfo);
80 Ok(ofmt)
81 }
82 }
83 }
2757a028 84 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
92d9fb69
KS
85 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
86 match encinfo.format {
87 NACodecTypeInfo::None => Err(EncoderError::FormatError),
88 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
89 NACodecTypeInfo::Audio(ainfo) => {
90 if ainfo.format != SND_S16P_FORMAT && ainfo.format != SND_S16_FORMAT {
91 return Err(EncoderError::FormatError);
92 }
93 if ainfo.channels != 1 && ainfo.channels != 2 {
94 return Err(EncoderError::FormatError);
95 }
96 self.channels = ainfo.channels as usize;
97
98 let soniton = NASoniton::new(4, 0);
99 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, soniton, if self.channels == 1 { 2051 } else { 4101 });
100 let info = NACodecInfo::new("flv-adpcm", NACodecTypeInfo::Audio(out_ainfo), None);
101 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, 1, ainfo.sample_rate, 0);
102 stream.set_num(stream_id as usize);
103 let stream = stream.into_ref();
104
105 self.stream = Some(stream.clone());
106 self.samples = Vec::with_capacity(BLOCK_LEN * self.channels);
107 self.srate = ainfo.sample_rate;
108 self.flush = false;
109
110 Ok(stream)
111 },
112 }
113 }
114 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
115 let buf = frm.get_buffer();
116 if let Some(ref abuf) = buf.get_abuf_i16() {
117 let src = abuf.get_data();
118 let len = abuf.get_length();
119 let ch = abuf.get_chmap().num_channels();
120 if abuf.get_step() > 1 || ch == 1 {
121 self.samples.extend_from_slice(&src[..len * ch]);
122 } else {
123 let astride = abuf.get_stride();
124 self.samples.reserve(len * ch);
125 for i in 0..len {
126 for ch in 0..self.channels {
127 self.samples.push(src[ch * astride + i]);
128 }
129 }
130 }
131 Ok(())
132 } else {
133 Err(EncoderError::InvalidParameters)
134 }
135 }
136 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
137 if let Ok(pkt) = self.encode_packet() {
138 Ok(Some(pkt))
139 } else {
140 Ok(None)
141 }
142 }
143 fn flush(&mut self) -> EncoderResult<()> {
144 self.flush = true;
145 Ok(())
146 }
147}
148
149impl NAOptionHandler for ADPCMEncoder {
150 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
151 fn set_options(&mut self, _options: &[NAOption]) {}
152 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
153}
154
155pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
156 Box::new(ADPCMEncoder::new())
157}
158
159#[cfg(test)]
160mod test {
161 use nihav_core::codecs::*;
162 use nihav_core::demuxers::*;
163 use nihav_core::muxers::*;
164 use nihav_codec_support::test::enc_video::*;
165 use crate::*;
166
167 #[test]
168 fn test_flv_adpcm_encoder() {
169
170 let mut dmx_reg = RegisteredDemuxers::new();
171 flash_register_all_demuxers(&mut dmx_reg);
172 let mut dec_reg = RegisteredDecoders::new();
173 flash_register_all_decoders(&mut dec_reg);
174 let mut mux_reg = RegisteredMuxers::new();
175 flash_register_all_muxers(&mut mux_reg);
176 let mut enc_reg = RegisteredEncoders::new();
177 flash_register_all_encoders(&mut enc_reg);
178
886cde48 179 // sample: https://samples.mplayerhq.hu/FLV/flash_flv_adpcm_testfiles/mono_11k.flv
92d9fb69
KS
180 let dec_config = DecoderTestParams {
181 demuxer: "flv",
182 in_name: "assets/Flash/mono_11k.flv",
183 stream_type: StreamType::Audio,
184 limit: Some(3700),
185 dmx_reg, dec_reg,
186 };
187 let enc_config = EncoderTestParams {
188 muxer: "flv",
189 enc_name: "flv-adpcm",
190 out_name: "flv_adpcm.flv",
191 mux_reg, enc_reg,
192 };
193 let dst_ainfo = NAAudioInfo {
194 sample_rate: 0,
195 channels: 0,
196 format: SND_S16_FORMAT,
197 block_len: 128,
198 };
199 let enc_params = EncodeParameters {
200 format: NACodecTypeInfo::Audio(dst_ainfo),
201 quality: 0,
202 bitrate: 0,
203 tb_num: 0,
204 tb_den: 0,
205 flags: 0,
206 };
207 //test_encoding_to_file(&dec_config, &enc_config, enc_params, &[]);
208
209 test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
210 &[0x6114b7de, 0xb84c226f, 0x0caab8e5, 0x2c7df63f]);
211 }
212}