This commit is contained in:
itsmattkc
2020-02-29 16:38:43 +11:00
52 changed files with 1166 additions and 819 deletions
+5 -5
View File
@@ -17,19 +17,19 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
exit 1
fi
BUNDLE_PATH=$(find . -name "Olive.app")
BUNDLE_NAME=Olive.app
echo Found app at: $BUNDLE_PATH
mv app/$BUNDLE_NAME .
# Move Qt deps into bundle
macdeployqt $BUNDLE_PATH
macdeployqt $BUNDLE_NAME
# Fix other deps that macdeployqt missed
wget -c -nv https://github.com/arl/macdeployqtfix/raw/master/macdeployqtfix.py
python2 macdeployqtfix.py $BUNDLE_PATH/Contents/MacOS/Olive /usr/local/Cellar/qt5/5.*/
python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/Olive /usr/local/Cellar/qt5/5.*/
# Distribute in zip
zip -r Olive-$VERSION-macOS.zip $BUNDLE_PATH
zip -r Olive-$VERSION-macOS.zip $BUNDLE_NAME
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+2
View File
@@ -43,6 +43,8 @@ find_package(OpenColorIO REQUIRED)
find_package(OpenImageIO REQUIRED)
find_package(OpenEXR REQUIRED)
find_package(Qt5 5.6 REQUIRED
COMPONENTS
Core
+41 -1
View File
@@ -106,9 +106,11 @@ target_include_directories(
${FFMPEG_INCLUDE_DIRS}
${OCIO_INCLUDE_DIRS}
${OIIO_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
target_link_libraries(${OLIVE_TARGET}
target_link_libraries(
${OLIVE_TARGET}
PRIVATE
Qt5::Core
Qt5::Gui
@@ -125,8 +127,17 @@ target_link_libraries(${OLIVE_TARGET}
FFMPEG::swresample
${OCIO_LIBRARIES}
${OIIO_LIBRARIES}
${OPENEXR_LIBRARIES}
)
if (WIN32)
target_link_libraries(
${OLIVE_TARGET}
PRIVATE
DbgHelp
)
endif()
set(OLIVE_TS_FILES
# FIXME: Empty variable
)
@@ -151,3 +162,32 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_EXTRACT_PRIVATE "YES")
doxygen_add_docs(docs ALL ${OLIVE_SOURCES})
endif()
set(OLIVE_CRASH_TARGET "crashhandler")
set(OLIVE_CRASH_SOURCES
dialog/crashhandler/crashhandler.h
dialog/crashhandler/crashhandler.cpp
dialog/crashhandler/crashhandlermain.cpp
)
if (WIN32)
add_executable(
${OLIVE_CRASH_TARGET}
WIN32
${OLIVE_CRASH_SOURCES}
)
else()
add_executable(
${OLIVE_CRASH_TARGET}
${OLIVE_CRASH_SOURCES}
)
endif()
target_link_libraries(
${OLIVE_CRASH_TARGET}
PRIVATE
Qt5::Core
Qt5::Gui
Qt5::Widgets
)
+1 -1
View File
@@ -61,7 +61,7 @@ void Decoder::set_stream(StreamPtr fs)
stream_ = fs;
}
FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/)
FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const int &/*divider*/)
{
return nullptr;
}
+1 -1
View File
@@ -142,7 +142,7 @@ public:
* A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or
* the media could not be opened.
*/
virtual FramePtr RetrieveVideo(const rational& timecode);
virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider);
/**
* @brief Retrieve video frame
+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:
+69 -40
View File
@@ -36,15 +36,17 @@ extern "C" {
#include "codec/waveinput.h"
#include "common/define.h"
#include "common/filefunctions.h"
#include "common/functiontimer.h"
#include "common/timecodefunctions.h"
#include "ffmpegcommon.h"
#include "render/diskmanager.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
FFmpegDecoder::FFmpegDecoder() :
fmt_ctx_(nullptr),
codec_ctx_(nullptr),
scale_ctx_(nullptr),
scale_divider_(-1),
cache_at_zero_(false),
cache_at_eof_(false),
opts_(nullptr)
@@ -153,31 +155,24 @@ 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");
}
scale_ctx_ = sws_getContext(avstream_->codecpar->width,
avstream_->codecpar->height,
static_cast<AVPixelFormat>(avstream_->codecpar->format),
avstream_->codecpar->width,
avstream_->codecpar->height,
ideal_pix_fmt_,
0,
nullptr,
nullptr,
nullptr);
if (!scale_ctx_) {
Error(QStringLiteral("Failed to allocate SwsContext"));
return false;
}
second_ts_ = qRound64(av_q2d(av_inv_q(avstream_->time_base)));
QMetaObject::invokeMethod(&clear_timer_, "start");
@@ -210,7 +205,7 @@ Decoder::RetrieveState FFmpegDecoder::GetRetrieveState(const rational& time)
return kReady;
}
FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int &divider)
{
QMutexLocker locker(&mutex_);
@@ -227,21 +222,30 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
Frame* return_frame = nullptr;
if (divider != scale_divider_) {
ClearFrameCache();
FreeScaler();
SetupScaler(divider);
}
// See if our RAM cache already has a frame that matches this timestamp
if (!cached_frames_.isEmpty()) {
if (cache_at_zero_ && target_ts < cached_frames_.first()->native_timestamp()) {
if (target_ts < cached_frames_.first()->native_timestamp()) {
return_frame = cached_frames_.first();
cached_frames_.accessedFirst();
if (cache_at_zero_) {
return_frame = cached_frames_.first();
cached_frames_.accessedFirst();
}
} else if (cache_at_eof_ && target_ts > cached_frames_.last()->native_timestamp()) {
} else if (target_ts > cached_frames_.last()->native_timestamp()) {
return_frame = cached_frames_.last();
cached_frames_.accessedLast();
if (cache_at_eof_) {
return_frame = cached_frames_.last();
cached_frames_.accessedLast();
}
} else if (target_ts >= cached_frames_.first()->native_timestamp()
&& target_ts <= cached_frames_.last()->native_timestamp()) {
} else {
// We already have this frame in the cache, find it
for (int i=0;i<cached_frames_.size();i++) {
@@ -288,7 +292,6 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
// If we have no disk cache, we'll need to find this frame ourselves
if (!return_frame) {
int64_t seek_ts = target_ts;
bool still_seeking = false;
@@ -363,8 +366,8 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
}
// Whatever it is, keep this frame in memory for the time being just in case
Frame* working_frame_converted = cached_frames_.append(VideoRenderingParams(avstream_->codecpar->width,
avstream_->codecpar->height,
Frame* working_frame_converted = cached_frames_.append(VideoRenderingParams(avstream_->codecpar->width / divider,
avstream_->codecpar->height / divider,
avstream_->time_base,
native_pix_fmt_,
RenderMode::kOffline));
@@ -375,7 +378,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,
@@ -389,10 +392,10 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
// We found the frame we want
return_frame = working_frame_converted;
}
}
if (return_frame) {
break;
}
if (return_frame) {
break;
}
}
@@ -937,10 +940,7 @@ void FFmpegDecoder::ClearResources()
ClearFrameCache();
if (scale_ctx_) {
sws_freeContext(scale_ctx_);
scale_ctx_ = nullptr;
}
FreeScaler();
if (codec_ctx_) {
avcodec_free_context(&codec_ctx_);
@@ -955,6 +955,35 @@ void FFmpegDecoder::ClearResources()
open_ = false;
}
void FFmpegDecoder::SetupScaler(const int &divider)
{
scale_ctx_ = sws_getContext(avstream_->codecpar->width,
avstream_->codecpar->height,
static_cast<AVPixelFormat>(avstream_->codecpar->format),
avstream_->codecpar->width / divider,
avstream_->codecpar->height / divider,
ideal_pix_fmt_,
SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
if (!scale_ctx_) {
Error(QStringLiteral("Failed to allocate SwsContext"));
} else {
scale_divider_ = divider;
}
}
void FFmpegDecoder::FreeScaler()
{
if (scale_ctx_) {
sws_freeContext(scale_ctx_);
scale_ctx_ = nullptr;
scale_divider_ = -1;
}
}
void FFmpegDecoder::ClearTimerEvent()
{
QMutexLocker locker(&mutex_);
+5 -3
View File
@@ -54,7 +54,7 @@ public:
virtual bool Open() override;
virtual RetrieveState GetRetrieveState(const rational &time) override;
virtual FramePtr RetrieveVideo(const rational &timecode) override;
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override;
virtual FramePtr RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams& params) override;
virtual void Close() override;
@@ -102,12 +102,13 @@ private:
void CacheFrameToDisk(AVFrame* f);
//void RemoveFirstFromFrameCache();
//void RemoveLastFromFrameCache();
void ClearFrameCache();
void ClearResources();
void SetupScaler(const int& divider);
void FreeScaler();
AVFormatContext* fmt_ctx_;
AVCodecContext* codec_ctx_;
AVStream* avstream_;
@@ -116,6 +117,7 @@ private:
PixelFormat::Format native_pix_fmt_;
SwsContext* scale_ctx_;
int scale_divider_;
FFmpegFrameCache::Client cached_frames_;
bool cache_at_zero_;
+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_));
}
+30 -25
View File
@@ -20,6 +20,7 @@
#include "oiiodecoder.h"
#include <OpenImageIO/imagebufalgo.h>
#include <QDebug>
#include <QFileInfo>
@@ -29,7 +30,7 @@ QStringList OIIODecoder::supported_formats_;
OIIODecoder::OIIODecoder() :
image_(nullptr),
frame_(nullptr)
buffer_(nullptr)
{
}
@@ -83,6 +84,9 @@ bool OIIODecoder::Probe(Footage *f, const QAtomicInt *cancelled)
image_stream->set_width(spec.width);
image_stream->set_height(spec.height);
// Images will always have just one stream
image_stream->set_index(0);
// OIIO automatically premultiplies alpha
// FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this likely reduces the
// fidelity?
@@ -112,25 +116,31 @@ 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
type_ = PixelFormat::GetOIIOTypeDesc(pix_fmt_);
is_rgba_ = (spec.nchannels == kRGBAChannels);
pix_fmt_info_ = PixelService::GetPixelFormatInfo(static_cast<PixelFormat::Format>(pix_fmt_));
#if OIIO_VERSION < 20100
buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type_));
#else
buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type_), OIIO::InitializePixels::No);
#endif
image_->read_image(type_, buffer_->localpixels());
open_ = true;
@@ -148,7 +158,7 @@ Decoder::RetrieveState OIIODecoder::GetRetrieveState(const rational &time)
return kReady;
}
FramePtr OIIODecoder::RetrieveVideo(const rational &timecode)
FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider)
{
QMutexLocker locker(&mutex_);
@@ -156,26 +166,20 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode)
return nullptr;
}
Q_UNUSED(timecode)
FramePtr frame = Frame::Create();
if (!frame_) {
frame_ = Frame::Create();
frame->set_width(width_ / divider);
frame->set_height(height_ / divider);
frame->set_format(pix_fmt_);
frame->allocate();
frame_->set_width(width_);
frame_->set_height(height_);
frame_->set_format(pix_fmt_);
frame_->allocate();
OIIO::ImageBuf dst(OIIO::ImageSpec(frame->width(), frame->height(), buffer_->spec().nchannels, buffer_->spec().format), frame->data());
// 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_);
}
if (!OIIO::ImageBufAlgo::resize(dst, *buffer_)) {
qWarning() << "OIIO resize failed";
}
return frame_;
return frame;
}
void OIIODecoder::Close()
@@ -190,7 +194,8 @@ void OIIODecoder::Close()
image_ = nullptr;
}
frame_ = nullptr;
delete buffer_;
buffer_ = nullptr;
}
bool OIIODecoder::SupportsVideo()
+5 -4
View File
@@ -22,9 +22,10 @@
#define OIIODECODER_H
#include <OpenImageIO/imageio.h>
#include <OpenImageIO/imagebuf.h>
#include "codec/decoder.h"
#include "render/pixelservice.h"
#include "render/pixelformat.h"
class OIIODecoder : public Decoder
{
@@ -37,7 +38,7 @@ public:
virtual bool Open() override;
virtual RetrieveState GetRetrieveState(const rational &time) override;
virtual FramePtr RetrieveVideo(const rational &timecode) override;
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override;
virtual void Close() override;
virtual bool SupportsVideo() override;
@@ -57,11 +58,11 @@ private:
PixelFormat::Format pix_fmt_;
PixelFormat::Info pix_fmt_info_;
OIIO::TypeDesc type_;
bool is_rgba_;
FramePtr frame_;
OIIO::ImageBuf* buffer_;
static QStringList supported_formats_;
+2
View File
@@ -22,6 +22,8 @@ set(OLIVE_SOURCES
common/channellayout.h
common/clamp.h
common/constructors.h
common/crashhandler.h
common/crashhandler.cpp
common/debug.h
common/debug.cpp
common/define.h
+122
View File
@@ -0,0 +1,122 @@
#include "crashhandler.h"
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QStandardPaths>
#include <QTextStream>
#include <QtGlobal>
#if defined(Q_OS_WINDOWS)
#include <Windows.h>
#include <DbgHelp.h>
#include <stdio.h>
#include <stdlib.h>
#elif defined(Q_OS_LINUX)
#include <execinfo.h>
#endif
void crash_handler(int sig) {
QString log_path = QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).filePath(QStringLiteral("olive_crash"));
QFile output(log_path);
output.open(QFile::WriteOnly);
QTextStream ostream(&output);
ostream << "Signal: " << sig << "\n\n";
#if defined(Q_OS_WINDOWS)
// Use Windows stackwalk API
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
SymInitialize(process, NULL, TRUE);
DWORD image;
STACKFRAME64 stackframe;
ZeroMemory(&stackframe, sizeof(STACKFRAME64));
#ifdef _M_IX86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
image = IMAGE_FILE_MACHINE_IA64;
stackframe.AddrPC.Offset = context.StIIP;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.IntSp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrBStore.Offset = context.RsBSP;
stackframe.AddrBStore.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.IntSp;
stackframe.AddrStack.Mode = AddrModeFlat;
#endif
for (int i = 0; i < 50; i++) {
BOOL result = StackWalk64(
image, process, thread,
&stackframe, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
if (!result) { break; }
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 displacement = 0;
ostream << "[" << i << "] ";
if (SymFromAddr(process, stackframe.AddrPC.Offset, &displacement, symbol)) {
ostream << symbol->Name;
//printf("[%i] %s\n", i, symbol->Name);
} else {
ostream << "???";
//printf("[%i] ???\n", i);
}
ostream << "\n";
}
SymCleanup(process);
#elif defined(Q_OS_MAC)
// FIXME: No Mac backtrace support yet
#elif defined(Q_OS_LINUX)
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
backtrace_symbols_fd(array, size, output.handle());
#endif
output.close();
QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("crashhandler"));
QProcess::startDetached(crash_handler_exe, {log_path});
exit(1);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef CRASHHANDLER_H
#define CRASHHANDLER_H
void crash_handler(int sig);
#endif // CRASHHANDLER_H
+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,
+61
View File
@@ -0,0 +1,61 @@
#include "crashhandler.h"
#include <QFile>
#include <QLabel>
#include <QDialogButtonBox>
#include <QScrollBar>
#include <QTextEdit>
#include <QVBoxLayout>
CrashHandlerDialog::CrashHandlerDialog(const char *log_file)
{
setWindowTitle(tr("Olive"));
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please send the following log to the developers to "
"help resolve this.")));
QTextEdit* edit = new QTextEdit();
edit->setReadOnly(true);
layout->addWidget(edit);
edit->append(QStringLiteral("Build Environment: %1 (%2)").arg(QSysInfo::buildCpuArchitecture(), QSysInfo::buildAbi()));
edit->append(QStringLiteral("Run Environment: %1").arg(QSysInfo::currentCpuArchitecture()));
edit->append(QStringLiteral("Kernel: %1 %2").arg(QSysInfo::kernelType(), QSysInfo::kernelVersion()));
edit->append(QStringLiteral("System: %1 (%2 %3)").arg(QSysInfo::prettyProductName(), QSysInfo::productType(), QSysInfo::productVersion()));
edit->append(QString());
QDialogButtonBox* buttons = new QDialogButtonBox();
// FIXME: Implement auto-reporting
//buttons->addButton(tr("Send Error Report"), QDialogButtonBox::AcceptRole);
//buttons->addButton(tr("Don't Send"), QDialogButtonBox::RejectRole);
buttons->addButton(QDialogButtonBox::Ok);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
layout->addWidget(buttons);
QFile log(log_file);
if (log.open(QFile::ReadOnly | QFile::Text)) {
edit->append(log.readAll());
QMetaObject::invokeMethod(edit->verticalScrollBar(),
"setValue",
Qt::QueuedConnection,
Q_ARG(int, 0));
log.close();
}
}
void CrashHandlerDialog::accept()
{
QDialog::accept();
}
void CrashHandlerDialog::reject()
{
QDialog::reject();
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef CRASHHANDLERDIALOG_H
#define CRASHHANDLERDIALOG_H
#include <QDialog>
class CrashHandlerDialog : public QDialog
{
Q_OBJECT
public:
CrashHandlerDialog(const char* log_file);
public slots:
virtual void accept() override;
virtual void reject() override;
};
#endif // CRASHHANDLERDIALOG_H
@@ -0,0 +1,17 @@
#include "crashhandler.h"
#include <QApplication>
int main(int argc, char *argv[])
{
if (argc < 2) {
return 1;
}
QApplication a(argc, argv);
CrashHandlerDialog chd(argv[1]);
chd.open();
return a.exec();
}
+14 -4
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(),
@@ -414,8 +414,18 @@ void ExportDialog::LoadPresets()
void ExportDialog::SetDefaultFilename()
{
QString doc_location = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QString file_location = QDir(doc_location).filePath("export");
Sequence* s = static_cast<Sequence*>(viewer_node_->parent());
Project* p = s->project();
QDir doc_location;
if (p->filename().isEmpty()) {
doc_location.setPath(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
} else {
doc_location = QFileInfo(p->filename()).dir();
}
QString file_location = doc_location.filePath(s->name());
filename_edit_->setText(file_location);
}
@@ -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);
+5
View File
@@ -31,15 +31,20 @@ extern "C" {
#include <libavfilter/avfilter.h>
}
#include <csignal>
#include <QApplication>
#include <QSurfaceFormat>
#include "core.h"
#include "common/crashhandler.h"
#include "common/debug.h"
int main(int argc, char *argv[]) {
av_log_set_level(AV_LOG_QUIET);
signal(SIGSEGV, crash_handler);
signal(SIGABRT, crash_handler);
// Set OpenGL display profile (3.2 Core)
QSurfaceFormat format;
format.setVersion(3, 2);
+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 -28
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
@@ -236,32 +236,6 @@ void Exporter::VideoHashesComplete()
TimeRangeList ranges;
ranges.append(TimeRange(0, viewer_node_->Length()));
QMap<rational, QByteArray>::const_iterator i;
QMap<rational, QByteArray>::iterator j;
// Copy time hash map
QMap<rational, QByteArray> time_hash_map = video_backend_->frame_cache()->time_hash_map();
// Check for any times that share duplicate hashes
for (i=time_hash_map.begin();i!=time_hash_map.end();i++) {
j = time_hash_map.begin();
while (j != time_hash_map.end()) {
if (i != j && i.value() == j.value()) {
// Remove the time range from this and
ranges.RemoveTimeRange(TimeRange(j.key(), j.key() + video_backend_->params().time_base()));
QList<rational> times_with_this_hash = matched_frames_.value(i.value());
times_with_this_hash.append(j.key());
matched_frames_.insert(i.value(), times_with_this_hash);
j = time_hash_map.erase(j);
} else {
j++;
}
}
}
// Set video backend to render mode but NOT hash or download
video_backend_->SetOperatingMode(VideoRenderWorker::kRenderOnly);
video_backend_->SetOnlySignalLastFrameRequested(false);
-2
View File
@@ -73,8 +73,6 @@ private:
QHash<rational, FramePtr> cached_frames_;
QHash< QByteArray, QList<rational> > matched_frames_;
private slots:
void FrameRendered(const rational &time, FramePtr value);
+20 -16
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),
@@ -60,7 +60,9 @@ void OpenGLProxy::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeR
if (stream->type() == Stream::kImage && still_image_cache_.Has(stream.get())) {
CachedStill cs = still_image_cache_.Get(stream.get());
if (cs.colorspace == colorspace_match && cs.alpha_is_associated == video_stream->premultiplied_alpha()) {
if (cs.colorspace == colorspace_match
&& cs.alpha_is_associated == video_stream->premultiplied_alpha()
&& cs.divider == video_params_.divider()) {
footage_tex_ref = cs.texture;
} else {
still_image_cache_.Remove(stream.get());
@@ -80,26 +82,30 @@ void OpenGLProxy::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeR
ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(video_params_.mode());
FramePtr frame = decoder->RetrieveVideo(range.in());;
FramePtr frame = decoder->RetrieveVideo(range.in(), video_params_.divider());
// OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU
if (ocio_method == ColorManager::kOCIOAccurate) {
bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format());
// If alpha is associated, disassociate for the color transform
if (video_stream->premultiplied_alpha()) {
if (has_alpha && video_stream->premultiplied_alpha()) {
ColorManager::DisassociateAlpha(frame);
}
// Convert frame to float for OCIO
frame = PixelService::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
frame = PixelFormat::ConvertPixelFormat(frame, has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F);
// Perform color transform
color_processor->ConvertFrame(frame);
// Associate alpha
if (video_stream->premultiplied_alpha()) {
ColorManager::ReassociateAlpha(frame);
} else {
ColorManager::AssociateAlpha(frame);
if (has_alpha) {
if (video_stream->premultiplied_alpha()) {
ColorManager::ReassociateAlpha(frame);
} else {
ColorManager::AssociateAlpha(frame);
}
}
}
@@ -154,7 +160,7 @@ void OpenGLProxy::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeR
}
if (stream->type() == Stream::kImage) {
still_image_cache_.Add(stream.get(), {footage_tex_ref, colorspace_match, video_stream->premultiplied_alpha()});
still_image_cache_.Add(stream.get(), {footage_tex_ref, colorspace_match, video_stream->premultiplied_alpha(), video_params_.divider()});
}
}
@@ -281,8 +287,8 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, c
int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(input->id()));
if (res_param_location > -1) {
shader->setUniformValue(res_param_location,
static_cast<GLfloat>(texture->texture()->width()),
static_cast<GLfloat>(texture->texture()->height()));
static_cast<GLfloat>(texture->texture()->width() * video_params_.divider()),
static_cast<GLfloat>(texture->texture()->height() * video_params_.divider()));
}
}
@@ -384,8 +390,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 +398,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();
+1
View File
@@ -69,6 +69,7 @@ private:
OpenGLTextureCache::ReferencePtr texture;
QString colorspace;
bool alpha_is_associated;
int divider;
};
RenderCache<Stream*, CachedStill> still_image_cache_;
@@ -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)
+2 -19
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) :
@@ -140,7 +140,6 @@ void VideoRenderBackend::ConnectWorkerToThis(RenderWorker *processor)
video_processor->SetOperatingMode(operating_mode_);
connect(video_processor, &VideoRenderWorker::CompletedFrame, this, &VideoRenderBackend::ThreadCompletedFrame, Qt::QueuedConnection);
connect(video_processor, &VideoRenderWorker::HashAlreadyBeingCached, this, &VideoRenderBackend::ThreadSkippedFrame, Qt::QueuedConnection);
connect(video_processor, &VideoRenderWorker::CompletedDownload, this, &VideoRenderBackend::ThreadCompletedDownload, Qt::QueuedConnection);
connect(video_processor, &VideoRenderWorker::HashAlreadyExists, this, &VideoRenderBackend::ThreadHashAlreadyExists, Qt::QueuedConnection);
@@ -262,22 +261,6 @@ TimeRange VideoRenderBackend::PopNextFrameFromQueue()
return TimeRange(frame_range.in(), frame_range.in());
}
void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value)
{
if (!only_signal_last_frame_requested_ || last_time_requested_ == path.in() || frame_cache_.TimeToHash(last_time_requested_) == hash) {
Q_UNUSED(job_time)
Q_UNUSED(value)
//EmitCachedFrameReady(path.in(), value, job_time);
}
if (!(operating_mode_ & VideoRenderWorker::kDownloadOnly)) {
// If we're not downloading, the worker is done here
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
CacheNext();
}
}
void VideoRenderBackend::ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash, bool texture_existed)
{
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
@@ -343,7 +326,7 @@ void VideoRenderBackend::TruncateFrameCacheLength(const rational &length)
void VideoRenderBackend::FrameRemovedFromDiskCache(const QByteArray &hash)
{
QList<rational> deleted_frames = frame_cache()->FramesWithHash(hash);
QList<rational> deleted_frames = frame_cache()->TakeFramesWithHash(hash);
foreach (const rational& frame, deleted_frames) {
TimeRange invalidated(frame, frame+params_.time_base());
-1
View File
@@ -128,7 +128,6 @@ private:
bool limit_caching_;
private slots:
void ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value);
void ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash, bool texture_existed);
void ThreadSkippedFrame(NodeDependency dep, qint64 job_time, QByteArray hash);
void ThreadHashAlreadyExists(NodeDependency dep, qint64 job_time, QByteArray hash);
+25 -4
View File
@@ -83,7 +83,7 @@ void VideoRenderFrameCache::RemoveHashFromCurrentlyCaching(const QByteArray &has
currently_caching_list_.removeOne(hash);
}
QList<rational> VideoRenderFrameCache::FramesWithHash(const QByteArray &hash)
QList<rational> VideoRenderFrameCache::FramesWithHash(const QByteArray &hash) const
{
QList<rational> times;
@@ -98,6 +98,25 @@ QList<rational> VideoRenderFrameCache::FramesWithHash(const QByteArray &hash)
return times;
}
QList<rational> VideoRenderFrameCache::TakeFramesWithHash(const QByteArray &hash)
{
QList<rational> times;
QMap<rational, QByteArray>::iterator iterator = time_hash_map_.begin();
while (iterator != time_hash_map_.end()) {
if (iterator.value() == hash) {
times.append(iterator.key());
iterator = time_hash_map_.erase(iterator);
} else {
iterator++;
}
}
return times;
}
const QMap<rational, QByteArray> &VideoRenderFrameCache::time_hash_map() const
{
return time_hash_map_;
@@ -107,9 +126,11 @@ QString VideoRenderFrameCache::CachePathName(const QByteArray& hash, const Pixel
{
QString ext;
if (pix_fmt == PixelFormat::PIX_FMT_RGBA8 || pix_fmt == PixelFormat::PIX_FMT_RGBA16U) {
// For some reason, integer EXRs are extremely slow to load, so we use TIFF instead.
ext = QStringLiteral("tiff");
if (pix_fmt == PixelFormat::PIX_FMT_RGB8
|| pix_fmt == PixelFormat::PIX_FMT_RGBA8
|| pix_fmt == PixelFormat::PIX_FMT_RGB16U
|| pix_fmt == PixelFormat::PIX_FMT_RGBA16U) {
ext = QStringLiteral("jpg");
} else {
ext = QStringLiteral("exr");
}
+9 -1
View File
@@ -43,7 +43,15 @@ public:
void RemoveHashFromCurrentlyCaching(const QByteArray& hash);
QList<rational> FramesWithHash(const QByteArray& hash);
/**
* @brief Returns a list of frames that use a particular hash
*/
QList<rational> FramesWithHash(const QByteArray& hash) const;
/**
* @brief Same as FramesWithHash() but also removes these frames from the map
*/
QList<rational> TakeFramesWithHash(const QByteArray& hash);
const QMap<rational, QByteArray>& time_hash_map() const;
+81 -28
View File
@@ -1,17 +1,22 @@
#include "videorenderworker.h"
#include <OpenEXR/ImfFloatAttribute.h>
#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfChannelList.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()
@@ -62,9 +67,6 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con
// Find texture in hash
QVariant texture = value.Get(NodeParam::kTexture);
// Signal that we have a frame in memory that could be shown right now
emit CompletedFrame(path, job_time, hash, texture);
// If we actually have a texture, download it into the disk cache
if (!texture.isNull()) {
Download(path.in(), texture, frame_cache_->CachePathName(hash, video_params_.format()));
@@ -225,38 +227,89 @@ 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);
if (video_params_.format() != PixelFormat::PIX_FMT_RGBA8
&& video_params_.format() != PixelFormat::PIX_FMT_RGBA16U) {
// Integer types don't use EXR (they use TIFF instead) because EXR is very slow with integer formats
spec.attribute("compression", "dwaa:200");
}
if (operating_mode_ & kDownloadOnly) {
TextureToBuffer(texture, download_buffer_.data());
std::string working_fn_std = filename.toStdString();
switch (video_params().format()) {
case PixelFormat::PIX_FMT_RGB8:
case PixelFormat::PIX_FMT_RGBA8:
case PixelFormat::PIX_FMT_RGB16U:
case PixelFormat::PIX_FMT_RGBA16U:
{
// Integer types are stored in JPEG which we run through OIIO
auto out = OIIO::ImageOutput::create(working_fn_std);
std::string fn_std = filename.toStdString();
// Keep export to this thread only
out->threads(1);
auto out = OIIO::ImageOutput::create(fn_std);
if (out) {
out->open(working_fn_std, spec);
out->write_image(format_info.oiio_desc, download_buffer_.data());
out->close();
if (out) {
// Attempt to keep this write to one thread
out->threads(1);
out->open(fn_std, OIIO::ImageSpec(video_params().effective_width(),
video_params().effective_height(),
PixelFormat::ChannelCount(video_params().format()),
PixelFormat::GetOIIOTypeDesc(video_params().format())));
out->write_image(PixelFormat::GetOIIOTypeDesc(video_params().format()), download_buffer_.data());
out->close();
#if OIIO_VERSION < 10903
OIIO::ImageOutput::destroy(out);
OIIO::ImageOutput::destroy(out);
#endif
} else {
qWarning() << "Failed to open output file:" << filename;
} else {
qCritical() << "Failed to write JPEG file:" << OIIO::geterror().c_str();
}
break;
}
case PixelFormat::PIX_FMT_RGB16F:
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGB32F:
case PixelFormat::PIX_FMT_RGBA32F:
{
// Floating point types are stored in EXR
Imf::PixelType pix_type;
if (video_params().format() == PixelFormat::PIX_FMT_RGB16F
|| video_params().format() == PixelFormat::PIX_FMT_RGBA16F) {
pix_type = Imf::HALF;
} else {
pix_type = Imf::FLOAT;
}
Imf::Header header(video_params().effective_width(),
video_params().effective_height());
header.channels().insert("R", Imf::Channel(pix_type));
header.channels().insert("G", Imf::Channel(pix_type));
header.channels().insert("B", Imf::Channel(pix_type));
header.channels().insert("A", Imf::Channel(pix_type));
header.compression() = Imf::DWAA_COMPRESSION;
header.insert("dwaCompressionLevel", Imf::FloatAttribute(200.0f));
Imf::OutputFile out(filename.toUtf8(), header, 0);
int bpc = PixelFormat::BytesPerChannel(video_params().format());
size_t xs = kRGBAChannels * bpc;
size_t ys = video_params().effective_width() * kRGBAChannels * bpc;
Imf::FrameBuffer framebuffer;
framebuffer.insert("R", Imf::Slice(pix_type, download_buffer_.data(), xs, ys));
framebuffer.insert("G", Imf::Slice(pix_type, download_buffer_.data() + bpc, xs, ys));
framebuffer.insert("B", Imf::Slice(pix_type, download_buffer_.data() + 2*bpc, xs, ys));
framebuffer.insert("A", Imf::Slice(pix_type, download_buffer_.data() + 3*bpc, xs, ys));
out.setFrameBuffer(framebuffer);
out.writePixels(video_params().effective_height());
break;
}
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
qCritical() << "Unable to cache invalid pixel format" << video_params().format();
break;
}
} else {
@@ -276,7 +329,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)
+3 -5
View File
@@ -48,13 +48,11 @@ public:
void SetOperatingMode(const OperatingMode& mode);
signals:
void CompletedFrame(NodeDependency CurrentPath, qint64 job_time, QByteArray hash, QVariant value);
void CompletedDownload(NodeDependency path, qint64 job_time, QByteArray hash, bool texture_existed);
void CompletedDownload(NodeDependency CurrentPath, qint64 job_time, QByteArray hash, bool texture_existed);
void HashAlreadyBeingCached(NodeDependency path, qint64 job_time, QByteArray hash);
void HashAlreadyBeingCached(NodeDependency CurrentPath, qint64 job_time, QByteArray hash);
void HashAlreadyExists(NodeDependency CurrentPath, qint64 job_time, QByteArray hash);
void HashAlreadyExists(NodeDependency path, qint64 job_time, QByteArray hash);
void GeneratedFrame(const rational &time, FramePtr frame);
+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);
}
+1 -1
View File
@@ -159,7 +159,7 @@ bool DiskManager::ClearDiskCache(bool quick_delete)
const HashTime& ht = disk_data_.at(i);
// We return a false result if any of the files fail to delete, but still try to delete as many as we can
if (QFile::remove(ht.file_name)) {
if (QFile::remove(ht.file_name) || !QFileInfo::exists(ht.file_name)) {
emit DeletedFrame(ht.hash);
disk_data_.removeAt(i);
i--;
+234
View File
@@ -19,3 +19,237 @@
***/
#include "pixelformat.h"
#include "OpenImageIO/imagebuf.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::BASETYPE 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::ImageBuf src(OIIO::ImageSpec(frame->width(), frame->height(), ChannelCount(frame->format()), GetOIIOTypeDesc(frame->format())), frame->data());
OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(), ChannelCount(converted->format()), GetOIIOTypeDesc(converted->format())), converted->data());
if (dst.copy_pixels(src)) {
return converted;
} else {
return nullptr;
}
}
+90 -17
View File
@@ -21,11 +21,19 @@
#ifndef BITDEPTHS_H
#define BITDEPTHS_H
#include <memory>
#include <OpenImageIO/imageio.h>
#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 +46,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::BASETYPE 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
+46 -1
View File
@@ -21,7 +21,11 @@
#include "projectexplorer.h"
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QMenu>
#include <QProcess>
#include <QUrl>
#include <QVBoxLayout>
#include "common/define.h"
@@ -242,9 +246,25 @@ void ProjectExplorer::ShowContextMenu()
QAction* project_properties = menu.addAction(tr("&Project Properties..."));
connect(project_properties, &QAction::triggered, Core::instance(), &Core::DialogProjectPropertiesShow);
} else {
if (selected_items.first()->type() == Item::kFootage) {
QString reveal_text;
#if defined(Q_OS_WINDOWS)
reveal_text = tr("Reveal in Explorer");
#elif defined(Q_OS_MAC)
reveal_text = tr("Reveal in Finder");
#else
reveal_text = tr("Reveal in File Manager");
#endif
QAction* reveal_action = menu.addAction(reveal_text);
connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage);
menu.addSeparator();
}
QAction* properties_action = menu.addAction(tr("P&roperties"));
// FIXME: Support for multiple items
if (selected_items.first()->type() == Item::kFootage) {
connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowFootagePropertiesDialog);
} else if (selected_items.first()->type() == Item::kSequence) {
@@ -269,6 +289,31 @@ void ProjectExplorer::ShowSequencePropertiesDialog()
sd.exec();
}
void ProjectExplorer::RevealSelectedFootage()
{
Footage* footage = static_cast<Footage*>(SelectedItems().first());
#if defined(Q_OS_WINDOWS)
// Explorer
QStringList args;
args << "/select," << QDir::toNativeSeparators(footage->filename());
QProcess::startDetached("explorer", args);
#elif defined(Q_OS_MAC)
QStringList args;
args << "-e";
args << "tell application \"Finder\"";
args << "-e";
args << "activate";
args << "-e";
args << "select POSIX file \""+footage->filename()+"\"";
args << "-e";
args << "end tell";
QProcess::startDetached("osascript", args);
#else
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(footage->filename()).dir().absolutePath()));
#endif
}
Project *ProjectExplorer::project()
{
return model_.project();
@@ -155,6 +155,8 @@ private slots:
void ShowSequencePropertiesDialog();
void RevealSelectedFootage();
};
#endif // PROJECTEXPLORER_H
+9 -6
View File
@@ -122,6 +122,9 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
TimelineWidget::~TimelineWidget()
{
// Ensure no blocks are selected before any child widgets are destroyed (prevents corrupt ViewSelectionChanged() signal)
Clear();
qDeleteAll(tools_);
}
@@ -129,14 +132,14 @@ void TimelineWidget::Clear()
{
SetTimebase(0);
QMapIterator<Block*, TimelineViewBlockItem*> iterator(block_items_);
QMap<Block*, TimelineViewBlockItem*>::iterator iterator = block_items_.begin();
while (iterator.hasNext()) {
iterator.next();
while (iterator != block_items_.end()) {
TimelineViewBlockItem* item = iterator.value();
if (iterator.value() != nullptr) {
delete iterator.value();
}
iterator = block_items_.erase(iterator);
delete item;
}
block_items_.clear();
+13 -7
View File
@@ -88,11 +88,13 @@ const int64_t &TimeRuler::GetTime()
void TimeRuler::SetCacheStatusLength(const rational &length)
{
cache_length_ = length;
if (show_cache_status_) {
cache_length_ = length;
dirty_cache_ranges_.RemoveTimeRange(TimeRange(length, RATIONAL_MAX));
dirty_cache_ranges_.RemoveTimeRange(TimeRange(length, RATIONAL_MAX));
update();
update();
}
}
void TimeRuler::SetTime(const int64_t &r)
@@ -111,16 +113,20 @@ void TimeRuler::SetScroll(int s)
void TimeRuler::CacheInvalidatedRange(const TimeRange& range)
{
dirty_cache_ranges_.InsertTimeRange(range);
if (show_cache_status_) {
dirty_cache_ranges_.InsertTimeRange(range);
update();
update();
}
}
void TimeRuler::CacheTimeReady(const rational &time)
{
dirty_cache_ranges_.RemoveTimeRange(TimeRange(time, time + timebase_));
if (show_cache_status_) {
dirty_cache_ranges_.RemoveTimeRange(TimeRange(time, time + timebase_));
update();
update();
}
}
void TimeRuler::paintEvent(QPaintEvent *)
+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();
+96 -91
View File
@@ -1,94 +1,99 @@
#
# Copyright 2016 Pixar
#
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the trade
# names, trademarks, service marks, or product names of the Licensor
# and its affiliates, except as required to comply with Section 4(c) of
# the License and to reproduce the content of the NOTICE file.
#
# You may obtain a copy of the Apache License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
#
find_path(OPENEXR_INCLUDE_DIR
OpenEXR/half.h
HINTS
"${OPENEXR_LOCATION}"
"$ENV{OPENEXR_LOCATION}"
PATH_SUFFIXES
include/
DOC
"OpenEXR headers path"
)
if(OPENEXR_INCLUDE_DIR)
set(openexr_config_file "${OPENEXR_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h")
if(EXISTS ${openexr_config_file})
file(STRINGS
${openexr_config_file}
TMP
REGEX "#define OPENEXR_VERSION_STRING.*$")
string(REGEX MATCHALL "[0-9.]+" OPENEXR_VERSION ${TMP})
file(STRINGS
${openexr_config_file}
TMP
REGEX "#define OPENEXR_VERSION_MAJOR.*$")
string(REGEX MATCHALL "[0-9]" OPENEXR_MAJOR_VERSION ${TMP})
file(STRINGS
${openexr_config_file}
TMP
REGEX "#define OPENEXR_VERSION_MINOR.*$")
string(REGEX MATCHALL "[0-9]" OPENEXR_MINOR_VERSION ${TMP})
endif()
endif()
foreach(OPENEXR_LIB
Half
Iex
Imath
IlmImf
IlmThread
)
# OpenEXR libraries may be suffixed with the version number, so we search
# using both versioned and unversioned names.
find_library(OPENEXR_${OPENEXR_LIB}_LIBRARY
NAMES
${OPENEXR_LIB}-${OPENEXR_MAJOR_VERSION}_${OPENEXR_MINOR_VERSION}
${OPENEXR_LIB}
HINTS
"${OPENEXR_LOCATION}"
"$ENV{OPENEXR_LOCATION}"
PATH_SUFFIXES
lib/
DOC
"OPENEXR's ${OPENEXR_LIB} library path"
)
if(OPENEXR_${OPENEXR_LIB}_LIBRARY)
list(APPEND OPENEXR_LIBRARIES ${OPENEXR_${OPENEXR_LIB}_LIBRARY})
endif()
endforeach(OPENEXR_LIB)
# So #include <half.h> works
list(APPEND OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR})
list(APPEND OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR}/OpenEXR)
include(FindPackageHandleStandardArgs)
find_path(OpenEXR_INCLUDE_DIRS OpenEXR/OpenEXRConfig.h)
find_path(OPENEXR_INCLUDE_PATHS NAMES ImfRgbaFile.h PATH_SUFFIXES OpenEXR)
file(STRINGS "${OpenEXR_INCLUDE_DIRS}/OpenEXR/OpenEXRConfig.h" OPENEXR_CONFIG_H)
string(REGEX REPLACE "^.*define OPENEXR_VERSION_MAJOR ([0-9]+).*$" "\\1" OpenEXR_VERSION_MAJOR "${OPENEXR_CONFIG_H}")
string(REGEX REPLACE "^.*define OPENEXR_VERSION_MINOR ([0-9]+).*$" "\\1" OpenEXR_VERSION_MINOR "${OPENEXR_CONFIG_H}")
set(OpenEXR_LIB_SUFFIX "${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}")
include(SelectLibraryConfigurations)
if(NOT OpenEXR_BASE_LIBRARY)
find_library(OpenEXR_BASE_LIBRARY_RELEASE NAMES IlmImf-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_BASE_LIBRARY_DEBUG NAMES IlmImf-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_BASE)
endif()
if(NOT OpenEXR_UTIL_LIBRARY)
find_library(OpenEXR_UTIL_LIBRARY_RELEASE NAMES IlmImfUtil-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_UTIL_LIBRARY_DEBUG NAMES IlmImfUtil-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_UTIL)
endif()
if(NOT OpenEXR_HALF_LIBRARY)
find_library(OpenEXR_HALF_LIBRARY_RELEASE NAMES Half-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_HALF_LIBRARY_DEBUG NAMES Half-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_HALF)
endif()
if(NOT OpenEXR_IEX_LIBRARY)
find_library(OpenEXR_IEX_LIBRARY_RELEASE NAMES Iex-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_IEX_LIBRARY_DEBUG NAMES Iex-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_IEX)
endif()
if(NOT OpenEXR_MATH_LIBRARY)
find_library(OpenEXR_MATH_LIBRARY_RELEASE NAMES Imath-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_MATH_LIBRARY_DEBUG NAMES Imath-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_MATH)
endif()
if(NOT OpenEXR_THREAD_LIBRARY)
find_library(OpenEXR_THREAD_LIBRARY_RELEASE NAMES IlmThread-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_THREAD_LIBRARY_DEBUG NAMES IlmThread-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_THREAD)
endif()
if(NOT OpenEXR_IEXMATH_LIBRARY)
find_library(OpenEXR_IEXMATH_LIBRARY_RELEASE NAMES IexMath-${OpenEXR_LIB_SUFFIX})
find_library(OpenEXR_IEXMATH_LIBRARY_DEBUG NAMES IexMath-${OpenEXR_LIB_SUFFIX}_d)
select_library_configurations(OpenEXR_IEXMATH)
endif()
set(OPENEXR_HALF_LIBRARY "${OpenEXR_HALF_LIBRARY}")
set(OPENEXR_Half_LIBRARY "${OpenEXR_HALF_LIBRARY}")
set(OPENEXR_IEX_LIBRARY "${OpenEXR_IEX_LIBRARY}")
set(OPENEXR_Iex_LIBRARY "${OpenEXR_IEX_LIBRARY}")
set(OPENEXR_IMATH_LIBRARY "${OpenEXR_MATH_LIBRARY}")
set(OPENEXR_ILMIMF_LIBRARY "${OpenEXR_BASE_LIBRARY}")
set(OPENEXR_IlmImf_LIBRARY "${OpenEXR_BASE_LIBRARY}")
set(OPENEXR_ILMIMFUTIL_LIBRARY "${OpenEXR_UTIL_LIBRARY}")
set(OPENEXR_ILMTHREAD_LIBRARY "${OpenEXR_THREAD_LIBRARY}")
set(OpenEXR_LIBRARY "${OpenEXR_BASE_LIBRARY}")
set(OpenEXR_LIBRARIES
${OpenEXR_LIBRARY}
${OpenEXR_MATH_LIBRARY}
${OpenEXR_IEXMATH_LIBRARY}
${OpenEXR_UTIL_LIBRARY}
${OpenEXR_HALF_LIBRARY}
${OpenEXR_IEX_LIBRARY}
${OpenEXR_THREAD_LIBRARY}
find_package_handle_standard_args(OpenEXR
REQUIRED_VARS
OPENEXR_INCLUDE_DIRS
OPENEXR_LIBRARIES
VERSION_VAR
OPENEXR_VERSION
)
set(OPENEXR_LIBRARIES
${OPENEXR_HALF_LIBRARY}
${OPENEXR_IEX_LIBRARY}
${OPENEXR_IMATH_LIBRARY}
${OPENEXR_ILMIMF_LIBRARY}
${OPENEXR_ILMTHREAD_LIBRARY}
)
set(OpenEXR_INCLUDE_DIR ${OpenEXR_INCLUDE_DIRS})
set(OPENEXR_INCLUDE_DIRS ${OpenEXR_INCLUDE_DIRS})
set(OPENEXR_INCLUDE_DIR ${OPENEXR_INCLUDE_PATHS})
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenEXR REQUIRED_VARS OpenEXR_LIBRARIES OpenEXR_INCLUDE_DIRS)
if(OpenEXR_FOUND)
set(OPENEXR_FOUND 1)
endif()