ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/trunk/xvidcore/src/motion/motion_est.c
(Generate patch)

Comparing trunk/xvidcore/src/motion/motion_est.c (file contents):
Revision 135 by chenm001, Tue Apr 23 00:04:51 2002 UTC vs.
Revision 136 by suxen_drol, Thu Apr 25 06:55:00 2002 UTC

# Line 2 | Line 2
2   *
3   *  Modifications:
4   *
5 + *      25.04.2002 partial prevMB conversion
6   *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>
7   *  14.04.2002 added MotionEstimationBVOP()
8   *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between
# Line 79 | Line 80 | int32_t PMVfastSearch16(
80                                          const IMAGE * const pCur,
81                                          const int x, const int y,
82                                          const uint32_t MotionFlags,
83 +                                        const uint32_t iQuant,
84 +                                        const uint32_t iFcode,
85                                          const MBParam * const pParam,
86 <                                        MACROBLOCK * const pMBs,
86 >                                        const MACROBLOCK * const pMBs,
87 >                                        const MACROBLOCK * const prevMBs,
88                                          VECTOR * const currMV,
89                                          VECTOR * const currPMV);
90  
# Line 92 | Line 96 | int32_t EPZSSearch16(
96                                          const IMAGE * const pCur,
97                                          const int x, const int y,
98                                          const uint32_t MotionFlags,
99 +                                        const uint32_t iQuant,
100 +                                        const uint32_t iFcode,
101                                          const MBParam * const pParam,
102 <                                        MACROBLOCK * const pMBs,
102 >                                        const MACROBLOCK * const pMBs,
103 >                                        const MACROBLOCK * const prevMBs,
104                                          VECTOR * const currMV,
105                                          VECTOR * const currPMV);
106  
# Line 105 | Line 112 | int32_t PMVfastSearch8(
112                                          const uint8_t * const pRefHV,
113                                          const IMAGE * const pCur,
114                                          const int x, const int y,
115 <                                        const int start_x, int start_y,
115 >                                        const int start_x, const int start_y,
116                                          const uint32_t MotionFlags,
117 +                                        const uint32_t iQuant,
118 +                                        const uint32_t iFcode,
119                                          const MBParam * const pParam,
120 <                                        MACROBLOCK * const pMBs,
120 >                                        const MACROBLOCK * const pMBs,
121 >                                        const MACROBLOCK * const prevMBs,
122                                          VECTOR * const currMV,
123                                          VECTOR * const currPMV);
124  
# Line 119 | Line 129 | int32_t EPZSSearch8(
129                                          const uint8_t * const pRefHV,
130                                          const IMAGE * const pCur,
131                                          const int x, const int y,
132 <                                        const int start_x, int start_y,
132 >                                        const int start_x, const int start_y,
133                                          const uint32_t MotionFlags,
134 +                                        const uint32_t iQuant,
135 +                                        const uint32_t iFcode,
136                                          const MBParam * const pParam,
137 <                                        MACROBLOCK * const pMBs,
137 >                                        const MACROBLOCK * const pMBs,
138 >                                        const MACROBLOCK * const prevMBs,
139                                          VECTOR * const currMV,
140                                          VECTOR * const currPMV);
141  
# Line 232 | Line 245 | static __inline uint32_t calc_delta_8(co
245   #endif
246  
247   bool MotionEstimation(
235        MACROBLOCK * const pMBs,
248          MBParam * const pParam,
249 <        const IMAGE * const pRef,
249 >        FRAMEINFO * const current,
250 >        FRAMEINFO * const reference,
251          const IMAGE * const pRefH,
252          const IMAGE * const pRefV,
253          const IMAGE * const pRefHV,
241        IMAGE * const pCurrent,
254          const uint32_t iLimit)
255  
256   {
257          const uint32_t iWcount = pParam->mb_width;
258          const uint32_t iHcount = pParam->mb_height;
259 +        MACROBLOCK * pMBs = current->mbs;
260 +        IMAGE * pCurrent = &current->image;
261 +
262 +        MACROBLOCK * prevMBs = reference->mbs;  // previous frame
263 +        IMAGE * pRef = &reference->image;
264 +
265  
266          uint32_t i, j, iIntra = 0;
267  
# Line 256 | Line 274 | bool MotionEstimation(
274  
275          if (sadInit)
276                  (*sadInit)();
277 +
278 +
279 +        /* eventhough we have a seperate prevMBs,
280 +           pmvfast/epsz does something "funny" with the previous frames data */
281 +
282 +        for (i = 0; i < iHcount; i++)
283 +                for (j = 0; j < iWcount; j++)
284 +                {
285 +                        pMBs[j + i * iWcount].mvs[0] = prevMBs[j + i * iWcount].mvs[0];
286 +                        pMBs[j + i * iWcount].mvs[1] = prevMBs[j + i * iWcount].mvs[1];
287 +                        pMBs[j + i * iWcount].mvs[2] = prevMBs[j + i * iWcount].mvs[2];
288 +                        pMBs[j + i * iWcount].mvs[3] = prevMBs[j + i * iWcount].mvs[3];
289 +                }
290 +
291 +        /*dprintf("*** BEFORE ***");
292 +        for (i = 0; i < iHcount; i++)
293 +                for (j = 0; j < iWcount; j++)
294 +                {
295 +                        dprintf("   [%i,%i] mode=%i dquant=%i mvs=(%i %i %i %i) sad8=(%i %i %i %i) sad16=(%i)", j,i,
296 +                                pMBs[j + i * iWcount].mode,
297 +                                pMBs[j + i * iWcount].dquant,
298 +                                pMBs[j + i * iWcount].mvs[0],
299 +                                pMBs[j + i * iWcount].mvs[1],
300 +                                pMBs[j + i * iWcount].mvs[2],
301 +                                pMBs[j + i * iWcount].mvs[3],
302 +                                prevMBs[j + i * iWcount].sad8[0],
303 +                                prevMBs[j + i * iWcount].sad8[1],
304 +                                prevMBs[j + i * iWcount].sad8[2],
305 +                                prevMBs[j + i * iWcount].sad8[3],
306 +                                prevMBs[j + i * iWcount].sad16);
307 +                }
308 +        */
309                  
310          // note: i==horizontal, j==vertical
311          for (i = 0; i < iHcount; i++)
312                  for (j = 0; j < iWcount; j++)
313                  {
314                          MACROBLOCK *pMB = &pMBs[j + i * iWcount];
315 +                        MACROBLOCK *prevMB = &prevMBs[j + i * iWcount];
316  
317                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
318 <                                         j, i, pParam->motion_flags,
319 <                                         pParam, pMBs, &mv16, &pmv16);
318 >                                         j, i, current->motion_flags, current->quant, current->fcode,
319 >                                         pParam, pMBs, prevMBs, &mv16, &pmv16);
320                          pMB->sad16=sad16;
321  
322  
# Line 281 | Line 332 | bool MotionEstimation(
332                                  pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
333                                  pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
334  
335 +                                pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
336 +
337                                  iIntra++;
338                                  if(iIntra >= iLimit)    
339                                          return 1;
# Line 288 | Line 341 | bool MotionEstimation(
341                                  continue;
342                          }
343  
344 <                        if (pParam->global_flags & XVID_INTER4V)
344 >                        if (current->global_flags & XVID_INTER4V)
345                          {
346                                  pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
347 <                                                       2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,
348 <                                                       pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);
347 >                                                       2 * j, 2 * i, mv16.x, mv16.y,
348 >                                                           current->motion_flags, current->quant, current->fcode,
349 >                                                       pParam, pMBs, prevMBs, &pMB->mvs[0], &pMB->pmvs[0]);
350  
351                                  pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
352 <                                                       2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,
353 <                                                       pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);
352 >                                                       2 * j + 1, 2 * i, mv16.x, mv16.y,
353 >                                                           current->motion_flags, current->quant, current->fcode,
354 >                                                       pParam, pMBs, prevMBs, &pMB->mvs[1], &pMB->pmvs[1]);
355  
356                                  pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
357 <                                                       2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,
358 <                                                       pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);
357 >                                                       2 * j, 2 * i + 1, mv16.x, mv16.y,
358 >                                                           current->motion_flags, current->quant, current->fcode,
359 >                                                       pParam, pMBs, prevMBs, &pMB->mvs[2], &pMB->pmvs[2]);
360                          
361                                  pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
362 <                                                       2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,
363 <                                                       pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);
362 >                                                       2 * j + 1, 2 * i + 1, mv16.x, mv16.y,
363 >                                                           current->motion_flags, current->quant, current->fcode,
364 >                                                       pParam, pMBs, prevMBs, &pMB->mvs[3], &pMB->pmvs[3]);
365  
366                                  sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];
367                          }
# Line 314 | Line 371 | bool MotionEstimation(
371                             mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v
372                          */
373  
374 <                        if (pMB->dquant == NO_CHANGE) {
375 <                                if (((pParam->global_flags & XVID_INTER4V)==0) ||
376 <                                    (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {
374 >                        if (!(current->global_flags & XVID_LUMIMASKING) || pMB->dquant == NO_CHANGE)
375 >                        {
376 >                                if (((current->global_flags & XVID_INTER4V)==0) ||
377 >                                    (sad16 < (sad8 + (int32_t)(IMV16X16 * current->quant))))
378 >                                {
379                          
380                                          sad8 = sad16;
381                                          pMB->mode = MODE_INTER;
# Line 339 | Line 398 | bool MotionEstimation(
398                          }
399                  }
400  
401 + /*      dprintf("*** AFTER ***", pMBs[0].b_mvs[0].x);
402 +        for (i = 0; i < iHcount; i++)
403 +                for (j = 0; j < iWcount; j++)
404 +                {
405 +                        dprintf("   [%i,%i] mode=%i dquant=%i mvs=(%i %i %i %i) sad8=(%i %i %i %i) sad16=(%i)", j,i,
406 +                                pMBs[j + i * iWcount].mode,
407 +                                pMBs[j + i * iWcount].dquant,
408 +                                pMBs[j + i * iWcount].mvs[0],
409 +                                pMBs[j + i * iWcount].mvs[1],
410 +                                pMBs[j + i * iWcount].mvs[2],
411 +                                pMBs[j + i * iWcount].mvs[3],
412 +                                pMBs[j + i * iWcount].sad8[0],
413 +                                pMBs[j + i * iWcount].sad8[1],
414 +                                pMBs[j + i * iWcount].sad8[2],
415 +                                pMBs[j + i * iWcount].sad8[3],
416 +                                pMBs[j + i * iWcount].sad16);
417 +                }
418 +        */
419 +
420          return 0;
421   }
422  
# Line 452 | Line 530 | int32_t ZeroSearch16(
530                                          const IMAGE * const pCur,
531                                          const int x, const int y,
532                                          const uint32_t MotionFlags,                            
533 +                                        const uint32_t iQuant,
534 +                                        const uint32_t iFcode,
535                                          MBParam * const pParam,
536 <                                        MACROBLOCK * const pMBs,                                
536 >                                        const MACROBLOCK * const pMBs,                          
537 >                                        const MACROBLOCK * const prevMBs,
538                                          VECTOR * const currMV,
539                                          VECTOR * const currPMV)
540   {
541          const int32_t iEdgedWidth = pParam->edged_width;
461        const int32_t iQuant = pParam->quant;
542          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
543          int32_t iSAD;
544          int32_t pred_x,pred_y;
# Line 780 | Line 860 | int32_t PMVfastSearch16(
860                                          const IMAGE * const pCur,
861                                          const int x, const int y,
862                                          const uint32_t MotionFlags,
863 +                                        const uint32_t iQuant,
864 +                                        const uint32_t iFcode,
865                                          const MBParam * const pParam,
866 <                                        MACROBLOCK * const pMBs,
866 >                                        const MACROBLOCK * const pMBs,
867 >                                        const MACROBLOCK * const prevMBs,
868                                          VECTOR * const currMV,
869                                          VECTOR * const currPMV)
870   {
871      const uint32_t iWcount = pParam->mb_width;
789        const int32_t iFcode = pParam->fixed_code;
790        const int32_t iQuant = pParam->quant;
872          const int32_t iWidth = pParam->width;
873          const int32_t iHeight = pParam->height;
874          const int32_t iEdgedWidth = pParam->edged_width;
# Line 809 | Line 890 | int32_t PMVfastSearch16(
890          VECTOR pmv[4];
891          int32_t psad[4];
892          
893 <        MACROBLOCK * const pMB = pMBs + x + y * iWcount;
893 >        const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
894 >        const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
895  
896          static int32_t threshA,threshB;
897          int32_t bPredEq;
# Line 853 | Line 935 | int32_t PMVfastSearch16(
935     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
936   */
937  
938 <        if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )
938 >        if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[0]) ) )
939                  iFound=2;
940  
941   /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
# Line 907 | Line 989 | int32_t PMVfastSearch16(
989                           iEdgedWidth, MV_MAX_ERROR);
990          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;
991          
992 <        if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) )
992 >        if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
993          {
994                  
995                  if (MotionFlags & PMV_QUICKSTOP16)
# Line 928 | Line 1010 | int32_t PMVfastSearch16(
1010          CHECK_MV16_ZERO;
1011  
1012   // previous frame MV is always possible
1013 <        CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);
1013 >        CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);
1014          
1015   // left neighbour, if allowed
1016          if (x != 0)
# Line 964 | Line 1046 | int32_t PMVfastSearch16(
1046     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1047   */
1048  
1049 <        if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD < pMB->sad16) ) )
1049 >        if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1050          {      
1051                  if (MotionFlags & PMV_QUICKSTOP16)
1052                          goto PMVfast16_Terminate_without_Refine;
# Line 1150 | Line 1232 | int32_t PMVfastSearch8(
1232                                          const uint8_t * const pRefHV,
1233                                          const IMAGE * const pCur,
1234                                          const int x, const int y,
1235 <                                        const int start_x, int start_y,
1235 >                                        const int start_x, const int start_y,
1236                                          const uint32_t MotionFlags,
1237 +                                        const uint32_t iQuant,
1238 +                                        const uint32_t iFcode,
1239                                          const MBParam * const pParam,
1240 <                                        MACROBLOCK * const pMBs,
1240 >                                        const MACROBLOCK * const pMBs,
1241 >                                        const MACROBLOCK * const prevMBs,
1242                                          VECTOR * const currMV,
1243                                          VECTOR * const currPMV)
1244   {
1245 <        const uint32_t iWcount = pParam->mb_width;
1161 <
1162 <        const int32_t iFcode = pParam->fixed_code;
1163 <        const int32_t iQuant = pParam->quant;
1245 >    const uint32_t iWcount = pParam->mb_width;
1246          const int32_t iWidth = pParam->width;
1247          const int32_t iHeight = pParam->height;
1248          const int32_t iEdgedWidth = pParam->edged_width;
# Line 1179 | Line 1261 | int32_t PMVfastSearch8(
1261          VECTOR newMV;
1262          VECTOR backupMV;
1263          
1264 <        MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1264 >        const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1265 >        const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
1266  
1267          static int32_t threshA,threshB;
1268          int32_t iFound,bPredEq;
# Line 1258 | Line 1341 | int32_t PMVfastSearch8(
1341                          iEdgedWidth);
1342          iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;
1343          
1344 <        if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) )
1344 >        if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1345          {
1346                  if (MotionFlags & PMV_QUICKSTOP16)
1347                          goto PMVfast8_Terminate_without_Refine;
# Line 1317 | Line 1400 | int32_t PMVfastSearch8(
1400     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1401   */
1402  
1403 <        if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) )
1403 >        if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1404          {      
1405                  if (MotionFlags & PMV_QUICKSTOP16)
1406                          goto PMVfast8_Terminate_without_Refine;
# Line 1407 | Line 1490 | int32_t EPZSSearch16(
1490                                          const IMAGE * const pCur,
1491                                          const int x, const int y,
1492                                          const uint32_t MotionFlags,
1493 +                                        const uint32_t iQuant,
1494 +                                        const uint32_t iFcode,
1495                                          const MBParam * const pParam,
1496 <                                        MACROBLOCK * const pMBs,
1496 >                                        const MACROBLOCK * const pMBs,
1497 >                                        const MACROBLOCK * const prevMBs,
1498                                          VECTOR * const currMV,
1499                                          VECTOR * const currPMV)
1500   {
1501      const uint32_t iWcount = pParam->mb_width;
1502      const uint32_t iHcount = pParam->mb_height;
1417        const int32_t iFcode = pParam->fixed_code;
1418        const int32_t iQuant = pParam->quant;
1503  
1504          const int32_t iWidth = pParam->width;
1505          const int32_t iHeight = pParam->height;
# Line 1435 | Line 1519 | int32_t EPZSSearch16(
1519          int32_t psad[8];
1520          
1521          static MACROBLOCK * oldMBs = NULL;
1522 <        MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1522 >        const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1523 >        const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
1524          MACROBLOCK * oldMB = NULL;
1525  
1526          static int32_t thresh2;
# Line 1498 | Line 1583 | int32_t EPZSSearch16(
1583          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;
1584          
1585   // thresh1 is fixed to 256
1586 <        if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) )
1586 >        if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1587                  {
1588                          if (MotionFlags & PMV_QUICKSTOP16)
1589                                  goto EPZS16_Terminate_without_Refine;
# Line 1565 | Line 1650 | int32_t EPZSSearch16(
1650   */
1651  
1652          if ( (iMinSAD <= thresh2)
1653 <                || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD <= pMB->sad16) ) )
1653 >                || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD <= prevMB->sad16) ) )
1654                  {      
1655                          if (MotionFlags & PMV_QUICKSTOP16)
1656                                  goto EPZS16_Terminate_without_Refine;
# Line 1691 | Line 1776 | int32_t EPZSSearch8(
1776                                          const int x, const int y,
1777                                          const int start_x, const int start_y,
1778                                          const uint32_t MotionFlags,
1779 +                                        const uint32_t iQuant,
1780 +                                        const uint32_t iFcode,
1781                                          const MBParam * const pParam,
1782 <                                        MACROBLOCK * const pMBs,
1782 >                                        const MACROBLOCK * const pMBs,
1783 >                                        const MACROBLOCK * const prevMBs,
1784                                          VECTOR * const currMV,
1785                                          VECTOR * const currPMV)
1786   {
1787      const uint32_t iWcount = pParam->mb_width;
1700        const int32_t iFcode = pParam->fixed_code;
1701        const int32_t iQuant = pParam->quant;
1702
1788          const int32_t iWidth = pParam->width;
1789          const int32_t iHeight = pParam->height;
1790          const int32_t iEdgedWidth = pParam->edged_width;
# Line 1721 | Line 1806 | int32_t EPZSSearch8(
1806  
1807          const   int32_t iSubBlock = ((y&1)<<1) + (x&1);
1808          
1809 <        MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1809 >        const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1810 >        const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
1811  
1812          int32_t bPredEq;
1813          int32_t iMinSAD,iSAD=9999;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines