⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 decoder.java

📁 J2ME MPEG4 解码代码。 以及使用方法。
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
import java.io.*;

public class Decoder {
	private Queue mQueue 		    = null;
    private InputBitStream mInput   = null;
    private VideoRenderer mRenderer = null;

    private Picture[] mPictureStore = new Picture[3];
    private int mCurrent = 0, mPrevious = -1, mFuture = -1;

    private MotionVector mForward   = new MotionVector();
    private MotionVector mBackward  = new MotionVector();

    private Idct mIdct 			    = new Idct();
    private Vlc mVlc 			    = new Vlc();

    private int mPictureCodingType;

    private int mWidth;
    private int mHeight;

    private int mMacroblockWidth;	// Width in macroblock units
    private int mMacroblockHeight;	// Height in macroblock units

    private int mMacroblockRow;
    private int mMacroblockCol;

    // Default intra quantization matrix
    private static final short[] DefaultIntraQuantizerMatrix = {
        8, 16, 19, 22, 26, 27, 29, 34,
        16, 16, 22, 24, 27, 29, 34, 37,
        19, 22, 26, 27, 29, 34, 34, 38,
        22, 22, 26, 27, 29, 34, 37, 40,
        22, 26, 27, 29, 32, 35, 40, 48,
        26, 27, 29, 32, 35, 40, 48, 58,
        26, 27, 29, 34, 38, 46, 56, 69,
        27, 29, 35, 38, 46, 56, 69, 83
    };

    // Default non-intra quantization matrix
    private static final short[] DefaultNonIntraQuantizerMatrix = {
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16,
        16, 16, 16, 16, 16, 16, 16, 16
    };

    private short[] IntraQuantizerMatrix 	= new short[64];
    private short[] NonIntraQuantizerMatrix = new short[64];

    // Zig-zag scan matrix
    private static final byte[] ScanMatrix = {
        0,  1,  5,  6, 14, 15, 27, 28,
        2,  4,  7, 13, 16, 26, 29, 42,
        3,  8, 12, 17, 25, 30, 41, 43,
        9, 11, 18, 24, 31, 40, 44, 53,
       10, 19, 23, 32, 39, 45, 52, 54,
       20, 22, 33, 38, 46, 51, 55, 60,
       21, 34, 37, 47, 50, 56, 59, 61,
       35, 36, 48, 49, 57, 58, 62, 63
    };


    /*
     * Start codes are reserved bit patterns that do not otherwise 
     * occur in the video stream. All start codes are byte aligned.
     */
    private static final int START_CODE 		  = 0x000001;		// 24-bit code

    private static final int PICTURE_START_CODE   = 0x00000100;
    private static final int SLICE_START_CODE     = 0x00000101;	// through 0x000001af

    private static final int USER_DATA_START_CODE = 0x000001b2;
    private static final int SEQUENCE_HEADER_CODE = 0x000001b3;
    private static final int EXTENSION_START_CODE = 0x000001b5;
    private static final int SEQUENCE_END_CODE    = 0x000001b7;
    private static final int GROUP_START_CODE     = 0x000001b8;

    /**
     * Constructs MPEG decoder
     * 
     * @param queue  Playout queue
     * @param input  Video bitstream
     * @param player Canvas canvas
     */
    public Decoder(Queue queue, InputBitStream input, VideoRenderer renderer) {
    	mQueue    = queue;
    	mInput    = input;
        mRenderer = renderer;
    }

    /*
     * Remove any zero bit and zero byte stuffing and locates the next
     * start code. See ISO/IEC 11172-2 Section 2.3
     */
    private void nextStartCode() throws IOException {
        while (!mInput.isByteAligned())
            mInput.getBits(1);

        while (mInput.nextBits(24) != START_CODE)
            mInput.getBits(8);
    }

    public void start() throws IOException {
        nextStartCode();

        /*
         * A video sequence starts with a sequence header and is 
         * followed by one or more groups of pictures and is ended 
         * by a SEQUENCE_END_CODE. Immediately before each of the 
         * groups of pictures there may be a sequence header.
         */

         do {
             parseSequenceHeader();

             mRenderer.setSize(mWidth, mHeight);

             mPictureStore[0] = new Picture(mMacroblockWidth, mMacroblockHeight);
             mPictureStore[1] = new Picture(mMacroblockWidth, mMacroblockHeight);
             mPictureStore[2] = new Picture(mMacroblockWidth, mMacroblockHeight);

             do {
                 parseGroupOfPictures();
             } while (mInput.nextBits(32) == GROUP_START_CODE);

         } while (mInput.nextBits(32) == SEQUENCE_HEADER_CODE);

         int sequenceEndCode = mInput.getBits(32);
    }

