Coverage Report

Created: 2025-09-05 06:47

/src/libvpx/vpx_scale/generic/yv12config.c
Line
Count
Source (jump to first uncovered line)
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 <assert.h>
12
#include <limits.h>
13
#include <stdint.h>
14
15
#include "vpx_scale/yv12config.h"
16
#include "vpx_mem/vpx_mem.h"
17
#include "vpx_ports/mem.h"
18
19
#if defined(VPX_MAX_ALLOCABLE_MEMORY)
20
#include "vp9/common/vp9_onyxc_int.h"
21
#endif  // VPX_MAX_ALLOCABLE_MEMORY
22
/****************************************************************************
23
 *  Exports
24
 ****************************************************************************/
25
26
/****************************************************************************
27
 *
28
 ****************************************************************************/
29
#define yv12_align_addr(addr, align) \
30
607k
  (void *)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
31
32
291k
int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
33
291k
  if (ybf) {
34
    // If libvpx is using frame buffer callbacks then buffer_alloc_sz must
35
    // not be set.
36
291k
    if (ybf->buffer_alloc_sz > 0) {
37
121k
      vpx_free(ybf->buffer_alloc);
38
121k
    }
39
40
    /* buffer_alloc isn't accessed by most functions.  Rather y_buffer,
41
      u_buffer and v_buffer point to buffer_alloc and are used.  Clear out
42
      all of this so that a freed pointer isn't inadvertently used */
43
291k
    memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
44
291k
  } else {
45
0
    return -1;
46
0
  }
47
48
291k
  return 0;
49
291k
}
50
51
int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width,
52
121k
                                  int height, int border) {
53
121k
  if (ybf) {
54
121k
    int aligned_width = (width + 15) & ~15;
55
121k
    int aligned_height = (height + 15) & ~15;
56
121k
    int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
57
121k
    int yplane_size = (aligned_height + 2 * border) * y_stride;
58
121k
    int uv_width = aligned_width >> 1;
59
121k
    int uv_height = aligned_height >> 1;
60
    /** There is currently a bunch of code which assumes
61
     *  uv_stride == y_stride/2, so enforce this here. */
62
121k
    int uv_stride = y_stride >> 1;
63
121k
    int uvplane_size = (uv_height + border) * uv_stride;
64
121k
    const size_t frame_size = yplane_size + 2 * uvplane_size;
65
66
121k
    if (!ybf->buffer_alloc) {
67
121k
      ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, frame_size);
68
121k
      if (!ybf->buffer_alloc) {
69
0
        ybf->buffer_alloc_sz = 0;
70
0
        return -1;
71
0
      }
72
121k
#if defined(__has_feature)
73
#if __has_feature(memory_sanitizer)
74
      // This memset is needed for fixing the issue of using uninitialized
75
      // value in msan test. It will cause a perf loss, so only do this for
76
      // msan test.
77
      memset(ybf->buffer_alloc, 0, frame_size);
78
#endif
79
121k
#endif
80
121k
      ybf->buffer_alloc_sz = frame_size;
81
121k
    }
82
83
121k
    if (ybf->buffer_alloc_sz < frame_size) return -1;
84
85
    /* Only support allocating buffers that have a border that's a multiple
86
     * of 32. The border restriction is required to get 16-byte alignment of
87
     * the start of the chroma rows without introducing an arbitrary gap
88
     * between planes, which would break the semantics of things like
89
     * vpx_img_set_rect(). */
90
121k
    if (border & 0x1f) return -3;
91
92
121k
    ybf->y_crop_width = width;
93
121k
    ybf->y_crop_height = height;
94
121k
    ybf->y_width = aligned_width;
95
121k
    ybf->y_height = aligned_height;
96
121k
    ybf->y_stride = y_stride;
97
98
121k
    ybf->uv_crop_width = (width + 1) / 2;
99
121k
    ybf->uv_crop_height = (height + 1) / 2;
100
121k
    ybf->uv_width = uv_width;
101
121k
    ybf->uv_height = uv_height;
102
121k
    ybf->uv_stride = uv_stride;
103
104
121k
    ybf->alpha_width = 0;
105
121k
    ybf->alpha_height = 0;
106
121k
    ybf->alpha_stride = 0;
107
108
121k
    ybf->border = border;
109
121k
    ybf->frame_size = frame_size;
110
111
121k
    ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
112
121k
    ybf->u_buffer =
113
121k
        ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2;
114
121k
    ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size +
115
121k
                    (border / 2 * uv_stride) + border / 2;
116
121k
    ybf->alpha_buffer = NULL;
117
118
121k
    ybf->corrupted = 0; /* assume not currupted by errors */
119
121k
    return 0;
120
121k
  }
