blob: 50c775604daab75806da2b12f35102ab6966b2a4 [file] [log] [blame]
// Copyright 2020 The libgav1 Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/gav1/frame_buffer.h"
#include <cstdint>
#include "src/frame_buffer_utils.h"
#include "src/utils/common.h"
extern "C" {
Libgav1StatusCode 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) {
switch (bitdepth) {
case 8:
#if LIBGAV1_MAX_BITDEPTH >= 10
case 10:
#endif
#if LIBGAV1_MAX_BITDEPTH == 12
case 12:
#endif
break;
default:
return kLibgav1StatusInvalidArgument;
}
switch (image_format) {
case kLibgav1ImageFormatYuv420:
case kLibgav1ImageFormatYuv422:
case kLibgav1ImageFormatYuv444:
case kLibgav1ImageFormatMonochrome400:
break;
default:
return kLibgav1StatusInvalidArgument;
}
// All int arguments must be nonnegative. Borders must be a multiple of 2.
// |stride_alignment| must be a power of 2.
if ((width | height | left_border | right_border | top_border |
bottom_border | stride_alignment) < 0 ||
((left_border | right_border | top_border | bottom_border) & 1) != 0 ||
(stride_alignment & (stride_alignment - 1)) != 0 || info == nullptr) {
return kLibgav1StatusInvalidArgument;
}
bool is_monochrome;
int8_t subsampling_x;
int8_t subsampling_y;
libgav1::DecomposeImageFormat(image_format, &is_monochrome, &subsampling_x,
&subsampling_y);
// Calculate y_stride (in bytes). It is padded to a multiple of
// |stride_alignment| bytes.
int y_stride = width + left_border + right_border;
#if LIBGAV1_MAX_BITDEPTH >= 10
if (bitdepth > 8) y_stride *= sizeof(uint16_t);
#endif
y_stride = libgav1::Align(y_stride, stride_alignment);
// Size of the Y buffer in bytes.
const uint64_t y_buffer_size =
(height + top_border + bottom_border) * static_cast<uint64_t>(y_stride) +
(stride_alignment - 1);
const int uv_width =
is_monochrome ? 0 : libgav1::SubsampledValue(width, subsampling_x);
const int uv_height =
is_monochrome ? 0 : libgav1::SubsampledValue(height, subsampling_y);
const int uv_left_border = is_monochrome ? 0 : left_border >> subsampling_x;
const int uv_right_border = is_monochrome ? 0 : right_border >> subsampling_x;
const int uv_top_border = is_monochrome ? 0 : top_border >> subsampling_y;
const int uv_bottom_border =
is_monochrome ? 0 : bottom_border >> subsampling_y;
// Calculate uv_stride (in bytes). It is padded to a multiple of
// |stride_alignment| bytes.
int uv_stride = uv_width + uv_left_border + uv_right_border;
#if LIBGAV1_MAX_BITDEPTH >= 10
if (bitdepth > 8) uv_stride *= sizeof(uint16_t);
#endif
uv_stride = libgav1::Align(uv_stride, stride_alignment);
// Size of the U or V buffer in bytes.
const uint64_t uv_buffer_size =
is_monochrome ? 0
: (uv_height + uv_top_border + uv_bottom_border) *
static_cast<uint64_t>(uv_stride) +
(stride_alignment - 1);
// Check if it is safe to cast y_buffer_size and uv_buffer_size to size_t.
if (y_buffer_size > SIZE_MAX || uv_buffer_size > SIZE_MAX) {
return kLibgav1StatusInvalidArgument;
}
int left_border_bytes = left_border;
int uv_left_border_bytes = uv_left_border;
#if LIBGAV1_MAX_BITDEPTH >= 10
if (bitdepth > 8) {
left_border_bytes *= sizeof(uint16_t);
uv_left_border_bytes *= sizeof(uint16_t);
}
#endif
info->y_stride = y_stride;
info->uv_stride = uv_stride;
info->y_buffer_size = static_cast<size_t>(y_buffer_size);
info->uv_buffer_size = static_cast<size_t>(uv_buffer_size);
info->y_plane_offset = top_border * y_stride + left_border_bytes;
info->uv_plane_offset = uv_top_border * uv_stride + uv_left_border_bytes;
info->stride_alignment = stride_alignment;
return kLibgav1StatusOk;
}
Libgav1StatusCode Libgav1SetFrameBuffer(const Libgav1FrameBufferInfo* info,
uint8_t* y_buffer, uint8_t* u_buffer,
uint8_t* v_buffer,
void* buffer_private_data,
Libgav1FrameBuffer* frame_buffer) {
if (info == nullptr ||
(info->uv_buffer_size == 0 &&
(u_buffer != nullptr || v_buffer != nullptr)) ||
frame_buffer == nullptr) {
return kLibgav1StatusInvalidArgument;
}
if (y_buffer == nullptr || (info->uv_buffer_size != 0 &&
(u_buffer == nullptr || v_buffer == nullptr))) {
return kLibgav1StatusOutOfMemory;
}
frame_buffer->plane[0] = libgav1::AlignAddr(y_buffer + info->y_plane_offset,
info->stride_alignment);
frame_buffer->plane[1] = libgav1::AlignAddr(u_buffer + info->uv_plane_offset,
info->stride_alignment);
frame_buffer->plane[2] = libgav1::AlignAddr(v_buffer + info->uv_plane_offset,
info->stride_alignment);
frame_buffer->stride[0] = info->y_stride;
frame_buffer->stride[1] = frame_buffer->stride[2] = info->uv_stride;
frame_buffer->private_data = buffer_private_data;
return kLibgav1StatusOk;
}
} // extern "C"