261 lines
5.0 KiB
C++
261 lines
5.0 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
#pragma once
|
|
|
|
#include "vdecmpeg4.h"
|
|
#include "M4Memory.h"
|
|
#include "M4Bitstream.h"
|
|
|
|
namespace vdecmpeg4
|
|
{
|
|
#define MK_VLC(a,b) \
|
|
( ((a)&0x1ffff) | ((b)<<17) )
|
|
|
|
#define VLC_CODE(a) \
|
|
((a)&0x1ffff)
|
|
|
|
#define VLC_LEN(a) \
|
|
((a)>>17)
|
|
|
|
#define VLC_ERROR MK_VLC(0x1ffff, 0)
|
|
#define VLC_ESCAPE 0x1BFF
|
|
|
|
typedef uint32 M4_VLC; //!< Definition of VLC data types
|
|
|
|
|
|
//! helper struct for passing some C++ tables to the ASM routines. Must be initialized only once.
|
|
struct M4BlockVlcCodeTab
|
|
{
|
|
M4_VLC* mVlcCodeTab[3];
|
|
void* mMaxLevel;
|
|
void* mMaxRun;
|
|
};
|
|
|
|
|
|
|
|
class M4VlcDecoder
|
|
{
|
|
public:
|
|
//! Default constructor
|
|
M4VlcDecoder()
|
|
{}
|
|
|
|
//! Destructor
|
|
~M4VlcDecoder()
|
|
{}
|
|
|
|
//! Init vlc tables
|
|
void init();
|
|
|
|
//!
|
|
int32 getCoeffIntraNoAsm(int32& run, int32& last, M4Bitstream& bs)
|
|
{
|
|
uint32 bits = bs.show(12);
|
|
M4CHECK(bits >= 8);
|
|
|
|
M4_VLC vlc = getIntraVlcTab(bits);
|
|
M4CHECK(vlc != VLC_ERROR);
|
|
|
|
bs.skip(VLC_LEN(vlc));
|
|
|
|
int32 level;
|
|
uint32 code = VLC_CODE(vlc);
|
|
if (code != VLC_ESCAPE)
|
|
{
|
|
run = (code >> 8) & 255;
|
|
level = code & 255;
|
|
last = (code >> 16) & 1;
|
|
int32 ret = bs.getBit() ? -level : level;
|
|
return ret;
|
|
}
|
|
|
|
uint32 escMode = bs.show(2);
|
|
if (escMode < 3)
|
|
{
|
|
bs.skip((escMode == 2) ? 2 : 1);
|
|
|
|
bits = bs.show(12);
|
|
M4CHECK(bits >= 8);
|
|
|
|
vlc = getIntraVlcTab(bits);
|
|
M4CHECK(vlc != VLC_ERROR);
|
|
|
|
bs.skip(VLC_LEN(vlc));
|
|
|
|
code = VLC_CODE(vlc);
|
|
run = (code >> 8) & 255;
|
|
level = code & 255;
|
|
last = (code >> 16) & 1;
|
|
|
|
if (escMode < 2) // first escape mode, level is offset
|
|
{
|
|
level += mMaxLevel[last][run]; // need to add back the max level
|
|
}
|
|
else if (escMode == 2) // second escape mode, run is offset
|
|
{
|
|
run += mMaxRun[last][level] + 1;
|
|
}
|
|
else
|
|
{
|
|
M4CHECK(0); //todo.... (needs a final verification)
|
|
}
|
|
|
|
int32 ret = bs.getBit() ? -level : level;
|
|
return ret;
|
|
}
|
|
|
|
// third escape mode - fixed length codes
|
|
bs.skip(2);
|
|
last = (int32) bs.getBits(1);
|
|
run = (int32) bs.getBits(6);
|
|
|
|
bs.skip(1); // marker
|
|
level = (int32) bs.getBits(12);
|
|
bs.skip(1); // marker
|
|
|
|
return (level & 0x800) ? (level | (-1 ^ 0xfff)) : level;
|
|
}
|
|
|
|
//!
|
|
int32 getCoeffInterNoAsm(int32& run, int32& last, M4Bitstream& bs)
|
|
{
|
|
// use ISO Table B-16, max 12 bit of VLC code
|
|
uint32 bits = bs.show(12);
|
|
M4CHECK(bits >= 8);
|
|
|
|
M4_VLC vlc = getInterVlcTab(bits);
|
|
M4CHECK(vlc != VLC_ERROR);
|
|
|
|
bs.skip(VLC_LEN(vlc));
|
|
|
|
int32 level;
|
|
uint32 code = VLC_CODE(vlc);
|
|
if (code != VLC_ESCAPE)
|
|
{
|
|
run = (code >> 4) & 255;
|
|
level = code & 15;
|
|
last = (code >> 12) & 1;
|
|
int32 ret = bs.getBit() ? -level : level;
|
|
return ret;
|
|
}
|
|
|
|
uint32 escMode = bs.show(2);
|
|
if (escMode < 3)
|
|
{
|
|
bs.skip((escMode == 2) ? 2 : 1);
|
|
|
|
bits = bs.show(12);
|
|
M4CHECK(bits >= 8);
|
|
|
|
vlc = getInterVlcTab(bits);
|
|
M4CHECK(vlc != VLC_ERROR);
|
|
|
|
bs.skip(VLC_LEN(vlc));
|
|
|
|
code = VLC_CODE(vlc);
|
|
run = (code >> 4) & 255;
|
|
level = code & 15;
|
|
last = (code >> 12) & 1;
|
|
|
|
if (escMode < 2) // first escape mode, level is offset
|
|
{
|
|
level += mMaxLevel[last + 2][run]; // need to add back the max level
|
|
}
|
|
else if (escMode == 2) // second escape mode, run is offset
|
|
{
|
|
run += mMaxRun[last + 2][level] + 1;
|
|
}
|
|
else
|
|
{
|
|
M4CHECK(0); //todo.... (needs a final verification)
|
|
}
|
|
|
|
int32 ret = bs.getBit() ? -level : level;
|
|
return ret;
|
|
}
|
|
|
|
// third escape mode - fixed length codes
|
|
bs.skip(2);
|
|
last = (int32) bs.getBits(1);
|
|
|
|
run = (int32) bs.getBits(6);
|
|
bs.skip(1); // marker
|
|
|
|
level = (int32) bs.getBits(12);
|
|
bs.skip(1); // marker
|
|
|
|
return (level & 0x800) ? (level | (-1 ^ 0xfff)) : level;
|
|
}
|
|
|
|
private:
|
|
//! Get vlc code for intra block
|
|
M4_VLC getIntraVlcTab(uint32 bits)
|
|
{
|
|
if (bits >=512)
|
|
{
|
|
return mIntraCodeTab.mVlcCodeTab[0][(bits >> 5) - 16];
|
|
}
|
|
else if (bits >= 128)
|
|
{
|
|
return mIntraCodeTab.mVlcCodeTab[1][(bits >> 2) - 32];
|
|
}
|
|
else
|
|
{
|
|
return mIntraCodeTab.mVlcCodeTab[2][bits - 8];
|
|
}
|
|
}
|
|
|
|
//! Get vlc code for inter block
|
|
M4_VLC getInterVlcTab(uint32 bits)
|
|
{
|
|
if (bits >=512)
|
|
{
|
|
return mInterCodeTab.mVlcCodeTab[0][(bits >> 5) - 16];
|
|
}
|
|
else if (bits >= 128)
|
|
{
|
|
return mInterCodeTab.mVlcCodeTab[1][(bits >> 2) - 32];
|
|
}
|
|
else
|
|
{
|
|
return mInterCodeTab.mVlcCodeTab[2][bits - 8];
|
|
}
|
|
}
|
|
|
|
//! Copy-constructor not implemented
|
|
M4VlcDecoder(const M4VlcDecoder &pObj);
|
|
|
|
//! Assignment operator not implemented
|
|
const M4VlcDecoder &operator=(const M4VlcDecoder &pObj);
|
|
|
|
M4BlockVlcCodeTab mIntraCodeTab;
|
|
M4BlockVlcCodeTab mInterCodeTab;
|
|
|
|
static uint8 mMaxLevel[4][64];
|
|
static uint8 mMaxRun[4][256];
|
|
|
|
static const M4_VLC mTabCbpCIntra[64];
|
|
static const M4_VLC mTabCbpCInter[257];
|
|
static const M4_VLC mTabCbpY[64];
|
|
|
|
static M4_VLC mTabTMNMV0[];
|
|
static M4_VLC mTabTMNMV1[];
|
|
static M4_VLC mTabTMNMV2[];
|
|
|
|
static M4_VLC mTabDCT3D0[];
|
|
static M4_VLC mTabDCT3D1[];
|
|
static M4_VLC mTabDCT3D2[];
|
|
|
|
static M4_VLC mTabDCT3D3[];
|
|
static M4_VLC mTabDCT3D4[];
|
|
static M4_VLC mTabDCT3D5[];
|
|
|
|
static const M4_VLC mDCLumTab[];
|
|
|
|
friend class M4BitstreamParser;
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|