nihav_duck = { path = "../nihav-duck" }
nihav_game = { path = "../nihav-game" }
nihav_indeo = { path = "../nihav-indeo" }
+nihav_ms = { path = "../nihav-ms" }
nihav_rad = { path = "../nihav-rad" }
nihav_realmedia = { path = "../nihav-realmedia" }
extern crate nihav_duck;
extern crate nihav_game;
extern crate nihav_indeo;
+extern crate nihav_ms;
extern crate nihav_rad;
extern crate nihav_realmedia;
use nihav_indeo::indeo_register_all_codecs;
+use nihav_ms::ms_register_all_codecs;
+
use nihav_rad::rad_register_all_codecs;
use nihav_rad::rad_register_all_demuxers;
duck_register_all_codecs(rd);
game_register_all_codecs(rd);
indeo_register_all_codecs(rd);
+ ms_register_all_codecs(rd);
rad_register_all_codecs(rd);
realmedia_register_all_codecs(rd);
}
--- /dev/null
+[package]
+name = "nihav_ms"
+version = "0.1.0"
+authors = ["Kostya Shishkov <kostya.shishkov@gmail.com>"]
+edition = "2018"
+
+[dependencies.nihav_core]
+path = "../nihav-core"
+features = []
+
+[dependencies.nihav_codec_support]
+path = "../nihav-codec-support"
+features = []
+
+[dev-dependencies]
+nihav_commonfmt = { path = "../nihav-commonfmt" }
+
+[features]
+default = ["all_decoders"]
+all_decoders = ["all_video_decoders", "all_audio_decoders"]
+decoders = []
+
+all_video_decoders = ["decoder_msvideo1"]
+decoder_msvideo1 = ["decoders"]
+
+all_audio_decoders = ["decoder_ima_adpcm_ms", "decoder_ms_adpcm"]
+decoder_ima_adpcm_ms = ["decoders"]
+decoder_ms_adpcm = ["decoders"]
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::imaadpcm::*;
+use std::str::FromStr;
+
+struct IMAADPCMDecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ ch_state: [IMAState; 2],
+ block_len: usize,
+}
+
+impl IMAADPCMDecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ ch_state: [IMAState::new(), IMAState::new()],
+ block_len: 0,
+ }
+ }
+}
+
+impl NADecoder for IMAADPCMDecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+ self.block_len = ainfo.get_block_len();
+ let channels = ainfo.get_channels() as usize;
+ validate!(channels == 2 || channels == 1);
+ validate!(self.block_len >= 8 * channels);
+ validate!((self.block_len & 3) == 0);
+ let len = (self.block_len / channels - 4) * 2 + 1;
+ self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, len);
+ self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ let channels = self.chmap.num_channels();
+ validate!(pktbuf.len() >= 8 * channels);
+ let nsamples = (pktbuf.len() / channels - 4) * 2 + 1;
+ let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
+ let mut adata = abuf.get_abuf_i16().unwrap();
+ let mut off = [adata.get_offset(0), adata.get_offset(1)];
+ let dst = adata.get_data_mut().unwrap();
+
+ let mut mr = MemoryReader::new_read(pktbuf.as_slice());
+ let mut br = ByteReader::new(&mut mr);
+ for ch in 0..channels {
+ let pred = br.read_u16le()? as i16;
+ let step = br.read_byte()?;
+ br.read_skip(1)?;
+ validate!(step <= IMA_MAX_STEP);
+ self.ch_state[ch].reset(pred, step);
+ dst[off[ch]] = pred;
+ off[ch] += 1;
+ }
+ while br.left() > 0 {
+ for ch in 0..channels {
+ let mut cw = br.read_u32le()?;
+ for _ in 0..8 {
+ dst[off[ch]] = self.ch_state[ch].expand_sample((cw & 0xF) as u8);
+ off[ch] += 1;
+ cw >>= 4;
+ }
+ }
+ }
+ let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+ frm.set_duration(Some(nsamples as u64));
+ frm.set_keyframe(false);
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+ Box::new(IMAADPCMDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::ms_register_all_codecs;
+ use nihav_commonfmt::generic_register_all_demuxers;
+ #[test]
+ fn test_ima_adpcm_ms() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ ms_register_all_codecs(&mut dec_reg);
+
+ test_decoding("avi", "ima-adpcm-ms", "assets/MS/IMAG0006.AVI", None, &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x0cdc640f, 0xb00df235, 0x1ec4a280, 0x065b5e9e]));
+ }
+}
--- /dev/null
+use nihav_core::codecs::*;
+
+macro_rules! validate {
+ ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } };
+}
+
+#[cfg(feature="decoder_msvideo1")]
+pub mod msvideo1;
+
+#[cfg(feature="decoder_ima_adpcm_ms")]
+pub mod imaadpcm;
+
+#[cfg(feature="decoder_ms_adpcm")]
+pub mod msadpcm;
+
+const MS_CODECS: &[DecoderInfo] = &[
+#[cfg(feature="decoder_msvideo1")]
+ DecoderInfo { name: "msvideo1", get_decoder: msvideo1::get_decoder },
+#[cfg(feature="decoder_ima_adpcm_ms")]
+ DecoderInfo { name: "ima-adpcm-ms", get_decoder: imaadpcm::get_decoder },
+#[cfg(feature="decoder_ms_adpcm")]
+ DecoderInfo { name: "ms-adpcm", get_decoder: msadpcm::get_decoder },
+];
+
+/// Registers all available codecs provided by this crate.
+pub fn ms_register_all_codecs(rd: &mut RegisteredDecoders) {
+ for decoder in MS_CODECS.iter() {
+ rd.add_decoder(decoder.clone());
+ }
+}
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use std::str::FromStr;
+
+const ADAPT_TABLE: [i32; 16] = [
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+];
+const ADAPT_COEFFS: [[i32; 2]; 7] = [
+ [ 256, 0 ], [ 512, -256 ], [ 0, 0 ], [ 192, 64 ],
+ [ 240, 0 ], [ 460, -208 ], [ 392, -232 ]
+];
+
+#[derive(Default)]
+struct Predictor {
+ sample1: i32,
+ sample2: i32,
+ delta: i32,
+ coef1: i32,
+ coef2: i32,
+}
+
+impl Predictor {
+ fn expand_nibble(&mut self, nibble: u8) -> i16 {
+ let mul = if (nibble & 8) == 0 { i32::from(nibble) } else { i32::from(nibble) - 16 };
+ let pred = ((self.sample1.wrapping_mul(self.coef1) + self.sample2.wrapping_mul(self.coef2)) >> 8) + self.delta.wrapping_mul(mul);
+ self.sample2 = self.sample1;
+ self.sample1 = pred.max(-0x8000).min(0x7FFF);
+ self.delta = (ADAPT_TABLE[nibble as usize].wrapping_mul(self.delta) >> 8).max(16);
+ self.sample1 as i16
+ }
+}
+
+struct MSADPCMDecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ adapt_coeffs: Vec<[i32; 2]>,
+ block_len: usize,
+ block_samps: usize,
+}
+
+impl MSADPCMDecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ adapt_coeffs: Vec::with_capacity(7),
+ block_len: 0,
+ block_samps: 0,
+ }
+ }
+}
+
+impl NADecoder for MSADPCMDecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+ self.block_len = ainfo.get_block_len();
+ let channels = ainfo.get_channels() as usize;
+ validate!(channels == 2 || channels == 1);
+ validate!(self.block_len >= 7 * channels + 1);
+ self.block_samps = (self.block_len / channels - 7) * 2 + 2;
+ self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, self.block_samps);
+ self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+ self.adapt_coeffs.truncate(0);
+ if let Some(ref buf) = info.get_extradata() {
+ validate!(buf.len() >= 6);
+ validate!((buf.len() & 3) == 0);
+ let mut mr = MemoryReader::new_read(buf.as_slice());
+ let mut br = ByteReader::new(&mut mr);
+ let _smth = br.read_u16le()?;
+ let ncoeffs = br.read_u16le()? as usize;
+ validate!(buf.len() == ncoeffs * 4 + 4);
+
+ for _ in 0..ncoeffs {
+ let pair = [
+ i32::from(br.read_u16le()? as i16),
+ i32::from(br.read_u16le()? as i16)];
+ self.adapt_coeffs.push(pair);
+ }
+ } else {
+ self.adapt_coeffs.extend_from_slice(&ADAPT_COEFFS);
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ let channels = self.chmap.num_channels();
+ validate!(pktbuf.len() > 0 && (pktbuf.len() % self.block_len) == 0);
+ let nblocks = pktbuf.len() / self.block_len;
+ let nsamples = nblocks * self.block_samps;
+ let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
+ let mut adata = abuf.get_abuf_i16().unwrap();
+ let mut off = [adata.get_offset(0), adata.get_offset(1)];
+ let dst = adata.get_data_mut().unwrap();
+
+ let mut pred = [Predictor::default(), Predictor::default()];
+
+ for blk in pktbuf.chunks(self.block_len) {
+ let mut mr = MemoryReader::new_read(blk);
+ let mut br = ByteReader::new(&mut mr);
+ for ch in 0..channels {
+ let coef_idx = br.read_byte()? as usize;
+ validate!(coef_idx < self.adapt_coeffs.len());
+ pred[ch].coef1 = self.adapt_coeffs[coef_idx][0];
+ pred[ch].coef2 = self.adapt_coeffs[coef_idx][1];
+ }
+ for ch in 0..channels {
+ pred[ch].delta = i32::from(br.read_u16le()?);
+ }
+ for ch in 0..channels {
+ let samp = br.read_u16le()? as i16;
+ pred[ch].sample1 = i32::from(samp);
+ dst[off[ch]] = samp;
+ off[ch] += 1;
+ }
+ for ch in 0..channels {
+ let samp = br.read_u16le()? as i16;
+ pred[ch].sample2 = i32::from(samp);
+ dst[off[ch]] = samp;
+ off[ch] += 1;
+ }
+ if channels == 1 {
+ while br.left() > 0 {
+ let idx = br.read_byte()?;
+ dst[off[0]] = pred[0].expand_nibble(idx >> 4);
+ off[0] += 1;
+ dst[off[0]] = pred[0].expand_nibble(idx & 0xF);
+ off[0] += 1;
+ }
+ } else {
+ while br.left() > 0 {
+ let idx = br.read_byte()?;
+ dst[off[0]] = pred[0].expand_nibble(idx >> 4);
+ off[0] += 1;
+ dst[off[1]] = pred[1].expand_nibble(idx & 0xF);
+ off[1] += 1;
+ }
+ }
+ }
+ let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+ frm.set_duration(Some(nsamples as u64));
+ frm.set_keyframe(false);
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+ Box::new(MSADPCMDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::ms_register_all_codecs;
+ use nihav_commonfmt::generic_register_all_demuxers;
+ #[test]
+ fn test_ms_adpcm() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ ms_register_all_codecs(&mut dec_reg);
+
+ test_decoding("avi", "ms-adpcm", "assets/MS/dance.avi", None, &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x9d6619e1, 0x60d83560, 0xfe5c1fb7, 0xad5d130d]));
+ }
+}
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::HAMShuffler;
+
+struct HAMShuffler16 {
+ lastframe: Option<NAVideoBufferRef<u16>>,
+}
+
+impl HAMShuffler16 {
+ fn clear(&mut self) { self.lastframe = None; }
+ fn add_frame(&mut self, buf: NAVideoBufferRef<u16>) {
+ self.lastframe = Some(buf);
+ }
+ fn clone_ref(&mut self) -> Option<NAVideoBufferRef<u16>> {
+ if let Some(ref mut frm) = self.lastframe {
+ let newfrm = frm.copy_buffer();
+ *frm = newfrm.clone().into_ref();
+ Some(newfrm.into_ref())
+ } else {
+ None
+ }
+ }
+ fn get_output_frame(&mut self) -> Option<NAVideoBufferRef<u16>> {
+ match self.lastframe {
+ Some(ref frm) => Some(frm.clone()),
+ None => None,
+ }
+ }
+}
+
+impl Default for HAMShuffler16 {
+ fn default() -> Self { Self { lastframe: None } }
+}
+
+const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton {
+ model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+ comp_info: [
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }),
+ None, None],
+ elem_size: 2, be: false, alpha: false, palette: false };
+
+#[derive(Default)]
+struct Video1Decoder {
+ info: NACodecInfoRef,
+ hams: HAMShuffler,
+ hams16: HAMShuffler16,
+ width: usize,
+ height: usize,
+ is_16bit: bool,
+}
+
+impl Video1Decoder {
+ fn new() -> Self {
+ Self::default()
+ }
+ fn decode_frame(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<FrameType> {
+ let off = frm.offset[0];
+ let stride = frm.stride[0];
+ let mut skip_count = 0;
+ let blk_w = (self.width + 3) >> 2;
+ let blk_h = (self.height + 3) >> 2;
+ let mut cur_x = 0;
+ let mut cur_y = 0;
+ while cur_x < blk_w && cur_y < blk_h {
+ let op = br.read_u16le()?;
+ let advance;
+ if op < 0x8000 {
+ let mut clr = [0; 2];
+ br.read_buf(&mut clr)?;
+ let mut flags = !op as usize;
+ let cur_off = off + cur_x * 4 + cur_y * 4 * stride;
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr[flags & 1];
+ flags >>= 1;
+ }
+ }
+ advance = 1;
+ } else if op < 0x8400 {
+ let cur_off = off + cur_x * 4 + cur_y * 4 * stride;
+ let clr = op as u8;
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr;
+ }
+ }
+ advance = 1;
+ } else if op < 0x8800 {
+ advance = (op & 0x3FF) as usize;
+ validate!(advance > 0);
+ skip_count += advance;
+ } else {
+ let mut clr = [0; 8];
+ br.read_buf(&mut clr)?;
+ let mut flags = !op as usize;
+ let cur_off = off + cur_x * 4 + cur_y * 4 * stride;
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)];
+ flags >>= 1;
+ }
+ }
+ advance = 1;
+ }
+ cur_x += advance;
+ while cur_x >= blk_w {
+ cur_x -= blk_w;
+ cur_y += 1;
+ }
+ }
+ validate!(cur_x == 0 && cur_y == blk_h);
+ if skip_count == 0 {
+ Ok(FrameType::I)
+ } else if skip_count < blk_w * blk_h {
+ Ok(FrameType::P)
+ } else {
+ Ok(FrameType::Skip)
+ }
+ }
+ fn decode_frame16(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u16>) -> DecoderResult<FrameType> {
+ let off = frm.offset[0];
+ let stride = frm.stride[0];
+ let mut skip_count = 0;
+ let blk_w = (self.width + 3) >> 2;
+ let blk_h = (self.height + 3) >> 2;
+ let mut cur_x = 0;
+ let mut cur_y = 0;
+ while cur_x < blk_w && cur_y < blk_h {
+ let op = br.read_u16le()?;
+ let advance;
+ if (op & 0x8000) == 0 {
+ let mut clr = [0; 8];
+ clr[0] = br.read_u16le()?;
+ clr[1] = br.read_u16le()?;
+ let mut flags = !op as usize;
+ let cur_off = off + cur_x * 4 + cur_y * 4 * stride;
+ if (clr[0] & 0x8000) == 0 {
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr[flags & 1];
+ flags >>= 1;
+ }
+ }
+ } else {
+ clr[2] = br.read_u16le()?;
+ clr[3] = br.read_u16le()?;
+ clr[4] = br.read_u16le()?;
+ clr[5] = br.read_u16le()?;
+ clr[6] = br.read_u16le()?;
+ clr[7] = br.read_u16le()?;
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr[(i >> 1) * 2 + (j >> 1) * 4 + (flags & 1)];
+ flags >>= 1;
+ }
+ }
+ }
+ advance = 1;
+ } else if (op & 0xFC00) == 0x8400 {
+ advance = (op & 0x3FF) as usize;
+ validate!(advance > 0);
+ skip_count += advance;
+ } else {
+ let cur_off = off + cur_x * 4 + cur_y * 4 * stride;
+ let clr = op & 0x7FFF;
+ for j in 0..4 {
+ for i in 0..4 {
+ frm.data[cur_off + i + j * stride] = clr;
+ }
+ }
+ advance = 1;
+ }
+ cur_x += advance;
+ while cur_x >= blk_w {
+ cur_x -= blk_w;
+ cur_y += 1;
+ }
+ }
+ validate!((cur_x == 0 || cur_x == 1) && cur_y == blk_h);
+ if skip_count == 0 {
+ Ok(FrameType::I)
+ } else if skip_count < blk_w * blk_h {
+ Ok(FrameType::P)
+ } else {
+ Ok(FrameType::Skip)
+ }
+ }
+}
+
+impl NADecoder for Video1Decoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+println!("fmt {}", vinfo.get_format());
+ self.is_16bit = !vinfo.get_format().palette;
+ let fmt = if !self.is_16bit { PAL8_FORMAT } else { RGB555_FORMAT };
+ self.width = vinfo.get_width();
+ self.height = vinfo.get_height();
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt));
+ self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ validate!(src.len() >= 2);
+ let mut mr = MemoryReader::new_read(src.as_slice());
+ let mut br = ByteReader::new(&mut mr);
+
+ let buftype;
+ let ftype;
+ if !self.is_16bit {
+ let bufret = self.hams.clone_ref();
+ let mut buf;
+ if let Some(bbuf) = bufret {
+ buf = bbuf;
+ } else {
+ let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?;
+ buf = bufinfo.get_vbuf().unwrap();
+ self.hams.add_frame(buf);
+ buf = self.hams.get_output_frame().unwrap();
+ }
+ let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+ ftype = self.decode_frame(&mut br, &mut frm)?;
+ let paloff = frm.offset[1];
+ let dpal = &mut frm.data[paloff..];
+let mut found_pal = false;
+ for sd in pkt.side_data.iter() {
+ match *sd {
+ NASideData::Palette(_, ref pal) => {
+ for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ }
+found_pal = true;
+ break;
+ },
+ _ => {},
+ };
+ }
+if !found_pal {
+ for i in 0..256 {
+ dpal[i * 3 + 0] = i as u8;
+ dpal[i * 3 + 1] = i as u8;
+ dpal[i * 3 + 2] = i as u8;
+ }
+}
+ buftype = NABufferType::Video(buf);
+ } else {
+ let bufret = self.hams16.clone_ref();
+ let mut buf;
+ if let Some(bbuf) = bufret {
+ buf = bbuf;
+ } else {
+ let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?;
+ buf = bufinfo.get_vbuf16().unwrap();
+ self.hams16.add_frame(buf);
+ buf = self.hams16.get_output_frame().unwrap();
+ }
+ let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+ ftype = self.decode_frame16(&mut br, &mut frm)?;
+ buftype = NABufferType::Video16(buf);
+ }
+
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
+ frm.set_keyframe(ftype == FrameType::I);
+ frm.set_frame_type(ftype);
+ Ok(frm.into_ref())
+ }
+ fn flush(&mut self) {
+ self.hams.clear();
+ self.hams16.clear();
+ }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+ Box::new(Video1Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::ms_register_all_codecs;
+ use nihav_commonfmt::generic_register_all_demuxers;
+ #[test]
+ fn test_ms_video1_8bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ ms_register_all_codecs(&mut dec_reg);
+
+ test_decoding("avi", "msvideo1", "assets/MS/toon.avi", Some(66), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x0c26ec42, 0xb75bfea7, 0x1e6342ae, 0xb14dcfa3]));
+ }
+ #[test]
+ fn test_ms_video1_16bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ ms_register_all_codecs(&mut dec_reg);
+
+ test_decoding("avi", "msvideo1", "assets/MS/clock-cram16.avi", None, &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x03381fa4, 0x5b294fec, 0xb97a7575, 0xa1a3ffe9]));
+ }
+}
--- /dev/null
+extern crate nihav_core;
+extern crate nihav_codec_support;
+
+mod codecs;
+pub use crate::codecs::ms_register_all_codecs;
desc!(video; "cinepak", "Cinepak"),
+ desc!(video; "msvideo1", "MS Video 1"),
+ desc!(audio; "ms-adpcm", "MS ADPCM"),
+ desc!(audio; "ima-adpcm-ms", "IMA ADPCM (MS variant)"),
+
desc!(video; "truemotion1", "TrueMotion 1"),
desc!(video-im; "truemotionrt", "TrueMotion RT"),
desc!(video; "truemotion2", "TrueMotion 2"),
];
static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
+ (b"CRAM", "msvideo1"),
+ (b"MSVC", "msvideo1"),
+ (b"WHAM", "msvideo1"),
+
(b"IF09", "indeo1"),
(b"RT21", "indeo2"),
(b"IV31", "indeo3"),
static WAV_CODEC_REGISTER: &'static [(u16, &str)] = &[
(0x0000, "pcm"),
(0x0001, "pcm"),
+ (0x0002, "ms-adpcm"),
(0x0003, "pcm"),
+ (0x0011, "ima-adpcm-ms"),
(0x0061, "adpcm-dk4"),
(0x0062, "adpcm-dk3"),
(0x0401, "imc"),