Statistics
| Branch: | Revision:

ffmpeg / libavcodec / imgresample.c @ a6493a8f

History | View | Annotate | Download (25 KB)

1
/*
2
 * High quality image resampling with polyphase filters
3
 * Copyright (c) 2001 Fabrice Bellard.
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
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
20
 */
21

    
22
/**
23
 * @file imgresample.c
24
 * High quality image resampling with polyphase filters .
25
 */
26

    
27
#include "avcodec.h"
28
#include "dsputil.h"
29
#include "imgconvert.h"
30
#include "libswscale/swscale.h"
31

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

    
36
#define NB_COMPONENTS 3
37

    
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 */
43

    
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
48

    
49
#define LINE_BUF_HEIGHT (NB_TAPS * 4)
50

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

    
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;
67

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

    
70
static inline int get_phase(int pos)
71
{
72
    return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
73
}
74

    
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)
79
{
80
    int src_pos, phase, sum, i;
81
    const uint8_t *s;
82
    int16_t *filter;
83

    
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
101
        {
102
            int j;
103
            sum = 0;
104
            for(j=0;j<NB_TAPS;j++)
105
                sum += s[j] * filter[j];
106
        }
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++;
116
    }
117
}
118

    
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)
122
{
123
    int sum, i;
124
    const uint8_t *s;
125

    
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
134
        {
135
            int j;
136
            uint8_t *s1 = s;
137

    
138
            sum = 0;
139
            for(j=0;j<NB_TAPS;j++) {
140
                sum += s1[0] * filter[j];
141
                s1 += wrap;
142
            }
143
        }
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++;
153
    }
154
}
155

    
156
#ifdef HAVE_MMX
157

    
158
#include "x86/mmx.h"
159

    
160
#define FILTER4(reg) \
161
{\
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;\
174
}
175

    
176
#define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
177

    
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)
182
{
183
    int src_pos, phase;
184
    const uint8_t *s;
185
    int16_t *filter;
186
    uint64_t tmp;
187

    
188
    src_pos = src_start;
189
    pxor_r2r(mm7, mm7);
190

    
191
    while (dst_width >= 4) {
192

    
193
        FILTER4(mm0);
194
        FILTER4(mm1);
195
        FILTER4(mm2);
196
        FILTER4(mm3);
197

    
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 & 0xFF;
204
        movq_r2m(mm1, tmp);
205
        dst[1] = tmp & 0xFF;
206
        movq_r2m(mm2, tmp);
207
        dst[2] = tmp & 0xFF;
208
        movq_r2m(mm3, tmp);
209
        dst[3] = tmp & 0xFF;
210
        dst += 4;
211
        dst_width -= 4;
212
    }
213
    while (dst_width > 0) {
214
        FILTER4(mm0);
215
        packuswb_r2r(mm7, mm0);
216
        movq_r2m(mm0, tmp);
217
        dst[0] = tmp & 0xFF;
218
        dst++;
219
        dst_width--;
220
    }
221
    emms();
222
}
223

    
224
static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
225
                            int wrap, int16_t *filter)
