2 * High quality image resampling with polyphase filters
3 * Copyright (c) 2001 Fabrice Bellard.
5 * This file is part of FFmpeg.
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.
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.
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
24 * High quality image resampling with polyphase filters .
32 #include "libvo/fastmemcpy.h"
35 #define NB_COMPONENTS 3
38 #define NB_PHASES (1 << PHASE_BITS)
40 #define FCENTER 1 /* index of the center of the filter */
41 //#define TEST 1 /* Test it */
43 #define POS_FRAC_BITS 16
44 #define POS_FRAC (1 << POS_FRAC_BITS)
45 /* 6 bits precision is needed for MMX */
48 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
51 struct ImgReSampleContext *resampling_ctx;
52 enum PixelFormat src_pix_fmt, dst_pix_fmt;
55 struct ImgReSampleContext {
56 int iwidth, iheight, owidth, oheight;
57 int topBand, bottomBand, leftBand, rightBand;
58 int padtop, padbottom, padleft, padright;
59 int pad_owidth, pad_oheight;
61 DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
62 DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
66 void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
68 static inline int get_phase(int pos)
70 return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
73 /* This function must be optimized */
74 static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
75 int src_width, int src_start, int src_incr,
78 int src_pos, phase, sum, i;
83 for(i=0;i<dst_width;i++) {
86 if ((src_pos >> POS_FRAC_BITS) < 0 ||
87 (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
90 s = src + (src_pos >> POS_FRAC_BITS);
91 phase = get_phase(src_pos);
92 filter = filters + phase * NB_TAPS;
94 sum = s[0] * filter[0] +
102 for(j=0;j<NB_TAPS;j++)
103 sum += s[j] * filter[j];
106 sum = sum >> FILTER_BITS;
117 /* This function must be optimized */
118 static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
119 int wrap, int16_t *filter)
125 for(i=0;i<dst_width;i++) {
127 sum = s[0 * wrap] * filter[0] +
128 s[1 * wrap] * filter[1] +
129 s[2 * wrap] * filter[2] +
130 s[3 * wrap] * filter[3];
137 for(j=0;j<NB_TAPS;j++) {
138 sum += s1[0] * filter[j];
143 sum = sum >> FILTER_BITS;
156 #include "i386/mmx.h"
158 #define FILTER4(reg) \
160 s = src + (src_pos >> POS_FRAC_BITS);\
161 phase = get_phase(src_pos);\
162 filter = filters + phase * NB_TAPS;\
164 punpcklbw_r2r(mm7, reg);\
165 movq_m2r(*filter, mm6);\
166 pmaddwd_r2r(reg, mm6);\
169 paddd_r2r(mm6, reg);\
170 psrad_i2r(FILTER_BITS, reg);\
171 src_pos += src_incr;\
174 #define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
176 /* XXX: do four pixels at a time */
177 static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
178 const uint8_t *src, int src_width,
179 int src_start, int src_incr, int16_t *filters)
189 while (dst_width >= 4) {
196 packuswb_r2r(mm7, mm0);
197 packuswb_r2r(mm7, mm1);
198 packuswb_r2r(mm7, mm3);
199 packuswb_r2r(mm7, mm2);
211 while (dst_width > 0) {
213 packuswb_r2r(mm7, mm0);
222 static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
223 int wrap, int16_t *filter)
240 while (dst_width >= 4) {
241 movq_m2r(s[0 * wrap], mm0);
242 punpcklbw_r2r(mm7, mm0);
243 movq_m2r(s[1 * wrap], mm1);
244 punpcklbw_r2r(mm7, mm1);
245 movq_m2r(s[2 * wrap], mm2);
246 punpcklbw_r2r(mm7, mm2);
247 movq_m2r(s[3 * wrap], mm3);
248 punpcklbw_r2r(mm7, mm3);
250 pmullw_m2r(coefs[0], mm0);
251 pmullw_m2r(coefs[1], mm1);
252 pmullw_m2r(coefs[2], mm2);
253 pmullw_m2r(coefs[3], mm3);
258 psraw_i2r(FILTER_BITS, mm0);
260 packuswb_r2r(mm7, mm0);
263 *(uint32_t *)dst = tmp.ud[0];
268 while (dst_width > 0) {
269 sum = s[0 * wrap] * filter[0] +
270 s[1 * wrap] * filter[1] +
271 s[2 * wrap] * filter[2] +
272 s[3 * wrap] * filter[3];
273 sum = sum >> FILTER_BITS;
285 #endif /* HAVE_MMX */
289 vector unsigned char v;
294 vector signed short v;
298 void v_resample16_altivec(uint8_t *dst, int dst_width, const uint8_t *src,
299 int wrap, int16_t *filter)
303 vector unsigned char *tv, tmp, dstv, zero;
304 vec_ss_t srchv[4], srclv[4], fv[4];
305 vector signed short zeros, sumhv, sumlv;
311 The vec_madds later on does an implicit >>15 on the result.
312 Since FILTER_BITS is 8, and we have 15 bits of magnitude in
313 a signed short, we have just enough bits to pre-shift our
314 filter constants <<7 to compensate for vec_madds.
316 fv[i].s[0] = filter[i] << (15-FILTER_BITS);
317 fv[i].v = vec_splat(fv[i].v, 0);
320 zero = vec_splat_u8(0);
321 zeros = vec_splat_s16(0);
325 When we're resampling, we'd ideally like both our input buffers,
326 and output buffers to be 16-byte aligned, so we can do both aligned
327 reads and writes. Sadly we can't always have this at the moment, so
328 we opt for aligned writes, as unaligned writes have a huge overhead.
329 To do this, do enough scalar resamples to get dst 16-byte aligned.
331 i = (-(int)dst) & 0xf;
333 sum = s[0 * wrap] * filter[0] +
334 s[1 * wrap] * filter[1] +
335 s[2 * wrap] * filter[2] +
336 s[3 * wrap] * filter[3];
337 sum = sum >> FILTER_BITS;
338 if (sum<0) sum = 0; else if (sum>255) sum=255;
346 /* Do our altivec resampling on 16 pixels at once. */
347 while(dst_width>=16) {
349 Read 16 (potentially unaligned) bytes from each of
350 4 lines into 4 vectors, and split them into shorts.
351 Interleave the multipy/accumulate for the resample
352 filter with the loads to hide the 3 cycle latency
355 tv = (vector unsigned char *) &s[0 * wrap];
356 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[i * wrap]));
357 srchv[0].v = (vector signed short) vec_mergeh(zero, tmp);
358 srclv[0].v = (vector signed short) vec_mergel(zero, tmp);
359 sumhv = vec_madds(srchv[0].v, fv[0].v, zeros);
360 sumlv = vec_madds(srclv[0].v, fv[0].v, zeros);
362 tv = (vector unsigned char *) &s[1 * wrap];
363 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[1 * wrap]));
364 srchv[1].v = (vector signed short) vec_mergeh(zero, tmp);
365 srclv[1].v = (vector signed short) vec_mergel(zero, tmp);
366 sumhv = vec_madds(srchv[1].v, fv[1].v, sumhv);
367 sumlv = vec_madds(srclv[1].v, fv[1].v, sumlv);
369 tv = (vector unsigned char *) &s[2 * wrap];
370 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[2 * wrap]));
371 srchv[2].v = (vector signed short) vec_mergeh(zero, tmp);
372 srclv[2].v = (vector signed short) vec_mergel(zero, tmp);
373 sumhv = vec_madds(srchv[2].v, fv[2].v, sumhv);
374 sumlv = vec_madds(srclv[2].v, fv[2].v, sumlv);
376 tv = (vector unsigned char *) &s[3 * wrap];
377 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[3 * wrap]));
378 srchv[3].v = (vector signed short) vec_mergeh(zero, tmp);
379 srclv[3].v = (vector signed short) vec_mergel(zero, tmp);
380 sumhv = vec_madds(srchv[3].v, fv[3].v, sumhv);
381 sumlv = vec_madds(srclv[3].v, fv[3].v, sumlv);
384 Pack the results into our destination vector,
385 and do an aligned write of that back to memory.
387 dstv = vec_packsu(sumhv, sumlv) ;
388 vec_st(dstv, 0, (vector unsigned char *) dst);
396 If there are any leftover pixels, resample them
397 with the slow scalar method.
400 sum = s[0 * wrap] * filter[0] +
401 s[1 * wrap] * filter[1] +
402 s[2 * wrap] * filter[2] +
403 s[3 * wrap] * filter[3];
404 sum = sum >> FILTER_BITS;
405 if (sum<0) sum = 0; else if (sum>255) sum=255;
412 #endif /* HAVE_ALTIVEC */
414 /* slow version to handle limit cases. Does not need optimisation */
415 static void h_resample_slow(uint8_t *dst, int dst_width,
416 const uint8_t *src, int src_width,
417 int src_start, int src_incr, int16_t *filters)
419 int src_pos, phase, sum, j, v, i;
420 const uint8_t *s, *src_end;
423 src_end = src + src_width;
425 for(i=0;i<dst_width;i++) {
426 s = src + (src_pos >> POS_FRAC_BITS);
427 phase = get_phase(src_pos);
428 filter = filters + phase * NB_TAPS;
430 for(j=0;j<NB_TAPS;j++) {
433 else if (s >= src_end)
437 sum += v * filter[j];
440 sum = sum >> FILTER_BITS;
451 static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
452 int src_width, int src_start, int src_incr,
458 n = (0 - src_start + src_incr - 1) / src_incr;
459 h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
462 src_start += n * src_incr;
464 src_end = src_start + dst_width * src_incr;
465 if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
466 n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
472 if ((mm_flags & MM_MMX) && NB_TAPS == 4)
473 h_resample_fast4_mmx(dst, n,
474 src, src_width, src_start, src_incr, filters);
477 h_resample_fast(dst, n,
478 src, src_width, src_start, src_incr, filters);
482 src_start += n * src_incr;
483 h_resample_slow(dst, dst_width,
484 src, src_width, src_start, src_incr, filters);
488 static void component_resample(ImgReSampleContext *s,
489 uint8_t *output, int owrap, int owidth, int oheight,
490 uint8_t *input, int iwrap, int iwidth, int iheight)
492 int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
493 uint8_t *new_line, *src_line;
495 last_src_y = - FCENTER - 1;
496 /* position of the bottom of the filter in the source image */
497 src_y = (last_src_y + NB_TAPS) * POS_FRAC;
498 ring_y = NB_TAPS; /* position in ring buffer */
499 for(y=0;y<oheight;y++) {
500 /* apply horizontal filter on new lines from input if needed */
501 src_y1 = src_y >> POS_FRAC_BITS;
502 while (last_src_y < src_y1) {
503 if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
506 /* handle limit conditions : replicate line (slightly
507 inefficient because we filter multiple times) */
511 } else if (y1 >= iheight) {
514 src_line = input + y1 * iwrap;
515 new_line = s->line_buf + ring_y * owidth;
516 /* apply filter and handle limit cases correctly */
517 h_resample(new_line, owidth,
518 src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
519 &s->h_filters[0][0]);
520 /* handle ring buffer wraping */
521 if (ring_y >= LINE_BUF_HEIGHT) {
522 memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
526 /* apply vertical filter */
527 phase_y = get_phase(src_y);
529 /* desactivated MMX because loss of precision */
530 if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
531 v_resample4_mmx(output, owidth,
532 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
533 &s->v_filters[phase_y][0]);
537 if ((mm_flags & MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
538 v_resample16_altivec(output, owidth,
539 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
540 &s->v_filters[phase_y][0]);
543 v_resample(output, owidth,
544 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
545 &s->v_filters[phase_y][0]);
553 ImgReSampleContext *img_resample_init(int owidth, int oheight,
554 int iwidth, int iheight)
556 return img_resample_full_init(owidth, oheight, iwidth, iheight,
557 0, 0, 0, 0, 0, 0, 0, 0);
560 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
561 int iwidth, int iheight,
562 int topBand, int bottomBand,
563 int leftBand, int rightBand,
564 int padtop, int padbottom,
565 int padleft, int padright)
567 ImgReSampleContext *s;
569 if (!owidth || !oheight || !iwidth || !iheight)
572 s = av_mallocz(sizeof(ImgReSampleContext));
575 if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
577 s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
582 s->oheight = oheight;
584 s->iheight = iheight;
586 s->topBand = topBand;
587 s->bottomBand = bottomBand;
588 s->leftBand = leftBand;
589 s->rightBand = rightBand;
592 s->padbottom = padbottom;
593 s->padleft = padleft;
594 s->padright = padright;
596 s->pad_owidth = owidth - (padleft + padright);
597 s->pad_oheight = oheight - (padtop + padbottom);
599 s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
600 s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
602 av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth /
603 (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
604 av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
605 (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
613 void img_resample(ImgReSampleContext *s,
614 AVPicture *output, const AVPicture *input)
620 shift = (i == 0) ? 0 : 1;
622 optr = output->data[i] + (((output->linesize[i] *
623 s->padtop) + s->padleft) >> shift);
625 component_resample(s, optr, output->linesize[i],
626 s->pad_owidth >> shift, s->pad_oheight >> shift,
627 input->data[i] + (input->linesize[i] *
628 (s->topBand >> shift)) + (s->leftBand >> shift),
629 input->linesize[i], ((s->iwidth - s->leftBand -
630 s->rightBand) >> shift),
631 (s->iheight - s->topBand - s->bottomBand) >> shift);
635 void img_resample_close(ImgReSampleContext *s)
637 av_free(s->line_buf);
641 struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
642 int dstW, int dstH, int dstFormat,
643 int flags, SwsFilter *srcFilter,
644 SwsFilter *dstFilter, double *param)
646 struct SwsContext *ctx;
648 ctx = av_malloc(sizeof(struct SwsContext));
650 av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
655 if ((srcH != dstH) || (srcW != dstW)) {
656 if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
657 av_log(NULL, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
659 ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
661 ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
662 ctx->resampling_ctx->iheight = srcH;
663 ctx->resampling_ctx->iwidth = srcW;
664 ctx->resampling_ctx->oheight = dstH;
665 ctx->resampling_ctx->owidth = dstW;
667 ctx->src_pix_fmt = srcFormat;
668 ctx->dst_pix_fmt = dstFormat;
673 void sws_freeContext(struct SwsContext *ctx)
677 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
678 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
679 img_resample_close(ctx->resampling_ctx);
681 av_free(ctx->resampling_ctx);
688 * Checks if context is valid or reallocs a new one instead.
689 * If context is NULL, just calls sws_getContext() to get a new one.
690 * Otherwise, checks if the parameters are the same already saved in context.
691 * If that is the case, returns the current context.
692 * Otherwise, frees context and gets a new one.
694 * Be warned that srcFilter, dstFilter are not checked, they are
695 * asumed to remain valid.
697 struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
698 int srcW, int srcH, int srcFormat,
699 int dstW, int dstH, int dstFormat, int flags,
700 SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
703 if ((ctx->resampling_ctx->iwidth != srcW) ||
704 (ctx->resampling_ctx->iheight != srcH) ||
705 (ctx->src_pix_fmt != srcFormat) ||
706 (ctx->resampling_ctx->owidth != dstW) ||
707 (ctx->resampling_ctx->oheight != dstH) ||
708 (ctx->dst_pix_fmt != dstFormat))
710 sws_freeContext(ctx);
715 return sws_getContext(srcW, srcH, srcFormat,
716 dstW, dstH, dstFormat, flags,
717 srcFilter, dstFilter, param);
722 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
723 int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
725 AVPicture src_pict, dst_pict;
727 AVPicture picture_format_temp;
728 AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
729 uint8_t *buf1 = NULL, *buf2 = NULL;
730 enum PixelFormat current_pix_fmt;
732 for (i = 0; i < 4; i++) {
733 src_pict.data[i] = src[i];
734 src_pict.linesize[i] = srcStride[i];
735 dst_pict.data[i] = dst[i];
736 dst_pict.linesize[i] = dstStride[i];
738 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
739 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
740 /* We have to rescale the picture, but only YUV420P rescaling is supported... */
742 if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
745 /* create temporary picture for rescaling input*/
746 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
747 buf1 = av_malloc(size);
752 formatted_picture = &picture_format_temp;
753 avpicture_fill((AVPicture*)formatted_picture, buf1,
754 PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
756 if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
757 &src_pict, ctx->src_pix_fmt,
758 ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
760 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
765 formatted_picture = &src_pict;
768 if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
771 /* create temporary picture for rescaling output*/
772 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
773 buf2 = av_malloc(size);
778 resampled_picture = &picture_resample_temp;
779 avpicture_fill((AVPicture*)resampled_picture, buf2,
780 PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
783 resampled_picture = &dst_pict;
786 /* ...and finally rescale!!! */
787 img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
788 current_pix_fmt = PIX_FMT_YUV420P;
790 resampled_picture = &src_pict;
791 current_pix_fmt = ctx->src_pix_fmt;
794 if (current_pix_fmt != ctx->dst_pix_fmt) {
795 if (img_convert(&dst_pict, ctx->dst_pix_fmt,
796 resampled_picture, current_pix_fmt,
797 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
799 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
804 } else if (resampled_picture != &dst_pict) {
805 av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
806 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
823 uint8_t img[XSIZE * YSIZE];
828 uint8_t img1[XSIZE1 * YSIZE1];
829 uint8_t img2[XSIZE1 * YSIZE1];
831 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
835 f=fopen(filename,"w");
836 fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
837 fwrite(img,1, xsize * ysize,f);
839 #define fprintf please_use_av_log
842 static void dump_filter(int16_t *filter)
846 for(ph=0;ph<NB_PHASES;ph++) {
847 av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
848 for(i=0;i<NB_TAPS;i++) {
849 av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
851 av_log(NULL, AV_LOG_INFO, "\n");
859 int main(int argc, char **argv)
861 int x, y, v, i, xsize, ysize;
862 ImgReSampleContext *s;
863 float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
866 /* build test image */
867 for(y=0;y<YSIZE;y++) {
868 for(x=0;x<XSIZE;x++) {
869 if (x < XSIZE/2 && y < YSIZE/2) {
870 if (x < XSIZE/4 && y < YSIZE/4) {
876 } else if (x < XSIZE/4) {
881 } else if (y < XSIZE/4) {
893 if (((x+3) % 4) <= 1 &&
900 } else if (x < XSIZE/2) {
901 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
902 } else if (y < XSIZE/2) {
903 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
905 v = ((x + y - XSIZE) * 255) / XSIZE;
907 img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
910 save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
911 for(i=0;i<sizeof(factors)/sizeof(float);i++) {
913 xsize = (int)(XSIZE * fact);
914 ysize = (int)((YSIZE - 100) * fact);
915 s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
916 av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
917 dump_filter(&s->h_filters[0][0]);
918 component_resample(s, img1, xsize, xsize, ysize,
919 img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
920 img_resample_close(s);
922 snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
923 save_pgm(buf, img1, xsize, ysize);
928 av_log(NULL, AV_LOG_INFO, "MMX test\n");
930 xsize = (int)(XSIZE * fact);
931 ysize = (int)(YSIZE * fact);
933 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
934 component_resample(s, img1, xsize, xsize, ysize,
935 img, XSIZE, XSIZE, YSIZE);
938 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
939 component_resample(s, img2, xsize, xsize, ysize,
940 img, XSIZE, XSIZE, YSIZE);
941 if (memcmp(img1, img2, xsize * ysize) != 0) {
942 av_log(NULL, AV_LOG_ERROR, "mmx error\n");
945 av_log(NULL, AV_LOG_INFO, "MMX OK\n");
946 #endif /* HAVE_MMX */