| // 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" |