226
{
227
    int sum, i;
228
    const uint8_t *s;
229
    uint64_t tmp;
230
    uint64_t coefs[4];
231

    
232
    for(i=0;i<4;i++) {
233
        tmp = filter[i];
234
        coefs[i] = (tmp<<48) + (tmp<<32) + (tmp<<16) + tmp;
235
    }
236

    
237
    pxor_r2r(mm7, mm7);
238
    s = src;
239
    while (dst_width >= 4) {
240
        movq_m2r(s[0 * wrap], mm0);
241
        punpcklbw_r2r(mm7, mm0);
242
        movq_m2r(s[1 * wrap], mm1);
243
        punpcklbw_r2r(mm7, mm1);
244
        movq_m2r(s[2 * wrap], mm2);
245
        punpcklbw_r2r(mm7, mm2);
246
        movq_m2r(s[3 * wrap], mm3);
247
        punpcklbw_r2r(mm7, mm3);
248

    
249
        pmullw_m2r(coefs[0], mm0);
250
        pmullw_m2r(coefs[1], mm1);
251
        pmullw_m2r(coefs[2], mm2);
252
        pmullw_m2r(coefs[3], mm3);
253

    
254
        paddw_r2r(mm1, mm0);
255
        paddw_r2r(mm3, mm2);
256
        paddw_r2r(mm2, mm0);
257
        psraw_i2r(FILTER_BITS, mm0);
258

    
259
        packuswb_r2r(mm7, mm0);
260
        movq_r2m(mm0, tmp);
261

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

    
286
/* slow version to handle limit cases. Does not need optimization */
287
static void h_resample_slow(uint8_t *dst, int dst_width,
288
                            const uint8_t *src, int src_width,
289
                            int src_start, int src_incr, int16_t *filters)
290
{
291
    int src_pos, phase, sum, j, v, i;
292
    const uint8_t *s, *src_end;
293
    int16_t *filter;
294

    
295
    src_end = src + src_width;
296
    src_pos = src_start;
297
    for(i=0;i<dst_width;i++) {
298
        s = src + (src_pos >> POS_FRAC_BITS);
299
        phase = get_phase(src_pos);
300
        filter = filters + phase * NB_TAPS;
301
        sum = 0;
302
        for(j=0;j<NB_TAPS;j++) {
303
            if (s < src)
304
                v = src[0];
305
            else if (s >= src_end)
306
                v = src_end[-1];
307
            else
308
                v = s[0];
309
            sum += v * filter[j];
310
            s++;
311
        }
312
        sum = sum >> FILTER_BITS;
313
        if (sum < 0)
314
            sum = 0;
315
        else if (sum > 255)
316
            sum = 255;
317
        dst[0] = sum;
318
        src_pos += src_incr;
319
        dst++;
320
    }
321
}
322

    
323
static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
324
                       int src_width, int src_start, int src_incr,
325
                       int16_t *filters)
326
{
327
    int n, src_end;
328

    
329
    if (src_start < 0) {
330
        n = (0 - src_start + src_incr - 1) / src_incr;
331
        h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
332
        dst += n;
333
        dst_width -= n;
334
        src_start += n * src_incr;
335
    }
336
    src_end = src_start + dst_width * src_incr;
337
    if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
338
        n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
339
            src_incr;
340
    } else {
341
        n = dst_width;
342
    }
343
#ifdef HAVE_MMX
344
    if ((mm_flags & FF_MM_MMX) && NB_TAPS == 4)
345
        h_resample_fast4_mmx(dst, n,
346
                             src, src_width, src_start, src_incr, filters);
347
    else
348
#endif
349
        h_resample_fast(dst, n,
350
                        src, src_width, src_start, src_incr, filters);
351
    if (n < dst_width) {
352
        dst += n;
353
        dst_width -= n;
354
        src_start += n * src_incr;
355
        h_resample_slow(dst, dst_width,
356
                        src, src_width, src_start, src_incr, filters);
357
    }
358
}
359

    
360
static void component_resample(ImgReSampleContext *s,
361
                               uint8_t *output, int owrap, int owidth, int oheight,
362
                               uint8_t *input, int iwrap, int iwidth, int iheight)
363
{
364
    int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
365
    uint8_t *new_line, *src_line;
366

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

    
419
        src_y += s->v_incr;
420

    
421
        output += owrap;
422
    }
423
}
424

    
425
ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
426
                                      int iwidth, int iheight,
427
                                      int topBand, int bottomBand,
428
        int leftBand, int rightBand,
429
        int padtop, int padbottom,
430
        int padleft, int padright)
