X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fcodecs%2Fgifenc.rs;h=475323516d3ad191bc5aded641848ac1b8529fc7;hb=c455a7946c1238093c78fad12bcf7110db086465;hp=6bb9263055606df4ffd1832160a3b915c1c8f256;hpb=fc39649daffd54a1f7277656f470df2751fcf620;p=nihav.git diff --git a/nihav-commonfmt/src/codecs/gifenc.rs b/nihav-commonfmt/src/codecs/gifenc.rs index 6bb9263..4753235 100644 --- a/nihav-commonfmt/src/codecs/gifenc.rs +++ b/nihav-commonfmt/src/codecs/gifenc.rs @@ -2,6 +2,16 @@ use nihav_core::codecs::*; use nihav_core::io::byteio::*; use nihav_core::io::bitwriter::*; +const GRAY_FORMAT: NAPixelFormaton = NAPixelFormaton { + model: ColorModel::YUV(YUVSubmodel::YUVJ), + components: 1, + comp_info: [Some(NAPixelChromaton{h_ss: 0, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 0, next_elem: 1}), None, None, None, None], + elem_size: 1, + be: true, + alpha: false, + palette: false, + }; + #[derive(Clone,Copy,Default,PartialEq)] enum CompressionLevel { None, @@ -134,7 +144,12 @@ impl LZWEncoder { match self.level { CompressionLevel::None => { + let sym_limit = 1 << (clr_bits + 1); for &b in src.iter() { + if self.dict.cur_size >= sym_limit { + bw.write(u32::from(self.dict.clear_code), self.dict.bit_len); + self.dict.reset(); + } bw.write(u32::from(b), self.dict.bit_len); self.dict.add(usize::from(b), 0); } @@ -206,6 +221,7 @@ struct GIFEncoder { first: bool, width: usize, height: usize, + grayscale: bool, lzw: LZWEncoder, p_trans: bool, tr_idx: Option, @@ -223,6 +239,7 @@ impl GIFEncoder { first: true, width: 0, height: 0, + grayscale: false, lzw: LZWEncoder::new(), p_trans: false, tr_idx: None, @@ -254,7 +271,8 @@ impl NAEncoder for GIFEncoder { }, NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError), NACodecTypeInfo::Video(vinfo) => { - let outinfo = NAVideoInfo::new(vinfo.width, vinfo.height, false, PAL8_FORMAT); + let format = if vinfo.format == GRAY_FORMAT { GRAY_FORMAT } else { PAL8_FORMAT }; + let outinfo = NAVideoInfo::new(vinfo.width, vinfo.height, false, format); let mut ofmt = *encinfo; ofmt.format = NACodecTypeInfo::Video(outinfo); Ok(ofmt) @@ -270,8 +288,12 @@ impl NAEncoder for GIFEncoder { if vinfo.width > 65535 || vinfo.height > 65535 { return Err(EncoderError::FormatError); } + if vinfo.format != PAL8_FORMAT && vinfo.format != GRAY_FORMAT { + return Err(EncoderError::FormatError); + } self.width = vinfo.width; self.height = vinfo.height; + self.grayscale = vinfo.format == GRAY_FORMAT; let edata = self.tr_idx.map(|val| vec![val]); @@ -314,11 +336,19 @@ impl NAEncoder for GIFEncoder { let cur_pal = &src[buf.get_offset(1)..][..768]; if self.first { - self.pal.copy_from_slice(cur_pal); + if !self.grayscale { + self.pal.copy_from_slice(cur_pal); + } else { + for (i, pal) in self.pal.chunks_exact_mut(3).enumerate() { + pal[0] = i as u8; + pal[1] = i as u8; + pal[2] = i as u8; + } + } } let mut pal_changed = false; - if !self.first { + if !self.first && !self.grayscale { let mut used = [false; 256]; for &b in self.cur_frm.iter() { used[usize::from(b)] = true; @@ -454,13 +484,25 @@ impl NAEncoder for GIFEncoder { self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, self.first, dbuf)); self.first = false; - if let NABufferType::Video(ref buf) = frm.get_buffer() { - let paloff = buf.get_offset(1); - let data = buf.get_data(); + if !self.grayscale { + if let NABufferType::Video(ref buf) = frm.get_buffer() { + let paloff = buf.get_offset(1); + let data = buf.get_data(); + let mut pal = [0; 1024]; + let srcpal = &data[paloff..][..768]; + for (dclr, sclr) in pal.chunks_exact_mut(4).zip(srcpal.chunks_exact(3)) { + dclr[..3].copy_from_slice(sclr); + } + if let Some(ref mut pkt) = &mut self.pkt { + pkt.side_data.push(NASideData::Palette(true, Arc::new(pal))); + } + } + } else { let mut pal = [0; 1024]; - let srcpal = &data[paloff..][..768]; - for (dclr, sclr) in pal.chunks_exact_mut(4).zip(srcpal.chunks_exact(3)) { - dclr[..3].copy_from_slice(sclr); + for (i, quad) in pal.chunks_exact_mut(4).enumerate() { + quad[0] = i as u8; + quad[1] = i as u8; + quad[2] = i as u8; } if let Some(ref mut pkt) = &mut self.pkt { pkt.side_data.push(NASideData::Palette(true, Arc::new(pal))); @@ -636,7 +678,7 @@ mod test { let enc_options = &[ NAOption { name: "compr", value: NAValue::String("none".to_string()) }, ]; - test_gif_encoder_single("none.gif", enc_options, &[0x2767a289, 0xdef9ad30, 0xca4c289b, 0x1fd0ec19]); + test_gif_encoder_single("none.gif", enc_options, &[0x32900cff, 0xef979bb0, 0x2d0355e8, 0x424bddee]); } #[test] fn test_gif_single_fast() {