package org.jcodec.movtool.streaming.tracks; import java.io.IOException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import org.jcodec.codecs.h264.H264Encoder; import org.jcodec.codecs.h264.H264Utils; import org.jcodec.codecs.h264.encode.ConstantRateControl; import org.jcodec.codecs.mpeg12.MPEGDecoder; import org.jcodec.codecs.mpeg12.Mpeg2Thumb2x2; import org.jcodec.codecs.mpeg12.Mpeg2Thumb4x4; import org.jcodec.common.VideoDecoder; import org.jcodec.common.model.ColorSpace; import org.jcodec.common.model.Picture; import org.jcodec.common.model.Rect; import org.jcodec.common.model.Size; import org.jcodec.scale.ColorUtil; import org.jcodec.scale.Transform; /** * An MPEG thumbnail to AVC transcoder implemented fully in java ( using jcodec * codecs ). * * @author Jay Codec * */ public class MPEGToAVCTranscoder { private VideoDecoder decoder; private H264Encoder encoder; private Picture pic0; private Picture pic1; private Transform transform; private ConstantRateControl rc; private int scaleFactor; private int thumbWidth; private int thumbHeight; public MPEGToAVCTranscoder(int scaleFactor) { this.scaleFactor = scaleFactor; rc = new ConstantRateControl(Mpeg2AVCTrack.TARGET_RATE); this.decoder = getDecoder(scaleFactor); this.encoder = new H264Encoder(rc); } protected VideoDecoder getDecoder(int scaleFactor) { switch (scaleFactor) { case 2: return new Mpeg2Thumb2x2(); case 1: return new Mpeg2Thumb4x4(); case 0: return new MPEGDecoder(); default: throw new IllegalArgumentException("Unsupported scale factor: " + scaleFactor); } } public ByteBuffer transcodeFrame(ByteBuffer src, ByteBuffer dst, boolean iframe, int poc) throws IOException { if (src == null) return null; if (pic0 == null) { Size size = MPEGDecoder.getSize(src.duplicate()); thumbWidth = size.getWidth() >> this.scaleFactor; thumbHeight = size.getHeight() >> this.scaleFactor; int mbW = (thumbWidth + 8) >> 4; int mbH = (thumbHeight + 8) >> 4; pic0 = Picture.create(mbW << 4, (mbH + 1) << 4, ColorSpace.YUV444); } Picture decoded = decoder.decodeFrame(src, pic0.getData()); if (pic1 == null) { pic1 = Picture.create(decoded.getWidth(), decoded.getHeight(), encoder.getSupportedColorSpaces()[0]); transform = ColorUtil.getTransform(decoded.getColor(), encoder.getSupportedColorSpaces()[0]); } Picture toEnc; if (transform != null) { transform.transform(decoded, pic1); toEnc = pic1; } else { toEnc = decoded; } pic1.setCrop(new Rect(0, 0, thumbWidth, thumbHeight)); int rate = Mpeg2AVCTrack.TARGET_RATE; do { try { encoder.encodeFrame(toEnc, dst, iframe, poc); break; } catch (BufferOverflowException ex) { System.out.println("Abandon frame!!!"); rate -= 10; rc.setRate(rate); } } while (rate > 10); rc.setRate(Mpeg2AVCTrack.TARGET_RATE); H264Utils.encodeMOVPacket(dst); return dst; } }