X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fmuxers%2Favi.rs;h=fad358cf2356604b0cdff092185d17647a3e3562;hb=405cec9eed5d7f58440ec8495f5cbc1f5c6fee40;hp=9b83296db938123f8609bbbc542a1c3fee720316;hpb=dc80f48ea3097c891b159667ea239d3c20c78bc8;p=nihav.git diff --git a/nihav-commonfmt/src/muxers/avi.rs b/nihav-commonfmt/src/muxers/avi.rs index 9b83296..fad358c 100644 --- a/nihav-commonfmt/src/muxers/avi.rs +++ b/nihav-commonfmt/src/muxers/avi.rs @@ -15,7 +15,7 @@ struct AVIStream { strh_pos: u64, nframes: u32, is_video: bool, - max_size: u32, + max_size: u32, } struct AVIMuxer<'a> { @@ -25,6 +25,7 @@ struct AVIMuxer<'a> { video_id: u32, data_pos: u64, stream_info: Vec, + pal_pos: Vec, } impl<'a> AVIMuxer<'a> { @@ -36,6 +37,7 @@ impl<'a> AVIMuxer<'a> { video_id: 0, data_pos: 0, stream_info: Vec::with_capacity(2), + pal_pos: Vec::with_capacity(2), } } } @@ -61,6 +63,8 @@ fn write_chunk_hdr(bw: &mut ByteWriter, stype: StreamType, str_no: u32) -> Muxer } impl<'a> MuxCore<'a> for AVIMuxer<'a> { + #[allow(clippy::unreadable_literal)] + #[allow(clippy::cast_lossless)] fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> { if strmgr.get_num_streams() == 0 { return Err(MuxerError::InvalidArgument); @@ -68,10 +72,10 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { if strmgr.get_num_streams() > 99 { return Err(MuxerError::UnsupportedFormat); } - for (str_no, str) in strmgr.iter().enumerate() { - if str.get_media_type() == StreamType::Video { + for (str_no, strm) in strmgr.iter().enumerate() { + if strm.get_media_type() == StreamType::Video { self.video_str = Some(str_no); - self.video_id = str.id; + self.video_id = strm.id; break; } } @@ -105,20 +109,22 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.write_u32le(0)?; // reserved self.bw.write_u32le(0)?; // reserved - for str in strmgr.iter() { + self.pal_pos.clear(); + self.pal_pos.resize(strmgr.get_num_streams(), 0); + for (strno, strm) in strmgr.iter().enumerate() { let strl_pos = self.bw.tell() + 8; self.bw.write_buf(b"LIST\0\0\0\0strlstrh")?; self.bw.write_u32le(56)?; // strh size - match str.get_media_type() { + match strm.get_media_type() { StreamType::Video => { self.bw.write_buf(b"vids")?; - let fcc = find_avi_fourcc(str.get_info().get_name()); + let fcc = find_avi_fourcc(strm.get_info().get_name()); if fcc.is_none() { return Err(MuxerError::UnsupportedFormat); } self.bw.write_buf(&fcc.unwrap_or([0; 4]))?; - let vinfo = str.get_info().get_properties().get_video_info().unwrap(); + let vinfo = strm.get_info().get_properties().get_video_info().unwrap(); if vinfo.width >= (1 << 16) || vinfo.height >= (1 << 16) { return Err(MuxerError::UnsupportedFormat); } @@ -135,7 +141,7 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { }; self.stream_info.push(AVIStream { strh_pos: self.bw.tell(), - is_video: str.get_media_type() == StreamType::Video, + is_video: strm.get_media_type() == StreamType::Video, nframes: 0, max_size: 0, }); @@ -144,8 +150,8 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.write_u16le(0)?; // priority self.bw.write_u16le(0)?; // language self.bw.write_u32le(0)?; // initial frames - self.bw.write_u32le(str.tb_num)?; - self.bw.write_u32le(str.tb_den)?; + self.bw.write_u32le(strm.tb_num)?; + self.bw.write_u32le(strm.tb_den)?; self.bw.write_u32le(0)?; // start self.bw.write_u32le(0)?; // length self.bw.write_u32le(0)?; // suggested buffer size @@ -159,20 +165,21 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.write_buf(b"strf")?; self.bw.write_u32le(0)?; let strf_pos = self.bw.tell(); - match str.get_media_type() { + match strm.get_media_type() { StreamType::Video => { - let vinfo = str.get_info().get_properties().get_video_info().unwrap(); + let vinfo = strm.get_info().get_properties().get_video_info().unwrap(); let hdr_pos = self.bw.tell(); self.bw.write_u32le(0)?; self.bw.write_u32le(vinfo.width as u32)?; - if vinfo.flipped { - self.bw.write_u32le((-(vinfo.height as i32)) as u32)?; + self.bw.write_u32le(vinfo.height as u32)?; + if !vinfo.format.palette { + self.bw.write_u16le(vinfo.format.components as u16)?; + self.bw.write_u16le(vinfo.format.get_total_depth() as u16)?; } else { - self.bw.write_u32le(vinfo.height as u32)?; + self.bw.write_u16le(1)?; + self.bw.write_u16le(8)?; } - self.bw.write_u16le(vinfo.format.components as u16)?; - self.bw.write_u16le(vinfo.format.get_total_depth() as u16)?; - let fcc = find_avi_fourcc(str.get_info().get_name()); + let fcc = find_avi_fourcc(strm.get_info().get_name()); if fcc.is_none() { return Err(MuxerError::UnsupportedFormat); } @@ -181,14 +188,17 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.write_u32le(0)?; // x dpi self.bw.write_u32le(0)?; // y dpi if vinfo.format.palette { -// unimplemented!(); - self.bw.write_u32le(0)?; // total colors + self.bw.write_u32le(256)?; // total colors self.bw.write_u32le(0)?; // important colors + self.pal_pos[strno] = self.bw.tell() as u32; + for _ in 0..256 { + self.bw.write_u32le(0)?; + } } else { self.bw.write_u32le(0)?; // total colors self.bw.write_u32le(0)?; // important colors } - if let Some(ref edata) = str.get_info().get_extradata() { + if let Some(ref edata) = strm.get_info().get_extradata() { self.bw.write_buf(edata.as_slice())?; } let bisize = self.bw.tell() - hdr_pos; @@ -197,8 +207,8 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.seek(SeekFrom::End(0))?; }, StreamType::Audio => { - let ainfo = str.get_info().get_properties().get_audio_info().unwrap(); - let twocc = find_wav_twocc(str.get_info().get_name()); + let ainfo = strm.get_info().get_properties().get_audio_info().unwrap(); + let twocc = find_wav_twocc(strm.get_info().get_name()); if twocc.is_none() { return Err(MuxerError::UnsupportedFormat); } @@ -208,21 +218,21 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { self.bw.write_u32le(0)?; // avg bytes per second self.bw.write_u16le(ainfo.block_len as u16)?; self.bw.write_u16le(ainfo.format.bits as u16)?; - if let Some(ref edata) = str.get_info().get_extradata() { + if let Some(ref edata) = strm.get_info().get_extradata() { self.bw.write_buf(edata.as_slice())?; } }, StreamType::Subtitles => { - if let Some(ref edata) = str.get_info().get_extradata() { + if let Some(ref edata) = strm.get_info().get_extradata() { self.bw.write_buf(edata.as_slice())?; } }, _ => unreachable!(), }; - patch_size(&mut self.bw, strf_pos)?; - patch_size(&mut self.bw, strl_pos)?; + patch_size(self.bw, strf_pos)?; + patch_size(self.bw, strl_pos)?; } - patch_size(&mut self.bw, hdrl_pos)?; + patch_size(self.bw, hdrl_pos)?; self.data_pos = self.bw.tell() + 8; self.bw.write_buf(b"LIST\0\0\0\0movi")?; @@ -233,44 +243,78 @@ impl<'a> MuxCore<'a> for AVIMuxer<'a> { if self.data_pos == 0 { return Err(MuxerError::NotCreated); } - let str = pkt.get_stream(); - let str_num = str.get_num(); + let stream = pkt.get_stream(); + let str_num = stream.get_num(); if str_num > 99 || str_num >= self.stream_info.len() { return Err(MuxerError::UnsupportedFormat); } let chunk_len = pkt.get_buffer().len() as u32; + if self.pal_pos[str_num] != 0 { + for sdata in pkt.side_data.iter() { + if let NASideData::Palette(_, ref pal) = sdata { + let cur_pos = self.bw.tell(); + self.bw.seek(SeekFrom::Start(u64::from(self.pal_pos[str_num])))?; + self.bw.write_buf(pal.as_ref())?; + self.bw.seek(SeekFrom::Start(cur_pos))?; + self.pal_pos[str_num] = 0; + break; + } + } + } else { + for sdata in pkt.side_data.iter() { + if let NASideData::Palette(true, ref pal) = sdata { + //todo search for changed region + let start_clr = 0usize; + let end_clr = 256usize; + if start_clr < end_clr { + let chunk_len = ((end_clr - start_clr) as u32) * 4 + 4; + self.bw.write_byte(b'0' + ((str_num / 10) as u8))?; + self.bw.write_byte(b'0' + ((str_num % 10) as u8))?; + self.bw.write_buf(b"pc")?; + self.bw.write_u32le(chunk_len)?; + self.bw.write_byte(start_clr as u8)?; + self.bw.write_byte((end_clr - start_clr) as u8)?; + self.bw.write_u16le(0)?; //flags + self.bw.write_buf(&pal[start_clr * 4..end_clr * 4])?; + } + } + } + } + self.stream_info[str_num].nframes += 1; self.stream_info[str_num].max_size = self.stream_info[str_num].max_size.max(chunk_len); -// todo palchange self.index.push(IdxEntry { stream: str_num as u32, - stype: str.get_media_type(), + stype: stream.get_media_type(), key: pkt.keyframe, pos: self.bw.tell() as u32, len: chunk_len }); - write_chunk_hdr(&mut self.bw, str.get_media_type(), str_num as u32)?; + write_chunk_hdr(self.bw, stream.get_media_type(), str_num as u32)?; self.bw.write_u32le(chunk_len)?; self.bw.write_buf(pkt.get_buffer().as_slice())?; + if (self.bw.tell() & 1) != 0 { + self.bw.write_byte(0)?; + } Ok(()) } fn flush(&mut self) -> MuxerResult<()> { Ok(()) } fn end(&mut self) -> MuxerResult<()> { - patch_size(&mut self.bw, self.data_pos)?; - if self.index.len() > 0 { + patch_size(self.bw, self.data_pos)?; + if !self.index.is_empty() { self.bw.write_buf(b"idx1")?; self.bw.write_u32le((self.index.len() * 16) as u32)?; for item in self.index.iter() { - write_chunk_hdr(&mut self.bw, item.stype, item.stream)?; + write_chunk_hdr(self.bw, item.stype, item.stream)?; self.bw.write_u32le(if item.key { 0x10 } else { 0 })?; self.bw.write_u32le(item.pos)?; self.bw.write_u32le(item.len)?; } } - patch_size(&mut self.bw, 8)?; + patch_size(self.bw, 8)?; let mut max_frames = 0; let mut max_size = 0; for stri in self.stream_info.iter() { @@ -306,40 +350,34 @@ impl MuxerCreator for AVIMuxerCreator { #[cfg(test)] mod test { - use super::*; - use std::fs::File; + use nihav_core::codecs::*; use nihav_core::demuxers::*; - use crate::demuxers::*; + use nihav_core::muxers::*; + use nihav_codec_support::test::enc_video::*; + use crate::*; #[test] fn test_avi_muxer() { let mut dmx_reg = RegisteredDemuxers::new(); generic_register_all_demuxers(&mut dmx_reg); - let mut file = File::open("assets/Indeo/laser05.avi").unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let dmx_f = dmx_reg.find_demuxer("avi").unwrap(); - let mut dmx = create_demuxer(dmx_f, &mut br).unwrap(); - - let ofile = File::create("assets/test_out/muxed.avi").unwrap(); - let mut fw = FileWriter::new_write(ofile); - let mut bw = ByteWriter::new(&mut fw); - let mut mux = AVIMuxer::new(&mut bw); - - mux.create(dmx.get_stream_manager()).unwrap(); - - loop { - let pktres = dmx.get_frame(); - if let Err(e) = pktres { - if e == DemuxerError::EOF { break; } - panic!("error"); - } - let pkt = pktres.unwrap(); - println!("Got {}", pkt); - mux.mux_frame(dmx.get_stream_manager(), pkt).unwrap(); - } - - mux.end().unwrap(); -panic!("end"); + //test sample: https://samples.mplayerhq.hu/V-codecs/RT21/320x240/laser05.avi + let dec_config = DecoderTestParams { + demuxer: "avi", + in_name: "assets/Indeo/laser05.avi", + limit: None, + stream_type: StreamType::None, + dmx_reg, dec_reg: RegisteredDecoders::new(), + }; + let mut mux_reg = RegisteredMuxers::new(); + generic_register_all_muxers(&mut mux_reg); + /*let enc_config = EncoderTestParams { + muxer: "avi", + enc_name: "", + out_name: "muxed.avi", + mux_reg, enc_reg: RegisteredEncoders::new(), + }; + test_remuxing(&dec_config, &enc_config);*/ + test_remuxing_md5(&dec_config, "avi", &mux_reg, + [0xa0fb0e47, 0x412e24dd, 0x6b89711c, 0x276fb799]); } }