431
{
432
    ImgReSampleContext *s;
433

    
434
    if (!owidth || !oheight || !iwidth || !iheight)
435
        return NULL;
436

    
437
    s = av_mallocz(sizeof(ImgReSampleContext));
438
    if (!s)
439
        return NULL;
440
    if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
441
        goto fail;
442
    s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
443
    if (!s->line_buf)
444
        goto fail;
445

    
446
    s->owidth = owidth;
447
    s->oheight = oheight;
448
    s->iwidth = iwidth;
449
    s->iheight = iheight;
450

    
451
    s->topBand = topBand;
452
    s->bottomBand = bottomBand;
453
    s->leftBand = leftBand;
454
    s->rightBand = rightBand;
455

    
456
    s->padtop = padtop;
457
    s->padbottom = padbottom;
458
    s->padleft = padleft;
459
    s->padright = padright;
460

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

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

    
467
    av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth  /
468
            (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
469
    av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
470
            (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
471

    
472
    return s;
473
fail:
474
    av_free(s);
475
    return NULL;
476
}
477

    
478
ImgReSampleContext *img_resample_init(int owidth, int oheight,
479
                                      int iwidth, int iheight)
480
{
481
    return img_resample_full_init(owidth, oheight, iwidth, iheight,
482
            0, 0, 0, 0, 0, 0, 0, 0);
483
}
484

    
485
void img_resample(ImgReSampleContext *s,
486
                  AVPicture *output, const AVPicture *input)
487
{
488
    int i, shift;
489
    uint8_t* optr;
490

    
491
    for (i=0;i<3;i++) {
492
        shift = (i == 0) ? 0 : 1;
493

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

    
497
        component_resample(s, optr, output->linesize[i],
498
                s->pad_owidth >> shift, s->pad_oheight >> shift,
499
                input->data[i] + (input->linesize[i] *
500
                    (s->topBand >> shift)) + (s->leftBand >> shift),
501
                input->linesize[i], ((s->iwidth - s->leftBand -
502
                        s->rightBand) >> shift),
503
                           (s->iheight - s->topBand - s->bottomBand) >> shift);
504
    }
505
}
506

    
507
void img_resample_close(ImgReSampleContext *s)
508
{
509
    av_free(s->line_buf);
510
    av_free(s);
511
}
512

    
513
static const char *context_to_name(void* ptr)
514
{
515
    return "imgconvert";
516
}
517

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

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

    
527
    ctx = av_malloc(sizeof(struct SwsContext));
528
    if (!ctx) {
529
        av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
530

    
531
        return NULL;
532
    }
533
    ctx->av_class = &context_class;
534

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

    
550
    return ctx;
551
}
552

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

    
566

    
567
/**
568
 * Checks if context is valid or reallocs a new one instead.
569
 * If context is NULL, just calls sws_getContext() to get a new one.
570
 * Otherwise, checks if the parameters are the same already saved in context.
571
 * If that is the case, returns the current context.
572
 * Otherwise, frees context and gets a new one.
573
 *
574
 * Be warned that srcFilter, dstFilter are not checked, they are
575
 * asumed to remain valid.
576
 */
577
struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
578
                        int srcW, int srcH, int srcFormat,
579
                        int dstW, int dstH, int dstFormat, int flags,
580
                        SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
581
{
582
    if (ctx != NULL) {
583
        if ((ctx->resampling_ctx->iwidth != srcW) ||
584
                        (ctx->resampling_ctx->iheight != srcH) ||
585
                        (ctx->src_pix_fmt != srcFormat) ||
586
                        (ctx->resampling_ctx->owidth != dstW) ||
587
                        (ctx->resampling_ctx->oheight != dstH) ||
588
                        (ctx->dst_pix_fmt != dstFormat))
589
        {
590
            sws_freeContext(ctx);
591
            ctx = NULL;
592
        }
593
    }
594
    if (ctx == NULL) {
595
        return sws_getContext(srcW, srcH, srcFormat,
596
                        dstW, dstH, dstFormat, flags,
597
                        srcFilter, dstFilter, param);
598
    }
599
    return ctx;
600
}
601

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

    
612
    for (i = 0; i < 4; i++) {
613
        src_pict.data[i] = src[i];
614
        src_pict.linesize[i] = srcStride[i];
615
        dst_pict.data[i] = dst[i];
616
        dst_pict.linesize[i] = dstStride[i];
617
    }
618
    if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
619
        (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
620
        /* We have to rescale the picture, but only YUV420P rescaling is supported... */
621

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

    
625
            /* create temporary picture for rescaling input*/
626
            size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
627
            buf1 = av_malloc(size);
628
            if (!buf1) {
629
                res = -1;
630
                goto the_end;
631
            }
632
            formatted_picture = &picture_format_temp;
633
            avpicture_fill((AVPicture*)formatted_picture, buf1,
634
                           PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
635

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

    
640
                av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
641
                res = -1;
642
                goto the_end;
643
            }
644
        } else {
645
            formatted_picture = &src_pict;
646
        }
647

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

    
651
            /* create temporary picture for rescaling output*/
652
            size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
653
            buf2 = av_malloc(size);
654
            if (!buf2) {
655
                res = -1;
656
                goto the_end;
657
            }
658
            resampled_picture = &picture_resample_temp;
659
            avpicture_fill((AVPicture*)resampled_picture, buf2,
660
                           PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
661

    
662
        } else {
663
            resampled_picture = &dst_pict;
664
        }
665

    
666
        /* ...and finally rescale!!! */
667
        img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
668
        current_pix_fmt = PIX_FMT_YUV420P;
669
    } else {
670
        resampled_picture = &src_pict;
671
        current_pix_fmt = ctx->src_pix_fmt;
672
    }
