/*===========================================================================* * block.c * * * * Block routines * * * * EXPORTED PROCEDURES: * * ComputeDiffDCTBlock * * ComputeDiffDCTs * * ComputeMotionBlock * * ComputeMotionLumBlock * * LumBlockMAD * * LumMotionError * * LumMotionErrorSubSampled * * LumAddMotionError * * AddMotionBlock * * BlockToData * * BlockifyFrame * * * * NOTES: MAD = Mean Absolute Difference * * * *===========================================================================*/ /* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* * $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/block.c,v 1.16 1995/08/07 21:43:29 smoot Exp $ * $Log: block.c,v $ * Revision 1.16 1995/08/07 21:43:29 smoot * restructured lumdiff so it read better and used a switch instead of ifs * * Revision 1.15 1995/06/21 22:21:16 smoot * added TUNEing options * * Revision 1.14 1995/05/08 22:47:45 smoot * typechecking better * * Revision 1.13 1995/05/08 22:44:14 smoot * added prototypes (postdct.h) * * Revision 1.12 1995/05/02 21:44:07 smoot * added tuneing parameters * * Revision 1.11 1995/03/31 23:50:45 smoot * removed block bound (moved to opts.c) * * Revision 1.10 1995/03/29 20:12:39 smoot * added block_bound for TUNEing * * Revision 1.9 1995/02/01 21:43:55 smoot * cleanup * * Revision 1.8 1995/01/19 23:52:43 smoot * Made computeDiffDCTs able to rule out changes to the pattern (diff too small) * * Revision 1.7 1995/01/19 23:07:17 eyhung * Changed copyrights * * Revision 1.6 1994/11/12 02:11:44 keving * nothing * * Revision 1.5 1993/12/22 19:19:01 keving * nothing * * Revision 1.5 1993/12/22 19:19:01 keving * nothing * * Revision 1.4 1993/07/22 22:23:43 keving * nothing * * Revision 1.3 1993/06/30 20:06:09 keving * nothing * * Revision 1.2 1993/06/03 21:08:08 keving * nothing * * Revision 1.1 1993/04/08 21:31:59 keving * nothing * */ /*==============* * HEADER FILES * *==============*/ #include "all.h" #include "mtypes.h" #include "frames.h" #include "bitio.h" #include "prototypes.h" #include "fsize.h" #include "opts.h" #include "postdct.h" #undef ABS #define ABS(x) ((x < 0) ? (-x) : x) #define TRUNCATE_UINT8(x) ((x < 0) ? 0 : ((x > 255) ? 255 : x)) /*==================* * GLOBAL VARIABLES * *==================*/ extern Block **dct, **dctb, **dctr; /*===========================* * COMPUTE DCT OF DIFFERENCE * *===========================*/ /*===========================================================================* * * ComputeDiffDCTBlock * * compute current-motionBlock, take the DCT, and put the difference * back into current * * RETURNS: current block modified * * SIDE EFFECTS: none * *===========================================================================*/ boolean ComputeDiffDCTBlock(current, dest, motionBlock) Block current, dest, motionBlock; { register int x, y, diff = 0; for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { current[y][x] -= motionBlock[y][x]; diff += ABS(current[y][x]); } } /* Kill the block if change is too small */ /* (block_bound defaults to 128, see opts.c) */ if (diff < block_bound) return FALSE; mp_fwd_dct_block2(current, dest); return TRUE; } /*===========================================================================* * * ComputeDiffDCTs * * appropriate (according to pattern, the coded block pattern) blocks * of 'current' are diff'ed and DCT'd. * * RETURNS: current blocks modified * * SIDE EFFECTS: Can remove too-small difference blocks from pattern * * PRECONDITIONS: appropriate blocks of 'current' have not yet been * modified * *===========================================================================*/ void ComputeDiffDCTs(current, prev, by, bx, my, mx, pattern) MpegFrame *current; MpegFrame *prev; int by; int bx; int my; int mx; int *pattern; { Block motionBlock; if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n"); if ( *pattern & 0x20 ) { ComputeMotionBlock(prev->ref_y, by, bx, my, mx, motionBlock); if (!ComputeDiffDCTBlock(current->y_blocks[by][bx], dct[by][bx], motionBlock)) *pattern^=0x20; } if ( *pattern & 0x10 ) { ComputeMotionBlock(prev->ref_y, by, bx+1, my, mx, motionBlock); if (!ComputeDiffDCTBlock(current->y_blocks[by][bx+1], dct[by][bx+1], motionBlock)) *pattern^=0x10; } if ( *pattern & 0x8 ) { ComputeMotionBlock(prev->ref_y, by+1, bx, my, mx, motionBlock); if (!ComputeDiffDCTBlock(current->y_blocks[by+1][bx], dct[by+1][bx], motionBlock)) *pattern^=0x8; } if ( *pattern & 0x4 ) { ComputeMotionBlock(prev->ref_y, by+1, bx+1, my, mx, motionBlock); if (!ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], dct[by+1][bx+1], motionBlock)) *pattern^=0x4; } if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n"); if ( *pattern & 0x2 ) { ComputeMotionBlock(prev->ref_cb, by >> 1, bx >> 1, my/2, mx/2, motionBlock); if (!ComputeDiffDCTBlock(current->cb_blocks[by >> 1][bx >> 1], dctb[by >> 1][bx >> 1], motionBlock)) *pattern^=0x2; } if ( *pattern & 0x1 ) { ComputeMotionBlock(prev->ref_cr, by >> 1, bx >> 1, my/2, mx/2, motionBlock); if (!ComputeDiffDCTBlock(current->cr_blocks[by >> 1][bx >> 1], dctr[by >> 1][bx >> 1], motionBlock)) *pattern^=0x1; } } /*======================* * COMPUTE MOTION BLOCK * *======================*/ /*===========================================================================* * * ComputeMotionBlock * * compute the motion-compensated block * * RETURNS: motionBlock * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * * NOTE: could try to speed this up using halfX, halfY, halfBoth, * but then would have to compute for chrominance, and it's just * not worth the trouble (this procedure is not called relatively * often -- a constant number of times per macroblock) * *===========================================================================*/ void ComputeMotionBlock(prev, by, bx, my, mx, motionBlock) uint8 **prev; int by; int bx; int my; int mx; Block motionBlock; { register int fy, fx; register int y; register int16 *destPtr; register uint8 *srcPtr; register uint8 *srcPtr2; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, (my/2), (mx/2), fy, fx); if ( xHalf && yHalf ) { /* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and (fy-1)+y+1 = fy+y */ if ( my < 0 ) { fy--; } if ( mx < 0 ) { fx--; } for ( y = 0; y < 8; y++ ) { destPtr = motionBlock[y]; srcPtr = &(prev[fy+y][fx]); srcPtr2 = &(prev[fy+y+1][fx]); destPtr[0] = (srcPtr[0]+srcPtr[1]+srcPtr2[0]+srcPtr2[1]+2)>>2; destPtr[1] = (srcPtr[1]+srcPtr[2]+srcPtr2[1]+srcPtr2[2]+2)>>2; destPtr[2] = (srcPtr[2]+srcPtr[3]+srcPtr2[2]+srcPtr2[3]+2)>>2; destPtr[3] = (srcPtr[3]+srcPtr[4]+srcPtr2[3]+srcPtr2[4]+2)>>2; destPtr[4] = (srcPtr[4]+srcPtr[5]+srcPtr2[4]+srcPtr2[5]+2)>>2; destPtr[5] = (srcPtr[5]+srcPtr[6]+srcPtr2[5]+srcPtr2[6]+2)>>2; destPtr[6] = (srcPtr[6]+srcPtr[7]+srcPtr2[6]+srcPtr2[7]+2)>>2; destPtr[7] = (srcPtr[7]+srcPtr[8]+srcPtr2[7]+srcPtr2[8]+2)>>2; } } else if ( xHalf ) { if ( mx < 0 ) { fx--; } for ( y = 0; y < 8; y++ ) { destPtr = motionBlock[y]; srcPtr = &(prev[fy+y][fx]); destPtr[0] = (srcPtr[0]+srcPtr[1]+1)>>1; destPtr[1] = (srcPtr[1]+srcPtr[2]+1)>>1; destPtr[2] = (srcPtr[2]+srcPtr[3]+1)>>1; destPtr[3] = (srcPtr[3]+srcPtr[4]+1)>>1; destPtr[4] = (srcPtr[4]+srcPtr[5]+1)>>1; destPtr[5] = (srcPtr[5]+srcPtr[6]+1)>>1; destPtr[6] = (srcPtr[6]+srcPtr[7]+1)>>1; destPtr[7] = (srcPtr[7]+srcPtr[8]+1)>>1; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } for ( y = 0; y < 8; y++ ) { destPtr = motionBlock[y]; srcPtr = &(prev[fy+y][fx]); srcPtr2 = &(prev[fy+y+1][fx]); destPtr[0] = (srcPtr[0]+srcPtr2[0]+1)>>1; destPtr[1] = (srcPtr[1]+srcPtr2[1]+1)>>1; destPtr[2] = (srcPtr[2]+srcPtr2[2]+1)>>1; destPtr[3] = (srcPtr[3]+srcPtr2[3]+1)>>1; destPtr[4] = (srcPtr[4]+srcPtr2[4]+1)>>1; destPtr[5] = (srcPtr[5]+srcPtr2[5]+1)>>1; destPtr[6] = (srcPtr[6]+srcPtr2[6]+1)>>1; destPtr[7] = (srcPtr[7]+srcPtr2[7]+1)>>1; } } else { for ( y = 0; y < 8; y++ ) { destPtr = motionBlock[y]; srcPtr = &(prev[fy+y][fx]); destPtr[0] = (uint8) srcPtr[0]; destPtr[1] = (uint8) srcPtr[1]; destPtr[2] = (uint8) srcPtr[2]; destPtr[3] = (uint8) srcPtr[3]; destPtr[4] = (uint8) srcPtr[4]; destPtr[5] = (uint8) srcPtr[5]; destPtr[6] = (uint8) srcPtr[6]; destPtr[7] = (uint8) srcPtr[7]; } } } /*===========================================================================* * * ComputeMotionLumBlock * * compute the motion-compensated luminance block * * RETURNS: motionBlock * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * * NOTE: see ComputeMotionBlock * *===========================================================================*/ void ComputeMotionLumBlock(prevFrame, by, bx, my, mx, motionBlock) MpegFrame *prevFrame; int by; int bx; int my; int mx; LumBlock motionBlock; { register uint8 *across; register int32 *macross; register int y; uint8 **prev; int fy, fx; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx); if ( xHalf ) { if ( mx < 0 ) { fx--; } if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfBoth; } else { prev = prevFrame->halfX; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfY; } else { prev = prevFrame->ref_y; } for ( y = 0; y < 16; y++ ) { across = &(prev[fy+y][fx]); macross = motionBlock[y]; macross[0] = across[0]; macross[1] = across[1]; macross[2] = across[2]; macross[3] = across[3]; macross[4] = across[4]; macross[5] = across[5]; macross[6] = across[6]; macross[7] = across[7]; macross[8] = across[8]; macross[9] = across[9]; macross[10] = across[10]; macross[11] = across[11]; macross[12] = across[12]; macross[13]= across[13]; macross[14] = across[14]; macross[15] = across[15]; } /* this is what's really happening, in slow motion: * * for ( y = 0; y < 16; y++, py++ ) * for ( x = 0; x < 16; x++, px++ ) * motionBlock[y][x] = prev[fy+y][fx+x]; * */ } /*=======================* * BASIC ERROR FUNCTIONS * *=======================*/ /*===========================================================================* * * LumBlockMAD * * return the MAD of two luminance blocks * * RETURNS: the MAD, if less than bestSoFar, or * some number bigger if not * * SIDE EFFECTS: none * *===========================================================================*/ int32 LumBlockMAD(currentBlock, motionBlock, bestSoFar) LumBlock currentBlock; LumBlock motionBlock; int32 bestSoFar; { register int32 diff = 0; /* max value of diff is 255*256 = 65280 */ register int32 localDiff; register int y, x; for ( y = 0; y < 16; y++ ) { for ( x = 0; x < 16; x++ ) { localDiff = currentBlock[y][x] - motionBlock[y][x]; diff += ABS(localDiff); } if ( diff > bestSoFar ) { return diff; } } return (int32)diff; } /*===========================================================================* * * LumMotionError * * return the MAD of the currentBlock and the motion-compensated block * (without TUNEing) * * RETURNS: the MAD, if less than bestSoFar, or * some number bigger if not * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * * NOTES: this is the procedure that is called the most, and should therefore * be the most optimized!!! * *===========================================================================*/ int32 LumMotionError(currentBlock, prevFrame, by, bx, my, mx, bestSoFar) LumBlock currentBlock; MpegFrame *prevFrame; int by; int bx; int my; int mx; int32 bestSoFar; { register int32 adiff = 0, diff = 0; /* max value of diff is 255*256 = 65280 */ register int32 localDiff; register uint8 *across; register int32 *cacross; register int y; uint8 **prev; int fy, fx; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx); if ( xHalf ) { if ( mx < 0 ) { fx--; } if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfBoth; } else { prev = prevFrame->halfX; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfY; } else { prev = prevFrame->ref_y; } switch (SearchCompareMode) { case DEFAULT_SEARCH: /* Default. */ /* this is what's happening: * ComputeMotionLumBlock(prevFrame, by, bx, my, mx, lumMotionBlock); * for ( y = 0; y < 16; y++ ) * for ( x = 0; x < 16; x++ ) * { * localDiff = currentBlock[y][x] - lumMotionBlock[y][x]; * diff += ABS(localDiff); * } */ for ( y = 0; y < 16; y++ ) { across = &(prev[fy+y][fx]); cacross = currentBlock[y]; localDiff = across[0]-cacross[0]; diff += ABS(localDiff); localDiff = across[1]-cacross[1]; diff += ABS(localDiff); localDiff = across[2]-cacross[2]; diff += ABS(localDiff); localDiff = across[3]-cacross[3]; diff += ABS(localDiff); localDiff = across[4]-cacross[4]; diff += ABS(localDiff); localDiff = across[5]-cacross[5]; diff += ABS(localDiff); localDiff = across[6]-cacross[6]; diff += ABS(localDiff); localDiff = across[7]-cacross[7]; diff += ABS(localDiff); localDiff = across[8]-cacross[8]; diff += ABS(localDiff); localDiff = across[9]-cacross[9]; diff += ABS(localDiff); localDiff = across[10]-cacross[10]; diff += ABS(localDiff); localDiff = across[11]-cacross[11]; diff += ABS(localDiff); localDiff = across[12]-cacross[12]; diff += ABS(localDiff); localDiff = across[13]-cacross[13]; diff += ABS(localDiff); localDiff = across[14]-cacross[14]; diff += ABS(localDiff); localDiff = across[15]-cacross[15]; diff += ABS(localDiff); if ( diff > bestSoFar ) { return diff; } } break; case LOCAL_DCT: { Block dctdiff[4], dctquant[4]; FlatBlock quant; int x, i, tmp; int distortion=0, datarate=0; int pq = GetPQScale(); for (y = 0; y < 16; y++) { across = &(prev[fy+y][fx]); cacross = currentBlock[y]; for (x = 0; x < 16; x++) { dctdiff[(x>7)+2*(y>7)][y%8][x%8] = cacross[x]-across[x]; }} /* Calculate rate */ for (i = 0; i < 4; i++) { mp_fwd_dct_block2(dctdiff[i], dctdiff[i]); if (Mpost_QuantZigBlock(dctdiff[i], quant, pq, FALSE) == MPOST_ZERO) { /* no sense in continuing */ memset((char *)dctquant[i], 0, sizeof(Block)); } else { Mpost_UnQuantZigBlock(quant, dctquant[i], pq, FALSE); mpeg_jrevdct((int16 *)dctquant[i]); datarate += CalcRLEHuffLength(quant); } } /* Calculate distortion */ for (y = 0; y < 16; y++) { across = &(prev[fy+y][fx]); cacross = currentBlock[y]; for (x = 0; x < 16; x++) { tmp = across[x] - cacross[x] + dctquant[(x>7)+2*(y>7)][y%8][x%8]; distortion += tmp*tmp; }} distortion /= 256; distortion *= LocalDCTDistortScale; datarate *= LocalDCTRateScale; diff = (int) sqrt(distortion*distortion + datarate*datarate); break; } case NO_DC_SEARCH: { extern int32 niqtable[]; int pq = niqtable[0]*GetPQScale(); for ( y = 0; y < 16; y++ ) { across = &(prev[fy+y][fx]); cacross = currentBlock[y]; localDiff = across[0]-cacross[0]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[1]-cacross[1]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[2]-cacross[2]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[3]-cacross[3]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[4]-cacross[4]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[5]-cacross[5]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[6]-cacross[6]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[7]-cacross[7]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[8]-cacross[8]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[9]-cacross[9]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[10]-cacross[10]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[11]-cacross[11]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[12]-cacross[12]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[13]-cacross[13]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[14]-cacross[14]; diff += localDiff; adiff += ABS(localDiff); localDiff = across[15]-cacross[15]; diff += localDiff; adiff += ABS(localDiff); } diff /= 64*pq; /* diff is now the DC difference (with QSCALE 1) */ adiff -= 64*pq*ABS(diff); diff = adiff; } break; case DO_Mean_Squared_Distortion: for ( y = 0; y < 16; y++ ) { across = &(prev[fy+y][fx]); cacross = currentBlock[y]; localDiff = across[0]-cacross[0]; diff += localDiff*localDiff; localDiff = across[1]-cacross[1]; diff += localDiff*localDiff; localDiff = across[2]-cacross[2]; diff += localDiff*localDiff; localDiff = across[3]-cacross[3]; diff += localDiff*localDiff; localDiff = across[4]-cacross[4]; diff += localDiff*localDiff; localDiff = across[5]-cacross[5]; diff += localDiff*localDiff; localDiff = across[6]-cacross[6]; diff += localDiff*localDiff; localDiff = across[7]-cacross[7]; diff += localDiff*localDiff; localDiff = across[8]-cacross[8]; diff += localDiff*localDiff; localDiff = across[9]-cacross[9]; diff += localDiff*localDiff; localDiff = across[10]-cacross[10]; diff += localDiff*localDiff; localDiff = across[11]-cacross[11]; diff += localDiff*localDiff; localDiff = across[12]-cacross[12]; diff += localDiff*localDiff; localDiff = across[13]-cacross[13]; diff += localDiff*localDiff; localDiff = across[14]-cacross[14]; diff += localDiff*localDiff; localDiff = across[15]-cacross[15]; diff += localDiff*localDiff; if ( diff > bestSoFar ) { return diff; } } break; } /* End of Switch */ return diff; } /*===========================================================================* * * LumAddMotionError * * return the MAD of the currentBlock and the average of the blockSoFar * and the motion-compensated block (this is used for B-frame searches) * * RETURNS: the MAD, if less than bestSoFar, or * some number bigger if not * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * *===========================================================================*/ int32 LumAddMotionError(currentBlock, blockSoFar, prevFrame, by, bx, my, mx, bestSoFar) LumBlock currentBlock; LumBlock blockSoFar; MpegFrame *prevFrame; int by; int bx; int my; int mx; int32 bestSoFar; { register int32 diff = 0; /* max value of diff is 255*256 = 65280 */ register int32 localDiff; register uint8 *across; register int32 *bacross; register int32 *cacross; register int y; uint8 **prev; int fy, fx; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx); if ( xHalf ) { if ( mx < 0 ) { fx--; } if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfBoth; } else { prev = prevFrame->halfX; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfY; } else { prev = prevFrame->ref_y; } /* do we add 1 before dividing by two? Yes -- see MPEG-1 doc page 46 */ #define ADD_ADD_DIFF(d,l,a,b,c,i) \ l = ((a[i]+b[i]+1)>>1)-c[i]; \ d += ABS(l) for ( y = 0; y < 16; y++ ) { across = &(prev[fy+y][fx]); bacross = blockSoFar[y]; cacross = currentBlock[y]; ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,0); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,1); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,2); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,3); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,4); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,5); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,6); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,7); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,8); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,9); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,10); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,11); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,12); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,13); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,14); ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,15); if ( diff > bestSoFar ) { return diff; } } /* this is what's happening: * * ComputeMotionLumBlock(prevFrame, by, bx, my, mx, lumMotionBlock); * * for ( y = 0; y < 16; y++ ) * for ( x = 0; x < 16; x++ ) * { * localDiff = currentBlock[y][x] - lumMotionBlock[y][x]; * diff += ABS(localDiff); * } * */ return diff; } /*===========================================================================* * * AddMotionBlock * * adds the motion-compensated block to the given block * * RETURNS: block modified * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * *===========================================================================*/ void AddMotionBlock(block, prev, by, bx, my, mx) Block block; uint8 **prev; int by; int bx; int my; int mx; { int fy, fx; int x, y; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, (my/2), (mx/2), fy, fx); if ( xHalf && yHalf ) { /* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and (fy-1)+y+1 = fy+y */ if ( my < 0 ) { fy--; } if ( mx < 0 ) { fx--; } for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+ prev[fy+y+1][fx+x]+prev[fy+y+1][fx+x+1]+2)>>2; } } } else if ( xHalf ) { if ( mx < 0 ) { fx--; } for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+1)>>1; } } } else if ( yHalf ) { if ( my < 0 ) { fy--; } for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { block[y][x] += (prev[fy+y][fx+x]+prev[fy+y+1][fx+x]+1)>>1; } } } else { for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { block[y][x] += (int16)prev[fy+y][fx+x]; } } } } /*===========================================================================* * * AddBMotionBlock * * adds the motion-compensated B-frame block to the given block * * RETURNS: block modified * * SIDE EFFECTS: none * * PRECONDITIONS: motion vectors MUST be valid * *===========================================================================*/ void AddBMotionBlock(block, prev, next, by, bx, mode, fmy, fmx, bmy, bmx) Block block; uint8 **prev; uint8 **next; int by; int bx; int mode; int fmy; int fmx; int bmy; int bmx; { int x, y; Block prevBlock, nextBlock; if ( mode == MOTION_FORWARD ) { AddMotionBlock(block, prev, by, bx, fmy, fmx); } else if ( mode == MOTION_BACKWARD ) { AddMotionBlock(block, next, by, bx, bmy, bmx); } else { ComputeMotionBlock(prev, by, bx, fmy, fmx, prevBlock); ComputeMotionBlock(next, by, bx, bmy, bmx, nextBlock); for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { block[y][x] += (prevBlock[y][x]+nextBlock[y][x]+1)/2; } } } } /*===========================================================================* * * BlockToData * * copies the given block into the appropriate data area * * RETURNS: data modified * * SIDE EFFECTS: none * *===========================================================================*/ void BlockToData(data, block, by, bx) uint8 **data; Block block; int by; int bx; { register int x, y; register int fy, fx; register int16 blockItem; BLOCK_TO_FRAME_COORD(by, bx, fy, fx); for ( y = 0; y < 8; y++ ) { for ( x = 0; x < 8; x++ ) { blockItem = block[y][x]; data[fy+y][fx+x] = TRUNCATE_UINT8(blockItem); } } } /*===========================================================================* * * BlockifyFrame * * copies data into appropriate blocks * * RETURNS: mf modified * * SIDE EFFECTS: none * * NOTES: probably shouldn't be in this file * *===========================================================================*/ void BlockifyFrame(framePtr) MpegFrame *framePtr; { register int dctx, dcty; register int x, y; register int bx, by; register int fy, fx; register int16 *destPtr; register uint8 *srcPtr; register int16 *destPtr2; register uint8 *srcPtr2; Block *blockPtr; Block *blockPtr2; dctx = Fsize_x / DCTSIZE; dcty = Fsize_y / DCTSIZE; /* * copy y data into y_blocks */ for (by = 0; by < dcty; by++) { fy = by*DCTSIZE; for (bx = 0; bx < dctx; bx++) { fx = bx*DCTSIZE; blockPtr = (Block *) &(framePtr->y_blocks[by][bx][0][0]); for (y = 0; y < DCTSIZE; y++) { destPtr = &((*blockPtr)[y][0]); srcPtr = &(framePtr->orig_y[fy+y][fx]); for (x = 0; x < DCTSIZE; x++) { destPtr[x] = srcPtr[x]; } } } } /* * copy cr/cb data into cr/cb_blocks */ for (by = 0; by < (dcty >> 1); by++) { fy = by*DCTSIZE; for (bx = 0; bx < (dctx >> 1); bx++) { fx = bx*DCTSIZE; blockPtr = (Block *) &(framePtr->cr_blocks[by][bx][0][0]); blockPtr2 = (Block *) &(framePtr->cb_blocks[by][bx][0][0]); for (y = 0; y < DCTSIZE; y++) { destPtr = &((*blockPtr)[y][0]); srcPtr = &(framePtr->orig_cr[fy+y][fx]); destPtr2 = &((*blockPtr2)[y][0]); srcPtr2 = &(framePtr->orig_cb[fy+y][fx]); for (x = 0; x < DCTSIZE; x++) { destPtr[x] = srcPtr[x]; destPtr2[x] = srcPtr2[x]; } } } } } /*===========================================================================* * * * UNUSED PROCEDURES * * * * The following procedures are all unused by the encoder * * * * They are listed here for your convenience. You might want to use * * them if you experiment with different search techniques * * * *===========================================================================*/ #ifdef UNUSED_PROCEDURES /* this procedure calculates the subsampled motion block (obviously) * * for speed, this procedure is probably not called anywhere (it is * incorporated directly into LumDiffA, LumDiffB, etc. * * but leave it here anyway for clarity * * (startY, startX) = (0,0) for A....(0,1) for B...(1,0) for C...(1,1) for D * */ void ComputeSubSampledMotionLumBlock(prevFrame, by, bx, my, mx, motionBlock, startY, startX) MpegFrame *prevFrame; int by; int bx; int my; int mx; LumBlock motionBlock; int startY; int startX; { register uint8 *across; register int32 *macross; register int32 *lastx; register int y; uint8 **prev; int fy, fx; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx); if ( xHalf ) { if ( mx < 0 ) { fx--; } if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfBoth; } else { prev = prevFrame->halfX; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfY; } else { prev = prevFrame->ref_y; } for ( y = startY; y < 16; y += 2 ) { across = &(prev[fy+y][fx+startX]); macross = &(motionBlock[y][startX]); lastx = &(motionBlock[y][16]); while ( macross < lastx ) { (*macross) = (*across); across += 2; macross += 2; } } /* this is what's really going on in slow motion: * * for ( y = startY; y < 16; y += 2 ) * for ( x = startX; x < 16; x += 2 ) * motionBlock[y][x] = prev[fy+y][fx+x]; * */ } /*===========================================================================* * * LumMotionErrorSubSampled * * return the MAD of the currentBlock and the motion-compensated block, * subsampled 4:1 with given starting coordinates (startY, startX) * * RETURNS: the MAD * * SIDE EFFECTS: none * * PRECONDITIONS: motion vector MUST be valid * * NOTES: this procedure is never called. Instead, see subsample.c. This * procedure is provided only for possible use in extensions * *===========================================================================*/ int32 LumMotionErrorSubSampled(currentBlock, prevFrame, by, bx, my, mx, startY, startX) LumBlock currentBlock; MpegFrame *prevFrame; int by; int bx; int my; int mx; int startY; int startX; { register int32 diff = 0; /* max value of diff is 255*256 = 65280 */ register int32 localDiff; register int32 *cacross; register uint8 *macross; register int32 *lastx; register int y; uint8 **prev; int fy, fx; boolean xHalf, yHalf; xHalf = (ABS(mx) % 2 == 1); yHalf = (ABS(my) % 2 == 1); MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx); if ( xHalf ) { if ( mx < 0 ) { fx--; } if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfBoth; } else { prev = prevFrame->halfX; } } else if ( yHalf ) { if ( my < 0 ) { fy--; } prev = prevFrame->halfY; } else { prev = prevFrame->ref_y; } for ( y = startY; y < 16; y += 2 ) { macross = &(prev[fy+y][fx+startX]); cacross = &(currentBlock[y][startX]); lastx = &(currentBlock[y][16]); while ( cacross < lastx ) { localDiff = (*cacross)-(*macross); diff += ABS(localDiff); macross += 2; cacross += 2; } } /* this is what's really happening: * * ComputeSubSampledMotionLumBlock(prevFrame, by, bx, my, mx, * lumMotionBlock, startY, startX); * * for ( y = startY; y < 16; y += 2 ) * for ( x = startX; x < 16; x += 2 ) * { * localDiff = currentBlock[y][x] - lumMotionBlock[y][x]; * diff += ABS(localDiff); * } * */ return (int32)diff; } #endif /* UNUSED_PROCEDURES */