video_util_resize.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:15k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  *      Filtered Image Rescaling
  3.  *
  4. Additional changes by Ray Gardener, Daylon Graphics Ltd.
  5. December 4, 1999
  6. Summary:
  7.     - Horizontal filter contributions are calculated on the fly,
  8.       as each column is mapped from src to dst image. This lets 
  9.       us omit having to allocate a temporary full horizontal stretch 
  10.       of the src image.
  11.     - If none of the src pixels within a sampling region differ, 
  12.       then the output pixel is forced to equal (any of) the source pixel.
  13.       This ensures that filters do not corrupt areas of constant color.
  14.     - Filter weight contribution results, after summing, are 
  15.       rounded to the nearest pixel color value instead of 
  16.       being casted to Pixel (usually an int or char). Otherwise, 
  17.       artifacting occurs. 
  18.     - All memory allocations checked for failure; scale() returns 
  19.       error code. new_image() returns NULL if unable to allocate 
  20.       pixel storage, even if Image struct can be allocated.
  21.       Some assertions added.
  22.     - load_image(), save_image() take filenames, not file handles.
  23.     - TGA bitmap format available. If you want to add a filetype, 
  24.       extend the gImageHandlers array, and factor in your load_image_xxx()
  25.       and save_image_xxx() functions. Search for string 'add your' 
  26.       to find appropriate code locations.
  27.     - The 'input' and 'output' command-line arguments do not have 
  28.       to specify .bm files; any supported filetype is okay.
  29.     - Added implementation of getopt() if compiling under Windows.
  30. */
  31. #include "mp4live.h"
  32. #include "video_util_resize.h"
  33. #ifndef M_PI
  34. #define M_PI 3.14159265358979323846
  35. #endif
  36. #define WHITE_PIXEL (255)
  37. #define BLACK_PIXEL (0)
  38. #define CLAMP(v) (((v) < (BLACK_PIXEL)) ? 
  39.                   (BLACK_PIXEL) :  
  40.                   (((v) > (WHITE_PIXEL)) ? (WHITE_PIXEL) : (v)))
  41. #define get_pixel(image, y, x) ((image)->data[(x) + (y) * image->span])
  42. #define put_pixel(image, y, x, p) ((image)->data[(x) + (y) * image->span] = (p))
  43. /* Helper data structures: */
  44. typedef struct {
  45.     int pixel;
  46.     fixdouble   weight;
  47. } CONTRIB;
  48. typedef struct {
  49.     int n;      /* number of contributors */
  50.     CONTRIB *p;     /* pointer to list of contributions */
  51. } CLIST;
  52. void scale_setup_image(image_t *img, int w, int h, int depth, pixel_t *data)
  53. {
  54.     img->xsize = h;
  55.     img->ysize = w;
  56.     img->pixspan = depth;
  57.     img->span = w * depth;
  58.     img->data = data;
  59. }
  60. image_t *scale_new_image(int w, int h, int depth)  /* create a blank image */
  61. {
  62.     image_t *image;
  63.     if((image = (image_t *)malloc(sizeof(image_t))))
  64.     {
  65. image->xsize = h;
  66. image->ysize = w;
  67. image->span = w * depth;
  68.     image->pixspan = depth;
  69. image->data = NULL;
  70.     }
  71.     return image;
  72. }
  73. void scale_free_image(image_t *image)
  74. {
  75.     free(image);
  76. }
  77. /*
  78.  *  filter function definitions
  79.  */
  80. double Hermite_filter(double t)
  81. {
  82.     // f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 
  83.     if(t < 0.0) t = -t;
  84.     if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
  85.     return(0.0);
  86. }
  87. double Box_filter(double t)
  88. {
  89.     if((t > -0.5) && (t <= 0.5)) return(1.0);
  90.     return(0.0);
  91. }
  92. double Triangle_filter(double t)
  93. {
  94.     if(t < 0.0) t = -t;
  95.     if(t < 1.0) return(1.0 - t);
  96.     return(0.0);
  97. }
  98. double Bell_filter(double t)        /* box (*) box (*) box */
  99. {
  100.     if(t < 0) t = -t;
  101.     if(t < .5) return(.75 - (t * t));
  102.     if(t < 1.5) {
  103.         t = (t - 1.5);
  104.         return(.5 * (t * t));
  105.     }
  106.     return(0.0);
  107. }
  108. double B_spline_filter(double t)    /* box (*) box (*) box (*) box */
  109. {
  110.     double tt;
  111.     if(t < 0) t = -t;
  112.     if(t < 1) {
  113.         tt = t * t;
  114.         return((.5 * tt * t) - tt + (2.0 / 3.0));
  115.     } else if(t < 2) {
  116.         t = 2 - t;
  117.         return((1.0 / 6.0) * (t * t * t));
  118.     }
  119.     return(0.0);
  120. }
  121. static double sinc(double x)
  122. {
  123.     x *= M_PI;
  124.     if(x != 0) return(sin(x) / x);
  125.     return(1.0);
  126. }
  127. double Lanczos3_filter(double t)
  128. {
  129.     if(t < 0) t = -t;
  130.     if(t < 3.0) return(sinc(t) * sinc(t/3.0));
  131.     return(0.0);
  132. }
  133. #define B   (1.0 / 3.0)
  134. #define C   (1.0 / 3.0)
  135. double Mitchell_filter(double t)
  136. {
  137.     double tt;
  138.     tt = t * t;
  139.     if(t < 0) t = -t;
  140.     if(t < 1.0) {
  141.         t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt))
  142.            + ((-18.0 + 12.0 * B + 6.0 * C) * tt)
  143.            + (6.0 - 2 * B));
  144.         return(t / 6.0);
  145.     } else if(t < 2.0) {
  146.         t = (((-1.0 * B - 6.0 * C) * (t * tt))
  147.            + ((6.0 * B + 30.0 * C) * tt)
  148.            + ((-12.0 * B - 48.0 * C) * t)
  149.            + (8.0 * B + 24 * C));
  150.         return(t / 6.0);
  151.     }
  152.     return(0.0);
  153. }
  154. /*
  155.  *  image rescaling routine
  156.  */
  157. /* 
  158.   calc_x_contrib(
  159.     CLIST* contribX;            * Receiver of contrib info
  160.     double xscale;              * Horizontal scaling
  161.     double fwidth;              * Filter sampling width
  162.     int dstwidth;               * Target bitmap width
  163.     int srcwidth;               * Source bitmap width
  164.     double (*filterf)(double);  * Filter proc
  165.     int i;                      * pixel_t column in source bitmap being processed
  166.   )
  167.     Calculates the filter weights for a single target column.
  168.     contribX->p must be freed afterwards.
  169.     Returns -1 if error, 0 otherwise.
  170. */
  171. static int calc_x_contrib(CLIST* contribX, double xscale, double fwidth, int dstwidth, int srcwidth, 
  172.                    double (*filterf)(double), int i)
  173. {
  174.     double width;
  175.     double fscale;
  176.     double center, left, right;
  177.     double weight;
  178.     int j, k, n;
  179.     if(xscale < 1.0)
  180.     {
  181.         /* Shrinking image */
  182.         width = fwidth / xscale;
  183.         fscale = 1.0 / xscale;
  184.         contribX->n = 0;
  185.         contribX->p = (CONTRIB *)calloc((int) (width * 2 + 1),
  186.                 sizeof(CONTRIB));
  187.         if(contribX->p == NULL)
  188.             return -1;
  189.         center = (double) i / xscale;
  190.         left = ceil(center - width);
  191.         right = floor(center + width);
  192.         for(j = (int)left; j <= right; ++j)
  193.         {
  194.             weight = center - (double) j;
  195.             weight = (*filterf)(weight / fscale) / fscale;
  196.             if(j < 0)
  197.                 n = -j;
  198.             else if(j >= srcwidth)
  199.                 n = (srcwidth - j) + srcwidth - 1;
  200.             else
  201.                 n = j;
  202.             
  203.             k = contribX->n++;
  204.             contribX->p[k].pixel = n;
  205.             contribX->p[k].weight = double2fixdouble(weight);
  206.         }
  207.     
  208.     }
  209.     else
  210.     {
  211.         /* Expanding image */
  212.         contribX->n = 0;
  213.         contribX->p = (CONTRIB *)calloc((int) (fwidth * 2 + 1),
  214.                 sizeof(CONTRIB));
  215.         if(contribX->p == NULL)
  216.             return -1;
  217.         center = (double) i / xscale;
  218.         left = ceil(center - fwidth);
  219.         right = floor(center + fwidth);
  220.         for(j = (int)left; j <= right; ++j)
  221.         {
  222.             weight = center - (double) j;
  223.             weight = (*filterf)(weight);
  224.             if(j < 0) {
  225.                 n = -j;
  226.             } else if(j >= srcwidth) {
  227.                 n = (srcwidth - j) + srcwidth - 1;
  228.             } else {
  229.                 n = j;
  230.             }
  231.             k = contribX->n++;
  232.             contribX->p[k].pixel = n;
  233.             contribX->p[k].weight = double2fixdouble(weight);
  234.         }
  235.     }
  236.     return 0;
  237. } /* calc_x_contrib */
  238. scaler_t *
  239. scale_image_init(image_t *dst, image_t *src, double (*filterf)(double), double fwidth)
  240. {
  241.     scaler_t *scaler;
  242.     int i, j, k;            /* loop variables */
  243.     int n;              /* pixel number */
  244.     int xx;
  245.     double center = 0.0, left, right;   /* filter calculation variables */
  246.     double width, fscale, weight;   /* filter calculation variables */
  247.     double xscale, yscale;
  248.     double maxwidth;
  249.     CLIST  contribX;
  250.     CLIST *contribY;
  251.     instruction_t *prg;
  252.     
  253.     scaler = (scaler_t*)malloc(sizeof(scaler_t));
  254.     scaler->src = src;
  255.     scaler->dst = dst;
  256.     /* create intermediate column to hold horizontal dst column scale */
  257.     scaler->tmp = (pixel_t*)malloc(src->ysize * sizeof(pixel_t));
  258.     if(scaler->tmp == NULL)
  259.     {
  260.         free(scaler);
  261.         return 0;
  262.     }
  263.     xscale = (double) dst->xsize / (double) src->xsize;
  264.     /* Build y weights */
  265.     /* pre-calculate filter contributions for a column */
  266.     contribY = (CLIST *)calloc(dst->ysize, sizeof(CLIST));
  267.     if(contribY == NULL)
  268.     {
  269.         free(scaler->tmp);
  270.         free(scaler);
  271.         return 0;
  272.     }
  273.     yscale = (double) dst->ysize / (double) src->ysize;
  274.     if(yscale < 1.0)
  275.     {
  276.         width = fwidth / yscale;
  277.         fscale = 1.0 / yscale;
  278.         for(i = 0; i < dst->ysize; ++i)
  279.         {
  280.             contribY[i].n = 0;
  281.             contribY[i].p = (CONTRIB *)calloc((int) (width * 2 + 1), sizeof(CONTRIB));
  282.             if(contribY[i].p == NULL)
  283.             {
  284.                 free(scaler->tmp);
  285.                 free(contribY);
  286.                 free(scaler);
  287.                 return 0;
  288.             }
  289.             center = (double) i / yscale;
  290.             left = ceil(center - width);
  291.             right = floor(center + width);
  292.             for(j = (int)left; j <= right; ++j) {
  293.                 weight = center - (double) j;
  294.                 weight = (*filterf)(weight / fscale) / fscale;
  295.                 if(j < 0) {
  296.                     n = -j;
  297.                 } else if(j >= src->ysize) {
  298.                     n = (src->ysize - j) + src->ysize - 1;
  299.                 } else {
  300.                     n = j;
  301.                 }
  302.                 k = contribY[i].n++;
  303.                 contribY[i].p[k].pixel = n;
  304.                 contribY[i].p[k].weight = double2fixdouble(weight);
  305.             }
  306.         }
  307.     } else {
  308.         for(i = 0; i < dst->ysize; ++i) {
  309.             contribY[i].n = 0;
  310.             contribY[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), sizeof(CONTRIB));
  311.             if(contribY[i].p == NULL)
  312.             {
  313.                 free(scaler->tmp);
  314.                 free(scaler);
  315.                 return 0;
  316.             }
  317.             center = (double) i / yscale;
  318.             left = ceil(center - fwidth);
  319.             right = floor(center + fwidth);
  320.             for(j = (int)left; j <= right; ++j) {
  321.                 weight = center - (double) j;
  322.                 weight = (*filterf)(weight);
  323.                 if(j < 0) {
  324.                     n = -j;
  325.                 } else if(j >= src->ysize) {
  326.                     n = (src->ysize - j) + src->ysize - 1;
  327.                 } else {
  328.                     n = j;
  329.                 }
  330.                 k = contribY[i].n++;
  331.                 contribY[i].p[k].pixel = n;
  332.                 contribY[i].p[k].weight = double2fixdouble(weight);
  333.             }
  334.         }
  335.     }
  336.     /* -------------------------------------------------------------
  337.        streamline contributions into two simple bytecode programs. This
  338.        single optimalization nearly doubles the performance! */
  339.     maxwidth = fwidth;
  340.     if (xscale < 1.0 || yscale < 1.0)
  341.        maxwidth = fwidth / (xscale < yscale ? xscale : yscale);
  342.     prg = scaler->programX = (instruction_t*)calloc(scaler->dst->xsize * 
  343.                                     (2 + 2*(int)(maxwidth*2+1)),
  344.                                     sizeof(instruction_t));
  345.     for(xx = 0; xx < scaler->dst->xsize; xx++)
  346.     {
  347.         calc_x_contrib(&contribX, xscale, fwidth, 
  348.                        scaler->dst->xsize, scaler->src->xsize,
  349.                        filterf, xx);
  350.         /*pel = get_pixel(scaler->src, contribX.p[0].pixel, k);*/
  351.         (prg++)->index = contribX.p[0].pixel * scaler->src->span;
  352.         (prg++)->count = contribX.n;
  353.         for(j = 0; j < contribX.n; ++j)
  354.         {
  355.             /*pel2 = get_pixel(scaler->src, contribX.p[j].pixel, k);*/
  356.             (prg++)->index = contribX.p[j].pixel * scaler->src->span;
  357.             /*weight += pel2 * contribX.p[j].weight;*/
  358.             (prg++)->weight = contribX.p[j].weight;
  359.         }
  360.         free(contribX.p);
  361.     }
  362.     prg = scaler->programY = (instruction_t*)calloc(scaler->dst->ysize * 
  363.                                     (2 + 2*(int)(maxwidth*2+1)),
  364.                                     sizeof(instruction_t));
  365.     
  366.     /* The temp column has been built. Now stretch it 
  367.      vertically into dst column. */
  368.     for(i = 0; i < scaler->dst->ysize; ++i)
  369.     {
  370.         /**(prg++) = scaler->contribY[i].p[0].pixel;*/
  371.         (prg++)->pixel = scaler->tmp + contribY[i].p[0].pixel;
  372.         (prg++)->count = contribY[i].n;
  373.         for(j = 0; j < contribY[i].n; ++j)
  374.         {
  375.             /*(prg++) = scaler->contribY[i].p[j].pixel;*/
  376.             (prg++)->pixel = scaler->tmp + contribY[i].p[j].pixel;
  377.             (prg++)->weight = contribY[i].p[j].weight;
  378.         }
  379.     } /* next dst row */
  380.     /* ---------------------------------------------------
  381.        free the memory allocated for vertical filter weights -- no 
  382.        longer needed, we have programX and programY */
  383.     for(i = 0; i < scaler->dst->ysize; ++i)
  384.         free(contribY[i].p);
  385.     free(contribY);
  386.     return scaler;
  387. }
  388. void scale_image_process(scaler_t *scaler)
  389. {
  390.     int x;
  391.     int i = 0, j, k;            /* loop variables */
  392.     pixel_t pel, pel2;
  393.     int bPelDelta;
  394.     fixdouble weight;
  395.     pixel_t *in;
  396.     pixel_t *out = scaler->dst->data;
  397.     pixel_t *tmpOut;
  398.     instruction_t *prgY, *prgX = NULL, *prgXa;
  399.     prgXa = scaler->programX;
  400.     
  401.     for(x = scaler->dst->xsize; x; --x) {
  402. /* Apply horz filter to make dst column in tmp. */
  403. for(in = scaler->src->data, tmpOut = scaler->tmp, 
  404.   k = scaler->src->ysize; k; --k, in++) {
  405. prgX = prgXa;
  406. weight = 0;
  407. bPelDelta = false;
  408. pel = in[(prgX++)->index];
  409. for(j = (prgX++)->count; j; --j) {
  410. pel2 = in[(prgX++)->index];
  411. if(pel2 != pel) {
  412. bPelDelta = true;
  413. }
  414. weight += pel2 * (prgX++)->weight;
  415. }
  416. *(tmpOut++) = 
  417. bPelDelta ? (pixel_t)CLAMP(fixdouble2int(weight)) : pel;
  418. } /* next row in temp column */
  419. prgXa = prgX;
  420. /*
  421.  * The temp column has been built. 
  422.  * Now stretch it vertically into dst column. 
  423.  */
  424. prgY = scaler->programY;
  425. for(i = scaler->dst->ysize; i; --i) {
  426. weight = 0;
  427. bPelDelta = false;
  428. pel = *((prgY++)->pixel);
  429. for(j = (prgY++)->count; j; --j) {
  430. pel2 = *((prgY++)->pixel);
  431. if(pel2 != pel) {
  432. bPelDelta = true;
  433. }
  434. weight += pel2 * (prgY++)->weight;
  435. }
  436. *(out++) = 
  437. bPelDelta ? (pixel_t)CLAMP(fixdouble2int(weight)) : pel;
  438. } /* next dst row */
  439.     } /* next dst column */
  440. }
  441. void scale_image_done(scaler_t *scaler)
  442. {
  443.     free(scaler->tmp);
  444.     free(scaler->programY);
  445.     free(scaler->programX);
  446.     free(scaler);
  447. }