You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

515 lines
12KB

  1. /*
  2. * Motion estimation
  3. * Copyright (c) 2000,2001 Gerard Lantau.
  4. *
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include "avcodec.h"
  23. #include "dsputil.h"
  24. #include "mpegvideo.h"
  25. static void halfpel_motion_search(MpegEncContext * s,
  26. int *mx_ptr, int *my_ptr, int dmin,
  27. int xmin, int ymin, int xmax, int ymax);
  28. /* config it to test motion vector encoding (send random vectors) */
  29. //#define CONFIG_TEST_MV_ENCODE
  30. static int pix_sum(UINT8 * pix, int line_size)
  31. {
  32. int s, i, j;
  33. s = 0;
  34. for (i = 0; i < 16; i++) {
  35. for (j = 0; j < 16; j += 8) {
  36. s += pix[0];
  37. s += pix[1];
  38. s += pix[2];
  39. s += pix[3];
  40. s += pix[4];
  41. s += pix[5];
  42. s += pix[6];
  43. s += pix[7];
  44. pix += 8;
  45. }
  46. pix += line_size - 16;
  47. }
  48. return s;
  49. }
  50. static int pix_norm1(UINT8 * pix, int line_size)
  51. {
  52. int s, i, j;
  53. UINT32 *sq = squareTbl + 256;
  54. s = 0;
  55. for (i = 0; i < 16; i++) {
  56. for (j = 0; j < 16; j += 8) {
  57. s += sq[pix[0]];
  58. s += sq[pix[1]];
  59. s += sq[pix[2]];
  60. s += sq[pix[3]];
  61. s += sq[pix[4]];
  62. s += sq[pix[5]];
  63. s += sq[pix[6]];
  64. s += sq[pix[7]];
  65. pix += 8;
  66. }
  67. pix += line_size - 16;
  68. }
  69. return s;
  70. }
  71. static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size)
  72. {
  73. int s, i, j;
  74. UINT32 *sq = squareTbl + 256;
  75. s = 0;
  76. for (i = 0; i < 16; i++) {
  77. for (j = 0; j < 16; j += 8) {
  78. s += sq[pix1[0] - pix2[0]];
  79. s += sq[pix1[1] - pix2[1]];
  80. s += sq[pix1[2] - pix2[2]];
  81. s += sq[pix1[3] - pix2[3]];
  82. s += sq[pix1[4] - pix2[4]];
  83. s += sq[pix1[5] - pix2[5]];
  84. s += sq[pix1[6] - pix2[6]];
  85. s += sq[pix1[7] - pix2[7]];
  86. pix1 += 8;
  87. pix2 += 8;
  88. }
  89. pix1 += line_size - 16;
  90. pix2 += line_size - 16;
  91. }
  92. return s;
  93. }
  94. static void no_motion_search(MpegEncContext * s,
  95. int *mx_ptr, int *my_ptr)
  96. {
  97. *mx_ptr = 16 * s->mb_x;
  98. *my_ptr = 16 * s->mb_y;
  99. }
  100. static int full_motion_search(MpegEncContext * s,
  101. int *mx_ptr, int *my_ptr, int range,
  102. int xmin, int ymin, int xmax, int ymax)
  103. {
  104. int x1, y1, x2, y2, xx, yy, x, y;
  105. int mx, my, dmin, d;
  106. UINT8 *pix;
  107. xx = 16 * s->mb_x;
  108. yy = 16 * s->mb_y;
  109. x1 = xx - range + 1; /* we loose one pixel to avoid boundary pb with half pixel pred */
  110. if (x1 < xmin)
  111. x1 = xmin;
  112. x2 = xx + range - 1;
  113. if (x2 > xmax)
  114. x2 = xmax;
  115. y1 = yy - range + 1;
  116. if (y1 < ymin)
  117. y1 = ymin;
  118. y2 = yy + range - 1;
  119. if (y2 > ymax)
  120. y2 = ymax;
  121. pix = s->new_picture[0] + (yy * s->linesize) + xx;
  122. dmin = 0x7fffffff;
  123. mx = 0;
  124. my = 0;
  125. for (y = y1; y <= y2; y++) {
  126. for (x = x1; x <= x2; x++) {
  127. d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x,
  128. s->linesize, 16);
  129. if (d < dmin ||
  130. (d == dmin &&
  131. (abs(x - xx) + abs(y - yy)) <
  132. (abs(mx - xx) + abs(my - yy)))) {
  133. dmin = d;
  134. mx = x;
  135. my = y;
  136. }
  137. }
  138. }
  139. *mx_ptr = mx;
  140. *my_ptr = my;
  141. #if 0
  142. if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
  143. *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
  144. fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
  145. }
  146. #endif
  147. return dmin;
  148. }
  149. static int log_motion_search(MpegEncContext * s,
  150. int *mx_ptr, int *my_ptr, int range,
  151. int xmin, int ymin, int xmax, int ymax)
  152. {
  153. int x1, y1, x2, y2, xx, yy, x, y;
  154. int mx, my, dmin, d;
  155. UINT8 *pix;
  156. xx = s->mb_x << 4;
  157. yy = s->mb_y << 4;
  158. /* Left limit */
  159. x1 = xx - range;
  160. if (x1 < xmin)
  161. x1 = xmin;
  162. /* Right limit */
  163. x2 = xx + range;
  164. if (x2 > xmax)
  165. x2 = xmax;
  166. /* Upper limit */
  167. y1 = yy - range;
  168. if (y1 < ymin)
  169. y1 = ymin;
  170. /* Lower limit */
  171. y2 = yy + range;
  172. if (y2 > ymax)
  173. y2 = ymax;
  174. pix = s->new_picture[0] + (yy * s->linesize) + xx;
  175. dmin = 0x7fffffff;
  176. mx = 0;
  177. my = 0;
  178. do {
  179. for (y = y1; y <= y2; y += range) {
  180. for (x = x1; x <= x2; x += range) {
  181. d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
  182. if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
  183. dmin = d;
  184. mx = x;
  185. my = y;
  186. }
  187. }
  188. }
  189. range = range >> 1;
  190. x1 = mx - range;
  191. if (x1 < xmin)
  192. x1 = xmin;
  193. x2 = mx + range;
  194. if (x2 > xmax)
  195. x2 = xmax;
  196. y1 = my - range;
  197. if (y1 < ymin)
  198. y1 = ymin;
  199. y2 = my + range;
  200. if (y2 > ymax)
  201. y2 = ymax;
  202. } while (range >= 1);
  203. #ifdef DEBUG
  204. fprintf(stderr, "log - MX: %d\tMY: %d\n", mx, my);
  205. #endif
  206. *mx_ptr = mx;
  207. *my_ptr = my;
  208. return dmin;
  209. }
  210. static int phods_motion_search(MpegEncContext * s,
  211. int *mx_ptr, int *my_ptr, int range,
  212. int xmin, int ymin, int xmax, int ymax)
  213. {
  214. int x1, y1, x2, y2, xx, yy, x, y, lastx, d;
  215. int mx, my, dminx, dminy;
  216. UINT8 *pix;
  217. xx = s->mb_x << 4;
  218. yy = s->mb_y << 4;
  219. /* Left limit */
  220. x1 = xx - range;
  221. if (x1 < xmin)
  222. x1 = xmin;
  223. /* Right limit */
  224. x2 = xx + range;
  225. if (x2 > xmax)
  226. x2 = xmax;
  227. /* Upper limit */
  228. y1 = yy - range;
  229. if (y1 < ymin)
  230. y1 = ymin;
  231. /* Lower limit */
  232. y2 = yy + range;
  233. if (y2 > ymax)
  234. y2 = ymax;
  235. pix = s->new_picture[0] + (yy * s->linesize) + xx;
  236. mx = 0;
  237. my = 0;
  238. x = xx;
  239. y = yy;
  240. do {
  241. dminx = 0x7fffffff;
  242. dminy = 0x7fffffff;
  243. lastx = x;
  244. for (x = x1; x <= x2; x += range) {
  245. d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
  246. if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
  247. dminx = d;
  248. mx = x;
  249. }
  250. }
  251. x = lastx;
  252. for (y = y1; y <= y2; y += range) {
  253. d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
  254. if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
  255. dminy = d;
  256. my = y;
  257. }
  258. }
  259. range = range >> 1;
  260. x = mx;
  261. y = my;
  262. x1 = mx - range;
  263. if (x1 < xmin)
  264. x1 = xmin;
  265. x2 = mx + range;
  266. if (x2 > xmax)
  267. x2 = xmax;
  268. y1 = my - range;
  269. if (y1 < ymin)
  270. y1 = ymin;
  271. y2 = my + range;
  272. if (y2 > ymax)
  273. y2 = ymax;
  274. } while (range >= 1);
  275. #ifdef DEBUG
  276. fprintf(stderr, "phods - MX: %d\tMY: %d\n", mx, my);
  277. #endif
  278. /* half pixel search */
  279. *mx_ptr = mx;
  280. *my_ptr = my;
  281. return dminy;
  282. }
  283. /* The idea would be to make half pel ME after Inter/Intra decision to
  284. save time. */
  285. static void halfpel_motion_search(MpegEncContext * s,
  286. int *mx_ptr, int *my_ptr, int dmin,
  287. int xmin, int ymin, int xmax, int ymax)
  288. {
  289. int mx, my, mx1, my1, d, xx, yy, dminh;
  290. UINT8 *pix;
  291. mx = *mx_ptr << 1;
  292. my = *my_ptr << 1;
  293. xx = 16 * s->mb_x;
  294. yy = 16 * s->mb_y;
  295. dminh = dmin;
  296. /* Half pixel search */
  297. mx1 = mx;
  298. my1 = my;
  299. pix = s->new_picture[0] + (yy * s->linesize) + xx;
  300. if ((mx > (xmin << 1)) && mx < (xmax << 1) &&
  301. (my > (ymin << 1)) && my < (ymax << 1)) {
  302. int dx, dy, px, py;
  303. UINT8 *ptr;
  304. for (dy = -1; dy <= 1; dy++) {
  305. for (dx = -1; dx <= 1; dx++) {
  306. if (dx != 0 || dy != 0) {
  307. px = mx1 + dx;
  308. py = my1 + dy;
  309. ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1);
  310. switch (((py & 1) << 1) | (px & 1)) {
  311. default:
  312. case 0:
  313. d = pix_abs16x16(pix, ptr, s->linesize, 16);
  314. break;
  315. case 1:
  316. d = pix_abs16x16_x2(pix, ptr, s->linesize, 16);
  317. break;
  318. case 2:
  319. d = pix_abs16x16_y2(pix, ptr, s->linesize, 16);
  320. break;
  321. case 3:
  322. d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16);
  323. break;
  324. }
  325. if (d < dminh) {
  326. dminh = d;
  327. mx = px;
  328. my = py;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. *mx_ptr = mx - (xx << 1);
  335. *my_ptr = my - (yy << 1);
  336. //fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr);
  337. }
  338. #ifndef CONFIG_TEST_MV_ENCODE
  339. int estimate_motion(MpegEncContext * s,
  340. int mb_x, int mb_y,
  341. int *mx_ptr, int *my_ptr)
  342. {
  343. UINT8 *pix, *ppix;
  344. int sum, varc, vard, mx, my, range, dmin, xx, yy;
  345. int xmin, ymin, xmax, ymax;
  346. range = 8 * (1 << (s->f_code - 1));
  347. /* XXX: temporary kludge to avoid overflow for msmpeg4 */
  348. if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
  349. range = range * 2;
  350. if (s->unrestricted_mv) {
  351. xmin = -16;
  352. ymin = -16;
  353. xmax = s->width;
  354. ymax = s->height;
  355. } else {
  356. xmin = 0;
  357. ymin = 0;
  358. xmax = s->width - 16;
  359. ymax = s->height - 16;
  360. }
  361. switch(s->full_search) {
  362. case ME_ZERO:
  363. default:
  364. no_motion_search(s, &mx, &my);
  365. dmin = 0;
  366. break;
  367. case ME_FULL:
  368. dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax);
  369. break;
  370. case ME_LOG:
  371. dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
  372. break;
  373. case ME_PHODS:
  374. dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
  375. break;
  376. }
  377. emms_c();
  378. /* intra / predictive decision */
  379. xx = mb_x * 16;
  380. yy = mb_y * 16;
  381. pix = s->new_picture[0] + (yy * s->linesize) + xx;
  382. /* At this point (mx,my) are full-pell and the absolute displacement */
  383. ppix = s->last_picture[0] + (my * s->linesize) + mx;
  384. sum = pix_sum(pix, s->linesize);
  385. varc = pix_norm1(pix, s->linesize);
  386. vard = pix_norm(pix, ppix, s->linesize);
  387. vard = vard >> 8;
  388. sum = sum >> 8;
  389. varc = (varc >> 8) - (sum * sum);
  390. #if 0
  391. printf("varc=%d (sum=%d) vard=%d mx=%d my=%d\n",
  392. varc, sum, vard, mx - xx, my - yy);
  393. #endif
  394. if (vard <= 64 || vard < varc) {
  395. if (s->full_search != ME_ZERO) {
  396. halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax);
  397. } else {
  398. mx -= 16 * s->mb_x;
  399. my -= 16 * s->mb_y;
  400. }
  401. *mx_ptr = mx;
  402. *my_ptr = my;
  403. return 0;
  404. } else {
  405. *mx_ptr = 0;
  406. *my_ptr = 0;
  407. return 1;
  408. }
  409. }
  410. #else
  411. /* test version which generates valid random vectors */
  412. int estimate_motion(MpegEncContext * s,
  413. int mb_x, int mb_y,
  414. int *mx_ptr, int *my_ptr)
  415. {
  416. int xx, yy, x1, y1, x2, y2, range;
  417. if ((random() % 10) >= 5) {
  418. range = 8 * (1 << (s->f_code - 1));
  419. if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
  420. range = range * 2;
  421. xx = 16 * s->mb_x;
  422. yy = 16 * s->mb_y;
  423. x1 = xx - range;
  424. if (x1 < 0)
  425. x1 = 0;
  426. x2 = xx + range - 1;
  427. if (x2 > (s->width - 16))
  428. x2 = s->width - 16;
  429. y1 = yy - range;
  430. if (y1 < 0)
  431. y1 = 0;
  432. y2 = yy + range - 1;
  433. if (y2 > (s->height - 16))
  434. y2 = s->height - 16;
  435. *mx_ptr = (random() % (2 * (x2 - x1 + 1))) + 2 * (x1 - xx);
  436. *my_ptr = (random() % (2 * (y2 - y1 + 1))) + 2 * (y1 - yy);
  437. return 0;
  438. } else {
  439. *mx_ptr = 0;
  440. *my_ptr = 0;
  441. return 1;
  442. }
  443. }
  444. #endif