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;
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;
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)
675 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
676 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
677 img_resample_close(ctx->resampling_ctx);
679 av_free(ctx->resampling_ctx);
686 * Checks if context is valid or reallocs a new one instead.
687 * If context is NULL, just calls sws_getContext() to get a new one.
688 * Otherwise, checks if the parameters are the same already saved in context.
689 * If that is the case, returns the current context.
690 * Otherwise, frees context and gets a new one.
692 * Be warned that srcFilter, dstFilter are not checked, they are
693 * asumed to remain valid.
695 struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
696 int srcW, int srcH, int srcFormat,
697 int dstW, int dstH, int dstFormat, int flags,
698 SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
701 if ((ctx->resampling_ctx->iwidth != srcW) ||
702 (ctx->resampling_ctx->iheight != srcH) ||
703 (ctx->src_pix_fmt != srcFormat) ||
704 (ctx->resampling_ctx->owidth != dstW) ||
705 (ctx->resampling_ctx->oheight != dstH) ||
706 (ctx->dst_pix_fmt != dstFormat))
708 sws_freeContext(ctx);
713 return sws_getContext(srcW, srcH, srcFormat,
714 dstW, dstH, dstFormat, flags,
715 srcFilter, dstFilter, param);
720 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
721 int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
723 AVPicture src_pict, dst_pict;
725 AVPicture picture_format_temp;
726 AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
727 uint8_t *buf1 = NULL, *buf2 = NULL;
728 enum PixelFormat current_pix_fmt;
730 for (i = 0; i < 4; i++) {
731 src_pict.data[i] = src[i];
732 src_pict.linesize[i] = srcStride[i];
733 dst_pict.data[i] = dst[i];
734 dst_pict.linesize[i] = dstStride[i];
736 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
737 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
738 /* We have to rescale the picture, but only YUV420P rescaling is supported... */
740 if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
743 /* create temporary picture for rescaling input*/
744 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
745 buf1 = av_malloc(size);
750 formatted_picture = &picture_format_temp;
751 avpicture_fill((AVPicture*)formatted_picture, buf1,
752 PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
754 if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
755 &src_pict, ctx->src_pix_fmt,
756 ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
758 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
763 formatted_picture = &src_pict;
766 if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
769 /* create temporary picture for rescaling output*/
770 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
771 buf2 = av_malloc(size);
776 resampled_picture = &picture_resample_temp;
777 avpicture_fill((AVPicture*)resampled_picture, buf2,
778 PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
781 resampled_picture = &dst_pict;
784 /* ...and finally rescale!!! */
785 img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
786 current_pix_fmt = PIX_FMT_YUV420P;
788 resampled_picture = &src_pict;
789 current_pix_fmt = ctx->src_pix_fmt;
792 if (current_pix_fmt != ctx->dst_pix_fmt) {
793 if (img_convert(&dst_pict, ctx->dst_pix_fmt,
794 resampled_picture, current_pix_fmt,
795 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
797 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
802 } else if (resampled_picture != &dst_pict) {
803 img_copy(&dst_pict, resampled_picture, current_pix_fmt,
804 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
820 uint8_t img[XSIZE * YSIZE];
825 uint8_t img1[XSIZE1 * YSIZE1];
826 uint8_t img2[XSIZE1 * YSIZE1];
828 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
832 f=fopen(filename,"w");
833 fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
834 fwrite(img,1, xsize * ysize,f);
836 #define fprintf please_use_av_log
839 static void dump_filter(int16_t *filter)
843 for(ph=0;ph<NB_PHASES;ph++) {
844 av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
845 for(i=0;i<NB_TAPS;i++) {
846 av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
848 av_log(NULL, AV_LOG_INFO, "\n");
856 int main(int argc, char **argv)
858 int x, y, v, i, xsize, ysize;
859 ImgReSampleContext *s;
860 float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
863 /* build test image */
864 for(y=0;y<YSIZE;y++) {
865 for(x=0;x<XSIZE;x++) {
866 if (x < XSIZE/2 && y < YSIZE/2) {
867 if (x < XSIZE/4 && y < YSIZE/4) {
873 } else if (x < XSIZE/4) {
878 } else if (y < XSIZE/4) {
890 if (((x+3) % 4) <= 1 &&
897 } else if (x < XSIZE/2) {
898 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
899 } else if (y < XSIZE/2) {
900 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
902 v = ((x + y - XSIZE) * 255) / XSIZE;
904 img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
907 save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
908 for(i=0;i<sizeof(factors)/sizeof(float);i++) {
910 xsize = (int)(XSIZE * fact);
911 ysize = (int)((YSIZE - 100) * fact);
912 s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
913 av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
914 dump_filter(&s->h_filters[0][0]);
915 component_resample(s, img1, xsize, xsize, ysize,
916 img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
917 img_resample_close(s);
919 snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
920 save_pgm(buf, img1, xsize, ysize);
925 av_log(NULL, AV_LOG_INFO, "MMX test\n");
927 xsize = (int)(XSIZE * fact);
928 ysize = (int)(YSIZE * fact);
930 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
931 component_resample(s, img1, xsize, xsize, ysize,
932 img, XSIZE, XSIZE, YSIZE);
935 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
936 component_resample(s, img2, xsize, xsize, ysize,
937 img, XSIZE, XSIZE, YSIZE);
938 if (memcmp(img1, img2, xsize * ysize) != 0) {
939 av_log(NULL, AV_LOG_ERROR, "mmx error\n");
942 av_log(NULL, AV_LOG_INFO, "MMX OK\n");