various: pixel optimizations

Several things are accomplished in this commit, including:

- Use OIIO instead of our own functions for pixel format conversions
  (cleaner code/less for us to maintain)

- Fold all PixelService functions into the PixelFormat class
  (cleaner code)

- Moved OpenGL pixel definitions to OpenGL classes and out of the
  global classes.

- Add support for RGB buffers as well as RGBA (optimization)
This commit is contained in:
itsmattkc
2020-02-27 13:54:38 +11:00
parent 0624184b18
commit 02ce48d0c6
27 changed files with 491 additions and 564 deletions
-2
View File
@@ -28,8 +28,6 @@ set(OLIVE_SOURCES
render/diskmanager.cpp
render/pixelformat.h
render/pixelformat.cpp
render/pixelservice.h
render/pixelservice.cpp
render/rendermodes.h
render/videoparams.h
render/videoparams.cpp
+2 -2
View File
@@ -3,7 +3,7 @@
#include "render/backend/audio/audiobackend.h"
#include "render/backend/opengl/openglbackend.h"
#include "render/colormanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
Exporter::Exporter(ViewerOutput* viewer,
Encoder *encoder,
@@ -121,7 +121,7 @@ void Exporter::EncodeFrame()
// OCIO conversion requires a frame in 32F format
if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) {
frame = PixelService::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
}
// Color conversion must be done with unassociated alpha, and the pipeline is always associated
+4 -6
View File
@@ -9,7 +9,7 @@
#include "openglcolorprocessor.h"
#include "openglrenderfunctions.h"
#include "render/colormanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
OpenGLProxy::OpenGLProxy(QObject *parent) :
QObject(parent),
@@ -90,7 +90,7 @@ void OpenGLProxy::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeR
}
// Convert frame to float for OCIO
frame = PixelService::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
// Perform color transform
color_processor->ConvertFrame(frame);
@@ -384,8 +384,6 @@ void OpenGLProxy::TextureToBuffer(const QVariant &tex_in, void *buffer)
{
OpenGLTextureCache::ReferencePtr texture = tex_in.value<OpenGLTextureCache::ReferencePtr>();
PixelFormat::Info format_info = PixelService::GetPixelFormatInfo(video_params_.format());
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
buffer_.Attach(texture->texture());
buffer_.Bind();
@@ -394,8 +392,8 @@ void OpenGLProxy::TextureToBuffer(const QVariant &tex_in, void *buffer)
0,
video_params_.effective_width(),
video_params_.effective_height(),
format_info.pixel_format,
format_info.gl_pixel_type,
OpenGLRenderFunctions::GetPixelFormat(video_params_.format()),
OpenGLRenderFunctions::GetPixelType(video_params_.format()),
buffer);
buffer_.Release();
@@ -71,6 +71,67 @@ void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f) {
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
GLint OpenGLRenderFunctions::GetInternalFormat(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
return GL_RGB8;
case PixelFormat::PIX_FMT_RGBA8:
return GL_RGBA8;
case PixelFormat::PIX_FMT_RGB16U:
return GL_RGB16;
case PixelFormat::PIX_FMT_RGBA16U:
return GL_RGBA16;
case PixelFormat::PIX_FMT_RGB16F:
return GL_RGB16F;
case PixelFormat::PIX_FMT_RGBA16F:
return GL_RGBA16F;
case PixelFormat::PIX_FMT_RGB32F:
return GL_RGB32F;
case PixelFormat::PIX_FMT_RGBA32F:
return GL_RGBA32F;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return GL_INVALID_VALUE;
}
GLenum OpenGLRenderFunctions::GetPixelFormat(const PixelFormat::Format &format)
{
if (PixelFormat::FormatHasAlphaChannel(format)) {
return GL_RGBA;
} else {
return GL_RGB;
}
}
GLenum OpenGLRenderFunctions::GetPixelType(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
return GL_UNSIGNED_BYTE;
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
return GL_UNSIGNED_SHORT;
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
return GL_HALF_FLOAT;
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
return GL_FLOAT;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return GL_INVALID_VALUE;
}
void OpenGLRenderFunctions::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix4x4 matrix) {
// FIXME: is currentContext() reliable here?
QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions();
@@ -26,6 +26,7 @@
#include <QOpenGLFunctions>
#include "openglshader.h"
#include "render/pixelformat.h"
class OpenGLRenderFunctions {
public:
@@ -50,6 +51,12 @@ public:
static void PrepareToDraw(QOpenGLFunctions* f);
static GLint GetInternalFormat(const PixelFormat::Format& format);
static GLenum GetPixelFormat(const PixelFormat::Format& format);
static GLenum GetPixelType(const PixelFormat::Format& format);
};
#endif // OPENGLFUNCTIONS_H
+7 -10
View File
@@ -23,7 +23,8 @@
#include <QDateTime>
#include <QDebug>
#include "render/pixelservice.h"
#include "openglrenderfunctions.h"
#include "render/pixelformat.h"
OpenGLTexture::OpenGLTexture() :
created_ctx_(nullptr),
@@ -120,16 +121,14 @@ void OpenGLTexture::Upload(const void *data)
Bind();
PixelFormat::Info info = PixelService::GetPixelFormatInfo(format_);
created_ctx_->functions()->glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
width_,
height_,
info.pixel_format,
info.gl_pixel_type,
OpenGLRenderFunctions::GetPixelFormat(format_),
OpenGLRenderFunctions::GetPixelType(format_),
data);
Release();
@@ -152,16 +151,14 @@ void OpenGLTexture::CreateInternal(QOpenGLContext* create_ctx, GLuint* tex, cons
f->glBindTexture(GL_TEXTURE_2D, *tex);
// Allocate storage for texture
const PixelFormat::Info& bit_depth = PixelService::GetPixelFormatInfo(format_);
f->glTexImage2D(GL_TEXTURE_2D,
0,
bit_depth.internal_format,
OpenGLRenderFunctions::GetInternalFormat(format_),
width_,
height_,
0,
bit_depth.pixel_format,
bit_depth.gl_pixel_type,
OpenGLRenderFunctions::GetPixelFormat(format_),
OpenGLRenderFunctions::GetPixelType(format_),
data);
// Set texture filtering to bilinear
+1 -1
View File
@@ -7,7 +7,7 @@
#include "openglcolorprocessor.h"
#include "openglrenderfunctions.h"
#include "render/colormanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
OpenGLWorker::OpenGLWorker(VideoRenderFrameCache *frame_cache, DecoderCache* decoder_cache, QObject *parent) :
VideoRenderWorker(frame_cache, decoder_cache, parent)
+1 -1
View File
@@ -31,7 +31,7 @@
#include "config/config.h"
#include "render/diskmanager.h"
#include "render/diskmanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
#include "videorenderworker.h"
VideoRenderBackend::VideoRenderBackend(QObject *parent) :
+8 -7
View File
@@ -1,17 +1,17 @@
#include "videorenderworker.h"
#include "common/define.h"
#include "common/functiontimer.h"
#include "node/block/transition/transition.h"
#include "node/node.h"
#include "project/project.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
VideoRenderWorker::VideoRenderWorker(VideoRenderFrameCache *frame_cache, DecoderCache* decoder_cache, QObject *parent) :
RenderWorker(decoder_cache, parent),
frame_cache_(frame_cache),
operating_mode_(kHashRenderCache)
{
}
const VideoRenderingParams &VideoRenderWorker::video_params()
@@ -225,10 +225,11 @@ void VideoRenderWorker::CloseInternal()
void VideoRenderWorker::Download(const rational& time, QVariant texture, QString filename)
{
PixelFormat::Info format_info = PixelService::GetPixelFormatInfo(video_params().format());
// Set up OIIO::ImageSpec for compressing cached images on disk
OIIO::ImageSpec spec(video_params().effective_width(), video_params().effective_height(), kRGBAChannels, format_info.oiio_desc);
OIIO::ImageSpec spec(video_params().effective_width(),
video_params().effective_height(),
PixelFormat::ChannelCount(video_params().format()),
PixelFormat::GetOIIOTypeDesc(video_params().format()));
if (video_params_.format() != PixelFormat::PIX_FMT_RGBA8
&& video_params_.format() != PixelFormat::PIX_FMT_RGBA16U) {
@@ -249,7 +250,7 @@ void VideoRenderWorker::Download(const rational& time, QVariant texture, QString
if (out) {
out->open(working_fn_std, spec);
out->write_image(format_info.oiio_desc, download_buffer_.data());
out->write_image(PixelFormat::GetOIIOTypeDesc(video_params().format()), download_buffer_.data());
out->close();
#if OIIO_VERSION < 10903
@@ -276,7 +277,7 @@ void VideoRenderWorker::Download(const rational& time, QVariant texture, QString
void VideoRenderWorker::ResizeDownloadBuffer()
{
download_buffer_.resize(PixelService::GetBufferSize(video_params_.format(), video_params_.effective_width(), video_params_.effective_height()));
download_buffer_.resize(PixelFormat::GetBufferSize(video_params_.format(), video_params_.effective_width(), video_params_.effective_height()));
}
NodeValueTable VideoRenderWorker::RenderBlock(const TrackOutput *track, const TimeRange &range)
+9
View File
@@ -123,6 +123,11 @@ void ColorManager::SetOCIOMethodForMode(RenderMode::Mode mode, ColorManager::OCI
void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f)
{
if (!PixelFormat::FormatHasAlphaChannel(f->format())) {
// This frame has no alpha channel, do nothing
return;
}
int pixel_count = f->width() * f->height() * kRGBAChannels;
switch (static_cast<PixelFormat::Format>(f->format())) {
@@ -130,15 +135,19 @@ void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action,
case PixelFormat::PIX_FMT_COUNT:
qWarning() << "Alpha association functions received an invalid pixel format";
break;
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
qWarning() << "Alpha association functions only works on float-based pixel formats at this time";
break;
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
{
AssociateAlphaInternal<qfloat16>(action, reinterpret_cast<qfloat16*>(f->data()), pixel_count);
break;
}
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
{
AssociateAlphaInternal<float>(action, reinterpret_cast<float*>(f->data()), pixel_count);
+1 -1
View File
@@ -38,7 +38,7 @@ ColorProcessor::ColorProcessor(OCIO::ConstConfigRcPtr config,
void ColorProcessor::ConvertFrame(FramePtr f)
{
OCIO::PackedImageDesc img(reinterpret_cast<float*>(f->data()), f->width(), f->height(), kRGBAChannels);
OCIO::PackedImageDesc img(reinterpret_cast<float*>(f->data()), f->width(), f->height(), PixelFormat::ChannelCount(f->format()));
processor->apply(img);
}
+234
View File
@@ -19,3 +19,237 @@
***/
#include "pixelformat.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFloat16>
#include "common/define.h"
#include "core.h"
bool PixelFormat::FormatHasAlphaChannel(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGBA8:
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGBA32F:
return true;
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return false;
}
OIIO::TypeDesc PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
return OIIO::TypeDesc::UINT8;
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
return OIIO::TypeDesc::UINT16;
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
return OIIO::TypeDesc::HALF;
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
return OIIO::TypeDesc::FLOAT;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return OIIO::TypeDesc::UNKNOWN;
}
QString PixelFormat::GetName(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
return tr("8-bit");
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
return tr("16-bit Integer");
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
return tr("Half-Float (16-bit)");
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
return tr("Full-Float (32-bit)");
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return tr("Unknown (%1)").arg(format);
}
PixelFormat* PixelFormat::instance_ = nullptr;
void PixelFormat::CreateInstance()
{
instance_ = new PixelFormat();
}
void PixelFormat::DestroyInstance()
{
delete instance_;
}
PixelFormat *PixelFormat::instance()
{
return instance_;
}
PixelFormat::Format PixelFormat::GetConfiguredFormatForMode(RenderMode::Mode mode)
{
return static_cast<PixelFormat::Format>(Core::GetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat")).toInt());
}
void PixelFormat::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format)
{
if (format != GetConfiguredFormatForMode(mode)) {
Core::SetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat"), format);
emit FormatChanged();
}
}
PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha)
{
if (desc == OIIO::TypeDesc::UINT8) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8;
} else if (desc == OIIO::TypeDesc::UINT16) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U;
} else if (desc == OIIO::TypeDesc::HALF) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F;
} else if (desc == OIIO::TypeDesc::FLOAT) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F;
}
return PixelFormat::PIX_FMT_INVALID;
}
/*PixelFormat::Info PixelFormat::GetPixelFormatInfo(const PixelFormat::Format &format)
{
PixelFormat::Info info;
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
info.name = tr("8-bit");
info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA8;
info.gl_pixel_type = GL_UNSIGNED_BYTE;
info.oiio_desc = OIIO::TypeDesc::UINT8;
break;
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
info.name = tr("16-bit Integer");
info.internal_format = (format == PixelFormat::PIX_FMT_RGB16U) ? GL_RGB8 : GL_RGBA16;
info.gl_pixel_type = GL_UNSIGNED_SHORT;
info.oiio_desc = OIIO::TypeDesc::UINT16;
break;
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
info.name = tr("Half-Float (16-bit)");
info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA16F;
info.gl_pixel_type = GL_HALF_FLOAT;
info.oiio_desc = OIIO::TypeDesc::HALF;
break;
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
info.name = tr("Full-Float (32-bit)");
info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA32F;
info.gl_pixel_type = GL_FLOAT;
info.oiio_desc = OIIO::TypeDesc::FLOAT;
break;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
qFatal("Invalid pixel format requested");
}
info.pixel_format = GL_RGBA;
info.bytes_per_pixel = BytesPerPixel(format);
return info;
}*/
int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height)
{
return BytesPerPixel(format) * width * height;
}
int PixelFormat::BytesPerPixel(const PixelFormat::Format &format)
{
return BytesPerChannel(format) * ChannelCount(format);
}
int PixelFormat::BytesPerChannel(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
return 1;
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_RGBA16F:
return 2;
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
return 4;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
qFatal("Invalid pixel format requested");
// qFatal will abort so we won't get here, but this suppresses compiler warnings
return 0;
}
int PixelFormat::ChannelCount(const PixelFormat::Format &format)
{
if (PixelFormat::FormatHasAlphaChannel(format)) {
return kRGBAChannels;
} else {
return kRGBChannels;
}
}
FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format)
{
if (frame->format() == dest_format) {
return frame;
}
FramePtr converted = Frame::Create();
// Copy parameters
converted->set_width(frame->width());
converted->set_height(frame->height());
converted->set_timestamp(frame->timestamp());
converted->set_format(dest_format);
converted->allocate();
OIIO::TypeDesc src_type = GetOIIOTypeDesc(frame->format());
OIIO::TypeDesc dst_type = GetOIIOTypeDesc(dest_format);
if (OIIO::convert_type(src_type, frame->data(), dst_type, converted->data())) {
return converted;
} else {
qDebug() << "Failed to convert type:" << OIIO::geterror().c_str();
return nullptr;
}
}
+89 -17
View File
@@ -25,7 +25,14 @@
#include <QOpenGLExtraFunctions>
#include <QString>
class PixelFormat {
#include "render/rendermodes.h"
class Frame;
using FramePtr = std::shared_ptr<Frame>;
class PixelFormat : public QObject
{
Q_OBJECT
public:
/**
* @brief Olive's internal supported pixel formats.
@@ -38,27 +45,92 @@ public:
PIX_FMT_RGBA16F,
PIX_FMT_RGBA32F,
PIX_FMT_RGB8,
PIX_FMT_RGB16U,
PIX_FMT_RGB16F,
PIX_FMT_RGB32F,
PIX_FMT_COUNT
};
static void CreateInstance();
static void DestroyInstance();
static PixelFormat* instance();
/**
* @brief A struct of information pertaining to each enum PixelFormat.
*
* Primarily this is a means of retrieving OpenGL texture information for different pixel formats/bit depths. Both
* RAM and VRAM buffers will need a PixelFormat. To keep consistency between the OpenGL code and CPU code when using
* a given PixelFormat, the PixelFormatInfo struct contains all necessary variables that you'll need to plug into
* OpenGL.
*
* Use the static function PixelService::GetPixelFormatInfo to generate a PixelFormatInfo object.
* @brief Returns the configured pixel format for a given mode
*/
struct Info {
QString name;
GLint internal_format;
GLenum pixel_format;
GLenum gl_pixel_type;
int bytes_per_pixel;
OIIO::TypeDesc oiio_desc;
};
Format GetConfiguredFormatForMode(RenderMode::Mode mode);
void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format);
static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha);
/**
* @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height.
*
* @param format
*
* The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum.
*
* @param width
*
* The width (in pixels) of the buffer.
*
* @param height
*
* The height (in pixels) of the buffer.
*/
static int GetBufferSize(const Format &format, const int& width, const int& height);
/**
* @brief Returns the number of bytes per pixel for a certain format
*
* Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel
* requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and
* are at least 1 bpc.
*/
static int BytesPerPixel(const Format &format);
/**
* @brief Returns the number of bytes per channel for a certain format
*/
static int BytesPerChannel(const Format& format);
/**
* @brief Return the number of channels in this format
*/
static int ChannelCount(const Format& format);
/**
* @brief Convert a frame to a pixel format
*
* If the frame's pixel format == the destination format, this just returns `frame`.
*/
static FramePtr ConvertPixelFormat(FramePtr frame, const Format &dest_format);
/**
* @brief Simple convenience function returning whether a pixel format has an alpha channel or not
*/
static bool FormatHasAlphaChannel(const Format& format);
/**
* @brief Get corresponding OpenImageIO TypeDesc for a given pixel format
*/
static OIIO::TypeDesc GetOIIOTypeDesc(const Format& format);
/**
* @brief Get format name
*/
static QString GetName(const Format& format);
signals:
void FormatChanged();
private:
PixelFormat() = default;
static PixelFormat* instance_;
};
#endif // BITDEPTHS_H
-366
View File
@@ -1,366 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "pixelservice.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFloat16>
#include "common/define.h"
#include "core.h"
PixelService* PixelService::instance_ = nullptr;
void PixelService::CreateInstance()
{
instance_ = new PixelService();
}
void PixelService::DestroyInstance()
{
delete instance_;
}
PixelService *PixelService::instance()
{
return instance_;
}
PixelFormat::Format PixelService::GetConfiguredFormatForMode(RenderMode::Mode mode)
{
return static_cast<PixelFormat::Format>(Core::GetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat")).toInt());
}
void PixelService::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format)
{
if (format != GetConfiguredFormatForMode(mode)) {
Core::SetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat"), format);
emit FormatChanged();
}
}
PixelFormat::Format PixelService::OIIOFormatToOliveFormat(OIIO::TypeDesc desc)
{
if (desc == OIIO::TypeDesc::UINT8) {
return PixelFormat::PIX_FMT_RGBA8;
} else if (desc == OIIO::TypeDesc::UINT16) {
return PixelFormat::PIX_FMT_RGBA16U;
} else if (desc == OIIO::TypeDesc::HALF) {
return PixelFormat::PIX_FMT_RGBA16F;
} else if (desc == OIIO::TypeDesc::FLOAT) {
return PixelFormat::PIX_FMT_RGBA32F;
}
return PixelFormat::PIX_FMT_INVALID;
}
PixelFormat::Info PixelService::GetPixelFormatInfo(const PixelFormat::Format &format)
{
PixelFormat::Info info;
switch (format) {
case PixelFormat::PIX_FMT_RGBA8:
info.name = tr("8-bit");
info.internal_format = GL_RGBA8;
info.gl_pixel_type = GL_UNSIGNED_BYTE;
info.oiio_desc = OIIO::TypeDesc::UINT8;
break;
case PixelFormat::PIX_FMT_RGBA16U:
info.name = tr("16-bit Integer");
info.internal_format = GL_RGBA16;
info.gl_pixel_type = GL_UNSIGNED_SHORT;
info.oiio_desc = OIIO::TypeDesc::UINT16;
break;
case PixelFormat::PIX_FMT_RGBA16F:
info.name = tr("Half-Float (16-bit)");
info.internal_format = GL_RGBA16F;
info.gl_pixel_type = GL_HALF_FLOAT;
info.oiio_desc = OIIO::TypeDesc::HALF;
break;
case PixelFormat::PIX_FMT_RGBA32F:
info.name = tr("Full-Float (32-bit)");
info.internal_format = GL_RGBA32F;
info.gl_pixel_type = GL_FLOAT;
info.oiio_desc = OIIO::TypeDesc::FLOAT;
break;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
qFatal("Invalid pixel format requested");
}
info.pixel_format = GL_RGBA;
info.bytes_per_pixel = BytesPerPixel(format);
return info;
}
int PixelService::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height)
{
return BytesPerPixel(format) * width * height;
}
int PixelService::BytesPerPixel(const PixelFormat::Format &format)
{
return BytesPerChannel(format) * kRGBAChannels;
}
int PixelService::BytesPerChannel(const PixelFormat::Format &format)
{
switch (format) {
case PixelFormat::PIX_FMT_RGBA8:
return 1;
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_RGBA16F:
return 2;
case PixelFormat::PIX_FMT_RGBA32F:
return 4;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
qFatal("Invalid pixel format requested");
// qFatal will abort so we won't get here, but this suppresses compiler warnings
return 0;
}
FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format)
{
if (frame->format() == dest_format) {
return frame;
}
// FIXME: It'd be nice if this was multithreaded soon
FramePtr converted = Frame::Create();
// Copy parameters
converted->set_width(frame->width());
converted->set_height(frame->height());
converted->set_timestamp(frame->timestamp());
converted->set_format(dest_format);
converted->allocate();
int pix_count = frame->width() * frame->height() * kRGBAChannels;
bool valid = true;
switch (static_cast<PixelFormat::Format>(frame->format())) {
case PixelFormat::PIX_FMT_RGBA8:
{
uint8_t* source = reinterpret_cast<uint8_t*>(frame->data());
switch (dest_format) {
case PixelFormat::PIX_FMT_RGBA16U: // 8-bit Integer -> 16-bit Integer
{
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint16_t>(source[i] * 257);
}
break;
}
case PixelFormat::PIX_FMT_RGBA16F: // 8-bit Integer -> 16-bit Float
{
qfloat16* destination = reinterpret_cast<qfloat16*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i] / 255.0f;
}
break;
}
case PixelFormat::PIX_FMT_RGBA32F: // 8-bit Integer -> 32-bit Float
{
float* destination = reinterpret_cast<float*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i] / 255.0f;
}
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_RGBA8:
case PixelFormat::PIX_FMT_COUNT:
valid = false;
}
break;
}
case PixelFormat::PIX_FMT_RGBA16U:
{
uint16_t* source = reinterpret_cast<uint16_t*>(frame->data());
switch (dest_format) {
case PixelFormat::PIX_FMT_RGBA8: // 16-bit Integer -> 8-bit Integer
{
uint8_t* destination = reinterpret_cast<uint8_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint8_t>(source[i] / 257);
}
break;
}
case PixelFormat::PIX_FMT_RGBA16F: // 16-bit Integer -> 16-bit Float
{
qfloat16* destination = reinterpret_cast<qfloat16*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i] / 65535.0f;
}
break;
}
case PixelFormat::PIX_FMT_RGBA32F: // 16-bit Integer -> 32-bit Float
{
float* destination = reinterpret_cast<float*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i] / 65535.0f;
}
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_COUNT:
valid = false;
}
break;
}
case PixelFormat::PIX_FMT_RGBA16F:
{
qfloat16* source = reinterpret_cast<qfloat16*>(frame->data());
switch (dest_format) {
case PixelFormat::PIX_FMT_RGBA8: // 16-bit Float -> 8-bit Integer
{
uint8_t* destination = reinterpret_cast<uint8_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint8_t>(source[i] * 255.0f);
}
break;
}
case PixelFormat::PIX_FMT_RGBA16U: // 16-bit Float -> 16-bit Integer
{
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint16_t>(source[i] * 65535.0f);
}
break;
}
case PixelFormat::PIX_FMT_RGBA32F: // 16-bit Float -> 32-bit Float
{
float* destination = reinterpret_cast<float*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i];
}
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_COUNT:
valid = false;
}
break;
}
case PixelFormat::PIX_FMT_RGBA32F:
{
float* source = reinterpret_cast<float*>(frame->data());
switch (dest_format) {
case PixelFormat::PIX_FMT_RGBA8: // 32-bit Float -> 8-bit Integer
{
uint8_t* destination = reinterpret_cast<uint8_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint8_t>(source[i] * 255.0f);
}
break;
}
case PixelFormat::PIX_FMT_RGBA16U: // 32-bit Float -> 16-bit Integer
{
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = static_cast<uint16_t>(source[i] * 65535.0f);
}
break;
}
case PixelFormat::PIX_FMT_RGBA16F: // 32-bit Float -> 16-bit Float
{
qfloat16* destination = reinterpret_cast<qfloat16*>(converted->data());
for (int i=0;i<pix_count;i++) {
destination[i] = source[i];
}
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_RGBA32F:
case PixelFormat::PIX_FMT_COUNT:
valid = false;
}
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
valid = false;
}
if (valid) {
return converted;
}
qWarning() << "Invalid parameters called for pixel format conversion";
return nullptr;
}
void PixelService::ConvertRGBtoRGBA(FramePtr frame)
{
PixelFormat::Format dest_format = static_cast<PixelFormat::Format>(frame->format());
int rgb_pixel_size = BytesPerChannel(dest_format) * kRGBChannels;
int rgb_frame_size = frame->width() * frame->height() * rgb_pixel_size;
int rgb_iter = rgb_frame_size - rgb_pixel_size;
int rgba_pixel_size = BytesPerChannel(dest_format) * kRGBAChannels;
int rgba_frame_size = frame->width() * frame->height() * rgba_pixel_size;
int rgba_iter = rgba_frame_size - rgba_pixel_size;
// Work backwards to save time
while (rgb_iter >= 0) {
memcpy(&frame->data()[rgba_iter], &frame->data()[rgb_iter], static_cast<size_t>(rgb_pixel_size));
uint8_t* alpha_ptr = reinterpret_cast<uint8_t*>(frame->data()) + rgba_iter + rgb_pixel_size;
// Write a full alpha value according to the format
switch (dest_format) {
case PixelFormat::PIX_FMT_RGBA8:
*alpha_ptr = UINT8_MAX;
break;
case PixelFormat::PIX_FMT_RGBA16U:
*reinterpret_cast<uint16_t*>(alpha_ptr) = UINT16_MAX;
break;
case PixelFormat::PIX_FMT_RGBA16F:
*reinterpret_cast<qfloat16*>(alpha_ptr) = 1.0f;
break;
case PixelFormat::PIX_FMT_RGBA32F:
*reinterpret_cast<float*>(alpha_ptr) = 1.0f;
break;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
qFatal("Invalid pixel format requested");
}
rgb_iter -= rgb_pixel_size;
rgba_iter -= rgba_pixel_size;
}
}
-106
View File
@@ -1,106 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef PIXELSERVICE_H
#define PIXELSERVICE_H
#include <QString>
#include "codec/frame.h"
#include "pixelformat.h"
#include "render/rendermodes.h"
class PixelService : public QObject
{
Q_OBJECT
public:
static void CreateInstance();
static void DestroyInstance();
static PixelService* instance();
/**
* @brief Returns the configured pixel format for a given mode
*/
PixelFormat::Format GetConfiguredFormatForMode(RenderMode::Mode mode);
void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format);
static PixelFormat::Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc);
/**
* @brief Return a PixelFormatInfo containing information for a certain format
*
* \see PixelFormatInfo
*/
static PixelFormat::Info GetPixelFormatInfo(const PixelFormat::Format& format);
/**
* @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height.
*
* @param format
*
* The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum.
*
* @param width
*
* The width (in pixels) of the buffer.
*
* @param height
*
* The height (in pixels) of the buffer.
*/
static int GetBufferSize(const PixelFormat::Format &format, const int& width, const int& height);
/**
* @brief Returns the number of bytes per pixel for a certain format
*
* Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel
* requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and
* are at least 1 bpc.
*/
static int BytesPerPixel(const PixelFormat::Format &format);
/**
* @brief Returns the number of bytes per channel for a certain format
*/
static int BytesPerChannel(const PixelFormat::Format& format);
/**
* @brief Convert a frame to a pixel format
*
* If the frame's pixel format == the destination format, this just returns `frame`.
*/
static FramePtr ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format);
/**
* @brief Convert an RGB image to an RGBA image
*/
static void ConvertRGBtoRGBA(FramePtr frame);
signals:
void FormatChanged();
private:
PixelService() = default;
static PixelService* instance_;
};
#endif // PIXELSERVICE_H