/* * Copyright (c) 2011 Michael Zucchi * * This file is part of jjmpeg, a java binding to ffmpeg's libraries. * * jjmpeg is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * jjmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with jjmpeg. If not, see <http://www.gnu.org/licenses/>. */ package au.notzed.jjmpeg; import au.notzed.jjmpeg.exception.AVDecodingError; import au.notzed.jjmpeg.exception.AVEncodingError; import au.notzed.jjmpeg.exception.AVIOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.nio.ShortBuffer; /** * * @author notzed */ public class AVCodecContext extends AVCodecContextAbstract { // TODO: move these to an interface public static final int AVMEDIA_TYPE_UNKNOWN = -1; public static final int AVMEDIA_TYPE_VIDEO = 0; public static final int AVMEDIA_TYPE_AUDIO = 1; public static final int AVMEDIA_TYPE_DATA = 2; public static final int AVMEDIA_TYPE_SUBTITLE = 3; public static final int AVMEDIA_TYPE_ATTACHMENT = 4; public static final int AVMEDIA_TYPE_NB = 5; // public static final int FF_MB_DECISION_SIMPLE = 0; ///< uses mb_cmp public static final int FF_MB_DECISION_BITS = 1; ///< chooses the one which needs the fewest bits public static final int FF_MB_DECISION_RD = 2; ///< rate distortion public static final int // ///< Use fixed qscale. public static final int CODEC_FLAG_QSCALE = 0x0002; ///< 4 MV per MB allowed / advanced prediction for H.263. public static final int CODEC_FLAG_4MV = 0x0004; ///< Use qpel MC. public static final int CODEC_FLAG_QPEL = 0x0010; ///< Use GMC. public static final int CODEC_FLAG_GMC = 0x0020; ///< Always try a MB with MV=<0,0>. public static final int CODEC_FLAG_MV0 = 0x0040; ///< Use data partitioning. public static final int CODEC_FLAG_PART = 0x0080; public static final int CODEC_FLAG_INPUT_PRESERVED = 0x0100; ///< Use internal 2pass ratecontrol in first pass mode. public static final int CODEC_FLAG_PASS1 = 0x0200; ///< Use internal 2pass ratecontrol in second pass mode. public static final int CODEC_FLAG_PASS2 = 0x0400; ///< Use external Huffman table (for MJPEG). public static final int CODEC_FLAG_EXTERN_HUFF = 0x1000; ///< Only decode/encode grayscale. public static final int CODEC_FLAG_GRAY = 0x2000; ///< Don't draw edges. public static final int CODEC_FLAG_EMU_EDGE = 0x4000; ///< error[?] variables will be set during encoding. public static final int CODEC_FLAG_PSNR = 0x8000; /** Input bitstream might be truncated at a random * public static final int CODEC_FLAG_TRUNCATED = 0x00010000; * location instead of only at frame boundaries. */ ///< Normalize adaptive quantization. public static final int CODEC_FLAG_NORMALIZE_AQP = 0x00020000; ///< Use interlaced DCT. public static final int CODEC_FLAG_INTERLACED_DCT = 0x00040000; ///< Force low delay. public static final int CODEC_FLAG_LOW_DELAY = 0x00080000; ///< Use alternate scan. public static final int CODEC_FLAG_ALT_SCAN = 0x00100000; ///< Place global headers in extradata instead of every keyframe. public static final int CODEC_FLAG_GLOBAL_HEADER = 0x00400000; ///< Use only bitexact stuff (except (I)DCT). public static final int CODEC_FLAG_BITEXACT = 0x00800000; /* Fx : Flag for h263+ extra options */ ///< H.263 advanced intra coding / MPEG-4 AC prediction public static final int CODEC_FLAG_AC_PRED = 0x01000000; ///< unlimited motion vector public static final int CODEC_FLAG_H263P_UMV = 0x02000000; ///< Use rate distortion optimization for cbp. public static final int CODEC_FLAG_CBP_RD = 0x04000000; ///< Use rate distortion optimization for qp selectioon. public static final int CODEC_FLAG_QP_RD = 0x08000000; ///< H.263 alternative inter VLC public static final int CODEC_FLAG_H263P_AIV = 0x00000008; ///< OBMC public static final int CODEC_FLAG_OBMC = 0x00000001; ///< loop filter public static final int CODEC_FLAG_LOOP_FILTER = 0x00000800; public static final int CODEC_FLAG_H263P_SLICE_STRUCT = 0x10000000; ///< interlaced motion estimation public static final int CODEC_FLAG_INTERLACED_ME = 0x20000000; ///< Will reserve space for SVCD scan offset user data. public static final int CODEC_FLAG_SVCD_SCAN_OFFSET = 0x40000000; public static final int CODEC_FLAG_CLOSED_GOP = 0x80000000; ///< Allow non spec compliant speedup tricks. public static final int CODEC_FLAG2_FAST = 0x00000001; ///< Strictly enforce GOP size. public static final int CODEC_FLAG2_STRICT_GOP = 0x00000002; ///< Skip bitstream encoding. public static final int CODEC_FLAG2_NO_OUTPUT = 0x00000004; ///< Place global headers at every keyframe instead of in extradata. public static final int CODEC_FLAG2_LOCAL_HEADER = 0x00000008; ///< H.264 allow B-frames to be used as references. public static final int CODEC_FLAG2_BPYRAMID = 0x00000010; ///< H.264 weighted biprediction for B-frames public static final int CODEC_FLAG2_WPRED = 0x00000020; ///< H.264 one reference per partition, as opposed to one reference per macroblock public static final int CODEC_FLAG2_MIXED_REFS = 0x00000040; ///< H.264 high profile 8x8 transform public static final int CODEC_FLAG2_8X8DCT = 0x00000080; ///< H.264 fast pskip public static final int CODEC_FLAG2_FASTPSKIP = 0x00000100; ///< H.264 access unit delimiters public static final int CODEC_FLAG2_AUD = 0x00000200; ///< B-frame rate-distortion optimization public static final int CODEC_FLAG2_BRDO = 0x00000400; ///< Use MPEG-2 intra VLC table. public static final int CODEC_FLAG2_INTRA_VLC = 0x00000800; ///< Only do ME/MC (I frames -> ref, P frame -> ME+MC). public static final int CODEC_FLAG2_MEMC_ONLY = 0x00001000; ///< timecode is in drop frame format. public static final int CODEC_FLAG2_DROP_FRAME_TIMECODE = 0x00002000; ///< RD optimal MB level residual skipping public static final int CODEC_FLAG2_SKIP_RD = 0x00004000; ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. public static final int CODEC_FLAG2_CHUNKS = 0x00008000; ///< Use MPEG-2 nonlinear quantizer. public static final int CODEC_FLAG2_NON_LINEAR_QUANT = 0x00010000; ///< Use a bit reservoir when encoding if possible public static final int CODEC_FLAG2_BIT_RESERVOIR = 0x00020000; ///< Use macroblock tree ratecontrol (x264 only) public static final int CODEC_FLAG2_MBTREE = 0x00040000; ///< Use psycho visual optimizations. public static final int CODEC_FLAG2_PSY = 0x00080000; ///< Compute SSIM during encoding, error[] values are undefined. public static final int CODEC_FLAG2_SSIM = 0x00100000; ///< Use periodic insertion of intra blocks instead of keyframes. public static final int CODEC_FLAG2_INTRA_REFRESH = 0x00200000; // public static final int FF_LAMBDA_SHIFT = 7; public static final int FF_LAMBDA_SCALE = (1 << FF_LAMBDA_SHIFT); public static final int FF_QP2LAMBDA = 118; ///< factor to convert from H.263 QP to lambda public static final int FF_LAMBDA_MAX = (256 * 128 - 1); // public static final long AV_TIME_BASE = 1000000; public static final long AV_NOPTS_VALUE = (0x8000000000000000L); public static final int AVCODEC_MAX_AUDIO_FRAME_SIZE = 192000; // 1 second of 48khz 32bit audio public static final int FF_MIN_BUFFER_SIZE = 16384; // private IntBuffer fin = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer(); protected AVCodecContext(ByteBuffer p) { setNative(new AVCodecContextNative(this, p)); } static AVCodecContext create(ByteBuffer p) { return new AVCodecContext(p); } public static AVCodecContext create() { AVCodecContext cc = allocContext(); if (cc != null) { ((AVCodecContextNative) cc.n).allocated = true; } return cc; } private boolean opened = false; public void open(AVCodec codec) throws AVIOException { int res = AVCodecContextNative.open(n.p, codec.n.p); if (res < 0) { throw new AVIOException(res); } opened = true; } @Override public int close() { if (opened) { opened = false; return super.close(); } else { return 0; } } @Override public void dispose() { close(); super.dispose(); } /** * Returns true if decoding frame complete. * * @param frame * @param packet * @return * @throws AVDecodingError */ public boolean decodeVideo(AVFrame frame, AVPacket packet) throws AVDecodingError { int res; res = decodeVideo2(frame, fin, packet); if (res < 0) { throw new AVDecodingError(-res); } return (fin.get(0) != 0); } /** * Encode video, writing result to buf. * * Note that it always writes to the start of the buffer, ignoring the position and limit. * * @param buf * @param pict Picture to encode, use null to flush encoded frames. * @return number of bytes written. When 0 with a null picture, encoding is complete. * @throws au.notzed.jjmpeg.exception.AVEncodingError */ public int encodeVideo(ByteBuffer buf, AVFrame pict) throws AVEncodingError { int buf_size = buf.capacity(); int len = encodeVideo(buf, buf_size, pict != null ? pict : null); if (len >= 0) { buf.limit(len); buf.position(0); return len; } else { throw new AVEncodingError(-len); } } /** * Decode an audio packet. * * @param samples on output the limit will be set to the number of short samples stored * @param packet * @return number of bytes written to samples * @throws AVDecodingError */ public int decodeAudio(AVSamples samples, AVAudioPacket packet) throws AVDecodingError { int data = 0; ByteBuffer buf = samples.getBuffer(); buf.limit(buf.capacity()); ShortBuffer s = (ShortBuffer) samples.getSamples(); while (data == 0 && packet.getSize() > 0) { int res = 0; fin.put(0, samples.getBuffer().capacity()); res = decodeAudio3(s, fin, packet); if (res < 0) { throw new AVDecodingError(-res); } data = fin.get(0); packet.consume(res); } samples.getBuffer().position(0); samples.getBuffer().limit(data); s.position(0); s.limit(data / 2); return data; } public int encodeAudio(ByteBuffer buf, AVSamples samples) throws AVEncodingError { int buf_size = buf.capacity(); int len = encodeAudio(buf, buf_size, (ShortBuffer) samples.getSamples()); assert (len < buf_size); if (len >= 0) { buf.limit(len); buf.position(0); return len; } else { throw new AVEncodingError(-len); } } } class AVCodecContextNative extends AVCodecContextNativeAbstract { boolean allocated = false; AVCodecContextNative(AVObject o, ByteBuffer p) { super(o, p); } @Override public void dispose() { if (p != null) { // close? if (allocated) { _free(p); } } super.dispose(); } }