mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-31 12:13:16 +00:00
media: add YUV420p module
Converts RGBA image to YUV420p, useful for most video codecs.
This commit is contained in:
parent
650264ea86
commit
1415254131
3 changed files with 200 additions and 0 deletions
|
|
@ -9,4 +9,6 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
vorbis.cpp
|
||||
vorbis.hpp
|
||||
vorbis_error.hpp
|
||||
yuv420p.cpp
|
||||
yuv420p.hpp
|
||||
)
|
||||
|
|
|
|||
124
src/media/yuv420p.cpp
Normal file
124
src/media/yuv420p.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include <libyuv/convert.h>
|
||||
#include <libyuv/scale_argb.h>
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
#include "../cxxutil.hpp"
|
||||
#include "yuv420p.hpp"
|
||||
|
||||
using namespace srb2::media;
|
||||
|
||||
bool YUV420pFrame::BufferRGBA::resize(int width, int height)
|
||||
{
|
||||
if (width == width_ && height == height_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
row_stride = width * 4;
|
||||
|
||||
const std::size_t new_size = row_stride * height;
|
||||
|
||||
// Overallocate since the vector's alignment can't be
|
||||
// easily controlled. This is not a significant waste.
|
||||
vec_.resize(new_size + (kAlignment - 1));
|
||||
|
||||
void* p = vec_.data();
|
||||
std::size_t n = vec_.size();
|
||||
|
||||
SRB2_ASSERT(std::align(kAlignment, 1, p, n) != nullptr);
|
||||
|
||||
plane = tcb::span<uint8_t>(reinterpret_cast<uint8_t*>(p), new_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void YUV420pFrame::BufferRGBA::erase()
|
||||
{
|
||||
std::fill(vec_.begin(), vec_.end(), 0);
|
||||
}
|
||||
|
||||
void YUV420pFrame::BufferRGBA::release()
|
||||
{
|
||||
if (!vec_.empty())
|
||||
{
|
||||
*this = {};
|
||||
}
|
||||
}
|
||||
|
||||
const VideoFrame::Buffer& YUV420pFrame::rgba_buffer() const
|
||||
{
|
||||
return *rgba_;
|
||||
}
|
||||
|
||||
void YUV420pFrame::convert() const
|
||||
{
|
||||
// ABGR = RGBA in memory
|
||||
libyuv::ABGRToI420(
|
||||
rgba_->plane.data(),
|
||||
rgba_->row_stride,
|
||||
y_.plane.data(),
|
||||
y_.row_stride,
|
||||
u_.plane.data(),
|
||||
u_.row_stride,
|
||||
v_.plane.data(),
|
||||
v_.row_stride,
|
||||
width(),
|
||||
height()
|
||||
);
|
||||
}
|
||||
|
||||
void YUV420pFrame::scale(const BufferRGBA& scaled_rgba)
|
||||
{
|
||||
int vw = scaled_rgba.width();
|
||||
int vh = scaled_rgba.height();
|
||||
|
||||
uint8_t* p = scaled_rgba.plane.data();
|
||||
|
||||
const float ru = width() / static_cast<float>(height());
|
||||
const float rs = vw / static_cast<float>(vh);
|
||||
|
||||
// Maintain aspect ratio of unscaled. Fit inside scaled
|
||||
// aspect by centering image.
|
||||
|
||||
if (rs > ru) // scaled is wider
|
||||
{
|
||||
vw = vh * ru;
|
||||
p += (scaled_rgba.width() - vw) / 2 * 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
vh = vw / ru;
|
||||
p += (scaled_rgba.height() - vh) / 2 * scaled_rgba.row_stride;
|
||||
}
|
||||
|
||||
// Curiously, this function doesn't care about channel order.
|
||||
libyuv::ARGBScale(
|
||||
rgba_->plane.data(),
|
||||
rgba_->row_stride,
|
||||
width(),
|
||||
height(),
|
||||
p,
|
||||
scaled_rgba.row_stride,
|
||||
vw,
|
||||
vh,
|
||||
libyuv::FilterMode::kFilterNone
|
||||
);
|
||||
|
||||
rgba_ = &scaled_rgba;
|
||||
}
|
||||
74
src/media/yuv420p.hpp
Normal file
74
src/media/yuv420p.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_MEDIA_YUV420P_HPP__
|
||||
#define __SRB2_MEDIA_YUV420P_HPP__
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "video_frame.hpp"
|
||||
|
||||
namespace srb2::media
|
||||
{
|
||||
|
||||
class YUV420pFrame : public VideoFrame
|
||||
{
|
||||
public:
|
||||
// 32-byte aligned for AVX optimizations (see libyuv)
|
||||
static constexpr int kAlignment = 32;
|
||||
|
||||
class BufferRGBA : public VideoFrame::Buffer
|
||||
{
|
||||
public:
|
||||
bool resize(int width, int height); // true if resized
|
||||
|
||||
void erase(); // fills with black
|
||||
void release();
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
private:
|
||||
int width_, height_;
|
||||
|
||||
std::vector<uint8_t> vec_;
|
||||
};
|
||||
|
||||
YUV420pFrame(int pts, Buffer y, Buffer u, Buffer v, const BufferRGBA& rgba) :
|
||||
VideoFrame(pts), y_(y), u_(u), v_(v), rgba_(&rgba)
|
||||
{
|
||||
}
|
||||
|
||||
~YUV420pFrame() = default;
|
||||
|
||||
// Simply resets PTS and RGBA buffer while keeping YUV
|
||||
// buffers intact.
|
||||
void reset(int pts, const BufferRGBA& rgba) { *this = YUV420pFrame(pts, y_, u_, v_, rgba); }
|
||||
|
||||
// Converts RGBA buffer to YUV planes.
|
||||
void convert() const;
|
||||
|
||||
// Scales the existing buffer into a new one. This new
|
||||
// buffer replaces the existing one.
|
||||
void scale(const BufferRGBA& rgba);
|
||||
|
||||
virtual int width() const override { return rgba_->width(); }
|
||||
virtual int height() const override { return rgba_->height(); }
|
||||
|
||||
virtual const Buffer& rgba_buffer() const override;
|
||||
|
||||
private:
|
||||
Buffer y_, u_, v_;
|
||||
const BufferRGBA* rgba_;
|
||||
};
|
||||
|
||||
}; // namespace srb2::media
|
||||
|
||||
#endif // __SRB2_MEDIA_YUV420P_HPP__
|
||||
Loading…
Add table
Reference in a new issue