2 * Copyright (C) 2001 the xine project
4 * This file is part of xine, a free video player.
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 * Deinterlace routines by Miguel Freitas
21 * based of DScaler project sources (deinterlace.sourceforge.net)
23 * Currently only available for Xv driver and MMX extensions
26 * - implement non-MMX versions for all methods
27 * - support MMX2 instructions
28 * - move some generic code from xv driver to this file
29 * - make it also work for yuy2 frames
35 #include "deinterlace.h"
36 #include "xineutils.h"
38 #define xine_fast_memcpy memcpy
39 #define xine_fast_memmove memmove
42 DeinterlaceFieldBob algorithm
43 Based on Virtual Dub plugin by Gunnar Thalin
44 MMX asm version from dscaler project (deinterlace.sourceforge.net)
45 Linux version for Xine player by Miguel Freitas
47 static void deinterlace_bob_yuv_mmx( uint8_t *pdst
, uint8_t *psrc
[],
48 int width
, int height
)
56 uint8_t* pEvenLines
= psrc
[0];
57 uint8_t* pOddLines
= psrc
[0]+width
;
58 int LineLength
= width
;
59 int SourcePitch
= width
* 2;
61 long EdgeDetect
= 625;
62 long JaggieThreshold
= 73;
66 uint64_t qwEdgeDetect
;
69 static mmx_t YMask
= {ub
:{0xff,0,0xff,0,0xff,0,0xff,0}};
70 static mmx_t Mask
= {ub
:{0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}};
72 qwEdgeDetect
= EdgeDetect
;
73 qwEdgeDetect
+= (qwEdgeDetect
<< 48) + (qwEdgeDetect
<< 32) + (qwEdgeDetect
<< 16);
74 qwThreshold
= JaggieThreshold
;
75 qwThreshold
+= (qwThreshold
<< 48) + (qwThreshold
<< 32) + (qwThreshold
<< 16);
78 // copy first even line no matter what, and the first odd line if we're
79 // processing an odd field.
80 xine_fast_memcpy(pdst
, pEvenLines
, LineLength
);
82 xine_fast_memcpy(pdst
+ LineLength
, pOddLines
, LineLength
);
85 for (Line
= 0; Line
< height
- 1; ++Line
)
89 YVal1
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
90 YVal2
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
91 YVal3
= (uint64_t *)(pOddLines
+ (Line
+ 1) * SourcePitch
);
92 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 2) * LineLength
);
96 YVal1
= (uint64_t *)(pEvenLines
+ Line
* SourcePitch
);
97 YVal2
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
98 YVal3
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
99 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 1) * LineLength
);
102 // For ease of reading, the comments below assume that we're operating on an odd
103 // field (i.e., that bIsOdd is true). The exact same processing is done when we
104 // operate on an even field, but the roles of the odd and even fields are reversed.
105 // It's just too cumbersome to explain the algorithm in terms of "the next odd
106 // line if we're doing an odd field, or the next even line if we're doing an
107 // even field" etc. So wherever you see "odd" or "even" below, keep in mind that
108 // half the time this function is called, those words' meanings will invert.
110 // Copy the odd line to the overlay verbatim.
111 xine_fast_memcpy((char *)Dest
+ LineLength
, YVal3
, LineLength
);
116 movq_m2r (*YVal1
++, mm0
);
117 movq_m2r (*YVal2
++, mm1
);
118 movq_m2r (*YVal3
++, mm2
);
120 // get intensities in mm3 - 4
121 movq_r2r ( mm0
, mm3
);
122 pand_m2r ( YMask
, mm3
);
123 movq_r2r ( mm1
, mm4
);
124 pand_m2r ( YMask
, mm4
);
125 movq_r2r ( mm2
, mm5
);
126 pand_m2r ( YMask
, mm5
);
128 // get average in mm0
129 pand_m2r ( Mask
, mm0
);
130 pand_m2r ( Mask
, mm2
);
131 psrlw_i2r ( 01, mm0
);
132 psrlw_i2r ( 01, mm2
);
133 paddw_r2r ( mm2
, mm0
);
135 // work out (O1 - E) * (O2 - E) / 2 - EdgeDetect * (O1 - O2) ^ 2 >> 12
136 // result will be in mm6
138 psrlw_i2r ( 01, mm3
);
139 psrlw_i2r ( 01, mm4
);
140 psrlw_i2r ( 01, mm5
);
142 movq_r2r ( mm3
, mm6
);
143 psubw_r2r ( mm4
, mm6
); //mm6 = O1 - E
145 movq_r2r ( mm5
, mm7
);
146 psubw_r2r ( mm4
, mm7
); //mm7 = O2 - E
148 pmullw_r2r ( mm7
, mm6
); // mm6 = (O1 - E) * (O2 - E)
150 movq_r2r ( mm3
, mm7
);
151 psubw_r2r ( mm5
, mm7
); // mm7 = (O1 - O2)
152 pmullw_r2r ( mm7
, mm7
); // mm7 = (O1 - O2) ^ 2
153 psrlw_i2r ( 12, mm7
); // mm7 = (O1 - O2) ^ 2 >> 12
154 pmullw_m2r ( *&qwEdgeDetect
, mm7
);// mm7 = EdgeDetect * (O1 - O2) ^ 2 >> 12
156 psubw_r2r ( mm7
, mm6
); // mm6 is what we want
158 pcmpgtw_m2r ( *&qwThreshold
, mm6
);
160 movq_r2r ( mm6
, mm7
);
162 pand_r2r ( mm6
, mm0
);
164 pandn_r2r ( mm1
, mm7
);
166 por_r2r ( mm0
, mm7
);
168 movq_r2m ( mm7
, *Dest
++ );
172 // Copy last odd line if we're processing an even field.
175 xine_fast_memcpy(pdst
+ (height
* 2 - 1) * LineLength
,
176 pOddLines
+ (height
- 1) * SourcePitch
,
180 // clear out the MMX registers ready for doing floating point
186 /* Deinterlace the latest field, with a tendency to weave rather than bob.
187 Good for high detail on low-movement scenes.
188 Seems to produce bad output in general case, need to check if this
189 is normal or if the code is broken.
191 static int deinterlace_weave_yuv_mmx( uint8_t *pdst
, uint8_t *psrc
[],
192 int width
, int height
)
202 uint8_t* pEvenLines
= psrc
[0];
203 uint8_t* pOddLines
= psrc
[0]+width
;
206 int LineLength
= width
;
207 int SourcePitch
= width
* 2;
210 long TemporalTolerance
= 300;
211 long SpatialTolerance
= 600;
212 long SimilarityThreshold
= 25;
216 uint64_t qwSpatialTolerance
;
217 uint64_t qwTemporalTolerance
;
218 uint64_t qwThreshold
;
220 static mmx_t YMask
= {ub
:{0xff,0,0xff,0,0xff,0,0xff,0}};
221 static mmx_t Mask
= {ub
:{0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}};
224 // Make sure we have all the data we need.
225 if ( psrc
[0] == NULL
|| psrc
[1] == NULL
)
229 pPrevLines
= psrc
[1] + width
;
231 pPrevLines
= psrc
[1];
233 // Since the code uses MMX to process 4 pixels at a time, we need our constants
234 // to be represented 4 times per quadword.
235 qwSpatialTolerance
= SpatialTolerance
;
236 qwSpatialTolerance
+= (qwSpatialTolerance
<< 48) + (qwSpatialTolerance
<< 32) + (qwSpatialTolerance
<< 16);
237 qwTemporalTolerance
= TemporalTolerance
;
238 qwTemporalTolerance
+= (qwTemporalTolerance
<< 48) + (qwTemporalTolerance
<< 32) + (qwTemporalTolerance
<< 16);
239 qwThreshold
= SimilarityThreshold
;
240 qwThreshold
+= (qwThreshold
<< 48) + (qwThreshold
<< 32) + (qwThreshold
<< 16);
242 // copy first even line no matter what, and the first odd line if we're
243 // processing an even field.
244 xine_fast_memcpy(pdst
, pEvenLines
, LineLength
);
246 xine_fast_memcpy(pdst
+ LineLength
, pOddLines
, LineLength
);
249 for (Line
= 0; Line
< height
- 1; ++Line
)
253 YVal1
= (uint64_t *)(pEvenLines
+ Line
* SourcePitch
);
254 YVal2
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
255 YVal3
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
256 YVal4
= (uint64_t *)(pPrevLines
+ Line
* SourcePitch
);
257 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 1) * LineLength
);
261 YVal1
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
262 YVal2
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
263 YVal3
= (uint64_t *)(pOddLines
+ (Line
+ 1) * SourcePitch
);
264 YVal4
= (uint64_t *)(pPrevLines
+ (Line
+ 1) * SourcePitch
);
265 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 2) * LineLength
);
268 // For ease of reading, the comments below assume that we're operating on an odd
269 // field (i.e., that bIsOdd is true). The exact same processing is done when we
270 // operate on an even field, but the roles of the odd and even fields are reversed.
271 // It's just too cumbersome to explain the algorithm in terms of "the next odd
272 // line if we're doing an odd field, or the next even line if we're doing an
273 // even field" etc. So wherever you see "odd" or "even" below, keep in mind that
274 // half the time this function is called, those words' meanings will invert.
276 // Copy the even scanline below this one to the overlay buffer, since we'll be
277 // adapting the current scanline to the even lines surrounding it. The scanline
278 // above has already been copied by the previous pass through the loop.
279 xine_fast_memcpy((char *)Dest
+ LineLength
, YVal3
, LineLength
);
284 movq_m2r ( *YVal1
++, mm0
); // mm0 = E1
285 movq_m2r ( *YVal2
++, mm1
); // mm1 = O
286 movq_m2r ( *YVal3
++, mm2
); // mm2 = E2
288 movq_r2r ( mm0
, mm3
); // mm3 = intensity(E1)
289 movq_r2r ( mm1
, mm4
); // mm4 = intensity(O)
290 movq_r2r ( mm2
, mm6
); // mm6 = intensity(E2)
292 pand_m2r ( YMask
, mm3
);
293 pand_m2r ( YMask
, mm4
);
294 pand_m2r ( YMask
, mm6
);
296 // Average E1 and E2 for interpolated bobbing.
297 // leave result in mm0
298 pand_m2r ( Mask
, mm0
); // mm0 = E1 with lower chroma bit stripped off
299 pand_m2r ( Mask
, mm2
); // mm2 = E2 with lower chroma bit stripped off
300 psrlw_i2r ( 01, mm0
); // mm0 = E1 / 2
301 psrlw_i2r ( 01, mm2
); // mm2 = E2 / 2
302 paddb_r2r ( mm2
, mm0
);
304 // The meat of the work is done here. We want to see whether this pixel is
305 // close in luminosity to ANY of: its top neighbor, its bottom neighbor,
306 // or its predecessor. To do this without branching, we use MMX's
307 // saturation feature, which gives us Z(x) = x if x>=0, or 0 if x<0.
309 // The formula we're computing here is
310 // Z(ST - (E1 - O) ^ 2) + Z(ST - (E2 - O) ^ 2) + Z(TT - (Oold - O) ^ 2)
311 // where ST is spatial tolerance and TT is temporal tolerance. The idea
312 // is that if a pixel is similar to none of its neighbors, the resulting
313 // value will be pretty low, probably zero. A high value therefore indicates
314 // that the pixel had a similar neighbor. The pixel in the same position
315 // in the field before last (Oold) is considered a neighbor since we want
316 // to be able to display 1-pixel-high horizontal lines.
318 movq_m2r ( *&qwSpatialTolerance
, mm7
);
319 movq_r2r ( mm3
, mm5
); // mm5 = E1
320 psubsw_r2r ( mm4
, mm5
); // mm5 = E1 - O
321 psraw_i2r ( 1, mm5
);
322 pmullw_r2r ( mm5
, mm5
); // mm5 = (E1 - O) ^ 2
323 psubusw_r2r ( mm5
, mm7
); // mm7 = ST - (E1 - O) ^ 2, or 0 if that's negative
325 movq_m2r ( *&qwSpatialTolerance
, mm3
);
326 movq_r2r ( mm6
, mm5
); // mm5 = E2
327 psubsw_r2r ( mm4
, mm5
); // mm5 = E2 - O
328 psraw_i2r ( 1, mm5
);
329 pmullw_r2r ( mm5
, mm5
); // mm5 = (E2 - O) ^ 2
330 psubusw_r2r ( mm5
, mm3
); // mm0 = ST - (E2 - O) ^ 2, or 0 if that's negative
331 paddusw_r2r ( mm3
, mm7
); // mm7 = (ST - (E1 - O) ^ 2) + (ST - (E2 - O) ^ 2)
333 movq_m2r ( *&qwTemporalTolerance
, mm3
);
334 movq_m2r ( *YVal4
++, mm5
); // mm5 = Oold
335 pand_m2r ( YMask
, mm5
);
336 psubsw_r2r ( mm4
, mm5
); // mm5 = Oold - O
337 psraw_i2r ( 1, mm5
); // XXX
338 pmullw_r2r ( mm5
, mm5
); // mm5 = (Oold - O) ^ 2
339 psubusw_r2r ( mm5
, mm3
); /* mm0 = TT - (Oold - O) ^ 2, or 0 if that's negative */
340 paddusw_r2r ( mm3
, mm7
); // mm7 = our magic number
343 * Now compare the similarity totals against our threshold. The pcmpgtw
344 * instruction will populate the target register with a bunch of mask bits,
345 * filling words where the comparison is true with 1s and ones where it's
346 * false with 0s. A few ANDs and NOTs and an OR later, we have bobbed
347 * values for pixels under the similarity threshold and weaved ones for
348 * pixels over the threshold.
351 pcmpgtw_m2r( *&qwThreshold
, mm7
); // mm7 = 0xffff where we're greater than the threshold, 0 elsewhere
352 movq_r2r ( mm7
, mm6
); // mm6 = 0xffff where we're greater than the threshold, 0 elsewhere
353 pand_r2r ( mm1
, mm7
); // mm7 = weaved data where we're greater than the threshold, 0 elsewhere
354 pandn_r2r ( mm0
, mm6
); // mm6 = bobbed data where we're not greater than the threshold, 0 elsewhere
355 por_r2r ( mm6
, mm7
); // mm7 = bobbed and weaved data
357 movq_r2m ( mm7
, *Dest
++ );
361 // Copy last odd line if we're processing an odd field.
364 xine_fast_memcpy(pdst
+ (height
* 2 - 1) * LineLength
,
365 pOddLines
+ (height
- 1) * SourcePitch
,
369 // clear out the MMX registers ready for doing floating point
379 // This is a simple lightweight DeInterlace method that uses little CPU time
380 // but gives very good results for low or intermedite motion. (MORE CPU THAN BOB)
381 // It defers frames by one field, but that does not seem to produce noticeable
382 // lip sync problems.
384 // The method used is to take either the older or newer weave pixel depending
385 // upon which give the smaller comb factor, and then clip to avoid large damage
388 // I'd intended this to be part of a larger more elaborate method added to
389 // Blended Clip but this give too good results for the CPU to ignore here.
390 static int deinterlace_greedy_yuv_mmx( uint8_t *pdst
, uint8_t *psrc
[],
391 int width
, int height
)
396 uint64_t *L1
; // ptr to Line1, of 3
397 uint64_t *L2
; // ptr to Line2, the weave line
398 uint64_t *L3
; // ptr to Line3
399 uint64_t *LP2
; // ptr to prev Line2
401 uint8_t* pEvenLines
= psrc
[0];
402 uint8_t* pOddLines
= psrc
[0]+width
;
405 static mmx_t ShiftMask
= {ub
:{0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}};
407 int LineLength
= width
;
408 int SourcePitch
= width
* 2;
410 long GreedyMaxComb
= 15;
411 static mmx_t MaxComb
;
414 if ( psrc
[0] == NULL
|| psrc
[1] == NULL
)
418 pPrevLines
= psrc
[1] + width
;
420 pPrevLines
= psrc
[1];
423 for( i
= 0; i
< 8; i
++ )
424 MaxComb
.ub
[i
] = GreedyMaxComb
; // How badly do we let it weave? 0-255
427 // copy first even line no matter what, and the first odd line if we're
428 // processing an EVEN field. (note diff from other deint rtns.)
429 xine_fast_memcpy(pdst
, pEvenLines
, LineLength
); //DL0
431 xine_fast_memcpy(pdst
+ LineLength
, pOddLines
, LineLength
); //DL1
434 for (Line
= 0; Line
< height
- 1; ++Line
)
436 LoopCtr
= LineLength
/ 8; // there are LineLength / 8 qwords per line
440 L1
= (uint64_t *)(pEvenLines
+ Line
* SourcePitch
);
441 L2
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
442 L3
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
443 LP2
= (uint64_t *)(pPrevLines
+ Line
* SourcePitch
); // prev Odd lines
444 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 1) * LineLength
);
448 L1
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
449 L2
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
450 L3
= (uint64_t *)(pOddLines
+ (Line
+ 1) * SourcePitch
);
451 LP2
= (uint64_t *)(pPrevLines
+ (Line
+ 1) * SourcePitch
); //prev even lines
452 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 2) * LineLength
);
455 xine_fast_memcpy((char *)Dest
+ LineLength
, L3
, LineLength
);
457 // For ease of reading, the comments below assume that we're operating on an odd
458 // field (i.e., that info->IsOdd is true). Assume the obvious for even lines..
462 movq_m2r ( *L1
++, mm1
);
463 movq_m2r ( *L2
++, mm2
);
464 movq_m2r ( *L3
++, mm3
);
465 movq_m2r ( *LP2
++, mm0
);
467 // average L1 and L3 leave result in mm4
468 movq_r2r ( mm1
, mm4
); // L1
470 pand_m2r ( ShiftMask
, mm4
);
471 psrlw_i2r ( 01, mm4
);
472 movq_r2r ( mm3
, mm5
); // L3
473 pand_m2r ( ShiftMask
, mm5
);
474 psrlw_i2r ( 01, mm5
);
475 paddb_r2r ( mm5
, mm4
); // the average, for computing comb
477 // get abs value of possible L2 comb
478 movq_r2r ( mm2
, mm7
); // L2
479 psubusb_r2r ( mm4
, mm7
); // L2 - avg
480 movq_r2r ( mm4
, mm5
); // avg
481 psubusb_r2r ( mm2
, mm5
); // avg - L2
482 por_r2r ( mm7
, mm5
); // abs(avg-L2)
483 movq_r2r ( mm4
, mm6
); // copy of avg for later
485 // get abs value of possible LP2 comb
486 movq_r2r ( mm0
, mm7
); // LP2
487 psubusb_r2r ( mm4
, mm7
); // LP2 - avg
488 psubusb_r2r ( mm0
, mm4
); // avg - LP2
489 por_r2r ( mm7
, mm4
); // abs(avg-LP2)
491 // use L2 or LP2 depending upon which makes smaller comb
492 psubusb_r2r ( mm5
, mm4
); // see if it goes to zero
493 psubusb_r2r ( mm5
, mm5
); // 0
494 pcmpeqb_r2r ( mm5
, mm4
); // if (mm4=0) then FF else 0
495 pcmpeqb_r2r ( mm4
, mm5
); // opposite of mm4
497 // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
498 pand_r2r ( mm2
, mm5
); // use L2 if mm5 == ff, else 0
499 pand_r2r ( mm0
, mm4
); // use LP2 if mm4 = ff, else 0
500 por_r2r ( mm5
, mm4
); // may the best win
502 // Now lets clip our chosen value to be not outside of the range
503 // of the high/low range L1-L3 by more than abs(L1-L3)
504 // This allows some comb but limits the damages and also allows more
505 // detail than a boring oversmoothed clip.
507 movq_r2r ( mm1
, mm2
); // copy L1
508 psubusb_r2r ( mm3
, mm2
); // - L3, with saturation
509 paddusb_r2r ( mm3
, mm2
); // now = Max(L1,L3)
511 pcmpeqb_r2r ( mm7
, mm7
); // all ffffffff
512 psubusb_r2r ( mm1
, mm7
); // - L1
513 paddusb_r2r ( mm7
, mm3
); // add, may sat at fff..
514 psubusb_r2r ( mm7
, mm3
); // now = Min(L1,L3)
516 // allow the value to be above the high or below the low by amt of MaxComb
517 paddusb_m2r ( MaxComb
, mm2
); // increase max by diff
518 psubusb_m2r ( MaxComb
, mm3
); // lower min by diff
520 psubusb_r2r ( mm3
, mm4
); // best - Min
521 paddusb_r2r ( mm3
, mm4
); // now = Max(best,Min(L1,L3)
523 pcmpeqb_r2r ( mm7
, mm7
); // all ffffffff
524 psubusb_r2r ( mm4
, mm7
); // - Max(best,Min(best,L3)
525 paddusb_r2r ( mm7
, mm2
); // add may sat at FFF..
526 psubusb_r2r ( mm7
, mm2
); // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
528 movq_r2m ( mm2
, *Dest
++ ); // move in our clipped best
533 /* Copy last odd line if we're processing an Odd field. */
536 xine_fast_memcpy(pdst
+ (height
* 2 - 1) * LineLength
,
537 pOddLines
+ (height
- 1) * SourcePitch
,
541 /* clear out the MMX registers ready for doing floating point again */
549 /* Use one field to interpolate the other (low cpu utilization)
550 Will lose resolution but does not produce weaving effect
551 (good for fast moving scenes) also know as "linear interpolation"
553 static void deinterlace_onefield_yuv_mmx( uint8_t *pdst
, uint8_t *psrc
[],
554 int width
, int height
)
561 uint8_t* pEvenLines
= psrc
[0];
562 uint8_t* pOddLines
= psrc
[0]+width
;
563 int LineLength
= width
;
564 int SourcePitch
= width
* 2;
569 static mmx_t Mask
= {ub
:{0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}};
572 * copy first even line no matter what, and the first odd line if we're
573 * processing an odd field.
576 xine_fast_memcpy(pdst
, pEvenLines
, LineLength
);
578 xine_fast_memcpy(pdst
+ LineLength
, pOddLines
, LineLength
);
581 for (Line
= 0; Line
< height
- 1; ++Line
)
585 YVal1
= (uint64_t *)(pOddLines
+ Line
* SourcePitch
);
586 YVal3
= (uint64_t *)(pOddLines
+ (Line
+ 1) * SourcePitch
);
587 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 2) * LineLength
);
591 YVal1
= (uint64_t *)(pEvenLines
+ Line
* SourcePitch
);
592 YVal3
= (uint64_t *)(pEvenLines
+ (Line
+ 1) * SourcePitch
);
593 Dest
= (uint64_t *)(pdst
+ (Line
* 2 + 1) * LineLength
);
596 // Copy the odd line to the overlay verbatim.
597 xine_fast_memcpy((char *)Dest
+ LineLength
, YVal3
, LineLength
);
602 movq_m2r (*YVal1
++, mm0
);
603 movq_m2r (*YVal3
++, mm2
);
605 // get average in mm0
606 pand_m2r ( Mask
, mm0
);
607 pand_m2r ( Mask
, mm2
);
608 psrlw_i2r ( 01, mm0
);
609 psrlw_i2r ( 01, mm2
);
610 paddw_r2r ( mm2
, mm0
);
612 movq_r2m ( mm0
, *Dest
++ );
616 /* Copy last odd line if we're processing an even field. */
619 xine_fast_memcpy(pdst
+ (height
* 2 - 1) * LineLength
,
620 pOddLines
+ (height
- 1) * SourcePitch
,
624 /* clear out the MMX registers ready for doing floating point
631 /* Linear Blend filter - does a kind of vertical blurring on the image.
632 (idea borrowed from mplayer's sources)
634 static void deinterlace_linearblend_yuv_mmx( uint8_t *pdst
, uint8_t *psrc
[],
635 int width
, int height
)
643 int LineLength
= width
;
647 /* Copy first line */
648 xine_fast_memmove(pdst
, psrc
[0], LineLength
);
650 for (Line
= 1; Line
< height
- 1; ++Line
)
652 YVal1
= (uint64_t *)(psrc
[0] + (Line
- 1) * LineLength
);
653 YVal2
= (uint64_t *)(psrc
[0] + (Line
) * LineLength
);
654 YVal3
= (uint64_t *)(psrc
[0] + (Line
+ 1) * LineLength
);
655 Dest
= (uint64_t *)(pdst
+ Line
* LineLength
);
660 /* load data from 3 lines */
661 movq_m2r (*YVal1
++, mm0
);
662 movq_m2r (*YVal2
++, mm1
);
663 movq_m2r (*YVal3
++, mm2
);
665 /* expand bytes to words */
666 punpckhbw_r2r (mm0
, mm3
);
667 punpckhbw_r2r (mm1
, mm4
);
668 punpckhbw_r2r (mm2
, mm5
);
669 punpcklbw_r2r (mm0
, mm0
);
670 punpcklbw_r2r (mm1
, mm1
);
671 punpcklbw_r2r (mm2
, mm2
);
675 * deint_line = (line0 + 2*line1 + line2) / 4
683 paddw_r2r (mm1
, mm0
);
684 paddw_r2r (mm2
, mm0
);
685 paddw_r2r (mm4
, mm3
);
686 paddw_r2r (mm5
, mm3
);
690 /* pack 8 words to 8 bytes in mm0 */
691 packuswb_r2r (mm3
, mm0
);
693 movq_r2m ( mm0
, *Dest
++ );
698 xine_fast_memmove(pdst
+ Line
* LineLength
,
699 psrc
[0] + Line
* LineLength
, LineLength
);
701 /* clear out the MMX registers ready for doing floating point
708 /* Linear Blend filter - C version contributed by Rogerio Brito.
709 This algorithm has the same interface as the other functions.
711 The destination "screen" (pdst) is constructed from the source
712 screen (psrc[0]) line by line.
714 The i-th line of the destination screen is the average of 3 lines
715 from the source screen: the (i-1)-th, i-th and (i+1)-th lines, with
716 the i-th line having weight 2 in the computation.
719 * each line on pdst doesn't depend on previous lines;
720 * due to the way the algorithm is defined, the first & last lines of the
721 screen aren't deinterlaced.
724 static void deinterlace_linearblend_yuv( uint8_t *pdst
, uint8_t *psrc
[],
725 int width
, int height
)
728 register uint8_t *l0
, *l1
, *l2
, *l3
;
730 l0
= pdst
; /* target line */
731 l1
= psrc
[0]; /* 1st source line */
732 l2
= l1
+ width
; /* 2nd source line = line that follows l1 */
733 l3
= l2
+ width
; /* 3rd source line = line that follows l2 */
735 /* Copy the first line */
736 xine_fast_memcpy(l0
, l1
, width
);
739 for (y
= 1; y
< height
-1; ++y
) {
740 /* computes avg of: l1 + 2*l2 + l3 */
742 for (x
= 0; x
< width
; ++x
) {
743 l0
[x
] = (l1
[x
] + (l2
[x
]<<1) + l3
[x
]) >> 2;
746 /* updates the line pointers */
747 l1
= l2
; l2
= l3
; l3
+= width
;
751 /* Copy the last line */
752 xine_fast_memcpy(l0
, l1
, width
);
755 static int check_for_mmx(void)
758 static int config_flags
= -1;
760 if ( config_flags
== -1 )
761 config_flags
= xine_mm_accel();
762 if (config_flags
& MM_ACCEL_X86_MMX
)
770 /* generic YUV deinterlacer
771 pdst -> pointer to destination bitmap
772 psrc -> array of pointers to source bitmaps ([0] = most recent)
773 width,height -> dimension for bitmaps
774 method -> DEINTERLACE_xxx
777 void deinterlace_yuv( uint8_t *pdst
, uint8_t *psrc
[],
778 int width
, int height
, int method
)
781 case DEINTERLACE_NONE
:
782 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
784 case DEINTERLACE_BOB
:
785 if( check_for_mmx() )
786 deinterlace_bob_yuv_mmx(pdst
,psrc
,width
,height
);
787 else /* FIXME: provide an alternative? */
788 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
790 case DEINTERLACE_WEAVE
:
791 if( check_for_mmx() )
793 if( !deinterlace_weave_yuv_mmx(pdst
,psrc
,width
,height
) )
794 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
796 else /* FIXME: provide an alternative? */
797 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
799 case DEINTERLACE_GREEDY
:
800 if( check_for_mmx() )
802 if( !deinterlace_greedy_yuv_mmx(pdst
,psrc
,width
,height
) )
803 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
805 else /* FIXME: provide an alternative? */
806 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
808 case DEINTERLACE_ONEFIELD
:
809 if( check_for_mmx() )
810 deinterlace_onefield_yuv_mmx(pdst
,psrc
,width
,height
);
811 else /* FIXME: provide an alternative? */
812 xine_fast_memcpy(pdst
,psrc
[0],width
*height
);
814 case DEINTERLACE_ONEFIELDXV
:
815 lprintf("ONEFIELDXV must be handled by the video driver.\n");
817 case DEINTERLACE_LINEARBLEND
:
818 if( check_for_mmx() )
819 deinterlace_linearblend_yuv_mmx(pdst
,psrc
,width
,height
);
821 deinterlace_linearblend_yuv(pdst
,psrc
,width
,height
);
824 lprintf("unknown method %d.\n",method
);
829 int deinterlace_yuv_supported ( int method
)
832 case DEINTERLACE_NONE
:
834 case DEINTERLACE_BOB
:
835 case DEINTERLACE_WEAVE
:
836 case DEINTERLACE_GREEDY
:
837 case DEINTERLACE_ONEFIELD
:
838 return check_for_mmx();
839 case DEINTERLACE_ONEFIELDXV
:
840 lprintf ("ONEFIELDXV must be handled by the video driver.\n");
842 case DEINTERLACE_LINEARBLEND
:
849 char *deinterlace_methods
[] = {