]> git.sesse.net Git - ffmpeg/blob - libavcodec/imgconvert.c
sync with mplayerxp. Fixes some 405.avi related flaws
[ffmpeg] / 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_t nb_components;     /* number of components in AVPicture array  */
33     uint8_t is_yuv : 1;    /* true if YUV instead of RGB color space */
34     uint8_t is_packed : 1; /* true if multiple components in same word */
35     uint8_t is_paletted : 1; /* true if paletted */
36     uint8_t is_alpha : 1;    /* true if alpha can be specified */
37     uint8_t is_gray : 1;     /* true if gray or monochrome format */
38     uint8_t x_chroma_shift; /* X chroma subsampling factor is 2 ^ shift */
39     uint8_t 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     /* paletted formats */
113     [PIX_FMT_PAL8] = {
114         .name = "pal8",
115         .nb_components = 1, .is_packed = 1, .is_paletted = 1,
116     },
117 };
118
119 void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift)
120 {
121     if (pix_fmt_info[pix_fmt].is_yuv) {
122         *h_shift = pix_fmt_info[pix_fmt].x_chroma_shift;
123         *v_shift = pix_fmt_info[pix_fmt].y_chroma_shift;
124     } else {
125         *h_shift=0;
126         *v_shift=0;
127     }
128 }
129
130 const char *avcodec_get_pix_fmt_name(int pix_fmt)
131 {
132     if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB)
133         return "???";
134     else
135         return pix_fmt_info[pix_fmt].name;
136 }
137
138 /* Picture field are filled with 'ptr' addresses. Also return size */
139 int avpicture_fill(AVPicture *picture, uint8_t *ptr,
140                    int pix_fmt, int width, int height)
141 {
142     int size, w2, h2, size2;
143     PixFmtInfo *pinfo;
144     
145     pinfo = &pix_fmt_info[pix_fmt];
146     size = width * height;
147     switch(pix_fmt) {
148     case PIX_FMT_YUV420P:
149     case PIX_FMT_YUV422P:
150     case PIX_FMT_YUV444P:
151     case PIX_FMT_YUV410P:
152     case PIX_FMT_YUV411P:
153         w2 = (width + (1 << pinfo->x_chroma_shift) - 1) >> pinfo->x_chroma_shift;
154         h2 = (height + (1 << pinfo->y_chroma_shift) - 1) >> pinfo->y_chroma_shift;
155         size2 = w2 * h2;
156         picture->data[0] = ptr;
157         picture->data[1] = picture->data[0] + size;
158         picture->data[2] = picture->data[1] + size2;
159         picture->linesize[0] = width;
160         picture->linesize[1] = w2;
161         picture->linesize[2] = w2;
162         return size + 2 * size2;
163     case PIX_FMT_RGB24:
164     case PIX_FMT_BGR24:
165         picture->data[0] = ptr;
166         picture->data[1] = NULL;
167         picture->data[2] = NULL;
168         picture->linesize[0] = width * 3;
169         return size * 3;
170     case PIX_FMT_RGBA32:
171         picture->data[0] = ptr;
172         picture->data[1] = NULL;
173         picture->data[2] = NULL;
174         picture->linesize[0] = width * 4;
175         return size * 4;
176     case PIX_FMT_RGB555:
177     case PIX_FMT_RGB565:
178     case PIX_FMT_YUV422:
179         picture->data[0] = ptr;
180         picture->data[1] = NULL;
181         picture->data[2] = NULL;
182         picture->linesize[0] = width * 2;
183         return size * 2;
184     case PIX_FMT_GRAY8:
185         picture->data[0] = ptr;
186         picture->data[1] = NULL;
187         picture->data[2] = NULL;
188         picture->linesize[0] = width;
189         return size;
190     case PIX_FMT_MONOWHITE:
191     case PIX_FMT_MONOBLACK:
192         picture->data[0] = ptr;
193         picture->data[1] = NULL;
194         picture->data[2] = NULL;
195         picture->linesize[0] = (width + 7) >> 3;
196         return picture->linesize[0] * height;
197     case PIX_FMT_PAL8:
198         size2 = (size + 3) & ~3;
199         picture->data[0] = ptr;
200         picture->data[1] = ptr + size2; /* palette is stored here as 256 32 bit words */
201         picture->data[2] = NULL;
202         picture->linesize[0] = width;
203         picture->linesize[1] = 4;
204         return size2 + 256 * 4;
205     default:
206         picture->data[0] = NULL;
207         picture->data[1] = NULL;
208         picture->data[2] = NULL;
209         picture->data[3] = NULL;
210         return -1;
211     }
212 }
213
214 int avpicture_get_size(int pix_fmt, int width, int height)
215 {
216     AVPicture dummy_pict;
217     return avpicture_fill(&dummy_pict, NULL, pix_fmt, width, height);
218 }
219
220
221 /* XXX: totally non optimized */
222
223 static void yuv422_to_yuv420p(AVPicture *dst, AVPicture *src,
224                               int width, int height)
225 {
226     uint8_t *lum, *cb, *cr;
227     int x, y;
228     const uint8_t *p;
229  
230     lum = dst->data[0];
231     cb = dst->data[1];
232     cr = dst->data[2];
233     p = src->data[0];
234    
235     for(y=0;y<height;y+=2) {
236         for(x=0;x<width;x+=2) {
237             lum[0] = p[0];
238             cb[0] = p[1];
239             lum[1] = p[2];
240             cr[0] = p[3];
241             p += 4;
242             lum += 2;
243             cb++;
244             cr++;
245         }
246         for(x=0;x<width;x+=2) {
247             lum[0] = p[0];
248             lum[1] = p[2];
249             p += 4;
250             lum += 2;
251         }
252     }
253 }
254
255 #define SCALEBITS 8
256 #define ONE_HALF  (1 << (SCALEBITS - 1))
257 #define FIX(x)          ((int) ((x) * (1L<<SCALEBITS) + 0.5))
258
259 /* XXX: use generic filter ? */
260 /* 1x2 -> 1x1 */
261 static void shrink2(uint8_t *dst, int dst_wrap, 
262                     uint8_t *src, int src_wrap,
263                     int width, int height)
264 {
265     int w;
266     uint8_t *s1, *s2, *d;
267
268     for(;height > 0; height--) {
269         s1 = src;
270         s2 = s1 + src_wrap;
271         d = dst;
272         for(w = width;w >= 4; w-=4) {
273             d[0] = (s1[0] + s2[0]) >> 1;
274             d[1] = (s1[1] + s2[1]) >> 1;
275             d[2] = (s1[2] + s2[2]) >> 1;
276             d[3] = (s1[3] + s2[3]) >> 1;
277             s1 += 4;
278             s2 += 4;
279             d += 4;
280         }
281         for(;w > 0; w--) {
282             d[0] = (s1[0] + s2[0]) >> 1;
283             s1++;
284             s2++;
285             d++;
286         }
287         src += 2 * src_wrap;
288         dst += dst_wrap;
289     }
290 }
291
292 /* 2x2 -> 1x1 */
293 static void shrink22(uint8_t *dst, int dst_wrap, 
294                      uint8_t *src, int src_wrap,
295                      int width, int height)
296 {
297     int w;
298     uint8_t *s1, *s2, *d;
299
300     for(;height > 0; height--) {
301         s1 = src;
302         s2 = s1 + src_wrap;
303         d = dst;
304         for(w = width;w >= 4; w-=4) {
305             d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 1;
306             d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 1;
307             d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 1;
308             d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 1;
309             s1 += 8;
310             s2 += 8;
311             d += 4;
312         }
313         for(;w > 0; w--) {
314             d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 1;
315             s1 += 2;
316             s2 += 2;
317             d++;
318         }
319         src += 2 * src_wrap;
320         dst += dst_wrap;
321     }
322 }
323
324 /* 1x1 -> 2x2 */
325 static void grow22(uint8_t *dst, int dst_wrap,
326                      uint8_t *src, int src_wrap,
327                      int width, int height)
328 {
329     int w;
330     uint8_t *s1, *d;
331
332     for(;height > 0; height--) {
333         s1 = src;
334         d = dst;
335         for(w = width;w >= 4; w-=4) {
336             d[1] = d[0] = s1[0];
337             d[3] = d[2] = s1[1];
338             s1 += 2;
339             d += 4;
340         }
341         for(;w > 0; w--) {
342             d[0] = s1[0];
343             s1 ++;
344             d++;
345         }
346         if (height%2)
347             src += src_wrap;
348         dst += dst_wrap;
349     }
350 }
351
352 /* 1x2 -> 2x1 */
353 static void conv411(uint8_t *dst, int dst_wrap, 
354                     uint8_t *src, int src_wrap,
355                     int width, int height)
356 {
357     int w, c;
358     uint8_t *s1, *s2, *d;
359
360     for(;height > 0; height--) {
361         s1 = src;
362         s2 = src + src_wrap;
363         d = dst;
364         for(w = width;w > 0; w--) {
365             c = (s1[0] + s2[0]) >> 1;
366             d[0] = c;
367             d[1] = c;
368             s1++;
369             s2++;
370             d += 2;
371         }
372         src += src_wrap * 2;
373         dst += dst_wrap;
374     }
375 }
376
377 static void img_copy(uint8_t *dst, int dst_wrap, 
378                      uint8_t *src, int src_wrap,
379                      int width, int height)
380 {
381     for(;height > 0; height--) {
382         memcpy(dst, src, width);
383         dst += dst_wrap;
384         src += src_wrap;
385     }
386 }
387
388 #define SCALE_BITS 10
389
390 #define C_Y  (76309 >> (16 - SCALE_BITS))
391 #define C_RV (117504 >> (16 - SCALE_BITS))
392 #define C_BU (138453 >> (16 - SCALE_BITS))
393 #define C_GU (13954 >> (16 - SCALE_BITS))
394 #define C_GV (34903 >> (16 - SCALE_BITS))
395
396 #define YUV_TO_RGB2(r, g, b, y1)\
397 {\
398     y = (y1 - 16) * C_Y;\
399     r = cm[(y + r_add) >> SCALE_BITS];\
400     g = cm[(y + g_add) >> SCALE_BITS];\
401     b = cm[(y + b_add) >> SCALE_BITS];\
402 }
403
404 /* XXX: no chroma interpolating is done */
405 #define RGB_FUNCTIONS(rgb_name)                                         \
406                                                                         \
407 static void yuv420p_to_ ## rgb_name (AVPicture *dst, AVPicture *src,    \
408                                      int width, int height)             \
409 {                                                                       \
410     uint8_t *y1_ptr, *y2_ptr, *cb_ptr, *cr_ptr, *d, *d1, *d2;             \
411     int w, y, cb, cr, r_add, g_add, b_add, width2;                      \
412     uint8_t *cm = cropTbl + MAX_NEG_CROP;                                 \
413     unsigned int r, g, b;                                               \
414                                                                         \
415     d = dst->data[0];                                                   \
416     y1_ptr = src->data[0];                                              \
417     cb_ptr = src->data[1];                                              \
418     cr_ptr = src->data[2];                                              \
419     width2 = (width + 1) >> 1;                                          \
420     for(;height >= 2; height -= 2) {                                    \
421         d1 = d;                                                         \
422         d2 = d + dst->linesize[0];                                      \
423         y2_ptr = y1_ptr + src->linesize[0];                             \
424         for(w = width; w >= 2; w -= 2) {                                \
425             cb = cb_ptr[0] - 128;                                       \
426             cr = cr_ptr[0] - 128;                                       \
427             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
428             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
429             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
430                                                                         \
431             /* output 4 pixels */                                       \
432             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
433             RGB_OUT(d1, r, g, b);                                       \
434                                                                         \
435             YUV_TO_RGB2(r, g, b, y1_ptr[1]);                            \
436             RGB_OUT(d1 + BPP, r, g, b);                                 \
437                                                                         \
438             YUV_TO_RGB2(r, g, b, y2_ptr[0]);                            \
439             RGB_OUT(d2, r, g, b);                                       \
440                                                                         \
441             YUV_TO_RGB2(r, g, b, y2_ptr[1]);                            \
442             RGB_OUT(d2 + BPP, r, g, b);                                 \
443                                                                         \
444             d1 += 2 * BPP;                                              \
445             d2 += 2 * BPP;                                              \
446                                                                         \
447             y1_ptr += 2;                                                \
448             y2_ptr += 2;                                                \
449             cb_ptr++;                                                   \
450             cr_ptr++;                                                   \
451         }                                                               \
452         /* handle odd width */                                          \
453         if (w) {                                                        \
454             cb = cb_ptr[0] - 128;                                       \
455             cr = cr_ptr[0] - 128;                                       \
456             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
457             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
458             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
459                                                                         \
460             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
461             RGB_OUT(d1, r, g, b);                                       \
462                                                                         \
463             YUV_TO_RGB2(r, g, b, y2_ptr[0]);                            \
464             RGB_OUT(d2, r, g, b);                                       \
465             d1 += BPP;                                                  \
466             d2 += BPP;                                                  \
467             y1_ptr++;                                                   \
468             y2_ptr++;                                                   \
469             cb_ptr++;                                                   \
470             cr_ptr++;                                                   \
471         }                                                               \
472         d += 2 * dst->linesize[0];                                      \
473         y1_ptr += 2 * src->linesize[0] - width;                         \
474         cb_ptr += src->linesize[1] - width2;                            \
475         cr_ptr += src->linesize[2] - width2;                            \
476     }                                                                   \
477     /* handle odd height */                                             \
478     if (height) {                                                       \
479         d1 = d;                                                         \
480         for(w = width; w >= 2; w -= 2) {                                \
481             cb = cb_ptr[0] - 128;                                       \
482             cr = cr_ptr[0] - 128;                                       \
483             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
484             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
485             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
486                                                                         \
487             /* output 2 pixels */                                       \
488             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
489             RGB_OUT(d1, r, g, b);                                       \
490                                                                         \
491             YUV_TO_RGB2(r, g, b, y1_ptr[1]);                            \
492             RGB_OUT(d1 + BPP, r, g, b);                                 \
493                                                                         \
494             d1 += 2 * BPP;                                              \
495                                                                         \
496             y1_ptr += 2;                                                \
497             cb_ptr++;                                                   \
498             cr_ptr++;                                                   \
499         }                                                               \
500         /* handle width */                                              \
501         if (w) {                                                        \
502             cb = cb_ptr[0] - 128;                                       \
503             cr = cr_ptr[0] - 128;                                       \
504             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
505             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
506             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
507                                                                         \
508             /* output 2 pixels */                                       \
509             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
510             RGB_OUT(d1, r, g, b);                                       \
511             d1 += BPP;                                                  \
512                                                                         \
513             y1_ptr++;                                                   \
514             cb_ptr++;                                                   \
515             cr_ptr++;                                                   \
516         }                                                               \
517     }                                                                   \
518 }                                                                       \
519                                                                         \
520 /* XXX: no chroma interpolating is done */                              \
521 static void yuv422p_to_ ## rgb_name (AVPicture *dst, AVPicture *src,    \
522                                     int width, int height)              \
523 {                                                                       \
524     uint8_t *y1_ptr, *cb_ptr, *cr_ptr, *d, *d1;                           \
525     int w, y, cb, cr, r_add, g_add, b_add, width2;                      \
526     uint8_t *cm = cropTbl + MAX_NEG_CROP;                                 \
527     unsigned int r, g, b;                                               \
528                                                                         \
529     d = dst->data[0];                                                   \
530     y1_ptr = src->data[0];                                              \
531     cb_ptr = src->data[1];                                              \
532     cr_ptr = src->data[2];                                              \
533     width2 = (width + 1) >> 1;                                          \
534     for(;height > 0; height --) {                                       \
535         d1 = d;                                                         \
536         for(w = width; w >= 2; w -= 2) {                                \
537             cb = cb_ptr[0] - 128;                                       \
538             cr = cr_ptr[0] - 128;                                       \
539             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
540             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
541             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
542                                                                         \
543             /* output 2 pixels */                                       \
544             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
545             RGB_OUT(d1, r, g, b);                                       \
546                                                                         \
547             YUV_TO_RGB2(r, g, b, y1_ptr[1]);                            \
548             RGB_OUT(d1 + BPP, r, g, b);                                 \
549                                                                         \
550             d1 += 2 * BPP;                                              \
551                                                                         \
552             y1_ptr += 2;                                                \
553             cb_ptr++;                                                   \
554             cr_ptr++;                                                   \
555         }                                                               \
556         /* handle width */                                              \
557         if (w) {                                                        \
558             cb = cb_ptr[0] - 128;                                       \
559             cr = cr_ptr[0] - 128;                                       \
560             r_add = C_RV * cr + (1 << (SCALE_BITS - 1));                \
561             g_add = - C_GU * cb - C_GV * cr + (1 << (SCALE_BITS - 1));  \
562             b_add = C_BU * cb + (1 << (SCALE_BITS - 1));                \
563                                                                         \
564             /* output 2 pixels */                                       \
565             YUV_TO_RGB2(r, g, b, y1_ptr[0]);                            \
566             RGB_OUT(d1, r, g, b);                                       \
567             d1 += BPP;                                                  \
568                                                                         \
569             y1_ptr++;                                                   \
570             cb_ptr++;                                                   \
571             cr_ptr++;                                                   \
572         }                                                               \
573         d += dst->linesize[0];                                          \
574         y1_ptr += src->linesize[0] - width;                             \
575         cb_ptr += src->linesize[1] - width2;                            \
576         cr_ptr += src->linesize[2] - width2;                            \
577     }                                                                   \
578 }                                                                       \
579                                                                         \
580 static void rgb_name ## _to_yuv420p(AVPicture *dst, AVPicture *src,     \
581                                     int width, int height)              \
582 {                                                                       \
583     int wrap, wrap3, x, y;                                              \
584     int r, g, b, r1, g1, b1;                                            \
585     uint8_t *lum, *cb, *cr;                                               \
586     const uint8_t *p;                                                     \
587                                                                         \
588     lum = dst->data[0];                                                 \
589     cb = dst->data[1];                                                  \
590     cr = dst->data[2];                                                  \
591                                                                         \
592     wrap = dst->linesize[0];                                            \
593     wrap3 = src->linesize[0];                                           \
594     p = src->data[0];                                                   \
595     for(y=0;y<height;y+=2) {                                            \
596         for(x=0;x<width;x+=2) {                                         \
597             RGB_IN(r, g, b, p);                                         \
598             r1 = r;                                                     \
599             g1 = g;                                                     \
600             b1 = b;                                                     \
601             lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
602                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
603             RGB_IN(r, g, b, p + BPP);                                   \
604             r1 += r;                                                    \
605             g1 += g;                                                    \
606             b1 += b;                                                    \
607             lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
608                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
609             p += wrap3;                                                 \
610             lum += wrap;                                                \
611                                                                         \
612             RGB_IN(r, g, b, p);                                         \
613             r1 += r;                                                    \
614             g1 += g;                                                    \
615             b1 += b;                                                    \
616             lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
617                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
618                                                                         \
619             RGB_IN(r, g, b, p + BPP);                                   \
620             r1 += r;                                                    \
621             g1 += g;                                                    \
622             b1 += b;                                                    \
623             lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +             \
624                       FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;        \
625                                                                         \
626             cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +         \
627                       FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >>          \
628                      (SCALEBITS + 2)) + 128;                            \
629             cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 -           \
630                      FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >>           \
631                      (SCALEBITS + 2)) + 128;                            \
632                                                                         \
633             cb++;                                                       \
634             cr++;                                                       \
635             p += -wrap3 + 2 * BPP;                                      \
636             lum += -wrap + 2;                                           \
637         }                                                               \
638         p += wrap3 + (wrap3 - width * BPP);                             \
639         lum += wrap + (wrap - width);                                   \
640         cb += dst->linesize[1] - width / 2;                             \
641         cr += dst->linesize[2] - width / 2;                             \
642     }                                                                   \
643 }                                                                       \
644                                                                         \
645 static void rgb_name ## _to_gray(AVPicture *dst, AVPicture *src,        \
646                                  int width, int height)                 \
647 {                                                                       \
648     const unsigned char *p;                                             \
649     unsigned char *q;                                                   \
650     int r, g, b, dst_wrap, src_wrap;                                    \
651     int x, y;                                                           \
652                                                                         \
653     p = src->data[0];                                                   \
654     src_wrap = src->linesize[0] - BPP * width;                          \
655                                                                         \
656     q = dst->data[0];                                                   \
657     dst_wrap = dst->linesize[0] - width;                                \
658                                                                         \
659     for(y=0;y<height;y++) {                                             \
660         for(x=0;x<width;x++) {                                          \
661             RGB_IN(r, g, b, p);                                         \
662             q[0] = (FIX(0.29900) * r + FIX(0.58700) * g +               \
663                     FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;          \
664             q++;                                                        \
665             p += BPP;                                                   \
666         }                                                               \
667         p += src_wrap;                                                  \
668         q += dst_wrap;                                                  \
669     }                                                                   \
670 }                                                                       \
671                                                                         \
672 static void gray_to_ ## rgb_name(AVPicture *dst, AVPicture *src,        \
673                                  int width, int height)                 \
674 {                                                                       \
675     const unsigned char *p;                                             \
676     unsigned char *q;                                                   \
677     int r, dst_wrap, src_wrap;                                          \
678     int x, y;                                                           \
679                                                                         \
680     p = src->data[0];                                                   \
681     src_wrap = src->linesize[0] - width;                                \
682                                                                         \
683     q = dst->data[0];                                                   \
684     dst_wrap = dst->linesize[0] - BPP * width;                          \
685                                                                         \
686     for(y=0;y<height;y++) {                                             \
687         for(x=0;x<width;x++) {                                          \
688             r = p[0];                                                   \
689             RGB_OUT(q, r, r, r);                                        \
690             q += BPP;                                                   \
691             p ++;                                                       \
692         }                                                               \
693         p += src_wrap;                                                  \
694         q += dst_wrap;                                                  \
695     }                                                                   \
696 }                                                                       \
697                                                                         \
698 static void pal8_to_ ## rgb_name(AVPicture *dst, AVPicture *src,        \
699                                  int width, int height)                 \
700 {                                                                       \
701     const unsigned char *p;                                             \
702     unsigned char *q;                                                   \
703     int r, g, b, dst_wrap, src_wrap;                                    \
704     int x, y;                                                           \
705     uint32_t v;\
706     const uint32_t *palette;\
707 \
708     p = src->data[0];                                                   \
709     src_wrap = src->linesize[0] - width;                                \
710     palette = (uint32_t *)src->data[1];\
711                                                                         \
712     q = dst->data[0];                                                   \
713     dst_wrap = dst->linesize[0] - BPP * width;                          \
714                                                                         \
715     for(y=0;y<height;y++) {                                             \
716         for(x=0;x<width;x++) {                                          \
717             v = palette[p[0]];\
718             r = (v >> 16) & 0xff;\
719             g = (v >> 8) & 0xff;\
720             b = (v) & 0xff;\
721             RGB_OUT(q, r, g, b);                                        \
722             q += BPP;                                                   \
723             p ++;                                                       \
724         }                                                               \
725         p += src_wrap;                                                  \
726         q += dst_wrap;                                                  \
727     }                                                                   \
728 }
729
730 /* copy bit n to bits 0 ... n - 1 */
731 static inline unsigned int bitcopy_n(unsigned int a, int n)
732 {
733     int mask;
734     mask = (1 << n) - 1;
735     return (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask);
736 }
737
738 /* rgb555 handling */
739
740 #define RGB_IN(r, g, b, s)\
741 {\
742     unsigned int v = ((const uint16_t *)(s))[0];\
743     r = bitcopy_n(v >> (10 - 3), 3);\
744     g = bitcopy_n(v >> (5 - 3), 3);\
745     b = bitcopy_n(v << 3, 3);\
746 }
747
748 #define RGB_OUT(d, r, g, b)\
749 {\
750     ((uint16_t *)(d))[0] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;\
751 }
752
753 #define BPP 2
754
755 RGB_FUNCTIONS(rgb555)
756
757 #undef RGB_IN
758 #undef RGB_OUT
759 #undef BPP
760
761 /* rgb565 handling */
762
763 #define RGB_IN(r, g, b, s)\
764 {\
765     unsigned int v = ((const uint16_t *)(s))[0];\
766     r = bitcopy_n(v >> (11 - 3), 3);\
767     g = bitcopy_n(v >> (5 - 2), 2);\
768     b = bitcopy_n(v << 3, 3);\
769 }
770
771 #define RGB_OUT(d, r, g, b)\
772 {\
773     ((uint16_t *)(d))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\
774 }
775
776 #define BPP 2
777
778 RGB_FUNCTIONS(rgb565)
779
780 #undef RGB_IN
781 #undef RGB_OUT
782 #undef BPP
783
784 /* bgr24 handling */
785
786 #define RGB_IN(r, g, b, s)\
787 {\
788     b = (s)[0];\
789     g = (s)[1];\
790     r = (s)[2];\
791 }
792
793 #define RGB_OUT(d, r, g, b)\
794 {\
795     (d)[0] = b;\
796     (d)[1] = g;\
797     (d)[2] = r;\
798 }
799
800 #define BPP 3
801
802 RGB_FUNCTIONS(bgr24)
803
804 #undef RGB_IN
805 #undef RGB_OUT
806 #undef BPP
807
808 /* rgb24 handling */
809
810 #define RGB_IN(r, g, b, s)\
811 {\
812     r = (s)[0];\
813     g = (s)[1];\
814     b = (s)[2];\
815 }
816
817 #define RGB_OUT(d, r, g, b)\
818 {\
819     (d)[0] = r;\
820     (d)[1] = g;\
821     (d)[2] = b;\
822 }
823
824 #define BPP 3
825
826 RGB_FUNCTIONS(rgb24)
827
828 #undef RGB_IN
829 #undef RGB_OUT
830 #undef BPP
831
832 /* rgba32 handling */
833
834 #define RGB_IN(r, g, b, s)\
835 {\
836     unsigned int v = ((const uint32_t *)(s))[0];\
837     r = (v >> 16) & 0xff;\
838     g = (v >> 8) & 0xff;\
839     b = v & 0xff;\
840 }
841
842 #define RGB_OUT(d, r, g, b)\
843 {\
844     ((uint32_t *)(d))[0] = (0xff << 24) | (r << 16) | (g << 8) | b;\
845 }
846
847 #define BPP 4
848
849 RGB_FUNCTIONS(rgba32)
850
851 #undef RGB_IN
852 #undef RGB_OUT
853 #undef BPP
854
855
856 static void rgb24_to_rgb565(AVPicture *dst, AVPicture *src,
857                             int width, int height)
858 {
859     const unsigned char *p;
860     unsigned char *q;
861     int r, g, b, dst_wrap, src_wrap;
862     int x, y;
863
864     p = src->data[0];
865     src_wrap = src->linesize[0] - 3 * width;
866
867     q = dst->data[0];
868     dst_wrap = dst->linesize[0] - 2 * width;
869
870     for(y=0;y<height;y++) {
871         for(x=0;x<width;x++) {
872             r = p[0];
873             g = p[1];
874             b = p[2];
875
876             ((unsigned short *)q)[0] = 
877                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
878             q += 2;
879             p += 3;
880         }
881         p += src_wrap;
882         q += dst_wrap;
883     }
884 }
885
886 /* NOTE: we also add a dummy alpha bit */
887 static void rgb24_to_rgb555(AVPicture *dst, AVPicture *src,
888                             int width, int height)
889 {
890     const unsigned char *p;
891     unsigned char *q;
892     int r, g, b, dst_wrap, src_wrap;
893     int x, y;
894
895     p = src->data[0];
896     src_wrap = src->linesize[0] - 3 * width;
897
898     q = dst->data[0];
899     dst_wrap = dst->linesize[0] - 2 * width;
900
901     for(y=0;y<height;y++) {
902         for(x=0;x<width;x++) {
903             r = p[0];
904             g = p[1];
905             b = p[2];
906
907             ((unsigned short *)q)[0] = 
908                 ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;
909             q += 2;
910             p += 3;
911         }
912         p += src_wrap;
913         q += dst_wrap;
914     }
915 }
916
917 static void mono_to_gray(AVPicture *dst, AVPicture *src,
918                          int width, int height, int xor_mask)
919 {
920     const unsigned char *p;
921     unsigned char *q;
922     int v, dst_wrap, src_wrap;
923     int y, w;
924
925     p = src->data[0];
926     src_wrap = src->linesize[0] - ((width + 7) >> 3);
927
928     q = dst->data[0];
929     dst_wrap = dst->linesize[0] - width;
930     for(y=0;y<height;y++) {
931         w = width; 
932         while (w >= 8) {
933             v = *p++ ^ xor_mask;
934             q[0] = -(v >> 7);
935             q[1] = -((v >> 6) & 1);
936             q[2] = -((v >> 5) & 1);
937             q[3] = -((v >> 4) & 1);
938             q[4] = -((v >> 3) & 1);
939             q[5] = -((v >> 2) & 1);
940             q[6] = -((v >> 1) & 1);
941             q[7] = -((v >> 0) & 1);
942             w -= 8;
943             q += 8;
944         }
945         if (w > 0) {
946             v = *p++ ^ xor_mask;
947             do {
948                 q[0] = -((v >> 7) & 1);
949                 q++;
950                 v <<= 1;
951             } while (--w);
952         }
953         p += src_wrap;
954         q += dst_wrap;
955     }
956 }
957
958 static void monowhite_to_gray(AVPicture *dst, AVPicture *src,
959                                int width, int height)
960 {
961     mono_to_gray(dst, src, width, height, 0xff);
962 }
963
964 static void monoblack_to_gray(AVPicture *dst, AVPicture *src,
965                                int width, int height)
966 {
967     mono_to_gray(dst, src, width, height, 0x00);
968 }
969
970 static void gray_to_mono(AVPicture *dst, AVPicture *src,
971                          int width, int height, int xor_mask)
972 {
973     int n;
974     const uint8_t *s;
975     uint8_t *d;
976     int j, b, v, n1, src_wrap, dst_wrap, y;
977
978     s = src->data[0];
979     src_wrap = src->linesize[0] - width;
980
981     d = dst->data[0];
982     dst_wrap = dst->linesize[0] - ((width + 7) >> 3);
983     printf("%d %d\n", width, height);
984
985     for(y=0;y<height;y++) {
986         n = width;
987         while (n >= 8) {
988             v = 0;
989             for(j=0;j<8;j++) {
990                 b = s[0];
991                 s++;
992                 v = (v << 1) | (b >> 7);
993             }
994             d[0] = v ^ xor_mask;
995             d++;
996             n -= 8;
997         }
998         if (n > 0) {
999             n1 = n;
1000             v = 0;
1001             while (n > 0) {
1002                 b = s[0];
1003                 s++;
1004                 v = (v << 1) | (b >> 7);
1005                 n--;
1006             }
1007             d[0] = (v << (8 - (n1 & 7))) ^ xor_mask;
1008             d++;
1009         }
1010         s += src_wrap;
1011         d += dst_wrap;
1012     }
1013 }
1014
1015 static void gray_to_monowhite(AVPicture *dst, AVPicture *src,
1016                               int width, int height)
1017 {
1018     gray_to_mono(dst, src, width, height, 0xff);
1019 }
1020
1021 static void gray_to_monoblack(AVPicture *dst, AVPicture *src,
1022                               int width, int height)
1023 {
1024     gray_to_mono(dst, src, width, height, 0x00);
1025 }
1026
1027 /* this is maybe slow, but allows for extensions */
1028 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
1029 {
1030     return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
1031 }
1032
1033 /* XXX: put jpeg quantize code instead */
1034 static void rgb24_to_pal8(AVPicture *dst, AVPicture *src,
1035                           int width, int height)
1036 {
1037     const unsigned char *p;
1038     unsigned char *q;
1039     int r, g, b, dst_wrap, src_wrap;
1040     int x, y, i;
1041     static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
1042     uint32_t *pal;
1043
1044     p = src->data[0];
1045     src_wrap = src->linesize[0] - 3 * width;
1046
1047     q = dst->data[0];
1048     dst_wrap = dst->linesize[0] - width;
1049
1050     for(y=0;y<height;y++) {
1051         for(x=0;x<width;x++) {
1052             r = p[0];
1053             g = p[1];
1054             b = p[2];
1055
1056             q[0] = gif_clut_index(r, g, b);
1057             q++;
1058             p += 3;
1059         }
1060         p += src_wrap;
1061         q += dst_wrap;
1062     }
1063
1064     /* build palette */
1065     pal = (uint32_t *)dst->data[1];
1066     i = 0;
1067     for(r = 0; r < 6; r++) {
1068         for(g = 0; g < 6; g++) {
1069             for(b = 0; b < 6; b++) {
1070                 pal[i++] = (0xff << 24) | (pal_value[r] << 16) | 
1071                     (pal_value[g] << 8) | pal_value[b];
1072             }
1073         }
1074     }
1075     while (i < 256)
1076         pal[i++] = 0;
1077 }
1078         
1079 typedef struct ConvertEntry {
1080     void (*convert)(AVPicture *dst, AVPicture *src, int width, int height);
1081 } ConvertEntry;
1082
1083 /* add each new convertion function in this table */
1084 /* constraints;
1085    - all non YUV modes must convert at least to and from PIX_FMT_RGB24
1086 */
1087 static ConvertEntry convert_table[PIX_FMT_NB][PIX_FMT_NB] = {
1088     [PIX_FMT_YUV420P] = {
1089         [PIX_FMT_RGB555] = { 
1090             .convert = yuv420p_to_rgb555
1091         },
1092         [PIX_FMT_RGB565] = { 
1093             .convert = yuv420p_to_rgb565
1094         },
1095         [PIX_FMT_BGR24] = { 
1096             .convert = yuv420p_to_bgr24
1097         },
1098         [PIX_FMT_RGB24] = { 
1099             .convert = yuv420p_to_rgb24
1100         },
1101         [PIX_FMT_RGBA32] = { 
1102             .convert = yuv420p_to_rgba32
1103         },
1104     },
1105     [PIX_FMT_YUV422P] = {
1106         [PIX_FMT_RGB555] = { 
1107             .convert = yuv422p_to_rgb555
1108         },
1109         [PIX_FMT_RGB565] = { 
1110             .convert = yuv422p_to_rgb565
1111         },
1112         [PIX_FMT_BGR24] = { 
1113             .convert = yuv422p_to_bgr24
1114         },
1115         [PIX_FMT_RGB24] = { 
1116             .convert = yuv422p_to_rgb24
1117         },
1118         [PIX_FMT_RGBA32] = { 
1119             .convert = yuv422p_to_rgba32
1120         },
1121     },
1122     [PIX_FMT_YUV422] = { 
1123         [PIX_FMT_YUV420P] = { 
1124             .convert = yuv422_to_yuv420p,
1125         },
1126     },
1127
1128     [PIX_FMT_RGB24] = {
1129         [PIX_FMT_YUV420P] = { 
1130             .convert = rgb24_to_yuv420p
1131         },
1132         [PIX_FMT_RGB565] = { 
1133             .convert = rgb24_to_rgb565
1134         },
1135         [PIX_FMT_RGB555] = { 
1136             .convert = rgb24_to_rgb555
1137         },
1138         [PIX_FMT_GRAY8] = { 
1139             .convert = rgb24_to_gray
1140         },
1141         [PIX_FMT_PAL8] = { 
1142             .convert = rgb24_to_pal8
1143         },
1144     },
1145     [PIX_FMT_RGBA32] = {
1146         [PIX_FMT_YUV420P] = { 
1147             .convert = rgba32_to_yuv420p
1148         },
1149         [PIX_FMT_GRAY8] = { 
1150             .convert = rgba32_to_gray
1151         },
1152     },
1153     [PIX_FMT_BGR24] = {
1154         [PIX_FMT_YUV420P] = { 
1155             .convert = bgr24_to_yuv420p
1156         },
1157         [PIX_FMT_GRAY8] = { 
1158             .convert = bgr24_to_gray
1159         },
1160     },
1161     [PIX_FMT_RGB555] = {
1162         [PIX_FMT_YUV420P] = { 
1163             .convert = rgb555_to_yuv420p
1164         },
1165         [PIX_FMT_GRAY8] = { 
1166             .convert = rgb555_to_gray
1167         },
1168     },
1169     [PIX_FMT_RGB565] = {
1170         [PIX_FMT_YUV420P] = { 
1171             .convert = rgb565_to_yuv420p
1172         },
1173         [PIX_FMT_GRAY8] = { 
1174             .convert = rgb565_to_gray
1175         },
1176     },
1177     [PIX_FMT_GRAY8] = {
1178         [PIX_FMT_RGB555] = { 
1179             .convert = gray_to_rgb555
1180         },
1181         [PIX_FMT_RGB565] = { 
1182             .convert = gray_to_rgb565
1183         },
1184         [PIX_FMT_RGB24] = { 
1185             .convert = gray_to_rgb24
1186         },
1187         [PIX_FMT_BGR24] = { 
1188             .convert = gray_to_bgr24
1189         },
1190         [PIX_FMT_RGBA32] = { 
1191             .convert = gray_to_rgba32
1192         },
1193         [PIX_FMT_MONOWHITE] = { 
1194             .convert = gray_to_monowhite
1195         },
1196         [PIX_FMT_MONOBLACK] = { 
1197             .convert = gray_to_monoblack
1198         },
1199     },
1200     [PIX_FMT_MONOWHITE] = {
1201         [PIX_FMT_GRAY8] = { 
1202             .convert = monowhite_to_gray
1203         },
1204     },
1205     [PIX_FMT_MONOBLACK] = {
1206         [PIX_FMT_GRAY8] = { 
1207             .convert = monoblack_to_gray
1208         },
1209     },
1210     [PIX_FMT_PAL8] = {
1211         [PIX_FMT_RGB555] = { 
1212             .convert = pal8_to_rgb555
1213         },
1214         [PIX_FMT_RGB565] = { 
1215             .convert = pal8_to_rgb565
1216         },
1217         [PIX_FMT_BGR24] = { 
1218             .convert = pal8_to_bgr24
1219         },
1220         [PIX_FMT_RGB24] = { 
1221             .convert = pal8_to_rgb24
1222         },
1223         [PIX_FMT_RGBA32] = { 
1224             .convert = pal8_to_rgba32
1225         },
1226     },
1227 };
1228
1229 static int avpicture_alloc(AVPicture *picture,
1230                            int pix_fmt, int width, int height)
1231 {
1232     unsigned int size;
1233     void *ptr;
1234
1235     size = avpicture_get_size(pix_fmt, width, height);
1236     if (size < 0)
1237         goto fail;
1238     ptr = av_malloc(size);
1239     if (!ptr)
1240         goto fail;
1241     avpicture_fill(picture, ptr, pix_fmt, width, height);
1242     return 0;
1243  fail:
1244     memset(picture, 0, sizeof(AVPicture));
1245     return -1;
1246 }
1247
1248 static void avpicture_free(AVPicture *picture)
1249 {
1250     av_free(picture->data[0]);
1251 }
1252
1253 /* XXX: always use linesize. Return -1 if not supported */
1254 int img_convert(AVPicture *dst, int dst_pix_fmt,
1255                 AVPicture *src, int src_pix_fmt, 
1256                 int src_width, int src_height)
1257 {
1258     int i, ret, dst_width, dst_height, int_pix_fmt;
1259     PixFmtInfo *src_pix, *dst_pix;
1260     ConvertEntry *ce;
1261     AVPicture tmp1, *tmp = &tmp1;
1262
1263     if (src_pix_fmt < 0 || src_pix_fmt >= PIX_FMT_NB ||
1264         dst_pix_fmt < 0 || dst_pix_fmt >= PIX_FMT_NB)
1265         return -1;
1266     if (src_width <= 0 || src_height <= 0)
1267         return 0;
1268
1269     dst_width = src_width;
1270     dst_height = src_height;
1271
1272     dst_pix = &pix_fmt_info[dst_pix_fmt];
1273     src_pix = &pix_fmt_info[src_pix_fmt];
1274     if (src_pix_fmt == dst_pix_fmt) {
1275         /* XXX: incorrect */
1276         /* same format: just copy */
1277         for(i = 0; i < dst_pix->nb_components; i++) {
1278             int w, h;
1279             w = dst_width;
1280             h = dst_height;
1281             if (dst_pix->is_yuv && (i == 1 || i == 2)) {
1282                 w >>= dst_pix->x_chroma_shift;
1283                 h >>= dst_pix->y_chroma_shift;
1284             }
1285             img_copy(dst->data[i], dst->linesize[i],
1286                      src->data[i], src->linesize[i],
1287                      w, h);
1288         }
1289         return 0;
1290     }
1291
1292     ce = &convert_table[src_pix_fmt][dst_pix_fmt];
1293     if (ce->convert) {
1294         /* specific convertion routine */
1295         ce->convert(dst, src, dst_width, dst_height);
1296         return 0;
1297     }
1298
1299     /* gray to YUV */
1300     if (dst_pix->is_yuv && src_pix_fmt == PIX_FMT_GRAY8) {
1301         int w, h, y;
1302         uint8_t *d;
1303
1304         img_copy(dst->data[0], dst->linesize[0],
1305                  src->data[0], src->linesize[0],
1306                  dst_width, dst_height);
1307         /* fill U and V with 128 */
1308         w = dst_width;
1309         h = dst_height;
1310         w >>= dst_pix->x_chroma_shift;
1311         h >>= dst_pix->y_chroma_shift;
1312         for(i = 1; i <= 2; i++) {
1313             d = dst->data[i];
1314             for(y = 0; y< h; y++) {
1315                 memset(d, 128, w);
1316                 d += dst->linesize[i];
1317             }
1318         }
1319         return 0;
1320     }
1321
1322     /* YUV to gray */
1323     if (src_pix->is_yuv && dst_pix_fmt == PIX_FMT_GRAY8) {
1324         img_copy(dst->data[0], dst->linesize[0],
1325                  src->data[0], src->linesize[0],
1326                  dst_width, dst_height);
1327         return 0;
1328     }
1329
1330     /* YUV to YUV */
1331     if (dst_pix->is_yuv && src_pix->is_yuv) {
1332         int x_shift, y_shift, w, h;
1333         void (*resize_func)(uint8_t *dst, int dst_wrap, 
1334                             uint8_t *src, int src_wrap,
1335                             int width, int height);
1336
1337         /* compute chroma size of the smallest dimensions */
1338         w = dst_width;
1339         h = dst_height;
1340         if (dst_pix->x_chroma_shift >= src_pix->x_chroma_shift)
1341             w >>= dst_pix->x_chroma_shift;
1342         else
1343             w >>= src_pix->x_chroma_shift;
1344         if (dst_pix->y_chroma_shift >= src_pix->y_chroma_shift)
1345             h >>= dst_pix->y_chroma_shift;
1346         else
1347             h >>= src_pix->y_chroma_shift;
1348
1349         x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);
1350         y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);
1351         if (x_shift == 0 && y_shift == 0) {
1352             resize_func = img_copy; /* should never happen */
1353         } else if (x_shift == 0 && y_shift == 1) {
1354             resize_func = shrink2;
1355         } else if (x_shift == 1 && y_shift == 1) {
1356             resize_func = shrink22;
1357         } else if (x_shift == -1 && y_shift == -1) {
1358             resize_func = grow22;
1359         } else if (x_shift == -1 && y_shift == 1) {
1360             resize_func = conv411;
1361         } else {
1362             /* currently not handled */
1363             return -1;
1364         }
1365
1366         img_copy(dst->data[0], dst->linesize[0],
1367                  src->data[0], src->linesize[0],
1368                  dst_width, dst_height);
1369
1370         for(i = 1;i <= 2; i++)
1371             resize_func(dst->data[i], dst->linesize[i],
1372                         src->data[i], src->linesize[i],
1373                         dst_width>>dst_pix->x_chroma_shift, dst_height>>dst_pix->y_chroma_shift);
1374        return 0;
1375     }
1376
1377     /* try to use an intermediate format */
1378     if (src_pix_fmt == PIX_FMT_MONOWHITE ||
1379         src_pix_fmt == PIX_FMT_MONOBLACK ||
1380         dst_pix_fmt == PIX_FMT_MONOWHITE ||
1381         dst_pix_fmt == PIX_FMT_MONOBLACK) {
1382         int_pix_fmt = PIX_FMT_GRAY8;
1383     } else {
1384         int_pix_fmt = PIX_FMT_RGB24;
1385     }
1386     if (avpicture_alloc(tmp, int_pix_fmt, dst_width, dst_height) < 0)
1387         return -1;
1388     ret = -1;
1389     if (img_convert(tmp, int_pix_fmt,
1390                     src, src_pix_fmt, src_width, src_height) < 0)
1391         goto fail1;
1392     if (img_convert(dst, dst_pix_fmt,
1393                     tmp, int_pix_fmt, dst_width, dst_height) < 0)
1394         goto fail1;
1395     ret = 0;
1396  fail1:
1397     avpicture_free(tmp);
1398     return ret;
1399 }
1400
1401
1402 #ifdef HAVE_MMX
1403 #define DEINT_INPLACE_LINE_LUM \
1404                     movd_m2r(lum_m4[0],mm0);\
1405                     movd_m2r(lum_m3[0],mm1);\
1406                     movd_m2r(lum_m2[0],mm2);\
1407                     movd_m2r(lum_m1[0],mm3);\
1408                     movd_m2r(lum[0],mm4);\
1409                     punpcklbw_r2r(mm7,mm0);\
1410                     movd_r2m(mm2,lum_m4[0]);\
1411                     punpcklbw_r2r(mm7,mm1);\
1412                     punpcklbw_r2r(mm7,mm2);\
1413                     punpcklbw_r2r(mm7,mm3);\
1414                     punpcklbw_r2r(mm7,mm4);\
1415                     paddw_r2r(mm3,mm1);\
1416                     psllw_i2r(1,mm2);\
1417                     paddw_r2r(mm4,mm0);\
1418                     psllw_i2r(2,mm1);\
1419                     paddw_r2r(mm6,mm2);\
1420                     paddw_r2r(mm2,mm1);\
1421                     psubusw_r2r(mm0,mm1);\
1422                     psrlw_i2r(3,mm1);\
1423                     packuswb_r2r(mm7,mm1);\
1424                     movd_r2m(mm1,lum_m2[0]);
1425
1426 #define DEINT_LINE_LUM \
1427                     movd_m2r(lum_m4[0],mm0);\
1428                     movd_m2r(lum_m3[0],mm1);\
1429                     movd_m2r(lum_m2[0],mm2);\
1430                     movd_m2r(lum_m1[0],mm3);\
1431                     movd_m2r(lum[0],mm4);\
1432                     punpcklbw_r2r(mm7,mm0);\
1433                     punpcklbw_r2r(mm7,mm1);\
1434                     punpcklbw_r2r(mm7,mm2);\
1435                     punpcklbw_r2r(mm7,mm3);\
1436                     punpcklbw_r2r(mm7,mm4);\
1437                     paddw_r2r(mm3,mm1);\
1438                     psllw_i2r(1,mm2);\
1439                     paddw_r2r(mm4,mm0);\
1440                     psllw_i2r(2,mm1);\
1441                     paddw_r2r(mm6,mm2);\
1442                     paddw_r2r(mm2,mm1);\
1443                     psubusw_r2r(mm0,mm1);\
1444                     psrlw_i2r(3,mm1);\
1445                     packuswb_r2r(mm7,mm1);\
1446                     movd_r2m(mm1,dst[0]);
1447 #endif
1448
1449 /* filter parameters: [-1 4 2 4 -1] // 8 */
1450 static void deinterlace_line(uint8_t *dst, uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum,
1451                                 int size)
1452 {
1453 #ifndef HAVE_MMX
1454     uint8_t *cm = cropTbl + MAX_NEG_CROP;
1455     int sum;
1456
1457     for(;size > 0;size--) {
1458         sum = -lum_m4[0];
1459         sum += lum_m3[0] << 2;
1460         sum += lum_m2[0] << 1;
1461         sum += lum_m1[0] << 2;
1462         sum += -lum[0];
1463         dst[0] = cm[(sum + 4) >> 3];
1464         lum_m4++;
1465         lum_m3++;
1466         lum_m2++;
1467         lum_m1++;
1468         lum++;
1469         dst++;
1470     }
1471 #else
1472
1473     {
1474         mmx_t rounder;
1475         rounder.uw[0]=4;
1476         rounder.uw[1]=4;
1477         rounder.uw[2]=4;
1478         rounder.uw[3]=4;
1479         pxor_r2r(mm7,mm7);
1480         movq_m2r(rounder,mm6);
1481     }
1482     for (;size > 3; size-=4) {
1483         DEINT_LINE_LUM
1484         lum_m4+=4;
1485         lum_m3+=4;
1486         lum_m2+=4;
1487         lum_m1+=4;
1488         lum+=4;
1489         dst+=4;
1490     }
1491 #endif
1492 }
1493 static void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum,
1494                              int size)
1495 {
1496 #ifndef HAVE_MMX
1497     uint8_t *cm = cropTbl + MAX_NEG_CROP;
1498     int sum;
1499
1500     for(;size > 0;size--) {
1501         sum = -lum_m4[0];
1502         sum += lum_m3[0] << 2;
1503         sum += lum_m2[0] << 1;
1504         lum_m4[0]=lum_m2[0];
1505         sum += lum_m1[0] << 2;
1506         sum += -lum[0];
1507         lum_m2[0] = cm[(sum + 4) >> 3];
1508         lum_m4++;
1509         lum_m3++;
1510         lum_m2++;
1511         lum_m1++;
1512         lum++;
1513     }
1514 #else
1515
1516     {
1517         mmx_t rounder;
1518         rounder.uw[0]=4;
1519         rounder.uw[1]=4;
1520         rounder.uw[2]=4;
1521         rounder.uw[3]=4;
1522         pxor_r2r(mm7,mm7);
1523         movq_m2r(rounder,mm6);
1524     }
1525     for (;size > 3; size-=4) {
1526         DEINT_INPLACE_LINE_LUM
1527         lum_m4+=4;
1528         lum_m3+=4;
1529         lum_m2+=4;
1530         lum_m1+=4;
1531         lum+=4;
1532     }
1533 #endif
1534 }
1535
1536 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
1537    top field is copied as is, but the bottom field is deinterlaced
1538    against the top field. */
1539 static void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
1540                                     uint8_t *src1, int src_wrap,
1541                                     int width, int height)
1542 {
1543     uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
1544     int y;
1545
1546     src_m2 = src1;
1547     src_m1 = src1;
1548     src_0=&src_m1[src_wrap];
1549     src_p1=&src_0[src_wrap];
1550     src_p2=&src_p1[src_wrap];
1551     for(y=0;y<(height-2);y+=2) {
1552         memcpy(dst,src_m1,width);
1553         dst += dst_wrap;
1554         deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
1555         src_m2 = src_0;
1556         src_m1 = src_p1;
1557         src_0 = src_p2;
1558         src_p1 += 2*src_wrap;
1559         src_p2 += 2*src_wrap;
1560         dst += dst_wrap;
1561     }
1562     memcpy(dst,src_m1,width);
1563     dst += dst_wrap;
1564     /* do last line */
1565     deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
1566 }
1567
1568 static void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
1569                                      int width, int height)
1570 {
1571     uint8_t *src_m1, *src_0, *src_p1, *src_p2;
1572     int y;
1573     uint8_t *buf;
1574     buf = (uint8_t*)av_malloc(width);
1575
1576     src_m1 = src1;
1577     memcpy(buf,src_m1,width);
1578     src_0=&src_m1[src_wrap];
1579     src_p1=&src_0[src_wrap];
1580     src_p2=&src_p1[src_wrap];
1581     for(y=0;y<(height-2);y+=2) {
1582         deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
1583         src_m1 = src_p1;
1584         src_0 = src_p2;
1585         src_p1 += 2*src_wrap;
1586         src_p2 += 2*src_wrap;
1587     }
1588     /* do last line */
1589     deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
1590     av_free(buf);
1591 }
1592
1593
1594 /* deinterlace - if not supported return -1 */
1595 int avpicture_deinterlace(AVPicture *dst, AVPicture *src,
1596                           int pix_fmt, int width, int height)
1597 {
1598     int i;
1599
1600     if (pix_fmt != PIX_FMT_YUV420P &&
1601         pix_fmt != PIX_FMT_YUV422P &&
1602         pix_fmt != PIX_FMT_YUV444P)
1603         return -1;
1604     if ((width & 3) != 0 || (height & 3) != 0)
1605         return -1;
1606
1607     for(i=0;i<3;i++) {
1608         if (i == 1) {
1609             switch(pix_fmt) {
1610             case PIX_FMT_YUV420P:
1611                 width >>= 1;
1612                 height >>= 1;
1613                 break;
1614             case PIX_FMT_YUV422P:
1615                 width >>= 1;
1616                 break;
1617             default:
1618                 break;
1619             }
1620         }
1621         if (src == dst) {
1622             deinterlace_bottom_field_inplace(src->data[i], src->linesize[i],
1623                                  width, height);
1624         } else {
1625             deinterlace_bottom_field(dst->data[i],dst->linesize[i],
1626                                         src->data[i], src->linesize[i],
1627                                         width, height);
1628         }
1629     }
1630 #ifdef HAVE_MMX
1631     emms();
1632 #endif
1633     return 0;
1634 }
1635
1636 #undef FIX