rmmux: better audio codec flavour detection
[nihav.git] / nihav-realmedia / src / muxers / rmvb / audiostream.rs
index fcb3d9c83cbd54bee91c98f3fdd9229870c7f8f2..1110b4bba0ade94b92e64637668083cebbee1f81 100644 (file)
@@ -16,6 +16,8 @@ static AUDIO_CODEC_REGISTRY: &[(&[u8;4], &str, &[u8;4], u8)] = &[
 ];
 
 struct InterleaveParams {
+    sample_rate:    u32,
+    channels:       u8,
     block_size:     usize,
     factor:         usize,
     frames_per_blk: usize,
@@ -26,6 +28,7 @@ trait Interleaver {
     fn get_block_size(&self) -> usize;
     fn get_factor(&self) -> usize;
     fn get_frames_per_block(&self) -> usize;
+    fn is_empty(&self) -> bool;
     fn add_packet(&mut self, src: &[u8]) -> bool;
     fn get_packet(&mut self) -> Option<(Vec<u8>, bool)>;
     fn flush(&mut self);
@@ -42,6 +45,7 @@ impl Interleaver for NoInterleaver {
     fn get_block_size(&self) -> usize { self.frame_size }
     fn get_factor(&self) -> usize { 1 }
     fn get_frames_per_block(&self) -> usize { 1 }
+    fn is_empty(&self) -> bool { self.pkt.is_none() }
     fn add_packet(&mut self, src: &[u8]) -> bool {
         if self.pkt.is_none() {
             self.pkt = Some(src.to_vec());
@@ -107,6 +111,7 @@ impl Interleaver for Int4Interleaver {
     fn get_block_size(&self) -> usize { self.block_size }
     fn get_factor(&self) -> usize { self.factor }
     fn get_frames_per_block(&self) -> usize { self.fpb }
+    fn is_empty(&self) -> bool { self.cur_frame == 0 }
     fn add_packet(&mut self, src: &[u8]) -> bool {
         if self.cur_frame == self.factor * self.fpb {
             return false;
@@ -149,7 +154,7 @@ struct GenericInterleaver {
     map:        Vec<usize>,
 }
 impl GenericInterleaver {
-    fn new(frame_size: usize, fcc: [u8; 4]) -> MuxerResult<Self> {
+    fn new(ainfo: NAAudioInfo, frame_size: usize, fcc: [u8; 4]) -> MuxerResult<Self> {
         let params = match &fcc {
                 b"atrc" => ATRAC_INTERLEAVE_PARAMS,
                 b"cook" => COOK_INTERLEAVE_PARAMS,
@@ -157,6 +162,12 @@ impl GenericInterleaver {
                 _ => return Err(MuxerError::UnsupportedFormat),
             };
         for (flavor, entry) in params.iter().enumerate() {
+            if entry.sample_rate != 0 && entry.sample_rate != ainfo.sample_rate {
+                continue;
+            }
+            if entry.channels != 0 && entry.channels != ainfo.channels {
+                continue;
+            }
             if entry.block_size / entry.frames_per_blk == frame_size {
                 let full_size = entry.frames_per_blk * entry.factor;
                 let mut map = vec![0; full_size];
@@ -200,6 +211,7 @@ impl Interleaver for GenericInterleaver {
     fn get_block_size(&self) -> usize { self.block_size }
     fn get_factor(&self) -> usize { self.factor }
     fn get_frames_per_block(&self) -> usize { self.fpb }
+    fn is_empty(&self) -> bool { self.cur_frame == 0 }
     fn add_packet(&mut self, src: &[u8]) -> bool {
         if self.cur_frame == self.factor * self.fpb {
             return false;
@@ -266,6 +278,7 @@ impl Interleaver for SiproInterleaver {
     fn get_block_size(&self) -> usize { self.block_size }
     fn get_factor(&self) -> usize { self.factor }
     fn get_frames_per_block(&self) -> usize { 1 }
+    fn is_empty(&self) -> bool { self.wr_pos == 0 }
     fn add_packet(&mut self, src: &[u8]) -> bool {
         if self.wr_pos < self.factor {
             self.buf[self.wr_pos * self.block_size..][..self.block_size].copy_from_slice(src);
@@ -340,6 +353,7 @@ impl Interleaver for AACInterleaver {
     fn get_block_size(&self) -> usize { self.frame_size }
     fn get_factor(&self) -> usize { 1 }
     fn get_frames_per_block(&self) -> usize { 1 }
+    fn is_empty(&self) -> bool { self.data.is_empty() }
     fn add_packet(&mut self, src: &[u8]) -> bool {
         if !self.full {
             self.data.extend_from_slice(src);
@@ -396,6 +410,10 @@ struct AudioStreamWriter {
     header_pos:     u64,
     interleave:     Box<dyn Interleaver>,
     data_size:      usize,
+    first_time:     u32,
+    last_time:      u32,
+    size_in:        usize,
+    size_out:       usize,
 }
 
 impl RMStreamWriter for AudioStreamWriter {
@@ -424,10 +442,18 @@ impl RMStreamWriter for AudioStreamWriter {
         }
         Ok(())
     }
-    fn queue_packet(&mut self, pkt: NAPacket) -> bool {
+    fn queue_packet(&mut self, pkt: NAPacket, ms: u32) -> bool {
         let src = pkt.get_buffer();
         self.data_size += src.len();
         let frame_size = self.interleave.get_frame_size();
+        self.last_time = ms;
+        if self.interleave.is_empty() {
+            self.first_time = ms;
+            self.size_in = 0;
+            self.size_out = 0;
+        } else {
+            self.size_in += src.len() / frame_size;
+        }
         if !self.is_raw {
             let mut ret = false;
             for frame in src.chunks(frame_size) {
@@ -438,7 +464,21 @@ impl RMStreamWriter for AudioStreamWriter {
             self.interleave.add_packet(&src)
         }
     }
-    fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { self.interleave.get_packet() }
+    fn get_packet(&mut self) -> Option<(Vec<u8>, u32, bool)> {
+        if let Some((pkt, first)) = self.interleave.get_packet() {
+            let time_add = if self.last_time > self.first_time && self.size_in > 0 {
+                    let size = pkt.len();
+                    let time_add = (self.size_out * ((self.last_time - self.first_time) as usize) / self.size_in) as u32;
+                    self.size_out += size / self.interleave.get_frame_size();
+                    time_add
+                } else {
+                    0
+                };
+            Some((pkt, self.first_time + time_add, first))
+        } else {
+            None
+        }
+    }
     fn flush(&mut self) { self.interleave.flush() }
     fn finish(&mut self, bw: &mut ByteWriter) -> MuxerResult<()> {
         let cur_pos = bw.tell();
@@ -587,7 +627,7 @@ fn create_interleaver(id: [u8; 4], fcc: [u8; 4], ainfo: NAAudioInfo) -> MuxerRes
         b"Int0" => Ok(Box::new(NoInterleaver{ frame_size, pkt: None })),
         b"Int4" => Ok(Box::new(Int4Interleaver::new(frame_size)?)),
         b"sipr" => Ok(Box::new(SiproInterleaver::new(frame_size)?)),
-        b"genr" => Ok(Box::new(GenericInterleaver::new(frame_size, fcc)?)),
+        b"genr" => Ok(Box::new(GenericInterleaver::new(ainfo, frame_size, fcc)?)),
         b"vbrs" | b"vbrf" => Ok(Box::new(AACInterleaver::new(1024))),
         _ => unimplemented!(),
     }
@@ -617,6 +657,10 @@ pub fn create_audio_stream(stream: &NAStream) -> MuxerResult<Box<dyn RMStreamWri
             interleave: create_interleaver(ileave, fourcc, ainfo)?,
             header_pos: 0,
             data_size:  0,
+            first_time: 0,
+            last_time:  0,
+            size_in:    0,
+            size_out:   0,
         }))
     } else {
         Err(MuxerError::UnsupportedFormat)
@@ -636,58 +680,70 @@ const SIPRO_SWAPS:   [[u8; 2]; 38] = [
     [ 67, 83 ], [ 77, 80 ]
 ];
 
+macro_rules! int_params {
+    ($rate:expr, $ch:expr, $bsize:expr, $factor:expr, $frm_per_blk:expr) => {
+        InterleaveParams {
+            sample_rate:    $rate,
+            channels:       $ch,
+            block_size:     $bsize,
+            factor:         $factor,
+            frames_per_blk: $frm_per_blk,
+        }
+    }
+}
+
 const RA_28_8_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
-    InterleaveParams { block_size: 228, factor: 12, frames_per_blk: 6 },
+    int_params!(0, 1, 228, 12, 6)
 ];
-const SIPRO_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
-    InterleaveParams { block_size: 232, factor: 6, frames_per_blk: 16 },
-    InterleaveParams { block_size: 304, factor: 6, frames_per_blk: 16 },
-    InterleaveParams { block_size: 296, factor: 6, frames_per_blk: 16 },
-    InterleaveParams { block_size: 320, factor: 6, frames_per_blk: 16 }
+const SIPRO_INTERLEAVE_PARAMS: &[InterleaveParams] = &[ //2,1,3,0
+    int_params!( 8000, 1, 232, 6, 16),
+    int_params!( 8000, 1, 304, 6, 16),
+    int_params!( 8000, 1, 296, 6, 16),
+    int_params!(16000, 1, 320, 6, 16),
 ];
 const ATRAC_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
-    InterleaveParams { block_size:  768, factor: 20, frames_per_blk: 4 },
-    InterleaveParams { block_size: 1088, factor: 20, frames_per_blk: 4 },
-    InterleaveParams { block_size:  912, factor: 30, frames_per_blk: 3 },
-    InterleaveParams { block_size: 1152, factor: 30, frames_per_blk: 3 },
-    InterleaveParams { block_size: 1272, factor: 30, frames_per_blk: 3 },
-    InterleaveParams { block_size: 1024, factor: 30, frames_per_blk: 2 },
-    InterleaveParams { block_size:  768, factor: 10, frames_per_blk: 1 },
-    InterleaveParams { block_size: 1024, factor: 10, frames_per_blk: 1 }
+    int_params!(0, 0,  768, 20, 4),
+    int_params!(0, 0, 1088, 20, 4),
+    int_params!(0, 0,  912, 30, 3),
+    int_params!(0, 0, 1152, 30, 3),
+    int_params!(0, 0, 1272, 30, 3),
+    int_params!(0, 0, 1024, 30, 2),
+    int_params!(0, 0,  768, 10, 1),
+    int_params!(0, 0, 1024, 10, 1),
 ];
 const COOK_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
-    InterleaveParams { block_size:  288, factor:  8, frames_per_blk:  9 },
-    InterleaveParams { block_size:  352, factor:  8, frames_per_blk: 11 },
-    InterleaveParams { block_size:  564, factor:  8, frames_per_blk: 12 },
-    InterleaveParams { block_size:  600, factor:  9, frames_per_blk: 10 },
-    InterleaveParams { block_size:  651, factor: 14, frames_per_blk:  7 },
-    InterleaveParams { block_size:  640, factor: 15, frames_per_blk:  5 },
-    InterleaveParams { block_size:  744, factor: 20, frames_per_blk:  4 },
-    InterleaveParams { block_size:  558, factor: 16, frames_per_blk:  6 },
-    InterleaveParams { block_size:  288, factor:  6, frames_per_blk: 12 },
-    InterleaveParams { block_size:  580, factor: 10, frames_per_blk: 10 },
-    InterleaveParams { block_size:  564, factor: 14, frames_per_blk:  6 },
-    InterleaveParams { block_size:  640, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  744, factor: 20, frames_per_blk:  4 },
-    InterleaveParams { block_size:  834, factor: 30, frames_per_blk:  3 },
-    InterleaveParams { block_size:  644, factor: 20, frames_per_blk:  4 },
-    InterleaveParams { block_size:  600, factor:  9, frames_per_blk: 10 },
-    InterleaveParams { block_size:  651, factor: 14, frames_per_blk:  7 },
-    InterleaveParams { block_size:  528, factor:  8, frames_per_blk: 11 },
-    InterleaveParams { block_size:  600, factor: 10, frames_per_blk: 10 },
-    InterleaveParams { block_size:  600, factor: 10, frames_per_blk: 10 },
-    InterleaveParams { block_size:  465, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  465, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  640, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  640, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  930, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size: 1400, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  376, factor:  8, frames_per_blk: 11 },
-    InterleaveParams { block_size:  930, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size: 1400, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size:  640, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size: 1395, factor: 16, frames_per_blk:  5 },
-    InterleaveParams { block_size: 1143, factor: 10, frames_per_blk:  3 },
-    InterleaveParams { block_size: 1064, factor: 10, frames_per_blk:  2 },
-    InterleaveParams { block_size:  778, factor:  1, frames_per_blk:  1 }
+    int_params!( 8000, 1,  288,  8,  9),
+    int_params!(11025, 1,  352,  8, 11),
+    int_params!(22050, 1,  564,  8, 12),
+    int_params!(22050, 1,  600,  9, 10),
+    int_params!(44100, 1,  651, 14,  7),
+    int_params!(44100, 1,  640, 15,  5),
+    int_params!(44100, 1,  744, 20,  4),
+    int_params!(22050, 1,  558, 16,  6),
+    int_params!( 8000, 1,  288,  6, 12),
+    int_params!(11025, 2,  580, 10, 10),
+    int_params!(22050, 2,  564, 14,  6),
+    int_params!(22050, 2,  640, 16,  5),
+    int_params!(44100, 2,  744, 20,  4),
+    int_params!(44100, 2,  834, 30,  3),
+    int_params!(44100, 1,  644, 20,  4),
+    int_params!(44100, 1,  600,  9, 10),
+    int_params!(44100, 1,  651, 14,  7),
+    int_params!(22050, 2,  528, 10, 10),
+    int_params!(22050, 2,  600, 10, 10),
+    int_params!(22050, 2,  600, 10, 10),
+    int_params!(22050, 2,  465, 16,  5),
+    int_params!(44100, 2,  465, 16,  5),
+    int_params!(44100, 2,  640, 16,  5),
+    int_params!(44100, 2,  640, 16,  5),
+    int_params!(44100, 2,  930, 16,  5),
+    int_params!(44100, 2, 1400, 16,  5),
+    int_params!(11025, 2,  376,  8, 11),
+    int_params!(44100, 2,  930, 16,  5),
+    int_params!(44100, 2, 1400, 16,  5),
+    int_params!(22050, 2,  640, 16,  5),
+    int_params!(44100, 5, 1395, 16,  5),
+    int_params!(44100, 6, 1143, 10,  3),
+    int_params!(44100, 6, 1064, 10,  2),
+    int_params!(44100, 6,  778,  1,  1),
 ];