121
0
  return -2;
122
121k
}
123
124
int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
125
121k
                                int border) {
126
121k
  if (ybf) {
127
121k
    vp8_yv12_de_alloc_frame_buffer(ybf);
128
121k
    return vp8_yv12_realloc_frame_buffer(ybf, width, height, border);
129
121k
  }
130
0
  return -2;
131
121k
}
132
133
#if CONFIG_VP9
134
// TODO(jkoleszar): Maybe replace this with struct vpx_image
135
136
194k
int vpx_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
137
194k
  if (ybf) {
138
194k
    if (ybf->buffer_alloc_sz > 0) {
139
0
      vpx_free(ybf->buffer_alloc);
140
0
    }
141
142
    /* buffer_alloc isn't accessed by most functions.  Rather y_buffer,
143
      u_buffer and v_buffer point to buffer_alloc and are used.  Clear out
144
      all of this so that a freed pointer isn't inadvertently used */
145
194k
    memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
146
194k
  } else {
147
0
    return -1;
148
0
  }
149
150
194k
  return 0;
151
194k
}
152
153
int vpx_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
154
                             int ss_x, int ss_y,
155
#if CONFIG_VP9_HIGHBITDEPTH
156
                             int use_highbitdepth,
157
#endif
158
                             int border, int byte_alignment,
159
                             vpx_codec_frame_buffer_t *fb,
160
152k
                             vpx_get_frame_buffer_cb_fn_t cb, void *cb_priv) {
161
152k
#if CONFIG_SIZE_LIMIT
162
152k
  if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1;
163
152k
#endif
164
165
  /* Only support allocating buffers that have a border that's a multiple
166
   * of 32. The border restriction is required to get 16-byte alignment of
167
   * the start of the chroma rows without introducing an arbitrary gap
168
   * between planes, which would break the semantics of things like
169
   * vpx_img_set_rect(). */
170
152k
  if (border & 0x1f) return -3;
171
172
152k
  if (ybf) {
173
152k
    const int vp9_byte_align = (byte_alignment == 0) ? 1 : byte_alignment;
174
152k
    const int aligned_width = (width + 7) & ~7;
175
152k
    const int aligned_height = (height + 7) & ~7;
176
152k
    const int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
177
152k
    const uint64_t yplane_size =
178
152k
        (aligned_height + 2 * border) * (uint64_t)y_stride + byte_alignment;
179
152k
    const int uv_width = aligned_width >> ss_x;
180
152k
    const int uv_height = aligned_height >> ss_y;
181
152k
    const int uv_stride = y_stride >> ss_x;
182
152k
    const int uv_border_w = border >> ss_x;
183
152k
    const int uv_border_h = border >> ss_y;
184
152k
    const uint64_t uvplane_size =
185
152k
        (uv_height + 2 * uv_border_h) * (uint64_t)uv_stride + byte_alignment;
186
187
152k
#if CONFIG_VP9_HIGHBITDEPTH
188
152k
    const uint64_t frame_size =
189
152k
        (1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size);
190
#else
191
    const uint64_t frame_size = yplane_size + 2 * uvplane_size;
192
#endif  // CONFIG_VP9_HIGHBITDEPTH
193
194
152k
    uint8_t *buf = NULL;
195
196
152k
#if defined(VPX_MAX_ALLOCABLE_MEMORY)
197
    // The decoder may allocate REF_FRAMES frame buffers in the frame buffer
198
    // pool. Bound the total amount of allocated memory as if these REF_FRAMES
199
    // frame buffers were allocated in a single allocation.
200
152k
    if (frame_size > VPX_MAX_ALLOCABLE_MEMORY / REF_FRAMES) return -1;
201
151k
#endif  // VPX_MAX_ALLOCABLE_MEMORY
202
203
#if UINT64_MAX > SIZE_MAX
204
    // frame_size is stored in buffer_alloc_sz, which is a size_t. If it won't
205
    // fit, fail early.
206
    if (frame_size > SIZE_MAX) {
207
      return -1;
208
    }
209
#endif
210
211
151k
    if (cb != NULL) {
212
151k
      const int align_addr_extra_size = 31;
213
151k
      const uint64_t external_frame_size = frame_size + align_addr_extra_size;
214
215
151k
      assert(fb != NULL);
216
217
151k
      if (external_frame_size != (size_t)external_frame_size) return -1;
218
219
      // Allocation to hold larger frame, or first allocation.
220
151k
      if (cb(cb_priv, (size_t)external_frame_size, fb) < 0) return -1;
221
222
151k
      if (fb->data == NULL || fb->size < external_frame_size) return -1;
223
224
151k
      ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32);
225
226
151k
#if defined(__has_feature)
227
#if __has_feature(memory_sanitizer)
228
      // This memset is needed for fixing the issue of using uninitialized
229
      // value in msan test. It will cause a perf loss, so only do this for
230
      // msan test.
231
      memset(ybf->buffer_alloc, 0, (size_t)frame_size);
232
#endif
233
151k
#endif
234
151k
    } else if (frame_size > ybf->buffer_alloc_sz) {
235
      // Allocation to hold larger frame, or first allocation.
236
0
      vpx_free(ybf->buffer_alloc);
237
0
      ybf->buffer_alloc = NULL;
238
0
      ybf->buffer_alloc_sz = 0;
239
240
0
      ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, (size_t)frame_size);
241
0
      if (!ybf->buffer_alloc) return -1;
242
243
0
      ybf->buffer_alloc_sz = (size_t)frame_size;
244
245
      // This memset is needed for fixing valgrind error from C loop filter
246
      // due to access uninitialized memory in frame border. It could be
247
      // removed if border is totally removed.
248
0
      memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz);
