imgresample.c 25 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * High quality image resampling with polyphase filters
3
 * Copyright (c) 2001 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
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
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
21

Michael Niedermayer's avatar
Michael Niedermayer committed
22 23 24 25
/**
 * @file imgresample.c
 * High quality image resampling with polyphase filters .
 */
26

Fabrice Bellard's avatar
Fabrice Bellard committed
27
#include "avcodec.h"
28
#include "dsputil.h"
29
#include "libswscale/swscale.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
30

31 32 33 34
#ifdef HAVE_ALTIVEC
#include "ppc/imgresample_altivec.h"
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
35 36 37 38 39 40
#define NB_COMPONENTS 3

#define PHASE_BITS 4
#define NB_PHASES  (1 << PHASE_BITS)
#define NB_TAPS    4
#define FCENTER    1  /* index of the center of the filter */
41
//#define TEST    1  /* Test it */
Fabrice Bellard's avatar
Fabrice Bellard committed
42 43 44 45 46 47 48 49

#define POS_FRAC_BITS 16
#define POS_FRAC      (1 << POS_FRAC_BITS)
/* 6 bits precision is needed for MMX */
#define FILTER_BITS   8

#define LINE_BUF_HEIGHT (NB_TAPS * 4)

50
struct SwsContext {
51
    const AVClass *av_class;
52 53 54 55
    struct ImgReSampleContext *resampling_ctx;
    enum PixelFormat src_pix_fmt, dst_pix_fmt;
};

Fabrice Bellard's avatar
Fabrice Bellard committed
56
struct ImgReSampleContext {
57 58 59 60
    int iwidth, iheight, owidth, oheight;
    int topBand, bottomBand, leftBand, rightBand;
    int padtop, padbottom, padleft, padright;
    int pad_owidth, pad_oheight;
Fabrice Bellard's avatar
Fabrice Bellard committed
61
    int h_incr, v_incr;
62 63
    DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
    DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
64
    uint8_t *line_buf;
Fabrice Bellard's avatar
Fabrice Bellard committed
65 66
};

67 68
void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);

Fabrice Bellard's avatar
Fabrice Bellard committed
69 70 71 72 73 74
static inline int get_phase(int pos)
{
    return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
}

/* This function must be optimized */
75
static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
76 77
                            int src_width, int src_start, int src_incr,
                            int16_t *filters)
Fabrice Bellard's avatar
Fabrice Bellard committed
78 79
{
    int src_pos, phase, sum, i;
80
    const uint8_t *s;
81
    int16_t *filter;
Fabrice Bellard's avatar
Fabrice Bellard committed
82 83 84 85 86 87 88

    src_pos = src_start;
    for(i=0;i<dst_width;i++) {
#ifdef TEST
        /* test */
        if ((src_pos >> POS_FRAC_BITS) < 0 ||
            (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
89
            av_abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#endif
        s = src + (src_pos >> POS_FRAC_BITS);
        phase = get_phase(src_pos);
        filter = filters + phase * NB_TAPS;
#if NB_TAPS == 4
        sum = s[0] * filter[0] +
            s[1] * filter[1] +
            s[2] * filter[2] +
            s[3] * filter[3];
#else
        {
            int j;
            sum = 0;
            for(j=0;j<NB_TAPS;j++)
                sum += s[j] * filter[j];
        }
#endif
        sum = sum >> FILTER_BITS;
        if (sum < 0)
            sum = 0;
        else if (sum > 255)
            sum = 255;
        dst[0] = sum;
        src_pos += src_incr;
        dst++;
    }
}

/* This function must be optimized */
119
static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
120
                       int wrap, int16_t *filter)
Fabrice Bellard's avatar
Fabrice Bellard committed
121 122
{
    int sum, i;
123
    const uint8_t *s;
Fabrice Bellard's avatar
Fabrice Bellard committed
124 125 126 127 128 129 130 131 132 133 134

    s = src;
    for(i=0;i<dst_width;i++) {
#if NB_TAPS == 4
        sum = s[0 * wrap] * filter[0] +
            s[1 * wrap] * filter[1] +
            s[2 * wrap] * filter[2] +
            s[3 * wrap] * filter[3];
#else
        {
            int j;
135
            uint8_t *s1 = s;
Fabrice Bellard's avatar
Fabrice Bellard committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

            sum = 0;
            for(j=0;j<NB_TAPS;j++) {
                sum += s1[0] * filter[j];
                s1 += wrap;
            }
        }
#endif
        sum = sum >> FILTER_BITS;
        if (sum < 0)
            sum = 0;
        else if (sum > 255)
            sum = 255;
        dst[0] = sum;
        dst++;
        s++;
    }
}

155
#ifdef HAVE_MMX
Fabrice Bellard's avatar
Fabrice Bellard committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

#include "i386/mmx.h"

#define FILTER4(reg) \
{\
        s = src + (src_pos >> POS_FRAC_BITS);\
        phase = get_phase(src_pos);\
        filter = filters + phase * NB_TAPS;\
        movq_m2r(*s, reg);\
        punpcklbw_r2r(mm7, reg);\
        movq_m2r(*filter, mm6);\
        pmaddwd_r2r(reg, mm6);\
        movq_r2r(mm6, reg);\
        psrlq_i2r(32, reg);\
        paddd_r2r(mm6, reg);\
        psrad_i2r(FILTER_BITS, reg);\
        src_pos += src_incr;\
}

175
#define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
Fabrice Bellard's avatar
Fabrice Bellard committed
176 177

/* XXX: do four pixels at a time */
178
static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
179
                                 const uint8_t *src, int src_width,
180
                                 int src_start, int src_incr, int16_t *filters)
