use nihav_core::frame::*;
-use nihav_codec_support::codecs::MV;
+use nihav_codec_support::codecs::{MV, ZERO_MV};
use nihav_codec_support::codecs::blockdsp::{BlkInterpFunc, edge_emu};
use nihav_codec_support::codecs::h263::code::*;
use nihav_codec_support::codecs::h263::data::H263_CHROMA_ROUND;
fn idct_dc(block: &mut [i16; 64]) -> u8 { (block[0] / 8).clip8() }
trait MVOps {
+ fn halve(&self) -> MV;
fn get_chroma_mv(&self) -> MV;
fn get_chroma_4mv(&self) -> MV;
}
impl MVOps for MV {
+ fn halve(&self) -> MV {
+ MV{ x: (self.x >> 1) | (self.x & 1), y: (self.y >> 1) | (self.y & 1) }
+ }
fn get_chroma_mv(&self) -> MV {
MV{ x: self.x >> 1, y: self.y >> 1 }
}
mc_funcs: &'static [BlkInterpFunc],
avg_mc_funcs: &'static [BlkInterpFunc],
align: u8,
+ qpel: bool,
}
impl DSP {
mc_funcs: ASP_INTERP_FUNCS_NR,
avg_mc_funcs: ASP_INTERP_AVG_FUNCS_NR,
align: 4,
+ qpel: false,
}
}
+ pub fn set_qpel(&mut self, qpel: bool) {
+ self.qpel = qpel;
+ }
+ pub fn is_qpel(&self) -> bool { self.qpel }
pub fn use_xvid_idct(&mut self) {
self.idct = xvidish_idct;
}
}
}
- pub fn mb_mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mv: MV) {
+ pub fn mb_mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mut mv: MV) {
+ if self.qpel {
+ mv = mv.halve();
+ }
let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 0, mb_x * 16, mb_y * 16, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, self.mc_funcs, self.align);
let cmv = mv.get_chroma_mv();
copy_block(frm, pframe, 2, mb_x * 8, mb_y * 8, cmv.x >> 1, cmv.y >> 1, 8, 8, 0, 1, cmode, self.mc_funcs, self.align);
}
- pub fn avg_mb_mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mv: MV) {
+ pub fn avg_mb_mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mut mv: MV) {
+ if self.qpel {
+ mv = mv.halve();
+ }
let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 0, mb_x * 16, mb_y * 16, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, self.avg_mc_funcs, self.align);
let cmv = mv.get_chroma_mv();
pub fn mb_4mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mvs: &[MV; 4]) {
for (n, &mv) in mvs.iter().enumerate() {
+ let mv = if !self.qpel { mv } else { mv.halve() };
let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 0, mb_x * 16 + (n & 1) * 8, mb_y * 16 + (n / 2) * 8, mv.x >> 1, mv.y >> 1, 8, 8, 0, 1, mode, self.mc_funcs, self.align);
}
- let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
+ let sum_mv = if !self.qpel {
+ mvs[0] + mvs[1] + mvs[2] + mvs[3]
+ } else {
+ mvs.iter().fold(ZERO_MV, |sum, a| sum + MV {x: a.x / 2, y: a.y / 2 })
+ };
let cmv = sum_mv.get_chroma_4mv();
let cmode = ((cmv.x & 1) + (cmv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 1, mb_x * 8, mb_y * 8, cmv.x >> 1, cmv.y >> 1, 8, 8, 0, 1, cmode, self.mc_funcs, self.align);
pub fn avg_mb_4mv(&self, frm: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, pframe: NAVideoBufferRef<u8>, mvs: &[MV; 4]) {
for (n, &mv) in mvs.iter().enumerate() {
+ let mv = if !self.qpel { mv } else { mv.halve() };
let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 0, mb_x * 16 + (n & 1) * 8, mb_y * 16 + (n / 2) * 8, mv.x >> 1, mv.y >> 1, 8, 8, 0, 1, mode, self.avg_mc_funcs, self.align);
}
- let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
+ let sum_mv = if !self.qpel {
+ mvs[0] + mvs[1] + mvs[2] + mvs[3]
+ } else {
+ mvs.iter().fold(ZERO_MV, |sum, a| sum + MV {x: a.x / 2, y: a.y / 2 })
+ };
let cmv = sum_mv.get_chroma_4mv();
let cmode = ((cmv.x & 1) + (cmv.y & 1) * 2) as usize;
copy_block(frm, pframe.clone(), 1, mb_x * 8, mb_y * 8, cmv.x >> 1, cmv.y >> 1, 8, 8, 0, 1, cmode, self.avg_mc_funcs, self.align);
last_ref_info: PicState,
pb_mode: bool,
assign_mode: AssignMode,
+ warned_qpel: bool,
}
impl ASPDecoder {
last_ref_info: PicState::new(0, 0, 0),
pb_mode: false,
assign_mode: AssignMode::default(),
+ warned_qpel: false,
}
}
}
// ES descriptor, usually happens in MOV
if edata.len() > 16 && &edata[..4] == b"esds" {
let (vol, bugs) = parse_es_descriptor(&edata[8..])?;
- if vol.quarter_sample {
- println!("quarterpel is not supported!");
- return Err(DecoderError::NotImplemented);
+ if vol.quarter_sample && !self.warned_qpel {
+ println!("Warning: quarterpel decoding is not (really) supported");
+ self.warned_qpel = true;
}
+ self.fctx.set_qpel(vol.quarter_sample);
if bugs.is_xvid_dct() {
self.fctx.use_xvid_idct();
}
0x00..=0x1F => {}, // video_object_start_code
0x20..=0x3F => { // video_object_layer_start_code
let vol = parse_video_object_layer(&obj_src[1..])?;
- if vol.quarter_sample {
- println!("quarterpel is not supported!");
- return Err(DecoderError::NotImplemented);
+ if vol.quarter_sample && !self.warned_qpel {
+ println!("Warning: quarterpel decoding is not (really) supported");
+ self.warned_qpel = true;
}
+ self.fctx.set_qpel(vol.quarter_sample);
if vol.width != 0 {
if self.assign_mode == AssignMode::Undefined && pkt.get_dts().is_none() && !vol.low_delay {
let tinfo = pkt.get_time_information();