vpx_image.c 8.3 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
 */

#include <stdlib.h>
#include <string.h>
13

14
#include "vpx/vpx_image.h"
15
#include "vpx/vpx_integer.h"
16
#include "vpx_mem/vpx_mem.h"
John Koleszar's avatar
John Koleszar committed
17

Deb Mukherjee's avatar
Deb Mukherjee committed
18
19
20
21
22
23
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,
24
                                     unsigned char *img_data) {
Deb Mukherjee's avatar
Deb Mukherjee committed
25
26
27
  unsigned int h, w, s, xcs, ycs, bps;
  unsigned int stride_in_bytes;
  int align;
John Koleszar's avatar
John Koleszar committed
28

John Koleszar's avatar
John Koleszar committed
29
30
31
32
33
34
35
36
  /* 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
37
38
39
  /* Treat align==0 like align==1 */
  if (!stride_align)
    stride_align = 1;
John Koleszar's avatar
John Koleszar committed
40

John Koleszar's avatar
John Koleszar committed
41
42
43
  /* Validate alignment (must be power of 2) */
  if (stride_align & (stride_align - 1))
    goto fail;
John Koleszar's avatar
John Koleszar committed
44

John Koleszar's avatar
John Koleszar committed
45
46
  /* Get sample size for this format */
  switch (fmt) {
James Zern's avatar
James Zern committed
47
48
49
50
    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
51
52
      bps = 32;
      break;
James Zern's avatar
James Zern committed
53
54
    case VPX_IMG_FMT_RGB24:
    case VPX_IMG_FMT_BGR24:
John Koleszar's avatar
John Koleszar committed
55
56
      bps = 24;
      break;
James Zern's avatar
James Zern committed
57
58
59
60
61
62
63
    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
64
65
      bps = 16;
      break;
James Zern's avatar
James Zern committed
66
67
68
69
    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
70
71
      bps = 12;
      break;
72
    case VPX_IMG_FMT_I422:
Deb Mukherjee's avatar
Deb Mukherjee committed
73
    case VPX_IMG_FMT_I440:
74
75
76
77
78
79
80
81
82
      bps = 16;
      break;
    case VPX_IMG_FMT_I444:
      bps = 24;
      break;
    case VPX_IMG_FMT_I42016:
      bps = 24;
      break;
    case VPX_IMG_FMT_I42216:
Deb Mukherjee's avatar
Deb Mukherjee committed
83
    case VPX_IMG_FMT_I44016:
84
85
86
87
88
      bps = 32;
      break;
    case VPX_IMG_FMT_I44416:
      bps = 48;
      break;
John Koleszar's avatar
John Koleszar committed
89
    default:
John Koleszar's avatar
John Koleszar committed
90
91
92
      bps = 16;
      break;
  }
John Koleszar's avatar
John Koleszar committed
93

John Koleszar's avatar
John Koleszar committed
94
95
  /* Get chroma shift values for this format */
  switch (fmt) {
James Zern's avatar
James Zern committed
96
97
98
99
    case VPX_IMG_FMT_I420:
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
100
101
102
    case VPX_IMG_FMT_I422:
    case VPX_IMG_FMT_I42016:
    case VPX_IMG_FMT_I42216:
John Koleszar's avatar
John Koleszar committed
103
104
      xcs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
105
    default:
John Koleszar's avatar
John Koleszar committed
106
107
108
      xcs = 0;
      break;
  }
John Koleszar's avatar
John Koleszar committed
109

John Koleszar's avatar
John Koleszar committed
110
  switch (fmt) {
James Zern's avatar
James Zern committed
111
    case VPX_IMG_FMT_I420:
Deb Mukherjee's avatar
Deb Mukherjee committed
112
    case VPX_IMG_FMT_I440:
James Zern's avatar
James Zern committed
113
114
115
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_VPXI420:
    case VPX_IMG_FMT_VPXYV12:
Deb Mukherjee's avatar
Deb Mukherjee committed
116
    case VPX_IMG_FMT_I42016:
Deb Mukherjee's avatar
Deb Mukherjee committed
117
    case VPX_IMG_FMT_I44016:
John Koleszar's avatar
John Koleszar committed
118
119
      ycs = 1;
      break;
John Koleszar's avatar
John Koleszar committed
120
    default:
John Koleszar's avatar
John Koleszar committed
121
122
123
124
125
126
127
128
129
130
131
      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);
Deb Mukherjee's avatar
Deb Mukherjee committed
132
  stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
John Koleszar's avatar
John Koleszar committed
133
134
135
136

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

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

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

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

John Koleszar's avatar
John Koleszar committed
148
  if (!img_data) {
149
150
151
152
153
154
    const uint64_t alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ?
                                (uint64_t)h * s * bps / 8 : (uint64_t)h * s;

    if (alloc_size != (size_t)alloc_size)
      goto fail;

155
    img->img_data = (uint8_t *)vpx_memalign(buf_align, (size_t)alloc_size);
John Koleszar's avatar
John Koleszar committed
156
157
    img->img_data_owner = 1;
  }
John Koleszar's avatar
John Koleszar committed
158

John Koleszar's avatar
John Koleszar committed
159
160
  if (!img->img_data)
    goto fail;
John Koleszar's avatar
John Koleszar committed
161

John Koleszar's avatar
John Koleszar committed
162
  img->fmt = fmt;
163
  img->bit_depth = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
John Koleszar's avatar
John Koleszar committed
164
165
166
167
168
  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
169

John Koleszar's avatar
John Koleszar committed
170
  /* Calculate strides */
Deb Mukherjee's avatar
Deb Mukherjee committed
171
172
  img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = stride_in_bytes;
  img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = stride_in_bytes >> xcs;
John Koleszar's avatar
John Koleszar committed
173

John Koleszar's avatar
John Koleszar committed
174
175
176
  /* 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
177
178

fail:
John Koleszar's avatar
John Koleszar committed
179
180
  vpx_img_free(img);
  return NULL;
John Koleszar's avatar
John Koleszar committed
181
182
183
}

vpx_image_t *vpx_img_alloc(vpx_image_t  *img,
James Zern's avatar
James Zern committed
184
                           vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
185
186
                           unsigned int  d_w,
                           unsigned int  d_h,
John Koleszar's avatar
John Koleszar committed
187
188
                           unsigned int  align) {
  return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
John Koleszar's avatar
John Koleszar committed
189
190
191
}

vpx_image_t *vpx_img_wrap(vpx_image_t  *img,
James Zern's avatar
James Zern committed
192
                          vpx_img_fmt_t fmt,
John Koleszar's avatar
John Koleszar committed
193
194
195
                          unsigned int  d_w,
                          unsigned int  d_h,
                          unsigned int  stride_align,
John Koleszar's avatar
John Koleszar committed
196
                          unsigned char       *img_data) {
John Koleszar's avatar
John Koleszar committed
197
198
199
  /* 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
200
201
202
203
204
205
}

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
206
207
208
209
210
211
212
213
214
215
216
217
                     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 {
Deb Mukherjee's avatar
Deb Mukherjee committed
218
219
      const int bytes_per_sample =
          (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
John Koleszar's avatar
John Koleszar committed
220
221
222
223
      data = img->img_data;

      if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
        img->planes[VPX_PLANE_ALPHA] =
Deb Mukherjee's avatar
Deb Mukherjee committed
224
            data + x * bytes_per_sample + y * img->stride[VPX_PLANE_ALPHA];
John Koleszar's avatar
John Koleszar committed
225
226
227
        data += img->h * img->stride[VPX_PLANE_ALPHA];
      }

Deb Mukherjee's avatar
Deb Mukherjee committed
228
229
      img->planes[VPX_PLANE_Y] = data + x * bytes_per_sample +
          y * img->stride[VPX_PLANE_Y];
John Koleszar's avatar
John Koleszar committed
230
231
232
      data += img->h * img->stride[VPX_PLANE_Y];

      if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) {
Deb Mukherjee's avatar
Deb Mukherjee committed
233
234
235
        img->planes[VPX_PLANE_U] =
            data + (x >> img->x_chroma_shift) * bytes_per_sample +
            (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
John Koleszar's avatar
John Koleszar committed
236
        data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
Deb Mukherjee's avatar
Deb Mukherjee committed
237
238
239
        img->planes[VPX_PLANE_V] =
            data + (x >> img->x_chroma_shift) * bytes_per_sample +
            (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
John Koleszar's avatar
John Koleszar committed
240
      } else {
Deb Mukherjee's avatar
Deb Mukherjee committed
241
242
243
        img->planes[VPX_PLANE_V] =
            data + (x >> img->x_chroma_shift) * bytes_per_sample +
            (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
John Koleszar's avatar
John Koleszar committed
244
        data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
Deb Mukherjee's avatar
Deb Mukherjee committed
245
246
247
        img->planes[VPX_PLANE_U] =
            data + (x >> img->x_chroma_shift) * bytes_per_sample +
            (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
John Koleszar's avatar
John Koleszar committed
248
      }
John Koleszar's avatar
John Koleszar committed
249
    }
John Koleszar's avatar
John Koleszar committed
250
251
252
    return 0;
  }
  return -1;
John Koleszar's avatar
John Koleszar committed
253
254
}

John Koleszar's avatar
John Koleszar committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
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
275
276
}

John Koleszar's avatar
John Koleszar committed
277
278
279
void vpx_img_free(vpx_image_t *img) {
  if (img) {
    if (img->img_data && img->img_data_owner)
280
      vpx_free(img->img_data);
John Koleszar's avatar
John Koleszar committed
281

John Koleszar's avatar
John Koleszar committed
282
283
284
    if (img->self_allocd)
      free(img);
  }
John Koleszar's avatar
John Koleszar committed
285
}