Coverage Report

Created: 2025-08-28 07:12

/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
1.95M
  (void *)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
31
32
395k
int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
33
395k
  if (ybf) {
34
    // If libvpx is using frame buffer callbacks then buffer_alloc_sz must
35
    // not be set.
36
395k
    if (ybf->buffer_alloc_sz > 0) {
37
114k
      vpx_free(ybf->buffer_alloc);
38
114k
    }
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
395k
    memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
44
395k
  } else {
45
0
    return -1;
46
0
  }
47
48
395k
  return 0;
49
395k
}
50
51
int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width,
52
114k
                                  int height, int border) {
53
114k
  if (ybf) {
54
114k
    int aligned_width = (width + 15) & ~15;
55
114k
    int aligned_height = (height + 15) & ~15;
56
114k
    int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
57
114k
    int yplane_size = (aligned_height + 2 * border) * y_stride;
58
114k
    int uv_width = aligned_width >> 1;
59
114k
    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
114k
    int uv_stride = y_stride >> 1;
63
114k
    int uvplane_size = (uv_height + border) * uv_stride;
64
114k
    const size_t frame_size = yplane_size + 2 * uvplane_size;
65
66
114k
    if (!ybf->buffer_alloc) {
67
114k
      ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, frame_size);
68
114k
      if (!ybf->buffer_alloc) {
69
0
        ybf->buffer_alloc_sz = 0;
70
0
        return -1;
71
0
      }
72
114k
#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
114k
#endif
80
114k
      ybf->buffer_alloc_sz = frame_size;
81
114k
    }
82
83
114k
    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
114k
    if (border & 0x1f) return -3;
91
92
114k
    ybf->y_crop_width = width;
93
114k
    ybf->y_crop_height = height;
94
114k
    ybf->y_width = aligned_width;
95
114k
    ybf->y_height = aligned_height;
96
114k
    ybf->y_stride = y_stride;
97
98
114k
    ybf->uv_crop_width = (width + 1) / 2;
99
114k
    ybf->uv_crop_height = (height + 1) / 2;
100
114k
    ybf->uv_width = uv_width;
101
114k
    ybf->uv_height = uv_height;
102
114k
    ybf->uv_stride = uv_stride;
103
104
114k
    ybf->alpha_width = 0;
105
114k
    ybf->alpha_height = 0;
106
114k
    ybf->alpha_stride = 0;
107
108
114k
    ybf->border = border;
109
114k
    ybf->frame_size = frame_size;
110
111
114k
    ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
112
114k
    ybf->u_buffer =
113
114k
        ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2;
114
114k
    ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size +
115
114k
                    (border / 2 * uv_stride) + border / 2;
116
114k
    ybf->alpha_buffer = NULL;
117
118
114k
    ybf->corrupted = 0; /* assume not currupted by errors */
119
114k
    return 0;
120
114k
  }
121
0
  return -2;
122
114k
}
123
124
int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
125
114k
                                int border) {
126
114k
  if (ybf) {
127
114k
    vp8_yv12_de_alloc_frame_buffer(ybf);
128
114k
    return vp8_yv12_realloc_frame_buffer(ybf, width, height, border);
129
114k
  }
130
0
  return -2;
131
114k
}
132
133
#if CONFIG_VP9
134
// TODO(jkoleszar): Maybe replace this with struct vpx_image
135
136
581k
int vpx_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
137
581k
  if (ybf) {
138
581k
    if (ybf->buffer_alloc_sz > 0) {
139
125k
      vpx_free(ybf->buffer_alloc);
140
125k
    }
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
581k
    memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
146
581k
  } else {
147
0
    return -1;
148
0
  }
149
150
581k
  return 0;
