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 #include "vpx/vpx_integer.h"
     16 
     17 #define ADDRESS_STORAGE_SIZE      sizeof(size_t)
     18 /*returns an addr aligned to the byte boundary specified by align*/
     19 #define align_addr(addr,align) (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
     20 
     21 /* Memalign code is copied from vpx_mem.c */
     22 static void *img_buf_memalign(size_t align, size_t size) {
     23   void *addr,
     24        * x = NULL;
     25 
     26   addr = malloc(size + align - 1 + ADDRESS_STORAGE_SIZE);
     27 
     28   if (addr) {
     29     x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align);
     30     /* save the actual malloc address */
     31     ((size_t *)x)[-1] = (size_t)addr;
     32   }
     33 
     34   return x;
     35 }
     36 
     37 static void img_buf_free(void *memblk) {
     38   if (memblk) {
     39     void *addr = (void *)(((size_t *)memblk)[-1]);
     40     free(addr);
     41   }
     42 }
     43 
     44 static vpx_image_t *img_alloc_helper(vpx_image_t   *img,
     45                                      vpx_img_fmt_t  fmt,
     46                                      unsigned int   d_w,
     47                                      unsigned int   d_h,
     48                                      unsigned int   buf_align,
     49                                      unsigned int   stride_align,
     50                                      unsigned char *img_data) {
     51 
     52   unsigned int  h, w, s, xcs, ycs, bps;
     53   int           align;
     54 
     55   /* Treat align==0 like align==1 */
     56   if (!buf_align)
     57     buf_align = 1;
     58 
     59   /* Validate alignment (must be power of 2) */
     60   if (buf_align & (buf_align - 1))
     61     goto fail;
     62 
     63   /* Treat align==0 like align==1 */
     64   if (!stride_align)
     65     stride_align = 1;
     66 
     67   /* Validate alignment (must be power of 2) */
     68   if (stride_align & (stride_align - 1))
     69     goto fail;
     70 
     71   /* Get sample size for this format */
     72   switch (fmt) {
     73     case VPX_IMG_FMT_RGB32:
     74     case VPX_IMG_FMT_RGB32_LE:
     75     case VPX_IMG_FMT_ARGB:
     76     case VPX_IMG_FMT_ARGB_LE:
     77       bps = 32;
     78       break;
     79     case VPX_IMG_FMT_RGB24:
     80     case VPX_IMG_FMT_BGR24:
     81       bps = 24;
     82       break;
     83     case VPX_IMG_FMT_RGB565:
     84     case VPX_IMG_FMT_RGB565_LE:
     85     case VPX_IMG_FMT_RGB555:
     86     case VPX_IMG_FMT_RGB555_LE:
     87     case VPX_IMG_FMT_UYVY:
     88     case VPX_IMG_FMT_YUY2:
     89     case VPX_IMG_FMT_YVYU:
     90       bps = 16;
     91       break;
     92     case VPX_IMG_FMT_I420:
     93     case VPX_IMG_FMT_YV12:
     94     case VPX_IMG_FMT_VPXI420:
     95     case VPX_IMG_FMT_VPXYV12:
     96       bps = 12;
     97       break;
     98     case VPX_IMG_FMT_I422:
     99       bps = 16;
    100       break;
    101     case VPX_IMG_FMT_I444:
    102       bps = 24;
    103       break;
    104     case VPX_IMG_FMT_I42016:
    105       bps = 24;
    106       break;
    107     case VPX_IMG_FMT_I42216:
    108       bps = 32;
    109       break;
    110     case VPX_IMG_FMT_I44416:
    111       bps = 48;
    112       break;
    113     default:
    114       bps = 16;
    115       break;
    116   }
    117 
    118   /* Get chroma shift values for this format */
    119   switch (fmt) {
    120     case VPX_IMG_FMT_I420:
    121     case VPX_IMG_FMT_YV12:
    122     case VPX_IMG_FMT_VPXI420:
    123     case VPX_IMG_FMT_VPXYV12:
    124     case VPX_IMG_FMT_I422:
    125     case VPX_IMG_FMT_I42016:
    126     case VPX_IMG_FMT_I42216:
    127       xcs = 1;
    128       break;
    129     default:
    130       xcs = 0;
    131       break;
    132   }
    133 
    134   switch (fmt) {
    135     case VPX_IMG_FMT_I420:
    136     case VPX_IMG_FMT_YV12:
    137     case VPX_IMG_FMT_VPXI420:
    138     case VPX_IMG_FMT_VPXYV12:
    139       ycs = 1;
    140       break;
    141     default:
    142       ycs = 0;
    143       break;
    144   }
    145 
    146   /* Calculate storage sizes given the chroma subsampling */
    147   align = (1 << xcs) - 1;
    148   w = (d_w + align) & ~align;
    149   align = (1 << ycs) - 1;
    150   h = (d_h + align) & ~align;
    151   s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
    152   s = (s + stride_align - 1) & ~(stride_align - 1);
    153 
    154   /* Allocate the new image */
    155   if (!img) {
    156     img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));
    157 
    158     if (!img)
    159       goto fail;
    160 
    161     img->self_allocd = 1;
    162   } else {
    163     memset(img, 0, sizeof(vpx_image_t));
    164   }
    165 
    166   img->img_data = img_data;
    167 
    168   if (!img_data) {
    169     const uint64_t alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ?
    170                                 (uint64_t)h * s * bps / 8 : (uint64_t)h * s;
    171 
    172     if (alloc_size != (size_t)alloc_size)
    173       goto fail;
    174 
    175     img->img_data = img_buf_memalign(buf_align, (size_t)alloc_size);
    176     img->img_data_owner = 1;
    177   }
    178 
    179   if (!img->img_data)
    180     goto fail;
    181 
    182   img->fmt = fmt;
    183   img->bit_depth = (fmt & VPX_IMG_FMT_HIGH) ? 16 : 8;
    184   img->w = w;
    185   img->h = h;
    186   img->x_chroma_shift = xcs;
    187   img->y_chroma_shift = ycs;
    188   img->bps = bps;
    189 
    190   /* Calculate strides */
    191   img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s;
    192   img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs;
    193 
    194   /* Default viewport to entire image */
    195   if (!vpx_img_set_rect(img, 0, 0, d_w, d_h))
    196     return img;
    197 
    198 fail:
    199   vpx_img_free(img);
    200   return NULL;
    201 }
    202 
    203 vpx_image_t *vpx_img_alloc(vpx_image_t  *img,
    204                            vpx_img_fmt_t fmt,
    205                            unsigned int  d_w,
    206                            unsigned int  d_h,
    207                            unsigned int  align) {
    208   return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
    209 }
    210 
    211 vpx_image_t *vpx_img_wrap(vpx_image_t  *img,
    212                           vpx_img_fmt_t fmt,
    213                           unsigned int  d_w,
    214                           unsigned int  d_h,
    215                           unsigned int  stride_align,
    216                           unsigned char       *img_data) {
    217   /* By setting buf_align = 1, we don't change buffer alignment in this
    218    * function. */
    219   return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, img_data);
    220 }
    221 
    222 int vpx_img_set_rect(vpx_image_t  *img,
    223                      unsigned int  x,
    224                      unsigned int  y,
    225                      unsigned int  w,
    226                      unsigned int  h) {
    227   unsigned char      *data;
    228 
    229   if (x + w <= img->w && y + h <= img->h) {
    230     img->d_w = w;
    231     img->d_h = h;
    232 
    233     /* Calculate plane pointers */
    234     if (!(img->fmt & VPX_IMG_FMT_PLANAR)) {
    235       img->planes[VPX_PLANE_PACKED] =
    236         img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED];
    237     } else {
    238       data = img->img_data;
    239 
    240       if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
    241         img->planes[VPX_PLANE_ALPHA] =
    242           data + x + y * img->stride[VPX_PLANE_ALPHA];
    243         data += img->h * img->stride[VPX_PLANE_ALPHA];
    244       }
    245 
    246       img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y];
    247       data += img->h * img->stride[VPX_PLANE_Y];
    248 
    249       if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) {
    250         img->planes[VPX_PLANE_U] = data
    251                                    + (x >> img->x_chroma_shift)
    252                                    + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    253         data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    254         img->planes[VPX_PLANE_V] = data
    255                                    + (x >> img->x_chroma_shift)
    256                                    + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    257       } else {
    258         img->planes[VPX_PLANE_V] = data
    259                                    + (x >> img->x_chroma_shift)
    260                                    + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    261         data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
    262         img->planes[VPX_PLANE_U] = data
    263                                    + (x >> img->x_chroma_shift)
    264                                    + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
    265       }
    266     }
    267 
    268     return 0;
    269   }
    270 
    271   return -1;
    272 }
    273 
    274 void vpx_img_flip(vpx_image_t *img) {
    275   /* Note: In the calculation pointer adjustment calculation, we want the
    276    * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
    277    * standard indicates that if the adjustment parameter is unsigned, the
    278    * stride parameter will be promoted to unsigned, causing errors when
    279    * the lhs is a larger type than the rhs.
    280    */
    281   img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y];
    282   img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y];
    283 
    284   img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
    285                               * img->stride[VPX_PLANE_U];
    286   img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U];
    287 
    288   img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
    289                               * img->stride[VPX_PLANE_V];
    290   img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V];
    291 
    292   img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA];
    293   img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA];
    294 }
    295 
    296 void vpx_img_free(vpx_image_t *img) {
    297   if (img) {
    298     if (img->img_data && img->img_data_owner)
    299       img_buf_free(img->img_data);
    300 
    301     if (img->self_allocd)
    302       free(img);
    303   }
    304 }
    305