• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/imgresample.c

Go to the documentation of this file.
00001 /*
00002  * High quality image resampling with polyphase filters
00003  * Copyright (c) 2001 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00030 #include "avcodec.h"
00031 #include "dsputil.h"
00032 #include "imgconvert.h"
00033 #include "libswscale/swscale.h"
00034 
00035 #if HAVE_ALTIVEC
00036 #include "ppc/imgresample_altivec.h"
00037 #endif
00038 
00039 #define NB_COMPONENTS 3
00040 
00041 #define PHASE_BITS 4
00042 #define NB_PHASES  (1 << PHASE_BITS)
00043 #define NB_TAPS    4
00044 #define FCENTER    1  /* index of the center of the filter */
00045 //#define TEST    1  /* Test it */
00046 
00047 #define POS_FRAC_BITS 16
00048 #define POS_FRAC      (1 << POS_FRAC_BITS)
00049 /* 6 bits precision is needed for MMX */
00050 #define FILTER_BITS   8
00051 
00052 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
00053 
00054 struct SwsContext {
00055     const AVClass *av_class;
00056     struct ImgReSampleContext *resampling_ctx;
00057     enum PixelFormat src_pix_fmt, dst_pix_fmt;
00058 };
00059 
00060 typedef struct ImgReSampleContext {
00061     int iwidth, iheight, owidth, oheight;
00062     int topBand, bottomBand, leftBand, rightBand;
00063     int padtop, padbottom, padleft, padright;
00064     int pad_owidth, pad_oheight;
00065     int h_incr, v_incr;
00066     DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
00067     DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
00068     uint8_t *line_buf;
00069 } ImgReSampleContext;
00070 
00071 void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
00072 
00073 static inline int get_phase(int pos)
00074 {
00075     return ((pos) >> (POS_FRAC_BITS - PHASE_BITS)) & ((1 << PHASE_BITS) - 1);
00076 }
00077 
00078 /* This function must be optimized */
00079 static void h_resample_fast(uint8_t *dst, int dst_width, const uint8_t *src,
00080                             int src_width, int src_start, int src_incr,
00081                             int16_t *filters)
00082 {
00083     int src_pos, phase, sum, i;
00084     const uint8_t *s;
00085     int16_t *filter;
00086 
00087     src_pos = src_start;
00088     for(i=0;i<dst_width;i++) {
00089 #ifdef TEST
00090         /* test */
00091         if ((src_pos >> POS_FRAC_BITS) < 0 ||
00092             (src_pos >> POS_FRAC_BITS) > (src_width - NB_TAPS))
00093             av_abort();
00094 #endif
00095         s = src + (src_pos >> POS_FRAC_BITS);
00096         phase = get_phase(src_pos);
00097         filter = filters + phase * NB_TAPS;
00098 #if NB_TAPS == 4
00099         sum = s[0] * filter[0] +
00100             s[1] * filter[1] +
00101             s[2] * filter[2] +
00102             s[3] * filter[3];
00103 #else
00104         {
00105             int j;
00106             sum = 0;
00107             for(j=0;j<NB_TAPS;j++)
00108                 sum += s[j] * filter[j];
00109         }
00110 #endif
00111         sum = sum >> FILTER_BITS;
00112         if (sum < 0)
00113             sum = 0;
00114         else if (sum > 255)
00115             sum = 255;
00116         dst[0] = sum;
00117         src_pos += src_incr;
00118         dst++;
00119     }
00120 }
00121 
00122 /* This function must be optimized */
00123 static void v_resample(uint8_t *dst, int dst_width, const uint8_t *src,
00124                        int wrap, int16_t *filter)
00125 {
00126     int sum, i;
00127     const uint8_t *s;
00128 
00129     s = src;
00130     for(i=0;i<dst_width;i++) {
00131 #if NB_TAPS == 4
00132         sum = s[0 * wrap] * filter[0] +
00133             s[1 * wrap] * filter[1] +
00134             s[2 * wrap] * filter[2] +
00135             s[3 * wrap] * filter[3];
00136 #else
00137         {
00138             int j;
00139             uint8_t *s1 = s;
00140 
00141             sum = 0;
00142             for(j=0;j<NB_TAPS;j++) {
00143                 sum += s1[0] * filter[j];
00144                 s1 += wrap;
00145             }
00146         }
00147 #endif
00148         sum = sum >> FILTER_BITS;
00149         if (sum < 0)
00150             sum = 0;
00151         else if (sum > 255)
00152             sum = 255;
00153         dst[0] = sum;
00154         dst++;
00155         s++;
00156     }
00157 }
00158 
00159 #if HAVE_MMX
00160 
00161 #include "x86/mmx.h"
00162 
00163 #define FILTER4(reg) \
00164 {\
00165         s = src + (src_pos >> POS_FRAC_BITS);\
00166         phase = get_phase(src_pos);\
00167         filter = filters + phase * NB_TAPS;\
00168         movq_m2r(*s, reg);\
00169         punpcklbw_r2r(mm7, reg);\
00170         movq_m2r(*filter, mm6);\
00171         pmaddwd_r2r(reg, mm6);\
00172         movq_r2r(mm6, reg);\
00173         psrlq_i2r(32, reg);\
00174         paddd_r2r(mm6, reg);\
00175         psrad_i2r(FILTER_BITS, reg);\
00176         src_pos += src_incr;\
00177 }
00178 
00179 #define DUMP(reg) movq_r2m(reg, tmp); printf(#reg "=%016"PRIx64"\n", tmp.uq);
00180 
00181 /* XXX: do four pixels at a time */
00182 static void h_resample_fast4_mmx(uint8_t *dst, int dst_width,
00183                                  const uint8_t *src, int src_width,
00184                                  int src_start, int src_incr, int16_t *filters)
00185 {
00186     int src_pos, phase;
00187     const uint8_t *s;
00188     int16_t *filter;
00189     uint64_t tmp;
00190 
00191     src_pos = src_start;
00192     pxor_r2r(mm7, mm7);
00193 
00194     while (dst_width >= 4) {
00195 
00196         FILTER4(mm0);
00197         FILTER4(mm1);
00198         FILTER4(mm2);
00199         FILTER4(mm3);
00200 
00201         packuswb_r2r(mm7, mm0);
00202         packuswb_r2r(mm7, mm1);
00203         packuswb_r2r(mm7, mm3);
00204         packuswb_r2r(mm7, mm2);
00205         movq_r2m(mm0, tmp);
00206         dst[0] = tmp & 0xFF;
00207         movq_r2m(mm1, tmp);
00208         dst[1] = tmp & 0xFF;
00209         movq_r2m(mm2, tmp);
00210         dst[2] = tmp & 0xFF;
00211         movq_r2m(mm3, tmp);
00212         dst[3] = tmp & 0xFF;
00213         dst += 4;
00214         dst_width -= 4;
00215     }
00216     while (dst_width > 0) {
00217         FILTER4(mm0);
00218         packuswb_r2r(mm7, mm0);
00219         movq_r2m(mm0, tmp);
00220         dst[0] = tmp & 0xFF;
00221         dst++;
00222         dst_width--;
00223     }
00224     emms();
00225 }
00226 
00227 static void v_resample4_mmx(uint8_t *dst, int dst_width, const uint8_t *src,
00228                             int wrap, int16_t *filter)
00229 {
00230     int sum, i;
00231     const uint8_t *s;
00232     uint64_t tmp;
00233     uint64_t coefs[4];
00234 
00235     for(i=0;i<4;i++) {
00236         tmp = filter[i];
00237         coefs[i] = (tmp<<48) + (tmp<<32) + (tmp<<16) + tmp;
00238     }
00239 
00240     pxor_r2r(mm7, mm7);
00241     s = src;
00242     while (dst_width >= 4) {
00243         movq_m2r(s[0 * wrap], mm0);
00244         punpcklbw_r2r(mm7, mm0);
00245         movq_m2r(s[1 * wrap], mm1);
00246         punpcklbw_r2r(mm7, mm1);
00247         movq_m2r(s[2 * wrap], mm2);
00248         punpcklbw_r2r(mm7, mm2);
00249         movq_m2r(s[3 * wrap], mm3);
00250         punpcklbw_r2r(mm7, mm3);
00251 
00252         pmullw_m2r(coefs[0], mm0);
00253         pmullw_m2r(coefs[1], mm1);
00254         pmullw_m2r(coefs[2], mm2);
00255         pmullw_m2r(coefs[3], mm3);
00256 
00257         paddw_r2r(mm1, mm0);
00258         paddw_r2r(mm3, mm2);
00259         paddw_r2r(mm2, mm0);
00260         psraw_i2r(FILTER_BITS, mm0);
00261 
00262         packuswb_r2r(mm7, mm0);
00263         movq_r2m(mm0, tmp);
00264 
00265         *(uint32_t *)dst = tmp & 0xFFFFFFFF;
00266         dst += 4;
00267         s += 4;
00268         dst_width -= 4;
00269     }
00270     while (dst_width > 0) {
00271         sum = s[0 * wrap] * filter[0] +
00272             s[1 * wrap] * filter[1] +
00273             s[2 * wrap] * filter[2] +
00274             s[3 * wrap] * filter[3];
00275         sum = sum >> FILTER_BITS;
00276         if (sum < 0)
00277             sum = 0;
00278         else if (sum > 255)
00279             sum = 255;
00280         dst[0] = sum;
00281         dst++;
00282         s++;
00283         dst_width--;
00284     }
00285     emms();
00286 }
00287 #endif /* HAVE_MMX */
00288 
00289 /* slow version to handle limit cases. Does not need optimization */
00290 static void h_resample_slow(uint8_t *dst, int dst_width,
00291                             const uint8_t *src, int src_width,
00292                             int src_start, int src_incr, int16_t *filters)
00293 {
00294     int src_pos, phase, sum, j, v, i;
00295     const uint8_t *s, *src_end;
00296     int16_t *filter;
00297 
00298     src_end = src + src_width;
00299     src_pos = src_start;
00300     for(i=0;i<dst_width;i++) {
00301         s = src + (src_pos >> POS_FRAC_BITS);
00302         phase = get_phase(src_pos);
00303         filter = filters + phase * NB_TAPS;
00304         sum = 0;
00305         for(j=0;j<NB_TAPS;j++) {
00306             if (s < src)
00307                 v = src[0];
00308             else if (s >= src_end)
00309                 v = src_end[-1];
00310             else
00311                 v = s[0];
00312             sum += v * filter[j];
00313             s++;
00314         }
00315         sum = sum >> FILTER_BITS;
00316         if (sum < 0)
00317             sum = 0;
00318         else if (sum > 255)
00319             sum = 255;
00320         dst[0] = sum;
00321         src_pos += src_incr;
00322         dst++;
00323     }
00324 }
00325 
00326 static void h_resample(uint8_t *dst, int dst_width, const uint8_t *src,
00327                        int src_width, int src_start, int src_incr,
00328                        int16_t *filters)
00329 {
00330     int n, src_end;
00331 
00332     if (src_start < 0) {
00333         n = (0 - src_start + src_incr - 1) / src_incr;
00334         h_resample_slow(dst, n, src, src_width, src_start, src_incr, filters);
00335         dst += n;
00336         dst_width -= n;
00337         src_start += n * src_incr;
00338     }
00339     src_end = src_start + dst_width * src_incr;
00340     if (src_end > ((src_width - NB_TAPS) << POS_FRAC_BITS)) {
00341         n = (((src_width - NB_TAPS + 1) << POS_FRAC_BITS) - 1 - src_start) /
00342             src_incr;
00343     } else {
00344         n = dst_width;
00345     }
00346 #if HAVE_MMX
00347     if ((mm_flags & FF_MM_MMX) && NB_TAPS == 4)
00348         h_resample_fast4_mmx(dst, n,
00349                              src, src_width, src_start, src_incr, filters);
00350     else
00351 #endif
00352         h_resample_fast(dst, n,
00353                         src, src_width, src_start, src_incr, filters);
00354     if (n < dst_width) {
00355         dst += n;
00356         dst_width -= n;
00357         src_start += n * src_incr;
00358         h_resample_slow(dst, dst_width,
00359                         src, src_width, src_start, src_incr, filters);
00360     }
00361 }
00362 
00363 static void component_resample(ImgReSampleContext *s,
00364                                uint8_t *output, int owrap, int owidth, int oheight,
00365                                uint8_t *input, int iwrap, int iwidth, int iheight)
00366 {
00367     int src_y, src_y1, last_src_y, ring_y, phase_y, y1, y;
00368     uint8_t *new_line, *src_line;
00369 
00370     last_src_y = - FCENTER - 1;
00371     /* position of the bottom of the filter in the source image */
00372     src_y = (last_src_y + NB_TAPS) * POS_FRAC;
00373     ring_y = NB_TAPS; /* position in ring buffer */
00374     for(y=0;y<oheight;y++) {
00375         /* apply horizontal filter on new lines from input if needed */
00376         src_y1 = src_y >> POS_FRAC_BITS;
00377         while (last_src_y < src_y1) {
00378             if (++ring_y >= LINE_BUF_HEIGHT + NB_TAPS)
00379                 ring_y = NB_TAPS;
00380             last_src_y++;
00381             /* handle limit conditions : replicate line (slightly
00382                inefficient because we filter multiple times) */
00383             y1 = last_src_y;
00384             if (y1 < 0) {
00385                 y1 = 0;
00386             } else if (y1 >= iheight) {
00387                 y1 = iheight - 1;
00388             }
00389             src_line = input + y1 * iwrap;
00390             new_line = s->line_buf + ring_y * owidth;
00391             /* apply filter and handle limit cases correctly */
00392             h_resample(new_line, owidth,
00393                        src_line, iwidth, - FCENTER * POS_FRAC, s->h_incr,
00394                        &s->h_filters[0][0]);
00395             /* handle ring buffer wrapping */
00396             if (ring_y >= LINE_BUF_HEIGHT) {
00397                 memcpy(s->line_buf + (ring_y - LINE_BUF_HEIGHT) * owidth,
00398                        new_line, owidth);
00399             }
00400         }
00401         /* apply vertical filter */
00402         phase_y = get_phase(src_y);
00403 #if HAVE_MMX
00404         /* desactivated MMX because loss of precision */
00405         if ((mm_flags & FF_MM_MMX) && NB_TAPS == 4 && 0)
00406             v_resample4_mmx(output, owidth,
00407                             s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
00408                             &s->v_filters[phase_y][0]);
00409         else
00410 #endif
00411 #if HAVE_ALTIVEC
00412         if ((mm_flags & FF_MM_ALTIVEC) && NB_TAPS == 4 && FILTER_BITS <= 6)
00413             v_resample16_altivec(output, owidth,
00414                                  s->line_buf + (ring_y - NB_TAPS + 1) * owidth,
00415                                  owidth, &s->v_filters[phase_y][0]);
00416         else
00417 #endif
00418             v_resample(output, owidth,
00419                        s->line_buf + (ring_y - NB_TAPS + 1) * owidth, owidth,
00420                        &s->v_filters[phase_y][0]);
00421 
00422         src_y += s->v_incr;
00423 
00424         output += owrap;
00425     }
00426 }
00427 
00428 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
00429                                       int iwidth, int iheight,
00430                                       int topBand, int bottomBand,
00431         int leftBand, int rightBand,
00432         int padtop, int padbottom,
00433         int padleft, int padright)
00434 {
00435     ImgReSampleContext *s;
00436 
00437     if (!owidth || !oheight || !iwidth || !iheight)
00438         return NULL;
00439 
00440     s = av_mallocz(sizeof(ImgReSampleContext));
00441     if (!s)
00442         return NULL;
00443     if((unsigned)owidth >= UINT_MAX / (LINE_BUF_HEIGHT + NB_TAPS))
00444         goto fail;
00445     s->line_buf = av_mallocz(owidth * (LINE_BUF_HEIGHT + NB_TAPS));
00446     if (!s->line_buf)
00447         goto fail;
00448 
00449     s->owidth = owidth;
00450     s->oheight = oheight;
00451     s->iwidth = iwidth;
00452     s->iheight = iheight;
00453 
00454     s->topBand = topBand;
00455     s->bottomBand = bottomBand;
00456     s->leftBand = leftBand;
00457     s->rightBand = rightBand;
00458 
00459     s->padtop = padtop;
00460     s->padbottom = padbottom;
00461     s->padleft = padleft;
00462     s->padright = padright;
00463 
00464     s->pad_owidth = owidth - (padleft + padright);
00465     s->pad_oheight = oheight - (padtop + padbottom);
00466 
00467     s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
00468     s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight;
00469 
00470     av_build_filter(&s->h_filters[0][0], (float) s->pad_owidth  /
00471             (float) (iwidth - leftBand - rightBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
00472     av_build_filter(&s->v_filters[0][0], (float) s->pad_oheight /
00473             (float) (iheight - topBand - bottomBand), NB_TAPS, NB_PHASES, 1<<FILTER_BITS, 0);
00474 
00475     return s;
00476 fail:
00477     av_free(s);
00478     return NULL;
00479 }
00480 
00481 ImgReSampleContext *img_resample_init(int owidth, int oheight,
00482                                       int iwidth, int iheight)
00483 {
00484     return img_resample_full_init(owidth, oheight, iwidth, iheight,
00485             0, 0, 0, 0, 0, 0, 0, 0);
00486 }
00487 
00488 void img_resample(ImgReSampleContext *s,
00489                   AVPicture *output, const AVPicture *input)
00490 {
00491     int i, shift;
00492     uint8_t* optr;
00493 
00494     for (i=0;i<3;i++) {
00495         shift = (i == 0) ? 0 : 1;
00496 
00497         optr = output->data[i] + (((output->linesize[i] *
00498                         s->padtop) + s->padleft) >> shift);
00499 
00500         component_resample(s, optr, output->linesize[i],
00501                 s->pad_owidth >> shift, s->pad_oheight >> shift,
00502                 input->data[i] + (input->linesize[i] *
00503                     (s->topBand >> shift)) + (s->leftBand >> shift),
00504                 input->linesize[i], ((s->iwidth - s->leftBand -
00505                         s->rightBand) >> shift),
00506                            (s->iheight - s->topBand - s->bottomBand) >> shift);
00507     }
00508 }
00509 
00510 void img_resample_close(ImgReSampleContext *s)
00511 {
00512     av_free(s->line_buf);
00513     av_free(s);
00514 }
00515 
00516 static const char *context_to_name(void* ptr)
00517 {
00518     return "imgconvert";
00519 }
00520 
00521 static const AVClass context_class = { "imgresample", context_to_name, NULL };
00522 
00523 struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat,
00524                                   int dstW, int dstH, int dstFormat,
00525                                   int flags, SwsFilter *srcFilter,
00526                                   SwsFilter *dstFilter, double *param)
00527 {
00528     struct SwsContext *ctx;
00529 
00530     ctx = av_malloc(sizeof(struct SwsContext));
00531     if (!ctx) {
00532         av_log(NULL, AV_LOG_ERROR, "Cannot allocate a resampling context!\n");
00533 
00534         return NULL;
00535     }
00536     ctx->av_class = &context_class;
00537 
00538     if ((srcH != dstH) || (srcW != dstW)) {
00539         if ((srcFormat != PIX_FMT_YUV420P) || (dstFormat != PIX_FMT_YUV420P)) {
00540             av_log(ctx, AV_LOG_INFO, "PIX_FMT_YUV420P will be used as an intermediate format for rescaling\n");
00541         }
00542         ctx->resampling_ctx = img_resample_init(dstW, dstH, srcW, srcH);
00543     } else {
00544         ctx->resampling_ctx = av_malloc(sizeof(ImgReSampleContext));
00545         ctx->resampling_ctx->iheight = srcH;
00546         ctx->resampling_ctx->iwidth = srcW;
00547         ctx->resampling_ctx->oheight = dstH;
00548         ctx->resampling_ctx->owidth = dstW;
00549     }
00550     ctx->src_pix_fmt = srcFormat;
00551     ctx->dst_pix_fmt = dstFormat;
00552 
00553     return ctx;
00554 }
00555 
00556 void sws_freeContext(struct SwsContext *ctx)
00557 {
00558     if (!ctx)
00559         return;
00560     if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
00561         (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
00562         img_resample_close(ctx->resampling_ctx);
00563     } else {
00564         av_free(ctx->resampling_ctx);
00565     }
00566     av_free(ctx);
00567 }
00568 
00569 
00580 struct SwsContext *sws_getCachedContext(struct SwsContext *ctx,
00581                         int srcW, int srcH, int srcFormat,
00582                         int dstW, int dstH, int dstFormat, int flags,
00583                         SwsFilter *srcFilter, SwsFilter *dstFilter, double *param)
00584 {
00585     if (ctx != NULL) {
00586         if ((ctx->resampling_ctx->iwidth != srcW) ||
00587                         (ctx->resampling_ctx->iheight != srcH) ||
00588                         (ctx->src_pix_fmt != srcFormat) ||
00589                         (ctx->resampling_ctx->owidth != dstW) ||
00590                         (ctx->resampling_ctx->oheight != dstH) ||
00591                         (ctx->dst_pix_fmt != dstFormat))
00592         {
00593             sws_freeContext(ctx);
00594             ctx = NULL;
00595         }
00596     }
00597     if (ctx == NULL) {
00598         return sws_getContext(srcW, srcH, srcFormat,
00599                         dstW, dstH, dstFormat, flags,
00600                         srcFilter, dstFilter, param);
00601     }
00602     return ctx;
00603 }
00604 
00605 int sws_scale(struct SwsContext *ctx, uint8_t* src[], int srcStride[],
00606               int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[])
00607 {
00608     AVPicture src_pict, dst_pict;
00609     int i, res = 0;
00610     AVPicture picture_format_temp;
00611     AVPicture picture_resample_temp, *formatted_picture, *resampled_picture;
00612     uint8_t *buf1 = NULL, *buf2 = NULL;
00613     enum PixelFormat current_pix_fmt;
00614 
00615     for (i = 0; i < 4; i++) {
00616         src_pict.data[i] = src[i];
00617         src_pict.linesize[i] = srcStride[i];
00618         dst_pict.data[i] = dst[i];
00619         dst_pict.linesize[i] = dstStride[i];
00620     }
00621     if ((ctx->resampling_ctx->iwidth != ctx->resampling_ctx->owidth) ||
00622         (ctx->resampling_ctx->iheight != ctx->resampling_ctx->oheight)) {
00623         /* We have to rescale the picture, but only YUV420P rescaling is supported... */
00624 
00625         if (ctx->src_pix_fmt != PIX_FMT_YUV420P) {
00626             int size;
00627 
00628             /* create temporary picture for rescaling input*/
00629             size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
00630             buf1 = av_malloc(size);
00631             if (!buf1) {
00632                 res = -1;
00633                 goto the_end;
00634             }
00635             formatted_picture = &picture_format_temp;
00636             avpicture_fill((AVPicture*)formatted_picture, buf1,
00637                            PIX_FMT_YUV420P, ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight);
00638 
00639             if (img_convert((AVPicture*)formatted_picture, PIX_FMT_YUV420P,
00640                             &src_pict, ctx->src_pix_fmt,
00641                             ctx->resampling_ctx->iwidth, ctx->resampling_ctx->iheight) < 0) {
00642 
00643                 av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
00644                 res = -1;
00645                 goto the_end;
00646             }
00647         } else {
00648             formatted_picture = &src_pict;
00649         }
00650 
00651         if (ctx->dst_pix_fmt != PIX_FMT_YUV420P) {
00652             int size;
00653 
00654             /* create temporary picture for rescaling output*/
00655             size = avpicture_get_size(PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
00656             buf2 = av_malloc(size);
00657             if (!buf2) {
00658                 res = -1;
00659                 goto the_end;
00660             }
00661             resampled_picture = &picture_resample_temp;
00662             avpicture_fill((AVPicture*)resampled_picture, buf2,
00663                            PIX_FMT_YUV420P, ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
00664 
00665         } else {
00666             resampled_picture = &dst_pict;
00667         }
00668 
00669         /* ...and finally rescale!!! */
00670         img_resample(ctx->resampling_ctx, resampled_picture, formatted_picture);
00671         current_pix_fmt = PIX_FMT_YUV420P;
00672     } else {
00673         resampled_picture = &src_pict;
00674         current_pix_fmt = ctx->src_pix_fmt;
00675     }
00676 
00677     if (current_pix_fmt != ctx->dst_pix_fmt) {
00678         if (img_convert(&dst_pict, ctx->dst_pix_fmt,
00679                         resampled_picture, current_pix_fmt,
00680                         ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight) < 0) {
00681 
00682             av_log(ctx, AV_LOG_ERROR, "pixel format conversion not handled\n");
00683 
00684             res = -1;
00685             goto the_end;
00686         }
00687     } else if (resampled_picture != &dst_pict) {
00688         av_picture_copy(&dst_pict, resampled_picture, current_pix_fmt,
00689                         ctx->resampling_ctx->owidth, ctx->resampling_ctx->oheight);
00690     }
00691 
00692 the_end:
00693     av_free(buf1);
00694     av_free(buf2);
00695     return res;
00696 }
00697 
00698 
00699 #ifdef TEST
00700 #include <stdio.h>
00701 #undef exit
00702 
00703 /* input */
00704 #define XSIZE 256
00705 #define YSIZE 256
00706 uint8_t img[XSIZE * YSIZE];
00707 
00708 /* output */
00709 #define XSIZE1 512
00710 #define YSIZE1 512
00711 uint8_t img1[XSIZE1 * YSIZE1];
00712 uint8_t img2[XSIZE1 * YSIZE1];
00713 
00714 void save_pgm(const char *filename, uint8_t *img, int xsize, int ysize)
00715 {
00716 #undef fprintf
00717     FILE *f;
00718     f=fopen(filename,"w");
00719     fprintf(f,"P5\n%d %d\n%d\n", xsize, ysize, 255);
00720     fwrite(img,1, xsize * ysize,f);
00721     fclose(f);
00722 #define fprintf please_use_av_log
00723 }
00724 
00725 static void dump_filter(int16_t *filter)
00726 {
00727     int i, ph;
00728 
00729     for(ph=0;ph<NB_PHASES;ph++) {
00730         av_log(NULL, AV_LOG_INFO, "%2d: ", ph);
00731         for(i=0;i<NB_TAPS;i++) {
00732             av_log(NULL, AV_LOG_INFO, " %5.2f", filter[ph * NB_TAPS + i] / 256.0);
00733         }
00734         av_log(NULL, AV_LOG_INFO, "\n");
00735     }
00736 }
00737 
00738 #if HAVE_MMX
00739 int mm_flags;
00740 #endif
00741 
00742 int main(int argc, char **argv)
00743 {
00744     int x, y, v, i, xsize, ysize;
00745     ImgReSampleContext *s;
00746     float fact, factors[] = { 1/2.0, 3.0/4.0, 1.0, 4.0/3.0, 16.0/9.0, 2.0 };
00747     char buf[256];
00748 
00749     /* build test image */
00750     for(y=0;y<YSIZE;y++) {
00751         for(x=0;x<XSIZE;x++) {
00752             if (x < XSIZE/2 && y < YSIZE/2) {
00753                 if (x < XSIZE/4 && y < YSIZE/4) {
00754                     if ((x % 10) <= 6 &&
00755                         (y % 10) <= 6)
00756                         v = 0xff;
00757                     else
00758                         v = 0x00;
00759                 } else if (x < XSIZE/4) {
00760                     if (x & 1)
00761                         v = 0xff;
00762                     else
00763                         v = 0;
00764                 } else if (y < XSIZE/4) {
00765                     if (y & 1)
00766                         v = 0xff;
00767                     else
00768                         v = 0;
00769                 } else {
00770                     if (y < YSIZE*3/8) {
00771                         if ((y+x) & 1)
00772                             v = 0xff;
00773                         else
00774                             v = 0;
00775                     } else {
00776                         if (((x+3) % 4) <= 1 &&
00777                             ((y+3) % 4) <= 1)
00778                             v = 0xff;
00779                         else
00780                             v = 0x00;
00781                     }
00782                 }
00783             } else if (x < XSIZE/2) {
00784                 v = ((x - (XSIZE/2)) * 255) / (XSIZE/2);
00785             } else if (y < XSIZE/2) {
00786                 v = ((y - (XSIZE/2)) * 255) / (XSIZE/2);
00787             } else {
00788                 v = ((x + y - XSIZE) * 255) / XSIZE;
00789             }
00790             img[(YSIZE - y) * XSIZE + (XSIZE - x)] = v;
00791         }
00792     }
00793     save_pgm("/tmp/in.pgm", img, XSIZE, YSIZE);
00794     for(i=0;i<FF_ARRAY_ELEMS(factors);i++) {
00795         fact = factors[i];
00796         xsize = (int)(XSIZE * fact);
00797         ysize = (int)((YSIZE - 100) * fact);
00798         s = img_resample_full_init(xsize, ysize, XSIZE, YSIZE, 50 ,50, 0, 0, 0, 0, 0, 0);
00799         av_log(NULL, AV_LOG_INFO, "Factor=%0.2f\n", fact);
00800         dump_filter(&s->h_filters[0][0]);
00801         component_resample(s, img1, xsize, xsize, ysize,
00802                            img + 50 * XSIZE, XSIZE, XSIZE, YSIZE - 100);
00803         img_resample_close(s);
00804 
00805         snprintf(buf, sizeof(buf), "/tmp/out%d.pgm", i);
00806         save_pgm(buf, img1, xsize, ysize);
00807     }
00808 
00809     /* mmx test */
00810 #if HAVE_MMX
00811     av_log(NULL, AV_LOG_INFO, "MMX test\n");
00812     fact = 0.72;
00813     xsize = (int)(XSIZE * fact);
00814     ysize = (int)(YSIZE * fact);
00815     mm_flags = FF_MM_MMX;
00816     s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
00817     component_resample(s, img1, xsize, xsize, ysize,
00818                        img, XSIZE, XSIZE, YSIZE);
00819 
00820     mm_flags = 0;
00821     s = img_resample_init(xsize, ysize, XSIZE, YSIZE);
00822     component_resample(s, img2, xsize, xsize, ysize,
00823                        img, XSIZE, XSIZE, YSIZE);
00824     if (memcmp(img1, img2, xsize * ysize) != 0) {
00825         av_log(NULL, AV_LOG_ERROR, "mmx error\n");
00826         exit(1);
00827     }
00828     av_log(NULL, AV_LOG_INFO, "MMX OK\n");
00829 #endif /* HAVE_MMX */
00830     return 0;
00831 }
00832 
00833 #endif /* TEST */

Generated on Sat Feb 16 2013 09:23:12 for ffmpeg by  doxygen 1.7.1