C99 initializers and kill warnings patch by (mru at users dot sourceforge dot net...
[ffmpeg.git] / libavcodec / imgconvert.c
1 /*
2  * Misc image convertion routines
3  * Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "avcodec.h"
20 #include "dsputil.h"
21
22 #ifdef USE_FASTMEMCPY
23 #include "fastmemcpy.h"
24 #endif
25
26 #ifdef HAVE_MMX
27 #include "i386/mmx.h"
28 #endif
29
30 typedef struct PixFmtInfo {
31     const char *name;
32     UINT8 nb_components;     /* number of components in AVPicture array  */
33     UINT8 is_yuv : 1;    /* true if YUV instead of RGB color space */
34     UINT8 is_packed : 1; /* true if multiple components in same word */
35     UINT8 is_paletted : 1; /* true if paletted */
36     UINT8 is_alpha : 1;    /* true if alpha can be specified */
37     UINT8 is_gray : 1;     /* true if gray or monochrome format */
38     UINT8 x_chroma_shift; /* X chroma subsampling factor is 2 ^ shift */
39     UINT8 y_chroma_shift; /* Y chroma subsampling factor is 2 ^ shift */
40 } PixFmtInfo;
41
42 /* this table gives more information about formats */
43 static PixFmtInfo pix_fmt_info[PIX_FMT_NB] = {
44     /* YUV formats */
45     [PIX_FMT_YUV420P] = {
46         .name = "yuv420p",
47         .nb_components = 3, .is_yuv = 1,
48         .x_chroma_shift = 1, .y_chroma_shift = 1, 
49     },
50     [PIX_FMT_YUV422P] = {
51         .name = "yuv422p",
52         .nb_components = 3, .is_yuv = 1,
53         .x_chroma_shift = 1, .y_chroma_shift = 0, 
54     },
55     [PIX_FMT_YUV444P] = {
56         .name = "yuv444p",
57         .nb_components = 3, .is_yuv = 1,
58         .x_chroma_shift = 0, .y_chroma_shift = 0, 
59     },
60     [PIX_FMT_YUV422] = {
61         .name = "yuv422",
62         .nb_components = 1, .is_yuv = 1, .is_packed = 1,
63         .x_chroma_shift = 1, .y_chroma_shift = 0,
64     },
65     [PIX_FMT_YUV410P] = {
66         .name = "yuv410p",
67         .nb_components = 3, .is_yuv = 1,
68         .x_chroma_shift = 2, .y_chroma_shift = 2,
69     },
70     [PIX_FMT_YUV411P] = {
71         .name = "yuv411p",
72         .nb_components = 3, .is_yuv = 1,
73         .x_chroma_shift = 2, .y_chroma_shift = 0,
74     },
75
76     /* RGB formats */
77     [PIX_FMT_RGB24] = {
78         .name = "rgb24",
79         .nb_components = 1, .is_packed = 1,
80     },
81     [PIX_FMT_BGR24] = {
82         .name = "bgr24",
83         .nb_components = 1, .is_packed = 1,
84     },
85     [PIX_FMT_RGBA32] = {
86         .name = "rgba32",
87         .nb_components = 1, .is_packed = 1, .is_alpha = 1,
88     },
89     [PIX_FMT_RGB565] = {
90         .name = "rgb565",
91         .nb_components = 1, .is_packed = 1,
92     },
93     [PIX_FMT_RGB555] = {
94         .name = "rgb555",
95         .nb_components = 1, .is_packed = 1, .is_alpha = 1,
96     },
97
98     /* gray / mono formats */
99     [PIX_FMT_GRAY8] = {
100         .name = "gray",
101         .nb_components = 1, .is_gray = 1,
102     },
103     [PIX_FMT_MONOWHITE] = {
104         .name = "monow",
105         .nb_components = 1, .is_packed = 1, .is_gray = 1,
106     },
107     [PIX_FMT_MONOBLACK] = {
108         .name = "monob",
109         .nb_components = 1, .is_packed = 1, .is_gray = 1,
110     },
111 };
112
113 void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift)
114 {
115     if (pix_fmt_info[pix_fmt].is_yuv) {
116         *h_shift = pix_fmt_info[pix_fmt].x_chroma_shift;
117         *v_shift = pix_fmt_info[pix_fmt].y_chroma_shift;
118     } else {
119         *h_shift=0;
120         *v_shift=0;
121     }
122 }
123
124 const char *avcodec_get_pix_fmt_name(int pix_fmt)
125 {
126     if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB)
127         return "???";
128     else
129         return pix_fmt_info[pix_fmt].name;
130 }
131
132 /* Picture field are filled with 'ptr' addresses. Also return size */
133 int avpicture_fill(AVPicture *picture, UINT8 *ptr,
134                    int pix_fmt, int width, int height)
135 {
136     int size;
137
138     size = width * height;
139     switch(pix_fmt) {
140     case PIX_FMT_YUV420P:
141         picture->data[0] = ptr;
142         picture->data[1] = picture->data[0] + size;
143         picture->data[2] = picture->data[1] + size / 4;
144         picture->linesize[0] = width;
145         picture->linesize[1] = width / 2;
146         picture->linesize[2] = width / 2;
147         return (size * 3) / 2;
148     case PIX_FMT_RGB24:
149     case PIX_FMT_BGR24:
150         picture->data[0] = ptr;
151         picture->data[1] = NULL;
152         picture->data[2] = NULL;
153         picture->linesize[0] = width * 3;
154         return size * 3;
155     case PIX_FMT_YUV422P:
156         picture->data[0] = ptr;
157         picture->data[1] = picture->data[0] + size;
158         picture->data[2] = picture->data[1] + size / 2;
159         picture->linesize[0] = width;
160         picture->linesize[1] = width / 2;
161         picture->linesize[2] = width / 2;
162         return (size * 2);
163     case PIX_FMT_YUV444P:
164         picture->data[0] = ptr;
165         picture->data[1] = picture->data[0] + size;
166         picture->data[2] = picture->data[1] + size;
167         picture->linesize[0] = width;
168         picture->linesize[1] = width;
169         picture->linesize[2] = width;
170         return size * 3;
171     case PIX_FMT_RGBA32:
172         picture->data[0] = ptr;
173         picture->data[1] = NULL;
174         picture->data[2] = NULL;
175         picture->linesize[0] = width * 4;
176         return size * 4;
177     case PIX_FMT_YUV410P:
178         picture->data[0] = ptr;
179         picture->data[1] = picture->data[0] + size;
180         picture->data[2] = picture->data[1] + size / 16;
181         picture->linesize[0] = width;
182         picture->linesize[1] = width / 4;
183         picture->linesize[2] = width / 4;
184         return size + (size / 8);
185     case PIX_FMT_YUV411P:
186         picture->data[0] = ptr;
187         picture->data[1] = picture->data[0] + size;
188         picture->data[2] = picture->data[1] + size / 4;
189         picture->linesize[0] = width;
190         picture->linesize[1] = width / 4;
191         picture->linesize[2] = width / 4;
192         return size + (size / 2);
193     case PIX_FMT_RGB555:
194     case PIX_FMT_RGB565:
195     case PIX_FMT_YUV422:
196         picture->data[0] = ptr;
197         picture->data[1] = NULL;
198         picture->data[2] = NULL;
199         picture->linesize[0] = width * 2;
200         return size * 2;
201     case PIX_FMT_GRAY8:
202         picture->data[0] = ptr;
203         picture->data[1] = NULL;
204         picture->data[2] = NULL;
205         picture->linesize[0] = width;
206         return size;
207     case PIX_FMT_MONOWHITE:
208     case PIX_FMT_MONOBLACK:
209         picture->data[0] = ptr;
210         picture->data[1] = NULL;
211         picture->data[2] = NULL;
212         picture->linesize[0] = (width + 7) >> 3;
213         return picture->linesize[0] * height;
214     default:
215         picture->data[0] = NULL;
216         picture->data[1] = NULL;
217         picture->data[2] = NULL;
218         return -1;
219     }
220 }
221
222 int avpicture_get_size(int pix_fmt, int width, int height)
223 {
224     AVPicture dummy_pict;
225     return avpicture_fill(&dummy_pict, NULL, pix_fmt, width, height);
226 }
227
228
229 /* XXX: totally non optimized */
230
231 static void yuv422_to_yuv420p(AVPicture *dst, AVPicture *src,
232                               int width, int height)
233 {
234     UINT8 *lum, *cb, *cr;
235     int x, y;
236     const UINT8 *p;
237  
238     lum = dst->data[0];
239     cb = dst->data[1];
240     cr = dst->data[2];
241     p = src->data[0];
242    
243     for(y=0;y<height;y+=2) {
244         for(x=0;x<width;x+=2) {
245             lum[0] = p[0];
246             cb[0] = p[1];
247             lum[1] = p[2];
248             cr[0] = p[3];
249             p += 4;
250             lum += 2;
251             cb++;
252             cr++;
253         }
254         for(x=0;x<width;x+=2) {
255             lum[0] = p[0];
256             lum[1] = p[2];
257             p += 4;
258             lum += 2;
259         }
260     }
261 }
262
263 #define SCALEBITS 8
264 #define ONE_HALF  (1 << (SCALEBITS - 1))
265 #define FIX(x)          ((int) ((x) * (1L<<SCALEBITS) + 0.5))
266
267 /* XXX: use generic filter ? */
268 /* 1x2 -> 1x1 */
269 static void shrink2(UINT8 *dst, int dst_wrap, 
270                     UINT8 *src, int src_wrap,
271                     int width, int height)
272 {
273     int w;
274     UINT8 *s1, *s2, *d;
275
276     for(;height > 0; height--) {
277         s1 = src;
278         s2 = s1 + src_wrap;
279         d = dst;
280         for(w = width;w >= 4; w-=4) {
281             d[0] = (s1[0] + s2[0]) >> 1;
282             d[1] = (s1[1] + s2[1]) >> 1;
283             d[2] = (s1[2] + s2[2]) >> 1;
284             d[3] = (s1[3] + s2[3]) >> 1;
285             s1 += 4;
286             s2 += 4;
287             d += 4;
288         }
289         for(;w > 0; w--) {
290             d[0] = (s1[0] + s2[0]) >> 1;
291             s1++;
292             s2++;
293             d++;
294         }
295         src += 2 * src_wrap;
296         dst += dst_wrap;
297     }
298 }
299
300 /* 2x2 -> 1x1 */
301 static void shrink22(UINT8 *dst, int dst_wrap, 
302                      UINT8 *src, int src_wrap,
303                      int width, int height)
304 {
305     int w;
306     UINT8 *s1, *s2, *d;
307
308     for(;height > 0; height--) {
309         s1 = src;
310         s2 = s1 + src_wrap;
311         d = dst;
312         for(w = width;w >= 4; w-=4) {
313             d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 1;
314             d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 1;
315             d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 1;
316             d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 1;
317             s1 += 8;
318             s2 += 8;
319             d += 4;
320         }
321         for(;w > 0; w--) {
322             d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 1;
323             s1 += 2;
324             s2 += 2;
325             d++;
326         }
327         src += 2 * src_wrap;
328         dst += dst_wrap;
329     }
330 }
331
332 /* 1x1 -> 2x2 */
333 static void grow22(UINT8 *dst, int dst_wrap,
334                      UINT8 *src, int src_wrap,
335                      int width, int height)
336 {
337     int w;
338     UINT8 *s1, *d;
339
340     for(;height > 0; height--) {
341         s1 = src;
342         d = dst;
343         for(w = width;w >= 4; w-=4) {
344             d[1] = d[0] = s1[0];
345             d[3] = d[2] = s1[1];
346             s1 += 2;
347             d += 4;
348         }
349         for(;w > 0; w--) {
350             d[0] = s1[0];
351             s1 ++;
352             d++;
353         }
354         if (height%2)
355             src += src_wrap;
356         dst += dst_wrap;
357     }
358 }
359
360 /* 1x2 -> 2x1 */
361 static void conv411(UINT8 *dst, int dst_wrap, 
362                     UINT8 *src, int src_wrap,
363                     int width, int height)
364 {
365     int w, c;
366     UINT8 *s1, *s2, *d;
367
368     for(;height > 0; height--) {
369         s1 = src;
370         s2 = src + src_wrap;
371         d = dst;
372         for(w = width;w > 0; w--) {
373             c = (s1[0] + s2[0]) >> 1;
374             d[0] = c;
375             d[1] = c;
376             s1++;
377             s2++;
378             d += 2;
379         }
380         src += src_wrap * 2;
381         dst += dst_wrap;
382     }
383 }
384
385 static void img_copy(UINT8 *dst, int dst_wrap, 
386                      UINT8 *src, int src_wrap,
387                      int width, int height)
388 {
389     for(;height > 0; height--) {
390         memcpy(dst, src, width);
391         dst += dst_wrap;
392         src += src_wrap;
393     }
394 }
395
396 #define SCALE_BITS 10
397
398 #define C_Y  (76309 >> (16 - SCALE_BITS))
399 #define C_RV (117504 >> (16 - SCALE_BITS))
400 #define C_BU (138453 >> (16 - SCALE_BITS))
401 #define C_GU (13954 >> (16 - SCALE_BITS))
402 #define C_GV (34903 >> (16 - SCALE_BITS))
403
404 #define YUV_TO_RGB2(r, g, b, y1)\
405 {\
406     y = (y1 - 16) * C_Y;\
407     r = cm[(y + r_add) >> SCALE_BITS];\
408     g = cm[(y + g_add) >> SCALE_BITS];\
409     b = cm[(y + b_add) >> SCALE_BITS];\
410 }
411
412 /* XXX: no chroma interpolating is done */
413 #define RGB_FUNCTIONS(rgb_name)                                         \
414                                                                         \
415 static void yuv420p_to_ ## rgb_name (AVPicture *dst, AVPicture *src,    \
416                                      int width, int height)             \
417 {                                                                       \
418     UINT8 *y1_ptr, *y2_ptr, *cb_ptr, *cr_ptr, *d, *d1, *d2;             \
419     int w, y, cb, cr, r_add, g_add, b_add, width2;                      \
420     UINT8 *cm = cropTbl + MAX_NEG_CROP;                                 \
421     unsigned int r, g, b;                                               \
422                                                                         \
423     d = dst->data[0];                                                   \
424     y1_ptr = src->data[0];                                              \
425     cb_ptr = src->data[1];                                              \
426     cr_ptr = src->data[2];                                              \
427     width2 = width >> 1;                                                \
428     for(;height > 0; height -= 2) {                                     \
429         d1 = d;                                                         \
430         d2 = d + dst->linesize[0];                                      \
431         y2_ptr = y1_ptr + src->linesize[0];                             \
432         for(w = width2; w > 0; w --) {                                  \
433             cb = cb_ptr[0] - 128;                                       \
434             cr = cr_ptr[0] - 128;                                       \
435             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
436             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
437             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
438                                                                         \
439             /* output 4 pixels */                                       \
440             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
441             RGB_OUT(d1, r, g, b);                                       \
442                                                                         \
443             YUV_TO_RGB2(r, g, b, y1_ptr[1]);                            \
444             RGB_OUT(d1 + BPP, r, g, b);                                 \
445                                                                         \
446             YUV_TO_RGB2(r, g, b, y2_ptr[0]);                            \
447             RGB_OUT(d2, r, g, b);                                       \
448                                                                         \
449             YUV_TO_RGB2(r, g, b, y2_ptr[1]);                            \
450             RGB_OUT(d2 + BPP, r, g, b);                                 \
451                                                                         \
452             d1 += 2 * BPP;                                              \
453             d2 += 2 * BPP;                                              \
454                                                                         \
455             y1_ptr += 2;                                                \
456             y2_ptr += 2;                                                \
457             cb_ptr++;                                                   \
458             cr_ptr++;                                                   \
459         }                                                               \
460         d += 2 * dst->linesize[0];                                      \
461         y1_ptr += 2 * src->linesize[0] - width;                         \
462         cb_ptr += src->linesize[1] - width2;                            \
463         cr_ptr += src->linesize[2] - width2;                            \
464     }                                                                   \
465 }                                                                       \
466                                                                         \
467 /* XXX: no chroma interpolating is done */                              \
468 static void yuv422p_to_ ## rgb_name (AVPicture *dst, AVPicture *src,    \
469                                     int width, int height)              \
470 {                                                                       \
471     UINT8 *y1_ptr, *cb_ptr, *cr_ptr, *d, *d1;                           \
472     int w, y, cb, cr, r_add, g_add, b_add, width2;                      \
473     UINT8 *cm = cropTbl + MAX_NEG_CROP;                                 \
474     unsigned int r, g, b;                                               \
475                                                                         \
476     d = dst->data[0];                                                   \
477     y1_ptr = src->data[0];                                              \
478     cb_ptr = src->data[1];                                              \
479     cr_ptr = src->data[2];                                              \
480     width2 = width >> 1;                                                \
481     for(;height > 0; height --) {                                       \
482         d1 = d;                                                         \
483         for(w = width2; w > 0; w --) {                                  \
484             cb = cb_ptr[0] - 128;                                       \
485             cr = cr_ptr[0] - 128;                                       \
486             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
487             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
488             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
489                                                                         \
490             /* output 2 pixels */                                       \
491             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
492             RGB_OUT(d, r, g, b);                                        \
493                                                                         \
494             YUV_TO_RGB2(r, g, b, y1_ptr[1]);                            \
495             RGB_OUT(d + BPP, r, g, b);                                  \
496                                                                         \
497             d += 2 * BPP;                                               \
498                                                                         \
499             y1_ptr += 2;                                                \
500             cb_ptr++;                                                   \
501             cr_ptr++;                                                   \
502         }                                                               \
503         d += dst->linesize[0];                                          \
504         y1_ptr += src->linesize[0] - width;                             \
505         cb_ptr += src->linesize[1] - width2;                            \
506         cr_ptr += src->linesize[2] - width2;                            \
507     }                                                                   \
508 }                                                                       \
509                                                                         \
510 static void rgb_name ## _to_yuv420p(AVPicture *dst, AVPicture *src,     \
511                                     int width, int height)              \
512 {                                                                       \
513     int wrap, wrap3, x, y;                                              \
514     int r, g, b, r1, g1, b1;                                            \
515     UINT8 *lum, *cb, *cr;                                               \
516     const UINT8 *p;                                                     \
517                                                                         \
518     lum = dst->data[0];                                                 \
519     cb = dst->data[1];                                                  \
520     cr = dst->data[2];                                                  \
521                                                                         \
522     wrap = width;                                                       \
523     wrap3 = width * 3;                                                  \
524     p = src->data[0];                                                   \
525     for(y=0;y<height;y+=2) {                                            \
526         for(x=0;x<width;x+=2) {                                         \
527             RGB_IN(r, g, b, p);                                         \
528             r1 = r;                                                     \
529             g1 = g;                                                     \
530             b1 = b;                                                     \
531             lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
532                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
533             RGB_IN(r, g, b, p + BPP);                                   \
534             r1 += r;                                                    \
535             g1 += g;                                                    \
536             b1 += b;                                                    \
537             lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
538                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
539             p += wrap3;                                                 \
540             lum += wrap;                                                \
541                                                                         \
542             RGB_IN(r, g, b, p);                                         \
543             r1 += r;                                                    \
544             g1 += g;                                                    \
545             b1 += b;                                                    \
546             lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
547                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
548                                                                         \
549             RGB_IN(r, g, b, p + BPP);                                   \
550             r1 += r;                                                    \
551             g1 += g;                                                    \
552             b1 += b;                                                    \
553             lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
554                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
555                                                                         \
556             cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +         \
557                       FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >>          \
558                      (SCALEBITS + 2)) + 128;                            \
559             cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 -           \
560                      FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >>           \
561                      (SCALEBITS + 2)) + 128;                            \
562                                                                         \
563             cb++;                                                       \
564             cr++;                                                       \
565             p += -wrap3 + 2 * 3;                                        \
566             lum += -wrap + 2;                                           \
567         }                                                               \
568         p += wrap3;                                                     \
569         lum += wrap;                                                    \
570     }                                                                   \
571 }
572
573 /* copy bit n to bits 0 ... n - 1 */
574 static inline unsigned int bitcopy_n(unsigned int a, int n)
575 {
576     int mask;
577     mask = (1 << n) - 1;
578     return (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask);
579 }
580
581 /* rgb555 handling */
582
583 #define RGB_IN(r, g, b, s)\
584 {\
585     unsigned int v = ((UINT16 *)(s))[0];\
586     r = bitcopy_n(v >> (10 - 3), 3);\
587     g = bitcopy_n(v >> (5 - 3), 3);\
588     b = bitcopy_n(v << 3, 3);\
589 }
590
591 #define RGB_OUT(d, r, g, b)\
592 {\
593     ((UINT16 *)(d))[0] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;\
594 }
595
596 #define BPP 2
597
598 RGB_FUNCTIONS(rgb555)
599
600 #undef RGB_IN
601 #undef RGB_OUT
602 #undef BPP
603
604 /* rgb565 handling */
605
606 #define RGB_IN(r, g, b, s)\
607 {\
608     unsigned int v = ((UINT16 *)(s))[0];\
609     r = bitcopy_n(v >> (11 - 3), 3);\
610     g = bitcopy_n(v >> (5 - 2), 2);\
611     b = bitcopy_n(v << 3, 3);\
612 }
613
614 #define RGB_OUT(d, r, g, b)\
615 {\
616     ((UINT16 *)(d))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\
617 }
618
619 #define BPP 2
620
621 RGB_FUNCTIONS(rgb565)
622
623 #undef RGB_IN
624 #undef RGB_OUT
625 #undef BPP
626
627 /* bgr24 handling */
628
629 #define RGB_IN(r, g, b, s)\
630 {\
631     b = (s)[0];\
632     g = (s)[1];\
633     r = (s)[2];\
634 }
635
636 #define RGB_OUT(d, r, g, b)\
637 {\
638     (d)[0] = b;\
639     (d)[1] = g;\
640     (d)[2] = r;\
641 }
642
643 #define BPP 3
644
645 RGB_FUNCTIONS(bgr24)
646
647 #undef RGB_IN
648 #undef RGB_OUT
649 #undef BPP
650
651 /* rgb24 handling */
652
653 #define RGB_IN(r, g, b, s)\
654 {\
655     r = (s)[0];\
656     g = (s)[1];\
657     b = (s)[2];\
658 }
659
660 #define RGB_OUT(d, r, g, b)\
661 {\
662     (d)[0] = r;\
663     (d)[1] = g;\
664     (d)[2] = b;\
665 }
666
667 #define BPP 3
668
669 RGB_FUNCTIONS(rgb24)
670
671 #undef RGB_IN
672 #undef RGB_OUT
673 #undef BPP
674
675 /* rgba32 handling */
676
677 #define RGB_IN(r, g, b, s)\
678 {\
679     unsigned int v = ((UINT32 *)(s))[0];\
680     r = (v >> 16) & 0xff;\
681     g = (v >> 8) & 0xff;\
682     b = v & 0xff;\
683 }
684
685 #define RGB_OUT(d, r, g, b)\
686 {\
687     ((UINT32 *)(d))[0] = (0xff << 24) | (r << 16) | (g << 8) | b;\
688 }
689
690 #define BPP 4
691
692 RGB_FUNCTIONS(rgba32)
693
694 #undef RGB_IN
695 #undef RGB_OUT
696 #undef BPP
697
698
699 static void rgb24_to_rgb565(AVPicture *dst, AVPicture *src,
700                             int width, int height)
701 {
702     const unsigned char *p;
703     unsigned char *q;
704     int r, g, b, dst_wrap, src_wrap;
705     int x, y;
706
707     p = src->data[0];
708     src_wrap = src->linesize[0] - 3 * width;
709
710     q = dst->data[0];
711     dst_wrap = dst->linesize[0] - 2 * width;
712
713     for(y=0;y<height;y++) {
714         for(x=0;x<width;x++) {
715             r = p[0];
716             g = p[1];
717             b = p[2];
718
719             ((unsigned short *)q)[0] = 
720                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
721             q += 2;
722             p += 3;
723         }
724         p += src_wrap;
725         q += dst_wrap;
726     }
727 }
728
729 /* NOTE: we also add a dummy alpha bit */
730 static void rgb24_to_rgb555(AVPicture *dst, AVPicture *src,
731                             int width, int height)
732 {
733     const unsigned char *p;
734     unsigned char *q;
735     int r, g, b, dst_wrap, src_wrap;
736     int x, y;
737
738     p = src->data[0];
739     src_wrap = src->linesize[0] - 3 * width;
740
741     q = dst->data[0];
742     dst_wrap = dst->linesize[0] - 2 * width;
743
744     for(y=0;y<height;y++) {
745         for(x=0;x<width;x++) {
746             r = p[0];
747             g = p[1];
748             b = p[2];
749
750             ((unsigned short *)q)[0] = 
751                 ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;
752             q += 2;
753             p += 3;
754         }
755         p += src_wrap;
756         q += dst_wrap;
757     }
758 }
759
760 static void rgb24_to_gray(AVPicture *dst, AVPicture *src,
761                           int width, int height)
762 {
763     const unsigned char *p;
764     unsigned char *q;
765     int r, g, b, dst_wrap, src_wrap;
766     int x, y;
767
768     p = src->data[0];
769     src_wrap = src->linesize[0] - 3 * width;
770
771     q = dst->data[0];
772     dst_wrap = dst->linesize[0] - width;
773
774     for(y=0;y<height;y++) {
775         for(x=0;x<width;x++) {
776             r = p[0];
777             g = p[1];
778             b = p[2];
779
780             q[0] = (FIX(0.29900) * r + FIX(0.58700) * g + 
781                     FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
782             q++;
783             p += 3;
784         }
785         p += src_wrap;
786         q += dst_wrap;
787     }
788 }
789
790 static void gray_to_rgb24(AVPicture *dst, AVPicture *src,
791                           int width, int height)
792 {
793     const unsigned char *p;
794     unsigned char *q;
795     int r, dst_wrap, src_wrap;
796     int x, y;
797
798     p = src->data[0];
799     src_wrap = src->linesize[0] - width;
800
801     q = dst->data[0];
802     dst_wrap = dst->linesize[0] - 3 * width;
803
804     for(y=0;y<height;y++) {
805         for(x=0;x<width;x++) {
806             r = p[0];
807
808             q[0] = r;
809             q[1] = r;
810             q[2] = r;
811             
812             q += 3;
813             p ++;
814         }
815         p += src_wrap;
816         q += dst_wrap;
817     }
818 }
819
820 static void mono_to_gray(AVPicture *dst, AVPicture *src,
821                          int width, int height, int xor_mask)
822 {
823     const unsigned char *p;
824     unsigned char *q;
825     int v, dst_wrap, src_wrap;
826     int y, w;
827
828     p = src->data[0];
829     src_wrap = src->linesize[0] - ((width + 7) >> 3);
830
831     q = dst->data[0];
832     dst_wrap = dst->linesize[0] - width;
833     for(y=0;y<height;y++) {
834         w = width; 
835         while (w >= 8) {
836             v = *p++ ^ xor_mask;
837             q[0] = -(v >> 7);
838             q[1] = -((v >> 6) & 1);
839             q[2] = -((v >> 5) & 1);
840             q[3] = -((v >> 4) & 1);
841             q[4] = -((v >> 3) & 1);
842             q[5] = -((v >> 2) & 1);
843             q[6] = -((v >> 1) & 1);
844             q[7] = -((v >> 0) & 1);
845             w -= 8;
846             q += 8;
847         }
848         if (w > 0) {
849             v = *p++ ^ xor_mask;
850             do {
851                 q[0] = -((v >> 7) & 1);
852                 q++;
853                 v <<= 1;
854             } while (--w);
855         }
856         p += src_wrap;
857         q += dst_wrap;
858     }
859 }
860
861 static void monowhite_to_gray(AVPicture *dst, AVPicture *src,
862                                int width, int height)
863 {
864     mono_to_gray(dst, src, width, height, 0xff);
865 }
866
867 static void monoblack_to_gray(AVPicture *dst, AVPicture *src,
868                                int width, int height)
869 {
870     mono_to_gray(dst, src, width, height, 0x00);
871 }
872
873 static void gray_to_mono(AVPicture *dst, AVPicture *src,
874                          int width, int height, int xor_mask)
875 {
876     int n;
877     const UINT8 *s;
878     UINT8 *d;
879     int j, b, v, n1, src_wrap, dst_wrap, y;
880
881     s = src->data[0];
882     src_wrap = src->linesize[0] - width;
883
884     d = dst->data[0];
885     dst_wrap = dst->linesize[0] - ((width + 7) >> 3);
886     printf("%d %d\n", width, height);
887
888     for(y=0;y<height;y++) {
889         n = width;
890         while (n >= 8) {
891             v = 0;
892             for(j=0;j<8;j++) {
893                 b = s[0];
894                 s++;
895                 v = (v << 1) | (b >> 7);
896             }
897             d[0] = v ^ xor_mask;
898             d++;
899             n -= 8;
900         }
901         if (n > 0) {
902             n1 = n;
903             v = 0;
904             while (n > 0) {
905                 b = s[0];
906                 s++;
907                 v = (v << 1) | (b >> 7);
908                 n--;
909             }
910             d[0] = (v << (8 - (n1 & 7))) ^ xor_mask;
911             d++;
912         }
913         s += src_wrap;
914         d += dst_wrap;
915     }
916 }
917
918 static void gray_to_monowhite(AVPicture *dst, AVPicture *src,
919                               int width, int height)
920 {
921     gray_to_mono(dst, src, width, height, 0xff);
922 }
923
924 static void gray_to_monoblack(AVPicture *dst, AVPicture *src,
925                               int width, int height)
926 {
927     gray_to_mono(dst, src, width, height, 0x00);
928 }
929
930 typedef struct ConvertEntry {
931     void (*convert)(AVPicture *dst, AVPicture *src, int width, int height);
932 } ConvertEntry;
933
934 /* add each new convertion function in this table */
935 /* constraints;
936    - all non YUV modes must convert at least to and from PIX_FMT_RGB24
937 */
938 static ConvertEntry convert_table[PIX_FMT_NB][PIX_FMT_NB] = {
939     [PIX_FMT_YUV420P] = {
940         [PIX_FMT_RGB555] = { 
941             .convert = yuv420p_to_rgb555
942         },
943         [PIX_FMT_RGB565] = { 
944             .convert = yuv420p_to_rgb565
945         },
946         [PIX_FMT_BGR24] = { 
947             .convert = yuv420p_to_bgr24
948         },
949         [PIX_FMT_RGB24] = { 
950             .convert = yuv420p_to_rgb24
951         },
952         [PIX_FMT_RGBA32] = { 
953             .convert = yuv420p_to_rgba32
954         },
955     },
956     [PIX_FMT_YUV422P] = {
957         [PIX_FMT_RGB555] = { 
958             .convert = yuv422p_to_rgb555
959         },
960         [PIX_FMT_RGB565] = { 
961             .convert = yuv422p_to_rgb565
962         },
963         [PIX_FMT_BGR24] = { 
964             .convert = yuv422p_to_bgr24
965         },
966         [PIX_FMT_RGB24] = { 
967             .convert = yuv422p_to_rgb24
968         },
969         [PIX_FMT_RGBA32] = { 
970             .convert = yuv422p_to_rgba32
971         },
972     },
973     [PIX_FMT_YUV422] = { 
974         [PIX_FMT_YUV420P] = { 
975             .convert = yuv422_to_yuv420p,
976         },
977     },
978
979     [PIX_FMT_RGB24] = {
980         [PIX_FMT_YUV420P] = { 
981             .convert = rgb24_to_yuv420p
982         },
983         [PIX_FMT_RGB565] = { 
984             .convert = rgb24_to_rgb565
985         },
986         [PIX_FMT_RGB555] = { 
987             .convert = rgb24_to_rgb555
988         },
989         [PIX_FMT_GRAY8] = { 
990             .convert = rgb24_to_gray
991         },
992     },
993     [PIX_FMT_RGBA32] = {
994         [PIX_FMT_YUV420P] = { 
995             .convert = rgba32_to_yuv420p
996         },
997     },
998     [PIX_FMT_BGR24] = {
999         [PIX_FMT_YUV420P] = { 
1000             .convert = bgr24_to_yuv420p
1001         },
1002     },
1003     [PIX_FMT_RGB555] = {
1004         [PIX_FMT_YUV420P] = { 
1005             .convert = rgb555_to_yuv420p
1006         },
1007     },
1008     [PIX_FMT_RGB565] = {
1009         [PIX_FMT_YUV420P] = { 
1010             .convert = rgb565_to_yuv420p
1011         },
1012     },
1013     [PIX_FMT_GRAY8] = {
1014         [PIX_FMT_RGB24] = { 
1015             .convert = gray_to_rgb24
1016         },
1017         [PIX_FMT_MONOWHITE] = { 
1018             .convert = gray_to_monowhite
1019         },
1020         [PIX_FMT_MONOBLACK] = { 
1021             .convert = gray_to_monoblack
1022         },
1023     },
1024     [PIX_FMT_MONOWHITE] = {
1025         [PIX_FMT_GRAY8] = { 
1026             .convert = monowhite_to_gray
1027         },
1028     },
1029     [PIX_FMT_MONOBLACK] = {
1030         [PIX_FMT_GRAY8] = { 
1031             .convert = monoblack_to_gray
1032         },
1033     },
1034 };
1035
1036 static int avpicture_alloc(AVPicture *picture,
1037                            int pix_fmt, int width, int height)
1038 {
1039     int size;
1040     void *ptr;
1041
1042     size = avpicture_get_size(pix_fmt, width, height);
1043     if (size < 0)
1044         goto fail;
1045     ptr = av_malloc(size);
1046     if (!ptr)
1047         goto fail;
1048     avpicture_fill(picture, ptr, pix_fmt, width, height);
1049     return 0;
1050  fail:
1051     memset(picture, 0, sizeof(AVPicture));
1052     return -1;
1053 }
1054
1055 static void avpicture_free(AVPicture *picture)
1056 {
1057     free(picture->data[0]);
1058 }
1059
1060 /* XXX: always use linesize. Return -1 if not supported */
1061 int img_convert(AVPicture *dst, int dst_pix_fmt,
1062                 AVPicture *src, int src_pix_fmt, 
1063                 int src_width, int src_height)
1064 {
1065     int i, ret, dst_width, dst_height, int_pix_fmt;
1066     PixFmtInfo *src_pix, *dst_pix;
1067     ConvertEntry *ce;
1068     AVPicture tmp1, *tmp = &tmp1;
1069
1070     if (src_pix_fmt < 0 || src_pix_fmt >= PIX_FMT_NB ||
1071         dst_pix_fmt < 0 || dst_pix_fmt >= PIX_FMT_NB)
1072         return -1;
1073     if (src_width <= 0 || src_height <= 0)
1074         return 0;
1075     
1076     dst_width = src_width;
1077     dst_height = src_height;
1078     
1079     dst_pix = &pix_fmt_info[dst_pix_fmt];
1080     src_pix = &pix_fmt_info[src_pix_fmt];
1081     if (src_pix_fmt == dst_pix_fmt) {
1082         /* XXX: incorrect */
1083         /* same format: just copy */
1084         for(i = 0; i < dst_pix->nb_components; i++) {
1085             int w, h;
1086             w = dst_width;
1087             h = dst_height;
1088             if (dst_pix->is_yuv && (i == 1 || i == 2)) {
1089                 w >>= dst_pix->x_chroma_shift;
1090                 h >>= dst_pix->y_chroma_shift;
1091             }
1092             img_copy(dst->data[i], dst->linesize[i],
1093                      src->data[i], src->linesize[i],
1094                      w, h);
1095         }
1096         return 0;
1097     }
1098
1099     ce = &convert_table[src_pix_fmt][dst_pix_fmt];
1100     if (ce->convert) {
1101         /* specific convertion routine */
1102         ce->convert(dst, src, dst_width, dst_height);
1103         return 0;
1104     }
1105
1106     /* gray to YUV */
1107     if (dst_pix->is_yuv && src_pix_fmt == PIX_FMT_GRAY8) {
1108         int w, h, y;
1109         uint8_t *d;
1110
1111         img_copy(dst->data[0], dst->linesize[0],
1112                  src->data[0], src->linesize[0],
1113                  dst_width, dst_height);
1114         /* fill U and V with 128 */
1115         w = dst_width;
1116         h = dst_height;
1117         w >>= dst_pix->x_chroma_shift;
1118         h >>= dst_pix->y_chroma_shift;
1119         for(i = 1; i <= 2; i++) {
1120             d = dst->data[i];
1121             for(y = 0; y< h; y++) {
1122                 memset(d, 128, w);
1123                 d += dst->linesize[i];
1124             }
1125         }
1126         return 0;
1127     }
1128
1129     /* YUV to gray */
1130     if (src_pix->is_yuv && dst_pix_fmt == PIX_FMT_GRAY8) {
1131         img_copy(dst->data[0], dst->linesize[0],
1132                  src->data[0], src->linesize[0],
1133                  dst_width, dst_height);
1134         return 0;
1135     }
1136
1137     /* YUV to YUV */
1138     if (dst_pix->is_yuv && src_pix->is_yuv) {
1139         int x_shift, y_shift, w, h;
1140         void (*resize_func)(UINT8 *dst, int dst_wrap, 
1141                             UINT8 *src, int src_wrap,
1142                             int width, int height);
1143
1144         /* compute chroma size of the smallest dimensions */
1145         w = dst_width;
1146         h = dst_height;
1147         if (dst_pix->x_chroma_shift >= src_pix->x_chroma_shift)
1148             w >>= dst_pix->x_chroma_shift;
1149         else
1150             w >>= src_pix->x_chroma_shift;
1151         if (dst_pix->y_chroma_shift >= src_pix->y_chroma_shift)
1152             h >>= dst_pix->y_chroma_shift;
1153         else
1154             h >>= src_pix->y_chroma_shift;
1155
1156         x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);
1157         y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);
1158         if (x_shift == 0 && y_shift == 0) {
1159             resize_func = img_copy; /* should never happen */
1160         } else if (x_shift == 0 && y_shift == 1) {
1161             resize_func = shrink2;
1162         } else if (x_shift == 1 && y_shift == 1) {
1163             resize_func = shrink22;
1164         } else if (x_shift == -1 && y_shift == -1) {
1165             resize_func = grow22;
1166         } else if (x_shift == -1 && y_shift == 1) {
1167             resize_func = conv411;
1168         } else {
1169             /* currently not handled */
1170             return -1;
1171         }
1172
1173         img_copy(dst->data[0], dst->linesize[0],
1174                  src->data[0], src->linesize[0],
1175                  dst_width, dst_height);
1176         for(i = 1;i <= 2; i++)
1177             resize_func(dst->data[1], dst->linesize[1],
1178                         src->data[1], src->linesize[1],
1179                         w, h);
1180     }
1181
1182     /* try to use an intermediate format */
1183     if (src_pix_fmt == PIX_FMT_MONOWHITE ||
1184         src_pix_fmt == PIX_FMT_MONOBLACK ||
1185         dst_pix_fmt == PIX_FMT_MONOWHITE ||
1186         dst_pix_fmt == PIX_FMT_MONOBLACK) {
1187         int_pix_fmt = PIX_FMT_GRAY8;
1188     } else {
1189         int_pix_fmt = PIX_FMT_RGB24;
1190     }
1191     if (avpicture_alloc(tmp, int_pix_fmt, dst_width, dst_height) < 0)
1192         return -1;
1193     ret = -1;
1194     if (img_convert(tmp, int_pix_fmt,
1195                     src, src_pix_fmt, src_width, src_height) < 0)
1196         goto fail1;
1197     if (img_convert(dst, dst_pix_fmt,
1198                     tmp, int_pix_fmt, dst_width, dst_height) < 0)
1199         goto fail1;
1200     ret = 0;
1201  fail1:
1202     avpicture_free(tmp);
1203     return ret;
1204 }
1205
1206
1207 #ifdef HAVE_MMX
1208 #define DEINT_INPLACE_LINE_LUM \
1209                     movd_m2r(lum_m4[0],mm0);\
1210                     movd_m2r(lum_m3[0],mm1);\
1211                     movd_m2r(lum_m2[0],mm2);\
1212                     movd_m2r(lum_m1[0],mm3);\
1213                     movd_m2r(lum[0],mm4);\
1214                     punpcklbw_r2r(mm7,mm0);\
1215                     movd_r2m(mm2,lum_m4[0]);\
1216                     punpcklbw_r2r(mm7,mm1);\
1217                     punpcklbw_r2r(mm7,mm2);\
1218                     punpcklbw_r2r(mm7,mm3);\
1219                     punpcklbw_r2r(mm7,mm4);\
1220                     paddw_r2r(mm3,mm1);\
1221                     psllw_i2r(1,mm2);\
1222                     paddw_r2r(mm4,mm0);\
1223                     psllw_i2r(2,mm1);\
1224                     paddw_r2r(mm6,mm2);\
1225                     paddw_r2r(mm2,mm1);\
1226                     psubusw_r2r(mm0,mm1);\
1227                     psrlw_i2r(3,mm1);\
1228                     packuswb_r2r(mm7,mm1);\
1229                     movd_r2m(mm1,lum_m2[0]);
1230
1231 #define DEINT_LINE_LUM \
1232                     movd_m2r(lum_m4[0],mm0);\
1233                     movd_m2r(lum_m3[0],mm1);\
1234                     movd_m2r(lum_m2[0],mm2);\
1235                     movd_m2r(lum_m1[0],mm3);\
1236                     movd_m2r(lum[0],mm4);\
1237                     punpcklbw_r2r(mm7,mm0);\
1238                     punpcklbw_r2r(mm7,mm1);\
1239                     punpcklbw_r2r(mm7,mm2);\
1240                     punpcklbw_r2r(mm7,mm3);\
1241                     punpcklbw_r2r(mm7,mm4);\
1242                     paddw_r2r(mm3,mm1);\
1243                     psllw_i2r(1,mm2);\
1244                     paddw_r2r(mm4,mm0);\
1245                     psllw_i2r(2,mm1);\
1246                     paddw_r2r(mm6,mm2);\
1247                     paddw_r2r(mm2,mm1);\
1248                     psubusw_r2r(mm0,mm1);\
1249                     psrlw_i2r(3,mm1);\
1250                     packuswb_r2r(mm7,mm1);\
1251                     movd_r2m(mm1,dst[0]);
1252 #endif
1253
1254 /* filter parameters: [-1 4 2 4 -1] // 8 */
1255 static void deinterlace_line(UINT8 *dst, UINT8 *lum_m4, UINT8 *lum_m3, UINT8 *lum_m2, UINT8 *lum_m1, UINT8 *lum,
1256                                 int size)
1257 {
1258 #ifndef HAVE_MMX
1259     UINT8 *cm = cropTbl + MAX_NEG_CROP;
1260     int sum;
1261
1262     for(;size > 0;size--) {
1263         sum = -lum_m4[0];
1264         sum += lum_m3[0] << 2;
1265         sum += lum_m2[0] << 1;
1266         sum += lum_m1[0] << 2;
1267         sum += -lum[0];
1268         dst[0] = cm[(sum + 4) >> 3];
1269         lum_m4++;
1270         lum_m3++;
1271         lum_m2++;
1272         lum_m1++;
1273         lum++;
1274         dst++;
1275     }
1276 #else
1277
1278     for (;size > 3; size-=4) {
1279         DEINT_LINE_LUM
1280         lum_m4+=4;
1281         lum_m3+=4;
1282         lum_m2+=4;
1283         lum_m1+=4;
1284         lum+=4;
1285         dst+=4;
1286     }
1287 #endif
1288 }
1289 static void deinterlace_line_inplace(UINT8 *lum_m4, UINT8 *lum_m3, UINT8 *lum_m2, UINT8 *lum_m1, UINT8 *lum,
1290                              int size)
1291 {
1292 #ifndef HAVE_MMX
1293     UINT8 *cm = cropTbl + MAX_NEG_CROP;
1294     int sum;
1295
1296     for(;size > 0;size--) {
1297         sum = -lum_m4[0];
1298         sum += lum_m3[0] << 2;
1299         sum += lum_m2[0] << 1;
1300         lum_m4[0]=lum_m2[0];
1301         sum += lum_m1[0] << 2;
1302         sum += -lum[0];
1303         lum_m2[0] = cm[(sum + 4) >> 3];
1304         lum_m4++;
1305         lum_m3++;
1306         lum_m2++;
1307         lum_m1++;
1308         lum++;
1309     }
1310 #else
1311
1312     for (;size > 3; size-=4) {
1313         DEINT_INPLACE_LINE_LUM
1314         lum_m4+=4;
1315         lum_m3+=4;
1316         lum_m2+=4;
1317         lum_m1+=4;
1318         lum+=4;
1319     }
1320 #endif
1321 }
1322
1323 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
1324    top field is copied as is, but the bottom field is deinterlaced
1325    against the top field. */
1326 static void deinterlace_bottom_field(UINT8 *dst, int dst_wrap,
1327                                     UINT8 *src1, int src_wrap,
1328                                     int width, int height)
1329 {
1330     UINT8 *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
1331     int y;
1332
1333     src_m2 = src1;
1334     src_m1 = src1;
1335     src_0=&src_m1[src_wrap];
1336     src_p1=&src_0[src_wrap];
1337     src_p2=&src_p1[src_wrap];
1338     for(y=0;y<(height-2);y+=2) {
1339         memcpy(dst,src_m1,width);
1340         dst += dst_wrap;
1341         deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
1342         src_m2 = src_0;
1343         src_m1 = src_p1;
1344         src_0 = src_p2;
1345         src_p1 += 2*src_wrap;
1346         src_p2 += 2*src_wrap;
1347         dst += dst_wrap;
1348     }
1349     memcpy(dst,src_m1,width);
1350     dst += dst_wrap;
1351     /* do last line */
1352     deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
1353 }
1354
1355 static void deinterlace_bottom_field_inplace(UINT8 *src1, int src_wrap,
1356                                      int width, int height)
1357 {
1358     UINT8 *src_m1, *src_0, *src_p1, *src_p2;
1359     int y;
1360     UINT8 *buf;
1361     buf = (UINT8*)av_malloc(width);
1362
1363     src_m1 = src1;
1364     memcpy(buf,src_m1,width);
1365     src_0=&src_m1[src_wrap];
1366     src_p1=&src_0[src_wrap];
1367     src_p2=&src_p1[src_wrap];
1368     for(y=0;y<(height-2);y+=2) {
1369         deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
1370         src_m1 = src_p1;
1371         src_0 = src_p2;
1372         src_p1 += 2*src_wrap;
1373         src_p2 += 2*src_wrap;
1374     }
1375     /* do last line */
1376     deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
1377     av_free(buf);
1378 }
1379
1380
1381 /* deinterlace - if not supported return -1 */
1382 int avpicture_deinterlace(AVPicture *dst, AVPicture *src,
1383                           int pix_fmt, int width, int height)
1384 {
1385     int i;
1386
1387     if (pix_fmt != PIX_FMT_YUV420P &&
1388         pix_fmt != PIX_FMT_YUV422P &&
1389         pix_fmt != PIX_FMT_YUV444P)
1390         return -1;
1391     if ((width & 3) != 0 || (height & 3) != 0)
1392         return -1;
1393
1394 #ifdef HAVE_MMX
1395     {
1396         mmx_t rounder;
1397         rounder.uw[0]=4;
1398         rounder.uw[1]=4;
1399         rounder.uw[2]=4;
1400         rounder.uw[3]=4;
1401         pxor_r2r(mm7,mm7);
1402         movq_m2r(rounder,mm6);
1403     }
1404 #endif
1405
1406     
1407     for(i=0;i<3;i++) {
1408         if (i == 1) {
1409             switch(pix_fmt) {
1410             case PIX_FMT_YUV420P:
1411                 width >>= 1;
1412                 height >>= 1;
1413                 break;
1414             case PIX_FMT_YUV422P:
1415                 width >>= 1;
1416                 break;
1417             default:
1418                 break;
1419             }
1420         }
1421         if (src == dst) {
1422             deinterlace_bottom_field_inplace(src->data[i], src->linesize[i],
1423                                  width, height);
1424         } else {
1425             deinterlace_bottom_field(dst->data[i],dst->linesize[i],
1426                                         src->data[i], src->linesize[i],
1427                                         width, height);
1428         }
1429     }
1430 #ifdef HAVE_MMX
1431     emms();
1432 #endif
1433     return 0;
1434 }
1435
1436 #undef FIX