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