org.jcodec.codecs.prores.Mpeg2Prores 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.prores;
import static org.jcodec.codecs.mpeg12.MPEGConst.BLOCK_TO_CC;
import static org.jcodec.common.model.ColorSpace.YUV422_10;
import java.nio.ByteBuffer;
import org.jcodec.codecs.mpeg12.MPEGDecoder;
import org.jcodec.codecs.mpeg12.bitstream.GOPHeader;
import org.jcodec.codecs.mpeg12.bitstream.SequenceHeader;
import org.jcodec.codecs.prores.ProresEncoder.Profile;
import org.jcodec.common.dct.DCTRef;
import org.jcodec.common.dct.SimpleIDCT10Bit;
import org.jcodec.common.model.Picture;
import org.jcodec.scale.ColorUtil;
import org.jcodec.scale.Transform;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Converts MPEG 2 I-frame to a ProRes frame without re-transcoding ( without
* inverse and forward DCT step and frame reconstruction ).
*
* This is possible due to MPEG 2 and ProRes use similar DCT 8x8 based
* compression with macroblocks of 16x16 pixels
*
* @author The JCodec project
*
*/
public class Mpeg2Prores extends MPEGDecoder {
private DCT2Prores dct2Prores;
public Mpeg2Prores(SequenceHeader sh, GOPHeader gh, Profile profile) {
super(sh, gh);
dct2Prores = new DCT2Prores(profile);
}
protected void idctPut(int[] block, int[][] buf, int stride, int chromaFormat, int blkNo, int mbX, int mbY,
int dctType) {
int mbAddr = mbY * (stride >> 4) + mbX;
int off = blkNo < 4 ? ((mbAddr << 8) + (blkNo << 6))
: ((mbAddr << (5 + chromaFormat)) + (((blkNo - 4) >> 1) << 6));
System.arraycopy(block, 0, buf[BLOCK_TO_CC[blkNo]], off, 64);
buf[3][mbAddr] = dctType;
}
public ByteBuffer transcode(ByteBuffer in, ByteBuffer _out) {
ByteBuffer out = _out.slice();
int width = (sh.horizontal_size + 15) & ~0xf;
int height = (sh.vertical_size + 15) & ~0xf;
int[][] buffer = new int[][] { new int[width * height], new int[width * height], new int[width * height],
new int[(width >> 4) * (height >> 4)] };
Picture dct = decodeFrame(in, buffer);
Picture[] pic = convert(dct);
if (pic.length == 1)
dct2Prores.encodeFrame(out, pic[0]);
else
dct2Prores.encodeFrame(out, pic[0], pic[1]);
out.flip();
return out;
}
private Picture[] convert(Picture dct) {
int nInterlaced = 0;
for (int i : dct.getPlaneData(3)) {
nInterlaced += i;
}
Picture[] result;
if (nInterlaced == 0) {
upShift(dct);
result = new Picture[] { colorCvt(dct) };
} /*
* else if (nInterlaced < dct.getDctTypes().length / 10) { result =
* new Picture[] { extend(progressive(dct)) }; }
*/else {
Picture[] field = interlaced(dct);
result = new Picture[] { colorCvt(field[0]), colorCvt(field[1]) };
}
System.out.println(nInterlaced);
return result;
}
private void upShift(Picture dct) {
for (int[] is : dct.getData()) {
upShift(is, 0, is.length);
}
}
private Picture[] interlaced(Picture dct) {
int mbWidth = (dct.getWidth() + 15) >> 4;
int mbHeight = (dct.getHeight() + 15) >> 4;
Picture field1 = Picture.create(dct.getWidth(), dct.getHeight() >> 1, dct.getColor());
Picture field2 = Picture.create(dct.getWidth(), dct.getHeight() >> 1, dct.getColor());
splitY(mbWidth, mbHeight, dct.getPlaneData(0), field1.getPlaneData(0), field2.getPlaneData(0),
dct.getPlaneData(3));
splitCbCr(mbWidth, mbHeight, dct.getPlaneData(1), field1.getPlaneData(1), field2.getPlaneData(1),
dct.getPlaneData(3));
splitCbCr(mbWidth, mbHeight, dct.getPlaneData(2), field1.getPlaneData(2), field2.getPlaneData(2),
dct.getPlaneData(3));
return new Picture[] { field1, field2 };
}
private final void splitY(int mbWidth, int mbHeight, int[] y, int[] y1, int[] y2, int[] dctTypes) {
int dstOff = 0, srcOff = 0, i = 0;
for (int mbY = 0; mbY < mbHeight; mbY++) {
for (int mbX = 0; mbX < mbWidth; mbX++, i++, dstOff += 256, srcOff += 256) {
if (dctTypes[i] == 0) {
SimpleIDCT10Bit.idct10(y, srcOff);
SimpleIDCT10Bit.idct10(y, srcOff + 64);
SimpleIDCT10Bit.idct10(y, srcOff + 128);
SimpleIDCT10Bit.idct10(y, srcOff + 192);
deinterleave(y, srcOff, srcOff + 128, y1, y2, dstOff);
deinterleave(y, srcOff + 64, srcOff + 192, y1, y2, dstOff + 64);
DCTRef.fdct(y1, dstOff);
DCTRef.fdct(y1, dstOff + 64);
DCTRef.fdct(y2, dstOff);
DCTRef.fdct(y2, dstOff + 64);
} else {
copyShift(y, srcOff, y1, dstOff, 128);
copyShift(y, srcOff + 128, y2, dstOff, 128);
}
}
if ((mbY & 0x1) == 0)
dstOff -= (mbWidth << 8) - 128;
else
dstOff -= 128;
}
}
private final void copyShift(int[] src, int srcOff, int[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++)
src[srcOff++] = dst[dstOff++] << 2;
}
private final void splitCbCr(int mbWidth, int mbHeight, int[] y, int[] y1, int[] y2, int[] dctTypes) {
int dstOff = 0, srcOff = 0, i = 0;
for (int mbY = 0; mbY < mbHeight; mbY++) {
for (int mbX = 0; mbX < mbWidth; mbX++, i++, dstOff += 128, srcOff += 128) {
if (dctTypes[i] == 0) {
SimpleIDCT10Bit.idct10(y, srcOff);
SimpleIDCT10Bit.idct10(y, srcOff + 64);
deinterleave(y, srcOff, srcOff + 64, y1, y2, dstOff);
DCTRef.fdct(y1, dstOff);
DCTRef.fdct(y2, dstOff);
} else {
copyShift(y, srcOff, y1, dstOff, 64);
copyShift(y, srcOff + 64, y2, dstOff, 64);
}
}
if ((mbY & 0x1) == 0)
dstOff -= (mbWidth << 7) - 64;
else
dstOff -= 64;
}
}
private void deinterleave(int[] y, int topOff, int botOff, int[] y1, int[] y2, int blkOff) {
copyLine(y, y1, topOff + 0, blkOff + 0);
copyLine(y, y1, topOff + 16, blkOff + 8);
copyLine(y, y1, topOff + 32, blkOff + 16);
copyLine(y, y1, topOff + 48, blkOff + 24);
copyLine(y, y1, botOff + 0, blkOff + 32);
copyLine(y, y1, botOff + 16, blkOff + 40);
copyLine(y, y1, botOff + 32, blkOff + 48);
copyLine(y, y1, botOff + 48, blkOff + 56);
copyLine(y, y2, topOff + 8, blkOff + 0);
copyLine(y, y2, topOff + 24, blkOff + 8);
copyLine(y, y2, topOff + 40, blkOff + 16);
copyLine(y, y2, topOff + 56, blkOff + 24);
copyLine(y, y2, botOff + 8, blkOff + 32);
copyLine(y, y2, botOff + 24, blkOff + 40);
copyLine(y, y2, botOff + 40, blkOff + 48);
copyLine(y, y2, botOff + 56, blkOff + 56);
}
private Picture progressive(Picture dct) {
progressiveY(dct.getPlaneData(0), dct.getPlaneData(3));
progressiveCbCr(dct.getPlaneData(0), dct.getPlaneData(3));
progressiveCbCr(dct.getPlaneData(0), dct.getPlaneData(3));
return dct;
}
private void progressiveY(int[] y, int[] dctTypes) {
for (int i = 0; i < dctTypes.length; i++) {
if (dctTypes[i] == 1) {
SimpleIDCT10Bit.idct10(y, (i << 8) + 0);
SimpleIDCT10Bit.idct10(y, (i << 8) + 64);
SimpleIDCT10Bit.idct10(y, (i << 8) + 128);
SimpleIDCT10Bit.idct10(y, (i << 8) + 192);
interleave(y, (i << 8) + 0, (i << 8) + 128);
interleave(y, (i << 8) + 64, (i << 8) + 192);
DCTRef.fdct(y, (i << 8) + 0);
DCTRef.fdct(y, (i << 8) + 64);
DCTRef.fdct(y, (i << 8) + 128);
DCTRef.fdct(y, (i << 8) + 192);
} else {
upShift(y, i << 8, 256);
}
}
}
private void upShift(int[] y, int off, int len) {
for (int i = 0; i < len; i++)
y[off++] <<= 2;
}
private void progressiveCbCr(int[] y, int[] dctTypes) {
for (int i = 0; i < dctTypes.length; i++) {
if (dctTypes[i] == 1) {
SimpleIDCT10Bit.idct10(y, (i << 7) + 0);
SimpleIDCT10Bit.idct10(y, (i << 7) + 64);
interleave(y, (i << 7) + 0, (i << 7) + 64);
DCTRef.fdct(y, (i << 7) + 0);
DCTRef.fdct(y, (i << 7) + 64);
} else {
upShift(y, i << 7, 128);
}
}
}
private void interleave(int[] y, int off1, int off2) {
int[] tmp = new int[64];
for (int i = 0; i < 64; i++)
tmp[i] = y[off2 + i];
copyLine(y, y, off1 + 56, off2 + 48);
copyLine(y, y, off1 + 48, off2 + 32);
copyLine(y, y, off1 + 40, off2 + 16);
copyLine(y, y, off1 + 32, off2);
copyLine(y, y, off1 + 24, off1 + 48);
copyLine(y, y, off1 + 16, off1 + 32);
copyLine(y, y, off1 + 8, off1 + 16);
copyLine(tmp, y, 0, off1 + 8);
copyLine(tmp, y, 8, off1 + 24);
copyLine(tmp, y, 16, off1 + 40);
copyLine(tmp, y, 24, off1 + 56);
copyLine(tmp, y, 32, off2 + 8);
copyLine(tmp, y, 40, off2 + 24);
copyLine(tmp, y, 48, off2 + 40);
}
private final void copyLine(int[] from, int[] to, int offFrom, int offTo) {
for (int i = 0; i < 8; i++)
to[offTo++] = from[offFrom++];
}
private Picture colorCvt(Picture in) {
Picture out;
if (in.getColor() == YUV422_10) {
out = in;
} else {
Transform trans = ColorUtil.getTransform(in.getColor(), YUV422_10);
out = Picture.create(in.getWidth(), in.getHeight(), YUV422_10);
trans.transform(in, out);
}
return out;
}
}