From 2a778f1da8f76e3bbcb64220017760092d899e3c Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Mon, 7 Apr 2025 19:05:08 +0200 Subject: [PATCH] create audio format converter when input format differs from expected This may be needed when the decoded format differs from the declared one (e.g. demuxer reports 16-bit audio while audio decoder outputs floats). Also factor out channel map generation code so in case it ever gets improved I don't have to change it in three places. --- src/transcoder.rs | 56 +++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/transcoder.rs b/src/transcoder.rs index bf054f2..fe4c318 100644 --- a/src/transcoder.rs +++ b/src/transcoder.rs @@ -141,11 +141,34 @@ pub trait EncoderInterface { pub struct AudioEncodeContext { pub encoder: Box, pub cvt: Option, + pub sainfo: NAAudioInfo, + pub dainfo: NAAudioInfo, +} + +// todo better channel map generation +fn generate_channel_map(info: &NAAudioInfo) -> Option { + match info.channels { + 1 => Some(NAChannelMap::from_ms_mapping(0x4)), + 2 => Some(NAChannelMap::from_ms_mapping(0x3)), + _ => { +println!("can't generate default channel map for {} channels", info.channels); + None + }, + } } impl EncoderInterface for AudioEncodeContext { fn encode_frame(&mut self, dst_id: u32, frm: NAFrameRef, _scale_opts: &[(String, String)], queue: &mut OutputQueue) -> EncoderResult { let buf = frm.get_buffer(); + // check for possible input parameters mismatch and create audio converter if needed + if self.cvt.is_none() { + let cur_info = buf.get_audio_info().unwrap(); + if cur_info != self.sainfo { + let dchmap = generate_channel_map(&self.dainfo).ok_or(EncoderError::FormatError)?; + self.cvt = Some(AudioConverter::new(&cur_info, &self.dainfo, dchmap)); + self.sainfo = cur_info; + } + } let cbuf = if let NABufferType::None = buf { buf } else if let Some(ref mut acvt) = self.cvt { @@ -872,19 +895,15 @@ impl Transcoder { (NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(dainfo)) => { let icodec = istr.get_info().get_name(); if (sainfo == dainfo) && (icodec != "pcm" || oopts.enc_name.as_str() == "pcm") { - Box::new(AudioEncodeContext { encoder, cvt: None }) + Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo: *dainfo }) } else { - let dchmap = match dainfo.channels { - 1 => NAChannelMap::from_ms_mapping(0x4), - 2 => NAChannelMap::from_ms_mapping(0x3), - _ => { -println!("can't generate default channel map for {} channels", dainfo.channels); - return RegisterResult::Failed; - }, + let dchmap = if let Some(ret) = generate_channel_map(dainfo) { + ret + } else { + return RegisterResult::Failed; }; let acvt = AudioConverter::new(sainfo, dainfo, dchmap); -//todo channelmap - Box::new(AudioEncodeContext { encoder, cvt: Some(acvt) }) + Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo: *dainfo }) } }, _ => unreachable!(), @@ -1001,20 +1020,15 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge } } if sainfo == &dainfo { - Box::new(AudioEncodeContext { encoder, cvt: None }) + Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo }) } else { - let dchmap = match dainfo.channels { - 1 => NAChannelMap::from_ms_mapping(0x4), - 2 => NAChannelMap::from_ms_mapping(0x3), - _ => { -println!("can't generate default channel map for {} channels", dainfo.channels); - return RegisterResult::Failed; - }, + let dchmap = if let Some(ret) = generate_channel_map(&dainfo) { + ret + } else { + return RegisterResult::Failed; }; - -//todo channelmap let acvt = AudioConverter::new(sainfo, &dainfo, dchmap); - Box::new(AudioEncodeContext { encoder, cvt: Some(acvt) }) + Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo }) } }, _ => unreachable!(), -- 2.39.5