aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2024-08-06 18:06:38 +0200
committerKostya Shishkov <kostya.shishkov@gmail.com>2024-08-06 18:06:38 +0200
commit12e9040136caa4a7ce81db5d717f12c0fea41ecd (patch)
treee9d28f2b8e73c556c3a311c7acf075d3ac0b9bdd
parentc81af4dc7401b6db3d9be0c8e23abb31b2feeb79 (diff)
downloadnihav-12e9040136caa4a7ce81db5d717f12c0fea41ecd.tar.gz
svq1: rework frame reconstruction
Apparently the codec applies all deltas and only then clips the result.
-rw-r--r--nihav-qt/src/codecs/svq1.rs75
1 files changed, 48 insertions, 27 deletions
diff --git a/nihav-qt/src/codecs/svq1.rs b/nihav-qt/src/codecs/svq1.rs
index e367145..f01c80f 100644
--- a/nihav-qt/src/codecs/svq1.rs
+++ b/nihav-qt/src/codecs/svq1.rs
@@ -207,13 +207,9 @@ impl SVQ1Decoder {
validate!(stages <= 0);
}
let (w, h) = div.get_size();
- let fill = if stages < 0 { 0 } else { br.read_cb(&self.intra_mean_cb)? } as u8;
- for line in dst[off..].chunks_mut(dstride).take(h) {
- for el in line.iter_mut().take(w) {
- *el = fill;
- }
- }
+ let fill = if stages < 0 { 0 } else { br.read_cb(&self.intra_mean_cb)? };
if stages > 0 {
+ let mut blk = [fill; 256];
for stage in 0..(stages as usize) {
let idx = br.read(4)? as usize;
let src: &[i8] = match div {
@@ -223,12 +219,23 @@ impl SVQ1Decoder {
BlockDiv::Div4x2 => &SVQ_INTRA_CB_4X2[stage * 16 + idx],
_ => unreachable!(),
};
- for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
- for x in 0..w {
- line[x] = (i16::from(line[x]) + i16::from(src[x])).max(0).min(255) as u8;
+ for (dst, src) in blk.chunks_exact_mut(w).zip(src.chunks_exact(w)) {
+ for (diff, &src) in dst.iter_mut().zip(src.iter()) {
+ *diff += i16::from(src);
}
}
}
+ for (dline, sline) in dst[off..].chunks_mut(dstride).zip(blk.chunks_exact(w)).take(h) {
+ for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
+ *dst = src.max(0).min(255) as u8;
+ }
+ }
+ } else {
+ for line in dst[off..].chunks_mut(dstride).take(h) {
+ for el in line.iter_mut().take(w) {
+ *el = fill as u8;
+ }
+ }
}
}
idx += 1;
@@ -255,29 +262,43 @@ impl SVQ1Decoder {
}
let (w, h) = div.get_size();
let fill = if stages < 0 { 0 } else { br.read_cb(&self.inter_mean_cb)? };
- if fill != 0 {
- for line in dst[off..].chunks_mut(dstride).take(h) {
- for el in line.iter_mut().take(w) {
- *el = el.wrapping_add(fill as u8);
+ if fill != 0 || stages != 0 {
+ let mut blk = [0; 256];
+
+ for (dline, sline) in blk.chunks_exact_mut(w).zip(dst[off..].chunks(dstride)).take(h) {
+ for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
+ *dst = i16::from(src);
}
}
- }
- if stages > 0 {
- for stage in 0..(stages as usize) {
- let idx = br.read(4)? as usize;
- let src: &[i8] = match div {
- BlockDiv::Div8x8 => &SVQ_INTER_CB_8X8[stage * 16 + idx],
- BlockDiv::Div8x4 => &SVQ_INTER_CB_8X4[stage * 16 + idx],
- BlockDiv::Div4x4 => &SVQ_INTER_CB_4X4[stage * 16 + idx],
- BlockDiv::Div4x2 => &SVQ_INTER_CB_4X2[stage * 16 + idx],
- _ => unreachable!(),
- };
- for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
- for x in 0..w {
- line[x] = line[x].wrapping_add(src[x] as u8);
+
+ if fill != 0 {
+ for el in blk.iter_mut().take(w * h) {
+ *el += fill;
+ }
+ }
+ if stages > 0 {
+ for stage in 0..(stages as usize) {
+ let idx = br.read(4)? as usize;
+ let src: &[i8] = match div {
+ BlockDiv::Div8x8 => &SVQ_INTER_CB_8X8[stage * 16 + idx],
+ BlockDiv::Div8x4 => &SVQ_INTER_CB_8X4[stage * 16 + idx],
+ BlockDiv::Div4x4 => &SVQ_INTER_CB_4X4[stage * 16 + idx],
+ BlockDiv::Div4x2 => &SVQ_INTER_CB_4X2[stage * 16 + idx],
+ _ => unreachable!(),
+ };
+ for (line, src) in blk.chunks_exact_mut(w).zip(src.chunks_exact(w)) {
+ for (dst, &src) in line.iter_mut().zip(src.iter()) {
+ *dst += i16::from(src);
+ }
}
}
}
+
+ for (dline, sline) in dst[off..].chunks_mut(dstride).zip(blk.chunks_exact(w)).take(h) {
+ for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
+ *dst = src.max(0).min(255) as u8;
+ }
+ }
}
}
idx += 1;