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#include "./vpx_config.h"
12#include "vpx_scale/yv12config.h"
13#include "vpx_mem/vpx_mem.h"
14
15/****************************************************************************
16*  Exports
17****************************************************************************/
18
19/****************************************************************************
20 *
21 ****************************************************************************/
22int
23vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
24  if (ybf) {
25    vpx_free(ybf->buffer_alloc);
26
27    /* buffer_alloc isn't accessed by most functions.  Rather y_buffer,
28      u_buffer and v_buffer point to buffer_alloc and are used.  Clear out
29      all of this so that a freed pointer isn't inadvertently used */
30    vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
31  } else {
32    return -1;
33  }
34
35  return 0;
36}
37
38int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
39                                  int width, int height, int border) {
40  if (ybf) {
41    int aligned_width = (width + 15) & ~15;
42    int aligned_height = (height + 15) & ~15;
43    int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
44    int yplane_size = (aligned_height + 2 * border) * y_stride;
45    int uv_width = aligned_width >> 1;
46    int uv_height = aligned_height >> 1;
47    /** There is currently a bunch of code which assumes
48      *  uv_stride == y_stride/2, so enforce this here. */
49    int uv_stride = y_stride >> 1;
50    int uvplane_size = (uv_height + border) * uv_stride;
51    const int frame_size = yplane_size + 2 * uvplane_size;
52
53    if (!ybf->buffer_alloc) {
54      ybf->buffer_alloc = vpx_memalign(32, frame_size);
55      ybf->buffer_alloc_sz = frame_size;
56    }
57
58    if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size)
59      return -1;
60
61    /* Only support allocating buffers that have a border that's a multiple
62     * of 32. The border restriction is required to get 16-byte alignment of
63     * the start of the chroma rows without introducing an arbitrary gap
64     * between planes, which would break the semantics of things like
65     * vpx_img_set_rect(). */
66    if (border & 0x1f)
67      return -3;
68
69    ybf->y_crop_width = width;
70    ybf->y_crop_height = height;
71    ybf->y_width  = aligned_width;
72    ybf->y_height = aligned_height;
73    ybf->y_stride = y_stride;
74
75    ybf->uv_width = uv_width;
76    ybf->uv_height = uv_height;
77    ybf->uv_stride = uv_stride;
78
79    ybf->alpha_width = 0;
80    ybf->alpha_height = 0;
81    ybf->alpha_stride = 0;
82
83    ybf->border = border;
84    ybf->frame_size = frame_size;
85
86    ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
87    ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2  * uv_stride) + border / 2;
88    ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2  * uv_stride) + border / 2;
89    ybf->alpha_buffer = NULL;
90
91    ybf->corrupted = 0; /* assume not currupted by errors */
92    return 0;
93  }
94  return -2;
95}
96
97int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
98                                int width, int height, int border) {
99  if (ybf) {
100    vp8_yv12_de_alloc_frame_buffer(ybf);
101    return vp8_yv12_realloc_frame_buffer(ybf, width, height, border);
102  }
103  return -2;
104}
105
106#if CONFIG_VP9
107// TODO(jkoleszar): Maybe replace this with struct vpx_image
108
109int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
110  if (ybf) {
111    vpx_free(ybf->buffer_alloc);
112
113    /* buffer_alloc isn't accessed by most functions.  Rather y_buffer,
114      u_buffer and v_buffer point to buffer_alloc and are used.  Clear out
115      all of this so that a freed pointer isn't inadvertently used */
116    vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
117  } else {
118    return -1;
119  }
120
121  return 0;
122}
123
124int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
125                             int width, int height,
126                             int ss_x, int ss_y, int border) {
127  if (ybf) {
128    const int aligned_width = (width + 7) & ~7;
129    const int aligned_height = (height + 7) & ~7;
130    const int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
131    const int yplane_size = (aligned_height + 2 * border) * y_stride;
132    const int uv_width = aligned_width >> ss_x;
133    const int uv_height = aligned_height >> ss_y;
134    const int uv_stride = y_stride >> ss_x;
135    const int uv_border_w = border >> ss_x;
136    const int uv_border_h = border >> ss_y;
137    const int uvplane_size = (uv_height + 2 * uv_border_h) * uv_stride;
138#if CONFIG_ALPHA
139    const int alpha_width = aligned_width;
140    const int alpha_height = aligned_height;
141    const int alpha_stride = y_stride;
142    const int alpha_border_w = border;
143    const int alpha_border_h = border;
144    const int alpha_plane_size = (alpha_height + 2 * alpha_border_h) *
145                                 alpha_stride;
146    const int frame_size = yplane_size + 2 * uvplane_size +
147                           alpha_plane_size;
148#else
149    const int frame_size = yplane_size + 2 * uvplane_size;
150#endif
151    if (frame_size > ybf->buffer_alloc_sz) {
152      // Allocation to hold larger frame, or first allocation.
153      if (ybf->buffer_alloc)
154        vpx_free(ybf->buffer_alloc);
155      ybf->buffer_alloc = vpx_memalign(32, frame_size);
156      ybf->buffer_alloc_sz = frame_size;
157    }
158
159    if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size)
160      return -1;
161
162    /* Only support allocating buffers that have a border that's a multiple
163     * of 32. The border restriction is required to get 16-byte alignment of
164     * the start of the chroma rows without introducing an arbitrary gap
165     * between planes, which would break the semantics of things like
166     * vpx_img_set_rect(). */
167    if (border & 0x1f)
168      return -3;
169
170    ybf->y_crop_width = width;
171    ybf->y_crop_height = height;
172    ybf->y_width  = aligned_width;
173    ybf->y_height = aligned_height;
174    ybf->y_stride = y_stride;
175
176    ybf->uv_crop_width = (width + ss_x) >> ss_x;
177    ybf->uv_crop_height = (height + ss_y) >> ss_y;
178    ybf->uv_width = uv_width;
179    ybf->uv_height = uv_height;
180    ybf->uv_stride = uv_stride;
181
182    ybf->border = border;
183    ybf->frame_size = frame_size;
184
185    ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
186    ybf->u_buffer = ybf->buffer_alloc + yplane_size +
187                    (uv_border_h * uv_stride) + uv_border_w;
188    ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size +
189                    (uv_border_h * uv_stride) + uv_border_w;
190
191#if CONFIG_ALPHA
192    ybf->alpha_width = alpha_width;
193    ybf->alpha_height = alpha_height;
194    ybf->alpha_stride = alpha_stride;
195    ybf->alpha_buffer = ybf->buffer_alloc + yplane_size + 2 * uvplane_size +
196                        (alpha_border_h * alpha_stride) + alpha_border_w;
197#endif
198    ybf->corrupted = 0; /* assume not corrupted by errors */
199    return 0;
200  }
201  return -2;
202}
203
204int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
205                           int width, int height,
206                           int ss_x, int ss_y, int border) {
207  if (ybf) {
208    vp9_free_frame_buffer(ybf);
209    return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border);
210  }
211  return -2;
212}
213#endif
214