]> git.nihav.org Git - nihav.git/commitdiff
TS 102.366 multi-frame stream decoder
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 23 Aug 2025 14:27:17 +0000 (16:27 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 23 Aug 2025 14:28:20 +0000 (16:28 +0200)
nihav-commonfmt/src/codecs/mod.rs
nihav-commonfmt/src/codecs/ts102366.rs
nihav-registry/src/register.rs

index 7e85553b8cb3cccbf396777cbe8d726eb4a980f1..7064b4b401fc59cb43cc0915c1445c7b474bd39d 100644 (file)
@@ -69,6 +69,8 @@ const DECODERS: &[DecoderInfo] = &[
     DecoderInfo { name: "sipro", get_decoder: sipro::get_decoder },
 #[cfg(feature="decoder_ts102366")]
     DecoderInfo { name: "ac3", get_decoder: ts102366::get_decoder },
+#[cfg(feature="decoder_ts102366")]
+    DecoderInfo { name: "ac3-multi", get_decoder: ts102366::get_decoder_multi },
 #[cfg(feature="decoder_atrac3")]
     DecoderInfo { name: "atrac3", get_decoder: atrac3::get_decoder },
 ];
index 729d94c2a67f99005aa5bdd031305b6066bf264b..12aee607879c4c3703f6bea6cc6a42d58ed6e499 100644 (file)
@@ -1253,6 +1253,95 @@ pub fn get_decoder() -> Box<dyn NADecoder + Send> {
     Box::new(AudioDecoder::new())
 }
 
+struct AudioMultiDecoder {
+    pkt:    AudioPacketiser,
+    dec:    AudioDecoder,
+}
+
+impl AudioMultiDecoder {
+    fn new() -> Self {
+        Self {
+            pkt:    AudioPacketiser::new(),
+            dec:    AudioDecoder::new(),
+        }
+    }
+}
+
+impl NADecoder for AudioMultiDecoder {
+    fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        self.dec.init(supp, info)
+    }
+    fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let src = pkt.get_buffer();
+
+            self.pkt.add_data(&src);
+
+            let _count = self.pkt.skip_junk()?;
+
+            let mut nsamples = 0;
+            let mut samples = Vec::new();
+            let mut cur_chmap = NAChannelMap::new();
+            let mut srate = 44100;
+            while let Ok(Some(subpkt)) = self.pkt.get_packet(pkt.get_stream()) {
+                let subfrm = self.dec.decode(supp, &subpkt)?;
+                if let NABufferType::AudioF32(abuf) = subfrm.get_buffer() {
+                    if cur_chmap.num_channels() == 0 {
+                        cur_chmap = abuf.get_chmap().clone();
+                        srate = abuf.get_info().get_sample_rate();
+                    }
+
+                    let src = abuf.get_data();
+                    let stride = abuf.get_stride();
+                    let len = abuf.get_length();
+                    while samples.len() < cur_chmap.num_channels() {
+                        samples.push(Vec::new());
+                    }
+                    for (dst_ch, src_ch) in samples.iter_mut().zip(src.chunks_exact(stride)) {
+                        dst_ch.resize(nsamples + len, 0.0);
+                        dst_ch[nsamples..].copy_from_slice(&src_ch[..len]);
+                    }
+                    nsamples += len;
+                }
+            }
+
+            let channels = cur_chmap.num_channels() as u8;
+            let ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, nsamples);
+            let abuf = alloc_audio_buffer(ainfo, nsamples, cur_chmap)?;
+            if nsamples > 0 {
+                let mut adata = abuf.get_abuf_f32().unwrap();
+                let stride = if channels == 1 { adata.get_length() } else { adata.get_stride() };
+                let dst = adata.get_data_mut().unwrap();
+                for (dch, sch) in dst.chunks_exact_mut(stride).zip(samples.iter()) {
+                    dch[..nsamples].copy_from_slice(sch);
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, self.dec.info.clone(), abuf);
+            frm.set_duration(Some(nsamples as u64));
+            frm.set_keyframe(true);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::Bug)
+        }
+    }
+    fn flush(&mut self) {
+        self.pkt.reset();
+        self.dec.flush();
+    }
+}
+
+impl NAOptionHandler for AudioMultiDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder_multi() -> Box<dyn NADecoder + Send> {
+    Box::new(AudioMultiDecoder::new())
+}
+
 #[derive(Default)]
 struct AudioPacketiser {
     buf:        Vec<u8>,
index 904ea5967bfd6941b60ddb9861c8fc8e5abacc98..eeb6c66cc10c16ccadc74b974e87ad544489663a 100644 (file)
@@ -179,6 +179,7 @@ static CODEC_REGISTER: &[CodecDescription] = &[
     desc!(audio;    "ralf",       "RealAudio Lossless"),
     desc!(audio;    "aac",        "AAC"),
     desc!(audio;    "ac3",        "ETSI TS 102 366"),
+    desc!(audio;    "ac3-multi",  "ETSI TS 102 366 (multiple frames)"),
     desc!(audio;    "atrac3",     "Sony Atrac3"),
     desc!(audio;    "sipro",      "Sipro Labs ADPCM"),
 
@@ -412,6 +413,7 @@ static WAV_CODEC_REGISTER: &[(u16, &str)] = &[
     (0x0402, "iac"),
     (0x0500, "on2avc-500"),
     (0x0501, "on2avc-501"),
+    (0x2000, "ac3-multi"),
 ];
 
 static MOV_VIDEO_CODEC_REGISTER: &[(&[u8;4], &str)] = &[