You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1445 lines
40 KiB
C++
1445 lines
40 KiB
C++
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|||
|
|
|
|||
|
|
#include "M4BitstreamParser.h"
|
|||
|
|
#include "vdecmpeg4.h"
|
|||
|
|
#include "M4Decoder.h"
|
|||
|
|
#include "M4MemOps.h"
|
|||
|
|
|
|||
|
|
namespace vdecmpeg4
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
#define ROUNDED_DIV(a,b) ( ((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1)) / (b) )
|
|||
|
|
|
|||
|
|
#define VIDOBJ_START_CODE 0x00000100 // ..0x0000011f
|
|||
|
|
#define VIDOBJLAY_START_CODE 0x00000120 // ..0x0000012f
|
|||
|
|
#define VISOBJSEQ_START_CODE 0x000001b0
|
|||
|
|
#define VISOBJSEQ_STOP_CODE 0x000001b1
|
|||
|
|
#define VISOBJ_START_CODE 0x000001b5
|
|||
|
|
#define VISOBJ_TYPE_VIDEO 1
|
|||
|
|
#define VIDOBJLAY_TYPE_SIMPLE 1
|
|||
|
|
#define VIDOBJLAY_TYPE_CORE 3
|
|||
|
|
#define VIDOBJLAY_TYPE_MAIN 4
|
|||
|
|
#define VIDOBJLAY_AR_EXTPAR 15
|
|||
|
|
#define VIDOBJLAY_DIVX_UNKNOWN1 17
|
|||
|
|
#define GRPOFVOP_START_CODE 0x000001b3
|
|||
|
|
#define VOP_START_CODE 0x1b6
|
|||
|
|
#define USERDATA_START_CODE 0x000001b2
|
|||
|
|
|
|||
|
|
#define SKIP_MARKER() mBitstream->skip(1)
|
|||
|
|
|
|||
|
|
|
|||
|
|
//! Indicated video texture shape
|
|||
|
|
enum
|
|||
|
|
{
|
|||
|
|
M4_SHAPE_RECT = 0,
|
|||
|
|
M4_SHAPE_BIN,
|
|||
|
|
M4_SHAPE_BIN_ONLY,
|
|||
|
|
M4_SHAPE_GRAY
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//! Possible sprite types
|
|||
|
|
enum
|
|||
|
|
{
|
|||
|
|
M4_SPRITE_STATIC = 1,
|
|||
|
|
M4_SPRITE_GMC
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const uint32 M4BitstreamParser::mIntraDCThresholdTable[8] =
|
|||
|
|
{
|
|||
|
|
32, // value greater than M4MAX allowed quant means 'use intra DC for entire VOP'
|
|||
|
|
13, 15, 17, 19, 21, 23,
|
|||
|
|
1 // value lower than M4MIN allowed quant means 'use intra AC for entire VOP'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
uint8 M4BitstreamParser::mScanTableInput[3][64] =
|
|||
|
|
{
|
|||
|
|
{ // zig zag
|
|||
|
|
0, 1, 8, 16, 9, 2, 3, 10,
|
|||
|
|
17, 24, 32, 25, 18, 11, 4, 5,
|
|||
|
|
12, 19, 26, 33, 40, 48, 41, 34,
|
|||
|
|
27, 20, 13, 6, 7, 14, 21, 28,
|
|||
|
|
35, 42, 49, 56, 57, 50, 43, 36,
|
|||
|
|
29, 22, 15, 23, 30, 37, 44, 51,
|
|||
|
|
58, 59, 52, 45, 38, 31, 39, 46,
|
|||
|
|
53, 60, 61, 54, 47, 55, 62, 63
|
|||
|
|
},
|
|||
|
|
{ // horizontal
|
|||
|
|
0, 1, 2, 3, 8, 9, 16, 17,
|
|||
|
|
10, 11, 4, 5, 6, 7, 15, 14,
|
|||
|
|
13, 12, 19, 18, 24, 25, 32, 33,
|
|||
|
|
26, 27, 20, 21, 22, 23, 28, 29,
|
|||
|
|
30, 31, 34, 35, 40, 41, 48, 49,
|
|||
|
|
42, 43, 36, 37, 38, 39, 44, 45,
|
|||
|
|
46, 47, 50, 51, 56, 57, 58, 59,
|
|||
|
|
52, 53, 54, 55, 60, 61, 62, 63
|
|||
|
|
},
|
|||
|
|
{ // vertical
|
|||
|
|
0, 8, 16, 24, 1, 9, 2, 10,
|
|||
|
|
17, 25, 32, 40, 48, 56, 57, 49,
|
|||
|
|
41, 33, 26, 18, 3, 11, 4, 12,
|
|||
|
|
19, 27, 34, 42, 50, 58, 35, 43,
|
|||
|
|
51, 59, 20, 28, 5, 13, 6, 14,
|
|||
|
|
21, 29, 36, 44, 52, 60, 37, 45,
|
|||
|
|
53, 61, 22, 30, 7, 15, 23, 31,
|
|||
|
|
38, 46, 54, 62, 39, 47, 55, 63
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//! Default MPEG4 dequant coefficients for INTRA blocks
|
|||
|
|
const uint8 M4BitstreamParser::mDefaultIntraMatrix[64] =
|
|||
|
|
{
|
|||
|
|
8,17,18,19,21,23,25,27,
|
|||
|
|
17,18,19,21,23,25,27,28,
|
|||
|
|
20,21,22,23,24,26,28,30,
|
|||
|
|
21,22,23,24,26,28,30,32,
|
|||
|
|
22,23,24,26,28,30,32,35,
|
|||
|
|
23,24,26,28,30,32,35,38,
|
|||
|
|
25,26,28,30,32,35,38,41,
|
|||
|
|
27,28,30,32,35,38,41,45
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//! Default MPEG4 dequant coefficients for INTER blocks
|
|||
|
|
const uint8 M4BitstreamParser::mDefaultInterMatrix[64] =
|
|||
|
|
{
|
|||
|
|
16,17,18,19,20,21,22,23,
|
|||
|
|
17,18,19,20,21,22,23,24,
|
|||
|
|
18,19,20,21,22,23,24,25,
|
|||
|
|
19,20,21,22,23,24,26,27,
|
|||
|
|
20,21,22,23,25,26,27,28,
|
|||
|
|
21,22,23,24,26,27,28,30,
|
|||
|
|
22,23,24,26,27,28,30,31,
|
|||
|
|
23,24,25,27,28,30,31,33
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static const char* M4PictureTypeNames[] =
|
|||
|
|
{
|
|||
|
|
"I_VOP",
|
|||
|
|
"P_VOP",
|
|||
|
|
"B_VOP",
|
|||
|
|
"S_VOP",
|
|||
|
|
"N_VOP",
|
|||
|
|
"SKIP_VOP",
|
|||
|
|
"ERROR"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
M4BitstreamParser::M4BitstreamParser()
|
|||
|
|
{
|
|||
|
|
FMemory::Memzero(&mHeaderInfo, sizeof(mHeaderInfo));
|
|||
|
|
mBitstream = nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
M4BitstreamParser::~M4BitstreamParser()
|
|||
|
|
{
|
|||
|
|
mDecoder->mMemSys.free(mHeaderInfo.mInvQuantIntra);
|
|||
|
|
mDecoder->mMemSys.free(mHeaderInfo.mInvQuantInter);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Generic parser init
|
|||
|
|
*
|
|||
|
|
* @param decoder
|
|||
|
|
* @param bitstream
|
|||
|
|
*
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
VIDError M4BitstreamParser::init(M4Decoder* decoder, M4Bitstream* bitstream)
|
|||
|
|
{
|
|||
|
|
VIDError error = VID_ERROR_OUT_OF_MEMORY;
|
|||
|
|
|
|||
|
|
mDecoder = decoder;
|
|||
|
|
mBitstream = bitstream;
|
|||
|
|
|
|||
|
|
mScanTable[0] = mScanTableInput[0];
|
|||
|
|
mScanTable[1] = mScanTableInput[1];
|
|||
|
|
mScanTable[2] = mScanTableInput[2];
|
|||
|
|
|
|||
|
|
if ((mHeaderInfo.mInvQuantIntra = (uint8*)mDecoder->mMemSys.malloc(sizeof(uint8) * 64)) != nullptr)
|
|||
|
|
{
|
|||
|
|
if ((mHeaderInfo.mInvQuantInter = (uint8*)mDecoder->mMemSys.malloc(sizeof(uint8) * 64)) != nullptr)
|
|||
|
|
{
|
|||
|
|
mVLCDecoder.init();
|
|||
|
|
reset();
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
mDecoder->mMemSys.free(mHeaderInfo.mInvQuantIntra);
|
|||
|
|
mDecoder->mMemSys.free(mHeaderInfo.mInvQuantInter);
|
|||
|
|
FMemory::Memzero(&mHeaderInfo, sizeof(mHeaderInfo));
|
|||
|
|
return error;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Attach parser to new stream
|
|||
|
|
*
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
VIDError M4BitstreamParser::reset()
|
|||
|
|
{
|
|||
|
|
mTicksPerSecond = mVopTime = 0.0;
|
|||
|
|
mLastTimeBase = mTimeBase = 0;
|
|||
|
|
mLastNonBTime = mTime = 0;
|
|||
|
|
mTimePP = mTimeBP = 0;
|
|||
|
|
|
|||
|
|
mVOLfound = false;
|
|||
|
|
mVOLCounter = 0;
|
|||
|
|
|
|||
|
|
FMemory::Memzero(&mVOLInfo, sizeof(mVOLInfo));
|
|||
|
|
|
|||
|
|
mLowDelay = 0;
|
|||
|
|
mShape = 0;
|
|||
|
|
mVopTimeIncrementBits = 0;
|
|||
|
|
mVopTimeIncrementResolution = 0;
|
|||
|
|
mbVopTimeFixedRate = false;
|
|||
|
|
mVopTimeFixedIncrement = 0;
|
|||
|
|
|
|||
|
|
mResyncMacroblockNumber = 0;
|
|||
|
|
|
|||
|
|
mTicksPerSecond = 0.0;
|
|||
|
|
mSpriteUsage = 0;
|
|||
|
|
mQuantBits = 5;
|
|||
|
|
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantIntra, mDefaultIntraMatrix);
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantInter, mDefaultInterMatrix);
|
|||
|
|
|
|||
|
|
mQuarterpel = 0;
|
|||
|
|
mScalability = 0;
|
|||
|
|
mNewPredEnable = 0;
|
|||
|
|
|
|||
|
|
mRefVop[0].x = 0;
|
|||
|
|
mRefVop[0].y = 0;
|
|||
|
|
|
|||
|
|
mRefVop[1].x = 0;
|
|||
|
|
mRefVop[1].y = 0;
|
|||
|
|
|
|||
|
|
mRefVop[2].x = 0;
|
|||
|
|
mRefVop[2].y = 0;
|
|||
|
|
|
|||
|
|
mRefVop[3].x = 0;
|
|||
|
|
mRefVop[3].y = 0;
|
|||
|
|
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Update parse init if frame size is known
|
|||
|
|
*
|
|||
|
|
* @param width
|
|||
|
|
* @param height
|
|||
|
|
*/
|
|||
|
|
void M4BitstreamParser::initFrame(int16 width, int16 height)
|
|||
|
|
{
|
|||
|
|
M4CHECK(mVOLInfo.mWidth == width);
|
|||
|
|
M4CHECK(mVOLInfo.mHeight == height);
|
|||
|
|
(void)width; (void)height;
|
|||
|
|
|
|||
|
|
mRefVop[0].x = mRefVop[0].y = 0;
|
|||
|
|
|
|||
|
|
mRefVop[1].x = mVOLInfo.mWidth;
|
|||
|
|
mRefVop[1].y = 0;
|
|||
|
|
|
|||
|
|
mRefVop[2].x = 0;
|
|||
|
|
mRefVop[2].y = mVOLInfo.mHeight;
|
|||
|
|
|
|||
|
|
mRefVop[3].x = mVOLInfo.mWidth;
|
|||
|
|
mRefVop[3].y = mVOLInfo.mHeight;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* getTrajaPoint
|
|||
|
|
*
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
int32 M4BitstreamParser::getTrajaPoint()
|
|||
|
|
{
|
|||
|
|
int32 code = (int32) mBitstream->show(12);
|
|||
|
|
if (code <= 1023)
|
|||
|
|
{
|
|||
|
|
// 00
|
|||
|
|
mBitstream->skip(2);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
else if (code <= 1535)
|
|||
|
|
{
|
|||
|
|
// 010
|
|||
|
|
mBitstream->skip(3);
|
|||
|
|
code = (int32) mBitstream->getBit();
|
|||
|
|
if (code < 1)
|
|||
|
|
{
|
|||
|
|
code -= 1;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 2047)
|
|||
|
|
{
|
|||
|
|
// 011
|
|||
|
|
mBitstream->skip(3);
|
|||
|
|
code = (int32) mBitstream->getBits(2);
|
|||
|
|
if (code < 2)
|
|||
|
|
{
|
|||
|
|
code -= 3;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 2559)
|
|||
|
|
{
|
|||
|
|
// 100
|
|||
|
|
mBitstream->skip(3);
|
|||
|
|
code = (int32) mBitstream->getBits(3);
|
|||
|
|
if (code < 4)
|
|||
|
|
{
|
|||
|
|
code -= 7;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 3071)
|
|||
|
|
{
|
|||
|
|
// 101
|
|||
|
|
mBitstream->skip(3);
|
|||
|
|
code = (int32) mBitstream->getBits(4);
|
|||
|
|
if (code < 8)
|
|||
|
|
{
|
|||
|
|
code -= 15;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 3583)
|
|||
|
|
{
|
|||
|
|
// 110
|
|||
|
|
mBitstream->skip(3);
|
|||
|
|
code = (int32) mBitstream->getBits(5);
|
|||
|
|
if (code < 16)
|
|||
|
|
{
|
|||
|
|
code -= 31;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 3839)
|
|||
|
|
{
|
|||
|
|
// 1110
|
|||
|
|
mBitstream->skip(4);
|
|||
|
|
code = (int32) mBitstream->getBits(6);
|
|||
|
|
if (code < 32)
|
|||
|
|
{
|
|||
|
|
code -= 63;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 3967)
|
|||
|
|
{
|
|||
|
|
// 11110
|
|||
|
|
mBitstream->skip(5);
|
|||
|
|
code = (int32) mBitstream->getBits(7);
|
|||
|
|
if (code < 64)
|
|||
|
|
{
|
|||
|
|
code -= 127;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4031)
|
|||
|
|
{
|
|||
|
|
// 111110
|
|||
|
|
mBitstream->skip(6);
|
|||
|
|
code = (int32) mBitstream->getBits(8);
|
|||
|
|
if (code < 128)
|
|||
|
|
{
|
|||
|
|
code -= 255;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4063)
|
|||
|
|
{
|
|||
|
|
// 1111110
|
|||
|
|
mBitstream->skip(7);
|
|||
|
|
code = (int32) mBitstream->getBits(9);
|
|||
|
|
if (code < 256)
|
|||
|
|
{
|
|||
|
|
code -= 511;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4079)
|
|||
|
|
{
|
|||
|
|
// 11111110
|
|||
|
|
mBitstream->skip(8);
|
|||
|
|
code = (int32) mBitstream->getBits(10);
|
|||
|
|
if (code < 512)
|
|||
|
|
{
|
|||
|
|
code -= 1023;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4087)
|
|||
|
|
{
|
|||
|
|
// 111111110
|
|||
|
|
mBitstream->skip(9);
|
|||
|
|
code = (int32) mBitstream->getBits(11);
|
|||
|
|
if (code < 1024)
|
|||
|
|
{
|
|||
|
|
code -= 2047;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4091)
|
|||
|
|
{
|
|||
|
|
// 1111111110
|
|||
|
|
mBitstream->skip(10);
|
|||
|
|
code = (int32) mBitstream->getBits(12);
|
|||
|
|
if (code < 2048)
|
|||
|
|
{
|
|||
|
|
code -= 4095;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code <= 4093)
|
|||
|
|
{
|
|||
|
|
// 11111111110
|
|||
|
|
mBitstream->skip(11);
|
|||
|
|
code = (int32) mBitstream->getBits(13);
|
|||
|
|
if (code < 4096)
|
|||
|
|
{
|
|||
|
|
code -= 8191;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
else if (code == 4094)
|
|||
|
|
{
|
|||
|
|
// 111111111110
|
|||
|
|
mBitstream->skip(12);
|
|||
|
|
code = (int32) mBitstream->getBits(14);
|
|||
|
|
if (code < 8192)
|
|||
|
|
{
|
|||
|
|
code -= 16383;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Parse MPEG4 Elementray Stream
|
|||
|
|
*
|
|||
|
|
* @param pictureType
|
|||
|
|
*
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
VIDError M4BitstreamParser::parseMPEG4ES(M4PictureType& pictureType)
|
|||
|
|
{
|
|||
|
|
M4CHECK(mBitstream);
|
|||
|
|
|
|||
|
|
uint32 startCode;
|
|||
|
|
uint32 vol_ver_id = 1;
|
|||
|
|
|
|||
|
|
do
|
|||
|
|
{
|
|||
|
|
mBitstream->align();
|
|||
|
|
startCode = mBitstream->show(32);
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* Visual Object Sequence - see MPEG4-P2, 6.2.2
|
|||
|
|
*****************************************************************************/
|
|||
|
|
if (startCode == VISOBJSEQ_START_CODE)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(32); // visual_object_sequence_start_code
|
|||
|
|
mVOLInfo.mProfileLevel = (uint8)mBitstream->getBits(8); // profile_and_level_indication
|
|||
|
|
}
|
|||
|
|
else if (startCode == VISOBJSEQ_STOP_CODE)
|
|||
|
|
{
|
|||
|
|
//check
|
|||
|
|
mBitstream->skip(32); // visual_object_sequence_stop_code
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* VisualObject() - see MPEG4-P2, 6.2.2
|
|||
|
|
*****************************************************************************/
|
|||
|
|
else if (startCode == VISOBJ_START_CODE)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(32); // visual_object_start_code
|
|||
|
|
|
|||
|
|
if (mBitstream->getBit()) // is_visual_object_identified
|
|||
|
|
{
|
|||
|
|
vol_ver_id = mBitstream->getBits(4); // visual_object_ver_id
|
|||
|
|
mBitstream->skip(3); // visual_object_priority
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
vol_ver_id = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mBitstream->show(4) != VISOBJ_TYPE_VIDEO) // visual_object_type
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: visual_object_type is not video! (See ISO/IEC 14496-2:2001-6.3.2)\n");
|
|||
|
|
return VID_ERROR_NOT_VIDEO_STREAM;
|
|||
|
|
}
|
|||
|
|
mBitstream->skip(4);
|
|||
|
|
|
|||
|
|
// video_signal_type()
|
|||
|
|
if (mBitstream->getBit()) // video_signal_type
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(3); // video_format (0=component,1=pal,2=ntsc,3=secam,4=MAC,5=unspecified)
|
|||
|
|
mBitstream->skip(1); // video_range
|
|||
|
|
if (mBitstream->getBit()) // color_description
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(8); // color_primaries
|
|||
|
|
mBitstream->skip(8); // transfer_characteristics
|
|||
|
|
mBitstream->skip(8); // matrix_coefficients
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
mBitstream->nextStartCode();
|
|||
|
|
}
|
|||
|
|
else if ((startCode & ~0x1fU) == VIDOBJ_START_CODE)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(32); // video_object_start_code
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* VideoObjectLayer() - see MPEG4-P2, 6.2.3
|
|||
|
|
*****************************************************************************/
|
|||
|
|
else if ((startCode & ~0xfU) == VIDOBJLAY_START_CODE)
|
|||
|
|
{
|
|||
|
|
mVOLCounter++;
|
|||
|
|
mVOLfound = true;
|
|||
|
|
|
|||
|
|
mBitstream->skip(32); // video_object_layer_start_code
|
|||
|
|
mBitstream->skip(1); // random_accessible_vol
|
|||
|
|
|
|||
|
|
// video_object_type_indication
|
|||
|
|
uint32 voType = mBitstream->getBits(8);
|
|||
|
|
|
|||
|
|
switch(voType)
|
|||
|
|
{
|
|||
|
|
case 0:
|
|||
|
|
case VIDOBJLAY_TYPE_SIMPLE:
|
|||
|
|
case VIDOBJLAY_TYPE_CORE:
|
|||
|
|
case VIDOBJLAY_TYPE_MAIN:
|
|||
|
|
case VIDOBJLAY_DIVX_UNKNOWN1:
|
|||
|
|
{
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
default:
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: found unknown video_object_type_indication %d. (See ISO/IEC 14496-2:2001-6.3.3)\n", voType);
|
|||
|
|
return VID_ERROR_BAD_VIDEO_OBJECT;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mBitstream->getBit()) // is_object_layer_identifier
|
|||
|
|
{
|
|||
|
|
vol_ver_id = mBitstream->getBits(4); // video_object_layer_verid
|
|||
|
|
mBitstream->skip(3); // video_object_layer_priority
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
vol_ver_id = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mVOLInfo.mAspectRatio = (uint8)mBitstream->getBits(4); // aspect_ratio_info
|
|||
|
|
|
|||
|
|
if (mVOLInfo.mAspectRatio == VIDOBJLAY_AR_EXTPAR)
|
|||
|
|
{
|
|||
|
|
mVOLInfo.mAspectRatioPARwidth = (uint8)mBitstream->getBits(8); // par_width
|
|||
|
|
mVOLInfo.mAspectRatioPARheight= (uint8)mBitstream->getBits(8); // par_height
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mBitstream->getBit()) // vol_control_parameters
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(2); // chroma_format
|
|||
|
|
|
|||
|
|
// if low_delay is '1' the VOL contains no B-VOPs!!
|
|||
|
|
mLowDelay = (uint16)mBitstream->getBit(); // low_delay
|
|||
|
|
|
|||
|
|
if (mBitstream->getBit()) // vbv_parameters
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(15); // first_half_bitrate
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(15); // latter_half_bitrate
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(15); // first_half_vbv_buffer_size
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(3); // latter_half_vbv_buffer_size
|
|||
|
|
mBitstream->skip(11); // first_half_vbv_occupancy
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(15); // latter_half_vbv_occupancy
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mShape = mBitstream->getBits(2); // video_object_layer_shape
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: video_object_layer_shape != \"rectangular\". (See ISO/IEC 14496-2:2001, page 112).\n");
|
|||
|
|
return VID_ERROR_STREAM_VOL_INVALID_SHAPE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape == M4_SHAPE_GRAY && vol_ver_id != 1)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(4); // video_object_layer_shape_extension
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
// This is a 16-bit unsigned integer that indicates the number of evenly spaced
|
|||
|
|
// subintervals, called TICKS, within one modulo time. One modulo time represents
|
|||
|
|
// the fixed interval of one second.
|
|||
|
|
// In other words, one second is devided into mVopTimeIncRes TICKS
|
|||
|
|
mVopTimeIncrementResolution = (uint16)mBitstream->getBits(16); // vop_time_increment_resolution
|
|||
|
|
mVopTimeIncrementBits = (uint16) log2bin(mVopTimeIncrementResolution - 1);
|
|||
|
|
if (mVopTimeIncrementBits < 1)
|
|||
|
|
{
|
|||
|
|
mVopTimeIncrementBits = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check standard
|
|||
|
|
mTicksPerSecond = 1.0 / mVopTimeIncrementResolution;
|
|||
|
|
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
mbVopTimeFixedRate = mBitstream->getBit() != 0;
|
|||
|
|
if (mbVopTimeFixedRate) // fixed_vop_rate
|
|||
|
|
{
|
|||
|
|
mVopTimeFixedIncrement = mBitstream->getBits(mVopTimeIncrementBits); // fixed_vop_time_increment
|
|||
|
|
|
|||
|
|
mVOLInfo.mFPSNumerator = mVopTimeIncrementResolution;
|
|||
|
|
mVOLInfo.mFPSDenominator = (uint16) mVopTimeFixedIncrement;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_BIN_ONLY)
|
|||
|
|
{
|
|||
|
|
if (mShape == M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
int16 width, height;
|
|||
|
|
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
width = (int16) mBitstream->getBits(13); // video_object_layer_width
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
height = (int16) mBitstream->getBits(13); // video_object_layer_height
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
if ((width&0xf) != 0)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: width %d not multiple of 16 pixel!\n", width);
|
|||
|
|
//return VID_ERROR_WIDTH_OR_HEIGHT_NOT_MULTIPLE_OF_16;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((height&0xf) != 0)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: height %d not multiple of 16 pixel!\n", height);
|
|||
|
|
//return VID_ERROR_WIDTH_OR_HEIGHT_NOT_MULTIPLE_OF_16;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mVOLInfo.mCodedWidth = width;
|
|||
|
|
mVOLInfo.mCodedHeight = height;
|
|||
|
|
|
|||
|
|
mVOLInfo.mHeight = (height + 15) & ~15;
|
|||
|
|
mVOLInfo.mWidth = (width + 15) & ~ 15;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// check if interlace mode and check that interlace mode is'active' for all frames in this movie
|
|||
|
|
bool interlace = mBitstream->getBit() ? true : false; // check interlace flag
|
|||
|
|
if (interlace)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: interlaced == 1 not supported!\n");
|
|||
|
|
return VID_ERROR_INTERLACED_NOT_SUPPORTED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
if (!mBitstream->getBit()) // obmc_disable
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: obmc_disable == 0 ignored. (See ISO/IEC 14496-2:2001, page 113).\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mSpriteUsage = mBitstream->getBits((vol_ver_id == 1 ? 1 : 2)); // sprite_enable
|
|||
|
|
|
|||
|
|
if (mSpriteUsage == M4_SPRITE_STATIC || mSpriteUsage == M4_SPRITE_GMC)
|
|||
|
|
{
|
|||
|
|
if (mSpriteUsage != M4_SPRITE_GMC)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: sprite_enable != \"GMC\". (See ISO/IEC 14496-2:2001, page 113).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mSpriteUsage != M4_SPRITE_GMC)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mSpriteWarpingPoints = (uint16)mBitstream->getBits(6);
|
|||
|
|
if (mSpriteWarpingPoints > 3)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: no_of_sprite_warping_points > 3 not valid for GMC sprites! (See ISO/IEC 14496-2:2001, page 114).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mSpriteWarpingAccuracy = (int16)mBitstream->getBits(2);
|
|||
|
|
|
|||
|
|
uint32 spriteBrightnessChange = mBitstream->getBits(1);
|
|||
|
|
if (spriteBrightnessChange)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: sprite_brightness_change != 0 not supported! (See ISO/IEC 14496-2:2001, page 114).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mSpriteUsage != M4_SPRITE_GMC)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(1); // low_latency_sprite
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (vol_ver_id != 1 && mShape != M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(1); // sadct_disable
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mBitstream->getBit()) // not_8_bit
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: IGNORED: not_8_bit == 1!\n");
|
|||
|
|
mQuantBits = mBitstream->getBits(4); // quant_precision
|
|||
|
|
mBitstream->skip(4); // bits_per_pixel
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
mQuantBits = 5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape == M4_SHAPE_GRAY)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(1); // no_gray_quant_update
|
|||
|
|
mBitstream->skip(1); // composition_method
|
|||
|
|
mBitstream->skip(1); // linear_composition
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mHeaderInfo.mFlags.mQuantType = (uint16)mBitstream->getBit(); // quant_type
|
|||
|
|
|
|||
|
|
// if quant_type == 1, we have mpeg4 quant and the possibility of 'different' dequant matrices
|
|||
|
|
if (mHeaderInfo.mFlags.mQuantType)
|
|||
|
|
{
|
|||
|
|
mLoadIntraQuant = mBitstream->getBit()?true:false; // load_intra_quant_mat
|
|||
|
|
if (mLoadIntraQuant)
|
|||
|
|
{
|
|||
|
|
uint8 matrix[64];
|
|||
|
|
getMatrix(matrix);
|
|||
|
|
// install INTRA matrix in quantizer
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantIntra, matrix);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantIntra, mDefaultIntraMatrix);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mLoadInterQuant = mBitstream->getBit()?true:false; // load_inter_quant_mat
|
|||
|
|
if (mLoadInterQuant)
|
|||
|
|
{
|
|||
|
|
uint8 matrix[64];
|
|||
|
|
getMatrix(matrix);
|
|||
|
|
// install INTER matrix in quantizer
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantInter, matrix);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
setMatrix(mHeaderInfo.mInvQuantInter, mDefaultInterMatrix);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (vol_ver_id != 1)
|
|||
|
|
{
|
|||
|
|
// motion compensation either works using 1/2 pel resolution or - if
|
|||
|
|
// mQuarterpel is set - using 1/4 pel rez.
|
|||
|
|
mQuarterpel = mBitstream->getBit(); // quarter_sample
|
|||
|
|
if (mQuarterpel)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: quarter sample mode not supported! (See ISO/IEC 14496-2:2001, page 116).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
mQuarterpel = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// complexity_estimation_disable
|
|||
|
|
if (!mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: complexity_estimation_disable == 0 not supported. (See ISO/IEC 14496-2:2001, page 117).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// resync_marker_disable
|
|||
|
|
if (!mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
//mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: resync_marker_disable == 0 not supported. (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
//return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// data_partitioned
|
|||
|
|
uint32 partitioned = mBitstream->getBit();
|
|||
|
|
if (partitioned)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: data_partitioned == 1 not supported. (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (vol_ver_id != 1)
|
|||
|
|
{
|
|||
|
|
mNewPredEnable = mBitstream->getBit();
|
|||
|
|
if (mNewPredEnable) // newpred_enable
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(2); // requested_upstream_message_type
|
|||
|
|
mBitstream->skip(1); // newpred_segment_type
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: newpred_enable == 1 not supported. (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// reduced_resolution_vop_enable
|
|||
|
|
if (mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: reduced_resolution_vop_enable == 1 not supported! (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mScalability = mBitstream->getBit(); // scalability
|
|||
|
|
if (mScalability)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: scalability == 1 not supported! (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else // mShape == M4_SHAPE_BIN_ONLY
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: video_object_layer_shape == \"binary only\" not supported!\n");
|
|||
|
|
return VID_ERROR_STREAM_VOL_INVALID_SHAPE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mBitstream->nextStartCode();
|
|||
|
|
|
|||
|
|
// flag as VOL: Decoder needs to check if video stuff needs to be reinitialized
|
|||
|
|
pictureType = M4PIC_VOL;
|
|||
|
|
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* Group of Video Object Plane - see MPEG4-P2, 6.2.4
|
|||
|
|
*****************************************************************************/
|
|||
|
|
else if (startCode == GRPOFVOP_START_CODE)
|
|||
|
|
{
|
|||
|
|
// Group_of_VideoObjectPlane()
|
|||
|
|
mBitstream->skip(32);
|
|||
|
|
|
|||
|
|
// time_code: 18bits
|
|||
|
|
uint32 hours = mBitstream->getBits(5);
|
|||
|
|
uint32 minutes = mBitstream->getBits(6);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
uint32 seconds = mBitstream->getBits(6);
|
|||
|
|
|
|||
|
|
mTimeBase = seconds + 60*(minutes + 60*hours);
|
|||
|
|
|
|||
|
|
mBitstream->skip(1); // closed_gov
|
|||
|
|
mBitstream->skip(1); // broken_link
|
|||
|
|
|
|||
|
|
mBitstream->nextStartCode();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* Video Object Plane- see MPEG4-P2, 6.2.5
|
|||
|
|
*****************************************************************************/
|
|||
|
|
else if (startCode == VOP_START_CODE)
|
|||
|
|
{
|
|||
|
|
mBitstream->totalBitsClear(); // reset statistics
|
|||
|
|
|
|||
|
|
mBitstream->skip(32); // vop_start_code
|
|||
|
|
pictureType = (M4PictureType)mBitstream->getBits(2);
|
|||
|
|
|
|||
|
|
// we must skip all VOPs until we have found a VOL...
|
|||
|
|
if (mVOLCounter == 0)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: found %s without preceeding VOL header.\n", M4PictureTypeNames[pictureType]);
|
|||
|
|
return VID_ERROR_STREAM_VOP_WITHOUT_VOL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// before we receive the 'Video Object Plane' we must parse a VideoObjectLayer
|
|||
|
|
if (pictureType == M4PIC_B_VOP && mLowDelay)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: low_delay == 1 and vop_coding_type == \"B\" is invalid! (See ISO/IEC 14496-2:2001, page 111)\n");
|
|||
|
|
return VID_ERROR_STREAM_ERROR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint32 moduloTimeBase = 0;
|
|||
|
|
while(mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
++moduloTimeBase;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
uint32 timeIncrement = mVopTimeIncrementBits > 0 ? mBitstream->getBits(mVopTimeIncrementBits) : 0; // vop_time_increment
|
|||
|
|
if (pictureType != M4PIC_B_VOP)
|
|||
|
|
{
|
|||
|
|
mLastTimeBase = mTimeBase;
|
|||
|
|
mTimeBase += moduloTimeBase;
|
|||
|
|
mTime = mTimeBase * mVopTimeIncrementResolution + timeIncrement;
|
|||
|
|
|
|||
|
|
if (mTime < mLastNonBTime)
|
|||
|
|
{
|
|||
|
|
// !!!BROKEN ENCODER HACK!!!
|
|||
|
|
mTimeBase++;
|
|||
|
|
mTime += mVopTimeIncrementResolution;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mTimePP = mTime - mLastNonBTime;
|
|||
|
|
mLastNonBTime = mTime;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
mTime = (mLastTimeBase + moduloTimeBase) * mVopTimeIncrementResolution + timeIncrement;
|
|||
|
|
mTimeBP = mTimePP - (mLastNonBTime - mTime);
|
|||
|
|
if (mTimePP <= mTimeBP || mTimePP <= mTimePP - mTimeBP || mTimePP <=0)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: frame skipped (seeking?)\n");
|
|||
|
|
return VID_ERROR_STREAM_VOP_NOT_CODED;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mVopTime = mTime * mTicksPerSecond;
|
|||
|
|
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
if (!mBitstream->getBit()) // vop_coded
|
|||
|
|
{
|
|||
|
|
mBitstream->nextStartCode();
|
|||
|
|
// ISO/IEC 14496-2:2001:
|
|||
|
|
// The luminance and chrominance planes of the reconstructed VOP shall be filled with the forward
|
|||
|
|
// reference VOP as defined in subclause 7.6.7.
|
|||
|
|
return VID_ERROR_STREAM_VOP_NOT_CODED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// newpred_enable
|
|||
|
|
// we have already errored out if this is set, so we do not need to handle it here.
|
|||
|
|
|
|||
|
|
// rounding_type
|
|||
|
|
mHeaderInfo.mFlags.mRounding = mShape != M4_SHAPE_BIN_ONLY
|
|||
|
|
&& ((pictureType == M4PIC_P_VOP)
|
|||
|
|
|| (pictureType == M4PIC_S_VOP && mSpriteUsage == M4_SPRITE_GMC)) ? mBitstream->getBit() : 0;
|
|||
|
|
|
|||
|
|
// reduced_resolution_vop_enable
|
|||
|
|
// we have already errored out if this is set, so we do not need to handle it here.
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
if (mSpriteUsage != M4_SPRITE_STATIC || pictureType != M4PIC_I_VOP)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
mBitstream->skip(13);
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// We have already errored out if scalability is set, so we do not need to handle it here.
|
|||
|
|
/*
|
|||
|
|
if (mShape != M4_SHAPE_BIN_ONLY && mScalability && enhancement_type)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(1); // background_composition
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
mBitstream->skip(1); // change_conv_ratio_disable
|
|||
|
|
if (mBitstream->getBit()) // vop_constant_alpha
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(8); // vop_constant_alpha_value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_BIN_ONLY)
|
|||
|
|
{
|
|||
|
|
// We already errored out if complexity_estimation_disable is set, so we do not need to implement read_vop_complexity_estimation_header()
|
|||
|
|
// ...
|
|||
|
|
|
|||
|
|
// Get a 3-bit code which allows to switch between two VLC’s for coding of Intra DC coefficients
|
|||
|
|
mIntraDCThreshold = mIntraDCThresholdTable[ mBitstream->getBits(3) ]; // intra_dc_vlc_thr
|
|||
|
|
|
|||
|
|
// Since interlaced is not supported we do not need to read/skip over
|
|||
|
|
// 'top_field_first' and 'alternate_vertical_scan_flag'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (pictureType == M4PIC_S_VOP && (mSpriteUsage == M4_SPRITE_STATIC || mSpriteUsage == M4_SPRITE_GMC))
|
|||
|
|
{
|
|||
|
|
if (mSpriteUsage == M4_SPRITE_STATIC)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: static sprite in SVOP not supported\n");
|
|||
|
|
return VID_ERROR_STREAM_ERROR;
|
|||
|
|
}
|
|||
|
|
FMemory::Memzero(mSprite, sizeof(mSprite));
|
|||
|
|
|
|||
|
|
for(uint32 i = 0; i < mSpriteWarpingPoints; i++)
|
|||
|
|
{
|
|||
|
|
int32 x, y;
|
|||
|
|
|
|||
|
|
x = getTrajaPoint();
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
y = getTrajaPoint();
|
|||
|
|
SKIP_MARKER();
|
|||
|
|
|
|||
|
|
M4CHECK(x > -16383 && x < 16383);
|
|||
|
|
M4CHECK(y > -16383 && y < 16383);
|
|||
|
|
|
|||
|
|
mSprite[i].x = (int16)x;
|
|||
|
|
mSprite[i].y = (int16)y;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
decodeGMCSprite();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_BIN_ONLY)
|
|||
|
|
{
|
|||
|
|
mHeaderInfo.mQuant = (uint16)mBitstream->getBits(mQuantBits); // vop_quant
|
|||
|
|
if (mHeaderInfo.mQuant < 1 || mHeaderInfo.mQuant > 31)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: vop_quant value invalid! (See ISO/IEC 14496-2:2001, page 123).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mShape == M4_SHAPE_GRAY)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: gray shape not supported.\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
/* Otherwise:
|
|||
|
|
for(i=0; i<aux_comp_count; i++)
|
|||
|
|
vop_alpha_quant[i]
|
|||
|
|
*/
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (pictureType != M4PIC_I_VOP)
|
|||
|
|
{
|
|||
|
|
mFcodeForward = (uint16)mBitstream->getBits(3); // fcode_forward
|
|||
|
|
if (mFcodeForward < 1 || mFcodeForward > 7)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: vop_fcode_forward value invalid! (See ISO/IEC 14496-2:2001, page 123).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (pictureType == M4PIC_B_VOP)
|
|||
|
|
{
|
|||
|
|
mFcodeBackward = (uint16)mBitstream->getBits(3); // fcode_backward
|
|||
|
|
if (mFcodeBackward < 1 || mFcodeBackward > 7)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: vop_fcode_backward value invalid! (See ISO/IEC 14496-2:2001, page 123).\n");
|
|||
|
|
return VID_ERROR_GENERIC;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!mScalability)
|
|||
|
|
{
|
|||
|
|
if ((mShape != M4_SHAPE_RECT) && (pictureType != M4PIC_I_VOP))
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(1); // vop_shape_coding_type
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// this case cannot happen!!
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: scalability == 1 not supported! (See ISO/IEC 14496-2:2001, page 118).\n");
|
|||
|
|
return VID_ERROR_STREAM_VOP_INVALID_SCALABILITY;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else // mShape == M4_SHAPE_BIN_ONLY
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::parseMPEG4ES: video_object_layer_shape == \"binary only\" not supported!\n");
|
|||
|
|
return VID_ERROR_STREAM_VOL_INVALID_SHAPE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/******************************************************************************
|
|||
|
|
* User data - see MPEG4-P2, 6.2.2.1
|
|||
|
|
*****************************************************************************/
|
|||
|
|
else if (startCode == USERDATA_START_CODE)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(32); // user_data_start_code
|
|||
|
|
while(!mBitstream->isEof() && mBitstream->show(24) != 0x000001)
|
|||
|
|
{
|
|||
|
|
mBitstream->skip(8);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else // start_code == ?
|
|||
|
|
{
|
|||
|
|
//check
|
|||
|
|
if (mBitstream->show(24) == 0x000001)
|
|||
|
|
{
|
|||
|
|
// Need to check if this causes too much console spam if the stream is corrupted somehow.
|
|||
|
|
mDecoder->VIDPrintf("*** M4BitstreamParser::parseMPEG4ES: unknown start_code: 0x%x\n", mBitstream->show(32));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// While seeking for something valid we do byte-by-byte steps...
|
|||
|
|
mBitstream->skip(8);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
while(!mBitstream->isEof());
|
|||
|
|
|
|||
|
|
return VID_ERROR_STREAM_EOF;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Parses a video_packet_header()
|
|||
|
|
* see ISO/IEC 14496-2:2001
|
|||
|
|
*
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
VIDError M4BitstreamParser::videoPacketHeader()
|
|||
|
|
{
|
|||
|
|
mBitstream->nextResyncMarker();
|
|||
|
|
mBitstream->skipResyncMarker();
|
|||
|
|
if (mShape != M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::videoPacketHeader(): video_object_layer_shape != \"rectangular\" not supported!\n");
|
|||
|
|
return VID_ERROR_STREAM_VOL_INVALID_SHAPE;
|
|||
|
|
}
|
|||
|
|
// macroblock_number. We have already rejected 'reduced_resolution_vop_enable' so we don't need to handle this here.
|
|||
|
|
mResyncMacroblockNumber = mBitstream->getBits(log2bin(mVOLInfo.mWidth * mVOLInfo.mHeight / 256 - 1));
|
|||
|
|
|
|||
|
|
if (mShape != M4_SHAPE_BIN_ONLY)
|
|||
|
|
{
|
|||
|
|
mHeaderInfo.mQuant = (uint16)mBitstream->getBits(mQuantBits); // quant_scale (updates vop_quant)
|
|||
|
|
}
|
|||
|
|
bool header_extension_code = false;
|
|||
|
|
if (mShape == M4_SHAPE_RECT)
|
|||
|
|
{
|
|||
|
|
header_extension_code = !!mBitstream->getBit();
|
|||
|
|
}
|
|||
|
|
if (header_extension_code)
|
|||
|
|
{
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::videoPacketHeader(): header_extension_code == 1 not supported!\n");
|
|||
|
|
return VID_ERROR_STREAM_ERROR;
|
|||
|
|
/*
|
|||
|
|
do {
|
|||
|
|
modulo_time_base 1 bslbf
|
|||
|
|
} while(modulo_time_base != ‘0’)
|
|||
|
|
marker_bit 1 bslbf
|
|||
|
|
vop_time_increment 1-16 bslbf
|
|||
|
|
marker_bit 1 bslbf
|
|||
|
|
vop_coding_type 2 uimsbf
|
|||
|
|
if (video_object_layer_shape != “rectangular”) {
|
|||
|
|
change_conv_ratio_disable 1 bslbf
|
|||
|
|
if (vop_coding_type != “I”)
|
|||
|
|
vop_shape_coding_type 1 bslbf
|
|||
|
|
}
|
|||
|
|
if (video_object_layer_shape != “binary only”) {
|
|||
|
|
intra_dc_vlc_thr 3 uimsbf
|
|||
|
|
if (sprite_enable == “GMC” && vop_coding_type == “S” && no_of_sprite_warping_points > 0)
|
|||
|
|
sprite_trajectory()
|
|||
|
|
if ((reduced_resolution_vop_enable) && (video_object_layer_shape == “rectangular”) && ((vop_coding_type == “P”) || (vop_coding_type == “I”)))
|
|||
|
|
vop_reduced_resolution 1 bslbf
|
|||
|
|
if (vop_coding_type != “I”)
|
|||
|
|
vop_fcode_forward 3 uimsbf
|
|||
|
|
if (vop_coding_type == “B”)
|
|||
|
|
vop_fcode_backward 3 uimsbf
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
}
|
|||
|
|
if (mNewPredEnable) // newpred_enable
|
|||
|
|
{
|
|||
|
|
// Already checked for earlier. Recheck just in case that changed.
|
|||
|
|
mDecoder->VIDPrintf("M4BitstreamParser::videoPacketHeader(): newpred_enable == 1 not supported.\n");
|
|||
|
|
return VID_ERROR_STREAM_ERROR;
|
|||
|
|
/*
|
|||
|
|
vop_id 4-15 uimsbf
|
|||
|
|
vop_id_for_prediction_indication 1 bslbf
|
|||
|
|
if (vop_id_for_prediction_indication)
|
|||
|
|
vop_id_for_prediction 4-15 uimsbf
|
|||
|
|
marker_bit 1 bslbf
|
|||
|
|
*/
|
|||
|
|
}
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Read GMC sprite paramters from file
|
|||
|
|
* See MPEG4-P2, 6.2.5.4 Sprite coding
|
|||
|
|
*/
|
|||
|
|
void M4BitstreamParser::readGMCSprite()
|
|||
|
|
{
|
|||
|
|
M4CHECK(mSpriteWarpingPoints < 4); // GMC sprite only supports max 3 warping points!
|
|||
|
|
|
|||
|
|
// IMPORTANT, because we use d[0] to d[3], which may not be initialized
|
|||
|
|
FMemory::Memzero(mSprite, sizeof(mSprite));
|
|||
|
|
M4_VECTOR* d = mSprite;
|
|||
|
|
for(uint32 i = 0; i < mSpriteWarpingPoints; i++)
|
|||
|
|
{
|
|||
|
|
d[i].x = (int32) mBitstream->getBits(14);
|
|||
|
|
if (mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
d[i].x = -d[i].x;
|
|||
|
|
}
|
|||
|
|
d[i].y = (int32) mBitstream->getBits(14);
|
|||
|
|
if (mBitstream->getBit())
|
|||
|
|
{
|
|||
|
|
d[i].y = -d[i].y;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
/**
|
|||
|
|
* Decode GMC sprite paramters from file
|
|||
|
|
* See MPEG4-P2, 6.2.5.4 Sprite coding
|
|||
|
|
*/
|
|||
|
|
void M4BitstreamParser::decodeGMCSprite()
|
|||
|
|
{
|
|||
|
|
M4_VECTOR refSprite[4];
|
|||
|
|
M4_VECTOR refVirtual[4];
|
|||
|
|
M4_VECTOR* d = mSprite;
|
|||
|
|
|
|||
|
|
// we need this because of 'signed' operations below
|
|||
|
|
int32 width = mVOLInfo.mWidth;
|
|||
|
|
int32 height = mVOLInfo.mHeight;
|
|||
|
|
|
|||
|
|
// hm, proper init call missing or what?
|
|||
|
|
M4CHECK(width > 0 && height > 0);
|
|||
|
|
|
|||
|
|
int32 rho= 3 - mSpriteWarpingAccuracy;
|
|||
|
|
int32 alpha = 0, beta = 0;
|
|||
|
|
while((1 << alpha) < width)
|
|||
|
|
{
|
|||
|
|
alpha++;
|
|||
|
|
}
|
|||
|
|
while((1 << beta) < height)
|
|||
|
|
{
|
|||
|
|
beta++;
|
|||
|
|
}
|
|||
|
|
int32 w2 = 1<<alpha;
|
|||
|
|
int32 h2 = 1<<beta;
|
|||
|
|
|
|||
|
|
// calculate the sprite reference points
|
|||
|
|
int32 accuracy = 2 << mSpriteWarpingAccuracy;
|
|||
|
|
int32 a1 = accuracy >> 1;
|
|||
|
|
refSprite[0].x = a1 * (2 * mRefVop[0].x + d[0].x);
|
|||
|
|
refSprite[0].y = a1 * (2 * mRefVop[0].y + d[0].y);
|
|||
|
|
|
|||
|
|
refSprite[1].x = a1 * (2 * mRefVop[1].x + d[0].x + d[1].x);
|
|||
|
|
refSprite[1].y = a1 * (2 * mRefVop[1].y + d[0].y + d[1].y);
|
|||
|
|
|
|||
|
|
refSprite[2].x = a1 * (2 * mRefVop[2].x + d[0].x + d[2].x);
|
|||
|
|
refSprite[2].y = a1 * (2 * mRefVop[2].y + d[0].y + d[2].y);
|
|||
|
|
|
|||
|
|
// the idea behind this virtual_ref mess is to be able to use shifts later per pixel instead of divides
|
|||
|
|
// so the distance between points is converted from w&h based to w2&h2 based which are of the 2^x form
|
|||
|
|
int32 r = 16 / accuracy;
|
|||
|
|
|
|||
|
|
int32 tmp = (width - w2) * (r*refSprite[0].x - 16*mRefVop[0].x) + w2 * (r*refSprite[1].x - 16*mRefVop[1].x);
|
|||
|
|
refVirtual[0].x = 16*(mRefVop[0].x + w2) + ROUNDED_DIV(tmp, width);
|
|||
|
|
|
|||
|
|
tmp = (width - w2) * (r*refSprite[0].y - 16*mRefVop[0].y) + w2 * (r*refSprite[1].y - 16*mRefVop[1].y);
|
|||
|
|
refVirtual[0].y = 16*mRefVop[0].y + ROUNDED_DIV(tmp ,width);
|
|||
|
|
|
|||
|
|
tmp = (height - h2) * (r*refSprite[0].x - 16*mRefVop[0].x) + h2*(r*refSprite[2].x - 16*mRefVop[2].x);
|
|||
|
|
refVirtual[1].x = 16*mRefVop[0].x + ROUNDED_DIV(tmp, height);
|
|||
|
|
|
|||
|
|
tmp = (height - h2) * (r*refSprite[0].y - 16*mRefVop[0].y) + h2 * (r*refSprite[2].y - 16*mRefVop[2].y);
|
|||
|
|
refVirtual[1].y = 16*(mRefVop[0].y + h2) + ROUNDED_DIV(tmp ,height);
|
|||
|
|
|
|||
|
|
FMemory::Memzero(mSpriteDelta, sizeof(mSpriteDelta));
|
|||
|
|
FMemory::Memzero(&mSpriteShift, sizeof(mSpriteShift));
|
|||
|
|
|
|||
|
|
switch (mSpriteWarpingPoints)
|
|||
|
|
{
|
|||
|
|
case 0:
|
|||
|
|
{
|
|||
|
|
mSpriteOffset[0].x = 0;
|
|||
|
|
mSpriteOffset[0].y = 0;
|
|||
|
|
mSpriteOffset[1].x = 0;
|
|||
|
|
mSpriteOffset[1].y = 0;
|
|||
|
|
|
|||
|
|
mSpriteDelta[0].x = accuracy;
|
|||
|
|
mSpriteDelta[0].y = 0;
|
|||
|
|
|
|||
|
|
mSpriteDelta[1].x = 0;
|
|||
|
|
mSpriteDelta[1].y = accuracy;
|
|||
|
|
|
|||
|
|
mSpriteShift.x = 0;
|
|||
|
|
mSpriteShift.y = 0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
case 1: //GMC only
|
|||
|
|
{
|
|||
|
|
mSpriteOffset[0].x = refSprite[0].x - accuracy * mRefVop[0].x;
|
|||
|
|
mSpriteOffset[0].y = refSprite[0].y - accuracy * mRefVop[0].y;
|
|||
|
|
|
|||
|
|
mSpriteOffset[1].x = ((refSprite[0].x>>1) | (refSprite[0].x&1)) - accuracy*( mRefVop[0].x / 2 );
|
|||
|
|
mSpriteOffset[1].y = ((refSprite[0].y>>1) | (refSprite[0].y&1)) - accuracy*( mRefVop[0].y / 2 );
|
|||
|
|
|
|||
|
|
mSpriteDelta[0].x = accuracy;
|
|||
|
|
mSpriteDelta[0].y = 0;
|
|||
|
|
mSpriteDelta[1].x = 0;
|
|||
|
|
mSpriteDelta[1].y = accuracy;
|
|||
|
|
mSpriteShift.x = 0;
|
|||
|
|
mSpriteShift.y = 0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
case 2:
|
|||
|
|
{
|
|||
|
|
mSpriteOffset[0].x = (refSprite[0].x<<(alpha+rho))
|
|||
|
|
+ (-r*refSprite[0].x + refVirtual[0].x)*(-mRefVop[0].x)
|
|||
|
|
+ ( r*refSprite[0].y - refVirtual[0].y)*(-mRefVop[0].y)
|
|||
|
|
+ (1<<(alpha+rho-1));
|
|||
|
|
mSpriteOffset[0].y = (refSprite[0].y<<(alpha+rho))
|
|||
|
|
+ (-r*refSprite[0].y + refVirtual[0].y)*(-mRefVop[0].x)
|
|||
|
|
+ (-r*refSprite[0].x + refVirtual[0].x)*(-mRefVop[0].y)
|
|||
|
|
+ (1<<(alpha+rho-1));
|
|||
|
|
mSpriteOffset[1].x = ( (-r*refSprite[0].x + refVirtual[0].x)*(-2*mRefVop[0].x + 1)
|
|||
|
|
+( r*refSprite[0].y - refVirtual[0].y)*(-2*mRefVop[0].y + 1)
|
|||
|
|
+2*w2*r*refSprite[0].x - 16*w2
|
|||
|
|
+ (1<<(alpha+rho+1)));
|
|||
|
|
mSpriteOffset[1].y = ( (-r*refSprite[0].y + refVirtual[0].y)*(-2*mRefVop[0].x + 1)
|
|||
|
|
+(-r*refSprite[0].x + refVirtual[0].x)*(-2*mRefVop[0].y + 1)
|
|||
|
|
+2*w2*r*refSprite[0].y - 16*w2
|
|||
|
|
+ (1<<(alpha+rho+1)));
|
|||
|
|
|
|||
|
|
mSpriteDelta[0].x = (-r*refSprite[0].x + refVirtual[0].x);
|
|||
|
|
mSpriteDelta[0].y = ( r*refSprite[0].y - refVirtual[0].y);
|
|||
|
|
mSpriteDelta[1].x = (-r*refSprite[0].y + refVirtual[0].y);
|
|||
|
|
mSpriteDelta[1].y = (-r*refSprite[0].x + refVirtual[0].x);
|
|||
|
|
|
|||
|
|
mSpriteShift.x = alpha+rho;
|
|||
|
|
mSpriteShift.y = alpha+rho+2;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
case 3:
|
|||
|
|
{
|
|||
|
|
int32 min_ab = M4MIN(alpha, beta);
|
|||
|
|
int32 w3 = w2>>min_ab;
|
|||
|
|
int32 h3 = h2>>min_ab;
|
|||
|
|
mSpriteOffset[0].x = (refSprite[0].x<<(alpha+beta+rho-min_ab))
|
|||
|
|
+ (-r*refSprite[0].x + refVirtual[0].x)*h3*(-mRefVop[0].x)
|
|||
|
|
+ (-r*refSprite[0].x + refVirtual[1].x)*w3*(-mRefVop[0].y)
|
|||
|
|
+ (1<<(alpha+beta+rho-min_ab-1));
|
|||
|
|
mSpriteOffset[0].y = (refSprite[0].y<<(alpha+beta+rho-min_ab))
|
|||
|
|
+ (-r*refSprite[0].y + refVirtual[0].y)*h3*(-mRefVop[0].x)
|
|||
|
|
+ (-r*refSprite[0].y + refVirtual[1].y)*w3*(-mRefVop[0].y)
|
|||
|
|
+ (1<<(alpha+beta+rho-min_ab-1));
|
|||
|
|
mSpriteOffset[1].x = (-r*refSprite[0].x + refVirtual[0].x)*h3*(-2*mRefVop[0].x + 1)
|
|||
|
|
+ (-r*refSprite[0].x + refVirtual[1].x)*w3*(-2*mRefVop[0].y + 1)
|
|||
|
|
+ 2*w2*h3*r*refSprite[0].x
|
|||
|
|
- 16*w2*h3
|
|||
|
|
+ (1<<(alpha+beta+rho-min_ab+1));
|
|||
|
|
mSpriteOffset[1].y = (-r*refSprite[0].y + refVirtual[0].y)*h3*(-2*mRefVop[0].x + 1)
|
|||
|
|
+ (-r*refSprite[0].y + refVirtual[1].y)*w3*(-2*mRefVop[0].y + 1)
|
|||
|
|
+ 2*w2*h3*r*refSprite[0].y
|
|||
|
|
- 16*w2*h3
|
|||
|
|
+ (1<<(alpha+beta+rho-min_ab+1));
|
|||
|
|
mSpriteDelta[0].x = (-r*refSprite[0].x + refVirtual[0].x)*h3;
|
|||
|
|
mSpriteDelta[0].y = (-r*refSprite[0].x + refVirtual[1].x)*w3;
|
|||
|
|
mSpriteDelta[1].x = (-r*refSprite[0].y + refVirtual[0].y)*h3;
|
|||
|
|
mSpriteDelta[1].y = (-r*refSprite[0].y + refVirtual[1].y)*w3;
|
|||
|
|
|
|||
|
|
mSpriteShift.x = alpha + beta + rho - min_ab;
|
|||
|
|
mSpriteShift.y = alpha + beta + rho - min_ab + 2;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (mSpriteDelta[0].x == accuracy<<mSpriteShift.x && mSpriteDelta[0].y == 0 &&
|
|||
|
|
mSpriteDelta[1].x == 0 && mSpriteDelta[1].y == accuracy<<mSpriteShift.x)
|
|||
|
|
{
|
|||
|
|
mSpriteOffset[0].x >>= mSpriteShift.x;
|
|||
|
|
mSpriteOffset[0].y >>= mSpriteShift.x;
|
|||
|
|
mSpriteOffset[1].x >>= mSpriteShift.y;
|
|||
|
|
mSpriteOffset[1].y >>= mSpriteShift.y;
|
|||
|
|
mSpriteDelta[0].x= accuracy;
|
|||
|
|
mSpriteDelta[0].y= 0;
|
|||
|
|
mSpriteDelta[1].x= 0;
|
|||
|
|
mSpriteDelta[1].y= accuracy;
|
|||
|
|
mSpriteShift.x = 0;
|
|||
|
|
mSpriteShift.y = 0;
|
|||
|
|
|
|||
|
|
mSpriteWarpingPointsUsed = 1;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
int32 shift_y = 16 - mSpriteShift.x;
|
|||
|
|
int32 shift_c = 16 - mSpriteShift.y;
|
|||
|
|
|
|||
|
|
mSpriteOffset[0].x <<= shift_y;
|
|||
|
|
mSpriteOffset[0].y <<= shift_y;
|
|||
|
|
|
|||
|
|
mSpriteOffset[1].x <<= shift_c;
|
|||
|
|
mSpriteOffset[1].y <<= shift_c;
|
|||
|
|
|
|||
|
|
mSpriteDelta[0].x <<= shift_y;
|
|||
|
|
mSpriteDelta[0].y <<= shift_y;
|
|||
|
|
|
|||
|
|
mSpriteDelta[1].x <<= shift_y;
|
|||
|
|
mSpriteDelta[1].y <<= shift_y;
|
|||
|
|
|
|||
|
|
mSpriteShift.x = 16;
|
|||
|
|
mSpriteShift.y = 16;
|
|||
|
|
|
|||
|
|
mSpriteWarpingPointsUsed = mSpriteWarpingPoints;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------------------------------------------------------
|
|||
|
|
// ------------------------------------------------------------------------------------------------
|
|||
|
|
// ------------------------------------------------------------------------------------------------
|
|||
|
|
// ------------------------------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
M4BitstreamCache::M4BitstreamCache()
|
|||
|
|
: mpCacheEntry(nullptr)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
M4BitstreamCache::~M4BitstreamCache()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
VIDError M4BitstreamCache::Init(M4MemHandler& memSys)
|
|||
|
|
{
|
|||
|
|
if ((mpCacheEntry = (M4BitstreamCacheEntry*)memSys.malloc(sizeof(M4BitstreamCacheEntry), 128)) != nullptr)
|
|||
|
|
{
|
|||
|
|
return VID_OK;
|
|||
|
|
}
|
|||
|
|
return VID_ERROR_OUT_OF_MEMORY;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void M4BitstreamCache::Exit(M4MemHandler& memSys)
|
|||
|
|
{
|
|||
|
|
memSys.free(mpCacheEntry);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|