151
581k
}
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
583k
                             vpx_get_frame_buffer_cb_fn_t cb, void *cb_priv) {
161
583k
#if CONFIG_SIZE_LIMIT
162
583k
  if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1;
163
582k
#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
582k
  if (border & 0x1f) return -3;
171
172
582k
  if (ybf) {
173
582k
    const int vp9_byte_align = (byte_alignment == 0) ? 1 : byte_alignment;
174
582k
    const int aligned_width = (width + 7) & ~7;
175
582k
    const int aligned_height = (height + 7) & ~7;
176
582k
    const int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
177
582k
    const uint64_t yplane_size =
178
582k
        (aligned_height + 2 * border) * (uint64_t)y_stride + byte_alignment;
179
582k
    const int uv_width = aligned_width >> ss_x;
180
582k
    const int uv_height = aligned_height >> ss_y;
181
582k
    const int uv_stride = y_stride >> ss_x;
182
582k
    const int uv_border_w = border >> ss_x;
183
582k
    const int uv_border_h = border >> ss_y;
184
582k
    const uint64_t uvplane_size =
185
582k
        (uv_height + 2 * uv_border_h) * (uint64_t)uv_stride + byte_alignment;
186
187
582k
#if CONFIG_VP9_HIGHBITDEPTH
188
582k
    const uint64_t frame_size =
189
582k
        (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
582k
    uint8_t *buf = NULL;
195
196
582k
#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
582k
    if (frame_size > VPX_MAX_ALLOCABLE_MEMORY / REF_FRAMES) return -1;
201
582k
#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
582k
    if (cb != NULL) {
212
204k
      const int align_addr_extra_size = 31;
213
204k
      const uint64_t external_frame_size = frame_size + align_addr_extra_size;
214
215
204k
      assert(fb != NULL);
216
217
204k
      if (external_frame_size != (size_t)external_frame_size) return -1;
218
219
      // Allocation to hold larger frame, or first allocation.
220
204k
      if (cb(cb_priv, (size_t)external_frame_size, fb) < 0) return -1;
221
222
204k
      if (fb->data == NULL || fb->size < external_frame_size) return -1;
223
224
204k
      ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32);
225
226
204k
#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
204k
#endif
234
378k
    } else if (frame_size > ybf->buffer_alloc_sz) {
235
      // Allocation to hold larger frame, or first allocation.
236
125k
      vpx_free(ybf->buffer_alloc);
237
125k
      ybf->buffer_alloc = NULL;
238
125k
      ybf->buffer_alloc_sz = 0;
239
240
125k
      ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, (size_t)frame_size);
241
125k
      if (!ybf->buffer_alloc) return -1;
242
243
125k
      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
125k
      memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz);
249
125k
    }
250
251
582k
    ybf->y_crop_width = width;
252
582k
    ybf->y_crop_height = height;
253
582k
    ybf->y_width = aligned_width;
254
582k
    ybf->y_height = aligned_height;
255
582k
    ybf->y_stride = y_stride;
256
257
582k
    ybf->uv_crop_width = (width + ss_x) >> ss_x;
258
582k
    ybf->uv_crop_height = (height + ss_y) >> ss_y;
259
582k
    ybf->uv_width = uv_width;
260
582k
    ybf->uv_height = uv_height;
261
582k
    ybf->uv_stride = uv_stride;
262
263
582k
    ybf->border = border;
264
582k
    ybf->frame_size = (size_t)frame_size;
265
582k
    ybf->subsampling_x = ss_x;
266
582k
    ybf->subsampling_y = ss_y;
267
268
582k
    buf = ybf->buffer_alloc;
269
582k
#if CONFIG_VP9_HIGHBITDEPTH
270
582k
    if (use_highbitdepth) {
271
      // Store uint16 addresses when using 16bit framebuffers
272
116k
      buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc);
273
116k
      ybf->flags = YV12_FLAG_HIGHBITDEPTH;
274
466k
    } else {
275
466k
      ybf->flags = 0;
276
466k
    }
277
582k
#endif  // CONFIG_VP9_HIGHBITDEPTH
278
279
582k
    ybf->y_buffer = (uint8_t *)yv12_align_addr(
280
582k
        buf + (border * y_stride) + border, vp9_byte_align);
281
582k
    ybf->u_buffer = (uint8_t *)yv12_align_addr(
282
582k
        buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w,
283
582k
        vp9_byte_align);
284
582k
    ybf->v_buffer =
285
582k
        (uint8_t *)yv12_align_addr(buf + yplane_size + uvplane_size +
286
582k
                                       (uv_border_h * uv_stride) + uv_border_w,
287
582k
                                   vp9_byte_align);
288
289
582k
    ybf->corrupted = 0; /* assume not corrupted by errors */
290
582k
    return 0;
291
582k
  }
292
0
  return -2;
293
582k
}
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
100k
                           int border, int byte_alignment) {
301
100k
  if (ybf) {
302
100k
    vpx_free_frame_buffer(ybf);
303
100k
    return vpx_realloc_frame_buffer(ybf, width, height, ss_x, ss_y,
304
100k
#if CONFIG_VP9_HIGHBITDEPTH
305
100k
                                    use_highbitdepth,
306
100k
#endif
307
100k
                                    border, byte_alignment, NULL, NULL, NULL);
308
100k
  }
309
0
  return -2;
310
100k
}
311
#endif