3a569f1b7806575f0e565a9095418f0018832c98
[ffmpeg.git] / libswscale / ppc / swscale_template.c
1 /*
2  * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
3  *
4  * This file is part of Libav.
5  *
6  * Libav is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * Libav 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21
22 #if COMPILE_TEMPLATE_ALTIVEC
23 #include "swscale_altivec_template.c"
24 #endif
25
26 static inline void RENAME(yuv2yuvX)(SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize,
27                                     const int16_t *chrFilter, const int16_t **chrSrc, int chrFilterSize, const int16_t **alpSrc,
28                                     uint8_t *dest, uint8_t *uDest, uint8_t *vDest, uint8_t *aDest, long dstW, long chrDstW)
29 {
30 #if COMPILE_TEMPLATE_ALTIVEC
31     yuv2yuvX_altivec_real(lumFilter, lumSrc, lumFilterSize,
32                           chrFilter, chrSrc, chrFilterSize,
33                           dest, uDest, vDest, dstW, chrDstW);
34 #else //COMPILE_TEMPLATE_ALTIVEC
35     yuv2yuvXinC(lumFilter, lumSrc, lumFilterSize,
36                 chrFilter, chrSrc, chrFilterSize,
37                 alpSrc, dest, uDest, vDest, aDest, dstW, chrDstW);
38 #endif //!COMPILE_TEMPLATE_ALTIVEC
39 }
40
41 static inline void RENAME(yuv2nv12X)(SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize,
42                                      const int16_t *chrFilter, const int16_t **chrSrc, int chrFilterSize,
43                                      uint8_t *dest, uint8_t *uDest, int dstW, int chrDstW, enum PixelFormat dstFormat)
44 {
45     yuv2nv12XinC(lumFilter, lumSrc, lumFilterSize,
46                  chrFilter, chrSrc, chrFilterSize,
47                  dest, uDest, dstW, chrDstW, dstFormat);
48 }
49
50 static inline void RENAME(yuv2yuv1)(SwsContext *c, const int16_t *lumSrc, const int16_t *chrSrc, const int16_t *alpSrc,
51                                     uint8_t *dest, uint8_t *uDest, uint8_t *vDest, uint8_t *aDest, long dstW, long chrDstW)
52 {
53     int i;
54     for (i=0; i<dstW; i++) {
55         int val= (lumSrc[i]+64)>>7;
56
57         if (val&256) {
58             if (val<0) val=0;
59             else       val=255;
60         }
61
62         dest[i]= val;
63     }
64
65     if (uDest)
66         for (i=0; i<chrDstW; i++) {
67             int u=(chrSrc[i       ]+64)>>7;
68             int v=(chrSrc[i + VOFW]+64)>>7;
69
70             if ((u|v)&256) {
71                 if (u<0)        u=0;
72                 else if (u>255) u=255;
73                 if (v<0)        v=0;
74                 else if (v>255) v=255;
75             }
76
77             uDest[i]= u;
78             vDest[i]= v;
79         }
80
81     if (CONFIG_SWSCALE_ALPHA && aDest)
82         for (i=0; i<dstW; i++) {
83             int val= (alpSrc[i]+64)>>7;
84             aDest[i]= av_clip_uint8(val);
85         }
86 }
87
88
89 /**
90  * vertical scale YV12 to RGB
91  */
92 static inline void RENAME(yuv2packedX)(SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize,
93                                        const int16_t *chrFilter, const int16_t **chrSrc, int chrFilterSize,
94                                        const int16_t **alpSrc, uint8_t *dest, long dstW, long dstY)
95 {
96 #if COMPILE_TEMPLATE_ALTIVEC
97     /* The following list of supported dstFormat values should
98        match what's found in the body of ff_yuv2packedX_altivec() */
99     if (!(c->flags & SWS_BITEXACT) && !c->alpPixBuf &&
100          (c->dstFormat==PIX_FMT_ABGR  || c->dstFormat==PIX_FMT_BGRA  ||
101           c->dstFormat==PIX_FMT_BGR24 || c->dstFormat==PIX_FMT_RGB24 ||
102           c->dstFormat==PIX_FMT_RGBA  || c->dstFormat==PIX_FMT_ARGB))
103             ff_yuv2packedX_altivec(c, lumFilter, lumSrc, lumFilterSize,
104                                    chrFilter, chrSrc, chrFilterSize,
105                                    dest, dstW, dstY);
106     else
107 #endif
108         yuv2packedXinC(c, lumFilter, lumSrc, lumFilterSize,
109                        chrFilter, chrSrc, chrFilterSize,
110                        alpSrc, dest, dstW, dstY);
111 }
112
113 /**
114  * vertical bilinear scale YV12 to RGB
115  */
116 static inline void RENAME(yuv2packed2)(SwsContext *c, const uint16_t *buf0, const uint16_t *buf1, const uint16_t *uvbuf0, const uint16_t *uvbuf1,
117                           const uint16_t *abuf0, const uint16_t *abuf1, uint8_t *dest, int dstW, int yalpha, int uvalpha, int y)
118 {
119     int  yalpha1=4095- yalpha;
120     int uvalpha1=4095-uvalpha;
121     int i;
122
123     YSCALE_YUV_2_ANYRGB_C(YSCALE_YUV_2_RGB2_C, YSCALE_YUV_2_PACKED2_C(void,0), YSCALE_YUV_2_GRAY16_2_C, YSCALE_YUV_2_MONO2_C)
124 }
125
126 /**
127  * YV12 to RGB without scaling or interpolating
128  */
129 static inline void RENAME(yuv2packed1)(SwsContext *c, const uint16_t *buf0, const uint16_t *uvbuf0, const uint16_t *uvbuf1,
130                           const uint16_t *abuf0, uint8_t *dest, int dstW, int uvalpha, enum PixelFormat dstFormat, int flags, int y)
131 {
132     const int yalpha1=0;
133     int i;
134
135     const uint16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
136     const int yalpha= 4096; //FIXME ...
137
138     if (flags&SWS_FULL_CHR_H_INT) {
139         c->yuv2packed2(c, buf0, buf0, uvbuf0, uvbuf1, abuf0, abuf0, dest, dstW, 0, uvalpha, y);
140         return;
141     }
142
143     if (uvalpha < 2048) {
144         YSCALE_YUV_2_ANYRGB_C(YSCALE_YUV_2_RGB1_C, YSCALE_YUV_2_PACKED1_C(void,0), YSCALE_YUV_2_GRAY16_1_C, YSCALE_YUV_2_MONO2_C)
145     } else {
146         YSCALE_YUV_2_ANYRGB_C(YSCALE_YUV_2_RGB1B_C, YSCALE_YUV_2_PACKED1B_C(void,0), YSCALE_YUV_2_GRAY16_1_C, YSCALE_YUV_2_MONO2_C)
147     }
148 }
149
150 //FIXME yuy2* can read up to 7 samples too much
151
152 static inline void RENAME(yuy2ToY)(uint8_t *dst, const uint8_t *src, long width, uint32_t *unused)
153 {
154     int i;
155     for (i=0; i<width; i++)
156         dst[i]= src[2*i];
157 }
158
159 static inline void RENAME(yuy2ToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
160 {
161     int i;
162     for (i=0; i<width; i++) {
163         dstU[i]= src1[4*i + 1];
164         dstV[i]= src1[4*i + 3];
165     }
166     assert(src1 == src2);
167 }
168
169 static inline void RENAME(LEToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
170 {
171     int i;
172     for (i=0; i<width; i++) {
173         dstU[i]= src1[2*i + 1];
174         dstV[i]= src2[2*i + 1];
175     }
176 }
177
178 /* This is almost identical to the previous, end exists only because
179  * yuy2ToY/UV)(dst, src+1, ...) would have 100% unaligned accesses. */
180 static inline void RENAME(uyvyToY)(uint8_t *dst, const uint8_t *src, long width, uint32_t *unused)
181 {
182     int i;
183     for (i=0; i<width; i++)
184         dst[i]= src[2*i+1];
185 }
186
187 static inline void RENAME(uyvyToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
188 {
189     int i;
190     for (i=0; i<width; i++) {
191         dstU[i]= src1[4*i + 0];
192         dstV[i]= src1[4*i + 2];
193     }
194     assert(src1 == src2);
195 }
196
197 static inline void RENAME(BEToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
198 {
199     int i;
200     for (i=0; i<width; i++) {
201         dstU[i]= src1[2*i];
202         dstV[i]= src2[2*i];
203     }
204 }
205
206 static inline void RENAME(nvXXtoUV)(uint8_t *dst1, uint8_t *dst2,
207                                     const uint8_t *src, long width)
208 {
209     int i;
210     for (i = 0; i < width; i++) {
211         dst1[i] = src[2*i+0];
212         dst2[i] = src[2*i+1];
213     }
214 }
215
216 static inline void RENAME(nv12ToUV)(uint8_t *dstU, uint8_t *dstV,
217                                     const uint8_t *src1, const uint8_t *src2,
218                                     long width, uint32_t *unused)
219 {
220     RENAME(nvXXtoUV)(dstU, dstV, src1, width);
221 }
222
223 static inline void RENAME(nv21ToUV)(uint8_t *dstU, uint8_t *dstV,
224                                     const uint8_t *src1, const uint8_t *src2,
225                                     long width, uint32_t *unused)
226 {
227     RENAME(nvXXtoUV)(dstV, dstU, src1, width);
228 }
229
230
231 static inline void RENAME(bgr24ToY)(uint8_t *dst, const uint8_t *src, long width, uint32_t *unused)
232 {
233     int i;
234     for (i=0; i<width; i++) {
235         int b= src[i*3+0];
236         int g= src[i*3+1];
237         int r= src[i*3+2];
238
239         dst[i]= ((RY*r + GY*g + BY*b + (33<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
240     }
241 }
242
243 static inline void RENAME(bgr24ToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
244 {
245     int i;
246     for (i=0; i<width; i++) {
247         int b= src1[3*i + 0];
248         int g= src1[3*i + 1];
249         int r= src1[3*i + 2];
250
251         dstU[i]= (RU*r + GU*g + BU*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT;
252         dstV[i]= (RV*r + GV*g + BV*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT;
253     }
254     assert(src1 == src2);
255 }
256
257 static inline void RENAME(bgr24ToUV_half)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
258 {
259     int i;
260     for (i=0; i<width; i++) {
261         int b= src1[6*i + 0] + src1[6*i + 3];
262         int g= src1[6*i + 1] + src1[6*i + 4];
263         int r= src1[6*i + 2] + src1[6*i + 5];
264
265         dstU[i]= (RU*r + GU*g + BU*b + (257<<RGB2YUV_SHIFT))>>(RGB2YUV_SHIFT+1);
266         dstV[i]= (RV*r + GV*g + BV*b + (257<<RGB2YUV_SHIFT))>>(RGB2YUV_SHIFT+1);
267     }
268     assert(src1 == src2);
269 }
270
271 static inline void RENAME(rgb24ToY)(uint8_t *dst, const uint8_t *src, long width, uint32_t *unused)
272 {
273     int i;
274     for (i=0; i<width; i++) {
275         int r= src[i*3+0];
276         int g= src[i*3+1];
277         int b= src[i*3+2];
278
279         dst[i]= ((RY*r + GY*g + BY*b + (33<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
280     }
281 }
282
283 static inline void RENAME(rgb24ToUV)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
284 {
285     int i;
286     assert(src1==src2);
287     for (i=0; i<width; i++) {
288         int r= src1[3*i + 0];
289         int g= src1[3*i + 1];
290         int b= src1[3*i + 2];
291
292         dstU[i]= (RU*r + GU*g + BU*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT;
293         dstV[i]= (RV*r + GV*g + BV*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT;
294     }
295 }
296
297 static inline void RENAME(rgb24ToUV_half)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, long width, uint32_t *unused)
298 {
299     int i;
300     assert(src1==src2);
301     for (i=0; i<width; i++) {
302         int r= src1[6*i + 0] + src1[6*i + 3];
303         int g= src1[6*i + 1] + src1[6*i + 4];
304         int b= src1[6*i + 2] + src1[6*i + 5];
305
306         dstU[i]= (RU*r + GU*g + BU*b + (257<<RGB2YUV_SHIFT))>>(RGB2YUV_SHIFT+1);
307         dstV[i]= (RV*r + GV*g + BV*b + (257<<RGB2YUV_SHIFT))>>(RGB2YUV_SHIFT+1);
308     }
309 }
310
311
312 // bilinear / bicubic scaling
313 static inline void RENAME(hScale)(int16_t *dst, int dstW, const uint8_t *src, int srcW, int xInc,
314                                   const int16_t *filter, const int16_t *filterPos, long filterSize)
315 {
316 #if COMPILE_TEMPLATE_ALTIVEC
317     hScale_altivec_real(dst, dstW, src, srcW, xInc, filter, filterPos, filterSize);
318 #else
319     int i;
320     for (i=0; i<dstW; i++) {
321         int j;
322         int srcPos= filterPos[i];
323         int val=0;
324         //printf("filterPos: %d\n", filterPos[i]);
325         for (j=0; j<filterSize; j++) {
326             //printf("filter: %d, src: %d\n", filter[i], src[srcPos + j]);
327             val += ((int)src[srcPos + j])*filter[filterSize*i + j];
328         }
329         //filter += hFilterSize;
330         dst[i] = FFMIN(val>>7, (1<<15)-1); // the cubic equation does overflow ...
331         //dst[i] = val>>7;
332     }
333 #endif /* COMPILE_TEMPLATE_ALTIVEC */
334 }
335
336 //FIXME all pal and rgb srcFormats could do this convertion as well
337 //FIXME all scalers more complex than bilinear could do half of this transform
338 static void RENAME(chrRangeToJpeg)(uint16_t *dst, int width)
339 {
340     int i;
341     for (i = 0; i < width; i++) {
342         dst[i     ] = (FFMIN(dst[i     ],30775)*4663 - 9289992)>>12; //-264
343         dst[i+VOFW] = (FFMIN(dst[i+VOFW],30775)*4663 - 9289992)>>12; //-264
344     }
345 }
346 static void RENAME(chrRangeFromJpeg)(uint16_t *dst, int width)
347 {
348     int i;
349     for (i = 0; i < width; i++) {
350         dst[i     ] = (dst[i     ]*1799 + 4081085)>>11; //1469
351         dst[i+VOFW] = (dst[i+VOFW]*1799 + 4081085)>>11; //1469
352     }
353 }
354 static void RENAME(lumRangeToJpeg)(uint16_t *dst, int width)
355 {
356     int i;
357     for (i = 0; i < width; i++)
358         dst[i] = (FFMIN(dst[i],30189)*19077 - 39057361)>>14;
359 }
360 static void RENAME(lumRangeFromJpeg)(uint16_t *dst, int width)
361 {
362     int i;
363     for (i = 0; i < width; i++)
364         dst[i] = (dst[i]*14071 + 33561947)>>14;
365 }
366
367 static inline void RENAME(hyscale_fast)(SwsContext *c, int16_t *dst,
368                                         long dstWidth, const uint8_t *src, int srcW,
369                                         int xInc)
370 {
371     int i;
372     unsigned int xpos=0;
373     for (i=0;i<dstWidth;i++) {
374         register unsigned int xx=xpos>>16;
375         register unsigned int xalpha=(xpos&0xFFFF)>>9;
376         dst[i]= (src[xx]<<7) + (src[xx+1] - src[xx])*xalpha;
377         xpos+=xInc;
378     }
379 }
380
381       // *** horizontal scale Y line to temp buffer
382 static inline void RENAME(hyscale)(SwsContext *c, uint16_t *dst, long dstWidth, const uint8_t *src, int srcW, int xInc,
383                                    const int16_t *hLumFilter,
384                                    const int16_t *hLumFilterPos, int hLumFilterSize,
385                                    uint8_t *formatConvBuffer,
386                                    uint32_t *pal, int isAlpha)
387 {
388     void (*toYV12)(uint8_t *, const uint8_t *, long, uint32_t *) = isAlpha ? c->alpToYV12 : c->lumToYV12;
389     void (*convertRange)(uint16_t *, int) = isAlpha ? NULL : c->lumConvertRange;
390
391     src += isAlpha ? c->alpSrcOffset : c->lumSrcOffset;
392
393     if (toYV12) {
394         toYV12(formatConvBuffer, src, srcW, pal);
395         src= formatConvBuffer;
396     }
397
398     if (!c->hyscale_fast) {
399         c->hScale(dst, dstWidth, src, srcW, xInc, hLumFilter, hLumFilterPos, hLumFilterSize);
400     } else { // fast bilinear upscale / crap downscale
401         c->hyscale_fast(c, dst, dstWidth, src, srcW, xInc);
402     }
403
404     if (convertRange)
405         convertRange(dst, dstWidth);
406 }
407
408 static inline void RENAME(hcscale_fast)(SwsContext *c, int16_t *dst,
409                                         long dstWidth, const uint8_t *src1,
410                                         const uint8_t *src2, int srcW, int xInc)
411 {
412     int i;
413     unsigned int xpos=0;
414     for (i=0;i<dstWidth;i++) {
415         register unsigned int xx=xpos>>16;
416         register unsigned int xalpha=(xpos&0xFFFF)>>9;
417         dst[i]=(src1[xx]*(xalpha^127)+src1[xx+1]*xalpha);
418         dst[i+VOFW]=(src2[xx]*(xalpha^127)+src2[xx+1]*xalpha);
419         /* slower
420         dst[i]= (src1[xx]<<7) + (src1[xx+1] - src1[xx])*xalpha;
421         dst[i+VOFW]=(src2[xx]<<7) + (src2[xx+1] - src2[xx])*xalpha;
422         */
423         xpos+=xInc;
424     }
425 }
426
427 inline static void RENAME(hcscale)(SwsContext *c, uint16_t *dst, long dstWidth, const uint8_t *src1, const uint8_t *src2,
428                                    int srcW, int xInc, const int16_t *hChrFilter,
429                                    const int16_t *hChrFilterPos, int hChrFilterSize,
430                                    uint8_t *formatConvBuffer,
431                                    uint32_t *pal)
432 {
433
434     src1 += c->chrSrcOffset;
435     src2 += c->chrSrcOffset;
436
437     if (c->chrToYV12) {
438         c->chrToYV12(formatConvBuffer, formatConvBuffer+VOFW, src1, src2, srcW, pal);
439         src1= formatConvBuffer;
440         src2= formatConvBuffer+VOFW;
441     }
442
443     if (!c->hcscale_fast) {
444         c->hScale(dst     , dstWidth, src1, srcW, xInc, hChrFilter, hChrFilterPos, hChrFilterSize);
445         c->hScale(dst+VOFW, dstWidth, src2, srcW, xInc, hChrFilter, hChrFilterPos, hChrFilterSize);
446     } else { // fast bilinear upscale / crap downscale
447         c->hcscale_fast(c, dst, dstWidth, src1, src2, srcW, xInc);
448     }
449
450     if (c->chrConvertRange)
451         c->chrConvertRange(dst, dstWidth);
452 }
453
454 #define DEBUG_SWSCALE_BUFFERS 0
455 #define DEBUG_BUFFERS(...) if (DEBUG_SWSCALE_BUFFERS) av_log(c, AV_LOG_DEBUG, __VA_ARGS__)
456
457 static int RENAME(swScale)(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
458                            int srcSliceH, uint8_t* dst[], int dstStride[])
459 {
460     /* load a few things into local vars to make the code more readable? and faster */
461     const int srcW= c->srcW;
462     const int dstW= c->dstW;
463     const int dstH= c->dstH;
464     const int chrDstW= c->chrDstW;
465     const int chrSrcW= c->chrSrcW;
466     const int lumXInc= c->lumXInc;
467     const int chrXInc= c->chrXInc;
468     const enum PixelFormat dstFormat= c->dstFormat;
469     const int flags= c->flags;
470     int16_t *vLumFilterPos= c->vLumFilterPos;
471     int16_t *vChrFilterPos= c->vChrFilterPos;
472     int16_t *hLumFilterPos= c->hLumFilterPos;
473     int16_t *hChrFilterPos= c->hChrFilterPos;
474     int16_t *vLumFilter= c->vLumFilter;
475     int16_t *vChrFilter= c->vChrFilter;
476     int16_t *hLumFilter= c->hLumFilter;
477     int16_t *hChrFilter= c->hChrFilter;
478     int32_t *lumMmxFilter= c->lumMmxFilter;
479     int32_t *chrMmxFilter= c->chrMmxFilter;
480     int32_t av_unused *alpMmxFilter= c->alpMmxFilter;
481     const int vLumFilterSize= c->vLumFilterSize;
482     const int vChrFilterSize= c->vChrFilterSize;
483     const int hLumFilterSize= c->hLumFilterSize;
484     const int hChrFilterSize= c->hChrFilterSize;
485     int16_t **lumPixBuf= c->lumPixBuf;
486     int16_t **chrPixBuf= c->chrPixBuf;
487     int16_t **alpPixBuf= c->alpPixBuf;
488     const int vLumBufSize= c->vLumBufSize;
489     const int vChrBufSize= c->vChrBufSize;
490     uint8_t *formatConvBuffer= c->formatConvBuffer;
491     const int chrSrcSliceY= srcSliceY >> c->chrSrcVSubSample;
492     const int chrSrcSliceH= -((-srcSliceH) >> c->chrSrcVSubSample);
493     int lastDstY;
494     uint32_t *pal=c->pal_yuv;
495
496     /* vars which will change and which we need to store back in the context */
497     int dstY= c->dstY;
498     int lumBufIndex= c->lumBufIndex;
499     int chrBufIndex= c->chrBufIndex;
500     int lastInLumBuf= c->lastInLumBuf;
501     int lastInChrBuf= c->lastInChrBuf;
502
503     if (isPacked(c->srcFormat)) {
504         src[0]=
505         src[1]=
506         src[2]=
507         src[3]= src[0];
508         srcStride[0]=
509         srcStride[1]=
510         srcStride[2]=
511         srcStride[3]= srcStride[0];
512     }
513     srcStride[1]<<= c->vChrDrop;
514     srcStride[2]<<= c->vChrDrop;
515
516     DEBUG_BUFFERS("swScale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n",
517                   src[0], srcStride[0], src[1], srcStride[1], src[2], srcStride[2], src[3], srcStride[3],
518                   dst[0], dstStride[0], dst[1], dstStride[1], dst[2], dstStride[2], dst[3], dstStride[3]);
519     DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n",
520                    srcSliceY,    srcSliceH,    dstY,    dstH);
521     DEBUG_BUFFERS("vLumFilterSize: %d vLumBufSize: %d vChrFilterSize: %d vChrBufSize: %d\n",
522                    vLumFilterSize,    vLumBufSize,    vChrFilterSize,    vChrBufSize);
523
524     if (dstStride[0]%8 !=0 || dstStride[1]%8 !=0 || dstStride[2]%8 !=0 || dstStride[3]%8 != 0) {
525         static int warnedAlready=0; //FIXME move this into the context perhaps
526         if (flags & SWS_PRINT_INFO && !warnedAlready) {
527             av_log(c, AV_LOG_WARNING, "Warning: dstStride is not aligned!\n"
528                    "         ->cannot do aligned memory accesses anymore\n");
529             warnedAlready=1;
530         }
531     }
532
533     /* Note the user might start scaling the picture in the middle so this
534        will not get executed. This is not really intended but works
535        currently, so people might do it. */
536     if (srcSliceY ==0) {
537         lumBufIndex=-1;
538         chrBufIndex=-1;
539         dstY=0;
540         lastInLumBuf= -1;
541         lastInChrBuf= -1;
542     }
543
544     lastDstY= dstY;
545
546     for (;dstY < dstH; dstY++) {
547         unsigned char *dest =dst[0]+dstStride[0]*dstY;
548         const int chrDstY= dstY>>c->chrDstVSubSample;
549         unsigned char *uDest=dst[1]+dstStride[1]*chrDstY;
550         unsigned char *vDest=dst[2]+dstStride[2]*chrDstY;
551         unsigned char *aDest=(CONFIG_SWSCALE_ALPHA && alpPixBuf) ? dst[3]+dstStride[3]*dstY : NULL;
552
553         const int firstLumSrcY= vLumFilterPos[dstY]; //First line needed as input
554         const int firstLumSrcY2= vLumFilterPos[FFMIN(dstY | ((1<<c->chrDstVSubSample) - 1), dstH-1)];
555         const int firstChrSrcY= vChrFilterPos[chrDstY]; //First line needed as input
556         int lastLumSrcY= firstLumSrcY + vLumFilterSize -1; // Last line needed as input
557         int lastLumSrcY2=firstLumSrcY2+ vLumFilterSize -1; // Last line needed as input
558         int lastChrSrcY= firstChrSrcY + vChrFilterSize -1; // Last line needed as input
559         int enough_lines;
560
561         //handle holes (FAST_BILINEAR & weird filters)
562         if (firstLumSrcY > lastInLumBuf) lastInLumBuf= firstLumSrcY-1;
563         if (firstChrSrcY > lastInChrBuf) lastInChrBuf= firstChrSrcY-1;
564         assert(firstLumSrcY >= lastInLumBuf - vLumBufSize + 1);
565         assert(firstChrSrcY >= lastInChrBuf - vChrBufSize + 1);
566
567         DEBUG_BUFFERS("dstY: %d\n", dstY);
568         DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n",
569                          firstLumSrcY,    lastLumSrcY,    lastInLumBuf);
570         DEBUG_BUFFERS("\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n",
571                          firstChrSrcY,    lastChrSrcY,    lastInChrBuf);
572
573         // Do we have enough lines in this slice to output the dstY line
574         enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH && lastChrSrcY < -((-srcSliceY - srcSliceH)>>c->chrSrcVSubSample);
575
576         if (!enough_lines) {
577             lastLumSrcY = srcSliceY + srcSliceH - 1;
578             lastChrSrcY = chrSrcSliceY + chrSrcSliceH - 1;
579             DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n",
580                                             lastLumSrcY, lastChrSrcY);
581         }
582
583         //Do horizontal scaling
584         while(lastInLumBuf < lastLumSrcY) {
585             const uint8_t *src1= src[0]+(lastInLumBuf + 1 - srcSliceY)*srcStride[0];
586             const uint8_t *src2= src[3]+(lastInLumBuf + 1 - srcSliceY)*srcStride[3];
587             lumBufIndex++;
588             assert(lumBufIndex < 2*vLumBufSize);
589             assert(lastInLumBuf + 1 - srcSliceY < srcSliceH);
590             assert(lastInLumBuf + 1 - srcSliceY >= 0);
591             RENAME(hyscale)(c, lumPixBuf[ lumBufIndex ], dstW, src1, srcW, lumXInc,
592                             hLumFilter, hLumFilterPos, hLumFilterSize,
593                             formatConvBuffer,
594                             pal, 0);
595             if (CONFIG_SWSCALE_ALPHA && alpPixBuf)
596                 RENAME(hyscale)(c, alpPixBuf[ lumBufIndex ], dstW, src2, srcW, lumXInc,
597                                 hLumFilter, hLumFilterPos, hLumFilterSize,
598                                 formatConvBuffer,
599                                 pal, 1);
600             lastInLumBuf++;
601             DEBUG_BUFFERS("\t\tlumBufIndex %d: lastInLumBuf: %d\n",
602                                lumBufIndex,    lastInLumBuf);
603         }
604         while(lastInChrBuf < lastChrSrcY) {
605             const uint8_t *src1= src[1]+(lastInChrBuf + 1 - chrSrcSliceY)*srcStride[1];
606             const uint8_t *src2= src[2]+(lastInChrBuf + 1 - chrSrcSliceY)*srcStride[2];
607             chrBufIndex++;
608             assert(chrBufIndex < 2*vChrBufSize);
609             assert(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH));
610             assert(lastInChrBuf + 1 - chrSrcSliceY >= 0);
611             //FIXME replace parameters through context struct (some at least)
612
613             if (c->needs_hcscale)
614                 RENAME(hcscale)(c, chrPixBuf[ chrBufIndex ], chrDstW, src1, src2, chrSrcW, chrXInc,
615                                 hChrFilter, hChrFilterPos, hChrFilterSize,
616                                 formatConvBuffer,
617                                 pal);
618             lastInChrBuf++;
619             DEBUG_BUFFERS("\t\tchrBufIndex %d: lastInChrBuf: %d\n",
620                                chrBufIndex,    lastInChrBuf);
621         }
622         //wrap buf index around to stay inside the ring buffer
623         if (lumBufIndex >= vLumBufSize) lumBufIndex-= vLumBufSize;
624         if (chrBufIndex >= vChrBufSize) chrBufIndex-= vChrBufSize;
625         if (!enough_lines)
626             break; //we can't output a dstY line so let's try with the next slice
627
628         if (dstY < dstH-2) {
629             const int16_t **lumSrcPtr= (const int16_t **) lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
630             const int16_t **chrSrcPtr= (const int16_t **) chrPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
631             const int16_t **alpSrcPtr= (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? (const int16_t **) alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
632             if (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21) {
633                 const int chrSkipMask= (1<<c->chrDstVSubSample)-1;
634                 if (dstY&chrSkipMask) uDest= NULL; //FIXME split functions in lumi / chromi
635                 c->yuv2nv12X(c,
636                              vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
637                              vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
638                              dest, uDest, dstW, chrDstW, dstFormat);
639             } else if (isPlanarYUV(dstFormat) || dstFormat==PIX_FMT_GRAY8) { //YV12 like
640                 const int chrSkipMask= (1<<c->chrDstVSubSample)-1;
641                 if ((dstY&chrSkipMask) || isGray(dstFormat)) uDest=vDest= NULL; //FIXME split functions in lumi / chromi
642                 if (is16BPS(dstFormat) || is9_OR_10BPS(dstFormat)) {
643                     yuv2yuvX16inC(
644                                   vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
645                                   vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
646                                   alpSrcPtr, (uint16_t *) dest, (uint16_t *) uDest, (uint16_t *) vDest, (uint16_t *) aDest, dstW, chrDstW,
647                                   dstFormat);
648                 } else if (vLumFilterSize == 1 && vChrFilterSize == 1) { // unscaled YV12
649                     const int16_t *lumBuf = lumSrcPtr[0];
650                     const int16_t *chrBuf= chrSrcPtr[0];
651                     const int16_t *alpBuf= (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? alpSrcPtr[0] : NULL;
652                     c->yuv2yuv1(c, lumBuf, chrBuf, alpBuf, dest, uDest, vDest, aDest, dstW, chrDstW);
653                 } else { //General YV12
654                     c->yuv2yuvX(c,
655                                 vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
656                                 vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
657                                 alpSrcPtr, dest, uDest, vDest, aDest, dstW, chrDstW);
658                 }
659             } else {
660                 assert(lumSrcPtr + vLumFilterSize - 1 < lumPixBuf + vLumBufSize*2);
661                 assert(chrSrcPtr + vChrFilterSize - 1 < chrPixBuf + vChrBufSize*2);
662                 if (vLumFilterSize == 1 && vChrFilterSize == 2) { //unscaled RGB
663                     int chrAlpha= vChrFilter[2*dstY+1];
664                     if(flags & SWS_FULL_CHR_H_INT) {
665                         yuv2rgbXinC_full(c, //FIXME write a packed1_full function
666                                          vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
667                                          vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
668                                          alpSrcPtr, dest, dstW, dstY);
669                     } else {
670                         c->yuv2packed1(c, *lumSrcPtr, *chrSrcPtr, *(chrSrcPtr+1),
671                                        alpPixBuf ? *alpSrcPtr : NULL,
672                                        dest, dstW, chrAlpha, dstFormat, flags, dstY);
673                     }
674                 } else if (vLumFilterSize == 2 && vChrFilterSize == 2) { //bilinear upscale RGB
675                     int lumAlpha= vLumFilter[2*dstY+1];
676                     int chrAlpha= vChrFilter[2*dstY+1];
677                     lumMmxFilter[2]=
678                     lumMmxFilter[3]= vLumFilter[2*dstY   ]*0x10001;
679                     chrMmxFilter[2]=
680                     chrMmxFilter[3]= vChrFilter[2*chrDstY]*0x10001;
681                     if(flags & SWS_FULL_CHR_H_INT) {
682                         yuv2rgbXinC_full(c, //FIXME write a packed2_full function
683                                          vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
684                                          vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
685                                          alpSrcPtr, dest, dstW, dstY);
686                     } else {
687                         c->yuv2packed2(c, *lumSrcPtr, *(lumSrcPtr+1), *chrSrcPtr, *(chrSrcPtr+1),
688                                        alpPixBuf ? *alpSrcPtr : NULL, alpPixBuf ? *(alpSrcPtr+1) : NULL,
689                                        dest, dstW, lumAlpha, chrAlpha, dstY);
690                     }
691                 } else { //general RGB
692                     if(flags & SWS_FULL_CHR_H_INT) {
693                         yuv2rgbXinC_full(c,
694                                          vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
695                                          vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
696                                          alpSrcPtr, dest, dstW, dstY);
697                     } else {
698                         c->yuv2packedX(c,
699                                        vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
700                                        vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
701                                        alpSrcPtr, dest, dstW, dstY);
702                     }
703                 }
704             }
705         } else { // hmm looks like we can't use MMX here without overwriting this array's tail
706             const int16_t **lumSrcPtr= (const int16_t **)lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
707             const int16_t **chrSrcPtr= (const int16_t **)chrPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
708             const int16_t **alpSrcPtr= (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? (const int16_t **)alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
709             if (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21) {
710                 const int chrSkipMask= (1<<c->chrDstVSubSample)-1;
711                 if (dstY&chrSkipMask) uDest= NULL; //FIXME split functions in lumi / chromi
712                 yuv2nv12XinC(
713                              vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
714                              vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
715                              dest, uDest, dstW, chrDstW, dstFormat);
716             } else if (isPlanarYUV(dstFormat) || dstFormat==PIX_FMT_GRAY8) { //YV12
717                 const int chrSkipMask= (1<<c->chrDstVSubSample)-1;
718                 if ((dstY&chrSkipMask) || isGray(dstFormat)) uDest=vDest= NULL; //FIXME split functions in lumi / chromi
719                 if (is16BPS(dstFormat) || is9_OR_10BPS(dstFormat)) {
720                     yuv2yuvX16inC(
721                                   vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
722                                   vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
723                                   alpSrcPtr, (uint16_t *) dest, (uint16_t *) uDest, (uint16_t *) vDest, (uint16_t *) aDest, dstW, chrDstW,
724                                   dstFormat);
725                 } else {
726                     yuv2yuvXinC(
727                                 vLumFilter+dstY*vLumFilterSize   , lumSrcPtr, vLumFilterSize,
728                                 vChrFilter+chrDstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
729                                 alpSrcPtr, dest, uDest, vDest, aDest, dstW, chrDstW);
730                 }
731             } else {
732                 assert(lumSrcPtr + vLumFilterSize - 1 < lumPixBuf + vLumBufSize*2);
733                 assert(chrSrcPtr + vChrFilterSize - 1 < chrPixBuf + vChrBufSize*2);
734                 if(flags & SWS_FULL_CHR_H_INT) {
735                     yuv2rgbXinC_full(c,
736                                      vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
737                                      vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
738                                      alpSrcPtr, dest, dstW, dstY);
739                 } else {
740                     yuv2packedXinC(c,
741                                    vLumFilter+dstY*vLumFilterSize, lumSrcPtr, vLumFilterSize,
742                                    vChrFilter+dstY*vChrFilterSize, chrSrcPtr, vChrFilterSize,
743                                    alpSrcPtr, dest, dstW, dstY);
744                 }
745             }
746         }
747     }
748
749     if ((dstFormat == PIX_FMT_YUVA420P) && !alpPixBuf)
750         fillPlane(dst[3], dstStride[3], dstW, dstY-lastDstY, lastDstY, 255);
751
752     /* store changed local vars back in the context */
753     c->dstY= dstY;
754     c->lumBufIndex= lumBufIndex;
755     c->chrBufIndex= chrBufIndex;
756     c->lastInLumBuf= lastInLumBuf;
757     c->lastInChrBuf= lastInChrBuf;
758
759     return dstY - lastDstY;
760 }
761
762 static void RENAME(sws_init_swScale)(SwsContext *c)
763 {
764     enum PixelFormat srcFormat = c->srcFormat;
765
766     c->yuv2nv12X    = RENAME(yuv2nv12X   );
767     c->yuv2yuv1     = RENAME(yuv2yuv1    );
768     c->yuv2yuvX     = RENAME(yuv2yuvX    );
769     c->yuv2packed1  = RENAME(yuv2packed1 );
770     c->yuv2packed2  = RENAME(yuv2packed2 );
771     c->yuv2packedX  = RENAME(yuv2packedX );
772
773     c->hScale       = RENAME(hScale      );
774
775     if (c->flags & SWS_FAST_BILINEAR)
776     {
777         c->hyscale_fast = RENAME(hyscale_fast);
778         c->hcscale_fast = RENAME(hcscale_fast);
779     }
780
781     switch(srcFormat) {
782         case PIX_FMT_YUYV422  : c->chrToYV12 = RENAME(yuy2ToUV); break;
783         case PIX_FMT_UYVY422  : c->chrToYV12 = RENAME(uyvyToUV); break;
784         case PIX_FMT_NV12     : c->chrToYV12 = RENAME(nv12ToUV); break;
785         case PIX_FMT_NV21     : c->chrToYV12 = RENAME(nv21ToUV); break;
786         case PIX_FMT_YUV420P16BE:
787         case PIX_FMT_YUV422P16BE:
788         case PIX_FMT_YUV444P16BE: c->chrToYV12 = RENAME(BEToUV); break;
789         case PIX_FMT_YUV420P16LE:
790         case PIX_FMT_YUV422P16LE:
791         case PIX_FMT_YUV444P16LE: c->chrToYV12 = RENAME(LEToUV); break;
792     }
793     if (c->chrSrcHSubSample) {
794         switch(srcFormat) {
795         case PIX_FMT_BGR24  : c->chrToYV12 = RENAME(bgr24ToUV_half); break;
796         case PIX_FMT_RGB24  : c->chrToYV12 = RENAME(rgb24ToUV_half); break;
797         }
798     } else {
799         switch(srcFormat) {
800         case PIX_FMT_BGR24  : c->chrToYV12 = RENAME(bgr24ToUV); break;
801         case PIX_FMT_RGB24  : c->chrToYV12 = RENAME(rgb24ToUV); break;
802         }
803     }
804
805     switch (srcFormat) {
806     case PIX_FMT_YUYV422  :
807     case PIX_FMT_YUV420P16BE:
808     case PIX_FMT_YUV422P16BE:
809     case PIX_FMT_YUV444P16BE:
810     case PIX_FMT_Y400A    :
811     case PIX_FMT_GRAY16BE : c->lumToYV12 = RENAME(yuy2ToY); break;
812     case PIX_FMT_UYVY422  :
813     case PIX_FMT_YUV420P16LE:
814     case PIX_FMT_YUV422P16LE:
815     case PIX_FMT_YUV444P16LE:
816     case PIX_FMT_GRAY16LE : c->lumToYV12 = RENAME(uyvyToY); break;
817     case PIX_FMT_BGR24    : c->lumToYV12 = RENAME(bgr24ToY); break;
818     case PIX_FMT_RGB24    : c->lumToYV12 = RENAME(rgb24ToY); break;
819     }
820     if (c->alpPixBuf) {
821         switch (srcFormat) {
822         case PIX_FMT_Y400A  : c->alpToYV12 = RENAME(yuy2ToY); break;
823         }
824     }
825
826     switch (srcFormat) {
827     case PIX_FMT_Y400A  :
828         c->alpSrcOffset = 1;
829         break;
830     case PIX_FMT_RGB32  :
831     case PIX_FMT_BGR32  :
832         c->alpSrcOffset = 3;
833         break;
834     case PIX_FMT_RGB48LE:
835         c->lumSrcOffset = 1;
836         c->chrSrcOffset = 1;
837         c->alpSrcOffset = 1;
838         break;
839     }
840
841     if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) {
842         if (c->srcRange) {
843             c->lumConvertRange = RENAME(lumRangeFromJpeg);
844             c->chrConvertRange = RENAME(chrRangeFromJpeg);
845         } else {
846             c->lumConvertRange = RENAME(lumRangeToJpeg);
847             c->chrConvertRange = RENAME(chrRangeToJpeg);
848         }
849     }
850
851     if (!(isGray(srcFormat) || isGray(c->dstFormat) ||
852           srcFormat == PIX_FMT_MONOBLACK || srcFormat == PIX_FMT_MONOWHITE))
853         c->needs_hcscale = 1;
854 }