249
0
    }
250
251
151k
    ybf->y_crop_width = width;
252
151k
    ybf->y_crop_height = height;
253
151k
    ybf->y_width = aligned_width;
254
151k
    ybf->y_height = aligned_height;
255
151k
    ybf->y_stride = y_stride;
256
257
151k
    ybf->uv_crop_width = (width + ss_x) >> ss_x;
258
151k
    ybf->uv_crop_height = (height + ss_y) >> ss_y;
259
151k
    ybf->uv_width = uv_width;
260
151k
    ybf->uv_height = uv_height;
261
151k
    ybf->uv_stride = uv_stride;
262
263
151k
    ybf->border = border;
264
151k
    ybf->frame_size = (size_t)frame_size;
265
151k
    ybf->subsampling_x = ss_x;
266
151k
    ybf->subsampling_y = ss_y;
267
268
151k
    buf = ybf->buffer_alloc;
269
151k
#if CONFIG_VP9_HIGHBITDEPTH
270
151k
    if (use_highbitdepth) {
271
      // Store uint16 addresses when using 16bit framebuffers
272
39.1k
      buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc);
273
39.1k
      ybf->flags = YV12_FLAG_HIGHBITDEPTH;
274
112k
    } else {
275
112k
      ybf->flags = 0;
276
112k
    }
277
151k
#endif  // CONFIG_VP9_HIGHBITDEPTH
278
279
151k
    ybf->y_buffer = (uint8_t *)yv12_align_addr(
280
151k
        buf + (border * y_stride) + border, vp9_byte_align);
281
151k
    ybf->u_buffer = (uint8_t *)yv12_align_addr(
282
151k
        buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w,
283
151k
        vp9_byte_align);
284
151k
    ybf->v_buffer =
285
151k
        (uint8_t *)yv12_align_addr(buf + yplane_size + uvplane_size +
286
151k
                                       (uv_border_h * uv_stride) + uv_border_w,
287
151k
                                   vp9_byte_align);
288
289
151k
    ybf->corrupted = 0; /* assume not corrupted by errors */
290
151k
    return 0;
291
151k
  }
292
0
  return -2;
293
152k
}
294
295
int vpx_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
296
                           int ss_x, int ss_y,
297
#if CONFIG_VP9_HIGHBITDEPTH
298
                           int use_highbitdepth,
299
#endif
300
0
                           int border, int byte_alignment) {
301
0
  if (ybf) {
302
0
    vpx_free_frame_buffer(ybf);
303
0
    return vpx_realloc_frame_buffer(ybf, width, height, ss_x, ss_y,
304
0
#if CONFIG_VP9_HIGHBITDEPTH
305
0
                                    use_highbitdepth,
306
0
#endif
307
0
                                    border, byte_alignment, NULL, NULL, NULL);
308
0
  }
309
0
  return -2;
310
0
}
311
#endif