?? decoder.java
字號(hào):
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
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -