vpx_image.c 8.56 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;
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    case VPX_IMG_FMT_I422:
      bps = 16;
      break;
    case VPX_IMG_FMT_I444:
      bps = 24;
      break;
    case VPX_IMG_FMT_I42016:
      bps = 24;
      break;
    case VPX_IMG_FMT_I42216:
      bps = 32;
      break;
    case VPX_IMG_FMT_I44416:
      bps = 48;
      break;
John Koleszar's avatar
John Koleszar committed
112
    default:
John Koleszar's avatar
John Koleszar committed
113 114 115
      bps = 16;
      break;
  }
John Koleszar's avatar
John Koleszar committed
116

John Koleszar's avatar
John Koleszar committed
117 118
  /* Get chroma shift values for this format */
  switch (fmt) {
James Zern's avatar
James Zern committed
119 120 121 122
    case VPX_IMG_FMT_I420:
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
123 124 125
    case VPX_IMG_FMT_I422:
    case VPX_IMG_FMT_I42016:
    case VPX_IMG_FMT_I42216:
John Koleszar's avatar
John Koleszar committed
126 127
      xcs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
128
    default:
John Koleszar's avatar
John Koleszar committed
129 130 131
      xcs = 0;
      break;
  }
John Koleszar's avatar
John Koleszar committed
132

John Koleszar's avatar
John Koleszar committed
133
  switch (fmt) {
James Zern's avatar
James Zern committed
134 135 136 137
    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
138 139
      ycs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
140
    default:
John Koleszar's avatar
John Koleszar committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
      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
156 157

    if (!img)
John Koleszar's avatar
John Koleszar committed
158
      goto fail;
John Koleszar's avatar
John Koleszar committed
159

John Koleszar's avatar
John Koleszar committed
160 161 162 163
    img->self_allocd = 1;
  } else {
    memset(img, 0, sizeof(vpx_image_t));
  }
John Koleszar's avatar
John Koleszar committed
164

John Koleszar's avatar
John Koleszar committed
165
  img->img_data = img_data;
John Koleszar's avatar
John Koleszar committed
166

John Koleszar's avatar
John Koleszar committed
167
  if (!img_data) {
John Koleszar's avatar
John Koleszar committed
168 169
    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
170 171
    img->img_data_owner = 1;
  }
John Koleszar's avatar
John Koleszar committed
172

John Koleszar's avatar
John Koleszar committed
173 174
  if (!img->img_data)
    goto fail;
John Koleszar's avatar
John Koleszar committed
175

John Koleszar's avatar
John Koleszar committed
176
  img->fmt = fmt;
177
  img->bit_depth = (fmt & VPX_IMG_FMT_HIGH) ? 16 : 8;
John Koleszar's avatar
John Koleszar committed
178 179 180 181 182
  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
183

John Koleszar's avatar
John Koleszar committed
184 185 186
  /* 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
187

John Koleszar's avatar
John Koleszar committed
188 189 190
  /* 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
191 192

fail:
John Koleszar's avatar
John Koleszar committed
193 194
  vpx_img_free(img);
  return NULL;
John Koleszar's avatar
John Koleszar committed
195 196 197
}

vpx_image_t *vpx_img_alloc(vpx_image_t  *img,
James Zern's avatar
James Zern committed
198
                           vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
199 200
                           unsigned int  d_w,
                           unsigned int  d_h,
John Koleszar's avatar
John Koleszar committed
201 202
                           unsigned int  align) {
  return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
John Koleszar's avatar
John Koleszar committed
203 204 205
}

vpx_image_t *vpx_img_wrap(vpx_image_t  *img,
James Zern's avatar
James Zern committed
206
                          vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
207 208 209
                          unsigned int  d_w,
                          unsigned int  d_h,
                          unsigned int  stride_align,
John Koleszar's avatar
John Koleszar committed
210
                          unsigned char       *img_data) {
John Koleszar's avatar
John Koleszar committed
211 212 213
  /* 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
214 215 216 217 218 219
}

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
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
                     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
260 261
    }

John Koleszar's avatar
John Koleszar committed
262 263 264 265
    return 0;
  }

  return -1;
John Koleszar's avatar
John Koleszar committed
266 267
}

John Koleszar's avatar
John Koleszar committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
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
288 289
}

John Koleszar's avatar
John Koleszar committed
290 291 292
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
293
      img_buf_free(img->img_data);
John Koleszar's avatar
John Koleszar committed
294

John Koleszar's avatar
John Koleszar committed
295 296 297
    if (img->self_allocd)
      free(img);
  }
John Koleszar's avatar
John Koleszar committed
298
}