2 * /brief fast motion estimation filter
3 * /author Zachary Drew, Copyright 2005
5 * Currently only uses Gamma data for comparisonon (bug or feature?)
6 * Vector optimization coming soon.
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. Thus, to know how a macroblock
10 * in the current frame will move in the future, the next frame is needed.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include "filter_motion_est.h"
29 #include <framework/mlt.h>
45 #define DIAMOND_SEARCH 0x0
46 #define FULL_SEARCH 0x1
48 #define MIN(a,b) ((a) > (b) ? (b) : (a))
49 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
55 typedef struct motion_vector_s motion_vector;
65 struct motion_est_context_s
67 int initialized; //<! true if filter has been initialized
69 /* same as mlt_frame's parameters */
72 /* Operational details */
73 int macroblock_width, macroblock_height;
75 //uint8_t *former_image; //<! Copy of the previous frame's image
76 struct yuv_data former_image, current_image;
77 int search_method, skip_prediction, shot_change;
78 int limit_x, limit_y; //<! max x and y of a motion vector
79 int edge_blocks_x, edge_blocks_y;
81 int check_chroma; // if check_chroma == 1 then compare chroma
86 struct mlt_geometry_item_s prev_bounds; // Cache last frame's bounds (needed for predictor vectors validity)
87 struct mlt_geometry_item_s *bounds; // Current bounds
89 /* bounds in macroblock units */
90 int left_mb, prev_left_mb, right_mb, prev_right_mb;
91 int top_mb, prev_top_mb, bottom_mb, prev_bottom_mb;
93 /* size of our vector buffers */
94 int mv_buffer_height, mv_buffer_width, mv_size;
97 int former_vectors_valid; //<! true if the previous frame's buffered motion vector data is valid
98 motion_vector *former_vectors, *current_vectors;
99 motion_vector *denoise_vectors;
100 mlt_position former_frame_position, current_frame_position;
102 /* two metrics for diagnostics. lower is a better estimation but beware of local minima */
103 float predictive_misses; // How often do the prediction metion vectors fail?
104 int comparison_average; // How far does the best estimation deviate from a perfect comparison?
107 int average_x, average_y;
109 /* run-time configurable comparison functions */
110 int (*compare_reference)(uint8_t *, uint8_t *, int, int, int, int);
111 int (*compare_optimized)(uint8_t *, uint8_t *, int, int, int, int);
116 // Clip the macroblocks as required. Only used for blocks at the edge of the picture
117 // "from" is assumed to be unclipped
118 inline static int clip( int *from_x,
122 int *w, //<! macroblock width
123 int *h, //<! macroblock height
124 int width, //<! image width
125 int height) //<! image height
128 uint32_t penalty = 1 << SHIFT; // Retain a few extra bits of precision minus floating-point's blemishes
131 // Origin of macroblock moves left of absolute boundy
133 if( *to_x + *w <= 0) return 0; // Clipped out of existance
134 penalty = (*w * penalty) / (*w + *to_x); // Recipricol of the fraction of the block that remains
139 // Portion of macroblock moves right of absolute boundry
140 else if( *to_x + *w > width ) {
141 if(*to_x >= width) return 0; // Clipped out of existance
142 diff = *to_x + *w - width; // Width of area clipped (0 < diff < macroblock width)
143 penalty = (*w * penalty) / (*w - diff); // Recipricol of the fraction of the block that remains
146 // Origin of macroblock moves above absolute boundy
148 if( *to_y + *h <= 0) return 0; // Clipped out of existance
149 penalty = (*h * penalty) / (*h + *to_y); // Recipricol of the fraction of the block that remains
154 // Portion of macroblock moves bellow absolute boundry
155 else if( *to_y + *h > height ) {
156 if(*to_y >= height) return 0; // Clipped out of existance
157 diff = *to_y + *h - height; // Height of area clipped (0 < diff < macroblock height)
158 penalty = (*h * penalty) / (*h - diff); // Recipricol of the fraction of the block that is clipped
165 /** /brief Reference Sum of Absolute Differences comparison function
168 inline static int sad_reference( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h )
171 for ( j = 0; j < h; j++ ){
172 for ( i = 0; i < w; i++ ){
173 score += ABS( block1[i*xstride] - block2[i*xstride] );
182 inline static void change_422_to_444_planar_rep( uint8_t *image, struct yuv_data yuv, struct motion_est_context_s *c )
184 register uint8_t *p = image;
185 register uint8_t *q = image + c->width * c->height * 2;
187 *(yuv.y++) = *(p ++);
189 *(yuv.u++) = *(p ++);
190 *(yuv.y++) = *(p ++);
192 *(yuv.v++) = *(p ++);
197 inline static void change_420p_to_444_planar_rep( uint8_t *image, struct yuv_data yuv, struct motion_est_context_s *c )
199 uint8_t *p = image + c->width * c->height;
200 uint8_t *q = p + c->width*c->height/2;
203 u2 = yuv.u + c->width;
210 *q += c->width*c->height/2;
212 v2 = yuv.v + c->width;
221 /** /brief Abstracted block comparison function
223 inline static int compare( uint8_t *from,
229 struct motion_est_context_s *c)
231 #ifdef COUNT_COMPARES
235 if( ABS(from_x - to_x) >= c->limit_x || ABS(from_y - to_y) >= c->limit_y )
239 int (*cmp)(uint8_t *, uint8_t *, int, int, int, int) = c->compare_optimized;
241 int mb_w = c->macroblock_width;
242 int mb_h = c->macroblock_height;
244 int penalty = clip(&from_x, &from_y, &to_x, &to_y, &mb_w, &mb_h, c->width, c->height);
245 if ( penalty == 1<<SHIFT)
246 penalty = clip(&to_x, &to_y, &from_x, &from_y, &mb_w, &mb_h, c->width, c->height);
248 if( penalty == 0 ) // Clipped out of existance
250 else if( penalty != 1<<SHIFT ) // SIMD optimized comparison won't work
251 cmp = c->compare_reference;
253 uint8_t *from_block = from + from_x * c->xstride + from_y * c->ystride;
254 uint8_t *to_block = to + to_x * c->xstride + to_y * c->ystride;
257 if( penalty == 1<<SHIFT ){
258 score = c->compare_reference( from_block, to_block, c->xstride, c->ystride, mb_w, mb_h );
259 int score2 = c->compare_optimized( from_block, to_block, c->xstride, c->ystride, mb_w, mb_h );
260 if ( score != score2 )
261 fprintf(stderr, "Your assembly doesn't work! Reference: %d Asm: %d\n", score, score2);
266 score = cmp( from_block, to_block, c->xstride, c->ystride, mb_w, mb_h );
268 return ( score * penalty ) >> SHIFT; // The extra precision is no longer wanted
271 static inline void check_candidates ( struct yuv_data *from, struct yuv_data *to,
272 int from_x, int from_y,
273 motion_vector *candidates, int count, int unique,
274 motion_vector *result,
275 struct motion_est_context_s *c )
278 /* Scan for the best candidate */
279 for ( i = 0; i < count; i++ )
281 // this little dohicky ignores duplicate candidates, if they are possible
286 if ( candidates[j].dx == candidates[i].dx &&
287 candidates[j].dy == candidates[i].dy )
295 score = compare( from->y, to->y, from_x, from_y,
296 from_x + candidates[i].dx, /* to x */
297 from_y + candidates[i].dy, /* to y */
300 if ( c->check_chroma ) {
301 if ( score >= result->msad ) // Early term
305 score += compare( from->u, to->u, from_x, from_y,
306 from_x + candidates[i].dx, /* to x */
307 from_y + candidates[i].dy, /* to y */
310 if ( score >= result->msad ) // Early term
314 score += compare( from->v, to->v, from_x, from_y,
315 from_x + candidates[i].dx, /* to x */
316 from_y + candidates[i].dy, /* to y */
320 if ( score < result->msad ) { // New minimum
321 result->dx = candidates[i].dx;
322 result->dy = candidates[i].dy;
323 result->msad = score;
329 /* /brief Diamond search
330 * Operates on a single macroblock
332 static inline void diamond_search(
333 struct yuv_data *from, //<! Image data from previous frame
334 struct yuv_data *to, //<! Image data in current frame
335 int mb_x, //<! X upper left corner of macroblock
336 int mb_y, //<! U upper left corner of macroblock
337 struct motion_vector_s *result, //<! Best predicted mv and eventual result
338 struct motion_est_context_s *c) //<! motion estimation context
341 // diamond search pattern
342 motion_vector candidates[4];
344 // Keep track of best and former best candidates
345 motion_vector best, former;
347 // The direction of the refinement needs to be known
348 motion_vector current;
352 // Loop through the search pattern
355 current.dx = result->dx;
356 current.dy = result->dy;
358 if ( first == 1 ) // Set the initial pattern
360 candidates[0].dx = result->dx + 1; candidates[0].dy = result->dy + 0;
361 candidates[1].dx = result->dx + 0; candidates[1].dy = result->dy + 1;
362 candidates[2].dx = result->dx - 1; candidates[2].dy = result->dy + 0;
363 candidates[3].dx = result->dx + 0; candidates[3].dy = result->dy - 1;
366 else // Construct the next portion of the search pattern
368 candidates[0].dx = result->dx + best.dx;
369 candidates[0].dy = result->dy + best.dy;
370 if (best.dx == former.dx && best.dy == former.dy) {
371 candidates[1].dx = result->dx + best.dy;
372 candidates[1].dy = result->dy + best.dx; // Yes, the wires
373 candidates[2].dx = result->dx - best.dy; // are crossed
374 candidates[2].dy = result->dy - best.dx;
377 candidates[1].dx = result->dx + former.dx;
378 candidates[1].dy = result->dy + former.dy;
382 former.dx = best.dx; former.dy = best.dy; // Keep track of new former best
385 check_candidates ( from, to, mb_x, mb_y, candidates, i, 1, result, c );
386 best.dx = result->dx - current.dx;
387 best.dy = result->dy - current.dy;
389 if ( best.dx == 0 && best.dy == 0 )
394 former.dx = best.dx; former.dy = best.dy; // First iteration, sensible value for former_d*
399 /* /brief Full (brute) search
400 * Operates on a single macroblock
402 static void full_search(
403 struct yuv_data *from, //<! Image data from previous frame
404 struct yuv_data *to, //<! Image data in current frame
405 int mb_x, //<! X upper left corner of macroblock
406 int mb_y, //<! U upper left corner of macroblock
407 struct motion_vector_s *result, //<! Best predicted mv and eventual result
408 struct motion_est_context_s *c) //<! motion estimation context
410 // Keep track of best candidate
414 for( i = -c->macroblock_width; i <= c->macroblock_width; i++ ){
415 for( j = -c->macroblock_height; j <= c->macroblock_height; j++ ){
417 score = compare( from->y, to->y,
424 if ( score < result->msad ) {
427 result->msad = score;
435 static inline int median_predictor(int a, int b, int c) {
450 // Macros for pointer calculations
451 #define CURRENT(i,j) ( c->current_vectors + (j)*c->mv_buffer_width + (i) )
452 #define FORMER(i,j) ( c->former_vectors + (j)*c->mv_buffer_width + (i) )
453 #define DENOISE(i,j) ( c->denoise_vectors + (j)*c->mv_buffer_width + (i) )
455 int ncompare (const void * a, const void * b)
457 return ( *(int*)a - *(int*)b );
460 // motion vector denoising
461 // for x and y components seperately,
462 // change the vector to be the median value of the 9 adjacent vectors
463 static void median_denoise( motion_vector *v, struct motion_est_context_s *c )
465 int xvalues[9], yvalues[9];
468 for( i = c->left_mb; i <= c->right_mb; i++ ){
469 for( j = c->top_mb; j <= c->bottom_mb; j++ )
473 xvalues[n ] = CURRENT(i,j)->dx; // Center
474 yvalues[n++] = CURRENT(i,j)->dy;
476 if( i > c->left_mb ) // Not in First Column
478 xvalues[n ] = CURRENT(i-1,j)->dx; // Left
479 yvalues[n++] = CURRENT(i-1,j)->dy;
481 if( j > c->top_mb ) {
482 xvalues[n ] = CURRENT(i-1,j-1)->dx; // Upper Left
483 yvalues[n++] = CURRENT(i-1,j-1)->dy;
486 if( j < c->bottom_mb ) {
487 xvalues[n ] = CURRENT(i-1,j+1)->dx; // Bottom Left
488 yvalues[n++] = CURRENT(i-1,j+1)->dy;
491 if( i < c->right_mb ) // Not in Last Column
493 xvalues[n ] = CURRENT(i+1,j)->dx; // Right
494 yvalues[n++] = CURRENT(i+1,j)->dy;
497 if( j > c->top_mb ) {
498 xvalues[n ] = CURRENT(i+1,j-1)->dx; // Upper Right
499 yvalues[n++] = CURRENT(i+1,j-1)->dy;
502 if( j < c->bottom_mb ) {
503 xvalues[n ] = CURRENT(i+1,j+1)->dx; // Bottom Right
504 yvalues[n++] = CURRENT(i+1,j+1)->dy;
507 if( j > c->top_mb ) // Not in First Row
509 xvalues[n ] = CURRENT(i,j-1)->dx; // Top
510 yvalues[n++] = CURRENT(i,j-1)->dy;
513 if( j < c->bottom_mb ) // Not in Last Row
515 xvalues[n ] = CURRENT(i,j+1)->dx; // Bottom
516 yvalues[n++] = CURRENT(i,j+1)->dy;
519 qsort (xvalues, n, sizeof(int), ncompare);
520 qsort (yvalues, n, sizeof(int), ncompare);
523 DENOISE(i,j)->dx = xvalues[n/2];
524 DENOISE(i,j)->dy = yvalues[n/2];
527 DENOISE(i,j)->dx = (xvalues[n/2] + xvalues[n/2+1])/2;
528 DENOISE(i,j)->dy = (yvalues[n/2] + yvalues[n/2+1])/2;
533 motion_vector *t = c->current_vectors;
534 c->current_vectors = c->denoise_vectors;
535 c->denoise_vectors = t;
539 /** /brief Motion search
542 * Search for the Vector that best represents the motion *from the last frame *to the current frame
543 * Vocab: Colocated - the pixel in the previous frame at the current position
545 * Based on enhanced predictive zonal search. [Tourapis 2002]
547 static void search( struct yuv_data from, //<! Image data. Motion vector source in previous frame
548 struct yuv_data to, //<! Image data. Motion vector destination current
549 struct motion_est_context_s *c) //<! The context
552 #ifdef COUNT_COMPARES
556 motion_vector candidates[10];
557 motion_vector *here; // This one gets used alot (about 30 times per macroblock)
562 // For every macroblock, perform motion vector estimation
563 for( i = c->left_mb; i <= c->right_mb; i++ ){
564 for( j = c->top_mb; j <= c->bottom_mb; j++ ){
569 here->msad = MAX_MSAD;
574 /* Stack the predictors [i.e. checked in reverse order] */
576 /* Adjacent to collocated */
577 if( c->former_vectors_valid )
580 if( j > c->prev_top_mb ){// && COL_TOP->valid ){
581 candidates[n ].dx = FORMER(i,j-1)->dx;
582 candidates[n++].dy = FORMER(i,j-1)->dy;
586 if( i > c->prev_left_mb ){// && COL_LEFT->valid ){
587 candidates[n ].dx = FORMER(i-1,j)->dx;
588 candidates[n++].dy = FORMER(i-1,j)->dy;
591 // Right of colocated
592 if( i < c->prev_right_mb ){// && COL_RIGHT->valid ){
593 candidates[n ].dx = FORMER(i+1,j)->dx;
594 candidates[n++].dy = FORMER(i+1,j)->dy;
597 // Bottom of colocated
598 if( j < c->prev_bottom_mb ){// && COL_BOTTOM->valid ){
599 candidates[n ].dx = FORMER(i,j+1)->dx;
600 candidates[n++].dy = FORMER(i,j+1)->dy;
603 // And finally, colocated
604 candidates[n ].dx = FORMER(i,j)->dx;
605 candidates[n++].dy = FORMER(i,j)->dy;
608 // For macroblocks not in the top row
609 if ( j > c->top_mb) {
611 // Top if ( TOP->valid ) {
612 candidates[n ].dx = CURRENT(i,j-1)->dx;
613 candidates[n++].dy = CURRENT(i,j-1)->dy;
616 // Top-Right, macroblocks not in the right row
617 if ( i < c->right_mb ){// && TOP_RIGHT->valid ) {
618 candidates[n ].dx = CURRENT(i+1,j-1)->dx;
619 candidates[n++].dy = CURRENT(i+1,j-1)->dy;
623 // Left, Macroblocks not in the left column
624 if ( i > c->left_mb ){// && LEFT->valid ) {
625 candidates[n ].dx = CURRENT(i-1,j)->dx;
626 candidates[n++].dy = CURRENT(i-1,j)->dy;
629 /* Median predictor vector (median of left, top, and top right adjacent vectors) */
630 if ( i > c->left_mb && j > c->top_mb && i < c->right_mb
631 )//&& LEFT->valid && TOP->valid && TOP_RIGHT->valid )
633 candidates[n ].dx = median_predictor( CURRENT(i-1,j)->dx, CURRENT(i,j-1)->dx, CURRENT(i+1,j-1)->dx);
634 candidates[n++].dy = median_predictor( CURRENT(i-1,j)->dy, CURRENT(i,j-1)->dy, CURRENT(i+1,j-1)->dy);
638 candidates[n ].dx = 0;
639 candidates[n++].dy = 0;
641 int from_x = i * c->macroblock_width;
642 int from_y = j * c->macroblock_height;
643 check_candidates ( &from, &to, from_x, from_y, candidates, n, 0, here, c );
647 diamond_search( &from, &to, from_x, from_y, here, c);
649 full_search( from, to, from_x, from_y, here, c);
652 } /* End column loop */
655 asm volatile ( "emms" );
657 #ifdef COUNT_COMPARES
658 fprintf(stderr, "%d comparisons per block were made", compares/count);
663 void collect_post_statistics( struct motion_est_context_s *c ) {
665 c->comparison_average = 0;
666 c->average_length = 0;
672 for ( i = c->left_mb; i <= c->right_mb; i++ ){
673 for ( j = c->top_mb; j <= c->bottom_mb; j++ ){
676 c->comparison_average += CURRENT(i,j)->msad;
677 c->average_x += CURRENT(i,j)->dx;
678 c->average_y += CURRENT(i,j)->dy;
686 c->comparison_average /= count;
687 c->average_x /= count;
688 c->average_y /= count;
689 c->average_length = sqrt( c->average_x * c->average_x + c->average_y * c->average_y );
694 static void init_optimizations( struct motion_est_context_s *c )
696 if ( c->check_chroma ) {
697 switch(c->macroblock_width){
698 case 8: if(c->macroblock_height == 8) c->compare_optimized = sad_sse_8x8;
699 else c->compare_optimized = sad_sse_8w;
701 case 16: if(c->macroblock_height == 16) c->compare_optimized = sad_sse_16x16;
702 else c->compare_optimized = sad_sse_16w;
704 case 32: if(c->macroblock_height == 32) c->compare_optimized = sad_sse_32x32;
705 else c->compare_optimized = sad_sse_32w;
707 case 64: c->compare_optimized = sad_sse_64w;
709 default: c->compare_optimized = sad_reference;
715 switch(c->macroblock_width){
716 case 4: if(c->macroblock_height == 4) c->compare_optimized = sad_sse_422_luma_4x4;
717 else c->compare_optimized = sad_sse_422_luma_4w;
719 case 8: if(c->macroblock_height == 8) c->compare_optimized = sad_sse_422_luma_8x8;
720 else c->compare_optimized = sad_sse_422_luma_8w;
722 case 16: if(c->macroblock_height == 16) c->compare_optimized = sad_sse_422_luma_16x16;
723 else c->compare_optimized = sad_sse_422_luma_16w;
725 case 32: if(c->macroblock_height == 32) c->compare_optimized = sad_sse_422_luma_32x32;
726 else c->compare_optimized = sad_sse_422_luma_32w;
728 case 64: c->compare_optimized = sad_sse_422_luma_64w;
730 default: c->compare_optimized = sad_reference;
736 // Image stack(able) method
737 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
740 mlt_filter filter = mlt_frame_pop_service( frame );
742 // Get the motion_est context object
743 struct motion_est_context_s *c = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "context", NULL);
746 struct timeval start; gettimeofday(&start, NULL );
749 // Get the new image and frame number
750 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
753 struct timeval finish; gettimeofday(&finish, NULL ); int difference = (finish.tv_sec - start.tv_sec) * 1000000 + (finish.tv_usec - start.tv_usec);
754 fprintf(stderr, " in frame %d:%d usec\n", c->current_frame_position, difference);
758 mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image() in motion_est", stderr );
760 c->current_frame_position = mlt_frame_get_position( frame );
762 /* Context Initialization */
763 if ( c->initialized == 0 ) {
765 // Get the filter properties object
766 mlt_properties properties = mlt_filter_properties( filter );
771 /* Get parameters that may have been overridden */
772 if( mlt_properties_get( properties, "macroblock_width") != NULL )
773 c->macroblock_width = mlt_properties_get_int( properties, "macroblock_width");
775 if( mlt_properties_get( properties, "macroblock_height") != NULL )
776 c->macroblock_height = mlt_properties_get_int( properties, "macroblock_height");
778 if( mlt_properties_get( properties, "prediction_thresh") != NULL )
779 c->initial_thresh = mlt_properties_get_int( properties, "prediction_thresh" );
781 c->initial_thresh = c->macroblock_width * c->macroblock_height;
783 if( mlt_properties_get( properties, "search_method") != NULL )
784 c->search_method = mlt_properties_get_int( properties, "search_method");
786 if( mlt_properties_get( properties, "skip_prediction") != NULL )
787 c->skip_prediction = mlt_properties_get_int( properties, "skip_prediction");
789 if( mlt_properties_get( properties, "limit_x") != NULL )
790 c->limit_x = mlt_properties_get_int( properties, "limit_x");
792 if( mlt_properties_get( properties, "limit_y") != NULL )
793 c->limit_y = mlt_properties_get_int( properties, "limit_y");
795 if( mlt_properties_get( properties, "check_chroma" ) != NULL )
796 c->check_chroma = mlt_properties_get_int( properties, "check_chroma" );
798 if( mlt_properties_get( properties, "denoise" ) != NULL )
799 c->denoise = mlt_properties_get_int( properties, "denoise" );
801 init_optimizations( c );
803 // Calculate the dimensions in macroblock units
804 c->mv_buffer_width = (*width / c->macroblock_width);
805 c->mv_buffer_height = (*height / c->macroblock_height);
807 // Size of the motion vector buffer
808 c->mv_size = c->mv_buffer_width * c->mv_buffer_height * sizeof(struct motion_vector_s);
810 // Allocate the motion vector buffers
811 c->former_vectors = mlt_pool_alloc( c->mv_size );
812 c->current_vectors = mlt_pool_alloc( c->mv_size );
813 c->denoise_vectors = mlt_pool_alloc( c->mv_size );
815 // Register motion buffers for destruction
816 mlt_properties_set_data( properties, "current_motion_vectors", (void *)c->current_vectors, 0, mlt_pool_release, NULL );
817 mlt_properties_set_data( properties, "former_motion_vectors", (void *)c->former_vectors, 0, mlt_pool_release, NULL );
818 mlt_properties_set_data( properties, "denoise_motion_vectors", (void *)c->denoise_vectors, 0, mlt_pool_release, NULL );
821 c->former_vectors_valid = 0;
822 memset( c->former_vectors, 0, c->mv_size );
824 // Figure out how many blocks should be considered edge blocks
825 c->edge_blocks_x = (c->limit_x + c->macroblock_width - 1) / c->macroblock_width;
826 c->edge_blocks_y = (c->limit_y + c->macroblock_height - 1) / c->macroblock_height;
828 // Calculate the size of our steps (the number of bytes that seperate adjacent pixels in X and Y direction)
830 case mlt_image_yuv422:
831 if ( c->check_chroma )
835 c->ystride = c->xstride * *width;
837 /* case mlt_image_yuv420p:
839 c->ystride = c->xstride * *width;
843 fprintf(stderr, "\"I am unfamiliar with your new fangled pixel format!\" -filter_motion_est\n");
847 if ( c->check_chroma ) {
848 // Allocate memory for the 444 images
849 c->former_image.y = mlt_pool_alloc( *width * *height * 3 );
850 c->current_image.y = mlt_pool_alloc( *width * *height * 3 );
851 c->current_image.u = c->current_image.y + *width * *height;
852 c->current_image.v = c->current_image.u + *width * *height;
853 c->former_image.u = c->former_image.y + *width * *height;
854 c->former_image.v = c->former_image.u + *width * *height;
855 // Register for destruction
856 mlt_properties_set_data( properties, "current_image", (void *)c->current_image.y, 0, mlt_pool_release, NULL );
860 c->former_image.y = mlt_pool_alloc( *width * *height * 2 );
862 // Register for destruction
863 mlt_properties_set_data( properties, "former_image", (void *)c->former_image.y, 0, mlt_pool_release, NULL );
866 c->former_frame_position = c->current_frame_position;
867 c->previous_msad = 0;
872 /* Check to see if somebody else has given us bounds */
873 c->bounds = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "bounds", NULL );
875 /* no bounds were given, they won't change next frame, so use a convient storage place */
876 if( c->bounds == NULL ) {
877 c->bounds = &c->prev_bounds;
880 c->bounds->w = *width - 1; // Zero indexed
881 c->bounds->h = *height - 1; // Zero indexed
884 // translate pixel units (from bounds) to macroblock units
885 // make sure whole macroblock stays within bounds
886 c->left_mb = ( c->bounds->x + c->macroblock_width - 1 ) / c->macroblock_width;
887 c->top_mb = ( c->bounds->y + c->macroblock_height - 1 ) / c->macroblock_height;
888 c->right_mb = ( c->bounds->x + c->bounds->w ) / c->macroblock_width - 1;
889 c->bottom_mb = ( c->bounds->y + c->bounds->h ) / c->macroblock_height - 1;
891 // Do the same thing for the previous frame's geometry
892 // This will be used for determining validity of predictors
893 c->prev_left_mb = ( c->prev_bounds.x + c->macroblock_width - 1) / c->macroblock_width;
894 c->prev_top_mb = ( c->prev_bounds.y + c->macroblock_height - 1) / c->macroblock_height;
895 c->prev_right_mb = ( c->prev_bounds.x + c->prev_bounds.w ) / c->macroblock_width - 1;
896 c->prev_bottom_mb = ( c->prev_bounds.y + c->prev_bounds.h ) / c->macroblock_height - 1;
899 // If video is advancing, run motion vector algorithm and etc...
900 if( c->former_frame_position + 1 == c->current_frame_position )
903 // Swap the motion vector buffers and reuse allocated memory
904 struct motion_vector_s *temp = c->current_vectors;
905 c->current_vectors = c->former_vectors;
906 c->former_vectors = temp;
908 // Swap the image buffers
909 if ( c->check_chroma ) {
911 temp_yuv = c->current_image.y;
912 c->current_image.y = c->former_image.y;
913 c->former_image.y = temp_yuv;
914 temp_yuv = c->current_image.u;
915 c->current_image.u = c->former_image.u;
916 c->former_image.u = temp_yuv;
917 temp_yuv = c->current_image.v;
918 c->current_image.v = c->former_image.v;
919 c->former_image.v = temp_yuv;
922 case mlt_image_yuv422:
923 change_422_to_444_planar_rep( *image, c->current_image, c );
925 case mlt_image_yuv420p:
926 change_420p_to_444_planar_rep( *image, c->current_image, c );
933 c->current_image.y = *image;
935 // Find a better place for this
936 memset( c->current_vectors, 0, c->mv_size );
938 // Perform the motion search
940 //collect_pre_statistics( context, *image );
941 search( c->current_image, c->former_image, c );
943 collect_post_statistics( c );
948 // Detect shot changes
949 if( c->comparison_average > 10 * c->macroblock_width * c->macroblock_height &&
950 c->comparison_average > c->previous_msad * 2 )
952 fprintf(stderr, " - SAD: %d <<Shot change>>\n", c->comparison_average);
953 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", 1);
954 // c->former_vectors_valid = 0; // Invalidate the previous frame's predictors
958 c->former_vectors_valid = 1;
960 //fprintf(stderr, " - SAD: %d\n", c->comparison_average);
963 c->previous_msad = c->comparison_average;
965 if( c->comparison_average != 0 ) {
967 // denoise the vector buffer
969 median_denoise( c->current_vectors, c );
971 // Pass the new vector data into the frame
972 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
973 (void*)c->current_vectors, c->mv_size, NULL, NULL );
977 // This fixes the ugliness caused by a duplicate frame
978 temp = c->current_vectors;
979 c->current_vectors = c->former_vectors;
980 c->former_vectors = temp;
981 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
982 (void*)c->former_vectors, c->mv_size, NULL, NULL );
987 else if( c->former_frame_position == c->current_frame_position )
989 // Pass the old vector data into the frame if it's valid
990 if( c->former_vectors_valid == 1 )
991 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors",
992 (void*)c->current_vectors, c->mv_size, NULL, NULL );
994 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", c->shot_change);
996 // there was jump in frame number
998 c->former_vectors_valid = 0;
1001 // Cache our bounding geometry for the next frame's processing
1002 if( c->bounds != &c->prev_bounds )
1003 memcpy( &c->prev_bounds, c->bounds, sizeof( struct mlt_geometry_item_s ) );
1005 // Remember which frame this is
1006 c->former_frame_position = c->current_frame_position;
1009 if ( c->check_chroma == 0 )
1010 memcpy( c->former_image.y, *image, *width * *height * c->xstride );
1012 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_width", c->macroblock_width );
1013 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_height", c->macroblock_height );
1020 /** filter processing.
1023 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
1026 // Keeps tabs on the filter object
1027 mlt_frame_push_service( frame, this);
1029 // Push the frame filter
1030 mlt_frame_push_get_image( frame, filter_get_image );
1035 /** Constructor for the filter.
1037 mlt_filter filter_motion_est_init( char *arg )
1039 mlt_filter this = mlt_filter_new( );
1042 // Get the properties object
1043 mlt_properties properties = MLT_FILTER_PROPERTIES( this );
1045 // Initialize the motion estimation context
1046 struct motion_est_context_s *context;
1047 context = mlt_pool_alloc( sizeof(struct motion_est_context_s) );
1048 mlt_properties_set_data( properties, "context", (void *)context, sizeof( struct motion_est_context_s ),
1049 mlt_pool_release, NULL );
1052 // Register the filter
1053 this->process = filter_process;
1055 /* defaults that may be overridden */
1056 context->macroblock_width = 16;
1057 context->macroblock_height = 16;
1058 context->skip_prediction = 0;
1059 context->limit_x = 64;
1060 context->limit_y = 64;
1061 context->search_method = DIAMOND_SEARCH;
1062 context->check_chroma = 0;
1063 context->denoise = 1;
1065 /* reference functions that may have optimized versions */
1066 context->compare_reference = sad_reference;
1067 //context->vert_deviation_reference = vertical_gradient_reference;
1068 //context->horiz_deviation_reference = horizontal_gradient_reference;
1070 // The rest of the buffers will be initialized when the filter is first processed
1071 context->initialized = 0;
1076 /** This source code will self destruct in 5...4...3... */