1 /* decomb.c
2 
3    Copyright (c) 2003-2021 HandBrake Team
4    This file is part of the HandBrake source code
5    Homepage: <http://handbrake.fr/>.
6    It may be used under the terms of the GNU General Public License v2.
7    For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 
9    The yadif algorithm was created by Michael Niedermayer.
10    Tritical's work inspired much of the comb detection code:
11    http://web.missouri.edu/~kes25c/
12 */
13 
14 /*****
15 Parameters:
16     Mode:
17         1 = yadif
18         2 = blend
19         4 = cubic interpolation
20         8 = EEDI2 interpolation
21        16 = Deinterlace each field to a separate frame
22        32 = Selectively deinterlace based on comb detection
23 
24 Appended for EEDI2:
25     Magnitude thresh : Variance thresh : Laplacian thresh : Dilation thresh :
26     Erosion thresh : Noise thresh : Max search distance : Post-processing
27 
28 Plus:
29     Parity
30 
31 Defaults:
32     7:10:20:20:4:2:50:24:1:-1
33 
34 *****/
35 
36 /*****
37 These modes can be layered. For example, Yadif (1) + EEDI2 (8) = 9,
38 which will feed EEDI2 interpolations to yadif.
39 
40 ** Working combos:
41  1: Just yadif
42  2: Just blend
43  3: Switch between yadif and blend
44  4: Just cubic interpolate
45  5: Cubic->yadif
46  6: Switch between cubic and blend
47  7: Switch between cubic->yadif and blend
48  8: Just EEDI2 interpolate
49  9: EEDI2->yadif
50 10: Switch between EEDI2 and blend
51 11: Switch between EEDI2->yadif and blend
52 ...okay I'm getting bored now listing all these different modes
53 
54 12-15: EEDI2 will override cubic interpolation
55 *****/
56 
57 #include "handbrake/handbrake.h"
58 #include "handbrake/hbffmpeg.h"
59 #include "handbrake/eedi2.h"
60 #include "handbrake/taskset.h"
61 #include "handbrake/decomb.h"
62 
63 #define PARITY_DEFAULT   -1
64 
65 #define MIN3(a,b,c) MIN(MIN(a,b),c)
66 #define MAX3(a,b,c) MAX(MAX(a,b),c)
67 
68 // Some names to correspond to the pv->eedi_half array's contents
69 #define SRCPF 0
70 #define MSKPF 1
71 #define TMPPF 2
72 #define DSTPF 3
73 // Some names to correspond to the pv->eedi_full array's contents
74 #define DST2PF 0
75 #define TMP2PF2 1
76 #define MSK2PF 2
77 #define TMP2PF 3
78 #define DST2MPF 4
79 
80 struct yadif_arguments_s {
81     hb_buffer_t *dst;
82     int parity;
83     int tff;
84     int mode;
85 };
86 
87 typedef struct yadif_arguments_s yadif_arguments_t;
88 
89 typedef struct eedi2_thread_arg_s {
90     hb_filter_private_t *pv;
91     int plane;
92 } eedi2_thread_arg_t;
93 
94 typedef struct yadif_thread_arg_s {
95     hb_filter_private_t *pv;
96     int segment;
97     int segment_start[3];
98     int segment_height[3];
99 } yadif_thread_arg_t;
100 
101 struct hb_filter_private_s
102 {
103     // Decomb parameters
104     int              mode;
105 
106     /* Make buffers to store a comb masks. */
107     hb_buffer_t    * mask;
108     hb_buffer_t    * mask_filtered;
109     hb_buffer_t    * mask_temp;
110     int              mask_box_x;
111     int              mask_box_y;
112     uint8_t          mask_box_color;
113 
114     // EEDI2 parameters
115     int                 magnitude_threshold;
116     int                 variance_threshold;
117     int                 laplacian_threshold;
118     int                 dilation_threshold;
119     int                 erosion_threshold;
120     int                 noise_threshold;
121     int                 maximum_search_distance;
122     int                 post_processing;
123 
124     // Deinterlace parameters
125     int                 parity;
126     int                 tff;
127 
128     int                 yadif_ready;
129 
130     int                 deinterlaced;
131     int                 blended;
132     int                 unfiltered;
133     int                 frames;
134 
135     hb_buffer_t       * ref[3];
136 
137     hb_buffer_t       * eedi_half[4];
138     hb_buffer_t       * eedi_full[5];
139     int               * cx2;
140     int               * cy2;
141     int               * cxy;
142     int               * tmpc;
143 
144     int                 cpu_count;
145     int                 segment_height[3];
146 
147     taskset_t           yadif_taskset;     // Threads for Yadif - one per CPU
148     yadif_arguments_t * yadif_arguments;   // Arguments to thread for work
149 
150     taskset_t           eedi2_taskset;     // Threads for eedi2 - one per plane
151 
152     hb_buffer_list_t    out_list;
153 
154     hb_filter_init_t    input;
155     hb_filter_init_t    output;
156 };
157 
158 typedef struct
159 {
160     int tap[5];
161     int normalize;
162 } filter_param_t;
163 
164 static int hb_decomb_init( hb_filter_object_t * filter,
165                            hb_filter_init_t * init );
166 
167 static int hb_decomb_work( hb_filter_object_t * filter,
168                            hb_buffer_t ** buf_in,
169                            hb_buffer_t ** buf_out );
170 
171 static void hb_decomb_close( hb_filter_object_t * filter );
172 
173 static const char decomb_template[] =
174     "mode=^"HB_INT_REG"$:"
175     "magnitude-thresh=^"HB_INT_REG"$:variance-thresh=^"HB_INT_REG"$:"
176     "laplacian-thresh=^"HB_INT_REG"$:dilation-thresh=^"HB_INT_REG"$:"
177     "erosion-thresh=^"HB_INT_REG"$:noise-thresh=^"HB_INT_REG"$:"
178     "search-distance=^"HB_INT_REG"$:postproc=^([0-3])$:parity=^([01])$";
179 
180 hb_filter_object_t hb_filter_decomb =
181 {
182     .id                = HB_FILTER_DECOMB,
183     .enforce_order     = 1,
184     .name              = "Decomb",
185     .settings          = NULL,
186     .init              = hb_decomb_init,
187     .work              = hb_decomb_work,
188     .close             = hb_decomb_close,
189     .settings_template = decomb_template,
190 };
191 
192 // Borrowed from libav
193 #define times4(x) x, x, x, x
194 #define times1024(x) times4(times4(times4(times4(times4(x)))))
195 
196 static const uint8_t hb_crop_table[256 + 2 * 1024] = {
197 times1024(0x00),
198 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
199 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
200 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
201 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
202 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
203 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
204 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
205 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
206 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
207 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
208 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
209 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
210 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
211 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
212 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
213 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
214 times1024(0xFF)
215 };
216 
cubic_interpolate_pixel(int y0,int y1,int y2,int y3)217 static inline int cubic_interpolate_pixel( int y0, int y1, int y2, int y3 )
218 {
219     /* From http://www.neuron2.net/library/cubicinterp.html */
220     int result = ( y0 * -3 ) + ( y1 * 23 ) + ( y2 * 23 ) + ( y3 * -3 );
221     result = hb_crop_table[(result / 40) + 1024];
222 
223     return result;
224 }
225 
cubic_interpolate_line(uint8_t * dst,uint8_t * cur,int width,int height,int stride,int y)226 static void cubic_interpolate_line(
227         uint8_t *dst,
228         uint8_t *cur,
229         int width,
230         int height,
231         int stride,
232         int y)
233 {
234     int w = width;
235     int x;
236 
237     for( x = 0; x < w; x++)
238     {
239         int a, b, c, d;
240         a = b = c = d = 0;
241 
242         if( y >= 3 )
243         {
244             /* Normal top*/
245             a = cur[-3*stride];
246             b = cur[-stride];
247         }
248         else if( y == 2 || y == 1 )
249         {
250             /* There's only one sample above this pixel, use it twice. */
251             a = cur[-stride];
252             b = cur[-stride];
253         }
254         else if( y == 0 )
255         {
256             /* No samples above, triple up on the one below. */
257             a = cur[+stride];
258             b = cur[+stride];
259         }
260 
261         if( y <= ( height - 4 ) )
262         {
263             /* Normal bottom*/
264             c = cur[+stride];
265             d = cur[3*stride];
266         }
267         else if( y == ( height - 3 ) || y == ( height - 2 ) )
268         {
269             /* There's only one sample below, use it twice. */
270             c = cur[+stride];
271             d = cur[+stride];
272         }
273         else if( y == height - 1)
274         {
275             /* No samples below, triple up on the one above. */
276             c = cur[-stride];
277             d = cur[-stride];
278         }
279 
280         dst[0] = cubic_interpolate_pixel( a, b, c, d );
281 
282         dst++;
283         cur++;
284     }
285 }
286 
store_ref(hb_filter_private_t * pv,hb_buffer_t * b)287 static void store_ref(hb_filter_private_t * pv, hb_buffer_t * b)
288 {
289     hb_buffer_close(&pv->ref[0]);
290     memmove(&pv->ref[0], &pv->ref[1], sizeof(hb_buffer_t *) * 2 );
291     pv->ref[2] = b;
292 }
293 
blend_filter_pixel(filter_param_t * filter,int up2,int up1,int current,int down1,int down2)294 static inline int blend_filter_pixel(filter_param_t *filter, int up2, int up1, int current, int down1, int down2)
295 {
296     /* Low-pass 5-tap filter */
297     int result = 0;
298 
299     result += up2 * filter->tap[0];
300     result += up1 * filter->tap[1];
301     result += current * filter->tap[2];
302     result += down1 * filter->tap[3];
303     result += down2 * filter->tap[4];
304     result >>= filter->normalize;
305 
306     result = hb_crop_table[result + 1024];
307     return result;
308 }
309 
blend_filter_line(filter_param_t * filter,uint8_t * dst,uint8_t * cur,int width,int height,int stride,int y)310 static void blend_filter_line(filter_param_t *filter,
311                                uint8_t *dst,
312                                uint8_t *cur,
313                                int width,
314                                int height,
315                                int stride,
316                                int y)
317 {
318     int w = width;
319     int x;
320     int up1, up2, down1, down2;
321 
322     if (y > 1 && y < (height - 2))
323     {
324         up1 = -1 * stride;
325         up2 = -2 * stride;
326         down1 = 1 * stride;
327         down2 = 2 * stride;
328     }
329     else if (y == 0)
330     {
331         /* First line, so A and B don't exist.*/
332         up1 = up2 = 0;
333         down1 = 1 * stride;
334         down2 = 2 * stride;
335     }
336     else if (y == 1)
337     {
338         /* Second line, no A. */
339         up1 = up2 = -1 * stride;
340         down1 = 1 * stride;
341         down2 = 2 * stride;
342     }
343     else if (y == (height - 2))
344     {
345         /* Second to last line, no E. */
346         up1 = -1 * stride;
347         up2 = -2 * stride;
348         down1 = down2 = 1 * stride;
349     }
350     else if (y == (height -1))
351     {
352         /* Last line, no D or E. */
353         up1 = -1 * stride;
354         up2 = -2 * stride;
355         down1 = down2 = 0;
356     }
357     else
358     {
359         hb_error("Invalid value y %d height %d", y, height);
360         return;
361     }
362 
363     for( x = 0; x < w; x++)
364     {
365         /* Low-pass 5-tap filter */
366         dst[0] = blend_filter_pixel(filter, cur[up2], cur[up1], cur[0],
367                                     cur[down1], cur[down2] );
368         dst++;
369         cur++;
370     }
371 }
372 
373 // This function calls all the eedi2 filters in sequence for a given plane.
374 // It outputs the final interpolated image to pv->eedi_full[DST2PF].
eedi2_interpolate_plane(hb_filter_private_t * pv,int plane)375 static void eedi2_interpolate_plane( hb_filter_private_t * pv, int plane )
376 {
377     /* We need all these pointers. No, seriously.
378        I swear. It's not a joke. They're used.
379        All nine of them.                         */
380     uint8_t * mskp = pv->eedi_half[MSKPF]->plane[plane].data;
381     uint8_t * srcp = pv->eedi_half[SRCPF]->plane[plane].data;
382     uint8_t * tmpp = pv->eedi_half[TMPPF]->plane[plane].data;
383     uint8_t * dstp = pv->eedi_half[DSTPF]->plane[plane].data;
384     uint8_t * dst2p = pv->eedi_full[DST2PF]->plane[plane].data;
385     uint8_t * tmp2p2 = pv->eedi_full[TMP2PF2]->plane[plane].data;
386     uint8_t * msk2p = pv->eedi_full[MSK2PF]->plane[plane].data;
387     uint8_t * tmp2p = pv->eedi_full[TMP2PF]->plane[plane].data;
388     uint8_t * dst2mp = pv->eedi_full[DST2MPF]->plane[plane].data;
389     int * cx2 = pv->cx2;
390     int * cy2 = pv->cy2;
391     int * cxy = pv->cxy;
392     int * tmpc = pv->tmpc;
393 
394     int pitch = pv->eedi_full[0]->plane[plane].stride;
395     int height = pv->eedi_full[0]->plane[plane].height;
396     int width = pv->eedi_full[0]->plane[plane].width;
397     int half_height = pv->eedi_half[0]->plane[plane].height;
398 
399     // edge mask
400     eedi2_build_edge_mask( mskp, pitch, srcp, pitch,
401                      pv->magnitude_threshold, pv->variance_threshold, pv->laplacian_threshold,
402                      half_height, width );
403     eedi2_erode_edge_mask( mskp, pitch, tmpp, pitch, pv->erosion_threshold, half_height, width );
404     eedi2_dilate_edge_mask( tmpp, pitch, mskp, pitch, pv->dilation_threshold, half_height, width );
405     eedi2_erode_edge_mask( mskp, pitch, tmpp, pitch, pv->erosion_threshold, half_height, width );
406     eedi2_remove_small_gaps( tmpp, pitch, mskp, pitch, half_height, width );
407 
408     // direction mask
409     eedi2_calc_directions( plane, mskp, pitch, srcp, pitch, tmpp, pitch,
410                      pv->maximum_search_distance, pv->noise_threshold,
411                      half_height, width );
412     eedi2_filter_dir_map( mskp, pitch, tmpp, pitch, dstp, pitch, half_height, width );
413     eedi2_expand_dir_map( mskp, pitch, dstp, pitch, tmpp, pitch, half_height, width );
414     eedi2_filter_map( mskp, pitch, tmpp, pitch, dstp, pitch, half_height, width );
415 
416     // upscale 2x vertically
417     eedi2_upscale_by_2( srcp, dst2p, half_height, pitch );
418     eedi2_upscale_by_2( dstp, tmp2p2, half_height, pitch );
419     eedi2_upscale_by_2( mskp, msk2p, half_height, pitch );
420 
421     // upscale the direction mask
422     eedi2_mark_directions_2x( msk2p, pitch, tmp2p2, pitch, tmp2p, pitch, pv->tff, height, width );
423     eedi2_filter_dir_map_2x( msk2p, pitch, tmp2p, pitch,  dst2mp, pitch, pv->tff, height, width );
424     eedi2_expand_dir_map_2x( msk2p, pitch, dst2mp, pitch, tmp2p, pitch, pv->tff, height, width );
425     eedi2_fill_gaps_2x( msk2p, pitch, tmp2p, pitch, dst2mp, pitch, pv->tff, height, width );
426     eedi2_fill_gaps_2x( msk2p, pitch, dst2mp, pitch, tmp2p, pitch, pv->tff, height, width );
427 
428     // interpolate a full-size plane
429     eedi2_interpolate_lattice( plane, tmp2p, pitch, dst2p, pitch, tmp2p2, pitch, pv->tff,
430                          pv->noise_threshold, height, width );
431 
432     if( pv->post_processing == 1 || pv->post_processing == 3 )
433     {
434         // make sure the edge directions are consistent
435         eedi2_bit_blit( tmp2p2, pitch, tmp2p, pitch, width, height );
436         eedi2_filter_dir_map_2x( msk2p, pitch, tmp2p, pitch, dst2mp, pitch, pv->tff, height, width );
437         eedi2_expand_dir_map_2x( msk2p, pitch, dst2mp, pitch, tmp2p, pitch, pv->tff, height, width );
438         eedi2_post_process( tmp2p, pitch, tmp2p2, pitch, dst2p, pitch, pv->tff, height, width );
439     }
440     if( pv->post_processing == 2 || pv->post_processing == 3 )
441     {
442         // filter junctions and corners
443         eedi2_gaussian_blur1( srcp, pitch, tmpp, pitch, srcp, pitch, half_height, width );
444         eedi2_calc_derivatives( srcp, pitch, half_height, width, cx2, cy2, cxy );
445         eedi2_gaussian_blur_sqrt2( cx2, tmpc, cx2, pitch, half_height, width);
446         eedi2_gaussian_blur_sqrt2( cy2, tmpc, cy2, pitch, half_height, width);
447         eedi2_gaussian_blur_sqrt2( cxy, tmpc, cxy, pitch, half_height, width);
448         eedi2_post_process_corner( cx2, cy2, cxy, pitch, tmp2p2, pitch, dst2p, pitch, height, width, pv->tff );
449     }
450 }
451 
452 /*
453  *  eedi2 interpolate this plane in a single thread.
454  */
eedi2_filter_thread(void * thread_args_v)455 static void eedi2_filter_thread( void *thread_args_v )
456 {
457     hb_filter_private_t * pv;
458     int plane;
459     eedi2_thread_arg_t *thread_args = thread_args_v;
460 
461     pv = thread_args->pv;
462     plane = thread_args->plane;
463 
464     hb_deep_log(3, "eedi2 thread started for plane %d", plane);
465 
466     while (1)
467     {
468         /*
469          * Wait here until there is work to do.
470          */
471         taskset_thread_wait4start( &pv->eedi2_taskset, plane );
472 
473         if( taskset_thread_stop( &pv->eedi2_taskset, plane ) )
474         {
475             /*
476              * No more work to do, exit this thread.
477              */
478             break;
479         }
480 
481         /*
482          * Process plane
483          */
484         eedi2_interpolate_plane( pv, plane );
485 
486         /*
487          * Finished this segment, let everyone know.
488          */
489         taskset_thread_complete( &pv->eedi2_taskset, plane );
490     }
491 
492     taskset_thread_complete( &pv->eedi2_taskset, plane );
493 }
494 
495 // Sets up the input field planes for EEDI2 in pv->eedi_half[SRCPF]
496 // and then runs eedi2_filter_thread for each plane.
eedi2_planer(hb_filter_private_t * pv)497 static void eedi2_planer( hb_filter_private_t * pv )
498 {
499     /* Copy the first field from the source to a half-height frame. */
500     int pp;
501     for( pp = 0;  pp < 3; pp++ )
502     {
503         int pitch = pv->ref[1]->plane[pp].stride;
504         int height = pv->ref[1]->plane[pp].height;
505         int start_line = !pv->tff;
506 
507         eedi2_fill_half_height_buffer_plane(
508                 &pv->ref[1]->plane[pp].data[pitch * start_line],
509                 pv->eedi_half[SRCPF]->plane[pp].data, pitch, height );
510     }
511 
512     /*
513      * Now that all data is ready for our threads, fire them off
514      * and wait for their completion.
515      */
516     taskset_cycle( &pv->eedi2_taskset );
517 }
518 
519 /* EDDI: Edge Directed Deinterlacing Interpolation
520    Checks 4 different slopes to see if there is more similarity along a diagonal
521    than there was vertically. If a diagonal is more similar, then it indicates
522    an edge, so interpolate along that instead of a vertical line, using either
523    linear or cubic interpolation depending on mode. */
524 #define YADIF_CHECK(j) {\
525         int score = ABS(cur[-stride-1+j] - cur[+stride-1-j])\
526                       + ABS(cur[-stride  +j] - cur[+stride  -j])\
527                       + ABS(cur[-stride+1+j] - cur[+stride+1-j]);\
528         if( score < spatial_score ){\
529             spatial_score = score;\
530             if( ( pv->mode & MODE_DECOMB_CUBIC ) && !vertical_edge )\
531             {\
532                 switch(j)\
533                 {\
534                     case -1:\
535                         spatial_pred = cubic_interpolate_pixel(cur[-3 * stride - 3], cur[-stride -1], cur[+stride + 1], cur[3* stride + 3] );\
536                     break;\
537                     case -2:\
538                         spatial_pred = cubic_interpolate_pixel( ( ( cur[-3*stride - 4] + cur[-stride - 4] ) / 2 ) , cur[-stride -2], cur[+stride + 2], ( ( cur[3*stride + 4] + cur[stride + 4] ) / 2 ) );\
539                     break;\
540                     case 1:\
541                         spatial_pred = cubic_interpolate_pixel(cur[-3 * stride +3], cur[-stride +1], cur[+stride - 1], cur[3* stride -3] );\
542                     break;\
543                     case 2:\
544                         spatial_pred = cubic_interpolate_pixel(( ( cur[-3*stride + 4] + cur[-stride + 4] ) / 2 ), cur[-stride +2], cur[+stride - 2], ( ( cur[3*stride - 4] + cur[stride - 4] ) / 2 ) );\
545                     break;\
546                 }\
547             }\
548             else\
549             {\
550                 spatial_pred = ( cur[-stride +j] + cur[+stride -j] ) >>1;\
551             }\
552 
yadif_filter_line(hb_filter_private_t * pv,uint8_t * dst,uint8_t * prev,uint8_t * cur,uint8_t * next,int plane,int width,int height,int stride,int parity,int y)553 static void yadif_filter_line(
554        hb_filter_private_t * pv,
555        uint8_t             * dst,
556        uint8_t             * prev,
557        uint8_t             * cur,
558        uint8_t             * next,
559        int                   plane,
560        int                   width,
561        int                   height,
562        int                   stride,
563        int                   parity,
564        int                   y)
565 {
566     /* While prev and next point to the previous and next frames,
567        prev2 and next2 will shift depending on the parity, usually 1.
568        They are the previous and next fields, the fields temporally adjacent
569        to the other field in the current frame--the one not being filtered.  */
570     uint8_t *prev2 = parity ? prev : cur ;
571     uint8_t *next2 = parity ? cur  : next;
572 
573     int x;
574     int eedi2_mode = ( pv->mode & MODE_DECOMB_EEDI2 );
575 
576     /* We can replace spatial_pred with this interpolation*/
577     uint8_t * eedi2_guess = NULL;
578     if (eedi2_mode)
579     {
580         eedi2_guess = &pv->eedi_full[DST2PF]->plane[plane].data[y*stride];
581     }
582 
583     /* Decomb's cubic interpolation can only function when there are
584        three samples above and below, so regress to yadif's traditional
585        two-tap interpolation when filtering at the top and bottom edges. */
586     int vertical_edge = 0;
587     if( ( y < 3 ) || ( y > ( height - 4 ) )  )
588         vertical_edge = 1;
589 
590     for( x = 0; x < width; x++)
591     {
592         /* Pixel above*/
593         int c              = cur[-stride];
594         /* Temporal average: the current location in the adjacent fields */
595         int d              = (prev2[0] + next2[0])>>1;
596         /* Pixel below */
597         int e              = cur[+stride];
598 
599         /* How the current pixel changes between the adjacent fields */
600         int temporal_diff0 = ABS(prev2[0] - next2[0]);
601         /* The average of how much the pixels above and below change from the frame before to now. */
602         int temporal_diff1 = ( ABS(prev[-stride] - cur[-stride]) + ABS(prev[+stride] - cur[+stride]) ) >> 1;
603         /* The average of how much the pixels above and below change from now to the next frame. */
604         int temporal_diff2 = ( ABS(next[-stride] - cur[-stride]) + ABS(next[+stride] - cur[+stride]) ) >> 1;
605         /* For the actual difference, use the largest of the previous average diffs. */
606         int diff           = MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);
607 
608         int spatial_pred;
609 
610         if( eedi2_mode )
611         {
612             /* Who needs yadif's spatial predictions when we can have EEDI2's? */
613             spatial_pred = eedi2_guess[0];
614             eedi2_guess++;
615         }
616         else // Yadif spatial interpolation
617         {
618             /* SAD of how the pixel-1, the pixel, and the pixel+1 change from the line above to below. */
619             int spatial_score  = ABS(cur[-stride-1] - cur[+stride-1]) + ABS(cur[-stride]-cur[+stride]) +
620                                          ABS(cur[-stride+1] - cur[+stride+1]) - 1;
621 
622             /* Spatial pred is either a bilinear or cubic vertical interpolation. */
623             if( ( pv->mode & MODE_DECOMB_CUBIC ) && !vertical_edge)
624             {
625                 spatial_pred = cubic_interpolate_pixel( cur[-3*stride], cur[-stride], cur[+stride], cur[3*stride] );
626             }
627             else
628             {
629                 spatial_pred = (c+e)>>1;
630             }
631 
632             // YADIF_CHECK requires a margin to avoid invalid memory access.
633             // In MODE_DECOMB_CUBIC, margin needed is 2 + ABS(param).
634             // Else, the margin needed is 1 + ABS(param).
635             int margin = 2;
636             if (pv->mode & MODE_DECOMB_CUBIC)
637                 margin = 3;
638 
639             if (x >= margin && x <= width - (margin + 1))
640             {
641                 YADIF_CHECK(-1)
642                 if (x >= margin + 1 && x <= width - (margin + 2))
643                     YADIF_CHECK(-2) }} }}
644             }
645             if (x >= margin && x <= width - (margin + 1))
646             {
647                 YADIF_CHECK(1)
648                 if (x >= margin + 1 && x <= width - (margin + 2))
649                     YADIF_CHECK(2) }} }}
650             }
651         }
652 
653         /* Temporally adjust the spatial prediction by
654            comparing against lines in the adjacent fields. */
655         int b = (prev2[-2*stride] + next2[-2*stride])>>1;
656         int f = (prev2[+2*stride] + next2[+2*stride])>>1;
657 
658         /* Find the median value */
659         int max = MAX3(d-e, d-c, MIN(b-c, f-e));
660         int min = MIN3(d-e, d-c, MAX(b-c, f-e));
661         diff = MAX3( diff, min, -max );
662 
663         if( spatial_pred > d + diff )
664         {
665             spatial_pred = d + diff;
666         }
667         else if( spatial_pred < d - diff )
668         {
669             spatial_pred = d - diff;
670         }
671 
672         dst[0] = spatial_pred;
673 
674         dst++;
675         cur++;
676         prev++;
677         next++;
678         prev2++;
679         next2++;
680     }
681 }
682 
683 /*
684  * deinterlace this segment of all three planes in a single thread.
685  */
686 static void yadif_decomb_filter_thread( void *thread_args_v )
687 {
688     yadif_arguments_t *yadif_work = NULL;
689     hb_filter_private_t * pv;
690     int segment, segment_start, segment_stop;
691     yadif_thread_arg_t *thread_args = thread_args_v;
692     filter_param_t filter;
693 
694     filter.tap[0] = -1;
695     filter.tap[1] = 2;
696     filter.tap[2] = 6;
697     filter.tap[3] = 2;
698     filter.tap[4] = -1;
699     filter.normalize = 3;
700 
701     pv = thread_args->pv;
702     segment = thread_args->segment;
703 
704     hb_deep_log(3, "yadif thread started for segment %d", segment);
705 
706     while (1)
707     {
708         /*
709          * Wait here until there is work to do.
710          */
711         taskset_thread_wait4start( &pv->yadif_taskset, segment );
712 
713         if( taskset_thread_stop( &pv->yadif_taskset, segment ) )
714         {
715             /*
716              * No more work to do, exit this thread.
717              */
718             break;
719         }
720 
721         yadif_work = &pv->yadif_arguments[segment];
722 
723         /*
724          * Process all three planes, but only this segment of it.
725          */
726         hb_buffer_t *dst;
727         int parity, tff, mode;
728 
729         mode = pv->yadif_arguments[segment].mode;
730         dst = yadif_work->dst;
731         tff = yadif_work->tff;
732         parity = yadif_work->parity;
733 
734         int pp;
735         for (pp = 0; pp < 3; pp++)
736         {
737             int yy;
738             int width = dst->plane[pp].width;
739             int stride = dst->plane[pp].stride;
740             int height = dst->plane[pp].height_stride;
741             int penultimate = height - 2;
742 
743             segment_start = thread_args->segment_start[pp];
744             segment_stop = segment_start + thread_args->segment_height[pp];
745 
746             // Filter parity lines
747             int start = parity ? (segment_start + 1) & ~1 : segment_start | 1;
748             uint8_t *dst2 = &dst->plane[pp].data[start * stride];
749             uint8_t *prev = &pv->ref[0]->plane[pp].data[start * stride];
750             uint8_t *cur  = &pv->ref[1]->plane[pp].data[start * stride];
751             uint8_t *next = &pv->ref[2]->plane[pp].data[start * stride];
752 
753             if (mode == MODE_DECOMB_BLEND)
754             {
755                 /* These will be useful if we ever do temporal blending. */
756                 for( yy = start; yy < segment_stop; yy += 2 )
757                 {
758                     /* This line gets blend filtered, not yadif filtered. */
759                     blend_filter_line(&filter, dst2, cur, width, height, stride, yy);
760                     dst2 += stride * 2;
761                     cur += stride * 2;
762                 }
763             }
764             else if (mode == MODE_DECOMB_CUBIC)
765             {
766                 for( yy = start; yy < segment_stop; yy += 2 )
767                 {
768                     /* Just apply vertical cubic interpolation */
769                     cubic_interpolate_line(dst2, cur, width, height, stride, yy);
770                     dst2 += stride * 2;
771                     cur += stride * 2;
772                 }
773             }
774             else if (mode & MODE_DECOMB_YADIF)
775             {
776                 for( yy = start; yy < segment_stop; yy += 2 )
777                 {
778                     if( yy > 1 && yy < penultimate )
779                     {
780                         // This isn't the top or bottom,
781                         // proceed as normal to yadif
782                         yadif_filter_line(pv, dst2, prev, cur, next, pp,
783                                           width, height, stride,
784                                           parity ^ tff, yy);
785                     }
786                     else
787                     {
788                         // parity == 0 (TFF), y1 = y0
789                         // parity == 1 (BFF), y0 = y1
790                         // parity == 0 (TFF), yu = yp
791                         // parity == 1 (BFF), yp = yu
792                         int yp = (yy ^ parity) * stride;
793                         memcpy(dst2, &pv->ref[1]->plane[pp].data[yp], width);
794                     }
795                     dst2 += stride * 2;
796                     prev += stride * 2;
797                     cur += stride * 2;
798                     next += stride * 2;
799                 }
800             }
801             else
802             {
803                 // No combing, copy frame
804                 for( yy = start; yy < segment_stop; yy += 2 )
805                 {
806                     memcpy(dst2, cur, width);
807                     dst2 += stride * 2;
808                     cur += stride * 2;
809                 }
810             }
811 
812             // Copy unfiltered lines
813             start = !parity ? (segment_start + 1) & ~1 : segment_start | 1;
814             dst2 = &dst->plane[pp].data[start * stride];
815             prev = &pv->ref[0]->plane[pp].data[start * stride];
816             cur  = &pv->ref[1]->plane[pp].data[start * stride];
817             next = &pv->ref[2]->plane[pp].data[start * stride];
818             for( yy = start; yy < segment_stop; yy += 2 )
819             {
820                 memcpy(dst2, cur, width);
821                 dst2 += stride * 2;
822                 cur += stride * 2;
823             }
824         }
825         taskset_thread_complete( &pv->yadif_taskset, segment );
826     }
827 
828     /*
829      * Finished this segment, let everyone know.
830      */
831     taskset_thread_complete( &pv->yadif_taskset, segment );
832 }
833 
834 static void yadif_filter( hb_filter_private_t * pv,
835                           hb_buffer_t * dst,
836                           int parity,
837                           int tff)
838 {
839     /* If we're running comb detection, do it now, otherwise default to true. */
840     int is_combed = HB_COMB_HEAVY;
841     int mode = 0;
842 
843     if (pv->mode & MODE_DECOMB_SELECTIVE)
844     {
845         is_combed = pv->ref[1]->s.combed;
846     }
847 
848     // Pick a mode based on the comb detect state and selected decomb modes
849     if ((pv->mode & MODE_DECOMB_BLEND) && is_combed == HB_COMB_LIGHT )
850     {
851         mode = MODE_DECOMB_BLEND;
852     }
853     else if (is_combed != HB_COMB_NONE)
854     {
855         mode = pv->mode & ~MODE_DECOMB_SELECTIVE;
856     }
857 
858     if (mode == MODE_DECOMB_BLEND)
859     {
860         pv->blended++;
861     }
862     else if (mode != 0)
863     {
864         pv->deinterlaced++;
865     }
866     else
867     {
868         pv->unfiltered++;
869     }
870     pv->frames++;
871 
872     if (mode & MODE_DECOMB_EEDI2)
873     {
874         /* Generate an EEDI2 interpolation */
875         eedi2_planer( pv );
876     }
877 
878     if (mode != 0)
879     {
880         if ((mode & MODE_DECOMB_EEDI2 ) && !(mode & MODE_DECOMB_YADIF))
881         {
882             // Just pass through the EEDI2 interpolation
883             int pp;
884             for( pp = 0; pp < 3; pp++ )
885             {
886                 uint8_t * ref = pv->eedi_full[DST2PF]->plane[pp].data;
887                 int ref_stride = pv->eedi_full[DST2PF]->plane[pp].stride;
888 
889                 uint8_t * dest = dst->plane[pp].data;
890                 int width = dst->plane[pp].width;
891                 int height = dst->plane[pp].height;
892                 int stride = dst->plane[pp].stride;
893 
894                 int yy;
895                 for( yy = 0; yy < height; yy++ )
896                 {
897                     memcpy(dest, ref, width);
898                     dest += stride;
899                     ref += ref_stride;
900                 }
901             }
902         }
903         else
904         {
905             int segment;
906 
907             for( segment = 0; segment < pv->cpu_count; segment++ )
908             {
909                 /*
910                  * Setup the work for this plane.
911                  */
912                 pv->yadif_arguments[segment].parity = parity;
913                 pv->yadif_arguments[segment].tff = tff;
914                 pv->yadif_arguments[segment].dst = dst;
915                 pv->yadif_arguments[segment].mode = mode;
916             }
917 
918             /*
919              * Allow the taskset threads to make one pass over the data.
920              */
921             taskset_cycle( &pv->yadif_taskset );
922 
923             /*
924              * Entire frame is now deinterlaced.
925              */
926         }
927     }
928     else
929     {
930         /*  Just passing through... */
931         pv->yadif_arguments[0].mode = mode; // 0
932         hb_buffer_copy(dst, pv->ref[1]);
933     }
934 }
935 
936 static int hb_decomb_init( hb_filter_object_t * filter,
937                            hb_filter_init_t * init )
938 {
939     filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
940     hb_filter_private_t * pv = filter->private_data;
941     pv->input                = *init;
942     hb_buffer_list_clear(&pv->out_list);
943 
944     pv->deinterlaced = 0;
945     pv->blended      = 0;
946     pv->unfiltered   = 0;
947     pv->frames       = 0;
948     pv->yadif_ready  = 0;
949 
950     pv->mode                    = MODE_DECOMB_YADIF | MODE_DECOMB_BLEND |
951                                   MODE_DECOMB_CUBIC;
952     pv->magnitude_threshold     = 10;
953     pv->variance_threshold      = 20;
954     pv->laplacian_threshold     = 20;
955     pv->dilation_threshold      = 4;
956     pv->erosion_threshold       = 2;
957     pv->noise_threshold         = 50;
958     pv->maximum_search_distance = 24;
959     pv->post_processing         = 1;
960     pv->parity                  = PARITY_DEFAULT;
961 
962     if (filter->settings)
963     {
964         hb_value_t * dict = filter->settings;
965 
966         // Get comb detection settings
967         hb_dict_extract_int(&pv->mode, dict, "mode");
968 
969         // Get deinterlace settings
970         hb_dict_extract_int(&pv->parity, dict, "parity");
971         if (pv->mode & MODE_DECOMB_EEDI2)
972         {
973             hb_dict_extract_int(&pv->magnitude_threshold, dict,
974                                 "magnitude-thresh");
975             hb_dict_extract_int(&pv->variance_threshold, dict,
976                                 "variance-thresh");
977             hb_dict_extract_int(&pv->laplacian_threshold, dict,
978                                 "laplacian-thresh");
979             hb_dict_extract_int(&pv->dilation_threshold, dict,
980                                 "dilation-thresh");
981             hb_dict_extract_int(&pv->erosion_threshold, dict,
982                                 "erosion-thresh");
983             hb_dict_extract_int(&pv->noise_threshold, dict,
984                                 "noise-thresh");
985             hb_dict_extract_int(&pv->maximum_search_distance, dict,
986                                 "search-distance");
987             hb_dict_extract_int(&pv->post_processing, dict,
988                                 "postproc");
989         }
990     }
991 
992     pv->cpu_count = hb_get_cpu_count();
993 
994     // Make segment sizes an even number of lines
995     int height = hb_image_height(init->pix_fmt, init->geometry.height, 0);
996     // Each segment must begin on the even "parity" row.
997     // I.e. each segment of each plane must begin on an even row.
998     pv->segment_height[0] = (height / pv->cpu_count) & ~3;
999     pv->segment_height[1] = hb_image_height(init->pix_fmt, pv->segment_height[0], 1);
1000     pv->segment_height[2] = hb_image_height(init->pix_fmt, pv->segment_height[0], 2);
1001 
1002     int ii;
1003     if( pv->mode & MODE_DECOMB_EEDI2 )
1004     {
1005         /* Allocate half-height eedi2 buffers */
1006         for( ii = 0; ii < 4; ii++ )
1007         {
1008             pv->eedi_half[ii] = hb_frame_buffer_init(
1009                 init->pix_fmt, init->geometry.width, init->geometry.height / 2);
1010         }
1011 
1012         /* Allocate full-height eedi2 buffers */
1013         for( ii = 0; ii < 5; ii++ )
1014         {
1015             pv->eedi_full[ii] = hb_frame_buffer_init(
1016                 init->pix_fmt, init->geometry.width, init->geometry.height);
1017         }
1018     }
1019 
1020     /*
1021      * Setup yadif taskset.
1022      */
1023     pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->cpu_count );
1024     if( pv->yadif_arguments == NULL ||
1025         taskset_init( &pv->yadif_taskset, pv->cpu_count,
1026                       sizeof( yadif_thread_arg_t ) ) == 0 )
1027     {
1028         hb_error( "yadif could not initialize taskset" );
1029     }
1030 
1031     yadif_thread_arg_t *yadif_prev_thread_args = NULL;
1032     for( ii = 0; ii < pv->cpu_count; ii++ )
1033     {
1034         yadif_thread_arg_t *thread_args;
1035 
1036         thread_args = taskset_thread_args( &pv->yadif_taskset, ii );
1037         thread_args->pv = pv;
1038         thread_args->segment = ii;
1039 
1040         int pp;
1041         for (pp = 0; pp < 3; pp++)
1042         {
1043             if (yadif_prev_thread_args != NULL)
1044             {
1045                 thread_args->segment_start[pp] =
1046                     yadif_prev_thread_args->segment_start[pp] +
1047                     yadif_prev_thread_args->segment_height[pp];
1048             }
1049             if( ii == pv->cpu_count - 1 )
1050             {
1051                 /*
1052                  * Final segment
1053                  */
1054                 thread_args->segment_height[pp] =
1055                     ((hb_image_height(init->pix_fmt, init->geometry.height, pp)
1056                      + 3) & ~3) - thread_args->segment_start[pp];
1057             } else {
1058                 thread_args->segment_height[pp] = pv->segment_height[pp];
1059             }
1060         }
1061         pv->yadif_arguments[ii].dst = NULL;
1062         if( taskset_thread_spawn( &pv->yadif_taskset, ii,
1063                                  "yadif_filter_segment",
1064                                  yadif_decomb_filter_thread,
1065                                  HB_NORMAL_PRIORITY ) == 0 )
1066         {
1067             hb_error( "yadif could not spawn thread" );
1068         }
1069         yadif_prev_thread_args = thread_args;
1070     }
1071 
1072     if( pv->mode & MODE_DECOMB_EEDI2 )
1073     {
1074         /*
1075          * Create eedi2 taskset.
1076          */
1077         if( taskset_init( &pv->eedi2_taskset, /*thread_count*/3,
1078                           sizeof( eedi2_thread_arg_t ) ) == 0 )
1079         {
1080             hb_error( "eedi2 could not initialize taskset" );
1081         }
1082 
1083         if( pv->post_processing > 1 )
1084         {
1085             int stride;
1086             stride = hb_image_stride(init->pix_fmt, init->geometry.width, 0);
1087 
1088             pv->cx2 = (int*)eedi2_aligned_malloc(
1089                     init->geometry.height * stride * sizeof(int), 16);
1090 
1091             pv->cy2 = (int*)eedi2_aligned_malloc(
1092                     init->geometry.height * stride * sizeof(int), 16);
1093 
1094             pv->cxy = (int*)eedi2_aligned_malloc(
1095                     init->geometry.height * stride * sizeof(int), 16);
1096 
1097             pv->tmpc = (int*)eedi2_aligned_malloc(
1098                     init->geometry.height * stride * sizeof(int), 16);
1099 
1100             if( !pv->cx2 || !pv->cy2 || !pv->cxy || !pv->tmpc )
1101                 hb_error("EEDI2: failed to malloc derivative arrays");
1102             else
1103                 hb_log("EEDI2: successfully malloced derivative arrays");
1104         }
1105 
1106         for( ii = 0; ii < 3; ii++ )
1107         {
1108             eedi2_thread_arg_t *eedi2_thread_args;
1109 
1110             eedi2_thread_args = taskset_thread_args( &pv->eedi2_taskset, ii );
1111 
1112             eedi2_thread_args->pv = pv;
1113             eedi2_thread_args->plane = ii;
1114 
1115             if( taskset_thread_spawn( &pv->eedi2_taskset, ii,
1116                                       "eedi2_filter_segment",
1117                                       eedi2_filter_thread,
1118                                       HB_NORMAL_PRIORITY ) == 0 )
1119             {
1120                 hb_error( "eedi2 could not spawn thread" );
1121             }
1122         }
1123     }
1124 
1125     pv->output = *init;
1126     init->job->use_decomb = 1;
1127 
1128     return 0;
1129 }
1130 
1131 static void hb_decomb_close( hb_filter_object_t * filter )
1132 {
1133     hb_filter_private_t * pv = filter->private_data;
1134 
1135     if( !pv )
1136     {
1137         return;
1138     }
1139 
1140     hb_log("decomb: deinterlaced %i | blended %i | unfiltered %i | total %i",
1141            pv->deinterlaced, pv->blended, pv->unfiltered, pv->frames);
1142 
1143     taskset_fini( &pv->yadif_taskset );
1144 
1145     if( pv->mode & MODE_DECOMB_EEDI2 )
1146     {
1147         taskset_fini( &pv->eedi2_taskset );
1148     }
1149 
1150     /* Cleanup reference buffers. */
1151     int ii;
1152     for (ii = 0; ii < 3; ii++)
1153     {
1154         hb_buffer_close(&pv->ref[ii]);
1155     }
1156 
1157     if( pv->mode & MODE_DECOMB_EEDI2 )
1158     {
1159         /* Cleanup eedi-half  buffers */
1160         int ii;
1161         for( ii = 0; ii < 4; ii++ )
1162         {
1163             hb_buffer_close(&pv->eedi_half[ii]);
1164         }
1165 
1166         /* Cleanup eedi-full  buffers */
1167         for( ii = 0; ii < 5; ii++ )
1168         {
1169             hb_buffer_close(&pv->eedi_full[ii]);
1170         }
1171     }
1172 
1173     if( pv->post_processing > 1  && ( pv->mode & MODE_DECOMB_EEDI2 ) )
1174     {
1175         if (pv->cx2) eedi2_aligned_free(pv->cx2);
1176         if (pv->cy2) eedi2_aligned_free(pv->cy2);
1177         if (pv->cxy) eedi2_aligned_free(pv->cxy);
1178         if (pv->tmpc) eedi2_aligned_free(pv->tmpc);
1179     }
1180 
1181     /*
1182      * free memory for yadif structs
1183      */
1184     free( pv->yadif_arguments );
1185 
1186     free( pv );
1187     filter->private_data = NULL;
1188 }
1189 
1190 // Fill rows above height with copy of last row to prevent color distortion
1191 // during blending
1192 static void fill_stride(hb_buffer_t * buf)
1193 {
1194     int pp, ii;
1195 
1196     for (pp = 0; pp < 3; pp++)
1197     {
1198         uint8_t * src, * dst;
1199 
1200         src = buf->plane[pp].data + (buf->plane[pp].height - 1) *
1201               buf->plane[pp].stride;
1202         dst = buf->plane[pp].data + buf->plane[pp].height *
1203               buf->plane[pp].stride;
1204         for (ii = 0; ii < 3; ii++)
1205         {
1206             memcpy(dst, src, buf->plane[pp].stride);
1207             dst += buf->plane[pp].stride;
1208         }
1209     }
1210 }
1211 
1212 static void process_frame( hb_filter_private_t * pv )
1213 {
1214     if ((pv->mode & MODE_DECOMB_SELECTIVE) &&
1215         pv->ref[1]->s.combed == HB_COMB_NONE)
1216     {
1217         // Input buffer is not combed.  Just make a dup of it.
1218         hb_buffer_t * buf = hb_buffer_dup(pv->ref[1]);
1219         hb_buffer_list_append(&pv->out_list, buf);
1220         pv->frames++;
1221         pv->unfiltered++;
1222     }
1223     else
1224     {
1225         /* Determine if top-field first layout */
1226         int tff;
1227         if (pv->parity < 0)
1228         {
1229             tff = !!(pv->ref[1]->s.flags & PIC_FLAG_TOP_FIELD_FIRST);
1230         }
1231         else
1232         {
1233             tff = (pv->parity & 1) ^ 1;
1234         }
1235 
1236         /* deinterlace both fields if bob */
1237         int frame, num_frames = 1;
1238         if (pv->mode & MODE_DECOMB_BOB)
1239         {
1240             num_frames = 2;
1241         }
1242 
1243         // Will need up to 2 buffers simultaneously
1244 
1245         /* Perform yadif filtering */
1246         for (frame = 0; frame < num_frames; frame++)
1247         {
1248             hb_buffer_t * buf;
1249             int parity = frame ^ tff ^ 1;
1250 
1251             // tff for eedi2
1252             pv->tff = !parity;
1253 
1254             buf = hb_frame_buffer_init(pv->ref[1]->f.fmt,
1255                                        pv->ref[1]->f.width,
1256                                        pv->ref[1]->f.height);
1257             buf->f.color_prim     = pv->output.color_prim;
1258             buf->f.color_transfer = pv->output.color_transfer;
1259             buf->f.color_matrix   = pv->output.color_matrix;
1260             buf->f.color_range    = pv->output.color_range ;
1261             yadif_filter(pv, buf, parity, tff);
1262 
1263             /* Copy buffered settings to output buffer settings */
1264             buf->s = pv->ref[1]->s;
1265 
1266             hb_buffer_list_append(&pv->out_list, buf);
1267         }
1268 
1269         /* if this frame was deinterlaced and bob mode is engaged, halve
1270            the duration of the saved timestamps. */
1271         if (pv->mode & MODE_DECOMB_BOB)
1272         {
1273             hb_buffer_t *first  = hb_buffer_list_head(&pv->out_list);
1274             hb_buffer_t *second = hb_buffer_list_tail(&pv->out_list);
1275             first->s.stop -= (first->s.stop - first->s.start) / 2LL;
1276             second->s.start = first->s.stop;
1277             second->s.new_chap = 0;
1278         }
1279     }
1280 }
1281 
1282 static int hb_decomb_work( hb_filter_object_t * filter,
1283                            hb_buffer_t ** buf_in,
1284                            hb_buffer_t ** buf_out )
1285 {
1286     hb_filter_private_t * pv = filter->private_data;
1287     hb_buffer_t * in = *buf_in;
1288 
1289     // Input buffer is always consumed.
1290     *buf_in = NULL;
1291     if (in->s.flags & HB_BUF_FLAG_EOF)
1292     {
1293         if (pv->ref[2] != NULL)
1294         {
1295             // Duplicate last frame and process refs
1296             store_ref(pv, hb_buffer_dup(pv->ref[2]));
1297             process_frame(pv);
1298         }
1299         hb_buffer_list_append(&pv->out_list, in);
1300         *buf_out = hb_buffer_list_clear(&pv->out_list);
1301         return HB_FILTER_DONE;
1302     }
1303 
1304     fill_stride(in);
1305 
1306     // yadif requires 3 buffers, prev, cur, and next.  For the first
1307     // frame, there can be no prev, so we duplicate the first frame.
1308     if (!pv->yadif_ready)
1309     {
1310         // If yadif is not ready, store another ref and return HB_FILTER_DELAY
1311         store_ref(pv, hb_buffer_dup(in));
1312         store_ref(pv, in);
1313         pv->yadif_ready = 1;
1314         // Wait for next
1315         return HB_FILTER_DELAY;
1316     }
1317 
1318     store_ref(pv, in);
1319     process_frame(pv);
1320 
1321     *buf_out = hb_buffer_list_clear(&pv->out_list);
1322     return HB_FILTER_OK;
1323 }
1324 
1325 void hb_deinterlace(hb_buffer_t *dst, hb_buffer_t *src)
1326 {
1327     int pp;
1328     filter_param_t filter;
1329 
1330     filter.tap[0] = -1;
1331     filter.tap[1] = 4;
1332     filter.tap[2] = 2;
1333     filter.tap[3] = 4;
1334     filter.tap[4] = -1;
1335     filter.normalize = 3;
1336 
1337     fill_stride(src);
1338     for (pp = 0; pp < 3; pp++)
1339     {
1340         int yy;
1341         int width  = src->plane[pp].width;
1342         int stride = src->plane[pp].stride;
1343         int height = src->plane[pp].height_stride;
1344 
1345         // Filter parity lines
1346         uint8_t *pdst = &dst->plane[pp].data[0];
1347         uint8_t *psrc = &src->plane[pp].data[0];
1348 
1349         /* These will be useful if we ever do temporal blending. */
1350         for( yy = 0; yy < height - 1; yy += 2 )
1351         {
1352             /* This line gets blend filtered, not yadif filtered. */
1353             memcpy(pdst, psrc, width);
1354             pdst += stride;
1355             psrc += stride;
1356             blend_filter_line(&filter, pdst, psrc, width, height, stride, yy + 1);
1357             pdst += stride;
1358             psrc += stride;
1359         }
1360     }
1361 }
1362 
1363