2 * High quality image resampling with polyphase filters
3 * Copyright (c) 2001 Fabrice Bellard.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * High quality image resampling with polyphase filters .
30 #include "fastmemcpy.h"
33 #define NB_COMPONENTS 3
36 #define NB_PHASES (1 << PHASE_BITS)
38 #define FCENTER 1 /* index of the center of the filter */
39 //#define TEST 1 /* Test it */
41 #define POS_FRAC_BITS 16
42 #define POS_FRAC (1 << POS_FRAC_BITS)
43 /* 6 bits precision is needed for MMX */
46 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
48 struct ImgReSampleContext {
49 int iwidth, iheight, owidth, oheight;
50 int topBand, bottomBand, leftBand, rightBand;
51 int padtop, padbottom, padleft, padright;
52 int pad_owidth, pad_oheight;
54 DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
55 DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
59 void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
61 static inline int get_phase(int pos)
63 return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
66 /* This function must be optimized */
67 static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
68 int src_width, int src_start, int src_incr,
71 int src_pos, phase, sum, i;
76 for(i=0;i<dst_width;i++) {
79 if ((src_pos >> POS_FRAC_BITS) < 0 ||
80 (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
83 s = src + (src_pos >> POS_FRAC_BITS);
84 phase = get_phase(src_pos);
85 filter = filters + phase * NB_TAPS;
87 sum = s[0] * filter[0] +
95 for(j=0;j<NB_TAPS;j++)
96 sum += s[j] * filter[j];
99 sum = sum >> FILTER_BITS;
110 /* This function must be optimized */
111 static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
112 int wrap, int16_t *filter)
118 for(i=0;i<dst_width;i++) {
120 sum = s[0 * wrap] * filter[0] +
121 s[1 * wrap] * filter[1] +
122 s[2 * wrap] * filter[2] +
123 s[3 * wrap] * filter[3];
130 for(j=0;j<NB_TAPS;j++) {
131 sum += s1[0] * filter[j];
136 sum = sum >> FILTER_BITS;
149 #include "i386/mmx.h"
151 #define FILTER4(reg) \
153 s = src + (src_pos >> POS_FRAC_BITS);\
154 phase = get_phase(src_pos);\
155 filter = filters + phase * NB_TAPS;\
157 punpcklbw_r2r(mm7, reg);\
158 movq_m2r(*filter, mm6);\
159 pmaddwd_r2r(reg, mm6);\
162 paddd_r2r(mm6, reg);\
163 psrad_i2r(FILTER_BITS, reg);\
164 src_pos += src_incr;\
167 #define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016Lx\n", tmp.uq);
169 /* XXX: do four pixels at a time */
170 static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
171 const uint8_t *src, int src_width,
172 int src_start, int src_incr, int16_t *filters)
182 while (dst_width >= 4) {
189 packuswb_r2r(mm7, mm0);
190 packuswb_r2r(mm7, mm1);
191 packuswb_r2r(mm7, mm3);
192 packuswb_r2r(mm7, mm2);
204 while (dst_width > 0) {
206 packuswb_r2r(mm7, mm0);
215 static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
216 int wrap, int16_t *filter)
233 while (dst_width >= 4) {
234 movq_m2r(s[0 * wrap], mm0);
235 punpcklbw_r2r(mm7, mm0);
236 movq_m2r(s[1 * wrap], mm1);
237 punpcklbw_r2r(mm7, mm1);
238 movq_m2r(s[2 * wrap], mm2);
239 punpcklbw_r2r(mm7, mm2);
240 movq_m2r(s[3 * wrap], mm3);
241 punpcklbw_r2r(mm7, mm3);
243 pmullw_m2r(coefs[0], mm0);
244 pmullw_m2r(coefs[1], mm1);
245 pmullw_m2r(coefs[2], mm2);
246 pmullw_m2r(coefs[3], mm3);
251 psraw_i2r(FILTER_BITS, mm0);
253 packuswb_r2r(mm7, mm0);
256 *(uint32_t *)dst = tmp.ud[0];
261 while (dst_width > 0) {
262 sum = s[0 * wrap] * filter[0] +
263 s[1 * wrap] * filter[1] +
264 s[2 * wrap] * filter[2] +
265 s[3 * wrap] * filter[3];
266 sum = sum >> FILTER_BITS;
282 vector unsigned char v;
287 vector signed short v;
291 void v_resample16_altivec(uint8_t *dst, int dst_width, const uint8_t *src,
292 int wrap, int16_t *filter)
296 vector unsigned char *tv, tmp, dstv, zero;
297 vec_ss_t srchv[4], srclv[4], fv[4];
298 vector signed short zeros, sumhv, sumlv;
304 The vec_madds later on does an implicit >>15 on the result.
305 Since FILTER_BITS is 8, and we have 15 bits of magnitude in
306 a signed short, we have just enough bits to pre-shift our
307 filter constants <<7 to compensate for vec_madds.
309 fv[i].s[0] = filter[i] << (15-FILTER_BITS);
310 fv[i].v = vec_splat(fv[i].v, 0);
313 zero = vec_splat_u8(0);
314 zeros = vec_splat_s16(0);
318 When we're resampling, we'd ideally like both our input buffers,
319 and output buffers to be 16-byte aligned, so we can do both aligned
320 reads and writes. Sadly we can't always have this at the moment, so
321 we opt for aligned writes, as unaligned writes have a huge overhead.
322 To do this, do enough scalar resamples to get dst 16-byte aligned.
324 i = (-(int)dst) & 0xf;
326 sum = s[0 * wrap] * filter[0] +
327 s[1 * wrap] * filter[1] +
328 s[2 * wrap] * filter[2] +
329 s[3 * wrap] * filter[3];
330 sum = sum >> FILTER_BITS;
331 if (sum<0) sum = 0; else if (sum>255) sum=255;
339 /* Do our altivec resampling on 16 pixels at once. */
340 while(dst_width>=16) {
342 Read 16 (potentially unaligned) bytes from each of
343 4 lines into 4 vectors, and split them into shorts.
344 Interleave the multipy/accumulate for the resample
345 filter with the loads to hide the 3 cycle latency
348 tv = (vector unsigned char *) &s[0 * wrap];
349 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[i * wrap]));
350 srchv[0].v = (vector signed short) vec_mergeh(zero, tmp);
351 srclv[0].v = (vector signed short) vec_mergel(zero, tmp);
352 sumhv = vec_madds(srchv[0].v, fv[0].v, zeros);
353 sumlv = vec_madds(srclv[0].v, fv[0].v, zeros);
355 tv = (vector unsigned char *) &s[1 * wrap];
356 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[1 * wrap]));
357 srchv[1].v = (vector signed short) vec_mergeh(zero, tmp);
358 srclv[1].v = (vector signed short) vec_mergel(zero, tmp);
359 sumhv = vec_madds(srchv[1].v, fv[1].v, sumhv);
360 sumlv = vec_madds(srclv[1].v, fv[1].v, sumlv);
362 tv = (vector unsigned char *) &s[2 * wrap];
363 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[2 * wrap]));
364 srchv[2].v = (vector signed short) vec_mergeh(zero, tmp);
365 srclv[2].v = (vector signed short) vec_mergel(zero, tmp);
366 sumhv = vec_madds(srchv[2].v, fv[2].v, sumhv);
367 sumlv = vec_madds(srclv[2].v, fv[2].v, sumlv);
369 tv = (vector unsigned char *) &s[3 * wrap];
370 tmp = vec_perm(tv[0], tv[1], vec_lvsl(0, &s[3 * wrap]));
371 srchv[3].v = (vector signed short) vec_mergeh(zero, tmp);
372 srclv[3].v = (vector signed short) vec_mergel(zero, tmp);
373 sumhv = vec_madds(srchv[3].v, fv[3].v, sumhv);
374 sumlv = vec_madds(srclv[3].v, fv[3].v, sumlv);
377 Pack the results into our destination vector,
378 and do an aligned write of that back to memory.
380 dstv = vec_packsu(sumhv, sumlv) ;
381 vec_st(dstv, 0, (vector unsigned char *) dst);
389 If there are any leftover pixels, resample them
390 with the slow scalar method.
393 sum = s[0 * wrap] * filter[0] +
394 s[1 * wrap] * filter[1] +
395 s[2 * wrap] * filter[2] +
396 s[3 * wrap] * filter[3];
397 sum = sum >> FILTER_BITS;
398 if (sum<0) sum = 0; else if (sum>255) sum=255;
407 /* slow version to handle limit cases. Does not need optimisation */
408 static void h_resample_slow(uint8_t *dst, int dst_width,
409 const uint8_t *src, int src_width,
410 int src_start, int src_incr, int16_t *filters)
412 int src_pos, phase, sum, j, v, i;
413 const uint8_t *s, *src_end;
416 src_end = src + src_width;
418 for(i=0;i<dst_width;i++) {
419 s = src + (src_pos >> POS_FRAC_BITS);
420 phase = get_phase(src_pos);
421 filter = filters + phase * NB_TAPS;
423 for(j=0;j<NB_TAPS;j++) {
426 else if (s >= src_end)
430 sum += v * filter[j];
433 sum = sum >> FILTER_BITS;
444 static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
445 int src_width, int src_start, int src_incr,
451 n = (0 - src_start + src_incr - 1) / src_incr;
452 h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
455 src_start += n * src_incr;
457 src_end = src_start + dst_width * src_incr;
458 if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
459 n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
465 if ((mm_flags & MM_MMX) && NB_TAPS == 4)
466 h_resample_fast4_mmx(dst, n,
467 src, src_width, src_start, src_incr, filters);
470 h_resample_fast(dst, n,
471 src, src_width, src_start, src_incr, filters);
475 src_start += n * src_incr;
476 h_resample_slow(dst, dst_width,
477 src, src_width, src_start, src_incr, filters);
481 static void component_resample(ImgReSampleContext *s,
482 uint8_t *output, int owrap, int owidth, int oheight,
483 uint8_t *input, int iwrap, int iwidth, int iheight)
485 int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
486 uint8_t *new_line, *src_line;
488 last_src_y = - FCENTER - 1;
489 /* position of the bottom of the filter in the source image */
490 src_y = (last_src_y + NB_TAPS) * POS_FRAC;
491 ring_y = NB_TAPS; /* position in ring buffer */
492 for(y=0;y<oheight;y++) {
493 /* apply horizontal filter on new lines from input if needed */
494 src_y1 = src_y >> POS_FRAC_BITS;
495 while (last_src_y < src_y1) {
496 if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
499 /* handle limit conditions : replicate line (slightly
500 inefficient because we filter multiple times) */
504 } else if (y1 >= iheight) {
507 src_line = input + y1 * iwrap;
508 new_line = s->line_buf + ring_y * owidth;
509 /* apply filter and handle limit cases correctly */
510 h_resample(new_line, owidth,
511 src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
512 &s->h_filters[0][0]);
513 /* handle ring buffer wraping */
514 if (ring_y >= LINE_BUF_HEIGHT) {
515 memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
519 /* apply vertical filter */
520 phase_y = get_phase(src_y);
522 /* desactivated MMX because loss of precision */
523 if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
524 v_resample4_mmx(output, owidth,
525 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
526 &s->v_filters[phase_y][0]);
530 if ((mm_flags & MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
531 v_resample16_altivec(output, owidth,
532 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
533 &s->v_filters[phase_y][0]);
536 v_resample(output, owidth,
537 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
538 &s->v_filters[phase_y][0]);
546 ImgReSampleContext *img_resample_init(int owidth, int oheight,
547 int iwidth, int iheight)
549 return img_resample_full_init(owidth, oheight, iwidth, iheight,
550 0, 0, 0, 0, 0, 0, 0, 0);
553 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
554 int iwidth, int iheight,
555 int topBand, int bottomBand,
556 int leftBand, int rightBand,
557 int padtop, int padbottom,
558 int padleft, int padright)
560 ImgReSampleContext *s;
562 if (!owidth || !oheight || !iwidth || !iheight)
565 s = av_mallocz(sizeof(ImgReSampleContext));
568 if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
570 s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
575 s->oheight = oheight;
577 s->iheight = iheight;
579 s->topBand = topBand;
580 s->bottomBand = bottomBand;
581 s->leftBand = leftBand;
582 s->rightBand = rightBand;
585 s->padbottom = padbottom;
586 s->padleft = padleft;
587 s->padright = padright;
589 s->pad_owidth = owidth - (padleft + padright);
590 s->pad_oheight = oheight - (padtop + padbottom);
592 s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
593 s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
595 av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth /
596 (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
597 av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
598 (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
606 void img_resample(ImgReSampleContext *s,
607 AVPicture *output, const AVPicture *input)
613 shift = (i == 0) ? 0 : 1;
615 optr = output->data[i] + (((output->linesize[i] *
616 s->padtop) + s->padleft) >> shift);
618 component_resample(s, optr, output->linesize[i],
619 s->pad_owidth >> shift, s->pad_oheight >> shift,
620 input->data[i] + (input->linesize[i] *
621 (s->topBand >> shift)) + (s->leftBand >> shift),
622 input->linesize[i], ((s->iwidth - s->leftBand -
623 s->rightBand) >> shift),
624 (s->iheight - s->topBand - s->bottomBand) >> shift);
628 void img_resample_close(ImgReSampleContext *s)
630 av_free(s->line_buf);
634 struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
635 int dstW, int dstH, int dstFormat,
636 int flags, SwsFilter *srcFilter,
637 SwsFilter *dstFilter, double *param)
639 struct SwsContext *ctx;
641 ctx = av_malloc(sizeof(struct SwsContext));
643 av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
648 if ((srcH != dstH) || (srcW != dstW)) {
649 if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
650 av_log(NULL, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
652 ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
654 ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
655 ctx->resampling_ctx->iheight = srcH;
656 ctx->resampling_ctx->iwidth = srcW;
657 ctx->resampling_ctx->oheight = dstH;
658 ctx->resampling_ctx->owidth = dstW;
660 ctx->src_pix_fmt = srcFormat;
661 ctx->dst_pix_fmt = dstFormat;
666 void sws_freeContext(struct SwsContext *ctx)
668 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
669 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
670 img_resample_close(ctx->resampling_ctx);
672 av_free(ctx->resampling_ctx);
677 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
678 int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
680 AVPicture src_pict, dst_pict;
682 AVPicture picture_format_temp;
683 AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
684 uint8_t *buf1 = NULL, *buf2 = NULL;
685 enum PixelFormat current_pix_fmt;
687 for (i = 0; i < 3; i++) {
688 src_pict.data[i] = src[i];
689 src_pict.linesize[i] = srcStride[i];
690 dst_pict.data[i] = dst[i];
691 dst_pict.linesize[i] = dstStride[i];
693 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
694 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
695 /* We have to rescale the picture, but only YUV420P rescaling is supported... */
697 if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
700 /* create temporary picture for rescaling input*/
701 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
702 buf1 = av_malloc(size);
707 formatted_picture = &picture_format_temp;
708 avpicture_fill((AVPicture*)formatted_picture, buf1,
709 PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
711 if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
712 &src_pict, ctx->src_pix_fmt,
713 ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
715 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
720 formatted_picture = &src_pict;
723 if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
726 /* create temporary picture for rescaling output*/
727 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
728 buf2 = av_malloc(size);
733 resampled_picture = &picture_resample_temp;
734 avpicture_fill((AVPicture*)resampled_picture, buf2,
735 PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
738 resampled_picture = &dst_pict;
741 /* ...and finally rescale!!! */
742 img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
743 current_pix_fmt = PIX_FMT_YUV420P;
745 resampled_picture = &src_pict;
746 current_pix_fmt = ctx->src_pix_fmt;
749 if (current_pix_fmt != ctx->dst_pix_fmt) {
750 if (img_convert(&dst_pict, ctx->dst_pix_fmt,
751 resampled_picture, current_pix_fmt,
752 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
754 av_log(NULL, AV_LOG_ERROR, "pixel format conversion not handled\n");
774 uint8_t img[XSIZE * YSIZE];
779 uint8_t img1[XSIZE1 * YSIZE1];
780 uint8_t img2[XSIZE1 * YSIZE1];
782 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
786 f=fopen(filename,"w");
787 fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
788 fwrite(img,1, xsize * ysize,f);
790 #define fprintf please_use_av_log
793 static void dump_filter(int16_t *filter)
797 for(ph=0;ph<NB_PHASES;ph++) {
798 av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
799 for(i=0;i<NB_TAPS;i++) {
800 av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
802 av_log(NULL, AV_LOG_INFO, "\n");
810 int main(int argc, char **argv)
812 int x, y, v, i, xsize, ysize;
813 ImgReSampleContext *s;
814 float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
817 /* build test image */
818 for(y=0;y<YSIZE;y++) {
819 for(x=0;x<XSIZE;x++) {
820 if (x < XSIZE/2 && y < YSIZE/2) {
821 if (x < XSIZE/4 && y < YSIZE/4) {
827 } else if (x < XSIZE/4) {
832 } else if (y < XSIZE/4) {
844 if (((x+3) % 4) <= 1 &&
851 } else if (x < XSIZE/2) {
852 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
853 } else if (y < XSIZE/2) {
854 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
856 v = ((x + y - XSIZE) * 255) / XSIZE;
858 img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
861 save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
862 for(i=0;i<sizeof(factors)/sizeof(float);i++) {
864 xsize = (int)(XSIZE * fact);
865 ysize = (int)((YSIZE - 100) * fact);
866 s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
867 av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
868 dump_filter(&s->h_filters[0][0]);
869 component_resample(s, img1, xsize, xsize, ysize,
870 img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
871 img_resample_close(s);
873 snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
874 save_pgm(buf, img1, xsize, ysize);
879 av_log(NULL, AV_LOG_INFO, "MMX test\n");
881 xsize = (int)(XSIZE * fact);
882 ysize = (int)(YSIZE * fact);
884 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
885 component_resample(s, img1, xsize, xsize, ysize,
886 img, XSIZE, XSIZE, YSIZE);
889 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
890 component_resample(s, img2, xsize, xsize, ysize,
891 img, XSIZE, XSIZE, YSIZE);
892 if (memcmp(img1, img2, xsize * ysize) != 0) {
893 av_log(NULL, AV_LOG_ERROR, "mmx error\n");
896 av_log(NULL, AV_LOG_INFO, "MMX OK\n");