Fabrice Bellard's avatar
Fabrice Bellard committed
181 182
{
    int src_pos, phase;
183
    const uint8_t *s;
184
    int16_t *filter;
Fabrice Bellard's avatar
Fabrice Bellard committed
185
    mmx_t tmp;
186

Fabrice Bellard's avatar
Fabrice Bellard committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
    src_pos = src_start;
    pxor_r2r(mm7, mm7);

    while (dst_width >= 4) {

        FILTER4(mm0);
        FILTER4(mm1);
        FILTER4(mm2);
        FILTER4(mm3);

        packuswb_r2r(mm7, mm0);
        packuswb_r2r(mm7, mm1);
        packuswb_r2r(mm7, mm3);
        packuswb_r2r(mm7, mm2);
        movq_r2m(mm0, tmp);
        dst[0] = tmp.ub[0];
        movq_r2m(mm1, tmp);
        dst[1] = tmp.ub[0];
        movq_r2m(mm2, tmp);
        dst[2] = tmp.ub[0];
        movq_r2m(mm3, tmp);
        dst[3] = tmp.ub[0];
        dst += 4;
        dst_width -= 4;
    }
    while (dst_width > 0) {
        FILTER4(mm0);
        packuswb_r2r(mm7, mm0);
        movq_r2m(mm0, tmp);
        dst[0] = tmp.ub[0];
        dst++;
        dst_width--;
    }
    emms();
}

223
static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
224
                            int wrap, int16_t *filter)
Fabrice Bellard's avatar
Fabrice Bellard committed
225 226
{
    int sum, i, v;
227
    const uint8_t *s;
Fabrice Bellard's avatar
Fabrice Bellard committed
228 229
    mmx_t tmp;
    mmx_t coefs[4];
230

Fabrice Bellard's avatar
Fabrice Bellard committed
231 232 233 234 235 236 237
    for(i=0;i<4;i++) {
        v = filter[i];
        coefs[i].uw[0] = v;
        coefs[i].uw[1] = v;
        coefs[i].uw[2] = v;
        coefs[i].uw[3] = v;
    }
238

Fabrice Bellard's avatar
Fabrice Bellard committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    pxor_r2r(mm7, mm7);
    s = src;
    while (dst_width >= 4) {
        movq_m2r(s[0 * wrap], mm0);
        punpcklbw_r2r(mm7, mm0);
        movq_m2r(s[1 * wrap], mm1);
        punpcklbw_r2r(mm7, mm1);
        movq_m2r(s[2 * wrap], mm2);
        punpcklbw_r2r(mm7, mm2);
        movq_m2r(s[3 * wrap], mm3);
        punpcklbw_r2r(mm7, mm3);

        pmullw_m2r(coefs[0], mm0);
        pmullw_m2r(coefs[1], mm1);
        pmullw_m2r(coefs[2], mm2);
        pmullw_m2r(coefs[3], mm3);

        paddw_r2r(mm1, mm0);
        paddw_r2r(mm3, mm2);
        paddw_r2r(mm2, mm0);
        psraw_i2r(FILTER_BITS, mm0);
260

Fabrice Bellard's avatar
Fabrice Bellard committed
261 262 263
        packuswb_r2r(mm7, mm0);
        movq_r2m(mm0, tmp);

264
        *(uint32_t *)dst = tmp.ud[0];
Fabrice Bellard's avatar
Fabrice Bellard committed
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        dst += 4;
        s += 4;
        dst_width -= 4;
    }
    while (dst_width > 0) {
        sum = s[0 * wrap] * filter[0] +
            s[1 * wrap] * filter[1] +
            s[2 * wrap] * filter[2] +
            s[3 * wrap] * filter[3];
        sum = sum >> FILTER_BITS;
        if (sum < 0)
            sum = 0;
        else if (sum > 255)
            sum = 255;
        dst[0] = sum;
        dst++;
        s++;
        dst_width--;
    }
    emms();
}
286
#endif /* HAVE_MMX */
Fabrice Bellard's avatar
Fabrice Bellard committed
287

