vpx_image.c 8.15 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  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.
John Koleszar's avatar
John Koleszar committed
9 10 11 12 13
 */


#include <stdlib.h>
#include <string.h>
14
#include "vpx/vpx_image.h"
John Koleszar's avatar
John Koleszar committed
15

John Koleszar's avatar
John Koleszar committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#define ADDRESS_STORAGE_SIZE      sizeof(size_t)
/*returns an addr aligned to the byte boundary specified by align*/
#define align_addr(addr,align) (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))

/* Memalign code is copied from vpx_mem.c */
static void *img_buf_memalign(size_t align, size_t size) {
  void *addr,
       * x = NULL;

  addr = malloc(size + align - 1 + ADDRESS_STORAGE_SIZE);

  if (addr) {
    x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align);
    /* save the actual malloc address */
    ((size_t *)x)[-1] = (size_t)addr;
  }

  return x;
}

static void img_buf_free(void *memblk) {
  if (memblk) {
    void *addr = (void *)(((size_t *)memblk)[-1]);
    free(addr);
  }
}

43 44 45 46 47 48 49
static vpx_image_t *img_alloc_helper(vpx_image_t  *img,
                                     vpx_img_fmt_t fmt,
                                     unsigned int  d_w,
                                     unsigned int  d_h,
                                     unsigned int  buf_align,
                                     unsigned int  stride_align,
                                     unsigned char      *img_data) {
John Koleszar's avatar
John Koleszar committed
50

John Koleszar's avatar
John Koleszar committed
51 52
  unsigned int  h, w, s, xcs, ycs, bps;
  int           align;
John Koleszar's avatar
John Koleszar committed
53

John Koleszar's avatar
John Koleszar committed
54 55 56 57 58 59 60 61
  /* Treat align==0 like align==1 */
  if (!buf_align)
    buf_align = 1;

  /* Validate alignment (must be power of 2) */
  if (buf_align & (buf_align - 1))
    goto fail;

John Koleszar's avatar
John Koleszar committed
62 63 64
  /* Treat align==0 like align==1 */
  if (!stride_align)
    stride_align = 1;
John Koleszar's avatar
John Koleszar committed
65

John Koleszar's avatar
John Koleszar committed
66 67 68
  /* Validate alignment (must be power of 2) */
  if (stride_align & (stride_align - 1))
    goto fail;
John Koleszar's avatar
John Koleszar committed
69

John Koleszar's avatar
John Koleszar committed
70 71
  /* Get sample size for this format */
  switch (fmt) {
James Zern's avatar
James Zern committed
72 73 74 75
    case VPX_IMG_FMT_RGB32:
    case VPX_IMG_FMT_RGB32_LE:
    case VPX_IMG_FMT_ARGB:
    case VPX_IMG_FMT_ARGB_LE:
John Koleszar's avatar
John Koleszar committed
76 77
      bps = 32;
      break;
James Zern's avatar
James Zern committed
78 79
    case VPX_IMG_FMT_RGB24:
    case VPX_IMG_FMT_BGR24:
John Koleszar's avatar
John Koleszar committed
80 81
      bps = 24;
      break;
James Zern's avatar
James Zern committed
82 83 84 85 86 87 88
    case VPX_IMG_FMT_RGB565:
    case VPX_IMG_FMT_RGB565_LE:
    case VPX_IMG_FMT_RGB555:
    case VPX_IMG_FMT_RGB555_LE:
    case VPX_IMG_FMT_UYVY:
    case VPX_IMG_FMT_YUY2:
    case VPX_IMG_FMT_YVYU:
John Koleszar's avatar
John Koleszar committed
89 90
      bps = 16;
      break;
James Zern's avatar
James Zern committed
91 92 93 94
    case VPX_IMG_FMT_I420:
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
John Koleszar's avatar
John Koleszar committed
95 96
      bps = 12;
      break;
John Koleszar's avatar
John Koleszar committed
97
    default:
John Koleszar's avatar
John Koleszar committed
98 99 100
      bps = 16;
      break;
  }
John Koleszar's avatar
John Koleszar committed
101

John Koleszar's avatar
John Koleszar committed
102 103
  /* Get chroma shift values for this format */
  switch (fmt) {
James Zern's avatar
James Zern committed
104 105 106 107
    case VPX_IMG_FMT_I420:
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
John Koleszar's avatar
John Koleszar committed
108 109
      xcs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
110
    default:
John Koleszar's avatar
John Koleszar committed
111 112 113
      xcs = 0;
      break;
  }
John Koleszar's avatar
John Koleszar committed
114

John Koleszar's avatar
John Koleszar committed
115
  switch (fmt) {
James Zern's avatar
James Zern committed
116 117 118 119
    case VPX_IMG_FMT_I420:
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
John Koleszar's avatar
John Koleszar committed
120 121
      ycs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
122
    default:
John Koleszar's avatar
John Koleszar committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
      ycs = 0;
      break;
  }

  /* Calculate storage sizes given the chroma subsampling */
  align = (1 << xcs) - 1;
  w = (d_w + align) & ~align;
  align = (1 << ycs) - 1;
  h = (d_h + align) & ~align;
  s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
  s = (s + stride_align - 1) & ~(stride_align - 1);

  /* Allocate the new image */
  if (!img) {
    img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));
John Koleszar's avatar
John Koleszar committed
138 139

    if (!img)
John Koleszar's avatar
John Koleszar committed
140
      goto fail;
John Koleszar's avatar
John Koleszar committed
141

John Koleszar's avatar
John Koleszar committed
142 143 144 145
    img->self_allocd = 1;
  } else {
    memset(img, 0, sizeof(vpx_image_t));
  }
