motest.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:102k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*************************************************************************
  2. This software module was originally developed by 
  3. Ming-Chieh Lee (mingcl@microsoft.com), Microsoft Corporation
  4. Wei-ge Chen (wchen@microsoft.com), Microsoft Corporation
  5. Bruce Lin (blin@microsoft.com), Microsoft Corporation
  6. (date: March, 1996)
  7. and edited by
  8.         Wei Wu (weiwu@stallion.risc.rockwell.com) Rockwell Science Center
  9. and edited by Xuemin Chen (xchen@gi.com) General Instrument Corp.)
  10. in the course of development of the MPEG-4 Video (ISO/IEC 14496-2). 
  11. This software module is an implementation of a part of one or more MPEG-4 Video tools 
  12. as specified by the MPEG-4 Video. 
  13. ISO/IEC gives users of the MPEG-4 Video free license to this software module or modifications 
  14. thereof for use in hardware or software products claiming conformance to the MPEG-4 Video. 
  15. Those intending to use this software module in hardware or software products are advised that its use may infringe existing patents. 
  16. The original developer of this software module and his/her company, 
  17. the subsequent editors and their companies, 
  18. and ISO/IEC have no liability for use of this software module or modifications thereof in an implementation. 
  19. Copyright is not released for non MPEG-4 Video conforming products. 
  20. Microsoft retains full right to use the code for his/her own purpose, 
  21. assign or donate the code to a third party and to inhibit third parties from using the code for non <MPEG standard> conforming products. 
  22. This copyright notice must be included in all copies or derivative works. 
  23. Copyright (c) 1996, 1997.
  24. Module Name:
  25. motEst.cpp
  26. Abstract:
  27. Motion estimation routines.
  28. Revision History:
  29. Dec 20, 1997: Interlaced tools added by NextLevel Systems
  30. May 9, 1999: tm5 rate control by DemoGraFX, duhoff@mediaone.net
  31. *************************************************************************/
  32. #include <stdio.h>
  33. #include <math.h>
  34. #include <stdlib.h>
  35. #include <iostream.h>
  36. #include "typeapi.h"
  37. #include "codehead.h"
  38. #include "global.hpp"
  39. #include "entropy/bitstrm.hpp"
  40. #include "entropy/entropy.hpp"
  41. #include "entropy/huffman.hpp"
  42. #include "mode.hpp"
  43. #include "vopses.hpp"
  44. #include "vopseenc.hpp"
  45. #ifdef __MFC_
  46. #ifdef _DEBUG
  47. #undef THIS_FILE
  48. static char BASED_CODE THIS_FILE[] = __FILE__;
  49. #endif
  50. #define new DEBUG_NEW    
  51. #endif // __MFC_
  52. #define FAVORZERO 129
  53. #define FAVOR_DIRECT 129
  54. #define FAVOR_INTER 512
  55. #define FAVOR_16x16 129
  56. #define FAVOR_FIELD  65 // P-VOP favor field over 8x8 due to fewer MVs
  57. inline Int minimum (Int a, Int b, Int c, Int d)
  58. {
  59. if (a <= b && a <= c && a <= d)
  60. return a;
  61. else if (b <= a && b <= c && b <= d)
  62. return b;
  63. else if (c <= a && c <= b && c <= d)
  64. return c;
  65. else
  66. return d;
  67. }
  68. Void CVideoObjectEncoder::motionEstPVOP ()
  69. {
  70. m_iMAD = 0;
  71. CoordI y = 0; 
  72. CMBMode* pmbmd = m_rgmbmd;
  73. CMotionVector* pmv = m_rgmv;
  74. const PixelC* ppxlcOrigY = m_pvopcOrig->pixelsBoundY ();
  75. const PixelC* ppxlcRefY = (m_volmd.bOriginalForME ? m_pvopcRefOrig0 : m_pvopcRefQ0)->pixelsY () + m_iStartInRefToCurrRctY;
  76. Int iMBX, iMBY;
  77. if (m_iMVFileUsage == 1)
  78. readPVOPMVs();
  79. for (iMBY = 0; iMBY < m_iNumMBY; iMBY++, y += MB_SIZE) {
  80. const PixelC* ppxlcOrigMBY = ppxlcOrigY;
  81. const PixelC* ppxlcRefMBY = ppxlcRefY;
  82. CoordI x = 0;
  83. for (iMBX = 0; iMBX < m_iNumMBX; iMBX++, x += MB_SIZE) {
  84. #ifdef __TRACE_AND_STATS_
  85. m_pbitstrmOut->trace (CSite (iMBX, iMBY), "MB_X_Y");
  86. #endif // __TRACE_AND_STATS_
  87. if (m_volmd.volType == ENHN_LAYER && m_vopmd.iRefSelectCode == 3) {
  88. motionEstMB_PVOP (x, y, pmv, pmbmd);
  89. }
  90. else {
  91. copyToCurrBuffY (ppxlcOrigMBY);
  92. pmbmd->m_bFieldDCT=0;
  93. m_iMAD += motionEstMB_PVOP (x, y, pmv, pmbmd, ppxlcRefMBY);
  94. }
  95. #ifdef __TRACE_AND_STATS_
  96. m_pbitstrmOut->trace (CSite (iMBX, iMBY), "MB_X_Y");
  97. m_pbitstrmOut->trace (pmv [0], "MV16");
  98. m_pbitstrmOut->trace (pmv [1], "MV8");
  99. m_pbitstrmOut->trace (pmv [2], "MV8");
  100. m_pbitstrmOut->trace (pmv [3], "MV8");
  101. m_pbitstrmOut->trace (pmv [4], "MV8");
  102. // INTERLACE
  103. if(pmbmd->m_bForwardTop)
  104. m_pbitstrmOut->trace (pmv [6], "MV16x8");
  105. else
  106. m_pbitstrmOut->trace (pmv [5], "MV16x8");
  107. if(pmbmd->m_bForwardBottom)
  108. m_pbitstrmOut->trace (pmv [8], "MV16x8");
  109. else
  110. m_pbitstrmOut->trace (pmv [7], "MV16x8");
  111. // ~INTERLACE
  112. #endif // __TRACE_AND_STATS_
  113. pmbmd++;
  114. pmv += PVOP_MV_PER_REF_PER_MB;
  115. ppxlcOrigMBY += MB_SIZE;
  116. ppxlcRefMBY += MB_SIZE;
  117. }
  118. ppxlcOrigY += m_iFrameWidthYxMBSize;
  119. ppxlcRefY += m_iFrameWidthYxMBSize;
  120. }
  121. if (m_iMVFileUsage == 2)
  122. writePVOPMVs();
  123. }
  124. Void CVideoObjectEncoder::motionEstPVOP_WithShape ()
  125. {
  126. m_iMAD = 0;
  127. CoordI y = m_rctCurrVOPY.top; 
  128. CMBMode* pmbmd = m_rgmbmd;
  129. CMotionVector* pmv = m_rgmv;
  130. const PixelC* ppxlcOrigY = m_pvopcOrig->pixelsBoundY ();
  131. const PixelC* ppxlcOrigBY = m_pvopcOrig->pixelsBoundBY ();
  132. const PixelC* ppxlcRefY = (m_volmd.bOriginalForME ? m_pvopcRefOrig0 : m_pvopcRefQ0)->pixelsY () + m_iStartInRefToCurrRctY;
  133. Int iMBX, iMBY;
  134. if (m_iMVFileUsage == 1)
  135. readPVOPMVs();
  136. for (iMBY = 0; iMBY < m_iNumMBY; iMBY++, y += MB_SIZE) {
  137. const PixelC* ppxlcOrigMBY = ppxlcOrigY;
  138. const PixelC* ppxlcOrigMBBY = ppxlcOrigBY;
  139. const PixelC* ppxlcRefMBY = ppxlcRefY;
  140. CoordI x = m_rctCurrVOPY.left;
  141. for (iMBX = 0; iMBX < m_iNumMBX; iMBX++, x += MB_SIZE) {
  142. #ifdef __TRACE_AND_STATS_
  143. if(m_volmd.bShapeOnly==FALSE)
  144. m_pbitstrmOut->trace (CSite (iMBX, iMBY), "MB_X_Y");
  145. #endif // __TRACE_AND_STATS_
  146. copyToCurrBuffWithShapeY (ppxlcOrigMBY, ppxlcOrigMBBY);
  147. decideTransparencyStatus (pmbmd, m_ppxlcCurrMBBY);
  148. if(m_volmd.bShapeOnly==FALSE)
  149. {
  150. if (pmbmd->m_rgTranspStatus [0] == NONE)
  151. {
  152. // new changes X. Chen
  153. pmbmd->m_bFieldDCT=0;
  154. m_iMAD += motionEstMB_PVOP (x, y, pmv, pmbmd, ppxlcRefMBY);
  155. }
  156. else if (pmbmd->m_rgTranspStatus [0] == PARTIAL)
  157. {
  158. // new changes X. Chen
  159. pmbmd->m_bFieldDCT=0;
  160. m_iMAD += motionEstMB_PVOP_WithShape (x, y, pmv, pmbmd, ppxlcRefMBY);
  161. }
  162. #ifdef __TRACE_AND_STATS_
  163. m_pbitstrmOut->trace (CSite (iMBX, iMBY), "MB_X_Y");
  164. m_pbitstrmOut->trace (pmv [0], "MV16");
  165. m_pbitstrmOut->trace (pmv [1], "MV8");
  166. m_pbitstrmOut->trace (pmv [2], "MV8");
  167. m_pbitstrmOut->trace (pmv [3], "MV8");
  168. m_pbitstrmOut->trace (pmv [4], "MV8");
  169. // INTERLACE
  170. // new changes
  171. if(pmbmd->m_bFieldDCT) {
  172. if(pmbmd->m_bForwardTop)
  173. m_pbitstrmOut->trace (pmv [6], "MV16x8");
  174. else
  175. m_pbitstrmOut->trace (pmv [5], "MV16x8");
  176. if(pmbmd->m_bForwardBottom)
  177. m_pbitstrmOut->trace (pmv [8], "MV16x8");
  178. else
  179. m_pbitstrmOut->trace (pmv [7], "MV16x8");
  180. }
  181. // end of new changes
  182. // ~INTERLACE
  183. #endif // __TRACE_AND_STATS_
  184. }
  185. pmbmd++;
  186. pmv += PVOP_MV_PER_REF_PER_MB;
  187. ppxlcOrigMBY += MB_SIZE;
  188. ppxlcOrigMBBY += MB_SIZE;
  189. ppxlcRefMBY += MB_SIZE;
  190. }
  191. ppxlcOrigY += m_iFrameWidthYxMBSize;
  192. ppxlcOrigBY += m_iFrameWidthYxMBSize;
  193. ppxlcRefY += m_iFrameWidthYxMBSize;
  194. }
  195. if (m_iMVFileUsage == 2)
  196. writePVOPMVs();
  197. }
  198. Void CVideoObjectEncoder::motionEstBVOP ()
  199. {
  200. if (m_iMVFileUsage == 1)
  201. readBVOPMVs();
  202. m_iMAD = 0;
  203. CoordI y = 0; // frame-based, always start from 0
  204. CMBMode* pmbmd = m_rgmbmd;
  205. const CMBMode* pmbmdRef = NULL;
  206. const CMotionVector* pmvRef = NULL; //mv in ref frame (for direct mode)
  207. if(m_bCodedFutureRef!=FALSE)
  208. {
  209. pmbmdRef = m_rgmbmdRef;
  210. pmvRef = m_rgmvRef;
  211. }
  212. CMotionVector* pmv = m_rgmv;
  213. CMotionVector* pmvBackward = m_rgmvBackward;
  214. const PixelC* ppxlcOrigY = m_pvopcOrig->pixelsBoundY ();
  215. const PixelC* ppxlcRef0Y = m_pvopcRefQ0->pixelsY () + m_iStartInRefToCurrRctY;
  216. const PixelC* ppxlcRef1Y = m_pvopcRefQ1->pixelsY () + m_iStartInRefToCurrRctY;
  217. Int iMBX, iMBY;
  218. for (iMBY = 0; iMBY < m_iNumMBY; iMBY++, y += MB_SIZE) {
  219. const PixelC* ppxlcOrigMBY = ppxlcOrigY;
  220. const PixelC* ppxlcRef0MBY = ppxlcRef0Y;
  221. const PixelC* ppxlcRef1MBY = ppxlcRef1Y;
  222. CoordI x = 0; // frame-based, always start from 0
  223. for (iMBX = 0; iMBX < m_iNumMBX; iMBX++, x += MB_SIZE) {
  224. pmbmd->m_dctMd = INTER; // B-VOP is always INTER
  225. pmbmd->m_bhas4MVForward = pmbmd->m_bhas4MVBackward = FALSE;  //out encoder doesn't support 4 mv in bvop (not even direct mode)
  226. // TPS FIX
  227. if(m_volmd.volType == ENHN_LAYER && (m_vopmd.iRefSelectCode != 3 || m_volmd.iEnhnType == 1)){
  228. pmbmd->m_bColocatedMBSkip= FALSE;
  229. copyToCurrBuffY(ppxlcOrigMBY); 
  230. // begin: modified by Sharp(98/3/10)
  231. if ( m_vopmd.iRefSelectCode == 0 )
  232. motionEstMB_BVOP (x, y, pmv, pmvBackward, pmbmd, ppxlcRef0MBY, ppxlcRef1MBY);
  233. else
  234. motionEstMB_BVOP (x, y, pmv, pmvBackward, pmbmd, pmbmdRef, pmvRef, ppxlcRef0MBY, ppxlcRef1MBY, TRUE);
  235. // end: modified by Sharp(98/3/10)
  236. }
  237. else {
  238. pmbmd->m_bColocatedMBSkip = (pmbmdRef==NULL) ? FALSE : pmbmdRef->m_bSkip;
  239. if (pmbmd->m_bColocatedMBSkip) {
  240. pmbmd->m_bSkip = TRUE;
  241. memset (pmv, 0, BVOP_MV_PER_REF_PER_MB * sizeof (CMotionVector));
  242. pmbmd->m_mbType = FORWARD; // can be set to FORWARD mode since the result is the same
  243. }
  244. else {
  245. copyToCurrBuffY (ppxlcOrigMBY);
  246. m_iMAD += m_vopmd.bInterlace ?
  247.                         motionEstMB_BVOP_Interlaced (x, y, pmv, pmvBackward, pmbmd,
  248.                                                      pmbmdRef, pmvRef, ppxlcRef0MBY, ppxlcRef1MBY, pmbmdRef!=NULL) :
  249.                         motionEstMB_BVOP            (x, y, pmv, pmvBackward, pmbmd,
  250.                                                      pmbmdRef, pmvRef, ppxlcRef0MBY, ppxlcRef1MBY, pmbmdRef!=NULL);
  251. }
  252. }
  253. pmbmd++;
  254. pmv         += BVOP_MV_PER_REF_PER_MB;
  255. pmvBackward += BVOP_MV_PER_REF_PER_MB;
  256. if(m_bCodedFutureRef!=FALSE)
  257. {
  258. pmbmdRef++;
  259. pmvRef += PVOP_MV_PER_REF_PER_MB;
  260. }
  261. ppxlcOrigMBY += MB_SIZE;
  262. ppxlcRef0MBY += MB_SIZE;
  263. ppxlcRef1MBY += MB_SIZE;
  264. }
  265. ppxlcOrigY += m_iFrameWidthYxMBSize;
  266. ppxlcRef0Y += m_iFrameWidthYxMBSize;
  267. ppxlcRef1Y += m_iFrameWidthYxMBSize;
  268. }
  269. if (m_iMVFileUsage == 2)
  270. writeBVOPMVs();
  271. }
  272. Void CVideoObjectEncoder::motionEstBVOP_WithShape ()
  273. {
  274. m_iMAD = 0;
  275. CoordI y = m_rctCurrVOPY.top; 
  276. CMBMode* pmbmd = m_rgmbmd;
  277. CMotionVector* pmv = m_rgmv;
  278. CMotionVector* pmvBackward = m_rgmvBackward;
  279. Bool bColocatedMBExist;
  280. const PixelC* ppxlcOrigY = m_pvopcOrig->pixelsBoundY ();
  281. const PixelC* ppxlcOrigBY = m_pvopcOrig->pixelsBoundBY ();
  282. const PixelC* ppxlcRef0Y = m_pvopcRefOrig0->pixelsY () + m_iStartInRefToCurrRctY;
  283. const PixelC* ppxlcRef1Y = m_pvopcRefOrig1->pixelsY () + m_iStartInRefToCurrRctY;
  284. Int iMBX, iMBY;
  285. if (m_iMVFileUsage == 1)
  286. readBVOPMVs();
  287. for (iMBY = 0; iMBY < m_iNumMBY; iMBY++, y += MB_SIZE) {
  288. const PixelC* ppxlcOrigMBY = ppxlcOrigY;
  289. const PixelC* ppxlcOrigMBBY = ppxlcOrigBY;
  290. const PixelC* ppxlcRef0MBY = ppxlcRef0Y;
  291. const PixelC* ppxlcRef1MBY = ppxlcRef1Y;
  292. CoordI x = m_rctCurrVOPY.left;
  293. for (iMBX = 0; iMBX < m_iNumMBX; iMBX++, x += MB_SIZE) {
  294. pmbmd->m_dctMd = INTER; // B-VOP is always INTER
  295. pmbmd->m_bhas4MVForward = pmbmd->m_bhas4MVBackward = FALSE;
  296. copyToCurrBuffWithShapeY (ppxlcOrigMBY, ppxlcOrigMBBY);
  297. decideTransparencyStatus (pmbmd, m_ppxlcCurrMBBY);
  298. if (pmbmd->m_rgTranspStatus [0] != ALL) {
  299. const CMBMode* pmbmdRef;
  300. const CMotionVector* pmvRef;
  301. findColocatedMB (iMBX, iMBY, pmbmdRef, pmvRef);
  302. pmbmd->m_bColocatedMBSkip = (pmbmdRef!=NULL && pmbmdRef->m_bSkip);
  303. // TPS FIX
  304. if(m_volmd.volType == ENHN_LAYER && (m_vopmd.iRefSelectCode != 3 || m_volmd.iEnhnType == 1)) {
  305. pmbmd->m_bColocatedMBSkip= FALSE;
  306. bColocatedMBExist = (pmbmdRef!=NULL);
  307. if (pmbmd->m_rgTranspStatus [0] == NONE) {
  308. m_iMAD += motionEstMB_BVOP (
  309. x, y, 
  310. pmv, pmvBackward,
  311. pmbmd, 
  312. pmbmdRef, pmvRef,
  313. ppxlcRef0MBY, ppxlcRef1MBY,
  314. bColocatedMBExist
  315. );
  316. }
  317. else if (pmbmd->m_rgTranspStatus [0] == PARTIAL) {
  318. m_iMAD += motionEstMB_BVOP_WithShape (
  319. x, y, 
  320. pmv, pmvBackward,
  321. pmbmd, 
  322. pmbmdRef, pmvRef,
  323. ppxlcRef0MBY, ppxlcRef1MBY,
  324. bColocatedMBExist
  325. );
  326. }
  327. else {
  328. if (pmbmd->m_bColocatedMBSkip) {
  329. pmbmd->m_bSkip = TRUE;
  330. memset (pmv, 0, BVOP_MV_PER_REF_PER_MB * sizeof (CMotionVector));
  331. m_statsMB.nDirectMB++;
  332. pmbmd->m_mbType = FORWARD;
  333. }
  334. else {
  335. bColocatedMBExist = (pmbmdRef!=NULL);
  336. if (pmbmd->m_rgTranspStatus [0] == NONE) {
  337. // new changes
  338. m_iMAD += m_vopmd.bInterlace ?
  339. motionEstMB_BVOP_Interlaced (x, y, pmv, pmvBackward, pmbmd,
  340.                                                      pmbmdRef, pmvRef, ppxlcRef0MBY, 
  341.  ppxlcRef1MBY,
  342.  bColocatedMBExist) :
  343. // end of new changes
  344. motionEstMB_BVOP (
  345. x, y, 
  346. pmv, pmvBackward,
  347. pmbmd, 
  348. pmbmdRef, pmvRef,
  349. ppxlcRef0MBY, ppxlcRef1MBY,
  350. bColocatedMBExist
  351. );
  352. }
  353. else if (pmbmd->m_rgTranspStatus [0] == PARTIAL) {
  354. // new changes
  355. m_iMAD += m_vopmd.bInterlace ?
  356.                         motionEstMB_BVOP_InterlacedWithShape (x, y, pmv, pmvBackward, pmbmd,
  357.                                                      pmbmdRef, pmvRef, ppxlcRef0MBY, 
  358.  ppxlcRef1MBY,
  359.  bColocatedMBExist) :
  360. // end of new changes
  361. motionEstMB_BVOP_WithShape (
  362. x, y, 
  363. pmv, pmvBackward,
  364. pmbmd, 
  365. pmbmdRef, pmvRef,
  366. ppxlcRef0MBY, ppxlcRef1MBY,
  367. bColocatedMBExist
  368. );
  369. }
  370. }
  371. }
  372. }
  373. ppxlcOrigMBBY += MB_SIZE;
  374. pmbmd++;
  375. pmv         += BVOP_MV_PER_REF_PER_MB;
  376. pmvBackward += BVOP_MV_PER_REF_PER_MB;
  377. ppxlcOrigMBY += MB_SIZE;
  378. ppxlcRef0MBY += MB_SIZE;
  379. ppxlcRef1MBY += MB_SIZE;
  380. }
  381. ppxlcOrigY += m_iFrameWidthYxMBSize;
  382. ppxlcOrigBY += m_iFrameWidthYxMBSize;
  383. ppxlcRef0Y += m_iFrameWidthYxMBSize;
  384. ppxlcRef1Y += m_iFrameWidthYxMBSize;
  385. }
  386. if (m_iMVFileUsage == 2)
  387. writeBVOPMVs();
  388. }
  389. Void CVideoObjectEncoder::copyToCurrBuffWithShapeY (const PixelC* ppxlcCurrY, const PixelC* ppxlcCurrBY)
  390. {
  391. Int iUnit = sizeof(PixelC); // NBIT: for memcpy
  392. PixelC* ppxlcCurrMBY = m_ppxlcCurrMBY;
  393. PixelC* ppxlcCurrMBBY = m_ppxlcCurrMBBY;
  394. Int ic;
  395. for (ic = 0; ic < MB_SIZE; ic++) {
  396. memcpy (ppxlcCurrMBY, ppxlcCurrY, MB_SIZE*iUnit);
  397. memcpy (ppxlcCurrMBBY, ppxlcCurrBY, MB_SIZE*iUnit);
  398. ppxlcCurrMBY += MB_SIZE; ppxlcCurrY += m_iFrameWidthY;
  399. ppxlcCurrMBBY += MB_SIZE; ppxlcCurrBY += m_iFrameWidthY;
  400. }
  401. }
  402. Void CVideoObjectEncoder::copyToCurrBuffY (const PixelC* ppxlcCurrY)
  403. {
  404. Int iUnit = sizeof(PixelC); // NBIT: for memcpy
  405. PixelC* ppxlcCurrMBY = m_ppxlcCurrMBY;
  406. Int ic;
  407. for (ic = 0; ic < MB_SIZE; ic++) {
  408. memcpy (ppxlcCurrMBY, ppxlcCurrY, MB_SIZE*iUnit);
  409. ppxlcCurrMBY += MB_SIZE; ppxlcCurrY += m_iFrameWidthY;
  410. }
  411. }
  412. //for spatial sclability: basically set every mv to zero
  413. Void CVideoObjectEncoder::motionEstMB_PVOP (CoordI x, CoordI y, 
  414. CMotionVector* pmv, CMBMode* pmbmd)
  415. {
  416. pmbmd -> m_bhas4MVForward = FALSE;
  417. pmbmd-> m_dctMd = INTER;
  418. memset (pmv, 0, sizeof (CMotionVector) * PVOP_MV_PER_REF_PER_MB);
  419. for (UInt i = 0; i < PVOP_MV_PER_REF_PER_MB; i++)  {
  420. pmv -> computeTrueMV (); 
  421. pmv++;
  422. }
  423. }
  424. Int CVideoObjectEncoder::motionEstMB_PVOP (
  425. CoordI x, CoordI y, 
  426. CMotionVector* pmv, CMBMode* pmbmd, 
  427. const PixelC* ppxlcRefMBY
  428. )
  429. {
  430. Int nBits = m_volmd.nBits; // NBIT
  431. Int iFavorZero = FAVORZERO; // NBIT
  432. Int iFavorInter = FAVOR_INTER; // NBIT
  433. Int iFavor16x16 = FAVOR_16x16; // NBIT
  434. // NBIT: addjust mode selection thresholds
  435. if (nBits > 8) {
  436. iFavorZero <<= (nBits-8);
  437. iFavorInter <<= (nBits-8);
  438. iFavor16x16 <<= (nBits-8);
  439. } else if (nBits < 8) {
  440. iFavorZero >>= (8-nBits);
  441. iFavorInter >>= (8-nBits);
  442. iFavor16x16 >>= (8-nBits);
  443. }
  444. Int iInitSAD = sad16x16At0 (ppxlcRefMBY);
  445. Int iSADInter = blkmatch16 (pmv, x, y, x, y, iInitSAD, ppxlcRefMBY, m_puciRefQZoom0, m_vopmd.iSearchRangeForward);
  446. Int iSumDev = sumDev ();
  447. #ifdef __TRACE_AND_STATS_
  448. m_pbitstrmOut->trace (iSADInter, "MB_SAD16");
  449. #endif // __TRACE_AND_STATS_
  450. // INTERLACE
  451. /* NBIT: change to a bigger number
  452. Int iSAD16x8 = 256*256;
  453. */
  454. Int iSAD16x8 = 4096*256;
  455. pmbmd -> m_bFieldMV = FALSE;
  456. if(m_vopmd.bInterlace) {
  457. // Field-Based Estimation
  458. CMotionVector* pmv16x8 = pmv + 5;
  459. const PixelC *ppxlcHalfPelRef = m_pvopcRefQ0->pixelsY()
  460. + EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME + x + y * m_iFrameWidthY; // 1.31.99 changes
  461. // top to top
  462. Int iSAD16x8top = blkmatch16x8 (pmv16x8, x, y, 0, ppxlcRefMBY,
  463. ppxlcHalfPelRef, m_vopmd.iSearchRangeForward);
  464. pmv16x8++;
  465. // bot to top
  466. Int iSAD16x8bot = blkmatch16x8 (pmv16x8, x, y, 0, ppxlcRefMBY + m_iFrameWidthY,
  467. ppxlcHalfPelRef + m_iFrameWidthY, m_vopmd.iSearchRangeForward);
  468. iSAD16x8=(iSAD16x8top<iSAD16x8bot) ? iSAD16x8top : iSAD16x8bot;
  469. pmbmd->m_bForwardTop = (iSAD16x8top<iSAD16x8bot) ? 0 : 1;
  470. pmv16x8++;
  471. // top to bot
  472. iSAD16x8top = blkmatch16x8 (pmv16x8, x, y, MB_SIZE, ppxlcRefMBY,
  473. ppxlcHalfPelRef, m_vopmd.iSearchRangeForward);
  474. pmv16x8++;
  475. // bot to bot
  476. iSAD16x8bot = blkmatch16x8 (pmv16x8, x, y, MB_SIZE, ppxlcRefMBY + m_iFrameWidthY,
  477. ppxlcHalfPelRef + m_iFrameWidthY, m_vopmd.iSearchRangeForward);
  478. iSAD16x8 += (iSAD16x8top<iSAD16x8bot) ? iSAD16x8top : iSAD16x8bot;
  479. pmbmd->m_bForwardBottom = (iSAD16x8top<iSAD16x8bot) ? 0 : 1;
  480. } else {
  481. /* NBIT: change to a bigger number
  482. iSAD16x8 = 256*256;
  483. */
  484. iSAD16x8 = 4096*256;
  485. for (Int iBlk = 5; iBlk <= 8; iBlk++) {  // 04/28/99 david ruhoff
  486. pmv [iBlk] = pmv [0];   // fill in field info to make mv file deterministic
  487. }
  488. }
  489. #ifdef __TRACE_AND_STATS_
  490. m_pbitstrmOut->trace (iSAD16x8, "MB_SAD16x8");
  491. #endif // __TRACE_AND_STATS_
  492. // ~INTERLACE
  493. CoordI blkX, blkY;
  494. Int iSAD8 = 0;
  495. CMotionVector* pmv8 = pmv + 1;
  496. blkX = x + BLOCK_SIZE;
  497. blkY = y + BLOCK_SIZE;
  498. const PixelC* ppxlcCodedBlkY = m_ppxlcCurrMBY;
  499. #ifdef __DISABLE_4MV_FOR_PVOP_
  500. iSAD8 = 4096*4096; // big number to disable 8x8 mode
  501. #else
  502. // 8x8
  503. iSAD8 += blockmatch8 (ppxlcCodedBlkY, pmv8, x, y, pmv, m_vopmd.iSearchRangeForward);
  504. pmv8++;
  505. ppxlcCodedBlkY += BLOCK_SIZE;
  506. #ifdef __TRACE_AND_STATS_
  507. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  508. #endif // __TRACE_AND_STATS_
  509. iSAD8 += blockmatch8 (ppxlcCodedBlkY, pmv8, blkX, y, pmv, m_vopmd.iSearchRangeForward);
  510. pmv8++;
  511. ppxlcCodedBlkY += BLOCK_SIZE * MB_SIZE - BLOCK_SIZE;
  512. #ifdef __TRACE_AND_STATS_
  513. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  514. #endif // __TRACE_AND_STATS_
  515. iSAD8 += blockmatch8 (ppxlcCodedBlkY, pmv8, x, blkY, pmv, m_vopmd.iSearchRangeForward);
  516. pmv8++;
  517. ppxlcCodedBlkY += BLOCK_SIZE;
  518. #ifdef __TRACE_AND_STATS_
  519. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  520. #endif // __TRACE_AND_STATS_
  521. iSAD8 += blockmatch8 (ppxlcCodedBlkY, pmv8, blkX, blkY, pmv, m_vopmd.iSearchRangeForward);
  522. #ifdef __TRACE_AND_STATS_
  523. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  524. #endif // __TRACE_AND_STATS_
  525. #endif // DISABLE_4MV_FOR_PVOP
  526. /* NBIT: change
  527. iSADInter -= FAVOR_16x16;
  528. */
  529. iSADInter -= iFavor16x16;
  530. iSAD16x8 -= FAVOR_FIELD;
  531. if ((iSADInter <= iSAD8) && (iSADInter <= iSAD16x8)) {
  532. /* NBIT: change
  533.     iSADInter += FAVOR_16x16;
  534. */
  535.     iSADInter += iFavor16x16;
  536. pmbmd -> m_bhas4MVForward = FALSE;
  537. pmv -> computeTrueMV (); // compute here instead of blkmatch to save computation
  538. for (UInt i = 1; i < PVOP_MV_PER_REF_PER_MB; i++) // didn't increment the last pmv
  539. pmv[i].m_vctTrueHalfPel = pmv->m_vctTrueHalfPel; // Save (iMVX, iMVY) for MV file
  540. }
  541. // INTERLACE
  542. else if (iSAD16x8 <= iSAD8) { // Field-based
  543. pmbmd -> m_bhas4MVForward = FALSE;
  544. pmbmd -> m_bFieldMV = TRUE;
  545. Int iTempX1, iTempY1, iTempX2, iTempY2;
  546. if(pmbmd->m_bForwardTop) {
  547. pmv [6].computeTrueMV ();
  548. iTempX1 = pmv[6].m_vctTrueHalfPel.x;
  549. iTempY1 = pmv[6].m_vctTrueHalfPel.y;
  550. }
  551. else {
  552. pmv [5].computeTrueMV ();
  553. iTempX1 = pmv[5].m_vctTrueHalfPel.x;
  554. iTempY1 = pmv[5].m_vctTrueHalfPel.y;
  555. }
  556. if(pmbmd->m_bForwardBottom) {
  557. pmv [8].computeTrueMV ();
  558. iTempX2 = pmv[8].m_vctTrueHalfPel.x;
  559. iTempY2 = pmv[8].m_vctTrueHalfPel.y;
  560. }
  561. else {
  562. pmv [7].computeTrueMV ();
  563. iTempX2 = pmv[7].m_vctTrueHalfPel.x;
  564. iTempY2 = pmv[7].m_vctTrueHalfPel.y;
  565. }
  566. iSADInter = iSAD16x8 + FAVOR_FIELD;
  567. Int iTemp;
  568. for (UInt i = 1; i < 5; i++) {
  569. iTemp = iTempX1 + iTempX2;
  570. pmv [i].m_vctTrueHalfPel.x = (iTemp & 3) ? ((iTemp>>1) | 1) : (iTemp>>1);
  571. iTemp = iTempY1 + iTempY2;
  572. pmv [i].m_vctTrueHalfPel.y = (iTemp & 3) ? ((iTemp>>1) | 1) : (iTemp>>1);
  573. }
  574. }
  575. // ~INTERLACE
  576. else {
  577. pmv [1].computeTrueMV ();
  578. pmv [2].computeTrueMV ();
  579. pmv [3].computeTrueMV ();
  580. pmv [4].computeTrueMV ();
  581. pmbmd -> m_bhas4MVForward = TRUE;
  582. iSADInter = iSAD8;
  583. }
  584. /* NBIT: change
  585. if (iSumDev < (iSADInter - FAVOR_INTER)) {
  586. */
  587. if (iSumDev < (iSADInter - iFavorInter)) {
  588. pmbmd -> m_bSkip = FALSE;
  589. pmbmd -> m_dctMd = INTRA;
  590. pmbmd -> m_bFieldMV = FALSE;
  591. memset (pmv, 0, PVOP_MV_PER_REF_PER_MB * sizeof (CMotionVector));
  592. return ((m_uiRateControl==RC_MPEG4) ? sumAbsCurrMB () : 0);
  593. }
  594. else {
  595. pmbmd -> m_dctMd = INTER;
  596. if (pmbmd->m_bhas4MVForward == FALSE
  597. && pmbmd -> m_bFieldMV == FALSE
  598. && pmv->m_vctTrueHalfPel.x == 0 && pmv->m_vctTrueHalfPel.y == 0)
  599. /* NBIT: change
  600. return (iSADInter + FAVORZERO);
  601. */
  602. return (iSADInter + iFavorZero);
  603. else 
  604. return iSADInter;
  605. }
  606. }
  607. Int CVideoObjectEncoder::motionEstMB_PVOP_WithShape (
  608. CoordI x, CoordI y, 
  609. CMotionVector* pmv, CMBMode* pmbmd, 
  610. const PixelC* ppxlcRefMBY
  611. )
  612. {
  613. assert (pmbmd->m_rgTranspStatus [0] == PARTIAL);
  614. UInt nBits = m_volmd.nBits; // NBIT
  615. Int iFavorZero = FAVORZERO;
  616. Int iFavor16x16 = (pmbmd->m_rgNumNonTranspPixels [0] >> 1) + 1; // NBIT
  617. Int iFavorInter = pmbmd->m_rgNumNonTranspPixels [0] << 1; // NBIT
  618. // NBIT: addjust mode selection thresholds
  619. if (nBits > 8) {
  620. iFavor16x16 <<= (nBits-8);
  621. iFavorInter <<= (nBits-8);
  622. iFavorZero <<= (nBits-8);
  623. } else if (nBits < 8) {
  624. iFavor16x16 >>= (8-nBits);
  625. iFavorInter >>= (8-nBits);
  626. iFavorZero >>= (8-nBits);
  627. }
  628. Int iInitSAD = sad16x16At0WithShape (ppxlcRefMBY, pmbmd);
  629. Int iSADInter = blkmatch16WithShape (pmv, x, y, x, y, iInitSAD, ppxlcRefMBY, m_puciRefQZoom0, pmbmd, m_vopmd.iSearchRangeForward,0);
  630. Int iSumDev = sumDevWithShape (pmbmd -> m_rgNumNonTranspPixels [0]);
  631. #ifdef __TRACE_AND_STATS_
  632. m_pbitstrmOut->trace (iSADInter, "MB_SAD16");
  633. #endif // __TRACE_AND_STATS_
  634. // INTERLACE
  635. // New Changes
  636. Int iSAD16x8 = 4096*256;
  637. pmbmd -> m_bFieldMV = FALSE;
  638. if(m_vopmd.bInterlace) {
  639. // Field-Based Estimation
  640. CMotionVector* pmv16x8 = pmv + 5;
  641. const PixelC *ppxlcHalfPelRef = m_pvopcRefQ0->pixelsY()
  642. + EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME + x + y * m_iFrameWidthY; // 1.31.99 changes
  643. // top to top
  644. Int iSAD16x8top = blkmatch16x8WithShape (pmv16x8, x, y, 0, ppxlcRefMBY,
  645. ppxlcHalfPelRef, m_vopmd.iSearchRangeForward,0);
  646. pmv16x8++;
  647. // bot to top
  648. Int iSAD16x8bot = blkmatch16x8WithShape (pmv16x8, x, y, 0, ppxlcRefMBY + m_iFrameWidthY,
  649. ppxlcHalfPelRef + m_iFrameWidthY, m_vopmd.iSearchRangeForward,0);
  650. iSAD16x8=(iSAD16x8top<iSAD16x8bot) ? iSAD16x8top : iSAD16x8bot;
  651. pmbmd->m_bForwardTop = (iSAD16x8top<iSAD16x8bot) ? 0 : 1;
  652. pmv16x8++;
  653. // top to bot
  654. iSAD16x8top = blkmatch16x8WithShape (pmv16x8, x, y, MB_SIZE, ppxlcRefMBY,
  655. ppxlcHalfPelRef, m_vopmd.iSearchRangeForward,0);
  656. pmv16x8++;
  657. // bot to bot
  658. iSAD16x8bot = blkmatch16x8WithShape (pmv16x8, x, y, MB_SIZE, ppxlcRefMBY + m_iFrameWidthY,
  659. ppxlcHalfPelRef + m_iFrameWidthY, m_vopmd.iSearchRangeForward,0);
  660. iSAD16x8 += (iSAD16x8top<iSAD16x8bot) ? iSAD16x8top : iSAD16x8bot;
  661. pmbmd->m_bForwardBottom = (iSAD16x8top<iSAD16x8bot) ? 0 : 1;
  662. } else {
  663. iSAD16x8 = 4096*256;
  664. for (Int iBlk = 5; iBlk <= 8; iBlk++) {  // 04/28/99 david ruhoff
  665. pmv [iBlk] = pmv [0];   // fill in field info to make mv file deterministic
  666. }
  667. }
  668. #ifdef __TRACE_AND_STATS_
  669. m_pbitstrmOut->trace (iSAD16x8, "MB_SAD16x8");
  670. #endif // __TRACE_AND_STATS_
  671. // end of New changes
  672. // ~INTERLACE
  673. CoordI blkX, blkY;
  674. Int iSAD8 = 0;
  675. CMotionVector* pmv8 = pmv + 1;
  676. blkX = x + BLOCK_SIZE;
  677. blkY = y + BLOCK_SIZE;
  678. const PixelC* ppxlcCodedBlkY = m_ppxlcCurrMBY;
  679. const PixelC* ppxlcCodedBlkBY = m_ppxlcCurrMBBY;
  680. // 8 x 8
  681. iSAD8 += 
  682. (pmbmd->m_rgTranspStatus [1] == PARTIAL) ? blockmatch8WithShape (ppxlcCodedBlkY, ppxlcCodedBlkBY, pmv8, x, y, pmv, m_vopmd.iSearchRangeForward,0) :
  683. (pmbmd->m_rgTranspStatus [1] == NONE) ? blockmatch8 (ppxlcCodedBlkY, pmv8, x, y, pmv, m_vopmd.iSearchRangeForward) : 0;
  684. pmv8++;
  685. ppxlcCodedBlkY += BLOCK_SIZE;
  686. ppxlcCodedBlkBY += BLOCK_SIZE;
  687. #ifdef __TRACE_AND_STATS_
  688. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  689. #endif // __TRACE_AND_STATS_
  690. iSAD8 += 
  691. (pmbmd->m_rgTranspStatus [2] == PARTIAL) ? blockmatch8WithShape (ppxlcCodedBlkY, ppxlcCodedBlkBY, pmv8, blkX, y, pmv, m_vopmd.iSearchRangeForward,0) :
  692. (pmbmd->m_rgTranspStatus [2] == NONE) ? blockmatch8 (ppxlcCodedBlkY, pmv8, blkX, y, pmv, m_vopmd.iSearchRangeForward) : 0;
  693. pmv8++;
  694. ppxlcCodedBlkY += BLOCK_SIZE * MB_SIZE - BLOCK_SIZE;
  695. ppxlcCodedBlkBY += BLOCK_SIZE * MB_SIZE - BLOCK_SIZE;
  696. #ifdef __TRACE_AND_STATS_
  697. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  698. #endif // __TRACE_AND_STATS_
  699. iSAD8 += 
  700. (pmbmd->m_rgTranspStatus [3] == PARTIAL) ? blockmatch8WithShape (ppxlcCodedBlkY, ppxlcCodedBlkBY, pmv8, x, blkY, pmv, m_vopmd.iSearchRangeForward,0) :
  701. (pmbmd->m_rgTranspStatus [3] == NONE) ? blockmatch8 (ppxlcCodedBlkY, pmv8, x, blkY, pmv, m_vopmd.iSearchRangeForward) : 0;
  702. pmv8++;
  703. ppxlcCodedBlkY += BLOCK_SIZE;
  704. ppxlcCodedBlkBY += BLOCK_SIZE;
  705. #ifdef __TRACE_AND_STATS_
  706. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  707. #endif // __TRACE_AND_STATS_
  708. iSAD8 += 
  709. (pmbmd->m_rgTranspStatus [4] == PARTIAL) ? blockmatch8WithShape (ppxlcCodedBlkY, ppxlcCodedBlkBY, pmv8, blkX, blkY, pmv, m_vopmd.iSearchRangeForward,0) :
  710. (pmbmd->m_rgTranspStatus [4] == NONE) ? blockmatch8 (ppxlcCodedBlkY, pmv8, blkX, blkY, pmv, m_vopmd.iSearchRangeForward) : 0;
  711. #ifdef __TRACE_AND_STATS_
  712. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  713. #endif // __TRACE_AND_STATS_
  714. // begin added by Sharp (98/9/10) prevents inter4v with one transp block
  715. if (( pmbmd->m_rgTranspStatus [1] != ALL && pmbmd->m_rgTranspStatus [2] == ALL
  716. && pmbmd->m_rgTranspStatus [3] == ALL && pmbmd->m_rgTranspStatus [4] == ALL )||
  717. ( pmbmd->m_rgTranspStatus [1] == ALL && pmbmd->m_rgTranspStatus [2] != ALL
  718. && pmbmd->m_rgTranspStatus [3] == ALL && pmbmd->m_rgTranspStatus [4] == ALL )||
  719. ( pmbmd->m_rgTranspStatus [1] == ALL && pmbmd->m_rgTranspStatus [2] == ALL
  720. && pmbmd->m_rgTranspStatus [3] != ALL && pmbmd->m_rgTranspStatus [4] == ALL )||
  721. ( pmbmd->m_rgTranspStatus [1] == ALL && pmbmd->m_rgTranspStatus [2] == ALL
  722. && pmbmd->m_rgTranspStatus [3] == ALL && pmbmd->m_rgTranspStatus [4] != ALL ))
  723. iSAD8 = 256 * 4096;
  724. // end added by Sharp (98/9/10)
  725. #ifdef __TRACE_AND_STATS_
  726. m_pbitstrmOut->trace (iSAD8, "MB_SAD8");
  727. #endif // __TRACE_AND_STATS_
  728. /* NBIT: change
  729. if ((iSADInter - ((pmbmd->m_rgNumNonTranspPixels [0] >> 1) + 1)) <= iSAD8) {
  730. */
  731. // new changes
  732. iSADInter -= iFavor16x16;
  733. iSAD16x8 -= FAVOR_FIELD;
  734. if ((iSADInter <= iSAD8)&&(iSADInter <= iSAD16x8)) {
  735. iSADInter += iFavor16x16;
  736. // end of new changes
  737. pmbmd -> m_bhas4MVForward = FALSE;
  738. pmv -> computeTrueMV (); // compute here instead of blkmatch to save computation
  739. for (UInt i = 1; i < PVOP_MV_PER_REF_PER_MB; i++) // didn't increment the last pmv
  740. pmv [i] = *pmv;
  741. }
  742. // INTERLACE
  743. // new changes
  744. else if (iSAD16x8 <= iSAD8) { // Field-based
  745. pmbmd -> m_bhas4MVForward = FALSE;
  746. pmbmd -> m_bFieldMV = TRUE;
  747. Int iTempX1, iTempY1, iTempX2, iTempY2;
  748. if(pmbmd->m_bForwardTop) {
  749. pmv [6].computeTrueMV ();
  750. iTempX1 = pmv[6].m_vctTrueHalfPel.x;
  751. iTempY1 = pmv[6].m_vctTrueHalfPel.y;
  752. }
  753. else {
  754. pmv [5].computeTrueMV ();
  755. iTempX1 = pmv[5].m_vctTrueHalfPel.x;
  756. iTempY1 = pmv[5].m_vctTrueHalfPel.y;
  757. }
  758. if(pmbmd->m_bForwardBottom) {
  759. pmv [8].computeTrueMV ();
  760. iTempX2 = pmv[8].m_vctTrueHalfPel.x;
  761. iTempY2 = pmv[8].m_vctTrueHalfPel.y;
  762. }
  763. else {
  764. pmv [7].computeTrueMV ();
  765. iTempX2 = pmv[7].m_vctTrueHalfPel.x;
  766. iTempY2 = pmv[7].m_vctTrueHalfPel.y;
  767. }
  768. iSADInter = iSAD16x8 + FAVOR_FIELD;
  769. Int iTemp;
  770. for (UInt i = 1; i < 5; i++) {
  771. iTemp = iTempX1 + iTempX2;
  772. pmv [i].m_vctTrueHalfPel.x = (iTemp & 3) ? ((iTemp>>1) | 1) : (iTemp>>1);
  773. iTemp = iTempY1 + iTempY2;
  774. pmv [i].m_vctTrueHalfPel.y = (iTemp & 3) ? ((iTemp>>1) | 1) : (iTemp>>1);
  775. }
  776. }
  777. //end of new changes
  778. // ~INTERLACE
  779. else {
  780. pmv [1].computeTrueMV ();
  781. pmv [2].computeTrueMV ();
  782. pmv [3].computeTrueMV ();
  783. pmv [4].computeTrueMV ();
  784. pmbmd -> m_bhas4MVForward = TRUE;
  785. iSADInter = iSAD8;
  786. }
  787. /* NBIT: change
  788. if (iSumDev < (iSADInter - (pmbmd->m_rgNumNonTranspPixels [0] << 1))) {
  789. */
  790. if (iSumDev < (iSADInter - iFavorInter)) {
  791. pmbmd -> m_bSkip = FALSE;
  792. pmbmd -> m_dctMd = INTRA;
  793. // new changes
  794. pmbmd -> m_bFieldMV = FALSE;
  795. memset (pmv, 0, PVOP_MV_PER_REF_PER_MB * sizeof (CMotionVector));
  796. return ((m_uiRateControl==RC_MPEG4) ? sumAbsCurrMB () : 0);
  797. }
  798. else {
  799. pmbmd -> m_dctMd = INTER;
  800. // new changes
  801. if (pmbmd->m_bhas4MVForward == FALSE
  802. && pmbmd -> m_bFieldMV == FALSE
  803. && pmv->m_vctTrueHalfPel.x == 0 && pmv->m_vctTrueHalfPel.y == 0)
  804. return (iSADInter + iFavorZero);
  805. else 
  806. return iSADInter;
  807. }
  808. }
  809. CMotionVector rgmvDirectBack [5];
  810. CMotionVector rgmvDirectForward [5];
  811. Int CVideoObjectEncoder::motionEstMB_BVOP (
  812. CoordI x, CoordI y, 
  813. CMotionVector* pmvForward, CMotionVector* pmvBackward,
  814. CMBMode* pmbmd,
  815. const CMBMode* pmbmdRef, const CMotionVector* pmvRef,
  816. const PixelC* ppxlcRef0MBY, const PixelC* ppxlcRef1MBY,
  817. Bool bColocatedMBExist
  818. )
  819. {
  820. //printf("(%d,%d)n", x, y);
  821. Int iInitSAD = sad16x16At0 (ppxlcRef0MBY) + FAVORZERO;
  822. Int iSADForward = blkmatch16 (pmvForward, x, y, x, y, iInitSAD, ppxlcRef0MBY, m_puciRefQZoom0, m_vopmd.iSearchRangeForward);
  823. pmvForward->computeTrueMV ();
  824. Int iSADDirect = 1000000000;
  825. CVector vctRefScaled;
  826. // TPS FIX
  827. if (bColocatedMBExist && pmbmdRef->m_bhas4MVForward == FALSE &&
  828. (m_volmd.volType != ENHN_LAYER || ( m_vopmd.iRefSelectCode != 1 && m_vopmd.iRefSelectCode != 2))) {
  829. Int iPartInterval = m_t - m_tPastRef; //initialize at MVDB = 0
  830. vctRefScaled = pmvRef->trueMVHalfPel () * iPartInterval;
  831. Int iFullInterval = m_tFutureRef - m_tPastRef;
  832. vctRefScaled.x /= iFullInterval; //truncation as per vm
  833. vctRefScaled.y /= iFullInterval; //truncation as per vm
  834. //set up initial forward vector; 
  835. rgmvDirectForward->iMVX = vctRefScaled.x / 2;
  836. rgmvDirectForward->iMVY = vctRefScaled.y / 2;
  837. rgmvDirectForward->iHalfX = 0;
  838. rgmvDirectForward->iHalfY = 0;
  839. rgmvDirectForward->computeTrueMV ();
  840. //set up initial backward vector
  841. pmbmd->m_vctDirectDeltaMV = rgmvDirectForward->m_vctTrueHalfPel - vctRefScaled; //mvdb not necessaryly 0 due to truncation of half pel 
  842. backwardMVFromForwardMV (rgmvDirectBack [0], rgmvDirectForward [0], *pmvRef, pmbmd->m_vctDirectDeltaMV);
  843. //compute initial sad
  844. iSADDirect = interpolateAndDiffY (rgmvDirectForward, rgmvDirectBack, x, y,
  845. &m_rctRefVOPY0, &m_rctRefVOPY1) - FAVORZERO;
  846. //set up inital position in ref frame
  847. Int iXInit = x + rgmvDirectForward->iMVX;
  848. Int iYInit = y + rgmvDirectForward->iMVY;
  849. const PixelC* ppxlcInitRefMBY = m_pvopcRefQ0->pixelsY () + m_rctRefFrameY.offset (iXInit, iYInit);
  850. //compute forward mv and sad; to be continue in iSADMin==iSADDirect
  851. Int isave = m_iMVFileUsage;                       // 04/28/99 david ruhoff
  852. if (!m_volmd.bOriginalForME) m_iMVFileUsage = 0;  // 04/28/99  must not use mv file based on reconstructed vop
  853. iSADDirect = blkmatch16 (rgmvDirectForward, iXInit, iYInit, x, y, iSADDirect, ppxlcInitRefMBY,
  854.         m_puciRefQZoom0, m_vopmd.iDirectModeRadius) - FAVOR_DIRECT;
  855. m_iMVFileUsage = isave;                           // 04/28/99 
  856. rgmvDirectForward->computeTrueMV ();
  857. pmbmd->m_vctDirectDeltaMV = rgmvDirectForward->m_vctTrueHalfPel - vctRefScaled;
  858. backwardMVFromForwardMV (rgmvDirectBack [0], rgmvDirectForward [0], *pmvRef, 
  859.  pmbmd->m_vctDirectDeltaMV);
  860. iSADDirect = interpolateAndDiffY (rgmvDirectForward, rgmvDirectBack, x, y,
  861.   &m_rctRefVOPY0, &m_rctRefVOPY1);
  862. if (pmbmd->m_vctDirectDeltaMV.x == 0 && pmbmd->m_vctDirectDeltaMV.y == 0)
  863. iSADDirect -= FAVORZERO;
  864. }
  865. iInitSAD = sad16x16At0 (ppxlcRef1MBY) + FAVORZERO;
  866. Int iSADBackward = blkmatch16 (pmvBackward, x, y, x, y, iInitSAD, ppxlcRef1MBY, m_puciRefQZoom1, m_vopmd.iSearchRangeBackward);
  867. pmvBackward->computeTrueMV ();
  868. Int iSADInterpolate = interpolateAndDiffY (
  869. pmvForward, pmvBackward,
  870. x, y, &m_rctRefVOPY0, &m_rctRefVOPY1
  871. );
  872. Int iSADMin = minimum (iSADDirect, iSADForward, iSADBackward, iSADInterpolate);
  873. if(m_bCodedFutureRef==FALSE)
  874. iSADMin = iSADForward; // force forward mode
  875. Int iBlk;
  876. if (iSADMin == iSADDirect) {
  877. pmbmd->m_mbType = DIRECT;
  878. //compute backward mv
  879. pmvForward [0]  = rgmvDirectForward  [0];
  880. pmvBackward [0] = rgmvDirectBack [0];
  881. }
  882. else if (iSADMin == iSADForward) {
  883. pmbmd->m_mbType = FORWARD;
  884. }
  885. else if (iSADMin == iSADBackward) {
  886. pmbmd->m_mbType = BACKWARD;
  887. }
  888. else {
  889. pmbmd->m_mbType = INTERPOLATE;
  890. }
  891. for (iBlk = 1; iBlk <= 4; iBlk++) {
  892. pmvForward [iBlk] = pmvForward [0];
  893. pmvBackward [iBlk] = pmvBackward [0];
  894. }
  895. return iSADMin;
  896. }
  897. // for spatial scalability only
  898. Int CVideoObjectEncoder::motionEstMB_BVOP (
  899. CoordI x, CoordI y, 
  900. CMotionVector* pmvForward, CMotionVector* pmvBackward,
  901. CMBMode* pmbmd,
  902. const PixelC* ppxlcRef0MBY, const PixelC* ppxlcRef1MBY
  903. )
  904. {
  905. Int iInitSAD = sad16x16At0 (ppxlcRef0MBY);
  906. Int iSADForward = blkmatch16 (pmvForward, x, y,x,y, iInitSAD, ppxlcRef0MBY, m_puciRefQZoom0, m_vopmd.iSearchRangeForward);
  907. pmvForward->computeTrueMV ();
  908. //Int iSADDirect = 1000000000;
  909. iInitSAD = sad16x16At0 (ppxlcRef1MBY);
  910. Int iSADBackward = iInitSAD;
  911. *pmvBackward = CMotionVector (0,0);
  912. pmvBackward->computeTrueMV ();
  913. Int iSADInterpolate = interpolateAndDiffY (pmvForward, pmvBackward, x, y,
  914. &m_rctRefVOPY0, &m_rctRefVOPY1);
  915. Int iSADMin=0;
  916. if(iSADForward <= iSADBackward && iSADForward <= iSADInterpolate)
  917. iSADMin = iSADForward;
  918. else if (iSADBackward <= iSADInterpolate)
  919. iSADMin = iSADBackward;
  920. else
  921. iSADMin = iSADInterpolate;
  922. Int iBlk;
  923. if (iSADMin == iSADForward) {
  924. pmbmd->m_mbType = FORWARD;
  925. }
  926. else if (iSADMin == iSADBackward) {
  927. pmbmd->m_mbType = BACKWARD;
  928. }
  929. else {
  930. pmbmd->m_mbType = INTERPOLATE;
  931. }
  932. for (iBlk = 1; iBlk <= 4; iBlk++) {
  933. pmvForward [iBlk] = pmvForward [0];
  934. pmvBackward [iBlk] = pmvBackward [0];
  935. }
  936. return iSADMin;
  937. }
  938. Int CVideoObjectEncoder::motionEstMB_BVOP_WithShape (
  939. CoordI x, CoordI y, 
  940. CMotionVector* pmvForward, CMotionVector* pmvBackward,
  941. CMBMode* pmbmd, 
  942. const CMBMode* pmbmdRef, const CMotionVector* pmvRef,
  943. const PixelC* ppxlcRef0MBY, const PixelC* ppxlcRef1MBY,
  944. Bool bColocatedMBExist
  945. )
  946. {
  947. assert (pmbmd->m_rgTranspStatus [0] == PARTIAL);
  948. Int iInitSAD = sad16x16At0WithShape (ppxlcRef0MBY, pmbmd); //shouldn't favor 0 mv inside this function
  949. Int iSADForward = blkmatch16WithShape (pmvForward, x, y, x, y, iInitSAD, ppxlcRef0MBY,
  950.         m_puciRefQZoom0, pmbmd, m_vopmd.iSearchRangeForward,0);
  951. pmvForward->computeTrueMV ();
  952. Int iSADDirect = 1000000000;
  953. CVector vctRefScaled;
  954. if (bColocatedMBExist && pmbmdRef->m_bhas4MVForward == FALSE && 
  955. (m_volmd.volType != ENHN_LAYER || ( m_vopmd.iRefSelectCode != 1 && m_vopmd.iRefSelectCode != 2))) {
  956. Int iPartInterval = m_t - m_tPastRef; //initialize at MVDB = 0
  957. vctRefScaled = pmvRef->trueMVHalfPel () * iPartInterval;
  958. Int iFullInterval = m_tFutureRef - m_tPastRef;
  959. vctRefScaled.x /= iFullInterval; //truncation as per vm
  960. vctRefScaled.y /= iFullInterval; //truncation as per vm
  961. //set up initial forward vector; 
  962. rgmvDirectForward->iMVX = vctRefScaled.x / 2;
  963. rgmvDirectForward->iMVY = vctRefScaled.y / 2;
  964. rgmvDirectForward->iHalfX = 0;
  965. rgmvDirectForward->iHalfY = 0;
  966. rgmvDirectForward->computeTrueMV ();
  967. //set up initial backward vector
  968. pmbmd->m_vctDirectDeltaMV = rgmvDirectForward->m_vctTrueHalfPel - vctRefScaled; //mvdb not necessaryly 0 due to truncation of half pel 
  969. backwardMVFromForwardMV (rgmvDirectBack [0], rgmvDirectForward [0], *pmvRef, pmbmd->m_vctDirectDeltaMV);
  970. //compute initial sad
  971. iSADDirect = interpolateAndDiffY_WithShape (rgmvDirectForward, rgmvDirectBack, x, y,
  972. &m_rctRefVOPY0, &m_rctRefVOPY1) - FAVORZERO;;
  973. //set up inital position in ref frame
  974. Int iXInit = x + rgmvDirectForward->iMVX;
  975. Int iYInit = y + rgmvDirectForward->iMVY;
  976. const PixelC* ppxlcInitRefMBY = m_pvopcRefQ0->pixelsY () + m_rctRefFrameY.offset (iXInit, iYInit);
  977. //compute forward mv and sad; to be continue in iSADMin==iSADDirect
  978. Int isave = m_iMVFileUsage;                       // 04/28/99 david ruhoff
  979. if (!m_volmd.bOriginalForME) m_iMVFileUsage = 0;  // 04/28/99  must not use mv file based on reconstructed vop
  980. iSADDirect = blkmatch16WithShape  (rgmvDirectForward, iXInit, iYInit, x, y, iSADDirect, ppxlcInitRefMBY,
  981.         m_puciRefQZoom0, pmbmd, m_vopmd.iDirectModeRadius,0) - FAVOR_DIRECT;
  982. m_iMVFileUsage = isave;                           // 04/28/99 
  983. rgmvDirectForward->computeTrueMV ();
  984. pmbmd->m_vctDirectDeltaMV = rgmvDirectForward->m_vctTrueHalfPel - vctRefScaled;
  985. backwardMVFromForwardMV (rgmvDirectBack [0], rgmvDirectForward [0], *pmvRef, 
  986.  pmbmd->m_vctDirectDeltaMV);
  987. iSADDirect = interpolateAndDiffY (rgmvDirectForward, rgmvDirectBack, x, y,
  988.   &m_rctRefVOPY0, &m_rctRefVOPY1);
  989. if (pmbmd->m_vctDirectDeltaMV.x == 0 && pmbmd->m_vctDirectDeltaMV.y == 0)
  990. iSADDirect -= FAVORZERO;
  991. }
  992. iInitSAD = sad16x16At0WithShape (ppxlcRef1MBY, pmbmd);//shouldn't favor 0 mv inside this function
  993. Int iSADBackward = blkmatch16WithShape (pmvBackward, x, y, x, y, iInitSAD, ppxlcRef1MBY,
  994. m_puciRefQZoom1, pmbmd, m_vopmd.iSearchRangeBackward,1);
  995. pmvBackward->computeTrueMV ();
  996. Int iSADInterpolate = interpolateAndDiffY_WithShape (
  997. pmvForward, pmvBackward,
  998. x, y, &m_rctRefVOPY0, &m_rctRefVOPY1
  999. );
  1000. Int iSADMin = minimum (iSADDirect, iSADForward, iSADBackward, iSADInterpolate);
  1001. Int iBlk;
  1002. if(m_bCodedFutureRef==FALSE)
  1003. iSADMin = iSADForward; // force forward mode
  1004. if (iSADMin == iSADDirect) {
  1005. pmbmd->m_mbType = DIRECT;
  1006. //compute backward mv
  1007. pmvForward [0] = rgmvDirectForward [0];
  1008. pmvBackward [0] = rgmvDirectBack [0];
  1009. }
  1010. else if (iSADMin == iSADForward) {
  1011. pmbmd->m_mbType = FORWARD;
  1012. }
  1013. else if (iSADMin == iSADBackward) {
  1014. pmbmd->m_mbType = BACKWARD;
  1015. }
  1016. else {
  1017. pmbmd->m_mbType = INTERPOLATE;
  1018. }
  1019. for (iBlk = 1; iBlk <= 4; iBlk++) {
  1020. pmvForward [iBlk] = pmvForward [0];
  1021. pmvBackward [iBlk] = pmvBackward [0];
  1022. }
  1023. return iSADMin;
  1024. }
  1025. // INTERLACE
  1026. #define BbiasAgainstFrameAve ((MB_SIZE*MB_SIZE)/2 + 1) // Biases favor modes with fewer MVs
  1027. #define BbiasAgainstFieldAve ((MB_SIZE*MB_SIZE)/1 + 1)
  1028. #define BbiasAgainstField ((MB_SIZE*MB_SIZE)/2 + 1)
  1029. #define BbiasFavorDirect ((MB_SIZE*MB_SIZE)/2 + 1)
  1030. Int CVideoObjectEncoder::motionEstMB_BVOP_Interlaced (
  1031. CoordI x, CoordI y, 
  1032. CMotionVector* pmvForward, CMotionVector* pmvBackward,
  1033. CMBMode* pmbmd,
  1034. const CMBMode* pmbmdRef, const CMotionVector* pmvRef,
  1035. const PixelC* ppxlcRef0MBY, const PixelC* ppxlcRef1MBY,
  1036. Bool bColocatedMBExist
  1037. )
  1038. {
  1039. Int iSAD, iSADnobias, iFieldSAD, iSADFrmMB[3];
  1040. MBType mbtype;
  1041. iSADFrmMB[0] = blkmatch16(pmvForward, x, y,x,y, sad16x16At0 (ppxlcRef0MBY),
  1042. ppxlcRef0MBY, m_puciRefQZoom0, m_vopmd.iSearchRangeForward);
  1043. pmvForward->computeTrueMV ();
  1044. iSADFrmMB[1] = blkmatch16(pmvBackward, x, y,x,y, sad16x16At0 (ppxlcRef1MBY),
  1045. ppxlcRef1MBY, m_puciRefQZoom1, m_vopmd.iSearchRangeBackward);
  1046. pmvBackward->computeTrueMV ();
  1047. iSADFrmMB[2] = interpolateAndDiffY(pmvForward, pmvBackward, x, y
  1048. , &m_rctRefVOPY0, &m_rctRefVOPY1);
  1049. #ifdef __TRACE_AND_STATS_
  1050. m_pbitstrmOut->trace (iSADFrmMB, 3, "SADFrmMB");
  1051. #endif // __TRACE_AND_STATS_
  1052. // Choose best 16x16 mode
  1053. pmbmd->m_bFieldMV = FALSE;
  1054. if (iSADFrmMB[0] < iSADFrmMB[1]) {
  1055. iSAD = iSADFrmMB[0];
  1056. pmbmd->m_mbType = FORWARD;
  1057. } else {
  1058. iSAD = iSADFrmMB[1];
  1059. pmbmd->m_mbType = BACKWARD;
  1060. }
  1061. iSADnobias = iSAD;
  1062. if ((iSADFrmMB[2] + BbiasAgainstFrameAve) < iSAD) {
  1063. iSAD = iSADFrmMB[2] + BbiasAgainstFrameAve;
  1064. iSADnobias = iSADFrmMB[2];
  1065. pmbmd->m_mbType = INTERPOLATE;
  1066. }
  1067. if(m_bCodedFutureRef==FALSE)
  1068. {
  1069. iSAD = iSADFrmMB[0];
  1070. pmbmd->m_mbType = FORWARD; // force forward mode
  1071. }
  1072. if (m_vopmd.bInterlace) {
  1073. const PixelC *ppxlcFwdHalfPelRef = m_pvopcRefQ0->pixelsY()
  1074. +EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME+ x + y * m_iFrameWidthY; // 1.31.99 changes
  1075. const PixelC *ppxlcBakHalfPelRef = m_pvopcRefQ1->pixelsY()
  1076. +EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME+ x + y * m_iFrameWidthY; // 1.31.99 changes
  1077. Int iSADFldMB[3], iSADFld[8];
  1078. // Choose best fwd top field predictor
  1079. iSADFld[0] = blkmatch16x8 (pmvForward+1, x, y, 0,
  1080. ppxlcRef0MBY, ppxlcFwdHalfPelRef, m_vopmd.iSearchRangeForward);
  1081. pmvForward[1].computeTrueMV();
  1082. iSADFld[1] = blkmatch16x8 (pmvForward+2, x, y, 0,
  1083. ppxlcRef0MBY + m_iFrameWidthY, ppxlcFwdHalfPelRef + m_iFrameWidthY,
  1084. m_vopmd.iSearchRangeForward);
  1085. pmvForward[2].computeTrueMV();
  1086. if (iSADFld[0] <= iSADFld[1]) {
  1087. pmbmd->m_bForwardTop = 0;
  1088. iSADFldMB[0] = iSADFld[0];
  1089. } else {
  1090. pmbmd->m_bForwardTop = 1;
  1091. iSADFldMB[0] = iSADFld[1];
  1092. }
  1093. // Choose best fwd botton field predictor
  1094. iSADFld[2] = blkmatch16x8 (pmvForward+3, x, y, MB_SIZE,
  1095. ppxlcRef0MBY, ppxlcFwdHalfPelRef, m_vopmd.iSearchRangeForward);
  1096. pmvForward[3].computeTrueMV();
  1097. iSADFld[3] = blkmatch16x8 (pmvForward+4, x, y, MB_SIZE,
  1098. ppxlcRef0MBY + m_iFrameWidthY, ppxlcFwdHalfPelRef + m_iFrameWidthY,
  1099. m_vopmd.iSearchRangeForward);
  1100. pmvForward[4].computeTrueMV();
  1101. if (iSADFld[2] < iSADFld[3]) {
  1102. pmbmd->m_bForwardBottom = 0;
  1103. iSADFldMB[0] += iSADFld[2];
  1104. } else {
  1105. pmbmd->m_bForwardBottom = 1;
  1106. iSADFldMB[0] += iSADFld[3];
  1107. }
  1108. // Choose best bak top field predictor
  1109. iSADFld[4] = blkmatch16x8 (pmvBackward+1, x, y, 0,
  1110. ppxlcRef1MBY, ppxlcBakHalfPelRef, m_vopmd.iSearchRangeBackward);
  1111. pmvBackward[1].computeTrueMV();
  1112. iSADFld[5] = blkmatch16x8 (pmvBackward+2, x, y, 0,
  1113. ppxlcRef1MBY + m_iFrameWidthY, ppxlcBakHalfPelRef + m_iFrameWidthY,
  1114. m_vopmd.iSearchRangeBackward);
  1115. pmvBackward[2].computeTrueMV();
  1116. if (iSADFld[4] <= iSADFld[5]) {
  1117. pmbmd->m_bBackwardTop = 0;
  1118. iSADFldMB[1] = iSADFld[4];
  1119. } else {
  1120. pmbmd->m_bBackwardTop = 1;
  1121. iSADFldMB[1] = iSADFld[5];
  1122. }
  1123. // Choose best bak bottom field predictor
  1124. iSADFld[6] = blkmatch16x8 (pmvBackward+3, x, y, MB_SIZE,
  1125. ppxlcRef1MBY, ppxlcBakHalfPelRef, m_vopmd.iSearchRangeBackward);
  1126. pmvBackward[3].computeTrueMV();
  1127. iSADFld[7] = blkmatch16x8 (pmvBackward+4, x, y, MB_SIZE,
  1128. ppxlcRef1MBY + m_iFrameWidthY, ppxlcBakHalfPelRef + m_iFrameWidthY,
  1129. m_vopmd.iSearchRangeBackward);
  1130. pmvBackward[4].computeTrueMV();
  1131. if (iSADFld[6] < iSADFld[7]) {
  1132. pmbmd->m_bBackwardBottom = 0;
  1133. iSADFldMB[1] += iSADFld[6];
  1134. } else {
  1135. pmbmd->m_bBackwardBottom = 1;
  1136. iSADFldMB[1] += iSADFld[7];
  1137. }
  1138. // Choose best of forward & backward field prediction
  1139. if (iSADFldMB[0] <= iSADFldMB[1]) {
  1140. iFieldSAD = iSADFldMB[0];
  1141. mbtype = FORWARD;
  1142. } else {
  1143. iFieldSAD = iSADFldMB[1];
  1144. mbtype = BACKWARD;
  1145. }
  1146. iFieldSAD += BbiasAgainstField;
  1147. iSADFldMB[2] = interpolateAndDiffYField(
  1148. pmvForward  + 1 + (int)pmbmd->m_bForwardTop,
  1149. pmvForward  + 3 + (int)pmbmd->m_bForwardBottom,
  1150. pmvBackward + 1 + (int)pmbmd->m_bBackwardTop,
  1151. pmvBackward + 3 + (int)pmbmd->m_bBackwardBottom,
  1152. x, y, pmbmd);
  1153. if ((iSADFldMB[2] + BbiasAgainstFieldAve) < iFieldSAD) {
  1154. iFieldSAD = iSADFldMB[2] + BbiasAgainstFieldAve;
  1155. mbtype = INTERPOLATE;
  1156. }
  1157. if(m_bCodedFutureRef==FALSE) // FORCE FORWARD
  1158. {
  1159. iFieldSAD = iSADFldMB[0];
  1160. mbtype = FORWARD;
  1161. }
  1162. // Field versus Frame prediction
  1163. if (iFieldSAD < iSAD) {
  1164. pmbmd->m_bFieldMV = TRUE;
  1165. pmbmd->m_mbType = mbtype;
  1166. iSAD = iFieldSAD;
  1167. iSADnobias = iFieldSAD - ((mbtype == INTERPOLATE) ? BbiasAgainstFieldAve : BbiasAgainstField);
  1168. }
  1169. #ifdef __TRACE_AND_STATS_
  1170. m_pbitstrmOut->trace (iSADFld,   8, "SADFld");
  1171. m_pbitstrmOut->trace (iSADFldMB, 3, "SADFldMB");
  1172. #endif // __TRACE_AND_STATS_
  1173. }
  1174. #if 1 // #if 0 to temporarily disable direct mode (debug only)
  1175. // Check direct mode
  1176. Int iSADDirect = 0;
  1177. if (bColocatedMBExist && m_volmd.fAUsage == RECTANGLE) {
  1178. iSADDirect= (pmbmdRef->m_bFieldMV) ?
  1179. directSADField(x, y, pmbmd, pmbmdRef, pmvRef, ppxlcRef0MBY, ppxlcRef1MBY) :
  1180. directSAD     (x, y, pmbmd, pmbmdRef, pmvRef);
  1181. if ((iSADDirect - BbiasFavorDirect) < iSAD) {
  1182. pmbmd->m_mbType = DIRECT;
  1183. pmbmd->m_bFieldMV = pmbmdRef->m_bFieldMV;
  1184. iSADnobias = iSADDirect;
  1185. }
  1186. }
  1187. #endif
  1188. #ifdef __TRACE_AND_STATS_
  1189. static char *cDirectType[] = { "FrmDirectSAD", "FldDirectSAD" };
  1190. static char *cWinner[] = { "FrmDirectn", "FrmAven", "FrmBakn", "FrmFwdn", "FldDirectn", "FldAven", "FldBakn", "FldFwdn" };
  1191. if(bColocatedMBExist)
  1192. m_pbitstrmOut->trace (iSADDirect, cDirectType[pmbmdRef->m_bFieldMV]);
  1193. m_pbitstrmOut->trace (cWinner[(Int)pmbmd->m_mbType + 4*pmbmd->m_bFieldMV]);
  1194. #if 0 // Put all MV candidates in trace file
  1195. Int iMV[10];
  1196. iMV[0] = pmvForward[0].m_vctTrueHalfPel.x; iMV[1] = pmvForward[0].m_vctTrueHalfPel.y;
  1197. iMV[2] = pmvForward[1].m_vctTrueHalfPel.x; iMV[3] = pmvForward[1].m_vctTrueHalfPel.y;
  1198. iMV[4] = pmvForward[2].m_vctTrueHalfPel.x; iMV[5] = pmvForward[2].m_vctTrueHalfPel.y;
  1199. iMV[6] = pmvForward[3].m_vctTrueHalfPel.x; iMV[7] = pmvForward[3].m_vctTrueHalfPel.y;
  1200. iMV[8] = pmvForward[4].m_vctTrueHalfPel.x; iMV[9] = pmvForward[4].m_vctTrueHalfPel.y;
  1201. m_pbitstrmOut->trace (iMV, 10, "FwdMV");
  1202. iMV[0] = pmvBackward[0].m_vctTrueHalfPel.x; iMV[1] = pmvBackward[0].m_vctTrueHalfPel.y;
  1203. iMV[2] = pmvBackward[1].m_vctTrueHalfPel.x; iMV[3] = pmvBackward[1].m_vctTrueHalfPel.y;
  1204. iMV[4] = pmvBackward[2].m_vctTrueHalfPel.x; iMV[5] = pmvBackward[2].m_vctTrueHalfPel.y;
  1205. iMV[6] = pmvBackward[3].m_vctTrueHalfPel.x; iMV[7] = pmvBackward[3].m_vctTrueHalfPel.y;
  1206. iMV[8] = pmvBackward[4].m_vctTrueHalfPel.x; iMV[9] = pmvBackward[4].m_vctTrueHalfPel.y;
  1207. m_pbitstrmOut->trace (iMV, 10, "BakMV");
  1208. #endif
  1209. #endif // __TRACE_AND_STATS_
  1210. pmbmd->m_bhas4MVForward  = FALSE;
  1211. pmbmd->m_bhas4MVBackward = FALSE;
  1212. return iSADnobias;
  1213. }
  1214. //end of INTERLACED
  1215. //INTERLACED
  1216. // new changes
  1217. Int CVideoObjectEncoder::motionEstMB_BVOP_InterlacedWithShape (
  1218. CoordI x, CoordI y, 
  1219. CMotionVector* pmvForward, CMotionVector* pmvBackward,
  1220. CMBMode* pmbmd,
  1221. const CMBMode* pmbmdRef, const CMotionVector* pmvRef,
  1222. const PixelC* ppxlcRef0MBY, const PixelC* ppxlcRef1MBY,
  1223. Bool bColocatedMBExist
  1224. )
  1225. {
  1226. assert (pmbmd->m_rgTranspStatus [0] == PARTIAL);
  1227. Int iSAD, iSADnobias, iFieldSAD, iSADFrmMB[3];
  1228. MBType mbtype;
  1229. iSADFrmMB[0] = blkmatch16WithShape(pmvForward, x, y,x,y, sad16x16At0WithShape (ppxlcRef0MBY,pmbmd),
  1230. ppxlcRef0MBY, m_puciRefQZoom0, pmbmd, m_vopmd.iSearchRangeForward,0);
  1231. pmvForward->computeTrueMV ();
  1232. iSADFrmMB[1] = blkmatch16WithShape(pmvBackward, x, y,x,y, sad16x16At0WithShape (ppxlcRef1MBY,pmbmd),
  1233. ppxlcRef1MBY, m_puciRefQZoom1, pmbmd, m_vopmd.iSearchRangeBackward,1);
  1234. pmvBackward->computeTrueMV ();
  1235. iSADFrmMB[2] = interpolateAndDiffY_WithShape(pmvForward, pmvBackward, x, y
  1236. , &m_rctRefVOPY0, &m_rctRefVOPY1);
  1237. #ifdef __TRACE_AND_STATS_
  1238. m_pbitstrmOut->trace (iSADFrmMB, 3, "SADFrmMB");
  1239. #endif // __TRACE_AND_STATS_
  1240. // Choose best 16x16 mode
  1241. pmbmd->m_bFieldMV = FALSE;
  1242. if (iSADFrmMB[0] < iSADFrmMB[1]) {
  1243. iSAD = iSADFrmMB[0];
  1244. pmbmd->m_mbType = FORWARD;
  1245. } else {
  1246. iSAD = iSADFrmMB[1];
  1247. pmbmd->m_mbType = BACKWARD;
  1248. }
  1249. iSADnobias = iSAD;
  1250. if ((iSADFrmMB[2] + BbiasAgainstFrameAve) < iSAD) {
  1251. iSAD = iSADFrmMB[2] + BbiasAgainstFrameAve;
  1252. iSADnobias = iSADFrmMB[2];
  1253. pmbmd->m_mbType = INTERPOLATE;
  1254. }
  1255. if(m_bCodedFutureRef==FALSE) // force forward
  1256. {
  1257. iSAD = iSADFrmMB[0];
  1258. pmbmd->m_mbType = FORWARD;
  1259. }
  1260. if (m_vopmd.bInterlace) {
  1261. const PixelC *ppxlcFwdHalfPelRef = m_pvopcRefQ0->pixelsY()
  1262. +EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME+ x + y * m_iFrameWidthY; // 1.31.99 changes
  1263. const PixelC *ppxlcBakHalfPelRef = m_pvopcRefQ1->pixelsY()
  1264. +EXPANDY_REF_FRAME * m_iFrameWidthY + EXPANDY_REF_FRAME+ x + y * m_iFrameWidthY; // 1.31.99 changes
  1265. Int iSADFldMB[3], iSADFld[8];
  1266. // Choose best fwd top field predictor
  1267. iSADFld[0] = blkmatch16x8WithShape (pmvForward+1, x, y, 0,
  1268. ppxlcRef0MBY, ppxlcFwdHalfPelRef, m_vopmd.iSearchRangeForward,0);
  1269. pmvForward[1].computeTrueMV();
  1270. iSADFld[1] = blkmatch16x8WithShape (pmvForward+2, x, y, 0,
  1271. ppxlcRef0MBY + m_iFrameWidthY, ppxlcFwdHalfPelRef + m_iFrameWidthY,
  1272. m_vopmd.iSearchRangeForward,0);
  1273. pmvForward[2].computeTrueMV();
  1274. if (iSADFld[0] <= iSADFld[1]) {
  1275. pmbmd->m_bForwardTop = 0;
  1276. iSADFldMB[0] = iSADFld[0];
  1277. } else {
  1278. pmbmd->m_bForwardTop = 1;
  1279. iSADFldMB[0] = iSADFld[1];
  1280. }
  1281. // Choose best fwd botton field predictor
  1282. iSADFld[2] = blkmatch16x8WithShape (pmvForward+3, x, y, MB_SIZE,
  1283. ppxlcRef0MBY, ppxlcFwdHalfPelRef, m_vopmd.iSearchRangeForward,0);
  1284. pmvForward[3].computeTrueMV();
  1285. iSADFld[3] = blkmatch16x8WithShape (pmvForward+4, x, y, MB_SIZE,
  1286. ppxlcRef0MBY + m_iFrameWidthY, ppxlcFwdHalfPelRef + m_iFrameWidthY,
  1287. m_vopmd.iSearchRangeForward,0);
  1288. pmvForward[4].computeTrueMV();
  1289. if (iSADFld[2] < iSADFld[3]) {
  1290. pmbmd->m_bForwardBottom = 0;
  1291. iSADFldMB[0] += iSADFld[2];
  1292. } else {
  1293. pmbmd->m_bForwardBottom = 1;
  1294. iSADFldMB[0] += iSADFld[3];
  1295. }
  1296. // Choose best bak top field predictor
  1297. iSADFld[4] = blkmatch16x8WithShape (pmvBackward+1, x, y, 0,
  1298. ppxlcRef1MBY, ppxlcBakHalfPelRef, m_vopmd.iSearchRangeBackward,1);
  1299. pmvBackward[1].computeTrueMV();
  1300. iSADFld[5] = blkmatch16x8WithShape (pmvBackward+2, x, y, 0,
  1301. ppxlcRef1MBY + m_iFrameWidthY, ppxlcBakHalfPelRef + m_iFrameWidthY,
  1302. m_vopmd.iSearchRangeBackward,1);
  1303. pmvBackward[2].computeTrueMV();
  1304. if (iSADFld[4] <= iSADFld[5]) {
  1305. pmbmd->m_bBackwardTop = 0;
  1306. iSADFldMB[1] = iSADFld[4];
  1307. } else {
  1308. pmbmd->m_bBackwardTop = 1;
  1309. iSADFldMB[1] = iSADFld[5];
  1310. }
  1311. // Choose best bak bottom field predictor
  1312. iSADFld[6] = blkmatch16x8WithShape (pmvBackward+3, x, y, MB_SIZE,
  1313. ppxlcRef1MBY, ppxlcBakHalfPelRef, m_vopmd.iSearchRangeBackward,1);
  1314. pmvBackward[3].computeTrueMV();
  1315. iSADFld[7] = blkmatch16x8WithShape (pmvBackward+4, x, y, MB_SIZE,
  1316. ppxlcRef1MBY + m_iFrameWidthY, ppxlcBakHalfPelRef + m_iFrameWidthY,
  1317. m_vopmd.iSearchRangeBackward,1);
  1318. pmvBackward[4].computeTrueMV();
  1319. if (iSADFld[6] < iSADFld[7]) {
  1320. pmbmd->m_bBackwardBottom = 0;
  1321. iSADFldMB[1] += iSADFld[6];
  1322. } else {
  1323. pmbmd->m_bBackwardBottom = 1;
  1324. iSADFldMB[1] += iSADFld[7];
  1325. }
  1326. // Choose best of forward & backward field prediction
  1327. if (iSADFldMB[0] <= iSADFldMB[1]) {
  1328. iFieldSAD = iSADFldMB[0];
  1329. mbtype = FORWARD;
  1330. } else {
  1331. iFieldSAD = iSADFldMB[1];
  1332. mbtype = BACKWARD;
  1333. }
  1334. iFieldSAD += BbiasAgainstField;
  1335. iSADFldMB[2] = interpolateAndDiffYField(
  1336. pmvForward  + 1 + (int)pmbmd->m_bForwardTop,
  1337. pmvForward  + 3 + (int)pmbmd->m_bForwardBottom,
  1338. pmvBackward + 1 + (int)pmbmd->m_bBackwardTop,
  1339. pmvBackward + 3 + (int)pmbmd->m_bBackwardBottom,
  1340. x, y, pmbmd);
  1341. if ((iSADFldMB[2] + BbiasAgainstFieldAve) < iFieldSAD) {
  1342. iFieldSAD = iSADFldMB[2] + BbiasAgainstFieldAve;
  1343. mbtype = INTERPOLATE;
  1344. }
  1345. if(m_bCodedFutureRef==FALSE) // force forward
  1346. {
  1347. iFieldSAD = iSADFldMB[0];
  1348. mbtype = FORWARD;
  1349. }
  1350. // Field versus Frame prediction
  1351. if (iFieldSAD < iSAD) {
  1352. pmbmd->m_bFieldMV = TRUE;
  1353. pmbmd->m_mbType = mbtype;
  1354. iSAD = iFieldSAD;
  1355. iSADnobias = iFieldSAD - ((mbtype == INTERPOLATE) ? BbiasAgainstFieldAve : BbiasAgainstField);
  1356. }
  1357. #ifdef __TRACE_AND_STATS_
  1358. m_pbitstrmOut->trace (iSADFld,   8, "SADFld");
  1359. m_pbitstrmOut->trace (iSADFldMB, 3, "SADFldMB");
  1360. #endif // __TRACE_AND_STATS_
  1361. }
  1362. #if 1 // #if 0 to temporarily disable direct mode (debug only)
  1363. // Check direct mode
  1364. // new changes
  1365. /* Int iSADDirect;
  1366. if (bColocatedMBExist) {
  1367. iSADDirect = (pmbmdRef->m_bFieldMV) ?
  1368. directSADField(x, y, pmbmd, pmbmdRef, pmvRef, ppxlcRef0MBY, ppxlcRef1MBY) :
  1369. directSAD     (x, y, pmbmd, pmbmdRef, pmvRef);
  1370. if ((iSADDirect - BbiasFavorDirect) < iSAD) {
  1371. pmbmd->m_mbType = DIRECT;
  1372. pmbmd->m_bFieldMV = pmbmdRef->m_bFieldMV;
  1373. iSADnobias = iSADDirect;
  1374. }
  1375. }  */
  1376. #endif
  1377. #ifdef __TRACE_AND_STATS_
  1378. /* static char *cDirectType[] = { "FrmDirectSAD", "FldDirectSAD" };
  1379. static char *cWinner[] = { "FrmDirectn", "FrmAven", "FrmBakn", "FrmFwdn", "FldDirectn", "FldAven", "FldBakn", "FldFwdn" };
  1380. if (bColocatedMBExist)
  1381. m_pbitstrmOut->trace (iSADDirect, cDirectType[pmbmdRef->m_bFieldMV]);
  1382. m_pbitstrmOut->trace (cWinner[(Int)pmbmd->m_mbType + 4*pmbmd->m_bFieldMV]); */
  1383. #if 0 // Put all MV candidates in trace file
  1384. Int iMV[10];
  1385. iMV[0] = pmvForward[0].m_vctTrueHalfPel.x; iMV[1] = pmvForward[0].m_vctTrueHalfPel.y;
  1386. iMV[2] = pmvForward[1].m_vctTrueHalfPel.x; iMV[3] = pmvForward[1].m_vctTrueHalfPel.y;
  1387. iMV[4] = pmvForward[2].m_vctTrueHalfPel.x; iMV[5] = pmvForward[2].m_vctTrueHalfPel.y;
  1388. iMV[6] = pmvForward[3].m_vctTrueHalfPel.x; iMV[7] = pmvForward[3].m_vctTrueHalfPel.y;
  1389. iMV[8] = pmvForward[4].m_vctTrueHalfPel.x; iMV[9] = pmvForward[4].m_vctTrueHalfPel.y;
  1390. m_pbitstrmOut->trace (iMV, 10, "FwdMV");
  1391. iMV[0] = pmvBackward[0].m_vctTrueHalfPel.x; iMV[1] = pmvBackward[0].m_vctTrueHalfPel.y;
  1392. iMV[2] = pmvBackward[1].m_vctTrueHalfPel.x; iMV[3] = pmvBackward[1].m_vctTrueHalfPel.y;
  1393. iMV[4] = pmvBackward[2].m_vctTrueHalfPel.x; iMV[5] = pmvBackward[2].m_vctTrueHalfPel.y;
  1394. iMV[6] = pmvBackward[3].m_vctTrueHalfPel.x; iMV[7] = pmvBackward[3].m_vctTrueHalfPel.y;
  1395. iMV[8] = pmvBackward[4].m_vctTrueHalfPel.x; iMV[9] = pmvBackward[4].m_vctTrueHalfPel.y;
  1396. m_pbitstrmOut->trace (iMV, 10, "BakMV");
  1397. #endif
  1398. #endif // __TRACE_AND_STATS_
  1399. pmbmd->m_bhas4MVForward  = FALSE;
  1400. pmbmd->m_bhas4MVBackward = FALSE;
  1401. return iSADnobias;
  1402. }
  1403. //end of new changes
  1404. //end of INTERLACED
  1405. Int CVideoObjectEncoder::blkmatch16 (
  1406. CMotionVector* pmv, 
  1407. CoordI iXRef, CoordI iYRef,
  1408. CoordI iXCurr, CoordI iYCurr,
  1409. Int iMinSAD,
  1410. const PixelC* ppxlcRefMBY,
  1411. const CU8Image* puciRefQZoomY,
  1412. Int iSearchRange
  1413. )
  1414. {
  1415. Int mbDiff; // start with big
  1416. Int iXDest = iXRef, iYDest = iYRef;
  1417. CoordI x = iXRef, y = iYRef, ix, iy;
  1418. Int uiPosInLoop, iLoop;
  1419. if (m_iMVFileUsage != 1) {
  1420.     // Spiral Search for the rest
  1421.     for (iLoop = 1; iLoop <= iSearchRange; iLoop++) {
  1422.     x++;
  1423.     y++;
  1424.     ppxlcRefMBY += m_iFrameWidthY + 1;
  1425.     for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  1426. if (
  1427.     x >= m_rctRefVOPY0.left && y >= m_rctRefVOPY0.top && 
  1428.     x <= m_rctRefVOPY0.right - MB_SIZE && y <= m_rctRefVOPY0.bottom - MB_SIZE
  1429.     ) {
  1430.     const PixelC* ppxlcTmpC = m_ppxlcCurrMBY;
  1431.     const PixelC* ppxlcRefMB = ppxlcRefMBY;
  1432.     mbDiff = 0;
  1433.     for (iy = 0; iy < MB_SIZE; iy++) {
  1434.     for (ix = 0; ix < MB_SIZE; ix++)
  1435.     mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefMB [ix]);
  1436.     if (mbDiff >= iMinSAD)
  1437.     goto NEXT_POSITION; // skip the current position
  1438.     ppxlcRefMB += m_iFrameWidthY;
  1439.     ppxlcTmpC += MB_SIZE;
  1440.     }
  1441.     iMinSAD = mbDiff;
  1442.     iXDest = x;
  1443.     iYDest = y;
  1444.     }
  1445. NEXT_POSITION:
  1446.     if (uiPosInLoop < (iLoop << 1)) {
  1447.     ppxlcRefMBY--;
  1448.     x--;
  1449.     }
  1450.     else if (uiPosInLoop < (iLoop << 2)) {
  1451.     ppxlcRefMBY -= m_iFrameWidthY;
  1452.     y--;
  1453.     }
  1454.     else if (uiPosInLoop < (iLoop * 6)) {
  1455.     ppxlcRefMBY++;   
  1456.     x++;
  1457.     }
  1458.     else {
  1459.     ppxlcRefMBY += m_iFrameWidthY;
  1460.     y++;
  1461.     }
  1462.     }
  1463.     }
  1464.     *pmv = CMotionVector (iXDest - iXCurr, iYDest - iYCurr);
  1465. } else {
  1466. iXDest = iXRef + pmv->iMVX;
  1467. iYDest = iYRef + pmv->iMVY;
  1468. }
  1469. /* NBIT: change to a bigger number
  1470. iMinSAD = 256*256; // Reset iMinSAD because reference VOP changed from original to reconstructed (Bob Eifrig)
  1471. */
  1472. iMinSAD = 4096*256;
  1473. /* NBIT: change
  1474. Int iFavorZero = pmv->isZero() ? -FAVORZERO : 0;
  1475. */
  1476. Int iFavorZero = pmv->isZero() ? FAVORZERO : 0;
  1477. Int nBits = m_volmd.nBits;
  1478. if (nBits > 8) {
  1479. iFavorZero <<= (nBits-8);
  1480. } else if (nBits < 8) {
  1481. iFavorZero >>= (8-nBits);
  1482. }
  1483. iFavorZero = -iFavorZero;
  1484. // half pel search
  1485. I8 destHalfX = 0, destHalfY = 0;
  1486. Int lowX = (iXDest == m_rctRefVOPY0.left) ? 0 : -1;
  1487. Int lowY = (iYDest == m_rctRefVOPY0.top) ? 0 : -1;
  1488. Int highX = (iXDest == m_rctRefVOPY0.right - MB_SIZE + 1) ? 0 : 1;
  1489. Int highY = (iYDest == m_rctRefVOPY0.bottom - MB_SIZE + 1) ? 0 : 1;
  1490. const PixelC* ppxlcRefZoom = puciRefQZoomY->pixels ((iXDest << 1) + lowX, (iYDest << 1) + lowY);
  1491. for (Int incY = lowY; incY <= highY; incY++) {
  1492. for (Int incX = lowX; incX <= highX; incX++) {
  1493. const PixelC* ppxlcRefZoomMB = ppxlcRefZoom;
  1494. const PixelC* ppxlcTmpC = m_ppxlcCurrMBY;
  1495. mbDiff = (incX || incY) ? 0 : iFavorZero;
  1496. for (iy = 0; iy < MB_SIZE; iy++) {
  1497. for (ix = 0; ix < MB_SIZE; ix++)
  1498. mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefZoomMB [2 * ix]);
  1499. if (mbDiff > iMinSAD) // Try to find shortest MV in case of equal SADs
  1500. goto NEXT_HALF_POSITION;
  1501. ppxlcRefZoomMB += m_iFrameWidthZoomY * 2;
  1502. ppxlcTmpC += MB_SIZE;
  1503. }
  1504. if ((iMinSAD > mbDiff) ||
  1505. ((abs(pmv->m_vctTrueHalfPel.x + destHalfX) + abs(pmv->m_vctTrueHalfPel.y + destHalfY)) >
  1506.  (abs(pmv->m_vctTrueHalfPel.x + incX)      + abs(pmv->m_vctTrueHalfPel.y + incY)))) {
  1507. iMinSAD = mbDiff;
  1508. destHalfX = incX;
  1509. destHalfY = incY;
  1510. }
  1511. NEXT_HALF_POSITION:
  1512. ppxlcRefZoom++;
  1513. }
  1514. ppxlcRefZoom += m_iFrameWidthZoomY - (highX - lowX + 1);
  1515. }
  1516. pmv -> iHalfX = destHalfX;
  1517. pmv -> iHalfY = destHalfY;
  1518. return iMinSAD;
  1519. }
  1520. Int CVideoObjectEncoder::blkmatch16WithShape (
  1521. CMotionVector* pmv, 
  1522. CoordI iXRef, CoordI iYRef,
  1523. CoordI iXCurr, CoordI iYCurr,
  1524. Int iMinSAD,
  1525. const PixelC* ppxlcRefMBY,
  1526. const CU8Image* puciRefQZoom,
  1527.     const CMBMode *pmbmd,
  1528. Int iSearchRange,
  1529. Int iDirection
  1530. )
  1531. {
  1532. Int mbDiff; // start with big
  1533. Int iXDest = iXRef, iYDest = iYRef;
  1534. CoordI x = iXRef, y = iYRef, ix, iy;
  1535. Int uiPosInLoop, iLoop;
  1536. CRct CTmp=(iDirection) ? m_rctRefVOPY1:m_rctRefVOPY0;
  1537. // Spiral Search for the rest
  1538. if (m_iMVFileUsage != 1) {
  1539.     for (iLoop = 1; iLoop <= iSearchRange; iLoop++) {
  1540.     x++;
  1541.     y++;
  1542.     ppxlcRefMBY += m_iFrameWidthY + 1;
  1543.     for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  1544. if (
  1545.     x >= CTmp.left && y >= CTmp.top && 
  1546.     x <= CTmp.right - MB_SIZE && y <= CTmp.bottom - MB_SIZE
  1547.     ) {
  1548.     const PixelC* ppxlcTmpC = m_ppxlcCurrMBY;
  1549.     const PixelC* ppxlcTmpCBY = m_ppxlcCurrMBBY;
  1550.     const PixelC* ppxlcRefMB = ppxlcRefMBY;
  1551.     mbDiff = 0;
  1552.     for (iy = 0; iy < MB_SIZE; iy++) {
  1553.     for (ix = 0; ix < MB_SIZE; ix++) {
  1554.     if (ppxlcTmpCBY [ix] != transpValue)
  1555.     mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefMB [ix]);
  1556.     }
  1557.     if (mbDiff >= iMinSAD)
  1558.     goto NEXT_POSITION; // skip the current position
  1559.     ppxlcRefMB += m_iFrameWidthY;
  1560.     ppxlcTmpC += MB_SIZE;
  1561.     ppxlcTmpCBY += MB_SIZE;
  1562.     }
  1563.     iMinSAD = mbDiff;
  1564.     iXDest = x;
  1565.     iYDest = y;
  1566.     }
  1567. NEXT_POSITION:
  1568.     if (uiPosInLoop < (iLoop << 1)) {
  1569.     ppxlcRefMBY--;
  1570.     x--;
  1571.     }
  1572.     else if (uiPosInLoop < (iLoop << 2)) {
  1573.     ppxlcRefMBY -= m_iFrameWidthY;
  1574.     y--;
  1575.     }
  1576.     else if (uiPosInLoop < (iLoop * 6)) {
  1577.     ppxlcRefMBY++;   
  1578.     x++;
  1579.     }
  1580.     else {
  1581.     ppxlcRefMBY += m_iFrameWidthY;
  1582.     y++;
  1583.     }
  1584.     }
  1585.     }
  1586.     *pmv = CMotionVector (iXDest - iXCurr, iYDest - iYCurr);
  1587. else {
  1588. iXDest = iXRef + pmv->iMVX;
  1589. iYDest = iYRef + pmv->iMVY;
  1590. }
  1591. // check for case when zero MV due to MB outside the extended BB.
  1592. if(iXDest==iXCurr && iYDest==iYCurr
  1593. && (iXDest < CTmp.left || iYDest < CTmp.top // 12.22.98 changes
  1594. || iXDest > CTmp.right - MB_SIZE // 12.22.98 changes
  1595. || iYDest > CTmp.bottom - MB_SIZE)) // 12.22.98 changes
  1596. {
  1597. pmv -> iHalfX = 0;
  1598. pmv -> iHalfY = 0;
  1599. return iMinSAD;  
  1600. }
  1601. /* NBIT: change to a bigger number
  1602. iMinSAD = 256*256; // Reset iMinSAD because reference VOP may change from original to reconstructed (Bob Eifrig)
  1603. */
  1604. iMinSAD = 4096*256;
  1605. Int iFavorZero = pmv->isZero() ? -(pmbmd -> m_rgNumNonTranspPixels [0] >> 1) - 1 : 0;
  1606. // half pel search
  1607. I8 destHalfX = 0, destHalfY = 0;
  1608. Int lowY, highY, lowX, highX;
  1609. lowX = (iXDest == CTmp.left) ? 0 : -1; // 12.22.98 changes
  1610. lowY = (iYDest == CTmp.top) ? 0 : -1; // 12.22.98 changes
  1611. highX = (iXDest == CTmp.right - MB_SIZE + 1) ? 0 : 1; // 12.22.98 changes
  1612. highY = (iYDest == CTmp.bottom - MB_SIZE + 1) ? 0 : 1; // 12.22.98 changes
  1613. const PixelC* ppxlcRefZoom = puciRefQZoom->pixels ((iXDest << 1) + lowX, (iYDest << 1) + lowY);
  1614. for (Int incY = lowY; incY <= highY; incY++) {
  1615. for (Int incX = lowX; incX <= highX; incX++) {
  1616. const PixelC* ppxlcRefZoomMB = ppxlcRefZoom;
  1617. const PixelC* ppxlcTmpC = m_ppxlcCurrMBY;
  1618. const PixelC* ppxlcTmpCBY = m_ppxlcCurrMBBY;
  1619. mbDiff = (incX || incY) ? 0 : iFavorZero;
  1620. for (iy = 0; iy < MB_SIZE; iy++) {
  1621. for (ix = 0; ix < MB_SIZE; ix++) {
  1622. if (ppxlcTmpCBY [ix] != transpValue) 
  1623. mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefZoomMB [2 * ix]);
  1624. }
  1625. if (mbDiff > iMinSAD) // Try to find shortest MV in case of equal SADs
  1626. goto NEXT_HALF_POSITION;
  1627. ppxlcRefZoomMB += m_iFrameWidthZoomY * 2;
  1628. ppxlcTmpC += MB_SIZE;
  1629. ppxlcTmpCBY += MB_SIZE;
  1630. }
  1631. if ((iMinSAD > mbDiff) ||
  1632. ((abs(pmv->m_vctTrueHalfPel.x + destHalfX) + abs(pmv->m_vctTrueHalfPel.y + destHalfY)) >
  1633.  (abs(pmv->m_vctTrueHalfPel.x + incX)      + abs(pmv->m_vctTrueHalfPel.y + incY)))) {
  1634. iMinSAD = mbDiff;
  1635. destHalfX = incX;
  1636. destHalfY = incY;
  1637. }
  1638. NEXT_HALF_POSITION:
  1639. ppxlcRefZoom++;
  1640. }
  1641. ppxlcRefZoom += m_iFrameWidthZoomY - (highX - lowX + 1);
  1642. }
  1643. pmv -> iHalfX = destHalfX;
  1644. pmv -> iHalfY = destHalfY;
  1645. return iMinSAD;
  1646. }
  1647. Int CVideoObjectEncoder::blockmatch8 (
  1648. const PixelC* ppxlcCodedBlkY, 
  1649. CMotionVector* pmv8, 
  1650. CoordI iXBlk, CoordI iYBlk,
  1651. const CMotionVector* pmvPred,
  1652. Int iSearchRange
  1653. )
  1654. {
  1655. Int mbDiff,iMinSAD; // start with big
  1656. CoordI ix,iy,iXDest,iYDest;
  1657. if (m_iMVFileUsage != 1) {
  1658.     CoordI x = iXBlk + pmvPred->iMVX, y = iYBlk + pmvPred->iMVY; // , ix, iy;
  1659.     CoordI left = -1 * min (abs (pmvPred->iMVX + iSearchRange), ADD_DISP);
  1660.     CoordI top = -1 * min (abs (pmvPred->iMVY + iSearchRange), ADD_DISP);
  1661.     CoordI right = min (abs (pmvPred->iMVX - iSearchRange), ADD_DISP);
  1662.     CoordI bottom = min (abs (pmvPred->iMVY - iSearchRange), ADD_DISP);
  1663.     //CoordI iOrigX = x, iOrigY = y;
  1664.     // CoordI 
  1665.     iXDest = x, iYDest = y;
  1666.     Int uiPosInLoop, iLoop;
  1667.     const PixelC* ppxlcRefBlk = (m_volmd.bOriginalForME ? m_pvopcRefOrig0 : m_pvopcRefQ0)->getPlane (Y_PLANE)->pixels (x, y);
  1668.     iMinSAD = sad8x8At0 (ppxlcCodedBlkY, ppxlcRefBlk);
  1669.     // Spiral Search for the rest
  1670.     Int iix = 0, iiy = 0;
  1671.     for (iLoop = 1; iLoop <= ADD_DISP; iLoop++) {
  1672.     x++;
  1673.     y++;
  1674.     iix++; iiy++;
  1675.     ppxlcRefBlk += m_iFrameWidthY + 1;
  1676.     for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  1677. if (
  1678.     iix >= left && iix <= right &&
  1679.     iiy >= top && iiy <= bottom &&
  1680.     x >= m_rctRefVOPY0.left && y >= m_rctRefVOPY0.top && 
  1681.     x <= m_rctRefVOPY0.right - MB_SIZE && y <= m_rctRefVOPY0.bottom - MB_SIZE
  1682.     ) {
  1683.     const PixelC* ppxlcTmpC = ppxlcCodedBlkY;
  1684.     const PixelC* ppxlcRefMB = ppxlcRefBlk;
  1685.     mbDiff = 0;
  1686.     for (iy = 0; iy < BLOCK_SIZE; iy++) {
  1687.     for (ix = 0; ix < BLOCK_SIZE; ix++)
  1688.     mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefMB [ix]);
  1689.     if (mbDiff > iMinSAD)
  1690.     goto NEXT_POSITION; // skip the current position
  1691.     ppxlcRefMB += m_iFrameWidthY;
  1692.     ppxlcTmpC += MB_SIZE;
  1693.     }
  1694.     iMinSAD = mbDiff;
  1695.     iXDest = x;
  1696.     iYDest = y;
  1697.     }
  1698. NEXT_POSITION:
  1699.     if (uiPosInLoop < (iLoop << 1)) {
  1700.     ppxlcRefBlk--;
  1701.     x--;
  1702.     iix--;
  1703.     }
  1704.     else if (uiPosInLoop < (iLoop << 2)) {
  1705.     ppxlcRefBlk -= m_iFrameWidthY;
  1706.     y--;
  1707.     iiy--;
  1708.     }
  1709.     else if (uiPosInLoop < (iLoop * 6)) {
  1710.     ppxlcRefBlk++;   
  1711.     x++;
  1712.     iix++;
  1713.     }
  1714.     else {
  1715.     ppxlcRefBlk += m_iFrameWidthY;
  1716.     y++;
  1717.     iiy++;
  1718.     }
  1719.     }
  1720.     }
  1721.     *pmv8 = CMotionVector (iXDest - iXBlk, iYDest - iYBlk);
  1722. else {
  1723. iXDest = iXBlk + pmv8->iMVX;
  1724. iYDest = iYBlk + pmv8->iMVY;
  1725. }
  1726. /* NBIT: change to a bigger number
  1727. iMinSAD = 256*256; // Reset iMinSAD because reference VOP changed from original to reconstructed (Bob Eifrig)
  1728. */
  1729. iMinSAD = 4096*256;
  1730. // half pel search
  1731. I8 destHalfX = 0, destHalfY = 0;
  1732. Int lowY, highY, lowX, highX;
  1733. lowX = (iXDest == m_rctRefVOPY0.left) ? 0 : -1;
  1734. lowY = (iYDest == m_rctRefVOPY0.top) ? 0 : -1;
  1735. highX = (iXDest == m_rctRefVOPY0.right - MB_SIZE + 1) ? 0 : 1;
  1736. highY = (iYDest == m_rctRefVOPY0.bottom - MB_SIZE + 1) ? 0 : 1;
  1737. const PixelC* ppxlcRefZoom = m_puciRefQZoom0->pixels ((iXDest << 1) + lowX, (iYDest << 1) + lowY);
  1738. for (Int incY = lowY; incY <= highY; incY++) {
  1739. for (Int incX = lowX; incX <= highX; incX++) {
  1740. // no longer skipp (0,0) due to using original as interger pel reference
  1741. //if (!(incX == 0 && incY == 0)) {
  1742. const PixelC* ppxlcRefZoomBlk = ppxlcRefZoom;
  1743. const PixelC* ppxlcTmpC = ppxlcCodedBlkY;
  1744. mbDiff = 0;
  1745. for (iy = 0; iy < BLOCK_SIZE; iy++) {
  1746. for (ix = 0; ix < BLOCK_SIZE; ix++)
  1747. mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefZoomBlk [2 * ix]);
  1748. if (mbDiff > iMinSAD)
  1749. goto NEXT_HALF_POSITION;
  1750. ppxlcRefZoomBlk += m_iFrameWidthZoomY * 2;
  1751. ppxlcTmpC += MB_SIZE;
  1752. }
  1753. if ((iMinSAD > mbDiff) ||
  1754. ((abs(pmv8->m_vctTrueHalfPel.x + destHalfX) + abs(pmv8->m_vctTrueHalfPel.y + destHalfY)) >
  1755.  (abs(pmv8->m_vctTrueHalfPel.x + incX)      + abs(pmv8->m_vctTrueHalfPel.y + incY)))) {
  1756. iMinSAD = mbDiff;
  1757. destHalfX = incX;
  1758. destHalfY = incY;
  1759. }
  1760. NEXT_HALF_POSITION:
  1761. ppxlcRefZoom++;
  1762. }
  1763. ppxlcRefZoom += m_iFrameWidthZoomY - (highX - lowX + 1);
  1764. }
  1765. pmv8 -> iHalfX = destHalfX;
  1766. pmv8 -> iHalfY = destHalfY;
  1767. return iMinSAD;
  1768. }
  1769. Int CVideoObjectEncoder::blockmatch8WithShape (
  1770. const PixelC* ppxlcCodedBlkY, 
  1771. const PixelC* ppxlcCodedBlkBY, 
  1772. CMotionVector* pmv8, 
  1773. CoordI iXBlk, CoordI iYBlk,
  1774. const CMotionVector* pmvPred,
  1775. Int iSearchRange,
  1776. Int iDirection
  1777. )
  1778. {
  1779. Int mbDiff; // start with big
  1780. CoordI x = iXBlk + pmvPred->iMVX, y = iYBlk + pmvPred->iMVY, ix, iy;
  1781. CoordI left = -1 * min (abs (pmvPred->iMVX + iSearchRange), ADD_DISP);
  1782. CoordI top = -1 * min (abs (pmvPred->iMVY + iSearchRange), ADD_DISP);
  1783. CoordI right = min (abs (pmvPred->iMVX - iSearchRange), ADD_DISP);
  1784. CoordI bottom = min (abs (pmvPred->iMVY - iSearchRange), ADD_DISP);
  1785. //CoordI iOrigX = x, iOrigY = y;
  1786. CoordI iXDest = x, iYDest = y;
  1787. Int uiPosInLoop, iLoop, iMinSAD = 0;
  1788. const PixelC* ppxlcRefBlk = (m_volmd.bOriginalForME ? m_pvopcRefOrig0 : m_pvopcRefQ0)->getPlane (Y_PLANE)->pixels (x, y);
  1789. CRct CTmp=(iDirection) ? m_rctRefVOPY1:m_rctRefVOPY0;
  1790. if (m_iMVFileUsage != 1) {
  1791.     iMinSAD = sad8x8At0WithShape (ppxlcCodedBlkY, ppxlcCodedBlkBY, ppxlcRefBlk);
  1792.     // Spiral Search for the rest
  1793.     Int iix = 0, iiy = 0;
  1794.     for (iLoop = 1; iLoop <= ADD_DISP; iLoop++) {
  1795.     x++;
  1796.     y++;
  1797.     iix++;
  1798.     iiy++;
  1799.     ppxlcRefBlk += m_iFrameWidthY + 1;
  1800.     for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  1801. if (
  1802.     iix >= left && iix <= right &&
  1803.     iiy >= top && iiy <= bottom &&
  1804.     x >= CTmp.left && y >= CTmp.top && 
  1805.     x <= CTmp.right - MB_SIZE && y <= CTmp.bottom - MB_SIZE
  1806.     ) {
  1807.     const PixelC* ppxlcTmpC = ppxlcCodedBlkY;
  1808.     const PixelC* ppxlcTmpCBY = ppxlcCodedBlkBY;
  1809.     const PixelC* ppxlcRefMB = ppxlcRefBlk;
  1810.     mbDiff = 0;
  1811.     for (iy = 0; iy < BLOCK_SIZE; iy++) {
  1812.     for (ix = 0; ix < BLOCK_SIZE; ix++) {
  1813.     if (ppxlcTmpCBY [ix] != transpValue)
  1814.     mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefMB [ix]);
  1815.     }
  1816.     if (mbDiff > iMinSAD)
  1817.     goto NEXT_POSITION; // skip the current position
  1818.     ppxlcRefMB += m_iFrameWidthY;
  1819.     ppxlcTmpC += MB_SIZE;
  1820.     ppxlcTmpCBY += MB_SIZE;
  1821.     }
  1822.     iMinSAD = mbDiff;
  1823.     iXDest = x;
  1824.     iYDest = y;
  1825.     }
  1826. NEXT_POSITION:
  1827.     if (uiPosInLoop < (iLoop << 1)) {
  1828.     ppxlcRefBlk--;
  1829.     x--;
  1830.     iix--;
  1831.     }
  1832.     else if (uiPosInLoop < (iLoop << 2)) {
  1833.     ppxlcRefBlk -= m_iFrameWidthY;
  1834.     y--;
  1835.     iiy--;
  1836.     }
  1837.     else if (uiPosInLoop < (iLoop * 6)) {
  1838.     ppxlcRefBlk++;   
  1839.     x++;
  1840.     iix++;
  1841.     }
  1842.     else {
  1843.     ppxlcRefBlk += m_iFrameWidthY;
  1844.     y++;
  1845.     iiy++;
  1846.     }
  1847.     }
  1848.     }
  1849.     *pmv8 = CMotionVector (iXDest - iXBlk, iYDest - iYBlk);
  1850. else {
  1851. iXDest = iXBlk + pmv8->iMVX;
  1852. iYDest = iYBlk + pmv8->iMVY;
  1853. }
  1854. // check for case when zero MV due to MB outside the extended BB.
  1855. if(iXDest==iXBlk && iYDest==iYBlk
  1856. && (iXDest < CTmp.left || iYDest < CTmp.top
  1857. || iXDest > CTmp.right - MB_SIZE
  1858. || iYDest > CTmp.bottom - MB_SIZE))
  1859. {
  1860. pmv8 -> iHalfX = 0;
  1861. pmv8 -> iHalfY = 0;
  1862. return iMinSAD;  
  1863. }
  1864. iMinSAD = 256*256; // Reset iMinSAD because reference VOP changed from original to reconstructed (Bob Eifrig)
  1865. // half pel search
  1866. I8 destHalfX = 0, destHalfY = 0;
  1867. Int lowY, highY, lowX, highX;
  1868. lowX = (iXDest == CTmp.left) ? 0 : -1;
  1869. lowY = (iYDest == CTmp.top) ? 0 : -1;
  1870. highX = (iXDest == CTmp.right - MB_SIZE + 1) ? 0 : 1;
  1871. highY = (iYDest == CTmp.bottom - MB_SIZE + 1) ? 0 : 1;
  1872. const PixelC* ppxlcRefZoom = m_puciRefQZoom0->pixels ((iXDest << 1) + lowX, (iYDest << 1) + lowY);
  1873. for (Int incY = lowY; incY <= highY; incY++) {
  1874. const PixelC* ppxlcRefZoomRow = ppxlcRefZoom;
  1875. for (Int incX = lowX; incX <= highX; incX++) {
  1876. // no longer skipp (0,0) due to using original as interger pel reference
  1877. //if (!(incX == 0 && incY == 0)) {
  1878. const PixelC* ppxlcRefZoomBlk = ppxlcRefZoomRow;
  1879. const PixelC* ppxlcTmpC = ppxlcCodedBlkY;
  1880. const PixelC* ppxlcTmpCBY = ppxlcCodedBlkBY;
  1881. mbDiff = 0;
  1882. for (iy = 0; iy < BLOCK_SIZE; iy++) {
  1883. for (ix = 0; ix < BLOCK_SIZE; ix++) {
  1884. if (ppxlcTmpCBY [ix] != transpValue)
  1885. mbDiff += abs (ppxlcTmpC [ix] - ppxlcRefZoomBlk [2 * ix]);
  1886. }
  1887. if (mbDiff > iMinSAD) // Try to find shortest MV in case of equal SADs
  1888. goto NEXT_HALF_POSITION;
  1889. ppxlcRefZoomBlk += m_iFrameWidthZoomY * 2;
  1890. ppxlcTmpC += MB_SIZE;
  1891. ppxlcTmpCBY += MB_SIZE;
  1892. }
  1893. if ((iMinSAD > mbDiff) ||
  1894. ((abs(pmv8->m_vctTrueHalfPel.x + destHalfX) + abs(pmv8->m_vctTrueHalfPel.y + destHalfY)) >
  1895.  (abs(pmv8->m_vctTrueHalfPel.x + incX)      + abs(pmv8->m_vctTrueHalfPel.y + incY)))) {
  1896. iMinSAD = mbDiff;
  1897. destHalfX = incX;
  1898. destHalfY = incY;
  1899. }
  1900. NEXT_HALF_POSITION:
  1901. ppxlcRefZoomRow++;
  1902. }
  1903. ppxlcRefZoom += m_iFrameWidthZoomY;
  1904. }
  1905. pmv8 -> iHalfX = destHalfX;
  1906. pmv8 -> iHalfY = destHalfY;
  1907. return iMinSAD;
  1908. }
  1909. Int CVideoObjectEncoder::sumDev () const // compute sum of deviation of an MB
  1910. {
  1911. const PixelC* ppxlcY = m_ppxlcCurrMBY;
  1912. Int iMean = 0;
  1913. UInt iy;
  1914. for (iy = 0; iy < MB_SQUARE_SIZE; iy++)
  1915. iMean += ppxlcY [iy];
  1916. iMean /= MB_SQUARE_SIZE;
  1917. Int iDevRet = 0;
  1918. for (iy = 0; iy < MB_SQUARE_SIZE; iy++)
  1919. iDevRet += abs (m_ppxlcCurrMBY [iy] - iMean);
  1920. return iDevRet;
  1921. }
  1922. Int CVideoObjectEncoder::sumDevWithShape (UInt uiNumTranspPels) const // compute sum of deviation of an MB
  1923. {
  1924. const PixelC* ppxlcY = m_ppxlcCurrMBY;
  1925. const PixelC* ppxlcBY = m_ppxlcCurrMBBY;
  1926. Int iMean = 0;
  1927. CoordI iy;
  1928. for (iy = 0; iy < MB_SQUARE_SIZE; iy++) {
  1929. if (ppxlcBY [iy] != transpValue)
  1930. iMean += ppxlcY [iy];
  1931. }
  1932. iMean /= uiNumTranspPels;
  1933. Int iDevRet = 0;
  1934. for (iy = 0; iy < MB_SQUARE_SIZE; iy++) {
  1935. if (m_ppxlcCurrMBBY [iy] != transpValue)
  1936. iDevRet += abs (m_ppxlcCurrMBY [iy] - iMean);
  1937. }
  1938. return iDevRet;
  1939. }
  1940. Int CVideoObjectEncoder::sad16x16At0 (const PixelC* ppxlcRefY) const
  1941. {
  1942. if (m_iMVFileUsage == 1)
  1943. return 0;
  1944. Int iInitSAD = 0;
  1945. UInt nBits = m_volmd.nBits; // NBIT
  1946. Int iFavorZero = FAVORZERO; // NBIT
  1947. // NBIT: addjust iFavorZero based on nBits
  1948. if (nBits > 8) {
  1949. iFavorZero <<= (nBits-8);
  1950. } else if (nBits < 8) {
  1951. iFavorZero >>= (8-nBits);
  1952. }
  1953. CoordI ix, iy;
  1954. const PixelC* ppxlcCurrY = m_ppxlcCurrMBY;
  1955. for (iy = 0; iy < MB_SIZE; iy++) {
  1956. for (ix = 0; ix < MB_SIZE; ix++)
  1957. iInitSAD += abs (ppxlcCurrY [ix] - ppxlcRefY [ix]);
  1958. ppxlcCurrY += MB_SIZE;
  1959. ppxlcRefY += m_iFrameWidthY;
  1960. }
  1961. /* NBIT: change
  1962. iInitSAD -= FAVORZERO;
  1963. */
  1964. iInitSAD -= iFavorZero;
  1965. return iInitSAD;
  1966. }
  1967. Int CVideoObjectEncoder::sad16x16At0WithShape (const PixelC* ppxlcRefY, const CMBMode* pmbmd) const
  1968. {
  1969. if (m_iMVFileUsage == 1)
  1970. return 0;
  1971. Int iInitSAD = 0;
  1972. UInt nBits = m_volmd.nBits; // NBIT
  1973. Int iFavorZero = (pmbmd->m_rgNumNonTranspPixels [0] >> 1) + 1; // NBIT
  1974. // NBIT: addjust iFavorZero based on nBits 
  1975.         if (nBits > 8) { 
  1976.                 iFavorZero <<= (nBits-8); 
  1977.         } else if (nBits < 8) { 
  1978.                 iFavorZero >>= (8-nBits); 
  1979.         } 
  1980. CoordI ix, iy;
  1981. const PixelC* ppxlcCurrY = m_ppxlcCurrMBY;
  1982. const PixelC* ppxlcCurrBY = m_ppxlcCurrMBBY;
  1983. for (iy = 0; iy < MB_SIZE; iy++) {
  1984. for (ix = 0; ix < MB_SIZE; ix++) {
  1985. if (ppxlcCurrBY [ix] != transpValue)
  1986. iInitSAD += abs (ppxlcCurrY [ix] - ppxlcRefY [ix]);
  1987. }
  1988. ppxlcCurrBY += MB_SIZE;
  1989. ppxlcCurrY += MB_SIZE;
  1990. ppxlcRefY += m_iFrameWidthY;
  1991. }
  1992. /* NBIT: change
  1993. iInitSAD -= (pmbmd->m_rgNumNonTranspPixels [0] >> 1) + 1;
  1994. */
  1995. iInitSAD -= iFavorZero;
  1996. return iInitSAD;
  1997. }
  1998. Int CVideoObjectEncoder::sad8x8At0 (const PixelC* ppxlcCurrY, const PixelC* ppxlcRefY) const
  1999. {
  2000. Int iInitSAD = 0;
  2001. CoordI ix, iy;
  2002. for (iy = 0; iy < BLOCK_SIZE; iy++) {
  2003. for (ix = 0; ix < BLOCK_SIZE; ix++)
  2004. iInitSAD += abs (ppxlcCurrY [ix] - ppxlcRefY [ix]);
  2005. ppxlcCurrY += MB_SIZE;
  2006. ppxlcRefY += m_iFrameWidthY;
  2007. }
  2008. return iInitSAD;
  2009. }
  2010. Int CVideoObjectEncoder::sad8x8At0WithShape (const PixelC* ppxlcCurrY, const PixelC* ppxlcCurrBY, const PixelC* ppxlcRefY) const
  2011. {
  2012. Int iInitSAD = 0;
  2013. CoordI ix, iy;
  2014. for (iy = 0; iy < BLOCK_SIZE; iy++) {
  2015. for (ix = 0; ix < BLOCK_SIZE; ix++) {
  2016. if (ppxlcCurrBY [ix] != transpValue)
  2017. iInitSAD += abs (ppxlcCurrY [ix] - ppxlcRefY [ix]);
  2018. }
  2019. ppxlcCurrBY += MB_SIZE;
  2020. ppxlcCurrY += MB_SIZE;
  2021. ppxlcRefY += m_iFrameWidthY;
  2022. }
  2023. return iInitSAD;
  2024. }
  2025. //Interlaced
  2026. Int CVideoObjectEncoder::directSAD(
  2027. CoordI x, CoordI y,
  2028. CMBMode *pmbmd,
  2029. const CMBMode *pmbmdRef,
  2030. const CMotionVector *pmvRef
  2031. )
  2032. {
  2033. static CRct rctBounds[4];
  2034. static Int iTempRefD, iTempRefB, iZeroOffset, iLastNumber = -1;
  2035. PixelC fwd[MB_SQUARE_SIZE], bak[MB_SQUARE_SIZE];
  2036. static Int iXOffset[] = { 0, BLOCK_SIZE, 0, BLOCK_SIZE };
  2037. static Int iYOffset[] = { 0, 0, BLOCK_SIZE, BLOCK_SIZE };
  2038. static Int iBlkOffset[] = { 0, BLOCK_SIZE, BLOCK_SIZE*MB_SIZE, BLOCK_SIZE*(MB_SIZE + 1) };
  2039. CMotionVector mvFwd[4], mvBak[4];
  2040. Int directSAD = 256*256;
  2041. if (iLastNumber != m_t) {
  2042. iTempRefD = m_tFutureRef - m_tPastRef;
  2043. iTempRefB = m_t          - m_tPastRef;
  2044. assert(m_rctRefVOPY0 == m_rctRefVOPY1);
  2045. rctBounds[0] = m_rctRefVOPY0.upSampleBy2();
  2046. rctBounds[1] = m_rctRefVOPY0.upSampleBy2();
  2047. rctBounds[2] = m_rctRefVOPY0.upSampleBy2();
  2048. rctBounds[3] = m_rctRefVOPY0.upSampleBy2();
  2049. rctBounds[0].expand(           0,            0, - 2*BLOCK_SIZE, - 2*BLOCK_SIZE);
  2050. rctBounds[1].expand(2*BLOCK_SIZE,            0, - 4*BLOCK_SIZE, - 2*BLOCK_SIZE);
  2051. rctBounds[2].expand(           0, 2*BLOCK_SIZE, - 2*BLOCK_SIZE, - 4*BLOCK_SIZE);
  2052. rctBounds[3].expand(2*BLOCK_SIZE, 2*BLOCK_SIZE, - 4*BLOCK_SIZE, - 4*BLOCK_SIZE);
  2053. iZeroOffset = m_puciRefQZoom0->where().offset(0,0);
  2054.         iLastNumber = m_t;
  2055. }
  2056. Int iRadius = m_vopmd.iDirectModeRadius;
  2057. CVector vctDMV, vctCurrZoomMB(x << 1, y << 1);
  2058. if ((pmbmdRef->m_dctMd == INTRA) || (pmbmdRef->m_dctMd == INTRAQ)) {
  2059. static CMotionVector mvZero[5];
  2060. pmvRef = mvZero;
  2061. }
  2062. for (vctDMV.y = -iRadius; vctDMV.y <= iRadius; vctDMV.y++) {
  2063. for (vctDMV.x = -iRadius; vctDMV.x <= iRadius; vctDMV.x++) {
  2064. Int iBlk;
  2065. for (iBlk = 0; iBlk < 4; iBlk++) {
  2066. mvFwd[iBlk] = (pmvRef[iBlk + 1].m_vctTrueHalfPel * iTempRefB) / iTempRefD + vctDMV;
  2067. if (!rctBounds[iBlk].includes(vctCurrZoomMB + mvFwd[iBlk].m_vctTrueHalfPel))
  2068. break;              // out-of-range
  2069.                 mvBak[iBlk] = CVector(vctDMV.x ?
  2070.                     (mvFwd[iBlk].m_vctTrueHalfPel.x - pmvRef[iBlk + 1].m_vctTrueHalfPel.x) :
  2071.                     ((pmvRef[iBlk + 1].m_vctTrueHalfPel.x * (iTempRefB - iTempRefD)) / iTempRefD),
  2072.                     vctDMV.y ? (mvFwd[iBlk].m_vctTrueHalfPel.y - pmvRef[iBlk + 1].m_vctTrueHalfPel.y) :
  2073.                     ((pmvRef[iBlk + 1].m_vctTrueHalfPel.y * (iTempRefB - iTempRefD)) / iTempRefD));
  2074. if (!rctBounds[iBlk].includes(vctCurrZoomMB + mvBak[iBlk].m_vctTrueHalfPel))
  2075. break; // out-of-range
  2076. }
  2077. if (iBlk < 4) // All mvFwd[] and mvBak[] vectors must be inbounds to continue
  2078. continue;
  2079. for (iBlk = 0; iBlk < 4; iBlk++) {
  2080. motionCompEncY(m_pvopcRefQ0->pixelsY (), m_puciRefQZoom0->pixels(),
  2081. fwd + iBlkOffset[iBlk], BLOCK_SIZE, &mvFwd[iBlk], x + iXOffset[iBlk], y + iYOffset[iBlk],0);
  2082. motionCompEncY(m_pvopcRefQ0->pixelsY (), m_puciRefQZoom1->pixels(),
  2083. bak + iBlkOffset[iBlk], BLOCK_SIZE, &mvBak[iBlk], x + iXOffset[iBlk], y + iYOffset[iBlk],0);
  2084. }
  2085. Int iSAD, i;
  2086. for (iSAD = 0, i = 0; i < MB_SQUARE_SIZE; i++)
  2087. iSAD += abs(m_ppxlcCurrMBY[i] - ((fwd[i] + bak[i] + 1) >> 1));
  2088. if (iSAD < directSAD) {
  2089. directSAD = iSAD;
  2090. //pmbmd->m_vctDMV = vctDMV;
  2091. //wchen-Jan06-97: to be consistent with non-interlaced case
  2092. pmbmd->m_vctDirectDeltaMV = vctDMV;
  2093. }
  2094. }
  2095. }
  2096. #if 0 // #ifdef __TRACE_AND_STATS_
  2097. Int iDirInfo[10];
  2098. iDirInfo[0] = pmvRef[1].m_vctTrueHalfPel.x; iDirInfo[1] = pmvRef[1].m_vctTrueHalfPel.y;
  2099. iDirInfo[2] = pmvRef[2].m_vctTrueHalfPel.x; iDirInfo[3] = pmvRef[2].m_vctTrueHalfPel.y;
  2100. iDirInfo[4] = pmvRef[3].m_vctTrueHalfPel.x; iDirInfo[5] = pmvRef[3].m_vctTrueHalfPel.y;
  2101. iDirInfo[6] = pmvRef[4].m_vctTrueHalfPel.x; iDirInfo[7] = pmvRef[4].m_vctTrueHalfPel.y;
  2102. //iDirInfo[8] = pmbmd->m_vctDMV.x;            iDirInfo[9] = pmbmd->m_vctDMV.y;
  2103. iDirInfo[8] = pmbmd->m_vctDirectDeltaMV.x;
  2104. iDirInfo[9] = pmbmd->m_vctDirectDeltaMV.y;
  2105. m_pbitstrmOut->trace (iDirInfo, 10, "FrameDirect");
  2106. #endif // __TRACE_AND_STATS_
  2107. return directSAD;
  2108. }
  2109. Int CVideoObjectEncoder::directSADField(
  2110. CoordI x, CoordI y,
  2111. CMBMode *pmbmd,
  2112. const CMBMode *pmbmdRef,
  2113. const CMotionVector *pmvRef,
  2114. const PixelC* ppxlcRef0MBY,
  2115. const PixelC* ppxlcRef1MBY
  2116. )
  2117. {
  2118. static I8 iTROffsetTop[] = {  0, 0,  1, 1, 0, 0, -1, -1 };
  2119. static I8 iTROffsetBot[] = { -1, 0, -1, 0, 1, 0,  1,  0 };
  2120. static CRct rctBounds;
  2121. static Int iLastNumber = -1;
  2122. const CMotionVector *pmvRefTop, *pmvRefBot;
  2123. PixelC fwd[MB_SQUARE_SIZE], bak[MB_SQUARE_SIZE];
  2124. CVector vctFwdTop, vctFwdBot, vctBakTop, vctBakBot, vctDMV, vctCurrZoomMB(x << 1, y << 1);
  2125. Int iDirectSAD = 256*256;
  2126. if (m_t != iLastNumber) {
  2127. assert(m_rctRefVOPY0 == m_rctRefVOPY1); // Probably only true for rectangular VOPs
  2128. rctBounds = m_rctRefVOPY0.upSampleBy2();
  2129. rctBounds.expand(0, 0, -2*MB_SIZE, -2*MB_SIZE);
  2130. iLastNumber = m_t;
  2131. }
  2132. assert((pmbmdRef->m_dctMd != INTRA) && (pmbmdRef->m_dctMd != INTRAQ));
  2133. Int iTopRefFldOffset = 0, iBotRefFldOffset = 0;
  2134. Int iCode = ((Int)vopmd().bTopFieldFirst) << 2;
  2135. if (pmbmdRef->m_bForwardTop) {
  2136. iCode |= 2;
  2137. iTopRefFldOffset = m_iFrameWidthY;
  2138. pmvRefTop = pmvRef + 6;
  2139. } else
  2140. pmvRefTop = pmvRef + 5;
  2141. if (pmbmdRef->m_bForwardBottom) {
  2142. iCode |= 1;
  2143. iBotRefFldOffset = m_iFrameWidthY;
  2144. pmvRefBot = pmvRef + 8;
  2145. } else
  2146. pmvRefBot = pmvRef + 7;
  2147. Int iTempRefDTop = 2*(m_tFutureRef - m_tPastRef) + iTROffsetTop[iCode];
  2148. Int iTempRefDBot = 2*(m_tFutureRef - m_tPastRef) + iTROffsetBot[iCode];
  2149. Int iTempRefBTop = 2*(m_t          - m_tPastRef) + iTROffsetTop[iCode];
  2150. Int iTempRefBBot = 2*(m_t          - m_tPastRef) + iTROffsetBot[iCode];
  2151. Int iRadius = m_vopmd.iDirectModeRadius;
  2152. ppxlcRef0MBY -= EXPANDY_REF_FRAME * (m_iFrameWidthY + 1);
  2153. ppxlcRef1MBY -= EXPANDY_REF_FRAME * (m_iFrameWidthY + 1);
  2154. for (vctDMV.y = -iRadius; vctDMV.y <= iRadius; vctDMV.y++) {
  2155. for (vctDMV.x = -iRadius; vctDMV.x <= iRadius; vctDMV.x++) {
  2156. // Find MVs for the top field
  2157. vctFwdTop = (pmvRefTop->m_vctTrueHalfPel * iTempRefBTop) / iTempRefDTop + vctDMV;
  2158. if (!rctBounds.includes(vctCurrZoomMB + vctFwdTop))
  2159. continue;
  2160.             vctBakTop.x = vctDMV.x ? (vctFwdTop.x - pmvRefTop->m_vctTrueHalfPel.x) :
  2161.                 ((pmvRefTop->m_vctTrueHalfPel.x * (iTempRefBTop - iTempRefDTop)) / iTempRefDTop);
  2162.             vctBakTop.y = vctDMV.y ? (vctFwdTop.y - pmvRefTop->m_vctTrueHalfPel.y) :
  2163.                 ((pmvRefTop->m_vctTrueHalfPel.y * (iTempRefBTop - iTempRefDTop)) / iTempRefDTop);
  2164. if (!rctBounds.includes(vctCurrZoomMB + vctBakTop))
  2165. continue;
  2166. // Find MVs for the bottom field
  2167. vctFwdBot = (pmvRefBot->m_vctTrueHalfPel * iTempRefBBot) / iTempRefDBot + vctDMV;
  2168. if (!rctBounds.includes(vctCurrZoomMB + vctFwdBot))
  2169. continue;
  2170.             vctBakBot.x = vctDMV.x ? (vctFwdBot.x - pmvRefBot->m_vctTrueHalfPel.x) :
  2171.                 ((pmvRefBot->m_vctTrueHalfPel.x * (iTempRefBBot - iTempRefDBot)) / iTempRefDBot);
  2172.             vctBakBot.y = vctDMV.y ? (vctFwdBot.y - pmvRefBot->m_vctTrueHalfPel.y) :
  2173.                 ((pmvRefBot->m_vctTrueHalfPel.y * (iTempRefBBot - iTempRefDBot)) / iTempRefDBot);
  2174. if (!rctBounds.includes(vctCurrZoomMB + vctBakBot))
  2175. continue;
  2176. // Motion compensate the luma top field
  2177. motionCompYField(fwd,           ppxlcRef0MBY + iTopRefFldOffset, vctFwdTop.x, vctFwdTop.y);
  2178. motionCompYField(bak,           ppxlcRef1MBY,                    vctBakTop.x, vctBakTop.y);
  2179. // Motion compensate the luma bottom field
  2180. motionCompYField(fwd + MB_SIZE, ppxlcRef0MBY + iBotRefFldOffset, vctFwdBot.x, vctFwdBot.y);
  2181. motionCompYField(bak + MB_SIZE, ppxlcRef1MBY + m_iFrameWidthY,   vctBakBot.x, vctBakBot.y);
  2182. // Coumpute SAD
  2183. Int iSAD = 0;
  2184. for (Int i = 0; i < MB_SQUARE_SIZE; i++)
  2185. iSAD += abs(m_ppxlcCurrMBY[i] - ((fwd[i] + bak[i] + 1) >> 1));
  2186. if (iSAD < iDirectSAD) {
  2187. iDirectSAD = iSAD;
  2188. //pmbmd->m_vctDMV = vctDMV;
  2189. pmbmd->m_vctDirectDeltaMV = vctDMV;
  2190. }
  2191. }
  2192. }
  2193. #if 0 // #ifdef __TRACE_AND_STATS_
  2194. Int iDirInfo[8];
  2195. iDirInfo[0] = iCode;
  2196. iDirInfo[1] = pmvRefTop->m_vctTrueHalfPel.x; iDirInfo[2] = pmvRefTop->m_vctTrueHalfPel.y;
  2197. iDirInfo[3] = pmvRefBot->m_vctTrueHalfPel.x; iDirInfo[4] = pmvRefBot->m_vctTrueHalfPel.y;
  2198. //iDirInfo[5] = pmbmd->m_vctDMV.x;             iDirInfo[6] = pmbmd->m_vctDMV.y;
  2199. iDirInfo[5] = pmbmd->m_vctDirectDeltaMV.x;
  2200. iDirInfo[6] = pmbmd->m_vctDirectDeltaMV.y;
  2201. m_pbitstrmOut->trace (iDirInfo, 7, "FieldDirect");
  2202. #endif // __TRACE_AND_STATS_
  2203. return iDirectSAD;
  2204. }
  2205. // ~INTERLACE
  2206. // INTERLACE
  2207. Int CVideoObjectEncoder::blkmatch16x8 (
  2208. CMotionVector* pmv, 
  2209. CoordI iXMB, CoordI iYMB,
  2210. Int iFieldSelect,
  2211. const PixelC* ppxlcRefMBY,
  2212. const PixelC* ppxlcRefHalfPel,
  2213. Int iSearchRange
  2214. )
  2215. {
  2216. Int mbDiff; // start with big
  2217. Int iWidth2 = 2*m_iFrameWidthY;
  2218. Int iXDest = iXMB, iYDest = iYMB;
  2219. CoordI x = iXMB, y = iYMB, ix, iy;
  2220. Int uiPosInLoop, iLoop;
  2221. Int iMinSAD = 0;
  2222. if (m_iMVFileUsage != 1) {
  2223. // Calculate the center point SAD
  2224. const PixelC* ppxlcCurrY = m_ppxlcCurrMBY + iFieldSelect;
  2225. const PixelC* ppxlcRefMB = ppxlcRefMBY;
  2226. for (iy = 0; iy < MB_SIZE/2; iy++) {
  2227. for (ix = 0; ix < MB_SIZE; ix++)
  2228. iMinSAD += abs (ppxlcCurrY [ix] - ppxlcRefMB [ix]);
  2229. ppxlcCurrY += 2*MB_SIZE;
  2230. ppxlcRefMB += iWidth2;
  2231. }
  2232. // iMinSAD -= FAVORZERO/2; // Apply center favoring bias?
  2233. // Spiral Search for the rest
  2234. for (iLoop = 1; iLoop <= iSearchRange; iLoop++) {
  2235. x++;
  2236. y++;
  2237. ppxlcRefMBY += m_iFrameWidthY + 1;
  2238. for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  2239. if (
  2240. x >= m_rctRefVOPY0.left && y >= m_rctRefVOPY0.top && 
  2241. x <= m_rctRefVOPY0.right - MB_SIZE && y <= m_rctRefVOPY0.bottom - MB_SIZE
  2242. && ((y-iYMB)%2==0)
  2243. ) {
  2244. ppxlcCurrY = m_ppxlcCurrMBY+iFieldSelect;
  2245. ppxlcRefMB = ppxlcRefMBY;
  2246. mbDiff = 0;
  2247. // full pel field prediction
  2248. for (iy = 0; iy < MB_SIZE; iy+=2) {
  2249. for (ix = 0; ix < MB_SIZE; ix++)
  2250. mbDiff += abs (ppxlcCurrY [ix] - ppxlcRefMB [ix]);
  2251. if (mbDiff > iMinSAD)
  2252. goto NEXT_POSITION; // skip the current position
  2253. ppxlcRefMB += iWidth2;
  2254. ppxlcCurrY += MB_SIZE*2;
  2255. }
  2256. iMinSAD = mbDiff;
  2257. iXDest = x;
  2258. iYDest = y;
  2259. }
  2260. NEXT_POSITION:
  2261. if (uiPosInLoop < (iLoop << 1)) {
  2262. ppxlcRefMBY--;
  2263. x--;
  2264. }
  2265. else if (uiPosInLoop < (iLoop << 2)) {
  2266. ppxlcRefMBY -= m_iFrameWidthY;
  2267. y--;
  2268. }
  2269. else if (uiPosInLoop < (iLoop * 6)) {
  2270. ppxlcRefMBY++;   
  2271. x++;
  2272. }
  2273. else {
  2274. ppxlcRefMBY += m_iFrameWidthY;
  2275. y++;
  2276. }
  2277. }
  2278. }
  2279. *pmv = CMotionVector (iXDest - iXMB, iYDest - iYMB);
  2280. } else {
  2281. iXDest = iXMB + pmv->iMVX;
  2282. iYDest = iYMB + pmv->iMVY;
  2283. }
  2284. // half pel search
  2285. I8 destHalfX = 0, destHalfY = 0;
  2286. Int lowX = (iXDest == m_rctRefVOPY0.left) ? 0 : -1;
  2287. Int lowY = (iYDest == m_rctRefVOPY0.top) ? 0 : -2;
  2288. Int highX = (iXDest == m_rctRefVOPY0.right - MB_SIZE) ? 0 : 1;
  2289. Int highY = (iYDest == m_rctRefVOPY0.bottom - MB_SIZE) ? 0 : 2;
  2290. Int iRound1 = 1 - m_vopmd.iRoundingControl;
  2291. Int iRound2 = 2 - m_vopmd.iRoundingControl;
  2292. assert(!(pmv->iMVY & 1));
  2293. ppxlcRefHalfPel += pmv->iMVX + m_iFrameWidthY * pmv->iMVY; // 12.22.98 changes
  2294. iMinSAD = 256*256;
  2295. for (Int incY = lowY; incY <= highY; incY += 2) {
  2296. for (Int incX = lowX; incX <= highX; incX++) {
  2297. const PixelC *ppxlcRef = ppxlcRefHalfPel;
  2298. const PixelC *ppxlcCur = m_ppxlcCurrMBY + iFieldSelect;
  2299. if (incY < 0)
  2300. ppxlcRef -= iWidth2;
  2301. if (incX < 0)
  2302. ppxlcRef--;
  2303. mbDiff = 0;
  2304. if (incY == 0) {
  2305. if (incX == 0) {
  2306. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2307. for (ix = 0; ix < MB_SIZE; ix++)
  2308. mbDiff += abs(ppxlcRef[ix] - ppxlcCur[ix]);
  2309. if (mbDiff > iMinSAD)
  2310. goto NEXT_HALF_POSITION;
  2311. ppxlcRef += iWidth2;
  2312. ppxlcCur += MB_SIZE*2;
  2313. }
  2314. } else {
  2315. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2316. for (ix = 0; ix < MB_SIZE; ix++)
  2317. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+1] + iRound1) >> 1) - ppxlcCur[ix]);
  2318. if (mbDiff > iMinSAD)
  2319. goto NEXT_HALF_POSITION;
  2320. ppxlcRef += iWidth2;
  2321. ppxlcCur += MB_SIZE*2;
  2322. }
  2323. }
  2324. } else {
  2325. if (incX == 0) {
  2326. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2327. for (ix = 0; ix < MB_SIZE; ix++)
  2328. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+iWidth2] + iRound1) >> 1) - ppxlcCur[ix]);
  2329. if (mbDiff > iMinSAD)
  2330. goto NEXT_HALF_POSITION;
  2331. ppxlcRef += iWidth2;
  2332. ppxlcCur += MB_SIZE*2;
  2333. }
  2334. } else {
  2335. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2336. for (ix = 0; ix < MB_SIZE; ix++)
  2337. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+1] + ppxlcRef[ix+iWidth2] +
  2338. ppxlcRef[ix+iWidth2+1] + iRound2) >> 2) - ppxlcCur[ix]);
  2339. if (mbDiff > iMinSAD)
  2340. goto NEXT_HALF_POSITION;
  2341. ppxlcRef += iWidth2;
  2342. ppxlcCur += MB_SIZE*2;
  2343. }
  2344. }
  2345. }
  2346. if ((iMinSAD > mbDiff) ||
  2347. ((abs(pmv->m_vctTrueHalfPel.x + destHalfX) + abs(pmv->m_vctTrueHalfPel.y + destHalfY)) >
  2348.  (abs(pmv->m_vctTrueHalfPel.x + incX)      + abs(pmv->m_vctTrueHalfPel.y + incY)))) {
  2349. iMinSAD = mbDiff;
  2350. destHalfX = incX;
  2351. destHalfY = incY;
  2352. }
  2353. NEXT_HALF_POSITION:
  2354. ;
  2355. }
  2356. }
  2357. pmv->iHalfX = destHalfX;
  2358. pmv->iHalfY = destHalfY; // Violates range of -1,0,1 but need to keep (iMVX,iMVY) pure for MV file write
  2359. return iMinSAD;
  2360. }
  2361. // new changes
  2362. Int CVideoObjectEncoder::blkmatch16x8WithShape (
  2363. CMotionVector* pmv, 
  2364. CoordI iXMB, CoordI iYMB,
  2365. Int iFieldSelect,
  2366. const PixelC* ppxlcRefMBY,
  2367. const PixelC* ppxlcRefHalfPel,
  2368. Int iSearchRange,
  2369. Int iDirection
  2370. )
  2371. {
  2372. Int mbDiff; // start with big
  2373. Int iWidth2 = 2*m_iFrameWidthY;
  2374. Int iXDest = iXMB, iYDest = iYMB;
  2375. CoordI x = iXMB, y = iYMB, ix, iy;
  2376. Int uiPosInLoop, iLoop;
  2377. Int iMinSAD = 0;
  2378. CRct CTmp=(iDirection) ? m_rctRefVOPY1 : m_rctRefVOPY0;
  2379. if (m_iMVFileUsage != 1) {
  2380. // Calculate the center point SAD
  2381. const PixelC* ppxlcCurrY = m_ppxlcCurrMBY + iFieldSelect;
  2382. const PixelC* ppxlcCurrBY = m_ppxlcCurrMBBY + iFieldSelect;
  2383. const PixelC* ppxlcRefMB = ppxlcRefMBY;
  2384. for (iy = 0; iy < MB_SIZE/2; iy++) {
  2385. for (ix = 0; ix < MB_SIZE; ix++) {
  2386. if(ppxlcCurrBY[ix] != transpValue)
  2387. iMinSAD += abs (ppxlcCurrY [ix] - ppxlcRefMB [ix]);
  2388. }
  2389. ppxlcCurrY += 2*MB_SIZE;
  2390. ppxlcCurrBY += 2*MB_SIZE;
  2391. ppxlcRefMB += iWidth2;
  2392. }
  2393. // iMinSAD -= FAVORZERO/2; // Apply center favoring bias?
  2394. // Spiral Search for the rest
  2395. for (iLoop = 1; iLoop <= iSearchRange; iLoop++) {
  2396. x++;
  2397. y++;
  2398. ppxlcRefMBY += m_iFrameWidthY + 1;
  2399. for (uiPosInLoop = 0; uiPosInLoop < (iLoop << 3); uiPosInLoop++) { // inside each spiral loop 
  2400. if (
  2401. x >= CTmp.left && y >= CTmp.top && 
  2402. x <= CTmp.right - MB_SIZE && y <= CTmp.bottom - MB_SIZE
  2403. && ((y-iYMB)%2==0)
  2404. ) {
  2405. ppxlcCurrY = m_ppxlcCurrMBY+iFieldSelect;
  2406. ppxlcCurrBY = m_ppxlcCurrMBBY + iFieldSelect;
  2407. ppxlcRefMB = ppxlcRefMBY;
  2408. mbDiff = 0;
  2409. // full pel field prediction
  2410. for (iy = 0; iy < MB_SIZE; iy+=2) {
  2411. for (ix = 0; ix < MB_SIZE; ix++) {
  2412. if(ppxlcCurrBY[ix] != transpValue)
  2413. mbDiff += abs (ppxlcCurrY [ix] - ppxlcRefMB [ix]);
  2414. }
  2415. if (mbDiff > iMinSAD)
  2416. goto NEXT_POSITION; // skip the current position
  2417. ppxlcRefMB += iWidth2;
  2418. ppxlcCurrY += MB_SIZE*2;
  2419. ppxlcCurrBY += MB_SIZE*2;
  2420. }
  2421. iMinSAD = mbDiff;
  2422. iXDest = x;
  2423. iYDest = y;
  2424. }
  2425. NEXT_POSITION:
  2426. if (uiPosInLoop < (iLoop << 1)) {
  2427. ppxlcRefMBY--;
  2428. x--;
  2429. }
  2430. else if (uiPosInLoop < (iLoop << 2)) {
  2431. ppxlcRefMBY -= m_iFrameWidthY;
  2432. y--;
  2433. }
  2434. else if (uiPosInLoop < (iLoop * 6)) {
  2435. ppxlcRefMBY++;   
  2436. x++;
  2437. }
  2438. else {
  2439. ppxlcRefMBY += m_iFrameWidthY;
  2440. y++;
  2441. }
  2442. }
  2443. }
  2444. *pmv = CMotionVector (iXDest - iXMB, iYDest - iYMB);
  2445. } else {
  2446. iXDest = iXMB + pmv->iMVX;
  2447. iYDest = iYMB + pmv->iMVY;
  2448. }
  2449. // 12.22.98 begin of changes, X. Chen
  2450. // check for case when zero MV due to MB outside the extended BB.
  2451. /* if(iXDest==iXMB && iYDest==iYMB
  2452. && (iXDest < CTmp.left || iYDest < CTmp.top
  2453. || iXDest > CTmp.right - MB_SIZE
  2454. || iYDest > CTmp.bottom - MB_SIZE))
  2455. {
  2456. pmv -> iHalfX = 0;
  2457. pmv -> iHalfY = 0;
  2458. return iMinSAD;  
  2459. } */
  2460. // 12.22.98 end of changes X.Chen
  2461. // half pel search
  2462. I8 destHalfX = 0, destHalfY = 0;
  2463. Int lowX = (iXDest == CTmp.left) ? 0 : -1; // 12.22.98 changes
  2464. Int lowY = (iYDest == CTmp.top) ? 0 : -2; // 12.22.98 changes
  2465. Int highX = (iXDest == CTmp.right - MB_SIZE) ? 0 : 1; // 12.22.98 changes
  2466. Int highY = (iYDest == CTmp.bottom - MB_SIZE) ? 0 : 2; // 12.22.98 changes
  2467. Int iRound1 = 1 - m_vopmd.iRoundingControl;
  2468. Int iRound2 = 2 - m_vopmd.iRoundingControl;
  2469. assert(!(pmv->iMVY & 1));
  2470. ppxlcRefHalfPel += pmv->iMVX + m_iFrameWidthY * pmv->iMVY; // 12.22.98
  2471. iMinSAD = 256*256;
  2472. for (Int incY = lowY; incY <= highY; incY += 2) {
  2473. for (Int incX = lowX; incX <= highX; incX++) {
  2474. const PixelC *ppxlcRef = ppxlcRefHalfPel;
  2475. const PixelC *ppxlcCurB = m_ppxlcCurrMBBY + iFieldSelect;
  2476. const PixelC *ppxlcCur = m_ppxlcCurrMBY + iFieldSelect;
  2477. if (incY < 0)
  2478. ppxlcRef -= iWidth2;
  2479. if (incX < 0)
  2480. ppxlcRef--;
  2481. mbDiff = 0;
  2482. if (incY == 0) {
  2483. if (incX == 0) {
  2484. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2485. for (ix = 0; ix < MB_SIZE; ix++) {
  2486. if(ppxlcCurB[ix] != transpValue)
  2487. mbDiff += abs(ppxlcRef[ix] - ppxlcCur[ix]);
  2488. }
  2489. if (mbDiff > iMinSAD)
  2490. goto NEXT_HALF_POSITION;
  2491. ppxlcRef += iWidth2;
  2492. ppxlcCur += MB_SIZE*2;
  2493. ppxlcCurB += MB_SIZE*2;
  2494. }
  2495. } else {
  2496. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2497. for (ix = 0; ix < MB_SIZE; ix++) {
  2498. if(ppxlcCurB[ix] != transpValue)
  2499. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+1] + iRound1) >> 1) - ppxlcCur[ix]);
  2500. }
  2501. if (mbDiff > iMinSAD)
  2502. goto NEXT_HALF_POSITION;
  2503. ppxlcRef += iWidth2;
  2504. ppxlcCur += MB_SIZE*2;
  2505. ppxlcCurB += MB_SIZE*2;
  2506. }
  2507. }
  2508. } else {
  2509. if (incX == 0) {
  2510. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2511. for (ix = 0; ix < MB_SIZE; ix++) {
  2512. if(ppxlcCurB[ix] != transpValue)
  2513. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+iWidth2] + iRound1) >> 1) - ppxlcCur[ix]);
  2514. }
  2515. if (mbDiff > iMinSAD)
  2516. goto NEXT_HALF_POSITION;
  2517. ppxlcRef += iWidth2;
  2518. ppxlcCur += MB_SIZE*2;
  2519. ppxlcCurB += MB_SIZE*2;
  2520. }
  2521. } else {
  2522. for (iy = 0; iy < MB_SIZE; iy += 2) {
  2523. for (ix = 0; ix < MB_SIZE; ix++) {
  2524. if(ppxlcCurB[ix] != transpValue)
  2525. mbDiff += abs(((ppxlcRef[ix] + ppxlcRef[ix+1] + ppxlcRef[ix+iWidth2] +
  2526. ppxlcRef[ix+iWidth2+1] + iRound2) >> 2) - ppxlcCur[ix]);
  2527. }
  2528. if (mbDiff > iMinSAD)
  2529. goto NEXT_HALF_POSITION;
  2530. ppxlcRef += iWidth2;
  2531. ppxlcCur += MB_SIZE*2;
  2532. ppxlcCurB += MB_SIZE*2;
  2533. }
  2534. if ((iMinSAD > mbDiff) ||
  2535. ((abs(pmv->m_vctTrueHalfPel.x + destHalfX) + abs(pmv->m_vctTrueHalfPel.y + destHalfY)) >
  2536.  (abs(pmv->m_vctTrueHalfPel.x + incX)      + abs(pmv->m_vctTrueHalfPel.y + incY)))) {
  2537. iMinSAD = mbDiff;
  2538. destHalfX = incX;
  2539. destHalfY = incY;
  2540. }
  2541. NEXT_HALF_POSITION:
  2542. ;
  2543. }
  2544. }
  2545. pmv->iHalfX = destHalfX;
  2546. pmv->iHalfY = destHalfY; // Violates range of -1,0,1 but need to keep (iMVX,iMVY) pure for MV file write
  2547.   return iMinSAD;
  2548. }
  2549. // end of new changes
  2550. // ~INTERLACE
  2551. Void CVideoObjectEncoder::readPVOPMVs()
  2552. {
  2553. Char line[150];
  2554. int pic, type, ref, rad;
  2555. CMotionVector* pmv = m_rgmv;
  2556.     CRct clip[9];
  2557. m_iMVLineNo++;
  2558. if (fgets(line, sizeof line, m_fMVFile) == NULL) {
  2559. fprintf(stderr, "EOF on %s at %dn", m_pchMVFileName, m_iMVLineNo);
  2560. exit(1);
  2561. }
  2562. if ((sscanf(line + 4, "%d %d %d %d", &pic, &type, &ref, &rad) != 4) ||
  2563. (pic != m_t) ||
  2564. (type != m_vopmd.vopPredType) ||
  2565. (ref != m_tPastRef)) {
  2566. fprintf(stderr, "%s:%d MV read error: expected %c%d(%d), got %c%d(%d)n",
  2567. m_pchMVFileName, m_iMVLineNo, "IPBS"[m_vopmd.vopPredType],
  2568. m_t, m_tPastRef, "IPBS"[type], pic, ref);
  2569. exit(1);
  2570. }
  2571. if (rad > m_vopmd.iSearchRangeForward) {
  2572. fprintf(stderr, "ME radius from file (%d) > current ME radius (%d)n",
  2573.   rad, m_vopmd.iSearchRangeForward);
  2574. exit(1);
  2575. }
  2576.     clip[0] = m_rctRefVOPY0; clip[0].expand(0,          0,          -MB_SIZE,    -MB_SIZE);    // 04/28/99
  2577.     clip[1] = m_rctRefVOPY0; clip[1].expand(0,          0,          -BLOCK_SIZE, -BLOCK_SIZE); // 04/28/99
  2578.     clip[2] = m_rctRefVOPY0; clip[2].expand(BLOCK_SIZE, 0,          -BLOCK_SIZE, -BLOCK_SIZE); // 04/28/99
  2579.     clip[3] = m_rctRefVOPY0; clip[3].expand(0,          BLOCK_SIZE, -BLOCK_SIZE, -BLOCK_SIZE); // 04/28/99
  2580.     clip[4] = m_rctRefVOPY0; clip[4].expand(BLOCK_SIZE, BLOCK_SIZE, -BLOCK_SIZE, -BLOCK_SIZE); // 04/28/99
  2581.     clip[5] = clip[0];
  2582.     clip[6] = clip[0];
  2583.     clip[7] = clip[0];
  2584.     clip[8] = clip[0];
  2585.     CRct ball(-rad, -rad, rad, rad);
  2586. for (Int iMBY = 0; iMBY < m_iNumMBY; iMBY++) {
  2587. for (Int iMBX = 0; iMBX < m_iNumMBX; iMBX++) {
  2588. int x, y, inter;
  2589. m_iMVLineNo++;
  2590. if (fgets(line, sizeof line, m_fMVFile) == NULL) {
  2591. fprintf(stderr, "EOF on %s at %dn", m_pchMVFileName, m_iMVLineNo);
  2592. exit(1);
  2593. }
  2594. if (sscanf(line,
  2595. "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
  2596. &x, &y, &inter,  // MB coordinates and predicted-flag
  2597. &pmv[0].iMVX, &pmv[0].iMVY, // 16x16 MV
  2598. &pmv[5].iMVX, &pmv[5].iMVY, // field top-top MV
  2599. &pmv[6].iMVX, &pmv[6].iMVY, // field top-bot MV
  2600. &pmv[7].iMVX, &pmv[7].iMVY, // field bot-top MV
  2601. &pmv[8].iMVX, &pmv[8].iMVY, // field bot-bot MV
  2602. &pmv[1].iMVX, &pmv[1].iMVY, // Upper left  8x8 block MV
  2603. &pmv[2].iMVX, &pmv[2].iMVY, // Upper right 8x8 block MV
  2604. &pmv[3].iMVX, &pmv[3].iMVY, // Lower left  8x8 block MV
  2605. &pmv[4].iMVX, &pmv[4].iMVY) // Lower right 8x8 block MV
  2606. != 21) {
  2607. fprintf(stderr, "%s: Read error on line %d: %sn",
  2608. m_pchMVFileName, m_iMVLineNo, line);
  2609. exit(1);
  2610. }
  2611. assert(x==iMBX && y==iMBY);
  2612.             x *= MB_SIZE;
  2613.             y *= MB_SIZE;
  2614. for (Int i = 0; i < PVOP_MV_PER_REF_PER_MB; i++) {
  2615. pmv[i].iMVX >>= 1;
  2616. pmv[i].iMVY >>= 1;
  2617.                 CRct bounds = clip[i];
  2618.                 bounds.shift(-x, -y);
  2619.                 bounds.clip(ball);
  2620.                 if (bounds.left   > pmv[i].iMVX) pmv[i].iMVX = bounds.left;
  2621.                 if (bounds.right  < pmv[i].iMVX) pmv[i].iMVX = bounds.right;
  2622.                 if (bounds.top    > pmv[i].iMVY) pmv[i].iMVY = bounds.top;
  2623.                 if (bounds.bottom < pmv[i].iMVY) pmv[i].iMVY = bounds.bottom;
  2624. pmv[i].iHalfX = 0;
  2625. pmv[i].iHalfY = 0;
  2626. pmv[i].computeTrueMV();
  2627. }
  2628. pmv += PVOP_MV_PER_REF_PER_MB;
  2629. }
  2630. }
  2631. }
  2632. Void CVideoObjectEncoder::writePVOPMVs()
  2633. {
  2634. CMotionVector* pmv = m_rgmv;
  2635. CMBMode* pmbmd = m_rgmbmd;
  2636. m_iMVLineNo++;
  2637. fprintf(m_fMVFile, "Pic %d %d %d %dn", m_t,
  2638. (int)m_vopmd.vopPredType, m_tPastRef, m_vopmd.iSearchRangeForward);
  2639. for (Int iMBY = 0; iMBY < m_iNumMBY; iMBY++) {
  2640. for (Int iMBX = 0; iMBX < m_iNumMBX; iMBX++) {
  2641. fprintf(m_fMVFile,
  2642. "%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3dn",
  2643. iMBX, iMBY, pmbmd->m_dctMd != INTRA,
  2644. 2*pmv[0].iMVX, 2*pmv[0].iMVY,
  2645. 2*pmv[5].iMVX, 2*pmv[5].iMVY,
  2646. 2*pmv[6].iMVX, 2*pmv[6].iMVY,
  2647. 2*pmv[7].iMVX, 2*pmv[7].iMVY,
  2648. 2*pmv[8].iMVX, 2*pmv[8].iMVY,
  2649. 2*pmv[1].iMVX, 2*pmv[1].iMVY,
  2650. 2*pmv[2].iMVX, 2*pmv[2].iMVY,
  2651. 2*pmv[3].iMVX, 2*pmv[3].iMVY,
  2652. 2*pmv[4].iMVX, 2*pmv[4].iMVY);
  2653. m_iMVLineNo++;
  2654. pmv += PVOP_MV_PER_REF_PER_MB;
  2655. pmbmd++;  // 04/28/99
  2656. }
  2657. }
  2658. }
  2659. Void CVideoObjectEncoder::readBVOPMVs()
  2660. {
  2661. Char line[150];
  2662. int pic, type, fref, bref, frad, brad;
  2663. CMotionVector* pmvf = m_rgmv;
  2664. CMotionVector* pmvb = m_rgmvBackward;
  2665. m_iMVLineNo++;
  2666. if (fgets(line, sizeof line, m_fMVFile) == NULL) {
  2667. fprintf(stderr, "EOF on %s at %dn", m_pchMVFileName, m_iMVLineNo);
  2668. exit(1);
  2669. }
  2670. if ((sscanf(line + 4, "%d %d %d %d %d %d",
  2671. &pic, &type, &fref, &bref, &frad, &brad) != 6) ||
  2672. (pic != m_t) ||
  2673. (type != m_vopmd.vopPredType) ||
  2674. (fref != m_tPastRef) ||
  2675. (bref != m_tFutureRef)) {
  2676. fprintf(stderr, "%s:%d MV read error: expected %c%d(%d,%d), got %c%d(%d.%d)n",
  2677. m_pchMVFileName, m_iMVLineNo,
  2678. "IPBS"[m_vopmd.vopPredType], m_t,
  2679. m_tPastRef, m_tFutureRef,
  2680. "IPBS"[type], pic, fref, bref);
  2681. exit(1);
  2682. }
  2683. if ((frad > m_vopmd.iSearchRangeForward) ||
  2684. (brad > m_vopmd.iSearchRangeBackward)) {
  2685. fprintf(stderr, "%s:%d(%c%d): MV file ME radii (%d,%d) exceed current range (%d,%d)n",
  2686. m_pchMVFileName, m_iMVLineNo, "IPBS"[type], pic, frad, brad,
  2687. m_vopmd.iSearchRangeForward, m_vopmd.iSearchRangeBackward);
  2688. exit(1);
  2689. }
  2690.     CRct clip = m_rctRefVOPY0; clip.expand(0, 0, -MB_SIZE, -MB_SIZE);
  2691.     CRct fball(-frad, -frad, frad, frad);
  2692.     CRct bball(-brad, -brad, brad, brad);
  2693. Int height = m_iNumMBY * MB_SIZE;
  2694. for (Int y = 0; y < height; y += MB_SIZE) {
  2695. for (Int x = 0; x < m_iVOPWidthY; x += MB_SIZE) {
  2696. m_iMVLineNo++;
  2697. if (fgets(line, sizeof line, m_fMVFile) == NULL) {
  2698. fprintf(stderr, "EOF on %s at %dn", m_pchMVFileName, m_iMVLineNo);
  2699. exit(1);
  2700. }
  2701. if (sscanf(line,
  2702. "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
  2703. &pmvf[0].iMVX, &pmvf[0].iMVY,
  2704. &pmvf[1].iMVX, &pmvf[1].iMVY,
  2705. &pmvf[2].iMVX, &pmvf[2].iMVY,
  2706. &pmvf[3].iMVX, &pmvf[3].iMVY,
  2707. &pmvf[4].iMVX, &pmvf[4].iMVY,
  2708. &pmvb[0].iMVX, &pmvb[0].iMVY,
  2709. &pmvb[1].iMVX, &pmvb[1].iMVY,
  2710. &pmvb[2].iMVX, &pmvb[2].iMVY,
  2711. &pmvb[3].iMVX, &pmvb[3].iMVY,
  2712. &pmvb[4].iMVX, &pmvb[4].iMVY) != 20) {
  2713. fprintf(stderr, "%s: Read error on line %d: %sn",
  2714. m_pchMVFileName, m_iMVLineNo, line);
  2715. exit(1);
  2716. }
  2717. for (Int i = 0; i < BVOP_MV_PER_REF_PER_MB; i++) {
  2718. pmvf[i].iMVX >>= 1;
  2719. pmvf[i].iMVY >>= 1;
  2720.                 CRct bounds(clip);
  2721.                 bounds.shift(-x, -y);
  2722.                 bounds.clip(fball);
  2723.                 if (bounds.left   > pmvf[i].iMVX) pmvf[i].iMVX = bounds.left;
  2724.                 if (bounds.right  < pmvf[i].iMVX) pmvf[i].iMVX = bounds.right;
  2725.                 if (bounds.top    > pmvf[i].iMVY) pmvf[i].iMVY = bounds.top;
  2726.                 if (bounds.bottom < pmvf[i].iMVY) pmvf[i].iMVY = bounds.bottom;
  2727. pmvf[i].iHalfX = 0;
  2728. pmvf[i].iHalfY = 0;
  2729. pmvf[i].computeTrueMV();
  2730. pmvb[i].iMVX >>= 1;
  2731. pmvb[i].iMVY >>= 1;
  2732.                 bounds = clip;
  2733.                 bounds.shift(-x, -y);
  2734.                 bounds.clip(bball);
  2735.                 if (bounds.left   > pmvb[i].iMVX) pmvb[i].iMVX = bounds.left;
  2736.                 if (bounds.right  < pmvb[i].iMVX) pmvb[i].iMVX = bounds.right;
  2737.                 if (bounds.top    > pmvb[i].iMVY) pmvb[i].iMVY = bounds.top;
  2738.                 if (bounds.bottom < pmvb[i].iMVY) pmvb[i].iMVY = bounds.bottom;
  2739. pmvb[i].iHalfX = 0;
  2740. pmvb[i].iHalfY = 0;
  2741. pmvb[i].computeTrueMV();
  2742. }
  2743. pmvf += BVOP_MV_PER_REF_PER_MB;
  2744. pmvb += BVOP_MV_PER_REF_PER_MB;
  2745. }
  2746. }
  2747. }
  2748. Void CVideoObjectEncoder::writeBVOPMVs()
  2749. {
  2750. CMotionVector* pmvf = m_rgmv;
  2751. CMotionVector* pmvb = m_rgmvBackward;
  2752. //CMBMode* pmbmd = m_rgmbmd;
  2753. m_iMVLineNo++;
  2754. fprintf(m_fMVFile, "Pic %d %d %d %d %d %dn",
  2755. m_t, (int)m_vopmd.vopPredType, m_tPastRef, m_tFutureRef,
  2756. m_vopmd.iSearchRangeForward, m_vopmd.iSearchRangeBackward);
  2757. for (Int iMBY = 0; iMBY < m_iNumMBY; iMBY++) {
  2758. for (Int iMBX = 0; iMBX < m_iNumMBX; iMBX++) {
  2759. fprintf(m_fMVFile,
  2760. "%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3dn",
  2761. 2*pmvf[0].iMVX, 2*pmvf[0].iMVY,
  2762. 2*pmvf[1].iMVX, 2*pmvf[1].iMVY,
  2763. 2*pmvf[2].iMVX, 2*pmvf[2].iMVY,
  2764. 2*pmvf[3].iMVX, 2*pmvf[3].iMVY,
  2765. 2*pmvf[4].iMVX, 2*pmvf[4].iMVY,
  2766. 2*pmvb[0].iMVX, 2*pmvb[0].iMVY,
  2767. 2*pmvb[1].iMVX, 2*pmvb[1].iMVY,
  2768. 2*pmvb[2].iMVX, 2*pmvb[2].iMVY,
  2769. 2*pmvb[3].iMVX, 2*pmvb[3].iMVY,
  2770. 2*pmvb[4].iMVX, 2*pmvb[4].iMVY);
  2771. pmvf += BVOP_MV_PER_REF_PER_MB;
  2772. pmvb += BVOP_MV_PER_REF_PER_MB;
  2773. }
  2774. }
  2775. }