Vitor Sessak's avatar
Vitor Sessak committed
288
/* slow version to handle limit cases. Does not need optimization */
289
static void h_resample_slow(uint8_t *dst, int dst_width,
290
                            const uint8_t *src, int src_width,
291
                            int src_start, int src_incr, int16_t *filters)
Fabrice Bellard's avatar
Fabrice Bellard committed
292 293
{
    int src_pos, phase, sum, j, v, i;
294
    const uint8_t *s, *src_end;
295
    int16_t *filter;
Fabrice Bellard's avatar
Fabrice Bellard committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

    src_end = src + src_width;
    src_pos = src_start;
    for(i=0;i<dst_width;i++) {
        s = src + (src_pos >> POS_FRAC_BITS);
        phase = get_phase(src_pos);
        filter = filters + phase * NB_TAPS;
        sum = 0;
        for(j=0;j<NB_TAPS;j++) {
            if (s < src)
                v = src[0];
            else if (s >= src_end)
                v = src_end[-1];
            else
                v = s[0];
            sum += v * filter[j];
            s++;
        }
        sum = sum >> FILTER_BITS;
        if (sum < 0)
            sum = 0;
        else if (sum > 255)
            sum = 255;
        dst[0] = sum;
        src_pos += src_incr;
        dst++;
    }
}

325
static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
326 327
                       int src_width, int src_start, int src_incr,
                       int16_t *filters)
Fabrice Bellard's avatar
Fabrice Bellard committed
328 329 330 331 332 333 334 335 336 337 338 339
{
    int n, src_end;

    if (src_start < 0) {
        n = (0 - src_start + src_incr - 1) / src_incr;
        h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
        dst += n;
        dst_width -= n;
        src_start += n * src_incr;
    }
    src_end = src_start + dst_width * src_incr;
    if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
340
        n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
Fabrice Bellard's avatar
Fabrice Bellard committed
341 342 343 344
            src_incr;
    } else {
        n = dst_width;
    }
345
#ifdef HAVE_MMX
Måns Rullgård's avatar
Måns Rullgård committed
346
    if ((mm_flags & MM_MMX) && NB_TAPS == 4)
347
        h_resample_fast4_mmx(dst, n,
Fabrice Bellard's avatar
Fabrice Bellard committed
348 349 350
                             src, src_width, src_start, src_incr, filters);
    else
#endif
351
        h_resample_fast(dst, n,
Fabrice Bellard's avatar
Fabrice Bellard committed
352 353 354 355 356
                        src, src_width, src_start, src_incr, filters);
    if (n < dst_width) {
        dst += n;
        dst_width -= n;
        src_start += n * src_incr;
357
        h_resample_slow(dst, dst_width,
Fabrice Bellard's avatar
Fabrice Bellard committed
358 359 360 361
                        src, src_width, src_start, src_incr, filters);
    }
}

362
static void component_resample(ImgReSampleContext *s,
363 364
                               uint8_t *output, int owrap, int owidth, int oheight,
                               uint8_t *input, int iwrap, int iwidth, int iheight)
