nframes: u32,
is_video: bool,
max_size: u32,
+ pal_change: bool,
}
struct AVIMuxer<'a> {
video_id: u32,
data_pos: u64,
stream_info: Vec<AVIStream>,
+ pal_pos: Vec<u32>,
}
impl<'a> AVIMuxer<'a> {
video_id: 0,
data_pos: 0,
stream_info: Vec::with_capacity(2),
+ pal_pos: Vec::with_capacity(2),
}
}
}
}
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);
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;
}
}
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);
}
};
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,
+ pal_change: false,
});
self.bw.write_u32le(0)?; // flags
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
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);
}
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;
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);
}
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")?;
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])))?;
+ for quad in pal.chunks(4) {
+ self.bw.write_byte(quad[2])?;
+ self.bw.write_byte(quad[1])?;
+ self.bw.write_byte(quad[0])?;
+ self.bw.write_byte(0)?;
+ }
+ 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].pal_change = true;
+ }
+ }
+ }
+ }
+
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() {
max_frames = max_frames.max(stri.nframes);
max_size = max_size.max(stri.max_size);
+ if stri.pal_change {
+ self.bw.seek(SeekFrom::Start(stri.strh_pos))?;
+ self.bw.write_u32le(0x00010000)?;
+ }
self.bw.seek(SeekFrom::Start(stri.strh_pos + 0x18))?;
self.bw.write_u32le(if stri.is_video { stri.nframes } else { 0 })?;
self.bw.write_u32le(stri.max_size)?;
fn test_avi_muxer() {
let mut dmx_reg = RegisteredDemuxers::new();
generic_register_all_demuxers(&mut dmx_reg);
+ //test sample: https://samples.mplayerhq.hu/V-codecs/RT21/320x240/laser05.avi
let dec_config = DecoderTestParams {
demuxer: "avi",
in_name: "assets/Indeo/laser05.avi",