]> git.nihav.org Git - nihav-encoder.git/commitdiff
create audio format converter when input format differs from expected
authorKostya Shishkov <kostya.shishkov@gmail.com>
Mon, 7 Apr 2025 17:05:08 +0000 (19:05 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Mon, 7 Apr 2025 17:05:08 +0000 (19:05 +0200)
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

index bf054f2336c4a78f83aa44f4717de4d469bb39bd..fe4c31885e47f049d39a2a11ef1da674b20e6797 100644 (file)
@@ -141,11 +141,34 @@ pub trait EncoderInterface {
 pub struct AudioEncodeContext {
     pub encoder:    Box<dyn NAEncoder>,
     pub cvt:        Option<AudioConverter>,
+    pub sainfo:     NAAudioInfo,
+    pub dainfo:     NAAudioInfo,
+}
+
+// todo better channel map generation
+fn generate_channel_map(info: &NAAudioInfo) -> Option<NAChannelMap> {
+    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<bool> {
         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!(),