Serenity Operating System
at master 94 lines 4.2 kB view raw
1/* 2 * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/NonnullOwnPtr.h> 8#include <AK/OwnPtr.h> 9#include <LibVideo/Color/ColorConverter.h> 10 11#include "VideoFrame.h" 12 13namespace Video { 14 15ErrorOr<NonnullOwnPtr<SubsampledYUVFrame>> SubsampledYUVFrame::try_create( 16 Gfx::IntSize size, 17 u8 bit_depth, CodingIndependentCodePoints cicp, 18 bool subsampling_horizontal, bool subsampling_vertical, 19 Span<u16> plane_y, Span<u16> plane_u, Span<u16> plane_v) 20{ 21 auto plane_y_array = TRY(FixedArray<u16>::create(plane_y)); 22 auto plane_u_array = TRY(FixedArray<u16>::create(plane_u)); 23 auto plane_v_array = TRY(FixedArray<u16>::create(plane_v)); 24 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)); 25} 26 27DecoderErrorOr<void> SubsampledYUVFrame::output_to_bitmap(Gfx::Bitmap& bitmap) 28{ 29 size_t width = this->width(); 30 size_t height = this->height(); 31 auto u_sample_row = DECODER_TRY_ALLOC(FixedArray<u16>::create(width)); 32 auto v_sample_row = DECODER_TRY_ALLOC(FixedArray<u16>::create(width)); 33 size_t uv_width = width >> m_subsampling_horizontal; 34 35 auto converter = TRY(ColorConverter::create(bit_depth(), cicp())); 36 37 for (size_t row = 0; row < height; row++) { 38 auto uv_row = row >> m_subsampling_vertical; 39 40 // Linearly interpolate the UV samples vertically first. 41 // This will write all UV samples that are located on the Y sample as well, 42 // so we only need to interpolate horizontally between UV samples in the next 43 // step. 44 if ((row & m_subsampling_vertical) == 0 || row == height - 1) { 45 for (size_t uv_column = 0; uv_column < uv_width; uv_column++) { 46 size_t column = uv_column << m_subsampling_horizontal; 47 size_t index = uv_row * uv_width + uv_column; 48 u_sample_row[column] = m_plane_u[index]; 49 v_sample_row[column] = m_plane_v[index]; 50 } 51 } else { 52 for (size_t uv_column = 0; uv_column < uv_width; uv_column++) { 53 size_t column = uv_column << m_subsampling_horizontal; 54 size_t index = (uv_row + 1) * uv_width + uv_column; 55 u_sample_row[column] = (u_sample_row[column] + m_plane_u[index]) >> 1; 56 v_sample_row[column] = (v_sample_row[column] + m_plane_v[index]) >> 1; 57 } 58 } 59 // Fill in the last pixel of the row which may not be applied by the above 60 // loops if the last pixel in each row is on an uneven index. 61 if ((width & 1) == 0) { 62 u_sample_row[width - 1] = u_sample_row[width - 2]; 63 v_sample_row[width - 1] = v_sample_row[width - 2]; 64 } 65 66 // Interpolate the samples horizontally. 67 if (m_subsampling_horizontal) { 68 for (size_t column = 1; column < width - 1; column += 2) { 69 u_sample_row[column] = (u_sample_row[column - 1] + u_sample_row[column + 1]) >> 1; 70 v_sample_row[column] = (v_sample_row[column - 1] + v_sample_row[column + 1]) >> 1; 71 } 72 } 73 74 for (size_t column = 0; column < width; column++) { 75 auto y_sample = m_plane_y[row * width + column]; 76 auto u_sample = u_sample_row[column]; 77 auto v_sample = v_sample_row[column]; 78 79 bitmap.set_pixel(Gfx::IntPoint(column, row), converter.convert_yuv_to_full_range_rgb(y_sample, u_sample, v_sample)); 80 81 /*auto r_float = clamp(y_sample + (v_sample - 128) * 219.0f / 224.0f * 1.5748f, 0, 255); 82 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); 83 auto b_float = clamp(y_sample + (u_sample - 128) * 219.0f / 224.0f * 1.8556f, 0, 255); 84 auto r = static_cast<u8>(r_float); 85 auto g = static_cast<u8>(g_float); 86 auto b = static_cast<u8>(b_float); 87 bitmap.set_pixel(Gfx::IntPoint(column, row), Color(r, g, b));*/ 88 } 89 } 90 91 return {}; 92} 93 94}