mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 12:35:29 -04:00
WebP performance optimizations & clean up.
This commit is contained in:
parent
2376d16ffd
commit
4dedf76ebc
@ -32,6 +32,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.webp;
|
package com.twelvemonkeys.imageio.plugins.webp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
import com.twelvemonkeys.imageio.metadata.xmp.XMPReader;
|
import com.twelvemonkeys.imageio.metadata.xmp.XMPReader;
|
||||||
@ -48,11 +49,14 @@ import javax.imageio.ImageReader;
|
|||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -83,7 +87,15 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
|
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);
|
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);
|
lsbBitReader = new LSBBitReader(imageInput);
|
||||||
}
|
}
|
||||||
@ -240,7 +252,8 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
(byte) ((value & 0x0000ff00) >> 8),
|
(byte) ((value & 0x0000ff00) >> 8),
|
||||||
(byte) ((value & 0x00ff0000) >> 16),
|
(byte) ((value & 0x00ff0000) >> 16),
|
||||||
(byte) ((value & 0xff000000) >>> 24),
|
(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,
|
// "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."
|
// but implementations of the format are free to use another representation internally."
|
||||||
// TODO: Doc says alpha flag is "hint only" :-P
|
// 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);
|
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) {
|
switch (header.fourCC) {
|
||||||
case WebP.CHUNK_VP8_:
|
case WebP.CHUNK_VP8_:
|
||||||
imageInput.seek(header.offset);
|
imageInput.seek(header.offset);
|
||||||
readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()));
|
readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WebP.CHUNK_VP8L:
|
case WebP.CHUNK_VP8L:
|
||||||
imageInput.seek(header.offset);
|
imageInput.seek(header.offset);
|
||||||
readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()));
|
readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -344,7 +362,7 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
opaqueAlpha(destination.getAlphaRaster()); // TODO: Remove when correctly implemented!
|
opaqueAlpha(destination.getAlphaRaster()); // TODO: Remove when correctly implemented!
|
||||||
readVP8Lossless(destination.getAlphaRaster());
|
readVP8Lossless(destination.getAlphaRaster(), param);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
processWarningOccurred("Unknown WebP alpha compression: " + compression);
|
processWarningOccurred("Unknown WebP alpha compression: " + compression);
|
||||||
@ -356,12 +374,12 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
case WebP.CHUNK_VP8_:
|
case WebP.CHUNK_VP8_:
|
||||||
readVP8(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel())
|
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;
|
break;
|
||||||
|
|
||||||
case WebP.CHUNK_VP8L:
|
case WebP.CHUNK_VP8L:
|
||||||
readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()));
|
readVP8Lossless(RasterUtils.asByteRaster(destination.getRaster(), destination.getColorModel()), param);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -409,13 +427,13 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
opaqueAlpha(alphaRaster);
|
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);
|
VP8LDecoder decoder = new VP8LDecoder(imageInput);
|
||||||
decoder.readVP8Lossless(raster, true);
|
decoder.readVP8Lossless(raster, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readVP8(final WritableRaster raster) throws IOException {
|
private void readVP8(final WritableRaster raster, final ImageReadParam param) throws IOException {
|
||||||
VP8Frame frame = new VP8Frame(imageInput);
|
VP8Frame frame = new VP8Frame(imageInput, DEBUG);
|
||||||
|
|
||||||
frame.setProgressListener(new ProgressListenerBase() {
|
frame.setProgressListener(new ProgressListenerBase() {
|
||||||
@Override
|
@Override
|
||||||
@ -424,9 +442,9 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Consider merging these operations...
|
if (!frame.decode(raster, param)) {
|
||||||
if (frame.decodeFrame(false)) {
|
// TODO: Does this make any sense? Only happens if frame type is not still (0)
|
||||||
frame.copyTo(raster);
|
processWarningOccurred("Nothing to decode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,10 +453,8 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
@Override
|
@Override
|
||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||||
readHeader(imageIndex);
|
readHeader(imageIndex);
|
||||||
// TODO: Read possible EXIF and 'XMP ' chunks
|
|
||||||
readMeta();
|
readMeta();
|
||||||
|
|
||||||
|
|
||||||
return new WebPImageMetadata(header);
|
return new WebPImageMetadata(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
||||||
|
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
final class Globals {
|
final class Globals {
|
||||||
|
|
||||||
/* predict DC using row above and column to the left */
|
/* predict DC using row above and column to the left */
|
||||||
@ -45,20 +48,21 @@ final class Globals {
|
|||||||
static final int B_PRED = 4;
|
static final int B_PRED = 4;
|
||||||
|
|
||||||
static String getModeAsString(int mode) {
|
static String getModeAsString(int mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DC_PRED:
|
case DC_PRED:
|
||||||
return "DC_PRED";
|
return "DC_PRED";
|
||||||
case V_PRED:
|
case V_PRED:
|
||||||
return "V_PRED";
|
return "V_PRED";
|
||||||
case H_PRED:
|
case H_PRED:
|
||||||
return "H_PRED";
|
return "H_PRED";
|
||||||
case TM_PRED:
|
case TM_PRED:
|
||||||
return "TM_PRED";
|
return "TM_PRED";
|
||||||
case B_PRED:
|
case B_PRED:
|
||||||
return "B_PRED";
|
return "B_PRED";
|
||||||
}
|
default:
|
||||||
return "not found";
|
throw new IllegalArgumentException("Unknown mode: " + mode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* intra_bmode */
|
/* intra_bmode */
|
||||||
static final int B_DC_PRED = 0; /*
|
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 final int B_HU_PRED = 9; /* ENE (horizontal up) "" */
|
||||||
|
|
||||||
static String getSubBlockModeAsString(int mode) {
|
static String getSubBlockModeAsString(int mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case B_DC_PRED:
|
case B_DC_PRED:
|
||||||
return "B_DC_PRED";
|
return "B_DC_PRED";
|
||||||
case B_TM_PRED:
|
case B_TM_PRED:
|
||||||
return "B_TM_PRED";
|
return "B_TM_PRED";
|
||||||
case B_VE_PRED:
|
case B_VE_PRED:
|
||||||
return "B_VE_PRED";
|
return "B_VE_PRED";
|
||||||
case B_HE_PRED:
|
case B_HE_PRED:
|
||||||
return "B_HE_PRED";
|
return "B_HE_PRED";
|
||||||
case B_LD_PRED:
|
case B_LD_PRED:
|
||||||
return "B_LD_PRED";
|
return "B_LD_PRED";
|
||||||
case B_RD_PRED:
|
case B_RD_PRED:
|
||||||
return "B_RD_PRED";
|
return "B_RD_PRED";
|
||||||
case B_VR_PRED:
|
case B_VR_PRED:
|
||||||
return "B_VR_PRED";
|
return "B_VR_PRED";
|
||||||
case B_VL_PRED:
|
case B_VL_PRED:
|
||||||
return "B_VL_PRED";
|
return "B_VL_PRED";
|
||||||
case B_HD_PRED:
|
case B_HD_PRED:
|
||||||
return "B_HD_PRED";
|
return "B_HD_PRED";
|
||||||
case B_HU_PRED:
|
case B_HU_PRED:
|
||||||
return "B_HU_PRED";
|
return "B_HU_PRED";
|
||||||
}
|
default:
|
||||||
return "not found";
|
throw new IllegalArgumentException("Unknown mode: " + mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final int MAX_MB_SEGMENTS = 4;
|
static final int MAX_MB_SEGMENTS = 4;
|
||||||
@ -814,9 +819,8 @@ final class Globals {
|
|||||||
return String.format("%1$#x ", c);
|
return String.format("%1$#x ", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clamp between 0 and value
|
// clamp between 0 and max
|
||||||
static int clamp(final int input, final int value) {
|
static int clamp(final int input, final int max) {
|
||||||
return input < 0 ? 0 : input > value ? value : input;
|
return max(0, min(input, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,17 +37,15 @@ final class IDCT {
|
|||||||
|
|
||||||
private static final int sinpi8sqrt2 = 35468;
|
private static final int sinpi8sqrt2 = 35468;
|
||||||
|
|
||||||
public static int[][] idct4x4llm(int input[]) {
|
public static int[][] idct4x4llm(int[] input) {
|
||||||
int i;
|
|
||||||
int a1, b1, c1, d1;
|
int a1, b1, c1, d1;
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
int[] output = new int[16];
|
int[] output = new int[16];
|
||||||
int temp1, temp2;
|
int temp1, temp2;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (int i = 0, offset = 0; i < 4; i++) {
|
||||||
a1 = input[offset + 0] + input[offset + 8];
|
a1 = input[offset] + input[offset + 8];
|
||||||
b1 = input[offset + 0] - input[offset + 8];
|
b1 = input[offset] - input[offset + 8];
|
||||||
|
|
||||||
temp1 = (input[offset + 4] * sinpi8sqrt2) >> 16;
|
temp1 = (input[offset + 4] * sinpi8sqrt2) >> 16;
|
||||||
temp2 = input[offset + 12]
|
temp2 = input[offset + 12]
|
||||||
@ -60,9 +58,9 @@ final class IDCT {
|
|||||||
temp2 = (input[offset + 12] * sinpi8sqrt2) >> 16;
|
temp2 = (input[offset + 12] * sinpi8sqrt2) >> 16;
|
||||||
d1 = temp1 + temp2;
|
d1 = temp1 + temp2;
|
||||||
|
|
||||||
output[offset + (0 * 4)] = a1 + d1;
|
output[offset ] = a1 + d1;
|
||||||
output[offset + (3 * 4)] = 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;
|
output[offset + (2 * 4)] = b1 - c1;
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
@ -70,22 +68,19 @@ final class IDCT {
|
|||||||
|
|
||||||
int diffo = 0;
|
int diffo = 0;
|
||||||
int[][] diff = new int[4][4];
|
int[][] diff = new int[4][4];
|
||||||
offset = 0;
|
for (int i = 0, offset = 0; i < 4; i++) {
|
||||||
for (i = 0; i < 4; i++) {
|
a1 = output[offset * 4] + output[(offset * 4) + 2];
|
||||||
a1 = output[(offset * 4) + 0] + output[(offset * 4) + 2];
|
b1 = output[offset * 4] - output[(offset * 4) + 2];
|
||||||
b1 = output[(offset * 4) + 0] - output[(offset * 4) + 2];
|
|
||||||
|
|
||||||
temp1 = (output[(offset * 4) + 1] * sinpi8sqrt2) >> 16;
|
temp1 = (output[(offset * 4) + 1] * sinpi8sqrt2) >> 16;
|
||||||
temp2 = output[(offset * 4) + 3]
|
temp2 = output[(offset * 4) + 3] + ((output[(offset * 4) + 3] * cospi8sqrt2minus1) >> 16);
|
||||||
+ ((output[(offset * 4) + 3] * cospi8sqrt2minus1) >> 16);
|
|
||||||
c1 = temp1 - temp2;
|
c1 = temp1 - temp2;
|
||||||
|
|
||||||
temp1 = output[(offset * 4) + 1]
|
temp1 = output[(offset * 4) + 1] + ((output[(offset * 4) + 1] * cospi8sqrt2minus1) >> 16);
|
||||||
+ ((output[(offset * 4) + 1] * cospi8sqrt2minus1) >> 16);
|
|
||||||
temp2 = (output[(offset * 4) + 3] * sinpi8sqrt2) >> 16;
|
temp2 = (output[(offset * 4) + 3] * sinpi8sqrt2) >> 16;
|
||||||
d1 = temp1 + temp2;
|
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) + 3] = (a1 - d1 + 4) >> 3;
|
||||||
output[(offset * 4) + 1] = (b1 + c1 + 4) >> 3;
|
output[(offset * 4) + 1] = (b1 + c1 + 4) >> 3;
|
||||||
output[(offset * 4) + 2] = (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) {
|
public static int[][] iwalsh4x4(int[] input) {
|
||||||
int i;
|
|
||||||
int a1, b1, c1, d1;
|
int a1, b1, c1, d1;
|
||||||
int a2, b2, c2, d2;
|
int a2, b2, c2, d2;
|
||||||
|
|
||||||
int[] output = new int[16];
|
int[] output = new int[16];
|
||||||
int[][] diff = new int[4][4];
|
int[][] diff = new int[4][4];
|
||||||
int offset = 0;
|
for (int i = 0, offset = 0; i < 4; i++) {
|
||||||
for (i = 0; i < 4; i++) {
|
a1 = input[offset ] + input[offset + 12];
|
||||||
a1 = input[offset + 0] + input[offset + 12];
|
|
||||||
b1 = input[offset + 4] + input[offset + 8];
|
b1 = input[offset + 4] + input[offset + 8];
|
||||||
c1 = 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 ] = a1 + b1;
|
||||||
output[offset + 4] = c1 + d1;
|
output[offset + 4] = c1 + d1;
|
||||||
output[offset + 8] = a1 - b1;
|
output[offset + 8] = a1 - b1;
|
||||||
output[offset + 12] = d1 - c1;
|
output[offset + 12] = d1 - c1;
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = 0;
|
for (int i = 0, offset = 0; i < 4; i++) {
|
||||||
|
a1 = output[offset ] + output[offset + 3];
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
a1 = output[offset + 0] + output[offset + 3];
|
|
||||||
b1 = output[offset + 1] + output[offset + 2];
|
b1 = output[offset + 1] + output[offset + 2];
|
||||||
c1 = 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;
|
a2 = a1 + b1;
|
||||||
b2 = c1 + d1;
|
b2 = c1 + d1;
|
||||||
c2 = a1 - b1;
|
c2 = a1 - b1;
|
||||||
d2 = d1 - c1;
|
d2 = d1 - c1;
|
||||||
output[offset + 0] = (a2 + 3) >> 3;
|
output[offset ] = (a2 + 3) >> 3;
|
||||||
output[offset + 1] = (b2 + 3) >> 3;
|
output[offset + 1] = (b2 + 3) >> 3;
|
||||||
output[offset + 2] = (c2 + 3) >> 3;
|
output[offset + 2] = (c2 + 3) >> 3;
|
||||||
output[offset + 3] = (d2 + 3) >> 3;
|
output[offset + 3] = (d2 + 3) >> 3;
|
||||||
|
@ -31,13 +31,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
||||||
|
|
||||||
final class LoopFilter {
|
import static java.lang.Math.*;
|
||||||
private static int abs(int v) {
|
|
||||||
return v < 0 ? -v : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int c(int v) {
|
final class LoopFilter {
|
||||||
return v < -128 ? -128 : (v > 127 ? 127 : v);
|
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) {
|
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 q0 = u2s(seg.Q0);
|
||||||
int q1 = u2s(seg.Q1);
|
int q1 = u2s(seg.Q1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disregarding clamping, when "use_outer_taps" is false, "a" is
|
* 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
|
* 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
|
* 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
|
* 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
|
* can be thought of as a refinement of 2*(q0 - p0) and the adjustment
|
||||||
* is something like (q0 - p0)/4.
|
* is something like (q0 - p0)/4.
|
||||||
*/
|
*/
|
||||||
int a = c((use_outer_taps ? c(p1 - q1) : 0) + 3 * (q0 - p0));
|
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
|
* 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.
|
* "fractional" part "f" of a/8 is exactly 1/2.
|
||||||
*/
|
*/
|
||||||
int b = (c(a + 3)) >> 3;
|
int b = (clamp(a + 3)) >> 3;
|
||||||
/*
|
/*
|
||||||
* Divide a by 8, rounding up when f >= 1/2. Although not strictly part
|
* 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
|
* of the "C" language, the right-shift is assumed to propagate the sign
|
||||||
* bit.
|
* bit.
|
||||||
*/
|
*/
|
||||||
a = c(a + 4) >> 3;
|
a = clamp(a + 4) >> 3;
|
||||||
/* Subtract "a" from q0, "bringing it closer" to p0. */
|
/* Subtract "a" from q0, "bringing it closer" to p0. */
|
||||||
seg.Q0 = s2u(q0 - a);
|
seg.Q0 = s2u(q0 - a);
|
||||||
/*
|
/*
|
||||||
* Add "a" (with adjustment "b") to p0, "bringing it closer" to q0. The
|
* Add "a" (with adjustment "b") to p0, "bringing it closer" to q0. The
|
||||||
* clamp of "a+b", while present in the reference decoder, is
|
* clamp of "a+b", while present in the reference decoder, is
|
||||||
* superfluous; we have -16 <= a <= 15 at this point.
|
* superfluous; we have -16 <= a <= 15 at this point.
|
||||||
*/
|
*/
|
||||||
seg.P0 = s2u(p0 + b);
|
seg.P0 = s2u(p0 + b);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
@ -85,17 +83,17 @@ final class LoopFilter {
|
|||||||
* for a horizontal edge (written "|"), an 8-pixel segment would be ordered
|
* for a horizontal edge (written "|"), an 8-pixel segment would be ordered
|
||||||
* p3 p2 p1 p0 | q0 q1 q2 q3.
|
* p3 p2 p1 p0 | q0 q1 q2 q3.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Filtering is disabled if the difference between any two adjacent
|
* Filtering is disabled if the difference between any two adjacent
|
||||||
* "interior" pixels in the 8-pixel segment exceeds the relevant threshold
|
* "interior" pixels in the 8-pixel segment exceeds the relevant threshold
|
||||||
* (I). A more complex thresholding calculation is done for the group of
|
* (I). A more complex thresholding calculation is done for the group of
|
||||||
* four pixels that straddle the edge, in line with the calculation in
|
* four pixels that straddle the edge, in line with the calculation in
|
||||||
* simple_segment() above.
|
* simple_segment() above.
|
||||||
*/
|
*/
|
||||||
private static boolean filter_yes(int I, /* limit on interior differences */
|
private static boolean filter_yes(int I, // limit on interior differences
|
||||||
int E, /* limit at the edge */
|
int E, // limit at the edge
|
||||||
int p3, int p2, int p1, int p0, /* pixels before edge */
|
int p3, int p2, int p1, int p0, // pixels before edge
|
||||||
int q0, int q1, int q2, int q3 /* pixels after 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
|
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
|
&& abs(p2 - p1) <= I && abs(p1 - p0) <= I && abs(q3 - q2) <= I
|
||||||
@ -106,6 +104,7 @@ final class LoopFilter {
|
|||||||
Segment seg = new Segment();
|
Segment seg = new Segment();
|
||||||
int[][] rdest = rsb.getDest();
|
int[][] rdest = rsb.getDest();
|
||||||
int[][] ldest = lsb.getDest();
|
int[][] ldest = lsb.getDest();
|
||||||
|
|
||||||
seg.P0 = ldest[3][a];
|
seg.P0 = ldest[3][a];
|
||||||
seg.P1 = ldest[2][a];
|
seg.P1 = ldest[2][a];
|
||||||
seg.P2 = ldest[1][a];
|
seg.P2 = ldest[1][a];
|
||||||
@ -114,6 +113,7 @@ final class LoopFilter {
|
|||||||
seg.Q1 = rdest[1][a];
|
seg.Q1 = rdest[1][a];
|
||||||
seg.Q2 = rdest[2][a];
|
seg.Q2 = rdest[2][a];
|
||||||
seg.Q3 = rdest[3][a];
|
seg.Q3 = rdest[3][a];
|
||||||
|
|
||||||
return seg;
|
return seg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +130,7 @@ final class LoopFilter {
|
|||||||
seg.Q1 = bdest[a][1];
|
seg.Q1 = bdest[a][1];
|
||||||
seg.Q2 = bdest[a][2];
|
seg.Q2 = bdest[a][2];
|
||||||
seg.Q3 = bdest[a][3];
|
seg.Q3 = bdest[a][3];
|
||||||
|
|
||||||
return seg;
|
return seg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,134 +138,138 @@ final class LoopFilter {
|
|||||||
* Filtering is altered if (at least) one of the differences on either side
|
* Filtering is altered if (at least) one of the differences on either side
|
||||||
* of the edge exceeds a threshold (we have "high edge variance").
|
* of the edge exceeds a threshold (we have "high edge variance").
|
||||||
*/
|
*/
|
||||||
private static boolean hev(int threshold, int p1, int p0, /*
|
private static boolean hev(int threshold,
|
||||||
* pixels before
|
int p1, int p0, // pixels before edge
|
||||||
* edge
|
int q0, int q1 // pixels after edge
|
||||||
*/
|
|
||||||
int q0, int q1 /* pixels after edge */
|
|
||||||
) {
|
) {
|
||||||
return abs(p1 - p0) > threshold || abs(q1 - q0) > threshold;
|
return abs(p1 - p0) > threshold || abs(q1 - q0) > threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loopFilter(VP8Frame frame) {
|
// public static void loopFilter(VP8Frame frame) {
|
||||||
// frame.fireLFProgressUpdate(0);
|
// if (frame.getFilterType() == 2) {
|
||||||
if (frame.getFilterType() == 2) {
|
// loopFilterUV(frame);
|
||||||
loopFilterUV(frame);
|
// loopFilterY(frame);
|
||||||
// frame.fireLFProgressUpdate(50);
|
// }
|
||||||
loopFilterY(frame);
|
// else if (frame.getFilterType() == 1) {
|
||||||
} else if (frame.getFilterType() == 1) {
|
// loopFilterSimple(frame);
|
||||||
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) {
|
private static void loopFilterSimple(VP8Frame frame) {
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
||||||
// frame.fireLFProgressUpdate((100.0f * ((float) (y + 1) / (float) (frame
|
// frame.fireLFProgressUpdate((100.0f * ((float) (y + 1) / (float) (frame
|
||||||
// .getMacroBlockRows()))));
|
// .getMacroBlockRows()))));
|
||||||
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
||||||
// System.out.println("x: "+x+" y: "+y);
|
loopFilterSimpleBlock(frame.getMacroBlock(x, y),
|
||||||
MacroBlock rmb = frame.getMacroBlock(x, y);
|
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
||||||
MacroBlock bmb = frame.getMacroBlock(x, y);
|
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
||||||
|
frame.getSharpnessLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int loop_filter_level = rmb.getFilterLevel();
|
static void loopFilterSimpleBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel) {
|
||||||
if (loop_filter_level != 0) {
|
// System.out.println("x: "+x+" y: "+y);
|
||||||
int interior_limit = rmb.getFilterLevel();
|
// 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) {
|
||||||
if (sharpnessLevel > 0) {
|
interior_limit >>= sharpnessLevel > 4 ? 2 : 1;
|
||||||
interior_limit >>= sharpnessLevel > 4 ? 2 : 1;
|
if (interior_limit > 9 - sharpnessLevel) {
|
||||||
if (interior_limit > 9 - sharpnessLevel) {
|
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 */
|
// sb top
|
||||||
int sub_bedge_limit = (loop_filter_level * 2) + interior_limit;
|
if (!cmb.isSkip_inner_lf()) {
|
||||||
if (sub_bedge_limit < 1) {
|
for (int a = 1; a < 4; a++) {
|
||||||
sub_bedge_limit = 1;
|
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);
|
||||||
/* Luma and Chroma use the same inter-macroblock edge limit */
|
for (int c = 0; c < 4; c++) {
|
||||||
int mbedge_limit = sub_bedge_limit + 4;
|
// System.out.println("sbtop");
|
||||||
|
Segment seg = getSegV(bsb, tsb, c);
|
||||||
// left
|
simple_segment(sub_bedge_limit, seg);
|
||||||
if (x > 0) {
|
// System.out.println(sub_bedge_limit);
|
||||||
MacroBlock lmb = frame.getMacroBlock(x - 1, y);
|
// subblock_filter(hev_threshold,interior_limit,sub_bedge_limit,
|
||||||
for (int b = 0; b < 4; b++) {
|
// seg);
|
||||||
SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, 0, b);
|
setSegV(bsb, tsb, seg, c);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,139 +279,127 @@ final class LoopFilter {
|
|||||||
|
|
||||||
private static void loopFilterUV(VP8Frame frame) {
|
private static void loopFilterUV(VP8Frame frame) {
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
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++) {
|
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
||||||
MacroBlock rmb = frame.getMacroBlock(x, y);
|
loopFilterUVBlock(frame.getMacroBlock(x, y),
|
||||||
MacroBlock bmb = frame.getMacroBlock(x, y);
|
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
||||||
int sharpnessLevel = frame.getSharpnessLevel();
|
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
||||||
int loop_filter_level = rmb.getFilterLevel();
|
frame.getSharpnessLevel(), frame.getFrameType()
|
||||||
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;
|
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;
|
// sb top
|
||||||
if (frame.getFrameType() == 0) /* current frame is a key frame */ {
|
if (!cmb.isSkip_inner_lf()) {
|
||||||
if (loop_filter_level >= 40) {
|
for (int a = 1; a < 2; a++) { // TODO: This does not loop...
|
||||||
hev_threshold = 2;
|
for (int b = 0; b < 2; b++) {
|
||||||
} else if (loop_filter_level >= 15) {
|
SubBlock tsbU = cmb.getSubBlock(SubBlock.Plane.U, b, a - 1);
|
||||||
hev_threshold = 1;
|
SubBlock bsbU = cmb.getSubBlock(SubBlock.Plane.U, b, a);
|
||||||
}
|
SubBlock tsbV = cmb.getSubBlock(SubBlock.Plane.V, b, a - 1);
|
||||||
} else /* current frame is an interframe */ {
|
SubBlock bsbV = cmb.getSubBlock(SubBlock.Plane.V, b, a);
|
||||||
if (loop_filter_level >= 40) {
|
for (int c = 0; c < 4; c++) {
|
||||||
hev_threshold = 3;
|
Segment seg = getSegV(bsbU, tsbU, c);
|
||||||
} else if (loop_filter_level >= 20) {
|
subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg);
|
||||||
hev_threshold = 2;
|
setSegV(bsbU, tsbU, seg, c);
|
||||||
} else if (loop_filter_level >= 15) {
|
seg = getSegV(bsbV, tsbV, c);
|
||||||
hev_threshold = 1;
|
subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg);
|
||||||
}
|
setSegV(bsbV, tsbV, seg, c);
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,111 +409,106 @@ final class LoopFilter {
|
|||||||
|
|
||||||
private static void loopFilterY(VP8Frame frame) {
|
private static void loopFilterY(VP8Frame frame) {
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
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++) {
|
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
||||||
MacroBlock rmb = frame.getMacroBlock(x, y);
|
loopFilterYBlock(frame.getMacroBlock(x, y),
|
||||||
MacroBlock bmb = frame.getMacroBlock(x, y);
|
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
||||||
int sharpnessLevel = frame.getSharpnessLevel();
|
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
||||||
int loop_filter_level = rmb.getFilterLevel();
|
frame.getSharpnessLevel(), frame.getFrameType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (loop_filter_level != 0) {
|
static void loopFilterYBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) {
|
||||||
int interior_limit = rmb.getFilterLevel();
|
int loop_filter_level = cmb.getFilterLevel();
|
||||||
|
|
||||||
if (sharpnessLevel > 0) {
|
if (loop_filter_level != 0) {
|
||||||
interior_limit >>= sharpnessLevel > 4 ? 2 : 1;
|
int interior_limit = cmb.getFilterLevel();
|
||||||
if (interior_limit > 9 - sharpnessLevel) {
|
|
||||||
interior_limit = 9 - sharpnessLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (interior_limit == 0) {
|
|
||||||
interior_limit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hev_threshold = 0;
|
if (sharpnessLevel > 0) {
|
||||||
if (frame.getFrameType() == 0) /* current frame is a key frame */ {
|
interior_limit >>= sharpnessLevel > 4 ? 2 : 1;
|
||||||
if (loop_filter_level >= 40) {
|
if (interior_limit > 9 - sharpnessLevel) {
|
||||||
hev_threshold = 2;
|
interior_limit = 9 - sharpnessLevel;
|
||||||
} else if (loop_filter_level >= 15) {
|
}
|
||||||
hev_threshold = 1;
|
}
|
||||||
}
|
if (interior_limit == 0) {
|
||||||
} else /* current frame is an interframe */ {
|
interior_limit = 1;
|
||||||
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 hev_threshold = 0;
|
||||||
int mbedge_limit = ((loop_filter_level + 2) * 2)
|
if (frameType == 0) { // current frame is a key frame
|
||||||
+ interior_limit;
|
if (loop_filter_level >= 40) {
|
||||||
/* Luma and Chroma use the same inter-subblock edge limit */
|
hev_threshold = 2;
|
||||||
int sub_bedge_limit = (loop_filter_level * 2) + interior_limit;
|
}
|
||||||
|
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
|
/* Luma and Chroma use the same inter-macroblock edge limit */
|
||||||
if (x > 0) {
|
int mbedge_limit = ((loop_filter_level + 2) * 2) + interior_limit;
|
||||||
MacroBlock lmb = frame.getMacroBlock(x - 1, y);
|
/* Luma and Chroma use the same inter-subblock edge limit */
|
||||||
for (int b = 0; b < 4; b++) {
|
int sub_bedge_limit = (loop_filter_level * 2) + interior_limit;
|
||||||
SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1, 0, b);
|
|
||||||
SubBlock lsb = lmb.getSubBlock(SubBlock.PLANE.Y1, 3, b);
|
// left
|
||||||
for (int a = 0; a < 4; a++) {
|
if (lmb != null) {
|
||||||
Segment seg = getSegH(rsb, lsb, a);
|
for (int b = 0; b < 4; b++) {
|
||||||
MBfilter(hev_threshold, interior_limit,
|
SubBlock rsb = cmb.getSubBlock(SubBlock.Plane.Y1, 0, b);
|
||||||
mbedge_limit, seg);
|
SubBlock lsb = lmb.getSubBlock(SubBlock.Plane.Y1, 3, b);
|
||||||
setSegH(rsb, lsb, seg, a);
|
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++) {
|
// top
|
||||||
for (int b = 0; b < 4; b++) {
|
if (tmb != null) {
|
||||||
SubBlock lsb = rmb.getSubBlock(SubBlock.PLANE.Y1,
|
for (int b = 0; b < 4; b++) {
|
||||||
a - 1, b);
|
SubBlock tsb = tmb.getSubBlock(SubBlock.Plane.Y1, b, 3);
|
||||||
SubBlock rsb = rmb.getSubBlock(SubBlock.PLANE.Y1,
|
SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, 0);
|
||||||
a, b);
|
for (int a = 0; a < 4; a++) {
|
||||||
for (int c = 0; c < 4; c++) {
|
Segment seg = getSegV(bsb, tsb, a);
|
||||||
// System.out.println("sbleft a:"+a+" b:"+b+" c:"+c);
|
MBfilter(hev_threshold, interior_limit, mbedge_limit, seg);
|
||||||
Segment seg = getSegH(rsb, lsb, c);
|
setSegV(bsb, tsb, seg, a);
|
||||||
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);
|
// sb top
|
||||||
for (int b = 0; b < 4; b++) {
|
if (!cmb.isSkip_inner_lf()) {
|
||||||
SubBlock tsb = tmb.getSubBlock(SubBlock.PLANE.Y1, b, 3);
|
for (int a = 1; a < 4; a++) {
|
||||||
SubBlock bsb = bmb.getSubBlock(SubBlock.PLANE.Y1, b, 0);
|
for (int b = 0; b < 4; b++) {
|
||||||
for (int a = 0; a < 4; a++) {
|
SubBlock tsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a - 1);
|
||||||
Segment seg = getSegV(bsb, tsb, a);
|
SubBlock bsb = cmb.getSubBlock(SubBlock.Plane.Y1, b, a);
|
||||||
MBfilter(hev_threshold, interior_limit,
|
for (int c = 0; c < 4; c++) {
|
||||||
mbedge_limit, seg);
|
Segment seg = getSegV(bsb, tsb, c);
|
||||||
setSegV(bsb, tsb, seg, a);
|
subblock_filter(hev_threshold, interior_limit, sub_bedge_limit, seg);
|
||||||
}
|
setSegV(bsb, tsb, seg, c);
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,12 +521,11 @@ final class LoopFilter {
|
|||||||
int edge_limit, Segment seg) {
|
int edge_limit, Segment seg) {
|
||||||
int p3 = u2s(seg.P3), p2 = u2s(seg.P2), p1 = u2s(seg.P1), p0 = u2s(seg.P0);
|
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);
|
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,
|
if (filter_yes(interior_limit, edge_limit, q3, q2, q1, q0, p0, p1, p2, p3)) {
|
||||||
p3)) {
|
|
||||||
if (!hev(hev_threshold, p1, p0, q0, q1)) {
|
if (!hev(hev_threshold, p1, p0, q0, q1)) {
|
||||||
// Same as the initial calculation in "common_adjust",
|
// Same as the initial calculation in "common_adjust",
|
||||||
// w is something like twice the edge difference
|
// 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.
|
// 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,
|
// So this a, used to adjust the pixels adjacent to the edge,
|
||||||
@ -556,9 +543,9 @@ final class LoopFilter {
|
|||||||
a = (9 * w + 63) >> 7;
|
a = (9 * w + 63) >> 7;
|
||||||
seg.Q2 = s2u(q2 - a);
|
seg.Q2 = s2u(q2 - a);
|
||||||
seg.P2 = s2u(p2 + 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
|
common_adjust(true, seg); // using outer taps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -566,7 +553,7 @@ final class LoopFilter {
|
|||||||
|
|
||||||
/* Clamp, then convert signed number back to pixel value. */
|
/* Clamp, then convert signed number back to pixel value. */
|
||||||
private static int s2u(int v) {
|
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) {
|
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[1][a] = seg.Q1;
|
||||||
rdest[2][a] = seg.Q2;
|
rdest[2][a] = seg.Q2;
|
||||||
rdest[3][a] = seg.Q3;
|
rdest[3][a] = seg.Q3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setSegV(SubBlock bsb, SubBlock tsb, Segment seg, int a) {
|
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][1] = seg.Q1;
|
||||||
bdest[a][2] = seg.Q2;
|
bdest[a][2] = seg.Q2;
|
||||||
bdest[a][3] = seg.Q3;
|
bdest[a][3] = seg.Q3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void simple_segment(int edge_limit, /*
|
private static void simple_segment(int edge_limit, // do nothing if edge difference exceeds limit
|
||||||
* do nothing if edge
|
Segment seg) {
|
||||||
* difference exceeds
|
|
||||||
* limit
|
|
||||||
*/
|
|
||||||
Segment seg) {
|
|
||||||
if ((abs(seg.P0 - seg.Q0) * 2 + abs(seg.P1 - seg.Q1) / 2) <= edge_limit) {
|
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 {
|
else {
|
||||||
// TODO?
|
// TODO?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void subblock_filter(int hev_threshold, /*
|
private static void subblock_filter(int hev_threshold, // detect high edge variance
|
||||||
* detect high edge
|
int interior_limit, // possibly disable filter
|
||||||
* variance
|
int edge_limit, Segment seg) {
|
||||||
*/
|
|
||||||
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 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);
|
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)) {
|
||||||
@ -630,7 +608,6 @@ final class LoopFilter {
|
|||||||
else {
|
else {
|
||||||
// TODO?
|
// TODO?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */
|
/* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */
|
||||||
|
@ -36,19 +36,19 @@ import java.io.IOException;
|
|||||||
final class MacroBlock {
|
final class MacroBlock {
|
||||||
|
|
||||||
private int filterLevel;
|
private int filterLevel;
|
||||||
private boolean keepDebugInfo = false;
|
private final boolean keepDebugInfo;
|
||||||
private int segmentId;
|
private int segmentId;
|
||||||
private int skipCoeff;
|
private int skipCoeff;
|
||||||
private boolean skipInnerLoopFilter;
|
private boolean skipInnerLoopFilter;
|
||||||
SubBlock[][] uSubBlocks;
|
final SubBlock[][] uSubBlocks;
|
||||||
private int uVFilterLevel;
|
private int uVFilterLevel;
|
||||||
|
|
||||||
private int uvMode;
|
private int uvMode;
|
||||||
SubBlock[][] vSubBlocks;
|
final SubBlock[][] vSubBlocks;
|
||||||
private int x, y;
|
private final int x, y;
|
||||||
SubBlock y2SubBlock;
|
final SubBlock y2SubBlock;
|
||||||
private int yMode;
|
private int yMode;
|
||||||
SubBlock[][] ySubBlocks;
|
final SubBlock[][] ySubBlocks;
|
||||||
|
|
||||||
MacroBlock(int x, int y, boolean keepDebugInfo) {
|
MacroBlock(int x, int y, boolean keepDebugInfo) {
|
||||||
this.x = x - 1;
|
this.x = x - 1;
|
||||||
@ -58,8 +58,8 @@ final class MacroBlock {
|
|||||||
ySubBlocks = new SubBlock[4][4];
|
ySubBlocks = new SubBlock[4][4];
|
||||||
uSubBlocks = new SubBlock[2][2];
|
uSubBlocks = new SubBlock[2][2];
|
||||||
vSubBlocks = new SubBlock[2][2];
|
vSubBlocks = new SubBlock[2][2];
|
||||||
SubBlock above = null;
|
SubBlock above;
|
||||||
SubBlock left = null;
|
SubBlock left;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
@ -72,7 +72,7 @@ final class MacroBlock {
|
|||||||
above = ySubBlocks[j][i - 1];
|
above = ySubBlocks[j][i - 1];
|
||||||
}
|
}
|
||||||
ySubBlocks[j][i] = new SubBlock(this, above, left,
|
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];
|
above = uSubBlocks[j][i - 1];
|
||||||
}
|
}
|
||||||
uSubBlocks[j][i] = new SubBlock(this, above, left,
|
uSubBlocks[j][i] = new SubBlock(this, above, left,
|
||||||
SubBlock.PLANE.U);
|
SubBlock.Plane.U);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,12 +101,10 @@ final class MacroBlock {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
above = vSubBlocks[j][i - 1];
|
above = vSubBlocks[j][i - 1];
|
||||||
}
|
}
|
||||||
vSubBlocks[j][i] = new SubBlock(this, above, left,
|
vSubBlocks[j][i] = new SubBlock(this, above, left, SubBlock.Plane.V);
|
||||||
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 {
|
public void decodeMacroBlock(VP8Frame frame) throws IOException {
|
||||||
@ -115,57 +113,51 @@ final class MacroBlock {
|
|||||||
if (mb.getYMode() != Globals.B_PRED) {
|
if (mb.getYMode() != Globals.B_PRED) {
|
||||||
mb.skipInnerLoopFilter = true;
|
mb.skipInnerLoopFilter = true;
|
||||||
}
|
}
|
||||||
} else if (mb.getYMode() != Globals.B_PRED) {
|
}
|
||||||
decodeMacroBlockTokens(frame, true);
|
else {
|
||||||
} else {
|
decodeMacroBlockTokens(frame, mb.getYMode() != Globals.B_PRED);
|
||||||
decodeMacroBlockTokens(frame, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decodeMacroBlockTokens(VP8Frame frame, boolean withY2)
|
private void decodeMacroBlockTokens(VP8Frame frame, boolean withY2) throws IOException {
|
||||||
throws IOException {
|
|
||||||
skipInnerLoopFilter = false;
|
|
||||||
if (withY2) {
|
if (withY2) {
|
||||||
skipInnerLoopFilter = skipInnerLoopFilter
|
skipInnerLoopFilter = decodePlaneTokens(frame, 1, SubBlock.Plane.Y2, false);
|
||||||
| decodePlaneTokens(frame, 1, SubBlock.PLANE.Y2, false);
|
|
||||||
}
|
}
|
||||||
skipInnerLoopFilter = skipInnerLoopFilter
|
|
||||||
| decodePlaneTokens(frame, 4, SubBlock.PLANE.Y1, withY2);
|
skipInnerLoopFilter |= decodePlaneTokens(frame, 4, SubBlock.Plane.Y1, withY2);
|
||||||
skipInnerLoopFilter = skipInnerLoopFilter
|
skipInnerLoopFilter |= decodePlaneTokens(frame, 2, SubBlock.Plane.U, false);
|
||||||
| decodePlaneTokens(frame, 2, SubBlock.PLANE.U, false);
|
skipInnerLoopFilter |= decodePlaneTokens(frame, 2, SubBlock.Plane.V, false);
|
||||||
skipInnerLoopFilter = skipInnerLoopFilter
|
|
||||||
| decodePlaneTokens(frame, 2, SubBlock.PLANE.V, false);
|
|
||||||
skipInnerLoopFilter = !skipInnerLoopFilter;
|
skipInnerLoopFilter = !skipInnerLoopFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean decodePlaneTokens(VP8Frame frame, int dimentions,
|
private boolean decodePlaneTokens(VP8Frame frame, int dimentions,
|
||||||
SubBlock.PLANE plane, boolean withY2) throws IOException {
|
SubBlock.Plane plane, boolean withY2) throws IOException {
|
||||||
MacroBlock mb = this;
|
MacroBlock mb = this;
|
||||||
boolean r = false;
|
boolean r = false;
|
||||||
|
|
||||||
for (int y = 0; y < dimentions; y++) {
|
for (int y = 0; y < dimentions; y++) {
|
||||||
for (int x = 0; x < dimentions; x++) {
|
for (int x = 0; x < dimentions; x++) {
|
||||||
int L = 0;
|
int L = 0;
|
||||||
int A = 0;
|
int A = 0;
|
||||||
int lc = 0;
|
int lc = 0;
|
||||||
|
|
||||||
SubBlock sb = mb.getSubBlock(plane, x, y);
|
SubBlock sb = mb.getSubBlock(plane, x, y);
|
||||||
SubBlock left = frame.getLeftSubBlock(sb, plane);
|
SubBlock left = frame.getLeftSubBlock(sb, plane);
|
||||||
SubBlock above = frame.getAboveSubBlock(sb, plane);
|
SubBlock above = frame.getAboveSubBlock(sb, plane);
|
||||||
if (left.hasNoZeroToken()) {
|
|
||||||
|
|
||||||
|
if (left.hasNoZeroToken()) {
|
||||||
L = 1;
|
L = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lc += L;
|
lc += L;
|
||||||
|
|
||||||
if (above.hasNoZeroToken()) {
|
if (above.hasNoZeroToken()) {
|
||||||
|
|
||||||
A = 1;
|
A = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lc += A;
|
lc += A;
|
||||||
sb.decodeSubBlock(frame.getTokenBoolDecoder(),
|
sb.decodeSubBlock(frame.getTokenBoolDecoder(), frame.getCoefProbs(), lc, SubBlock.planeToType(plane, withY2), withY2);
|
||||||
frame.getCoefProbs(), lc,
|
|
||||||
SubBlock.planeToType(plane, withY2), withY2);
|
|
||||||
r = r | sb.hasNoZeroToken();
|
r = r | sb.hasNoZeroToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,7 +172,7 @@ final class MacroBlock {
|
|||||||
.getY2ac_delta_q();
|
.getY2ac_delta_q();
|
||||||
int dcQValue = frame.getSegmentQuants().getSegQuants()[this.getSegmentId()].getY2dc();
|
int dcQValue = frame.getSegmentQuants().getSegQuants()[this.getSegmentId()].getY2dc();
|
||||||
|
|
||||||
int input[] = new int[16];
|
int[] input = new int[16];
|
||||||
input[0] = sb.getTokens()[0] * dcQValue;
|
input[0] = sb.getTokens()[0] * dcQValue;
|
||||||
|
|
||||||
for (int x = 1; x < 16; x++) {
|
for (int x = 1; x < 16; x++) {
|
||||||
@ -206,8 +198,8 @@ final class MacroBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb.recon_mb();
|
mb.recon_mb();
|
||||||
|
}
|
||||||
} else {
|
else {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
SubBlock sb = mb.getYSubBlock(i, j);
|
SubBlock sb = mb.getYSubBlock(i, j);
|
||||||
@ -260,7 +252,7 @@ final class MacroBlock {
|
|||||||
return this.filterLevel;
|
return this.filterLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getBottomSubBlock(int x, SubBlock.PLANE plane) {
|
public SubBlock getBottomSubBlock(int x, SubBlock.Plane plane) {
|
||||||
switch (plane) {
|
switch (plane) {
|
||||||
case Y1:
|
case Y1:
|
||||||
return ySubBlocks[x][3];
|
return ySubBlocks[x][3];
|
||||||
@ -275,7 +267,7 @@ final class MacroBlock {
|
|||||||
throw new IllegalArgumentException("Bad plane: " + plane);
|
throw new IllegalArgumentException("Bad plane: " + plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getLeftSubBlock(int y, SubBlock.PLANE plane) {
|
public SubBlock getLeftSubBlock(int y, SubBlock.Plane plane) {
|
||||||
switch (plane) {
|
switch (plane) {
|
||||||
case Y1:
|
case Y1:
|
||||||
return ySubBlocks[0][y];
|
return ySubBlocks[0][y];
|
||||||
@ -290,7 +282,7 @@ final class MacroBlock {
|
|||||||
throw new IllegalArgumentException("Bad plane: " + plane);
|
throw new IllegalArgumentException("Bad plane: " + plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getRightSubBlock(int y, SubBlock.PLANE plane) {
|
public SubBlock getRightSubBlock(int y, SubBlock.Plane plane) {
|
||||||
switch (plane) {
|
switch (plane) {
|
||||||
case Y1:
|
case Y1:
|
||||||
return ySubBlocks[3][y];
|
return ySubBlocks[3][y];
|
||||||
@ -309,7 +301,7 @@ final class MacroBlock {
|
|||||||
return skipCoeff;
|
return skipCoeff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getSubBlock(SubBlock.PLANE plane, int i, int j) {
|
public SubBlock getSubBlock(SubBlock.Plane plane, int i, int j) {
|
||||||
switch (plane) {
|
switch (plane) {
|
||||||
case Y1:
|
case Y1:
|
||||||
return getYSubBlock(i, j);
|
return getYSubBlock(i, j);
|
||||||
@ -325,7 +317,7 @@ final class MacroBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getSubblockX(SubBlock sb) {
|
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 y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
if (ySubBlocks[x][y] == sb) {
|
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 y = 0; y < 2; y++) {
|
||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
if (uSubBlocks[x][y] == sb) {
|
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 y = 0; y < 2; y++) {
|
||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
if (vSubBlocks[x][y] == sb) {
|
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 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -100;
|
return -100;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSubblockY(SubBlock sb) {
|
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 y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
if (ySubBlocks[x][y] == sb) {
|
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 y = 0; y < 2; y++) {
|
||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
if (uSubBlocks[x][y] == sb) {
|
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 y = 0; y < 2; y++) {
|
||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
if (vSubBlocks[x][y] == sb) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,8 +442,8 @@ final class MacroBlock {
|
|||||||
boolean left_available = false;
|
boolean left_available = false;
|
||||||
int Uaverage = 0;
|
int Uaverage = 0;
|
||||||
int Vaverage = 0;
|
int Vaverage = 0;
|
||||||
int expected_udc = 0;
|
int expected_udc;
|
||||||
int expected_vdc = 0;
|
int expected_vdc;
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
left_available = true;
|
left_available = true;
|
||||||
}
|
}
|
||||||
@ -486,19 +483,20 @@ final class MacroBlock {
|
|||||||
|
|
||||||
expected_udc = (Uaverage + (1 << (shift - 1))) >> shift;
|
expected_udc = (Uaverage + (1 << (shift - 1))) >> shift;
|
||||||
expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift;
|
expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
expected_udc = 128;
|
expected_udc = 128;
|
||||||
expected_vdc = 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 y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
ufill[x][y] = expected_udc;
|
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 y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
vfill[x][y] = expected_vdc;
|
vfill[x][y] = expected_vdc;
|
||||||
@ -529,8 +527,8 @@ final class MacroBlock {
|
|||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
SubBlock usb = uSubBlocks[y][x];
|
SubBlock usb = uSubBlocks[y][x];
|
||||||
SubBlock vsb = vSubBlocks[y][x];
|
SubBlock vsb = vSubBlocks[y][x];
|
||||||
int ublock[][] = new int[4][4];
|
int[][] ublock = new int[4][4];
|
||||||
int vblock[][] = new int[4][4];
|
int[][] vblock = new int[4][4];
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
ublock[j][i] = aboveUSb[y]
|
ublock[j][i] = aboveUSb[y]
|
||||||
@ -560,8 +558,8 @@ final class MacroBlock {
|
|||||||
for (int x = 0; x < 2; x++) {
|
for (int x = 0; x < 2; x++) {
|
||||||
SubBlock usb = uSubBlocks[x][y];
|
SubBlock usb = uSubBlocks[x][y];
|
||||||
SubBlock vsb = vSubBlocks[x][y];
|
SubBlock vsb = vSubBlocks[x][y];
|
||||||
int ublock[][] = new int[4][4];
|
int[][] ublock = new int[4][4];
|
||||||
int vblock[][] = new int[4][4];
|
int[][] vblock = new int[4][4];
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
ublock[i][j] = leftUSb[y]
|
ublock[i][j] = leftUSb[y]
|
||||||
@ -610,10 +608,8 @@ final class MacroBlock {
|
|||||||
+ aboveVSb[d].getDest()[c][3] - alv;
|
+ aboveVSb[d].getDest()[c][3] - alv;
|
||||||
vpred = Globals.clamp(vpred, 255);
|
vpred = Globals.clamp(vpred, 255);
|
||||||
vSubBlocks[d][b].setPixel(c, a, vpred);
|
vSubBlocks[d][b].setPixel(c, a, vpred);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +631,7 @@ final class MacroBlock {
|
|||||||
boolean left_available = false;
|
boolean left_available = false;
|
||||||
|
|
||||||
int average = 0;
|
int average = 0;
|
||||||
int expected_dc = 0;
|
int expected_dc;
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
left_available = true;
|
left_available = true;
|
||||||
}
|
}
|
||||||
@ -671,11 +667,12 @@ final class MacroBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected_dc = (average + (1 << (shift - 1))) >> shift;
|
expected_dc = (average + (1 << (shift - 1))) >> shift;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
expected_dc = 128;
|
expected_dc = 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fill[][] = new int[4][4];
|
int[][] fill = new int[4][4];
|
||||||
for (int y = 0; y < 4; y++) {
|
for (int y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
fill[x][y] = expected_dc;
|
fill[x][y] = expected_dc;
|
||||||
@ -700,7 +697,7 @@ final class MacroBlock {
|
|||||||
for (int y = 0; y < 4; y++) {
|
for (int y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
SubBlock sb = ySubBlocks[x][y];
|
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 j = 0; j < 4; j++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
block[i][j] = aboveYSb[x].getPredict(
|
block[i][j] = aboveYSb[x].getPredict(
|
||||||
@ -708,7 +705,6 @@ final class MacroBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.setPredict(block);
|
sb.setPredict(block);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,7 +721,7 @@ final class MacroBlock {
|
|||||||
for (int y = 0; y < 4; y++) {
|
for (int y = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
SubBlock sb = ySubBlocks[x][y];
|
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 j = 0; j < 4; j++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
block[i][j] = leftYSb[y].getPredict(
|
block[i][j] = leftYSb[y].getPredict(
|
||||||
@ -736,10 +732,10 @@ final class MacroBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubBlock[] leftUSb = new SubBlock[2];
|
// SubBlock[] leftUSb = new SubBlock[2];
|
||||||
for (int x = 0; x < 2; x++) {
|
// for (int x = 0; x < 2; x++) {
|
||||||
leftUSb[x] = leftMb.getYSubBlock(1, x);
|
// leftUSb[x] = leftMb.getYSubBlock(1, x);
|
||||||
}
|
// }
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Globals.TM_PRED:
|
case Globals.TM_PRED:
|
||||||
@ -756,23 +752,20 @@ final class MacroBlock {
|
|||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
leftYSb[x] = leftMb.getYSubBlock(3, 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 b = 0; b < 4; b++) {
|
||||||
for (int a = 0; a < 4; a++) {
|
for (int a = 0; a < 4; a++) {
|
||||||
|
|
||||||
for (int d = 0; d < 4; d++) {
|
for (int d = 0; d < 4; d++) {
|
||||||
for (int c = 0; c < 4; c++) {
|
for (int c = 0; c < 4; c++) {
|
||||||
|
|
||||||
int pred = leftYSb[b].getDest()[3][a]
|
int pred = leftYSb[b].getDest()[3][a]
|
||||||
+ aboveYSb[d].getDest()[c][3] - al;
|
+ aboveYSb[d].getDest()[c][3] - al;
|
||||||
|
|
||||||
ySubBlocks[d][b].setPixel(c, a,
|
ySubBlocks[d][b].setPixel(c, a,
|
||||||
Globals.clamp(pred, 255));
|
Globals.clamp(pred, 255));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,7 +796,6 @@ final class MacroBlock {
|
|||||||
sb.reconstruct();
|
sb.reconstruct();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFilterLevel(int value) {
|
public void setFilterLevel(int value) {
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.plugins.webp.vp8.Globals.clamp;
|
||||||
|
|
||||||
final class SegmentQuant {
|
final class SegmentQuant {
|
||||||
private int filterStrength;
|
private int filterStrength;
|
||||||
private int Qindex;
|
private int Qindex;
|
||||||
@ -41,17 +43,6 @@ final class SegmentQuant {
|
|||||||
private int y2ac;
|
private int y2ac;
|
||||||
private int y2dc;
|
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() {
|
public int getQindex() {
|
||||||
return Qindex;
|
return Qindex;
|
||||||
}
|
}
|
||||||
@ -89,31 +80,31 @@ final class SegmentQuant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setUvac_delta_q(int uvac_delta_q) {
|
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) {
|
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() {
|
public void setY1ac() {
|
||||||
this.y1ac = Globals.vp8AcQLookup[clip(Qindex, 127)];
|
this.y1ac = Globals.vp8AcQLookup[clamp(Qindex, 127)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY1dc(int y1dc) {
|
public void setY1dc(int y1dc) {
|
||||||
this.y1dc = Globals.vp8DcQLookup[clip(Qindex + y1dc, 127)];
|
this.y1dc = Globals.vp8DcQLookup[clamp(Qindex + y1dc, 127)];
|
||||||
this.setY1ac();
|
this.setY1ac();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY2ac_delta_q(int y2ac_delta_q) {
|
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) {
|
if (this.y2ac < 8) {
|
||||||
this.y2ac = 8;
|
this.y2ac = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY2dc(int y2dc_delta_q) {
|
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() {
|
public int getFilterStrength() {
|
||||||
|
@ -35,8 +35,17 @@ import java.io.IOException;
|
|||||||
|
|
||||||
final class SegmentQuants {
|
final class SegmentQuants {
|
||||||
|
|
||||||
private static DeltaQ get_delta_q(BoolDecoder bc, int prev)
|
private int qIndex;
|
||||||
throws IOException {
|
|
||||||
|
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();
|
DeltaQ ret = new DeltaQ();
|
||||||
ret.v = 0;
|
ret.v = 0;
|
||||||
ret.update = false;
|
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) {
|
if (ret.v != prev) {
|
||||||
ret.update = true;
|
ret.update = true;
|
||||||
}
|
}
|
||||||
@ -57,16 +66,6 @@ final class SegmentQuants {
|
|||||||
return ret;
|
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() {
|
public int getqIndex() {
|
||||||
return qIndex;
|
return qIndex;
|
||||||
}
|
}
|
||||||
@ -76,7 +75,7 @@ final class SegmentQuants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void parse(BoolDecoder bc, boolean segmentation_enabled,
|
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);
|
qIndex = bc.readLiteral(7);
|
||||||
boolean q_update = false;
|
boolean q_update = false;
|
||||||
DeltaQ v = get_delta_q(bc, 0);
|
DeltaQ v = get_delta_q(bc, 0);
|
||||||
@ -98,7 +97,8 @@ final class SegmentQuants {
|
|||||||
for (SegmentQuant s : segQuants) {
|
for (SegmentQuant s : segQuants) {
|
||||||
if (!segmentation_enabled) {
|
if (!segmentation_enabled) {
|
||||||
s.setQindex(qIndex);
|
s.setQindex(qIndex);
|
||||||
} else if (!mb_segement_abs_delta) {
|
}
|
||||||
|
else if (!mb_segement_abs_delta) {
|
||||||
s.setQindex(s.getQindex() + qIndex);
|
s.setQindex(s.getQindex() + qIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +107,6 @@ final class SegmentQuants {
|
|||||||
s.setY2ac_delta_q(y2ac_delta_q);
|
s.setY2ac_delta_q(y2ac_delta_q);
|
||||||
s.setUvdc_delta_q(uvdc_delta_q);
|
s.setUvdc_delta_q(uvdc_delta_q);
|
||||||
s.setUvac_delta_q(uvac_delta_q);
|
s.setUvac_delta_q(uvac_delta_q);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSegQuants(SegmentQuant[] segQuants) {
|
|
||||||
this.segQuants = segQuants;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
package com.twelvemonkeys.imageio.plugins.webp.vp8;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
import javax.imageio.event.IIOReadProgressListener;
|
import javax.imageio.event.IIOReadProgressListener;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@ -41,30 +43,26 @@ import java.util.List;
|
|||||||
|
|
||||||
import static com.twelvemonkeys.imageio.color.YCbCrConverter.convertYCbCr2RGB;
|
import static com.twelvemonkeys.imageio.color.YCbCrConverter.convertYCbCr2RGB;
|
||||||
|
|
||||||
|
|
||||||
public final class VP8Frame {
|
public final class VP8Frame {
|
||||||
private static int BLOCK_TYPES = 4;
|
private static final int BLOCK_TYPES = 4;
|
||||||
private static int COEF_BANDS = 8;
|
private static final int COEF_BANDS = 8;
|
||||||
private static int MAX_ENTROPY_TOKENS = 12;
|
private static final int MAX_ENTROPY_TOKENS = 12;
|
||||||
private static int MAX_MODE_LF_DELTAS = 4;
|
private static final int MAX_MODE_LF_DELTAS = 4;
|
||||||
private static int MAX_REF_LF_DELTAS = 4;
|
private static final int MAX_REF_LF_DELTAS = 4;
|
||||||
private static int PREV_COEF_CONTEXTS = 3;
|
private static final int PREV_COEF_CONTEXTS = 3;
|
||||||
|
|
||||||
|
|
||||||
private IIOReadProgressListener listener = null;
|
private IIOReadProgressListener listener = null;
|
||||||
|
|
||||||
// private int bufferCount;
|
// private int bufferCount;
|
||||||
// private int buffersToCreate = 1;
|
// private int buffersToCreate = 1;
|
||||||
private int[][][][] coefProbs;
|
private final int[][][][] coefProbs;
|
||||||
private boolean debug = false;
|
|
||||||
private int filterLevel;
|
private int filterLevel;
|
||||||
|
|
||||||
private int filterType;
|
private final ImageInputStream frame;
|
||||||
|
private final boolean debug;
|
||||||
private ImageInputStream frame;
|
|
||||||
private int frameType;
|
private int frameType;
|
||||||
private int height;
|
private int height;
|
||||||
// private Logger logger;
|
|
||||||
private int macroBlockCols;
|
private int macroBlockCols;
|
||||||
private int macroBlockNoCoeffSkip;
|
private int macroBlockNoCoeffSkip;
|
||||||
private int macroBlockRows;
|
private int macroBlockRows;
|
||||||
@ -72,58 +70,50 @@ public final class VP8Frame {
|
|||||||
private MacroBlock[][] macroBlocks;
|
private MacroBlock[][] macroBlocks;
|
||||||
private int macroBlockSegementAbsoluteDelta;
|
private int macroBlockSegementAbsoluteDelta;
|
||||||
private int[] macroBlockSegmentTreeProbs;
|
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 modeRefLoopFilterDeltaEnabled;
|
||||||
private int modeRefLoopFilterDeltaUpdate;
|
private int modeRefLoopFilterDeltaUpdate;
|
||||||
private int multiTokenPartition = 0;
|
private int multiTokenPartition = 0;
|
||||||
|
|
||||||
private long offset;
|
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 refreshEntropyProbs;
|
||||||
private int refreshLastFrame;
|
private int refreshLastFrame;
|
||||||
private int segmentationIsEnabled;
|
private int segmentationIsEnabled;
|
||||||
private SegmentQuants segmentQuants;
|
private SegmentQuants segmentQuants;
|
||||||
private int sharpnessLevel;
|
private int sharpnessLevel;
|
||||||
private int simpleFilter;
|
private boolean simpleFilter;
|
||||||
private BoolDecoder tokenBoolDecoder;
|
private BoolDecoder tokenBoolDecoder;
|
||||||
private List<BoolDecoder> tokenBoolDecoders;
|
private final List<BoolDecoder> tokenBoolDecoders;
|
||||||
private int updateMacroBlockSegmentationMap;
|
private int updateMacroBlockSegmentationMap;
|
||||||
private int updateMacroBlockSegmentatonData;
|
private int updateMacroBlockSegmentatonData;
|
||||||
private int width;
|
private int width;
|
||||||
|
|
||||||
public VP8Frame(ImageInputStream stream) throws IOException {
|
public VP8Frame(final ImageInputStream stream, boolean debug) throws IOException {
|
||||||
this.frame = stream;
|
this.frame = stream;
|
||||||
offset = frame.getStreamPosition();
|
this.debug = debug;
|
||||||
this.coefProbs = Globals.getDefaultCoefProbs();
|
|
||||||
tokenBoolDecoders = new ArrayList<>();
|
|
||||||
// logger = new Logger();
|
|
||||||
}
|
|
||||||
|
|
||||||
// public VP8Frame(ImageInputStream stream, int[][][][] coefProbs) throws IOException {
|
offset = frame.getStreamPosition();
|
||||||
// this.frame = stream;
|
coefProbs = Globals.getDefaultCoefProbs();
|
||||||
// offset = frame.getStreamPosition();
|
tokenBoolDecoders = new ArrayList<>();
|
||||||
// this.coefProbs = coefProbs;
|
}
|
||||||
// tokenBoolDecoders = new ArrayList<>();
|
|
||||||
// logger = new Logger();
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void setProgressListener(IIOReadProgressListener listener) {
|
public void setProgressListener(IIOReadProgressListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createMacroBlocks() {
|
private void createMacroBlocks() {
|
||||||
macroBlocks = new MacroBlock[macroBlockCols + 2][macroBlockRows + 2];
|
macroBlocks = new MacroBlock[macroBlockRows + 2][macroBlockCols + 2];
|
||||||
for (int x = 0; x < macroBlockCols + 2; x++) {
|
for (int y = 0; y < macroBlockRows + 2; y++) {
|
||||||
for (int y = 0; y < macroBlockRows + 2; y++) {
|
for (int x = 0; x < macroBlockCols + 2; x++) {
|
||||||
macroBlocks[x][y] = new MacroBlock(x, y, debug);
|
macroBlocks[y][x] = new MacroBlock(x, y, debug);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean decodeFrame(boolean debug) throws IOException {
|
public boolean decode(final WritableRaster raster, final ImageReadParam param) throws IOException {
|
||||||
this.debug = debug;
|
|
||||||
segmentQuants = new SegmentQuants();
|
segmentQuants = new SegmentQuants();
|
||||||
|
|
||||||
int c = frame.readUnsignedByte();
|
int c = frame.readUnsignedByte();
|
||||||
frameType = getBitAsInt(c, 0);
|
frameType = getBitAsInt(c, 0);
|
||||||
// logger.log("Frame type: " + frameType);
|
// logger.log("Frame type: " + frameType);
|
||||||
@ -216,7 +206,7 @@ public final class VP8Frame {
|
|||||||
|
|
||||||
if (updateMacroBlockSegmentatonData > 0) {
|
if (updateMacroBlockSegmentatonData > 0) {
|
||||||
macroBlockSegementAbsoluteDelta = bc.readBit();
|
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++) {
|
for (int i = 0; i < Globals.MAX_MB_SEGMENTS; i++) {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
if (bc.readBit() > 0) {
|
if (bc.readBit() > 0) {
|
||||||
@ -241,19 +231,14 @@ public final class VP8Frame {
|
|||||||
if (updateMacroBlockSegmentationMap > 0) {
|
if (updateMacroBlockSegmentationMap > 0) {
|
||||||
macroBlockSegmentTreeProbs = new int[Globals.MB_FEATURE_TREE_PROBS];
|
macroBlockSegmentTreeProbs = new int[Globals.MB_FEATURE_TREE_PROBS];
|
||||||
for (int i = 0; i < Globals.MB_FEATURE_TREE_PROBS; i++) {
|
for (int i = 0; i < Globals.MB_FEATURE_TREE_PROBS; i++) {
|
||||||
int value = 255;
|
int value = bc.readBit() > 0 ? bc.readLiteral(8) : 255;
|
||||||
if (bc.readBit() > 0) {
|
|
||||||
value = bc.readLiteral(8);
|
|
||||||
} else {
|
|
||||||
value = 255;
|
|
||||||
}
|
|
||||||
macroBlockSegmentTreeProbs[i] = value;
|
macroBlockSegmentTreeProbs[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simpleFilter = bc.readBit();
|
simpleFilter = bc.readBit() != 0;
|
||||||
// logger.log("simpleFilter: " + simpleFilter);
|
// logger.log("simpleFilter: " + simpleFilter);
|
||||||
filterLevel = bc.readLiteral(6);
|
filterLevel = bc.readLiteral(6);
|
||||||
|
|
||||||
@ -271,19 +256,16 @@ public final class VP8Frame {
|
|||||||
for (int i = 0; i < MAX_REF_LF_DELTAS; i++) {
|
for (int i = 0; i < MAX_REF_LF_DELTAS; i++) {
|
||||||
if (bc.readBit() > 0) {
|
if (bc.readBit() > 0) {
|
||||||
refLoopFilterDeltas[i] = bc.readLiteral(6);
|
refLoopFilterDeltas[i] = bc.readLiteral(6);
|
||||||
if (bc.readBit() > 0) // Apply sign
|
if (bc.readBit() > 0) { // Apply sign
|
||||||
{
|
|
||||||
refLoopFilterDeltas[i] = refLoopFilterDeltas[i] * -1;
|
refLoopFilterDeltas[i] = refLoopFilterDeltas[i] * -1;
|
||||||
}
|
}
|
||||||
// logger.log("ref_lf_deltas[i]: " + refLoopFilterDeltas[i]);
|
// logger.log("ref_lf_deltas[i]: " + refLoopFilterDeltas[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) {
|
for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) {
|
||||||
|
|
||||||
if (bc.readBit() > 0) {
|
if (bc.readBit() > 0) {
|
||||||
modeLoopFilterDeltas[i] = bc.readLiteral(6);
|
modeLoopFilterDeltas[i] = bc.readLiteral(6);
|
||||||
if (bc.readBit() > 0) // Apply sign
|
if (bc.readBit() > 0) { // Apply sign
|
||||||
{
|
|
||||||
modeLoopFilterDeltas[i] = modeLoopFilterDeltas[i] * -1;
|
modeLoopFilterDeltas[i] = modeLoopFilterDeltas[i] * -1;
|
||||||
}
|
}
|
||||||
// logger.log("mode_lf_deltas[i]: " + modeLoopFilterDeltas[i]);
|
// 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);
|
setupTokenDecoder(bc, firstPartitionLengthInBytes, offset);
|
||||||
bc.seek();
|
bc.seek();
|
||||||
|
|
||||||
@ -317,7 +296,8 @@ public final class VP8Frame {
|
|||||||
refreshLastFrame = 0;
|
refreshLastFrame = 0;
|
||||||
if (frameType == 0) {
|
if (frameType == 0) {
|
||||||
refreshLastFrame = 1;
|
refreshLastFrame = 1;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
refreshLastFrame = bc.readBit();
|
refreshLastFrame = bc.readBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +307,6 @@ public final class VP8Frame {
|
|||||||
for (int j = 0; j < COEF_BANDS; j++) {
|
for (int j = 0; j < COEF_BANDS; j++) {
|
||||||
for (int k = 0; k < PREV_COEF_CONTEXTS; k++) {
|
for (int k = 0; k < PREV_COEF_CONTEXTS; k++) {
|
||||||
for (int l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) {
|
for (int l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) {
|
||||||
|
|
||||||
if (bc.readBool(Globals.vp8CoefUpdateProbs[i][j][k][l]) > 0) {
|
if (bc.readBool(Globals.vp8CoefUpdateProbs[i][j][k][l]) > 0) {
|
||||||
int newp = bc.readLiteral(8);
|
int newp = bc.readLiteral(8);
|
||||||
this.coefProbs[i][j][k][l] = newp;
|
this.coefProbs[i][j][k][l] = newp;
|
||||||
@ -343,100 +322,109 @@ public final class VP8Frame {
|
|||||||
|
|
||||||
if (frameType == 0) {
|
if (frameType == 0) {
|
||||||
readModes(bc);
|
readModes(bc);
|
||||||
} else {
|
}
|
||||||
// TODO
|
else {
|
||||||
throw new IllegalArgumentException("Bad input: Not an Intra frame");
|
throw new IIOException("Bad input: Not an Intra frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ibc = 0;
|
int ibc = 0;
|
||||||
int num_part = 1 << multiTokenPartition;
|
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) {
|
if (num_part > 1) {
|
||||||
tokenBoolDecoder = tokenBoolDecoders.get(ibc);
|
tokenBoolDecoder = tokenBoolDecoders.get(ibc);
|
||||||
tokenBoolDecoder.seek();
|
tokenBoolDecoder.seek();
|
||||||
|
|
||||||
decodeMacroBlockRow(mb_row);
|
decodeMacroBlockRow(row, raster, param);
|
||||||
|
|
||||||
ibc++;
|
ibc++;
|
||||||
if (ibc == num_part) {
|
if (ibc == num_part) {
|
||||||
ibc = 0;
|
ibc = 0;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
decodeMacroBlockRow(mb_row);
|
else {
|
||||||
|
decodeMacroBlockRow(row, raster, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
fireProgressUpdate(mb_row);
|
fireProgressUpdate(row);
|
||||||
}
|
|
||||||
|
|
||||||
if (getFilterType() > 0 && getFilterLevel() != 0) {
|
|
||||||
LoopFilter.loopFilter(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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++) {
|
for (int mbCol = 0; mbCol < macroBlockCols; mbCol++) {
|
||||||
MacroBlock mb = getMacroBlock(mbCol, mbRow);
|
MacroBlock mb = currRow[mbCol + 1];
|
||||||
|
|
||||||
mb.decodeMacroBlock(this);
|
mb.decodeMacroBlock(this);
|
||||||
mb.dequantMacroBlock(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) {
|
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);
|
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
|
// this might break at right edge
|
||||||
SubBlock r;
|
SubBlock r;
|
||||||
MacroBlock mb = sb.getMacroBlock();
|
MacroBlock mb = sb.getMacroBlock();
|
||||||
int x = mb.getSubblockX(sb);
|
int x = mb.getSubblockX(sb);
|
||||||
int y = mb.getSubblockY(sb);
|
int y = mb.getSubblockY(sb);
|
||||||
|
|
||||||
if (plane == SubBlock.PLANE.Y1) {
|
if (plane == SubBlock.Plane.Y1) {
|
||||||
|
|
||||||
// top row
|
// top row
|
||||||
if (y == 0 && x < 3) {
|
if (y == 0 && x < 3) {
|
||||||
|
|
||||||
MacroBlock mb2 = this.getMacroBlock(mb.getX(), mb.getY() - 1);
|
MacroBlock mb2 = this.getMacroBlock(mb.getX(), mb.getY() - 1);
|
||||||
r = mb2.getSubBlock(plane, x + 1, 3);
|
r = mb2.getSubBlock(plane, x + 1, 3);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
//top right
|
//top right
|
||||||
else if (y == 0 && x == 3) {
|
else if (y == 0 && x == 3) {
|
||||||
|
|
||||||
MacroBlock mb2 = this.getMacroBlock(mb.getX() + 1, mb.getY() - 1);
|
MacroBlock mb2 = this.getMacroBlock(mb.getX() + 1, mb.getY() - 1);
|
||||||
r = mb2.getSubBlock(plane, 0, 3);
|
r = mb2.getSubBlock(plane, 0, 3);
|
||||||
|
|
||||||
if (mb2.getX() == this.getMacroBlockCols()) {
|
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 b = 0; b < 4; b++) {
|
||||||
for (int a = 0; a < 4; a++) {
|
for (int a = 0; a < 4; a++) {
|
||||||
if (mb2.getY() < 0) {
|
if (mb2.getY() < 0) {
|
||||||
dest[a][b] = 127;
|
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);
|
r.setDest(dest);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
//not right edge or top row
|
//not right edge or top row
|
||||||
else if (y > 0 && x < 3) {
|
else if (y > 0 && x < 3) {
|
||||||
|
|
||||||
r = mb.getSubBlock(plane, x + 1, y - 1);
|
r = mb.getSubBlock(plane, x + 1, y - 1);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -445,34 +433,36 @@ public final class VP8Frame {
|
|||||||
SubBlock sb2 = mb.getSubBlock(sb.getPlane(), 3, 0);
|
SubBlock sb2 = mb.getSubBlock(sb.getPlane(), 3, 0);
|
||||||
return this.getAboveRightSubBlock(sb2, plane);
|
return this.getAboveRightSubBlock(sb2, plane);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// TODO
|
// TODO
|
||||||
throw new IllegalArgumentException("bad input: getAboveRightSubBlock()");
|
throw new IllegalArgumentException("bad input: getAboveRightSubBlock()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getAboveSubBlock(SubBlock sb, SubBlock.PLANE plane) {
|
public SubBlock getAboveSubBlock(SubBlock sb, SubBlock.Plane plane) {
|
||||||
SubBlock r = sb.getAbove();
|
SubBlock above = sb.getAbove();
|
||||||
if (r == null) {
|
|
||||||
|
if (above == null) {
|
||||||
MacroBlock mb = sb.getMacroBlock();
|
MacroBlock mb = sb.getMacroBlock();
|
||||||
int x = mb.getSubblockX(sb);
|
int x = mb.getSubblockX(sb);
|
||||||
|
|
||||||
MacroBlock mb2 = getMacroBlock(mb.getX(), mb.getY() - 1);
|
MacroBlock mb2 = getMacroBlock(mb.getX(), mb.getY() - 1);
|
||||||
//TODO: SPLIT
|
//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);
|
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) {
|
// private boolean getBit(int data, int bit) {
|
||||||
int r = data & (1 << bit);
|
// int r = data & (1 << bit);
|
||||||
return r != 0;
|
// return r != 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private int getBitAsInt(int data, int bit) {
|
private int getBitAsInt(int data, int bit) {
|
||||||
int r = data & (1 << bit);
|
int r = data & (1 << bit);
|
||||||
@ -492,11 +482,11 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int yy, u, v;
|
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];
|
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];
|
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];
|
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[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[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));
|
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);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int yy, u, v;
|
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];
|
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];
|
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];
|
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[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[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));
|
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);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int u;
|
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[0] = u;
|
||||||
c[1] = u;
|
c[1] = u;
|
||||||
c[2] = u;
|
c[2] = u;
|
||||||
@ -577,9 +567,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int u;
|
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[0] = u;
|
||||||
c[1] = u;
|
c[1] = u;
|
||||||
c[2] = u;
|
c[2] = u;
|
||||||
@ -604,9 +594,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int u;
|
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[0] = u;
|
||||||
c[1] = u;
|
c[1] = u;
|
||||||
c[2] = u;
|
c[2] = u;
|
||||||
@ -631,9 +621,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int v;
|
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[0] = v;
|
||||||
c[1] = v;
|
c[1] = v;
|
||||||
c[2] = v;
|
c[2] = v;
|
||||||
@ -658,9 +648,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int v;
|
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[0] = v;
|
||||||
c[1] = v;
|
c[1] = v;
|
||||||
c[2] = v;
|
c[2] = v;
|
||||||
@ -685,9 +675,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int v;
|
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[0] = v;
|
||||||
c[1] = v;
|
c[1] = v;
|
||||||
c[2] = v;
|
c[2] = v;
|
||||||
@ -712,9 +702,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int yy;
|
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[0] = yy;
|
||||||
c[1] = yy;
|
c[1] = yy;
|
||||||
c[2] = yy;
|
c[2] = yy;
|
||||||
@ -739,9 +729,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int yy;
|
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[0] = yy;
|
||||||
c[1] = yy;
|
c[1] = yy;
|
||||||
c[2] = yy;
|
c[2] = yy;
|
||||||
@ -766,9 +756,9 @@ public final class VP8Frame {
|
|||||||
WritableRaster imRas = bi.getWritableTile(0, 0);
|
WritableRaster imRas = bi.getWritableTile(0, 0);
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
int c[] = new int[3];
|
int[] c = new int[3];
|
||||||
int yy;
|
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[0] = yy;
|
||||||
c[1] = yy;
|
c[1] = yy;
|
||||||
c[2] = yy;
|
c[2] = yy;
|
||||||
@ -788,23 +778,19 @@ public final class VP8Frame {
|
|||||||
return bi;
|
return bi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFilterLevel() {
|
|
||||||
return filterLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFilterType() {
|
|
||||||
return filterType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFrameType() {
|
public int getFrameType() {
|
||||||
return frameType;
|
return frameType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getLeftSubBlock(SubBlock sb, SubBlock.PLANE plane) {
|
public SubBlock getLeftSubBlock(SubBlock sb, SubBlock.Plane plane) {
|
||||||
SubBlock r = sb.getLeft();
|
SubBlock r = sb.getLeft();
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
MacroBlock mb = sb.getMacroBlock();
|
MacroBlock mb = sb.getMacroBlock();
|
||||||
@ -812,19 +798,19 @@ public final class VP8Frame {
|
|||||||
MacroBlock mb2 = getMacroBlock(mb.getX() - 1, mb.getY());
|
MacroBlock mb2 = getMacroBlock(mb.getX() - 1, mb.getY());
|
||||||
//TODO: SPLIT
|
//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());
|
mb2 = getMacroBlock(mb2.getX() - 1, mb2.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
r = mb2.getRightSubBlock(y, sb.getPlane());
|
r = mb2.getRightSubBlock(y, sb.getPlane());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MacroBlock getMacroBlock(int mbCol, int mbRow) {
|
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() {
|
public int getMacroBlockCols() {
|
||||||
@ -832,18 +818,18 @@ public final class VP8Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getMacroBlockDebugString(int mbx, int mby, int sbx, int sby) {
|
public String getMacroBlockDebugString(int mbx, int mby, int sbx, int sby) {
|
||||||
String r = new String();
|
String r = "";
|
||||||
if (mbx < this.macroBlockCols && mby < this.getMacroBlockRows()) {
|
if (mbx < this.macroBlockCols && mby < this.getMacroBlockRows()) {
|
||||||
MacroBlock mb = getMacroBlock(mbx, mby);
|
MacroBlock mb = getMacroBlock(mbx, mby);
|
||||||
r = r + mb.getDebugString();
|
r = r + mb.getDebugString();
|
||||||
if (sbx < 4 && sby < 4) {
|
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();
|
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();
|
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();
|
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();
|
r = r + "\n SubBlock " + sbx / 2 + ", " + sby / 2 + "\n " + sb.getDebugString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -871,72 +857,65 @@ public final class VP8Frame {
|
|||||||
return tokenBoolDecoder;
|
return tokenBoolDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[][] getUBuffer() {
|
// public int[][] getUBuffer() {
|
||||||
int r[][] = new int[macroBlockCols * 8][macroBlockRows * 8];
|
// int[][] r = new int[macroBlockCols * 8][macroBlockRows * 8];
|
||||||
for (int y = 0; y < macroBlockRows; y++) {
|
// for (int y = 0; y < macroBlockRows; y++) {
|
||||||
for (int x = 0; x < macroBlockCols; x++) {
|
// for (int x = 0; x < macroBlockCols; x++) {
|
||||||
MacroBlock mb = macroBlocks[x + 1][y + 1];
|
// MacroBlock mb = macroBlocks[x + 1][y + 1];
|
||||||
for (int b = 0; b < 2; b++) {
|
// for (int b = 0; b < 2; b++) {
|
||||||
for (int a = 0; a < 2; a++) {
|
// for (int a = 0; a < 2; a++) {
|
||||||
SubBlock sb = mb.getUSubBlock(a, b);
|
// SubBlock sb = mb.getUSubBlock(a, b);
|
||||||
for (int d = 0; d < 4; d++) {
|
// for (int d = 0; d < 4; d++) {
|
||||||
for (int c = 0; c < 4; c++) {
|
// for (int c = 0; c < 4; c++) {
|
||||||
r[(x * 8) + (a * 4) + c][(y * 8) + (b * 4) + d] = sb.getDest()[c][d];
|
// 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;
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
// 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++) {
|
||||||
return r;
|
// for (int a = 0; a < 4; a++) {
|
||||||
}
|
// SubBlock sb = mb.getYSubBlock(a, b);
|
||||||
|
// for (int d = 0; d < 4; d++) {
|
||||||
public int[][] getVBuffer() {
|
// for (int c = 0; c < 4; c++) {
|
||||||
int r[][] = new int[macroBlockCols * 8][macroBlockRows * 8];
|
// r[(x * 16) + (a * 4) + c][(y * 16) + (b * 4) + d] = sb.getDest()[c][d];
|
||||||
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++) {
|
// return r;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readModes(BoolDecoder bc) throws IOException {
|
private void readModes(BoolDecoder bc) throws IOException {
|
||||||
int mb_row = -1;
|
int mb_row = -1;
|
||||||
@ -949,7 +928,6 @@ public final class VP8Frame {
|
|||||||
while (++mb_row < macroBlockRows) {
|
while (++mb_row < macroBlockRows) {
|
||||||
int mb_col = -1;
|
int mb_col = -1;
|
||||||
while (++mb_col < macroBlockCols) {
|
while (++mb_col < macroBlockCols) {
|
||||||
|
|
||||||
//if (this.segmentation_enabled > 0) {
|
//if (this.segmentation_enabled > 0) {
|
||||||
// logger.log(Level.SEVERE, "TODO:");
|
// logger.log(Level.SEVERE, "TODO:");
|
||||||
// throw new IllegalArgumentException("bad input: segmentation_enabled()");
|
// throw new IllegalArgumentException("bad input: segmentation_enabled()");
|
||||||
@ -966,9 +944,10 @@ public final class VP8Frame {
|
|||||||
if (modeRefLoopFilterDeltaEnabled > 0) {
|
if (modeRefLoopFilterDeltaEnabled > 0) {
|
||||||
int level = filterLevel;
|
int level = filterLevel;
|
||||||
level = level + refLoopFilterDeltas[0];
|
level = level + refLoopFilterDeltas[0];
|
||||||
level = (level < 0) ? 0 : (level > 63) ? 63 : level;
|
level = (level < 0) ? 0 : Math.min(level, 63);
|
||||||
mb.setFilterLevel(level);
|
mb.setFilterLevel(level);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
mb.setFilterLevel(segmentQuants.getSegQuants()[mb.getSegmentId()].getFilterStrength());
|
mb.setFilterLevel(segmentQuants.getSegQuants()[mb.getSegmentId()].getFilterStrength());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,35 +962,27 @@ public final class VP8Frame {
|
|||||||
if (y_mode == Globals.B_PRED) {
|
if (y_mode == Globals.B_PRED) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
|
|
||||||
SubBlock sb = mb.getYSubBlock(j, i);
|
SubBlock sb = mb.getYSubBlock(j, i);
|
||||||
|
SubBlock A = getAboveSubBlock(sb, SubBlock.Plane.Y1);
|
||||||
SubBlock A = getAboveSubBlock(sb, SubBlock.PLANE.Y1);
|
SubBlock L = getLeftSubBlock(sb, SubBlock.Plane.Y1);
|
||||||
|
|
||||||
SubBlock L = getLeftSubBlock(sb, SubBlock.PLANE.Y1);
|
|
||||||
|
|
||||||
int mode = readSubBlockMode(bc, A.getMode(), L.getMode());
|
int mode = readSubBlockMode(bc, A.getMode(), L.getMode());
|
||||||
|
|
||||||
sb.setMode(mode);
|
sb.setMode(mode);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modeRefLoopFilterDeltaEnabled > 0) {
|
if (modeRefLoopFilterDeltaEnabled > 0) {
|
||||||
int level = mb.getFilterLevel();
|
int level = mb.getFilterLevel();
|
||||||
level = level + this.modeLoopFilterDeltas[0];
|
level = level + this.modeLoopFilterDeltas[0];
|
||||||
level = (level < 0) ? 0 : (level > 63) ? 63 : level;
|
level = (level < 0) ? 0 : Math.min(level, 63);
|
||||||
mb.setFilterLevel(level);
|
mb.setFilterLevel(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int BMode;
|
int BMode;
|
||||||
|
|
||||||
|
|
||||||
switch (y_mode) {
|
switch (y_mode) {
|
||||||
case Globals.DC_PRED:
|
|
||||||
BMode = Globals.B_DC_PRED;
|
|
||||||
break;
|
|
||||||
case Globals.V_PRED:
|
case Globals.V_PRED:
|
||||||
BMode = Globals.B_VE_PRED;
|
BMode = Globals.B_VE_PRED;
|
||||||
break;
|
break;
|
||||||
@ -1021,10 +992,12 @@ public final class VP8Frame {
|
|||||||
case Globals.TM_PRED:
|
case Globals.TM_PRED:
|
||||||
BMode = Globals.B_TM_PRED;
|
BMode = Globals.B_TM_PRED;
|
||||||
break;
|
break;
|
||||||
|
case Globals.DC_PRED:
|
||||||
default:
|
default:
|
||||||
BMode = Globals.B_DC_PRED;
|
BMode = Globals.B_DC_PRED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < 4; x++) {
|
||||||
for (int y = 0; y < 4; y++) {
|
for (int y = 0; y < 4; y++) {
|
||||||
SubBlock sb = mb.getYSubBlock(x, y);
|
SubBlock sb = mb.getYSubBlock(x, y);
|
||||||
@ -1041,7 +1014,6 @@ public final class VP8Frame {
|
|||||||
private int readPartitionSize(long l) throws IOException {
|
private int readPartitionSize(long l) throws IOException {
|
||||||
frame.seek(l);
|
frame.seek(l);
|
||||||
return frame.readUnsignedByte() + (frame.readUnsignedByte() << 8) + (frame.readUnsignedByte() << 16);
|
return frame.readUnsignedByte() + (frame.readUnsignedByte() << 8) + (frame.readUnsignedByte() << 16);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readSubBlockMode(BoolDecoder bc, int A, int L) throws IOException {
|
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);
|
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 {
|
private void setupTokenDecoder(BoolDecoder bc, int first_partition_length_in_bytes, long offset) throws IOException {
|
||||||
long partitionSize;
|
long partitionSize;
|
||||||
long partitionsStart = offset + first_partition_length_in_bytes;
|
long partitionsStart = offset + first_partition_length_in_bytes;
|
||||||
@ -1073,15 +1040,12 @@ public final class VP8Frame {
|
|||||||
partition += 3 * (num_part - 1);
|
partition += 3 * (num_part - 1);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < num_part; i++) {
|
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) {
|
if (i < num_part - 1) {
|
||||||
|
|
||||||
partitionSize = readPartitionSize(partitionsStart + (i * 3));
|
partitionSize = readPartitionSize(partitionsStart + (i * 3));
|
||||||
bc.seek();
|
bc.seek();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
partitionSize = frame.length() - partition;
|
partitionSize = frame.length() - partition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,40 +1056,27 @@ public final class VP8Frame {
|
|||||||
tokenBoolDecoder = tokenBoolDecoders.get(0);
|
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
|
// 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
|
// We might be copying into a smaller raster
|
||||||
int w = Math.min(width, byteRGBRaster.getWidth());
|
int yStart = macroBlock.getY() * 16;
|
||||||
int h = Math.min(height, byteRGBRaster.getHeight());
|
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];
|
for (int y = 0; y < yEnd; y++) {
|
||||||
byte[] rgb = new byte[4]; // Allow decoding into RGBA, leaving the alpha out.
|
for (int x = 0; x < xEnd; x++) {
|
||||||
|
yuv[0] = (byte) macroBlock.getSubBlock(SubBlock.Plane.Y1, x / 4, y / 4).getDest()[x % 4][y % 4];
|
||||||
for (int y = 0; y < h; y++) {
|
yuv[1] = (byte) macroBlock.getSubBlock(SubBlock.Plane.U, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
||||||
for (int x = 0; x < w; x++) {
|
yuv[2] = (byte) macroBlock.getSubBlock(SubBlock.Plane.V, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
||||||
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];
|
|
||||||
|
|
||||||
convertYCbCr2RGB(yuv, rgb, 0);
|
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();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user