12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- /*
- * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/NonnullOwnPtr.h>
- #include <AK/OwnPtr.h>
- #include <LibVideo/Color/ColorConverter.h>
- #include "VideoFrame.h"
- namespace Video {
- ErrorOr<NonnullOwnPtr<SubsampledYUVFrame>> SubsampledYUVFrame::try_create(
- Gfx::IntSize size,
- u8 bit_depth, CodingIndependentCodePoints cicp,
- bool subsampling_horizontal, bool subsampling_vertical,
- Span<u16> plane_y, Span<u16> plane_u, Span<u16> plane_v)
- {
- auto plane_y_array = TRY(FixedArray<u16>::create(plane_y));
- auto plane_u_array = TRY(FixedArray<u16>::create(plane_u));
- auto plane_v_array = TRY(FixedArray<u16>::create(plane_v));
- return adopt_nonnull_own_or_enomem(new (nothrow) SubsampledYUVFrame(size, bit_depth, cicp, subsampling_horizontal, subsampling_vertical, plane_y_array, plane_u_array, plane_v_array));
- }
- DecoderErrorOr<void> SubsampledYUVFrame::output_to_bitmap(Gfx::Bitmap& bitmap)
- {
- size_t width = this->width();
- size_t height = this->height();
- auto u_sample_row = DECODER_TRY_ALLOC(FixedArray<u16>::create(width));
- auto v_sample_row = DECODER_TRY_ALLOC(FixedArray<u16>::create(width));
- size_t uv_width = width >> m_subsampling_horizontal;
- auto converter = TRY(ColorConverter::create(bit_depth(), cicp()));
- for (size_t row = 0; row < height; row++) {
- auto uv_row = row >> m_subsampling_vertical;
- // Linearly interpolate the UV samples vertically first.
- // This will write all UV samples that are located on the Y sample as well,
- // so we only need to interpolate horizontally between UV samples in the next
- // step.
- if ((row & m_subsampling_vertical) == 0 || row == height - 1) {
- for (size_t uv_column = 0; uv_column < uv_width; uv_column++) {
- size_t column = uv_column << m_subsampling_horizontal;
- size_t index = uv_row * uv_width + uv_column;
- u_sample_row[column] = m_plane_u[index];
- v_sample_row[column] = m_plane_v[index];
- }
- } else {
- for (size_t uv_column = 0; uv_column < uv_width; uv_column++) {
- size_t column = uv_column << m_subsampling_horizontal;
- size_t index = (uv_row + 1) * uv_width + uv_column;
- u_sample_row[column] = (u_sample_row[column] + m_plane_u[index]) >> 1;
- v_sample_row[column] = (v_sample_row[column] + m_plane_v[index]) >> 1;
- }
- }
- // Fill in the last pixel of the row which may not be applied by the above
- // loops if the last pixel in each row is on an uneven index.
- if ((width & 1) == 0) {
- u_sample_row[width - 1] = u_sample_row[width - 2];
- v_sample_row[width - 1] = v_sample_row[width - 2];
- }
- // Interpolate the samples horizontally.
- if (m_subsampling_horizontal) {
- for (size_t column = 1; column < width - 1; column += 2) {
- u_sample_row[column] = (u_sample_row[column - 1] + u_sample_row[column + 1]) >> 1;
- v_sample_row[column] = (v_sample_row[column - 1] + v_sample_row[column + 1]) >> 1;
- }
- }
- for (size_t column = 0; column < width; column++) {
- auto y_sample = m_plane_y[row * width + column];
- auto u_sample = u_sample_row[column];
- auto v_sample = v_sample_row[column];
- bitmap.set_pixel(Gfx::IntPoint(column, row), converter.convert_yuv_to_full_range_rgb(y_sample, u_sample, v_sample));
- /*auto r_float = clamp(y_sample + (v_sample - 128) * 219.0f / 224.0f * 1.5748f, 0, 255);
- auto g_float = clamp(y_sample + (u_sample - 128) * 219.0f / 224.0f * -0.0722f * 1.8556f / 0.7152f + (v_sample - 128) * 219.0f / 224.0f * -0.2126f * 1.5748f / 0.7152f, 0, 255);
- auto b_float = clamp(y_sample + (u_sample - 128) * 219.0f / 224.0f * 1.8556f, 0, 255);
- auto r = static_cast<u8>(r_float);
- auto g = static_cast<u8>(g_float);
- auto b = static_cast<u8>(b_float);
- bitmap.set_pixel(Gfx::IntPoint(column, row), Color(r, g, b));*/
- }
- }
- return {};
- }
- }
|