From cf74dc4b92fd88b535982f79cb0b388a0b4b1c09 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sat, 23 Aug 2025 16:27:17 +0200 Subject: [PATCH] TS 102.366 multi-frame stream decoder --- nihav-commonfmt/src/codecs/mod.rs | 2 + nihav-commonfmt/src/codecs/ts102366.rs | 89 ++++++++++++++++++++++++++ nihav-registry/src/register.rs | 2 + 3 files changed, 93 insertions(+) diff --git a/nihav-commonfmt/src/codecs/mod.rs b/nihav-commonfmt/src/codecs/mod.rs index 7e85553..7064b4b 100644 --- a/nihav-commonfmt/src/codecs/mod.rs +++ b/nihav-commonfmt/src/codecs/mod.rs @@ -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 }, ]; diff --git a/nihav-commonfmt/src/codecs/ts102366.rs b/nihav-commonfmt/src/codecs/ts102366.rs index 729d94c..12aee60 100644 --- a/nihav-commonfmt/src/codecs/ts102366.rs +++ b/nihav-commonfmt/src/codecs/ts102366.rs @@ -1253,6 +1253,95 @@ pub fn get_decoder() -> Box { 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 { + 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 { None } +} + +pub fn get_decoder_multi() -> Box { + Box::new(AudioMultiDecoder::new()) +} + #[derive(Default)] struct AudioPacketiser { buf: Vec, diff --git a/nihav-registry/src/register.rs b/nihav-registry/src/register.rs index 904ea59..eeb6c66 100644 --- a/nihav-registry/src/register.rs +++ b/nihav-registry/src/register.rs @@ -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)] = &[ -- 2.39.5