org.jcodec.codecs.mjpeg.JpegDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.codecs.mjpeg;
import static org.jcodec.codecs.mjpeg.JpegUtils.zigzagDecodeAll;
import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import org.jcodec.common.JCodecUtil;
import org.jcodec.common.dct.DCT;
import org.jcodec.common.dct.IntDCT;
/**
* This class is part of JCodec ( www.jcodec.org )
* This software is distributed under FreeBSD License
*
* @author Jay Codec
*
*/
public class JpegDecoder {
private static final byte[] JFIF = JCodecUtil.asciiString("JFIF");
public static DecodedImage doIt(InputStream is) throws IOException {
JpegDecoder decoder = new JpegDecoder();
return decoder.decode(new JpegParser().parse(is));
}
private final static int align(int val, int align) {
return align + ((val - 1) & ~(align - 1));
}
public DecodedImage decode(CodedImage coded) throws IOException {
return decode(coded, new DecodedImage(coded.getWidth(), coded
.getHeight(), new int[coded.getWidth() * coded.getHeight()]));
}
public DecodedImage decode(CodedImage coded, DecodedImage decoded)
throws IOException {
IntBuffer result = IntBuffer.wrap(decoded.getPixels());
JPEGBitStream jbs = new JPEGBitStream(coded);
int blockH = coded.frame.getHmax() << 3;
int blockV = coded.frame.getVmax() << 3;
int width = coded.getWidth();
int height = coded.getHeight();
int alignedWidth = align(width, blockH);
int alignedHeight = align(height, blockV);
int xBlocks = alignedWidth / blockH;
int xxBlocks = width / blockH;
int yBlocks = alignedHeight / blockV;
int yyBlocks = height / blockV;
int dWidth = alignedWidth - width;
int dHeight = alignedHeight - height;
MCU block = MCU.create(coded.frame);
for (int by = 0; by < yyBlocks; by++) {
for (int bx = 0; bx < xxBlocks; bx++) {
readAndDecode(coded, jbs, block);
putBlock(result, width, block, bx, by);
}
for (int bx = xxBlocks; bx < xBlocks; bx++) {
readAndDecode(coded, jbs, block);
putBlock(result, width, block, bx, by, blockH - dWidth, blockV);
}
}
for (int by = yyBlocks; by < yBlocks; by++) {
for (int bx = 0; bx < xxBlocks; bx++) {
readAndDecode(coded, jbs, block);
putBlock(result, width, block, bx, by, blockH, blockV - dHeight);
}
for (int bx = xxBlocks; bx < xBlocks; bx++) {
readAndDecode(coded, jbs, block);
putBlock(result, width, block, bx, by, blockH - dWidth, blockV
- dHeight);
}
}
return decoded;
}
private static void putBlock(IntBuffer result, int width, MCU block,
int bx, int by) {
int blockH = block.h;
int blockV = block.v;
IntBuffer rgb = block.getRgb24();
int bY = by * blockV * width;
int bX = bx * blockH;
int blockPtr = bY + bX;
for (int j = 0; j < blockV; j++) {
result.position(blockPtr);
for (int i = 0; i < blockH; i++) {
result.put(rgb.get());
}
blockPtr += width;
}
}
/** Corner case of putBlock */
private static void putBlock(IntBuffer result, int width, MCU block,
int bx, int by, int blockH, int blockV) {
IntBuffer rgb = block.getRgb24();
int bY = by * block.v * width;
int bX = bx * block.h;
int blockPtr = bY + bX;
for (int j = 0; j < blockV; j++) {
result.position(blockPtr);
for (int i = 0; i < blockH; i++) {
result.put(rgb.get());
}
rgb.position(rgb.position() + (block.h - blockH));
blockPtr += width;
}
}
private static void readAndDecode(CodedImage coded, JPEGBitStream jbs,
MCU block) throws IOException {
jbs.readBlock(block);
decodeBlock(block, coded.getQuantLum(), coded.getQuantChrom());
}
protected static DCT dct = new IntDCT();
// private final static SlowDCT dct = new SlowDCT();
private static void decodeBlock(MCU block, QuantTable qLum,
QuantTable qChrom) {
zigzagDecodeAll(block.lum.data);
zigzagDecodeAll(block.cb.data);
zigzagDecodeAll(block.cr.data);
dequantAll(block.lum.data, qLum);
dequantAll(block.cb.data, qChrom);
dequantAll(block.cr.data, qChrom);
dct.decodeAll(block.lum.data);
dct.decodeAll(block.cb.data);
dct.decodeAll(block.cr.data);
IntBuffer rgb = block.getRgb24();
IntBuffer Cb = IntBuffer.wrap(block.cb.data[0]);
IntBuffer Cr = IntBuffer.wrap(block.cr.data[0]);
if (block.is420()) {
IntBuffer y00 = IntBuffer.wrap(block.lum.data[0]);
IntBuffer y01 = IntBuffer.wrap(block.lum.data[1]);
IntBuffer y10 = IntBuffer.wrap(block.lum.data[2]);
IntBuffer y11 = IntBuffer.wrap(block.lum.data[3]);
for (int j = 0; j < 8; j++) {
Cb.position((j & ~1) << 2);
Cr.position((j & ~1) << 2);
lineToRgb(y00, Cb, Cr, rgb);
lineToRgb(y01, Cb, Cr, rgb);
}
for (int j = 8; j < 16; j++) {
Cb.position((j & ~1) << 2);
Cr.position((j & ~1) << 2);
lineToRgb(y10, Cb, Cr, rgb);
lineToRgb(y11, Cb, Cr, rgb);
}
} else if (block.is422()) {
IntBuffer y00 = IntBuffer.wrap(block.lum.data[0]);
IntBuffer y01 = IntBuffer.wrap(block.lum.data[1]);
for (int j = 0; j < 8; j++) {
Cb.position(j << 3);
Cr.position(j << 3);
lineToRgb(y00, Cb, Cr, rgb);
lineToRgb(y01, Cb, Cr, rgb);
}
} else if (block.is444()) {
IntBuffer Y = IntBuffer.wrap(block.lum.data[0]);
while (rgb.hasRemaining()) {
rgb.put(ImageConvert
.ycbcr_to_rgb24(Y.get(), Cb.get(), Cr.get()));
}
} else {
throw new IllegalStateException("unsupported MCU");
}
}
private static void lineToRgb(IntBuffer Y, IntBuffer Cb, IntBuffer Cr,
IntBuffer rgb) {
for (int i = 0; i < 8; i++) {
Cb.position(Cb.position() - (i & 1));
Cr.position(Cr.position() - (i & 1));
int y = Y.get();
int cb = Cb.get();
int cr = Cr.get();
rgb.put(ImageConvert.ycbcr_to_rgb24(y, cb, cr));
}
}
private static void dequantAll(int[][] src, QuantTable quantTable) {
for (int i = 0; i < src.length; i++) {
dequant(src[i], quantTable);
}
}
private static void dequant(int[] src, QuantTable quantTable) {
for (int i = 0; i < 64; i++) {
src[i] = (quantTable.getValues()[i] * src[i]);
}
}
}