Fabrice Bellard's avatar
Fabrice Bellard committed
365 366
{
    int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
367
    uint8_t *new_line, *src_line;
Fabrice Bellard's avatar
Fabrice Bellard committed
368 369 370

    last_src_y = - FCENTER - 1;
    /* position of the bottom of the filter in the source image */
371
    src_y = (last_src_y + NB_TAPS) * POS_FRAC;
Fabrice Bellard's avatar
Fabrice Bellard committed
372 373 374 375 376 377 378 379
    ring_y = NB_TAPS; /* position in ring buffer */
    for(y=0;y<oheight;y++) {
        /* apply horizontal filter on new lines from input if needed */
        src_y1 = src_y >> POS_FRAC_BITS;
        while (last_src_y < src_y1) {
            if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
                ring_y = NB_TAPS;
            last_src_y++;
380 381
            /* handle limit conditions : replicate line (slightly
               inefficient because we filter multiple times) */
Fabrice Bellard's avatar
Fabrice Bellard committed
382 383 384 385 386 387 388 389 390
            y1 = last_src_y;
            if (y1 < 0) {
                y1 = 0;
            } else if (y1 >= iheight) {
                y1 = iheight - 1;
            }
            src_line = input + y1 * iwrap;
            new_line = s->line_buf + ring_y * owidth;
            /* apply filter and handle limit cases correctly */
391 392
            h_resample(new_line, owidth,
                       src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
Fabrice Bellard's avatar
Fabrice Bellard committed
393
                       &s->h_filters[0][0]);
Diego Biurrun's avatar
Diego Biurrun committed
394
            /* handle ring buffer wrapping */
Fabrice Bellard's avatar
Fabrice Bellard committed
395 396 397 398 399 400 401
            if (ring_y >= LINE_BUF_HEIGHT) {
                memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
                       new_line, owidth);
            }
        }
        /* apply vertical filter */
        phase_y = get_phase(src_y);
402
#ifdef HAVE_MMX
Fabrice Bellard's avatar
Fabrice Bellard committed
403
        /* desactivated MMX because loss of precision */
Måns Rullgård's avatar
Måns Rullgård committed
404
        if ((mm_flags & MM_MMX) && NB_TAPS == 4 && 0)
405 406
            v_resample4_mmx(output, owidth,
                            s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
Fabrice Bellard's avatar
Fabrice Bellard committed
407
                            &s->v_filters[phase_y][0]);
408 409 410
        else
#endif
#ifdef HAVE_ALTIVEC
Måns Rullgård's avatar
Måns Rullgård committed
411
            if ((mm_flags & MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
412 413 414
                v_resample16_altivec(output, owidth,
                                s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
                                &s->v_filters[phase_y][0]);
Fabrice Bellard's avatar
Fabrice Bellard committed
415 416
        else
#endif
417 418
            v_resample(output, owidth,
                       s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
Fabrice Bellard's avatar
Fabrice Bellard committed
419
                       &s->v_filters[phase_y][0]);
420

Fabrice Bellard's avatar
Fabrice Bellard committed
421
        src_y += s->v_incr;
422

Fabrice Bellard's avatar
Fabrice Bellard committed
423 424 425 426 427 428
        output += owrap;
    }
}

ImgReSampleContext *img_resample_init(int owidth, int oheight,
                                      int iwidth, int iheight)
429
{
430
    return img_resample_full_init(owidth, oheight, iwidth, iheight,
431
            0, 0, 0, 0, 0, 0, 0, 0);
432 433 434 435 436
}

ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
                                      int iwidth, int iheight,
                                      int topBand, int bottomBand,
437 438 439
        int leftBand, int rightBand,
        int padtop, int padbottom,
        int padleft, int padright)
