1 /* $Id: eedi2.c,v 1.0 2009/03/06 5:00:00 jbrjake Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.fr/>.
5 It may be used under the terms of the GNU General Public License.
7 The EEDI2 interpolator was created by tritical:
8 http://web.missouri.edu/~kes25c/
15 * EEDI2 directional limit lookup table
17 * These values are used to limit the range of edge direction searches and filtering.
19 const int eedi2_limlut[33] __attribute__ ((aligned (16))) = {
20 6, 6, 7, 7, 8, 8, 9, 9, 9, 10,
21 10, 11, 11, 12, 12, 12, 12, 12, 12, 12,
22 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
26 * Analog of _aligned_malloc
27 * @param size Size of memory being pointed to
28 * @param align_size Size of memory chunks to align to (must be power of 2)
30 void *eedi2_aligned_malloc( size_t size, size_t align_size )
32 char * ptr, * ptr2, * aligned_ptr;
33 int align_mask = align_size - 1;
35 ptr = (char *)malloc( size + align_size + sizeof( int ) );
36 if( ptr==NULL ) return( NULL );
38 ptr2 = ptr + sizeof( int );
39 aligned_ptr = ptr2 + ( align_size - ( (size_t)ptr2 & align_mask ) );
42 ptr2 = aligned_ptr - sizeof( int );
43 *( (int *)ptr2 ) = (int)( aligned_ptr - ptr );
45 return( aligned_ptr );
49 * Analog of _aligned_free
50 * @param ptr The aligned pointer, created with eedi2_aligned_malloc, to be freed
52 void eedi2_aligned_free( void *ptr )
54 int * ptr2 = (int *)ptr - 1;
60 * Sorts metrics for median filtering
61 * @param order Pointer to the table of values to sort
62 * @param length Length of the order array
64 void eedi2_sort_metrics( int *order, const int length )
67 for( i = 1; i < length; ++i )
70 const int temp = order[j];
71 while( j > 0 && order[j-1] > temp )
73 order[j] = order[j-1];
81 * Bitblits an image plane (overwrites one bitmap with another)
82 * @param dtsp Pointer to destination bitmap
83 * @param dst_pitch Stride of destination bitmap
84 * @param srcp Pointer to source bitmap
85 * @param src_pitch Stride of destination bitmap
86 * @param row_size Width of the bitmap being copied
87 * @param height Height of the source bitmap
89 * When row_size, dst_pitch, and src_pitch are equal, eedi2_bit_blit can work more quickly by copying the whole plane at once instead of individual lines.
91 void eedi2_bit_blit( uint8_t * dstp, int dst_pitch,
92 const uint8_t * srcp, int src_pitch,
93 int row_size, int height )
95 if( ( !height ) || ( !row_size ) )
98 if( height == 1 || ( dst_pitch == src_pitch && src_pitch == row_size ) )
100 memcpy( dstp, srcp, row_size * height );
105 for( y = height; y > 0; --y )
107 memcpy( dstp, srcp, row_size );
115 * A specialized variant of bit_blit, just for setting up the initial, field-sized bitmap planes that EEDI2 interpolates from.
116 * @param src Pointer to source bitmap plane being copied from
117 * @param dst Pointer to the destination bitmap plane being copied to
118 * @param pitch Stride of both bitmaps
119 * @param height Height of the original, full-size src plane being copied from
121 void eedi2_fill_half_height_buffer_plane( uint8_t * src, uint8_t * dst, int pitch, int height )
123 /* When TFF, we want to copy alternating
124 lines starting at 0, the top field.
125 When BFF, we want to start at line 1. */
127 for( y = height; y > 0; y = y - 2 )
129 memcpy( dst, src, pitch );
136 * A specialized variant of bit_blit, just for resizing the field-height maps EEDI2 generates to frame-height...a simple line doubler
137 * @param srcp Pointer to source bitmap plane being copied from
138 * @param dstp Pointer to the destination bitmap plane being copied to
139 * @param height Height of the input, half-size src plane being copied from
140 * @param pitch Stride of both bitmaps
142 void eedi2_upscale_by_2( uint8_t * srcp, uint8_t * dstp, int height, int pitch )
145 for( y = height; y > 0; y-- )
147 memcpy( dstp, srcp, pitch );
149 memcpy( dstp, srcp, pitch );
156 * Finds places where verticaly adjacent pixels abruptly change in intensity, i.e., sharp edges.
157 * @param dstp Pointer to the destination bitmap
158 * @param dst_pitch Stride of dstp
159 * @param srcp Pointer to the source bitmap
160 * @param src_pitch Stride of srcp
161 * @param mtresh Magnitude threshold, ensures it doesn't mark edges on pixels that are too similar (10 is a good default value)
162 * @param vthresh Variance threshold, ensures it doesn't look for edges in highly random pixel blocks (20 is a good default value)
163 * @param lthresh Laplacian threshold, ensures edges are still prominent in the 2nd spatial derivative of the srcp plane (20 is a good default value)
164 * @param height Height of half-height single-field frame
165 * @param width Width of srcp bitmap rows, as opposed to the padded stride in src_pitch
167 void eedi2_build_edge_mask( uint8_t * dstp, int dst_pitch, uint8_t *srcp, int src_pitch,
168 int mthresh, int lthresh, int vthresh, int height, int width )
172 mthresh = mthresh * 10;
173 vthresh = vthresh * 81;
175 memset( dstp, 0, ( height / 2 ) * dst_pitch );
179 unsigned char *srcpp = srcp-src_pitch;
180 unsigned char *srcpn = srcp+src_pitch;
181 for( y = 1; y < height - 1; ++y )
183 for( x = 1; x < width-1; ++x )
185 if( ( abs( srcpp[x] - srcp[x] ) < 10 &&
186 abs( srcp[x] - srcpn[x] ) < 10 &&
187 abs( srcpp[x] - srcpn[x] ) < 10 )
189 ( abs( srcpp[x-1] - srcp[x-1] ) < 10 &&
190 abs( srcp[x-1] - srcpn[x-1] ) < 10 &&
191 abs( srcpp[x-1] - srcpn[x-1] ) < 10 &&
192 abs( srcpp[x+1] - srcp[x+1] ) < 10 &&
193 abs( srcp[x+1] - srcpn[x+1] ) < 10 &&
194 abs( srcpp[x+1] - srcpn[x+1] ) < 10) )
197 const int sum = srcpp[x-1] + srcpp[x] + srcpp[x+1] +
198 srcp[x-1] + srcp[x]+ srcp[x+1] +
199 srcpn[x-1] + srcpn[x] + srcpn[x+1];
201 const int sumsq = srcpp[x-1] * srcpp[x-1] +
202 srcpp[x] * srcpp[x] +
203 srcpp[x+1] * srcpp[x+1] +
204 srcp[x-1] * srcp[x-1] +
206 srcp[x+1] * srcp[x+1] +
207 srcpn[x-1] * srcpn[x-1] +
208 srcpn[x] * srcpn[x] +
209 srcpn[x+1] * srcpn[x+1];
211 if( 9 * sumsq-sum * sum < vthresh )
214 const int Ix = srcp[x+1] - srcp[x-1];
215 const int Iy = MAX( MAX( abs( srcpp[x] - srcpn[x] ),
216 abs( srcpp[x] - srcp[x] ) ),
217 abs( srcp[x] - srcpn[x] ) );
218 if( Ix * Ix + Iy * Iy >= mthresh )
224 const int Ixx = srcp[x-1] - 2 * srcp[x] + srcp[x+1];
225 const int Iyy = srcpp[x] - 2 * srcp[x] + srcpn[x];
226 if( abs( Ixx ) + abs( Iyy ) >= lthresh )
237 * Expands and smooths out the edge mask
238 * @param mskp Pointer to the source edge mask being read from
239 * @param msk_pitch Stride of mskp
240 * @param dstp Pointer to the destination to store the dilated edge mask
241 * @param dst_pitch Stride of dstp
242 * @param dstr Dilation threshold, ensures a pixel is only retained as an edge in dstp if this number of adjacent pixels or greater are also edges in mskp (4 is a good default value)
243 * @param height Height of half-height field-sized frame
244 * @param width Width of mskp bitmap rows, as opposed to the pdded stride in msk_pitch
246 void eedi2_dilate_edge_mask( uint8_t *mskp, int msk_pitch, uint8_t *dstp, int dst_pitch,
247 int dstr, int height, int width )
251 eedi2_bit_blit( dstp, dst_pitch, mskp, msk_pitch, width, height );
254 unsigned char *mskpp = mskp - msk_pitch;
255 unsigned char *mskpn = mskp + msk_pitch;
257 for( y = 1; y < height - 1; ++y )
259 for( x = 1; x < width - 1; ++x )
265 if( mskpp[x-1] == 0xFF ) ++count;
266 if( mskpp[x] == 0xFF ) ++count;
267 if( mskpp[x+1] == 0xFF ) ++count;
268 if( mskp[x-1] == 0xFF ) ++count;
269 if( mskp[x+1] == 0xFF ) ++count;
270 if( mskpn[x-1] == 0xFF ) ++count;
271 if( mskpn[x] == 0xFF ) ++count;
272 if( mskpn[x+1] == 0xFF ) ++count;
285 * Contracts the edge mask
286 * @param mskp Pointer to the source edge mask being read from
287 * @param msk_pitch Stride of mskp
288 * @param dstp Pointer to the destination to store the eroded edge mask
289 * @param dst_pitch Stride of dstp
290 * @param estr Erosion threshold, ensures a pixel isn't retained as an edge in dstp if fewer than this number of adjacent pixels are also edges in mskp (2 is a good default value)
291 * @param height Height of half-height field-sized frame
292 * @param width Width of mskp bitmap rows, as opposed to the pdded stride in msk_pitch
294 void eedi2_erode_edge_mask( uint8_t *mskp, int msk_pitch, uint8_t *dstp, int dst_pitch,
295 int estr, int height, int width )
299 eedi2_bit_blit( dstp, dst_pitch, mskp, msk_pitch, width, height );
302 unsigned char *mskpp = mskp - msk_pitch;
303 unsigned char *mskpn = mskp + msk_pitch;
305 for ( y = 1; y < height - 1; ++y )
307 for ( x = 1; x < width - 1; ++x )
309 if( mskp[x] != 0xFF ) continue;
312 if ( mskpp[x-1] == 0xFF ) ++count;
313 if ( mskpp[x] == 0xFF ) ++count;
314 if ( mskpp[x+1] == 0xFF ) ++count;
315 if ( mskp[x-1] == 0xFF ) ++count;
316 if ( mskp[x+1] == 0xFF ) ++count;
317 if ( mskpn[x-1] == 0xFF ) ++count;
318 if ( mskpn[x] == 0xFF ) ++count;
319 if ( mskpn[x+1] == 0xFF ) ++count;
321 if ( count < estr) dstp[x] = 0;
331 * Smooths out horizontally aligned holes in the mask
333 * If none of the 6 horizontally adjacent pixels are edges, mark the current pixel as not edged.
334 * If at least 1 of the 3 on either side are edges, mark the current pixel as an edge.
336 * @param mskp Pointer to the source edge mask being read from
337 * @param msk_pitch Stride of mskp
338 * @param dstp Pointer to the destination to store the smoothed edge mask
339 * @param dst_pitch Stride of dstp
340 * @param height Height of half-height field-sized frame
341 * @param width Width of mskp bitmap rows, as opposed to the pdded stride in msk_pitch
343 void eedi2_remove_small_gaps( uint8_t * mskp, int msk_pitch, uint8_t * dstp, int dst_pitch,
344 int height, int width )
348 eedi2_bit_blit( dstp, dst_pitch, mskp, msk_pitch, width, height );
352 for( y = 1; y < height - 1; ++y )
354 for( x = 3; x < width - 3; ++x )
358 if( mskp[x-3] ) continue;
359 if( mskp[x-2] ) continue;
360 if( mskp[x-1] ) continue;
361 if( mskp[x+1] ) continue;
362 if( mskp[x+2] ) continue;
363 if( mskp[x+3] ) continue;
368 if ( ( mskp[x+1] && ( mskp[x-1] || mskp[x-2] || mskp[x-3] ) ) ||
369 ( mskp[x+2] && ( mskp[x-1] || mskp[x-2] ) ) ||
370 ( mskp[x+3] && mskp[x-1] ) )
380 * Calculates spatial direction vectors for the edges. This is EEDI2's timesink, and can be thought of as YADIF_CHECK on steroids, as both try to discern which angle a given edge follows
381 * @param plane The plane of the image being processed, to know to reduce maxd for chroma planes (HandBrake only works with YUV420 video so it is assumed they are half-height)
382 * @param mskp Pointer to the source edge mask being read from
383 * @param msk_pitch Stride of mskp
384 * @param srcp Pointer to the source image being filtered
385 * @param src_pitch Stride of srcp
386 * @param dstp Pointer to the destination to store the dilated edge mask
387 * @param dst_pitch Stride of dstp
388 * @param maxd Maximum pixel distance to search (24 is a good default value)
389 * @param nt Noise threshold (50 is a good default value)
390 * @param height Height of half-height field-sized frame
391 * @param width Width of srcp bitmap rows, as opposed to the pdded stride in src_pitch
393 void eedi2_calc_directions( const int plane, uint8_t * mskp, int msk_pitch, uint8_t * srcp, int src_pitch,
394 uint8_t * dstp, int dst_pitch, int maxd, int nt, int height, int width )
398 memset( dstp, 255, dst_pitch * height );
402 unsigned char *src2p = srcp - src_pitch * 2;
403 unsigned char *srcpp = srcp - src_pitch;
404 unsigned char *srcpn = srcp + src_pitch;
405 unsigned char *src2n = srcp + src_pitch * 2;
406 unsigned char *mskpp = mskp - msk_pitch;
407 unsigned char *mskpn = mskp + msk_pitch;
408 const int maxdt = plane == 0 ? maxd : ( maxd >> 1 );
410 for( y = 1; y < height - 1; ++y )
412 for( x = 1; x < width - 1; ++x )
414 if( mskp[x] != 0xFF || ( mskp[x-1] != 0xFF && mskp[x+1] != 0xFF ) )
416 const int startu = MAX( -x + 1, -maxdt );
417 const int stopu = MIN( width - 2 - x, maxdt );
418 int minb = MIN( 13 * nt,
419 ( abs( srcp[x] - srcpn[x] ) +
420 abs( srcp[x] - srcpp[x] ) ) * 6 );
421 int mina = MIN( 19 * nt,
422 ( abs( srcp[x] - srcpn[x] ) +
423 abs( srcp[x] - srcpp[x] ) ) * 9 );
427 int dira = -5000, dirb = -5000, dirc = -5000, dird = -5000, dire = -5000;
428 for( u = startu; u <= stopu; ++u )
431 mskpp[x-1+u] == 0xFF || mskpp[x+u] == 0xFF || mskpp[x+1+u] == 0xFF )
433 if( y == height - 2 ||
434 mskpn[x-1-u] == 0xFF || mskpn[x-u] == 0xFF || mskpn[x+1-u] == 0xFF )
436 const int diffsn = abs( srcp[x-1] - srcpn[x-1-u] ) +
437 abs( srcp[x] - srcpn[x-u] ) +
438 abs( srcp[x+1] - srcpn[x+1-u] );
440 const int diffsp = abs( srcp[x-1] - srcpp[x-1+u] ) +
441 abs( srcp[x] - srcpp[x+u] ) +
442 abs( srcp[x+1] - srcpp[x+1+u] );
444 const int diffps = abs( srcpp[x-1] - srcp[x-1-u] ) +
445 abs( srcpp[x] - srcp[x-u] ) +
446 abs( srcpp[x+1] - srcp[x+1-u] );
448 const int diffns = abs( srcpn[x-1] - srcp[x-1+u] ) +
449 abs( srcpn[x] - srcp[x+u] ) +
450 abs( srcpn[x+1] - srcp[x+1+u] );
452 const int diff = diffsn + diffsp + diffps + diffns;
453 int diffd = diffsp + diffns;
454 int diffe = diffsn + diffps;
460 if( __builtin_expect( y > 1, 1) )
462 const int diff2pp = abs( src2p[x-1] - srcpp[x-1-u] ) +
463 abs( src2p[x] - srcpp[x-u] ) +
464 abs( src2p[x+1] - srcpp[x+1-u] );
465 const int diffp2p = abs( srcpp[x-1] - src2p[x-1+u] ) +
466 abs( srcpp[x] - src2p[x+u] ) +
467 abs( srcpp[x+1] - src2p[x+1+u] );
468 const int diffa = diff + diff2pp + diffp2p;
477 if( __builtin_expect( y < height-2, 1) )
479 const int diff2nn = abs( src2n[x-1] - srcpn[x-1+u] ) +
480 abs( src2n[x] - srcpn[x+u] ) +
481 abs( src2n[x+1] - srcpn[x+1+u] );
482 const int diffn2n = abs( srcpn[x-1] - src2n[x-1-u] ) +
483 abs( srcpn[x] - src2n[x-u] ) +
484 abs( srcpn[x+1] - src2n[x+1-u] );
485 const int diffc = diff + diff2nn + diffn2n;
508 if( dira != -5000 ) order[k++] = dira;
509 if( dirb != -5000 ) order[k++] = dirb;
510 if( dirc != -5000 ) order[k++] = dirc;
511 if( dird != -5000 ) order[k++] = dird;
512 if( dire != -5000 ) order[k++] = dire;
515 eedi2_sort_metrics( order, k );
516 const int mid = ( k & 1 ) ?
518 ( order[(k-1)>>1] + order[k>>1] + 1 ) >> 1;
519 const int tlim = MAX( eedi2_limlut[abs(mid)] >> 2, 2 );
520 int sum = 0, count = 0;
521 for( i = 0; i < k; ++i )
523 if( abs( order[i] - mid ) <= tlim )
530 dstp[x] = 128 + ( (int)( (float)sum / (float)count ) * 4 );
549 * Filters the edge mask
550 * @param mskp Pointer to the source edge mask being read from
551 * @param msk_pitch Stride of mskp
552 * @param dmskp Pointer to the edge direction mask
553 * @param dmsk_pitch Stride of dmskp
554 * @param dstp Pointer to the destination to store the filtered edge mask
555 * @param dst_pitch Stride of dstp
556 * @param height Height of half-height field-sized frame
557 * @param width Width of mskp bitmap rows, as opposed to the pdded stride in msk_pitch
559 void eedi2_filter_map( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
560 uint8_t * dstp, int dst_pitch, int height, int width )
564 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
569 unsigned char *dmskpp = dmskp - dmsk_pitch;
570 unsigned char *dmskpn = dmskp + dmsk_pitch;
572 for( y = 1; y < height - 1; ++y )
574 for( x = 1; x < width - 1; ++x )
576 if( dmskp[x] == 0xFF || mskp[x] != 0xFF )
578 const int dir = ( dmskp[x] - 128 ) >> 2;
579 const int lim = MAX( abs( dir ) * 2, 12 );
580 int ict = 0, icb = 0;
583 const int dirt = MAX( -x, dir );
584 for( j = dirt; j <= 0; ++j )
586 if( ( abs( dmskpp[x+j] - dmskp[x] ) > lim && dmskpp[x+j] != 0xFF ) ||
587 ( dmskp[x+j] == 0xFF && dmskpp[x+j] == 0xFF ) ||
588 ( abs( dmskp[x+j] - dmskp[x] ) > lim && dmskp[x+j] != 0xFF ) )
597 const int dirt = MIN( width - x - 1, dir );
598 for( j = 0; j <= dirt; ++j )
600 if( ( abs( dmskpp[x+j] - dmskp[x] ) > lim && dmskpp[x+j] != 0xFF ) ||
601 ( dmskp[x+j] == 0xFF && dmskpp[x+j] == 0xFF ) ||
602 ( abs( dmskp[x+j] - dmskp[x] ) > lim && dmskp[x+j] != 0xFF ) )
613 const int dirt = MIN( width - x - 1, abs( dir ) );
614 for( j = 0; j <= dirt; ++j )
616 if( ( abs( dmskpn[x+j] - dmskp[x] ) > lim && dmskpn[x+j] != 0xFF ) ||
617 ( dmskpn[x+j] == 0xFF && dmskp[x+j] == 0xFF ) ||
618 ( abs( dmskp[x+j] - dmskp[x] ) > lim && dmskp[x+j] != 0xFF ) )
627 const int dirt = MAX( -x, -dir );
628 for( j = dirt; j <= 0; ++j )
630 if( ( abs( dmskpn[x+j] - dmskp[x] ) > lim && dmskpn[x+j] != 0xFF ) ||
631 ( dmskpn[x+j] == 0xFF && dmskp[x+j] == 0xFF ) ||
632 ( abs( dmskp[x+j] - dmskp[x] ) > lim && dmskp[x+j] != 0xFF ) )
644 dmskpp += dmsk_pitch;
646 dmskpn += dmsk_pitch;
653 * Filters the edge direction mask
654 * @param mskp Pointer to the edge mask
655 * @param msk_pitch Stride of mskp
656 * @param dmskp Pointer to the edge direction mask being read from
657 * @param dmsk_pitch Stride of dmskp
658 * @param dstp Pointer to the destination to store the filtered edge direction mask
659 * @param dst_pitch Stride of dstp
660 * @param height Height of half_height field-sized frame
661 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
663 void eedi2_filter_dir_map( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
664 uint8_t * dstp, int dst_pitch, int height, int width )
668 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
671 unsigned char *dmskpp = dmskp - dmsk_pitch;
672 unsigned char *dmskpn = dmskp + dmsk_pitch;
675 for( y = 1; y < height - 1; ++y )
677 for( x = 1; x < width - 1; ++x )
679 if( mskp[x] != 0xFF ) continue;
681 if( dmskpp[x-1] != 0xFF ) order[u++] = dmskpp[x-1];
682 if( dmskpp[x] != 0xFF ) order[u++] = dmskpp[x];
683 if( dmskpp[x+1] != 0xFF ) order[u++] = dmskpp[x+1];
684 if( dmskp[x-1] != 0xFF ) order[u++] = dmskp[x-1];
685 if( dmskp[x] != 0xFF ) order[u++] = dmskp[x];
686 if( dmskp[x+1] != 0xFF ) order[u++] = dmskp[x+1];
687 if( dmskpn[x-1] != 0xFF ) order[u++] = dmskpn[x-1];
688 if( dmskpn[x] != 0xFF ) order[u++] = dmskpn[x];
689 if( dmskpn[x+1] != 0xFF ) order[u++] = dmskpn[x+1];
695 eedi2_sort_metrics( order, u );
696 const int mid = ( u & 1 ) ?
697 order[u>>1] : ( order[(u-1)>>1] + order[u>>1] + 1 ) >> 1;
698 int sum = 0, count = 0;
699 const int lim = eedi2_limlut[abs(mid-128)>>2];
700 for( i = 0; i < u; ++i )
702 if( abs( order[i] - mid ) <= lim )
708 if( count < 4 || ( count < 5 && dmskp[x] == 0xFF ) )
713 dstp[x] = (int)( ( (float)( sum + mid ) / (float)( count + 1 ) ) + 0.5f );
715 dmskpp += dmsk_pitch;
717 dmskpn += dmsk_pitch;
724 * Smoothes out the edge direction map
725 * @param mskp Pointer to the edge mask
726 * @param msk_pitch Stride of mskp
727 * @param dmskp Pointer to the edge direction mask being read from
728 * @param dmsk_pitch Stride of dmskp
729 * @param dstp Pointer to the destination to store the expanded edge direction mask
730 * @param dst_pitch Stride of dstp
731 * @param height Height of half-height field-sized frame
732 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
734 void eedi2_expand_dir_map( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
735 uint8_t * dstp, int dst_pitch, int height, int width )
739 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
742 unsigned char *dmskpp = dmskp - dmsk_pitch;
743 unsigned char *dmskpn = dmskp + dmsk_pitch;
746 for( y = 1; y < height - 1; ++y )
748 for( x = 1; x < width - 1; ++x )
750 if( dmskp[x] != 0xFF || mskp[x] != 0xFF ) continue;
752 if( dmskpp[x-1] != 0xFF ) order[u++] = dmskpp[x-1];
753 if( dmskpp[x] != 0xFF ) order[u++] = dmskpp[x];
754 if( dmskpp[x+1] != 0xFF ) order[u++] = dmskpp[x+1];
755 if( dmskp[x-1] != 0xFF ) order[u++] = dmskp[x-1];
756 if( dmskp[x+1] != 0xFF ) order[u++] = dmskp[x+1];
757 if( dmskpn[x-1] != 0xFF ) order[u++] = dmskpn[x-1];
758 if( dmskpn[x] != 0xFF ) order[u++] = dmskpn[x];
759 if( dmskpn[x+1] != 0xFF ) order[u++] = dmskpn[x+1];
760 if( u < 5 ) continue;
761 eedi2_sort_metrics( order, u );
762 const int mid = ( u & 1 ) ?
763 order[u>>1] : ( order[(u-1)>>1] + order[u>>1] + 1 ) >> 1;
764 int sum = 0, count = 0;
765 const int lim = eedi2_limlut[abs(mid-128)>>2];
766 for( i = 0; i < u; ++i )
768 if( abs( order[i] - mid ) <= lim )
774 if( count < 5 ) continue;
775 dstp[x] = (int)( ( (float)( sum + mid ) / (float)( count + 1 ) ) + 0.5f );
777 dmskpp += dmsk_pitch;
779 dmskpn += dmsk_pitch;
786 * Re-draws a clearer, less blocky frame-height edge direction mask
787 * @param mskp Pointer to the edge mask
788 * @param msk_pitch Stride of mskp
789 * @param dmskp Pointer to the edge direction mask being read from
790 * @param dmsk_pitch Stride of dmskp
791 * @param dstp Pointer to the destination to store the redrawn direction mask
792 * @param dst_pitch Stride of dstp
793 * @param tff Whether or not the frame parity is Top Field First
794 * @param height Height of the full-frame output
795 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
797 void eedi2_mark_directions_2x( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
798 uint8_t * dstp, int dst_pitch, int tff, int height, int width )
801 memset( dstp, 255, dst_pitch * height );
802 dstp += dst_pitch * ( 2 - tff );
803 dmskp += dmsk_pitch * ( 1 - tff );
804 mskp += msk_pitch * ( 1 - tff );
805 unsigned char *dmskpn = dmskp + dmsk_pitch * 2;
806 unsigned char *mskpn = mskp + msk_pitch * 2;
807 for( y = 2 - tff; y < height - 1; y += 2 )
809 for( x = 1; x < width - 1; ++x )
811 if( mskp[x] != 0xFF && mskpn[x] != 0xFF ) continue;
813 if( dmskp[x-1] != 0xFF ) order[v++] = dmskp[x-1];
814 if( dmskp[x] != 0xFF ) order[v++] = dmskp[x];
815 if( dmskp[x+1] != 0xFF ) order[v++] = dmskp[x+1];
816 if( dmskpn[x-1] != 0xFF ) order[v++] = dmskpn[x-1];
817 if( dmskpn[x] != 0xFF ) order[v++] = dmskpn[x];
818 if( dmskpn[x+1] != 0xFF ) order[v++] = dmskpn[x+1];
819 if( v < 3 ) continue;
822 eedi2_sort_metrics( order, v );
823 const int mid = ( v & 1 ) ? order[v>>1] : ( order[(v-1)>>1] + order[v>>1]+1) >> 1;
824 const int lim = eedi2_limlut[abs(mid-128)>>2];
826 if( abs( dmskp[x-1] - dmskpn[x-1] ) <= lim ||
827 dmskp[x-1] == 0xFF || dmskpn[x-1] == 0xFF )
829 if( abs( dmskp[x] - dmskpn[x] ) <= lim ||
830 dmskp[x] == 0xFF || dmskpn[x] == 0xFF )
832 if( abs( dmskp[x+1] - dmskpn[x-1] ) <= lim ||
833 dmskp[x+1] == 0xFF || dmskpn[x+1] == 0xFF)
835 if( u < 2 ) continue;
836 int count = 0, sum = 0;
837 for( i = 0; i < v; ++i )
839 if( abs( order[i] - mid ) <= lim )
845 if( count < v - 2 || count < 2 ) continue;
846 dstp[x] = (int)( ( (float)( sum + mid ) / (float)( count + 1 ) ) + 0.5f );
849 mskp += msk_pitch * 2;
850 mskpn += msk_pitch * 2;
851 dstp += dst_pitch * 2;
852 dmskp += dmsk_pitch * 2;
853 dmskpn += dmsk_pitch * 2;
858 * Filters the frane-height edge direction mask
859 * @param mskp Pointer to the edge mask
860 * @param msk_pitch Stride of mskp
861 * @param dmskp Pointer to the edge direction mask being read from
862 * @param dmsk_pitch Stride of dmskp
863 * @param dstp Pointer to the destination to store the filtered direction mask
864 * @param dst_pitch Stride of dstp
865 * @param field Field to filter
866 * @param height Height of the full-frame output
867 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
869 void eedi2_filter_dir_map_2x( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
870 uint8_t * dstp, int dst_pitch, int field, int height, int width )
873 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
874 dmskp += dmsk_pitch * ( 2 - field );
875 unsigned char *dmskpp = dmskp - dmsk_pitch * 2;
876 unsigned char *dmskpn = dmskp + dmsk_pitch * 2;
877 mskp += msk_pitch * ( 1 - field );
878 unsigned char *mskpn = mskp + msk_pitch * 2;
879 dstp += dst_pitch * ( 2 - field );
880 for( y = 2 - field; y < height - 1; y += 2 )
882 for( x = 1; x < width - 1; ++x )
884 if( mskp[x] != 0xFF && mskpn[x] != 0xFF ) continue;
888 if( dmskpp[x-1] != 0xFF ) order[u++] = dmskpp[x-1];
889 if( dmskpp[x] != 0xFF ) order[u++] = dmskpp[x];
890 if( dmskpp[x+1] != 0xFF ) order[u++] = dmskpp[x+1];
892 if( dmskp[x-1] != 0xFF ) order[u++] = dmskp[x-1];
893 if( dmskp[x] != 0xFF ) order[u++] = dmskp[x];
894 if( dmskp[x+1] != 0xFF ) order[u++] = dmskp[x+1];
897 if( dmskpn[x-1] != 0xFF ) order[u++] = dmskpn[x-1];
898 if( dmskpn[x] != 0xFF ) order[u++] = dmskpn[x];
899 if( dmskpn[x+1] != 0xFF ) order[u++] = dmskpn[x+1];
906 eedi2_sort_metrics( order, u );
907 const int mid = ( u & 1 ) ? order[u>>1] : (order[(u-1)>>1] + order[u>>1] + 1 ) >> 1;
908 int sum = 0, count = 0;
909 const int lim = eedi2_limlut[abs(mid-128)>>2];
910 for( i = 0; i < u; ++i )
912 if( abs( order[i] - mid ) <= lim )
918 if( count < 4 || ( count < 5 && dmskp[x] == 0xFF ) )
923 dstp[x] = (int)( ( (float)( sum + mid ) / (float)( count + 1 ) ) + 0.5f );
925 mskp += msk_pitch * 2;
926 mskpn += msk_pitch * 2;
927 dmskpp += dmsk_pitch * 2;
928 dmskp += dmsk_pitch * 2;
929 dmskpn += dmsk_pitch * 2;
930 dstp += dst_pitch * 2;
935 * Smoothes out the frame-height edge direction mask
936 * @param mskp Pointer to the edge mask
937 * @param msk_pitch Stride of mskp
938 * @param dmskp Pointer to the edge direction mask being read from
939 * @param dmsk_pitch Stride of dmskp
940 * @param dstp Pointer to the destination to store the expanded direction mask
941 * @param dst_pitch Stride of dstp
942 * @param field Field to filter
943 * @param height Height of the full-frame output
944 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
946 void eedi2_expand_dir_map_2x( uint8_t * mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
947 uint8_t * dstp, int dst_pitch, int field, int height, int width )
951 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
953 dmskp += dmsk_pitch * ( 2 - field );
954 unsigned char *dmskpp = dmskp - dmsk_pitch * 2;
955 unsigned char *dmskpn = dmskp + dmsk_pitch * 2;
956 mskp += msk_pitch * ( 1 - field );
957 unsigned char *mskpn = mskp + msk_pitch * 2;
958 dstp += dst_pitch * ( 2 - field );
959 for( y = 2 - field; y < height - 1; y += 2)
961 for( x = 1; x < width - 1; ++x )
963 if( dmskp[x] != 0xFF || ( mskp[x] != 0xFF && mskpn[x] != 0xFF ) ) continue;
967 if( dmskpp[x-1] != 0xFF ) order[u++] = dmskpp[x-1];
968 if( dmskpp[x] != 0xFF ) order[u++] = dmskpp[x];
969 if( dmskpp[x+1] != 0xFF ) order[u++] = dmskpp[x+1];
971 if( dmskp[x-1] != 0xFF ) order[u++] = dmskp[x-1];
972 if( dmskp[x+1] != 0xFF ) order[u++] = dmskp[x+1];
975 if( dmskpn[x-1] != 0xFF) order[u++] = dmskpn[x-1];
976 if( dmskpn[x] != 0xFF) order[u++] = dmskpn[x];
977 if( dmskpn[x+1] != 0xFF) order[u++] = dmskpn[x+1];
979 if( u < 5 ) continue;
980 eedi2_sort_metrics( order, u );
981 const int mid = ( u & 1 ) ? order[u>>1] : ( order[(u-1)>>1] + order[u>>1] + 1 ) >> 1;
982 int sum = 0, count = 0;
983 const int lim = eedi2_limlut[abs(mid-128)>>2];
984 for( i = 0; i < u; ++i )
986 if( abs( order[i] - mid ) <= lim )
992 if( count < 5 ) continue;
993 dstp[x] = (int)( ( (float)( sum + mid ) / (float)( count + 1 ) ) + 0.5f );
995 mskp += msk_pitch * 2;
996 mskpn += msk_pitch * 2;
997 dmskpp += dmsk_pitch * 2;
998 dmskp += dmsk_pitch * 2;
999 dmskpn += dmsk_pitch * 2;
1000 dstp += dst_pitch * 2;
1005 * Like the name suggests, this function fills in gaps in the frame-height edge direction mask
1006 * @param mskp Pointer to the edge mask
1007 * @param msk_pitch Stride of mskp
1008 * @param dmskp Pointer to the edge direction mask being read from
1009 * @param dmsk_pitch Stride of dmskp
1010 * @param dstp Pointer to the destination to store the filled-in direction mask
1011 * @param dst_pitch Stride of dstp
1012 * @param field Field to filter
1013 * @param height Height of the full-frame output
1014 * @param width Width of dmskp bitmap rows, as opposed to the pdded stride in dmsk_pitch
1016 void eedi2_fill_gaps_2x( uint8_t *mskp, int msk_pitch, uint8_t * dmskp, int dmsk_pitch,
1017 uint8_t * dstp, int dst_pitch, int field, int height, int width )
1021 eedi2_bit_blit( dstp, dst_pitch, dmskp, dmsk_pitch, width, height );
1023 dmskp += dmsk_pitch * ( 2 - field );
1024 unsigned char *dmskpp = dmskp - dmsk_pitch * 2;
1025 unsigned char *dmskpn = dmskp + dmsk_pitch * 2;
1026 mskp += msk_pitch * ( 1 - field );
1027 unsigned char *mskpp = mskp - msk_pitch * 2;
1028 unsigned char *mskpn = mskp + msk_pitch * 2;
1029 unsigned char *mskpnn = mskpn + msk_pitch * 2;
1030 dstp += dst_pitch * ( 2 - field );
1031 for( y = 2 - field; y < height - 1; y += 2 )
1033 for( x = 1; x < width - 1; ++x )
1035 if( dmskp[x] != 0xFF ||
1036 ( mskp[x] != 0xFF && mskpn[x] != 0xFF ) ) continue;
1037 int u = x - 1, back = 500, forward = -500;
1040 if( dmskp[u] != 0xFF )
1045 if( mskp[u] != 0xFF && mskpn[u] != 0xFF ) break;
1051 if( dmskp[v] != 0xFF )
1056 if( mskp[v] != 0xFF && mskpn[v] != 0xFF ) break;
1060 int mint = 500, maxt = -20;
1061 int minb = 500, maxb = -20;
1062 for( j = u; j <= v; ++j )
1066 if( y <= 2 || dmskpp[j] == 0xFF || ( mskpp[j] != 0xFF && mskp[j] != 0xFF ) )
1073 if( dmskpp[j] < mint ) mint = dmskpp[j];
1074 if( dmskpp[j] > maxt ) maxt = dmskpp[j];
1079 if( y >= height - 3 || dmskpn[j] == 0xFF || ( mskpn[j] != 0xFF && mskpnn[j] != 0xFF ) )
1086 if( dmskpn[j] < minb ) minb = dmskpn[j];
1087 if( dmskpn[j] > maxb ) maxb = dmskpn[j];
1091 if( maxt == -20 ) maxt = mint = 20;
1092 if( maxb == -20 ) maxb = minb = 20;
1094 MAX( MAX( abs( forward - 128 ), abs( back - 128 ) ) >> 2, 8 ),
1095 MAX( abs( mint - maxt ), abs( minb - maxb ) ) );
1096 const int flim = MIN(
1097 MAX( abs( forward - 128 ), abs( back - 128 ) ) >> 2,
1099 if( abs( forward - back ) <= thresh && ( v - u - 1 <= flim || tc || bc ) )
1101 double step = (double)( forward - back ) / (double)( v - u );
1102 for( j = 0; j < v - u - 1; ++j )
1103 dstp[u+j+1] = back + (int)( j * step + 0.5 );
1106 mskpp += msk_pitch * 2;
1107 mskp += msk_pitch * 2;
1108 mskpn += msk_pitch * 2;
1109 mskpnn += msk_pitch * 2;
1110 dmskpp += dmsk_pitch * 2;
1111 dmskp += dmsk_pitch * 2;
1112 dmskpn += dmsk_pitch * 2;
1113 dstp += dst_pitch * 2;
1118 * Actually renders the output frame, based on the edge and edge direction masks
1119 * @param plane The plane of the image being processed, to know to reduce a search distance for chroma planes (HandBrake only works with YUV420 video so it is assumed they are half-height)
1120 * @param dmskp Pointer to the edge direction mask being read from
1121 * @param dmsk_pitch Stride of dmskp
1122 * @param dstp Pointer to the line-doubled source field used being filtered in place
1123 * @param dst_pitch Stride of dstp
1124 * @param omskp Pointer to the destination to store the output edge mask used for post-processing
1125 * @param osmk_pitch Stride of omskp
1126 * @param field Field to filter
1127 * @nt Noise threshold, (50 is a good default value)
1128 * @param height Height of the full-frame output
1129 * @param width Width of dstp bitmap rows, as opposed to the pdded stride in dst_pitch
1131 void eedi2_interpolate_lattice( const int plane, uint8_t * dmskp, int dmsk_pitch, uint8_t * dstp,
1132 int dst_pitch, uint8_t * omskp, int omsk_pitch, int field, int nt,
1133 int height, int width )
1139 eedi2_bit_blit( dstp + ( height - 1 ) * dst_pitch,
1141 dstp + ( height - 2 ) * dst_pitch,
1148 eedi2_bit_blit( dstp,
1156 dstp += dst_pitch * ( 1 - field );
1157 omskp += omsk_pitch * ( 1 - field );
1158 unsigned char *dstpn = dstp + dst_pitch;
1159 unsigned char *dstpnn = dstp + dst_pitch * 2;
1160 unsigned char *omskn = omskp + omsk_pitch * 2;
1161 dmskp += dmsk_pitch * ( 2 - field );
1162 for( y = 2 - field; y < height - 1; y += 2 )
1164 for( x = 0; x < width; ++x )
1167 const int lim = eedi2_limlut[abs(dir-128)>>2];
1169 ( abs( dmskp[x] - dmskp[x-1] ) > lim &&
1170 abs( dmskp[x] - dmskp[x+1] ) > lim ) )
1172 dstpn[x] = ( dstp[x] + dstpnn[x] + 1 ) >> 1;
1173 if( dir != 255 ) dmskp[x] = 128;
1178 const int sum = dstp[x-1] + dstp[x] + dstp[x+1] +
1179 dstpnn[x-1] + dstpnn[x] + dstpnn[x+1];
1180 const int sumsq = dstp[x-1] * dstp[x-1] +
1182 dstp[x+1] * dstp[x+1] +
1183 dstpnn[x-1] * dstpnn[x-1] +
1184 dstpnn[x] * dstpnn[x] +
1185 dstpnn[x+1] * dstpnn[x+1];
1186 if( 6 * sumsq - sum * sum < 576 )
1188 dstpn[x] = ( dstp[x] + dstpnn[x] + 1 ) >> 1;
1193 if( x > 1 && x < width - 2 &&
1194 ( dstp[x] < MAX( dstp[x-2], dstp[x-1] ) - 3 &&
1195 dstp[x] < MAX( dstp[x+2], dstp[x+1] ) - 3 &&
1196 dstpnn[x] < MAX( dstpnn[x-2], dstpnn[x-1] ) - 3 &&
1197 dstpnn[x] < MAX( dstpnn[x+2], dstpnn[x+1] ) - 3 )
1199 ( dstp[x] > MIN( dstp[x-2], dstp[x-1] ) + 3 &&
1200 dstp[x] > MIN( dstp[x+2], dstp[x+1] ) + 3 &&
1201 dstpnn[x] > MIN( dstpnn[x-2], dstpnn[x-1] ) + 3 &&
1202 dstpnn[x] > MIN( dstpnn[x+2], dstpnn[x+1] ) + 3 ) )
1204 dstpn[x] = ( dstp[x] + dstpnn[x] + 1 ) >> 1;
1208 dir = ( dir - 128 + 2 ) >> 2;
1209 int val = ( dstp[x] + dstpnn[x] + 1 ) >> 1;
1210 const int startu = ( dir - 2 < 0 ) ?
1211 MAX( -x + 1, MAX( dir - 2, -width + 2 + x ) )
1213 MIN( x - 1, MIN( dir - 2, width - 2 - x ) );
1214 const int stopu = ( dir + 2 < 0 ) ?
1215 MAX( -x + 1, MAX( dir + 2, -width + 2 + x ) )
1217 MIN( x - 1, MIN( dir + 2, width - 2 - x ) );
1219 for( u = startu; u <= stopu; ++u )
1222 abs( dstp[x-1] - dstpnn[x-u-1] ) +
1223 abs( dstp[x] - dstpnn[x-u] ) +
1224 abs( dstp[x+1] - dstpnn[x-u+1] ) +
1225 abs( dstpnn[x-1] - dstp[x+u-1] ) +
1226 abs( dstpnn[x] - dstp[x+u] ) +
1227 abs( dstpnn[x+1] - dstp[x+u+1] );
1229 ( ( omskp[x-1+u] != 0xFF && abs( omskp[x-1+u] - dmskp[x] ) <= lim ) ||
1230 ( omskp[x+u] != 0xFF && abs( omskp[x+u] - dmskp[x]) <= lim ) ||
1231 ( omskp[x+1+u] != 0xFF && abs( omskp[x+1+u] - dmskp[x]) <= lim ) ) &&
1232 ( ( omskn[x-1-u] != 0xFF && abs( omskn[x-1-u] - dmskp[x]) <= lim ) ||
1233 ( omskn[x-u] != 0xFF && abs( omskn[x-u] - dmskp[x]) <= lim ) ||
1234 ( omskn[x+1-u] != 0xFF && abs( omskn[x+1-u] - dmskp[x]) <= lim ) ) )
1237 abs( dstp[x+(u>>1)-1] - dstpnn[x-(u>>1)-1] ) +
1238 abs( dstp[x+(u>>1)] - dstpnn[x-(u>>1)] ) +
1239 abs( dstp[x+(u>>1)+1] - dstpnn[x-(u>>1)+1] );
1240 if( diff2 < 4 * nt &&
1241 ( ( ( abs( omskp[x+(u>>1)] - omskn[x-(u>>1)] ) <= lim ||
1242 abs( omskp[x+(u>>1)] - omskn[x-((u+1)>>1)] ) <= lim ) &&
1243 omskp[x+(u>>1)] != 0xFF )
1245 ( ( abs( omskp[x+((u+1)>>1)] - omskn[x-(u>>1)] ) <= lim ||
1246 abs( omskp[x+((u+1)>>1)] - omskn[x-((u+1)>>1)] ) <= lim ) &&
1247 omskp[x+((u+1)>>1)] != 0xFF ) ) )
1249 if( ( abs( dmskp[x] - omskp[x+(u>>1)] ) <= lim ||
1250 abs( dmskp[x] - omskp[x+((u+1)>>1)] ) <= lim ) &&
1251 ( abs( dmskp[x] - omskn[x-(u>>1)] ) <= lim ||
1252 abs( dmskp[x] - omskn[x-((u+1)>>1)] ) <= lim ) )
1254 val = ( dstp[x+(u>>1)] + dstp[x+((u+1)>>1)] +
1255 dstpnn[x-(u>>1)] + dstpnn[x-((u+1)>>1)] + 2 ) >> 2;
1265 dmskp[x] = 128 + dir * 4;
1269 const int minm = MIN( dstp[x], dstpnn[x] );
1270 const int maxm = MAX( dstp[x], dstpnn[x] );
1271 const int d = plane == 0 ? 4 : 2;
1272 const int startu = MAX( -x + 1, -d );
1273 const int stopu = MIN( width - 2 - x, d );
1275 for( u = startu; u <= stopu; ++u )
1277 const int p1 = dstp[x+(u>>1)] + dstp[x+((u+1)>>1)];
1278 const int p2 = dstpnn[x-(u>>1)] + dstpnn[x-((u+1)>>1)];
1280 abs( dstp[x-1] - dstpnn[x-u-1] ) +
1281 abs( dstp[x] - dstpnn[x-u] ) +
1282 abs( dstp[x+1] - dstpnn[x-u+1] ) +
1283 abs( dstpnn[x-1] - dstp[x+u-1] ) +
1284 abs( dstpnn[x] - dstp[x+u] ) +
1285 abs( dstpnn[x+1] - dstp[x+u+1] ) +
1289 const int valt = ( p1 + p2 + 2 ) >> 2;
1290 if( valt >= minm && valt <= maxm )
1299 if( min == 7*nt ) dmskp[x] = 128;
1300 else dmskp[x] = 128 + dir * 4;
1303 dstp += dst_pitch * 2;
1304 dstpn += dst_pitch * 2;
1305 dstpnn += dst_pitch * 2;
1306 dmskp += dmsk_pitch * 2;
1307 omskp += omsk_pitch * 2;
1308 omskn += omsk_pitch * 2;
1313 * Applies some extra filtering to smooth the edge direction mask
1314 * @param nmskp Pointer to the newly-filtered edge direction mask being read from
1315 * @param nmsk_pitch Stride of nmskp
1316 * @param omskp Pointer to the old unfiltered edge direction mask being read from
1317 * @param omsk_pitch Stride of osmkp
1318 * @param dstp Pointer to the output image being filtered in place
1319 * @param src_pitch Stride of dstp ....not sure why it's named this
1320 * @param field Field to filter
1321 * @param height Height of the full-frame output
1322 * @param width Width of dstp bitmap rows, as opposed to the pdded stride in src_pitch
1324 void eedi2_post_process( uint8_t * nmskp, int nmsk_pitch, uint8_t * omskp, int omsk_pitch,
1325 uint8_t * dstp, int src_pitch, int field, int height, int width )
1329 nmskp += ( 2 - field ) * nmsk_pitch;
1330 omskp += ( 2 - field ) * omsk_pitch;
1331 dstp += ( 2 - field ) * src_pitch;
1332 unsigned char *srcpp = dstp - src_pitch;
1333 unsigned char *srcpn = dstp + src_pitch;
1334 for( y = 2 - field; y < height - 1; y += 2 )
1336 for( x = 0; x < width; ++x )
1338 const int lim = eedi2_limlut[abs(nmskp[x]-128)>>2];
1339 if( abs( nmskp[x] - omskp[x] ) > lim && omskp[x] != 255 && omskp[x] != 128 )
1340 dstp[x] = ( srcpp[x] + srcpn[x] + 1 ) >> 1;
1342 nmskp += nmsk_pitch * 2;
1343 omskp += omsk_pitch * 2;
1344 srcpp += src_pitch * 2;
1345 dstp += src_pitch * 2;
1346 srcpn += src_pitch * 2;
1351 * Blurs the source field plane
1352 * @param src Pointer to the half-height source field plane
1353 * @param src_pitch Stride of src
1354 * @param tmp Pointer to a temporary buffer for juggling bitmaps
1355 * @param tmp_pitch Stride of tmp
1356 * @param dst Pointer to the destination to store the blurred field plane
1357 * @param dst_pitch Stride of dst
1358 * @param height Height of the hakf-height field-sized frame
1359 * @param width Width of dstp bitmap rows, as opposed to the padded stride in dst_pitch
1361 void eedi2_gaussian_blur1( uint8_t * src, int src_pitch, uint8_t * tmp, int tmp_pitch, uint8_t * dst, int dst_pitch, int height, int width )
1363 uint8_t * srcp = src;
1364 uint8_t * dstp = tmp;
1367 for( y = 0; y < height; ++y )
1369 dstp[0] = ( srcp[3] * 582 + srcp[2] * 7078 + srcp[1] * 31724 +
1370 srcp[0] * 26152 + 32768 ) >> 16;
1371 dstp[1] = ( srcp[4] * 582 + srcp[3] * 7078 +
1372 ( srcp[0] + srcp[2] ) * 15862 +
1373 srcp[1] * 26152 + 32768 ) >> 16;
1374 dstp[2] = ( srcp[5] * 582 + ( srcp[0] + srcp[4] ) * 3539 +
1375 ( srcp[1] + srcp[3] ) * 15862 +
1376 srcp[2]*26152 + 32768 ) >> 16;
1377 for( x = 3; x < width - 3; ++x )
1379 dstp[x] = ( ( srcp[x-3] + srcp[x+3] ) * 291 +
1380 ( srcp[x-2] + srcp[x+2] ) * 3539 +
1381 ( srcp[x-1] + srcp[x+1] ) * 15862 +
1382 srcp[x] * 26152 + 32768 ) >> 16;
1384 dstp[x] = ( srcp[x-3] * 582 + ( srcp[x-2] + srcp[x+2] ) * 3539 +
1385 ( srcp[x-1] + srcp[x+1] ) * 15862 +
1386 srcp[x] * 26152 + 32768 ) >> 16;
1388 dstp[x] = ( srcp[x-3] * 582 + srcp[x-2] * 7078 +
1389 ( srcp[x-1] + srcp[x+1] ) * 15862 +
1390 srcp[x] * 26152 + 32768 ) >> 16;
1392 dstp[x] = ( srcp[x-3] * 582 + srcp[x-2] * 7078 +
1393 srcp[x-1] * 31724 + srcp[x] * 26152 + 32768 ) >> 16;
1399 unsigned char *src3p = srcp - tmp_pitch * 3;
1400 unsigned char *src2p = srcp - tmp_pitch * 2;
1401 unsigned char *srcpp = srcp - tmp_pitch;
1402 unsigned char *srcpn = srcp + tmp_pitch;
1403 unsigned char *src2n = srcp + tmp_pitch * 2;
1404 unsigned char *src3n = srcp + tmp_pitch * 3;
1405 for( x = 0; x < width; ++x )
1407 dstp[x] = ( src3n[x] * 582 + src2n[x] * 7078 + srcpn[x] * 31724 +
1408 srcp[x] * 26152 + 32768 ) >> 16;
1418 for( x = 0; x < width; ++x )
1420 dstp[x] = ( src3n[x] * 582 + src2n[x] * 7078 +
1421 ( srcpp[x] + srcpn[x] ) * 15862 +
1422 srcp[x] * 26152 + 32768 ) >> 16;
1432 for( x = 0; x < width; ++x )
1434 dstp[x] = ( src3n[x] * 582 + ( src2p[x] + src2n[x] ) * 3539 +
1435 ( srcpp[x] + srcpn[x] ) * 15862 +
1436 srcp[x] * 26152 + 32768 ) >> 16;
1446 for( y = 3; y < height - 3; ++y )
1448 for( x = 0; x < width; ++x )
1450 dstp[x] = ( ( src3p[x] + src3n[x] ) * 291 +
1451 ( src2p[x] + src2n[x] ) * 3539 +
1452 ( srcpp[x] + srcpn[x] ) * 15862 +
1453 srcp[x] * 26152 + 32768 ) >> 16;
1464 for( x = 0; x < width; ++x )
1466 dstp[x] = ( src3p[x] * 582 + ( src2p[x] + src2n[x] ) *3539 +
1467 ( srcpp[x] + srcpn[x] ) * 15862 +
1468 srcp[x] * 26152 + 32768 ) >> 16;
1478 for( x = 0; x < width; ++x )
1480 dstp[x] = ( src3p[x] * 582 + src2p[x] * 7078 +
1481 ( srcpp[x] + srcpn[x] ) * 15862 +
1482 srcp[x] * 26152 + 32768 ) >> 16;
1492 for( x = 0; x < width; ++x )
1494 dstp[x] = ( src3p[x] * 582 + src2p[x] * 7078 +
1495 srcpp[x] * 31724 + srcp[x] * 26152 + 32768 ) >> 16;
1501 * Blurs the spatial derivatives of the source field plane
1502 * @param src Pointer to the derivative array to filter
1503 * @param tmp Pointer to a temporary storage for the derivative array while it's being filtered
1504 * @param dst Pointer to the destination to store the filtered output derivative array
1505 * @param pitch Stride of the bitmap from which the src array is derived
1506 * @param height Height of the half-height field-sized frame from which the src array derivs were taken
1507 * @param width Width of the bitmap from which the src array is derived, as opposed to the padded stride in pitch
1509 void eedi2_gaussian_blur_sqrt2( int *src, int *tmp, int *dst, const int pitch, int height, const int width )
1515 for( y = 0; y < height; ++y )
1518 dstp[x] = ( srcp[x+4] * 678 + srcp[x+3] * 3902 + srcp[x+2] * 13618 +
1519 srcp[x+1] * 28830 + srcp[x] * 18508 + 32768 ) >> 16;
1521 dstp[x] = ( srcp[x+4] * 678 + srcp[x+3] * 3902 + srcp[x+2] * 13618 +
1522 ( srcp[x-1] + srcp[x+1] ) *14415 +
1523 srcp[x] * 18508 + 32768 ) >> 16;
1525 dstp[x] = ( srcp[x+4] * 678 + srcp[x+3] * 3902 +
1526 ( srcp[x-2] + srcp[x+2] ) * 6809 +
1527 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1528 srcp[x] * 18508 + 32768 ) >> 16;
1530 dstp[x] = ( srcp[x+4] * 678 + ( srcp[x-3] + srcp[x+3] ) * 1951 +
1531 ( srcp[x-2] + srcp[x+2] ) * 6809 +
1532 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1533 srcp[x] * 18508 + 32768 ) >> 16;
1535 for( x = 4; x < width - 4; ++x )
1537 dstp[x] = ( ( srcp[x-4] + srcp[x+4] ) * 339 +
1538 ( srcp[x-3] + srcp[x+3] ) * 1951 +
1539 ( srcp[x-2] + srcp[x+2] ) * 6809 +
1540 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1541 srcp[x] * 18508 + 32768 ) >> 16;
1544 dstp[x] = ( srcp[x-4] * 678 + ( srcp[x-3] + srcp[x+3] ) * 1951 +
1545 ( srcp[x-2] + srcp[x+2] ) * 6809 +
1546 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1547 srcp[x] * 18508 + 32768 ) >> 16;
1549 dstp[x] = ( srcp[x-4] * 678 + srcp[x-3] * 3902 +
1550 ( srcp[x-2] + srcp[x+2] ) * 6809 +
1551 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1552 srcp[x] * 18508 + 32768 ) >> 16;
1554 dstp[x] = ( srcp[x-4] * 678 + srcp[x+3] * 3902 + srcp[x-2] * 13618 +
1555 ( srcp[x-1] + srcp[x+1] ) * 14415 +
1556 srcp[x] * 18508 + 32768 ) >> 16;
1558 dstp[x] = ( srcp[x-4] * 678 + srcp[x-3] * 3902 + srcp[x-2] * 13618 +
1560 srcp[x] * 18508 + 32768 ) >> 16;
1566 int * src4p = srcp - pitch * 4;
1567 int * src3p = srcp - pitch * 3;
1568 int * src2p = srcp - pitch * 2;
1569 int * srcpp = srcp - pitch;
1570 int * srcpn = srcp + pitch;
1571 int * src2n = srcp + pitch * 2;
1572 int * src3n = srcp + pitch * 3;
1573 int * src4n = srcp + pitch * 4;
1574 for( x = 0; x < width; ++x )
1576 dstp[x] = ( src4n[x] * 678 + src3n[x] * 3902 +
1577 src2n[x] * 13618 + srcpn[x] * 28830 +
1578 srcp[x] * 18508 + 32768 ) >> 18;
1590 for( x = 0; x < width; ++x )
1592 dstp[x] = ( src4n[x] * 678 + src3n[x] * 3902 + src2n[x] * 13618 +
1593 ( srcpp[x] + srcpn[x] ) * 14415 +
1594 srcp[x] * 18508 + 32768 ) >> 18;
1606 for( x = 0; x < width; ++x )
1608 dstp[x] = ( src4n[x] * 678 + src3n[x] * 3902 +
1609 ( src2p[x] + src2n[x] ) * 6809 +
1610 ( srcpp[x] + srcpn[x] ) * 14415 +
1611 srcp[x] * 18508 + 32768 ) >> 18;
1623 for( x = 0; x < width; ++x )
1625 dstp[x] = ( src4n[x] * 678 + ( src3p[x] + src3n[x] ) * 1951 +
1626 ( src2p[x] + src2n[x] ) * 6809 +
1627 ( srcpp[x] + srcpn[x] ) * 14415 +
1628 srcp[x] * 18508 + 32768 ) >> 18;
1640 for( y = 4; y < height - 4; ++y )
1642 for( x = 0; x < width; ++x )
1644 dstp[x] = ( ( src4p[x] + src4n[x] ) * 339 +
1645 ( src3p[x] + src3n[x] ) * 1951 +
1646 ( src2p[x] + src2n[x] ) * 6809 +
1647 ( srcpp[x] + srcpn[x] ) * 14415 +
1648 srcp[x] * 18508 + 32768 ) >> 18;
1661 for( x = 0; x < width; ++x )
1663 dstp[x] = ( src4p[x] * 678 +
1664 ( src3p[x] + src3n[x] ) * 1951 +
1665 ( src2p[x] + src2n[x] ) * 6809 +
1666 ( srcpp[x] + srcpn[x] ) * 14415 +
1667 srcp[x] * 18508 + 32768 ) >> 18;
1679 for( x = 0; x < width; ++x )
1681 dstp[x] = ( src4p[x] * 678 + src3p[x] * 3902 +
1682 ( src2p[x] + src2n[x] ) * 6809 +
1683 ( srcpp[x] + srcpn[x] ) * 14415 +
1684 srcp[x] * 18508 + 32768 ) >> 18;
1696 for( x = 0; x < width; ++x )
1698 dstp[x] = ( src4p[x] * 678 + src3p[x] * 3902 + src2p[x] * 13618 +
1699 ( srcpp[x] + srcpn[x] ) * 14415 +
1700 srcp[x] * 18508 + 32768 ) >> 18;
1712 for( x = 0; x < width; ++x )
1714 dstp[x] = ( src4p[x] * 678 + src3p[x] * 3902 +
1715 src2p[x] * 13618 + srcpp[x] * 28830 +
1716 srcp[x] * 18508 + 32768 ) >> 18;
1721 * Finds spatial derivatives for a a source field plane
1722 * @param srcp Pointer to the plane to derive
1723 * @param src_pitch Stride of srcp
1724 * @param height Height of the half-height field-sized frame
1725 * @param width Width of srcp bitmap rows, as opposed to the padded stride in src_pitch
1726 * @param x2 Pointed to the array to store the x/x derivatives
1727 * @param y2 Pointer to the array to store the y/y derivatives
1728 * @param xy Pointer to the array to store the x/y derivatives
1730 void eedi2_calc_derivatives( uint8_t *srcp, int src_pitch, int height, int width, int *x2, int *y2, int *xy)
1733 unsigned char * srcpp = srcp - src_pitch;
1734 unsigned char * srcpn = srcp + src_pitch;
1737 const int Ix = srcp[1] - srcp[0];
1738 const int Iy = srcp[0] - srcpn[0];
1739 x2[0] = ( Ix * Ix ) >> 1;
1740 y2[0] = ( Iy * Iy ) >> 1;
1741 xy[0] = ( Ix * Iy ) >> 1;
1743 for( x = 1; x < width - 1; ++x )
1745 const int Ix = srcp[x+1] - srcp[x-1];
1746 const int Iy = srcp[x] - srcpn[x];
1747 x2[x] = ( Ix * Ix ) >> 1;
1748 y2[x] = ( Iy * Iy ) >> 1;
1749 xy[x] = ( Ix * Iy ) >> 1;
1752 const int Ix = srcp[x] - srcp[x-1];
1753 const int Iy = srcp[x] - srcpn[x];
1754 x2[x] = ( Ix * Ix ) >> 1;
1755 y2[x] = ( Iy * Iy ) >> 1;
1756 xy[x] = ( Ix * Iy ) >> 1;
1764 for( y = 1; y < height - 1; ++y )
1767 const int Ix = srcp[1] - srcp[0];
1768 const int Iy = srcpp[0] - srcpn[0];
1769 x2[0] = ( Ix * Ix ) >> 1;
1770 y2[0] = ( Iy * Iy ) >> 1;
1771 xy[0] = ( Ix * Iy ) >> 1;
1773 for ( x = 1; x < width - 1; ++x )
1775 const int Ix = srcp[x+1] - srcp[x-1];
1776 const int Iy = srcpp[x] - srcpn[x];
1777 x2[x] = ( Ix * Ix ) >> 1;
1778 y2[x] = ( Iy * Iy ) >> 1;
1779 xy[x] = ( Ix * Iy ) >> 1;
1782 const int Ix = srcp[x] - srcp[x-1];
1783 const int Iy = srcpp[x] - srcpn[x];
1784 x2[x] = ( Ix *Ix ) >> 1;
1785 y2[x] = ( Iy *Iy ) >> 1;
1786 xy[x] = ( Ix *Iy ) >> 1;
1796 const int Ix = srcp[1] - srcp[0];
1797 const int Iy = srcpp[0] - srcp[0];
1798 x2[0] = ( Ix * Ix ) >> 1;
1799 y2[0] = ( Iy * Iy ) >> 1;
1800 xy[0] = ( Ix * Iy ) >> 1;
1802 for( x = 1; x < width - 1; ++x )
1804 const int Ix = srcp[x+1] - srcp[x-1];
1805 const int Iy = srcpp[x] - srcp[x];
1806 x2[x] = ( Ix * Ix ) >> 1;
1807 y2[x] = ( Iy * Iy ) >> 1;
1808 xy[x] = ( Ix * Iy ) >> 1;
1811 const int Ix = srcp[x] - srcp[x-1];
1812 const int Iy = srcpp[x] - srcp[x];
1813 x2[x] = ( Ix * Ix ) >> 1;
1814 y2[x] = ( Iy * Iy ) >> 1;
1815 xy[x] = ( Ix * Iy ) >> 1;
1820 * Filters junctions and corners for the output image
1821 * @param x2 Pointer to the x/x derivatives
1822 * @param y2 Pointer to the y/y derivatives
1823 * @param xy Pointer to the x/y derivatives
1824 * @param pitch Stride of the source field plane from which the derivatives were calculated
1825 * @param mskp Pointer to the edge direction mask
1826 * @param msk_pitch Stride of mskp
1827 * @param dstp Pointer to the output image being filtered in place
1828 * @param dst_pitch Stride of dstp
1829 * @param height Height of the full-frame output plane
1830 * @param width Width of dstp bitmap rows, as opposed to the padded stride in dst_pitch
1831 * @param field Field to filter
1833 void eedi2_post_process_corner( int *x2, int *y2, int *xy, const int pitch, uint8_t * mskp, int msk_pitch, uint8_t * dstp, int dst_pitch, int height, int width, int field )
1835 mskp += ( 8 - field ) * msk_pitch;
1836 dstp += ( 8 - field ) * dst_pitch;
1837 unsigned char * dstpp = dstp - dst_pitch;
1838 unsigned char * dstpn = dstp + dst_pitch;
1842 int *x2n = x2 + pitch;
1843 int *y2n = y2 + pitch;
1844 int *xyn = xy + pitch;
1847 for( y = 8 - field; y < height - 7; y += 2 )
1849 for( x = 4; x < width - 4; ++x )
1851 if( mskp[x] == 255 || mskp[x] == 128 ) continue;
1852 const int c1 = (int)( x2[x] * y2[x] - xy[x] * xy[x] - 0.09 *
1853 ( x2[x] + y2[x] ) * ( x2[x] + y2[x] ) );
1854 const int c2 = (int)( x2n[x] * y2n[x] - xyn[x]* xyn[x] - 0.09 *
1855 ( x2n[x] + y2n[x] ) * ( x2n[x] + y2n[x] ) );
1856 if (c1 > 775 || c2 > 775)
1857 dstp[x] = ( dstpp[x] + dstpn[x] + 1 ) >> 1;
1859 mskp += msk_pitch * 2;
1860 dstpp += dst_pitch * 2;
1861 dstp += dst_pitch * 2;
1862 dstpn += dst_pitch * 2;