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