📄 mp4_mblock.c
字号:
/********************************************************************************
* *
* This code has been developed by Project Mayo. This software is an *
* implementation of a part of one or more MPEG-4 Video tools as *
* specified in ISO/IEC 14496-2 standard. Those intending to use this *
* software module in hardware or software products are advised that its *
* use may infringe existing patents or copyrights, and any such use *
* would be at such party's own risk. The original developer of this *
* software module and his/her company, and subsequent editors and their *
* companies (including Project Mayo), will have no liability for use of *
* this software or modifications or derivatives thereof. *
* *
********************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* The GPL can be found at: http://www.gnu.org/copyleft/gpl.html *
* *
* Authors: *
* *
* Andrea Graziani (Ag): *
* - Original source code (Open Divx Decoder 0.4a). *
* *
* Marc Dukette (Md) and *
* Pedro Mateu (Pm): *
* - Heavily modified and optimized code + MIPS ASM *
* *
********************************************************************************/
// mp4_mblock.c //
#define GLOBAL
#include "global.h"
#include "mp4_mblock.h"
#include "mp4_predict.h"
// idct.c
extern void IDCT_S (idct_block_t *DCT_Block, uint8_t *DestU8, int Stride, unsigned char Mode);
// recon.c
extern void reconstruct (int bx, int by, int mode);
static void clearblock(idct_block_t * psblock);
static unsigned short getDCsizeLum();
static unsigned short getDCsizeChr();
static int getDCdiff(int dct_dc_size);
static int Get_DC_Scaler(int block_num);
static void blockIntra(int block_num, idct_block_t *block, int coded);
static void blockInter(int block_num, idct_block_t *block);
int LastDropped;
/**/
static void blockIntra(int block_num, idct_block_t *block, int coded)
{
int i;
int dct_dc_size, dct_dc_diff;
// dc coeff
mp4_hdr.dc_scaler = Get_DC_Scaler(block_num); // calculate DC scaler
if (block_num < 4) dct_dc_size = getDCsizeLum();
else dct_dc_size = getDCsizeChr();
if (dct_dc_size)
dct_dc_diff = getDCdiff(dct_dc_size);
else dct_dc_diff = 0;
if (dct_dc_size > 8) //*//
flushbits(1); // marker bit //*//
clearblock(block);
block[0] = (idct_block_t) dct_dc_diff;
// dc reconstruction, prediction direction
dc_recon(block_num, block);
if (coded)
{
int event,level;
const unsigned char * zigzag; // zigzag scan dir
register int q_scale = (mp4_hdr.quantizer) << 1;
register int q_add = ((q_scale>>1) & 1) ? (q_scale>>1) : ((q_scale>>1) - 1);
if (mp4_hdr.ac_pred_flag == 1) {
if (coeff_pred.predict_dir == TOP)
zigzag = alternate_horizontal_scan;
else
zigzag = alternate_vertical_scan;
}
else {
zigzag = zig_zag_scan;
}
i = 1;
do // event vld
{
event = vld_intra_dct();
level = event>>16;
i+= (event&0xFF);
if (level > 0) {
block[zigzag[i]] = (q_scale * level) + q_add;
}
else {
block[zigzag[i]] = (q_scale * level) - q_add;
}
i++;
} while (!((event>>8)&0xFF));
}
// ac reconstruction
ac_recon(block_num, block);
}
/**/
static void blockInter(int block_num, idct_block_t *block)
{
int event;
int level;
int i;
register int q_scale = (mp4_hdr.quantizer) << 1;
register int q_add = ((q_scale>>1) & 1) ? (q_scale>>1) : ((q_scale>>1) - 1);
i = 0;
clearblock(block);
do // event vld
{
event = vld_inter_dct();
level = event>>16;
i+= (event&0xFF);
if (level > 0) {
block[zig_zag_scan[i]] = (q_scale * level) + q_add;
}
else {
block[zig_zag_scan[i]] = (q_scale * level) - q_add;
}
i++;
} while (!((event>>8)&0xFF));
}
/**/
static unsigned short getDCsizeLum()
{
unsigned short code;
unsigned char i;
code = showbits(11);
for (i=0;i<8;i++)
{
if ((code >> i)==1)
{
flushbits(11-i);
return 12-i;
}
}
code >>= 8;
if (code == 1) {
flushbits(3);
return 4;
}
else if (code == 2) {
flushbits(3);
return 3;
}
else if (code == 3) {
flushbits(3);
return 0;
}
code >>=1;
if (code == 2) {
flushbits(2);
return 2;
}
else if (code == 3) {
flushbits(2);
return 1;
}
return 0;
}
static unsigned short getDCsizeChr()
{
unsigned char i;
unsigned short code;
code = showbits(12);
for (i=0;i<10;i++)
{
if ((code >> i)==1)
{
flushbits(12-i);
return 12-i;
}
}
return (3 - getbits(2));
}
/**/
static int getDCdiff(int dct_dc_size)
{
#ifdef MIPS_ASM
__asm ("jal getbits;"
"addi $8,$4,-1;"//dct_dc_size-1
"srlv $9,$2,$8;"//code >>
"bne $9,$0,MSB_NO_0;"
"li $25,1;"
"sllv $25,$25,$4;"//<<dct_dc_size
"addi $25,$25,-1;"
"xor $2,$2,$25;"
"neg $2;"
"MSB_NO_0:"
);
#else
int code = getbits(dct_dc_size);
int msb = code >> (dct_dc_size - 1);
if (msb == 0) return (-(code^((1<<dct_dc_size) - 1)));
else return code;
#endif
}
/**/
static int Get_DC_Scaler(int block_num)
{
int quant = mp4_hdr.quantizer;
if (block_num < 4) {
if (quant >24) return (quant - 16)<<1;
else if (quant>8) return (quant + 8);
else if (quant>4) return quant<<1;
else return 8;
}
else {
if (quant > 24) return (quant - 6);
else if (quant > 4) return (quant + 13)>>1;
else return 8;
}
}
#ifdef MIPS_ASM_64
static void clearblock (idct_block_t *psblock)
{
__asm ("addi $2,$0,2;"
"comienzo:sdr $0,0($4);"
"sdr $0,8($4);"
"sdr $0,16($4);"
"sdr $0,24($4);"
"sdr $0,32($4);"
"sdr $0,40($4);"
"sdr $0,48($4);"
"sdr $0,56($4);"
"addi $4,$4,64;"
"addi $2,$2,-1;"
"bgtz $2,comienzo;");
}
#else
static void clearblock (idct_block_t *psblock)
{
int i;
for (i=0; i<64;i++)
psblock[i]=0;
}
#endif
/**/
static short getMCBPC();
static short getCBPY();
/**/
static void addblock (int comp, int bx, int by,int idct_mode)
{
unsigned char *rfp;
if (comp < 4) // luminance
{
// pixel coordinates
bx <<= 4;
by <<= 4;
// frame DCT coding
rfp = frame_ref[0] + mp4_hdr.coded_picture_width * (by + ((comp & 2) << 2)) + bx + ((comp & 1) << 3);
IDCT_S(ld.block, rfp, mp4_hdr.coded_picture_width,idct_mode);
return;
}
else // chrominance
{
// pixel coordinates
bx <<= 3;
by <<= 2; //chrominance
// frame DCT coding
rfp = frame_ref[(comp & 1) + 1] + mp4_hdr.coded_picture_width * by + bx;
IDCT_S(ld.block, rfp, mp4_hdr.coded_picture_width>>1,idct_mode);
}
}
/**/
void IVOP_macroblock()
{
unsigned char j;
mp4_hdr.mcbpc = getMCBPC(); // mcbpc
mp4_hdr.derived_mb_type = mp4_hdr.mcbpc & 7;
mp4_hdr.cbpc = (mp4_hdr.mcbpc >> 4) & 3;
//INTRA
mp4_hdr.ac_pred_flag = getbits1();
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
if (mp4_hdr.derived_mb_type== INTRA_Q){
mp4_hdr.quantizer += DQtab[getbits(2)]; //DQtab[dquant]
if (mp4_hdr.quantizer > 31)
mp4_hdr.quantizer = 31;
else if (mp4_hdr.quantizer < 1)
mp4_hdr.quantizer = 1;
}
// texture decoding add
for (j = 0; j < 6; j++) {
blockIntra(j, ld.block, mp4_hdr.cbp & (1 << (5 - j)));
addblock(j, mp4_hdr.mb_xpos, mp4_hdr.mb_ypos,0);
}
#ifdef Direct_YUV
if (Render_Flag)
Direct_YUV_to_RGB(mp4_hdr.mb_xpos, mp4_hdr.mb_ypos);
#endif
// not coded macroblock
if (mp4_hdr.mb_xpos < (mp4_hdr.mb_xsize-1)) {
mp4_hdr.mb_xpos++;
}
else {
mp4_hdr.mb_ypos++;
mp4_hdr.mb_xpos = 0;
}
}
void PVOP_macroblock()
{
unsigned char j;
unsigned char interFlag;
// coded macroblock
if (!getbits1()) { //if coded
mp4_hdr.mcbpc = getMCBPC(); // mcbpc
mp4_hdr.derived_mb_type = mp4_hdr.mcbpc & 7;
mp4_hdr.cbpc = (mp4_hdr.mcbpc >> 4) & 3;
modemap[mp4_hdr.mba] = mp4_hdr.derived_mb_type;
switch(mp4_hdr.derived_mb_type)
{
case INTRA:
interFlag=0;
mp4_hdr.ac_pred_flag = getbits1();
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
#ifdef MIPS_ASM_64
__asm ( "sdr $0,0($4);"
"sdr $0,8($4);",&MV[mp4_hdr.mb_xpos][0]);
#else
{
int i;
for (i = 0; i < 4; i++) {
MV[mp4_hdr.mb_xpos][i] = 0;
}
}
#endif
break;
case INTRA_Q:
interFlag=0;
mp4_hdr.ac_pred_flag = getbits1();
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
mp4_hdr.quantizer += DQtab[getbits(2)]; //DQtab[dquant]
if (mp4_hdr.quantizer > 31)
mp4_hdr.quantizer = 31;
else if (mp4_hdr.quantizer < 1)
mp4_hdr.quantizer = 1;
#ifdef MIPS_ASM_64
__asm ( "sdr $0,0($4);"
"sdr $0,8($4);",&MV[mp4_hdr.mb_xpos][0]);
#else
{
int i;
for (i = 0; i < 4; i++) {
MV[mp4_hdr.mb_xpos][i] = 0;
}
}
#endif
break;
case INTER_Q:
interFlag=1;
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
mp4_hdr.quantizer += DQtab[getbits(2)]; //DQtab[dquant]
if (mp4_hdr.quantizer > 31)
mp4_hdr.quantizer = 31;
else if (mp4_hdr.quantizer < 1)
mp4_hdr.quantizer = 1;
setMV(-1); // mv
break;
case INTER:
interFlag=1;
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
setMV(-1); // mv
break;
case INTER4V:
interFlag=1;
mp4_hdr.cbp = (getCBPY() << 2) | mp4_hdr.cbpc;
for (j = 0; j < 4; j++) {
setMV(j); // mv
}
break;
default: //case STUFFING:
return;
}
// motion compensation
if (interFlag)
{
reconstruct(mp4_hdr.mb_xpos, mp4_hdr.mb_ypos, mp4_hdr.derived_mb_type);
// texture decoding add
for (j = 0; j < 6; j++) {
if (mp4_hdr.cbp & (1 << (5 - j))) //if coded
{
blockInter(j, ld.block);
addblock(j, mp4_hdr.mb_xpos, mp4_hdr.mb_ypos,1);
}
}
}
else
{
rescue_predict(); //Restore AC_DC values
for (j = 0; j < 6; j++) {
blockIntra(j, ld.block, mp4_hdr.cbp & (1 << (5 - j)));
addblock(j, mp4_hdr.mb_xpos, mp4_hdr.mb_ypos,0);
}
}
#ifdef Direct_YUV
if (Render_Flag)
Direct_YUV_to_RGB(mp4_hdr.mb_xpos, mp4_hdr.mb_ypos);
#endif
}
// not coded macroblock
else {
#ifdef MIPS_ASM_64
__asm ( "sdr $0,0($4);"
"sdr $0,8($4);",&MV[mp4_hdr.mb_xpos][0]);
#else
MV[mp4_hdr.mb_xpos][0]= 0;
MV[mp4_hdr.mb_xpos][1]= 0;
MV[mp4_hdr.mb_xpos][2]= 0;
MV[mp4_hdr.mb_xpos][3]= 0;
#endif
if (modemap[mp4_hdr.mba] != NOT_CODED||(mp4_hdr.last_prediction_type==I_VOP)){
modemap[mp4_hdr.mba] = NOT_CODED; // [Review] used only in P-VOPs
reconstruct(mp4_hdr.mb_xpos, mp4_hdr.mb_ypos, mp4_hdr.derived_mb_type);
}
#ifdef Direct_YUV
if (Render_Flag&&(LastDropped))
Direct_YUV_to_RGB(mp4_hdr.mb_xpos, mp4_hdr.mb_ypos);
#endif
}
if (mp4_hdr.mb_xpos < (mp4_hdr.mb_xsize-1)) {
mp4_hdr.mb_xpos++;
}
else {
mp4_hdr.mb_ypos++;
mp4_hdr.mb_xpos = 0;
}
}
/**/
static short getMCBPC()
{
short code;
code = showbits(9);
if (mp4_hdr.prediction_type == I_VOP)
{
if (code == 1) {
flushbits(9); // stuffing
return 0;
}
else if (code < 8) return -1;
code >>= 3;
if (code >= 32) {
flushbits(1);
return 3;
}
flushbits(MCBPCtabIntra[(code<<1)+1]);
return MCBPCtabIntra[code<<1];
}
else
{
if (code == 0) return -1;
if (code >= 256)
{
flushbits(1);
return 0;
}
flushbits(MCBPCtabInter[(code<<1)+1]);
return MCBPCtabInter[code<<1];
}
}
/**/
static short getCBPY()
{
short code;
code = showbits(6);
if (code < 2) return -1;
if (code >= 48) {
flushbits(2);
code = 15;
}
else {
flushbits(CBPYtab[(code<<1)+1]);
code = CBPYtab[code<<1];
}
if (!((mp4_hdr.derived_mb_type == 3) || (mp4_hdr.derived_mb_type == 4)))
code = 15 - code;
return code;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -