Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
      3  *
      4  * This source code is subject to the terms of the BSD 2 Clause License and
      5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      6  * was not distributed with this source code in the LICENSE file, you can
      7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
      8  * Media Patent License 1.0 was not distributed with this source code in the
      9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     10  */
     11 
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #include "aom/aom_image.h"
     16 #include "aom/aom_integer.h"
     17 #include "aom_mem/aom_mem.h"
     18 
     19 static INLINE unsigned int align_image_dimension(unsigned int d,
     20                                                  unsigned int subsampling,
     21                                                  unsigned int size_align) {
     22   unsigned int align;
     23 
     24   align = (1 << subsampling) - 1;
     25   align = (size_align - 1 > align) ? (size_align - 1) : align;
     26   return ((d + align) & ~align);
     27 }
     28 
     29 static aom_image_t *img_alloc_helper(
     30     aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w, unsigned int d_h,
     31     unsigned int buf_align, unsigned int stride_align, unsigned int size_align,
     32     unsigned char *img_data, unsigned int border) {
     33   unsigned int h, w, s, xcs, ycs, bps;
     34   unsigned int stride_in_bytes;
     35 
     36   /* Treat align==0 like align==1 */
     37   if (!buf_align) buf_align = 1;
     38 
     39   /* Validate alignment (must be power of 2) */
     40   if (buf_align & (buf_align - 1)) goto fail;
     41 
     42   /* Treat align==0 like align==1 */
     43   if (!stride_align) stride_align = 1;
     44 
     45   /* Validate alignment (must be power of 2) */
     46   if (stride_align & (stride_align - 1)) goto fail;
     47 
     48   /* Treat align==0 like align==1 */
     49   if (!size_align) size_align = 1;
     50 
     51   /* Validate alignment (must be power of 2) */
     52   if (size_align & (size_align - 1)) goto fail;
     53 
     54   /* Get sample size for this format */
     55   switch (fmt) {
     56     case AOM_IMG_FMT_I420:
     57     case AOM_IMG_FMT_YV12:
     58     case AOM_IMG_FMT_AOMI420:
     59     case AOM_IMG_FMT_AOMYV12: bps = 12; break;
     60     case AOM_IMG_FMT_I422:
     61     case AOM_IMG_FMT_I444: bps = 24; break;
     62     case AOM_IMG_FMT_YV1216:
     63     case AOM_IMG_FMT_I42016: bps = 24; break;
     64     case AOM_IMG_FMT_I42216:
     65     case AOM_IMG_FMT_I44416: bps = 48; break;
     66     default: bps = 16; break;
     67   }
     68 
     69   /* Get chroma shift values for this format */
     70   switch (fmt) {
     71     case AOM_IMG_FMT_I420:
     72     case AOM_IMG_FMT_YV12:
     73     case AOM_IMG_FMT_AOMI420:
     74     case AOM_IMG_FMT_AOMYV12:
     75     case AOM_IMG_FMT_I422:
     76     case AOM_IMG_FMT_I42016:
     77     case AOM_IMG_FMT_YV1216:
     78     case AOM_IMG_FMT_I42216: xcs = 1; break;
     79     default: xcs = 0; break;
     80   }
     81 
     82   switch (fmt) {
     83     case AOM_IMG_FMT_I420:
     84     case AOM_IMG_FMT_YV12:
     85     case AOM_IMG_FMT_AOMI420:
     86     case AOM_IMG_FMT_AOMYV12:
     87     case AOM_IMG_FMT_YV1216:
     88     case AOM_IMG_FMT_I42016: ycs = 1; break;
     89     default: ycs = 0; break;
     90   }
     91 
     92   /* Calculate storage sizes given the chroma subsampling */
     93   w = align_image_dimension(d_w, xcs, size_align);
     94   h = align_image_dimension(d_h, ycs, size_align);
     95 
     96   s = (fmt & AOM_IMG_FMT_PLANAR) ? w : bps * w / 8;
     97   s = (s + 2 * border + stride_align - 1) & ~(stride_align - 1);
     98   stride_in_bytes = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
     99 
    100   /* Allocate the new image */
    101   if (!img) {
    102     img = (aom_image_t *)calloc(1, sizeof(aom_image_t));
    103 
    104     if (!img) goto fail;
    105 
    106     img->self_allocd = 1;
    107   } else {
    108     memset(img, 0, sizeof(aom_image_t));
    109   }
    110 
    111   img->img_data = img_data;
    112 
    113   if (!img_data) {
    114     const uint64_t alloc_size =
    115         (fmt & AOM_IMG_FMT_PLANAR)
    116             ? (uint64_t)(h + 2 * border) * stride_in_bytes * bps / 8
    117             : (uint64_t)(h + 2 * border) * stride_in_bytes;
    118 
    119     if (alloc_size != (size_t)alloc_size) goto fail;
    120 
    121     img->img_data = (uint8_t *)aom_memalign(buf_align, (size_t)alloc_size);
    122     img->img_data_owner = 1;
    123     img->sz = (size_t)alloc_size;
    124   }
    125 
    126   if (!img->img_data) goto fail;
    127 
    128   img->fmt = fmt;
    129   img->bit_depth = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
    130   // aligned width and aligned height
    131   img->w = w;
    132   img->h = h;
    133   img->x_chroma_shift = xcs;
    134   img->y_chroma_shift = ycs;
    135   img->bps = bps;
    136 
    137   /* Calculate strides */
    138   img->stride[AOM_PLANE_Y] = stride_in_bytes;
    139   img->stride[AOM_PLANE_U] = img->stride[AOM_PLANE_V] = stride_in_bytes >> xcs;
    140 
    141   /* Default viewport to entire image */
    142   if (!aom_img_set_rect(img, 0, 0, d_w, d_h, border)) return img;
    143 
    144 fail:
    145   aom_img_free(img);
    146   return NULL;
    147 }
    148 
    149 aom_image_t *aom_img_alloc(aom_image_t *img, aom_img_fmt_t fmt,
    150                            unsigned int d_w, unsigned int d_h,
    151                            unsigned int align) {
    152   return img_alloc_helper(img, fmt, d_w, d_h, align, align, 1, NULL, 0);
    153 }
    154 
    155 aom_image_t *aom_img_wrap(aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w,
    156                           unsigned int d_h, unsigned int stride_align,
    157                           unsigned char *img_data) {
    158   /* By setting buf_align = 1, we don't change buffer alignment in this
    159    * function. */
    160   return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, 1, img_data, 0);
    161 }
    162 
    163 aom_image_t *aom_img_alloc_with_border(aom_image_t *img, aom_img_fmt_t fmt,
    164                                        unsigned int d_w, unsigned int d_h,
    165                                        unsigned int align,
    166                                        unsigned int size_align,
    167                                        unsigned int border) {
    168   return img_alloc_helper(img, fmt, d_w, d_h, align, align, size_align, NULL,
    169                           border);
    170 }
    171 
    172 int aom_img_set_rect(aom_image_t *img, unsigned int x, unsigned int y,
    173                      unsigned int w, unsigned int h, unsigned int border) {
    174   unsigned char *data;
    175 
    176   if (x + w <= img->w && y + h <= img->h) {
    177     img->d_w = w;
    178     img->d_h = h;
    179 
    180     x += border;
    181     y += border;
    182 
    183     /* Calculate plane pointers */
    184     if (!(img->fmt & AOM_IMG_FMT_PLANAR)) {
    185       img->planes[AOM_PLANE_PACKED] =
    186           img->img_data + x * img->bps / 8 + y * img->stride[AOM_PLANE_PACKED];
    187     } else {
    188       const int bytes_per_sample =
    189           (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
    190       data = img->img_data;
    191 
    192       img->planes[AOM_PLANE_Y] =
    193           data + x * bytes_per_sample + y * img->stride[AOM_PLANE_Y];
    194       data += (img->h + 2 * border) * img->stride[AOM_PLANE_Y];
    195 
    196       unsigned int uv_border_h = border >> img->y_chroma_shift;
    197       unsigned int uv_x = x >> img->x_chroma_shift;
    198       unsigned int uv_y = y >> img->y_chroma_shift;
    199       if (!(img->fmt & AOM_IMG_FMT_UV_FLIP)) {
    200         img->planes[AOM_PLANE_U] =
    201             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
    202         data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
    203                 img->stride[AOM_PLANE_U];
    204         img->planes[AOM_PLANE_V] =
    205             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
    206       } else {
    207         img->planes[AOM_PLANE_V] =
    208             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
    209         data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
    210                 img->stride[AOM_PLANE_V];
    211         img->planes[AOM_PLANE_U] =
    212             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
    213       }
    214     }
    215     return 0;
    216   }
    217   return -1;
    218 }
    219 
    220 void aom_img_flip(aom_image_t *img) {
    221   /* Note: In the calculation pointer adjustment calculation, we want the
    222    * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
    223    * standard indicates that if the adjustment parameter is unsigned, the
    224    * stride parameter will be promoted to unsigned, causing errors when
    225    * the lhs is a larger type than the rhs.
    226    */
    227   img->planes[AOM_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[AOM_PLANE_Y];
    228   img->stride[AOM_PLANE_Y] = -img->stride[AOM_PLANE_Y];
    229 
    230   img->planes[AOM_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
    231                               img->stride[AOM_PLANE_U];
    232   img->stride[AOM_PLANE_U] = -img->stride[AOM_PLANE_U];
    233 
    234   img->planes[AOM_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
    235                               img->stride[AOM_PLANE_V];
    236   img->stride[AOM_PLANE_V] = -img->stride[AOM_PLANE_V];
    237 }
    238 
    239 void aom_img_free(aom_image_t *img) {
    240   if (img) {
    241     if (img->img_data && img->img_data_owner) aom_free(img->img_data);
    242 
    243     if (img->self_allocd) free(img);
    244   }
    245 }
    246 
    247 int aom_img_plane_width(const aom_image_t *img, int plane) {
    248   if (plane > 0 && img->x_chroma_shift > 0)
    249     return (img->d_w + 1) >> img->x_chroma_shift;
    250   else
    251     return img->d_w;
    252 }
    253 
    254 int aom_img_plane_height(const aom_image_t *img, int plane) {
    255   if (plane > 0 && img->y_chroma_shift > 0)
    256     return (img->d_h + 1) >> img->y_chroma_shift;
    257   else
    258     return img->d_h;
    259 }
    260