1 /**
2  *
3  *  Copyright 2016-2020 Netflix, Inc.
4  *
5  *     Licensed under the BSD+Patent License (the "License");
6  *     you may not use this file except in compliance with the License.
7  *     You may obtain a copy of the License at
8  *
9  *         https://opensource.org/licenses/BSDplusPatent
10  *
11  *     Unless required by applicable law or agreed to in writing, software
12  *     distributed under the License is distributed on an "AS IS" BASIS,
13  *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *     See the License for the specific language governing permissions and
15  *     limitations under the License.
16  *
17  */
18 
19 #include <errno.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "mem.h"
25 #include "picture.h"
26 #include "ref.h"
27 
28 #define DATA_ALIGN 32
29 
vmaf_picture_alloc(VmafPicture * pic,enum VmafPixelFormat pix_fmt,unsigned bpc,unsigned w,unsigned h)30 int vmaf_picture_alloc(VmafPicture *pic, enum VmafPixelFormat pix_fmt,
31                        unsigned bpc, unsigned w, unsigned h)
32 {
33     if (!pic) return -EINVAL;
34     if (!pix_fmt) return -EINVAL;
35     if (bpc < 8 || bpc > 16) return -EINVAL;
36 
37     memset(pic, 0, sizeof(*pic));
38     pic->pix_fmt = pix_fmt;
39     pic->bpc = bpc;
40     const int ss_hor = pic->pix_fmt != VMAF_PIX_FMT_YUV444P;
41     const int ss_ver = pic->pix_fmt == VMAF_PIX_FMT_YUV420P;
42     pic->w[0] = w;
43     pic->w[1] = pic->w[2] = w >> ss_hor;
44     pic->h[0] = h;
45     pic->h[1] = pic->h[2] = h >> ss_ver;
46     if (pic->pix_fmt == VMAF_PIX_FMT_YUV400P)
47         pic->w[1] = pic->w[2] = pic->h[1] = pic->h[2] = 0;
48 
49     const int aligned_y = (pic->w[0] + DATA_ALIGN - 1) & ~(DATA_ALIGN - 1);
50     const int aligned_c = (pic->w[1] + DATA_ALIGN - 1) & ~(DATA_ALIGN - 1);
51     const int hbd = pic->bpc > 8;
52     pic->stride[0] = aligned_y << hbd;
53     pic->stride[1] = pic->stride[2] = aligned_c << hbd;
54     const size_t y_sz = pic->stride[0] * pic->h[0];
55     const size_t uv_sz = pic->stride[1] * pic->h[1];
56     const size_t pic_size = y_sz + 2 * uv_sz;
57 
58     uint8_t *data = aligned_malloc(pic_size, DATA_ALIGN);
59     if (!data) goto fail;
60     memset(data, 0, pic_size);
61     pic->data[0] = data;
62     pic->data[1] = data + y_sz;
63     pic->data[2] = data + y_sz + uv_sz;
64     if (pic->pix_fmt == VMAF_PIX_FMT_YUV400P)
65         pic->data[1] = pic->data[2] = NULL;
66 
67     int err = vmaf_ref_init(&pic->ref);
68     if (err) goto free_data;
69 
70     return 0;
71 
72 free_data:
73     aligned_free(data);
74 fail:
75     return -ENOMEM;
76 }
77 
vmaf_picture_ref(VmafPicture * dst,VmafPicture * src)78 int vmaf_picture_ref(VmafPicture *dst, VmafPicture *src) {
79     if (!dst || !src) return -EINVAL;
80 
81     memcpy(dst, src, sizeof(*src));
82     vmaf_ref_fetch_increment(src->ref);
83     return 0;
84 }
85 
vmaf_picture_unref(VmafPicture * pic)86 int vmaf_picture_unref(VmafPicture *pic) {
87     if (!pic) return -EINVAL;
88     if (!pic->ref) return -EINVAL;
89 
90     vmaf_ref_fetch_decrement(pic->ref);
91     if (vmaf_ref_load(pic->ref) == 0) {
92         aligned_free(pic->data[0]);
93         vmaf_ref_close(pic->ref);
94     }
95     memset(pic, 0, sizeof(*pic));
96     return 0;
97 }
98