673

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

    
679
            av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
680

    
681
            res = -1;
682
            goto the_end;
683
        }
684
    } else if (resampled_picture != &dst_pict) {
685
        av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
686
                        ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
687
    }
688

    
689
the_end:
690
    av_free(buf1);
691
    av_free(buf2);
692
    return res;
693
}
694

    
695

    
696
#ifdef TEST
697
#include <stdio.h>
698
#undef exit
699

    
700
/* input */
701
#define XSIZE 256
702
#define YSIZE 256
703
uint8_t img[XSIZE * YSIZE];
704

    
705
/* output */
706
#define XSIZE1 512
707
#define YSIZE1 512
708
uint8_t img1[XSIZE1 * YSIZE1];
709
uint8_t img2[XSIZE1 * YSIZE1];
710

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

    
722
static void dump_filter(int16_t *filter)
723
{
724
    int i, ph;
725

    
726
    for(ph=0;ph<NB_PHASES;ph++) {
727
        av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
728
        for(i=0;i<NB_TAPS;i++) {
729
            av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
730
        }
731
        av_log(NULL, AV_LOG_INFO, "\n");
732
    }
733
}
734

    
735
#ifdef HAVE_MMX
736
int mm_flags;
737
#endif
738

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

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

    
802
        snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
803
        save_pgm(buf, img1, xsize, ysize);
804
    }
805

    
806
    /* mmx test */
807
#ifdef HAVE_MMX
808
    av_log(NULL, AV_LOG_INFO, "MMX test\n");
809
    fact = 0.72;
810
    xsize = (int)(XSIZE * fact);
811
    ysize = (int)(YSIZE * fact);
812
    mm_flags = FF_MM_MMX;
813
    s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
814
    component_resample(s, img1, xsize, xsize, ysize,
815
                       img, XSIZE, XSIZE, YSIZE);
816

    
817
    mm_flags = 0;
818
    s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
819
    component_resample(s, img2, xsize, xsize, ysize,
820
                       img, XSIZE, XSIZE, YSIZE);
821
    if (memcmp(img1, img2, xsize * ysize) != 0) {
822
        av_log(NULL, AV_LOG_ERROR, "mmx error\n");
823
        exit(1);
824
    }
825
    av_log(NULL, AV_LOG_INFO, "MMX OK\n");
826
#endif /* HAVE_MMX */
827
    return 0;
828
}
829

    
830
#endif /* TEST */