]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/imgresample.c
Remove redundant fastmemcpy.h #include, it is indirectly #included by avutil.h.
[frescor/ffmpeg.git] / libavcodec / imgresample.c
1 /*
2  * High quality image resampling with polyphase filters
3  * Copyright (c) 2001 Fabrice Bellard.
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file imgresample.c
24  * High quality image resampling with polyphase filters .
25  */
26
27 #include "avcodec.h"
28 #include "swscale.h"
29 #include "dsputil.h"
30
31 #define NB_COMPONENTS 3
32
33 #define PHASE_BITS 4
34 #define NB_PHASES  (1 << PHASE_BITS)
35 #define NB_TAPS    4
36 #define FCENTER    1  /* index of the center of the filter */
37 //#define TEST    1  /* Test it */
38
39 #define POS_FRAC_BITS 16
40 #define POS_FRAC      (1 << POS_FRAC_BITS)
41 /* 6 bits precision is needed for MMX */
42 #define FILTER_BITS   8
43
44 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
45
46 struct SwsContext {
47     struct ImgReSampleContext *resampling_ctx;
48     enum PixelFormat src_pix_fmt, dst_pix_fmt;
49 };
50
51 struct ImgReSampleContext {
52     int iwidth, iheight, owidth, oheight;
53     int topBand, bottomBand, leftBand, rightBand;
54     int padtop, padbottom, padleft, padright;
55     int pad_owidth, pad_oheight;
56     int h_incr, v_incr;
57     DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
58     DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
59     uint8_t *line_buf;
60 };
61
62 void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
63
64 static inline int get_phase(int pos)
65 {
66     return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
67 }
68
69 /* This function must be optimized */
70 static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
71                             int src_width, int src_start, int src_incr,
72                             int16_t *filters)
73 {
74     int src_pos, phase, sum, i;
75     const uint8_t *s;
76     int16_t *filter;
77
78     src_pos = src_start;
79     for(i=0;i<dst_width;i++) {
80 #ifdef TEST
81         /* test */
82         if ((src_pos >> POS_FRAC_BITS) < 0 ||
83             (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
84             av_abort();
85 #endif
86         s = src + (src_pos >> POS_FRAC_BITS);
87         phase = get_phase(src_pos);
88         filter = filters + phase * NB_TAPS;
89 #if NB_TAPS == 4
90         sum = s[0] * filter[0] +
91             s[1] * filter[1] +
92             s[2] * filter[2] +
93             s[3] * filter[3];
94 #else
95         {
96             int j;
97             sum = 0;
98             for(j=0;j<NB_TAPS;j++)
99                 sum += s[j] * filter[j];
100         }
101 #endif
102         sum = sum >> FILTER_BITS;
103         if (sum < 0)
104             sum = 0;
105         else if (sum > 255)
106             sum = 255;
107         dst[0] = sum;
108         src_pos += src_incr;
109         dst++;
110     }
111 }
112
113 /* This function must be optimized */
114 static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
115                        int wrap, int16_t *filter)
116 {
117     int sum, i;
118     const uint8_t *s;
119
120     s = src;
121     for(i=0;i<dst_width;i++) {
122 #if NB_TAPS == 4
123         sum = s[0 * wrap] * filter[0] +
124             s[1 * wrap] * filter[1] +
125             s[2 * wrap] * filter[2] +
126             s[3 * wrap] * filter[3];
127 #else
128         {
129             int j;
130             uint8_t *s1 = s;
131
132             sum = 0;
133             for(j=0;j<NB_TAPS;j++) {
134                 sum += s1[0] * filter[j];
135                 s1 += wrap;
136             }
137         }
138 #endif
139         sum = sum >> FILTER_BITS;
140         if (sum < 0)
141             sum = 0;
142         else if (sum > 255)
143             sum = 255;
144         dst[0] = sum;
145         dst++;
146         s++;
147     }
148 }
149
150 #ifdef HAVE_MMX
151
152 #include "i386/mmx.h"
153
154 #define FILTER4(reg) \
155 {\
156         s = src + (src_pos >> POS_FRAC_BITS);\
157         phase = get_phase(src_pos);\
158         filter = filters + phase * NB_TAPS;\
159         movq_m2r(*s, reg);\
160         punpcklbw_r2r(mm7, reg);\
161         movq_m2r(*filter, mm6);\
162         pmaddwd_r2r(reg, mm6);\
163         movq_r2r(mm6, reg);\
164         psrlq_i2r(32, reg);\
165         paddd_r2r(mm6, reg);\
166         psrad_i2r(FILTER_BITS, reg);\
167         src_pos += src_incr;\
168 }
169
170 #define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
171
172 /* XXX: do four pixels at a time */
173 static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
174                                  const uint8_t *src, int src_width,
175                                  int src_start, int src_incr, int16_t *filters)
176 {
177     int src_pos, phase;
178     const uint8_t *s;
179     int16_t *filter;
180     mmx_t tmp;
181
182     src_pos = src_start;
183     pxor_r2r(mm7, mm7);
184
185     while (dst_width >= 4) {
186
187         FILTER4(mm0);
188         FILTER4(mm1);
189         FILTER4(mm2);
190         FILTER4(mm3);
191
192         packuswb_r2r(mm7, mm0);
193         packuswb_r2r(mm7, mm1);
194         packuswb_r2r(mm7, mm3);
195         packuswb_r2r(mm7, mm2);
196         movq_r2m(mm0, tmp);
197         dst[0] = tmp.ub[0];
198         movq_r2m(mm1, tmp);
199         dst[1] = tmp.ub[0];
200         movq_r2m(mm2, tmp);
201         dst[2] = tmp.ub[0];
202         movq_r2m(mm3, tmp);
203         dst[3] = tmp.ub[0];
204         dst += 4;
205         dst_width -= 4;
206     }
207     while (dst_width > 0) {
208         FILTER4(mm0);
209         packuswb_r2r(mm7, mm0);
210         movq_r2m(mm0, tmp);
211         dst[0] = tmp.ub[0];
212         dst++;
213         dst_width--;
214     }
215     emms();
216 }
217
218 static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
219                             int wrap, int16_t *filter)
220 {
221     int sum, i, v;
222     const uint8_t *s;
223     mmx_t tmp;
224     mmx_t coefs[4];
225
226     for(i=0;i<4;i++) {
227         v = filter[i];
228         coefs[i].uw[0] = v;
229         coefs[i].uw[1] = v;
230         coefs[i].uw[2] = v;
231         coefs[i].uw[3] = v;
232     }
233
234     pxor_r2r(mm7, mm7);
235     s = src;
236     while (dst_width >= 4) {
237         movq_m2r(s[0 * wrap], mm0);
238         punpcklbw_r2r(mm7, mm0);
239         movq_m2r(s[1 * wrap], mm1);
240         punpcklbw_r2r(mm7, mm1);
241         movq_m2r(s[2 * wrap], mm2);
242         punpcklbw_r2r(mm7, mm2);
243         movq_m2r(s[3 * wrap], mm3);
244         punpcklbw_r2r(mm7, mm3);
245
246         pmullw_m2r(coefs[0], mm0);
247         pmullw_m2r(coefs[1], mm1);
248         pmullw_m2r(coefs[2], mm2);
249         pmullw_m2r(coefs[3], mm3);
250
251         paddw_r2r(mm1, mm0);
252         paddw_r2r(mm3, mm2);
253         paddw_r2r(mm2, mm0);
254         psraw_i2r(FILTER_BITS, mm0);
255
256         packuswb_r2r(mm7, mm0);
257         movq_r2m(mm0, tmp);
258
259         *(uint32_t *)dst = tmp.ud[0];
260         dst += 4;
261         s += 4;
262         dst_width -= 4;
263     }
264     while (dst_width > 0) {
265         sum = s[0 * wrap] * filter[0] +
266             s[1 * wrap] * filter[1] +
267             s[2 * wrap] * filter[2] +
268             s[3 * wrap] * filter[3];
269         sum = sum >> FILTER_BITS;
270         if (sum < 0)
271             sum = 0;
272         else if (sum > 255)
273             sum = 255;
274         dst[0] = sum;
275         dst++;
276         s++;
277         dst_width--;
278     }
279     emms();
280 }
281 #endif /* HAVE_MMX */
282
283 #ifdef HAVE_ALTIVEC
284 typedef         union {
285     vector unsigned char v;
286     unsigned char c[16];
287 } vec_uc_t;
288
289 typedef         union {
290     vector signed short v;
291     signed short s[8];
292 } vec_ss_t;
293
294 void v_resample16_altivec(uint8_t *dst, int dst_width, const uint8_t *src,
295                           int wrap, int16_t *filter)
296 {
297     int sum, i;
298     const uint8_t *s;
299     vector unsigned char *tv, tmp, dstv, zero;
300     vec_ss_t srchv[4], srclv[4], fv[4];
301     vector signed short zeros, sumhv, sumlv;
302     s = src;
303
304     for(i=0;i<4;i++)
305     {
306         /*
307            The vec_madds later on does an implicit >>15 on the result.
308            Since FILTER_BITS is 8, and we have 15 bits of magnitude in
309            a signed short, we have just enough bits to pre-shift our
310            filter constants <<7 to compensate for vec_madds.
311         */
312         fv[i].s[0] = filter[i] << (15-FILTER_BITS);
313         fv[i].v = vec_splat(fv[i].v, 0);
314     }
315
316     zero = vec_splat_u8(0);
317     zeros = vec_splat_s16(0);
318
319
320     /*
321        When we're resampling, we'd ideally like both our input buffers,
322        and output buffers to be 16-byte aligned, so we can do both aligned
323        reads and writes. Sadly we can't always have this at the moment, so
324        we opt for aligned writes, as unaligned writes have a huge overhead.
325        To do this, do enough scalar resamples to get dst 16-byte aligned.
326     */
327     i = (-(int)dst) & 0xf;
328     while(i>0) {
329         sum = s[0 * wrap] * filter[0] +
330         s[1 * wrap] * filter[1] +
331         s[2 * wrap] * filter[2] +
332         s[3 * wrap] * filter[3];
333         sum = sum >> FILTER_BITS;
334         if (sum<0) sum = 0; else if (sum>255) sum=255;
335         dst[0] = sum;
336         dst++;
337         s++;
338         dst_width--;
339         i--;
340     }
341
342     /* Do our altivec resampling on 16 pixels at once. */
343     while(dst_width>=16) {
344         /*
345            Read 16 (potentially unaligned) bytes from each of
346            4 lines into 4 vectors, and split them into shorts.
347            Interleave the multipy/accumulate for the resample
348            filter with the loads to hide the 3 cycle latency
349            the vec_madds have.
350         */
351         tv = (vector unsigned char *) &s[0 * wrap];
352         tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[i * wrap]));
353         srchv[0].v = (vector signed short) vec_mergeh(zero, tmp);
354         srclv[0].v = (vector signed short) vec_mergel(zero, tmp);
355         sumhv = vec_madds(srchv[0].v, fv[0].v, zeros);
356         sumlv = vec_madds(srclv[0].v, fv[0].v, zeros);
357
358         tv = (vector unsigned char *) &s[1 * wrap];
359         tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[1 * wrap]));
360         srchv[1].v = (vector signed short) vec_mergeh(zero, tmp);
361         srclv[1].v = (vector signed short) vec_mergel(zero, tmp);
362         sumhv = vec_madds(srchv[1].v, fv[1].v, sumhv);
363         sumlv = vec_madds(srclv[1].v, fv[1].v, sumlv);
364
365         tv = (vector unsigned char *) &s[2 * wrap];
366         tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[2 * wrap]));
367         srchv[2].v = (vector signed short) vec_mergeh(zero, tmp);
368         srclv[2].v = (vector signed short) vec_mergel(zero, tmp);
369         sumhv = vec_madds(srchv[2].v, fv[2].v, sumhv);
370         sumlv = vec_madds(srclv[2].v, fv[2].v, sumlv);
371
372         tv = (vector unsigned char *) &s[3 * wrap];
373         tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[3 * wrap]));
374         srchv[3].v = (vector signed short) vec_mergeh(zero, tmp);
375         srclv[3].v = (vector signed short) vec_mergel(zero, tmp);
376         sumhv = vec_madds(srchv[3].v, fv[3].v, sumhv);
377         sumlv = vec_madds(srclv[3].v, fv[3].v, sumlv);
378
379         /*
380            Pack the results into our destination vector,
381            and do an aligned write of that back to memory.
382         */
383         dstv = vec_packsu(sumhv, sumlv) ;
384         vec_st(dstv, 0, (vector unsigned char *) dst);
385
386         dst+=16;
387         s+=16;
388         dst_width-=16;
389     }
390
391     /*
392        If there are any leftover pixels, resample them
393        with the slow scalar method.
394     */
395     while(dst_width>0) {
396         sum = s[0 * wrap] * filter[0] +
397         s[1 * wrap] * filter[1] +
398         s[2 * wrap] * filter[2] +
399         s[3 * wrap] * filter[3];
400         sum = sum >> FILTER_BITS;
401         if (sum<0) sum = 0; else if (sum>255) sum=255;
402         dst[0] = sum;
403         dst++;
404         s++;
405         dst_width--;
406     }
407 }
408 #endif /* HAVE_ALTIVEC */
409
410 /* slow version to handle limit cases. Does not need optimisation */
411 static void h_resample_slow(uint8_t *dst, int dst_width,
412                             const uint8_t *src, int src_width,
413                             int src_start, int src_incr, int16_t *filters)
414 {
415     int src_pos, phase, sum, j, v, i;
416     const uint8_t *s, *src_end;
417     int16_t *filter;
418
419     src_end = src + src_width;
420     src_pos = src_start;
421     for(i=0;i<dst_width;i++) {
422         s = src + (src_pos >> POS_FRAC_BITS);
423         phase = get_phase(src_pos);
424         filter = filters + phase * NB_TAPS;
425         sum = 0;
426         for(j=0;j<NB_TAPS;j++) {
427             if (s < src)
428                 v = src[0];
429             else if (s >= src_end)
430                 v = src_end[-1];
431             else
432                 v = s[0];
433             sum += v * filter[j];
434             s++;
435         }
436         sum = sum >> FILTER_BITS;
437         if (sum < 0)
438             sum = 0;
439         else if (sum > 255)
440             sum = 255;
441         dst[0] = sum;
442         src_pos += src_incr;
443         dst++;
444     }
445 }
446
447 static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
448                        int src_width, int src_start, int src_incr,
449                        int16_t *filters)
450 {
451     int n, src_end;
452
453     if (src_start < 0) {
454         n = (0 - src_start + src_incr - 1) / src_incr;
455         h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
456         dst += n;
457         dst_width -= n;
458         src_start += n * src_incr;
459     }
460     src_end = src_start + dst_width * src_incr;
461     if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
462         n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
463             src_incr;
464     } else {
465         n = dst_width;
466     }
467 #ifdef HAVE_MMX
468     if ((mm_flags & MM_MMX) && NB_TAPS == 4)
469         h_resample_fast4_mmx(dst, n,
470                              src, src_width, src_start, src_incr, filters);
471     else
472 #endif
473         h_resample_fast(dst, n,
474                         src, src_width, src_start, src_incr, filters);
475     if (n < dst_width) {
476         dst += n;
477         dst_width -= n;
478         src_start += n * src_incr;
479         h_resample_slow(dst, dst_width,
480                         src, src_width, src_start, src_incr, filters);
481     }
482 }
483
484 static void component_resample(ImgReSampleContext *s,
485                                uint8_t *output, int owrap, int owidth, int oheight,
486                                uint8_t *input, int iwrap, int iwidth, int iheight)
487 {
488     int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
489     uint8_t *new_line, *src_line;
490
491     last_src_y = - FCENTER - 1;
492     /* position of the bottom of the filter in the source image */
493     src_y = (last_src_y + NB_TAPS) * POS_FRAC;
494     ring_y = NB_TAPS; /* position in ring buffer */
495     for(y=0;y<oheight;y++) {
496         /* apply horizontal filter on new lines from input if needed */
497         src_y1 = src_y >> POS_FRAC_BITS;
498         while (last_src_y < src_y1) {
499             if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
500                 ring_y = NB_TAPS;
501             last_src_y++;
502             /* handle limit conditions : replicate line (slightly
503                inefficient because we filter multiple times) */
504             y1 = last_src_y;
505             if (y1 < 0) {
506                 y1 = 0;
507             } else if (y1 >= iheight) {
508                 y1 = iheight - 1;
509             }
510             src_line = input + y1 * iwrap;
511             new_line = s->line_buf + ring_y * owidth;
512             /* apply filter and handle limit cases correctly */
513             h_resample(new_line, owidth,
514                        src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
515                        &s->h_filters[0][0]);
516             /* handle ring buffer wraping */
517             if (ring_y >= LINE_BUF_HEIGHT) {
518                 memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
519                        new_line, owidth);
520             }
521         }
522         /* apply vertical filter */
523         phase_y = get_phase(src_y);
524 #ifdef HAVE_MMX
525         /* desactivated MMX because loss of precision */
526         if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
527             v_resample4_mmx(output, owidth,
528                             s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
529                             &s->v_filters[phase_y][0]);
530         else
531 #endif
532 #ifdef HAVE_ALTIVEC
533             if ((mm_flags & MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
534                 v_resample16_altivec(output, owidth,
535                                 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
536                                 &s->v_filters[phase_y][0]);
537         else
538 #endif
539             v_resample(output, owidth,
540                        s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
541                        &s->v_filters[phase_y][0]);
542
543         src_y += s->v_incr;
544
545         output += owrap;
546     }
547 }
548
549 ImgReSampleContext *img_resample_init(int owidth, int oheight,
550                                       int iwidth, int iheight)
551 {
552     return img_resample_full_init(owidth, oheight, iwidth, iheight,
553             0, 0, 0, 0, 0, 0, 0, 0);
554 }
555
556 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
557                                       int iwidth, int iheight,
558                                       int topBand, int bottomBand,
559         int leftBand, int rightBand,
560         int padtop, int padbottom,
561         int padleft, int padright)
562 {
563     ImgReSampleContext *s;
564
565     if (!owidth || !oheight || !iwidth || !iheight)
566         return NULL;
567
568     s = av_mallocz(sizeof(ImgReSampleContext));
569     if (!s)
570         return NULL;
571     if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
572         return NULL;
573     s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
574     if (!s->line_buf)
575         goto fail;
576
577     s->owidth = owidth;
578     s->oheight = oheight;
579     s->iwidth = iwidth;
580     s->iheight = iheight;
581
582     s->topBand = topBand;
583     s->bottomBand = bottomBand;
584     s->leftBand = leftBand;
585     s->rightBand = rightBand;
586
587     s->padtop = padtop;
588     s->padbottom = padbottom;
589     s->padleft = padleft;
590     s->padright = padright;
591
592     s->pad_owidth = owidth - (padleft + padright);
593     s->pad_oheight = oheight - (padtop + padbottom);
594
595     s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
596     s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
597
598     av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth  /
599             (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
600     av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
601             (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
602
603     return s;
604 fail:
605     av_free(s);
606     return NULL;
607 }
608
609 void img_resample(ImgReSampleContext *s,
610                   AVPicture *output, const AVPicture *input)
611 {
612     int i, shift;
613     uint8_t* optr;
614
615     for (i=0;i<3;i++) {
616         shift = (i == 0) ? 0 : 1;
617
618         optr = output->data[i] + (((output->linesize[i] *
619                         s->padtop) + s->padleft) >> shift);
620
621         component_resample(s, optr, output->linesize[i],
622                 s->pad_owidth >> shift, s->pad_oheight >> shift,
623                 input->data[i] + (input->linesize[i] *
624                     (s->topBand >> shift)) + (s->leftBand >> shift),
625                 input->linesize[i], ((s->iwidth - s->leftBand -
626                         s->rightBand) >> shift),
627                            (s->iheight - s->topBand - s->bottomBand) >> shift);
628     }
629 }
630
631 void img_resample_close(ImgReSampleContext *s)
632 {
633     av_free(s->line_buf);
634     av_free(s);
635 }
636
637 struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
638                                   int dstW, int dstH, int dstFormat,
639                                   int flags, SwsFilter *srcFilter,
640                                   SwsFilter *dstFilter, double *param)
641 {
642     struct SwsContext *ctx;
643
644     ctx = av_malloc(sizeof(struct SwsContext));
645     if (ctx == NULL) {
646         av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
647
648         return NULL;
649     }
650
651     if ((srcH != dstH) || (srcW != dstW)) {
652         if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
653             av_log(NULL, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
654         }
655         ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
656     } else {
657         ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
658         ctx->resampling_ctx->iheight = srcH;
659         ctx->resampling_ctx->iwidth = srcW;
660         ctx->resampling_ctx->oheight = dstH;
661         ctx->resampling_ctx->owidth = dstW;
662     }
663     ctx->src_pix_fmt = srcFormat;
664     ctx->dst_pix_fmt = dstFormat;
665
666     return ctx;
667 }
668
669 void sws_freeContext(struct SwsContext *ctx)
670 {
671     if (!ctx)
672         return;
673     if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
674         (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
675         img_resample_close(ctx->resampling_ctx);
676     } else {
677         av_free(ctx->resampling_ctx);
678     }
679     av_free(ctx);
680 }
681
682
683 /**
684  * Checks if context is valid or reallocs a new one instead.
685  * If context is NULL, just calls sws_getContext() to get a new one.
686  * Otherwise, checks if the parameters are the same already saved in context.
687  * If that is the case, returns the current context.
688  * Otherwise, frees context and gets a new one.
689  *
690  * Be warned that srcFilter, dstFilter are not checked, they are
691  * asumed to remain valid.
692  */
693 struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
694                         int srcW, int srcH, int srcFormat,
695                         int dstW, int dstH, int dstFormat, int flags,
696                         SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
697 {
698     if (ctx != NULL) {
699         if ((ctx->resampling_ctx->iwidth != srcW) ||
700                         (ctx->resampling_ctx->iheight != srcH) ||
701                         (ctx->src_pix_fmt != srcFormat) ||
702                         (ctx->resampling_ctx->owidth != dstW) ||
703                         (ctx->resampling_ctx->oheight != dstH) ||
704                         (ctx->dst_pix_fmt != dstFormat))
705         {
706             sws_freeContext(ctx);
707             ctx = NULL;
708         }
709     }
710     if (ctx == NULL) {
711         return sws_getContext(srcW, srcH, srcFormat,
712                         dstW, dstH, dstFormat, flags,
713                         srcFilter, dstFilter, param);
714     }
715     return ctx;
716 }
717
718 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
719               int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
720 {
721     AVPicture src_pict, dst_pict;
722     int i, res = 0;
723     AVPicture picture_format_temp;
724     AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
725     uint8_t *buf1 = NULL, *buf2 = NULL;
726     enum PixelFormat current_pix_fmt;
727
728     for (i = 0; i < 4; i++) {
729         src_pict.data[i] = src[i];
730         src_pict.linesize[i] = srcStride[i];
731         dst_pict.data[i] = dst[i];
732         dst_pict.linesize[i] = dstStride[i];
733     }
734     if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
735         (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
736         /* We have to rescale the picture, but only YUV420P rescaling is supported... */
737
738         if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
739             int size;
740
741             /* create temporary picture for rescaling input*/
742             size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
743             buf1 = av_malloc(size);
744             if (!buf1) {
745                 res = -1;
746                 goto the_end;
747             }
748             formatted_picture = &picture_format_temp;
749             avpicture_fill((AVPicture*)formatted_picture, buf1,
750                            PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
751
752             if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
753                             &src_pict, ctx->src_pix_fmt,
754                             ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
755
756                 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
757                 res = -1;
758                 goto the_end;
759             }
760         } else {
761             formatted_picture = &src_pict;
762         }
763
764         if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
765             int size;
766
767             /* create temporary picture for rescaling output*/
768             size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
769             buf2 = av_malloc(size);
770             if (!buf2) {
771                 res = -1;
772                 goto the_end;
773             }
774             resampled_picture = &picture_resample_temp;
775             avpicture_fill((AVPicture*)resampled_picture, buf2,
776                            PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
777
778         } else {
779             resampled_picture = &dst_pict;
780         }
781
782         /* ...and finally rescale!!! */
783         img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
784         current_pix_fmt = PIX_FMT_YUV420P;
785     } else {
786         resampled_picture = &src_pict;
787         current_pix_fmt = ctx->src_pix_fmt;
788     }
789
790     if (current_pix_fmt != ctx->dst_pix_fmt) {
791         if (img_convert(&dst_pict, ctx->dst_pix_fmt,
792                         resampled_picture, current_pix_fmt,
793                         ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
794
795             av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
796
797             res = -1;
798             goto the_end;
799         }
800     } else if (resampled_picture != &dst_pict) {
801         av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
802                         ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
803     }
804
805 the_end:
806     av_free(buf1);
807     av_free(buf2);
808     return res;
809 }
810
811
812 #ifdef TEST
813 #include <stdio.h>
814 #undef exit
815
816 /* input */
817 #define XSIZE 256
818 #define YSIZE 256
819 uint8_t img[XSIZE * YSIZE];
820
821 /* output */
822 #define XSIZE1 512
823 #define YSIZE1 512
824 uint8_t img1[XSIZE1 * YSIZE1];
825 uint8_t img2[XSIZE1 * YSIZE1];
826
827 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
828 {
829 #undef fprintf
830     FILE *f;
831     f=fopen(filename,"w");
832     fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
833     fwrite(img,1, xsize * ysize,f);
834     fclose(f);
835 #define fprintf please_use_av_log
836 }
837
838 static void dump_filter(int16_t *filter)
839 {
840     int i, ph;
841
842     for(ph=0;ph<NB_PHASES;ph++) {
843         av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
844         for(i=0;i<NB_TAPS;i++) {
845             av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
846         }
847         av_log(NULL, AV_LOG_INFO, "\n");
848     }
849 }
850
851 #ifdef HAVE_MMX
852 int mm_flags;
853 #endif
854
855 int main(int argc, char **argv)
856 {
857     int x, y, v, i, xsize, ysize;
858     ImgReSampleContext *s;
859     float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
860     char buf[256];
861
862     /* build test image */
863     for(y=0;y<YSIZE;y++) {
864         for(x=0;x<XSIZE;x++) {
865             if (x < XSIZE/2 && y < YSIZE/2) {
866                 if (x < XSIZE/4 && y < YSIZE/4) {
867                     if ((x % 10) <= 6 &&
868                         (y % 10) <= 6)
869                         v = 0xff;
870                     else
871                         v = 0x00;
872                 } else if (x < XSIZE/4) {
873                     if (x & 1)
874                         v = 0xff;
875                     else
876                         v = 0;
877                 } else if (y < XSIZE/4) {
878                     if (y & 1)
879                         v = 0xff;
880                     else
881                         v = 0;
882                 } else {
883                     if (y < YSIZE*3/8) {
884                         if ((y+x) & 1)
885                             v = 0xff;
886                         else
887                             v = 0;
888                     } else {
889                         if (((x+3) % 4) <= 1 &&
890                             ((y+3) % 4) <= 1)
891                             v = 0xff;
892                         else
893                             v = 0x00;
894                     }
895                 }
896             } else if (x < XSIZE/2) {
897                 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
898             } else if (y < XSIZE/2) {
899                 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
900             } else {
901                 v = ((x + y - XSIZE) * 255) / XSIZE;
902             }
903             img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
904         }
905     }
906     save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
907     for(i=0;i<sizeof(factors)/sizeof(float);i++) {
908         fact = factors[i];
909         xsize = (int)(XSIZE * fact);
910         ysize = (int)((YSIZE - 100) * fact);
911         s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
912         av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
913         dump_filter(&s->h_filters[0][0]);
914         component_resample(s, img1, xsize, xsize, ysize,
915                            img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
916         img_resample_close(s);
917
918         snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
919         save_pgm(buf, img1, xsize, ysize);
920     }
921
922     /* mmx test */
923 #ifdef HAVE_MMX
924     av_log(NULL, AV_LOG_INFO, "MMX test\n");
925     fact = 0.72;
926     xsize = (int)(XSIZE * fact);
927     ysize = (int)(YSIZE * fact);
928     mm_flags = MM_MMX;
929     s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
930     component_resample(s, img1, xsize, xsize, ysize,
931                        img, XSIZE, XSIZE, YSIZE);
932
933     mm_flags = 0;
934     s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
935     component_resample(s, img2, xsize, xsize, ysize,
936                        img, XSIZE, XSIZE, YSIZE);
937     if (memcmp(img1, img2, xsize * ysize) != 0) {
938         av_log(NULL, AV_LOG_ERROR, "mmx error\n");
939         exit(1);
940     }
941     av_log(NULL, AV_LOG_INFO, "MMX OK\n");
942 #endif /* HAVE_MMX */
943     return 0;
944 }
945
946 #endif /* TEST */