    /*
     * All fields in each sequence header with the exception of
     * the quantization matrices shall have the same values as
     * in the first sequence header.
     */
    private void parseSequenceHeader() throws IOException {
        int sequenceHeaderCode = mInput.getBits(32);

        mWidth = mInput.getBits(12);
        mHeight = mInput.getBits(12);

        mMacroblockWidth = (mWidth + 15) >> 4;
        mMacroblockHeight = (mHeight + 15) >> 4;

        int pelAspectRatio = mInput.getBits(4);
        int pictureRate = mInput.getBits(4);

        int bitRate = mInput.getBits(18);
        int markerBit = mInput.getBits(1);	// Should be == 0x1

        int vbvBufferSize = mInput.getBits(10);

//        int minimumBufferSize = vbvBufferSize << 14;

        int constrainedParameterFlag = mInput.getBits(1);

        boolean loadIntraQuantizerMatrix = (mInput.getBits(1) == 1);
        if (loadIntraQuantizerMatrix)
            loadIntraQuantizerMatrix();
        else
            loadDefaultIntraQuantizerMatrix();

        boolean loadNonIntraQuantizerMatrix = (mInput.getBits(1) == 1);
        if (loadNonIntraQuantizerMatrix)
            loadNonIntraQuantizerMatrix();
        else
            loadDefaultNonIntraQuantizerMatrix();

        nextStartCode();

        if (mInput.nextBits(32) == EXTENSION_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int sequenceExtensionData = mInput.getBits(8);
            }

            nextStartCode();
        }

        if (mInput.nextBits(32) == USER_DATA_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int userData = mInput.getBits(8);
            }

