You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1153 lines
29 KiB
1153 lines
29 KiB
/*
|
|
stores macroblock infos
|
|
Copyright (C) 2000 Martin Vogt
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation.
|
|
|
|
For more information look at the file COPYRIGHT in this package
|
|
|
|
*/
|
|
|
|
|
|
#include "macroBlock.h"
|
|
|
|
#define DEBUG_MACROBLOCK(x)
|
|
//#define DEBUG_MACROBLOCK(x) x
|
|
|
|
|
|
|
|
MacroBlock::MacroBlock(VideoDecoder* vid_stream) {
|
|
this->vid_stream=vid_stream;
|
|
copyFunctions=new CopyFunctions();
|
|
}
|
|
|
|
|
|
MacroBlock::~MacroBlock() {
|
|
delete copyFunctions;
|
|
}
|
|
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ParseMacroBlock --
|
|
*
|
|
* Parseoff macroblock. Reconstructs DCT values. Applies
|
|
* inverse DCT, reconstructs motion vectors, calculates and
|
|
* set pixel values for macroblock in current pict image
|
|
* structure.
|
|
*
|
|
* Results:
|
|
* Here's where everything really happens. Welcome to the
|
|
* heart of darkness.
|
|
*
|
|
* Side effects:
|
|
* Bit stream irreversibly parsed off.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
int MacroBlock::processMacroBlock(PictureArray* pictureArray) {
|
|
unsigned int data;
|
|
int recon_right_for, recon_down_for, recon_right_back,
|
|
recon_down_back;
|
|
int mb_quant = 0, mb_motion_forw = 0, mb_motion_back = 0,
|
|
mb_pattern = 0;
|
|
|
|
int addr_incr;
|
|
MpegVideoStream* mpegVideoStream=vid_stream->mpegVideoStream;
|
|
DecoderClass* decoderClass=vid_stream->decoderClass;
|
|
|
|
/*
|
|
* Parse off macroblock address increment and add to macroblock address.
|
|
*/
|
|
do {
|
|
addr_incr=decoderClass->decodeMBAddrInc();
|
|
if (addr_incr==MB_ESCAPE) {
|
|
mb_address += 33;
|
|
addr_incr=MB_STUFFING;
|
|
}
|
|
|
|
} while (addr_incr == MB_STUFFING);
|
|
mb_address+=addr_incr;
|
|
|
|
|
|
|
|
if (mb_address > (vid_stream->mpegVideoHeader)->getMB_Size()) {
|
|
|
|
DEBUG_MACROBLOCK(cout <<"ParseMacroBlock: SKIP_TO_START_CODE"<<endl;)
|
|
DEBUG_MACROBLOCK(cout <<"mb_address "<<mb_address<<endl;)
|
|
|
|
int h=(vid_stream->mpegVideoHeader)->getMB_Height();
|
|
int w=(vid_stream->mpegVideoHeader)->getMB_Width();
|
|
|
|
|
|
DEBUG_MACROBLOCK(cout <<"mb_height*mb_width-1:"<<(h*w - 1)<<endl;)
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* If macroblocks have been skipped, process skipped macroblocks.
|
|
*/
|
|
|
|
int code_type=(vid_stream->picture)->getCodeType();
|
|
|
|
if (mb_address - past_mb_addr > 1) {
|
|
|
|
processSkippedPictures(pictureArray,code_type,
|
|
(vid_stream->mpegVideoHeader)->getMB_Width());
|
|
|
|
}
|
|
|
|
|
|
/* Set past macroblock address to current macroblock address. */
|
|
past_mb_addr = mb_address;
|
|
/* Based on picture type decode macroblock type. */
|
|
|
|
|
|
switch (code_type) {
|
|
case I_TYPE:
|
|
decoderClass->decodeMBTypeI(mb_quant, mb_motion_forw,
|
|
mb_motion_back, mb_pattern,
|
|
mb_intra);
|
|
break;
|
|
|
|
case P_TYPE:
|
|
decoderClass->decodeMBTypeP(mb_quant, mb_motion_forw,
|
|
mb_motion_back, mb_pattern,
|
|
mb_intra);
|
|
break;
|
|
|
|
case B_TYPE:
|
|
decoderClass->decodeMBTypeB(mb_quant, mb_motion_forw,
|
|
mb_motion_back, mb_pattern,
|
|
mb_intra);
|
|
break;
|
|
case D_TYPE:
|
|
DEBUG_MACROBLOCK(cout <<"ERROR: MPEG-1 Streams with D-frames are not supported"<<endl;)
|
|
return false;
|
|
|
|
}
|
|
/* If quantization flag set, parse off new quantization scale. */
|
|
if (mb_quant == true) {
|
|
data=mpegVideoStream->getBits(5);
|
|
(vid_stream->slice)->setQuantScale(data);
|
|
}
|
|
/* If forward motion vectors exist... */
|
|
|
|
if (mb_motion_forw == true) {
|
|
// Parse off and decode horizontal forward motion vector.
|
|
motion_h_forw_code=decoderClass->decodeMotionVectors();
|
|
|
|
// If horiz. forward r data exists, parse off.
|
|
|
|
if ((vid_stream->picture->getForw_f() != 1) &&
|
|
(motion_h_forw_code != 0)) {
|
|
data=vid_stream->picture->geth_forw_r(mpegVideoStream);
|
|
motion_h_forw_r = data;
|
|
}
|
|
// Parse off and decode vertical forward motion vector.
|
|
|
|
motion_v_forw_code=decoderClass->decodeMotionVectors();
|
|
|
|
// If vert. forw. r data exists, parse off.
|
|
|
|
if ((vid_stream->picture->getForw_f() != 1) &&
|
|
(motion_v_forw_code != 0)) {
|
|
|
|
data=vid_stream->picture->getv_forw_r(mpegVideoStream);
|
|
motion_v_forw_r = data;
|
|
}
|
|
}
|
|
|
|
/* If back motion vectors exist... */
|
|
|
|
if (mb_motion_back == true) {
|
|
// Parse off and decode horiz. back motion vector.
|
|
motion_h_back_code=decoderClass->decodeMotionVectors();
|
|
|
|
// If horiz. back r data exists, parse off.
|
|
|
|
if ((vid_stream->picture->getBack_f() != 1) &&
|
|
(motion_h_back_code != 0)) {
|
|
data=vid_stream->picture->geth_back_r(mpegVideoStream);
|
|
motion_h_back_r = data;
|
|
}
|
|
// Parse off and decode vert. back motion vector.
|
|
motion_v_back_code=decoderClass->decodeMotionVectors();
|
|
|
|
// If vert. back r data exists, parse off.
|
|
|
|
if ((vid_stream->picture->getBack_f() != 1) &&
|
|
(motion_v_back_code != 0)) {
|
|
data=vid_stream->picture->getv_back_r(mpegVideoStream);
|
|
motion_v_back_r = data;
|
|
}
|
|
}
|
|
|
|
/* If mblock pattern flag set, parse and decode CBP (code block pattern). */
|
|
if (mb_pattern == true) {
|
|
cbp=decoderClass->decodeCBP();
|
|
}
|
|
/* Otherwise, set CBP to zero. */
|
|
else
|
|
cbp = 0;
|
|
|
|
|
|
|
|
/* Reconstruct motion vectors depending on picture type. */
|
|
if (code_type == P_TYPE) {
|
|
|
|
/*
|
|
* If no forw motion vectors, reset previous and current vectors to 0.
|
|
*/
|
|
if (!mb_motion_forw) {
|
|
recon_right_for = 0;
|
|
recon_down_for = 0;
|
|
recon_right_for_prev = 0;
|
|
recon_down_for_prev = 0;
|
|
}
|
|
/*
|
|
* Otherwise, compute new forw motion vectors. Reset previous vectors to
|
|
* current vectors.
|
|
*/
|
|
|
|
else {
|
|
computeForwVector(&recon_right_for, &recon_down_for);
|
|
|
|
}
|
|
}
|
|
if (code_type == B_TYPE) {
|
|
|
|
/* Reset prev. and current vectors to zero if mblock is intracoded. */
|
|
if (mb_intra) {
|
|
recon_right_for_prev = 0;
|
|
recon_down_for_prev = 0;
|
|
recon_right_back_prev = 0;
|
|
recon_down_back_prev = 0;
|
|
} else {
|
|
|
|
/* If no forw vectors, current vectors equal prev. vectors. */
|
|
|
|
if (!mb_motion_forw) {
|
|
recon_right_for = recon_right_for_prev;
|
|
recon_down_for = recon_down_for_prev;
|
|
}
|
|
/*
|
|
* Otherwise compute forw. vectors. Reset prev vectors to new values.
|
|
*/
|
|
|
|
else {
|
|
computeForwVector(&recon_right_for, &recon_down_for);
|
|
|
|
}
|
|
|
|
/* If no back vectors, set back vectors to prev back vectors. */
|
|
|
|
if (!mb_motion_back) {
|
|
recon_right_back = recon_right_back_prev;
|
|
recon_down_back = recon_down_back_prev;
|
|
}
|
|
/* Otherwise compute new vectors and reset prev. back vectors. */
|
|
|
|
else {
|
|
computeBackVector(&recon_right_back,&recon_down_back);
|
|
|
|
}
|
|
|
|
/*
|
|
* Store vector existence flags in structure for possible skipped
|
|
* macroblocks to follow.
|
|
*/
|
|
|
|
bpict_past_forw = mb_motion_forw;
|
|
bpict_past_back = mb_motion_back;
|
|
}
|
|
}
|
|
int back;
|
|
back=reconstruct(recon_right_for,
|
|
recon_down_for,
|
|
recon_right_back,
|
|
recon_down_back,
|
|
mb_motion_forw,
|
|
mb_motion_back,
|
|
pictureArray);
|
|
|
|
|
|
/* If D Type picture, flush marker bit. */
|
|
if (code_type == D_TYPE) {
|
|
mpegVideoStream->flushBits(1);
|
|
}
|
|
|
|
/* If macroblock was intracoded, set macroblock past intra address. */
|
|
if (mb_intra) {
|
|
past_intra_addr=mb_address;
|
|
}
|
|
if (back == false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
int MacroBlock::resetMacroBlock() {
|
|
/* Reset past intrablock address. */
|
|
past_intra_addr = -2;
|
|
|
|
/* Reset previous recon motion vectors. */
|
|
|
|
|
|
recon_right_for_prev = 0;
|
|
recon_down_for_prev = 0;
|
|
recon_right_back_prev = 0;
|
|
recon_down_back_prev = 0;
|
|
|
|
/* Reset macroblock address. */
|
|
mb_address = (((vid_stream->slice)->getVertPos()-1) *
|
|
(vid_stream->mpegVideoHeader)->getMB_Width()) - 1;
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
int MacroBlock::resetPastMacroBlock() {
|
|
/* Reset past macroblock address field. */
|
|
|
|
past_mb_addr = -1;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
int MacroBlock::reconstruct(int& recon_right_for,
|
|
int& recon_down_for,
|
|
int& recon_right_back,
|
|
int& recon_down_back,
|
|
int& mb_motion_forw,
|
|
int& mb_motion_back,
|
|
PictureArray* pictureArray) {
|
|
int tqmask, i;
|
|
int zero_block_flag;
|
|
int mb_row;
|
|
int mb_col;
|
|
int mb_width=(vid_stream->mpegVideoHeader)->getMB_Width();
|
|
int row_size=pictureArray->getWidth();
|
|
short int* dct_start=(vid_stream->decoderClass)->getDCT();
|
|
unsigned int qscale=(vid_stream->slice)->getQuantScale();
|
|
int codeType=(vid_stream->picture)->getCodeType();
|
|
DecoderClass* decoderClass=vid_stream->decoderClass;
|
|
int lflag=false;
|
|
Recon* recon=vid_stream->recon;
|
|
unsigned int* iqmatrixptr=
|
|
(vid_stream->mpegVideoHeader)->getIntra_quant_matrix();
|
|
unsigned int* niqmatrixptr=
|
|
(vid_stream->mpegVideoHeader)->getNon_intra_quant_matrix();
|
|
|
|
|
|
|
|
|
|
|
|
if (mb_address-past_intra_addr > 1) {
|
|
lflag=true;
|
|
}
|
|
|
|
if (mb_width <= 0) {
|
|
DEBUG_MACROBLOCK(cout << "mb_width <= 0"<<endl;)
|
|
return false;
|
|
}
|
|
/* Calculate macroblock row and column from address. */
|
|
mb_row=mb_address / mb_width;
|
|
mb_col=mb_address % mb_width;
|
|
|
|
copyFunctions->startNOFloatSection();
|
|
|
|
for (tqmask = 32, i = 0; i < 6; tqmask >>= 1, i++) {
|
|
|
|
|
|
/* If block exists... */
|
|
if ((mb_intra) || (cbp & tqmask)) {
|
|
zero_block_flag = 0;
|
|
//copyFunctions->endNOFloatSection();
|
|
decoderClass->ParseReconBlock(i,mb_intra,
|
|
qscale,lflag,iqmatrixptr,niqmatrixptr);
|
|
//copyFunctions->endNOFloatSection();
|
|
} else {
|
|
zero_block_flag = 1;
|
|
}
|
|
|
|
|
|
// If macroblock is intra coded...
|
|
|
|
|
|
if (mb_intra) {
|
|
recon->ReconIMBlock(i,mb_row,mb_col,row_size,
|
|
dct_start,pictureArray);
|
|
//copyFunctions->endNOFloatSection();
|
|
} else if (mb_motion_forw && mb_motion_back) {
|
|
recon->ReconBiMBlock(i,recon_right_for,
|
|
recon_down_for,recon_right_back,
|
|
recon_down_back,zero_block_flag,
|
|
mb_row,mb_col,row_size,dct_start,
|
|
pictureArray);
|
|
//copyFunctions->endNOFloatSection();
|
|
} else if (mb_motion_forw || (codeType ==P_TYPE)){
|
|
recon->ReconPMBlock(i,recon_right_for,
|
|
recon_down_for,zero_block_flag,
|
|
mb_row,mb_col,row_size,dct_start,
|
|
pictureArray, codeType);
|
|
//copyFunctions->endNOFloatSection();
|
|
} else if (mb_motion_back) {
|
|
recon->ReconBMBlock(i,recon_right_back,
|
|
recon_down_back,zero_block_flag,
|
|
mb_row,mb_col,row_size,dct_start,
|
|
pictureArray);
|
|
//copyFunctions->endNOFloatSection();
|
|
|
|
} else {
|
|
//DEBUG_MACROBLOCK(cout << "nothing"<<endl;)
|
|
}
|
|
|
|
}
|
|
copyFunctions->endNOFloatSection();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ComputeForwVector --
|
|
*
|
|
* Computes forward motion vector by calling ComputeVector
|
|
* with appropriate parameters.
|
|
*
|
|
* Results:
|
|
* Reconstructed motion vector placed in recon_right_for_ptr and
|
|
* recon_down_for_ptr.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
void MacroBlock::computeForwVector(int* recon_right_for_ptr,
|
|
int* recon_down_for_ptr) {
|
|
|
|
Picture *picture;
|
|
|
|
|
|
picture = vid_stream->picture;
|
|
|
|
|
|
unsigned int forw_f=picture->getForw_f();
|
|
unsigned int full_pel_forw_vector=picture->getFull_pel_forw_vector();
|
|
vid_stream->motionVector->computeVector(recon_right_for_ptr,
|
|
recon_down_for_ptr,
|
|
recon_right_for_prev,
|
|
recon_down_for_prev,
|
|
forw_f,
|
|
full_pel_forw_vector,
|
|
motion_h_forw_code,
|
|
motion_v_forw_code,
|
|
motion_h_forw_r,
|
|
motion_v_forw_r);
|
|
picture->setForw_f(forw_f);
|
|
picture->setFull_pel_forw_vector(full_pel_forw_vector);
|
|
}
|
|
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ComputeBackVector --
|
|
*
|
|
* Computes backward motion vector by calling ComputeVector
|
|
* with appropriate parameters.
|
|
*
|
|
* Results:
|
|
* Reconstructed motion vector placed in recon_right_back_ptr and
|
|
* recon_down_back_ptr.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
void MacroBlock::computeBackVector(int* recon_right_back_ptr,
|
|
int* recon_down_back_ptr) {
|
|
|
|
Picture *picture;
|
|
|
|
|
|
picture = vid_stream->picture;
|
|
|
|
|
|
unsigned int back_f=picture->getBack_f();
|
|
unsigned int full_pel_back_vector=picture->getFull_pel_back_vector();
|
|
|
|
vid_stream->motionVector->computeVector(recon_right_back_ptr,
|
|
recon_down_back_ptr,
|
|
recon_right_back_prev,
|
|
recon_down_back_prev,
|
|
back_f,
|
|
full_pel_back_vector,
|
|
motion_h_back_code,
|
|
motion_v_back_code,
|
|
motion_h_back_r,
|
|
motion_v_back_r);
|
|
picture->setBack_f(back_f);
|
|
picture->setFull_pel_back_vector(full_pel_back_vector);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MacroBlock::processSkippedPictures(PictureArray* pictureArray,
|
|
int code_type,
|
|
int mb_width) {
|
|
copyFunctions->startNOFloatSection();
|
|
|
|
if (code_type == P_TYPE) {
|
|
|
|
ProcessSkippedPFrameMBlocks(pictureArray->getCurrent(),
|
|
pictureArray->getFuture(),
|
|
mb_width);
|
|
|
|
} else {
|
|
if (code_type == B_TYPE) {
|
|
ProcessSkippedBFrameMBlocks(vid_stream->picture,
|
|
pictureArray->getPast(),
|
|
pictureArray->getCurrent(),
|
|
pictureArray->getFuture(),
|
|
mb_width);
|
|
}
|
|
}
|
|
|
|
copyFunctions->endNOFloatSection();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ProcessSkippedPFrameMBlocks --
|
|
*
|
|
* Processes skipped macroblocks in P frames.
|
|
*
|
|
* Results:
|
|
* Calculates pixel values for luminance, Cr, and Cb planes
|
|
* in current pict image for skipped macroblocks.
|
|
*
|
|
* Side effects:
|
|
* Pixel values in pict image changed.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
void MacroBlock::ProcessSkippedPFrameMBlocks(YUVPicture* current,
|
|
YUVPicture* future,
|
|
int mb_width) {
|
|
|
|
int row_size, half_row, mb_row, mb_col, row, col, rr;
|
|
int addr, row_incr, half_row_incr, crow, ccol;
|
|
int *dest, *src, *dest1, *src1;
|
|
|
|
/* For each row in macroblock luminance plane... */
|
|
if (mb_width == 0) {
|
|
DEBUG_MACROBLOCK(cout << "mb_width in skipped is 0"<<endl;)
|
|
return;
|
|
}
|
|
|
|
|
|
/* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
|
|
|
|
row_size = mb_width << 4;
|
|
half_row = (row_size >> 1);
|
|
row_incr = row_size >> 2;
|
|
half_row_incr = half_row >> 2;
|
|
|
|
/* For each skipped macroblock, do... */
|
|
int lumEnd=current->getLumLength();
|
|
int colorEnd=current->getColorLength();
|
|
|
|
unsigned char *picDest;
|
|
unsigned char *picSrc;
|
|
|
|
unsigned char *picDestStart;
|
|
unsigned char *picSrcStart;
|
|
|
|
|
|
|
|
for (addr = past_mb_addr + 1; addr < mb_address; addr++) {
|
|
|
|
/* Calculate macroblock row and col. */
|
|
|
|
mb_row = addr / mb_width;
|
|
mb_col = addr % mb_width;
|
|
|
|
/* Calculate upper left pixel row,col for luminance plane. */
|
|
|
|
row = mb_row << 4;
|
|
col = mb_col << 4;
|
|
|
|
picDest=current->getLuminancePtr();
|
|
picSrc=future->getLuminancePtr();
|
|
|
|
picDestStart=(picDest+(row*row_size)+col);
|
|
picSrcStart=(picSrc+(row*row_size)+col);
|
|
|
|
if ((picDestStart+7*row_size+7 >= picDest+lumEnd) ||
|
|
(picDestStart < picDest)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -1"<<endl;)
|
|
break;
|
|
}
|
|
if ((picSrcStart+7*row_size+7 >= picSrc+lumEnd) ||
|
|
(picSrcStart < picSrc)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -2"<<endl;)
|
|
break;
|
|
}
|
|
|
|
dest=(int*)picDestStart;
|
|
src=(int*)picSrcStart;
|
|
|
|
|
|
|
|
for (rr = 0; rr < 8; rr++) {
|
|
|
|
/* Copy pixel values from last I or P picture. */
|
|
memcpy(dest,src,sizeof(int)*4);
|
|
|
|
dest += row_incr;
|
|
src += row_incr;
|
|
memcpy(dest,src,sizeof(int)*4);
|
|
|
|
dest += row_incr;
|
|
src += row_incr;
|
|
}
|
|
|
|
/*
|
|
* Divide row,col to get upper left pixel of macroblock in Cr and Cb
|
|
* planes.
|
|
*/
|
|
|
|
crow = row >> 1;
|
|
ccol = col >> 1;
|
|
|
|
/* For each row in Cr, and Cb planes... */
|
|
picDest=current->getCrPtr();
|
|
picDestStart=(picDest+(crow*half_row)+ccol);
|
|
if ((picDestStart+7*half_row_incr+7 >= picDest+colorEnd) ||
|
|
(picDestStart < picDest)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -3"<<endl;)
|
|
break;
|
|
}
|
|
|
|
|
|
dest=(int*)(current->getCrPtr()+(crow*half_row)+ccol);
|
|
src=(int*)(future->getCrPtr()+(crow*half_row)+ccol);
|
|
dest1=(int*)(current->getCbPtr()+(crow*half_row)+ccol);
|
|
src1=(int*)(future->getCbPtr()+(crow*half_row)+ccol);
|
|
|
|
for (rr = 0; rr < 4; rr++) {
|
|
|
|
/* Copy pixel values from last I or P picture. */
|
|
memcpy(dest,src,sizeof(int)*2);
|
|
memcpy(dest1,src1,sizeof(int)*2);
|
|
|
|
|
|
dest += half_row_incr;
|
|
src += half_row_incr;
|
|
dest1 += half_row_incr;
|
|
src1 += half_row_incr;
|
|
|
|
memcpy(dest,src,sizeof(int)*2);
|
|
memcpy(dest1,src1,sizeof(int)*2);
|
|
|
|
dest += half_row_incr;
|
|
src += half_row_incr;
|
|
dest1 += half_row_incr;
|
|
src1 += half_row_incr;
|
|
}
|
|
|
|
}
|
|
|
|
recon_right_for_prev = 0;
|
|
recon_down_for_prev = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ProcessSkippedBFrameMBlocks --
|
|
*
|
|
* Processes skipped macroblocks in B frames.
|
|
*
|
|
* Results:
|
|
* Calculates pixel values for luminance, Cr, and Cb planes
|
|
* in current pict image for skipped macroblocks.
|
|
*
|
|
* Side effects:
|
|
* Pixel values in pict image changed.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
void MacroBlock::ProcessSkippedBFrameMBlocks(Picture* picture,
|
|
YUVPicture* past,
|
|
YUVPicture* current,
|
|
YUVPicture* future,
|
|
int mb_width) {
|
|
int row_size, half_row, mb_row, mb_col, row, col, rr;
|
|
int right_half_for = 0, down_half_for = 0;
|
|
int c_right_half_for = 0, c_down_half_for = 0;
|
|
int right_half_back = 0, down_half_back = 0;
|
|
int c_right_half_back = 0, c_down_half_back = 0;
|
|
int addr, right_for = 0, down_for = 0;
|
|
int recon_right_for, recon_down_for;
|
|
int recon_right_back, recon_down_back;
|
|
int right_back = 0, down_back = 0;
|
|
int c_right_for = 0, c_down_for = 0;
|
|
int c_right_back = 0, c_down_back = 0;
|
|
unsigned char forw_lum[256];
|
|
unsigned char forw_cr[64], forw_cb[64];
|
|
unsigned char back_lum[256], back_cr[64], back_cb[64];
|
|
int row_incr, half_row_incr;
|
|
int ccol, crow;
|
|
|
|
|
|
/* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
|
|
|
|
if (mb_width == 0) {
|
|
DEBUG_MACROBLOCK(cout << "mb_width in skipped is 0 (2)"<<endl;)
|
|
return;
|
|
}
|
|
|
|
row_size = mb_width << 4;
|
|
half_row = (row_size >> 1);
|
|
row_incr = row_size >> 2;
|
|
half_row_incr = half_row >> 2;
|
|
|
|
/* Establish motion vector codes based on full pixel flag. */
|
|
|
|
if (picture->getFull_pel_forw_vector()) {
|
|
recon_right_for = recon_right_for_prev << 1;
|
|
recon_down_for = recon_down_for_prev << 1;
|
|
} else {
|
|
recon_right_for = recon_right_for_prev;
|
|
recon_down_for = recon_down_for_prev;
|
|
}
|
|
|
|
if (picture->getFull_pel_back_vector()) {
|
|
recon_right_back = recon_right_back_prev << 1;
|
|
recon_down_back = recon_down_back_prev << 1;
|
|
} else {
|
|
recon_right_back = recon_right_back_prev;
|
|
recon_down_back = recon_down_back_prev;
|
|
}
|
|
|
|
|
|
/* If only one motion vector, do display copy, else do full
|
|
calculation.
|
|
*/
|
|
|
|
/* Calculate motion vectors. */
|
|
|
|
if (bpict_past_forw) {
|
|
right_for = recon_right_for >> 1;
|
|
down_for = recon_down_for >> 1;
|
|
right_half_for = recon_right_for & 0x1;
|
|
down_half_for = recon_down_for & 0x1;
|
|
|
|
recon_right_for /= 2;
|
|
recon_down_for /= 2;
|
|
c_right_for = recon_right_for >> 1;
|
|
c_down_for = recon_down_for >> 1;
|
|
c_right_half_for = recon_right_for & 0x1;
|
|
c_down_half_for = recon_down_for & 0x1;
|
|
|
|
}
|
|
if (bpict_past_back) {
|
|
right_back = recon_right_back >> 1;
|
|
down_back = recon_down_back >> 1;
|
|
right_half_back = recon_right_back & 0x1;
|
|
down_half_back = recon_down_back & 0x1;
|
|
|
|
recon_right_back /= 2;
|
|
recon_down_back /= 2;
|
|
c_right_back = recon_right_back >> 1;
|
|
c_down_back = recon_down_back >> 1;
|
|
c_right_half_back = recon_right_back & 0x1;
|
|
c_down_half_back = recon_down_back & 0x1;
|
|
|
|
}
|
|
/* For each skipped macroblock, do... */
|
|
|
|
for (addr = past_mb_addr + 1;
|
|
addr < mb_address; addr++) {
|
|
|
|
/* Calculate macroblock row and col. */
|
|
|
|
mb_row = addr / mb_width;
|
|
mb_col = addr % mb_width;
|
|
|
|
/* Calculate upper left pixel row,col for luminance plane. */
|
|
|
|
row = mb_row << 4;
|
|
col = mb_col << 4;
|
|
crow = row / 2;
|
|
ccol = col / 2;
|
|
|
|
/* If forward predicted, calculate prediction values. */
|
|
if (bpict_past_forw) {
|
|
int lumEnd=current->getLumLength();
|
|
int colorEnd=current->getColorLength();
|
|
ReconSkippedBlock(past->getLuminancePtr(),
|
|
forw_lum,row,col,row_size,
|
|
right_for,down_for,
|
|
right_half_for,
|
|
down_half_for,16,lumEnd);
|
|
ReconSkippedBlock(past->getCrPtr(),
|
|
forw_cr,crow,ccol, half_row,
|
|
c_right_for,c_down_for,
|
|
c_right_half_for,
|
|
c_down_half_for,8,colorEnd);
|
|
ReconSkippedBlock(past->getCbPtr(),
|
|
forw_cb,crow,ccol,half_row,
|
|
c_right_for,c_down_for,
|
|
c_right_half_for,
|
|
c_down_half_for,8,colorEnd);
|
|
}
|
|
/* If back predicted, calculate prediction values. */
|
|
|
|
if (bpict_past_back) {
|
|
int lumEnd=current->getLumLength();
|
|
int colorEnd=current->getColorLength();
|
|
ReconSkippedBlock(future->getLuminancePtr(),
|
|
back_lum,row,col,row_size,
|
|
right_back,down_back,
|
|
right_half_back,down_half_back,
|
|
16,lumEnd);
|
|
ReconSkippedBlock(future->getCrPtr(),
|
|
back_cr,crow,ccol,
|
|
half_row,c_right_back,
|
|
c_down_back,c_right_half_back,
|
|
c_down_half_back,8,colorEnd);
|
|
ReconSkippedBlock(future->getCbPtr(),
|
|
back_cb,crow,ccol,half_row,
|
|
c_right_back,c_down_back,
|
|
c_right_half_back,
|
|
c_down_half_back,8,colorEnd);
|
|
}
|
|
unsigned char* picDest=current->getLuminancePtr();
|
|
int lumEnd=current->getLumLength();
|
|
int colorEnd=current->getColorLength();
|
|
|
|
unsigned char* picDestStart=(picDest+(row*row_size)+col);
|
|
|
|
|
|
if ((picDestStart+7*row_size+7 >= picDest+lumEnd) ||
|
|
(picDestStart < picDest)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -4"<<endl;)
|
|
return;
|
|
}
|
|
|
|
picDest=current->getCrPtr();
|
|
picDestStart=(picDest+(crow*half_row)+ccol);
|
|
if ((picDestStart+7*half_row_incr+7 >= picDest+colorEnd) ||
|
|
(picDestStart < picDest)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -5"<<endl;)
|
|
exit(0);
|
|
}
|
|
|
|
|
|
if (bpict_past_forw && !bpict_past_back) {
|
|
|
|
int *dest, *dest1;
|
|
int *src, *src1;
|
|
dest=(int*)(current->getLuminancePtr()+(row*row_size)+col);
|
|
src=(int*)forw_lum;
|
|
|
|
for (rr = 0; rr < 16; rr++) {
|
|
|
|
/* memcpy(dest, forw_lum+(rr<<4), 16); */
|
|
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest[3] = src[3];
|
|
dest += row_incr;
|
|
src += 4;
|
|
}
|
|
|
|
dest = (int*)(current->getCrPtr()+(crow*half_row)+ccol);
|
|
dest1 = (int*)(current->getCbPtr()+(crow*half_row)+ccol);
|
|
src = (int*)forw_cr;
|
|
src1 = (int*)forw_cb;
|
|
|
|
for (rr = 0; rr < 8; rr++) {
|
|
/*
|
|
* memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3),
|
|
* 8);
|
|
*/
|
|
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
|
|
dest1[0] = src1[0];
|
|
dest1[1] = src1[1];
|
|
|
|
dest += half_row_incr;
|
|
dest1 += half_row_incr;
|
|
src += 2;
|
|
src1 += 2;
|
|
}
|
|
} else if (bpict_past_back && !bpict_past_forw) {
|
|
|
|
int *src, *src1;
|
|
int *dest, *dest1;
|
|
dest=(int*)(current->getLuminancePtr()+(row*row_size)+col);
|
|
src = (int*)back_lum;
|
|
|
|
for (rr = 0; rr < 16; rr++) {
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest[3] = src[3];
|
|
dest += row_incr;
|
|
src += 4;
|
|
}
|
|
|
|
|
|
dest = (int *)(current->getCrPtr()+(crow*half_row)+ccol);
|
|
dest1 = (int *)(current->getCbPtr()+(crow*half_row)+ccol);
|
|
src = (int *)back_cr;
|
|
src1 = (int *)back_cb;
|
|
|
|
for (rr = 0; rr < 8; rr++) {
|
|
/*
|
|
* memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3),
|
|
* 8);
|
|
*/
|
|
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
|
|
dest1[0] = src1[0];
|
|
dest1[1] = src1[1];
|
|
|
|
dest += half_row_incr;
|
|
dest1 += half_row_incr;
|
|
src += 2;
|
|
src1 += 2;
|
|
}
|
|
} else {
|
|
|
|
unsigned char *src1, *src2, *src1a, *src2a;
|
|
unsigned char *dest, *dest1;
|
|
dest = current->getLuminancePtr()+(row*row_size)+col;
|
|
src1 = forw_lum;
|
|
src2 = back_lum;
|
|
|
|
for (rr = 0; rr < 16; rr++) {
|
|
dest[0] = (int) (src1[0] + src2[0]) >> 1;
|
|
dest[1] = (int) (src1[1] + src2[1]) >> 1;
|
|
dest[2] = (int) (src1[2] + src2[2]) >> 1;
|
|
dest[3] = (int) (src1[3] + src2[3]) >> 1;
|
|
dest[4] = (int) (src1[4] + src2[4]) >> 1;
|
|
dest[5] = (int) (src1[5] + src2[5]) >> 1;
|
|
dest[6] = (int) (src1[6] + src2[6]) >> 1;
|
|
dest[7] = (int) (src1[7] + src2[7]) >> 1;
|
|
dest[8] = (int) (src1[8] + src2[8]) >> 1;
|
|
dest[9] = (int) (src1[9] + src2[9]) >> 1;
|
|
dest[10] = (int) (src1[10] + src2[10]) >> 1;
|
|
dest[11] = (int) (src1[11] + src2[11]) >> 1;
|
|
dest[12] = (int) (src1[12] + src2[12]) >> 1;
|
|
dest[13] = (int) (src1[13] + src2[13]) >> 1;
|
|
dest[14] = (int) (src1[14] + src2[14]) >> 1;
|
|
dest[15] = (int) (src1[15] + src2[15]) >> 1;
|
|
dest += row_size;
|
|
src1 += 16;
|
|
src2 += 16;
|
|
}
|
|
|
|
|
|
dest = current->getCrPtr() + (crow * half_row) + ccol;
|
|
dest1 = current->getCbPtr() + (crow * half_row) + ccol;
|
|
src1 = forw_cr;
|
|
src2 = back_cr;
|
|
src1a = forw_cb;
|
|
src2a = back_cb;
|
|
|
|
for (rr = 0; rr < 8; rr++) {
|
|
dest[0] = (int) (src1[0] + src2[0]) >> 1;
|
|
dest[1] = (int) (src1[1] + src2[1]) >> 1;
|
|
dest[2] = (int) (src1[2] + src2[2]) >> 1;
|
|
dest[3] = (int) (src1[3] + src2[3]) >> 1;
|
|
dest[4] = (int) (src1[4] + src2[4]) >> 1;
|
|
dest[5] = (int) (src1[5] + src2[5]) >> 1;
|
|
dest[6] = (int) (src1[6] + src2[6]) >> 1;
|
|
dest[7] = (int) (src1[7] + src2[7]) >> 1;
|
|
dest += half_row;
|
|
src1 += 8;
|
|
src2 += 8;
|
|
|
|
dest1[0] = (int) (src1a[0] + src2a[0]) >> 1;
|
|
dest1[1] = (int) (src1a[1] + src2a[1]) >> 1;
|
|
dest1[2] = (int) (src1a[2] + src2a[2]) >> 1;
|
|
dest1[3] = (int) (src1a[3] + src2a[3]) >> 1;
|
|
dest1[4] = (int) (src1a[4] + src2a[4]) >> 1;
|
|
dest1[5] = (int) (src1a[5] + src2a[5]) >> 1;
|
|
dest1[6] = (int) (src1a[6] + src2a[6]) >> 1;
|
|
dest1[7] = (int) (src1a[7] + src2a[7]) >> 1;
|
|
dest1 += half_row;
|
|
src1a += 8;
|
|
src2a += 8;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* ReconSkippedBlock --
|
|
*
|
|
* Reconstructs predictive block for skipped macroblocks
|
|
* in B Frames.
|
|
*
|
|
* Results:
|
|
* No return values.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
void MacroBlock::ReconSkippedBlock(unsigned char* source,
|
|
unsigned char* dest,
|
|
int row,
|
|
int col,
|
|
int row_size,
|
|
int right,
|
|
int down,
|
|
int right_half,
|
|
int down_half,
|
|
int width,int maxLen) {
|
|
int rr;
|
|
unsigned char *source2;
|
|
unsigned char *tmp;
|
|
|
|
tmp = source+((row + down) * row_size) + col + right;
|
|
|
|
|
|
if ((tmp+7*row_size+7 >= source+maxLen) ||
|
|
(tmp < source)) {
|
|
DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -6"<<endl;)
|
|
return;
|
|
}
|
|
|
|
source=tmp;
|
|
if (width == 16) {
|
|
if ((!right_half) && (!down_half)) {
|
|
if (right & 0x1) {
|
|
/* No tqalignment, use bye copy */
|
|
for (rr = 0; rr < 16; rr++) {
|
|
|
|
memcpy(dest,source,sizeof(char)*16);
|
|
|
|
dest += 16;
|
|
source += row_size;
|
|
}
|
|
} else if (right & 0x2) {
|
|
/* Half-word bit aligned, use 16 bit copy */
|
|
short *src = (short *)source;
|
|
short *d = (short *)dest;
|
|
row_size >>= 1;
|
|
for (rr = 0; rr < 16; rr++) {
|
|
|
|
memcpy(d,src,sizeof(short)*8);
|
|
|
|
d += 8;
|
|
src += row_size;
|
|
}
|
|
} else {
|
|
/* Word aligned, use 32 bit copy */
|
|
int *src = (int *)source;
|
|
int *d = (int *)dest;
|
|
row_size >>= 2;
|
|
for (rr = 0; rr < 16; rr++) {
|
|
d[0] = src[0];
|
|
d[1] = src[1];
|
|
d[2] = src[2];
|
|
d[3] = src[3];
|
|
d += 4;
|
|
src += row_size;
|
|
}
|
|
}
|
|
} else {
|
|
source2 = source + right_half + (row_size * down_half);
|
|
copyFunctions->copy16_div2_destlinear_nocrop(source,source2,dest,
|
|
row_size);
|
|
|
|
|
|
}
|
|
} else { /* (width == 8) */
|
|
assert(width == 8);
|
|
if ((!right_half) && (!down_half)) {
|
|
if (right & 0x1) {
|
|
for (rr = 0; rr < width; rr++) {
|
|
|
|
memcpy(dest,source,sizeof(char)*8);
|
|
|
|
dest += 8;
|
|
source += row_size;
|
|
}
|
|
} else if (right & 0x02) {
|
|
short *d = (short *)dest;
|
|
short *src = (short *)source;
|
|
row_size >>= 1;
|
|
for (rr = 0; rr < width; rr++) {
|
|
d[0] = src[0];
|
|
d[1] = src[1];
|
|
d[2] = src[2];
|
|
d[3] = src[3];
|
|
d += 4;
|
|
src += row_size;
|
|
}
|
|
} else {
|
|
int *d = (int *)dest;
|
|
int *src = (int *)source;
|
|
row_size >>= 2;
|
|
for (rr = 0; rr < width; rr++) {
|
|
d[0] = src[0];
|
|
d[1] = src[1];
|
|
d += 2;
|
|
src += row_size;
|
|
}
|
|
}
|
|
} else {
|
|
source2 = source + right_half + (row_size * down_half);
|
|
copyFunctions->copy8_div2_destlinear_nocrop(source,source2,
|
|
dest,row_size);
|
|
}
|
|
}
|
|
}
|
|
|