Fabrice Bellard's avatar
Fabrice Bellard committed
440 441 442
{
    ImgReSampleContext *s;

443
    if (!owidth || !oheight || !iwidth || !iheight)
444
        return NULL;
445

Fabrice Bellard's avatar
Fabrice Bellard committed
446 447 448
    s = av_mallocz(sizeof(ImgReSampleContext));
    if (!s)
        return NULL;
449
    if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
450
        goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
451
    s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
452
    if (!s->line_buf)
Fabrice Bellard's avatar
Fabrice Bellard committed
453
        goto fail;
454

Fabrice Bellard's avatar
Fabrice Bellard committed
455 456 457 458
    s->owidth = owidth;
    s->oheight = oheight;
    s->iwidth = iwidth;
    s->iheight = iheight;
459

460 461 462 463
    s->topBand = topBand;
    s->bottomBand = bottomBand;
    s->leftBand = leftBand;
    s->rightBand = rightBand;
464

465 466 467 468 469 470 471 472 473
    s->padtop = padtop;
    s->padbottom = padbottom;
    s->padleft = padleft;
    s->padright = padright;

    s->pad_owidth = owidth - (padleft + padright);
    s->pad_oheight = oheight - (padtop + padbottom);

    s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
474
    s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
475

476
    av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth  /
477
            (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
478
    av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
479
            (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
480 481

    return s;
482
fail:
483
    av_free(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
484 485 486
    return NULL;
}

487
void img_resample(ImgReSampleContext *s,
488
                  AVPicture *output, const AVPicture *input)
Fabrice Bellard's avatar
Fabrice Bellard committed
489 490
{
    int i, shift;
491
    uint8_t* optr;
Fabrice Bellard's avatar
Fabrice Bellard committed
492

493
    for (i=0;i<3;i++) {
Fabrice Bellard's avatar
Fabrice Bellard committed
494
        shift = (i == 0) ? 0 : 1;
495

496
        optr = output->data[i] + (((output->linesize[i] *
497 498
                        s->padtop) + s->padleft) >> shift);

499
        component_resample(s, optr, output->linesize[i],
500
                s->pad_owidth >> shift, s->pad_oheight >> shift,
501
                input->data[i] + (input->linesize[i] *
502
                    (s->topBand >> shift)) + (s->leftBand >> shift),
503
                input->linesize[i], ((s->iwidth - s->leftBand -
504
                        s->rightBand) >> shift),
505
                           (s->iheight - s->topBand - s->bottomBand) >> shift);
Fabrice Bellard's avatar
Fabrice Bellard committed
506 507 508 509 510
    }
}

void img_resample_close(ImgReSampleContext *s)
{
511 512
    av_free(s->line_buf);
    av_free(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
513 514
}

515 516 517 518 519 520
static const char *context_to_name(void* ptr)
{
    return "imgconvert";
}

static const AVClass context_class = { "imgresample", context_to_name, NULL };
521

522 523 524 525 526 527 528 529
struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
                                  int dstW, int dstH, int dstFormat,
                                  int flags, SwsFilter *srcFilter,
                                  SwsFilter *dstFilter, double *param)
{
    struct SwsContext *ctx;

    ctx = av_malloc(sizeof(struct SwsContext));
530
    if (!ctx) {
531 532 533 534
        av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");

        return NULL;
    }
535
    ctx->av_class = &context_class;
536 537 538

    if ((srcH != dstH) || (srcW != dstW)) {
        if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
539
            av_log(ctx, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
        }
        ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
    } else {
        ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
        ctx->resampling_ctx->iheight = srcH;
        ctx->resampling_ctx->iwidth = srcW;
        ctx->resampling_ctx->oheight = dstH;
        ctx->resampling_ctx->owidth = dstW;
    }
    ctx->src_pix_fmt = srcFormat;
    ctx->dst_pix_fmt = dstFormat;

    return ctx;
}

void sws_freeContext(struct SwsContext *ctx)
{
557 558
    if (!ctx)
        return;
559 560 561 562 563 564 565 566 567
    if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
        (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
        img_resample_close(ctx->resampling_ctx);
    } else {
        av_free(ctx->resampling_ctx);
    }
    av_free(ctx);
}

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

/**
 * Checks if context is valid or reallocs a new one instead.
 * If context is NULL, just calls sws_getContext() to get a new one.
 * Otherwise, checks if the parameters are the same already saved in context.
 * If that is the case, returns the current context.
 * Otherwise, frees context and gets a new one.
 *
 * Be warned that srcFilter, dstFilter are not checked, they are
 * asumed to remain valid.
 */
struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
                        int srcW, int srcH, int srcFormat,
                        int dstW, int dstH, int dstFormat, int flags,
                        SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
{
    if (ctx != NULL) {
        if ((ctx->resampling_ctx->iwidth != srcW) ||
                        (ctx->resampling_ctx->iheight != srcH) ||
                        (ctx->src_pix_fmt != srcFormat) ||
                        (ctx->resampling_ctx->owidth != dstW) ||
                        (ctx->resampling_ctx->oheight != dstH) ||
                        (ctx->dst_pix_fmt != dstFormat))
        {
            sws_freeContext(ctx);
            ctx = NULL;
        }
    }
    if (ctx == NULL) {
        return sws_getContext(srcW, srcH, srcFormat,
                        dstW, dstH, dstFormat, flags,
                        srcFilter, dstFilter, param);
    }
    return ctx;
}

604 605 606 607 608 609 610 611 612 613
int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
              int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
{
    AVPicture src_pict, dst_pict;
    int i, res = 0;
    AVPicture picture_format_temp;
    AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
    uint8_t *buf1 = NULL, *buf2 = NULL;
    enum PixelFormat current_pix_fmt;

614
    for (i = 0; i < 4; i++) {
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
        src_pict.data[i] = src[i];
        src_pict.linesize[i] = srcStride[i];
        dst_pict.data[i] = dst[i];
        dst_pict.linesize[i] = dstStride[i];
    }
    if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
        (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
        /* We have to rescale the picture, but only YUV420P rescaling is supported... */

        if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
            int size;

            /* create temporary picture for rescaling input*/
            size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
            buf1 = av_malloc(size);
            if (!buf1) {
                res = -1;
                goto the_end;
            }
            formatted_picture = &picture_format_temp;
            avpicture_fill((AVPicture*)formatted_picture, buf1,
                           PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);

            if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
                            &src_pict, ctx->src_pix_fmt,
                            ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {

642
                av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
                res = -1;
                goto the_end;
            }
        } else {
            formatted_picture = &src_pict;
        }

        if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
            int size;

            /* create temporary picture for rescaling output*/
            size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
            buf2 = av_malloc(size);
            if (!buf2) {
                res = -1;
                goto the_end;
            }
            resampled_picture = &picture_resample_temp;
            avpicture_fill((AVPicture*)resampled_picture, buf2,
                           PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);

        } else {
            resampled_picture = &dst_pict;
        }

        /* ...and finally rescale!!! */
        img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
        current_pix_fmt = PIX_FMT_YUV420P;
    } else {
        resampled_picture = &src_pict;
        current_pix_fmt = ctx->src_pix_fmt;
    }

    if (current_pix_fmt != ctx->dst_pix_fmt) {
        if (img_convert(&dst_pict, ctx->dst_pix_fmt,
                        resampled_picture, current_pix_fmt,
                        ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {

681
            av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
682 683 684 685

            res = -1;
            goto the_end;
        }
686
    } else if (resampled_picture != &dst_pict) {
687
        av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
688
                        ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
689 690 691 692 693 694 695 696 697
    }

the_end:
    av_free(buf1);
    av_free(buf2);
    return res;
}


Fabrice Bellard's avatar
Fabrice Bellard committed
698
#ifdef TEST
699
#include <stdio.h>
700
#undef exit
701

Fabrice Bellard's avatar
Fabrice Bellard committed
702 703 704
/* input */
#define XSIZE 256
#define YSIZE 256
705
uint8_t img[XSIZE * YSIZE];
Fabrice Bellard's avatar
Fabrice Bellard committed
706 707 708 709

/* output */
#define XSIZE1 512
#define YSIZE1 512
710 711
uint8_t img1[XSIZE1 * YSIZE1];
uint8_t img2[XSIZE1 * YSIZE1];
Fabrice Bellard's avatar
Fabrice Bellard committed
712

713
void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
Fabrice Bellard's avatar
Fabrice Bellard committed
714
{
715
#undef fprintf
Fabrice Bellard's avatar
Fabrice Bellard committed
716 717 718 719 720
    FILE *f;
    f=fopen(filename,"w");
    fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
    fwrite(img,1, xsize * ysize,f);
    fclose(f);
721
#define fprintf please_use_av_log
Fabrice Bellard's avatar
Fabrice Bellard committed
722 723
}

724
static void dump_filter(int16_t *filter)
Fabrice Bellard's avatar
Fabrice Bellard committed
725 726 727 728
{
    int i, ph;

    for(ph=0;ph<NB_PHASES;ph++) {
729
        av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
Fabrice Bellard's avatar
Fabrice Bellard committed
730
        for(i=0;i<NB_TAPS;i++) {
731
            av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
Fabrice Bellard's avatar
Fabrice Bellard committed
732
        }
733
        av_log(NULL, AV_LOG_INFO, "\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
734 735 736
    }
}

737
#ifdef HAVE_MMX
Michael Niedermayer's avatar
Michael Niedermayer committed
738
int mm_flags;
Fabrice Bellard's avatar
Fabrice Bellard committed
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
#endif

int main(int argc, char **argv)
{
    int x, y, v, i, xsize, ysize;
    ImgReSampleContext *s;
    float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
    char buf[256];

    /* build test image */
    for(y=0;y<YSIZE;y++) {
        for(x=0;x<XSIZE;x++) {
            if (x < XSIZE/2 && y < YSIZE/2) {
                if (x < XSIZE/4 && y < YSIZE/4) {
                    if ((x % 10) <= 6 &&
                        (y % 10) <= 6)
                        v = 0xff;
                    else
                        v = 0x00;
                } else if (x < XSIZE/4) {
759
                    if (x & 1)
Fabrice Bellard's avatar
Fabrice Bellard committed
760
                        v = 0xff;
761
                    else
Fabrice Bellard's avatar
Fabrice Bellard committed
762 763
                        v = 0;
                } else if (y < XSIZE/4) {
764
                    if (y & 1)
Fabrice Bellard's avatar
Fabrice Bellard committed
765
                        v = 0xff;
766
                    else
Fabrice Bellard's avatar
Fabrice Bellard committed
767 768 769
                        v = 0;
                } else {
                    if (y < YSIZE*3/8) {
770
                        if ((y+x) & 1)
Fabrice Bellard's avatar
Fabrice Bellard committed
771
                            v = 0xff;
772
                        else
Fabrice Bellard's avatar
Fabrice Bellard committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
                            v = 0;
                    } else {
                        if (((x+3) % 4) <= 1 &&
                            ((y+3) % 4) <= 1)
                            v = 0xff;
                        else
                            v = 0x00;
                    }
                }
            } else if (x < XSIZE/2) {
                v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
            } else if (y < XSIZE/2) {
                v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
            } else {
                v = ((x + y - XSIZE) * 255) / XSIZE;
            }
789
            img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
Fabrice Bellard's avatar
Fabrice Bellard committed
790 791 792 793 794 795
        }
    }
    save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
    for(i=0;i<sizeof(factors)/sizeof(float);i++) {
        fact = factors[i];
        xsize = (int)(XSIZE * fact);
796
        ysize = (int)((YSIZE - 100) * fact);
797 798
        s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
        av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
Fabrice Bellard's avatar
Fabrice Bellard committed
799 800
        dump_filter(&s->h_filters[0][0]);
        component_resample(s, img1, xsize, xsize, ysize,
801
                           img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
Fabrice Bellard's avatar
Fabrice Bellard committed
802 803
        img_resample_close(s);

Michael Niedermayer's avatar
Michael Niedermayer committed
804
        snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
Fabrice Bellard's avatar
Fabrice Bellard committed
805 806 807 808
        save_pgm(buf, img1, xsize, ysize);
    }

    /* mmx test */
809
#ifdef HAVE_MMX
810
    av_log(NULL, AV_LOG_INFO, "MMX test\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
811 812 813 814 815 816 817 818 819 820 821 822 823
    fact = 0.72;
    xsize = (int)(XSIZE * fact);
    ysize = (int)(YSIZE * fact);
    mm_flags = MM_MMX;
    s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
    component_resample(s, img1, xsize, xsize, ysize,
                       img, XSIZE, XSIZE, YSIZE);

    mm_flags = 0;
    s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
    component_resample(s, img2, xsize, xsize, ysize,
                       img, XSIZE, XSIZE, YSIZE);
    if (memcmp(img1, img2, xsize * ysize) != 0) {
824
        av_log(NULL, AV_LOG_ERROR, "mmx error\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
825 826
        exit(1);
    }
827
    av_log(NULL, AV_LOG_INFO, "MMX OK\n");
828
#endif /* HAVE_MMX */
Fabrice Bellard's avatar
Fabrice Bellard committed
829 830 831
    return 0;
}

832
#endif /* TEST */