1 /*
2  *	/brief fast motion estimation filter
3  *	/author Zachary Drew, Copyright 2005
4  *
5  *	Currently only uses Gamma data for comparisonon (bug or feature?)
6  *	SSE optimized where available.
7  *
8  *	Vector orientation: The vector data that is generated for the current frame specifies
9  *	the motion from the previous frame to the current frame. To know how a macroblock
10  *	in the current frame will move in the future, the next frame is needed.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
25  */
26 
27 
28 #include "filter_motion_est.h"
29 #include <framework/mlt.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 
37 #ifdef USE_SSE
38 #include "sad_sse.h"
39 #endif
40 
41 #define NDEBUG
42 #include <assert.h>
43 
44 #undef DEBUG
45 #undef DEBUG_ASM
46 #undef BENCHMARK
47 #undef COUNT_COMPARES
48 
49 #define DIAMOND_SEARCH 0x0
50 #define FULL_SEARCH 0x1
51 #define SHIFT 8
52 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
53 
54 
55 struct motion_est_context_s
56 {
57 	int initialized;				// true if filter has been initialized
58 
59 #ifdef COUNT_COMPARES
60 	int compares;
61 #endif
62 
63 	/* same as mlt_frame's parameters */
64 	int width, height;
65 
66 	/* Operational details */
67 	int mb_w, mb_h;
68 	int xstride, ystride;
69 	uint8_t *cache_image;			// Copy of current frame
70 	uint8_t *former_image;			// Copy of former frame
71 	int search_method;
72 	int skip_prediction;
73 	int shot_change;
74 	int limit_x, limit_y;			// max x and y of a motion vector
75 	int initial_thresh;
76 	int check_chroma;			// if check_chroma == 1 then compare chroma
77 	int denoise;
78 	int previous_msad;
79 	int show_reconstruction;
80 	int toggle_when_paused;
81 	int show_residual;
82 
83 	/* bounds */
84 	struct mlt_geometry_item_s bounds;	// Current bounds (from filters crop_detect, autotrack rectangle, or other)
85 
86 	/* bounds in macroblock units; macroblocks are completely contained within the boundry */
87 	int left_mb, prev_left_mb, right_mb, prev_right_mb;
88 	int top_mb, prev_top_mb, bottom_mb, prev_bottom_mb;
89 
90 	/* size of our vector buffers */
91 	int mv_buffer_height, mv_buffer_width, mv_size;
92 
93 	/* vector buffers */
94 	int former_vectors_valid;		//<! true if the previous frame's buffered motion vector data is valid
95 	motion_vector *former_vectors;
96 	motion_vector *current_vectors;
97 	motion_vector *denoise_vectors;
98 	mlt_position former_frame_position, current_frame_position;
99 
100 	/* diagnostic metrics */
101 	float predictive_misses;		// How often do the prediction motion vectors fail?
102 	int comparison_average;			// How far does the best estimation deviate from a perfect comparison?
103 	int bad_comparisons;
104 	int average_length;
105 	int average_x, average_y;
106 
107 	/* run-time configurable comparison functions */
108 	int (*compare_reference)(uint8_t *, uint8_t *, int, int, int, int);
109 	int (*compare_optimized)(uint8_t *, uint8_t *, int, int, int, int);
110 
111 };
112 
113 // This is used to constrains pixel operations between two blocks to be within the image boundry
constrain(int * x,int * y,int * w,int * h,const int dx,const int dy,const int left,const int right,const int top,const int bottom)114 inline static int constrain(	int *x, int *y, int *w,	int *h,
115 				const int dx, const int dy,
116 				const int left, const int right,
117 				const int top, const int bottom)
118 {
119 	uint32_t penalty = 1 << SHIFT;			// Retain a few extra bits of precision
120 	int x2 = *x + dx;
121 	int y2 = *y + dy;
122 	int w_remains = *w;
123 	int h_remains = *h;
124 
125 	// Origin of macroblock moves left of image boundy
126 	if( *x < left || x2 < left ) {
127 		w_remains = *w - left + ((*x < x2) ?  *x : x2);
128 		*x += *w - w_remains;
129 	}
130 	// Portion of macroblock moves right of image boundry
131 	else if( *x + *w > right || x2 + *w > right )
132 		w_remains = right - ((*x > x2) ? *x : x2);
133 
134 	// Origin of macroblock moves above image boundy
135 	if( *y < top || y2 < top ) {
136 		h_remains = *h - top + ((*y < y2) ? *y : y2);
137 		*y += *h - h_remains;
138 	}
139 	// Portion of macroblock moves below image boundry
140 	else if( *y + *h > bottom || y2 + *h > bottom )
141 		h_remains = bottom - ((*y > y2) ?  *y : y2);
142 
143 	if( w_remains == *w && h_remains == *h ) return penalty;
144 	if( w_remains <= 0 || h_remains <= 0) return 0;	// Block is clipped out of existence
145 	penalty = (*w * *h * penalty)
146 		/ ( w_remains * h_remains);		// Recipricol of the fraction of the block that remains
147 
148 	assert(*x >= left); assert(x2 + *w - w_remains >= left);
149 	assert(*y >= top); assert(y2 + *h - h_remains >= top);
150 	assert(*x + w_remains <= right); assert(x2 + w_remains <= right);
151 	assert(*y + h_remains <= bottom); assert(y2 + h_remains <= bottom);
152 
153 	*w = w_remains;					// Update the width and height
154 	*h = h_remains;
155 
156 	return penalty;
157 }
158 
159 /** /brief Reference Sum of Absolute Differences comparison function
160 *
161 */
sad_reference(uint8_t * block1,uint8_t * block2,const int xstride,const int ystride,const int w,const int h)162 static int sad_reference( uint8_t *block1, uint8_t *block2, const int xstride, const int ystride, const int w, const int h )
163 {
164 	int i, j, score = 0;
165 	for ( j = 0; j < h; j++ ){
166 		for ( i = 0; i < w; i++ ){
167 			score += ABS( block1[i*xstride] - block2[i*xstride] );
168 		}
169 		block1 += ystride;
170 		block2 += ystride;
171 	}
172 
173 	return score;
174 }
175 
176 
177 /** /brief Abstracted block comparison function
178 */
block_compare(uint8_t * block1,uint8_t * block2,int x,int y,int dx,int dy,struct motion_est_context_s * c)179 inline static int block_compare( uint8_t *block1,
180 			   uint8_t *block2,
181 			   int x,
182 			   int y,
183 			   int dx,
184 			   int dy,
185 			   struct motion_est_context_s *c)
186 {
187 
188 #ifdef COUNT_COMPARES
189 	c->compares++;
190 #endif
191 
192 	int score;
193 
194 	// Default comparison may be overridden by the slower, more capable reference comparison
195 	int (*cmp)(uint8_t *, uint8_t *, int, int, int, int) = c->compare_optimized;
196 
197 	// vector displacement limited has been exceeded
198 	if( ABS( dx ) >= c->limit_x || ABS( dy ) >= c->limit_y )
199 		return MAX_MSAD;
200 
201 	int mb_w = c->mb_w;	// Some writeable local copies
202 	int mb_h = c->mb_h;
203 
204 	// Determine if either macroblock got clipped
205 	int penalty = constrain( &x, &y, &mb_w,	&mb_h, dx, dy, 0, c->width, 0, c->height);
206 
207 	// Some gotchas
208 	if( penalty == 0 )			// Clipped out of existence: Return worst score
209 		return MAX_MSAD;
210 	else if( penalty != 1<<SHIFT )		// Nonstandard macroblock dimensions: Disable SIMD optimizizations.
211 		cmp = c->compare_reference;
212 
213 	// Calculate the memory locations of the macroblocks
214 	block1 += x	 * c->xstride + y 	* c->ystride;
215 	block2 += (x+dx) * c->xstride + (y+dy)  * c->ystride;
216 
217 	#ifdef DEBUG_ASM
218 	if( penalty == 1<<SHIFT ){
219 		score = c->compare_reference( block1, block2, c->xstride, c->ystride, mb_w, mb_h );
220 		int score2 = c->compare_optimized( block1, block2, c->xstride, c->ystride, mb_w, mb_h );
221 		if ( score != score2 )
222 			fprintf(stderr, "Your assembly doesn't work! Reference: %d Asm: %d\n", score, score2);
223 	}
224 	else
225 	#endif
226 
227 	score = cmp( block1, block2, c->xstride, c->ystride, mb_w, mb_h );
228 
229 	return ( score * penalty ) >> SHIFT;			// Ditch the extra precision
230 }
231 
check_candidates(uint8_t * ref,uint8_t * candidate_base,const int x,const int y,const motion_vector * candidates,const int count,const int unique,motion_vector * result,struct motion_est_context_s * c)232 static inline void check_candidates (   uint8_t *ref,
233 					uint8_t *candidate_base,
234 					const int x,
235 					const int y,
236 					const motion_vector *candidates,// Contains to_x & to_y
237 					const int count,		// Number of candidates
238 					const int unique,		// Sometimes we know the candidates are unique
239 					motion_vector *result,
240 					struct motion_est_context_s *c )
241 {
242 		int score, i, j;
243 		/* Scan for the best candidate */
244 		for ( i = 0; i < count; i++ )
245 		{
246 			// this little dohicky ignores duplicate candidates, if they are possible
247 			if ( unique == 0 ) {
248 				j = 0;
249 				while ( j < i )
250 				{
251 					if ( candidates[j].dx == candidates[i].dx &&
252 					     candidates[j].dy == candidates[i].dy )
253 							goto next_for_loop;
254 
255 					j++;
256 				}
257 			}
258 
259 			// Luma
260 			score = block_compare( ref, candidate_base,
261 						x, y,
262 						candidates[i].dx,	// from
263 						candidates[i].dy,
264 						c);
265 
266 			if ( score < result->msad ) {	// New minimum
267 				result->dx = candidates[i].dx;
268 				result->dy = candidates[i].dy;
269 				result->msad = score;
270 			}
271 			next_for_loop:;
272 		}
273 }
274 
275 /* /brief Diamond search
276 * Operates on a single macroblock
277 */
diamond_search(uint8_t * ref,uint8_t * candidate_base,const int x,const int y,struct motion_vector_s * result,struct motion_est_context_s * c)278 static inline void diamond_search(
279 			uint8_t *ref,				//<! Image data from previous frame
280 			uint8_t *candidate_base,		//<! Image data in current frame
281 			const int x,				//<! X upper left corner of macroblock
282 			const int y,				//<! U upper left corner of macroblock
283 			struct motion_vector_s *result,		//<! Best predicted mv and eventual result
284 			struct motion_est_context_s *c)		//<! motion estimation context
285 {
286 
287 	// diamond search pattern
288 	motion_vector candidates[4];
289 
290 	// Keep track of best and former best candidates
291 	motion_vector best, former;
292 	best.dx = 0;
293 	best.dy = 0;
294 	former.dx = 0;
295 	former.dy = 0;
296 
297 	// The direction of the refinement needs to be known
298 	motion_vector current;
299 
300 	int i, first = 1;
301 
302 	// Loop through the search pattern
303 	while( 1 ) {
304 
305 		current.dx = result->dx;
306 		current.dy = result->dy;
307 
308 		if ( first == 1 )	// Set the initial pattern
309 		{
310 			candidates[0].dx = result->dx + 1; candidates[0].dy = result->dy + 0;
311 			candidates[1].dx = result->dx + 0; candidates[1].dy = result->dy + 1;
312 			candidates[2].dx = result->dx - 1; candidates[2].dy = result->dy + 0;
313 			candidates[3].dx = result->dx + 0; candidates[3].dy = result->dy - 1;
314 			i = 4;
315 		}
316 		else	 // Construct the next portion of the search pattern
317 		{
318 			candidates[0].dx = result->dx + best.dx;
319 			candidates[0].dy = result->dy + best.dy;
320 			if (best.dx == former.dx && best.dy == former.dy) {
321 				candidates[1].dx = result->dx + best.dy;
322 				candidates[1].dy = result->dy + best.dx;		//	Yes, the wires
323 				candidates[2].dx = result->dx - best.dy;		// 	are crossed
324 				candidates[2].dy = result->dy - best.dx;
325 				i = 3;
326 			} else {
327 				candidates[1].dx = result->dx + former.dx;
328 				candidates[1].dy = result->dy + former.dy;
329 				i = 2;
330 			}
331 
332 			former.dx = best.dx; former.dy = best.dy; 	// Keep track of new former best
333 		}
334 
335 		check_candidates ( ref, candidate_base, x, y, candidates, i, 1, result, c );
336 
337 		// Which candidate was the best?
338 		best.dx = result->dx - current.dx;
339 		best.dy = result->dy - current.dy;
340 
341 		// A better candidate was not found
342 		if ( best.dx == 0 && best.dy == 0 )
343 			return;
344 
345 		if ( first == 1 ){
346 			first = 0;
347 			former.dx = best.dx; former.dy = best.dy; // First iteration, sensible value for former.d*
348 		}
349 	}
350 }
351 
352 /* /brief Full (brute) search
353 * Operates on a single macroblock
354 */
355 __attribute__((used))
full_search(uint8_t * ref,uint8_t * candidate_base,int x,int y,struct motion_vector_s * result,struct motion_est_context_s * c)356 static void full_search(
357 			uint8_t *ref,				//<! Image data from previous frame
358 			uint8_t *candidate_base,		//<! Image data in current frame
359 			int x,					//<! X upper left corner of macroblock
360 			int y,					//<! U upper left corner of macroblock
361 			struct motion_vector_s *result,		//<! Best predicted mv and eventual result
362 			struct motion_est_context_s *c)		//<! motion estimation context
363 {
364 	// Keep track of best candidate
365 	int i,j,score;
366 
367 	// Go loopy
368 	for( i = -c->mb_w; i <= c->mb_w; i++ ){
369 		for( j = -c->mb_h; j <=  c->mb_h; j++ ){
370 
371 			score = block_compare( ref, candidate_base,
372 					 	x,
373 					 	y,
374 					 	x + i,
375 					 	y + j,
376 					 	c);
377 
378 			if ( score < result->msad ) {
379 				result->dx = i;
380 				result->dy = j;
381 				result->msad = score;
382 			}
383 		}
384 	}
385 }
386 
387 // Macros for pointer calculations
388 #define CURRENT(i,j)	( c->current_vectors + (j)*c->mv_buffer_width + (i) )
389 #define FORMER(i,j)	( c->former_vectors + (j)*c->mv_buffer_width + (i) )
390 #define DENOISE(i,j)	( c->denoise_vectors + (j)*c->mv_buffer_width + (i) )
391 
ncompare(const void * a,const void * b)392 int ncompare (const void * a, const void * b)
393 {
394 	return ( *(const int*)a - *(const int*)b );
395 }
396 
397 // motion vector denoising
398 // for x and y components separately,
399 // change the vector to be the median value of the 9 adjacent vectors
median_denoise(motion_vector * v,struct motion_est_context_s * c)400 static void median_denoise( motion_vector *v, struct motion_est_context_s *c )
401 {
402 	int xvalues[9], yvalues[9];
403 
404 	int i,j,n;
405 	for( j = c->top_mb; j <= c->bottom_mb; j++ )
406 		for( i = c->left_mb; i <= c->right_mb; i++ ){
407 		{
408 			n = 0;
409 
410 			xvalues[n  ] = CURRENT(i,j)->dx; // Center
411 			yvalues[n++] = CURRENT(i,j)->dy;
412 
413 			if( i > c->left_mb ) // Not in First Column
414 			{
415 				xvalues[n  ] = CURRENT(i-1,j)->dx; // Left
416 				yvalues[n++] = CURRENT(i-1,j)->dy;
417 
418 				if( j > c->top_mb ) {
419 					xvalues[n  ] = CURRENT(i-1,j-1)->dx; // Upper Left
420 					yvalues[n++] = CURRENT(i-1,j-1)->dy;
421 				}
422 
423 				if( j < c->bottom_mb ) {
424 					xvalues[n  ] = CURRENT(i-1,j+1)->dx; // Bottom Left
425 					yvalues[n++] = CURRENT(i-1,j+1)->dy;
426 				}
427 			}
428 			if( i < c->right_mb ) // Not in Last Column
429 			{
430 				xvalues[n  ] = CURRENT(i+1,j)->dx; // Right
431 				yvalues[n++] = CURRENT(i+1,j)->dy;
432 
433 
434 				if( j > c->top_mb ) {
435 					xvalues[n  ] = CURRENT(i+1,j-1)->dx; // Upper Right
436 					yvalues[n++] = CURRENT(i+1,j-1)->dy;
437 				}
438 
439 				if( j < c->bottom_mb ) {
440 					xvalues[n  ] = CURRENT(i+1,j+1)->dx; // Bottom Right
441 					yvalues[n++] = CURRENT(i+1,j+1)->dy;
442 				}
443 			}
444 			if( j > c->top_mb ) // Not in First Row
445 			{
446 				xvalues[n  ] = CURRENT(i,j-1)->dx; // Top
447 				yvalues[n++] = CURRENT(i,j-1)->dy;
448 			}
449 
450 			if( j < c->bottom_mb ) // Not in Last Row
451 			{
452 				xvalues[n  ] = CURRENT(i,j+1)->dx; // Bottom
453 				yvalues[n++] = CURRENT(i,j+1)->dy;
454 			}
455 
456 			qsort (xvalues, n, sizeof(int), ncompare);
457 			qsort (yvalues, n, sizeof(int), ncompare);
458 
459 			if( n % 2 == 1 ) {
460 				DENOISE(i,j)->dx = xvalues[n/2];
461 				DENOISE(i,j)->dy = yvalues[n/2];
462 			}
463 			else {
464 				DENOISE(i,j)->dx = (xvalues[n/2] + xvalues[n/2+1])/2;
465 				DENOISE(i,j)->dy = (yvalues[n/2] + yvalues[n/2+1])/2;
466 			}
467 		}
468 	}
469 
470 	motion_vector *t = c->current_vectors;
471 	c->current_vectors = c->denoise_vectors;
472 	c->denoise_vectors = t;
473 
474 }
475 
476 // Credits: ffmpeg
477 // return the median
median_predictor(int a,int b,int c)478 static inline int median_predictor(int a, int b, int c) {
479 	if ( a > b ){
480 		if ( c > b ){
481 			if ( c > a  ) b = a;
482 			else	  b = c;
483 		}
484 	} else {
485 		if ( b > c ){
486 			if ( c > a ) b = c;
487 			else	 b = a;
488 		}
489 	}
490 	return b;
491 }
492 
493 
494 /** /brief Motion search
495 *
496 * For each macroblock in the current frame, estimate the block from the last frame that
497 * matches best.
498 *
499 * Vocab: Colocated - the pixel in the previous frame at the current position
500 *
501 * Based on enhanced predictive zonal search. [Tourapis 2002]
502 */
motion_search(uint8_t * from,uint8_t * to,struct motion_est_context_s * c)503 static void motion_search( uint8_t *from,			//<! Image data.
504 		   	   uint8_t *to,				//<! Image data. Rigid grid.
505 			   struct motion_est_context_s *c)	//<! The context
506 {
507 
508 #ifdef COUNT_COMPARES
509 	compares = 0;
510 #endif
511 
512 	motion_vector candidates[10];
513 	motion_vector *here;		// This one gets used a lot (about 30 times per macroblock)
514 	int n = 0;
515 
516 	int i, j, count=0;
517 
518 	// For every macroblock, perform motion vector estimation
519 	for( i = c->left_mb; i <= c->right_mb; i++ ){
520 	 for( j = c->top_mb; j <= c->bottom_mb; j++ ){
521 
522 		here = CURRENT(i,j);
523 		here->valid = 1;
524 		here->color = 100;
525 		here->msad = MAX_MSAD;
526 		count++;
527 		n = 0;
528 
529 
530 		/* Stack the predictors [i.e. checked in reverse order] */
531 
532 		/* Adjacent to collocated */
533 		if( c->former_vectors_valid )
534 		{
535 			// Top of colocated
536 			if( j > c->prev_top_mb ){// && COL_TOP->valid ){
537 				candidates[n  ].dx = FORMER(i,j-1)->dx;
538 				candidates[n++].dy = FORMER(i,j-1)->dy;
539 			}
540 
541 			// Left of colocated
542 			if( i > c->prev_left_mb ){// && COL_LEFT->valid ){
543 				candidates[n  ].dx = FORMER(i-1,j)->dx;
544 				candidates[n++].dy = FORMER(i-1,j)->dy;
545 			}
546 
547 			// Right of colocated
548 			if( i < c->prev_right_mb ){// && COL_RIGHT->valid ){
549 				candidates[n  ].dx = FORMER(i+1,j)->dx;
550 				candidates[n++].dy = FORMER(i+1,j)->dy;
551 			}
552 
553 			// Bottom of colocated
554 			if( j < c->prev_bottom_mb ){// && COL_BOTTOM->valid ){
555 				candidates[n  ].dx = FORMER(i,j+1)->dx;
556 				candidates[n++].dy = FORMER(i,j+1)->dy;
557 			}
558 
559 			// And finally, colocated
560 			candidates[n  ].dx = FORMER(i,j)->dx;
561 			candidates[n++].dy = FORMER(i,j)->dy;
562 		}
563 
564 		// For macroblocks not in the top row
565 		if ( j > c->top_mb) {
566 
567 			// Top if ( TOP->valid ) {
568 				candidates[n  ].dx = CURRENT(i,j-1)->dx;
569 				candidates[n++].dy = CURRENT(i,j-1)->dy;
570 			//}
571 
572 			// Top-Right, macroblocks not in the right row
573 			if ( i < c->right_mb ){// && TOP_RIGHT->valid ) {
574 				candidates[n  ].dx = CURRENT(i+1,j-1)->dx;
575 				candidates[n++].dy = CURRENT(i+1,j-1)->dy;
576 			}
577 		}
578 
579 		// Left, Macroblocks not in the left column
580 		if ( i > c->left_mb ){// && LEFT->valid ) {
581 			candidates[n  ].dx = CURRENT(i-1,j)->dx;
582 			candidates[n++].dy = CURRENT(i-1,j)->dy;
583 		}
584 
585 		/* Median predictor vector (median of left, top, and top right adjacent vectors) */
586 		if ( i > c->left_mb && j > c->top_mb && i < c->right_mb
587 			 )//&& LEFT->valid && TOP->valid && TOP_RIGHT->valid )
588 		{
589 			candidates[n  ].dx = median_predictor( CURRENT(i-1,j)->dx, CURRENT(i,j-1)->dx, CURRENT(i+1,j-1)->dx);
590 			candidates[n++].dy = median_predictor( CURRENT(i-1,j)->dy, CURRENT(i,j-1)->dy, CURRENT(i+1,j-1)->dy);
591 		}
592 
593 		// Zero vector
594 		candidates[n  ].dx = 0;
595 		candidates[n++].dy = 0;
596 
597 		int x = i * c->mb_w;
598 		int y = j * c->mb_h;
599 		check_candidates ( to, from, x, y, candidates, n, 0, here, c );
600 
601 
602 #ifndef FULLSEARCH
603 		diamond_search( to, from, x, y, here, c);
604 #else
605 		full_search( to, from, x, y, here, c);
606 #endif
607 
608 		assert( x + c->mb_w + here->dx > 0 );	// All macroblocks must have area > 0
609 		assert( y + c->mb_h + here->dy > 0 );
610 		assert( x + here->dx < c->width );
611 		assert( y + here->dy < c->height );
612 
613 	 } /* End column loop */
614 	} /* End row loop */
615 
616 #ifdef USE_SSE
617 	asm volatile ( "emms" );
618 #endif
619 
620 #ifdef COUNT_COMPARES
621 	fprintf(stderr, "%d comparisons per block were made", compares/count);
622 #endif
623 	return;
624 }
625 
collect_post_statistics(struct motion_est_context_s * c)626 void collect_post_statistics( struct motion_est_context_s *c ) {
627 
628 	c->comparison_average = 0;
629 	c->average_length = 0;
630 	c->average_x = 0;
631 	c->average_y = 0;
632 
633 	int i, j, count = 0;
634 
635 	for ( i = c->left_mb; i <= c->right_mb; i++ ){
636 	 for ( j = c->top_mb; j <= c->bottom_mb; j++ ){
637 
638 		count++;
639 		c->comparison_average += CURRENT(i,j)->msad;
640 		c->average_x += CURRENT(i,j)->dx;
641 		c->average_y += CURRENT(i,j)->dy;
642 
643 
644 	 }
645 	}
646 
647 	if ( count > 0 )
648 	{
649 		c->comparison_average /= count;
650 		c->average_x /= count;
651 		c->average_y /= count;
652 		c->average_length = sqrt( c->average_x * c->average_x + c->average_y * c->average_y );
653 	}
654 
655 }
656 
init_optimizations(struct motion_est_context_s * c)657 static void init_optimizations( struct motion_est_context_s *c )
658 {
659 	switch(c->mb_w){
660 #ifdef USE_SSE
661 		case 4:  if(c->mb_h == 4)	c->compare_optimized = sad_sse_422_luma_4x4;
662 			 else				c->compare_optimized = sad_sse_422_luma_4w;
663 			 break;
664 		case 8:  if(c->mb_h == 8)  c->compare_optimized = sad_sse_422_luma_8x8;
665 			 else				c->compare_optimized = sad_sse_422_luma_8w;
666 			 break;
667 		case 16: if(c->mb_h == 16) c->compare_optimized = sad_sse_422_luma_16x16;
668 			 else				c->compare_optimized = sad_sse_422_luma_16w;
669 			 break;
670 		case 32: if(c->mb_h == 32) c->compare_optimized = sad_sse_422_luma_32x32;
671 			 else				c->compare_optimized = sad_sse_422_luma_32w;
672 			 break;
673 		case 64: c->compare_optimized = sad_sse_422_luma_64w;
674 			 break;
675 #endif
676 		default: c->compare_optimized = sad_reference;
677 			 break;
678 	}
679 }
680 
set_red(uint8_t * image,struct motion_est_context_s * c)681 inline static void set_red(uint8_t *image, struct motion_est_context_s *c)
682 {
683 	int n;
684 	for( n = 0; n < c->width * c->height * 2; n+=4 )
685 	{
686 		image[n]   = 79;
687 		image[n+1] = 91;
688 		image[n+2] = 79;
689 		image[n+3] = 237;
690 	}
691 
692 }
693 
show_residual(uint8_t * result,struct motion_est_context_s * c)694 static void show_residual( uint8_t *result,  struct motion_est_context_s *c )
695 {
696 	int i, j;
697 	int x,y,w,h;
698 	int dx, dy;
699 	int tx,ty;
700 	uint8_t *b, *r;
701 
702 //	set_red(result,c);
703 
704 	for( j = c->top_mb; j <= c->bottom_mb; j++ ){
705 	 for( i = c->left_mb; i <= c->right_mb; i++ ){
706 
707 		dx = CURRENT(i,j)->dx;
708 		dy = CURRENT(i,j)->dy;
709 		w = c->mb_w;
710 		h = c->mb_h;
711 		x = i * w;
712 		y = j * h;
713 
714 		// Denoise function caused some blocks to be completely clipped, ignore them
715 		if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 )
716 			continue;
717 
718 		for( ty = y; ty < y + h ; ty++ ){
719 		 for( tx = x; tx < x + w ; tx++ ){
720 
721 			b = c->former_image +  (tx+dx)*c->xstride + (ty+dy)*c->ystride;
722 			r = result +		tx*c->xstride + ty*c->ystride;
723 
724 			r[0] = 16 + ABS( r[0] - b[0] );
725 
726 			if( dx % 2 == 0 )
727 				r[1] = 128 + ABS( r[1] - b[1] );
728 			else
729 				// FIXME: may exceed boundaries
730 				r[1] = 128 + ABS( r[1] - ( *(b-1) + b[3] ) /2 );
731 		 }
732 		}
733 	 }
734 	}
735 }
736 
show_reconstruction(uint8_t * result,struct motion_est_context_s * c)737 static void show_reconstruction( uint8_t *result, struct motion_est_context_s *c )
738 {
739 	int i, j;
740 	int x,y,w,h;
741 	int dx,dy;
742 	uint8_t *r, *s;
743 	int tx,ty;
744 
745 	for( i = c->left_mb; i <= c->right_mb; i++ ){
746 	 for( j = c->top_mb; j <= c->bottom_mb; j++ ){
747 
748 		dx = CURRENT(i,j)->dx;
749 		dy = CURRENT(i,j)->dy;
750 		w = c->mb_w;
751 		h = c->mb_h;
752 		x = i * w;
753 		y = j * h;
754 
755 		// Denoise function caused some blocks to be completely clipped, ignore them
756 		if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 )
757 			continue;
758 
759 		for( ty = y; ty < y + h ; ty++ ){
760 		 for( tx = x; tx < x + w ; tx++ ){
761 
762 			r = result +          tx*c->xstride + ty*c->ystride;
763 			s = c->former_image + (tx+dx)*c->xstride + (ty+dy)*c->ystride;
764 
765 			r[0] = s[0];
766 
767 			if( dx % 2 == 0 )
768 				r[1] = s[1];
769 			else
770 				// FIXME: may exceed boundaries
771 				r[1] = ( *(s-1) + s[3] ) /2;
772 		 }
773 		}
774 	 }
775 	}
776 }
777 
778 // Image stack(able) method
filter_get_image(mlt_frame frame,uint8_t ** image,mlt_image_format * format,int * width,int * height,int writable)779 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
780 {
781 	// Get the filter
782 	mlt_filter filter = mlt_frame_pop_service( frame );
783 	mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter));
784 
785 	// Disable consumer scaling
786 	if (profile && profile->width && profile->height) {
787 		*width = profile->width;
788 		*height = profile->height;
789 	}
790 
791 	mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
792 
793 	// Get the motion_est context object
794 	struct motion_est_context_s *c = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "context", NULL);
795 
796 	// Get the new image and frame number
797 	*format = mlt_image_yuv422;
798 	int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
799 
800 	#ifdef BENCHMARK
801 	struct timeval start; gettimeofday(&start, NULL );
802 	#endif
803 
804 
805 	if( error != 0 )
806 		mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image() in motion_est", stderr );
807 
808 	c->current_frame_position = mlt_frame_get_position( frame );
809 
810 	/* Context Initialization */
811 	if ( c->initialized == 0 ) {
812 
813 		// Get the filter properties object
814 		mlt_properties properties = mlt_filter_properties( filter );
815 
816 		c->width = *width;
817 		c->height = *height;
818 
819 		/* Get parameters that may have been overridden */
820 		if( mlt_properties_get( properties, "macroblock_width") != NULL )
821 			c->mb_w = mlt_properties_get_int( properties, "macroblock_width");
822 
823 		if( mlt_properties_get( properties, "macroblock_height") != NULL )
824 			c->mb_h = mlt_properties_get_int( properties, "macroblock_height");
825 
826 		if( mlt_properties_get( properties, "prediction_thresh") != NULL )
827 			c->initial_thresh = mlt_properties_get_int( properties, "prediction_thresh" );
828 		else
829 			c->initial_thresh = c->mb_w * c->mb_h;
830 
831 		if( mlt_properties_get( properties, "search_method") != NULL )
832 			c->search_method = mlt_properties_get_int( properties, "search_method");
833 
834 		if( mlt_properties_get( properties, "skip_prediction") != NULL )
835 			c->skip_prediction = mlt_properties_get_int( properties, "skip_prediction");
836 
837 		if( mlt_properties_get( properties, "limit_x") != NULL )
838 			c->limit_x = mlt_properties_get_int( properties, "limit_x");
839 
840 		if( mlt_properties_get( properties, "limit_y") != NULL )
841 			c->limit_y = mlt_properties_get_int( properties, "limit_y");
842 
843 		if( mlt_properties_get( properties, "check_chroma" ) != NULL )
844 			c->check_chroma = mlt_properties_get_int( properties, "check_chroma" );
845 
846 		if( mlt_properties_get( properties, "denoise" ) != NULL )
847 			c->denoise = mlt_properties_get_int( properties, "denoise" );
848 
849 		if( mlt_properties_get( properties, "show_reconstruction" ) != NULL )
850 			c->show_reconstruction = mlt_properties_get_int( properties, "show_reconstruction" );
851 
852 		if( mlt_properties_get( properties, "show_residual" ) != NULL )
853 			c->show_residual = mlt_properties_get_int( properties, "show_residual" );
854 
855 		if( mlt_properties_get( properties, "toggle_when_paused" ) != NULL )
856 			c->toggle_when_paused = mlt_properties_get_int( properties, "toggle_when_paused" );
857 
858 		init_optimizations( c );
859 
860 		// Calculate the dimensions in macroblock units
861 		c->mv_buffer_width = (*width / c->mb_w);
862 		c->mv_buffer_height = (*height / c->mb_h);
863 
864 		// Size of the motion vector buffer
865 		c->mv_size =  c->mv_buffer_width * c->mv_buffer_height * sizeof(struct motion_vector_s);
866 
867 		// Allocate the motion vector buffers
868 		c->former_vectors = mlt_pool_alloc( c->mv_size );
869 		c->current_vectors = mlt_pool_alloc( c->mv_size );
870 		c->denoise_vectors = mlt_pool_alloc( c->mv_size );
871 
872 		// Register motion buffers for destruction
873 		mlt_properties_set_data( properties, "current_motion_vectors", (void *)c->current_vectors, 0, mlt_pool_release, NULL );
874 		mlt_properties_set_data( properties, "former_motion_vectors", (void *)c->former_vectors, 0, mlt_pool_release, NULL );
875 		mlt_properties_set_data( properties, "denoise_motion_vectors", (void *)c->denoise_vectors, 0, mlt_pool_release, NULL );
876 
877 		c->former_vectors_valid = 0;
878 		memset( c->former_vectors, 0, c->mv_size );
879 
880 		c->xstride = 2;
881 		c->ystride = c->xstride * *width;
882 
883 		// Allocate a cache for the previous frame's image
884 		c->former_image = mlt_pool_alloc( *width * *height * 2 );
885 		c->cache_image = mlt_pool_alloc( *width * *height * 2 );
886 
887 		// Register for destruction
888 		mlt_properties_set_data( properties, "cache_image", (void *)c->cache_image, 0, mlt_pool_release, NULL );
889 		mlt_properties_set_data( properties, "former_image", (void *)c->former_image, 0, mlt_pool_release, NULL );
890 
891 		c->former_frame_position = c->current_frame_position;
892 		c->previous_msad = 0;
893 
894 		c->initialized = 1;
895 	}
896 
897 	/* Check to see if somebody else has given us bounds */
898 	struct mlt_geometry_item_s *bounds = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "bounds", NULL );
899 
900 	if ( !bounds )
901 	{
902 		char *property = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "bounding" );
903 		if ( property )
904 		{
905 			mlt_geometry geometry = mlt_geometry_init( );
906 			mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) );
907 			if ( geometry )
908 			{
909 				mlt_geometry_parse( geometry, property, 0, profile->width, profile->height );
910 				bounds = calloc( 1, sizeof(*bounds) );
911 				mlt_properties_set_data( MLT_FILTER_PROPERTIES(filter), "bounds", bounds, sizeof(*bounds), free, NULL );
912 				mlt_geometry_fetch( geometry, bounds, 0 );
913 				mlt_geometry_close( geometry );
914 			}
915 		}
916 	}
917 
918 	if( bounds != NULL ) {
919 		// translate pixel units (from bounds) to macroblock units
920 		// make sure whole macroblock stays within bounds
921 		c->left_mb = ( bounds->x + c->mb_w - 1 ) / c->mb_w;
922 		c->top_mb = ( bounds->y + c->mb_h - 1 ) / c->mb_h;
923 		c->right_mb = ( bounds->x + bounds->w ) / c->mb_w - 1;
924 		c->bottom_mb = ( bounds->y + bounds->h ) / c->mb_h - 1;
925 		c->bounds.x = bounds->x;
926 		c->bounds.y = bounds->y;
927 		c->bounds.w = bounds->w;
928 		c->bounds.h = bounds->h;
929 	} else {
930 		c->left_mb = c->prev_left_mb = 0;
931 		c->top_mb = c->prev_top_mb = 0;
932 		c->right_mb = c->prev_right_mb = c->mv_buffer_width - 1;	// Zero indexed
933 		c->bottom_mb = c->prev_bottom_mb = c->mv_buffer_height - 1;
934 		c->bounds.x = 0;
935 		c->bounds.y = 0;
936 		c->bounds.w = *width;
937 		c->bounds.h = *height;
938 	}
939 
940 	// If video is advancing, run motion vector algorithm and etc...
941 	if( c->former_frame_position + 1 == c->current_frame_position )
942 	{
943 
944 		// Swap the motion vector buffers and reuse allocated memory
945 		struct motion_vector_s *temp = c->current_vectors;
946 		c->current_vectors = c->former_vectors;
947 		c->former_vectors = temp;
948 
949 		// This is done because filter_vismv doesn't pay attention to frame boundry
950 		memset( c->current_vectors, 0, c->mv_size );
951 
952 		// Perform the motion search
953 		motion_search( c->cache_image, *image, c );
954 
955 		collect_post_statistics( c );
956 
957 
958 		// Detect shot changes
959 		if( c->comparison_average > 10 * c->mb_w * c->mb_h &&
960 		    c->comparison_average > c->previous_msad * 2 )
961 		{
962 			mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
963 			mlt_log_verbose( MLT_FILTER_SERVICE(filter), "shot change: %d\n", c->comparison_average);
964 			mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", 1);
965 			c->shot_change = 1;
966 
967 			// Add the shot change to the list
968 			mlt_geometry key_frames = mlt_properties_get_data( properties, "shot_change_list", NULL );
969 			if ( !key_frames )
970 			{
971 				key_frames = mlt_geometry_init();
972 				mlt_properties_set_data( properties, "shot_change_list", key_frames, 0,
973 					(mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise );
974 				if ( key_frames )
975 					mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) );
976 			}
977 			if ( key_frames )
978 			{
979 				struct mlt_geometry_item_s item;
980 				item.frame = (int) c->current_frame_position;
981 				item.x = c->comparison_average;
982 				item.f[0] = 1;
983 				item.f[1] = item.f[2] = item.f[3] = item.f[4] = 0;
984 				mlt_geometry_insert( key_frames, &item );
985 			}
986 		}
987 		else {
988 			c->former_vectors_valid = 1;
989 			c->shot_change = 0;
990 			//fprintf(stderr, " - SAD: %d\n", c->comparison_average);
991 		}
992 
993 		c->previous_msad = c->comparison_average;
994 
995 		if( c->comparison_average != 0 ) { // If the frame is not a duplicate of the previous frame
996 
997 			// denoise the vector buffer
998 			if( c->denoise )
999 				median_denoise( c->current_vectors, c );
1000 
1001 			// Pass the new vector data into the frame
1002 			mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
1003 					 (void*)c->current_vectors, c->mv_size, NULL, NULL );
1004 
1005 			// Cache the frame's image. Save the old cache. Reuse memory.
1006 			// After this block, exactly two unique frames will be cached
1007 			uint8_t *timg = c->cache_image;
1008 			c->cache_image = c->former_image;
1009 			c->former_image = timg;
1010 			memcpy( c->cache_image, *image, *width * *height * c->xstride );
1011 
1012 
1013 		}
1014 		else {
1015 			// Undo the Swap, This fixes the ugliness caused by a duplicate frame
1016 			temp = c->current_vectors;
1017 			c->current_vectors = c->former_vectors;
1018 			c->former_vectors = temp;
1019 			mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
1020 					 (void*)c->former_vectors, c->mv_size, NULL, NULL );
1021 		}
1022 
1023 
1024 		if( c->shot_change == 1)
1025 			;
1026 		else if( c->show_reconstruction )
1027 			show_reconstruction( *image, c );
1028 		else if( c->show_residual )
1029 			show_residual( *image, c );
1030 
1031 	}
1032 	// paused
1033 	else if( c->former_frame_position == c->current_frame_position )
1034 	{
1035 		// Pass the old vector data into the frame if it's valid
1036 		if( c->former_vectors_valid == 1 ) {
1037 			mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
1038 					 (void*)c->current_vectors, c->mv_size, NULL, NULL );
1039 
1040 			if( c->shot_change == 1)
1041 				;
1042 			else if( c->toggle_when_paused == 1 ) {
1043 				if( c->show_reconstruction )
1044 					show_reconstruction( *image, c );
1045 				else if( c->show_residual )
1046 					show_residual( *image, c );
1047 				c->toggle_when_paused = 2;
1048 			}
1049 			else if( c->toggle_when_paused == 2 )
1050 				c->toggle_when_paused = 1;
1051 			else {
1052 				if( c->show_reconstruction )
1053 					show_reconstruction( *image, c );
1054 				else if( c->show_residual )
1055 					show_residual( *image, c );
1056 			}
1057 
1058 		}
1059 
1060 		mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", c->shot_change);
1061 	}
1062 	// there was jump in frame number
1063 	else {
1064 //		fprintf(stderr, "Warning: there was a frame number jumped from %d to %d.\n", c->former_frame_position, c->current_frame_position);
1065 		c->former_vectors_valid = 0;
1066 	}
1067 
1068 
1069 	// Cache our bounding geometry for the next frame's processing
1070 	c->prev_left_mb = c->left_mb;
1071 	c->prev_top_mb = c->top_mb;
1072 	c->prev_right_mb = c->right_mb;
1073 	c->prev_bottom_mb = c->bottom_mb;
1074 
1075 	// Remember which frame this is
1076 	c->former_frame_position = c->current_frame_position;
1077 
1078 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_width", c->mb_w );
1079 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_height", c->mb_h );
1080 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.left_mb", c->left_mb );
1081 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.right_mb", c->right_mb );
1082 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.top_mb", c->top_mb );
1083 	mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.bottom_mb", c->bottom_mb );
1084 
1085 	#ifdef BENCHMARK
1086 	struct timeval finish; gettimeofday(&finish, NULL ); int difference = (finish.tv_sec - start.tv_sec) * 1000000 + (finish.tv_usec - start.tv_usec);
1087 	fprintf(stderr, " in frame %d:%d usec\n", c->current_frame_position, difference);
1088 	#endif
1089 
1090 	mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
1091 
1092 	return error;
1093 }
1094 
1095 
1096 
1097 /** filter processing.
1098 */
1099 
filter_process(mlt_filter this,mlt_frame frame)1100 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
1101 {
1102 
1103 	// Keeps tabs on the filter object
1104 	mlt_frame_push_service( frame, this);
1105 
1106 	// Push the frame filter
1107 	mlt_frame_push_get_image( frame, filter_get_image );
1108 
1109 	return frame;
1110 }
1111 
1112 /** Constructor for the filter.
1113 */
filter_motion_est_init(mlt_profile profile,mlt_service_type type,const char * id,char * arg)1114 mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
1115 {
1116 	mlt_filter this = mlt_filter_new( );
1117 	if ( this != NULL )
1118 	{
1119 		// Get the properties object
1120 		mlt_properties properties = MLT_FILTER_PROPERTIES( this );
1121 
1122 		// Initialize the motion estimation context
1123 		struct motion_est_context_s *context;
1124 		context = mlt_pool_alloc( sizeof(struct motion_est_context_s) );
1125 		mlt_properties_set_data( properties, "context", (void *)context, sizeof( struct motion_est_context_s ),
1126 					mlt_pool_release, NULL );
1127 
1128 
1129 		// Register the filter
1130 		this->process = filter_process;
1131 
1132 		/* defaults that may be overridden */
1133 		context->mb_w = 16;
1134 		context->mb_h = 16;
1135 		context->skip_prediction = 0;
1136 		context->limit_x = 64;
1137 		context->limit_y = 64;
1138 		context->search_method = DIAMOND_SEARCH;	// FIXME: not used
1139 		context->check_chroma = 0;
1140 		context->denoise = 1;
1141 		context->show_reconstruction = 0;
1142 		context->show_residual = 0;
1143 		context->toggle_when_paused = 0;
1144 
1145 		/* reference functions that may have optimized versions */
1146 		context->compare_reference = sad_reference;
1147 
1148 		// The rest of the buffers will be initialized when the filter is first processed
1149 		context->initialized = 0;
1150 	}
1151 	return this;
1152 }
1153