Rename rtp_payload_data_t to avoid clashes with the POSIX namespace
[ffmpeg-lucabe.git] / libavcodec / imgresample.c
blob34c68899f09b4794911609b56aa6b935c3fd5473
1 /*
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
22 /**
23 * @file imgresample.c
24 * High quality image resampling with polyphase filters .
27 #include "avcodec.h"
28 #include "dsputil.h"
29 #include "imgconvert.h"
30 #include "libswscale/swscale.h"
32 #ifdef HAVE_ALTIVEC
33 #include "ppc/imgresample_altivec.h"
34 #endif
36 #define NB_COMPONENTS 3
38 #define PHASE_BITS 4
39 #define NB_PHASES (1 << PHASE_BITS)
40 #define NB_TAPS 4
41 #define FCENTER 1 /* index of the center of the filter */
42 //#define TEST 1 /* Test it */
44 #define POS_FRAC_BITS 16
45 #define POS_FRAC (1 << POS_FRAC_BITS)
46 /* 6 bits precision is needed for MMX */
47 #define FILTER_BITS 8
49 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
51 struct SwsContext {
52 const AVClass *av_class;
53 struct ImgReSampleContext *resampling_ctx;
54 enum PixelFormat src_pix_fmt, dst_pix_fmt;
57 typedef struct ImgReSampleContext {
58 int iwidth, iheight, owidth, oheight;
59 int topBand, bottomBand, leftBand, rightBand;
60 int padtop, padbottom, padleft, padright;
61 int pad_owidth, pad_oheight;
62 int h_incr, v_incr;
63 DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
64 DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
65 uint8_t *line_buf;
66 } ImgReSampleContext;
68 void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
70 static inline int get_phase(int pos)
72 return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
75 /* This function must be optimized */
76 static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
77 int src_width, int src_start, int src_incr,
78 int16_t *filters)
80 int src_pos, phase, sum, i;
81 const uint8_t *s;
82 int16_t *filter;
84 src_pos = src_start;
85 for(i=0;i<dst_width;i++) {
86 #ifdef TEST
87 /* test */
88 if ((src_pos >> POS_FRAC_BITS) < 0 ||
89 (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
90 av_abort();
91 #endif
92 s = src + (src_pos >> POS_FRAC_BITS);
93 phase = get_phase(src_pos);
94 filter = filters + phase * NB_TAPS;
95 #if NB_TAPS == 4
96 sum = s[0] * filter[0] +
97 s[1] * filter[1] +
98 s[2] * filter[2] +
99 s[3] * filter[3];
100 #else
102 int j;
103 sum = 0;
104 for(j=0;j<NB_TAPS;j++)
105 sum += s[j] * filter[j];
107 #endif
108 sum = sum >> FILTER_BITS;
109 if (sum < 0)
110 sum = 0;
111 else if (sum > 255)
112 sum = 255;
113 dst[0] = sum;
114 src_pos += src_incr;
115 dst++;
119 /* This function must be optimized */
120 static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
121 int wrap, int16_t *filter)
123 int sum, i;
124 const uint8_t *s;
126 s = src;
127 for(i=0;i<dst_width;i++) {
128 #if NB_TAPS == 4
129 sum = s[0 * wrap] * filter[0] +
130 s[1 * wrap] * filter[1] +
131 s[2 * wrap] * filter[2] +
132 s[3 * wrap] * filter[3];
133 #else
135 int j;
136 uint8_t *s1 = s;
138 sum = 0;
139 for(j=0;j<NB_TAPS;j++) {
140 sum += s1[0] * filter[j];
141 s1 += wrap;
144 #endif
145 sum = sum >> FILTER_BITS;
146 if (sum < 0)
147 sum = 0;
148 else if (sum > 255)
149 sum = 255;
150 dst[0] = sum;
151 dst++;
152 s++;
156 #ifdef HAVE_MMX
158 #include "i386/mmx.h"
160 #define FILTER4(reg) \
162 s = src + (src_pos >> POS_FRAC_BITS);\
163 phase = get_phase(src_pos);\
164 filter = filters + phase * NB_TAPS;\
165 movq_m2r(*s, reg);\
166 punpcklbw_r2r(mm7, reg);\
167 movq_m2r(*filter, mm6);\
168 pmaddwd_r2r(reg, mm6);\
169 movq_r2r(mm6, reg);\
170 psrlq_i2r(32, reg);\
171 paddd_r2r(mm6, reg);\
172 psrad_i2r(FILTER_BITS, reg);\
173 src_pos += src_incr;\
176 #define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
178 /* XXX: do four pixels at a time */
179 static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
180 const uint8_t *src, int src_width,
181 int src_start, int src_incr, int16_t *filters)
183 int src_pos, phase;
184 const uint8_t *s;
185 int16_t *filter;
186 mmx_t tmp;
188 src_pos = src_start;
189 pxor_r2r(mm7, mm7);
191 while (dst_width >= 4) {
193 FILTER4(mm0);
194 FILTER4(mm1);
195 FILTER4(mm2);
196 FILTER4(mm3);
198 packuswb_r2r(mm7, mm0);
199 packuswb_r2r(mm7, mm1);
200 packuswb_r2r(mm7, mm3);
201 packuswb_r2r(mm7, mm2);
202 movq_r2m(mm0, tmp);
203 dst[0] = tmp.ub[0];
204 movq_r2m(mm1, tmp);
205 dst[1] = tmp.ub[0];
206 movq_r2m(mm2, tmp);
207 dst[2] = tmp.ub[0];
208 movq_r2m(mm3, tmp);
209 dst[3] = tmp.ub[0];
210 dst += 4;
211 dst_width -= 4;
213 while (dst_width > 0) {
214 FILTER4(mm0);
215 packuswb_r2r(mm7, mm0);
216 movq_r2m(mm0, tmp);
217 dst[0] = tmp.ub[0];
218 dst++;
219 dst_width--;
221 emms();
224 static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
225 int wrap, int16_t *filter)
227 int sum, i, v;
228 const uint8_t *s;
229 mmx_t tmp;
230 mmx_t coefs[4];
232 for(i=0;i<4;i++) {
233 v = filter[i];
234 coefs[i].uw[0] = v;
235 coefs[i].uw[1] = v;
236 coefs[i].uw[2] = v;
237 coefs[i].uw[3] = v;
240 pxor_r2r(mm7, mm7);
241 s = src;
242 while (dst_width >= 4) {
243 movq_m2r(s[0 * wrap], mm0);
244 punpcklbw_r2r(mm7, mm0);
245 movq_m2r(s[1 * wrap], mm1);
246 punpcklbw_r2r(mm7, mm1);
247 movq_m2r(s[2 * wrap], mm2);
248 punpcklbw_r2r(mm7, mm2);
249 movq_m2r(s[3 * wrap], mm3);
250 punpcklbw_r2r(mm7, mm3);
252 pmullw_m2r(coefs[0], mm0);
253 pmullw_m2r(coefs[1], mm1);
254 pmullw_m2r(coefs[2], mm2);
255 pmullw_m2r(coefs[3], mm3);
257 paddw_r2r(mm1, mm0);
258 paddw_r2r(mm3, mm2);
259 paddw_r2r(mm2, mm0);
260 psraw_i2r(FILTER_BITS, mm0);
262 packuswb_r2r(mm7, mm0);
263 movq_r2m(mm0, tmp);
265 *(uint32_t *)dst = tmp.ud[0];
266 dst += 4;
267 s += 4;
268 dst_width -= 4;
270 while (dst_width > 0) {
271 sum = s[0 * wrap] * filter[0] +
272 s[1 * wrap] * filter[1] +
273 s[2 * wrap] * filter[2] +
274 s[3 * wrap] * filter[3];
275 sum = sum >> FILTER_BITS;
276 if (sum < 0)
277 sum = 0;
278 else if (sum > 255)
279 sum = 255;
280 dst[0] = sum;
281 dst++;
282 s++;
283 dst_width--;
285 emms();
287 #endif /* HAVE_MMX */
289 /* slow version to handle limit cases. Does not need optimization */
290 static void h_resample_slow(uint8_t *dst, int dst_width,
291 const uint8_t *src, int src_width,
292 int src_start, int src_incr, int16_t *filters)
294 int src_pos, phase, sum, j, v, i;
295 const uint8_t *s, *src_end;
296 int16_t *filter;
298 src_end = src + src_width;
299 src_pos = src_start;
300 for(i=0;i<dst_width;i++) {
301 s = src + (src_pos >> POS_FRAC_BITS);
302 phase = get_phase(src_pos);
303 filter = filters + phase * NB_TAPS;
304 sum = 0;
305 for(j=0;j<NB_TAPS;j++) {
306 if (s < src)
307 v = src[0];
308 else if (s >= src_end)
309 v = src_end[-1];
310 else
311 v = s[0];
312 sum += v * filter[j];
313 s++;
315 sum = sum >> FILTER_BITS;
316 if (sum < 0)
317 sum = 0;
318 else if (sum > 255)
319 sum = 255;
320 dst[0] = sum;
321 src_pos += src_incr;
322 dst++;
326 static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
327 int src_width, int src_start, int src_incr,
328 int16_t *filters)
330 int n, src_end;
332 if (src_start < 0) {
333 n = (0 - src_start + src_incr - 1) / src_incr;
334 h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
335 dst += n;
336 dst_width -= n;
337 src_start += n * src_incr;
339 src_end = src_start + dst_width * src_incr;
340 if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
341 n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
342 src_incr;
343 } else {
344 n = dst_width;
346 #ifdef HAVE_MMX
347 if ((mm_flags & FF_MM_MMX) && NB_TAPS == 4)
348 h_resample_fast4_mmx(dst, n,
349 src, src_width, src_start, src_incr, filters);
350 else
351 #endif
352 h_resample_fast(dst, n,
353 src, src_width, src_start, src_incr, filters);
354 if (n < dst_width) {
355 dst += n;
356 dst_width -= n;
357 src_start += n * src_incr;
358 h_resample_slow(dst, dst_width,
359 src, src_width, src_start, src_incr, filters);
363 static void component_resample(ImgReSampleContext *s,
364 uint8_t *output, int owrap, int owidth, int oheight,
365 uint8_t *input, int iwrap, int iwidth, int iheight)
367 int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
368 uint8_t *new_line, *src_line;
370 last_src_y = - FCENTER - 1;
371 /* position of the bottom of the filter in the source image */
372 src_y = (last_src_y + NB_TAPS) * POS_FRAC;
373 ring_y = NB_TAPS; /* position in ring buffer */
374 for(y=0;y<oheight;y++) {
375 /* apply horizontal filter on new lines from input if needed */
376 src_y1 = src_y >> POS_FRAC_BITS;
377 while (last_src_y < src_y1) {
378 if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
379 ring_y = NB_TAPS;
380 last_src_y++;
381 /* handle limit conditions : replicate line (slightly
382 inefficient because we filter multiple times) */
383 y1 = last_src_y;
384 if (y1 < 0) {
385 y1 = 0;
386 } else if (y1 >= iheight) {
387 y1 = iheight - 1;
389 src_line = input + y1 * iwrap;
390 new_line = s->line_buf + ring_y * owidth;
391 /* apply filter and handle limit cases correctly */
392 h_resample(new_line, owidth,
393 src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
394 &s->h_filters[0][0]);
395 /* handle ring buffer wrapping */
396 if (ring_y >= LINE_BUF_HEIGHT) {
397 memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
398 new_line, owidth);
401 /* apply vertical filter */
402 phase_y = get_phase(src_y);
403 #ifdef HAVE_MMX
404 /* desactivated MMX because loss of precision */
405 if ((mm_flags & FF_MM_MMX) && NB_TAPS == 4 && 0)
406 v_resample4_mmx(output, owidth,
407 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
408 &s->v_filters[phase_y][0]);
409 else
410 #endif
411 #ifdef HAVE_ALTIVEC
412 if ((mm_flags & FF_MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
413 v_resample16_altivec(output, owidth,
414 s->line_buf + (ring_y - NB_TAPS + 1) * owidth,
415 owidth, &s->v_filters[phase_y][0]);
416 else
417 #endif
418 v_resample(output, owidth,
419 s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
420 &s->v_filters[phase_y][0]);
422 src_y += s->v_incr;
424 output += owrap;
428 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
429 int iwidth, int iheight,
430 int topBand, int bottomBand,
431 int leftBand, int rightBand,
432 int padtop, int padbottom,
433 int padleft, int padright)
435 ImgReSampleContext *s;
437 if (!owidth || !oheight || !iwidth || !iheight)
438 return NULL;
440 s = av_mallocz(sizeof(ImgReSampleContext));
441 if (!s)
442 return NULL;
443 if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
444 goto fail;
445 s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
446 if (!s->line_buf)
447 goto fail;
449 s->owidth = owidth;
450 s->oheight = oheight;
451 s->iwidth = iwidth;
452 s->iheight = iheight;
454 s->topBand = topBand;
455 s->bottomBand = bottomBand;
456 s->leftBand = leftBand;
457 s->rightBand = rightBand;
459 s->padtop = padtop;
460 s->padbottom = padbottom;
461 s->padleft = padleft;
462 s->padright = padright;
464 s->pad_owidth = owidth - (padleft + padright);
465 s->pad_oheight = oheight - (padtop + padbottom);
467 s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
468 s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
470 av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth /
471 (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
472 av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
473 (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
475 return s;
476 fail:
477 av_free(s);
478 return NULL;
481 ImgReSampleContext *img_resample_init(int owidth, int oheight,
482 int iwidth, int iheight)
484 return img_resample_full_init(owidth, oheight, iwidth, iheight,
485 0, 0, 0, 0, 0, 0, 0, 0);
488 void img_resample(ImgReSampleContext *s,
489 AVPicture *output, const AVPicture *input)
491 int i, shift;
492 uint8_t* optr;
494 for (i=0;i<3;i++) {
495 shift = (i == 0) ? 0 : 1;
497 optr = output->data[i] + (((output->linesize[i] *
498 s->padtop) + s->padleft) >> shift);
500 component_resample(s, optr, output->linesize[i],
501 s->pad_owidth >> shift, s->pad_oheight >> shift,
502 input->data[i] + (input->linesize[i] *
503 (s->topBand >> shift)) + (s->leftBand >> shift),
504 input->linesize[i], ((s->iwidth - s->leftBand -
505 s->rightBand) >> shift),
506 (s->iheight - s->topBand - s->bottomBand) >> shift);
510 void img_resample_close(ImgReSampleContext *s)
512 av_free(s->line_buf);
513 av_free(s);
516 static const char *context_to_name(void* ptr)
518 return "imgconvert";
521 static const AVClass context_class = { "imgresample", context_to_name, NULL };
523 struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
524 int dstW, int dstH, int dstFormat,
525 int flags, SwsFilter *srcFilter,
526 SwsFilter *dstFilter, double *param)
528 struct SwsContext *ctx;
530 ctx = av_malloc(sizeof(struct SwsContext));
531 if (!ctx) {
532 av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
534 return NULL;
536 ctx->av_class = &context_class;
538 if ((srcH != dstH) || (srcW != dstW)) {
539 if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
540 av_log(ctx, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
542 ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
543 } else {
544 ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
545 ctx->resampling_ctx->iheight = srcH;
546 ctx->resampling_ctx->iwidth = srcW;
547 ctx->resampling_ctx->oheight = dstH;
548 ctx->resampling_ctx->owidth = dstW;
550 ctx->src_pix_fmt = srcFormat;
551 ctx->dst_pix_fmt = dstFormat;
553 return ctx;
556 void sws_freeContext(struct SwsContext *ctx)
558 if (!ctx)
559 return;
560 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
561 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
562 img_resample_close(ctx->resampling_ctx);
563 } else {
564 av_free(ctx->resampling_ctx);
566 av_free(ctx);
571 * Checks if context is valid or reallocs a new one instead.
572 * If context is NULL, just calls sws_getContext() to get a new one.
573 * Otherwise, checks if the parameters are the same already saved in context.
574 * If that is the case, returns the current context.
575 * Otherwise, frees context and gets a new one.
577 * Be warned that srcFilter, dstFilter are not checked, they are
578 * asumed to remain valid.
580 struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
581 int srcW, int srcH, int srcFormat,
582 int dstW, int dstH, int dstFormat, int flags,
583 SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
585 if (ctx != NULL) {
586 if ((ctx->resampling_ctx->iwidth != srcW) ||
587 (ctx->resampling_ctx->iheight != srcH) ||
588 (ctx->src_pix_fmt != srcFormat) ||
589 (ctx->resampling_ctx->owidth != dstW) ||
590 (ctx->resampling_ctx->oheight != dstH) ||
591 (ctx->dst_pix_fmt != dstFormat))
593 sws_freeContext(ctx);
594 ctx = NULL;
597 if (ctx == NULL) {
598 return sws_getContext(srcW, srcH, srcFormat,
599 dstW, dstH, dstFormat, flags,
600 srcFilter, dstFilter, param);
602 return ctx;
605 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
606 int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
608 AVPicture src_pict, dst_pict;
609 int i, res = 0;
610 AVPicture picture_format_temp;
611 AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
612 uint8_t *buf1 = NULL, *buf2 = NULL;
613 enum PixelFormat current_pix_fmt;
615 for (i = 0; i < 4; i++) {
616 src_pict.data[i] = src[i];
617 src_pict.linesize[i] = srcStride[i];
618 dst_pict.data[i] = dst[i];
619 dst_pict.linesize[i] = dstStride[i];
621 if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
622 (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
623 /* We have to rescale the picture, but only YUV420P rescaling is supported... */
625 if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
626 int size;
628 /* create temporary picture for rescaling input*/
629 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
630 buf1 = av_malloc(size);
631 if (!buf1) {
632 res = -1;
633 goto the_end;
635 formatted_picture = &picture_format_temp;
636 avpicture_fill((AVPicture*)formatted_picture, buf1,
637 PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
639 if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
640 &src_pict, ctx->src_pix_fmt,
641 ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
643 av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
644 res = -1;
645 goto the_end;
647 } else {
648 formatted_picture = &src_pict;
651 if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
652 int size;
654 /* create temporary picture for rescaling output*/
655 size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
656 buf2 = av_malloc(size);
657 if (!buf2) {
658 res = -1;
659 goto the_end;
661 resampled_picture = &picture_resample_temp;
662 avpicture_fill((AVPicture*)resampled_picture, buf2,
663 PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
665 } else {
666 resampled_picture = &dst_pict;
669 /* ...and finally rescale!!! */
670 img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
671 current_pix_fmt = PIX_FMT_YUV420P;
672 } else {
673 resampled_picture = &src_pict;
674 current_pix_fmt = ctx->src_pix_fmt;
677 if (current_pix_fmt != ctx->dst_pix_fmt) {
678 if (img_convert(&dst_pict, ctx->dst_pix_fmt,
679 resampled_picture, current_pix_fmt,
680 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
682 av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
684 res = -1;
685 goto the_end;
687 } else if (resampled_picture != &dst_pict) {
688 av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
689 ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
692 the_end:
693 av_free(buf1);
694 av_free(buf2);
695 return res;
699 #ifdef TEST
700 #include <stdio.h>
701 #undef exit
703 /* input */
704 #define XSIZE 256
705 #define YSIZE 256
706 uint8_t img[XSIZE * YSIZE];
708 /* output */
709 #define XSIZE1 512
710 #define YSIZE1 512
711 uint8_t img1[XSIZE1 * YSIZE1];
712 uint8_t img2[XSIZE1 * YSIZE1];
714 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
716 #undef fprintf
717 FILE *f;
718 f=fopen(filename,"w");
719 fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
720 fwrite(img,1, xsize * ysize,f);
721 fclose(f);
722 #define fprintf please_use_av_log
725 static void dump_filter(int16_t *filter)
727 int i, ph;
729 for(ph=0;ph<NB_PHASES;ph++) {
730 av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
731 for(i=0;i<NB_TAPS;i++) {
732 av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
734 av_log(NULL, AV_LOG_INFO, "\n");
738 #ifdef HAVE_MMX
739 int mm_flags;
740 #endif
742 int main(int argc, char **argv)
744 int x, y, v, i, xsize, ysize;
745 ImgReSampleContext *s;
746 float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
747 char buf[256];
749 /* build test image */
750 for(y=0;y<YSIZE;y++) {
751 for(x=0;x<XSIZE;x++) {
752 if (x < XSIZE/2 && y < YSIZE/2) {
753 if (x < XSIZE/4 && y < YSIZE/4) {
754 if ((x % 10) <= 6 &&
755 (y % 10) <= 6)
756 v = 0xff;
757 else
758 v = 0x00;
759 } else if (x < XSIZE/4) {
760 if (x & 1)
761 v = 0xff;
762 else
763 v = 0;
764 } else if (y < XSIZE/4) {
765 if (y & 1)
766 v = 0xff;
767 else
768 v = 0;
769 } else {
770 if (y < YSIZE*3/8) {
771 if ((y+x) & 1)
772 v = 0xff;
773 else
774 v = 0;
775 } else {
776 if (((x+3) % 4) <= 1 &&
777 ((y+3) % 4) <= 1)
778 v = 0xff;
779 else
780 v = 0x00;
783 } else if (x < XSIZE/2) {
784 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
785 } else if (y < XSIZE/2) {
786 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
787 } else {
788 v = ((x + y - XSIZE) * 255) / XSIZE;
790 img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
793 save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
794 for(i=0;i<FF_ARRAY_ELEMS(factors);i++) {
795 fact = factors[i];
796 xsize = (int)(XSIZE * fact);
797 ysize = (int)((YSIZE - 100) * fact);
798 s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
799 av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
800 dump_filter(&s->h_filters[0][0]);
801 component_resample(s, img1, xsize, xsize, ysize,
802 img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
803 img_resample_close(s);
805 snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
806 save_pgm(buf, img1, xsize, ysize);
809 /* mmx test */
810 #ifdef HAVE_MMX
811 av_log(NULL, AV_LOG_INFO, "MMX test\n");
812 fact = 0.72;
813 xsize = (int)(XSIZE * fact);
814 ysize = (int)(YSIZE * fact);
815 mm_flags = FF_MM_MMX;
816 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
817 component_resample(s, img1, xsize, xsize, ysize,
818 img, XSIZE, XSIZE, YSIZE);
820 mm_flags = 0;
821 s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
822 component_resample(s, img2, xsize, xsize, ysize,
823 img, XSIZE, XSIZE, YSIZE);
824 if (memcmp(img1, img2, xsize * ysize) != 0) {
825 av_log(NULL, AV_LOG_ERROR, "mmx error\n");
826 exit(1);
828 av_log(NULL, AV_LOG_INFO, "MMX OK\n");
829 #endif /* HAVE_MMX */
830 return 0;
833 #endif /* TEST */