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