Coverage Report

Created: 2026-09-14 08:00

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