John Koleszar's avatar
John Koleszar committed
146

John Koleszar's avatar
John Koleszar committed
147
  img->img_data = img_data;
John Koleszar's avatar
John Koleszar committed
148

John Koleszar's avatar
John Koleszar committed
149
  if (!img_data) {
John Koleszar's avatar
John Koleszar committed
150 151
    img->img_data = img_buf_memalign(buf_align, ((fmt & VPX_IMG_FMT_PLANAR) ?
                                                 h * s * bps / 8 : h * s));
John Koleszar's avatar
John Koleszar committed
152 153
    img->img_data_owner = 1;
  }
John Koleszar's avatar
John Koleszar committed
154

John Koleszar's avatar
John Koleszar committed
155 156
  if (!img->img_data)
    goto fail;
John Koleszar's avatar
John Koleszar committed
157

John Koleszar's avatar
John Koleszar committed
158 159 160 161 162 163
  img->fmt = fmt;
  img->w = w;
  img->h = h;
  img->x_chroma_shift = xcs;
  img->y_chroma_shift = ycs;
  img->bps = bps;
John Koleszar's avatar
John Koleszar committed
164

John Koleszar's avatar
John Koleszar committed
165 166 167
  /* Calculate strides */
  img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s;
  img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs;
John Koleszar's avatar
John Koleszar committed
168

John Koleszar's avatar
John Koleszar committed
169 170 171
  /* Default viewport to entire image */
  if (!vpx_img_set_rect(img, 0, 0, d_w, d_h))
    return img;
John Koleszar's avatar
John Koleszar committed
172 173

fail:
John Koleszar's avatar
John Koleszar committed
174 175
  vpx_img_free(img);
  return NULL;
John Koleszar's avatar
John Koleszar committed
176 177 178
}

vpx_image_t *vpx_img_alloc(vpx_image_t  *img,
James Zern's avatar
James Zern committed
179
                           vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
180 181
                           unsigned int  d_w,
                           unsigned int  d_h,
John Koleszar's avatar
John Koleszar committed
182 183
                           unsigned int  align) {
  return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
John Koleszar's avatar
John Koleszar committed
184 185 186
}

vpx_image_t *vpx_img_wrap(vpx_image_t  *img,
James Zern's avatar
James Zern committed
187
                          vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
188 189 190
                          unsigned int  d_w,
                          unsigned int  d_h,
                          unsigned int  stride_align,
John Koleszar's avatar
John Koleszar committed
191
                          unsigned char       *img_data) {
John Koleszar's avatar
John Koleszar committed
192 193 194
  /* By setting buf_align = 1, we don't change buffer alignment in this
   * function. */
  return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, img_data);
John Koleszar's avatar
John Koleszar committed
195 196 197 198 199 200
}

int vpx_img_set_rect(vpx_image_t  *img,
                     unsigned int  x,
                     unsigned int  y,
                     unsigned int  w,
John Koleszar's avatar
John Koleszar committed
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
                     unsigned int  h) {
  unsigned char      *data;

  if (x + w <= img->w && y + h <= img->h) {
    img->d_w = w;
    img->d_h = h;

    /* Calculate plane pointers */
    if (!(img->fmt & VPX_IMG_FMT_PLANAR)) {
      img->planes[VPX_PLANE_PACKED] =
        img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED];
    } else {
      data = img->img_data;

      if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
        img->planes[VPX_PLANE_ALPHA] =
          data + x + y * img->stride[VPX_PLANE_ALPHA];
        data += img->h * img->stride[VPX_PLANE_ALPHA];
      }

      img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y];
      data += img->h * img->stride[VPX_PLANE_Y];

      if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) {
        img->planes[VPX_PLANE_U] = data
                                   + (x >> img->x_chroma_shift)
                                   + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
        data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
        img->planes[VPX_PLANE_V] = data
                                   + (x >> img->x_chroma_shift)
                                   + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
      } else {
        img->planes[VPX_PLANE_V] = data
                                   + (x >> img->x_chroma_shift)
                                   + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
        data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
        img->planes[VPX_PLANE_U] = data
                                   + (x >> img->x_chroma_shift)
                                   + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
      }
John Koleszar's avatar
John Koleszar committed
241 242
    }

John Koleszar's avatar
John Koleszar committed
243 244 245 246
    return 0;
  }

  return -1;
John Koleszar's avatar
John Koleszar committed
247 248
}

John Koleszar's avatar
John Koleszar committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
void vpx_img_flip(vpx_image_t *img) {
  /* Note: In the calculation pointer adjustment calculation, we want the
   * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
   * standard indicates that if the adjustment parameter is unsigned, the
   * stride parameter will be promoted to unsigned, causing errors when
   * the lhs is a larger type than the rhs.
   */
  img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y];
  img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y];

  img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
                              * img->stride[VPX_PLANE_U];
  img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U];

  img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
                              * img->stride[VPX_PLANE_V];
  img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V];

  img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA];
  img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA];
John Koleszar's avatar
John Koleszar committed
269 270
}

John Koleszar's avatar
John Koleszar committed
271 272 273
void vpx_img_free(vpx_image_t *img) {
  if (img) {
    if (img->img_data && img->img_data_owner)
John Koleszar's avatar
John Koleszar committed
274
      img_buf_free(img->img_data);
John Koleszar's avatar
John Koleszar committed
275

John Koleszar's avatar
John Koleszar committed
276 277 278
    if (img->self_allocd)
      free(img);
  }
John Koleszar's avatar
John Koleszar committed
279
}