Coverage Report

Created: 2025-11-16 07:20

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