package net.sourceforge.jffmpeg; import javax.media.ResourceUnavailableException; import javax.media.Codec; import javax.media.Format; import javax.media.format.VideoFormat; import javax.media.format.RGBFormat; import javax.media.format.YUVFormat; import javax.media.Buffer; import java.awt.Dimension; import net.sourceforge.jffmpeg.ffmpegnative.NativeDecoder; import net.sourceforge.jffmpeg.JMFCodec; /** * This class manages all ffmpeg native video codecs */ public class VideoDecoder implements Codec { private CodecManager codecManager = new CodecManager(); private JMFCodec peer = null; /** * Retrieve the supported input formats. * * @return Format[] the supported input formats */ public Format[] getSupportedInputFormats() { return codecManager.getSupportedVideoFormats(); } /** * Retrieve the supported output formats. Currently RGBVideo * for Java codecs. * * @return Format[] the supported output formats */ public Format[] getSupportedOutputFormats(Format format) { /* Sanity check */ if ( format == null ) return new Format[ 0 ]; /* Get corresponding Jffmpeg Format */ JffmpegVideoFormat videoCodec = codecManager.getVideoCodec( format.getEncoding() ); if ( format instanceof VideoFormat && videoCodec.isNative() ) { /* Video format */ VideoFormat videoIn = (VideoFormat)format; Dimension inSize = videoIn.getSize(); // System.out.println("Decoder:: getMatchingOutputFormats(" + in.getEncoding() + ", size:" + inSize + ", fps:" + videoIn.getFrameRate() + ")"); int strideY = inSize.width; int strideUV = strideY / 2; int offsetU = strideY * inSize.height; int offsetV = offsetU + strideUV * inSize.height / 2; return new VideoFormat [] { new YUVFormat(inSize, (strideY + strideUV) * inSize.height, Format.byteArray, videoIn.getFrameRate(), YUVFormat.YUV_420, strideY, strideUV, 0, offsetU, offsetV), new RGBFormat(inSize, inSize.width * inSize.height, Format.shortArray, videoIn.getFrameRate(), 15, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height, Format.shortArray, videoIn.getFrameRate(), 16, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height * 3, Format.byteArray, videoIn.getFrameRate(), 24, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, 3, inSize.width * 3, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height, Format.intArray, videoIn.getFrameRate(), 32, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height, Format.shortArray, videoIn.getFrameRate(), 16, 0x7c00, 0x3e0, 0x1f, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height, Format.shortArray, videoIn.getFrameRate(), 16, 0xf800, 0x3e0, 0x1f, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height * 3, Format.byteArray, videoIn.getFrameRate(), 24, 3, 2, 1, 3, inSize.width * 3, Format.FALSE, Format.NOT_SPECIFIED), new RGBFormat(inSize, inSize.width * inSize.height, Format.intArray, videoIn.getFrameRate(), 32, 0xff0000, 0x00ff00, 0x0000ff, 1, inSize.width, Format.FALSE, Format.NOT_SPECIFIED) }; } else if ( format instanceof VideoFormat && !videoCodec.isNative() ) { /* Java video codec */ return new Format[] { new RGBFormat() }; } else { /* Audio format */ return new Format[ 0 ]; } } /** * Negotiate the format for the input data. * * Only the width and height entries are used * * @return Format the negotiated input format */ public Format setInputFormat( Format format ) { JffmpegVideoFormat videoCodec = codecManager.getVideoCodec( format.getEncoding() ); if ( videoCodec == null ) return null; Dimension videoSize = ((VideoFormat)format).getSize(); if ( videoSize == null ) return null; /* Construct Codec */ try { peer = (JMFCodec)Class.forName( videoCodec.getCodecClass() ).newInstance(); if ( !peer.isCodecAvailable() ) return null; } catch ( ClassNotFoundException e ) { e.printStackTrace(); return null; } catch ( InstantiationException e ) { e.printStackTrace(); return null; } catch ( IllegalAccessException e ) { e.printStackTrace(); return null; } peer.setVideoSize( videoSize ); peer.setEncoding( videoCodec.getFFMpegCodecName() ); peer.setIsRtp( videoCodec.isRtp() ); peer.setIsTruncated( videoCodec.isTruncated() ); return format; } /** * Negotiate the format for screen display renderer. * * Only the frame rate entry is used. All the other * values are populated using the negotiated input formnat. * * @return Format RGBFormat to supply to display renderer. */ public Format setOutputFormat( Format format ) { if ( peer == null ) throw new IllegalArgumentException( "Must set Input Format first" ); return peer.setOutputFormat( format ); } /** * Convert data using this codec * * @return BUFFER_PROCESSED_OK The output buffer contains a valid frame * @return BUFFER_PROCESSED_FAILED A decoding problem was encountered */ public int process( Buffer in, Buffer out ) { return peer.process( in, out ); } /** * Initialise the video codec for use. */ public void open() throws ResourceUnavailableException { peer.open(); } /** * Deallocate resources, and shutdown. */ public void close() { peer.close(); } /** * Reset the internal state of the video codec. */ public void reset() { peer.reset(); } /** * Retrives the name of this video codec: "FFMPEG video decoder" * @return Codec name */ public String getName() { return "FFMPEG video decoder"; } /** * This method returns the interfaces that can be used * to control this codec. Currently no interfaces are defined. */ public Object[] getControls() { return null; //peer.getControls(); } /** * This method returns an interface that can be used * to control this codec. Currently no interfaces are defined. */ public Object getControl( String type ) { return null; //peer.getControl( type ); } }