1 // Copyright 2020 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/gav1/frame_buffer.h"
16
17 #include <cstdint>
18
19 #include "src/frame_buffer_utils.h"
20 #include "src/utils/common.h"
21
22 extern "C" {
23
Libgav1ComputeFrameBufferInfo(int bitdepth,Libgav1ImageFormat image_format,int width,int height,int left_border,int right_border,int top_border,int bottom_border,int stride_alignment,Libgav1FrameBufferInfo * info)24 Libgav1StatusCode Libgav1ComputeFrameBufferInfo(
25 int bitdepth, Libgav1ImageFormat image_format, int width, int height,
26 int left_border, int right_border, int top_border, int bottom_border,
27 int stride_alignment, Libgav1FrameBufferInfo* info) {
28 switch (bitdepth) {
29 case 8:
30 #if LIBGAV1_MAX_BITDEPTH >= 10
31 case 10:
32 #endif
33 #if LIBGAV1_MAX_BITDEPTH == 12
34 case 12:
35 #endif
36 break;
37 default:
38 return kLibgav1StatusInvalidArgument;
39 }
40 switch (image_format) {
41 case kLibgav1ImageFormatYuv420:
42 case kLibgav1ImageFormatYuv422:
43 case kLibgav1ImageFormatYuv444:
44 case kLibgav1ImageFormatMonochrome400:
45 break;
46 default:
47 return kLibgav1StatusInvalidArgument;
48 }
49 // All int arguments must be nonnegative. Borders must be a multiple of 2.
50 // |stride_alignment| must be a power of 2.
51 if ((width | height | left_border | right_border | top_border |
52 bottom_border | stride_alignment) < 0 ||
53 ((left_border | right_border | top_border | bottom_border) & 1) != 0 ||
54 (stride_alignment & (stride_alignment - 1)) != 0 || info == nullptr) {
55 return kLibgav1StatusInvalidArgument;
56 }
57
58 bool is_monochrome;
59 int8_t subsampling_x;
60 int8_t subsampling_y;
61 libgav1::DecomposeImageFormat(image_format, &is_monochrome, &subsampling_x,
62 &subsampling_y);
63
64 // Calculate y_stride (in bytes). It is padded to a multiple of
65 // |stride_alignment| bytes.
66 int y_stride = width + left_border + right_border;
67 #if LIBGAV1_MAX_BITDEPTH >= 10
68 if (bitdepth > 8) y_stride *= sizeof(uint16_t);
69 #endif
70 y_stride = libgav1::Align(y_stride, stride_alignment);
71 // Size of the Y buffer in bytes.
72 const uint64_t y_buffer_size =
73 (height + top_border + bottom_border) * static_cast<uint64_t>(y_stride) +
74 (stride_alignment - 1);
75
76 const int uv_width =
77 is_monochrome ? 0 : libgav1::SubsampledValue(width, subsampling_x);
78 const int uv_height =
79 is_monochrome ? 0 : libgav1::SubsampledValue(height, subsampling_y);
80 const int uv_left_border = is_monochrome ? 0 : left_border >> subsampling_x;
81 const int uv_right_border = is_monochrome ? 0 : right_border >> subsampling_x;
82 const int uv_top_border = is_monochrome ? 0 : top_border >> subsampling_y;
83 const int uv_bottom_border =
84 is_monochrome ? 0 : bottom_border >> subsampling_y;
85
86 // Calculate uv_stride (in bytes). It is padded to a multiple of
87 // |stride_alignment| bytes.
88 int uv_stride = uv_width + uv_left_border + uv_right_border;
89 #if LIBGAV1_MAX_BITDEPTH >= 10
90 if (bitdepth > 8) uv_stride *= sizeof(uint16_t);
91 #endif
92 uv_stride = libgav1::Align(uv_stride, stride_alignment);
93 // Size of the U or V buffer in bytes.
94 const uint64_t uv_buffer_size =
95 is_monochrome ? 0
96 : (uv_height + uv_top_border + uv_bottom_border) *
97 static_cast<uint64_t>(uv_stride) +
98 (stride_alignment - 1);
99
100 // Check if it is safe to cast y_buffer_size and uv_buffer_size to size_t.
101 if (y_buffer_size > SIZE_MAX || uv_buffer_size > SIZE_MAX) {
102 return kLibgav1StatusInvalidArgument;
103 }
104
105 int left_border_bytes = left_border;
106 int uv_left_border_bytes = uv_left_border;
107 #if LIBGAV1_MAX_BITDEPTH >= 10
108 if (bitdepth > 8) {
109 left_border_bytes *= sizeof(uint16_t);
110 uv_left_border_bytes *= sizeof(uint16_t);
111 }
112 #endif
113
114 info->y_stride = y_stride;
115 info->uv_stride = uv_stride;
116 info->y_buffer_size = static_cast<size_t>(y_buffer_size);
117 info->uv_buffer_size = static_cast<size_t>(uv_buffer_size);
118 info->y_plane_offset = top_border * y_stride + left_border_bytes;
119 info->uv_plane_offset = uv_top_border * uv_stride + uv_left_border_bytes;
120 info->stride_alignment = stride_alignment;
121 return kLibgav1StatusOk;
122 }
123
Libgav1SetFrameBuffer(const Libgav1FrameBufferInfo * info,uint8_t * y_buffer,uint8_t * u_buffer,uint8_t * v_buffer,void * buffer_private_data,Libgav1FrameBuffer * frame_buffer)124 Libgav1StatusCode Libgav1SetFrameBuffer(const Libgav1FrameBufferInfo* info,
125 uint8_t* y_buffer, uint8_t* u_buffer,
126 uint8_t* v_buffer,
127 void* buffer_private_data,
128 Libgav1FrameBuffer* frame_buffer) {
129 if (info == nullptr ||
130 (info->uv_buffer_size == 0 &&
131 (u_buffer != nullptr || v_buffer != nullptr)) ||
132 frame_buffer == nullptr) {
133 return kLibgav1StatusInvalidArgument;
134 }
135 if (y_buffer == nullptr || (info->uv_buffer_size != 0 &&
136 (u_buffer == nullptr || v_buffer == nullptr))) {
137 return kLibgav1StatusOutOfMemory;
138 }
139 frame_buffer->plane[0] = libgav1::AlignAddr(y_buffer + info->y_plane_offset,
140 info->stride_alignment);
141 frame_buffer->plane[1] = libgav1::AlignAddr(u_buffer + info->uv_plane_offset,
142 info->stride_alignment);
143 frame_buffer->plane[2] = libgav1::AlignAddr(v_buffer + info->uv_plane_offset,
144 info->stride_alignment);
145 frame_buffer->stride[0] = info->y_stride;
146 frame_buffer->stride[1] = frame_buffer->stride[2] = info->uv_stride;
147 frame_buffer->private_data = buffer_private_data;
148 return kLibgav1StatusOk;
149 }
150
151 } // extern "C"
152