From 4dedf76ebc9e123f4731c9db51b9f4f0c415737d Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Mon, 30 Nov 2020 17:10:35 +0100 Subject: [PATCH] WebP performance optimizations & clean up. --- .../imageio/plugins/webp/WebPImageReader.java | 46 +- .../imageio/plugins/webp/vp8/Globals.java | 86 +- .../imageio/plugins/webp/vp8/IDCT.java | 53 +- .../imageio/plugins/webp/vp8/LoopFilter.java | 777 ++++++----- .../imageio/plugins/webp/vp8/MacroBlock.java | 146 +-- .../plugins/webp/vp8/SegmentQuant.java | 25 +- .../plugins/webp/vp8/SegmentQuants.java | 35 +- .../imageio/plugins/webp/vp8/SubBlock.java | 1167 +++++++++-------- .../imageio/plugins/webp/vp8/VP8Frame.java | 465 +++---- 9 files changed, 1368 insertions(+), 1432 deletions(-) diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java index 4338d580..a45329ae 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java @@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.webp; import com.twelvemonkeys.imageio.ImageReaderBase; +import com.twelvemonkeys.imageio.color.ColorSpaces; import com.twelvemonkeys.imageio.metadata.Directory; import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader; import com.twelvemonkeys.imageio.metadata.xmp.XMPReader; @@ -48,11 +49,14 @@ import javax.imageio.ImageReader; import javax.imageio.ImageTypeSpecifier; import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageReaderSpi; +import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; import java.awt.image.WritableRaster; import java.io.IOException; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -83,7 +87,15 @@ final class WebPImageReader extends ImageReaderBase { @Override public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { + // TODO: Figure out why this makes the reader order of magnitudes faster (2-3x?) + // ...or, how to make VP8 decoder make longer reads/make a better FileImageInputStream... super.setInput(input, seekForwardOnly, ignoreMetadata); +// try { +// super.setInput(new BufferedImageInputStream((ImageInputStream) input), seekForwardOnly, ignoreMetadata); +// } +// catch (IOException e) { +// throw new IOError(e); +// } lsbBitReader = new LSBBitReader(imageInput); } @@ -240,7 +252,8 @@ final class WebPImageReader extends ImageReaderBase { (byte) ((value & 0x0000ff00) >> 8), (byte) ((value & 0x00ff0000) >> 16), (byte) ((value & 0xff000000) >>> 24), - } + }, + StandardCharsets.US_ASCII ); } @@ -270,7 +283,12 @@ final class WebPImageReader extends ImageReaderBase { // "alpha value is codified in bits 31..24, red in bits 23..16, green in bits 15..8 and blue in bits 7..0, // but implementations of the format are free to use another representation internally." // TODO: Doc says alpha flag is "hint only" :-P - // TODO: ICC profile?! + if (iccProfile != null && !ColorSpaces.isCS_sRGB(iccProfile)) { + ICC_ColorSpace colorSpace = ColorSpaces.createColorSpace(iccProfile); + int[] bandOffsets = header.containsALPH ? new int[] {0, 1, 2, 3} : new int[] {0, 1, 2}; + return ImageTypeSpecifiers.createInterleaved(colorSpace, bandOffsets, DataBuffer.TYPE_BYTE, header.containsALPH, false); + } + return ImageTypeSpecifiers.createFromBufferedImageType(header.containsALPH ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR); } @@ -296,13 +314,13 @@ final class WebPImageReader extends ImageReaderBase { switch (header.fourCC) { case WebP.CHUNK_VP8_: imageInput.seek(header.offset); - readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel())); + readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param); break; case WebP.CHUNK_VP8L: imageInput.seek(header.offset); - readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel())); + readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param); break; @@ -344,7 +362,7 @@ final class WebPImageReader extends ImageReaderBase { break; case 1: opaqueAlpha(destination.getAlphaRaster()); // TODO: Remove when correctly implemented! - readVP8Lossless(destination.getAlphaRaster()); + readVP8Lossless(destination.getAlphaRaster(), param); break; default: processWarningOccurred("Unknown WebP alpha compression: " + compression); @@ -356,12 +374,12 @@ final class WebPImageReader extends ImageReaderBase { case WebP.CHUNK_VP8_: readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()) - .createWritableChild(0, 0, width, height, 0, 0, new int[]{0, 1, 2})); + .createWritableChild(0, 0, width, height, 0, 0, new int[]{0, 1, 2}), param); break; case WebP.CHUNK_VP8L: - readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel())); + readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param); break; @@ -409,13 +427,13 @@ final class WebPImageReader extends ImageReaderBase { opaqueAlpha(alphaRaster); } - private void readVP8Lossless(final WritableRaster raster) throws IOException { + private void readVP8Lossless(final WritableRaster raster, final ImageReadParam param) throws IOException { VP8LDecoder decoder = new VP8LDecoder(imageInput); decoder.readVP8Lossless(raster, true); } - private void readVP8(final WritableRaster raster) throws IOException { - VP8Frame frame = new VP8Frame(imageInput); + private void readVP8(final WritableRaster raster, final ImageReadParam param) throws IOException { + VP8Frame frame = new VP8Frame(imageInput, DEBUG); frame.setProgressListener(new ProgressListenerBase() { @Override @@ -424,9 +442,9 @@ final class WebPImageReader extends ImageReaderBase { } }); - // TODO: Consider merging these operations... - if (frame.decodeFrame(false)) { - frame.copyTo(raster); + if (!frame.decode(raster, param)) { + // TODO: Does this make any sense? Only happens if frame type is not still (0) + processWarningOccurred("Nothing to decode"); } } @@ -435,10 +453,8 @@ final class WebPImageReader extends ImageReaderBase { @Override public IIOMetadata getImageMetadata(int imageIndex) throws IOException { readHeader(imageIndex); - // TODO: Read possible EXIF and 'XMP ' chunks readMeta(); - return new WebPImageMetadata(header); } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java index 4282f3bf..e396655f 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java @@ -31,6 +31,9 @@ package com.twelvemonkeys.imageio.plugins.webp.vp8; +import static java.lang.Math.max; +import static java.lang.Math.min; + final class Globals { /* predict DC using row above and column to the left */ @@ -45,20 +48,21 @@ final class Globals { static final int B_PRED = 4; static String getModeAsString(int mode) { - switch (mode) { - case DC_PRED: - return "DC_PRED"; - case V_PRED: - return "V_PRED"; - case H_PRED: - return "H_PRED"; - case TM_PRED: - return "TM_PRED"; - case B_PRED: - return "B_PRED"; - } - return "not found"; - } + switch (mode) { + case DC_PRED: + return "DC_PRED"; + case V_PRED: + return "V_PRED"; + case H_PRED: + return "H_PRED"; + case TM_PRED: + return "TM_PRED"; + case B_PRED: + return "B_PRED"; + default: + throw new IllegalArgumentException("Unknown mode: " + mode); + } + } /* intra_bmode */ static final int B_DC_PRED = 0; /* @@ -88,29 +92,30 @@ final class Globals { static final int B_HU_PRED = 9; /* ENE (horizontal up) "" */ static String getSubBlockModeAsString(int mode) { - switch (mode) { - case B_DC_PRED: - return "B_DC_PRED"; - case B_TM_PRED: - return "B_TM_PRED"; - case B_VE_PRED: - return "B_VE_PRED"; - case B_HE_PRED: - return "B_HE_PRED"; - case B_LD_PRED: - return "B_LD_PRED"; - case B_RD_PRED: - return "B_RD_PRED"; - case B_VR_PRED: - return "B_VR_PRED"; - case B_VL_PRED: - return "B_VL_PRED"; - case B_HD_PRED: - return "B_HD_PRED"; - case B_HU_PRED: - return "B_HU_PRED"; - } - return "not found"; + switch (mode) { + case B_DC_PRED: + return "B_DC_PRED"; + case B_TM_PRED: + return "B_TM_PRED"; + case B_VE_PRED: + return "B_VE_PRED"; + case B_HE_PRED: + return "B_HE_PRED"; + case B_LD_PRED: + return "B_LD_PRED"; + case B_RD_PRED: + return "B_RD_PRED"; + case B_VR_PRED: + return "B_VR_PRED"; + case B_VL_PRED: + return "B_VL_PRED"; + case B_HD_PRED: + return "B_HD_PRED"; + case B_HU_PRED: + return "B_HU_PRED"; + default: + throw new IllegalArgumentException("Unknown mode: " + mode); + } } static final int MAX_MB_SEGMENTS = 4; @@ -814,9 +819,8 @@ final class Globals { return String.format("%1$#x ", c); } - // clamp between 0 and value - static int clamp(final int input, final int value) { - return input < 0 ? 0 : input > value ? value : input; + // clamp between 0 and max + static int clamp(final int input, final int max) { + return max(0, min(input, max)); } - } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/IDCT.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/IDCT.java index d7df9d2d..3803fb12 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/IDCT.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/IDCT.java @@ -37,17 +37,15 @@ final class IDCT { private static final int sinpi8sqrt2 = 35468; - public static int[][] idct4x4llm(int input[]) { - int i; + public static int[][] idct4x4llm(int[] input) { int a1, b1, c1, d1; - int offset = 0; int[] output = new int[16]; int temp1, temp2; - for (i = 0; i < 4; i++) { - a1 = input[offset + 0] + input[offset + 8]; - b1 = input[offset + 0] - input[offset + 8]; + for (int i = 0, offset = 0; i < 4; i++) { + a1 = input[offset] + input[offset + 8]; + b1 = input[offset] - input[offset + 8]; temp1 = (input[offset + 4] * sinpi8sqrt2) >> 16; temp2 = input[offset + 12] @@ -60,9 +58,9 @@ final class IDCT { temp2 = (input[offset + 12] * sinpi8sqrt2) >> 16; d1 = temp1 + temp2; - output[offset + (0 * 4)] = a1 + d1; + output[offset ] = a1 + d1; output[offset + (3 * 4)] = a1 - d1; - output[offset + (1 * 4)] = b1 + c1; + output[offset + ( 4)] = b1 + c1; output[offset + (2 * 4)] = b1 - c1; offset++; @@ -70,22 +68,19 @@ final class IDCT { int diffo = 0; int[][] diff = new int[4][4]; - offset = 0; - for (i = 0; i < 4; i++) { - a1 = output[(offset * 4) + 0] + output[(offset * 4) + 2]; - b1 = output[(offset * 4) + 0] - output[(offset * 4) + 2]; + for (int i = 0, offset = 0; i < 4; i++) { + a1 = output[offset * 4] + output[(offset * 4) + 2]; + b1 = output[offset * 4] - output[(offset * 4) + 2]; temp1 = (output[(offset * 4) + 1] * sinpi8sqrt2) >> 16; - temp2 = output[(offset * 4) + 3] - + ((output[(offset * 4) + 3] * cospi8sqrt2minus1) >> 16); + temp2 = output[(offset * 4) + 3] + ((output[(offset * 4) + 3] * cospi8sqrt2minus1) >> 16); c1 = temp1 - temp2; - temp1 = output[(offset * 4) + 1] - + ((output[(offset * 4) + 1] * cospi8sqrt2minus1) >> 16); + temp1 = output[(offset * 4) + 1] + ((output[(offset * 4) + 1] * cospi8sqrt2minus1) >> 16); temp2 = (output[(offset * 4) + 3] * sinpi8sqrt2) >> 16; d1 = temp1 + temp2; - output[(offset * 4) + 0] = (a1 + d1 + 4) >> 3; + output[(offset * 4) ] = (a1 + d1 + 4) >> 3; output[(offset * 4) + 3] = (a1 - d1 + 4) >> 3; output[(offset * 4) + 1] = (b1 + c1 + 4) >> 3; output[(offset * 4) + 2] = (b1 - c1 + 4) >> 3; @@ -104,39 +99,35 @@ final class IDCT { } public static int[][] iwalsh4x4(int[] input) { - int i; int a1, b1, c1, d1; int a2, b2, c2, d2; int[] output = new int[16]; int[][] diff = new int[4][4]; - int offset = 0; - for (i = 0; i < 4; i++) { - a1 = input[offset + 0] + input[offset + 12]; + for (int i = 0, offset = 0; i < 4; i++) { + a1 = input[offset ] + input[offset + 12]; b1 = input[offset + 4] + input[offset + 8]; c1 = input[offset + 4] - input[offset + 8]; - d1 = input[offset + 0] - input[offset + 12]; + d1 = input[offset ] - input[offset + 12]; - output[offset + 0] = a1 + b1; - output[offset + 4] = c1 + d1; - output[offset + 8] = a1 - b1; + output[offset ] = a1 + b1; + output[offset + 4] = c1 + d1; + output[offset + 8] = a1 - b1; output[offset + 12] = d1 - c1; offset++; } - offset = 0; - - for (i = 0; i < 4; i++) { - a1 = output[offset + 0] + output[offset + 3]; + for (int i = 0, offset = 0; i < 4; i++) { + a1 = output[offset ] + output[offset + 3]; b1 = output[offset + 1] + output[offset + 2]; c1 = output[offset + 1] - output[offset + 2]; - d1 = output[offset + 0] - output[offset + 3]; + d1 = output[offset ] - output[offset + 3]; a2 = a1 + b1; b2 = c1 + d1; c2 = a1 - b1; d2 = d1 - c1; - output[offset + 0] = (a2 + 3) >> 3; + output[offset ] = (a2 + 3) >> 3; output[offset + 1] = (b2 + 3) >> 3; output[offset + 2] = (c2 + 3) >> 3; output[offset + 3] = (d2 + 3) >> 3; diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java index 083de9d9..000a0311 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java @@ -31,13 +31,11 @@ package com.twelvemonkeys.imageio.plugins.webp.vp8; -final class LoopFilter { - private static int abs(int v) { - return v < 0 ? -v : v; - } +import static java.lang.Math.*; - private static int c(int v) { - return v < -128 ? -128 : (v > 127 ? 127 : v); +final class LoopFilter { + private static int clamp(int value) { + return max(min(value, 127), -128); } private static int common_adjust(boolean use_outer_taps, /* filter is 2 or 4 taps wide */ Segment seg) { @@ -46,33 +44,33 @@ final class LoopFilter { int q0 = u2s(seg.Q0); int q1 = u2s(seg.Q1); - /* - * Disregarding clamping, when "use_outer_taps" is false, "a" is - * 3*(q0-p0). Since we are about to divide "a" by 8, in this case we end - * up multiplying the edge difference by 5/8. When "use_outer_taps" is - * true (as for the simple filter), "a" is p1 - 3*p0 + 3*q0 - q1, which - * can be thought of as a refinement of 2*(q0 - p0) and the adjustment - * is something like (q0 - p0)/4. - */ - int a = c((use_outer_taps ? c(p1 - q1) : 0) + 3 * (q0 - p0)); - /* - * b is used to balance the rounding of a/8 in the case where the - * "fractional" part "f" of a/8 is exactly 1/2. - */ - int b = (c(a + 3)) >> 3; - /* - * Divide a by 8, rounding up when f >= 1/2. Although not strictly part - * of the "C" language, the right-shift is assumed to propagate the sign - * bit. - */ - a = c(a + 4) >> 3; - /* Subtract "a" from q0, "bringing it closer" to p0. */ + /* + * Disregarding clamping, when "use_outer_taps" is false, "a" is + * 3*(q0-p0). Since we are about to divide "a" by 8, in this case we end + * up multiplying the edge difference by 5/8. When "use_outer_taps" is + * true (as for the simple filter), "a" is p1 - 3*p0 + 3*q0 - q1, which + * can be thought of as a refinement of 2*(q0 - p0) and the adjustment + * is something like (q0 - p0)/4. + */ + int a = clamp((use_outer_taps ? clamp(p1 - q1) : 0) + 3 * (q0 - p0)); + /* + * b is used to balance the rounding of a/8 in the case where the + * "fractional" part "f" of a/8 is exactly 1/2. + */ + int b = (clamp(a + 3)) >> 3; + /* + * Divide a by 8, rounding up when f >= 1/2. Although not strictly part + * of the "C" language, the right-shift is assumed to propagate the sign + * bit. + */ + a = clamp(a + 4) >> 3; + /* Subtract "a" from q0, "bringing it closer" to p0. */ seg.Q0 = s2u(q0 - a); - /* - * Add "a" (with adjustment "b") to p0, "bringing it closer" to q0. The - * clamp of "a+b", while present in the reference decoder, is - * superfluous; we have -16 <= a <= 15 at this point. - */ + /* + * Add "a" (with adjustment "b") to p0, "bringing it closer" to q0. The + * clamp of "a+b", while present in the reference decoder, is + * superfluous; we have -16 <= a <= 15 at this point. + */ seg.P0 = s2u(p0 + b); return a; @@ -85,17 +83,17 @@ final class LoopFilter { * for a horizontal edge (written "|"), an 8-pixel segment would be ordered * p3 p2 p1 p0 | q0 q1 q2 q3. */ - /* - * Filtering is disabled if the difference between any two adjacent - * "interior" pixels in the 8-pixel segment exceeds the relevant threshold - * (I). A more complex thresholding calculation is done for the group of - * four pixels that straddle the edge, in line with the calculation in - * simple_segment() above. - */ - private static boolean filter_yes(int I, /* limit on interior differences */ - int E, /* limit at the edge */ - int p3, int p2, int p1, int p0, /* pixels before edge */ - int q0, int q1, int q2, int q3 /* pixels after edge */ + /* + * Filtering is disabled if the difference between any two adjacent + * "interior" pixels in the 8-pixel segment exceeds the relevant threshold + * (I). A more complex thresholding calculation is done for the group of + * four pixels that straddle the edge, in line with the calculation in + * simple_segment() above. + */ + private static boolean filter_yes(int I, // limit on interior differences + int E, // limit at the edge + int p3, int p2, int p1, int p0, // pixels before edge + int q0, int q1, int q2, int q3 // pixels after edge ) { return (abs(p0 - q0) * 2 + abs(p1 - q1) / 2) <= E && abs(p3 - p2) <= I && abs(p2 - p1) <= I && abs(p1 - p0) <= I && abs(q3 - q2) <= I @@ -106,6 +104,7 @@ final class LoopFilter { Segment seg = new Segment(); int[][] rdest = rsb.getDest(); int[][] ldest = lsb.getDest(); + seg.P0 = ldest[3][a]; seg.P1 = ldest[2][a]; seg.P2 = ldest[1][a]; @@ -114,6 +113,7 @@ final class LoopFilter { seg.Q1 = rdest[1][a]; seg.Q2 = rdest[2][a]; seg.Q3 = rdest[3][a]; + return seg; } @@ -130,6 +130,7 @@ final class LoopFilter { seg.Q1 = bdest[a][1]; seg.Q2 = bdest[a][2]; seg.Q3 = bdest[a][3]; + return seg; } @@ -137,134 +138,138 @@ final class LoopFilter { * Filtering is altered if (at least) one of the differences on either side * of the edge exceeds a threshold (we have "high edge variance"). */ - private static boolean hev(int threshold, int p1, int p0, /* - * pixels before - * edge - */ - int q0, int q1 /* pixels after edge */ + private static boolean hev(int threshold, + int p1, int p0, // pixels before edge + int q0, int q1 // pixels after edge ) { return abs(p1 - p0) > threshold || abs(q1 - q0) > threshold; } - public static void loopFilter(VP8Frame frame) { -// frame.fireLFProgressUpdate(0); - if (frame.getFilterType() == 2) { - loopFilterUV(frame); -// frame.fireLFProgressUpdate(50); - loopFilterY(frame); - } else if (frame.getFilterType() == 1) { - loopFilterSimple(frame); +// public static void loopFilter(VP8Frame frame) { +// if (frame.getFilterType() == 2) { +// loopFilterUV(frame); +// loopFilterY(frame); +// } +// else if (frame.getFilterType() == 1) { +// loopFilterSimple(frame); +// } +// } + + static void loopFilterBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, int frameType, boolean simpleFilter, int sharpness) { + if (simpleFilter) { + loopFilterSimpleBlock(cmb, lmb, tmb, sharpness); + } + else { + loopFilterUVBlock(cmb, lmb, tmb, sharpness, frameType); + loopFilterYBlock(cmb, lmb, tmb, sharpness, frameType); } -// frame.fireLFProgressUpdate(100); } + private static void loopFilterSimple(VP8Frame frame) { for (int y = 0; y < frame.getMacroBlockRows(); y++) { // frame.fireLFProgressUpdate((100.0f * ((float) (y + 1) / (float) (frame // .getMacroBlockRows())))); for (int x = 0; x < frame.getMacroBlockCols(); x++) { - // System.out.println("x: "+x+" y: "+y); - MacroBlock rmb = frame.getMacroBlock(x, y); - MacroBlock bmb = frame.getMacroBlock(x, y); + loopFilterSimpleBlock(frame.getMacroBlock(x, y), + x > 0 ? frame.getMacroBlock(x - 1, y) : null, + y > 0 ? frame.getMacroBlock(x, y - 1) : null, + frame.getSharpnessLevel()); + } + } + } - int loop_filter_level = rmb.getFilterLevel(); - if (loop_filter_level != 0) { - int interior_limit = rmb.getFilterLevel(); + static void loopFilterSimpleBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel) { + // System.out.println("x: "+x+" y: "+y); +// MacroBlock bmb = frame.getMacroBlock(x, y); // TODO: Same..? + int loop_filter_level = cmb.getFilterLevel(); + if (loop_filter_level != 0) { + int interior_limit = cmb.getFilterLevel(); - int sharpnessLevel = frame.getSharpnessLevel(); - if (sharpnessLevel > 0) { - interior_limit >>= sharpnessLevel > 4 ? 2 : 1; - if (interior_limit > 9 - sharpnessLevel) { - interior_limit = 9 - sharpnessLevel; + if (sharpnessLevel > 0) { + interior_limit >>= sharpnessLevel > 4 ? 2 : 1; + if (interior_limit > 9 - sharpnessLevel) { + interior_limit = 9 - sharpnessLevel; + } + } + if (interior_limit == 0) { + interior_limit = 1; + } + + // Luma and Chroma use the same inter-subblock edge limit + int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; + if (sub_bedge_limit < 1) { + sub_bedge_limit = 1; + } + + // Luma and Chroma use the same inter-macroblock edge limit + int mbedge_limit = sub_bedge_limit + 4; + + // left + if (lmb != null) { + for (int b = 0; b < 4; b++) { + SubBlock rsb = cmb.getSubBlock(SubBlock.Plane.Y1, 0, b); + SubBlock lsb = lmb.getSubBlock(SubBlock.Plane.Y1, 3, b); + for (int a = 0; a < 4; a++) { + Segment seg = getSegH(rsb, lsb, a); + // MBfilter(hev_threshold, interior_limit, + // mbedge_limit, seg); + // System.out.println(mbedge_limit); + simple_segment(mbedge_limit, seg); + setSegH(rsb, lsb, seg, a); + } + } + } + + // sb left + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 4; a++) { + for (int b = 0; b < 4; b++) { + SubBlock lsb = cmb.getSubBlock(SubBlock.Plane.Y1, a - 1, b); + SubBlock rsb = cmb.getSubBlock(SubBlock.Plane.Y1, a, b); + for (int c = 0; c < 4; c++) { + // System.out.println("sbleft a:"+a+" b:"+b+" c:"+c); + Segment seg = getSegH(rsb, lsb, c); + simple_segment(sub_bedge_limit, seg); + // System.out.println(sub_bedge_limit); + // subblock_filter(hev_threshold,interior_limit,sub_bedge_limit, + // seg); + setSegH(rsb, lsb, seg, c); } } - if (interior_limit == 0) { - interior_limit = 1; + } + } + + // top + if (tmb != null) { + for (int b = 0; b < 4; b++) { + SubBlock tsb = tmb.getSubBlock(SubBlock.Plane.Y1, b, 3); + SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, 0); + for (int a = 0; a < 4; a++) { + Segment seg = getSegV(bsb, tsb, a); + simple_segment(mbedge_limit, seg); + // System.out.println(mbedge_limit); + // MBfilter(hev_threshold, interior_limit, + // mbedge_limit, seg); + setSegV(bsb, tsb, seg, a); } + } + } - /* Luma and Chroma use the same inter-subblock edge limit */ - int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; - if (sub_bedge_limit < 1) { - sub_bedge_limit = 1; - } - - /* Luma and Chroma use the same inter-macroblock edge limit */ - int mbedge_limit = sub_bedge_limit + 4; - - // left - if (x > 0) { - MacroBlock lmb = frame.getMacroBlock(x - 1, y); - for (int b = 0; b < 4; b++) { - SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, 0, b); - SubBlock lsb = lmb.getSubBlock(SubBlock.PLANE.Y1, 3, b); - for (int a = 0; a < 4; a++) { - Segment seg = getSegH(rsb, lsb, a); - // MBfilter(hev_threshold, interior_limit, - // mbedge_limit, seg); - // System.out.println(mbedge_limit); - simple_segment(mbedge_limit, seg); - setSegH(rsb, lsb, seg, a); - } - } - } - - // sb left - if (!rmb.isSkip_inner_lf()) { - - for (int a = 1; a < 4; a++) { - for (int b = 0; b < 4; b++) { - SubBlock lsb = rmb.getSubBlock(SubBlock.PLANE.Y1, - a - 1, b); - SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, - a, b); - for (int c = 0; c < 4; c++) { - // System.out.println("sbleft a:"+a+" b:"+b+" c:"+c); - Segment seg = getSegH(rsb, lsb, c); - simple_segment(sub_bedge_limit, seg); - // System.out.println(sub_bedge_limit); - // subblock_filter(hev_threshold,interior_limit,sub_bedge_limit, - // seg); - setSegH(rsb, lsb, seg, c); - } - } - } - } - - // top - if (y > 0) { - MacroBlock tmb = frame.getMacroBlock(x, y - 1); - for (int b = 0; b < 4; b++) { - SubBlock tsb = tmb.getSubBlock(SubBlock.PLANE.Y1, b, 3); - SubBlock bsb = bmb.getSubBlock(SubBlock.PLANE.Y1, b, 0); - for (int a = 0; a < 4; a++) { - Segment seg = getSegV(bsb, tsb, a); - simple_segment(mbedge_limit, seg); - // System.out.println(mbedge_limit); - // MBfilter(hev_threshold, interior_limit, - // mbedge_limit, seg); - setSegV(bsb, tsb, seg, a); - } - } - } - - // sb top - if (!rmb.isSkip_inner_lf()) { - for (int a = 1; a < 4; a++) { - for (int b = 0; b < 4; b++) { - SubBlock tsb = bmb.getSubBlock(SubBlock.PLANE.Y1, - b, a - 1); - SubBlock bsb = bmb.getSubBlock(SubBlock.PLANE.Y1, - b, a); - for (int c = 0; c < 4; c++) { - // System.out.println("sbtop"); - Segment seg = getSegV(bsb, tsb, c); - simple_segment(sub_bedge_limit, seg); - // System.out.println(sub_bedge_limit); - // subblock_filter(hev_threshold,interior_limit,sub_bedge_limit, - // seg); - setSegV(bsb, tsb, seg, c); - } - } + // sb top + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 4; a++) { + for (int b = 0; b < 4; b++) { + SubBlock tsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a - 1); + SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a); + for (int c = 0; c < 4; c++) { + // System.out.println("sbtop"); + Segment seg = getSegV(bsb, tsb, c); + simple_segment(sub_bedge_limit, seg); + // System.out.println(sub_bedge_limit); + // subblock_filter(hev_threshold,interior_limit,sub_bedge_limit, + // seg); + setSegV(bsb, tsb, seg, c); } } } @@ -274,139 +279,127 @@ final class LoopFilter { private static void loopFilterUV(VP8Frame frame) { for (int y = 0; y < frame.getMacroBlockRows(); y++) { -// frame.fireLFProgressUpdate((100.0f * ((float) (y + 1) / (float) (frame -// .getMacroBlockRows()))) / 2); for (int x = 0; x < frame.getMacroBlockCols(); x++) { - MacroBlock rmb = frame.getMacroBlock(x, y); - MacroBlock bmb = frame.getMacroBlock(x, y); - int sharpnessLevel = frame.getSharpnessLevel(); - int loop_filter_level = rmb.getFilterLevel(); - if (loop_filter_level != 0) { - int interior_limit = rmb.getFilterLevel(); - if (sharpnessLevel > 0) { - interior_limit >>= sharpnessLevel > 4 ? 2 : 1; - if (interior_limit > 9 - sharpnessLevel) { - interior_limit = 9 - sharpnessLevel; + loopFilterUVBlock(frame.getMacroBlock(x, y), + x > 0 ? frame.getMacroBlock(x - 1, y) : null, + y > 0 ? frame.getMacroBlock(x, y - 1) : null, + frame.getSharpnessLevel(), frame.getFrameType() + ); + } + } + } + + static void loopFilterUVBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) { + int loop_filter_level = cmb.getFilterLevel(); + if (loop_filter_level != 0) { + int interior_limit = cmb.getFilterLevel(); + if (sharpnessLevel > 0) { + interior_limit >>= sharpnessLevel > 4 ? 2 : 1; + if (interior_limit > 9 - sharpnessLevel) { + interior_limit = 9 - sharpnessLevel; + } + } + if (interior_limit == 0) { + interior_limit = 1; + } + + int hev_threshold = 0; + if (frameType == 0) { // current frame is a key frame + if (loop_filter_level >= 40) { + hev_threshold = 2; + } + else if (loop_filter_level >= 15) { + hev_threshold = 1; + } + } + else { // current frame is an interframe + if (loop_filter_level >= 40) { + hev_threshold = 3; + } + else if (loop_filter_level >= 20) { + hev_threshold = 2; + } + else if (loop_filter_level >= 15) { + hev_threshold = 1; + } + } + + // Luma and Chroma use the same inter-macroblock edge limit + int mbedge_limit = ((loop_filter_level + 2) * 2) + interior_limit; + // Luma and Chroma use the same inter-subblock edge limit + int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; + + if (lmb != null) { + for (int b = 0; b < 2; b++) { + SubBlock rsbU = cmb.getSubBlock(SubBlock.Plane.U, 0, b); + SubBlock lsbU = lmb.getSubBlock(SubBlock.Plane.U, 1, b); + SubBlock rsbV = cmb.getSubBlock(SubBlock.Plane.V, 0, b); + SubBlock lsbV = lmb.getSubBlock(SubBlock.Plane.V, 1, b); + for (int a = 0; a < 4; a++) { + Segment seg = getSegH(rsbU, lsbU, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegH(rsbU, lsbU, seg, a); + seg = getSegH(rsbV, lsbV, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegH(rsbV, lsbV, seg, a); + } + } + } + // sb left + + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 2; a++) { // TODO: This does not loop? + for (int b = 0; b < 2; b++) { + SubBlock lsbU = cmb.getSubBlock(SubBlock.Plane.U, a - 1, b); + SubBlock rsbU = cmb.getSubBlock(SubBlock.Plane.U, a, b); + SubBlock lsbV = cmb.getSubBlock(SubBlock.Plane.V, a - 1, b); + SubBlock rsbV = cmb.getSubBlock(SubBlock.Plane.V, a, b); + for (int c = 0; c < 4; c++) { + Segment seg = getSegH(rsbU, lsbU, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegH(rsbU, lsbU, seg, c); + seg = getSegH(rsbV, lsbV, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegH(rsbV, lsbV, seg, c); } } - if (interior_limit == 0) { - interior_limit = 1; + } + } + + // top + if (tmb != null) { + for (int b = 0; b < 2; b++) { + SubBlock tsbU = tmb.getSubBlock(SubBlock.Plane.U, b, 1); + SubBlock bsbU = cmb.getSubBlock(SubBlock.Plane.U, b, 0); + SubBlock tsbV = tmb.getSubBlock(SubBlock.Plane.V, b, 1); + SubBlock bsbV = cmb.getSubBlock(SubBlock.Plane.V, b, 0); + for (int a = 0; a < 4; a++) { + // System.out.println("l"); + Segment seg = getSegV(bsbU, tsbU, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegV(bsbU, tsbU, seg, a); + seg = getSegV(bsbV, tsbV, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegV(bsbV, tsbV, seg, a); } + } + } - int hev_threshold = 0; - if (frame.getFrameType() == 0) /* current frame is a key frame */ { - if (loop_filter_level >= 40) { - hev_threshold = 2; - } else if (loop_filter_level >= 15) { - hev_threshold = 1; - } - } else /* current frame is an interframe */ { - if (loop_filter_level >= 40) { - hev_threshold = 3; - } else if (loop_filter_level >= 20) { - hev_threshold = 2; - } else if (loop_filter_level >= 15) { - hev_threshold = 1; - } - } - - /* Luma and Chroma use the same inter-macroblock edge limit */ - int mbedge_limit = ((loop_filter_level + 2) * 2) - + interior_limit; - /* Luma and Chroma use the same inter-subblock edge limit */ - int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; - - if (x > 0) { - MacroBlock lmb = frame.getMacroBlock(x - 1, y); - for (int b = 0; b < 2; b++) { - SubBlock rsbU = rmb.getSubBlock(SubBlock.PLANE.U, 0, b); - SubBlock lsbU = lmb.getSubBlock(SubBlock.PLANE.U, 1, b); - SubBlock rsbV = rmb.getSubBlock(SubBlock.PLANE.V, 0, b); - SubBlock lsbV = lmb.getSubBlock(SubBlock.PLANE.V, 1, b); - for (int a = 0; a < 4; a++) { - Segment seg = getSegH(rsbU, lsbU, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegH(rsbU, lsbU, seg, a); - seg = getSegH(rsbV, lsbV, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegH(rsbV, lsbV, seg, a); - - } - } - } - // sb left - - if (!rmb.isSkip_inner_lf()) { - for (int a = 1; a < 2; a++) { - for (int b = 0; b < 2; b++) { - SubBlock lsbU = rmb.getSubBlock(SubBlock.PLANE.U, - a - 1, b); - SubBlock rsbU = rmb.getSubBlock(SubBlock.PLANE.U, - a, b); - SubBlock lsbV = rmb.getSubBlock(SubBlock.PLANE.V, - a - 1, b); - SubBlock rsbV = rmb.getSubBlock(SubBlock.PLANE.V, - a, b); - for (int c = 0; c < 4; c++) { - Segment seg = getSegH(rsbU, lsbU, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegH(rsbU, lsbU, seg, c); - seg = getSegH(rsbV, lsbV, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegH(rsbV, lsbV, seg, c); - } - } - } - } - // top - if (y > 0) { - MacroBlock tmb = frame.getMacroBlock(x, y - 1); - for (int b = 0; b < 2; b++) { - SubBlock tsbU = tmb.getSubBlock(SubBlock.PLANE.U, b, 1); - SubBlock bsbU = bmb.getSubBlock(SubBlock.PLANE.U, b, 0); - SubBlock tsbV = tmb.getSubBlock(SubBlock.PLANE.V, b, 1); - SubBlock bsbV = bmb.getSubBlock(SubBlock.PLANE.V, b, 0); - for (int a = 0; a < 4; a++) { - // System.out.println("l"); - Segment seg = getSegV(bsbU, tsbU, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegV(bsbU, tsbU, seg, a); - seg = getSegV(bsbV, tsbV, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegV(bsbV, tsbV, seg, a); - } - } - } - // sb top - - if (!rmb.isSkip_inner_lf()) { - for (int a = 1; a < 2; a++) { - for (int b = 0; b < 2; b++) { - SubBlock tsbU = bmb.getSubBlock(SubBlock.PLANE.U, - b, a - 1); - SubBlock bsbU = bmb.getSubBlock(SubBlock.PLANE.U, - b, a); - SubBlock tsbV = bmb.getSubBlock(SubBlock.PLANE.V, - b, a - 1); - SubBlock bsbV = bmb.getSubBlock(SubBlock.PLANE.V, - b, a); - for (int c = 0; c < 4; c++) { - Segment seg = getSegV(bsbU, tsbU, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegV(bsbU, tsbU, seg, c); - seg = getSegV(bsbV, tsbV, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegV(bsbV, tsbV, seg, c); - } - } + // sb top + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 2; a++) { // TODO: This does not loop... + for (int b = 0; b < 2; b++) { + SubBlock tsbU = cmb.getSubBlock(SubBlock.Plane.U, b, a - 1); + SubBlock bsbU = cmb.getSubBlock(SubBlock.Plane.U, b, a); + SubBlock tsbV = cmb.getSubBlock(SubBlock.Plane.V, b, a - 1); + SubBlock bsbV = cmb.getSubBlock(SubBlock.Plane.V, b, a); + for (int c = 0; c < 4; c++) { + Segment seg = getSegV(bsbU, tsbU, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegV(bsbU, tsbU, seg, c); + seg = getSegV(bsbV, tsbV, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegV(bsbV, tsbV, seg, c); } } } @@ -416,111 +409,106 @@ final class LoopFilter { private static void loopFilterY(VP8Frame frame) { for (int y = 0; y < frame.getMacroBlockRows(); y++) { -// frame.fireLFProgressUpdate(50 + (100.0f * ((float) (y + 1) / (float) (frame -// .getMacroBlockRows()))) / 2); for (int x = 0; x < frame.getMacroBlockCols(); x++) { - MacroBlock rmb = frame.getMacroBlock(x, y); - MacroBlock bmb = frame.getMacroBlock(x, y); - int sharpnessLevel = frame.getSharpnessLevel(); - int loop_filter_level = rmb.getFilterLevel(); + loopFilterYBlock(frame.getMacroBlock(x, y), + x > 0 ? frame.getMacroBlock(x - 1, y) : null, + y > 0 ? frame.getMacroBlock(x, y - 1) : null, + frame.getSharpnessLevel(), frame.getFrameType()); + } + } + } - if (loop_filter_level != 0) { - int interior_limit = rmb.getFilterLevel(); + static void loopFilterYBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) { + int loop_filter_level = cmb.getFilterLevel(); - if (sharpnessLevel > 0) { - interior_limit >>= sharpnessLevel > 4 ? 2 : 1; - if (interior_limit > 9 - sharpnessLevel) { - interior_limit = 9 - sharpnessLevel; - } - } - if (interior_limit == 0) { - interior_limit = 1; - } + if (loop_filter_level != 0) { + int interior_limit = cmb.getFilterLevel(); - int hev_threshold = 0; - if (frame.getFrameType() == 0) /* current frame is a key frame */ { - if (loop_filter_level >= 40) { - hev_threshold = 2; - } else if (loop_filter_level >= 15) { - hev_threshold = 1; - } - } else /* current frame is an interframe */ { - if (loop_filter_level >= 40) { - hev_threshold = 3; - } else if (loop_filter_level >= 20) { - hev_threshold = 2; - } else if (loop_filter_level >= 15) { - hev_threshold = 1; - } - } + if (sharpnessLevel > 0) { + interior_limit >>= sharpnessLevel > 4 ? 2 : 1; + if (interior_limit > 9 - sharpnessLevel) { + interior_limit = 9 - sharpnessLevel; + } + } + if (interior_limit == 0) { + interior_limit = 1; + } - /* Luma and Chroma use the same inter-macroblock edge limit */ - int mbedge_limit = ((loop_filter_level + 2) * 2) - + interior_limit; - /* Luma and Chroma use the same inter-subblock edge limit */ - int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; + int hev_threshold = 0; + if (frameType == 0) { // current frame is a key frame + if (loop_filter_level >= 40) { + hev_threshold = 2; + } + else if (loop_filter_level >= 15) { + hev_threshold = 1; + } + } + else { // current frame is an interframe + if (loop_filter_level >= 40) { + hev_threshold = 3; + } + else if (loop_filter_level >= 20) { + hev_threshold = 2; + } + else if (loop_filter_level >= 15) { + hev_threshold = 1; + } + } - // left - if (x > 0) { - MacroBlock lmb = frame.getMacroBlock(x - 1, y); - for (int b = 0; b < 4; b++) { - SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, 0, b); - SubBlock lsb = lmb.getSubBlock(SubBlock.PLANE.Y1, 3, b); - for (int a = 0; a < 4; a++) { - Segment seg = getSegH(rsb, lsb, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegH(rsb, lsb, seg, a); - } + /* Luma and Chroma use the same inter-macroblock edge limit */ + int mbedge_limit = ((loop_filter_level + 2) * 2) + interior_limit; + /* Luma and Chroma use the same inter-subblock edge limit */ + int sub_bedge_limit = (loop_filter_level * 2) + interior_limit; + + // left + if (lmb != null) { + for (int b = 0; b < 4; b++) { + SubBlock rsb = cmb.getSubBlock(SubBlock.Plane.Y1, 0, b); + SubBlock lsb = lmb.getSubBlock(SubBlock.Plane.Y1, 3, b); + for (int a = 0; a < 4; a++) { + Segment seg = getSegH(rsb, lsb, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegH(rsb, lsb, seg, a); + } + } + } + // sb left + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 4; a++) { + for (int b = 0; b < 4; b++) { + SubBlock lsb = cmb.getSubBlock(SubBlock.Plane.Y1, a - 1, b); + SubBlock rsb = cmb.getSubBlock(SubBlock.Plane.Y1, a, b); + for (int c = 0; c < 4; c++) { + // System.out.println("sbleft a:"+a+" b:"+b+" c:"+c); + Segment seg = getSegH(rsb, lsb, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegH(rsb, lsb, seg, c); } } - // sb left - if (!rmb.isSkip_inner_lf()) { - for (int a = 1; a < 4; a++) { - for (int b = 0; b < 4; b++) { - SubBlock lsb = rmb.getSubBlock(SubBlock.PLANE.Y1, - a - 1, b); - SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, - a, b); - for (int c = 0; c < 4; c++) { - // System.out.println("sbleft a:"+a+" b:"+b+" c:"+c); - Segment seg = getSegH(rsb, lsb, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegH(rsb, lsb, seg, c); - } - } - } + } + } + // top + if (tmb != null) { + for (int b = 0; b < 4; b++) { + SubBlock tsb = tmb.getSubBlock(SubBlock.Plane.Y1, b, 3); + SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, 0); + for (int a = 0; a < 4; a++) { + Segment seg = getSegV(bsb, tsb, a); + MBfilter(hev_threshold, interior_limit, mbedge_limit, seg); + setSegV(bsb, tsb, seg, a); } - // top - if (y > 0) { - MacroBlock tmb = frame.getMacroBlock(x, y - 1); - for (int b = 0; b < 4; b++) { - SubBlock tsb = tmb.getSubBlock(SubBlock.PLANE.Y1, b, 3); - SubBlock bsb = bmb.getSubBlock(SubBlock.PLANE.Y1, b, 0); - for (int a = 0; a < 4; a++) { - Segment seg = getSegV(bsb, tsb, a); - MBfilter(hev_threshold, interior_limit, - mbedge_limit, seg); - setSegV(bsb, tsb, seg, a); - } - } - } - // sb top - if (!rmb.isSkip_inner_lf()) { - for (int a = 1; a < 4; a++) { - for (int b = 0; b < 4; b++) { - SubBlock tsb = bmb.getSubBlock(SubBlock.PLANE.Y1, - b, a - 1); - SubBlock bsb = bmb.getSubBlock(SubBlock.PLANE.Y1, - b, a); - for (int c = 0; c < 4; c++) { - Segment seg = getSegV(bsb, tsb, c); - subblock_filter(hev_threshold, interior_limit, - sub_bedge_limit, seg); - setSegV(bsb, tsb, seg, c); - } - } + } + } + // sb top + if (!cmb.isSkip_inner_lf()) { + for (int a = 1; a < 4; a++) { + for (int b = 0; b < 4; b++) { + SubBlock tsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a - 1); + SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a); + for (int c = 0; c < 4; c++) { + Segment seg = getSegV(bsb, tsb, c); + subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg); + setSegV(bsb, tsb, seg, c); } } } @@ -533,12 +521,11 @@ final class LoopFilter { int edge_limit, Segment seg) { int p3 = u2s(seg.P3), p2 = u2s(seg.P2), p1 = u2s(seg.P1), p0 = u2s(seg.P0); int q0 = u2s(seg.Q0), q1 = u2s(seg.Q1), q2 = u2s(seg.Q2), q3 = u2s(seg.Q3); - if (filter_yes(interior_limit, edge_limit, q3, q2, q1, q0, p0, p1, p2, - p3)) { + if (filter_yes(interior_limit, edge_limit, q3, q2, q1, q0, p0, p1, p2, p3)) { if (!hev(hev_threshold, p1, p0, q0, q1)) { // Same as the initial calculation in "common_adjust", // w is something like twice the edge difference - int w = c(c(p1 - q1) + 3 * (q0 - p0)); + int w = clamp(clamp(p1 - q1) + 3 * (q0 - p0)); // 9/64 is approximately 9/63 = 1/7 and 1<<7 = 128 = 2*64. // So this a, used to adjust the pixels adjacent to the edge, @@ -556,9 +543,9 @@ final class LoopFilter { a = (9 * w + 63) >> 7; seg.Q2 = s2u(q2 - a); seg.P2 = s2u(p2 + a); - } else - // if hev, do simple filter - { + } + else { + // if hev, do simple filter common_adjust(true, seg); // using outer taps } } @@ -566,7 +553,7 @@ final class LoopFilter { /* Clamp, then convert signed number back to pixel value. */ private static int s2u(int v) { - return c(v) + 128; + return clamp(v) + 128; } private static void setSegH(SubBlock rsb, SubBlock lsb, Segment seg, int a) { @@ -580,7 +567,6 @@ final class LoopFilter { rdest[1][a] = seg.Q1; rdest[2][a] = seg.Q2; rdest[3][a] = seg.Q3; - } private static void setSegV(SubBlock bsb, SubBlock tsb, Segment seg, int a) { @@ -594,29 +580,21 @@ final class LoopFilter { bdest[a][1] = seg.Q1; bdest[a][2] = seg.Q2; bdest[a][3] = seg.Q3; - } - private static void simple_segment(int edge_limit, /* - * do nothing if edge - * difference exceeds - * limit - */ - Segment seg) { + private static void simple_segment(int edge_limit, // do nothing if edge difference exceeds limit + Segment seg) { if ((abs(seg.P0 - seg.Q0) * 2 + abs(seg.P1 - seg.Q1) / 2) <= edge_limit) { - common_adjust(true, seg); /* use outer taps */ + common_adjust(true, seg); // use outer taps } else { // TODO? } } - private static void subblock_filter(int hev_threshold, /* - * detect high edge - * variance - */ - int interior_limit, /* possibly disable filter */ - int edge_limit, Segment seg) { + private static void subblock_filter(int hev_threshold, // detect high edge variance + int interior_limit, // possibly disable filter + int edge_limit, Segment seg) { int p3 = u2s(seg.P3), p2 = u2s(seg.P2), p1 = u2s(seg.P1), p0 = u2s(seg.P0); int q0 = u2s(seg.Q0), q1 = u2s(seg.Q1), q2 = u2s(seg.Q2), q3 = u2s(seg.Q3); if (filter_yes(interior_limit, edge_limit, q3, q2, q1, q0, p0, p1, p2, p3)) { @@ -630,7 +608,6 @@ final class LoopFilter { else { // TODO? } - } /* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */ diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/MacroBlock.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/MacroBlock.java index 5a15befb..d9ed2fbc 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/MacroBlock.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/MacroBlock.java @@ -36,19 +36,19 @@ import java.io.IOException; final class MacroBlock { private int filterLevel; - private boolean keepDebugInfo = false; + private final boolean keepDebugInfo; private int segmentId; private int skipCoeff; private boolean skipInnerLoopFilter; - SubBlock[][] uSubBlocks; + final SubBlock[][] uSubBlocks; private int uVFilterLevel; private int uvMode; - SubBlock[][] vSubBlocks; - private int x, y; - SubBlock y2SubBlock; + final SubBlock[][] vSubBlocks; + private final int x, y; + final SubBlock y2SubBlock; private int yMode; - SubBlock[][] ySubBlocks; + final SubBlock[][] ySubBlocks; MacroBlock(int x, int y, boolean keepDebugInfo) { this.x = x - 1; @@ -58,8 +58,8 @@ final class MacroBlock { ySubBlocks = new SubBlock[4][4]; uSubBlocks = new SubBlock[2][2]; vSubBlocks = new SubBlock[2][2]; - SubBlock above = null; - SubBlock left = null; + SubBlock above; + SubBlock left; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -72,7 +72,7 @@ final class MacroBlock { above = ySubBlocks[j][i - 1]; } ySubBlocks[j][i] = new SubBlock(this, above, left, - SubBlock.PLANE.Y1); + SubBlock.Plane.Y1); } } @@ -87,7 +87,7 @@ final class MacroBlock { above = uSubBlocks[j][i - 1]; } uSubBlocks[j][i] = new SubBlock(this, above, left, - SubBlock.PLANE.U); + SubBlock.Plane.U); } } @@ -101,12 +101,10 @@ final class MacroBlock { if (i > 0) { above = vSubBlocks[j][i - 1]; } - vSubBlocks[j][i] = new SubBlock(this, above, left, - SubBlock.PLANE.V); + vSubBlocks[j][i] = new SubBlock(this, above, left, SubBlock.Plane.V); } } - y2SubBlock = new SubBlock(this, null, null, SubBlock.PLANE.Y2); - + y2SubBlock = new SubBlock(this, null, null, SubBlock.Plane.Y2); } public void decodeMacroBlock(VP8Frame frame) throws IOException { @@ -115,57 +113,51 @@ final class MacroBlock { if (mb.getYMode() != Globals.B_PRED) { mb.skipInnerLoopFilter = true; } - } else if (mb.getYMode() != Globals.B_PRED) { - decodeMacroBlockTokens(frame, true); - } else { - decodeMacroBlockTokens(frame, false); + } + else { + decodeMacroBlockTokens(frame, mb.getYMode() != Globals.B_PRED); } } - private void decodeMacroBlockTokens(VP8Frame frame, boolean withY2) - throws IOException { - skipInnerLoopFilter = false; + private void decodeMacroBlockTokens(VP8Frame frame, boolean withY2) throws IOException { if (withY2) { - skipInnerLoopFilter = skipInnerLoopFilter - | decodePlaneTokens(frame, 1, SubBlock.PLANE.Y2, false); + skipInnerLoopFilter = decodePlaneTokens(frame, 1, SubBlock.Plane.Y2, false); } - skipInnerLoopFilter = skipInnerLoopFilter - | decodePlaneTokens(frame, 4, SubBlock.PLANE.Y1, withY2); - skipInnerLoopFilter = skipInnerLoopFilter - | decodePlaneTokens(frame, 2, SubBlock.PLANE.U, false); - skipInnerLoopFilter = skipInnerLoopFilter - | decodePlaneTokens(frame, 2, SubBlock.PLANE.V, false); + + skipInnerLoopFilter |= decodePlaneTokens(frame, 4, SubBlock.Plane.Y1, withY2); + skipInnerLoopFilter |= decodePlaneTokens(frame, 2, SubBlock.Plane.U, false); + skipInnerLoopFilter |= decodePlaneTokens(frame, 2, SubBlock.Plane.V, false); + skipInnerLoopFilter = !skipInnerLoopFilter; } private boolean decodePlaneTokens(VP8Frame frame, int dimentions, - SubBlock.PLANE plane, boolean withY2) throws IOException { + SubBlock.Plane plane, boolean withY2) throws IOException { MacroBlock mb = this; boolean r = false; + for (int y = 0; y < dimentions; y++) { for (int x = 0; x < dimentions; x++) { int L = 0; int A = 0; int lc = 0; + SubBlock sb = mb.getSubBlock(plane, x, y); SubBlock left = frame.getLeftSubBlock(sb, plane); SubBlock above = frame.getAboveSubBlock(sb, plane); - if (left.hasNoZeroToken()) { + if (left.hasNoZeroToken()) { L = 1; } lc += L; if (above.hasNoZeroToken()) { - A = 1; } lc += A; - sb.decodeSubBlock(frame.getTokenBoolDecoder(), - frame.getCoefProbs(), lc, - SubBlock.planeToType(plane, withY2), withY2); + sb.decodeSubBlock(frame.getTokenBoolDecoder(), frame.getCoefProbs(), lc, SubBlock.planeToType(plane, withY2), withY2); r = r | sb.hasNoZeroToken(); } } @@ -180,7 +172,7 @@ final class MacroBlock { .getY2ac_delta_q(); int dcQValue = frame.getSegmentQuants().getSegQuants()[this.getSegmentId()].getY2dc(); - int input[] = new int[16]; + int[] input = new int[16]; input[0] = sb.getTokens()[0] * dcQValue; for (int x = 1; x < 16; x++) { @@ -206,8 +198,8 @@ final class MacroBlock { } } mb.recon_mb(); - - } else { + } + else { for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { SubBlock sb = mb.getYSubBlock(i, j); @@ -260,7 +252,7 @@ final class MacroBlock { return this.filterLevel; } - public SubBlock getBottomSubBlock(int x, SubBlock.PLANE plane) { + public SubBlock getBottomSubBlock(int x, SubBlock.Plane plane) { switch (plane) { case Y1: return ySubBlocks[x][3]; @@ -275,7 +267,7 @@ final class MacroBlock { throw new IllegalArgumentException("Bad plane: " + plane); } - public SubBlock getLeftSubBlock(int y, SubBlock.PLANE plane) { + public SubBlock getLeftSubBlock(int y, SubBlock.Plane plane) { switch (plane) { case Y1: return ySubBlocks[0][y]; @@ -290,7 +282,7 @@ final class MacroBlock { throw new IllegalArgumentException("Bad plane: " + plane); } - public SubBlock getRightSubBlock(int y, SubBlock.PLANE plane) { + public SubBlock getRightSubBlock(int y, SubBlock.Plane plane) { switch (plane) { case Y1: return ySubBlocks[3][y]; @@ -309,7 +301,7 @@ final class MacroBlock { return skipCoeff; } - public SubBlock getSubBlock(SubBlock.PLANE plane, int i, int j) { + public SubBlock getSubBlock(SubBlock.Plane plane, int i, int j) { switch (plane) { case Y1: return getYSubBlock(i, j); @@ -325,7 +317,7 @@ final class MacroBlock { } public int getSubblockX(SubBlock sb) { - if (sb.getPlane() == SubBlock.PLANE.Y1) { + if (sb.getPlane() == SubBlock.Plane.Y1) { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (ySubBlocks[x][y] == sb) { @@ -333,7 +325,8 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.U) { + } + else if (sb.getPlane() == SubBlock.Plane.U) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { if (uSubBlocks[x][y] == sb) { @@ -341,7 +334,8 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.V) { + } + else if (sb.getPlane() == SubBlock.Plane.V) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { if (vSubBlocks[x][y] == sb) { @@ -349,16 +343,16 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.Y2) { + } + else if (sb.getPlane() == SubBlock.Plane.Y2) { return 0; } return -100; - } public int getSubblockY(SubBlock sb) { - if (sb.getPlane() == SubBlock.PLANE.Y1) { + if (sb.getPlane() == SubBlock.Plane.Y1) { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (ySubBlocks[x][y] == sb) { @@ -366,7 +360,8 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.U) { + } + else if (sb.getPlane() == SubBlock.Plane.U) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { if (uSubBlocks[x][y] == sb) { @@ -374,7 +369,8 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.V) { + } + else if (sb.getPlane() == SubBlock.Plane.V) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { if (vSubBlocks[x][y] == sb) { @@ -382,7 +378,8 @@ final class MacroBlock { } } } - } else if (sb.getPlane() == SubBlock.PLANE.Y2) { + } + else if (sb.getPlane() == SubBlock.Plane.Y2) { return 0; } @@ -445,8 +442,8 @@ final class MacroBlock { boolean left_available = false; int Uaverage = 0; int Vaverage = 0; - int expected_udc = 0; - int expected_vdc = 0; + int expected_udc; + int expected_vdc; if (x > 0) { left_available = true; } @@ -486,19 +483,20 @@ final class MacroBlock { expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; - } else { + } + else { expected_udc = 128; expected_vdc = 128; } - int ufill[][] = new int[4][4]; + int[][] ufill = new int[4][4]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { ufill[x][y] = expected_udc; } } - int vfill[][] = new int[4][4]; + int[][] vfill = new int[4][4]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { vfill[x][y] = expected_vdc; @@ -529,8 +527,8 @@ final class MacroBlock { for (int x = 0; x < 2; x++) { SubBlock usb = uSubBlocks[y][x]; SubBlock vsb = vSubBlocks[y][x]; - int ublock[][] = new int[4][4]; - int vblock[][] = new int[4][4]; + int[][] ublock = new int[4][4]; + int[][] vblock = new int[4][4]; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { ublock[j][i] = aboveUSb[y] @@ -560,8 +558,8 @@ final class MacroBlock { for (int x = 0; x < 2; x++) { SubBlock usb = uSubBlocks[x][y]; SubBlock vsb = vSubBlocks[x][y]; - int ublock[][] = new int[4][4]; - int vblock[][] = new int[4][4]; + int[][] ublock = new int[4][4]; + int[][] vblock = new int[4][4]; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { ublock[i][j] = leftUSb[y] @@ -610,10 +608,8 @@ final class MacroBlock { + aboveVSb[d].getDest()[c][3] - alv; vpred = Globals.clamp(vpred, 255); vSubBlocks[d][b].setPixel(c, a, vpred); - } } - } } @@ -635,7 +631,7 @@ final class MacroBlock { boolean left_available = false; int average = 0; - int expected_dc = 0; + int expected_dc; if (x > 0) { left_available = true; } @@ -671,11 +667,12 @@ final class MacroBlock { } expected_dc = (average + (1 << (shift - 1))) >> shift; - } else { + } + else { expected_dc = 128; } - int fill[][] = new int[4][4]; + int[][] fill = new int[4][4]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { fill[x][y] = expected_dc; @@ -700,7 +697,7 @@ final class MacroBlock { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { SubBlock sb = ySubBlocks[x][y]; - int block[][] = new int[4][4]; + int[][] block = new int[4][4]; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { block[i][j] = aboveYSb[x].getPredict( @@ -708,7 +705,6 @@ final class MacroBlock { } } sb.setPredict(block); - } } @@ -725,7 +721,7 @@ final class MacroBlock { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { SubBlock sb = ySubBlocks[x][y]; - int block[][] = new int[4][4]; + int[][] block = new int[4][4]; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { block[i][j] = leftYSb[y].getPredict( @@ -736,10 +732,10 @@ final class MacroBlock { } } - SubBlock[] leftUSb = new SubBlock[2]; - for (int x = 0; x < 2; x++) { - leftUSb[x] = leftMb.getYSubBlock(1, x); - } +// SubBlock[] leftUSb = new SubBlock[2]; +// for (int x = 0; x < 2; x++) { +// leftUSb[x] = leftMb.getYSubBlock(1, x); +// } break; case Globals.TM_PRED: @@ -756,23 +752,20 @@ final class MacroBlock { for (int x = 0; x < 4; x++) { leftYSb[x] = leftMb.getYSubBlock(3, x); } - fill = new int[4][4]; +// fill = new int[4][4]; for (int b = 0; b < 4; b++) { for (int a = 0; a < 4; a++) { for (int d = 0; d < 4; d++) { for (int c = 0; c < 4; c++) { - int pred = leftYSb[b].getDest()[3][a] + aboveYSb[d].getDest()[c][3] - al; ySubBlocks[d][b].setPixel(c, a, Globals.clamp(pred, 255)); - } } - } } @@ -803,7 +796,6 @@ final class MacroBlock { sb.reconstruct(); } } - } public void setFilterLevel(int value) { diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuant.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuant.java index 5304fb37..f58491f4 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuant.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuant.java @@ -31,6 +31,8 @@ package com.twelvemonkeys.imageio.plugins.webp.vp8; +import static com.twelvemonkeys.imageio.plugins.webp.vp8.Globals.clamp; + final class SegmentQuant { private int filterStrength; private int Qindex; @@ -41,17 +43,6 @@ final class SegmentQuant { private int y2ac; private int y2dc; - private int clip(int val, int max) { - int r = val; - if (val > max) { - r = max; - } - if (r < 0) { - r = 0; - } - return r; - } - public int getQindex() { return Qindex; } @@ -89,31 +80,31 @@ final class SegmentQuant { } public void setUvac_delta_q(int uvac_delta_q) { - this.uvac = Globals.vp8AcQLookup[clip(Qindex + uvac_delta_q, 127)]; + this.uvac = Globals.vp8AcQLookup[clamp(Qindex + uvac_delta_q, 127)]; } public void setUvdc_delta_q(int uvdc_delta_q) { - this.uvdc = Globals.vp8DcQLookup[clip(Qindex + uvdc_delta_q, 127)]; + this.uvdc = Globals.vp8DcQLookup[clamp(Qindex + uvdc_delta_q, 127)]; } public void setY1ac() { - this.y1ac = Globals.vp8AcQLookup[clip(Qindex, 127)]; + this.y1ac = Globals.vp8AcQLookup[clamp(Qindex, 127)]; } public void setY1dc(int y1dc) { - this.y1dc = Globals.vp8DcQLookup[clip(Qindex + y1dc, 127)]; + this.y1dc = Globals.vp8DcQLookup[clamp(Qindex + y1dc, 127)]; this.setY1ac(); } public void setY2ac_delta_q(int y2ac_delta_q) { - this.y2ac = Globals.vp8AcQLookup[clip(Qindex + y2ac_delta_q, 127)] * 155 / 100; + this.y2ac = Globals.vp8AcQLookup[clamp(Qindex + y2ac_delta_q, 127)] * 155 / 100; if (this.y2ac < 8) { this.y2ac = 8; } } public void setY2dc(int y2dc_delta_q) { - this.y2dc = Globals.vp8DcQLookup[clip(Qindex + y2dc_delta_q, 127)] * 2; + this.y2dc = Globals.vp8DcQLookup[clamp(Qindex + y2dc_delta_q, 127)] * 2; } public int getFilterStrength() { diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuants.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuants.java index 1099fe75..32536f6b 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuants.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SegmentQuants.java @@ -35,8 +35,17 @@ import java.io.IOException; final class SegmentQuants { - private static DeltaQ get_delta_q(BoolDecoder bc, int prev) - throws IOException { + private int qIndex; + + private final SegmentQuant[] segQuants = new SegmentQuant[Globals.MAX_MB_SEGMENTS]; + + public SegmentQuants() { + for (int x = 0; x < Globals.MAX_MB_SEGMENTS; x++) { + segQuants[x] = new SegmentQuant(); + } + } + + private static DeltaQ get_delta_q(BoolDecoder bc, int prev) throws IOException { DeltaQ ret = new DeltaQ(); ret.v = 0; ret.update = false; @@ -49,7 +58,7 @@ final class SegmentQuants { } } - /* Trigger a quantizer update if the delta-q value has changed */ + // Trigger a quantizer update if the delta-q value has changed if (ret.v != prev) { ret.update = true; } @@ -57,16 +66,6 @@ final class SegmentQuants { return ret; } - private int qIndex; - - private SegmentQuant[] segQuants = new SegmentQuant[Globals.MAX_MB_SEGMENTS]; - - public SegmentQuants() { - for (int x = 0; x < Globals.MAX_MB_SEGMENTS; x++) { - segQuants[x] = new SegmentQuant(); - } - } - public int getqIndex() { return qIndex; } @@ -76,7 +75,7 @@ final class SegmentQuants { } public void parse(BoolDecoder bc, boolean segmentation_enabled, - boolean mb_segement_abs_delta) throws IOException { + boolean mb_segement_abs_delta) throws IOException { qIndex = bc.readLiteral(7); boolean q_update = false; DeltaQ v = get_delta_q(bc, 0); @@ -98,7 +97,8 @@ final class SegmentQuants { for (SegmentQuant s : segQuants) { if (!segmentation_enabled) { s.setQindex(qIndex); - } else if (!mb_segement_abs_delta) { + } + else if (!mb_segement_abs_delta) { s.setQindex(s.getQindex() + qIndex); } @@ -107,11 +107,6 @@ final class SegmentQuants { s.setY2ac_delta_q(y2ac_delta_q); s.setUvdc_delta_q(uvdc_delta_q); s.setUvac_delta_q(uvac_delta_q); - } } - - public void setSegQuants(SegmentQuant[] segQuants) { - this.segQuants = segQuants; - } } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java index 0577d8b5..4158ece7 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java @@ -34,75 +34,72 @@ package com.twelvemonkeys.imageio.plugins.webp.vp8; import java.io.IOException; final class SubBlock { - public enum PLANE { - U, V, Y1, Y2 - } + public enum Plane { + U, V, Y1, Y2 + } - public static int planeToType(PLANE plane, Boolean withY2) { - switch (plane) { - case Y2: - return 1; - case Y1: - if (withY2) - return 0; - else - return 3; - case U: - return 2; - case V: - return 2; - } - return -1; + private final SubBlock above; - } + private int[][] dest; + private int[][] diff; + private boolean hasNoZeroToken; + private final SubBlock left; + private final MacroBlock macroBlock; + private int mode; + private final Plane plane; + private int[][] predict; + private int[] tokens = new int[16]; - private SubBlock above; + SubBlock(MacroBlock macroBlock, SubBlock above, SubBlock left, Plane plane) { + this.macroBlock = macroBlock; + this.plane = plane; + this.above = above; + this.left = left; + mode = 0; - private int[][] dest; - private int[][] diff; - private boolean hasNoZeroToken; - private SubBlock left; - private MacroBlock macroBlock; - private int mode; - private PLANE plane; - private int predict[][]; - private int tokens[]; + for (int z = 0; z < 16; z++) { + tokens[z] = 0; + } + } - SubBlock(MacroBlock macroBlock, SubBlock above, SubBlock left, - SubBlock.PLANE plane) { - this.macroBlock = macroBlock; - this.plane = plane; - this.above = above; - this.left = left; - mode = 0; - tokens = new int[16]; - for (int z = 0; z < 16; z++) - tokens[z] = 0; - } + public static int planeToType(Plane plane, boolean withY2) { + switch (plane) { + case Y2: + return 1; + case Y1: + return withY2 ? 0 : 3; + case U: + case V: + return 2; + } - private int DCTextra(BoolDecoder bc2, int p[]) throws IOException { - int v = 0; - int offset = 0; - do { - v += v + bc2.readBool(p[offset]); - offset++; - } while (p[offset] > 0); - return v; - } + return -1; + } - public void decodeSubBlock(BoolDecoder bc2, int[][][][] coef_probs, - int ilc, int type, boolean withY2) throws IOException { - SubBlock sb = this; - int startAt = 0; - if (withY2) - startAt = 1; - int lc = ilc; - int c = 0; - int v = 1; + private int DCTextra(BoolDecoder bc2, int[] p) throws IOException { + int v = 0; + int offset = 0; + do { + v += v + bc2.readBool(p[offset]); + offset++; + } while (p[offset] > 0); + return v; + } - boolean skip = false; + public void decodeSubBlock(BoolDecoder bc2, int[][][][] coef_probs, + int ilc, int type, boolean withY2) throws IOException { + SubBlock sb = this; + int startAt = 0; + if (withY2) { + startAt = 1; + } + int lc = ilc; + int c = 0; + int v = 1; - while (!(v == Globals.dct_eob) && c + startAt < 16) { + boolean skip = false; + + while (!(v == Globals.dct_eob) && c + startAt < 16) { // if (!skip) // v = bc2.readTree(Globals.vp8CoefTree, @@ -112,518 +109,540 @@ final class SubBlock { // Globals.vp8CoefTree, // coef_probs[type][Globals.vp8CoefBands[c + startAt]][lc], // 1); - v = bc2.readTree(Globals.vp8CoefTree, coef_probs[type][Globals.vp8CoefBands[c + startAt]][lc], - skip ? 1 : 0); - - int dv = decodeToken(bc2, v); - lc = 0; - skip = false; - if (dv == 1 || dv == -1) - lc = 1; - else if (dv > 1 || dv < -1) - lc = 2; - else if (dv == Globals.DCT_0) - skip = true; - - int tokens[] = sb.getTokens(); - - if (v != Globals.dct_eob) - tokens[Globals.vp8defaultZigZag1d[c + startAt]] = dv; - c++; - } - hasNoZeroToken = false; - for (int x = 0; x < 16; x++) - if (tokens[x] != 0) - hasNoZeroToken = true; - } - - private int decodeToken(BoolDecoder bc2, int v) throws IOException { - int r = v; - - if (v == Globals.dct_cat1) { - r = 5 + DCTextra(bc2, Globals.Pcat1); - } - if (v == Globals.dct_cat2) { - r = 7 + DCTextra(bc2, Globals.Pcat2); - } - if (v == Globals.dct_cat3) { - r = 11 + DCTextra(bc2, Globals.Pcat3); - } - if (v == Globals.dct_cat4) { - r = 19 + DCTextra(bc2, Globals.Pcat4); - } - if (v == Globals.dct_cat5) { - r = 35 + DCTextra(bc2, Globals.Pcat5); - } - if (v == Globals.dct_cat6) { - r = 67 + DCTextra(bc2, Globals.Pcat6); - } - if (v != Globals.DCT_0 && v != Globals.dct_eob) { - if (bc2.readBit() > 0) - r = -r; - } - - return r; - } - - public void dequantSubBlock(VP8Frame frame, Integer Dc) { - SubBlock sb = this; - - int[] adjustedValues = new int[16]; - for (int i = 0; i < 16; i++) { - int QValue; - if (plane == PLANE.U || plane == PLANE.V) { - QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] - .getUvac_delta_q(); - if (i == 0) - QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] - .getUvdc_delta_q(); - } else { - QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()].getY1ac(); - if (i == 0) - QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] - .getY1dc(); - } - - int inputValue = sb.getTokens()[i]; - adjustedValues[i] = inputValue * QValue; - - } - - if (Dc != null) - adjustedValues[0] = Dc; - - int[][] diff = IDCT.idct4x4llm(adjustedValues); - sb.setDiff(diff); - - } - - public void drawDebug() { - if (dest != null) { - dest[0][0] = 128; - dest[1][0] = 128; - dest[2][0] = 128; - dest[3][0] = 128; - dest[0][0] = 128; - dest[0][1] = 128; - dest[0][2] = 128; - dest[0][3] = 128; - } - - } - - public void drawDebugH() { - if (dest != null) { - dest[0][0] = 0; - dest[1][0] = 0; - dest[2][0] = 0; - dest[3][0] = 0; - } - - } - - public void drawDebugV() { - if (dest != null) { - dest[0][0] = 0; - dest[0][1] = 0; - dest[0][2] = 0; - dest[0][3] = 0; - } - } - - public SubBlock getAbove() { - - return above; - } - - public String getDebugString() { - String r = new String(); - r = r + " " + plane; - if (getMacroBlock().getYMode() == Globals.B_PRED - && plane == SubBlock.PLANE.Y1) - r = r + "\n " + Globals.getSubBlockModeAsString(mode); - return r; - } - - public int[][] getDest() { - if (dest != null) - return dest; - else - return new int[4][4]; - } - - public int[][] getDiff() { - - return diff; - } - - public SubBlock getLeft() { - - return left; - } - - public MacroBlock getMacroBlock() { - return macroBlock; - } - - public int[][] getMacroBlockPredict(int intra_mode) { - if (dest != null) - return dest; - - else { - int rv = 127; - if (intra_mode == Globals.H_PRED) - rv = 129; - int r[][] = new int[4][4]; - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - r[i][j] = rv; - return r; - } - } - - public int getMode() { - return mode; - } - - public PLANE getPlane() { - return plane; - } - - public int[][] getPredict() { - if (predict != null) - return predict; - return getPredict(Globals.B_DC_PRED, false); - } - - public int[][] getPredict(int intra_bmode, boolean left) { - if (dest != null) - return dest; - if (predict != null) - return predict; - else { - int rv = 127; - - if ((intra_bmode == Globals.B_TM_PRED - || intra_bmode == Globals.B_DC_PRED - || intra_bmode == Globals.B_VE_PRED - || intra_bmode == Globals.B_HE_PRED - || intra_bmode == Globals.B_VR_PRED - || intra_bmode == Globals.B_RD_PRED || intra_bmode == Globals.B_HD_PRED) - && left) - - rv = 129; - int r[][] = new int[4][4]; - for (int j = 0; j < 4; j++) - for (int i = 0; i < 4; i++) - r[i][j] = rv; - return r; - } - } - - int[] getTokens() { - return tokens; - } - - public boolean hasNoZeroToken() { - return hasNoZeroToken; - } - - public boolean isDest() { - if (dest == null) - return false; - return true; - } - - public void predict(VP8Frame frame) { - SubBlock sb = this; - SubBlock aboveSb = frame.getAboveSubBlock(sb, sb.getPlane()); - SubBlock leftSb = frame.getLeftSubBlock(sb, sb.getPlane()); - - int[] above = new int[4]; - int[] left = new int[4]; - - above[0] = aboveSb.getPredict(sb.getMode(), false)[0][3]; - above[1] = aboveSb.getPredict(sb.getMode(), false)[1][3]; - above[2] = aboveSb.getPredict(sb.getMode(), false)[2][3]; - above[3] = aboveSb.getPredict(sb.getMode(), false)[3][3]; - left[0] = leftSb.getPredict(sb.getMode(), true)[3][0]; - left[1] = leftSb.getPredict(sb.getMode(), true)[3][1]; - left[2] = leftSb.getPredict(sb.getMode(), true)[3][2]; - left[3] = leftSb.getPredict(sb.getMode(), true)[3][3]; - SubBlock AL = frame.getLeftSubBlock(aboveSb, sb.getPlane()); - - // for above left if left and above is null use left (129?) else use - // above (127?) - int al; - if (!leftSb.isDest() && !aboveSb.isDest()) { - - al = AL.getPredict(sb.getMode(), false)[3][3]; - } else if (!aboveSb.isDest()) { - - al = AL.getPredict(sb.getMode(), false)[3][3]; - } else - al = AL.getPredict(sb.getMode(), true)[3][3]; - SubBlock AR = frame.getAboveRightSubBlock(sb, sb.plane); - int ar[] = new int[4]; - ar[0] = AR.getPredict(sb.getMode(), false)[0][3]; - ar[1] = AR.getPredict(sb.getMode(), false)[1][3]; - ar[2] = AR.getPredict(sb.getMode(), false)[2][3]; - ar[3] = AR.getPredict(sb.getMode(), false)[3][3]; - int[][] p = new int[4][4]; - int pp[]; - switch (sb.getMode()) { - case Globals.B_DC_PRED: - // System.out.println("B_DC_PRED"); - int expected_dc = 0; - - for (int i = 0; i < 4; i++) { - expected_dc += above[i]; - expected_dc += left[i]; - } - expected_dc = (expected_dc + 4) >> 3; - - for (int y = 0; y < 4; y++) - for (int x = 0; x < 4; x++) - p[x][y] = expected_dc; - - break; - case Globals.B_TM_PRED: - - // System.out.println("B_TM_PRED"); - - // prediction similar to true_motion prediction - - for (int r = 0; r < 4; r++) { - for (int c = 0; c < 4; c++) { - - int pred = above[c] - al + left[r]; - if (pred < 0) - pred = 0; - - if (pred > 255) - pred = 255; - - p[c][r] = pred; - } - } - break; - case Globals.B_VE_PRED: - // System.out.println("B_VE_PRED"); - - int ap[] = new int[4]; - ap[0] = (al + 2 * above[0] + above[1] + 2) >> 2; - ap[1] = (above[0] + 2 * above[1] + above[2] + 2) >> 2; - ap[2] = (above[1] + 2 * above[2] + above[3] + 2) >> 2; - ap[3] = (above[2] + 2 * above[3] + ar[0] + 2) >> 2; - - for (int r = 0; r < 4; r++) { - for (int c = 0; c < 4; c++) { - - p[c][r] = ap[c]; - - } - } - break; - case Globals.B_HE_PRED: - // System.out.println("B_HE_PRED"); - - int lp[] = new int[4]; - lp[0] = (al + 2 * left[0] + left[1] + 2) >> 2; - lp[1] = (left[0] + 2 * left[1] + left[2] + 2) >> 2; - lp[2] = (left[1] + 2 * left[2] + left[3] + 2) >> 2; - lp[3] = (left[2] + 2 * left[3] + left[3] + 2) >> 2; - - for (int r = 0; r < 4; r++) { - for (int c = 0; c < 4; c++) { - p[c][r] = lp[r]; - } - } - break; - case Globals.B_LD_PRED: - // System.out.println("B_LD_PRED"); - p[0][0] = (above[0] + above[1] * 2 + above[2] + 2) >> 2; - p[1][0] = p[0][1] = (above[1] + above[2] * 2 + above[3] + 2) >> 2; - p[2][0] = p[1][1] = p[0][2] = (above[2] + above[3] * 2 + ar[0] + 2) >> 2; - p[3][0] = p[2][1] = p[1][2] = p[0][3] = (above[3] + ar[0] * 2 - + ar[1] + 2) >> 2; - p[3][1] = p[2][2] = p[1][3] = (ar[0] + ar[1] * 2 + ar[2] + 2) >> 2; - p[3][2] = p[2][3] = (ar[1] + ar[2] * 2 + ar[3] + 2) >> 2; - p[3][3] = (ar[2] + ar[3] * 2 + ar[3] + 2) >> 2; - - break; - case Globals.B_RD_PRED: - // System.out.println("B_RD_PRED"); - pp = new int[9]; - - pp[0] = left[3]; - pp[1] = left[2]; - pp[2] = left[1]; - pp[3] = left[0]; - pp[4] = al; - pp[5] = above[0]; - pp[6] = above[1]; - pp[7] = above[2]; - pp[8] = above[3]; - - p[0][3] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; - p[1][3] = p[0][2] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; - p[2][3] = p[1][2] = p[0][1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; - p[3][3] = p[2][2] = p[1][1] = p[0][0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; - p[3][2] = p[2][1] = p[1][0] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; - p[3][1] = p[2][0] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; - p[3][0] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; - break; - - case Globals.B_VR_PRED: - // System.out.println("B_VR_PRED"); - pp = new int[9]; - - pp[0] = left[3]; - pp[1] = left[2]; - pp[2] = left[1]; - pp[3] = left[0]; - pp[4] = al; - pp[5] = above[0]; - pp[6] = above[1]; - pp[7] = above[2]; - pp[8] = above[3]; - - p[0][3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; - p[0][2] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; - p[1][3] = p[0][1] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; - p[1][2] = p[0][0] = (pp[4] + pp[5] + 1) >> 1; - p[2][3] = p[1][1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; - p[2][2] = p[1][0] = (pp[5] + pp[6] + 1) >> 1; - p[3][3] = p[2][1] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; - p[3][2] = p[2][0] = (pp[6] + pp[7] + 1) >> 1; - p[3][1] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; - p[3][0] = (pp[7] + pp[8] + 1) >> 1; - - break; - case Globals.B_VL_PRED: - // System.out.println("B_VL_PRED"); - - p[0][0] = (above[0] + above[1] + 1) >> 1; - p[0][1] = (above[0] + above[1] * 2 + above[2] + 2) >> 2; - p[0][2] = p[1][0] = (above[1] + above[2] + 1) >> 1; - p[1][1] = p[0][3] = (above[1] + above[2] * 2 + above[3] + 2) >> 2; - p[1][2] = p[2][0] = (above[2] + above[3] + 1) >> 1; - p[1][3] = p[2][1] = (above[2] + above[3] * 2 + ar[0] + 2) >> 2; - p[3][0] = p[2][2] = (above[3] + ar[0] + 1) >> 1; - p[3][1] = p[2][3] = (above[3] + ar[0] * 2 + ar[1] + 2) >> 2; - p[3][2] = (ar[0] + ar[1] * 2 + ar[2] + 2) >> 2; - p[3][3] = (ar[1] + ar[2] * 2 + ar[3] + 2) >> 2; - - break; - case Globals.B_HD_PRED: - // System.out.println("B_HD_PRED"); - pp = new int[9]; - pp[0] = left[3]; - pp[1] = left[2]; - pp[2] = left[1]; - pp[3] = left[0]; - pp[4] = al; - pp[5] = above[0]; - pp[6] = above[1]; - pp[7] = above[2]; - pp[8] = above[3]; - - p[0][3] = (pp[0] + pp[1] + 1) >> 1; - p[1][3] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; - p[0][2] = p[2][3] = (pp[1] + pp[2] + 1) >> 1; - p[1][2] = p[3][3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; - p[2][2] = p[0][1] = (pp[2] + pp[3] + 1) >> 1; - p[3][2] = p[1][1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; - p[2][1] = p[0][0] = (pp[3] + pp[4] + 1) >> 1; - p[3][1] = p[1][0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; - p[2][0] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; - p[3][0] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; - break; - case Globals.B_HU_PRED: - // System.out.println("B_HU_PRED"); - - p[0][0] = (left[0] + left[1] + 1) >> 1; - p[1][0] = (left[0] + left[1] * 2 + left[2] + 2) >> 2; - p[2][0] = p[0][1] = (left[1] + left[2] + 1) >> 1; - p[3][0] = p[1][1] = (left[1] + left[2] * 2 + left[3] + 2) >> 2; - p[2][1] = p[0][2] = (left[2] + left[3] + 1) >> 1; - p[3][1] = p[1][2] = (left[2] + left[3] * 2 + left[3] + 2) >> 2; - p[2][2] = p[3][2] = p[0][3] = p[1][3] = p[2][3] = p[3][3] = left[3]; - break; - - default: - // TODO: FixME! - throw new AssertionError("TODO mode: " + sb.getMode()); - } - - sb.setPredict(p); - } - - public void reconstruct() { - SubBlock sb = this; - - int r, c; - int p[][] = sb.getPredict(1, false); - - int dest[][] = new int[4][4]; - int diff[][] = sb.getDiff(); - - for (r = 0; r < 4; r++) { - for (c = 0; c < 4; c++) { - int a = diff[r][c] + p[r][c]; - - if (a < 0) - a = 0; - - if (a > 255) - a = 255; - - dest[r][c] = a; - - } - - } - - sb.setDest(dest); - if (!this.getMacroBlock().isKeepDebugInfo()) { - sb.diff = null; - sb.predict = null; - sb.tokens = null; - } - } - - public void setDest(int[][] dest) { - this.dest = dest; - } - - public void setDiff(int[][] diff) { - this.diff = diff; - } - - public void setMode(int mode) { - this.mode = mode; - } - - public void setPixel(int x, int y, int p) { - if (dest == null) { - dest = new int[4][4]; - } - dest[x][y] = p; - } - - public void setPredict(int[][] predict) { - this.predict = predict; - - } - - public String toString() { - String r = "["; - for (int x = 0; x < 16; x++) - r = r + tokens[x] + " "; - r = r + "]"; - - return r; - } - + v = bc2.readTree(Globals.vp8CoefTree, coef_probs[type][Globals.vp8CoefBands[c + startAt]][lc], + skip ? 1 : 0); + + int dv = decodeToken(bc2, v); + lc = 0; + skip = false; + if (dv == 1 || dv == -1) { + lc = 1; + } + else if (dv > 1 || dv < -1) { + lc = 2; + } + else if (dv == Globals.DCT_0) { + skip = true; + } + + int[] tokens = sb.getTokens(); + + if (v != Globals.dct_eob) { + tokens[Globals.vp8defaultZigZag1d[c + startAt]] = dv; + } + c++; + } + hasNoZeroToken = false; + for (int x = 0; x < 16; x++) { + if (tokens[x] != 0) { + hasNoZeroToken = true; + } + } + } + + private int decodeToken(BoolDecoder bc2, int v) throws IOException { + int r = v; + + if (v == Globals.dct_cat1) { + r = 5 + DCTextra(bc2, Globals.Pcat1); + } + if (v == Globals.dct_cat2) { + r = 7 + DCTextra(bc2, Globals.Pcat2); + } + if (v == Globals.dct_cat3) { + r = 11 + DCTextra(bc2, Globals.Pcat3); + } + if (v == Globals.dct_cat4) { + r = 19 + DCTextra(bc2, Globals.Pcat4); + } + if (v == Globals.dct_cat5) { + r = 35 + DCTextra(bc2, Globals.Pcat5); + } + if (v == Globals.dct_cat6) { + r = 67 + DCTextra(bc2, Globals.Pcat6); + } + if (v != Globals.DCT_0 && v != Globals.dct_eob) { + if (bc2.readBit() > 0) { + r = -r; + } + } + + return r; + } + + public void dequantSubBlock(VP8Frame frame, Integer Dc) { + SubBlock sb = this; + + int[] adjustedValues = new int[16]; + for (int i = 0; i < 16; i++) { + int QValue; + if (plane == Plane.U || plane == Plane.V) { + QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] + .getUvac_delta_q(); + if (i == 0) { + QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] + .getUvdc_delta_q(); + } + } + else { + QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()].getY1ac(); + if (i == 0) { + QValue = frame.getSegmentQuants().getSegQuants()[this.getMacroBlock().getSegmentId()] + .getY1dc(); + } + } + + int inputValue = sb.getTokens()[i]; + adjustedValues[i] = inputValue * QValue; + } + + if (Dc != null) { + adjustedValues[0] = Dc; + } + + int[][] diff = IDCT.idct4x4llm(adjustedValues); + sb.setDiff(diff); + } + + public void drawDebug() { + if (dest != null) { + dest[0][0] = 128; + dest[1][0] = 128; + dest[2][0] = 128; + dest[3][0] = 128; + dest[0][0] = 128; + dest[0][1] = 128; + dest[0][2] = 128; + dest[0][3] = 128; + } + } + + public void drawDebugH() { + if (dest != null) { + dest[0][0] = 0; + dest[1][0] = 0; + dest[2][0] = 0; + dest[3][0] = 0; + } + } + + public void drawDebugV() { + if (dest != null) { + dest[0][0] = 0; + dest[0][1] = 0; + dest[0][2] = 0; + dest[0][3] = 0; + } + } + + public SubBlock getAbove() { + + return above; + } + + public String getDebugString() { + String r = ""; + r = r + " " + plane; + if (getMacroBlock().getYMode() == Globals.B_PRED + && plane == Plane.Y1) { + r = r + "\n " + Globals.getSubBlockModeAsString(mode); + } + return r; + } + + public int[][] getDest() { + if (dest != null) { + return dest; + } + else { + return new int[4][4]; + } + } + + public int[][] getDiff() { + + return diff; + } + + public SubBlock getLeft() { + + return left; + } + + public MacroBlock getMacroBlock() { + return macroBlock; + } + + public int[][] getMacroBlockPredict(int intra_mode) { + if (dest != null) { + return dest; + } + + else { + int rv = 127; + if (intra_mode == Globals.H_PRED) { + rv = 129; + } + int[][] r = new int[4][4]; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r[i][j] = rv; + } + } + return r; + } + } + + public int getMode() { + return mode; + } + + public Plane getPlane() { + return plane; + } + + public int[][] getPredict() { + if (predict != null) { + return predict; + } + return getPredict(Globals.B_DC_PRED, false); + } + + public int[][] getPredict(int intra_bmode, boolean left) { + if (dest != null) { + return dest; + } + if (predict != null) { + return predict; + } + else { + int rv = 127; + + if ((intra_bmode == Globals.B_TM_PRED + || intra_bmode == Globals.B_DC_PRED + || intra_bmode == Globals.B_VE_PRED + || intra_bmode == Globals.B_HE_PRED + || intra_bmode == Globals.B_VR_PRED + || intra_bmode == Globals.B_RD_PRED || intra_bmode == Globals.B_HD_PRED) + && left) { + rv = 129; + } + int[][] r = new int[4][4]; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r[i][j] = rv; + } + } + return r; + } + } + + int[] getTokens() { + return tokens; + } + + public boolean hasNoZeroToken() { + return hasNoZeroToken; + } + + public boolean isDest() { + return dest != null; + } + + public void predict(VP8Frame frame) { + SubBlock sb = this; + SubBlock aboveSb = frame.getAboveSubBlock(sb, sb.getPlane()); + SubBlock leftSb = frame.getLeftSubBlock(sb, sb.getPlane()); + + int[] above = new int[4]; + int[] left = new int[4]; + + above[0] = aboveSb.getPredict(sb.getMode(), false)[0][3]; + above[1] = aboveSb.getPredict(sb.getMode(), false)[1][3]; + above[2] = aboveSb.getPredict(sb.getMode(), false)[2][3]; + above[3] = aboveSb.getPredict(sb.getMode(), false)[3][3]; + left[0] = leftSb.getPredict(sb.getMode(), true)[3][0]; + left[1] = leftSb.getPredict(sb.getMode(), true)[3][1]; + left[2] = leftSb.getPredict(sb.getMode(), true)[3][2]; + left[3] = leftSb.getPredict(sb.getMode(), true)[3][3]; + SubBlock AL = frame.getLeftSubBlock(aboveSb, sb.getPlane()); + + // for above left if left and above is null use left (129?) else use + // above (127?) + int al; + if (!leftSb.isDest() && !aboveSb.isDest()) { + + al = AL.getPredict(sb.getMode(), false)[3][3]; + } + else if (!aboveSb.isDest()) { + + al = AL.getPredict(sb.getMode(), false)[3][3]; + } + else { + al = AL.getPredict(sb.getMode(), true)[3][3]; + } + SubBlock AR = frame.getAboveRightSubBlock(sb, sb.plane); + int[] ar = new int[4]; + ar[0] = AR.getPredict(sb.getMode(), false)[0][3]; + ar[1] = AR.getPredict(sb.getMode(), false)[1][3]; + ar[2] = AR.getPredict(sb.getMode(), false)[2][3]; + ar[3] = AR.getPredict(sb.getMode(), false)[3][3]; + int[][] p = new int[4][4]; + int[] pp; + switch (sb.getMode()) { + case Globals.B_DC_PRED: + // System.out.println("B_DC_PRED"); + int expected_dc = 0; + + for (int i = 0; i < 4; i++) { + expected_dc += above[i]; + expected_dc += left[i]; + } + expected_dc = (expected_dc + 4) >> 3; + + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + p[x][y] = expected_dc; + } + } + + break; + case Globals.B_TM_PRED: + + // System.out.println("B_TM_PRED"); + + // prediction similar to true_motion prediction + + for (int r = 0; r < 4; r++) { + for (int c = 0; c < 4; c++) { + + int pred = above[c] - al + left[r]; + if (pred < 0) { + pred = 0; + } + + if (pred > 255) { + pred = 255; + } + + p[c][r] = pred; + } + } + break; + case Globals.B_VE_PRED: + // System.out.println("B_VE_PRED"); + + int[] ap = new int[4]; + ap[0] = (al + 2 * above[0] + above[1] + 2) >> 2; + ap[1] = (above[0] + 2 * above[1] + above[2] + 2) >> 2; + ap[2] = (above[1] + 2 * above[2] + above[3] + 2) >> 2; + ap[3] = (above[2] + 2 * above[3] + ar[0] + 2) >> 2; + + for (int r = 0; r < 4; r++) { + for (int c = 0; c < 4; c++) { + + p[c][r] = ap[c]; + } + } + break; + case Globals.B_HE_PRED: + // System.out.println("B_HE_PRED"); + + int[] lp = new int[4]; + lp[0] = (al + 2 * left[0] + left[1] + 2) >> 2; + lp[1] = (left[0] + 2 * left[1] + left[2] + 2) >> 2; + lp[2] = (left[1] + 2 * left[2] + left[3] + 2) >> 2; + lp[3] = (left[2] + 2 * left[3] + left[3] + 2) >> 2; + + for (int r = 0; r < 4; r++) { + for (int c = 0; c < 4; c++) { + p[c][r] = lp[r]; + } + } + break; + case Globals.B_LD_PRED: + // System.out.println("B_LD_PRED"); + p[0][0] = (above[0] + above[1] * 2 + above[2] + 2) >> 2; + p[1][0] = p[0][1] = (above[1] + above[2] * 2 + above[3] + 2) >> 2; + p[2][0] = p[1][1] = p[0][2] = (above[2] + above[3] * 2 + ar[0] + 2) >> 2; + p[3][0] = p[2][1] = p[1][2] = p[0][3] = (above[3] + ar[0] * 2 + + ar[1] + 2) >> 2; + p[3][1] = p[2][2] = p[1][3] = (ar[0] + ar[1] * 2 + ar[2] + 2) >> 2; + p[3][2] = p[2][3] = (ar[1] + ar[2] * 2 + ar[3] + 2) >> 2; + p[3][3] = (ar[2] + ar[3] * 2 + ar[3] + 2) >> 2; + + break; + case Globals.B_RD_PRED: + // System.out.println("B_RD_PRED"); + pp = new int[9]; + + pp[0] = left[3]; + pp[1] = left[2]; + pp[2] = left[1]; + pp[3] = left[0]; + pp[4] = al; + pp[5] = above[0]; + pp[6] = above[1]; + pp[7] = above[2]; + pp[8] = above[3]; + + p[0][3] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + p[1][3] = p[0][2] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + p[2][3] = p[1][2] = p[0][1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + p[3][3] = p[2][2] = p[1][1] = p[0][0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + p[3][2] = p[2][1] = p[1][0] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + p[3][1] = p[2][0] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + p[3][0] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + break; + + case Globals.B_VR_PRED: + // System.out.println("B_VR_PRED"); + pp = new int[9]; + + pp[0] = left[3]; + pp[1] = left[2]; + pp[2] = left[1]; + pp[3] = left[0]; + pp[4] = al; + pp[5] = above[0]; + pp[6] = above[1]; + pp[7] = above[2]; + pp[8] = above[3]; + + p[0][3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + p[0][2] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + p[1][3] = p[0][1] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + p[1][2] = p[0][0] = (pp[4] + pp[5] + 1) >> 1; + p[2][3] = p[1][1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + p[2][2] = p[1][0] = (pp[5] + pp[6] + 1) >> 1; + p[3][3] = p[2][1] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + p[3][2] = p[2][0] = (pp[6] + pp[7] + 1) >> 1; + p[3][1] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + p[3][0] = (pp[7] + pp[8] + 1) >> 1; + + break; + case Globals.B_VL_PRED: + // System.out.println("B_VL_PRED"); + + p[0][0] = (above[0] + above[1] + 1) >> 1; + p[0][1] = (above[0] + above[1] * 2 + above[2] + 2) >> 2; + p[0][2] = p[1][0] = (above[1] + above[2] + 1) >> 1; + p[1][1] = p[0][3] = (above[1] + above[2] * 2 + above[3] + 2) >> 2; + p[1][2] = p[2][0] = (above[2] + above[3] + 1) >> 1; + p[1][3] = p[2][1] = (above[2] + above[3] * 2 + ar[0] + 2) >> 2; + p[3][0] = p[2][2] = (above[3] + ar[0] + 1) >> 1; + p[3][1] = p[2][3] = (above[3] + ar[0] * 2 + ar[1] + 2) >> 2; + p[3][2] = (ar[0] + ar[1] * 2 + ar[2] + 2) >> 2; + p[3][3] = (ar[1] + ar[2] * 2 + ar[3] + 2) >> 2; + + break; + case Globals.B_HD_PRED: + // System.out.println("B_HD_PRED"); + pp = new int[9]; + pp[0] = left[3]; + pp[1] = left[2]; + pp[2] = left[1]; + pp[3] = left[0]; + pp[4] = al; + pp[5] = above[0]; + pp[6] = above[1]; + pp[7] = above[2]; + pp[8] = above[3]; + + p[0][3] = (pp[0] + pp[1] + 1) >> 1; + p[1][3] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + p[0][2] = p[2][3] = (pp[1] + pp[2] + 1) >> 1; + p[1][2] = p[3][3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + p[2][2] = p[0][1] = (pp[2] + pp[3] + 1) >> 1; + p[3][2] = p[1][1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + p[2][1] = p[0][0] = (pp[3] + pp[4] + 1) >> 1; + p[3][1] = p[1][0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + p[2][0] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + p[3][0] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + break; + case Globals.B_HU_PRED: + // System.out.println("B_HU_PRED"); + + p[0][0] = (left[0] + left[1] + 1) >> 1; + p[1][0] = (left[0] + left[1] * 2 + left[2] + 2) >> 2; + p[2][0] = p[0][1] = (left[1] + left[2] + 1) >> 1; + p[3][0] = p[1][1] = (left[1] + left[2] * 2 + left[3] + 2) >> 2; + p[2][1] = p[0][2] = (left[2] + left[3] + 1) >> 1; + p[3][1] = p[1][2] = (left[2] + left[3] * 2 + left[3] + 2) >> 2; + p[2][2] = p[3][2] = p[0][3] = p[1][3] = p[2][3] = p[3][3] = left[3]; + break; + + default: + // TODO: FixME! + throw new AssertionError("TODO mode: " + sb.getMode()); + } + + sb.setPredict(p); + } + + public void reconstruct() { + SubBlock sb = this; + + int r, c; + int[][] p = sb.getPredict(1, false); + + int[][] dest = new int[4][4]; + int[][] diff = sb.getDiff(); + + for (r = 0; r < 4; r++) { + for (c = 0; c < 4; c++) { + int a = diff[r][c] + p[r][c]; + + if (a < 0) { + a = 0; + } + + if (a > 255) { + a = 255; + } + + dest[r][c] = a; + } + } + + sb.setDest(dest); + if (!this.getMacroBlock().isKeepDebugInfo()) { + sb.diff = null; + sb.predict = null; + sb.tokens = null; + } + } + + public void setDest(int[][] dest) { + this.dest = dest; + } + + public void setDiff(int[][] diff) { + this.diff = diff; + } + + public void setMode(int mode) { + this.mode = mode; + } + + public void setPixel(int x, int y, int p) { + if (dest == null) { + dest = new int[4][4]; + } + dest[x][y] = p; + } + + public void setPredict(int[][] predict) { + this.predict = predict; + } + + public String toString() { + String r = "["; + for (int x = 0; x < 16; x++) { + r = r + tokens[x] + " "; + } + r = r + "]"; + + return r; + } } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java index a2b2748e..48f05cca 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java @@ -31,6 +31,8 @@ package com.twelvemonkeys.imageio.plugins.webp.vp8; +import javax.imageio.IIOException; +import javax.imageio.ImageReadParam; import javax.imageio.event.IIOReadProgressListener; import javax.imageio.stream.ImageInputStream; import java.awt.image.BufferedImage; @@ -41,30 +43,26 @@ import java.util.List; import static com.twelvemonkeys.imageio.color.YCbCrConverter.convertYCbCr2RGB; - public final class VP8Frame { - private static int BLOCK_TYPES = 4; - private static int COEF_BANDS = 8; - private static int MAX_ENTROPY_TOKENS = 12; - private static int MAX_MODE_LF_DELTAS = 4; - private static int MAX_REF_LF_DELTAS = 4; - private static int PREV_COEF_CONTEXTS = 3; - + private static final int BLOCK_TYPES = 4; + private static final int COEF_BANDS = 8; + private static final int MAX_ENTROPY_TOKENS = 12; + private static final int MAX_MODE_LF_DELTAS = 4; + private static final int MAX_REF_LF_DELTAS = 4; + private static final int PREV_COEF_CONTEXTS = 3; private IIOReadProgressListener listener = null; -// private int bufferCount; + // private int bufferCount; // private int buffersToCreate = 1; - private int[][][][] coefProbs; - private boolean debug = false; + private final int[][][][] coefProbs; private int filterLevel; - private int filterType; - - private ImageInputStream frame; + private final ImageInputStream frame; + private final boolean debug; private int frameType; private int height; -// private Logger logger; + private int macroBlockCols; private int macroBlockNoCoeffSkip; private int macroBlockRows; @@ -72,58 +70,50 @@ public final class VP8Frame { private MacroBlock[][] macroBlocks; private int macroBlockSegementAbsoluteDelta; private int[] macroBlockSegmentTreeProbs; - private int[] modeLoopFilterDeltas = new int[MAX_MODE_LF_DELTAS]; + private final int[] modeLoopFilterDeltas = new int[MAX_MODE_LF_DELTAS]; private int modeRefLoopFilterDeltaEnabled; private int modeRefLoopFilterDeltaUpdate; private int multiTokenPartition = 0; private long offset; - private int[] refLoopFilterDeltas = new int[MAX_REF_LF_DELTAS]; + private final int[] refLoopFilterDeltas = new int[MAX_REF_LF_DELTAS]; private int refreshEntropyProbs; private int refreshLastFrame; private int segmentationIsEnabled; private SegmentQuants segmentQuants; private int sharpnessLevel; - private int simpleFilter; + private boolean simpleFilter; private BoolDecoder tokenBoolDecoder; - private List tokenBoolDecoders; + private final List tokenBoolDecoders; private int updateMacroBlockSegmentationMap; private int updateMacroBlockSegmentatonData; private int width; - public VP8Frame(ImageInputStream stream) throws IOException { + public VP8Frame(final ImageInputStream stream, boolean debug) throws IOException { this.frame = stream; - offset = frame.getStreamPosition(); - this.coefProbs = Globals.getDefaultCoefProbs(); - tokenBoolDecoders = new ArrayList<>(); -// logger = new Logger(); - } + this.debug = debug; -// public VP8Frame(ImageInputStream stream, int[][][][] coefProbs) throws IOException { -// this.frame = stream; -// offset = frame.getStreamPosition(); -// this.coefProbs = coefProbs; -// tokenBoolDecoders = new ArrayList<>(); -// logger = new Logger(); -// } + offset = frame.getStreamPosition(); + coefProbs = Globals.getDefaultCoefProbs(); + tokenBoolDecoders = new ArrayList<>(); + } public void setProgressListener(IIOReadProgressListener listener) { this.listener = listener; } private void createMacroBlocks() { - macroBlocks = new MacroBlock[macroBlockCols + 2][macroBlockRows + 2]; - for (int x = 0; x < macroBlockCols + 2; x++) { - for (int y = 0; y < macroBlockRows + 2; y++) { - macroBlocks[x][y] = new MacroBlock(x, y, debug); - + macroBlocks = new MacroBlock[macroBlockRows + 2][macroBlockCols + 2]; + for (int y = 0; y < macroBlockRows + 2; y++) { + for (int x = 0; x < macroBlockCols + 2; x++) { + macroBlocks[y][x] = new MacroBlock(x, y, debug); } } } - public boolean decodeFrame(boolean debug) throws IOException { - this.debug = debug; + public boolean decode(final WritableRaster raster, final ImageReadParam param) throws IOException { segmentQuants = new SegmentQuants(); + int c = frame.readUnsignedByte(); frameType = getBitAsInt(c, 0); // logger.log("Frame type: " + frameType); @@ -216,7 +206,7 @@ public final class VP8Frame { if (updateMacroBlockSegmentatonData > 0) { macroBlockSegementAbsoluteDelta = bc.readBit(); - /* For each segmentation feature (Quant and loop filter level) */ + /* For each segmentation feature (Quant and loop filter level) */ for (int i = 0; i < Globals.MAX_MB_SEGMENTS; i++) { int value = 0; if (bc.readBit() > 0) { @@ -241,19 +231,14 @@ public final class VP8Frame { if (updateMacroBlockSegmentationMap > 0) { macroBlockSegmentTreeProbs = new int[Globals.MB_FEATURE_TREE_PROBS]; for (int i = 0; i < Globals.MB_FEATURE_TREE_PROBS; i++) { - int value = 255; - if (bc.readBit() > 0) { - value = bc.readLiteral(8); - } else { - value = 255; - } + int value = bc.readBit() > 0 ? bc.readLiteral(8) : 255; macroBlockSegmentTreeProbs[i] = value; } } } } - simpleFilter = bc.readBit(); + simpleFilter = bc.readBit() != 0; // logger.log("simpleFilter: " + simpleFilter); filterLevel = bc.readLiteral(6); @@ -271,19 +256,16 @@ public final class VP8Frame { for (int i = 0; i < MAX_REF_LF_DELTAS; i++) { if (bc.readBit() > 0) { refLoopFilterDeltas[i] = bc.readLiteral(6); - if (bc.readBit() > 0) // Apply sign - { + if (bc.readBit() > 0) { // Apply sign refLoopFilterDeltas[i] = refLoopFilterDeltas[i] * -1; } // logger.log("ref_lf_deltas[i]: " + refLoopFilterDeltas[i]); } } for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) { - if (bc.readBit() > 0) { modeLoopFilterDeltas[i] = bc.readLiteral(6); - if (bc.readBit() > 0) // Apply sign - { + if (bc.readBit() > 0) { // Apply sign modeLoopFilterDeltas[i] = modeLoopFilterDeltas[i] * -1; } // logger.log("mode_lf_deltas[i]: " + modeLoopFilterDeltas[i]); @@ -292,9 +274,6 @@ public final class VP8Frame { } } - filterType = (filterLevel == 0) ? 0 : (simpleFilter > 0) ? 1 : 2; -// logger.log("filter_type: " + filterType); - setupTokenDecoder(bc, firstPartitionLengthInBytes, offset); bc.seek(); @@ -317,7 +296,8 @@ public final class VP8Frame { refreshLastFrame = 0; if (frameType == 0) { refreshLastFrame = 1; - } else { + } + else { refreshLastFrame = bc.readBit(); } @@ -327,7 +307,6 @@ public final class VP8Frame { for (int j = 0; j < COEF_BANDS; j++) { for (int k = 0; k < PREV_COEF_CONTEXTS; k++) { for (int l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) { - if (bc.readBool(Globals.vp8CoefUpdateProbs[i][j][k][l]) > 0) { int newp = bc.readLiteral(8); this.coefProbs[i][j][k][l] = newp; @@ -343,100 +322,109 @@ public final class VP8Frame { if (frameType == 0) { readModes(bc); - } else { - // TODO - throw new IllegalArgumentException("Bad input: Not an Intra frame"); + } + else { + throw new IIOException("Bad input: Not an Intra frame"); } int ibc = 0; int num_part = 1 << multiTokenPartition; - for (int mb_row = 0; mb_row < macroBlockRows; mb_row++) { +// final boolean filter = getFilterType() > 0 && getFilterLevel() != 0; + + for (int row = 0; row < macroBlockRows; row++) { if (num_part > 1) { tokenBoolDecoder = tokenBoolDecoders.get(ibc); tokenBoolDecoder.seek(); - decodeMacroBlockRow(mb_row); + decodeMacroBlockRow(row, raster, param); ibc++; if (ibc == num_part) { ibc = 0; } - } else { - decodeMacroBlockRow(mb_row); + } + else { + decodeMacroBlockRow(row, raster, param); } - fireProgressUpdate(mb_row); - } - - if (getFilterType() > 0 && getFilterLevel() != 0) { - LoopFilter.loopFilter(this); + fireProgressUpdate(row); } return true; } - private void decodeMacroBlockRow(int mbRow) throws IOException { + private void decodeMacroBlockRow(final int mbRow, final WritableRaster raster, final ImageReadParam param) throws IOException { + final boolean filter = filterLevel != 0; + + MacroBlock left = null; + MacroBlock[] prevRow = macroBlocks[mbRow]; + MacroBlock[] currRow = macroBlocks[mbRow + 1]; + for (int mbCol = 0; mbCol < macroBlockCols; mbCol++) { - MacroBlock mb = getMacroBlock(mbCol, mbRow); + MacroBlock mb = currRow[mbCol + 1]; mb.decodeMacroBlock(this); mb.dequantMacroBlock(this); + + if (filter) { + MacroBlock top = mbRow > 0 ? prevRow[mbCol + 1] : null; + LoopFilter.loopFilterBlock(mb, left, top, frameType, simpleFilter, sharpnessLevel); + } + + copyBlock(mb, raster, param); + + left = mb; } } - private void fireProgressUpdate(int mb_row) { + private void fireProgressUpdate(int mbRow) { if (listener != null) { - float percentageDone = (100.0f * ((float) (mb_row + 1) / (float) getMacroBlockRows())); + float percentageDone = (100.0f * ((float) (mbRow + 1) / (float) getMacroBlockRows())); listener.imageProgress(null, percentageDone); } } - public SubBlock getAboveRightSubBlock(SubBlock sb, SubBlock.PLANE plane) { + public SubBlock getAboveRightSubBlock(SubBlock sb, SubBlock.Plane plane) { // this might break at right edge SubBlock r; MacroBlock mb = sb.getMacroBlock(); int x = mb.getSubblockX(sb); int y = mb.getSubblockY(sb); - if (plane == SubBlock.PLANE.Y1) { - + if (plane == SubBlock.Plane.Y1) { // top row if (y == 0 && x < 3) { - MacroBlock mb2 = this.getMacroBlock(mb.getX(), mb.getY() - 1); r = mb2.getSubBlock(plane, x + 1, 3); return r; } //top right else if (y == 0 && x == 3) { - MacroBlock mb2 = this.getMacroBlock(mb.getX() + 1, mb.getY() - 1); r = mb2.getSubBlock(plane, 0, 3); if (mb2.getX() == this.getMacroBlockCols()) { - int dest[][] = new int[4][4]; + int[][] dest = new int[4][4]; for (int b = 0; b < 4; b++) { for (int a = 0; a < 4; a++) { if (mb2.getY() < 0) { dest[a][b] = 127; - } else { - dest[a][b] = this.getMacroBlock(mb.getX(), mb.getY() - 1).getSubBlock(SubBlock.PLANE.Y1, 3, 3).getDest()[3][3]; + } + else { + dest[a][b] = this.getMacroBlock(mb.getX(), mb.getY() - 1).getSubBlock(SubBlock.Plane.Y1, 3, 3).getDest()[3][3]; } } } - r = new SubBlock(mb2, null, null, SubBlock.PLANE.Y1); + r = new SubBlock(mb2, null, null, SubBlock.Plane.Y1); r.setDest(dest); - - } return r; } //not right edge or top row else if (y > 0 && x < 3) { - r = mb.getSubBlock(plane, x + 1, y - 1); return r; } @@ -445,34 +433,36 @@ public final class VP8Frame { SubBlock sb2 = mb.getSubBlock(sb.getPlane(), 3, 0); return this.getAboveRightSubBlock(sb2, plane); } - } else { + } + else { // TODO throw new IllegalArgumentException("bad input: getAboveRightSubBlock()"); } } - public SubBlock getAboveSubBlock(SubBlock sb, SubBlock.PLANE plane) { - SubBlock r = sb.getAbove(); - if (r == null) { + public SubBlock getAboveSubBlock(SubBlock sb, SubBlock.Plane plane) { + SubBlock above = sb.getAbove(); + + if (above == null) { MacroBlock mb = sb.getMacroBlock(); int x = mb.getSubblockX(sb); MacroBlock mb2 = getMacroBlock(mb.getX(), mb.getY() - 1); //TODO: SPLIT - while (plane == SubBlock.PLANE.Y2 && mb2.getYMode() == Globals.B_PRED) { + while (plane == SubBlock.Plane.Y2 && mb2.getYMode() == Globals.B_PRED) { mb2 = getMacroBlock(mb2.getX(), mb2.getY() - 1); } - r = mb2.getBottomSubBlock(x, sb.getPlane()); + above = mb2.getBottomSubBlock(x, sb.getPlane()); } - return r; + return above; } - private boolean getBit(int data, int bit) { - int r = data & (1 << bit); - return r != 0; - } +// private boolean getBit(int data, int bit) { +// int r = data & (1 << bit); +// return r != 0; +// } private int getBitAsInt(int data, int bit) { int r = data & (1 << bit); @@ -492,11 +482,11 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int yy, u, v; - yy = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getDiff()[x % 4][y % 4]; - u = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; - v = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; + yy = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.Y1, (x % 16) / 4, (y % 16) / 4).getDiff()[x % 4][y % 4]; + u = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; + v = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; c[0] = (int) (1.164 * (yy - 16) + 1.596 * (v - 128)); c[1] = (int) (1.164 * (yy - 16) - 0.813 * (v - 128) - 0.391 * (u - 128)); c[2] = (int) (1.164 * (yy - 16) + 2.018 * (u - 128)); @@ -521,11 +511,11 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int yy, u, v; - yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getPredict()[x % 4][y % 4]; - u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; - v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; + yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.Y1, (x % 16) / 4, (y % 16) / 4).getPredict()[x % 4][y % 4]; + u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; + v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; c[0] = (int) (1.164 * (yy - 16) + 1.596 * (v - 128)); c[1] = (int) (1.164 * (yy - 16) - 0.813 * (v - 128) - 0.391 * (u - 128)); c[2] = (int) (1.164 * (yy - 16) + 2.018 * (u - 128)); @@ -550,9 +540,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int u; - u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; + u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; c[0] = u; c[1] = u; c[2] = u; @@ -577,9 +567,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int u; - u = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; + u = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; c[0] = u; c[1] = u; c[2] = u; @@ -604,9 +594,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int u; - u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; + u = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; c[0] = u; c[1] = u; c[2] = u; @@ -631,9 +621,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int v; - v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; + v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; c[0] = v; c[1] = v; c[2] = v; @@ -658,9 +648,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int v; - v = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; + v = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDiff()[(x / 2) % 4][(y / 2) % 4]; c[0] = v; c[1] = v; c[2] = v; @@ -685,9 +675,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int v; - v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; + v = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getPredict()[(x / 2) % 4][(y / 2) % 4]; c[0] = v; c[1] = v; c[2] = v; @@ -712,9 +702,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int yy; - yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getDest()[x % 4][y % 4]; + yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.Y1, (x % 16) / 4, (y % 16) / 4).getDest()[x % 4][y % 4]; c[0] = yy; c[1] = yy; c[2] = yy; @@ -739,9 +729,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int yy; - yy = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getDiff()[x % 4][y % 4]; + yy = 127 + this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.Y1, (x % 16) / 4, (y % 16) / 4).getDiff()[x % 4][y % 4]; c[0] = yy; c[1] = yy; c[2] = yy; @@ -766,9 +756,9 @@ public final class VP8Frame { WritableRaster imRas = bi.getWritableTile(0, 0); for (int x = 0; x < getWidth(); x++) { for (int y = 0; y < getHeight(); y++) { - int c[] = new int[3]; + int[] c = new int[3]; int yy; - yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getPredict()[x % 4][y % 4]; + yy = this.getMacroBlock(x / 16, y / 16).getSubBlock(SubBlock.Plane.Y1, (x % 16) / 4, (y % 16) / 4).getPredict()[x % 4][y % 4]; c[0] = yy; c[1] = yy; c[2] = yy; @@ -788,23 +778,19 @@ public final class VP8Frame { return bi; } - public int getFilterLevel() { - return filterLevel; - } - - public int getFilterType() { - return filterType; - } - public int getFrameType() { return frameType; } + public int getWidth() { + return width; + } + public int getHeight() { return height; } - public SubBlock getLeftSubBlock(SubBlock sb, SubBlock.PLANE plane) { + public SubBlock getLeftSubBlock(SubBlock sb, SubBlock.Plane plane) { SubBlock r = sb.getLeft(); if (r == null) { MacroBlock mb = sb.getMacroBlock(); @@ -812,19 +798,19 @@ public final class VP8Frame { MacroBlock mb2 = getMacroBlock(mb.getX() - 1, mb.getY()); //TODO: SPLIT - while (plane == SubBlock.PLANE.Y2 && mb2.getYMode() == Globals.B_PRED) { + while (plane == SubBlock.Plane.Y2 && mb2.getYMode() == Globals.B_PRED) { mb2 = getMacroBlock(mb2.getX() - 1, mb2.getY()); } r = mb2.getRightSubBlock(y, sb.getPlane()); - } return r; } public MacroBlock getMacroBlock(int mbCol, int mbRow) { - return macroBlocks[mbCol + 1][mbRow + 1]; +// return macroBlocks[mbCol + 1][mbRow + 1]; + return macroBlocks[mbRow + 1][mbCol + 1]; } public int getMacroBlockCols() { @@ -832,18 +818,18 @@ public final class VP8Frame { } public String getMacroBlockDebugString(int mbx, int mby, int sbx, int sby) { - String r = new String(); + String r = ""; if (mbx < this.macroBlockCols && mby < this.getMacroBlockRows()) { MacroBlock mb = getMacroBlock(mbx, mby); r = r + mb.getDebugString(); if (sbx < 4 && sby < 4) { - SubBlock sb = mb.getSubBlock(SubBlock.PLANE.Y1, sbx, sby); + SubBlock sb = mb.getSubBlock(SubBlock.Plane.Y1, sbx, sby); r = r + "\n SubBlock " + sbx + ", " + sby + "\n " + sb.getDebugString(); - sb = mb.getSubBlock(SubBlock.PLANE.Y2, sbx, sby); + sb = mb.getSubBlock(SubBlock.Plane.Y2, sbx, sby); r = r + "\n SubBlock " + sbx + ", " + sby + "\n " + sb.getDebugString(); - sb = mb.getSubBlock(SubBlock.PLANE.U, sbx / 2, sby / 2); + sb = mb.getSubBlock(SubBlock.Plane.U, sbx / 2, sby / 2); r = r + "\n SubBlock " + sbx / 2 + ", " + sby / 2 + "\n " + sb.getDebugString(); - sb = mb.getSubBlock(SubBlock.PLANE.V, sbx / 2, sby / 2); + sb = mb.getSubBlock(SubBlock.Plane.V, sbx / 2, sby / 2); r = r + "\n SubBlock " + sbx / 2 + ", " + sby / 2 + "\n " + sb.getDebugString(); } } @@ -871,72 +857,65 @@ public final class VP8Frame { return tokenBoolDecoder; } - public int[][] getUBuffer() { - int r[][] = new int[macroBlockCols * 8][macroBlockRows * 8]; - for (int y = 0; y < macroBlockRows; y++) { - for (int x = 0; x < macroBlockCols; x++) { - MacroBlock mb = macroBlocks[x + 1][y + 1]; - for (int b = 0; b < 2; b++) { - for (int a = 0; a < 2; a++) { - SubBlock sb = mb.getUSubBlock(a, b); - for (int d = 0; d < 4; d++) { - for (int c = 0; c < 4; c++) { - r[(x * 8) + (a * 4) + c][(y * 8) + (b * 4) + d] = sb.getDest()[c][d]; +// public int[][] getUBuffer() { +// int[][] r = new int[macroBlockCols * 8][macroBlockRows * 8]; +// for (int y = 0; y < macroBlockRows; y++) { +// for (int x = 0; x < macroBlockCols; x++) { +// MacroBlock mb = macroBlocks[x + 1][y + 1]; +// for (int b = 0; b < 2; b++) { +// for (int a = 0; a < 2; a++) { +// SubBlock sb = mb.getUSubBlock(a, b); +// for (int d = 0; d < 4; d++) { +// for (int c = 0; c < 4; c++) { +// r[(x * 8) + (a * 4) + c][(y * 8) + (b * 4) + d] = sb.getDest()[c][d]; +// } +// } +// } +// } +// } +// } +// return r; +// } +// +// public int[][] getVBuffer() { +// int[][] r = new int[macroBlockCols * 8][macroBlockRows * 8]; +// for (int y = 0; y < macroBlockRows; y++) { +// for (int x = 0; x < macroBlockCols; x++) { +// MacroBlock mb = macroBlocks[x + 1][y + 1]; +// for (int b = 0; b < 2; b++) { +// for (int a = 0; a < 2; a++) { +// SubBlock sb = mb.getVSubBlock(a, b); +// for (int d = 0; d < 4; d++) { +// for (int c = 0; c < 4; c++) { +// r[(x * 8) + (a * 4) + c][(y * 8) + (b * 4) + d] = sb.getDest()[c][d]; +// } +// } +// } +// } +// } +// } +// return r; +// } - } - } - } - } - } - } - return r; - } - - public int[][] getVBuffer() { - int r[][] = new int[macroBlockCols * 8][macroBlockRows * 8]; - for (int y = 0; y < macroBlockRows; y++) { - for (int x = 0; x < macroBlockCols; x++) { - MacroBlock mb = macroBlocks[x + 1][y + 1]; - for (int b = 0; b < 2; b++) { - for (int a = 0; a < 2; a++) { - SubBlock sb = mb.getVSubBlock(a, b); - for (int d = 0; d < 4; d++) { - for (int c = 0; c < 4; c++) { - r[(x * 8) + (a * 4) + c][(y * 8) + (b * 4) + d] = sb.getDest()[c][d]; - - } - } - } - } - } - } - return r; - } - - public int getWidth() { - return width; - } - - public int[][] getYBuffer() { - int r[][] = new int[macroBlockCols * 16][macroBlockRows * 16]; - for (int y = 0; y < macroBlockRows; y++) { - for (int x = 0; x < macroBlockCols; x++) { - MacroBlock mb = macroBlocks[x + 1][y + 1]; - for (int b = 0; b < 4; b++) { - for (int a = 0; a < 4; a++) { - SubBlock sb = mb.getYSubBlock(a, b); - for (int d = 0; d < 4; d++) { - for (int c = 0; c < 4; c++) { - r[(x * 16) + (a * 4) + c][(y * 16) + (b * 4) + d] = sb.getDest()[c][d]; - - } - } - } - } - } - } - return r; - } +// public int[][] getYBuffer() { +// int[][] r = new int[macroBlockCols * 16][macroBlockRows * 16]; +// for (int y = 0; y < macroBlockRows; y++) { +// for (int x = 0; x < macroBlockCols; x++) { +// MacroBlock mb = macroBlocks[x + 1][y + 1]; +// for (int b = 0; b < 4; b++) { +// for (int a = 0; a < 4; a++) { +// SubBlock sb = mb.getYSubBlock(a, b); +// for (int d = 0; d < 4; d++) { +// for (int c = 0; c < 4; c++) { +// r[(x * 16) + (a * 4) + c][(y * 16) + (b * 4) + d] = sb.getDest()[c][d]; +// } +// } +// } +// } +// } +// } +// return r; +// } private void readModes(BoolDecoder bc) throws IOException { int mb_row = -1; @@ -949,7 +928,6 @@ public final class VP8Frame { while (++mb_row < macroBlockRows) { int mb_col = -1; while (++mb_col < macroBlockCols) { - //if (this.segmentation_enabled > 0) { // logger.log(Level.SEVERE, "TODO:"); // throw new IllegalArgumentException("bad input: segmentation_enabled()"); @@ -966,9 +944,10 @@ public final class VP8Frame { if (modeRefLoopFilterDeltaEnabled > 0) { int level = filterLevel; level = level + refLoopFilterDeltas[0]; - level = (level < 0) ? 0 : (level > 63) ? 63 : level; + level = (level < 0) ? 0 : Math.min(level, 63); mb.setFilterLevel(level); - } else { + } + else { mb.setFilterLevel(segmentQuants.getSegQuants()[mb.getSegmentId()].getFilterStrength()); } @@ -983,35 +962,27 @@ public final class VP8Frame { if (y_mode == Globals.B_PRED) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - SubBlock sb = mb.getYSubBlock(j, i); - - SubBlock A = getAboveSubBlock(sb, SubBlock.PLANE.Y1); - - SubBlock L = getLeftSubBlock(sb, SubBlock.PLANE.Y1); + SubBlock A = getAboveSubBlock(sb, SubBlock.Plane.Y1); + SubBlock L = getLeftSubBlock(sb, SubBlock.Plane.Y1); int mode = readSubBlockMode(bc, A.getMode(), L.getMode()); sb.setMode(mode); - } } if (modeRefLoopFilterDeltaEnabled > 0) { int level = mb.getFilterLevel(); level = level + this.modeLoopFilterDeltas[0]; - level = (level < 0) ? 0 : (level > 63) ? 63 : level; + level = (level < 0) ? 0 : Math.min(level, 63); mb.setFilterLevel(level); } } else { int BMode; - switch (y_mode) { - case Globals.DC_PRED: - BMode = Globals.B_DC_PRED; - break; case Globals.V_PRED: BMode = Globals.B_VE_PRED; break; @@ -1021,10 +992,12 @@ public final class VP8Frame { case Globals.TM_PRED: BMode = Globals.B_TM_PRED; break; + case Globals.DC_PRED: default: BMode = Globals.B_DC_PRED; break; } + for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { SubBlock sb = mb.getYSubBlock(x, y); @@ -1041,7 +1014,6 @@ public final class VP8Frame { private int readPartitionSize(long l) throws IOException { frame.seek(l); return frame.readUnsignedByte() + (frame.readUnsignedByte() << 8) + (frame.readUnsignedByte() << 16); - } private int readSubBlockMode(BoolDecoder bc, int A, int L) throws IOException { @@ -1056,11 +1028,6 @@ public final class VP8Frame { return bc.readTree(Globals.vp8KeyFrameYModeTree, Globals.vp8KeyFrameYModeProb, 0); } -// public void setBuffersToCreate(int count) { -// this.buffersToCreate = 3 + count; -//// this.bufferCount = 0; -// } - private void setupTokenDecoder(BoolDecoder bc, int first_partition_length_in_bytes, long offset) throws IOException { long partitionSize; long partitionsStart = offset + first_partition_length_in_bytes; @@ -1073,15 +1040,12 @@ public final class VP8Frame { partition += 3 * (num_part - 1); } for (int i = 0; i < num_part; i++) { - /* - * Calculate the length of this partition. The last partition size - * is implicit. - */ + // Calculate the length of this partition. The last partition size is implicit. if (i < num_part - 1) { - partitionSize = readPartitionSize(partitionsStart + (i * 3)); bc.seek(); - } else { + } + else { partitionSize = frame.length() - partition; } @@ -1092,40 +1056,27 @@ public final class VP8Frame { tokenBoolDecoder = tokenBoolDecoders.get(0); } - public void copyTo(final WritableRaster byteRGBRaster) { + private final byte[] yuv = new byte[3]; + private final byte[] rgb = new byte[4]; // Allow decoding into RGBA, leaving the alpha out. + + private void copyBlock(final MacroBlock macroBlock, final WritableRaster byteRGBRaster, final ImageReadParam param) { // TODO: Consider doing YCbCr -> RGB in reader instead, or pass a flag to allow readRaster reading direct YUV/YCbCr values // We might be copying into a smaller raster - int w = Math.min(width, byteRGBRaster.getWidth()); - int h = Math.min(height, byteRGBRaster.getHeight()); + int yStart = macroBlock.getY() * 16; + int yEnd = Math.min(16, byteRGBRaster.getHeight() - yStart); + int xStart = macroBlock.getX() * 16; + int xEnd = Math.min(16, byteRGBRaster.getWidth() - xStart); - byte[] yuv = new byte[3]; - byte[] rgb = new byte[4]; // Allow decoding into RGBA, leaving the alpha out. - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - MacroBlock macroBlock = getMacroBlock(x / 16, y / 16); - - yuv[0] = (byte) macroBlock.getSubBlock(SubBlock.PLANE.Y1, (x % 16) / 4, (y % 16) / 4).getDest()[x % 4][y % 4]; - yuv[1] = (byte) macroBlock.getSubBlock(SubBlock.PLANE.U, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; - yuv[2] = (byte) macroBlock.getSubBlock(SubBlock.PLANE.V, ((x / 2) % 8) / 4, ((y / 2) % 8) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; + for (int y = 0; y < yEnd; y++) { + for (int x = 0; x < xEnd; x++) { + yuv[0] = (byte) macroBlock.getSubBlock(SubBlock.Plane.Y1, x / 4, y / 4).getDest()[x % 4][y % 4]; + yuv[1] = (byte) macroBlock.getSubBlock(SubBlock.Plane.U, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; + yuv[2] = (byte) macroBlock.getSubBlock(SubBlock.Plane.V, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4]; convertYCbCr2RGB(yuv, rgb, 0); - byteRGBRaster.setDataElements(x, y, rgb); + byteRGBRaster.setDataElements(xStart + x, yStart + y, rgb); } } } - -// public void setFrame(ImageInputStream frame) { -// try { -// this.frame.flush(); -// this.frame.close(); -// this.frame = frame; -// offset = frame.getStreamPosition(); -// this.coefProbs=Globals.getDefaultCoefProbs(); -// tokenBoolDecoders = new ArrayList<>(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } }