use av_malloc() functions - added av_strdup and av_realloc()
[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 * BPP;                                                \
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 * BPP;                                      \
566             lum += -wrap + 2;                                           \
567         }                                                               \
568         p += wrap3;                                                     \
569         lum += wrap;                                                    \
570     }                                                                   \
571 }                                                                       \
572                                                                         \
573 static void rgb_name ## _to_gray(AVPicture *dst, AVPicture *src,        \
574                                  int width, int height)                 \
575 {                                                                       \
576     const unsigned char *p;                                             \
577     unsigned char *q;                                                   \
578     int r, g, b, dst_wrap, src_wrap;                                    \
579     int x, y;                                                           \
580                                                                         \
581     p = src->data[0];                                                   \
582     src_wrap = src->linesize[0] - BPP * width;                          \
583                                                                         \
584     q = dst->data[0];                                                   \
585     dst_wrap = dst->linesize[0] - width;                                \
586                                                                         \
587     for(y=0;y<height;y++) {                                             \
588         for(x=0;x<width;x++) {                                          \
589             RGB_IN(r, g, b, p);                                         \
590             q[0] = (FIX(0.29900) * r + FIX(0.58700) * g +               \
591                     FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;          \
592             q++;                                                        \
593             p += BPP;                                                   \
594         }                                                               \
595         p += src_wrap;                                                  \
596         q += dst_wrap;                                                  \
597     }                                                                   \
598 }                                                                       \
599                                                                         \
600 static void gray_to_ ## rgb_name(AVPicture *dst, AVPicture *src,        \
601                                  int width, int height)                 \
602 {                                                                       \
603     const unsigned char *p;                                             \
604     unsigned char *q;                                                   \
605     int r, dst_wrap, src_wrap;                                          \
606     int x, y;                                                           \
607                                                                         \
608     p = src->data[0];                                                   \
609     src_wrap = src->linesize[0] - width;                                \
610                                                                         \
611     q = dst->data[0];                                                   \
612     dst_wrap = dst->linesize[0] - BPP * width;                          \
613                                                                         \
614     for(y=0;y<height;y++) {                                             \
615         for(x=0;x<width;x++) {                                          \
616             r = p[0];                                                   \
617             RGB_OUT(q, r, r, r);                                        \
618             q += BPP;                                                   \
619             p ++;                                                       \
620         }                                                               \
621         p += src_wrap;                                                  \
622         q += dst_wrap;                                                  \
623     }                                                                   \
624 }
625
626 /* copy bit n to bits 0 ... n - 1 */
627 static inline unsigned int bitcopy_n(unsigned int a, int n)
628 {
629     int mask;
630     mask = (1 << n) - 1;
631     return (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask);
632 }
633
634 /* rgb555 handling */
635
636 #define RGB_IN(r, g, b, s)\
637 {\
638     unsigned int v = ((UINT16 *)(s))[0];\
639     r = bitcopy_n(v >> (10 - 3), 3);\
640     g = bitcopy_n(v >> (5 - 3), 3);\
641     b = bitcopy_n(v << 3, 3);\
642 }
643
644 #define RGB_OUT(d, r, g, b)\
645 {\
646     ((UINT16 *)(d))[0] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;\
647 }
648
649 #define BPP 2
650
651 RGB_FUNCTIONS(rgb555)
652
653 #undef RGB_IN
654 #undef RGB_OUT
655 #undef BPP
656
657 /* rgb565 handling */
658
659 #define RGB_IN(r, g, b, s)\
660 {\
661     unsigned int v = ((UINT16 *)(s))[0];\
662     r = bitcopy_n(v >> (11 - 3), 3);\
663     g = bitcopy_n(v >> (5 - 2), 2);\
664     b = bitcopy_n(v << 3, 3);\
665 }
666
667 #define RGB_OUT(d, r, g, b)\
668 {\
669     ((UINT16 *)(d))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\
670 }
671
672 #define BPP 2
673
674 RGB_FUNCTIONS(rgb565)
675
676 #undef RGB_IN
677 #undef RGB_OUT
678 #undef BPP
679
680 /* bgr24 handling */
681
682 #define RGB_IN(r, g, b, s)\
683 {\
684     b = (s)[0];\
685     g = (s)[1];\
686     r = (s)[2];\
687 }
688
689 #define RGB_OUT(d, r, g, b)\
690 {\
691     (d)[0] = b;\
692     (d)[1] = g;\
693     (d)[2] = r;\
694 }
695
696 #define BPP 3
697
698 RGB_FUNCTIONS(bgr24)
699
700 #undef RGB_IN
701 #undef RGB_OUT
702 #undef BPP
703
704 /* rgb24 handling */
705
706 #define RGB_IN(r, g, b, s)\
707 {\
708     r = (s)[0];\
709     g = (s)[1];\
710     b = (s)[2];\
711 }
712
713 #define RGB_OUT(d, r, g, b)\
714 {\
715     (d)[0] = r;\
716     (d)[1] = g;\
717     (d)[2] = b;\
718 }
719
720 #define BPP 3
721
722 RGB_FUNCTIONS(rgb24)
723
724 #undef RGB_IN
725 #undef RGB_OUT
726 #undef BPP
727
728 /* rgba32 handling */
729
730 #define RGB_IN(r, g, b, s)\
731 {\
732     unsigned int v = ((UINT32 *)(s))[0];\
733     r = (v >> 16) & 0xff;\
734     g = (v >> 8) & 0xff;\
735     b = v & 0xff;\
736 }
737
738 #define RGB_OUT(d, r, g, b)\
739 {\
740     ((UINT32 *)(d))[0] = (0xff << 24) | (r << 16) | (g << 8) | b;\
741 }
742
743 #define BPP 4
744
745 RGB_FUNCTIONS(rgba32)
746
747 #undef RGB_IN
748 #undef RGB_OUT
749 #undef BPP
750
751
752 static void rgb24_to_rgb565(AVPicture *dst, AVPicture *src,
753                             int width, int height)
754 {
755     const unsigned char *p;
756     unsigned char *q;
757     int r, g, b, dst_wrap, src_wrap;
758     int x, y;
759
760     p = src->data[0];
761     src_wrap = src->linesize[0] - 3 * width;
762
763     q = dst->data[0];
764     dst_wrap = dst->linesize[0] - 2 * width;
765
766     for(y=0;y<height;y++) {
767         for(x=0;x<width;x++) {
768             r = p[0];
769             g = p[1];
770             b = p[2];
771
772             ((unsigned short *)q)[0] = 
773                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
774             q += 2;
775             p += 3;
776         }
777         p += src_wrap;
778         q += dst_wrap;
779     }
780 }
781
782 /* NOTE: we also add a dummy alpha bit */
783 static void rgb24_to_rgb555(AVPicture *dst, AVPicture *src,
784                             int width, int height)
785 {
786     const unsigned char *p;
787     unsigned char *q;
788     int r, g, b, dst_wrap, src_wrap;
789     int x, y;
790
791     p = src->data[0];
792     src_wrap = src->linesize[0] - 3 * width;
793
794     q = dst->data[0];
795     dst_wrap = dst->linesize[0] - 2 * width;
796
797     for(y=0;y<height;y++) {
798         for(x=0;x<width;x++) {
799             r = p[0];
800             g = p[1];
801             b = p[2];
802
803             ((unsigned short *)q)[0] = 
804                 ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) | 0x8000;
805             q += 2;
806             p += 3;
807         }
808         p += src_wrap;
809         q += dst_wrap;
810     }
811 }
812
813 static void mono_to_gray(AVPicture *dst, AVPicture *src,
814                          int width, int height, int xor_mask)
815 {
816     const unsigned char *p;
817     unsigned char *q;
818     int v, dst_wrap, src_wrap;
819     int y, w;
820
821     p = src->data[0];
822     src_wrap = src->linesize[0] - ((width + 7) >> 3);
823
824     q = dst->data[0];
825     dst_wrap = dst->linesize[0] - width;
826     for(y=0;y<height;y++) {
827         w = width; 
828         while (w >= 8) {
829             v = *p++ ^ xor_mask;
830             q[0] = -(v >> 7);
831             q[1] = -((v >> 6) & 1);
832             q[2] = -((v >> 5) & 1);
833             q[3] = -((v >> 4) & 1);
834             q[4] = -((v >> 3) & 1);
835             q[5] = -((v >> 2) & 1);
836             q[6] = -((v >> 1) & 1);
837             q[7] = -((v >> 0) & 1);
838             w -= 8;
839             q += 8;
840         }
841         if (w > 0) {
842             v = *p++ ^ xor_mask;
843             do {
844                 q[0] = -((v >> 7) & 1);
845                 q++;
846                 v <<= 1;
847             } while (--w);
848         }
849         p += src_wrap;
850         q += dst_wrap;
851     }
852 }
853
854 static void monowhite_to_gray(AVPicture *dst, AVPicture *src,
855                                int width, int height)
856 {
857     mono_to_gray(dst, src, width, height, 0xff);
858 }
859
860 static void monoblack_to_gray(AVPicture *dst, AVPicture *src,
861                                int width, int height)
862 {
863     mono_to_gray(dst, src, width, height, 0x00);
864 }
865
866 static void gray_to_mono(AVPicture *dst, AVPicture *src,
867                          int width, int height, int xor_mask)
868 {
869     int n;
870     const UINT8 *s;
871     UINT8 *d;
872     int j, b, v, n1, src_wrap, dst_wrap, y;
873
874     s = src->data[0];
875     src_wrap = src->linesize[0] - width;
876
877     d = dst->data[0];
878     dst_wrap = dst->linesize[0] - ((width + 7) >> 3);
879     printf("%d %d\n", width, height);
880
881     for(y=0;y<height;y++) {
882         n = width;
883         while (n >= 8) {
884             v = 0;
885             for(j=0;j<8;j++) {
886                 b = s[0];
887                 s++;
888                 v = (v << 1) | (b >> 7);
889             }
890             d[0] = v ^ xor_mask;
891             d++;
892             n -= 8;
893         }
894         if (n > 0) {
895             n1 = n;
896             v = 0;
897             while (n > 0) {
898                 b = s[0];
899                 s++;
900                 v = (v << 1) | (b >> 7);
901                 n--;
902             }
903             d[0] = (v << (8 - (n1 & 7))) ^ xor_mask;
904             d++;
905         }
906         s += src_wrap;
907         d += dst_wrap;
908     }
909 }
910
911 static void gray_to_monowhite(AVPicture *dst, AVPicture *src,
912                               int width, int height)
913 {
914     gray_to_mono(dst, src, width, height, 0xff);
915 }
916
917 static void gray_to_monoblack(AVPicture *dst, AVPicture *src,
918                               int width, int height)
919 {
920     gray_to_mono(dst, src, width, height, 0x00);
921 }
922
923 typedef struct ConvertEntry {
924     void (*convert)(AVPicture *dst, AVPicture *src, int width, int height);
925 } ConvertEntry;
926
927 /* add each new convertion function in this table */
928 /* constraints;
929    - all non YUV modes must convert at least to and from PIX_FMT_RGB24
930 */
931 static ConvertEntry convert_table[PIX_FMT_NB][PIX_FMT_NB] = {
932     [PIX_FMT_YUV420P] = {
933         [PIX_FMT_RGB555] = { 
934             .convert = yuv420p_to_rgb555
935         },
936         [PIX_FMT_RGB565] = { 
937             .convert = yuv420p_to_rgb565
938         },
939         [PIX_FMT_BGR24] = { 
940             .convert = yuv420p_to_bgr24
941         },
942         [PIX_FMT_RGB24] = { 
943             .convert = yuv420p_to_rgb24
944         },
945         [PIX_FMT_RGBA32] = { 
946             .convert = yuv420p_to_rgba32
947         },
948     },
949     [PIX_FMT_YUV422P] = {
950         [PIX_FMT_RGB555] = { 
951             .convert = yuv422p_to_rgb555
952         },
953         [PIX_FMT_RGB565] = { 
954             .convert = yuv422p_to_rgb565
955         },
956         [PIX_FMT_BGR24] = { 
957             .convert = yuv422p_to_bgr24
958         },
959         [PIX_FMT_RGB24] = { 
960             .convert = yuv422p_to_rgb24
961         },
962         [PIX_FMT_RGBA32] = { 
963             .convert = yuv422p_to_rgba32
964         },
965     },
966     [PIX_FMT_YUV422] = { 
967         [PIX_FMT_YUV420P] = { 
968             .convert = yuv422_to_yuv420p,
969         },
970     },
971
972     [PIX_FMT_RGB24] = {
973         [PIX_FMT_YUV420P] = { 
974             .convert = rgb24_to_yuv420p
975         },
976         [PIX_FMT_RGB565] = { 
977             .convert = rgb24_to_rgb565
978         },
979         [PIX_FMT_RGB555] = { 
980             .convert = rgb24_to_rgb555
981         },
982         [PIX_FMT_GRAY8] = { 
983             .convert = rgb24_to_gray
984         },
985     },
986     [PIX_FMT_RGBA32] = {
987         [PIX_FMT_YUV420P] = { 
988             .convert = rgba32_to_yuv420p
989         },
990         [PIX_FMT_GRAY8] = { 
991             .convert = rgba32_to_gray
992         },
993     },
994     [PIX_FMT_BGR24] = {
995         [PIX_FMT_YUV420P] = { 
996             .convert = bgr24_to_yuv420p
997         },
998         [PIX_FMT_GRAY8] = { 
999             .convert = bgr24_to_gray
1000         },
1001     },
1002     [PIX_FMT_RGB555] = {
1003         [PIX_FMT_YUV420P] = { 
1004             .convert = rgb555_to_yuv420p
1005         },
1006         [PIX_FMT_GRAY8] = { 
1007             .convert = rgb555_to_gray
1008         },
1009     },
1010     [PIX_FMT_RGB565] = {
1011         [PIX_FMT_YUV420P] = { 
1012             .convert = rgb565_to_yuv420p
1013         },
1014         [PIX_FMT_GRAY8] = { 
1015             .convert = rgb565_to_gray
1016         },
1017     },
1018     [PIX_FMT_GRAY8] = {
1019         [PIX_FMT_RGB555] = { 
1020             .convert = gray_to_rgb555
1021         },
1022         [PIX_FMT_RGB565] = { 
1023             .convert = gray_to_rgb565
1024         },
1025         [PIX_FMT_RGB24] = { 
1026             .convert = gray_to_rgb24
1027         },
1028         [PIX_FMT_BGR24] = { 
1029             .convert = gray_to_bgr24
1030         },
1031         [PIX_FMT_RGBA32] = { 
1032             .convert = gray_to_rgba32
1033         },
1034         [PIX_FMT_MONOWHITE] = { 
1035             .convert = gray_to_monowhite
1036         },
1037         [PIX_FMT_MONOBLACK] = { 
1038             .convert = gray_to_monoblack
1039         },
1040     },
1041     [PIX_FMT_MONOWHITE] = {
1042         [PIX_FMT_GRAY8] = { 
1043             .convert = monowhite_to_gray
1044         },
1045     },
1046     [PIX_FMT_MONOBLACK] = {
1047         [PIX_FMT_GRAY8] = { 
1048             .convert = monoblack_to_gray
1049         },
1050     },
1051 };
1052
1053 static int avpicture_alloc(AVPicture *picture,
1054                            int pix_fmt, int width, int height)
1055 {
1056     int size;
1057     void *ptr;
1058
1059     size = avpicture_get_size(pix_fmt, width, height);
1060     if (size < 0)
1061         goto fail;
1062     ptr = av_malloc(size);
1063     if (!ptr)
1064         goto fail;
1065     avpicture_fill(picture, ptr, pix_fmt, width, height);
1066     return 0;
1067  fail:
1068     memset(picture, 0, sizeof(AVPicture));
1069     return -1;
1070 }
1071
1072 static void avpicture_free(AVPicture *picture)
1073 {
1074     av_free(picture->data[0]);
1075 }
1076
1077 /* XXX: always use linesize. Return -1 if not supported */
1078 int img_convert(AVPicture *dst, int dst_pix_fmt,
1079                 AVPicture *src, int src_pix_fmt, 
1080                 int src_width, int src_height)
1081 {
1082     int i, ret, dst_width, dst_height, int_pix_fmt;
1083     PixFmtInfo *src_pix, *dst_pix;
1084     ConvertEntry *ce;
1085     AVPicture tmp1, *tmp = &tmp1;
1086
1087     if (src_pix_fmt < 0 || src_pix_fmt >= PIX_FMT_NB ||
1088         dst_pix_fmt < 0 || dst_pix_fmt >= PIX_FMT_NB)
1089         return -1;
1090     if (src_width <= 0 || src_height <= 0)
1091         return 0;
1092
1093     dst_width = src_width;
1094     dst_height = src_height;
1095
1096     dst_pix = &pix_fmt_info[dst_pix_fmt];
1097     src_pix = &pix_fmt_info[src_pix_fmt];
1098     if (src_pix_fmt == dst_pix_fmt) {
1099         /* XXX: incorrect */
1100         /* same format: just copy */
1101         for(i = 0; i < dst_pix->nb_components; i++) {
1102             int w, h;
1103             w = dst_width;
1104             h = dst_height;
1105             if (dst_pix->is_yuv && (i == 1 || i == 2)) {
1106                 w >>= dst_pix->x_chroma_shift;
1107                 h >>= dst_pix->y_chroma_shift;
1108             }
1109             img_copy(dst->data[i], dst->linesize[i],
1110                      src->data[i], src->linesize[i],
1111                      w, h);
1112         }
1113         return 0;
1114     }
1115
1116     ce = &convert_table[src_pix_fmt][dst_pix_fmt];
1117     if (ce->convert) {
1118         /* specific convertion routine */
1119         ce->convert(dst, src, dst_width, dst_height);
1120         return 0;
1121     }
1122
1123     /* gray to YUV */
1124     if (dst_pix->is_yuv && src_pix_fmt == PIX_FMT_GRAY8) {
1125         int w, h, y;
1126         uint8_t *d;
1127
1128         img_copy(dst->data[0], dst->linesize[0],
1129                  src->data[0], src->linesize[0],
1130                  dst_width, dst_height);
1131         /* fill U and V with 128 */
1132         w = dst_width;
1133         h = dst_height;
1134         w >>= dst_pix->x_chroma_shift;
1135         h >>= dst_pix->y_chroma_shift;
1136         for(i = 1; i <= 2; i++) {
1137             d = dst->data[i];
1138             for(y = 0; y< h; y++) {
1139                 memset(d, 128, w);
1140                 d += dst->linesize[i];
1141             }
1142         }
1143         return 0;
1144     }
1145
1146     /* YUV to gray */
1147     if (src_pix->is_yuv && dst_pix_fmt == PIX_FMT_GRAY8) {
1148         img_copy(dst->data[0], dst->linesize[0],
1149                  src->data[0], src->linesize[0],
1150                  dst_width, dst_height);
1151         return 0;
1152     }
1153
1154     /* YUV to YUV */
1155     if (dst_pix->is_yuv && src_pix->is_yuv) {
1156         int x_shift, y_shift, w, h;
1157         void (*resize_func)(UINT8 *dst, int dst_wrap, 
1158                             UINT8 *src, int src_wrap,
1159                             int width, int height);
1160
1161         /* compute chroma size of the smallest dimensions */
1162         w = dst_width;
1163         h = dst_height;
1164         if (dst_pix->x_chroma_shift >= src_pix->x_chroma_shift)
1165             w >>= dst_pix->x_chroma_shift;
1166         else
1167             w >>= src_pix->x_chroma_shift;
1168         if (dst_pix->y_chroma_shift >= src_pix->y_chroma_shift)
1169             h >>= dst_pix->y_chroma_shift;
1170         else
1171             h >>= src_pix->y_chroma_shift;
1172
1173         x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);
1174         y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);
1175         if (x_shift == 0 && y_shift == 0) {
1176             resize_func = img_copy; /* should never happen */
1177         } else if (x_shift == 0 && y_shift == 1) {
1178             resize_func = shrink2;
1179         } else if (x_shift == 1 && y_shift == 1) {
1180             resize_func = shrink22;
1181         } else if (x_shift == -1 && y_shift == -1) {
1182             resize_func = grow22;
1183         } else if (x_shift == -1 && y_shift == 1) {
1184             resize_func = conv411;
1185         } else {
1186             /* currently not handled */
1187             return -1;
1188         }
1189
1190         img_copy(dst->data[0], dst->linesize[0],
1191                  src->data[0], src->linesize[0],
1192                  dst_width, dst_height);
1193
1194         for(i = 1;i <= 2; i++)
1195             resize_func(dst->data[i], dst->linesize[i],
1196                         src->data[i], src->linesize[i],
1197                         w, h);
1198        return 0;
1199     }
1200
1201     /* try to use an intermediate format */
1202     if (src_pix_fmt == PIX_FMT_MONOWHITE ||
1203         src_pix_fmt == PIX_FMT_MONOBLACK ||
1204         dst_pix_fmt == PIX_FMT_MONOWHITE ||
1205         dst_pix_fmt == PIX_FMT_MONOBLACK) {
1206         int_pix_fmt = PIX_FMT_GRAY8;
1207     } else {
1208         int_pix_fmt = PIX_FMT_RGB24;
1209     }
1210     if (avpicture_alloc(tmp, int_pix_fmt, dst_width, dst_height) < 0)
1211         return -1;
1212     ret = -1;
1213     if (img_convert(tmp, int_pix_fmt,
1214                     src, src_pix_fmt, src_width, src_height) < 0)
1215         goto fail1;
1216     if (img_convert(dst, dst_pix_fmt,
1217                     tmp, int_pix_fmt, dst_width, dst_height) < 0)
1218         goto fail1;
1219     ret = 0;
1220  fail1:
1221     avpicture_free(tmp);
1222     return ret;
1223 }
1224
1225
1226 #ifdef HAVE_MMX
1227 #define DEINT_INPLACE_LINE_LUM \
1228                     movd_m2r(lum_m4[0],mm0);\
1229                     movd_m2r(lum_m3[0],mm1);\
1230                     movd_m2r(lum_m2[0],mm2);\
1231                     movd_m2r(lum_m1[0],mm3);\
1232                     movd_m2r(lum[0],mm4);\
1233                     punpcklbw_r2r(mm7,mm0);\
1234                     movd_r2m(mm2,lum_m4[0]);\
1235                     punpcklbw_r2r(mm7,mm1);\
1236                     punpcklbw_r2r(mm7,mm2);\
1237                     punpcklbw_r2r(mm7,mm3);\
1238                     punpcklbw_r2r(mm7,mm4);\
1239                     paddw_r2r(mm3,mm1);\
1240                     psllw_i2r(1,mm2);\
1241                     paddw_r2r(mm4,mm0);\
1242                     psllw_i2r(2,mm1);\
1243                     paddw_r2r(mm6,mm2);\
1244                     paddw_r2r(mm2,mm1);\
1245                     psubusw_r2r(mm0,mm1);\
1246                     psrlw_i2r(3,mm1);\
1247                     packuswb_r2r(mm7,mm1);\
1248                     movd_r2m(mm1,lum_m2[0]);
1249
1250 #define DEINT_LINE_LUM \
1251                     movd_m2r(lum_m4[0],mm0);\
1252                     movd_m2r(lum_m3[0],mm1);\
1253                     movd_m2r(lum_m2[0],mm2);\
1254                     movd_m2r(lum_m1[0],mm3);\
1255                     movd_m2r(lum[0],mm4);\
1256                     punpcklbw_r2r(mm7,mm0);\
1257                     punpcklbw_r2r(mm7,mm1);\
1258                     punpcklbw_r2r(mm7,mm2);\
1259                     punpcklbw_r2r(mm7,mm3);\
1260                     punpcklbw_r2r(mm7,mm4);\
1261                     paddw_r2r(mm3,mm1);\
1262                     psllw_i2r(1,mm2);\
1263                     paddw_r2r(mm4,mm0);\
1264                     psllw_i2r(2,mm1);\
1265                     paddw_r2r(mm6,mm2);\
1266                     paddw_r2r(mm2,mm1);\
1267                     psubusw_r2r(mm0,mm1);\
1268                     psrlw_i2r(3,mm1);\
1269                     packuswb_r2r(mm7,mm1);\
1270                     movd_r2m(mm1,dst[0]);
1271 #endif
1272
1273 /* filter parameters: [-1 4 2 4 -1] // 8 */
1274 static void deinterlace_line(UINT8 *dst, UINT8 *lum_m4, UINT8 *lum_m3, UINT8 *lum_m2, UINT8 *lum_m1, UINT8 *lum,
1275                                 int size)
1276 {
1277 #ifndef HAVE_MMX
1278     UINT8 *cm = cropTbl + MAX_NEG_CROP;
1279     int sum;
1280
1281     for(;size > 0;size--) {
1282         sum = -lum_m4[0];
1283         sum += lum_m3[0] << 2;
1284         sum += lum_m2[0] << 1;
1285         sum += lum_m1[0] << 2;
1286         sum += -lum[0];
1287         dst[0] = cm[(sum + 4) >> 3];
1288         lum_m4++;
1289         lum_m3++;
1290         lum_m2++;
1291         lum_m1++;
1292         lum++;
1293         dst++;
1294     }
1295 #else
1296
1297     for (;size > 3; size-=4) {
1298         DEINT_LINE_LUM
1299         lum_m4+=4;
1300         lum_m3+=4;
1301         lum_m2+=4;
1302         lum_m1+=4;
1303         lum+=4;
1304         dst+=4;
1305     }
1306 #endif
1307 }
1308 static void deinterlace_line_inplace(UINT8 *lum_m4, UINT8 *lum_m3, UINT8 *lum_m2, UINT8 *lum_m1, UINT8 *lum,
1309                              int size)
1310 {
1311 #ifndef HAVE_MMX
1312     UINT8 *cm = cropTbl + MAX_NEG_CROP;
1313     int sum;
1314
1315     for(;size > 0;size--) {
1316         sum = -lum_m4[0];
1317         sum += lum_m3[0] << 2;
1318         sum += lum_m2[0] << 1;
1319         lum_m4[0]=lum_m2[0];
1320         sum += lum_m1[0] << 2;
1321         sum += -lum[0];
1322         lum_m2[0] = cm[(sum + 4) >> 3];
1323         lum_m4++;
1324         lum_m3++;
1325         lum_m2++;
1326         lum_m1++;
1327         lum++;
1328     }
1329 #else
1330
1331     for (;size > 3; size-=4) {
1332         DEINT_INPLACE_LINE_LUM
1333         lum_m4+=4;
1334         lum_m3+=4;
1335         lum_m2+=4;
1336         lum_m1+=4;
1337         lum+=4;
1338     }
1339 #endif
1340 }
1341
1342 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
1343    top field is copied as is, but the bottom field is deinterlaced
1344    against the top field. */
1345 static void deinterlace_bottom_field(UINT8 *dst, int dst_wrap,
1346                                     UINT8 *src1, int src_wrap,
1347                                     int width, int height)
1348 {
1349     UINT8 *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
1350     int y;
1351
1352     src_m2 = src1;
1353     src_m1 = src1;
1354     src_0=&src_m1[src_wrap];
1355     src_p1=&src_0[src_wrap];
1356     src_p2=&src_p1[src_wrap];
1357     for(y=0;y<(height-2);y+=2) {
1358         memcpy(dst,src_m1,width);
1359         dst += dst_wrap;
1360         deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
1361         src_m2 = src_0;
1362         src_m1 = src_p1;
1363         src_0 = src_p2;
1364         src_p1 += 2*src_wrap;
1365         src_p2 += 2*src_wrap;
1366         dst += dst_wrap;
1367     }
1368     memcpy(dst,src_m1,width);
1369     dst += dst_wrap;
1370     /* do last line */
1371     deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
1372 }
1373
1374 static void deinterlace_bottom_field_inplace(UINT8 *src1, int src_wrap,
1375                                      int width, int height)
1376 {
1377     UINT8 *src_m1, *src_0, *src_p1, *src_p2;
1378     int y;
1379     UINT8 *buf;
1380     buf = (UINT8*)av_malloc(width);
1381
1382     src_m1 = src1;
1383     memcpy(buf,src_m1,width);
1384     src_0=&src_m1[src_wrap];
1385     src_p1=&src_0[src_wrap];
1386     src_p2=&src_p1[src_wrap];
1387     for(y=0;y<(height-2);y+=2) {
1388         deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
1389         src_m1 = src_p1;
1390         src_0 = src_p2;
1391         src_p1 += 2*src_wrap;
1392         src_p2 += 2*src_wrap;
1393     }
1394     /* do last line */
1395     deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
1396     av_free(buf);
1397 }
1398
1399
1400 /* deinterlace - if not supported return -1 */
1401 int avpicture_deinterlace(AVPicture *dst, AVPicture *src,
1402                           int pix_fmt, int width, int height)
1403 {
1404     int i;
1405
1406     if (pix_fmt != PIX_FMT_YUV420P &&
1407         pix_fmt != PIX_FMT_YUV422P &&
1408         pix_fmt != PIX_FMT_YUV444P)
1409         return -1;
1410     if ((width & 3) != 0 || (height & 3) != 0)
1411         return -1;
1412
1413 #ifdef HAVE_MMX
1414     {
1415         mmx_t rounder;
1416         rounder.uw[0]=4;
1417         rounder.uw[1]=4;
1418         rounder.uw[2]=4;
1419         rounder.uw[3]=4;
1420         pxor_r2r(mm7,mm7);
1421         movq_m2r(rounder,mm6);
1422     }
1423 #endif
1424
1425     
1426     for(i=0;i<3;i++) {
1427         if (i == 1) {
1428             switch(pix_fmt) {
1429             case PIX_FMT_YUV420P:
1430                 width >>= 1;
1431                 height >>= 1;
1432                 break;
1433             case PIX_FMT_YUV422P:
1434                 width >>= 1;
1435                 break;
1436             default:
1437                 break;
1438             }
1439         }
1440         if (src == dst) {
1441             deinterlace_bottom_field_inplace(src->data[i], src->linesize[i],
1442                                  width, height);
1443         } else {
1444             deinterlace_bottom_field(dst->data[i],dst->linesize[i],
1445                                         src->data[i], src->linesize[i],
1446                                         width, height);
1447         }
1448     }
1449 #ifdef HAVE_MMX
1450     emms();
1451 #endif
1452     return 0;
1453 }
1454
1455 #undef FIX