diff options
Diffstat (limited to 'src/yuv_buffer.h')
-rw-r--r-- | src/yuv_buffer.h | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/yuv_buffer.h b/src/yuv_buffer.h new file mode 100644 index 0000000..b9e8cd3 --- /dev/null +++ b/src/yuv_buffer.h @@ -0,0 +1,183 @@ +/* + * Copyright 2019 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. + */ + +#ifndef LIBGAV1_SRC_YUV_BUFFER_H_ +#define LIBGAV1_SRC_YUV_BUFFER_H_ + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <type_traits> + +#include "src/gav1/frame_buffer.h" +#include "src/utils/constants.h" + +namespace libgav1 { + +class YuvBuffer { + public: + // Allocates the buffer. Returns true on success. Returns false on failure. + // + // * |width| and |height| are the image dimensions in pixels. + // * |subsampling_x| and |subsampling_y| (either 0 or 1) specify the + // subsampling of the width and height of the chroma planes, respectively. + // * |left_border|, |right_border|, |top_border|, and |bottom_border| are + // the sizes (in pixels) of the borders on the left, right, top, and + // bottom sides, respectively. The four border sizes must all be a + // multiple of 2. + // * If |get_frame_buffer| is not null, it is invoked to allocate the memory. + // If |get_frame_buffer| is null, YuvBuffer allocates the memory directly + // and ignores the |callback_private_data| and |buffer_private_data| + // parameters, which should be null. + // + // NOTE: The strides are a multiple of 16. Since the first row in each plane + // is 16-byte aligned, subsequent rows are also 16-byte aligned. + // + // Example: bitdepth=8 width=20 height=6 left/right/top/bottom_border=2. The + // diagram below shows how Realloc() allocates the data buffer for the Y + // plane. + // + // 16-byte aligned + // | + // v + // ++++++++++++++++++++++++pppppppp + // ++++++++++++++++++++++++pppppppp + // ++01234567890123456789++pppppppp + // ++11234567890123456789++pppppppp + // ++21234567890123456789++pppppppp + // ++31234567890123456789++pppppppp + // ++41234567890123456789++pppppppp + // ++51234567890123456789++pppppppp + // ++++++++++++++++++++++++pppppppp + // ++++++++++++++++++++++++pppppppp + // | | + // |<-- stride (multiple of 16) ->| + // + // The video frame has 6 rows of 20 pixels each. Each row is shown as the + // pattern r1234567890123456789, where |r| is 0, 1, 2, 3, 4, 5. + // + // Realloc() first adds a border of 2 pixels around the video frame. The + // border pixels are shown as '+'. + // + // Each row is then padded to a multiple of the default alignment in bytes, + // which is 16. The padding bytes are shown as lowercase 'p'. (Since + // |bitdepth| is 8 in this example, each pixel is one byte.) The padded size + // in bytes is the stride. In this example, the stride is 32 bytes. + // + // Finally, Realloc() aligns the first byte of frame data, which is the '0' + // pixel/byte in the upper left corner of the frame, to the default (16-byte) + // alignment boundary. + // + // TODO(wtc): Add a check for width and height limits to defend against + // invalid bitstreams. + bool Realloc(int bitdepth, bool is_monochrome, int width, int height, + int8_t subsampling_x, int8_t subsampling_y, int left_border, + int right_border, int top_border, int bottom_border, + GetFrameBufferCallback get_frame_buffer, + void* callback_private_data, void** buffer_private_data); + + int bitdepth() const { return bitdepth_; } + + bool is_monochrome() const { return is_monochrome_; } + + int8_t subsampling_x() const { return subsampling_x_; } + int8_t subsampling_y() const { return subsampling_y_; } + + int width(int plane) const { + return (plane == kPlaneY) ? y_width_ : uv_width_; + } + int height(int plane) const { + return (plane == kPlaneY) ? y_height_ : uv_height_; + } + + // Returns border sizes in pixels. + int left_border(int plane) const { return left_border_[plane]; } + int right_border(int plane) const { return right_border_[plane]; } + int top_border(int plane) const { return top_border_[plane]; } + int bottom_border(int plane) const { return bottom_border_[plane]; } + + // Returns the alignment of frame buffer row in bytes. + int alignment() const { return kFrameBufferRowAlignment; } + + // Backup the current set of warnings and disable -Warray-bounds for the + // following three functions as the compiler cannot, in all cases, determine + // whether |plane| is within [0, kMaxPlanes), e.g., with a variable based for + // loop. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif + // Returns the data buffer for |plane|. + uint8_t* data(int plane) { + assert(plane >= 0); + assert(static_cast<size_t>(plane) < std::extent<decltype(buffer_)>::value); + return buffer_[plane]; + } + const uint8_t* data(int plane) const { + assert(plane >= 0); + assert(static_cast<size_t>(plane) < std::extent<decltype(buffer_)>::value); + return buffer_[plane]; + } + + // Returns the stride in bytes for |plane|. + int stride(int plane) const { + assert(plane >= 0); + assert(static_cast<size_t>(plane) < std::extent<decltype(stride_)>::value); + return stride_[plane]; + } + // Restore the previous set of compiler warnings. +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + private: + static constexpr int kFrameBufferRowAlignment = 16; + int bitdepth_ = 0; + bool is_monochrome_ = false; + + // y_width_ and y_height_ are the |width| and |height| arguments passed to the + // Realloc() method. + // + // uv_width_ and uv_height_ are computed from y_width_ and y_height_ as + // follows: + // uv_width_ = (y_width_ + subsampling_x_) >> subsampling_x_ + // uv_height_ = (y_height_ + subsampling_y_) >> subsampling_y_ + int y_width_ = 0; + int uv_width_ = 0; + int y_height_ = 0; + int uv_height_ = 0; + + int left_border_[kMaxPlanes] = {}; + int right_border_[kMaxPlanes] = {}; + int top_border_[kMaxPlanes] = {}; + int bottom_border_[kMaxPlanes] = {}; + + int stride_[kMaxPlanes] = {}; + uint8_t* buffer_[kMaxPlanes] = {}; + + // buffer_alloc_ and buffer_alloc_size_ are only used if the + // get_frame_buffer callback is null and we allocate the buffer ourselves. + std::unique_ptr<uint8_t[]> buffer_alloc_; + size_t buffer_alloc_size_ = 0; + + int8_t subsampling_x_ = 0; // 0 or 1. + int8_t subsampling_y_ = 0; // 0 or 1. +}; + +} // namespace libgav1 + +#endif // LIBGAV1_SRC_YUV_BUFFER_H_ |