            nextStartCode();
        }
    }

    /*
     * This is a list of sixty-four 8-bit unsigned integers.
     * The value for [0][0] shall always be 8. For the 8-bit 
     * unsigned integers, the value zero is forbidden.
     * The new values shall be in effect until the next occurrence
     * of a sequence header.
     */
    private void loadIntraQuantizerMatrix() throws IOException {
        for (int i = 0; i < 64; ++i) {
            int value = mInput.getBits(8);
            IntraQuantizerMatrix[i] = (short)(value & 0xff);
        }
    }

    private void loadDefaultIntraQuantizerMatrix() {
    	System.arraycopy(DefaultIntraQuantizerMatrix, 0, IntraQuantizerMatrix, 0, 64);
    }

    /*
     * This is a list of sixty-four 8-bit unsigned integers.
     * For the 8-bit unsigned integers, the value zero is forbidden.
     * The new values shall be in effect until the next occurrence 
     * of a sequence header.
     */
    private void loadNonIntraQuantizerMatrix() throws IOException {
        for (int i = 0; i < 64; ++i) {
            int value = mInput.getBits(8);
            NonIntraQuantizerMatrix[i] = (short)(value & 0xff);
        }
    }

    private void loadDefaultNonIntraQuantizerMatrix() {
    	System.arraycopy(DefaultNonIntraQuantizerMatrix, 0, NonIntraQuantizerMatrix, 0, 64);
    }

    /*
     * The first coded picture in a group of pictures is an I-Picture. 
     * The order of the pictures in the coded stream is the order in 
     * which the decoder processes them in normal play. In particular, 
     * adjacent B-Pictures in the coded stream are in display order. 
     * The last coded picture, in display order, of a group of pictures 
     * is either an I-Picture or a P-Picture.
     */
    private void parseGroupOfPictures() throws IOException {
        int groupStartCode = mInput.getBits(32);
        int timeCode = mInput.getBits(25);
        boolean closedGop = mInput.getBits(1) == 1;
        boolean brokenLink = mInput.getBits(1) == 1;

        nextStartCode();

        if (mInput.nextBits(32) == EXTENSION_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int groupExtensionData = mInput.getBits(8);
            }

            nextStartCode();
        }

        if (mInput.nextBits(32) == USER_DATA_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int userData = mInput.getBits(8);
            }

            nextStartCode();
        }

        // Reset picture store indexes
        if (closedGop) {
        	mPrevious = mFuture = -1;
        }

    	do {
    		parsePicture();

    		// Send picture to player
    		mQueue.put(mPictureStore[mCurrent]);
/*
            try {
            	Thread.sleep(100);
            } catch(InterruptedException ignore) {}
*/
    		// Store current picture in Previous or Future Picture Store
    		// Refer to section 2-D.2.4
           	if (mPictureCodingType == Picture.I_TYPE || mPictureCodingType == Picture.P_TYPE) {
           		if (mPrevious == -1)
           		{
           			mPrevious = mCurrent;
           		}
           		else if (mFuture == -1)
           		{
           			mFuture = mCurrent;
           		}
           		else
           		{
           			mFuture = mCurrent;
           		}

           		mCurrent = (mCurrent + 1) % 3;
            }

    	} while (mInput.nextBits(32) == PICTURE_START_CODE);
    }

    // Only present in P and B pictures
    private int mForwardF;
    private int mForwardRSize;

    private int mBackwardF;
    private int mBackwardRSize;

    private void parsePicture() throws IOException {
        int pictureStartCode = mInput.getBits(32);
        int temporalReference = mInput.getBits(10);
        mPictureCodingType = mInput.getBits(3);
        int vbvDelay = mInput.getBits(16);

        // This data is to be used later by the player
        mPictureStore[mCurrent].mTime = temporalReference;
        mPictureStore[mCurrent].mType = mPictureCodingType;

		// "Copy" picture from Future Picture Store to Previous Picture Store
		// Refer to section 2-D.2.4
        if (mPictureCodingType == Picture.I_TYPE || mPictureCodingType == Picture.P_TYPE)
        	if (mFuture != -1)
        		mPrevious = mFuture;

        if (mPictureCodingType == Picture.P_TYPE || mPictureCodingType == Picture.B_TYPE) {
            boolean fullPelForwardVector = mInput.getBits(1) == 1;
            int forwardFCode = mInput.getBits(3);  // Can't be 0
            mForwardRSize = forwardFCode - 1;
            mForwardF = 1 << mForwardRSize;

            mForward.init(mForwardF, fullPelForwardVector);
        }

        if (mPictureCodingType == Picture.B_TYPE) {
            boolean fullPelBackwardVector = mInput.getBits(1) == 1;
            int backwardFCode = mInput.getBits(3); // Can't be 0
            mBackwardRSize = backwardFCode - 1;
            mBackwardF = 1 << mBackwardRSize;

            mBackward.init(mBackwardF, fullPelBackwardVector);
        }

        int extraBitPicture = 0;
        while (mInput.nextBits(1) == 0x1) {
            extraBitPicture = mInput.getBits(1);
            int extraInformationPicture = mInput.getBits(8);
        }
        extraBitPicture = mInput.getBits(1);

        nextStartCode();

        if (mInput.nextBits(32) == EXTENSION_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int pictureExtensionData = mInput.getBits(8);
            }

            nextStartCode();
        }

        if (mInput.nextBits(32) == USER_DATA_START_CODE) {
            mInput.getBits(32);

            while (mInput.nextBits(24) != START_CODE) {
                int userData = mInput.getBits(8);
            }

            nextStartCode();
        }

        do {
            parseSlice();
        } while (mInput.nextBits(32) == SLICE_START_CODE);
    }

    // Predictors
    private int mDctDcYPast;
    private int mDctDcCbPast;
    private int mDctDcCrPast;

    private int mPastIntraAddress;
    private int mMacroblockAddress;
    private int mQuantizerScale;

    /*
     * A slice is a series of an arbitrary number of macroblocks with 
     * the order of macroblocks starting from the upper-left of the 
     * picture and proceeding by raster-scan order from left to right 
     * and top to bottom. Every slice shall contain at least one 
     * macroblock. Slices shall not overlap and there shall be no gaps 
     * between slices.
     */
    private void parseSlice() throws IOException {
        int sliceStartCode = mInput.getBits(32);   // Ranging from 0x00000101 - 0x000001af
        int sliceVerticalPosition = sliceStartCode & 0xff; // Range: 0x01 - 0xaf

        mDctDcYPast = mDctDcCbPast = mDctDcCrPast = 1024; // See ISO-11172-2 page 35

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -