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
+14
View File
@@ -3,7 +3,9 @@
AVPixelFormat FFmpegCommon::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt)
{
AVPixelFormat possible_pix_fmts[] = {
AV_PIX_FMT_RGB24,
AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGB48,
AV_PIX_FMT_RGBA64,
AV_PIX_FMT_NONE
};
@@ -73,8 +75,14 @@ AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_
return AV_PIX_FMT_RGBA;
case PixelFormat::PIX_FMT_RGBA16U:
return AV_PIX_FMT_RGBA64;
case PixelFormat::PIX_FMT_RGB8:
return AV_PIX_FMT_RGB24;
case PixelFormat::PIX_FMT_RGB16U:
return AV_PIX_FMT_RGB48;
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGBA32F:
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
@@ -86,8 +94,14 @@ AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_
PixelFormat::Format FFmpegCommon::GetCompatiblePixelFormat(const PixelFormat::Format &pix_fmt)
{
switch (pix_fmt) {
case PixelFormat::PIX_FMT_RGB8:
return PixelFormat::PIX_FMT_RGB8;
case PixelFormat::PIX_FMT_RGBA8:
return PixelFormat::PIX_FMT_RGBA8;
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGB32F:
return PixelFormat::PIX_FMT_RGB16U;
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGBA32F:
+14 -5
View File
@@ -40,7 +40,7 @@ extern "C" {
#include "common/timecodefunctions.h"
#include "ffmpegcommon.h"
#include "render/diskmanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
FFmpegDecoder::FFmpegDecoder() :
fmt_ctx_(nullptr),
@@ -154,11 +154,20 @@ bool FFmpegDecoder::Open()
// Determine which Olive native pixel format we retrieved
// Note that FFmpeg doesn't support float formats
if (ideal_pix_fmt_ == AV_PIX_FMT_RGBA) {
switch (ideal_pix_fmt_) {
case AV_PIX_FMT_RGB24:
native_pix_fmt_ = PixelFormat::PIX_FMT_RGB8;
break;
case AV_PIX_FMT_RGBA:
native_pix_fmt_ = PixelFormat::PIX_FMT_RGBA8;
} else if (ideal_pix_fmt_ == AV_PIX_FMT_RGBA64) {
break;
case AV_PIX_FMT_RGB48:
native_pix_fmt_ = PixelFormat::PIX_FMT_RGB16U;
break;
case AV_PIX_FMT_RGBA64:
native_pix_fmt_ = PixelFormat::PIX_FMT_RGBA16U;
} else {
break;
default:
// We should never get here, but just in case...
qFatal("Invalid output format");
}
@@ -378,7 +387,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
// Convert frame to RGBA for the rest of the pipeline
uint8_t* output_data = reinterpret_cast<uint8_t*>(working_frame_converted->data());
int output_linesize = working_frame_converted->width() * kRGBAChannels * PixelService::BytesPerChannel(native_pix_fmt_);
int output_linesize = working_frame_converted->width() * PixelFormat::ChannelCount(native_pix_fmt_) * PixelFormat::BytesPerChannel(native_pix_fmt_);
sws_scale(scale_ctx_,
working_frame->data,
+3 -3
View File
@@ -3,7 +3,7 @@
#include <QFile>
#include "ffmpegcommon.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
FFmpegEncoder::FFmpegEncoder(const EncodingParams &params) :
Encoder(params),
@@ -188,12 +188,12 @@ void FFmpegEncoder::WriteInternal(FramePtr frame)
// We may need to convert this frame to a frame that swscale will understand
if (frame->format() != video_conversion_fmt_) {
frame = PixelService::ConvertPixelFormat(frame, video_conversion_fmt_);
frame = PixelFormat::ConvertPixelFormat(frame, video_conversion_fmt_);
}
// Use swscale context to convert formats/linesizes
input_data = frame->const_data();
input_linesize = frame->width() * PixelService::BytesPerPixel(video_conversion_fmt_);
input_linesize = frame->width() * PixelFormat::BytesPerPixel(video_conversion_fmt_);
error_code = sws_scale(video_scale_ctx_,
reinterpret_cast<const uint8_t**>(&input_data),
&input_linesize,
+1 -3
View File
@@ -23,8 +23,6 @@
#include <QDebug>
#include <QtGlobal>
#include "render/pixelservice.h"
Frame::Frame() :
width_(0),
height_(0),
@@ -139,7 +137,7 @@ void Frame::allocate()
{
// Assume this frame is intended to be a video frame
if (width_ > 0 && height_ > 0) {
data_.resize(PixelService::GetBufferSize(static_cast<PixelFormat::Format>(format_), width_, height_));
data_.resize(PixelFormat::GetBufferSize(static_cast<PixelFormat::Format>(format_), width_, height_));
} else if (sample_count_ > 0) {
data_.resize(audio_params_.samples_to_bytes(sample_count_));
}
+8 -14
View File
@@ -115,25 +115,24 @@ bool OIIODecoder::Open()
width_ = spec.width;
height_ = spec.height;
is_rgba_ = (spec.nchannels == kRGBAChannels);
// Weirdly, switch statement doesn't work correctly here
if (spec.format == OIIO::TypeDesc::UINT8) {
pix_fmt_ = PixelFormat::PIX_FMT_RGBA8;
pix_fmt_ = is_rgba_ ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8;
} else if (spec.format == OIIO::TypeDesc::UINT16) {
pix_fmt_ = PixelFormat::PIX_FMT_RGBA16U;
pix_fmt_ = is_rgba_ ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U;
} else if (spec.format == OIIO::TypeDesc::HALF) {
pix_fmt_ = PixelFormat::PIX_FMT_RGBA16F;
pix_fmt_ = is_rgba_ ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F;
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
pix_fmt_ = PixelFormat::PIX_FMT_RGBA32F;
pix_fmt_ = is_rgba_ ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F;
} else {
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
return false;
}
// FIXME: Many OIIO pixel formats are not handled here
is_rgba_ = (spec.nchannels == kRGBAChannels);
pix_fmt_info_ = PixelService::GetPixelFormatInfo(static_cast<PixelFormat::Format>(pix_fmt_));
type_ = PixelFormat::GetOIIOTypeDesc(pix_fmt_);
open_ = true;
@@ -170,12 +169,7 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode)
frame_->allocate();
// Use the native format to determine what format OIIO should return
// FIXME: Behavior of RGB images as opposed to RGBA?
image_->read_image(pix_fmt_info_.oiio_desc, frame_->data());
if (!is_rgba_) {
PixelService::ConvertRGBtoRGBA(frame_);
}
image_->read_image(type_, frame_->data());
}
return frame_;
+2 -2
View File
@@ -24,7 +24,7 @@
#include <OpenImageIO/imageio.h>
#include "codec/decoder.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
class OIIODecoder : public Decoder
{
@@ -57,7 +57,7 @@ private:
PixelFormat::Format pix_fmt_;
PixelFormat::Info pix_fmt_info_;
OIIO::TypeDesc type_;
bool is_rgba_;
+3 -3
View File
@@ -48,7 +48,7 @@
#include "render/backend/opengl/opengltexturecache.h"
#include "render/colormanager.h"
#include "render/diskmanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
#include "task/taskmanager.h"
#include "ui/style/style.h"
#include "undo/undostack.h"
@@ -145,7 +145,7 @@ void Core::Stop()
DiskManager::DestroyInstance();
PixelService::DestroyInstance();
PixelFormat::DestroyInstance();
NodeFactory::Destroy();
@@ -385,7 +385,7 @@ void Core::StartGUI(bool full_screen)
TaskManager::CreateInstance();
// Initialize pixel service
PixelService::CreateInstance();
PixelFormat::CreateInstance();
// Connect the PanelFocusManager to the application's focus change signal
connect(qApp,
+2 -2
View File
@@ -12,7 +12,7 @@
#include "project/item/sequence/sequence.h"
#include "project/project.h"
#include "render/backend/exporter.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
#include "ui/icons/icons.h"
ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
@@ -210,7 +210,7 @@ void ExportDialog::accept()
VideoRenderingParams video_render_params(dest_width,
dest_height,
video_tab_->frame_rate().flipped(),
PixelService::instance()->GetConfiguredFormatForMode(render_mode),
PixelFormat::instance()->GetConfiguredFormatForMode(render_mode),
render_mode);
AudioRenderingParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(),
@@ -5,7 +5,7 @@
#include <QVBoxLayout>
#include "render/colormanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
PreferencesQualityTab::PreferencesQualityTab()
{
@@ -26,13 +26,13 @@ PreferencesQualityTab::PreferencesQualityTab()
quality_stack_ = new QStackedWidget();
offline_group_ = new PreferencesQualityGroup(tr("Offline Quality"));
offline_group_->bit_depth_combobox()->setCurrentIndex(PixelService::instance()->GetConfiguredFormatForMode(RenderMode::kOffline));
offline_group_->bit_depth_combobox()->setCurrentIndex(PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline));
offline_group_->sample_fmt_combobox()->setCurrentIndex(SampleFormat::GetConfiguredFormatForMode(RenderMode::kOffline));
offline_group_->ocio_method()->setCurrentIndex(ColorManager::GetOCIOMethodForMode(RenderMode::kOffline));
quality_stack_->addWidget(offline_group_);
online_group_ = new PreferencesQualityGroup(tr("Online Quality"));
online_group_->bit_depth_combobox()->setCurrentIndex(PixelService::instance()->GetConfiguredFormatForMode(RenderMode::kOnline));
online_group_->bit_depth_combobox()->setCurrentIndex(PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOnline));
online_group_->sample_fmt_combobox()->setCurrentIndex(SampleFormat::GetConfiguredFormatForMode(RenderMode::kOnline));
online_group_->ocio_method()->setCurrentIndex(ColorManager::GetOCIOMethodForMode(RenderMode::kOnline));
quality_stack_->addWidget(online_group_);
@@ -46,8 +46,8 @@ void PreferencesQualityTab::Accept()
{
ColorManager::SetOCIOMethodForMode(RenderMode::kOffline, static_cast<ColorManager::OCIOMethod>(offline_group_->ocio_method()->currentIndex()));
ColorManager::SetOCIOMethodForMode(RenderMode::kOnline, static_cast<ColorManager::OCIOMethod>(online_group_->ocio_method()->currentIndex()));
PixelService::instance()->SetConfiguredFormatForMode(RenderMode::kOffline, static_cast<PixelFormat::Format>(offline_group_->bit_depth_combobox()->currentData().toInt()));
PixelService::instance()->SetConfiguredFormatForMode(RenderMode::kOnline, static_cast<PixelFormat::Format>(online_group_->bit_depth_combobox()->currentData().toInt()));
PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOffline, static_cast<PixelFormat::Format>(offline_group_->bit_depth_combobox()->currentData().toInt()));
PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOnline, static_cast<PixelFormat::Format>(online_group_->bit_depth_combobox()->currentData().toInt()));
SampleFormat::SetConfiguredFormatForMode(RenderMode::kOffline, static_cast<SampleFormat::Format>(offline_group_->sample_fmt_combobox()->currentData().toInt()));
SampleFormat::SetConfiguredFormatForMode(RenderMode::kOnline, static_cast<SampleFormat::Format>(online_group_->sample_fmt_combobox()->currentData().toInt()));
}
@@ -70,8 +70,13 @@ PreferencesQualityGroup::PreferencesQualityGroup(const QString &title, QWidget *
// Populate with bit depths
for (int i=0;i<PixelFormat::PIX_FMT_COUNT;i++) {
bit_depth_combobox_->addItem(PixelService::GetPixelFormatInfo(static_cast<PixelFormat::Format>(i)).name,
i);
PixelFormat::Format pix_fmt = static_cast<PixelFormat::Format>(i);
// We always render with an alpha channel internally
if (PixelFormat::FormatHasAlphaChannel(pix_fmt)) {
bit_depth_combobox_->addItem(PixelFormat::GetName(pix_fmt),
i);
}
}
video_layout->addWidget(bit_depth_combobox_, row, 1);
+1 -1
View File
@@ -7,7 +7,7 @@
#include "codec/ffmpeg/ffmpegdecoder.h"
#include "core.h"
#include "project/item/footage/footage.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
VideoInput::VideoInput()
{
-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
+3 -3
View File
@@ -31,7 +31,7 @@
#include "config/config.h"
#include "project/item/sequence/sequence.h"
#include "project/project.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
#include "widget/menu/menu.h"
ViewerWidget::ViewerWidget(QWidget *parent) :
@@ -85,7 +85,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange);
audio_renderer_ = new AudioBackend(this);
connect(PixelService::instance(), &PixelService::FormatChanged, this, &ViewerWidget::UpdateRendererParameters);
connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererParameters);
SetAutoMaxScrollBar(true);
}
@@ -296,7 +296,7 @@ void ViewerWidget::UpdateRendererParameters()
RenderMode::Mode render_mode = RenderMode::kOffline;
VideoRenderingParams vparam(GetConnectedNode()->video_params(),
PixelService::instance()->GetConfiguredFormatForMode(render_mode),
PixelFormat::instance()->GetConfiguredFormatForMode(render_mode),
render_mode,
divider_);
+4 -2
View File
@@ -27,9 +27,10 @@
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include "common/define.h"
#include "render/backend/opengl/openglrenderfunctions.h"
#include "render/backend/opengl/openglshader.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
#ifdef Q_OS_LINUX
bool ViewerGLWidget::nouveau_check_done_ = false;
@@ -83,7 +84,8 @@ void ViewerGLWidget::SetImage(const QString &fn)
if (input) {
PixelFormat::Format image_format = PixelService::OIIOFormatToOliveFormat(input->spec().format);
PixelFormat::Format image_format = PixelFormat::OIIOFormatToOliveFormat(input->spec().format,
input->spec().nchannels == kRGBAChannels);
// Ensure the following texture operations are done in our context (in case we're in a separate window for instance)
makeCurrent();