// 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 #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(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(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(y_buffer_size); info->uv_buffer_size = static_cast(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"