Merge branch 'master' of https://github.com/olive-editor/olive
This commit is contained in:
+5
-5
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 ÷r)
|
||||
{
|
||||
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 ÷r)
|
||||
{
|
||||
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_);
|
||||
|
||||
@@ -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,7 +3,7 @@
|
||||
#include <QFile>
|
||||
|
||||
#include "ffmpegcommon.h"
|
||||
#include "render/pixelservice.h"
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
FFmpegEncoder::FFmpegEncoder(const EncodingParams ¶ms) :
|
||||
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
@@ -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_));
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CRASHHANDLER_H
|
||||
#define CRASHHANDLER_H
|
||||
|
||||
void crash_handler(int sig);
|
||||
|
||||
#endif // CRASHHANDLER_H
|
||||
+3
-3
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 *)
|
||||
|
||||
@@ -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_);
|
||||
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user