Home | History | Annotate | Download | only in src
      1 /*
      2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include "vpx/vpx_image.h"
     15 
     16 static vpx_image_t *img_alloc_helper(vpx_image_t  *img,
     17                                      vpx_img_fmt_t fmt,
     18                                      unsigned int  d_w,
     19                                      unsigned int  d_h,
     20                                      unsigned int  stride_align,
     21                                      unsigned char      *img_data)
     22 {
     23 
     24     unsigned int  h, w, s, xcs, ycs, bps;
     25     int           align;
     26 
     27     /* Treat align==0 like align==1 */
     28     if (!stride_align)
     29         stride_align = 1;
     30 
     31     /* Validate alignment (must be power of 2) */
     32     if (stride_align & (stride_align - 1))
     33         goto fail;
     34 
     35     /* Get sample size for this format */
     36     switch (fmt)
     37     {
     38     case VPX_IMG_FMT_RGB32:
     39     case VPX_IMG_FMT_RGB32_LE:
     40     case VPX_IMG_FMT_ARGB:
     41     case VPX_IMG_FMT_ARGB_LE:
     42         bps = 32;
     43         break;
     44     case VPX_IMG_FMT_RGB24:
     45     case VPX_IMG_FMT_BGR24:
     46         bps = 24;
     47         break;
     48     case VPX_IMG_FMT_RGB565:
     49     case VPX_IMG_FMT_RGB565_LE:
     50     case VPX_IMG_FMT_RGB555:
     51     case VPX_IMG_FMT_RGB555_LE:
     52     case VPX_IMG_FMT_UYVY:
     53     case VPX_IMG_FMT_YUY2:
     54     case VPX_IMG_FMT_YVYU:
     55         bps = 16;
     56         break;
     57     case VPX_IMG_FMT_I420:
     58     case VPX_IMG_FMT_YV12:
     59     case VPX_IMG_FMT_VPXI420:
     60     case VPX_IMG_FMT_VPXYV12:
     61         bps = 12;
     62         break;
     63     default:
     64         bps = 16;
     65         break;
     66     }
     67 
     68     /* Get chroma shift values for this format */
     69     switch (fmt)
     70     {
     71     case VPX_IMG_FMT_I420:
     72     case VPX_IMG_FMT_YV12:
     73     case VPX_IMG_FMT_VPXI420:
     74     case VPX_IMG_FMT_VPXYV12:
     75         xcs = 1;
     76         break;
     77     default:
     78         xcs = 0;
     79         break;
     80     }
     81 
     82     switch (fmt)
     83     {
     84     case VPX_IMG_FMT_I420:
     85     case VPX_IMG_FMT_YV12:
     86     case VPX_IMG_FMT_VPXI420:
     87     case VPX_IMG_FMT_VPXYV12:
     88         ycs = 1;
     89         break;
     90     default:
     91         ycs = 0;
     92         break;
     93     }
     94 
     95     /* Calculate storage sizes given the chroma subsampling */
     96     align = (1 << xcs) - 1;
     97     w = (d_w + align) & ~align;
     98     align = (1 << ycs) - 1;
     99     h = (d_h + align) & ~align;
    100     s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
    101     s = (s + stride_align - 1) & ~(stride_align - 1);
    102 
    103     /* Allocate the new image */
    104     if (!img)
    105     {
    106         img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));
    107 
    108         if (!img)
    109             goto fail;
    110 
    111         img->self_allocd = 1;
    112     }
    113     else
    114     {
    115         memset(img, 0, sizeof(vpx_image_t));
    116     }
    117 
    118     img->img_data = img_data;
    119 
    120     if (!img_data)
    121     {
    122         img->img_data = malloc((fmt & VPX_IMG_FMT_PLANAR) ? h * w * bps / 8 : h * s);
    123         img->img_data_owner = 1;
    124     }
    125 
    126     if (!img->img_data)
    127         goto fail;
    128 
    129     img->fmt = fmt;
    130     img->w = w;
    131     img->h = h;
    132     img->x_chroma_shift = xcs;
    133     img->y_chroma_shift = ycs;
    134     img->bps = bps;
    135 
    136     /* Calculate strides */
    137     img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s;
    138     img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs;
    139 
    140     /* Default viewport to entire image */
    141     if (!vpx_img_set_rect(img, 0, 0, d_w, d_h))
    142         return img;
    143 
    144 fail:
    145     vpx_img_free(img);
    146     return NULL;
    147 }
    148 
    149 vpx_image_t *vpx_img_alloc(vpx_image_t  *img,
    150                            vpx_img_fmt_t fmt,
    151                            unsigned int  d_w,
    152                            unsigned int  d_h,
    153                            unsigned int  stride_align)
    154 {
    155     return img_alloc_helper(img, fmt, d_w, d_h, stride_align, NULL);
    156 }
    157 
    158 vpx_image_t *vpx_img_wrap(vpx_image_t  *img,
    159                           vpx_img_fmt_t fmt,
    160                           unsigned int  d_w,
    161                           unsigned int  d_h,
    162                           unsigned int  stride_align,
    163                           unsigned char       *img_data)
    164 {
    165     return img_alloc_helper(img, fmt, d_w, d_h, stride_align, img_data);
    166 }
    167 
    168 int vpx_img_set_rect(vpx_image_t  *img,
    169                      unsigned int  x,
    170                      unsigned int  y,
    171                      unsigned int  w,
    172                      unsigned int  h)
    173 {
    174     unsigned char      *data;
    175 
    176     if (x + w <= img->w && y + h <= img->h)
    177     {
    178         img->d_w = w;
    179         img->d_h = h;
    180 
    181         /* Calculate plane pointers */
    182         if (!(img->fmt & VPX_IMG_FMT_PLANAR))
    183         {
    184             img->planes[VPX_PLANE_PACKED] =
    185                 img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED];
    186         }
    187         else
    188         {
    189             data = img->img_data;
    190 
    191             if (img->fmt & VPX_IMG_FMT_HAS_ALPHA)
    192             {
    193                 img->planes[VPX_PLANE_ALPHA] =
    194                     data + x + y * img->stride[VPX_PLANE_ALPHA];
    195                 data += img->h * img->stride[VPX_PLANE_ALPHA];
    196             }
    197 
    198             img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y];
    199             data += img->h * img->stride[VPX_PLANE_Y];
    200 
    201             if (!(img->fmt & VPX_IMG_FMT_UV_FLIP))
    202             {
    203                 img->planes[VPX_PLANE_U] = data
    204                                        + (x >> img->x_chroma_shift)
    205                                        + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    206                 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    207                 img->planes[VPX_PLANE_V] = data
    208                                        + (x >> img->x_chroma_shift)
    209                                        + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    210             }
    211             else
    212             {
    213                 img->planes[VPX_PLANE_V] = data
    214                                        + (x >> img->x_chroma_shift)
    215                                        + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    216                 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    217                 img->planes[VPX_PLANE_U] = data
    218                                        + (x >> img->x_chroma_shift)
    219                                        + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    220             }
    221         }
    222 
    223         return 0;
    224     }
    225 
    226     return -1;
    227 }
    228 
    229 void vpx_img_flip(vpx_image_t *img)
    230 {
    231     /* Note: In the calculation pointer adjustment calculation, we want the
    232      * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
    233      * standard indicates that if the adjustment parameter is unsigned, the
    234      * stride parameter will be promoted to unsigned, causing errors when
    235      * the lhs is a larger type than the rhs.
    236      */
    237     img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y];
    238     img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y];
    239 
    240     img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
    241                             * img->stride[VPX_PLANE_U];
    242     img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U];
    243 
    244     img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
    245                             * img->stride[VPX_PLANE_V];
    246     img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V];
    247 
    248     img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA];
    249     img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA];
    250 }
    251 
    252 void vpx_img_free(vpx_image_t *img)
    253 {
    254     if (img)
    255     {
    256         if (img->img_data && img->img_data_owner)
    257             free(img->img_data);
    258 
    259         if (img->self_allocd)
    260             free(img);
    261     }
    262 }
    263