format: reformatting files
This commit is contained in:
@@ -57,7 +57,8 @@ AudioLevelMeter::AnalyzeSampleBuffer(const core::SampleBuffer &samples)
|
|||||||
square_sum += value * value;
|
square_sum += value * value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const double mean_square = square_sum / static_cast<double>(sample_count);
|
const double mean_square =
|
||||||
|
square_sum / static_cast<double>(sample_count);
|
||||||
const double rms = std::sqrt(mean_square);
|
const double rms = std::sqrt(mean_square);
|
||||||
|
|
||||||
ChannelStats channel_stats;
|
ChannelStats channel_stats;
|
||||||
@@ -74,8 +75,8 @@ AudioLevelMeter::AnalyzeSampleBuffer(const core::SampleBuffer &samples)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stats.silence = qFuzzyIsNull(stats.max_peak_linear);
|
stats.silence = qFuzzyIsNull(stats.max_peak_linear);
|
||||||
stats.integrated_lufs = PowerToLufs(
|
stats.integrated_lufs =
|
||||||
total_square / static_cast<double>(total_samples));
|
PowerToLufs(total_square / static_cast<double>(total_samples));
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ AudioSynchronizer::Placement AudioSynchronizer::PlaceBySourceTime(
|
|||||||
const core::rational &reference_timeline_in)
|
const core::rational &reference_timeline_in)
|
||||||
{
|
{
|
||||||
Placement placement;
|
Placement placement;
|
||||||
if (!reference.has_source_start_time ||
|
if (!reference.has_source_start_time || !candidate.has_source_start_time ||
|
||||||
!candidate.has_source_start_time ||
|
|
||||||
reference.source_start_time.isNaN() ||
|
reference.source_start_time.isNaN() ||
|
||||||
candidate.source_start_time.isNaN()) {
|
candidate.source_start_time.isNaN()) {
|
||||||
return placement;
|
return placement;
|
||||||
@@ -55,9 +54,9 @@ AudioSynchronizer::Placement AudioSynchronizer::PlaceByWaveformOffset(
|
|||||||
return placement;
|
return placement;
|
||||||
}
|
}
|
||||||
|
|
||||||
placement.timeline_in =
|
placement.timeline_in = reference_timeline_in +
|
||||||
reference_timeline_in +
|
core::rational::fromDouble(
|
||||||
core::rational::fromDouble(static_cast<double>(candidate_offset_samples) /
|
static_cast<double>(candidate_offset_samples) /
|
||||||
static_cast<double>(sample_rate));
|
static_cast<double>(sample_rate));
|
||||||
placement.valid = !placement.timeline_in.isNaN();
|
placement.valid = !placement.timeline_in.isNaN();
|
||||||
return placement;
|
return placement;
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ public:
|
|||||||
bool valid = false;
|
bool valid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Placement PlaceBySourceTime(const SourceClip &reference,
|
static Placement
|
||||||
const SourceClip &candidate,
|
PlaceBySourceTime(const SourceClip &reference, const SourceClip &candidate,
|
||||||
const core::rational &reference_timeline_in);
|
const core::rational &reference_timeline_in);
|
||||||
|
|
||||||
static Placement PlaceByWaveformOffset(
|
static Placement
|
||||||
const core::rational &reference_timeline_in,
|
PlaceByWaveformOffset(const core::rational &reference_timeline_in,
|
||||||
int64_t candidate_offset_samples, int sample_rate);
|
int64_t candidate_offset_samples, int sample_rate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ AudioWaveformSync::OffsetResult AudioWaveformSync::EstimateEnvelopeOffset(
|
|||||||
int64_t best_lag = 0;
|
int64_t best_lag = 0;
|
||||||
|
|
||||||
for (int64_t lag = -max_offset_windows; lag <= max_offset_windows; lag++) {
|
for (int64_t lag = -max_offset_windows; lag <= max_offset_windows; lag++) {
|
||||||
const int reference_start = static_cast<int>(std::max<int64_t>(0, -lag));
|
const int reference_start =
|
||||||
|
static_cast<int>(std::max<int64_t>(0, -lag));
|
||||||
const int candidate_start = static_cast<int>(std::max<int64_t>(0, lag));
|
const int candidate_start = static_cast<int>(std::max<int64_t>(0, lag));
|
||||||
const int overlap = std::min(reference.size() - reference_start,
|
const int overlap = std::min(reference.size() - reference_start,
|
||||||
candidate.size() - candidate_start);
|
candidate.size() - candidate_start);
|
||||||
@@ -142,8 +143,7 @@ AudioWaveformSync::OffsetResult AudioWaveformSync::EstimateEnvelopeOffset(
|
|||||||
if (best_score > -2.0) {
|
if (best_score > -2.0) {
|
||||||
result.valid = true;
|
result.valid = true;
|
||||||
result.confidence = std::max(0.0, best_score);
|
result.confidence = std::max(0.0, best_score);
|
||||||
result.offset_samples =
|
result.offset_samples = best_lag * static_cast<int64_t>(window_samples);
|
||||||
best_lag * static_cast<int64_t>(window_samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ public:
|
|||||||
bool valid = false;
|
bool valid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static QVector<double>
|
static QVector<double> ExtractRmsEnvelope(const core::SampleBuffer &samples,
|
||||||
ExtractRmsEnvelope(const core::SampleBuffer &samples, size_t window_samples);
|
size_t window_samples);
|
||||||
|
|
||||||
static OffsetResult EstimateOffset(const core::SampleBuffer &reference,
|
static OffsetResult EstimateOffset(const core::SampleBuffer &reference,
|
||||||
const core::SampleBuffer &candidate,
|
const core::SampleBuffer &candidate,
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ extern "C" {
|
|||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
|
{
|
||||||
|
|
||||||
static FramePtr CopyPackedAVFrameToFrame(const AVFramePtr &src,
|
static FramePtr CopyPackedAVFrameToFrame(const AVFramePtr &src,
|
||||||
PixelFormat format,
|
PixelFormat format, int channel_count,
|
||||||
int channel_count,
|
|
||||||
const rational ×tamp)
|
const rational ×tamp)
|
||||||
{
|
{
|
||||||
if (!src || !src->data[0]) {
|
if (!src || !src->data[0]) {
|
||||||
@@ -48,8 +48,7 @@ static FramePtr CopyPackedAVFrameToFrame(const AVFramePtr &src,
|
|||||||
VideoParams::GetBytesPerPixel(format, channel_count);
|
VideoParams::GetBytesPerPixel(format, channel_count);
|
||||||
for (int y = 0; y < frame->height(); y++) {
|
for (int y = 0; y < frame->height(); y++) {
|
||||||
memcpy(frame->data() + y * frame->linesize_bytes(),
|
memcpy(frame->data() + y * frame->linesize_bytes(),
|
||||||
src->data[0] + y * src->linesize[0],
|
src->data[0] + y * src->linesize[0], size_t(row_bytes));
|
||||||
size_t(row_bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
@@ -97,7 +96,8 @@ namespace olive
|
|||||||
QVariant Yuv2RgbShader;
|
QVariant Yuv2RgbShader;
|
||||||
QVariant DeinterlaceShader;
|
QVariant DeinterlaceShader;
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
constexpr int64_t kAnalyzeDurationUs = 5000000;
|
constexpr int64_t kAnalyzeDurationUs = 5000000;
|
||||||
constexpr int64_t kProbeSizeBytes = 20000000;
|
constexpr int64_t kProbeSizeBytes = 20000000;
|
||||||
@@ -133,8 +133,9 @@ void DiscardSubtitleStreams(AVFormatContext *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimecodeMetadata::SourceTime ExtractSourceStartTime(
|
TimecodeMetadata::SourceTime ExtractSourceStartTime(AVDictionary *metadata,
|
||||||
AVDictionary *metadata, const rational &timebase, int sample_rate)
|
const rational &timebase,
|
||||||
|
int sample_rate)
|
||||||
{
|
{
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return TimecodeMetadata::SourceTime();
|
return TimecodeMetadata::SourceTime();
|
||||||
@@ -458,14 +459,15 @@ FramePtr FFmpegDecoder::RetrieveVideoFrameInternal(const RetrieveVideoParams &p)
|
|||||||
AVFramePtr dest = CreateAVFramePtr();
|
AVFramePtr dest = CreateAVFramePtr();
|
||||||
dest->width = f->width;
|
dest->width = f->width;
|
||||||
dest->height = f->height;
|
dest->height = f->height;
|
||||||
dest->format = p.maximum_format == PixelFormat::U8
|
dest->format = p.maximum_format == PixelFormat::U8 ? AV_PIX_FMT_RGBA :
|
||||||
? AV_PIX_FMT_RGBA
|
AV_PIX_FMT_RGBA64;
|
||||||
: AV_PIX_FMT_RGBA64;
|
|
||||||
dest->color_range = f->color_range;
|
dest->color_range = f->color_range;
|
||||||
dest->colorspace = f->colorspace;
|
dest->colorspace = f->colorspace;
|
||||||
if (p.divider > 1) {
|
if (p.divider > 1) {
|
||||||
dest->width = VideoParams::GetScaledDimension(dest->width, p.divider);
|
dest->width =
|
||||||
dest->height = VideoParams::GetScaledDimension(dest->height, p.divider);
|
VideoParams::GetScaledDimension(dest->width, p.divider);
|
||||||
|
dest->height =
|
||||||
|
VideoParams::GetScaledDimension(dest->height, p.divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = av_frame_get_buffer(dest.get(), 0);
|
int r = av_frame_get_buffer(dest.get(), 0);
|
||||||
@@ -504,8 +506,8 @@ FramePtr FFmpegDecoder::RetrieveVideoFrameInternal(const RetrieveVideoParams &p)
|
|||||||
// zero-initializes the destination, leaving alpha at 0. The color
|
// zero-initializes the destination, leaving alpha at 0. The color
|
||||||
// management shader later multiplies RGB by alpha, producing black.
|
// management shader later multiplies RGB by alpha, producing black.
|
||||||
// Ensure alpha is opaque for source formats that have no alpha.
|
// Ensure alpha is opaque for source formats that have no alpha.
|
||||||
const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(
|
const AVPixFmtDescriptor *src_desc =
|
||||||
static_cast<AVPixelFormat>(f->format));
|
av_pix_fmt_desc_get(static_cast<AVPixelFormat>(f->format));
|
||||||
if (src_desc && !(src_desc->flags & AV_PIX_FMT_FLAG_ALPHA)) {
|
if (src_desc && !(src_desc->flags & AV_PIX_FMT_FLAG_ALPHA)) {
|
||||||
const int bpc = (dest->format == AV_PIX_FMT_RGBA) ? 1 : 2;
|
const int bpc = (dest->format == AV_PIX_FMT_RGBA) ? 1 : 2;
|
||||||
const int stride = dest->linesize[0];
|
const int stride = dest->linesize[0];
|
||||||
@@ -522,11 +524,10 @@ FramePtr FFmpegDecoder::RetrieveVideoFrameInternal(const RetrieveVideoParams &p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return CopyPackedAVFrameToFrame(dest,
|
return CopyPackedAVFrameToFrame(dest,
|
||||||
dest->format == AV_PIX_FMT_RGBA
|
dest->format == AV_PIX_FMT_RGBA ?
|
||||||
? PixelFormat::U8
|
PixelFormat::U8 :
|
||||||
: PixelFormat::U16,
|
PixelFormat::U16,
|
||||||
VideoParams::kRGBAChannelCount,
|
VideoParams::kRGBAChannelCount, p.time);
|
||||||
p.time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -580,7 +581,8 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
AVFormatContext *fmt_ctx = nullptr;
|
AVFormatContext *fmt_ctx = nullptr;
|
||||||
AVDictionary *format_opts = nullptr;
|
AVDictionary *format_opts = nullptr;
|
||||||
ApplyFormatOpenOptions(&format_opts);
|
ApplyFormatOpenOptions(&format_opts);
|
||||||
error_code = avformat_open_input(&fmt_ctx, filename_c, nullptr, &format_opts);
|
error_code =
|
||||||
|
avformat_open_input(&fmt_ctx, filename_c, nullptr, &format_opts);
|
||||||
av_dict_free(&format_opts);
|
av_dict_free(&format_opts);
|
||||||
TuneFormatContext(fmt_ctx);
|
TuneFormatContext(fmt_ctx);
|
||||||
DiscardSubtitleStreams(fmt_ctx);
|
DiscardSubtitleStreams(fmt_ctx);
|
||||||
@@ -591,9 +593,8 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
avformat_find_stream_info(fmt_ctx, nullptr);
|
avformat_find_stream_info(fmt_ctx, nullptr);
|
||||||
|
|
||||||
int64_t footage_duration = fmt_ctx->duration;
|
int64_t footage_duration = fmt_ctx->duration;
|
||||||
TimecodeMetadata::SourceTime source_start_time =
|
TimecodeMetadata::SourceTime source_start_time = ExtractSourceStartTime(
|
||||||
ExtractSourceStartTime(fmt_ctx->metadata, rational(1, AV_TIME_BASE),
|
fmt_ctx->metadata, rational(1, AV_TIME_BASE), 0);
|
||||||
0);
|
|
||||||
|
|
||||||
bool duration_guessed_from_bitrate =
|
bool duration_guessed_from_bitrate =
|
||||||
(fmt_ctx->duration_estimation_method ==
|
(fmt_ctx->duration_estimation_method ==
|
||||||
@@ -629,12 +630,14 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
AVPacket *pkt = av_packet_alloc();
|
AVPacket *pkt = av_packet_alloc();
|
||||||
AVFrame *frame = av_frame_alloc();
|
AVFrame *frame = av_frame_alloc();
|
||||||
|
|
||||||
VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone;
|
VideoParams::Interlacing interlacing =
|
||||||
|
VideoParams::kInterlaceNone;
|
||||||
AVRational pixel_aspect_ratio = { 1, 1 };
|
AVRational pixel_aspect_ratio = { 1, 1 };
|
||||||
AVRational frame_rate = avstream->avg_frame_rate;
|
AVRational frame_rate = avstream->avg_frame_rate;
|
||||||
AVPixelFormat compatible_pix_fmt =
|
AVPixelFormat compatible_pix_fmt =
|
||||||
FFmpegUtils::GetCompatiblePixelFormat(
|
FFmpegUtils::GetCompatiblePixelFormat(
|
||||||
static_cast<AVPixelFormat>(avstream->codecpar->format));
|
static_cast<AVPixelFormat>(
|
||||||
|
avstream->codecpar->format));
|
||||||
bool image_is_still = false;
|
bool image_is_still = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -643,15 +646,17 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
AVCodecContext *avctx = instance.codec_ctx();
|
AVCodecContext *avctx = instance.codec_ctx();
|
||||||
interlacing = FFmpegFieldOrderToOlive(avctx->field_order);
|
interlacing =
|
||||||
|
FFmpegFieldOrderToOlive(avctx->field_order);
|
||||||
|
|
||||||
if (instance.GetFrame(pkt, frame) >= 0) {
|
if (instance.GetFrame(pkt, frame) >= 0) {
|
||||||
pixel_aspect_ratio =
|
pixel_aspect_ratio =
|
||||||
av_guess_sample_aspect_ratio(instance.fmt_ctx(),
|
av_guess_sample_aspect_ratio(
|
||||||
instance.avstream(), frame);
|
instance.fmt_ctx(), instance.avstream(),
|
||||||
frame_rate =
|
frame);
|
||||||
av_guess_frame_rate(instance.fmt_ctx(),
|
frame_rate = av_guess_frame_rate(
|
||||||
instance.avstream(), frame);
|
instance.fmt_ctx(), instance.avstream(),
|
||||||
|
frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = instance.GetFrame(pkt, frame);
|
int ret = instance.GetFrame(pkt, frame);
|
||||||
@@ -660,7 +665,8 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
} else if (avstream->duration == AV_NOPTS_VALUE ||
|
} else if (avstream->duration == AV_NOPTS_VALUE ||
|
||||||
duration_guessed_from_bitrate) {
|
duration_guessed_from_bitrate) {
|
||||||
int64_t last_ts = frame->best_effort_timestamp;
|
int64_t last_ts = frame->best_effort_timestamp;
|
||||||
while (instance.GetFrame(pkt, frame) >= 0 &&
|
while (
|
||||||
|
instance.GetFrame(pkt, frame) >= 0 &&
|
||||||
(!cancelled || !cancelled->IsCancelled()))
|
(!cancelled || !cancelled->IsCancelled()))
|
||||||
last_ts = frame->best_effort_timestamp;
|
last_ts = frame->best_effort_timestamp;
|
||||||
avstream->duration = last_ts;
|
avstream->duration = last_ts;
|
||||||
@@ -677,26 +683,30 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename,
|
|||||||
stream.set_stream_index(i);
|
stream.set_stream_index(i);
|
||||||
stream.set_width(avstream->codecpar->width);
|
stream.set_width(avstream->codecpar->width);
|
||||||
stream.set_height(avstream->codecpar->height);
|
stream.set_height(avstream->codecpar->height);
|
||||||
stream.set_video_type(image_is_still ? VideoParams::kVideoTypeStill
|
stream.set_video_type(image_is_still ?
|
||||||
: VideoParams::kVideoTypeVideo);
|
VideoParams::kVideoTypeStill :
|
||||||
stream.set_format(GetNativePixelFormat(compatible_pix_fmt));
|
VideoParams::kVideoTypeVideo);
|
||||||
stream.set_channel_count(GetNativeChannelCount(compatible_pix_fmt));
|
stream.set_format(
|
||||||
|
GetNativePixelFormat(compatible_pix_fmt));
|
||||||
|
stream.set_channel_count(
|
||||||
|
GetNativeChannelCount(compatible_pix_fmt));
|
||||||
stream.set_interlacing(interlacing); // <-- 已正确填充
|
stream.set_interlacing(interlacing); // <-- 已正确填充
|
||||||
stream.set_pixel_aspect_ratio(pixel_aspect_ratio);
|
stream.set_pixel_aspect_ratio(pixel_aspect_ratio);
|
||||||
stream.set_frame_rate(frame_rate);
|
stream.set_frame_rate(frame_rate);
|
||||||
stream.set_start_time(avstream->start_time);
|
stream.set_start_time(avstream->start_time);
|
||||||
stream.set_time_base(avstream->time_base);
|
stream.set_time_base(avstream->time_base);
|
||||||
stream.set_duration(avstream->duration);
|
stream.set_duration(avstream->duration);
|
||||||
stream.set_color_range(avstream->codecpar->color_range == AVCOL_RANGE_JPEG
|
stream.set_color_range(
|
||||||
? VideoParams::kColorRangeFull
|
avstream->codecpar->color_range ==
|
||||||
: VideoParams::kColorRangeLimited);
|
AVCOL_RANGE_JPEG ?
|
||||||
|
VideoParams::kColorRangeFull :
|
||||||
|
VideoParams::kColorRangeLimited);
|
||||||
stream.set_premultiplied_alpha(false);
|
stream.set_premultiplied_alpha(false);
|
||||||
|
|
||||||
desc.AddVideoStream(stream);
|
desc.AddVideoStream(stream);
|
||||||
image_is_still ? still_streams++ : video_streams++;
|
image_is_still ? still_streams++ : video_streams++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else if (avstream->codecpar->codec_type ==
|
} else if (avstream->codecpar->codec_type ==
|
||||||
AVMEDIA_TYPE_AUDIO) {
|
AVMEDIA_TYPE_AUDIO) {
|
||||||
// Create an audio stream object
|
// Create an audio stream object
|
||||||
@@ -1270,14 +1280,14 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational &time,
|
|||||||
|
|
||||||
AVFramePtr FFmpegDecoder::TransferHardwareFrame(AVFramePtr f)
|
AVFramePtr FFmpegDecoder::TransferHardwareFrame(AVFramePtr f)
|
||||||
{
|
{
|
||||||
if (!instance_.hwaccel_enabled() ||
|
if (!instance_.hwaccel_enabled() || f->format != instance_.hw_pix_fmt()) {
|
||||||
f->format != instance_.hw_pix_fmt()) {
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFrame *sw_frame = av_frame_alloc();
|
AVFrame *sw_frame = av_frame_alloc();
|
||||||
if (!sw_frame) {
|
if (!sw_frame) {
|
||||||
qCritical() << "Failed to allocate software frame for hardware transfer";
|
qCritical()
|
||||||
|
<< "Failed to allocate software frame for hardware transfer";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1291,7 +1301,8 @@ AVFramePtr FFmpegDecoder::TransferHardwareFrame(AVFramePtr f)
|
|||||||
|
|
||||||
ret = av_frame_copy_props(sw_frame, f.get());
|
ret = av_frame_copy_props(sw_frame, f.get());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qWarning() << "Failed to copy frame properties during hardware transfer:"
|
qWarning()
|
||||||
|
<< "Failed to copy frame properties during hardware transfer:"
|
||||||
<< FFmpegError(ret);
|
<< FFmpegError(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1372,7 +1383,8 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
|
|||||||
// Open file in a format context
|
// Open file in a format context
|
||||||
AVDictionary *format_opts = nullptr;
|
AVDictionary *format_opts = nullptr;
|
||||||
ApplyFormatOpenOptions(&format_opts);
|
ApplyFormatOpenOptions(&format_opts);
|
||||||
int error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, &format_opts);
|
int error_code =
|
||||||
|
avformat_open_input(&fmt_ctx_, filename, nullptr, &format_opts);
|
||||||
av_dict_free(&format_opts);
|
av_dict_free(&format_opts);
|
||||||
TuneFormatContext(fmt_ctx_);
|
TuneFormatContext(fmt_ctx_);
|
||||||
DiscardSubtitleStreams(fmt_ctx_);
|
DiscardSubtitleStreams(fmt_ctx_);
|
||||||
@@ -1437,13 +1449,14 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
|
|||||||
error_code = avcodec_open2(codec_ctx_, codec, &opts_);
|
error_code = avcodec_open2(codec_ctx_, codec, &opts_);
|
||||||
if (error_code == 0) {
|
if (error_code == 0) {
|
||||||
hwaccel_enabled_ = true;
|
hwaccel_enabled_ = true;
|
||||||
qDebug() << "Hardware decoding enabled for" << filename
|
qDebug() << "Hardware decoding enabled for" << filename << "using"
|
||||||
<< "using" << av_hwdevice_get_type_name(hw_device_type_)
|
<< av_hwdevice_get_type_name(hw_device_type_)
|
||||||
<< "pixel format" << av_get_pix_fmt_name(hw_pix_fmt_);
|
<< "pixel format" << av_get_pix_fmt_name(hw_pix_fmt_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning() << "Failed to open hardware codec, falling back to software decoding:";
|
qWarning()
|
||||||
|
<< "Failed to open hardware codec, falling back to software decoding:";
|
||||||
char buf[512];
|
char buf[512];
|
||||||
av_strerror(error_code, buf, 512);
|
av_strerror(error_code, buf, 512);
|
||||||
qWarning() << FFmpegError(error_code) << buf;
|
qWarning() << FFmpegError(error_code) << buf;
|
||||||
@@ -1454,11 +1467,13 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
|
|||||||
|
|
||||||
codec_ctx_ = avcodec_alloc_context3(codec);
|
codec_ctx_ = avcodec_alloc_context3(codec);
|
||||||
if (codec_ctx_ == nullptr) {
|
if (codec_ctx_ == nullptr) {
|
||||||
qCritical() << "Failed to allocate codec context for software fallback";
|
qCritical()
|
||||||
|
<< "Failed to allocate codec context for software fallback";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_code = avcodec_parameters_to_context(codec_ctx_, avstream_->codecpar);
|
error_code =
|
||||||
|
avcodec_parameters_to_context(codec_ctx_, avstream_->codecpar);
|
||||||
if (error_code < 0) {
|
if (error_code < 0) {
|
||||||
qCritical()
|
qCritical()
|
||||||
<< "Failed to copy parameters from AVStream to AVCodecContext";
|
<< "Failed to copy parameters from AVStream to AVCodecContext";
|
||||||
@@ -1494,7 +1509,8 @@ AVHWDeviceType FFmpegDecoder::Instance::ChooseHardwareDevice()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
for (AVHWDeviceType type : { AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2,
|
for (AVHWDeviceType type :
|
||||||
|
{ AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2,
|
||||||
AV_HWDEVICE_TYPE_CUDA }) {
|
AV_HWDEVICE_TYPE_CUDA }) {
|
||||||
if (av_hwdevice_find_type_by_name(av_hwdevice_get_type_name(type)) !=
|
if (av_hwdevice_find_type_by_name(av_hwdevice_get_type_name(type)) !=
|
||||||
AV_HWDEVICE_TYPE_NONE) {
|
AV_HWDEVICE_TYPE_NONE) {
|
||||||
@@ -1502,17 +1518,17 @@ AVHWDeviceType FFmpegDecoder::Instance::ChooseHardwareDevice()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_MACOS)
|
#elif defined(Q_OS_MACOS)
|
||||||
if (av_hwdevice_find_type_by_name(
|
if (av_hwdevice_find_type_by_name(av_hwdevice_get_type_name(
|
||||||
av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX)) !=
|
AV_HWDEVICE_TYPE_VIDEOTOOLBOX)) != AV_HWDEVICE_TYPE_NONE) {
|
||||||
AV_HWDEVICE_TYPE_NONE) {
|
|
||||||
return AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
|
return AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return AV_HWDEVICE_TYPE_NONE;
|
return AV_HWDEVICE_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVPixelFormat FFmpegDecoder::Instance::GetHardwareFormat(
|
AVPixelFormat
|
||||||
AVCodecContext *ctx, const AVPixelFormat *pix_fmts)
|
FFmpegDecoder::Instance::GetHardwareFormat(AVCodecContext *ctx,
|
||||||
|
const AVPixelFormat *pix_fmts)
|
||||||
{
|
{
|
||||||
const Instance *inst = static_cast<const Instance *>(ctx->opaque);
|
const Instance *inst = static_cast<const Instance *>(ctx->opaque);
|
||||||
for (const AVPixelFormat *p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
|
for (const AVPixelFormat *p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
|
||||||
@@ -1521,7 +1537,8 @@ AVPixelFormat FFmpegDecoder::Instance::GetHardwareFormat(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning() << "Hardware pixel format not supported by decoder, using first software format";
|
qWarning()
|
||||||
|
<< "Hardware pixel format not supported by decoder, using first software format";
|
||||||
return pix_fmts[0];
|
return pix_fmts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,8 +1564,8 @@ bool FFmpegDecoder::Instance::InitHardwareAcceleration(const AVCodec *codec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hw_pix_fmt_ == AV_PIX_FMT_NONE) {
|
if (hw_pix_fmt_ == AV_PIX_FMT_NONE) {
|
||||||
qDebug() << "Codec" << codec->id
|
qDebug()
|
||||||
<< "does not support hardware device type"
|
<< "Codec" << codec->id << "does not support hardware device type"
|
||||||
<< av_hwdevice_get_type_name(device_type);
|
<< av_hwdevice_get_type_name(device_type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ protected:
|
|||||||
virtual bool OpenInternal() override;
|
virtual bool OpenInternal() override;
|
||||||
virtual TexturePtr
|
virtual TexturePtr
|
||||||
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
|
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
|
||||||
virtual FramePtr RetrieveVideoFrameInternal(const RetrieveVideoParams &p) override;
|
virtual FramePtr
|
||||||
|
RetrieveVideoFrameInternal(const RetrieveVideoParams &p) override;
|
||||||
virtual bool ConformAudioInternal(const QVector<QString> &filenames,
|
virtual bool ConformAudioInternal(const QVector<QString> &filenames,
|
||||||
const AudioParams ¶ms,
|
const AudioParams ¶ms,
|
||||||
CancelAtom *cancelled) override;
|
CancelAtom *cancelled) override;
|
||||||
|
|||||||
@@ -185,7 +185,8 @@ FramePtr OIIODecoder::RetrieveVideoFrameInternal(const RetrieveVideoParams &p)
|
|||||||
if (!frame->allocate()) {
|
if (!frame->allocate()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
memcpy(frame->data(), buffer_.const_data(), size_t(buffer_.allocated_size()));
|
memcpy(frame->data(), buffer_.const_data(),
|
||||||
|
size_t(buffer_.allocated_size()));
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ protected:
|
|||||||
virtual bool OpenInternal() override;
|
virtual bool OpenInternal() override;
|
||||||
virtual TexturePtr
|
virtual TexturePtr
|
||||||
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
|
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
|
||||||
virtual FramePtr RetrieveVideoFrameInternal(const RetrieveVideoParams &p) override;
|
virtual FramePtr
|
||||||
|
RetrieveVideoFrameInternal(const RetrieveVideoParams &p) override;
|
||||||
virtual void CloseInternal() override;
|
virtual void CloseInternal() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
+12
-14
@@ -52,14 +52,12 @@ QString ProxyManager::GetProxyFilename(const QString &cache_path,
|
|||||||
const QString proxy_dir = GetProxyDirectory(cache_path);
|
const QString proxy_dir = GetProxyDirectory(cache_path);
|
||||||
const QString extension =
|
const QString extension =
|
||||||
params.extension.isEmpty() ? QStringLiteral("mp4") : params.extension;
|
params.extension.isEmpty() ? QStringLiteral("mp4") : params.extension;
|
||||||
const QString filename = QStringLiteral("%1-%2.%3x%4.v%5.%6")
|
const QString filename =
|
||||||
.arg(FileFunctions::GetUniqueFileIdentifier(
|
QStringLiteral("%1-%2.%3x%4.v%5.%6")
|
||||||
source_filename),
|
.arg(FileFunctions::GetUniqueFileIdentifier(source_filename),
|
||||||
QString::number(stream_index),
|
QString::number(stream_index), QString::number(params.width),
|
||||||
QString::number(params.width),
|
|
||||||
QString::number(params.height),
|
QString::number(params.height),
|
||||||
QString::number(params.version),
|
QString::number(params.version), extension);
|
||||||
extension);
|
|
||||||
|
|
||||||
return QDir(proxy_dir).filePath(filename);
|
return QDir(proxy_dir).filePath(filename);
|
||||||
}
|
}
|
||||||
@@ -119,9 +117,10 @@ ProxyManager::ProxyStateFromString(const QString &state)
|
|||||||
return kProxyMissing;
|
return kProxyMissing;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyManager::Proxy ProxyManager::GetOrStartProxy(
|
ProxyManager::Proxy
|
||||||
const QString &cache_path, const QString &source_filename,
|
ProxyManager::GetOrStartProxy(const QString &cache_path,
|
||||||
int stream_index, const ProxyParams ¶ms)
|
const QString &source_filename, int stream_index,
|
||||||
|
const ProxyParams ¶ms)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mutex_);
|
QMutexLocker locker(&mutex_);
|
||||||
|
|
||||||
@@ -145,10 +144,9 @@ ProxyManager::Proxy ProxyManager::GetOrStartProxy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString working_filename = GetWorkingProxyFilename(filename);
|
const QString working_filename = GetWorkingProxyFilename(filename);
|
||||||
ProxyTask *task = new ProxyTask(source_filename, stream_index, params,
|
ProxyTask *task =
|
||||||
working_filename);
|
new ProxyTask(source_filename, stream_index, params, working_filename);
|
||||||
connect(task, &Task::Finished, this,
|
connect(task, &Task::Finished, this, &ProxyManager::ProxyTaskFinished);
|
||||||
&ProxyManager::ProxyTaskFinished);
|
|
||||||
task->moveToThread(TaskManager::instance()->thread());
|
task->moveToThread(TaskManager::instance()->thread());
|
||||||
QMetaObject::invokeMethod(TaskManager::instance(), "AddTask",
|
QMetaObject::invokeMethod(TaskManager::instance(), "AddTask",
|
||||||
Qt::QueuedConnection, Q_ARG(Task *, task));
|
Qt::QueuedConnection, Q_ARG(Task *, task));
|
||||||
|
|||||||
@@ -90,8 +90,7 @@ public:
|
|||||||
static ProxyState ProxyStateFromString(const QString &state);
|
static ProxyState ProxyStateFromString(const QString &state);
|
||||||
|
|
||||||
Proxy GetOrStartProxy(const QString &cache_path,
|
Proxy GetOrStartProxy(const QString &cache_path,
|
||||||
const QString &source_filename,
|
const QString &source_filename, int stream_index,
|
||||||
int stream_index,
|
|
||||||
const ProxyParams ¶ms);
|
const ProxyParams ¶ms);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@@ -28,8 +28,9 @@
|
|||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
TimecodeMetadata::SourceTime TimecodeMetadata::FromTimecodeString(
|
TimecodeMetadata::SourceTime
|
||||||
const QString &timecode, const core::rational &timebase)
|
TimecodeMetadata::FromTimecodeString(const QString &timecode,
|
||||||
|
const core::rational &timebase)
|
||||||
{
|
{
|
||||||
SourceTime result;
|
SourceTime result;
|
||||||
const QString trimmed = timecode.trimmed();
|
const QString trimmed = timecode.trimmed();
|
||||||
@@ -39,8 +40,8 @@ TimecodeMetadata::SourceTime TimecodeMetadata::FromTimecodeString(
|
|||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
const core::Timecode::Display display =
|
const core::Timecode::Display display =
|
||||||
trimmed.contains(';') ? core::Timecode::kTimecodeDropFrame
|
trimmed.contains(';') ? core::Timecode::kTimecodeDropFrame :
|
||||||
: core::Timecode::kTimecodeNonDropFrame;
|
core::Timecode::kTimecodeNonDropFrame;
|
||||||
result.time = core::Timecode::timecode_to_time(trimmed.toStdString(),
|
result.time = core::Timecode::timecode_to_time(trimmed.toStdString(),
|
||||||
timebase, display, &ok);
|
timebase, display, &ok);
|
||||||
result.valid = ok;
|
result.valid = ok;
|
||||||
@@ -50,8 +51,9 @@ TimecodeMetadata::SourceTime TimecodeMetadata::FromTimecodeString(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimecodeMetadata::SourceTime TimecodeMetadata::FromBwfTimeReference(
|
TimecodeMetadata::SourceTime
|
||||||
const QString &time_reference, int sample_rate)
|
TimecodeMetadata::FromBwfTimeReference(const QString &time_reference,
|
||||||
|
int sample_rate)
|
||||||
{
|
{
|
||||||
SourceTime result;
|
SourceTime result;
|
||||||
if (sample_rate <= 0) {
|
if (sample_rate <= 0) {
|
||||||
@@ -73,8 +75,7 @@ TimecodeMetadata::SourceTime TimecodeMetadata::FromBwfTimeReference(
|
|||||||
const qulonglong rational_limit =
|
const qulonglong rational_limit =
|
||||||
static_cast<qulonglong>(std::numeric_limits<int>::max());
|
static_cast<qulonglong>(std::numeric_limits<int>::max());
|
||||||
if (numerator <= rational_limit && denominator <= rational_limit) {
|
if (numerator <= rational_limit && denominator <= rational_limit) {
|
||||||
result.time =
|
result.time = core::rational(static_cast<int>(numerator),
|
||||||
core::rational(static_cast<int>(numerator),
|
|
||||||
static_cast<int>(denominator));
|
static_cast<int>(denominator));
|
||||||
} else {
|
} else {
|
||||||
result.time = core::rational::fromDouble(
|
result.time = core::rational::fromDouble(
|
||||||
|
|||||||
@@ -73,10 +73,12 @@ public:
|
|||||||
return plugin_cache_;
|
return plugin_cache_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPluginCache(std::shared_ptr<OFX::Host::ImageEffect::PluginCache> cache)
|
void
|
||||||
|
setPluginCache(std::shared_ptr<OFX::Host::ImageEffect::PluginCache> cache)
|
||||||
{
|
{
|
||||||
plugin_cache_ = cache;
|
plugin_cache_ = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Current current;
|
static Current current;
|
||||||
olive::VideoParams currentVideoParams_;
|
olive::VideoParams currentVideoParams_;
|
||||||
@@ -85,6 +87,4 @@ private:
|
|||||||
std::shared_ptr<OFX::Host::ImageEffect::PluginCache> plugin_cache_;
|
std::shared_ptr<OFX::Host::ImageEffect::PluginCache> plugin_cache_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //CURRENT_H
|
#endif //CURRENT_H
|
||||||
|
|||||||
@@ -341,8 +341,8 @@ void Config::Load()
|
|||||||
// Config::Load() is called before Core (and therefore the main window)
|
// Config::Load() is called before Core (and therefore the main window)
|
||||||
// is constructed, so we cannot use Core::instance()->main_window() as
|
// is constructed, so we cannot use Core::instance()->main_window() as
|
||||||
// the message box parent. Passing nullptr creates a top-level dialog.
|
// the message box parent. Passing nullptr creates a top-level dialog.
|
||||||
QWidget *parent = Core::instance() ? Core::instance()->main_window()
|
QWidget *parent = Core::instance() ? Core::instance()->main_window() :
|
||||||
: nullptr;
|
nullptr;
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
parent,
|
parent,
|
||||||
QCoreApplication::translate("Config", "Error loading settings"),
|
QCoreApplication::translate("Config", "Error loading settings"),
|
||||||
|
|||||||
+18
-18
@@ -80,7 +80,8 @@
|
|||||||
#include "widget/menu/menushared.h"
|
#include "widget/menu/menushared.h"
|
||||||
#include "window/mainwindow/mainwindow.h"
|
#include "window/mainwindow/mainwindow.h"
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
QStringList FootageVideoExtensions()
|
QStringList FootageVideoExtensions()
|
||||||
{
|
{
|
||||||
@@ -95,22 +96,21 @@ QStringList FootageVideoExtensions()
|
|||||||
|
|
||||||
QStringList FootageAudioExtensions()
|
QStringList FootageAudioExtensions()
|
||||||
{
|
{
|
||||||
return QStringList{
|
return QStringList{ QStringLiteral("wav"), QStringLiteral("mp3"),
|
||||||
QStringLiteral("wav"), QStringLiteral("mp3"), QStringLiteral("flac"),
|
QStringLiteral("flac"), QStringLiteral("aac"),
|
||||||
QStringLiteral("aac"), QStringLiteral("ogg"), QStringLiteral("opus"),
|
QStringLiteral("ogg"), QStringLiteral("opus"),
|
||||||
QStringLiteral("m4a"), QStringLiteral("alac"), QStringLiteral("aif"),
|
QStringLiteral("m4a"), QStringLiteral("alac"),
|
||||||
QStringLiteral("aiff"), QStringLiteral("aifc"), QStringLiteral("wma")
|
QStringLiteral("aif"), QStringLiteral("aiff"),
|
||||||
};
|
QStringLiteral("aifc"), QStringLiteral("wma") };
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList FootageImageExtensions()
|
QStringList FootageImageExtensions()
|
||||||
{
|
{
|
||||||
return QStringList{
|
return QStringList{ QStringLiteral("png"), QStringLiteral("jpg"),
|
||||||
QStringLiteral("png"), QStringLiteral("jpg"), QStringLiteral("jpeg"),
|
QStringLiteral("jpeg"), QStringLiteral("tif"),
|
||||||
QStringLiteral("tif"), QStringLiteral("tiff"), QStringLiteral("bmp"),
|
QStringLiteral("tiff"), QStringLiteral("bmp"),
|
||||||
QStringLiteral("gif"), QStringLiteral("exr"), QStringLiteral("dpx"),
|
QStringLiteral("gif"), QStringLiteral("exr"),
|
||||||
QStringLiteral("webp")
|
QStringLiteral("dpx"), QStringLiteral("webp") };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BuildFootageFilterGroup(const QString &label,
|
QString BuildFootageFilterGroup(const QString &label,
|
||||||
@@ -122,8 +122,8 @@ QString BuildFootageFilterGroup(const QString &label,
|
|||||||
patterns.append(QStringLiteral("*.%1").arg(ext));
|
patterns.append(QStringLiteral("*.%1").arg(ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
return QStringLiteral("%1 (%2)")
|
return QStringLiteral("%1 (%2)").arg(label,
|
||||||
.arg(label, patterns.join(QLatin1Char(' ')));
|
patterns.join(QLatin1Char(' ')));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BuildFootageFileDialogFilter()
|
QString BuildFootageFileDialogFilter()
|
||||||
@@ -457,9 +457,9 @@ void Core::DialogAboutShow()
|
|||||||
void Core::DialogImportShow()
|
void Core::DialogImportShow()
|
||||||
{
|
{
|
||||||
// Open dialog for user to select files
|
// Open dialog for user to select files
|
||||||
QStringList files = QFileDialog::getOpenFileNames(
|
QStringList files =
|
||||||
main_window_, tr("Import footage..."), QString(),
|
QFileDialog::getOpenFileNames(main_window_, tr("Import footage..."),
|
||||||
FootageFileDialogFilter());
|
QString(), FootageFileDialogFilter());
|
||||||
|
|
||||||
// Check if the user actually selected files to import
|
// Check if the user actually selected files to import
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ CrashHandlerDialog::CrashHandlerDialog(const QString &report_path)
|
|||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
|
|
||||||
layout->addWidget(new QLabel(
|
layout->addWidget(new QLabel(tr(
|
||||||
tr("We're sorry, Oak Video Editor has crashed. Please help us fix it by "
|
"We're sorry, Oak Video Editor has crashed. Please help us fix it by "
|
||||||
"sending an error report.")));
|
"sending an error report.")));
|
||||||
|
|
||||||
QSplitter *splitter = new QSplitter(Qt::Vertical);
|
QSplitter *splitter = new QSplitter(Qt::Vertical);
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent)
|
|||||||
"<p>%3</p>" // Description
|
"<p>%3</p>" // Description
|
||||||
"<p>%4</p>" // Fork notice
|
"<p>%4</p>" // Fork notice
|
||||||
"</body></html>")
|
"</body></html>")
|
||||||
.arg(QApplication::applicationName(),
|
.arg(
|
||||||
|
QApplication::applicationName(),
|
||||||
QApplication::applicationVersion(),
|
QApplication::applicationVersion(),
|
||||||
tr("Oak Video Editor is a free open source non-linear video editor. "
|
tr("Oak Video Editor is a free open source non-linear video editor. "
|
||||||
"This software is licensed under the GNU GPL Version 3."),
|
"This software is licensed under the GNU GPL Version 3."),
|
||||||
|
|||||||
@@ -79,5 +79,6 @@ while True:
|
|||||||
break
|
break
|
||||||
|
|
||||||
text_file = open("patreon.h", "w", encoding="utf-8")
|
text_file = open("patreon.h", "w", encoding="utf-8")
|
||||||
text_file.write("#ifndef PATREON_H\n#define PATREON_H\n\n#include <QStringList>\n\nQStringList patrons = {\n%s\n};\n\n#endif // PATREON_H\n" % name_list)
|
text_file.write(
|
||||||
|
"#ifndef PATREON_H\n#define PATREON_H\n\n#include <QStringList>\n\nQStringList patrons = {\n%s\n};\n\n#endif // PATREON_H\n" % name_list)
|
||||||
text_file.close()
|
text_file.close()
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
|
||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
|
|
||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -46,15 +46,18 @@ PreferencesDialog::PreferencesDialog(MainWindow *main_window, int start_tab)
|
|||||||
AddTab(new PreferencesGeneralTab(), tr("General"));
|
AddTab(new PreferencesGeneralTab(), tr("General"));
|
||||||
AddTab(new PreferencesAppearanceTab(), tr("Appearance"));
|
AddTab(new PreferencesAppearanceTab(), tr("Appearance"));
|
||||||
AddTab(new PreferencesAudioTab(), tr("Audio"));
|
AddTab(new PreferencesAudioTab(), tr("Audio"));
|
||||||
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryTimeline),
|
AddTab(
|
||||||
|
new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryTimeline),
|
||||||
tr("Timeline"));
|
tr("Timeline"));
|
||||||
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryPlayback),
|
AddTab(
|
||||||
|
new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryPlayback),
|
||||||
tr("Playback"));
|
tr("Playback"));
|
||||||
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryProject),
|
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryProject),
|
||||||
tr("Project"));
|
tr("Project"));
|
||||||
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryNodes),
|
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryNodes),
|
||||||
tr("Nodes"));
|
tr("Nodes"));
|
||||||
AddTab(new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryRendering),
|
AddTab(
|
||||||
|
new PreferencesBehaviorTab(PreferencesBehaviorTab::kCategoryRendering),
|
||||||
tr("Rendering"));
|
tr("Rendering"));
|
||||||
AddTab(new PreferencesDiskTab(), tr("Disk"));
|
AddTab(new PreferencesDiskTab(), tr("Disk"));
|
||||||
AddTab(new PreferencesKeyboardTab(main_window), tr("Keyboard"));
|
AddTab(new PreferencesKeyboardTab(main_window), tr("Keyboard"));
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ PreferencesBehaviorTab::PreferencesBehaviorTab(Category category)
|
|||||||
AddItems({
|
AddItems({
|
||||||
{ tr("Auto-Seek to Imported Clips"),
|
{ tr("Auto-Seek to Imported Clips"),
|
||||||
QStringLiteral("EnableSeekToImport") },
|
QStringLiteral("EnableSeekToImport") },
|
||||||
{ tr("Edit Tool Also Seeks"),
|
{ tr("Edit Tool Also Seeks"), QStringLiteral("EditToolAlsoSeeks") },
|
||||||
QStringLiteral("EditToolAlsoSeeks") },
|
|
||||||
{ tr("Edit Tool Selects Links"),
|
{ tr("Edit Tool Selects Links"),
|
||||||
QStringLiteral("EditToolSelectsLinks") },
|
QStringLiteral("EditToolSelectsLinks") },
|
||||||
{ tr("Enable Drag Files to Timeline"),
|
{ tr("Enable Drag Files to Timeline"),
|
||||||
@@ -83,8 +82,7 @@ PreferencesBehaviorTab::PreferencesBehaviorTab(Category category)
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCategoryRendering:
|
case kCategoryRendering: {
|
||||||
{
|
|
||||||
QLabel *backend_label = new QLabel(tr("Graphics Backend"));
|
QLabel *backend_label = new QLabel(tr("Graphics Backend"));
|
||||||
backend_label->setToolTip(
|
backend_label->setToolTip(
|
||||||
tr("Selects the graphics API Oak should request on next launch. "
|
tr("Selects the graphics API Oak should request on next launch. "
|
||||||
@@ -100,11 +98,10 @@ PreferencesBehaviorTab::PreferencesBehaviorTab(Category category)
|
|||||||
const QString current_backend =
|
const QString current_backend =
|
||||||
OLIVE_CONFIG("GraphicsBackend").toString().toLower();
|
OLIVE_CONFIG("GraphicsBackend").toString().toLower();
|
||||||
const int backend_index = graphics_backend_combobox_->findData(
|
const int backend_index = graphics_backend_combobox_->findData(
|
||||||
current_backend.isEmpty() ? QStringLiteral("opengl")
|
current_backend.isEmpty() ? QStringLiteral("opengl") :
|
||||||
: current_backend);
|
current_backend);
|
||||||
graphics_backend_combobox_->setCurrentIndex(backend_index >= 0
|
graphics_backend_combobox_->setCurrentIndex(
|
||||||
? backend_index
|
backend_index >= 0 ? backend_index : 0);
|
||||||
: 0);
|
|
||||||
|
|
||||||
QHBoxLayout *backend_layout = new QHBoxLayout();
|
QHBoxLayout *backend_layout = new QHBoxLayout();
|
||||||
backend_layout->addWidget(backend_label);
|
backend_layout->addWidget(backend_label);
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ public:
|
|||||||
|
|
||||||
static QString BehaviorPrefTr(const char *text)
|
static QString BehaviorPrefTr(const char *text)
|
||||||
{
|
{
|
||||||
return QCoreApplication::translate("olive::PreferencesBehaviorTab", text);
|
return QCoreApplication::translate("olive::PreferencesBehaviorTab",
|
||||||
|
text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -105,16 +105,14 @@ PreferencesDiskTab::PreferencesDiskTab()
|
|||||||
proxy_width_slider_ = new IntegerSlider();
|
proxy_width_slider_ = new IntegerSlider();
|
||||||
proxy_width_slider_->SetMinimum(160);
|
proxy_width_slider_->SetMinimum(160);
|
||||||
proxy_width_slider_->SetMaximum(4096);
|
proxy_width_slider_->SetMaximum(4096);
|
||||||
proxy_width_slider_->SetValue(
|
proxy_width_slider_->SetValue(OLIVE_CONFIG("ProxyWidth").value<int>());
|
||||||
OLIVE_CONFIG("ProxyWidth").value<int>());
|
|
||||||
proxy_layout->addWidget(proxy_width_slider_, proxy_row, 1);
|
proxy_layout->addWidget(proxy_width_slider_, proxy_row, 1);
|
||||||
|
|
||||||
proxy_layout->addWidget(new QLabel(tr("Proxy Height:")), proxy_row, 2);
|
proxy_layout->addWidget(new QLabel(tr("Proxy Height:")), proxy_row, 2);
|
||||||
proxy_height_slider_ = new IntegerSlider();
|
proxy_height_slider_ = new IntegerSlider();
|
||||||
proxy_height_slider_->SetMinimum(120);
|
proxy_height_slider_->SetMinimum(120);
|
||||||
proxy_height_slider_->SetMaximum(2160);
|
proxy_height_slider_->SetMaximum(2160);
|
||||||
proxy_height_slider_->SetValue(
|
proxy_height_slider_->SetValue(OLIVE_CONFIG("ProxyHeight").value<int>());
|
||||||
OLIVE_CONFIG("ProxyHeight").value<int>());
|
|
||||||
proxy_layout->addWidget(proxy_height_slider_, proxy_row, 3);
|
proxy_layout->addWidget(proxy_height_slider_, proxy_row, 3);
|
||||||
|
|
||||||
proxy_row++;
|
proxy_row++;
|
||||||
@@ -123,28 +121,22 @@ PreferencesDiskTab::PreferencesDiskTab()
|
|||||||
proxy_crf_slider_ = new IntegerSlider();
|
proxy_crf_slider_ = new IntegerSlider();
|
||||||
proxy_crf_slider_->SetMinimum(0);
|
proxy_crf_slider_->SetMinimum(0);
|
||||||
proxy_crf_slider_->SetMaximum(51);
|
proxy_crf_slider_->SetMaximum(51);
|
||||||
proxy_crf_slider_->SetValue(
|
proxy_crf_slider_->SetValue(OLIVE_CONFIG("ProxyCRF").value<int>());
|
||||||
OLIVE_CONFIG("ProxyCRF").value<int>());
|
|
||||||
proxy_layout->addWidget(proxy_crf_slider_, proxy_row, 1);
|
proxy_layout->addWidget(proxy_crf_slider_, proxy_row, 1);
|
||||||
|
|
||||||
proxy_layout->addWidget(new QLabel(tr("Proxy Preset:")), proxy_row, 2);
|
proxy_layout->addWidget(new QLabel(tr("Proxy Preset:")), proxy_row, 2);
|
||||||
proxy_preset_combo_ = new QComboBox();
|
proxy_preset_combo_ = new QComboBox();
|
||||||
const QStringList presets = {
|
const QStringList presets = {
|
||||||
QStringLiteral("ultrafast"),
|
QStringLiteral("ultrafast"), QStringLiteral("superfast"),
|
||||||
QStringLiteral("superfast"),
|
QStringLiteral("veryfast"), QStringLiteral("faster"),
|
||||||
QStringLiteral("veryfast"),
|
QStringLiteral("fast"), QStringLiteral("medium"),
|
||||||
QStringLiteral("faster"),
|
QStringLiteral("slow"), QStringLiteral("slower"),
|
||||||
QStringLiteral("fast"),
|
|
||||||
QStringLiteral("medium"),
|
|
||||||
QStringLiteral("slow"),
|
|
||||||
QStringLiteral("slower"),
|
|
||||||
QStringLiteral("veryslow"),
|
QStringLiteral("veryslow"),
|
||||||
};
|
};
|
||||||
for (const QString &preset : presets) {
|
for (const QString &preset : presets) {
|
||||||
proxy_preset_combo_->addItem(preset);
|
proxy_preset_combo_->addItem(preset);
|
||||||
}
|
}
|
||||||
proxy_preset_combo_->setCurrentText(
|
proxy_preset_combo_->setCurrentText(OLIVE_CONFIG("ProxyPreset").toString());
|
||||||
OLIVE_CONFIG("ProxyPreset").toString());
|
|
||||||
proxy_layout->addWidget(proxy_preset_combo_, proxy_row, 3);
|
proxy_layout->addWidget(proxy_preset_combo_, proxy_row, 3);
|
||||||
|
|
||||||
outer_layout->addStretch();
|
outer_layout->addStretch();
|
||||||
@@ -185,8 +177,10 @@ void PreferencesDiskTab::Accept(MultiUndoCommand *command)
|
|||||||
OLIVE_CONFIG("DiskCacheAhead") = QVariant::fromValue(
|
OLIVE_CONFIG("DiskCacheAhead") = QVariant::fromValue(
|
||||||
rational::fromDouble(cache_ahead_slider_->GetValue()));
|
rational::fromDouble(cache_ahead_slider_->GetValue()));
|
||||||
|
|
||||||
OLIVE_CONFIG("ProxyWidth") = static_cast<int>(proxy_width_slider_->GetValue());
|
OLIVE_CONFIG("ProxyWidth") =
|
||||||
OLIVE_CONFIG("ProxyHeight") = static_cast<int>(proxy_height_slider_->GetValue());
|
static_cast<int>(proxy_width_slider_->GetValue());
|
||||||
|
OLIVE_CONFIG("ProxyHeight") =
|
||||||
|
static_cast<int>(proxy_height_slider_->GetValue());
|
||||||
OLIVE_CONFIG("ProxyCRF") = static_cast<int>(proxy_crf_slider_->GetValue());
|
OLIVE_CONFIG("ProxyCRF") = static_cast<int>(proxy_crf_slider_->GetValue());
|
||||||
OLIVE_CONFIG("ProxyPreset") = proxy_preset_combo_->currentText();
|
OLIVE_CONFIG("ProxyPreset") = proxy_preset_combo_->currentText();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,21 +169,25 @@ PreferencesGeneralTab::PreferencesGeneralTab()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QGroupBox *behavior_groupbox = new QGroupBox(PreferencesBehaviorTab::BehaviorPrefTr("Behavior"));
|
QGroupBox *behavior_groupbox =
|
||||||
|
new QGroupBox(PreferencesBehaviorTab::BehaviorPrefTr("Behavior"));
|
||||||
QVBoxLayout *behavior_layout = new QVBoxLayout(behavior_groupbox);
|
QVBoxLayout *behavior_layout = new QVBoxLayout(behavior_groupbox);
|
||||||
layout->addWidget(behavior_groupbox);
|
layout->addWidget(behavior_groupbox);
|
||||||
|
|
||||||
hover_focus_ = new QCheckBox(PreferencesBehaviorTab::BehaviorPrefTr("Enable hover focus"));
|
hover_focus_ = new QCheckBox(
|
||||||
|
PreferencesBehaviorTab::BehaviorPrefTr("Enable hover focus"));
|
||||||
hover_focus_->setToolTip(PreferencesBehaviorTab::BehaviorPrefTr(
|
hover_focus_->setToolTip(PreferencesBehaviorTab::BehaviorPrefTr(
|
||||||
"Panels will be considered focused when the mouse cursor is over them without having to click them."));
|
"Panels will be considered focused when the mouse cursor is over them without having to click them."));
|
||||||
hover_focus_->setChecked(OLIVE_CONFIG("HoverFocus").toBool());
|
hover_focus_->setChecked(OLIVE_CONFIG("HoverFocus").toBool());
|
||||||
behavior_layout->addWidget(hover_focus_);
|
behavior_layout->addWidget(hover_focus_);
|
||||||
|
|
||||||
slider_ladder_ = new QCheckBox(PreferencesBehaviorTab::BehaviorPrefTr("Enable slider ladder"));
|
slider_ladder_ = new QCheckBox(
|
||||||
|
PreferencesBehaviorTab::BehaviorPrefTr("Enable slider ladder"));
|
||||||
slider_ladder_->setChecked(OLIVE_CONFIG("UseSliderLadders").toBool());
|
slider_ladder_->setChecked(OLIVE_CONFIG("UseSliderLadders").toBool());
|
||||||
behavior_layout->addWidget(slider_ladder_);
|
behavior_layout->addWidget(slider_ladder_);
|
||||||
|
|
||||||
scroll_zooms_ = new QCheckBox(PreferencesBehaviorTab::BehaviorPrefTr("Scrolling zooms by default"));
|
scroll_zooms_ = new QCheckBox(PreferencesBehaviorTab::BehaviorPrefTr(
|
||||||
|
"Scrolling zooms by default"));
|
||||||
scroll_zooms_->setToolTip(PreferencesBehaviorTab::BehaviorPrefTr(
|
scroll_zooms_->setToolTip(PreferencesBehaviorTab::BehaviorPrefTr(
|
||||||
"By default, scrolling will move the view around, and holding Ctrl/Cmd will make it zoom instead. "
|
"By default, scrolling will move the view around, and holding Ctrl/Cmd will make it zoom instead. "
|
||||||
"Enabling this will switch those, scrolling will zoom by default, and holding Ctrl/Cmd will move the view instead."));
|
"Enabling this will switch those, scrolling will zoom by default, and holding Ctrl/Cmd will move the view instead."));
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
|
||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
|
||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
+6
-8
@@ -148,7 +148,6 @@ int decompress_project(const QString &project)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
// Set up debug handler
|
// Set up debug handler
|
||||||
qInstallMessageHandler(olive::DebugHandler);
|
qInstallMessageHandler(olive::DebugHandler);
|
||||||
|
|
||||||
@@ -229,8 +228,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
auto no_plugin = parser.AddOption(
|
auto no_plugin = parser.AddOption(
|
||||||
{ QStringLiteral("-no-plugin") },
|
{ QStringLiteral("-no-plugin") },
|
||||||
QCoreApplication::translate("main", "Don't load plugins")
|
QCoreApplication::translate("main", "Don't load plugins"));
|
||||||
);
|
|
||||||
|
|
||||||
// Qt options re-implemented (add to this as necessary)
|
// Qt options re-implemented (add to this as necessary)
|
||||||
//
|
//
|
||||||
@@ -352,13 +350,13 @@ int main(int argc, char *argv[])
|
|||||||
olive::Config::Current()[QStringLiteral("GraphicsBackend")]
|
olive::Config::Current()[QStringLiteral("GraphicsBackend")]
|
||||||
.toString()
|
.toString()
|
||||||
.toLower();
|
.toLower();
|
||||||
qputenv("QSG_RHI_BACKEND",
|
qputenv("QSG_RHI_BACKEND", graphics_backend == QStringLiteral("vulkan") ?
|
||||||
graphics_backend == QStringLiteral("vulkan")
|
QByteArrayLiteral("vulkan") :
|
||||||
? QByteArrayLiteral("vulkan")
|
QByteArrayLiteral("opengl"));
|
||||||
: QByteArrayLiteral("opengl"));
|
|
||||||
|
|
||||||
if (auto *gui_app = qobject_cast<QGuiApplication *>(a.get())) {
|
if (auto *gui_app = qobject_cast<QGuiApplication *>(a.get())) {
|
||||||
gui_app->setWindowIcon(QIcon(QStringLiteral(":/graphics/oak-logo.png")));
|
gui_app->setWindowIcon(
|
||||||
|
QIcon(QStringLiteral(":/graphics/oak-logo.png")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_plugins) {
|
if (load_plugins) {
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ const QString OCIOLutNode::kDirectionInput = QStringLiteral("lut_dir_in");
|
|||||||
|
|
||||||
#define super OCIOBaseNode
|
#define super OCIOBaseNode
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
bool IsSupportedLutExtension(const QString &suffix)
|
bool IsSupportedLutExtension(const QString &suffix)
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,8 @@ bool IsSupportedLutExtension(const QString &suffix)
|
|||||||
|
|
||||||
bool IsMainProcess()
|
bool IsMainProcess()
|
||||||
{
|
{
|
||||||
return qobject_cast<QApplication *>(QCoreApplication::instance()) != nullptr;
|
return qobject_cast<QApplication *>(QCoreApplication::instance()) !=
|
||||||
|
nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadDirectionInput(const Node *node)
|
int ReadDirectionInput(const Node *node)
|
||||||
@@ -245,9 +247,8 @@ bool OCIOLutNode::CreateProcessorFromInputs() const
|
|||||||
|
|
||||||
ColorProcessorPtr processor;
|
ColorProcessorPtr processor;
|
||||||
try {
|
try {
|
||||||
const bool forward =
|
const bool forward = static_cast<ColorProcessor::Direction>(
|
||||||
static_cast<ColorProcessor::Direction>(direction) ==
|
direction) == ColorProcessor::kNormal;
|
||||||
ColorProcessor::kNormal;
|
|
||||||
qDebug() << "OCIOLutNode: creating processor for" << path
|
qDebug() << "OCIOLutNode: creating processor for" << path
|
||||||
<< "direction=" << direction
|
<< "direction=" << direction
|
||||||
<< "ocio_dir=" << (forward ? "FORWARD" : "INVERSE")
|
<< "ocio_dir=" << (forward ? "FORWARD" : "INVERSE")
|
||||||
@@ -256,10 +257,11 @@ bool OCIOLutNode::CreateProcessorFromInputs() const
|
|||||||
OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
|
OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
|
||||||
transform->setSrc(path.toUtf8().constData());
|
transform->setSrc(path.toUtf8().constData());
|
||||||
transform->setInterpolation(OCIO::INTERP_LINEAR);
|
transform->setInterpolation(OCIO::INTERP_LINEAR);
|
||||||
transform->setDirection(
|
transform->setDirection(forward ? OCIO::TRANSFORM_DIR_FORWARD :
|
||||||
forward ? OCIO::TRANSFORM_DIR_FORWARD : OCIO::TRANSFORM_DIR_INVERSE);
|
OCIO::TRANSFORM_DIR_INVERSE);
|
||||||
|
|
||||||
processor = ColorProcessor::Create(manager()->GetConfig()->getProcessor(transform));
|
processor = ColorProcessor::Create(
|
||||||
|
manager()->GetConfig()->getProcessor(transform));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
qWarning() << "OCIO LUT processor error:" << e.what();
|
qWarning() << "OCIO LUT processor error:" << e.what();
|
||||||
processor = nullptr;
|
processor = nullptr;
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ void ThreeWayColorNode::Retranslate()
|
|||||||
SetInputName(kHighlightsAmountInput, tr("Highlights Amount"));
|
SetInputName(kHighlightsAmountInput, tr("Highlights Amount"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCode
|
ShaderCode ThreeWayColorNode::GetShaderCode(const ShaderRequest &request) const
|
||||||
ThreeWayColorNode::GetShaderCode(const ShaderRequest &request) const
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(request)
|
Q_UNUSED(request)
|
||||||
return ShaderCode(
|
return ShaderCode(
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ void NodeFactory::Initialize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
RegisterPluginNodes();
|
RegisterPluginNodes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeFactory::Destroy()
|
void NodeFactory::Destroy()
|
||||||
@@ -151,8 +150,7 @@ Menu *NodeFactory::CreateMenu(QWidget *parent, bool create_none_item,
|
|||||||
// Determine final destination (support secondary grouping)
|
// Determine final destination (support secondary grouping)
|
||||||
Menu *destination = top_menu;
|
Menu *destination = top_menu;
|
||||||
QString sub = n->SubCategory();
|
QString sub = n->SubCategory();
|
||||||
if (!sub.isEmpty() &&
|
if (!sub.isEmpty() && n->Category().contains(Node::kCategoryOpenFX)) {
|
||||||
n->Category().contains(Node::kCategoryOpenFX)) {
|
|
||||||
QList<QAction *> sub_actions = top_menu->actions();
|
QList<QAction *> sub_actions = top_menu->actions();
|
||||||
foreach (QAction *action, sub_actions) {
|
foreach (QAction *action, sub_actions) {
|
||||||
if (action->menu() && action->menu()->title() == sub) {
|
if (action->menu() && action->menu()->title() == sub) {
|
||||||
@@ -249,16 +247,15 @@ void NodeFactory::RegisterPluginNodes()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString plugin_id = QString::fromStdString(
|
const QString plugin_id =
|
||||||
image_effect->getIdentifier());
|
QString::fromStdString(image_effect->getIdentifier());
|
||||||
if (existing_ids.contains(plugin_id)) {
|
if (existing_ids.contains(plugin_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &contexts = image_effect->getContexts();
|
const auto &contexts = image_effect->getContexts();
|
||||||
if (contexts.empty()) {
|
if (contexts.empty()) {
|
||||||
qWarning() << "Skipping OFX plugin with no contexts:"
|
qWarning() << "Skipping OFX plugin with no contexts:" << plugin_id;
|
||||||
<< plugin_id;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string context = kOfxImageEffectContextFilter;
|
std::string context = kOfxImageEffectContextFilter;
|
||||||
|
|||||||
+5
-2
@@ -182,7 +182,10 @@ public:
|
|||||||
* @brief Return a sub-category string for secondary grouping
|
* @brief Return a sub-category string for secondary grouping
|
||||||
* within the primary category (e.g. "Filter" under "OpenFX").
|
* within the primary category (e.g. "Filter" under "OpenFX").
|
||||||
*/
|
*/
|
||||||
virtual QString SubCategory() const { return QString(); }
|
virtual QString SubCategory() const
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a description of this node's purpose (optional for subclassing, but recommended)
|
* @brief Return a description of this node's purpose (optional for subclassing, but recommended)
|
||||||
@@ -1144,8 +1147,8 @@ public:
|
|||||||
{
|
{
|
||||||
return plugin_instance_ ? plugin_instance_->getPlugin() : nullptr;
|
return plugin_instance_ ? plugin_instance_->getPlugin() : nullptr;
|
||||||
}
|
}
|
||||||
protected:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
// If set, this node owns a plugin instance.
|
// If set, this node owns a plugin instance.
|
||||||
OFX::Host::ImageEffect::Instance *plugin_instance_ = nullptr;
|
OFX::Host::ImageEffect::Instance *plugin_instance_ = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -581,12 +581,12 @@ void ViewerOutput::set_parameters_from_footage(
|
|||||||
found_video_params = true;
|
found_video_params = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetVideoParams(VideoParams(
|
SetVideoParams(
|
||||||
s.width(), s.height(), using_timebase,
|
VideoParams(s.width(), s.height(), using_timebase,
|
||||||
static_cast<PixelFormat::Format>(
|
static_cast<PixelFormat::Format>(
|
||||||
OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||||
VideoParams::kInternalChannelCount, s.pixel_aspect_ratio(),
|
VideoParams::kInternalChannelCount,
|
||||||
s.interlacing(), 1));
|
s.pixel_aspect_ratio(), s.interlacing(), 1));
|
||||||
|
|
||||||
if (found_video_params) {
|
if (found_video_params) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
+43
-69
@@ -32,7 +32,8 @@
|
|||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
QHash<QString, QHash<QString, QVariant>> g_plugin_param_defaults;
|
QHash<QString, QHash<QString, QVariant>> g_plugin_param_defaults;
|
||||||
|
|
||||||
static bool IsNormalisedCoordSystem(const OFX::Host::Param::Base *param)
|
static bool IsNormalisedCoordSystem(const OFX::Host::Param::Base *param)
|
||||||
@@ -61,8 +62,7 @@ QVariant DefaultValueForParam(const OFX::Host::Param::Base *param)
|
|||||||
const std::string &ofxType = param->getType();
|
const std::string &ofxType = param->getType();
|
||||||
const auto &props = param->getProperties();
|
const auto &props = param->getProperties();
|
||||||
|
|
||||||
if (ofxType == kOfxParamTypeInteger ||
|
if (ofxType == kOfxParamTypeInteger || ofxType == kOfxParamTypeChoice) {
|
||||||
ofxType == kOfxParamTypeChoice) {
|
|
||||||
return props.getIntProperty(kOfxParamPropDefault);
|
return props.getIntProperty(kOfxParamPropDefault);
|
||||||
}
|
}
|
||||||
if (ofxType == kOfxParamTypeBoolean) {
|
if (ofxType == kOfxParamTypeBoolean) {
|
||||||
@@ -77,14 +77,12 @@ QVariant DefaultValueForParam(const OFX::Host::Param::Base *param)
|
|||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
if (ofxType == kOfxParamTypeString ||
|
if (ofxType == kOfxParamTypeString || ofxType == kOfxParamTypeStrChoice ||
|
||||||
ofxType == kOfxParamTypeStrChoice ||
|
|
||||||
ofxType == kOfxParamTypeCustom) {
|
ofxType == kOfxParamTypeCustom) {
|
||||||
return QString::fromStdString(
|
return QString::fromStdString(
|
||||||
props.getStringProperty(kOfxParamPropDefault));
|
props.getStringProperty(kOfxParamPropDefault));
|
||||||
}
|
}
|
||||||
if (ofxType == kOfxParamTypeRGB ||
|
if (ofxType == kOfxParamTypeRGB || ofxType == kOfxParamTypeRGBA) {
|
||||||
ofxType == kOfxParamTypeRGBA) {
|
|
||||||
const int count = (ofxType == kOfxParamTypeRGBA) ? 4 : 3;
|
const int count = (ofxType == kOfxParamTypeRGBA) ? 4 : 3;
|
||||||
double values[4] = { 0.0, 0.0, 0.0, 1.0 };
|
double values[4] = { 0.0, 0.0, 0.0, 1.0 };
|
||||||
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
|
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
|
||||||
@@ -92,17 +90,15 @@ QVariant DefaultValueForParam(const OFX::Host::Param::Base *param)
|
|||||||
return QVariant::fromValue(
|
return QVariant::fromValue(
|
||||||
olive::core::Color(values[0], values[1], values[2], alpha));
|
olive::core::Color(values[0], values[1], values[2], alpha));
|
||||||
}
|
}
|
||||||
if (ofxType == kOfxParamTypeDouble2D ||
|
if (ofxType == kOfxParamTypeDouble2D || ofxType == kOfxParamTypeDouble3D ||
|
||||||
ofxType == kOfxParamTypeDouble3D ||
|
|
||||||
ofxType == kOfxParamTypeInteger2D ||
|
ofxType == kOfxParamTypeInteger2D ||
|
||||||
ofxType == kOfxParamTypeInteger3D) {
|
ofxType == kOfxParamTypeInteger3D) {
|
||||||
const bool is_double =
|
const bool is_double = (ofxType == kOfxParamTypeDouble2D ||
|
||||||
(ofxType == kOfxParamTypeDouble2D ||
|
|
||||||
ofxType == kOfxParamTypeDouble3D);
|
ofxType == kOfxParamTypeDouble3D);
|
||||||
const int count = (ofxType == kOfxParamTypeDouble2D ||
|
const int count = (ofxType == kOfxParamTypeDouble2D ||
|
||||||
ofxType == kOfxParamTypeInteger2D)
|
ofxType == kOfxParamTypeInteger2D) ?
|
||||||
? 2
|
2 :
|
||||||
: 3;
|
3;
|
||||||
if (is_double) {
|
if (is_double) {
|
||||||
double values[3] = { 0.0, 0.0, 0.0 };
|
double values[3] = { 0.0, 0.0, 0.0 };
|
||||||
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
|
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
|
||||||
@@ -156,8 +152,7 @@ QString DeduceColorSemantic(const OFX::Host::Param::Base *param,
|
|||||||
// Rule 1: explicit color keywords → color
|
// Rule 1: explicit color keywords → color
|
||||||
static const QStringList kColorKeywords = {
|
static const QStringList kColorKeywords = {
|
||||||
QStringLiteral("color"), QStringLiteral("colour"),
|
QStringLiteral("color"), QStringLiteral("colour"),
|
||||||
QStringLiteral("fill"), QStringLiteral("tint"),
|
QStringLiteral("fill"), QStringLiteral("tint"), QStringLiteral("key")
|
||||||
QStringLiteral("key")
|
|
||||||
};
|
};
|
||||||
for (const QString &kw : kColorKeywords) {
|
for (const QString &kw : kColorKeywords) {
|
||||||
if (label.contains(kw) || hint.contains(kw) || name.contains(kw)) {
|
if (label.contains(kw) || hint.contains(kw) || name.contains(kw)) {
|
||||||
@@ -227,14 +222,13 @@ QString DeduceColorSemantic(const OFX::Host::Param::Base *param,
|
|||||||
return QStringLiteral("color");
|
return QStringLiteral("color");
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QString, QVariant>
|
QHash<QString, QVariant> BuildDefaultValues(
|
||||||
BuildDefaultValues(const std::map<std::string, OFX::Host::Param::Instance *> ¶ms)
|
const std::map<std::string, OFX::Host::Param::Instance *> ¶ms)
|
||||||
{
|
{
|
||||||
QHash<QString, QVariant> defaults;
|
QHash<QString, QVariant> defaults;
|
||||||
for (const auto ¶m : params) {
|
for (const auto ¶m : params) {
|
||||||
const std::string &ofxType = param.second->getType();
|
const std::string &ofxType = param.second->getType();
|
||||||
if (ofxType == kOfxParamTypeGroup ||
|
if (ofxType == kOfxParamTypeGroup || ofxType == kOfxParamTypePage ||
|
||||||
ofxType == kOfxParamTypePage ||
|
|
||||||
ofxType == kOfxParamTypePushButton) {
|
ofxType == kOfxParamTypePushButton) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -254,7 +248,8 @@ BuildDefaultValues(const std::map<std::string, OFX::Host::Param::Instance *> &pa
|
|||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static QString ClipLabelForName(const std::string &name,
|
static QString
|
||||||
|
ClipLabelForName(const std::string &name,
|
||||||
const OFX::Host::ImageEffect::ClipDescriptor *desc)
|
const OFX::Host::ImageEffect::ClipDescriptor *desc)
|
||||||
{
|
{
|
||||||
if (name == kOfxImageEffectSimpleSourceClipName) {
|
if (name == kOfxImageEffectSimpleSourceClipName) {
|
||||||
@@ -278,8 +273,7 @@ static QString ClipLabelForName(const std::string &name,
|
|||||||
return QString::fromStdString(name);
|
return QString::fromStdString(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::plugin::PluginNode::PluginNode(
|
olive::plugin::PluginNode::PluginNode(OFX::Host::ImageEffect::Instance *plugin)
|
||||||
OFX::Host::ImageEffect::Instance *plugin)
|
|
||||||
{
|
{
|
||||||
plugin_instance_ = plugin;
|
plugin_instance_ = plugin;
|
||||||
|
|
||||||
@@ -300,8 +294,8 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
QHash<QString, QString> page_for_param;
|
QHash<QString, QString> page_for_param;
|
||||||
|
|
||||||
auto params = plugin_instance_->getParams();
|
auto params = plugin_instance_->getParams();
|
||||||
const QString plugin_id = QString::fromStdString(
|
const QString plugin_id =
|
||||||
plugin_instance_->getPlugin()->getIdentifier());
|
QString::fromStdString(plugin_instance_->getPlugin()->getIdentifier());
|
||||||
auto defaults_iter = g_plugin_param_defaults.find(plugin_id);
|
auto defaults_iter = g_plugin_param_defaults.find(plugin_id);
|
||||||
if (defaults_iter == g_plugin_param_defaults.end()) {
|
if (defaults_iter == g_plugin_param_defaults.end()) {
|
||||||
g_plugin_param_defaults.insert(plugin_id, BuildDefaultValues(params));
|
g_plugin_param_defaults.insert(plugin_id, BuildDefaultValues(params));
|
||||||
@@ -337,7 +331,6 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto param : params) {
|
for (auto param : params) {
|
||||||
|
|
||||||
NodeValue::Type type = NodeValue::kNone;
|
NodeValue::Type type = NodeValue::kNone;
|
||||||
|
|
||||||
const std::string &ofxType = param.second->getType();
|
const std::string &ofxType = param.second->getType();
|
||||||
@@ -356,14 +349,14 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
type = NodeValue::kCombo;
|
type = NodeValue::kCombo;
|
||||||
} else if (ofxType == kOfxParamTypeDouble2D ||
|
} else if (ofxType == kOfxParamTypeDouble2D ||
|
||||||
ofxType == kOfxParamTypeInteger2D) {
|
ofxType == kOfxParamTypeInteger2D) {
|
||||||
type = NodeValue::kVec2;}
|
type = NodeValue::kVec2;
|
||||||
else if (ofxType == kOfxParamTypeDouble3D ||
|
} else if (ofxType == kOfxParamTypeDouble3D ||
|
||||||
ofxType == kOfxParamTypeInteger3D) {
|
ofxType == kOfxParamTypeInteger3D) {
|
||||||
type = NodeValue::kVec3;
|
type = NodeValue::kVec3;
|
||||||
} else if (ofxType == kOfxParamTypeStrChoice) {
|
} else if (ofxType == kOfxParamTypeStrChoice) {
|
||||||
type = NodeValue::kStrCombo;
|
type = NodeValue::kStrCombo;
|
||||||
}else if (ofxType == kOfxParamTypeBytes
|
} else if (ofxType == kOfxParamTypeBytes ||
|
||||||
|| ofxType == kOfxParamTypeCustom) {
|
ofxType == kOfxParamTypeCustom) {
|
||||||
type = NodeValue::kBinary;
|
type = NodeValue::kBinary;
|
||||||
} else if (ofxType == kOfxParamTypePushButton) {
|
} else if (ofxType == kOfxParamTypePushButton) {
|
||||||
type = NodeValue::kPushButton;
|
type = NodeValue::kPushButton;
|
||||||
@@ -374,7 +367,8 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
type = NodeValue::kNone;
|
type = NodeValue::kNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString input_id = QString::fromStdString(param.second->getName());
|
const QString input_id =
|
||||||
|
QString::fromStdString(param.second->getName());
|
||||||
if (input_id.isEmpty()) {
|
if (input_id.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -395,8 +389,7 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
if (is_secret) {
|
if (is_secret) {
|
||||||
SetInputFlag(input_id, kInputFlagHidden);
|
SetInputFlag(input_id, kInputFlagHidden);
|
||||||
}
|
}
|
||||||
const QString label =
|
const QString label = QString::fromStdString(param.second->getLabel());
|
||||||
QString::fromStdString(param.second->getLabel());
|
|
||||||
if (!label.isEmpty()) {
|
if (!label.isEmpty()) {
|
||||||
SetInputName(input_id, label);
|
SetInputName(input_id, label);
|
||||||
} else {
|
} else {
|
||||||
@@ -413,33 +406,22 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
page_for_param.value(input_id));
|
page_for_param.value(input_id));
|
||||||
}
|
}
|
||||||
if (type == NodeValue::kColor) {
|
if (type == NodeValue::kColor) {
|
||||||
QString semantic =
|
QString semantic = DeduceColorSemantic(param.second, group_labels);
|
||||||
DeduceColorSemantic(param.second, group_labels);
|
SetInputProperty(input_id, QStringLiteral("color_semantic"),
|
||||||
SetInputProperty(input_id,
|
|
||||||
QStringLiteral("color_semantic"),
|
|
||||||
semantic);
|
semantic);
|
||||||
|
|
||||||
const int dim =
|
const int dim = (ofxType == kOfxParamTypeRGBA) ? 4 : 3;
|
||||||
(ofxType == kOfxParamTypeRGBA) ? 4 : 3;
|
|
||||||
double dmin[4] = { 0, 0, 0, 0 };
|
double dmin[4] = { 0, 0, 0, 0 };
|
||||||
double dmax[4] = { 1, 1, 1, 1 };
|
double dmax[4] = { 1, 1, 1, 1 };
|
||||||
props.getDoublePropertyN(kOfxParamPropDisplayMin,
|
props.getDoublePropertyN(kOfxParamPropDisplayMin, dmin, dim);
|
||||||
dmin, dim);
|
props.getDoublePropertyN(kOfxParamPropDisplayMax, dmax, dim);
|
||||||
props.getDoublePropertyN(kOfxParamPropDisplayMax,
|
SetInputProperty(input_id, QStringLiteral("min"), dmin[0]);
|
||||||
dmax, dim);
|
SetInputProperty(input_id, QStringLiteral("max"), dmax[0]);
|
||||||
SetInputProperty(input_id,
|
|
||||||
QStringLiteral("min"),
|
|
||||||
dmin[0]);
|
|
||||||
SetInputProperty(input_id,
|
|
||||||
QStringLiteral("max"),
|
|
||||||
dmax[0]);
|
|
||||||
|
|
||||||
const QString hint = QString::fromStdString(
|
const QString hint =
|
||||||
param.second->getHint());
|
QString::fromStdString(param.second->getHint());
|
||||||
if (!hint.isEmpty()) {
|
if (!hint.isEmpty()) {
|
||||||
SetInputProperty(input_id,
|
SetInputProperty(input_id, QStringLiteral("tooltip"), hint);
|
||||||
QStringLiteral("tooltip"),
|
|
||||||
hint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type == NodeValue::kCombo || type == NodeValue::kStrCombo) {
|
if (type == NodeValue::kCombo || type == NodeValue::kStrCombo) {
|
||||||
@@ -447,8 +429,7 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
QStringList option_values;
|
QStringList option_values;
|
||||||
const int label_count =
|
const int label_count =
|
||||||
props.getDimension(kOfxParamPropChoiceOption);
|
props.getDimension(kOfxParamPropChoiceOption);
|
||||||
const int value_count =
|
const int value_count = props.getDimension(kOfxParamPropChoiceEnum);
|
||||||
props.getDimension(kOfxParamPropChoiceEnum);
|
|
||||||
|
|
||||||
for (int i = 0; i < label_count; ++i) {
|
for (int i = 0; i < label_count; ++i) {
|
||||||
const std::string &label =
|
const std::string &label =
|
||||||
@@ -478,13 +459,11 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
indices[i] = i;
|
indices[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stable_sort(indices.begin(), indices.end(),
|
std::stable_sort(
|
||||||
[&](int a, int b) {
|
indices.begin(), indices.end(), [&](int a, int b) {
|
||||||
return props.getIntProperty(
|
return props.getIntProperty(kOfxParamPropChoiceOrder,
|
||||||
kOfxParamPropChoiceOrder,
|
|
||||||
a) <
|
a) <
|
||||||
props.getIntProperty(
|
props.getIntProperty(kOfxParamPropChoiceOrder,
|
||||||
kOfxParamPropChoiceOrder,
|
|
||||||
b);
|
b);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -520,15 +499,13 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
has_texture_input = true;
|
has_texture_input = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const QString source_id =
|
const QString source_id =
|
||||||
QString::fromUtf8(kOfxImageEffectSimpleSourceClipName);
|
QString::fromUtf8(kOfxImageEffectSimpleSourceClipName);
|
||||||
if (HasInputWithID(source_id)) {
|
if (HasInputWithID(source_id)) {
|
||||||
SetEffectInput(source_id);
|
SetEffectInput(source_id);
|
||||||
} else if (HasInputWithID(kTextureInput)) {
|
} else if (HasInputWithID(kTextureInput)) {
|
||||||
SetEffectInput(kTextureInput);
|
SetEffectInput(kTextureInput);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (has_texture_input) {
|
if (has_texture_input) {
|
||||||
AddInput(kTextureInput, NodeValue::kTexture);
|
AddInput(kTextureInput, NodeValue::kTexture);
|
||||||
SetInputName(kTextureInput, tr("Texture"));
|
SetInputName(kTextureInput, tr("Texture"));
|
||||||
@@ -545,7 +522,6 @@ QString olive::plugin::PluginNode::Name() const
|
|||||||
.getProps()
|
.getProps()
|
||||||
.getStringProperty(kOfxPropLabel)
|
.getStringProperty(kOfxPropLabel)
|
||||||
.data();
|
.data();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<olive::Node::CategoryID> olive::plugin::PluginNode::Category() const
|
QVector<olive::Node::CategoryID> olive::plugin::PluginNode::Category() const
|
||||||
@@ -565,7 +541,6 @@ QString olive::plugin::PluginNode::Description() const
|
|||||||
.getProps()
|
.getProps()
|
||||||
.getStringProperty(kOfxPropPluginDescription)
|
.getStringProperty(kOfxPropPluginDescription)
|
||||||
.data();
|
.data();
|
||||||
|
|
||||||
}
|
}
|
||||||
void olive::plugin::PluginNode::ProcessSamples(const NodeValueRow &values,
|
void olive::plugin::PluginNode::ProcessSamples(const NodeValueRow &values,
|
||||||
const SampleBuffer &input,
|
const SampleBuffer &input,
|
||||||
@@ -689,8 +664,7 @@ QString olive::plugin::PluginNode::id() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto *node = new PluginNode(instance);
|
auto *node = new PluginNode(instance);
|
||||||
if (auto *olive_instance =
|
if (auto *olive_instance = dynamic_cast<OlivePluginInstance *>(instance)) {
|
||||||
dynamic_cast<OlivePluginInstance *>(instance)) {
|
|
||||||
olive_instance->setNode(
|
olive_instance->setNode(
|
||||||
std::shared_ptr<PluginNode>(node, [](PluginNode *) {}));
|
std::shared_ptr<PluginNode>(node, [](PluginNode *) {}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ public:
|
|||||||
PluginNode(OFX::Host::ImageEffect::Instance *plugin);
|
PluginNode(OFX::Host::ImageEffect::Instance *plugin);
|
||||||
~PluginNode() override;
|
~PluginNode() override;
|
||||||
|
|
||||||
|
|
||||||
QString Name() const override;
|
QString Name() const override;
|
||||||
QString id() const override;
|
QString id() const override;
|
||||||
QVector<CategoryID> Category() const override;
|
QVector<CategoryID> Category() const override;
|
||||||
@@ -58,8 +57,8 @@ public:
|
|||||||
* corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior
|
* corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior
|
||||||
* of the NodeParam objects will handle everything related to it automatically.
|
* of the NodeParam objects will handle everything related to it automatically.
|
||||||
*/
|
*/
|
||||||
void Value(const NodeValueRow &value,
|
void Value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||||
const NodeGlobals &globals, NodeValueTable *table) const override;
|
NodeValueTable *table) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief If Value() pushes a ShaderJob, this is the function that will process them.
|
* @brief If Value() pushes a ShaderJob, this is the function that will process them.
|
||||||
@@ -82,11 +81,9 @@ private:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void pushButtonClicked(QString name);
|
void pushButtonClicked(QString name);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //PLUGIN_H
|
#endif //PLUGIN_H
|
||||||
|
|||||||
@@ -121,9 +121,8 @@ SerializedData Project::Load(QXmlStreamReader *reader)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString path = bundle_path.isEmpty()
|
const QString path = bundle_path.isEmpty() ? file_path :
|
||||||
? file_path
|
bundle_path;
|
||||||
: bundle_path;
|
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
plugin_paths.insert(path);
|
plugin_paths.insert(path);
|
||||||
}
|
}
|
||||||
@@ -250,8 +249,7 @@ void Project::Save(QXmlStreamWriter *writer) const
|
|||||||
seen.insert(key);
|
seen.insert(key);
|
||||||
|
|
||||||
QMap<QString, QString> attrs;
|
QMap<QString, QString> attrs;
|
||||||
attrs.insert(QStringLiteral("id"),
|
attrs.insert(QStringLiteral("id"), QString::fromStdString(id));
|
||||||
QString::fromStdString(id));
|
|
||||||
attrs.insert(QStringLiteral("major"), QString::number(major));
|
attrs.insert(QStringLiteral("major"), QString::number(major));
|
||||||
attrs.insert(QStringLiteral("minor"), QString::number(minor));
|
attrs.insert(QStringLiteral("minor"), QString::number(minor));
|
||||||
if (!bundle_path.isEmpty()) {
|
if (!bundle_path.isEmpty()) {
|
||||||
@@ -269,8 +267,8 @@ void Project::Save(QXmlStreamWriter *writer) const
|
|||||||
writer->writeStartElement(QStringLiteral("plugins"));
|
writer->writeStartElement(QStringLiteral("plugins"));
|
||||||
for (const auto &entry : plugins_to_save) {
|
for (const auto &entry : plugins_to_save) {
|
||||||
writer->writeStartElement(QStringLiteral("plugin"));
|
writer->writeStartElement(QStringLiteral("plugin"));
|
||||||
for (auto it = entry.second.cbegin();
|
for (auto it = entry.second.cbegin(); it != entry.second.cend();
|
||||||
it != entry.second.cend(); ++it) {
|
++it) {
|
||||||
writer->writeAttribute(it.key(), it.value());
|
writer->writeAttribute(it.key(), it.value());
|
||||||
}
|
}
|
||||||
writer->writeEndElement();
|
writer->writeEndElement();
|
||||||
|
|||||||
@@ -242,11 +242,8 @@ void Footage::set_proxy_enabled(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Footage::SetProxy(const QString &path,
|
void Footage::SetProxy(const QString &path, ProxyManager::ProxyState state,
|
||||||
ProxyManager::ProxyState state,
|
int video_stream_index, int preset_version, bool enabled)
|
||||||
int video_stream_index,
|
|
||||||
int preset_version,
|
|
||||||
bool enabled)
|
|
||||||
{
|
{
|
||||||
qDebug() << "Footage::SetProxy:" << filename() << "enabled=" << enabled
|
qDebug() << "Footage::SetProxy:" << filename() << "enabled=" << enabled
|
||||||
<< "state=" << ProxyManager::ProxyStateToString(state)
|
<< "state=" << ProxyManager::ProxyStateToString(state)
|
||||||
@@ -598,11 +595,10 @@ void Footage::SaveCustom(QXmlStreamWriter *writer) const
|
|||||||
if (!proxy_path_.isEmpty() || proxy_enabled_) {
|
if (!proxy_path_.isEmpty() || proxy_enabled_) {
|
||||||
writer->writeStartElement(QStringLiteral("proxy"));
|
writer->writeStartElement(QStringLiteral("proxy"));
|
||||||
writer->writeAttribute(QStringLiteral("enabled"),
|
writer->writeAttribute(QStringLiteral("enabled"),
|
||||||
proxy_enabled_ ? QStringLiteral("1")
|
proxy_enabled_ ? QStringLiteral("1") :
|
||||||
: QStringLiteral("0"));
|
QStringLiteral("0"));
|
||||||
writer->writeAttribute(QStringLiteral("state"),
|
writer->writeAttribute(QStringLiteral("state"),
|
||||||
ProxyManager::ProxyStateToString(
|
ProxyManager::ProxyStateToString(proxy_state_));
|
||||||
proxy_state_));
|
|
||||||
writer->writeAttribute(QStringLiteral("stream"),
|
writer->writeAttribute(QStringLiteral("stream"),
|
||||||
QString::number(proxy_video_stream_index_));
|
QString::number(proxy_video_stream_index_));
|
||||||
writer->writeAttribute(QStringLiteral("preset"),
|
writer->writeAttribute(QStringLiteral("preset"),
|
||||||
|
|||||||
@@ -200,11 +200,8 @@ public:
|
|||||||
return proxy_state_;
|
return proxy_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetProxy(const QString &path,
|
void SetProxy(const QString &path, ProxyManager::ProxyState state,
|
||||||
ProxyManager::ProxyState state,
|
int video_stream_index, int preset_version, bool enabled);
|
||||||
int video_stream_index,
|
|
||||||
int preset_version,
|
|
||||||
bool enabled);
|
|
||||||
|
|
||||||
void ClearProxy();
|
void ClearProxy();
|
||||||
|
|
||||||
|
|||||||
@@ -78,8 +78,7 @@ bool FootageDescription::Load(const QString &filename)
|
|||||||
const QStringList split =
|
const QStringList split =
|
||||||
reader.readElementText().split('/');
|
reader.readElementText().split('/');
|
||||||
if (split.size() == 2) {
|
if (split.size() == 2) {
|
||||||
SetSourceStartTime(
|
SetSourceStartTime(rational(split.at(0).toInt(),
|
||||||
rational(split.at(0).toInt(),
|
|
||||||
split.at(1).toInt()),
|
split.at(1).toInt()),
|
||||||
source);
|
source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -502,19 +502,20 @@ void NodeTraverser::ResolveJobs(NodeValue &val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
val.set_value(tex);
|
val.set_value(tex);
|
||||||
}
|
} else if (plugin::PluginJob *plugin_job =
|
||||||
else if (plugin::PluginJob* plugin_job=dynamic_cast<plugin::PluginJob*>(base_job)) {
|
dynamic_cast<plugin::PluginJob *>(
|
||||||
|
base_job)) {
|
||||||
VideoParams tex_params = job_tex->params();
|
VideoParams tex_params = job_tex->params();
|
||||||
// Force internal working format (F32) for plugin processing,
|
// Force internal working format (F32) for plugin processing,
|
||||||
// matching FootageJob/GenerateJob behavior.
|
// matching FootageJob/GenerateJob behavior.
|
||||||
tex_params.set_format(GetCacheVideoParams().format());
|
tex_params.set_format(GetCacheVideoParams().format());
|
||||||
tex_params.set_channel_count(VideoParams::kRGBAChannelCount);
|
tex_params.set_channel_count(
|
||||||
|
VideoParams::kRGBAChannelCount);
|
||||||
|
|
||||||
TexturePtr tex = CreateTexture(tex_params);
|
TexturePtr tex = CreateTexture(tex_params);
|
||||||
|
|
||||||
ProcessPluginJob(job_tex, tex, val.source());
|
ProcessPluginJob(job_tex, tex, val.source());
|
||||||
val.set_value(tex);
|
val.set_value(tex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache resolved value
|
// Cache resolved value
|
||||||
|
|||||||
@@ -147,7 +147,9 @@ protected:
|
|||||||
return SampleBuffer();
|
return SampleBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TexturePtr ProcessPluginJob(TexturePtr texture, TexturePtr destination, const Node *node);
|
virtual TexturePtr ProcessPluginJob(TexturePtr texture,
|
||||||
|
TexturePtr destination,
|
||||||
|
const Node *node);
|
||||||
SampleBuffer CreateSampleBuffer(const AudioParams ¶ms,
|
SampleBuffer CreateSampleBuffer(const AudioParams ¶ms,
|
||||||
const rational &length)
|
const rational &length)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-2
@@ -131,8 +131,7 @@ void PanelWidget::changeEvent(QEvent *e)
|
|||||||
if (e->type() == QEvent::WindowStateChange) {
|
if (e->type() == QEvent::WindowStateChange) {
|
||||||
if (isVisible() && !isMinimized()) {
|
if (isVisible() && !isMinimized()) {
|
||||||
emit shown(Qt::OtherFocusReason);
|
emit shown(Qt::OtherFocusReason);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
emit hidden();
|
emit hidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ signals:
|
|||||||
void CloseRequested();
|
void CloseRequested();
|
||||||
void shown(Qt::FocusReason reason);
|
void shown(Qt::FocusReason reason);
|
||||||
void hidden();
|
void hidden();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief paintEvent
|
* @brief paintEvent
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ extern "C" {
|
|||||||
#include <libswscale/swscale.h>
|
#include <libswscale/swscale.h>
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
}
|
}
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
const std::string kBitDepthNoneStr(kOfxBitDepthNone);
|
const std::string kBitDepthNoneStr(kOfxBitDepthNone);
|
||||||
const std::string kBitDepthByteStr(kOfxBitDepthByte);
|
const std::string kBitDepthByteStr(kOfxBitDepthByte);
|
||||||
const std::string kBitDepthShortStr(kOfxBitDepthShort);
|
const std::string kBitDepthShortStr(kOfxBitDepthShort);
|
||||||
@@ -117,16 +118,16 @@ static bool PackedDstInfo(AVPixelFormat fmt, int *channels,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
static olive::AVFramePtr
|
||||||
|
ReadbackTextureToFrame(olive::TexturePtr texture,
|
||||||
const olive::VideoParams ¶ms)
|
const olive::VideoParams ¶ms)
|
||||||
{
|
{
|
||||||
if (!texture || texture->IsDummy() || !texture->renderer()) {
|
if (!texture || texture->IsDummy() || !texture->renderer()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVPixelFormat pix_fmt =
|
AVPixelFormat pix_fmt = olive::FFmpegUtils::GetFFmpegPixelFormat(
|
||||||
olive::FFmpegUtils::GetFFmpegPixelFormat(params.format(),
|
params.format(), params.channel_count());
|
||||||
params.channel_count());
|
|
||||||
if (pix_fmt == AV_PIX_FMT_NONE) {
|
if (pix_fmt == AV_PIX_FMT_NONE) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -145,15 +146,15 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const int linesize_pixels = BytesToPixels(frame->linesize[0], params);
|
const int linesize_pixels = BytesToPixels(frame->linesize[0], params);
|
||||||
texture->renderer()->DownloadFromTexture(texture->id(), params,
|
texture->renderer()->DownloadFromTexture(
|
||||||
frame->data[0],
|
texture->id(), params, frame->data[0], linesize_pixels);
|
||||||
linesize_pixels);
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::VideoParams rgba_params(
|
olive::VideoParams rgba_params(params.width(), params.height(),
|
||||||
params.width(), params.height(), olive::core::PixelFormat::U8, 4,
|
olive::core::PixelFormat::U8, 4,
|
||||||
params.pixel_aspect_ratio(), params.interlacing(), params.divider());
|
params.pixel_aspect_ratio(),
|
||||||
|
params.interlacing(), params.divider());
|
||||||
|
|
||||||
olive::AVFramePtr rgba_frame = olive::CreateAVFramePtr();
|
olive::AVFramePtr rgba_frame = olive::CreateAVFramePtr();
|
||||||
rgba_frame->format = AV_PIX_FMT_RGBA;
|
rgba_frame->format = AV_PIX_FMT_RGBA;
|
||||||
@@ -165,9 +166,8 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
|||||||
|
|
||||||
const int linesize_pixels =
|
const int linesize_pixels =
|
||||||
BytesToPixels(rgba_frame->linesize[0], rgba_params);
|
BytesToPixels(rgba_frame->linesize[0], rgba_params);
|
||||||
texture->renderer()->DownloadFromTexture(texture->id(), rgba_params,
|
texture->renderer()->DownloadFromTexture(
|
||||||
rgba_frame->data[0],
|
texture->id(), rgba_params, rgba_frame->data[0], linesize_pixels);
|
||||||
linesize_pixels);
|
|
||||||
|
|
||||||
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
||||||
dst->format = pix_fmt;
|
dst->format = pix_fmt;
|
||||||
@@ -179,9 +179,8 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
|||||||
|
|
||||||
SwsContext *sws_ctx = sws_getContext(
|
SwsContext *sws_ctx = sws_getContext(
|
||||||
rgba_frame->width, rgba_frame->height,
|
rgba_frame->width, rgba_frame->height,
|
||||||
static_cast<AVPixelFormat>(rgba_frame->format),
|
static_cast<AVPixelFormat>(rgba_frame->format), dst->width, dst->height,
|
||||||
dst->width, dst->height, pix_fmt, SWS_POINT,
|
pix_fmt, SWS_POINT, nullptr, nullptr, nullptr);
|
||||||
nullptr, nullptr, nullptr);
|
|
||||||
if (!sws_ctx) {
|
if (!sws_ctx) {
|
||||||
return rgba_frame;
|
return rgba_frame;
|
||||||
}
|
}
|
||||||
@@ -218,9 +217,7 @@ static olive::AVFramePtr ConvertPackedFloatFrame(olive::AVFramePtr src,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clamp01 = [](float v) -> float {
|
auto clamp01 = [](float v) -> float { return std::clamp(v, 0.0f, 1.0f); };
|
||||||
return std::clamp(v, 0.0f, 1.0f);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int y = 0; y < src->height; ++y) {
|
for (int y = 0; y < src->height; ++y) {
|
||||||
const float *src_row = reinterpret_cast<const float *>(
|
const float *src_row = reinterpret_cast<const float *>(
|
||||||
@@ -242,17 +239,13 @@ static olive::AVFramePtr ConvertPackedFloatFrame(olive::AVFramePtr src,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dst_row_u16[x * dst_channels + 0] =
|
dst_row_u16[x * dst_channels + 0] =
|
||||||
static_cast<uint16_t>(
|
static_cast<uint16_t>(std::lround(clamp01(r) * 65535.0f));
|
||||||
std::lround(clamp01(r) * 65535.0f));
|
|
||||||
dst_row_u16[x * dst_channels + 1] =
|
dst_row_u16[x * dst_channels + 1] =
|
||||||
static_cast<uint16_t>(
|
static_cast<uint16_t>(std::lround(clamp01(g) * 65535.0f));
|
||||||
std::lround(clamp01(g) * 65535.0f));
|
|
||||||
dst_row_u16[x * dst_channels + 2] =
|
dst_row_u16[x * dst_channels + 2] =
|
||||||
static_cast<uint16_t>(
|
static_cast<uint16_t>(std::lround(clamp01(b) * 65535.0f));
|
||||||
std::lround(clamp01(b) * 65535.0f));
|
|
||||||
if (dst_channels == 4) {
|
if (dst_channels == 4) {
|
||||||
dst_row_u16[x * dst_channels + 3] =
|
dst_row_u16[x * dst_channels + 3] = static_cast<uint16_t>(
|
||||||
static_cast<uint16_t>(
|
|
||||||
std::lround(clamp01(a) * 65535.0f));
|
std::lround(clamp01(a) * 65535.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,18 +263,14 @@ static olive::AVFramePtr ConvertPackedFloatFrame(olive::AVFramePtr src,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dst_row[x * dst_channels + 0] =
|
dst_row[x * dst_channels + 0] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(std::lround(clamp01(r) * 255.0f));
|
||||||
std::lround(clamp01(r) * 255.0f));
|
|
||||||
dst_row[x * dst_channels + 1] =
|
dst_row[x * dst_channels + 1] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(std::lround(clamp01(g) * 255.0f));
|
||||||
std::lround(clamp01(g) * 255.0f));
|
|
||||||
dst_row[x * dst_channels + 2] =
|
dst_row[x * dst_channels + 2] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(std::lround(clamp01(b) * 255.0f));
|
||||||
std::lround(clamp01(b) * 255.0f));
|
|
||||||
if (dst_channels == 4) {
|
if (dst_channels == 4) {
|
||||||
dst_row[x * dst_channels + 3] =
|
dst_row[x * dst_channels + 3] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(std::lround(clamp01(a) * 255.0f));
|
||||||
std::lround(clamp01(a) * 255.0f));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,7 +416,8 @@ olive::plugin::OliveClipInstance::getImage(OfxTime time,
|
|||||||
if (name_ == "Output") {
|
if (name_ == "Output") {
|
||||||
if (!images_.contains(time)) {
|
if (!images_.contains(time)) {
|
||||||
// make a new ref counted image
|
// make a new ref counted image
|
||||||
images_.insert(time, new Image(*const_cast<OliveClipInstance *>(this),
|
images_.insert(time,
|
||||||
|
new Image(*const_cast<OliveClipInstance *>(this),
|
||||||
params_, bounds, rod, true));
|
params_, bounds, rod, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +494,8 @@ olive::plugin::OliveClipInstance::getOutputImage(OfxTime time)
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::VideoParams olive::plugin::OliveClipInstance::getPluginPreferredParams() const
|
olive::VideoParams
|
||||||
|
olive::plugin::OliveClipInstance::getPluginPreferredParams() const
|
||||||
{
|
{
|
||||||
VideoParams result = params_;
|
VideoParams result = params_;
|
||||||
|
|
||||||
@@ -584,7 +575,10 @@ void olive::plugin::OliveClipInstance::setParams(const VideoParams ¶ms)
|
|||||||
setComponents(getUnmappedComponents());
|
setComponents(getUnmappedComponents());
|
||||||
}
|
}
|
||||||
|
|
||||||
void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTime time, bool readback_cpu){
|
void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture,
|
||||||
|
OfxTime time,
|
||||||
|
bool readback_cpu)
|
||||||
|
{
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -622,9 +616,8 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
if (!frame || !frame->data[0]) {
|
if (!frame || !frame->data[0]) {
|
||||||
frame = ReadbackTextureToFrame(texture, params_);
|
frame = ReadbackTextureToFrame(texture, params_);
|
||||||
}
|
}
|
||||||
AVPixelFormat expected_fmt =
|
AVPixelFormat expected_fmt = FFmpegUtils::GetFFmpegPixelFormat(
|
||||||
FFmpegUtils::GetFFmpegPixelFormat(params_.format(),
|
params_.format(), params_.channel_count());
|
||||||
params_.channel_count());
|
|
||||||
if (expected_fmt == AV_PIX_FMT_NONE) {
|
if (expected_fmt == AV_PIX_FMT_NONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -642,8 +635,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
pruneImagesCache();
|
pruneImagesCache();
|
||||||
image = new Image(*this, params_, bounds,
|
image = new Image(*this, params_, bounds, regionOfDefinition, false);
|
||||||
regionOfDefinition, false);
|
|
||||||
image->EnsureAllocatedFromParams(params_, bounds, regionOfDefinition,
|
image->EnsureAllocatedFromParams(params_, bounds, regionOfDefinition,
|
||||||
false);
|
false);
|
||||||
images_.insert(time, image);
|
images_.insert(time, image);
|
||||||
@@ -669,10 +661,12 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
int row_floats = frame->linesize[0] / static_cast<int>(sizeof(float));
|
int row_floats = frame->linesize[0] / static_cast<int>(sizeof(float));
|
||||||
bool has_nan = false;
|
bool has_nan = false;
|
||||||
for (int y = 0; y < params_.height() && !has_nan; ++y) {
|
for (int y = 0; y < params_.height() && !has_nan; ++y) {
|
||||||
for (int x = 0; x < params_.width() * params_.channel_count(); ++x) {
|
for (int x = 0; x < params_.width() * params_.channel_count();
|
||||||
|
++x) {
|
||||||
float v = fptr[y * row_floats + x];
|
float v = fptr[y * row_floats + x];
|
||||||
if (std::isnan(v) || std::isinf(v)) {
|
if (std::isnan(v) || std::isinf(v)) {
|
||||||
qWarning() << "[PLUGIN] NaN/Inf detected in input frame at pixel ("
|
qWarning()
|
||||||
|
<< "[PLUGIN] NaN/Inf detected in input frame at pixel ("
|
||||||
<< x / params_.channel_count() << "," << y
|
<< x / params_.channel_count() << "," << y
|
||||||
<< ") channel=" << (x % params_.channel_count())
|
<< ") channel=" << (x % params_.channel_count())
|
||||||
<< " value=" << v;
|
<< " value=" << v;
|
||||||
@@ -682,19 +676,19 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (has_nan) {
|
if (has_nan) {
|
||||||
qWarning() << "[PLUGIN] Filling corrupted input frame with black to avoid CImg crash";
|
qWarning()
|
||||||
|
<< "[PLUGIN] Filling corrupted input frame with black to avoid CImg crash";
|
||||||
std::memset(dst, 0, image->row_bytes() * image->height());
|
std::memset(dst, 0, image->row_bytes() * image->height());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFramePtr src_frame = frame;
|
AVFramePtr src_frame = frame;
|
||||||
if (frame->format != expected_fmt ||
|
if (frame->format != expected_fmt || frame->width != params_.width() ||
|
||||||
frame->width != params_.width() ||
|
|
||||||
frame->height != params_.height()) {
|
frame->height != params_.height()) {
|
||||||
if (PackedFloatChannels(static_cast<AVPixelFormat>(frame->format)) > 0) {
|
if (PackedFloatChannels(static_cast<AVPixelFormat>(frame->format)) >
|
||||||
AVFramePtr converted =
|
0) {
|
||||||
ConvertPackedFloatFrame(frame, expected_fmt);
|
AVFramePtr converted = ConvertPackedFloatFrame(frame, expected_fmt);
|
||||||
if (converted) {
|
if (converted) {
|
||||||
src_frame = converted;
|
src_frame = converted;
|
||||||
goto copy_pixels;
|
goto copy_pixels;
|
||||||
@@ -710,9 +704,8 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
|
|
||||||
SwsContext *sws_ctx = sws_getContext(
|
SwsContext *sws_ctx = sws_getContext(
|
||||||
frame->width, frame->height,
|
frame->width, frame->height,
|
||||||
static_cast<AVPixelFormat>(frame->format),
|
static_cast<AVPixelFormat>(frame->format), converted->width,
|
||||||
converted->width, converted->height,
|
converted->height, static_cast<AVPixelFormat>(converted->format),
|
||||||
static_cast<AVPixelFormat>(converted->format),
|
|
||||||
SWS_POINT, nullptr, nullptr, nullptr);
|
SWS_POINT, nullptr, nullptr, nullptr);
|
||||||
if (!sws_ctx) {
|
if (!sws_ctx) {
|
||||||
return;
|
return;
|
||||||
@@ -727,12 +720,12 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
|
|
||||||
copy_pixels:
|
copy_pixels:
|
||||||
int bytes_per_component = params_.format().byte_count();
|
int bytes_per_component = params_.format().byte_count();
|
||||||
int bytes_per_row = params_.width() * params_.channel_count() *
|
int bytes_per_row =
|
||||||
bytes_per_component;
|
params_.width() * params_.channel_count() * bytes_per_component;
|
||||||
int src_row_bytes = src_frame->linesize[0];
|
int src_row_bytes = src_frame->linesize[0];
|
||||||
int dst_row_bytes = image->row_bytes();
|
int dst_row_bytes = image->row_bytes();
|
||||||
int copy_bytes = std::min(bytes_per_row,
|
int copy_bytes =
|
||||||
std::min(src_row_bytes, dst_row_bytes));
|
std::min(bytes_per_row, std::min(src_row_bytes, dst_row_bytes));
|
||||||
int copy_height = std::min(image->height(), src_frame->height);
|
int copy_height = std::min(image->height(), src_frame->height);
|
||||||
|
|
||||||
const uint8_t *src = src_frame->data[0];
|
const uint8_t *src = src_frame->data[0];
|
||||||
@@ -754,7 +747,8 @@ copy_pixels:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (has_nan) {
|
if (has_nan) {
|
||||||
qWarning() << "[PLUGIN] NaN/Inf scrubbed from input frame data during copy";
|
qWarning()
|
||||||
|
<< "[PLUGIN] NaN/Inf scrubbed from input frame data during copy";
|
||||||
}
|
}
|
||||||
} else if (dst_row_bytes == src_row_bytes && src_row_bytes == copy_bytes) {
|
} else if (dst_row_bytes == src_row_bytes && src_row_bytes == copy_bytes) {
|
||||||
std::memcpy(dst, src, copy_bytes * copy_height);
|
std::memcpy(dst, src, copy_bytes * copy_height);
|
||||||
@@ -764,8 +758,6 @@ copy_pixels:
|
|||||||
copy_bytes);
|
copy_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void olive::plugin::OliveClipInstance::setOutputTexture(TexturePtr texture,
|
void olive::plugin::OliveClipInstance::setOutputTexture(TexturePtr texture,
|
||||||
@@ -818,17 +810,17 @@ olive::plugin::OliveClipInstance::loadTexture(OfxTime time, const char *format,
|
|||||||
bounds.x2 = std::min(bounds.x2, rod.x2);
|
bounds.x2 = std::min(bounds.x2, rod.x2);
|
||||||
bounds.y2 = std::min(bounds.y2, rod.y2);
|
bounds.y2 = std::min(bounds.y2, rod.y2);
|
||||||
|
|
||||||
const int bytes_per_row =
|
const int bytes_per_row = params_.width() * params_.channel_count() *
|
||||||
params_.width() * params_.channel_count() * params_.format().byte_count();
|
params_.format().byte_count();
|
||||||
const std::string &field = getFieldOrder();
|
const std::string &field = getFieldOrder();
|
||||||
const std::string unique_id = std::to_string(
|
const std::string unique_id =
|
||||||
reinterpret_cast<uintptr_t>(gl_texture.get())) + "_" +
|
std::to_string(reinterpret_cast<uintptr_t>(gl_texture.get())) + "_" +
|
||||||
std::to_string(static_cast<long long>(time));
|
std::to_string(static_cast<long long>(time));
|
||||||
|
|
||||||
const int texture_id = gl_texture->id().value<GLuint>();
|
const int texture_id = gl_texture->id().value<GLuint>();
|
||||||
OFX::Host::ImageEffect::Texture *texture =
|
OFX::Host::ImageEffect::Texture *texture =
|
||||||
new OFX::Host::ImageEffect::Texture(
|
new OFX::Host::ImageEffect::Texture(*this, 1.0, 1.0, texture_id,
|
||||||
*this, 1.0, 1.0, texture_id, GL_TEXTURE_2D, bounds, rod,
|
GL_TEXTURE_2D, bounds, rod,
|
||||||
bytes_per_row, field, unique_id);
|
bytes_per_row, field, unique_id);
|
||||||
texture->addReference();
|
texture->addReference();
|
||||||
return texture;
|
return texture;
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ namespace plugin
|
|||||||
class OliveClipInstance : public OFX::Host::ImageEffect::ClipInstance {
|
class OliveClipInstance : public OFX::Host::ImageEffect::ClipInstance {
|
||||||
public:
|
public:
|
||||||
OliveClipInstance(OFX::Host::ImageEffect::Instance *effectInstance,
|
OliveClipInstance(OFX::Host::ImageEffect::Instance *effectInstance,
|
||||||
OFX::Host::ImageEffect::ClipDescriptor& desc,VideoParams ¶ms)
|
OFX::Host::ImageEffect::ClipDescriptor &desc,
|
||||||
|
VideoParams ¶ms)
|
||||||
: ClipInstance(effectInstance, desc)
|
: ClipInstance(effectInstance, desc)
|
||||||
, params_(params)
|
, params_(params)
|
||||||
, defaultRegionOfDefinitions_{ 0, 0, 0, 0 }
|
, defaultRegionOfDefinitions_{ 0, 0, 0, 0 }
|
||||||
@@ -56,21 +57,24 @@ public:
|
|||||||
const std::string &getFieldOrder() const override;
|
const std::string &getFieldOrder() const override;
|
||||||
bool getConnected() const override;
|
bool getConnected() const override;
|
||||||
double getUnmappedFrameRate() const override;
|
double getUnmappedFrameRate() const override;
|
||||||
void getUnmappedFrameRange(double &startFrame, double &endFrame) const override;
|
void getUnmappedFrameRange(double &startFrame,
|
||||||
|
double &endFrame) const override;
|
||||||
bool getContinuousSamples() const override;
|
bool getContinuousSamples() const override;
|
||||||
OFX::Host::ImageEffect::Image* getImage(OfxTime time, const OfxRectD *optionalBounds) override;
|
OFX::Host::ImageEffect::Image *
|
||||||
|
getImage(OfxTime time, const OfxRectD *optionalBounds) override;
|
||||||
OfxRectD getRegionOfDefinition(OfxTime time) const override;
|
OfxRectD getRegionOfDefinition(OfxTime time) const override;
|
||||||
|
|
||||||
void setRegionOfDefinition(OfxRectD regionOfDefinition, OfxTime time);
|
void setRegionOfDefinition(OfxRectD regionOfDefinition, OfxTime time);
|
||||||
void setDefaultRegionOfDefinition(OfxRectD regionOfDefinition);
|
void setDefaultRegionOfDefinition(OfxRectD regionOfDefinition);
|
||||||
void setParams(const VideoParams ¶ms);
|
void setParams(const VideoParams ¶ms);
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
OFX::Host::ImageEffect::Texture* loadTexture(OfxTime time,
|
OFX::Host::ImageEffect::Texture *
|
||||||
const char *format,
|
loadTexture(OfxTime time, const char *format,
|
||||||
const OfxRectD *optionalBounds) override;
|
const OfxRectD *optionalBounds) override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void setInputTexture(TexturePtr texture, OfxTime time, bool readback_cpu = true);
|
void setInputTexture(TexturePtr texture, OfxTime time,
|
||||||
|
bool readback_cpu = true);
|
||||||
void setOutputTexture(TexturePtr texture, OfxTime time);
|
void setOutputTexture(TexturePtr texture, OfxTime time);
|
||||||
|
|
||||||
// Get the plugin-preferred VideoParams based on base class _pixelDepth/_components
|
// Get the plugin-preferred VideoParams based on base class _pixelDepth/_components
|
||||||
@@ -99,6 +103,4 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //OLIVECLIP_H
|
#endif //OLIVECLIP_H
|
||||||
|
|||||||
@@ -37,14 +37,18 @@
|
|||||||
using namespace OFX::Host;
|
using namespace OFX::Host;
|
||||||
using namespace olive::plugin;
|
using namespace olive::plugin;
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
namespace plugin {
|
{
|
||||||
|
namespace plugin
|
||||||
|
{
|
||||||
class PluginNode;
|
class PluginNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
void AddPluginPath(OFX::Host::PluginCache *cache, const QString &path, bool recurse = true)
|
{
|
||||||
|
void AddPluginPath(OFX::Host::PluginCache *cache, const QString &path,
|
||||||
|
bool recurse = true)
|
||||||
{
|
{
|
||||||
if (!cache || path.isEmpty()) {
|
if (!cache || path.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -80,7 +84,8 @@ void olive::plugin::loadPlugins(QString path)
|
|||||||
host = std::make_shared<OliveHost>();
|
host = std::make_shared<OliveHost>();
|
||||||
Current::getInstance().setPluginHost(host);
|
Current::getInstance().setPluginHost(host);
|
||||||
|
|
||||||
imageEffectPluginCache = std::make_shared<ImageEffect::PluginCache>(*host);
|
imageEffectPluginCache =
|
||||||
|
std::make_shared<ImageEffect::PluginCache>(*host);
|
||||||
Current::getInstance().setPluginCache(imageEffectPluginCache);
|
Current::getInstance().setPluginCache(imageEffectPluginCache);
|
||||||
|
|
||||||
imageEffectPluginCache->registerInCache(
|
imageEffectPluginCache->registerInCache(
|
||||||
@@ -92,7 +97,8 @@ void olive::plugin::loadPlugins(QString path)
|
|||||||
const QString home_path = QDir::homePath();
|
const QString home_path = QDir::homePath();
|
||||||
AddPluginPath(cache, QDir(home_path).filePath(".OFX/Plugins"));
|
AddPluginPath(cache, QDir(home_path).filePath(".OFX/Plugins"));
|
||||||
AddPluginPath(cache, QDir(home_path).filePath(".local/share/OFX/Plugins"));
|
AddPluginPath(cache, QDir(home_path).filePath(".local/share/OFX/Plugins"));
|
||||||
AddPluginPath(cache, QDir(home_path).filePath(".local/share/olive/ofx/Plugins"));
|
AddPluginPath(cache,
|
||||||
|
QDir(home_path).filePath(".local/share/olive/ofx/Plugins"));
|
||||||
|
|
||||||
const QString app_dir = QCoreApplication::applicationDirPath();
|
const QString app_dir = QCoreApplication::applicationDirPath();
|
||||||
AddPluginPath(cache, QDir(app_dir).filePath("../OFX/Plugins"));
|
AddPluginPath(cache, QDir(app_dir).filePath("../OFX/Plugins"));
|
||||||
@@ -109,7 +115,6 @@ void olive::plugin::loadPlugins(QString path)
|
|||||||
}
|
}
|
||||||
OliveHost::~OliveHost()
|
OliveHost::~OliveHost()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OliveHost::destroyInstance(OFX::Host::ImageEffect::Instance *instance)
|
void OliveHost::destroyInstance(OFX::Host::ImageEffect::Instance *instance)
|
||||||
@@ -151,10 +156,11 @@ OliveHost::makeDescriptor(const std::string &bundlePath,
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageEffect::Instance* OliveHost::newInstance(void *clientData,
|
ImageEffect::Instance *
|
||||||
ImageEffect::ImageEffectPlugin* plugin,
|
OliveHost::newInstance(void *clientData, ImageEffect::ImageEffectPlugin *plugin,
|
||||||
ImageEffect::Descriptor &desc,
|
ImageEffect::Descriptor &desc,
|
||||||
const std::string& context){
|
const std::string &context)
|
||||||
|
{
|
||||||
auto *instance = new OlivePluginInstance(
|
auto *instance = new OlivePluginInstance(
|
||||||
plugin, desc, context, Current::getInstance().interactive());
|
plugin, desc, context, Current::getInstance().interactive());
|
||||||
if (clientData) {
|
if (clientData) {
|
||||||
@@ -165,8 +171,9 @@ ImageEffect::Instance* OliveHost::newInstance(void *clientData,
|
|||||||
instances_.append(std::shared_ptr<OlivePluginInstance>(instance));
|
instances_.append(std::shared_ptr<OlivePluginInstance>(instance));
|
||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, const char *format,
|
OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id,
|
||||||
va_list args){
|
const char *format, va_list args)
|
||||||
|
{
|
||||||
if (!type || !format) {
|
if (!type || !format) {
|
||||||
return kOfxStatFailed;
|
return kOfxStatFailed;
|
||||||
}
|
}
|
||||||
@@ -178,8 +185,7 @@ OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, c
|
|||||||
|
|
||||||
auto *app = qobject_cast<QApplication *>(QCoreApplication::instance());
|
auto *app = qobject_cast<QApplication *>(QCoreApplication::instance());
|
||||||
if (!app) {
|
if (!app) {
|
||||||
qWarning().noquote()
|
qWarning().noquote() << "OFX message:" << type << message;
|
||||||
<< "OFX message:" << type << message;
|
|
||||||
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
||||||
return kOfxStatReplyNo;
|
return kOfxStatReplyNo;
|
||||||
}
|
}
|
||||||
@@ -187,8 +193,8 @@ OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
||||||
auto ret = QMessageBox::question(nullptr, "", message,
|
auto ret = QMessageBox::question(nullptr, "", message, QMessageBox::Ok,
|
||||||
QMessageBox::Ok, QMessageBox::Cancel);
|
QMessageBox::Cancel);
|
||||||
return (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo;
|
return (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,8 +209,10 @@ OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, c
|
|||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
// TODO: Persistent messages shouldn't use pop-up window.
|
// TODO: Persistent messages shouldn't use pop-up window.
|
||||||
OfxStatus olive::plugin::OliveHost::setPersistentMessage(
|
OfxStatus olive::plugin::OliveHost::setPersistentMessage(const char *type,
|
||||||
const char *type, const char *id, const char *format, va_list args)
|
const char *id,
|
||||||
|
const char *format,
|
||||||
|
va_list args)
|
||||||
{
|
{
|
||||||
if (!type || !format) {
|
if (!type || !format) {
|
||||||
return kOfxStatFailed;
|
return kOfxStatFailed;
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ namespace olive
|
|||||||
{
|
{
|
||||||
namespace plugin
|
namespace plugin
|
||||||
{
|
{
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
const std::string kImageFieldNoneStr(kOfxImageFieldNone);
|
const std::string kImageFieldNoneStr(kOfxImageFieldNone);
|
||||||
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
||||||
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
||||||
@@ -62,7 +63,8 @@ QString FormatOfxMessage(const char *format, va_list args)
|
|||||||
return QString::fromUtf8(buffer);
|
return QString::fromUtf8(buffer);
|
||||||
}
|
}
|
||||||
QByteArray dynamic_buffer(needed + 1, 0);
|
QByteArray dynamic_buffer(needed + 1, 0);
|
||||||
const int written = vsnprintf(dynamic_buffer.data(), dynamic_buffer.size(), format, args);
|
const int written =
|
||||||
|
vsnprintf(dynamic_buffer.data(), dynamic_buffer.size(), format, args);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -136,7 +138,8 @@ ViewerOutput *GetActiveViewerOutput()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<TimelinePanel *> timelines = manager->GetPanelsOfType<TimelinePanel>();
|
QList<TimelinePanel *> timelines =
|
||||||
|
manager->GetPanelsOfType<TimelinePanel>();
|
||||||
for (TimelinePanel *panel : timelines) {
|
for (TimelinePanel *panel : timelines) {
|
||||||
if (panel && panel->GetConnectedViewer()) {
|
if (panel && panel->GetConnectedViewer()) {
|
||||||
return panel->GetConnectedViewer();
|
return panel->GetConnectedViewer();
|
||||||
@@ -180,7 +183,8 @@ OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id,
|
|||||||
if (is_question) {
|
if (is_question) {
|
||||||
const auto ret = QMessageBox::question(
|
const auto ret = QMessageBox::question(
|
||||||
nullptr, "", message, QMessageBox::Ok, QMessageBox::Cancel);
|
nullptr, "", message, QMessageBox::Ok, QMessageBox::Cancel);
|
||||||
result = (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo;
|
result = (ret == QMessageBox::Ok) ? kOfxStatReplyYes :
|
||||||
|
kOfxStatReplyNo;
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(nullptr, "", message);
|
QMessageBox::information(nullptr, "", message);
|
||||||
result = kOfxStatOK;
|
result = kOfxStatOK;
|
||||||
@@ -191,7 +195,8 @@ OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id,
|
|||||||
show_message();
|
show_message();
|
||||||
} else if (auto *app = QCoreApplication::instance()) {
|
} else if (auto *app = QCoreApplication::instance()) {
|
||||||
if (is_question) {
|
if (is_question) {
|
||||||
QMetaObject::invokeMethod(app, show_message, Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(app, show_message,
|
||||||
|
Qt::BlockingQueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(app, show_message, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(app, show_message, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
@@ -201,8 +206,10 @@ OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char *id,
|
OfxStatus OlivePluginInstance::setPersistentMessage(const char *type,
|
||||||
const char *format, va_list args)
|
const char *id,
|
||||||
|
const char *format,
|
||||||
|
va_list args)
|
||||||
{
|
{
|
||||||
const QString message = FormatOfxMessage(format, args);
|
const QString message = FormatOfxMessage(format, args);
|
||||||
if (message.isEmpty()) {
|
if (message.isEmpty()) {
|
||||||
@@ -215,11 +222,13 @@ OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char
|
|||||||
error_type = ErrorType::Error;
|
error_type = ErrorType::Error;
|
||||||
}
|
}
|
||||||
// A warning
|
// A warning
|
||||||
else if (strncmp(type, kOfxMessageWarning, strlen(kOfxMessageWarning)) == 0) {
|
else if (strncmp(type, kOfxMessageWarning, strlen(kOfxMessageWarning)) ==
|
||||||
|
0) {
|
||||||
error_type = ErrorType::Warning;
|
error_type = ErrorType::Warning;
|
||||||
}
|
}
|
||||||
// A simple information
|
// A simple information
|
||||||
else if (strncmp(type, kOfxMessageMessage, strlen(kOfxMessageMessage)) == 0) {
|
else if (strncmp(type, kOfxMessageMessage, strlen(kOfxMessageMessage)) ==
|
||||||
|
0) {
|
||||||
error_type = ErrorType::Message;
|
error_type = ErrorType::Message;
|
||||||
} else {
|
} else {
|
||||||
return kOfxStatFailed;
|
return kOfxStatFailed;
|
||||||
@@ -272,7 +281,8 @@ void OlivePluginInstance::getProjectSize(double &xSize, double &ySize) const
|
|||||||
xSize = params_.width() * par;
|
xSize = params_.width() * par;
|
||||||
ySize = params_.height();
|
ySize = params_.height();
|
||||||
}
|
}
|
||||||
void OlivePluginInstance::getProjectOffset(double &xOffset, double &yOffset) const
|
void OlivePluginInstance::getProjectOffset(double &xOffset,
|
||||||
|
double &yOffset) const
|
||||||
{
|
{
|
||||||
double par = params_.pixel_aspect_ratio().toDouble();
|
double par = params_.pixel_aspect_ratio().toDouble();
|
||||||
xOffset = params_.x() * par;
|
xOffset = params_.x() * par;
|
||||||
@@ -343,8 +353,7 @@ OlivePluginInstance::newParam(const std::string &name,
|
|||||||
return new Double3DInstance(node_, name, desc, this);
|
return new Double3DInstance(node_, name, desc, this);
|
||||||
} else if (type == kOfxParamTypeInteger3D) {
|
} else if (type == kOfxParamTypeInteger3D) {
|
||||||
return new Integer3DInstance(node_, name, desc, this);
|
return new Integer3DInstance(node_, name, desc, this);
|
||||||
} else if (type == kOfxParamTypeCustom ||
|
} else if (type == kOfxParamTypeCustom || type == kOfxParamTypeBytes) {
|
||||||
type == kOfxParamTypeBytes) {
|
|
||||||
return new CustomInstance(node_, name, desc, this);
|
return new CustomInstance(node_, name, desc, this);
|
||||||
} else if (type == kOfxParamTypeGroup) {
|
} else if (type == kOfxParamTypeGroup) {
|
||||||
return new GroupInstance(desc, this);
|
return new GroupInstance(desc, this);
|
||||||
@@ -366,8 +375,7 @@ OfxStatus OlivePluginInstance::editBegin(const std::string &name)
|
|||||||
edit_param_count_ = 0;
|
edit_param_count_ = 0;
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
edit_first_label_ =
|
edit_first_label_ =
|
||||||
QCoreApplication::translate(
|
QCoreApplication::translate("OlivePluginInstance", "Change %1")
|
||||||
"OlivePluginInstance", "Change %1")
|
|
||||||
.arg(QString::fromStdString(name));
|
.arg(QString::fromStdString(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,15 +391,14 @@ OfxStatus OlivePluginInstance::editEnd()
|
|||||||
if (label.isEmpty()) {
|
if (label.isEmpty()) {
|
||||||
if (edit_param_count_ <= 1 && !edit_first_label_.isEmpty()) {
|
if (edit_param_count_ <= 1 && !edit_first_label_.isEmpty()) {
|
||||||
label = edit_first_label_;
|
label = edit_first_label_;
|
||||||
} else if (edit_param_count_ > 1 &&
|
} else if (edit_param_count_ > 1 && !edit_first_label_.isEmpty()) {
|
||||||
!edit_first_label_.isEmpty()) {
|
label = QCoreApplication::translate("OlivePluginInstance",
|
||||||
label = QCoreApplication::translate(
|
"%1 (+%2)")
|
||||||
"OlivePluginInstance", "%1 (+%2)")
|
|
||||||
.arg(edit_first_label_)
|
.arg(edit_first_label_)
|
||||||
.arg(edit_param_count_ - 1);
|
.arg(edit_param_count_ - 1);
|
||||||
} else {
|
} else {
|
||||||
label = QCoreApplication::translate(
|
label = QCoreApplication::translate("OlivePluginInstance",
|
||||||
"OlivePluginInstance", "Edit Parameters");
|
"Edit Parameters");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Core::instance()->undo_stack()->push(edit_command_, label);
|
Core::instance()->undo_stack()->push(edit_command_, label);
|
||||||
@@ -450,9 +457,8 @@ void OlivePluginInstance::progressStart(const std::string &message,
|
|||||||
progress_dialog_->deleteLater();
|
progress_dialog_->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString dialog_message = message.empty()
|
QString dialog_message = message.empty() ? QStringLiteral("Processing...") :
|
||||||
? QStringLiteral("Processing...")
|
QString::fromStdString(message);
|
||||||
: QString::fromStdString(message);
|
|
||||||
|
|
||||||
progress_dialog_ = new ::olive::ProgressDialog(
|
progress_dialog_ = new ::olive::ProgressDialog(
|
||||||
dialog_message, QStringLiteral("OpenFX"), nullptr);
|
dialog_message, QStringLiteral("OpenFX"), nullptr);
|
||||||
@@ -547,11 +553,11 @@ void OlivePluginInstance::setCustomInArgs(const std::string &action,
|
|||||||
|
|
||||||
OFX::Host::ImageEffect::ClipInstance *OlivePluginInstance::newClipInstance(
|
OFX::Host::ImageEffect::ClipInstance *OlivePluginInstance::newClipInstance(
|
||||||
OFX::Host::ImageEffect::Instance *plugin,
|
OFX::Host::ImageEffect::Instance *plugin,
|
||||||
OFX::Host::ImageEffect::ClipDescriptor *descriptor,
|
OFX::Host::ImageEffect::ClipDescriptor *descriptor, int index)
|
||||||
int index)
|
|
||||||
{
|
{
|
||||||
// Create a new clip instance
|
// Create a new clip instance
|
||||||
OliveClipInstance* clipInstance = new OliveClipInstance(plugin, *descriptor, params_);
|
OliveClipInstance *clipInstance =
|
||||||
|
new OliveClipInstance(plugin, *descriptor, params_);
|
||||||
|
|
||||||
// Initialize base class clip properties from VideoParams so that
|
// Initialize base class clip properties from VideoParams so that
|
||||||
// setupClipPreferencesArgs and plugin constructors (which may fetch
|
// setupClipPreferencesArgs and plugin constructors (which may fetch
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qlist.h>
|
#include <qlist.h>
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
|
{
|
||||||
|
|
||||||
inline bool IsGuiThread()
|
inline bool IsGuiThread()
|
||||||
{
|
{
|
||||||
@@ -43,24 +44,19 @@ inline bool IsGuiThread()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
class ProgressDialog;
|
class ProgressDialog;
|
||||||
namespace plugin {
|
namespace plugin
|
||||||
|
{
|
||||||
class PluginNode;
|
class PluginNode;
|
||||||
enum class ErrorType{
|
enum class ErrorType { Error, Warning, Message };
|
||||||
Error,
|
|
||||||
Warning,
|
|
||||||
Message
|
|
||||||
};
|
|
||||||
struct PersistentErrors {
|
struct PersistentErrors {
|
||||||
ErrorType type;
|
ErrorType type;
|
||||||
QString message;
|
QString message;
|
||||||
};
|
};
|
||||||
class OlivePluginInstance : public OFX::Host::ImageEffect::Instance {
|
class OlivePluginInstance : public OFX::Host::ImageEffect::Instance {
|
||||||
public:
|
public:
|
||||||
OlivePluginInstance(
|
OlivePluginInstance(OFX::Host::ImageEffect::ImageEffectPlugin *plugin,
|
||||||
OFX::Host::ImageEffect::ImageEffectPlugin* plugin,
|
|
||||||
OFX::Host::ImageEffect::Descriptor &desc,
|
OFX::Host::ImageEffect::Descriptor &desc,
|
||||||
const std::string& context,
|
const std::string &context, bool interactive)
|
||||||
bool interactive)
|
|
||||||
: OFX::Host::ImageEffect::Instance(plugin, desc, context, interactive)
|
: OFX::Host::ImageEffect::Instance(plugin, desc, context, interactive)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -78,7 +74,8 @@ public:
|
|||||||
_outputFielding = instance._outputFielding;
|
_outputFielding = instance._outputFielding;
|
||||||
_outputFrameRate = instance._outputFrameRate;
|
_outputFrameRate = instance._outputFrameRate;
|
||||||
}
|
}
|
||||||
explicit OlivePluginInstance(Instance & instance):Instance(instance){};
|
explicit OlivePluginInstance(Instance &instance)
|
||||||
|
: Instance(instance) {};
|
||||||
~OlivePluginInstance() override;
|
~OlivePluginInstance() override;
|
||||||
const std::string &getDefaultOutputFielding() const override;
|
const std::string &getDefaultOutputFielding() const override;
|
||||||
|
|
||||||
@@ -99,20 +96,16 @@ public:
|
|||||||
{
|
{
|
||||||
return _created;
|
return _created;
|
||||||
}
|
}
|
||||||
OFX::Host::ImageEffect::ClipInstance *newClipInstance(
|
OFX::Host::ImageEffect::ClipInstance *
|
||||||
OFX::Host::ImageEffect::Instance *plugin,
|
newClipInstance(OFX::Host::ImageEffect::Instance *plugin,
|
||||||
OFX::Host::ImageEffect::ClipDescriptor *descriptor,
|
OFX::Host::ImageEffect::ClipDescriptor *descriptor,
|
||||||
int index) override;
|
int index) override;
|
||||||
|
|
||||||
OfxStatus vmessage(const char* type,
|
OfxStatus vmessage(const char *type, const char *id, const char *format,
|
||||||
const char* id,
|
|
||||||
const char* format,
|
|
||||||
va_list args) override;
|
va_list args) override;
|
||||||
|
|
||||||
OfxStatus setPersistentMessage(const char* type,
|
OfxStatus setPersistentMessage(const char *type, const char *id,
|
||||||
const char* id,
|
const char *format, va_list args) override;
|
||||||
const char* format,
|
|
||||||
va_list args) override;
|
|
||||||
|
|
||||||
OfxStatus clearPersistentMessage() override;
|
OfxStatus clearPersistentMessage() override;
|
||||||
int persistentMessageCount() const
|
int persistentMessageCount() const
|
||||||
@@ -153,7 +146,9 @@ public:
|
|||||||
/// make a parameter instance
|
/// make a parameter instance
|
||||||
///
|
///
|
||||||
/// Client host code needs to implement this
|
/// Client host code needs to implement this
|
||||||
OFX::Host::Param::Instance* newParam(const std::string& name, OFX::Host::Param::Descriptor& Descriptor) override;
|
OFX::Host::Param::Instance *
|
||||||
|
newParam(const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &Descriptor) override;
|
||||||
|
|
||||||
void SubmitUndoCommand(UndoCommand *command, const QString &label);
|
void SubmitUndoCommand(UndoCommand *command, const QString &label);
|
||||||
|
|
||||||
@@ -210,7 +205,6 @@ public:
|
|||||||
void setCustomInArgs(const std::string &action,
|
void setCustomInArgs(const std::string &action,
|
||||||
OFX::Host::Property::Set &inArgs) override;
|
OFX::Host::Property::Set &inArgs) override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<PersistentErrors> persistentErrors_;
|
QList<PersistentErrors> persistentErrors_;
|
||||||
VideoParams params_;
|
VideoParams params_;
|
||||||
@@ -224,8 +218,13 @@ private:
|
|||||||
bool progress_cancelled_ = false;
|
bool progress_cancelled_ = false;
|
||||||
bool progress_active_ = false;
|
bool progress_active_ = false;
|
||||||
bool open_gl_enabled_ = false;
|
bool open_gl_enabled_ = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::mutex& mutex() { return mutex_; }
|
std::mutex &mutex()
|
||||||
|
{
|
||||||
|
return mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|||||||
+16
-29
@@ -23,8 +23,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
namespace plugin {
|
{
|
||||||
|
namespace plugin
|
||||||
|
{
|
||||||
|
|
||||||
static const char *PixelDepthToOfx(core::PixelFormat format)
|
static const char *PixelDepthToOfx(core::PixelFormat format)
|
||||||
{
|
{
|
||||||
@@ -75,10 +77,8 @@ Image::Image(OFX::Host::ImageEffect::ClipInstance &clip_instance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Image::Image(OFX::Host::ImageEffect::ClipInstance &clip_instance,
|
Image::Image(OFX::Host::ImageEffect::ClipInstance &clip_instance,
|
||||||
const VideoParams ¶ms,
|
const VideoParams ¶ms, const OfxRectI &bounds,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &rod, bool clear)
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear)
|
|
||||||
: OFX::Host::ImageEffect::Image(clip_instance)
|
: OFX::Host::ImageEffect::Image(clip_instance)
|
||||||
, width_(0)
|
, width_(0)
|
||||||
, height_(0)
|
, height_(0)
|
||||||
@@ -97,24 +97,17 @@ Image::~Image()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Image::AllocateFromParams(const VideoParams ¶ms,
|
void Image::AllocateFromParams(const VideoParams ¶ms,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &bounds, const OfxRectI &rod,
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear)
|
bool clear)
|
||||||
{
|
{
|
||||||
Allocate(bounds.x2 - bounds.x1,
|
Allocate(bounds.x2 - bounds.x1, bounds.y2 - bounds.y1, params.format(),
|
||||||
bounds.y2 - bounds.y1,
|
params.channel_count(), params.premultiplied_alpha(), bounds, rod,
|
||||||
params.format(),
|
|
||||||
params.channel_count(),
|
|
||||||
params.premultiplied_alpha(),
|
|
||||||
bounds,
|
|
||||||
rod,
|
|
||||||
clear);
|
clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::EnsureAllocatedFromParams(const VideoParams ¶ms,
|
void Image::EnsureAllocatedFromParams(const VideoParams ¶ms,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &bounds,
|
||||||
const OfxRectI &rod,
|
const OfxRectI &rod, bool clear)
|
||||||
bool clear)
|
|
||||||
{
|
{
|
||||||
bool same = (width_ == bounds.x2 - bounds.x1) &&
|
bool same = (width_ == bounds.x2 - bounds.x1) &&
|
||||||
(height_ == bounds.y2 - bounds.y1) &&
|
(height_ == bounds.y2 - bounds.y1) &&
|
||||||
@@ -133,14 +126,9 @@ void Image::EnsureAllocatedFromParams(const VideoParams ¶ms,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::Allocate(int width,
|
void Image::Allocate(int width, int height, core::PixelFormat format,
|
||||||
int height,
|
int channel_count, bool premultiplied_alpha,
|
||||||
core::PixelFormat format,
|
const OfxRectI &bounds, const OfxRectI &rod, bool clear)
|
||||||
int channel_count,
|
|
||||||
bool premultiplied_alpha,
|
|
||||||
const OfxRectI &bounds,
|
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear)
|
|
||||||
{
|
{
|
||||||
width_ = width;
|
width_ = width;
|
||||||
height_ = height;
|
height_ = height;
|
||||||
@@ -174,11 +162,10 @@ void Image::Allocate(int width,
|
|||||||
setIntProperty(kOfxImagePropRegionOfDefinition, rod.y2, 3);
|
setIntProperty(kOfxImagePropRegionOfDefinition, rod.y2, 3);
|
||||||
setStringProperty(kOfxImageEffectPropComponents,
|
setStringProperty(kOfxImageEffectPropComponents,
|
||||||
ComponentsToOfx(channel_count_));
|
ComponentsToOfx(channel_count_));
|
||||||
setStringProperty(kOfxImageEffectPropPixelDepth,
|
setStringProperty(kOfxImageEffectPropPixelDepth, PixelDepthToOfx(format_));
|
||||||
PixelDepthToOfx(format_));
|
|
||||||
setStringProperty(kOfxImageEffectPropPreMultiplication,
|
setStringProperty(kOfxImageEffectPropPreMultiplication,
|
||||||
premultiplied_alpha_ ? kOfxImagePreMultiplied
|
premultiplied_alpha_ ? kOfxImagePreMultiplied :
|
||||||
: kOfxImageUnPreMultiplied);
|
kOfxImageUnPreMultiplied);
|
||||||
}
|
}
|
||||||
|
|
||||||
core::PixelFormat Image::pixel_format()
|
core::PixelFormat Image::pixel_format()
|
||||||
|
|||||||
+11
-18
@@ -37,12 +37,11 @@ class Image : public OFX::Host::ImageEffect::Image {
|
|||||||
public:
|
public:
|
||||||
Image(OFX::Host::ImageEffect::ClipInstance &clip_instance);
|
Image(OFX::Host::ImageEffect::ClipInstance &clip_instance);
|
||||||
Image(OFX::Host::ImageEffect::ClipInstance &clip_instance,
|
Image(OFX::Host::ImageEffect::ClipInstance &clip_instance,
|
||||||
const VideoParams ¶ms,
|
const VideoParams ¶ms, const OfxRectI &bounds,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &rod, bool clear = true);
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear = true);
|
|
||||||
~Image();
|
~Image();
|
||||||
uint8_t *data() {
|
uint8_t *data()
|
||||||
|
{
|
||||||
return (uint8_t *)getPointerProperty(kOfxImagePropData);
|
return (uint8_t *)getPointerProperty(kOfxImagePropData);
|
||||||
}
|
}
|
||||||
int width();
|
int width();
|
||||||
@@ -51,26 +50,20 @@ public:
|
|||||||
bool premultiplied_alpha();
|
bool premultiplied_alpha();
|
||||||
int channel_count();
|
int channel_count();
|
||||||
|
|
||||||
void AllocateFromParams(const VideoParams ¶ms,
|
void AllocateFromParams(const VideoParams ¶ms, const OfxRectI &bounds,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &rod, bool clear = true);
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear = true);
|
|
||||||
void EnsureAllocatedFromParams(const VideoParams ¶ms,
|
void EnsureAllocatedFromParams(const VideoParams ¶ms,
|
||||||
const OfxRectI &bounds,
|
const OfxRectI &bounds, const OfxRectI &rod,
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear = false);
|
bool clear = false);
|
||||||
void Allocate(int width,
|
void Allocate(int width, int height, core::PixelFormat format,
|
||||||
int height,
|
int channel_count, bool premultiplied_alpha,
|
||||||
core::PixelFormat format,
|
const OfxRectI &bounds, const OfxRectI &rod,
|
||||||
int channel_count,
|
|
||||||
bool premultiplied_alpha,
|
|
||||||
const OfxRectI &bounds,
|
|
||||||
const OfxRectI &rod,
|
|
||||||
bool clear = true);
|
bool clear = true);
|
||||||
int row_bytes() const
|
int row_bytes() const
|
||||||
{
|
{
|
||||||
return row_bytes_;
|
return row_bytes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<uint8_t> image_;
|
std::vector<uint8_t> image_;
|
||||||
int width_;
|
int width_;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "paraminstance.h"
|
#include "paraminstance.h"
|
||||||
|
|
||||||
#include "OlivePluginInstance.h"
|
#include "OlivePluginInstance.h"
|
||||||
@@ -35,8 +34,7 @@ void SubmitUndoCommand(const std::shared_ptr<PluginNode> &node,
|
|||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
auto *instance = node->getPluginInstance();
|
auto *instance = node->getPluginInstance();
|
||||||
auto *olive_instance =
|
auto *olive_instance = dynamic_cast<OlivePluginInstance *>(instance);
|
||||||
dynamic_cast<OlivePluginInstance *>(instance);
|
|
||||||
if (olive_instance) {
|
if (olive_instance) {
|
||||||
olive_instance->SubmitUndoCommand(command, label);
|
olive_instance->SubmitUndoCommand(command, label);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ namespace olive
|
|||||||
namespace plugin
|
namespace plugin
|
||||||
{
|
{
|
||||||
|
|
||||||
inline bool IsNormalisedCoordinateSystem(
|
inline bool
|
||||||
const OFX::Host::Param::Descriptor &descriptor)
|
IsNormalisedCoordinateSystem(const OFX::Host::Param::Descriptor &descriptor)
|
||||||
{
|
{
|
||||||
return descriptor.getDefaultCoordinateSystem() ==
|
return descriptor.getDefaultCoordinateSystem() ==
|
||||||
kOfxParamCoordinatesNormalised;
|
kOfxParamCoordinatesNormalised;
|
||||||
@@ -84,8 +84,10 @@ class PushbuttonInstance : public OFX::Host::Param::PushbuttonInstance,
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor *_descriptor;
|
OFX::Host::Param::Descriptor *_descriptor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PushbuttonInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
PushbuttonInstance(std::shared_ptr<PluginNode> effect,
|
||||||
|
const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &descriptor,
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::PushbuttonInstance(descriptor, paramSet)
|
: OFX::Host::Param::PushbuttonInstance(descriptor, paramSet)
|
||||||
@@ -108,8 +110,10 @@ protected:
|
|||||||
mutable std::mutex no_node_mutex_;
|
mutable std::mutex no_node_mutex_;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
int value_ = 0;
|
int value_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntegerInstance(std::shared_ptr<PluginNode>node, OFX::Host::Param::Descriptor &descriptor,
|
IntegerInstance(std::shared_ptr<PluginNode> node,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::IntegerInstance(descriptor, paramSet)
|
: OFX::Host::Param::IntegerInstance(descriptor, paramSet)
|
||||||
, _node(node)
|
, _node(node)
|
||||||
@@ -117,7 +121,8 @@ public:
|
|||||||
, id(_descriptor.getName().c_str())
|
, id(_descriptor.getName().c_str())
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
value_ = _descriptor.getProperties().getIntProperty(kOfxParamPropDefault);
|
value_ = _descriptor.getProperties().getIntProperty(
|
||||||
|
kOfxParamPropDefault);
|
||||||
has_value_ = true;
|
has_value_ = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
value_ = 0;
|
value_ = 0;
|
||||||
@@ -157,7 +162,8 @@ public:
|
|||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
return kOfxStatErrBadHandle;
|
return kOfxStatErrBadHandle;
|
||||||
}
|
}
|
||||||
QVariant variant=_node->GetValueAtTime(id, rational::fromDouble(time));
|
QVariant variant =
|
||||||
|
_node->GetValueAtTime(id, rational::fromDouble(time));
|
||||||
if (variant.canConvert<int>()) {
|
if (variant.canConvert<int>()) {
|
||||||
data = variant.toInt();
|
data = variant.toInt();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -205,8 +211,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
double value_ = 0.0;
|
double value_ = 0.0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DoubleInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
DoubleInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::DoubleInstance(descriptor, paramSet)
|
: OFX::Host::Param::DoubleInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -214,7 +222,8 @@ public:
|
|||||||
{
|
{
|
||||||
(void)name;
|
(void)name;
|
||||||
try {
|
try {
|
||||||
value_ = _descriptor.getProperties().getDoubleProperty(kOfxParamPropDefault);
|
value_ = _descriptor.getProperties().getDoubleProperty(
|
||||||
|
kOfxParamPropDefault);
|
||||||
has_value_ = true;
|
has_value_ = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
value_ = 0.0;
|
value_ = 0.0;
|
||||||
@@ -231,7 +240,8 @@ public:
|
|||||||
data = has_value_ ? value_ : 0.0;
|
data = has_value_ ? value_ : 0.0;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant =
|
||||||
|
node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<double>()) {
|
if (variant.canConvert<double>()) {
|
||||||
data = variant.toDouble();
|
data = variant.toDouble();
|
||||||
if (IsNormalisedCoordinateSystem(_descriptor)) {
|
if (IsNormalisedCoordinateSystem(_descriptor)) {
|
||||||
@@ -250,8 +260,7 @@ public:
|
|||||||
data = has_value_ ? value_ : 0.0;
|
data = has_value_ ? value_ : 0.0;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant =
|
QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
if (variant.canConvert<double>()) {
|
if (variant.canConvert<double>()) {
|
||||||
data = variant.toDouble();
|
data = variant.toDouble();
|
||||||
@@ -299,8 +308,8 @@ public:
|
|||||||
val = ToCanonical(val, xSize);
|
val = ToCanonical(val, xSize);
|
||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(NodeInput(node.get(),
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
_descriptor.getName().c_str()),
|
||||||
rational::fromDouble(time), val, 0, command, true);
|
rational::fromDouble(time), val, 0, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -324,11 +333,13 @@ protected:
|
|||||||
bool value_ = false;
|
bool value_ = false;
|
||||||
bool DefaultValue() const
|
bool DefaultValue() const
|
||||||
{
|
{
|
||||||
return _descriptor.getProperties()
|
return _descriptor.getProperties().getIntProperty(
|
||||||
.getIntProperty(kOfxParamPropDefault) != 0;
|
kOfxParamPropDefault) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BooleanInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
BooleanInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::BooleanInstance(descriptor, paramSet)
|
: OFX::Host::Param::BooleanInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -348,7 +359,8 @@ public:
|
|||||||
data = has_value_ ? value_ : false;
|
data = has_value_ ? value_ : false;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant =
|
||||||
|
node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<bool>()) {
|
if (variant.canConvert<bool>()) {
|
||||||
data = variant.toBool();
|
data = variant.toBool();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -362,11 +374,12 @@ public:
|
|||||||
data = has_value_ ? value_ : false;
|
data = has_value_ ? value_ : false;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant =
|
QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
if (variant.isNull()) {
|
if (variant.isNull()) {
|
||||||
qWarning().noquote()<<"Boolean get failed: Varient is null" << time << rational::fromDouble(time).toDouble();
|
qWarning().noquote()
|
||||||
|
<< "Boolean get failed: Varient is null" << time
|
||||||
|
<< rational::fromDouble(time).toDouble();
|
||||||
}
|
}
|
||||||
if (!variant.isValid()) {
|
if (!variant.isValid()) {
|
||||||
qWarning().noquote()
|
qWarning().noquote()
|
||||||
@@ -417,8 +430,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
int value_ = 0;
|
int value_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChoiceInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
ChoiceInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::ChoiceInstance(descriptor, paramSet)
|
: OFX::Host::Param::ChoiceInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -426,7 +441,8 @@ public:
|
|||||||
{
|
{
|
||||||
(void)name;
|
(void)name;
|
||||||
try {
|
try {
|
||||||
value_ = _descriptor.getProperties().getIntProperty(kOfxParamPropDefault);
|
value_ = _descriptor.getProperties().getIntProperty(
|
||||||
|
kOfxParamPropDefault);
|
||||||
has_value_ = true;
|
has_value_ = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
value_ = 0;
|
value_ = 0;
|
||||||
@@ -443,7 +459,8 @@ public:
|
|||||||
data = has_value_ ? value_ : 0;
|
data = has_value_ ? value_ : 0;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant =
|
||||||
|
node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<int>()) {
|
if (variant.canConvert<int>()) {
|
||||||
data = variant.toInt();
|
data = variant.toInt();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -457,8 +474,7 @@ public:
|
|||||||
data = has_value_ ? value_ : 0;
|
data = has_value_ ? value_ : 0;
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant =
|
QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
if (variant.canConvert<int>()) {
|
if (variant.canConvert<int>()) {
|
||||||
data = variant.toInt();
|
data = variant.toInt();
|
||||||
@@ -504,8 +520,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
double value_[4] = { 0.0, 0.0, 0.0, 0.0 };
|
double value_[4] = { 0.0, 0.0, 0.0, 0.0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RGBAInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
RGBAInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::RGBAInstance(descriptor, paramSet)
|
: OFX::Host::Param::RGBAInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -594,20 +612,19 @@ public:
|
|||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
r, 0, command, true);
|
rational::fromDouble(time), r, 0, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
g, 1, command, true);
|
rational::fromDouble(time), g, 1, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
b, 2, command, true);
|
rational::fromDouble(time), b, 2, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
a, 3, command, true);
|
rational::fromDouble(time), a, 3, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RGBInstance : public OFX::Host::Param::RGBInstance,
|
class RGBInstance : public OFX::Host::Param::RGBInstance,
|
||||||
public NodeBoundParam {
|
public NodeBoundParam {
|
||||||
protected:
|
protected:
|
||||||
@@ -615,8 +632,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
double value_[3] = { 0.0, 0.0, 0.0 };
|
double value_[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RGBInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
RGBInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::RGBInstance(descriptor, paramSet)
|
: OFX::Host::Param::RGBInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -699,12 +718,12 @@ public:
|
|||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
r, 0, command, true);
|
rational::fromDouble(time), r, 0, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
g, 1, command, true);
|
rational::fromDouble(time), g, 1, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
b, 2, command, true);
|
rational::fromDouble(time), b, 2, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
@@ -717,8 +736,11 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
double value_[2] = { 0.0, 0.0 };
|
double value_[2] = { 0.0, 0.0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Double2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
Double2DInstance(std::shared_ptr<PluginNode> effect,
|
||||||
|
const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::Double2DInstance(descriptor, paramSet)
|
: OFX::Host::Param::Double2DInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -741,8 +763,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector2D vec =
|
QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
x = static_cast<double>(vec.x());
|
x = static_cast<double>(vec.x());
|
||||||
y = static_cast<double>(vec.y());
|
y = static_cast<double>(vec.y());
|
||||||
@@ -765,8 +786,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector2D vec =
|
QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
x = static_cast<double>(vec.x());
|
x = static_cast<double>(vec.x());
|
||||||
@@ -818,10 +838,10 @@ public:
|
|||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
xv, 0, command, true);
|
rational::fromDouble(time), xv, 0, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
yv, 1, command, true);
|
rational::fromDouble(time), yv, 1, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
@@ -834,8 +854,11 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
int value_[2] = { 0, 0 };
|
int value_[2] = { 0, 0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Integer2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor,
|
Integer2DInstance(std::shared_ptr<PluginNode> effect,
|
||||||
|
const std::string &name,
|
||||||
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::Integer2DInstance(descriptor, paramSet)
|
: OFX::Host::Param::Integer2DInstance(descriptor, paramSet)
|
||||||
, node(effect)
|
, node(effect)
|
||||||
@@ -858,8 +881,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector2D vec =
|
QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
x = static_cast<int>(vec.x());
|
x = static_cast<int>(vec.x());
|
||||||
y = static_cast<int>(vec.y());
|
y = static_cast<int>(vec.y());
|
||||||
@@ -876,8 +898,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector2D vec =
|
QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
x = static_cast<int>(vec.x());
|
x = static_cast<int>(vec.x());
|
||||||
@@ -909,10 +930,10 @@ public:
|
|||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
x, 0, command, true);
|
rational::fromDouble(time), x, 0, command, true);
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
y, 1, command, true);
|
rational::fromDouble(time), y, 1, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
@@ -925,8 +946,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
double value_[3] = { 0.0, 0.0, 0.0 };
|
double value_[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Double3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
Double3DInstance(std::shared_ptr<PluginNode> effect,
|
||||||
|
const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &descriptor,
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::Double3DInstance(descriptor, paramSet)
|
: OFX::Host::Param::Double3DInstance(descriptor, paramSet)
|
||||||
@@ -951,8 +974,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector3D vec =
|
QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
x = static_cast<double>(vec.x());
|
x = static_cast<double>(vec.x());
|
||||||
y = static_cast<double>(vec.y());
|
y = static_cast<double>(vec.y());
|
||||||
@@ -978,8 +1000,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector3D vec =
|
QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
x = static_cast<double>(vec.x());
|
x = static_cast<double>(vec.x());
|
||||||
@@ -1055,8 +1076,10 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
int value_[3] = { 0, 0, 0 };
|
int value_[3] = { 0, 0, 0 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Integer3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
Integer3DInstance(std::shared_ptr<PluginNode> effect,
|
||||||
|
const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &descriptor,
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
OFX::Host::Param::SetInstance *paramSet = nullptr)
|
||||||
: OFX::Host::Param::Integer3DInstance(descriptor, paramSet)
|
: OFX::Host::Param::Integer3DInstance(descriptor, paramSet)
|
||||||
@@ -1081,8 +1104,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector3D vec =
|
QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
x = static_cast<int>(vec.x());
|
x = static_cast<int>(vec.x());
|
||||||
y = static_cast<int>(vec.y());
|
y = static_cast<int>(vec.y());
|
||||||
@@ -1101,8 +1123,7 @@ public:
|
|||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVector3D vec =
|
QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
x = static_cast<int>(vec.x());
|
x = static_cast<int>(vec.x());
|
||||||
@@ -1155,6 +1176,7 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
std::string value_;
|
std::string value_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
StringInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &descriptor,
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
@@ -1165,7 +1187,8 @@ public:
|
|||||||
{
|
{
|
||||||
(void)name;
|
(void)name;
|
||||||
try {
|
try {
|
||||||
value_ = _descriptor.getProperties().getStringProperty(kOfxParamPropDefault);
|
value_ = _descriptor.getProperties().getStringProperty(
|
||||||
|
kOfxParamPropDefault);
|
||||||
has_value_ = true;
|
has_value_ = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
value_.clear();
|
value_.clear();
|
||||||
@@ -1182,7 +1205,8 @@ public:
|
|||||||
data = has_value_ ? value_ : std::string();
|
data = has_value_ ? value_ : std::string();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant =
|
||||||
|
node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<QString>()) {
|
if (variant.canConvert<QString>()) {
|
||||||
data = variant.toString().toStdString();
|
data = variant.toString().toStdString();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -1196,8 +1220,7 @@ public:
|
|||||||
data = has_value_ ? value_ : std::string();
|
data = has_value_ ? value_ : std::string();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant =
|
QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
if (variant.canConvert<QString>()) {
|
if (variant.canConvert<QString>()) {
|
||||||
data = variant.toString().toStdString();
|
data = variant.toString().toStdString();
|
||||||
@@ -1229,9 +1252,10 @@ public:
|
|||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(NodeInput(node.get(),
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
_descriptor.getName().c_str()),
|
||||||
rational::fromDouble(time), QString::fromUtf8(data), 0, command, true);
|
rational::fromDouble(time),
|
||||||
|
QString::fromUtf8(data), 0, command, true);
|
||||||
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor));
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
@@ -1244,6 +1268,7 @@ protected:
|
|||||||
OFX::Host::Param::Descriptor &_descriptor;
|
OFX::Host::Param::Descriptor &_descriptor;
|
||||||
bool has_value_ = false;
|
bool has_value_ = false;
|
||||||
std::string value_;
|
std::string value_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CustomInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
CustomInstance(std::shared_ptr<PluginNode> effect, const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &descriptor,
|
OFX::Host::Param::Descriptor &descriptor,
|
||||||
@@ -1264,7 +1289,8 @@ public:
|
|||||||
data = has_value_ ? value_ : std::string();
|
data = has_value_ ? value_ : std::string();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant =
|
||||||
|
node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<QByteArray>()) {
|
if (variant.canConvert<QByteArray>()) {
|
||||||
data = variant.toByteArray().toStdString();
|
data = variant.toByteArray().toStdString();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
@@ -1282,8 +1308,7 @@ public:
|
|||||||
data = has_value_ ? value_ : std::string();
|
data = has_value_ ? value_ : std::string();
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
QVariant variant =
|
QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
if (variant.canConvert<QByteArray>()) {
|
if (variant.canConvert<QByteArray>()) {
|
||||||
data = variant.toByteArray().toStdString();
|
data = variant.toByteArray().toStdString();
|
||||||
@@ -1347,6 +1372,4 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // HOST_DEMO_PARAM_INSTANCE_H
|
#endif // HOST_DEMO_PARAM_INSTANCE_H
|
||||||
|
|||||||
@@ -37,21 +37,24 @@ DynamicRenderer::~DynamicRenderer()
|
|||||||
// system libGL/libvulkan loader is never mistaken for an Oak render backend.
|
// system libGL/libvulkan loader is never mistaken for an Oak render backend.
|
||||||
QString DynamicRenderer::LibraryFilename() const
|
QString DynamicRenderer::LibraryFilename() const
|
||||||
{
|
{
|
||||||
const QString base = backend_ == QStringLiteral("vulkan")
|
const QString base = backend_ == QStringLiteral("vulkan") ?
|
||||||
? QStringLiteral("oakvulkan")
|
QStringLiteral("oakvulkan") :
|
||||||
: QStringLiteral("oakgl");
|
QStringLiteral("oakgl");
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
const QString filename = base + QStringLiteral(".dll");
|
const QString filename = base + QStringLiteral(".dll");
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
const QString filename = QStringLiteral("lib") + base + QStringLiteral(".dylib");
|
const QString filename =
|
||||||
|
QStringLiteral("lib") + base + QStringLiteral(".dylib");
|
||||||
#else
|
#else
|
||||||
const QString filename = QStringLiteral("lib") + base + QStringLiteral(".so");
|
const QString filename =
|
||||||
|
QStringLiteral("lib") + base + QStringLiteral(".so");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const QDir app_dir(QCoreApplication::applicationDirPath());
|
const QDir app_dir(QCoreApplication::applicationDirPath());
|
||||||
const QStringList candidates = {
|
const QStringList candidates = {
|
||||||
app_dir.filePath(filename),
|
app_dir.filePath(filename),
|
||||||
app_dir.filePath(QDir(QStringLiteral("render_backends")).filePath(filename)),
|
app_dir.filePath(
|
||||||
|
QDir(QStringLiteral("render_backends")).filePath(filename)),
|
||||||
app_dir.filePath(QDir(QStringLiteral("../lib")).filePath(filename)),
|
app_dir.filePath(QDir(QStringLiteral("../lib")).filePath(filename)),
|
||||||
app_dir.filePath(QDir(QStringLiteral("../../lib")).filePath(filename)),
|
app_dir.filePath(QDir(QStringLiteral("../../lib")).filePath(filename)),
|
||||||
app_dir.filePath(QDir(QStringLiteral("../app")).filePath(filename)),
|
app_dir.filePath(QDir(QStringLiteral("../app")).filePath(filename)),
|
||||||
@@ -77,9 +80,9 @@ bool DynamicRenderer::Load()
|
|||||||
library_.setFileName(LibraryFilename());
|
library_.setFileName(LibraryFilename());
|
||||||
if (!library_.load()) {
|
if (!library_.load()) {
|
||||||
if (backend_ == QStringLiteral("vulkan")) {
|
if (backend_ == QStringLiteral("vulkan")) {
|
||||||
qWarning() << "Failed to load Vulkan render backend"
|
qWarning()
|
||||||
<< library_.fileName() << library_.errorString()
|
<< "Failed to load Vulkan render backend" << library_.fileName()
|
||||||
<< "falling back to OpenGL backend";
|
<< library_.errorString() << "falling back to OpenGL backend";
|
||||||
backend_ = QStringLiteral("opengl");
|
backend_ = QStringLiteral("opengl");
|
||||||
library_.setFileName(LibraryFilename());
|
library_.setFileName(LibraryFilename());
|
||||||
}
|
}
|
||||||
@@ -128,7 +131,8 @@ bool DynamicRenderer::ResolveFunctions()
|
|||||||
ResetFunctions();
|
ResetFunctions();
|
||||||
#define RESOLVE(member, type, symbol) \
|
#define RESOLVE(member, type, symbol) \
|
||||||
member = reinterpret_cast<type>(library_.resolve(symbol)); \
|
member = reinterpret_cast<type>(library_.resolve(symbol)); \
|
||||||
if (!member) return false
|
if (!member) \
|
||||||
|
return false
|
||||||
|
|
||||||
RESOLVE(create_, OakBackendCreateFn, "oak_renderer_create");
|
RESOLVE(create_, OakBackendCreateFn, "oak_renderer_create");
|
||||||
RESOLVE(destroy_, OakBackendDestroyFn, "oak_renderer_destroy");
|
RESOLVE(destroy_, OakBackendDestroyFn, "oak_renderer_destroy");
|
||||||
@@ -281,8 +285,8 @@ void DynamicRenderer::DestroyNativeShader(QVariant shader)
|
|||||||
|
|
||||||
// Uploads CPU pixel data into a backend texture through the dynamic ABI.
|
// Uploads CPU pixel data into a backend texture through the dynamic ABI.
|
||||||
void DynamicRenderer::UploadToTexture(const QVariant &handle,
|
void DynamicRenderer::UploadToTexture(const QVariant &handle,
|
||||||
const VideoParams ¶ms, const void *data,
|
const VideoParams ¶ms,
|
||||||
int linesize)
|
const void *data, int linesize)
|
||||||
{
|
{
|
||||||
upload_to_texture_(handle_, &handle, ¶ms, data, linesize);
|
upload_to_texture_(handle_, &handle, ¶ms, data, linesize);
|
||||||
}
|
}
|
||||||
@@ -313,9 +317,9 @@ Color DynamicRenderer::GetPixelFromTexture(Texture *texture, const QPointF &pt)
|
|||||||
// null so callers can avoid GL-only paths.
|
// null so callers can avoid GL-only paths.
|
||||||
QOpenGLContext *DynamicRenderer::OpenGLContext() const
|
QOpenGLContext *DynamicRenderer::OpenGLContext() const
|
||||||
{
|
{
|
||||||
return opengl_context_ && handle_
|
return opengl_context_ && handle_ ?
|
||||||
? static_cast<QOpenGLContext *>(opengl_context_(handle_))
|
static_cast<QOpenGLContext *>(opengl_context_(handle_)) :
|
||||||
: nullptr;
|
nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reports the effective backend after any load-time fallback has completed.
|
// Reports the effective backend after any load-time fallback has completed.
|
||||||
@@ -340,7 +344,8 @@ void DynamicRenderer::Blit(QVariant shader, AcceleratedJob &job,
|
|||||||
|
|
||||||
// Allocates a backend-native texture and wraps its opaque handle in QVariant.
|
// Allocates a backend-native texture and wraps its opaque handle in QVariant.
|
||||||
QVariant DynamicRenderer::CreateNativeTexture(int width, int height, int depth,
|
QVariant DynamicRenderer::CreateNativeTexture(int width, int height, int depth,
|
||||||
PixelFormat format, int channel_count,
|
PixelFormat format,
|
||||||
|
int channel_count,
|
||||||
const void *data, int linesize)
|
const void *data, int linesize)
|
||||||
{
|
{
|
||||||
QVariant out;
|
QVariant out;
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ public:
|
|||||||
// Runs backend post-init setup.
|
// Runs backend post-init setup.
|
||||||
virtual void PostInit() override;
|
virtual void PostInit() override;
|
||||||
// Clears either a native texture destination or the backend output target.
|
// Clears either a native texture destination or the backend output target.
|
||||||
virtual void ClearDestination(Texture *texture = nullptr,
|
virtual void ClearDestination(Texture *texture = nullptr, double r = 0.0,
|
||||||
double r = 0.0, double g = 0.0,
|
double g = 0.0, double b = 0.0,
|
||||||
double b = 0.0, double a = 0.0) override;
|
double a = 0.0) override;
|
||||||
// Creates a native shader through the dynamic backend.
|
// Creates a native shader through the dynamic backend.
|
||||||
virtual QVariant CreateNativeShader(ShaderCode code) override;
|
virtual QVariant CreateNativeShader(ShaderCode code) override;
|
||||||
// Destroys a native shader through the dynamic backend.
|
// Destroys a native shader through the dynamic backend.
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define OAK_RENDER_BACKEND_EXPORT extern "C" __declspec(dllexport)
|
#define OAK_RENDER_BACKEND_EXPORT extern "C" __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define OAK_RENDER_BACKEND_EXPORT extern "C" __attribute__((visibility("default")))
|
#define OAK_RENDER_BACKEND_EXPORT \
|
||||||
|
extern "C" __attribute__((visibility("default")))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -69,11 +70,9 @@ typedef void (*OakBackendClearDestinationFn)(OakRenderBackendHandle handle,
|
|||||||
void *texture, double r, double g,
|
void *texture, double r, double g,
|
||||||
double b, double a);
|
double b, double a);
|
||||||
/* Creates a native texture and writes a QVariant-compatible handle. */
|
/* Creates a native texture and writes a QVariant-compatible handle. */
|
||||||
typedef void (*OakBackendCreateNativeTextureFn)(OakRenderBackendHandle handle,
|
typedef void (*OakBackendCreateNativeTextureFn)(
|
||||||
int width, int height, int depth,
|
OakRenderBackendHandle handle, int width, int height, int depth, int format,
|
||||||
int format, int channel_count,
|
int channel_count, const void *data, int linesize, void *out_variant);
|
||||||
const void *data, int linesize,
|
|
||||||
void *out_variant);
|
|
||||||
/* Destroys a native texture represented by a QVariant-compatible handle. */
|
/* Destroys a native texture represented by a QVariant-compatible handle. */
|
||||||
typedef void (*OakBackendDestroyNativeTextureFn)(OakRenderBackendHandle handle,
|
typedef void (*OakBackendDestroyNativeTextureFn)(OakRenderBackendHandle handle,
|
||||||
const void *variant);
|
const void *variant);
|
||||||
@@ -98,7 +97,8 @@ typedef void (*OakBackendDownloadFromTextureFn)(OakRenderBackendHandle handle,
|
|||||||
typedef void (*OakBackendFlushFn)(OakRenderBackendHandle handle);
|
typedef void (*OakBackendFlushFn)(OakRenderBackendHandle handle);
|
||||||
/* Reads one pixel from a texture. */
|
/* Reads one pixel from a texture. */
|
||||||
typedef void (*OakBackendGetPixelFromTextureFn)(OakRenderBackendHandle handle,
|
typedef void (*OakBackendGetPixelFromTextureFn)(OakRenderBackendHandle handle,
|
||||||
void *texture, const void *point,
|
void *texture,
|
||||||
|
const void *point,
|
||||||
void *out_color);
|
void *out_color);
|
||||||
/* Executes a shader blit job. */
|
/* Executes a shader blit job. */
|
||||||
typedef void (*OakBackendBlitFn)(OakRenderBackendHandle handle,
|
typedef void (*OakBackendBlitFn)(OakRenderBackendHandle handle,
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job,
|
|||||||
OCIO::GpuShaderDesc::TextureType channel =
|
OCIO::GpuShaderDesc::TextureType channel =
|
||||||
OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
|
OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
|
||||||
OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
|
OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
|
||||||
#if OCIO_VERSION_MAJOR > 2 || (OCIO_VERSION_MAJOR == 2 && OCIO_VERSION_MINOR >= 3)
|
#if OCIO_VERSION_MAJOR > 2 || \
|
||||||
|
(OCIO_VERSION_MAJOR == 2 && OCIO_VERSION_MINOR >= 3)
|
||||||
OCIO::GpuShaderDesc::TextureDimensions dimensions =
|
OCIO::GpuShaderDesc::TextureDimensions dimensions =
|
||||||
OCIO::GpuShaderDesc::TEXTURE_2D;
|
OCIO::GpuShaderDesc::TEXTURE_2D;
|
||||||
shader_desc->getTexture(i, tex_name, sampler_name, width, height,
|
shader_desc->getTexture(i, tex_name, sampler_name, width, height,
|
||||||
@@ -149,12 +150,14 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate 1D LUT
|
// Allocate 1D LUT
|
||||||
int lut_channels = (channel ==
|
int lut_channels =
|
||||||
OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ?
|
(channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ?
|
||||||
1 :
|
1 :
|
||||||
VideoParams::kRGBChannelCount;
|
VideoParams::kRGBChannelCount;
|
||||||
VideoParams lut_params(width, height, PixelFormat::F32, lut_channels);
|
VideoParams lut_params(width, height, PixelFormat::F32,
|
||||||
color_ctx.lut1d_textures[i].texture = CreateTexture(lut_params, values);
|
lut_channels);
|
||||||
|
color_ctx.lut1d_textures[i].texture =
|
||||||
|
CreateTexture(lut_params, values);
|
||||||
color_ctx.lut1d_textures[i].name = sampler_name;
|
color_ctx.lut1d_textures[i].name = sampler_name;
|
||||||
color_ctx.lut1d_textures[i].interpolation =
|
color_ctx.lut1d_textures[i].interpolation =
|
||||||
(interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest :
|
(interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest :
|
||||||
@@ -176,9 +179,9 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job,
|
|||||||
ShaderJob fallback_job;
|
ShaderJob fallback_job;
|
||||||
fallback_job.Insert(QStringLiteral("ove_maintex"),
|
fallback_job.Insert(QStringLiteral("ove_maintex"),
|
||||||
color_job.GetInputTexture());
|
color_job.GetInputTexture());
|
||||||
fallback_job.Insert(
|
fallback_job.Insert(QStringLiteral("ove_mvpmat"),
|
||||||
QStringLiteral("ove_mvpmat"),
|
NodeValue(NodeValue::kMatrix,
|
||||||
NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix()));
|
color_job.GetTransformMatrix()));
|
||||||
|
|
||||||
if (destination) {
|
if (destination) {
|
||||||
BlitToTexture(GetDefaultShader(), fallback_job, destination,
|
BlitToTexture(GetDefaultShader(), fallback_job, destination,
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input,
|
|||||||
} else {
|
} else {
|
||||||
auto group = OCIO::GroupTransform::Create();
|
auto group = OCIO::GroupTransform::Create();
|
||||||
|
|
||||||
const char *out_cs = OCIO::LookTransform::GetLooksResultColorSpace(
|
const char *out_cs =
|
||||||
|
OCIO::LookTransform::GetLooksResultColorSpace(
|
||||||
ocio_config, ocio_config->getCurrentContext(),
|
ocio_config, ocio_config->getCurrentContext(),
|
||||||
transform.look().toUtf8());
|
transform.look().toUtf8());
|
||||||
|
|
||||||
@@ -105,7 +106,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input,
|
|||||||
ColorProcessor::ColorProcessor(OCIO::ConstProcessorRcPtr processor)
|
ColorProcessor::ColorProcessor(OCIO::ConstProcessorRcPtr processor)
|
||||||
{
|
{
|
||||||
processor_ = processor;
|
processor_ = processor;
|
||||||
cpu_processor_ = processor_ ? processor_->getDefaultCPUProcessor() : nullptr;
|
cpu_processor_ = processor_ ? processor_->getDefaultCPUProcessor() :
|
||||||
|
nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorProcessor::ConvertFrame(Frame *f)
|
void ColorProcessor::ConvertFrame(Frame *f)
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ size_t FrameSlotPool::BytesNeeded(uint32_t slot_count, size_t slot_data_bytes)
|
|||||||
{
|
{
|
||||||
const uint32_t ring_cap = RingCapacity(slot_count);
|
const uint32_t ring_cap = RingCapacity(slot_count);
|
||||||
size_t total = AlignUp(sizeof(Header), kAlign);
|
size_t total = AlignUp(sizeof(Header), kAlign);
|
||||||
total += AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // free ring
|
total +=
|
||||||
total += AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // ready ring
|
AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // free ring
|
||||||
total += AlignUp(sizeof(FrameSlotMeta) * slot_count, kAlign); // metadata array
|
total +=
|
||||||
|
AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // ready ring
|
||||||
|
total +=
|
||||||
|
AlignUp(sizeof(FrameSlotMeta) * slot_count, kAlign); // metadata array
|
||||||
total += AlignUp(slot_data_bytes, kAlign) * slot_count; // pixel data blocks
|
total += AlignUp(slot_data_bytes, kAlign) * slot_count; // pixel data blocks
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
@@ -111,9 +114,12 @@ FrameSlotPool FrameSlotPool::Attach(void *mem)
|
|||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.free_ring_ = SpscRingBuffer::Attach(pool.base_ + pool.header_->free_ring_offset);
|
pool.free_ring_ =
|
||||||
pool.ready_ring_ = SpscRingBuffer::Attach(pool.base_ + pool.header_->ready_ring_offset);
|
SpscRingBuffer::Attach(pool.base_ + pool.header_->free_ring_offset);
|
||||||
pool.meta_ = reinterpret_cast<FrameSlotMeta *>(pool.base_ + pool.header_->meta_offset);
|
pool.ready_ring_ =
|
||||||
|
SpscRingBuffer::Attach(pool.base_ + pool.header_->ready_ring_offset);
|
||||||
|
pool.meta_ = reinterpret_cast<FrameSlotMeta *>(pool.base_ +
|
||||||
|
pool.header_->meta_offset);
|
||||||
pool.data_ = pool.base_ + pool.header_->data_offset;
|
pool.data_ = pool.base_ + pool.header_->data_offset;
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ public:
|
|||||||
* Initializes both rings, seeds the free ring with every slot index, and zeroes metadata.
|
* Initializes both rings, seeds the free ring with every slot index, and zeroes metadata.
|
||||||
* `mem` must provide at least BytesNeeded(slot_count, slot_data_bytes) bytes.
|
* `mem` must provide at least BytesNeeded(slot_count, slot_data_bytes) bytes.
|
||||||
*/
|
*/
|
||||||
static FrameSlotPool Create(void *mem, uint32_t slot_count, size_t slot_data_bytes);
|
static FrameSlotPool Create(void *mem, uint32_t slot_count,
|
||||||
|
size_t slot_data_bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map an existing, already-initialized pool (peer side).
|
* @brief Map an existing, already-initialized pool (peer side).
|
||||||
@@ -148,7 +149,6 @@ public:
|
|||||||
FrameSlotPool() = default;
|
FrameSlotPool() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t slot_count;
|
uint32_t slot_count;
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ bool ReadMessage(QByteArray *buffer, QJsonObject *out, bool *ok = nullptr);
|
|||||||
struct HandshakeMsg {
|
struct HandshakeMsg {
|
||||||
int protocol_version = 0;
|
int protocol_version = 0;
|
||||||
QString shm_key; ///< Worker->main output shared-memory segment key.
|
QString shm_key; ///< Worker->main output shared-memory segment key.
|
||||||
QString input_shm_key; ///< Main->worker input shared-memory segment key (optional).
|
QString
|
||||||
|
input_shm_key; ///< Main->worker input shared-memory segment key (optional).
|
||||||
int input_slots = 0; ///< Number of main->worker input frame slots.
|
int input_slots = 0; ///< Number of main->worker input frame slots.
|
||||||
int output_slots = 0; ///< Number of worker->main output frame slots.
|
int output_slots = 0; ///< Number of worker->main output frame slots.
|
||||||
qint64 slot_data_bytes = 0; ///< Per-output-slot pixel block size.
|
qint64 slot_data_bytes = 0; ///< Per-output-slot pixel block size.
|
||||||
@@ -104,8 +105,10 @@ struct HandshakeMsg {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RenderFrameMsg {
|
struct RenderFrameMsg {
|
||||||
qint64 ticket_id = 0; ///< Correlates this request with the eventual frame_ready.
|
qint64 ticket_id =
|
||||||
QString node_uuid; ///< Output/viewer node to render, by stable uuid in the loaded graph.
|
0; ///< Correlates this request with the eventual frame_ready.
|
||||||
|
QString
|
||||||
|
node_uuid; ///< Output/viewer node to render, by stable uuid in the loaded graph.
|
||||||
qint64 time_num = 0;
|
qint64 time_num = 0;
|
||||||
qint64 time_den = 1;
|
qint64 time_den = 1;
|
||||||
int width = 0; ///< Forced output size (0 = use graph default).
|
int width = 0; ///< Forced output size (0 = use graph default).
|
||||||
@@ -113,8 +116,10 @@ struct RenderFrameMsg {
|
|||||||
int format = -1; ///< Forced PixelFormat::Format (-1 = default/INVALID).
|
int format = -1; ///< Forced PixelFormat::Format (-1 = default/INVALID).
|
||||||
int channel_count = 0; ///< 0 = default.
|
int channel_count = 0; ///< 0 = default.
|
||||||
int mode = 0; ///< RenderMode::Mode.
|
int mode = 0; ///< RenderMode::Mode.
|
||||||
int input_slot = -1; ///< Optional main->worker decoded input slot for footage nodes.
|
int input_slot =
|
||||||
QVector<int> input_slots; ///< Optional ordered decoded input slots for footage nodes.
|
-1; ///< Optional main->worker decoded input slot for footage nodes.
|
||||||
|
QVector<int>
|
||||||
|
input_slots; ///< Optional ordered decoded input slots for footage nodes.
|
||||||
|
|
||||||
// Output color transform to apply before returning the frame. When empty,
|
// Output color transform to apply before returning the frame. When empty,
|
||||||
// the worker returns the image in the project's reference space.
|
// the worker returns the image in the project's reference space.
|
||||||
|
|||||||
@@ -75,16 +75,20 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
|
|||||||
const std::wstring wname = mapping_name.toStdWString();
|
const std::wstring wname = mapping_name.toStdWString();
|
||||||
|
|
||||||
if (mode == kCreate) {
|
if (mode == kCreate) {
|
||||||
const DWORD size_high = static_cast<DWORD>((quint64(size) >> 32) & 0xFFFFFFFF);
|
const DWORD size_high =
|
||||||
|
static_cast<DWORD>((quint64(size) >> 32) & 0xFFFFFFFF);
|
||||||
const DWORD size_low = static_cast<DWORD>(quint64(size) & 0xFFFFFFFF);
|
const DWORD size_low = static_cast<DWORD>(quint64(size) & 0xFFFFFFFF);
|
||||||
handle_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
|
handle_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
|
||||||
size_high, size_low, wname.c_str());
|
PAGE_READWRITE, size_high, size_low,
|
||||||
|
wname.c_str());
|
||||||
if (!handle_) {
|
if (!handle_) {
|
||||||
error_ = QStringLiteral("CreateFileMapping failed: %1").arg(GetLastError());
|
error_ = QStringLiteral("CreateFileMapping failed: %1")
|
||||||
|
.arg(GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||||
error_ = QStringLiteral("Shared memory key already exists: %1").arg(key);
|
error_ =
|
||||||
|
QStringLiteral("Shared memory key already exists: %1").arg(key);
|
||||||
CloseHandle(handle_);
|
CloseHandle(handle_);
|
||||||
handle_ = nullptr;
|
handle_ = nullptr;
|
||||||
return false;
|
return false;
|
||||||
@@ -92,7 +96,8 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
|
|||||||
} else {
|
} else {
|
||||||
handle_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, wname.c_str());
|
handle_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, wname.c_str());
|
||||||
if (!handle_) {
|
if (!handle_) {
|
||||||
error_ = QStringLiteral("OpenFileMapping failed: %1").arg(GetLastError());
|
error_ =
|
||||||
|
QStringLiteral("OpenFileMapping failed: %1").arg(GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,7 +170,8 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
|
|||||||
|
|
||||||
data_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
|
data_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
|
||||||
if (data_ == MAP_FAILED) {
|
if (data_ == MAP_FAILED) {
|
||||||
error_ = QStringLiteral("mmap failed: %1").arg(QString::fromUtf8(strerror(errno)));
|
error_ = QStringLiteral("mmap failed: %1")
|
||||||
|
.arg(QString::fromUtf8(strerror(errno)));
|
||||||
data_ = nullptr;
|
data_ = nullptr;
|
||||||
::close(fd_);
|
::close(fd_);
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
|
|||||||
@@ -174,7 +174,8 @@ private:
|
|||||||
std::atomic<uint32_t> tail_;
|
std::atomic<uint32_t> tail_;
|
||||||
uint32_t capacity_;
|
uint32_t capacity_;
|
||||||
|
|
||||||
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t),
|
static_assert(
|
||||||
|
sizeof(std::atomic<uint32_t>) == sizeof(uint32_t),
|
||||||
"atomic<uint32_t> must be lock-free POD-sized for shared memory use");
|
"atomic<uint32_t> must be lock-free POD-sized for shared memory use");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
#include "pluginjob.h"
|
#include "pluginjob.h"
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
namespace plugin {
|
{
|
||||||
|
namespace plugin
|
||||||
|
{
|
||||||
} // plugin
|
} // plugin
|
||||||
} // olive
|
} // olive
|
||||||
@@ -26,8 +26,10 @@
|
|||||||
#include <any>
|
#include <any>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
namespace olive {
|
namespace olive
|
||||||
namespace plugin {
|
{
|
||||||
|
namespace plugin
|
||||||
|
{
|
||||||
|
|
||||||
class PluginJob : public AcceleratedJob {
|
class PluginJob : public AcceleratedJob {
|
||||||
public:
|
public:
|
||||||
@@ -47,15 +49,18 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginNode *node() const {
|
PluginNode *node() const
|
||||||
|
{
|
||||||
return const_cast<PluginNode *>(node_);
|
return const_cast<PluginNode *>(node_);
|
||||||
}
|
}
|
||||||
|
|
||||||
OFX::Host::ImageEffect::Instance* pluginInstance() {
|
OFX::Host::ImageEffect::Instance *pluginInstance()
|
||||||
|
{
|
||||||
return const_cast<OFX::Host::ImageEffect::Instance *>(pluginInstance_);
|
return const_cast<OFX::Host::ImageEffect::Instance *>(pluginInstance_);
|
||||||
}
|
}
|
||||||
|
|
||||||
double time_seconds() const {
|
double time_seconds() const
|
||||||
|
{
|
||||||
return time_seconds_;
|
return time_seconds_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
#include "render/texture.h"
|
#include "render/texture.h"
|
||||||
#include "render/videoparams.h"
|
#include "render/videoparams.h"
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
class BackendOpenGLRenderer : public olive::OpenGLRenderer {
|
class BackendOpenGLRenderer : public olive::OpenGLRenderer {
|
||||||
public:
|
public:
|
||||||
@@ -39,29 +40,32 @@ const QVariant &VariantRef(const void *variant)
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Creates the backend object and returns it as an opaque C handle.
|
// Creates the backend object and returns it as an opaque C handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle oak_renderer_create(void *parent)
|
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle
|
||||||
|
oak_renderer_create(void *parent)
|
||||||
{
|
{
|
||||||
return new BackendOpenGLRenderer(static_cast<QObject *>(parent));
|
return new BackendOpenGLRenderer(static_cast<QObject *>(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the opaque backend object created by oak_renderer_create().
|
// Destroys the opaque backend object created by oak_renderer_create().
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handle)
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
|
oak_renderer_destroy(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
delete Renderer(handle);
|
delete Renderer(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reports static OpenGL backend capabilities to the adapter.
|
// Reports static OpenGL backend capabilities to the adapter.
|
||||||
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
|
OAK_RENDER_BACKEND_EXPORT bool
|
||||||
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
|
oak_renderer_get_info(OakRenderBackendHandle handle,
|
||||||
|
OakRenderBackendInfo *out_info)
|
||||||
{
|
{
|
||||||
if (!handle || !out_info) {
|
if (!handle || !out_info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_info->abi_version = 1;
|
out_info->abi_version = 1;
|
||||||
out_info->kind = OAK_RENDER_BACKEND_OPENGL;
|
out_info->kind = OAK_RENDER_BACKEND_OPENGL;
|
||||||
out_info->capabilities = OAK_RENDER_BACKEND_CAP_TEXTURES |
|
out_info->capabilities =
|
||||||
OAK_RENDER_BACKEND_CAP_SHADERS | OAK_RENDER_BACKEND_CAP_BLIT |
|
OAK_RENDER_BACKEND_CAP_TEXTURES | OAK_RENDER_BACKEND_CAP_SHADERS |
|
||||||
OAK_RENDER_BACKEND_CAP_READBACK |
|
OAK_RENDER_BACKEND_CAP_BLIT | OAK_RENDER_BACKEND_CAP_READBACK |
|
||||||
OAK_RENDER_BACKEND_CAP_VIEWER_CONTEXT;
|
OAK_RENDER_BACKEND_CAP_VIEWER_CONTEXT;
|
||||||
out_info->name = "opengl";
|
out_info->name = "opengl";
|
||||||
out_info->status = "available";
|
out_info->status = "available";
|
||||||
@@ -70,8 +74,8 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
|
|||||||
|
|
||||||
// OpenGL availability is context-dependent, so object creation is the minimum
|
// OpenGL availability is context-dependent, so object creation is the minimum
|
||||||
// availability signal for this backend.
|
// availability signal for this backend.
|
||||||
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
|
OAK_RENDER_BACKEND_EXPORT bool
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_is_available(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
return handle != nullptr;
|
return handle != nullptr;
|
||||||
}
|
}
|
||||||
@@ -83,35 +87,37 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_init(OakRenderBackendHandle handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the backend against a caller-owned viewer OpenGL context.
|
// Initializes the backend against a caller-owned viewer OpenGL context.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_init_with_context(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *context)
|
oak_renderer_init_with_context(OakRenderBackendHandle handle, void *context)
|
||||||
{
|
{
|
||||||
Renderer(handle)->Init(static_cast<QOpenGLContext *>(context));
|
Renderer(handle)->Init(static_cast<QOpenGLContext *>(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs renderer post-initialization once the GL context is available.
|
// Runs renderer post-initialization once the GL context is available.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_init(OakRenderBackendHandle handle)
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
|
oak_renderer_post_init(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->PostInit();
|
Renderer(handle)->PostInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases post-init OpenGL surface/context state.
|
// Releases post-init OpenGL surface/context state.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_destroy(OakRenderBackendHandle handle)
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
|
oak_renderer_post_destroy(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->PostDestroy();
|
Renderer(handle)->PostDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases renderer-owned GL resources before object destruction.
|
// Releases renderer-owned GL resources before object destruction.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_internal(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_destroy_internal(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyInternal();
|
Renderer(handle)->DestroyInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears either the widget framebuffer or a texture destination.
|
// Clears either the widget framebuffer or a texture destination.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_clear_destination(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *texture, double r, double g, double b,
|
oak_renderer_clear_destination(OakRenderBackendHandle handle, void *texture,
|
||||||
double a)
|
double r, double g, double b, double a)
|
||||||
{
|
{
|
||||||
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
|
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
|
||||||
r, g, b, a);
|
r, g, b, a);
|
||||||
@@ -122,51 +128,58 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_texture(
|
|||||||
OakRenderBackendHandle handle, int width, int height, int depth, int format,
|
OakRenderBackendHandle handle, int width, int height, int depth, int format,
|
||||||
int channel_count, const void *data, int linesize, void *out_variant)
|
int channel_count, const void *data, int linesize, void *out_variant)
|
||||||
{
|
{
|
||||||
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeTexture(
|
*static_cast<QVariant *>(out_variant) =
|
||||||
width, height, depth, static_cast<olive::PixelFormat::Format>(format),
|
Renderer(handle)->CreateNativeTexture(
|
||||||
channel_count, data, linesize);
|
width, height, depth,
|
||||||
|
static_cast<olive::PixelFormat::Format>(format), channel_count,
|
||||||
|
data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys an OpenGL texture represented by a QVariant handle.
|
// Destroys an OpenGL texture represented by a QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant)
|
oak_renderer_destroy_native_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *variant)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
|
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiles an OpenGL shader program and returns its QVariant handle.
|
// Compiles an OpenGL shader program and returns its QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_shader(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *shader_code, void *out_variant)
|
oak_renderer_create_native_shader(OakRenderBackendHandle handle,
|
||||||
|
const void *shader_code, void *out_variant)
|
||||||
{
|
{
|
||||||
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeShader(
|
*static_cast<QVariant *>(out_variant) =
|
||||||
|
Renderer(handle)->CreateNativeShader(
|
||||||
*static_cast<const olive::ShaderCode *>(shader_code));
|
*static_cast<const olive::ShaderCode *>(shader_code));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys an OpenGL shader program represented by a QVariant handle.
|
// Destroys an OpenGL shader program represented by a QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_shader(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant)
|
oak_renderer_destroy_native_shader(OakRenderBackendHandle handle,
|
||||||
|
const void *variant)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
|
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uploads CPU pixel data into an OpenGL texture.
|
// Uploads CPU pixel data into an OpenGL texture.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_upload_to_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant, const void *video_params,
|
oak_renderer_upload_to_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *variant, const void *video_params,
|
||||||
const void *data, int linesize)
|
const void *data, int linesize)
|
||||||
{
|
{
|
||||||
Renderer(handle)->UploadToTexture(
|
Renderer(handle)->UploadToTexture(
|
||||||
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
|
VariantRef(variant),
|
||||||
data, linesize);
|
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads an OpenGL texture back to CPU memory.
|
// Reads an OpenGL texture back to CPU memory.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
|
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
|
||||||
OakRenderBackendHandle handle, const void *variant, const void *video_params,
|
OakRenderBackendHandle handle, const void *variant,
|
||||||
void *data, int linesize)
|
const void *video_params, void *data, int linesize)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DownloadFromTexture(
|
Renderer(handle)->DownloadFromTexture(
|
||||||
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
|
VariantRef(variant),
|
||||||
data, linesize);
|
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flushes/waits for pending OpenGL work as required by the renderer.
|
// Flushes/waits for pending OpenGL work as required by the renderer.
|
||||||
@@ -176,18 +189,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_flush(OakRenderBackendHandle handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reads one pixel from an OpenGL texture.
|
// Reads one pixel from an OpenGL texture.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_get_pixel_from_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *texture, const void *point,
|
oak_renderer_get_pixel_from_texture(OakRenderBackendHandle handle,
|
||||||
|
void *texture, const void *point,
|
||||||
void *out_color)
|
void *out_color)
|
||||||
{
|
{
|
||||||
*static_cast<olive::Color *>(out_color) = Renderer(handle)->GetPixelFromTexture(
|
*static_cast<olive::Color *>(out_color) =
|
||||||
static_cast<olive::Texture *>(texture), *static_cast<const QPointF *>(point));
|
Renderer(handle)->GetPixelFromTexture(
|
||||||
|
static_cast<olive::Texture *>(texture),
|
||||||
|
*static_cast<const QPointF *>(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes a shader blit through the wrapped C++ OpenGL renderer.
|
// Executes a shader blit through the wrapped C++ OpenGL renderer.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
|
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(OakRenderBackendHandle handle,
|
||||||
OakRenderBackendHandle handle, const void *shader, void *job,
|
const void *shader, void *job,
|
||||||
void *destination, const void *destination_params, bool clear_destination)
|
void *destination,
|
||||||
|
const void *destination_params,
|
||||||
|
bool clear_destination)
|
||||||
{
|
{
|
||||||
Renderer(handle)->Blit(
|
Renderer(handle)->Blit(
|
||||||
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
|
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
|
||||||
@@ -197,22 +215,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exposes the wrapped OpenGL context for GL-specific integrations.
|
// Exposes the wrapped OpenGL context for GL-specific integrations.
|
||||||
OAK_RENDER_BACKEND_EXPORT void *oak_renderer_opengl_context(
|
OAK_RENDER_BACKEND_EXPORT void *
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_opengl_context(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
return Renderer(handle)->context();
|
return Renderer(handle)->context();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binds an output texture for OFX OpenGL rendering.
|
// Binds an output texture for OFX OpenGL rendering.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *texture_id)
|
oak_renderer_attach_output_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *texture_id)
|
||||||
{
|
{
|
||||||
Renderer(handle)->AttachTextureAsDestination(VariantRef(texture_id));
|
Renderer(handle)->AttachTextureAsDestination(VariantRef(texture_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detaches any OFX OpenGL output texture binding.
|
// Detaches any OFX OpenGL output texture binding.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_detach_output_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_detach_output_texture(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DetachTextureAsDestination();
|
Renderer(handle)->DetachTextureAsDestination();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,8 +265,8 @@ void OpenGLRenderer::AttachTextureAsDestination(const QVariant &texture)
|
|||||||
void OpenGLRenderer::DetachTextureAsDestination()
|
void OpenGLRenderer::DetachTextureAsDestination()
|
||||||
{
|
{
|
||||||
// QOpenGLWidget renders to a non-zero default FBO.
|
// QOpenGLWidget renders to a non-zero default FBO.
|
||||||
const GLuint default_fbo =
|
const GLuint default_fbo = context_ ? context_->defaultFramebufferObject() :
|
||||||
context_ ? context_->defaultFramebufferObject() : 0;
|
0;
|
||||||
functions_->glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
|
functions_->glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,8 +504,8 @@ struct TextureToBind {
|
|||||||
Texture::Interpolation interpolation;
|
Texture::Interpolation interpolation;
|
||||||
};
|
};
|
||||||
|
|
||||||
void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destination,
|
void OpenGLRenderer::Blit(QVariant s, AcceleratedJob &a_job,
|
||||||
VideoParams destination_params,
|
Texture *destination, VideoParams destination_params,
|
||||||
bool clear_destination)
|
bool clear_destination)
|
||||||
{
|
{
|
||||||
GL_PREAMBLE;
|
GL_PREAMBLE;
|
||||||
@@ -585,7 +585,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
case NodeValue::kColor: {
|
case NodeValue::kColor: {
|
||||||
Color color = value.toColor();
|
Color color = value.toColor();
|
||||||
functions_->glUniform4f(variable_location, color.red(),
|
functions_->glUniform4f(variable_location, color.red(),
|
||||||
color.green(), color.blue(), color.alpha());
|
color.green(), color.blue(),
|
||||||
|
color.alpha());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeValue::kBoolean:
|
case NodeValue::kBoolean:
|
||||||
@@ -595,7 +596,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
TexturePtr texture = value.toTexture();
|
TexturePtr texture = value.toTexture();
|
||||||
|
|
||||||
// Set value to bound texture
|
// Set value to bound texture
|
||||||
functions_->glUniform1i(variable_location, textures_to_bind.size());
|
functions_->glUniform1i(variable_location,
|
||||||
|
textures_to_bind.size());
|
||||||
|
|
||||||
texture_index_map.insert(it.key(), textures_to_bind.size());
|
texture_index_map.insert(it.key(), textures_to_bind.size());
|
||||||
|
|
||||||
@@ -605,8 +607,10 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
// Set enable flag if shader wants it
|
// Set enable flag if shader wants it
|
||||||
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
|
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
|
||||||
int enable_param_location = functions_->glGetUniformLocation(
|
int enable_param_location = functions_->glGetUniformLocation(
|
||||||
shader,
|
shader, QStringLiteral("%1_enabled")
|
||||||
QStringLiteral("%1_enabled").arg(it.key()).toUtf8().constData());
|
.arg(it.key())
|
||||||
|
.toUtf8()
|
||||||
|
.constData());
|
||||||
if (enable_param_location > -1) {
|
if (enable_param_location > -1) {
|
||||||
functions_->glUniform1i(enable_param_location, tex_id > 0);
|
functions_->glUniform1i(enable_param_location, tex_id > 0);
|
||||||
}
|
}
|
||||||
@@ -637,7 +641,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
|
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
|
||||||
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D :
|
GLenum target = (texture && texture->params().is_3d()) ?
|
||||||
|
GL_TEXTURE_3D :
|
||||||
GL_TEXTURE_2D;
|
GL_TEXTURE_2D;
|
||||||
functions_->glBindTexture(target, tex_id);
|
functions_->glBindTexture(target, tex_id);
|
||||||
|
|
||||||
@@ -647,12 +652,12 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
if (texture->channel_count() == 1 &&
|
if (texture->channel_count() == 1 &&
|
||||||
destination_params.channel_count() != 1) {
|
destination_params.channel_count() != 1) {
|
||||||
// Interpret this texture as a grayscale texture
|
// Interpret this texture as a grayscale texture
|
||||||
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R,
|
functions_->glTexParameteri(GL_TEXTURE_2D,
|
||||||
GL_RED);
|
GL_TEXTURE_SWIZZLE_R, GL_RED);
|
||||||
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G,
|
functions_->glTexParameteri(GL_TEXTURE_2D,
|
||||||
GL_RED);
|
GL_TEXTURE_SWIZZLE_G, GL_RED);
|
||||||
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B,
|
functions_->glTexParameteri(GL_TEXTURE_2D,
|
||||||
GL_RED);
|
GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -683,7 +688,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
if (!job.GetVertexCoordinates().isEmpty()) {
|
if (!job.GetVertexCoordinates().isEmpty()) {
|
||||||
Q_ASSERT(job.GetVertexCoordinates().size() == 18);
|
Q_ASSERT(job.GetVertexCoordinates().size() == 18);
|
||||||
vert_vbo_.allocate(job.GetVertexCoordinates().constData(),
|
vert_vbo_.allocate(job.GetVertexCoordinates().constData(),
|
||||||
job.GetVertexCoordinates().size() * sizeof(float));
|
job.GetVertexCoordinates().size() *
|
||||||
|
sizeof(float));
|
||||||
} else {
|
} else {
|
||||||
vert_vbo_.allocate(blit_vertices.constData(),
|
vert_vbo_.allocate(blit_vertices.constData(),
|
||||||
blit_vertices.size() * sizeof(GLfloat));
|
blit_vertices.size() * sizeof(GLfloat));
|
||||||
@@ -707,12 +713,13 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
vert_vbo_.release();
|
vert_vbo_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint tex_location = functions_->glGetAttribLocation(shader, "a_texcoord");
|
GLint tex_location =
|
||||||
|
functions_->glGetAttribLocation(shader, "a_texcoord");
|
||||||
if (tex_location != -1) {
|
if (tex_location != -1) {
|
||||||
frag_vbo_.bind();
|
frag_vbo_.bind();
|
||||||
functions_->glEnableVertexAttribArray(tex_location);
|
functions_->glEnableVertexAttribArray(tex_location);
|
||||||
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE,
|
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT,
|
||||||
0, nullptr);
|
GL_FALSE, 0, nullptr);
|
||||||
frag_vbo_.release();
|
frag_vbo_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,9 +795,9 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
// Blit this texture through this shader
|
// Blit this texture through this shader
|
||||||
{
|
{
|
||||||
PRINT_GL_ERRORS;
|
PRINT_GL_ERRORS;
|
||||||
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
|
functions_->glDrawArrays(GL_TRIANGLES, 0,
|
||||||
|
blit_vertices.size() / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination) {
|
if (destination) {
|
||||||
@@ -801,7 +808,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
// Release any textures we bound before
|
// Release any textures we bound before
|
||||||
for (int i = textures_to_bind.size() - 1; i >= 0; i--) {
|
for (int i = textures_to_bind.size() - 1; i >= 0; i--) {
|
||||||
TexturePtr texture = textures_to_bind.at(i).texture;
|
TexturePtr texture = textures_to_bind.at(i).texture;
|
||||||
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D :
|
GLenum target = (texture && texture->params().is_3d()) ?
|
||||||
|
GL_TEXTURE_3D :
|
||||||
GL_TEXTURE_2D;
|
GL_TEXTURE_2D;
|
||||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||||
functions_->glBindTexture(target, 0);
|
functions_->glBindTexture(target, 0);
|
||||||
@@ -815,9 +823,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
|
|||||||
vert_vbo_.destroy();
|
vert_vbo_.destroy();
|
||||||
vao_.release();
|
vao_.release();
|
||||||
vao_.destroy();
|
vao_.destroy();
|
||||||
|
} catch (std::bad_cast e) {
|
||||||
}
|
}
|
||||||
catch (std::bad_cast e){}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint OpenGLRenderer::GetInternalFormat(PixelFormat format, int channel_layout)
|
GLint OpenGLRenderer::GetInternalFormat(PixelFormat format, int channel_layout)
|
||||||
@@ -965,11 +972,11 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
|
|||||||
const int major = context_ ? context_->format().majorVersion() : 0;
|
const int major = context_ ? context_->format().majorVersion() : 0;
|
||||||
const int minor = context_ ? context_->format().minorVersion() : 0;
|
const int minor = context_ ? context_->format().minorVersion() : 0;
|
||||||
const bool is_gles2 = is_gles && (major < 3);
|
const bool is_gles2 = is_gles && (major < 3);
|
||||||
const QString gles_preamble = is_gles2
|
const QString gles_preamble =
|
||||||
? QStringLiteral("#version 100\n\n"
|
is_gles2 ? QStringLiteral("#version 100\n\n"
|
||||||
"precision highp float;\n\n"
|
"precision highp float;\n\n"
|
||||||
"#define frag_color gl_FragColor\n")
|
"#define frag_color gl_FragColor\n") :
|
||||||
: QStringLiteral("#version 300 es\n\n"
|
QStringLiteral("#version 300 es\n\n"
|
||||||
"precision highp float;\n\n");
|
"precision highp float;\n\n");
|
||||||
const QString desktop_preamble =
|
const QString desktop_preamble =
|
||||||
// Use appropriate GL 3.2 shader header
|
// Use appropriate GL 3.2 shader header
|
||||||
@@ -991,7 +998,8 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
|
|||||||
|
|
||||||
QString complete_code;
|
QString complete_code;
|
||||||
if (base_code.startsWith(QStringLiteral("#version"))) {
|
if (base_code.startsWith(QStringLiteral("#version"))) {
|
||||||
if (is_gles || !desktop_preamble.startsWith(QStringLiteral("#version"))) {
|
if (is_gles ||
|
||||||
|
!desktop_preamble.startsWith(QStringLiteral("#version"))) {
|
||||||
int newline = base_code.indexOf('\n');
|
int newline = base_code.indexOf('\n');
|
||||||
if (newline >= 0) {
|
if (newline >= 0) {
|
||||||
complete_code = shader_preamble + base_code.mid(newline + 1);
|
complete_code = shader_preamble + base_code.mid(newline + 1);
|
||||||
@@ -1007,17 +1015,21 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
|
|||||||
|
|
||||||
if (is_gles2) {
|
if (is_gles2) {
|
||||||
if (type == GL_VERTEX_SHADER) {
|
if (type == GL_VERTEX_SHADER) {
|
||||||
complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")),
|
complete_code.replace(
|
||||||
|
QRegularExpression(QStringLiteral("\\bin\\b")),
|
||||||
QStringLiteral("attribute"));
|
QStringLiteral("attribute"));
|
||||||
complete_code.replace(QRegularExpression(QStringLiteral("\\bout\\b")),
|
complete_code.replace(
|
||||||
|
QRegularExpression(QStringLiteral("\\bout\\b")),
|
||||||
QStringLiteral("varying"));
|
QStringLiteral("varying"));
|
||||||
} else if (type == GL_FRAGMENT_SHADER) {
|
} else if (type == GL_FRAGMENT_SHADER) {
|
||||||
complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")),
|
complete_code.replace(
|
||||||
|
QRegularExpression(QStringLiteral("\\bin\\b")),
|
||||||
QStringLiteral("varying"));
|
QStringLiteral("varying"));
|
||||||
complete_code.replace(QRegularExpression(
|
complete_code.replace(QRegularExpression(QStringLiteral(
|
||||||
QStringLiteral("\\bout\\s+vec4\\s+frag_color\\s*;")),
|
"\\bout\\s+vec4\\s+frag_color\\s*;")),
|
||||||
QStringLiteral("// frag_color output"));
|
QStringLiteral("// frag_color output"));
|
||||||
complete_code.replace(QRegularExpression(QStringLiteral("\\btexture\\b")),
|
complete_code.replace(
|
||||||
|
QRegularExpression(QStringLiteral("\\btexture\\b")),
|
||||||
QStringLiteral("texture2D"));
|
QStringLiteral("texture2D"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1070,8 @@ bool OpenGLRenderer::EnsureContextCurrent(const char *caller)
|
|||||||
// paint code can receive textures produced by a render-thread OpenGL
|
// paint code can receive textures produced by a render-thread OpenGL
|
||||||
// renderer, so guard here before makeCurrent() can crash inside Qt/GL.
|
// renderer, so guard here before makeCurrent() can crash inside Qt/GL.
|
||||||
if (context_->thread() != QThread::currentThread()) {
|
if (context_->thread() != QThread::currentThread()) {
|
||||||
qWarning() << caller << "called from the wrong thread for this OpenGL context";
|
qWarning()
|
||||||
|
<< caller << "called from the wrong thread for this OpenGL context";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -31,8 +31,10 @@
|
|||||||
|
|
||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
namespace plugin{
|
namespace plugin
|
||||||
namespace detail {
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
// 作用:将字节行跨度转换为像素跨度,便于纹理读写。
|
// 作用:将字节行跨度转换为像素跨度,便于纹理读写。
|
||||||
// Purpose: Convert byte stride to pixel stride for texture I/O.
|
// Purpose: Convert byte stride to pixel stride for texture I/O.
|
||||||
int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms);
|
int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms);
|
||||||
@@ -46,9 +48,15 @@ int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms);
|
|||||||
class PluginRenderer : public QObject {
|
class PluginRenderer : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PluginRenderer(olive::Renderer *renderer, QObject *parent = nullptr)
|
explicit PluginRenderer(olive::Renderer *renderer,
|
||||||
: QObject(parent), renderer_(renderer) {}
|
QObject *parent = nullptr)
|
||||||
virtual ~PluginRenderer() override {}
|
: QObject(parent)
|
||||||
|
, renderer_(renderer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~PluginRenderer() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
olive::Renderer *renderer() const
|
olive::Renderer *renderer() const
|
||||||
{
|
{
|
||||||
@@ -74,6 +82,4 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //PLUGINRENDERER_H
|
#endif //PLUGINRENDERER_H
|
||||||
|
|||||||
@@ -561,7 +561,8 @@ void PreviewAutoCacher::TryRender()
|
|||||||
video_immediate_passthroughs_[watcher].append(t);
|
video_immediate_passthroughs_[watcher].append(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to find copied node for SFR ticket, requeueing";
|
qWarning()
|
||||||
|
<< "Failed to find copied node for SFR ticket, requeueing";
|
||||||
single_frame_render_ = t;
|
single_frame_render_ = t;
|
||||||
if (!delayed_requeue_timer_.isActive()) {
|
if (!delayed_requeue_timer_.isActive()) {
|
||||||
delayed_requeue_timer_.start();
|
delayed_requeue_timer_.start();
|
||||||
@@ -594,7 +595,8 @@ void PreviewAutoCacher::TryRender()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to find node copy for video job, retrying";
|
qWarning()
|
||||||
|
<< "Failed to find node copy for video job, retrying";
|
||||||
if (!delayed_requeue_timer_.isActive()) {
|
if (!delayed_requeue_timer_.isActive()) {
|
||||||
delayed_requeue_timer_.start();
|
delayed_requeue_timer_.start();
|
||||||
}
|
}
|
||||||
@@ -636,7 +638,8 @@ void PreviewAutoCacher::TryRender()
|
|||||||
|
|
||||||
RenderAudio(copy, d.context, use_range, d.cache);
|
RenderAudio(copy, d.context, use_range, d.cache);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to find node copy for audio job, retrying";
|
qWarning()
|
||||||
|
<< "Failed to find node copy for audio job, retrying";
|
||||||
pop = false;
|
pop = false;
|
||||||
if (!delayed_requeue_timer_.isActive()) {
|
if (!delayed_requeue_timer_.isActive()) {
|
||||||
delayed_requeue_timer_.start();
|
delayed_requeue_timer_.start();
|
||||||
|
|||||||
@@ -265,7 +265,9 @@ void ProjectCopier::InsertIntoCopyMap(Node *node, Node *copy)
|
|||||||
if (Footage *src_footage = dynamic_cast<Footage *>(node)) {
|
if (Footage *src_footage = dynamic_cast<Footage *>(node)) {
|
||||||
if (dynamic_cast<Footage *>(copy)) {
|
if (dynamic_cast<Footage *>(copy)) {
|
||||||
connect(src_footage, &Footage::ProxySettingsChanged, this,
|
connect(src_footage, &Footage::ProxySettingsChanged, this,
|
||||||
[this, src_footage]() { SyncFootageProxySettings(src_footage); });
|
[this, src_footage]() {
|
||||||
|
SyncFootageProxySettings(src_footage);
|
||||||
|
});
|
||||||
SyncFootageProxySettings(src_footage);
|
SyncFootageProxySettings(src_footage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,10 +285,11 @@ void ProjectCopier::SyncFootageProxySettings(Footage *source)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "ProjectCopier::SyncFootageProxySettings:" << source->filename()
|
qDebug()
|
||||||
|
<< "ProjectCopier::SyncFootageProxySettings:" << source->filename()
|
||||||
<< "enabled=" << source->proxy_enabled() << "->"
|
<< "enabled=" << source->proxy_enabled() << "->"
|
||||||
<< copy->proxy_enabled() << "state="
|
<< copy->proxy_enabled()
|
||||||
<< ProxyManager::ProxyStateToString(source->proxy_state());
|
<< "state=" << ProxyManager::ProxyStateToString(source->proxy_state());
|
||||||
|
|
||||||
copy->SetProxy(source->proxy_path(), source->proxy_state(),
|
copy->SetProxy(source->proxy_path(), source->proxy_state(),
|
||||||
source->proxy_video_stream_index(),
|
source->proxy_video_stream_index(),
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
// Forward declarations to keep the render core header lightweight
|
// Forward declarations to keep the render core header lightweight
|
||||||
namespace olive {
|
namespace olive
|
||||||
|
{
|
||||||
class ColorTransformJob;
|
class ColorTransformJob;
|
||||||
class Node;
|
class Node;
|
||||||
}
|
}
|
||||||
@@ -63,11 +64,10 @@ public:
|
|||||||
{
|
{
|
||||||
Blit(shader, job, destination, destination->params(),
|
Blit(shader, job, destination, destination->params(),
|
||||||
clear_destination);
|
clear_destination);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blit(QVariant shader, olive::AcceleratedJob& job, olive::VideoParams params,
|
void Blit(QVariant shader, olive::AcceleratedJob &job,
|
||||||
bool clear_destination = true)
|
olive::VideoParams params, bool clear_destination = true)
|
||||||
{
|
{
|
||||||
Blit(shader, job, nullptr, params, clear_destination);
|
Blit(shader, job, nullptr, params, clear_destination);
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,9 @@ public:
|
|||||||
*
|
*
|
||||||
* Default implementation is a no-op.
|
* Default implementation is a no-op.
|
||||||
*/
|
*/
|
||||||
virtual void DetachOutputTexture() {}
|
virtual void DetachOutputTexture()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
|
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
|
||||||
|
|||||||
@@ -78,24 +78,26 @@ QString RenderManager::BackendToString(Backend backend)
|
|||||||
}
|
}
|
||||||
|
|
||||||
RenderManager::RenderManager(QObject *parent)
|
RenderManager::RenderManager(QObject *parent)
|
||||||
: backend_(BackendFromString(
|
: backend_(BackendFromString(OLIVE_CONFIG("GraphicsBackend").toString()))
|
||||||
OLIVE_CONFIG("GraphicsBackend").toString()))
|
|
||||||
, requested_backend_(backend_)
|
, requested_backend_(backend_)
|
||||||
, aggressive_gc_(0)
|
, aggressive_gc_(0)
|
||||||
, worker_pool_(nullptr)
|
, worker_pool_(nullptr)
|
||||||
{
|
{
|
||||||
if (backend_ == kVulkan) {
|
if (backend_ == kVulkan) {
|
||||||
#ifndef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
#ifndef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
||||||
qWarning() << "Vulkan backend requested but dynamic render backend is not enabled. Falling back to OpenGL.";
|
qWarning()
|
||||||
|
<< "Vulkan backend requested but dynamic render backend is not enabled. Falling back to OpenGL.";
|
||||||
backend_ = kOpenGL;
|
backend_ = kOpenGL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend_ == kOpenGL || backend_ == kVulkan) {
|
if (backend_ == kOpenGL || backend_ == kVulkan) {
|
||||||
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
||||||
auto *dynamic_renderer = new DynamicRenderer(BackendToString(requested_backend_));
|
auto *dynamic_renderer =
|
||||||
|
new DynamicRenderer(BackendToString(requested_backend_));
|
||||||
if (!dynamic_renderer->Load()) {
|
if (!dynamic_renderer->Load()) {
|
||||||
qWarning() << "Failed to load dynamic render backend" << BackendToString(requested_backend_)
|
qWarning() << "Failed to load dynamic render backend"
|
||||||
|
<< BackendToString(requested_backend_)
|
||||||
<< ", falling back to OpenGL";
|
<< ", falling back to OpenGL";
|
||||||
delete dynamic_renderer;
|
delete dynamic_renderer;
|
||||||
backend_ = kOpenGL;
|
backend_ = kOpenGL;
|
||||||
@@ -104,7 +106,8 @@ RenderManager::RenderManager(QObject *parent)
|
|||||||
context_ = dynamic_renderer;
|
context_ = dynamic_renderer;
|
||||||
// DynamicRenderer may internally fall back (e.g. Vulkan -> OpenGL).
|
// DynamicRenderer may internally fall back (e.g. Vulkan -> OpenGL).
|
||||||
// Synchronize RenderManager's view of the actual runtime backend.
|
// Synchronize RenderManager's view of the actual runtime backend.
|
||||||
Backend actual_backend = BackendFromString(dynamic_renderer->backend_name());
|
Backend actual_backend =
|
||||||
|
BackendFromString(dynamic_renderer->backend_name());
|
||||||
if (actual_backend != backend_) {
|
if (actual_backend != backend_) {
|
||||||
qWarning() << "Dynamic render backend fell back from"
|
qWarning() << "Dynamic render backend fell back from"
|
||||||
<< BackendToString(backend_) << "to"
|
<< BackendToString(backend_) << "to"
|
||||||
@@ -218,10 +221,12 @@ RenderTicketPtr RenderManager::RenderFrame(const RenderVideoParams ¶ms)
|
|||||||
|
|
||||||
if (worker_params.return_type == ReturnType::kNull) {
|
if (worker_params.return_type == ReturnType::kNull) {
|
||||||
dry_run_thread_->AddTicket(ticket);
|
dry_run_thread_->AddTicket(ticket);
|
||||||
} else if (worker_pool_ && worker_pool_->SubmitFrame(ticket, worker_params)) {
|
} else if (worker_pool_ &&
|
||||||
|
worker_pool_->SubmitFrame(ticket, worker_params)) {
|
||||||
return ticket;
|
return ticket;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "RenderManager: worker pool unavailable, finishing ticket "
|
qWarning()
|
||||||
|
<< "RenderManager: worker pool unavailable, finishing ticket "
|
||||||
"without result";
|
"without result";
|
||||||
ticket->Finish();
|
ticket->Finish();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QVector4D>
|
#include <QVector4D>
|
||||||
|
|
||||||
|
|
||||||
#include "audio/audioprocessor.h"
|
#include "audio/audioprocessor.h"
|
||||||
#include "node/block/clip/clip.h"
|
#include "node/block/clip/clip.h"
|
||||||
#include "node/block/transition/transition.h"
|
#include "node/block/transition/transition.h"
|
||||||
@@ -159,7 +158,6 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture,
|
|||||||
QString::fromUtf8(output_color_transform->id()));
|
QString::fromUtf8(output_color_transform->id()));
|
||||||
frame->set_video_params(display_params);
|
frame->set_video_params(display_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
@@ -416,7 +414,8 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (using_colorspace.isEmpty()) {
|
if (using_colorspace.isEmpty()) {
|
||||||
qWarning() << "RenderProcessor ProcessVideoFootage: no input colorspace available";
|
qWarning()
|
||||||
|
<< "RenderProcessor ProcessVideoFootage: no input colorspace available";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto blit_color_managed = [&](const TexturePtr &unmanaged_texture,
|
auto blit_color_managed = [&](const TexturePtr &unmanaged_texture,
|
||||||
@@ -427,8 +426,8 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
|
|
||||||
// We convert to our rendering pixel format, since that will always be float-based which
|
// We convert to our rendering pixel format, since that will always be float-based which
|
||||||
// is necessary for correct color conversion
|
// is necessary for correct color conversion
|
||||||
ColorProcessorPtr processor = ColorProcessor::Create(
|
ColorProcessorPtr processor =
|
||||||
color_manager, using_colorspace,
|
ColorProcessor::Create(color_manager, using_colorspace,
|
||||||
color_manager->GetReferenceColorSpace());
|
color_manager->GetReferenceColorSpace());
|
||||||
|
|
||||||
ColorTransformJob job;
|
ColorTransformJob job;
|
||||||
@@ -436,7 +435,8 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
job.SetInputTexture(unmanaged_texture);
|
job.SetInputTexture(unmanaged_texture);
|
||||||
|
|
||||||
if (texture_params.channel_count() != VideoParams::kRGBAChannelCount ||
|
if (texture_params.channel_count() != VideoParams::kRGBAChannelCount ||
|
||||||
texture_params.colorspace() == color_manager->GetReferenceColorSpace()) {
|
texture_params.colorspace() ==
|
||||||
|
color_manager->GetReferenceColorSpace()) {
|
||||||
job.SetInputAlphaAssociation(kAlphaNone);
|
job.SetInputAlphaAssociation(kAlphaNone);
|
||||||
} else if (texture_params.premultiplied_alpha()) {
|
} else if (texture_params.premultiplied_alpha()) {
|
||||||
job.SetInputAlphaAssociation(kAlphaAssociated);
|
job.SetInputAlphaAssociation(kAlphaAssociated);
|
||||||
@@ -450,12 +450,14 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
render_ctx_->Flush();
|
render_ctx_->Flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto *input_pool =
|
auto *input_pool = QtUtils::ValueToPtr<ipc::FrameSlotPool>(
|
||||||
QtUtils::ValueToPtr<ipc::FrameSlotPool>(ticket_->property("ipc_input_pool"));
|
ticket_->property("ipc_input_pool"));
|
||||||
int input_slot = -1;
|
int input_slot = -1;
|
||||||
const QVariantList input_slots = ticket_->property("ipc_input_slots").toList();
|
const QVariantList input_slots =
|
||||||
|
ticket_->property("ipc_input_slots").toList();
|
||||||
if (!input_slots.isEmpty()) {
|
if (!input_slots.isEmpty()) {
|
||||||
const QVariant cursor_value = ticket_->property("ipc_input_slot_cursor");
|
const QVariant cursor_value =
|
||||||
|
ticket_->property("ipc_input_slot_cursor");
|
||||||
const int cursor = cursor_value.isValid() ? cursor_value.toInt() : 0;
|
const int cursor = cursor_value.isValid() ? cursor_value.toInt() : 0;
|
||||||
if (cursor >= 0 && cursor < input_slots.size()) {
|
if (cursor >= 0 && cursor < input_slots.size()) {
|
||||||
input_slot = input_slots.at(cursor).toInt();
|
input_slot = input_slots.at(cursor).toInt();
|
||||||
@@ -467,13 +469,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
}
|
}
|
||||||
if (render_ctx_ && input_pool && input_slot >= 0) {
|
if (render_ctx_ && input_pool && input_slot >= 0) {
|
||||||
if (input_slot >= int(input_pool->slot_count())) {
|
if (input_slot >= int(input_pool->slot_count())) {
|
||||||
qWarning() << "RenderProcessor received out-of-range IPC input frame slot"
|
qWarning()
|
||||||
|
<< "RenderProcessor received out-of-range IPC input frame slot"
|
||||||
<< input_slot;
|
<< input_slot;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipc::FrameSlotMeta *meta = input_pool->Meta(uint32_t(input_slot));
|
const ipc::FrameSlotMeta *meta = input_pool->Meta(uint32_t(input_slot));
|
||||||
if (meta && meta->width > 0 && meta->height > 0 && meta->data_size > 0 &&
|
if (meta && meta->width > 0 && meta->height > 0 &&
|
||||||
|
meta->data_size > 0 &&
|
||||||
meta->data_size <= int(input_pool->slot_data_bytes())) {
|
meta->data_size <= int(input_pool->slot_data_bytes())) {
|
||||||
VideoParams input_params = stream_data;
|
VideoParams input_params = stream_data;
|
||||||
input_params.set_width(meta->width);
|
input_params.set_width(meta->width);
|
||||||
@@ -486,7 +490,6 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
input_params.set_depth(1);
|
input_params.set_depth(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prefer the colorspace that the main process used when decoding this
|
// Prefer the colorspace that the main process used when decoding this
|
||||||
// frame. The FootageJob reconstructed in the worker may have stale or
|
// frame. The FootageJob reconstructed in the worker may have stale or
|
||||||
// empty colorspace if the project snapshot was saved before stream
|
// empty colorspace if the project snapshot was saved before stream
|
||||||
@@ -498,9 +501,9 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int bytes_per_pixel = input_params.GetBytesPerPixel();
|
const int bytes_per_pixel = input_params.GetBytesPerPixel();
|
||||||
const int linesize_pixels = bytes_per_pixel > 0
|
const int linesize_pixels = bytes_per_pixel > 0 ?
|
||||||
? meta->linesize / bytes_per_pixel
|
meta->linesize / bytes_per_pixel :
|
||||||
: input_params.effective_width();
|
input_params.effective_width();
|
||||||
|
|
||||||
const void *slot_data = input_pool->SlotData(uint32_t(input_slot));
|
const void *slot_data = input_pool->SlotData(uint32_t(input_slot));
|
||||||
TexturePtr unmanaged_texture = render_ctx_->CreateTexture(
|
TexturePtr unmanaged_texture = render_ctx_->CreateTexture(
|
||||||
@@ -509,12 +512,14 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
blit_color_managed(unmanaged_texture, input_params);
|
blit_color_managed(unmanaged_texture, input_params);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qWarning() << "RenderProcessor received invalid IPC input frame slot" << input_slot;
|
qWarning() << "RenderProcessor received invalid IPC input frame slot"
|
||||||
|
<< input_slot;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decoder_cache_) {
|
if (!decoder_cache_) {
|
||||||
qWarning() << "RenderProcessor has no decoder cache or IPC input frame for"
|
qWarning()
|
||||||
|
<< "RenderProcessor has no decoder cache or IPC input frame for"
|
||||||
<< stream->filename();
|
<< stream->filename();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -523,15 +528,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
static_cast<RenderMode::Mode>(ticket_->property("mode").toInt()) ==
|
static_cast<RenderMode::Mode>(ticket_->property("mode").toInt()) ==
|
||||||
RenderMode::kOffline &&
|
RenderMode::kOffline &&
|
||||||
stream->has_proxy() && QFileInfo::exists(stream->proxy_filename());
|
stream->has_proxy() && QFileInfo::exists(stream->proxy_filename());
|
||||||
const QString decode_filename =
|
const QString decode_filename = use_proxy ? stream->proxy_filename() :
|
||||||
use_proxy ? stream->proxy_filename() : stream->filename();
|
stream->filename();
|
||||||
const QString decoder_id =
|
const QString decoder_id = use_proxy ? stream->proxy_decoder() :
|
||||||
use_proxy ? stream->proxy_decoder() : stream->decoder();
|
stream->decoder();
|
||||||
const int stream_index =
|
const int stream_index = use_proxy ? stream->proxy_stream_index() :
|
||||||
use_proxy ? stream->proxy_stream_index() : stream_data.stream_index();
|
stream_data.stream_index();
|
||||||
|
|
||||||
Decoder::CodecStream default_codec_stream(
|
Decoder::CodecStream default_codec_stream(decode_filename, stream_index,
|
||||||
decode_filename, stream_index, GetCurrentBlock());
|
GetCurrentBlock());
|
||||||
|
|
||||||
DecoderPtr decoder = nullptr;
|
DecoderPtr decoder = nullptr;
|
||||||
|
|
||||||
@@ -553,8 +558,8 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
|
|||||||
decode_filename, frame_number);
|
decode_filename, frame_number);
|
||||||
|
|
||||||
// Decoder will close automatically since it's a stream_ptr
|
// Decoder will close automatically since it's a stream_ptr
|
||||||
decoder->Open(Decoder::CodecStream(
|
decoder->Open(Decoder::CodecStream(frame_filename, stream_index,
|
||||||
frame_filename, stream_index, GetCurrentBlock()));
|
GetCurrentBlock()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -643,7 +648,8 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node,
|
|||||||
locker.unlock();
|
locker.unlock();
|
||||||
|
|
||||||
// Run shader
|
// Run shader
|
||||||
render_ctx_->BlitToTexture(shader, const_cast<ShaderJob&>(*job), destination.get());
|
render_ctx_->BlitToTexture(shader, const_cast<ShaderJob &>(*job),
|
||||||
|
destination.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderProcessor::ProcessSamples(SampleBuffer &destination,
|
void RenderProcessor::ProcessSamples(SampleBuffer &destination,
|
||||||
@@ -720,8 +726,7 @@ TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
|
|||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *plugin_job =
|
auto *plugin_job = dynamic_cast<plugin::PluginJob *>(texture->job());
|
||||||
dynamic_cast<plugin::PluginJob *>(texture->job());
|
|
||||||
if (!plugin_job) {
|
if (!plugin_job) {
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
@@ -779,13 +784,8 @@ TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin_renderer.RenderPlugin(
|
plugin_renderer.RenderPlugin(src, *plugin_job, destination,
|
||||||
src,
|
destination->params(), true, false);
|
||||||
*plugin_job,
|
|
||||||
destination,
|
|
||||||
destination->params(),
|
|
||||||
true,
|
|
||||||
false);
|
|
||||||
|
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
@@ -797,7 +797,8 @@ TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val)
|
|||||||
// Auto-detect and discard black/empty cached frames (macOS TBDR artifact)
|
// Auto-detect and discard black/empty cached frames (macOS TBDR artifact)
|
||||||
bool all_black = true;
|
bool all_black = true;
|
||||||
if (frame->data() && frame->allocated_size() > 0) {
|
if (frame->data() && frame->allocated_size() > 0) {
|
||||||
const uint8_t *pixels = reinterpret_cast<const uint8_t *>(frame->data());
|
const uint8_t *pixels =
|
||||||
|
reinterpret_cast<const uint8_t *>(frame->data());
|
||||||
size_t alloc_size = static_cast<size_t>(frame->allocated_size());
|
size_t alloc_size = static_cast<size_t>(frame->allocated_size());
|
||||||
size_t check_bytes = std::min(alloc_size, size_t(4096));
|
size_t check_bytes = std::min(alloc_size, size_t(4096));
|
||||||
for (size_t i = 0; i < check_bytes; ++i) {
|
for (size_t i = 0; i < check_bytes; ++i) {
|
||||||
@@ -808,7 +809,8 @@ TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (all_black) {
|
if (all_black) {
|
||||||
qWarning() << "[CACHE] Discarding black cached frame:" << val->GetFilename()
|
qWarning() << "[CACHE] Discarding black cached frame:"
|
||||||
|
<< val->GetFilename()
|
||||||
<< "time=" << frame->timestamp().toDouble()
|
<< "time=" << frame->timestamp().toDouble()
|
||||||
<< "size=" << frame->allocated_size();
|
<< "size=" << frame->allocated_size();
|
||||||
QFile::remove(val->GetFilename());
|
QFile::remove(val->GetFilename());
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace plugin {
|
namespace plugin
|
||||||
|
{
|
||||||
class PluginRenderer;
|
class PluginRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+129
-119
@@ -62,8 +62,8 @@ struct FootageInput {
|
|||||||
|
|
||||||
class FootageInputCollector : public NodeTraverser {
|
class FootageInputCollector : public NodeTraverser {
|
||||||
public:
|
public:
|
||||||
QVector<FootageInput> Collect(const RenderManager::RenderVideoParams ¶ms,
|
QVector<FootageInput>
|
||||||
CancelAtom *cancel)
|
Collect(const RenderManager::RenderVideoParams ¶ms, CancelAtom *cancel)
|
||||||
{
|
{
|
||||||
SetCancelPointer(cancel);
|
SetCancelPointer(cancel);
|
||||||
VideoParams cache_params = params.video_params;
|
VideoParams cache_params = params.video_params;
|
||||||
@@ -75,16 +75,14 @@ public:
|
|||||||
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
|
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
|
||||||
frame_length /= 2;
|
frame_length /= 2;
|
||||||
}
|
}
|
||||||
NodeValueTable table = GenerateTable(params.node,
|
NodeValueTable table = GenerateTable(
|
||||||
TimeRange(params.time,
|
params.node, TimeRange(params.time, params.time + frame_length));
|
||||||
params.time + frame_length));
|
|
||||||
NodeValue texture = table.Get(NodeValue::kTexture);
|
NodeValue texture = table.Get(NodeValue::kTexture);
|
||||||
ResolveJobs(texture);
|
ResolveJobs(texture);
|
||||||
|
|
||||||
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
|
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
|
||||||
NodeValueTable second_table =
|
NodeValueTable second_table = GenerateTable(
|
||||||
GenerateTable(params.node,
|
params.node, TimeRange(params.time + frame_length,
|
||||||
TimeRange(params.time + frame_length,
|
|
||||||
params.time + frame_length * 2));
|
params.time + frame_length * 2));
|
||||||
NodeValue second_texture = second_table.Get(NodeValue::kTexture);
|
NodeValue second_texture = second_table.Get(NodeValue::kTexture);
|
||||||
ResolveJobs(second_texture);
|
ResolveJobs(second_texture);
|
||||||
@@ -94,8 +92,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ProcessVideoFootage(TexturePtr destination,
|
void ProcessVideoFootage(TexturePtr destination, const FootageJob *stream,
|
||||||
const FootageJob *stream,
|
|
||||||
const rational &input_time) override
|
const rational &input_time) override
|
||||||
{
|
{
|
||||||
Q_UNUSED(destination)
|
Q_UNUSED(destination)
|
||||||
@@ -140,8 +137,7 @@ DecoderPtr ResolveDecoderFromCache(DecoderCache *decoder_cache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
|
FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
|
||||||
const FootageInput &input,
|
const FootageInput &input, CancelAtom *cancel)
|
||||||
CancelAtom *cancel)
|
|
||||||
{
|
{
|
||||||
VideoParams stream_data = input.job.video_params();
|
VideoParams stream_data = input.job.video_params();
|
||||||
QString filename = input.job.filename();
|
QString filename = input.job.filename();
|
||||||
@@ -162,19 +158,17 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
|
|||||||
case VideoParams::kVideoTypeVideo:
|
case VideoParams::kVideoTypeVideo:
|
||||||
case VideoParams::kVideoTypeStill:
|
case VideoParams::kVideoTypeStill:
|
||||||
decoder = ResolveDecoderFromCache(
|
decoder = ResolveDecoderFromCache(
|
||||||
decoder_cache,
|
decoder_cache, decoder_id,
|
||||||
decoder_id,
|
|
||||||
Decoder::CodecStream(filename, stream_index, nullptr));
|
Decoder::CodecStream(filename, stream_index, nullptr));
|
||||||
break;
|
break;
|
||||||
case VideoParams::kVideoTypeImageSequence: {
|
case VideoParams::kVideoTypeImageSequence: {
|
||||||
const int64_t frame_number =
|
const int64_t frame_number =
|
||||||
stream_data.get_time_in_timebase_units(input.time);
|
stream_data.get_time_in_timebase_units(input.time);
|
||||||
filename = Decoder::TransformImageSequenceFileName(filename, frame_number);
|
filename =
|
||||||
|
Decoder::TransformImageSequenceFileName(filename, frame_number);
|
||||||
decoder = Decoder::CreateFromID(decoder_id);
|
decoder = Decoder::CreateFromID(decoder_id);
|
||||||
if (decoder &&
|
if (decoder && !decoder->Open(Decoder::CodecStream(
|
||||||
!decoder->Open(Decoder::CodecStream(filename,
|
filename, stream_index, nullptr))) {
|
||||||
stream_index,
|
|
||||||
nullptr))) {
|
|
||||||
decoder = nullptr;
|
decoder = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -188,9 +182,9 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
|
|||||||
Decoder::RetrieveVideoParams retrieve;
|
Decoder::RetrieveVideoParams retrieve;
|
||||||
retrieve.divider = stream_data.divider();
|
retrieve.divider = stream_data.divider();
|
||||||
retrieve.maximum_format = PixelFormat::U16;
|
retrieve.maximum_format = PixelFormat::U16;
|
||||||
retrieve.time = stream_data.video_type() == VideoParams::kVideoTypeVideo
|
retrieve.time = stream_data.video_type() == VideoParams::kVideoTypeVideo ?
|
||||||
? input.time
|
input.time :
|
||||||
: Decoder::kAnyTimecode;
|
Decoder::kAnyTimecode;
|
||||||
retrieve.cancelled = cancel;
|
retrieve.cancelled = cancel;
|
||||||
retrieve.force_range = stream_data.color_range();
|
retrieve.force_range = stream_data.color_range();
|
||||||
retrieve.src_interlacing = stream_data.interlacing();
|
retrieve.src_interlacing = stream_data.interlacing();
|
||||||
@@ -207,15 +201,13 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
|
|||||||
frame_params.set_colorspace(stream_data.colorspace());
|
frame_params.set_colorspace(stream_data.colorspace());
|
||||||
frame->set_video_params(frame_params);
|
frame->set_video_params(frame_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodeInputFrames(DecoderCache *decoder_cache,
|
bool DecodeInputFrames(DecoderCache *decoder_cache,
|
||||||
const RenderManager::RenderVideoParams ¶ms,
|
const RenderManager::RenderVideoParams ¶ms,
|
||||||
CancelAtom *cancel,
|
CancelAtom *cancel, QVector<FramePtr> *frames)
|
||||||
QVector<FramePtr> *frames)
|
|
||||||
{
|
{
|
||||||
frames->clear();
|
frames->clear();
|
||||||
|
|
||||||
@@ -271,7 +263,8 @@ bool WriteControlMessage(QProcess *process, const QJsonObject &obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
|
const QByteArray line =
|
||||||
|
QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
|
||||||
const qint64 written = process->write(line);
|
const qint64 written = process->write(line);
|
||||||
if (written != line.size()) {
|
if (written != line.size()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -285,7 +278,8 @@ void TryWriteControlMessage(QProcess *process, const QJsonObject &obj)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
|
const QByteArray line =
|
||||||
|
QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
|
||||||
process->write(line);
|
process->write(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,12 +309,14 @@ bool IsProcessAlive(qint64 process_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, DWORD(process_id));
|
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
|
||||||
|
DWORD(process_id));
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DWORD exit_code = 0;
|
DWORD exit_code = 0;
|
||||||
const bool alive = GetExitCodeProcess(handle, &exit_code) && exit_code == STILL_ACTIVE;
|
const bool alive = GetExitCodeProcess(handle, &exit_code) &&
|
||||||
|
exit_code == STILL_ACTIVE;
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
return alive;
|
return alive;
|
||||||
#else
|
#else
|
||||||
@@ -334,11 +330,11 @@ QString WorkerProcessDetails(const QProcess *process)
|
|||||||
return QStringLiteral("worker process unavailable");
|
return QStringLiteral("worker process unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString exit_status =
|
const QString exit_status = process->exitStatus() == QProcess::CrashExit ?
|
||||||
process->exitStatus() == QProcess::CrashExit
|
QStringLiteral("crash") :
|
||||||
? QStringLiteral("crash")
|
QStringLiteral("normal");
|
||||||
: QStringLiteral("normal");
|
return QStringLiteral(
|
||||||
return QStringLiteral("state=%1 exit_status=%2 exit_code=%3 process_error=%4 error=\"%5\"")
|
"state=%1 exit_status=%2 exit_code=%3 process_error=%4 error=\"%5\"")
|
||||||
.arg(int(process->state()))
|
.arg(int(process->state()))
|
||||||
.arg(exit_status)
|
.arg(exit_status)
|
||||||
.arg(process->exitCode())
|
.arg(process->exitCode())
|
||||||
@@ -355,7 +351,8 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
|
|||||||
*error = QStringLiteral("worker exited before response: %1")
|
*error = QStringLiteral("worker exited before response: %1")
|
||||||
.arg(WorkerProcessDetails(process));
|
.arg(WorkerProcessDetails(process));
|
||||||
} else {
|
} else {
|
||||||
*error = QStringLiteral("timeout waiting for worker response: %1")
|
*error =
|
||||||
|
QStringLiteral("timeout waiting for worker response: %1")
|
||||||
.arg(WorkerProcessDetails(process));
|
.arg(WorkerProcessDetails(process));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,7 +369,8 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
|
|||||||
const QJsonDocument doc = QJsonDocument::fromJson(line, &parse_error);
|
const QJsonDocument doc = QJsonDocument::fromJson(line, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError || !doc.isObject()) {
|
if (parse_error.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||||
if (error) {
|
if (error) {
|
||||||
*error = QStringLiteral("worker emitted malformed control JSON");
|
*error =
|
||||||
|
QStringLiteral("worker emitted malformed control JSON");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -397,8 +395,7 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RenderWorkerPool::RenderWorkerPool(DecoderCache *decoder_cache,
|
RenderWorkerPool::RenderWorkerPool(DecoderCache *decoder_cache,
|
||||||
const QString &gpu_backend,
|
const QString &gpu_backend, QObject *parent)
|
||||||
QObject *parent)
|
|
||||||
: QThread(parent)
|
: QThread(parent)
|
||||||
, decoder_cache_(decoder_cache)
|
, decoder_cache_(decoder_cache)
|
||||||
, gpu_backend_(gpu_backend)
|
, gpu_backend_(gpu_backend)
|
||||||
@@ -410,8 +407,8 @@ RenderWorkerPool::~RenderWorkerPool()
|
|||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderWorkerPool::SubmitFrame(RenderTicketPtr ticket,
|
bool RenderWorkerPool::SubmitFrame(
|
||||||
const RenderManager::RenderVideoParams ¶ms)
|
RenderTicketPtr ticket, const RenderManager::RenderVideoParams ¶ms)
|
||||||
{
|
{
|
||||||
Job job(ticket, params);
|
Job job(ticket, params);
|
||||||
if (!PrepareJob(ticket, params, &job)) {
|
if (!PrepareJob(ticket, params, &job)) {
|
||||||
@@ -505,13 +502,13 @@ void RenderWorkerPool::run()
|
|||||||
active_jobs_.resize(worker_count);
|
active_jobs_.resize(worker_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<std::unique_ptr<PooledWorker>>> local_pools(worker_count);
|
std::vector<std::vector<std::unique_ptr<PooledWorker>>> local_pools(
|
||||||
|
worker_count);
|
||||||
std::vector<std::thread> workers;
|
std::vector<std::thread> workers;
|
||||||
workers.reserve(size_t(worker_count));
|
workers.reserve(size_t(worker_count));
|
||||||
for (int i = 0; i < worker_count; i++) {
|
for (int i = 0; i < worker_count; i++) {
|
||||||
workers.emplace_back([this, i, &local_pools]() {
|
workers.emplace_back(
|
||||||
WorkerLoop(i, &local_pools[i]);
|
[this, i, &local_pools]() { WorkerLoop(i, &local_pools[i]); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::thread &worker : workers) {
|
for (std::thread &worker : workers) {
|
||||||
@@ -529,8 +526,7 @@ void RenderWorkerPool::run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RenderWorkerPool::WorkerLoop(
|
void RenderWorkerPool::WorkerLoop(
|
||||||
int worker_index,
|
int worker_index, std::vector<std::unique_ptr<PooledWorker>> *local_pool)
|
||||||
std::vector<std::unique_ptr<PooledWorker>> *local_pool)
|
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
@@ -561,7 +557,8 @@ bool RenderWorkerPool::PrepareJob(RenderTicketPtr ticket,
|
|||||||
|
|
||||||
Project *project = Project::GetProjectFromObject(params.node);
|
Project *project = Project::GetProjectFromObject(params.node);
|
||||||
if (!project) {
|
if (!project) {
|
||||||
qWarning() << "RenderWorkerPool could not resolve project for render node";
|
qWarning()
|
||||||
|
<< "RenderWorkerPool could not resolve project for render node";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,11 +579,13 @@ bool RenderWorkerPool::PrepareJob(RenderTicketPtr ticket,
|
|||||||
if (it != graph_cache_.end() && !project->is_modified()) {
|
if (it != graph_cache_.end() && !project->is_modified()) {
|
||||||
graph_path = it->path;
|
graph_path = it->path;
|
||||||
AddGraphPathRefLocked(graph_path);
|
AddGraphPathRefLocked(graph_path);
|
||||||
qDebug() << "RenderWorkerPool::PrepareJob: using cached graph snapshot"
|
qDebug()
|
||||||
|
<< "RenderWorkerPool::PrepareJob: using cached graph snapshot"
|
||||||
<< graph_path;
|
<< graph_path;
|
||||||
} else {
|
} else {
|
||||||
if (it != graph_cache_.end()) {
|
if (it != graph_cache_.end()) {
|
||||||
qDebug() << "RenderWorkerPool::PrepareJob: graph stale, rewriting"
|
qDebug()
|
||||||
|
<< "RenderWorkerPool::PrepareJob: graph stale, rewriting"
|
||||||
<< project->is_modified();
|
<< project->is_modified();
|
||||||
SetGraphPathCachedLocked(it->path, false);
|
SetGraphPathCachedLocked(it->path, false);
|
||||||
graph_cache_.erase(it);
|
graph_cache_.erase(it);
|
||||||
@@ -625,17 +624,21 @@ bool RenderWorkerPool::WriteGraphSnapshot(Project *project, QString *path)
|
|||||||
// still referenced them.
|
// still referenced them.
|
||||||
const QString graph_dir = QDir::tempPath();
|
const QString graph_dir = QDir::tempPath();
|
||||||
|
|
||||||
QTemporaryFile file(QDir(graph_dir).filePath(QStringLiteral("oak-render-graph-XXXXXX.ove")));
|
QTemporaryFile file(QDir(graph_dir).filePath(
|
||||||
|
QStringLiteral("oak-render-graph-XXXXXX.ove")));
|
||||||
file.setAutoRemove(false);
|
file.setAutoRemove(false);
|
||||||
if (!file.open()) {
|
if (!file.open()) {
|
||||||
qWarning() << "RenderWorkerPool failed to create graph snapshot temp file"
|
qWarning()
|
||||||
|
<< "RenderWorkerPool failed to create graph snapshot temp file"
|
||||||
<< file.errorString();
|
<< file.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QXmlStreamWriter writer(&file);
|
QXmlStreamWriter writer(&file);
|
||||||
ProjectSerializer::SaveData data(ProjectSerializer::kProject, project, file.fileName());
|
ProjectSerializer::SaveData data(ProjectSerializer::kProject, project,
|
||||||
const ProjectSerializer::Result result = ProjectSerializer::Save(&writer, data);
|
file.fileName());
|
||||||
|
const ProjectSerializer::Result result =
|
||||||
|
ProjectSerializer::Save(&writer, data);
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
if (result.code() != ProjectSerializer::kSuccess || writer.hasError()) {
|
if (result.code() != ProjectSerializer::kSuccess || writer.hasError()) {
|
||||||
@@ -652,7 +655,8 @@ bool RenderWorkerPool::WriteGraphSnapshot(Project *project, QString *path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderWorkerPool::IsSupported(const RenderManager::RenderVideoParams ¶ms) const
|
bool RenderWorkerPool::IsSupported(
|
||||||
|
const RenderManager::RenderVideoParams ¶ms) const
|
||||||
{
|
{
|
||||||
return params.node && params.return_type == RenderManager::kFrame &&
|
return params.node && params.return_type == RenderManager::kFrame &&
|
||||||
params.video_params.is_valid();
|
params.video_params.is_valid();
|
||||||
@@ -662,7 +666,8 @@ void RenderWorkerPool::ProcessJob(
|
|||||||
const Job &job, int worker_index,
|
const Job &job, int worker_index,
|
||||||
std::vector<std::unique_ptr<PooledWorker>> *local_pool)
|
std::vector<std::unique_ptr<PooledWorker>> *local_pool)
|
||||||
{
|
{
|
||||||
const qint64 ticket_id = qint64(reinterpret_cast<quintptr>(job.ticket.get()));
|
const qint64 ticket_id =
|
||||||
|
qint64(reinterpret_cast<quintptr>(job.ticket.get()));
|
||||||
SetActiveWorker(worker_index, job.ticket, nullptr, ticket_id);
|
SetActiveWorker(worker_index, job.ticket, nullptr, ticket_id);
|
||||||
|
|
||||||
job.ticket->Start();
|
job.ticket->Start();
|
||||||
@@ -672,7 +677,8 @@ void RenderWorkerPool::ProcessJob(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PooledWorker> worker = AcquireWorker(local_pool, job.graph_path);
|
std::unique_ptr<PooledWorker> worker =
|
||||||
|
AcquireWorker(local_pool, job.graph_path);
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
qWarning() << "RenderWorkerPool failed to acquire worker for ticket"
|
qWarning() << "RenderWorkerPool failed to acquire worker for ticket"
|
||||||
<< ticket_id;
|
<< ticket_id;
|
||||||
@@ -685,22 +691,24 @@ void RenderWorkerPool::ProcessJob(
|
|||||||
if (attempt > 0) {
|
if (attempt > 0) {
|
||||||
worker = AcquireWorker(local_pool, job.graph_path);
|
worker = AcquireWorker(local_pool, job.graph_path);
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
qWarning() << "RenderWorkerPool failed to acquire worker for retry"
|
qWarning()
|
||||||
|
<< "RenderWorkerPool failed to acquire worker for retry"
|
||||||
<< ticket_id;
|
<< ticket_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const JobResult result = ProcessJobAttempt(job, worker_index, attempt,
|
const JobResult result =
|
||||||
worker.get());
|
ProcessJobAttempt(job, worker_index, attempt, worker.get());
|
||||||
const qint64 worker_pid = worker && worker->process
|
const qint64 worker_pid =
|
||||||
? worker->process->processId()
|
worker && worker->process ? worker->process->processId() : 0;
|
||||||
: 0;
|
|
||||||
const bool process_state_running = worker && worker->process &&
|
const bool process_state_running = worker && worker->process &&
|
||||||
worker->process->state() == QProcess::Running;
|
worker->process->state() ==
|
||||||
|
QProcess::Running;
|
||||||
const bool os_alive = worker_pid > 0 && IsProcessAlive(worker_pid);
|
const bool os_alive = worker_pid > 0 && IsProcessAlive(worker_pid);
|
||||||
const bool worker_healthy = process_state_running || os_alive;
|
const bool worker_healthy = process_state_running || os_alive;
|
||||||
const bool keep_alive = (result == JobResult::kFinished) && worker_healthy;
|
const bool keep_alive = (result == JobResult::kFinished) &&
|
||||||
|
worker_healthy;
|
||||||
|
|
||||||
ReturnWorker(local_pool, std::move(worker), keep_alive);
|
ReturnWorker(local_pool, std::move(worker), keep_alive);
|
||||||
worker.reset();
|
worker.reset();
|
||||||
@@ -733,11 +741,12 @@ void RenderWorkerPool::ProcessJob(
|
|||||||
ClearActiveWorker(worker_index, 0);
|
ClearActiveWorker(worker_index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
RenderWorkerPool::JobResult
|
||||||
const Job &job, int worker_index, int attempt_index,
|
RenderWorkerPool::ProcessJobAttempt(const Job &job, int worker_index,
|
||||||
PooledWorker *worker)
|
int attempt_index, PooledWorker *worker)
|
||||||
{
|
{
|
||||||
const qint64 ticket_id = qint64(reinterpret_cast<quintptr>(job.ticket.get()));
|
const qint64 ticket_id =
|
||||||
|
qint64(reinterpret_cast<quintptr>(job.ticket.get()));
|
||||||
if (job.ticket->IsCancelled()) {
|
if (job.ticket->IsCancelled()) {
|
||||||
return JobResult::kCancelled;
|
return JobResult::kCancelled;
|
||||||
}
|
}
|
||||||
@@ -748,27 +757,25 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
|
|
||||||
const qint64 worker_process_id = worker->process->processId();
|
const qint64 worker_process_id = worker->process->processId();
|
||||||
|
|
||||||
const int output_width = job.params.force_size.width() > 0
|
const int output_width = job.params.force_size.width() > 0 ?
|
||||||
? job.params.force_size.width()
|
job.params.force_size.width() :
|
||||||
: job.params.video_params.effective_width();
|
job.params.video_params.effective_width();
|
||||||
const int output_height = job.params.force_size.height() > 0
|
const int output_height = job.params.force_size.height() > 0 ?
|
||||||
? job.params.force_size.height()
|
job.params.force_size.height() :
|
||||||
: job.params.video_params.effective_height();
|
job.params.video_params.effective_height();
|
||||||
const PixelFormat::Format output_format =
|
const PixelFormat::Format output_format =
|
||||||
job.params.force_format != PixelFormat::INVALID
|
job.params.force_format != PixelFormat::INVALID ?
|
||||||
? PixelFormat::Format(job.params.force_format)
|
PixelFormat::Format(job.params.force_format) :
|
||||||
: PixelFormat::F32;
|
PixelFormat::F32;
|
||||||
const int output_channels = job.params.force_channel_count > 0
|
const int output_channels = job.params.force_channel_count > 0 ?
|
||||||
? job.params.force_channel_count
|
job.params.force_channel_count :
|
||||||
: VideoParams::kRGBAChannelCount;
|
VideoParams::kRGBAChannelCount;
|
||||||
const int output_linesize =
|
const int output_linesize = Frame::generate_linesize_bytes(
|
||||||
Frame::generate_linesize_bytes(output_width, output_format,
|
output_width, output_format, output_channels);
|
||||||
output_channels);
|
|
||||||
const size_t estimated_output_slot_bytes =
|
const size_t estimated_output_slot_bytes =
|
||||||
size_t(output_linesize) * size_t(output_height);
|
size_t(output_linesize) * size_t(output_height);
|
||||||
const int f32_rgba_linesize =
|
const int f32_rgba_linesize = Frame::generate_linesize_bytes(
|
||||||
Frame::generate_linesize_bytes(output_width, PixelFormat::F32,
|
output_width, PixelFormat::F32, VideoParams::kRGBAChannelCount);
|
||||||
VideoParams::kRGBAChannelCount);
|
|
||||||
const size_t f32_rgba_slot_bytes =
|
const size_t f32_rgba_slot_bytes =
|
||||||
size_t(f32_rgba_linesize) * size_t(output_height);
|
size_t(f32_rgba_linesize) * size_t(output_height);
|
||||||
const size_t output_slot_bytes =
|
const size_t output_slot_bytes =
|
||||||
@@ -797,7 +804,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
if (!worker->output_region.Open(worker->output_shm_key,
|
if (!worker->output_region.Open(worker->output_shm_key,
|
||||||
output_region_bytes,
|
output_region_bytes,
|
||||||
ipc::SharedMemoryRegion::kCreate)) {
|
ipc::SharedMemoryRegion::kCreate)) {
|
||||||
qWarning() << "RenderWorkerPool failed to create output shared memory"
|
qWarning()
|
||||||
|
<< "RenderWorkerPool failed to create output shared memory"
|
||||||
<< worker->output_region.error();
|
<< worker->output_region.error();
|
||||||
return JobResult::kFatalFailure;
|
return JobResult::kFatalFailure;
|
||||||
}
|
}
|
||||||
@@ -823,17 +831,19 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
ipc::SharedMemoryRegion::MakeKey(worker_process_id, 1) +
|
ipc::SharedMemoryRegion::MakeKey(worker_process_id, 1) +
|
||||||
QStringLiteral("-in");
|
QStringLiteral("-in");
|
||||||
}
|
}
|
||||||
const size_t input_region_bytes =
|
const size_t input_region_bytes = ipc::FrameSlotPool::BytesNeeded(
|
||||||
ipc::FrameSlotPool::BytesNeeded(input_slot_count, input_slot_bytes);
|
input_slot_count, input_slot_bytes);
|
||||||
if (!worker->input_region.Open(worker->input_shm_key,
|
if (!worker->input_region.Open(worker->input_shm_key,
|
||||||
input_region_bytes,
|
input_region_bytes,
|
||||||
ipc::SharedMemoryRegion::kCreate)) {
|
ipc::SharedMemoryRegion::kCreate)) {
|
||||||
qWarning() << "RenderWorkerPool failed to create input shared memory"
|
qWarning()
|
||||||
|
<< "RenderWorkerPool failed to create input shared memory"
|
||||||
<< worker->input_region.error();
|
<< worker->input_region.error();
|
||||||
return JobResult::kFatalFailure;
|
return JobResult::kFatalFailure;
|
||||||
}
|
}
|
||||||
worker->input_pool = ipc::FrameSlotPool::Create(
|
worker->input_pool =
|
||||||
worker->input_region.data(), input_slot_count, input_slot_bytes);
|
ipc::FrameSlotPool::Create(worker->input_region.data(),
|
||||||
|
input_slot_count, input_slot_bytes);
|
||||||
worker->input_slot_bytes = input_slot_bytes;
|
worker->input_slot_bytes = input_slot_bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -843,7 +853,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
if (input_slot_count > 0) {
|
if (input_slot_count > 0) {
|
||||||
for (const FramePtr &frame : job.input_frames) {
|
for (const FramePtr &frame : job.input_frames) {
|
||||||
if (frame->allocated_size() > int(worker->input_slot_bytes)) {
|
if (frame->allocated_size() > int(worker->input_slot_bytes)) {
|
||||||
qWarning() << "RenderWorkerPool decoded input frame exceeds slot size";
|
qWarning()
|
||||||
|
<< "RenderWorkerPool decoded input frame exceeds slot size";
|
||||||
return JobResult::kFatalFailure;
|
return JobResult::kFatalFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,8 +880,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
const QString cs = frame->video_params().colorspace();
|
const QString cs = frame->video_params().colorspace();
|
||||||
if (!cs.isEmpty()) {
|
if (!cs.isEmpty()) {
|
||||||
const QByteArray cs_utf8 = cs.toUtf8();
|
const QByteArray cs_utf8 = cs.toUtf8();
|
||||||
const size_t copy_len = qMin(
|
const size_t copy_len =
|
||||||
static_cast<size_t>(cs_utf8.size()),
|
qMin(static_cast<size_t>(cs_utf8.size()),
|
||||||
sizeof(meta->colorspace) - 1);
|
sizeof(meta->colorspace) - 1);
|
||||||
memcpy(meta->colorspace, cs_utf8.constData(), copy_len);
|
memcpy(meta->colorspace, cs_utf8.constData(), copy_len);
|
||||||
meta->colorspace[copy_len] = '\0';
|
meta->colorspace[copy_len] = '\0';
|
||||||
@@ -905,16 +916,16 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
handshake.input_slots = input_slots.size();
|
handshake.input_slots = input_slots.size();
|
||||||
handshake.output_slots = int(kOutputSlots);
|
handshake.output_slots = int(kOutputSlots);
|
||||||
handshake.slot_data_bytes = qint64(output_slot_bytes);
|
handshake.slot_data_bytes = qint64(output_slot_bytes);
|
||||||
handshake.input_slot_data_bytes = input_slots.isEmpty()
|
handshake.input_slot_data_bytes =
|
||||||
? 0
|
input_slots.isEmpty() ? 0 : qint64(input_slot_bytes);
|
||||||
: qint64(input_slot_bytes);
|
|
||||||
if (!WriteControlMessage(worker->process, handshake.ToJson())) {
|
if (!WriteControlMessage(worker->process, handshake.ToJson())) {
|
||||||
if (!job.ticket->IsCancelled()) {
|
if (!job.ticket->IsCancelled()) {
|
||||||
qWarning() << "RenderWorkerPool failed to send shared-memory handshake";
|
qWarning()
|
||||||
|
<< "RenderWorkerPool failed to send shared-memory handshake";
|
||||||
}
|
}
|
||||||
ClearActiveWorker(worker_index, worker_process_id);
|
ClearActiveWorker(worker_index, worker_process_id);
|
||||||
return job.ticket->IsCancelled() ? JobResult::kCancelled
|
return job.ticket->IsCancelled() ? JobResult::kCancelled :
|
||||||
: JobResult::kRetryableFailure;
|
JobResult::kRetryableFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worker->loaded_graph_path != job.graph_path) {
|
if (worker->loaded_graph_path != job.graph_path) {
|
||||||
@@ -929,11 +940,10 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
<< error << worker->process->readAllStandardError();
|
<< error << worker->process->readAllStandardError();
|
||||||
}
|
}
|
||||||
ClearActiveWorker(worker_index, worker_process_id);
|
ClearActiveWorker(worker_index, worker_process_id);
|
||||||
return job.ticket->IsCancelled() ? JobResult::kCancelled
|
return job.ticket->IsCancelled() ? JobResult::kCancelled :
|
||||||
: JobResult::kRetryableFailure;
|
JobResult::kRetryableFailure;
|
||||||
}
|
}
|
||||||
worker->loaded_graph_path = job.graph_path;
|
worker->loaded_graph_path = job.graph_path;
|
||||||
|
|
||||||
}
|
}
|
||||||
ipc::RenderFrameMsg render;
|
ipc::RenderFrameMsg render;
|
||||||
render.ticket_id = ticket_id;
|
render.ticket_id = ticket_id;
|
||||||
@@ -960,8 +970,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
qWarning() << "RenderWorkerPool failed to send render_frame";
|
qWarning() << "RenderWorkerPool failed to send render_frame";
|
||||||
}
|
}
|
||||||
ClearActiveWorker(worker_index, worker_process_id);
|
ClearActiveWorker(worker_index, worker_process_id);
|
||||||
return job.ticket->IsCancelled() ? JobResult::kCancelled
|
return job.ticket->IsCancelled() ? JobResult::kCancelled :
|
||||||
: JobResult::kRetryableFailure;
|
JobResult::kRetryableFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
@@ -974,8 +984,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
|
|||||||
<< error << worker->process->readAllStandardError();
|
<< error << worker->process->readAllStandardError();
|
||||||
}
|
}
|
||||||
ClearActiveWorker(worker_index, worker_process_id);
|
ClearActiveWorker(worker_index, worker_process_id);
|
||||||
return job.ticket->IsCancelled() ? JobResult::kCancelled
|
return job.ticket->IsCancelled() ? JobResult::kCancelled :
|
||||||
: JobResult::kRetryableFailure;
|
JobResult::kRetryableFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipc::FrameReadyMsg::FromJson(response, &ready)) {
|
if (ipc::FrameReadyMsg::FromJson(response, &ready)) {
|
||||||
@@ -1068,8 +1078,8 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
|
|||||||
local_pool->erase(local_pool->begin() + i);
|
local_pool->erase(local_pool->begin() + i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const bool candidate_state_running =
|
const bool candidate_state_running = candidate->process->state() ==
|
||||||
candidate->process->state() == QProcess::Running;
|
QProcess::Running;
|
||||||
const bool candidate_os_alive =
|
const bool candidate_os_alive =
|
||||||
IsProcessAlive(candidate->process->processId());
|
IsProcessAlive(candidate->process->processId());
|
||||||
if (!candidate_state_running && !candidate_os_alive) {
|
if (!candidate_state_running && !candidate_os_alive) {
|
||||||
@@ -1085,7 +1095,8 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
|
|||||||
if (best_index < 0 ||
|
if (best_index < 0 ||
|
||||||
(!candidate->loaded_graph_path.isEmpty() &&
|
(!candidate->loaded_graph_path.isEmpty() &&
|
||||||
candidate->loaded_graph_path == graph_path &&
|
candidate->loaded_graph_path == graph_path &&
|
||||||
((*local_pool)[size_t(best_index)]->loaded_graph_path != graph_path))) {
|
((*local_pool)[size_t(best_index)]->loaded_graph_path !=
|
||||||
|
graph_path))) {
|
||||||
best_index = int(i);
|
best_index = int(i);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
@@ -1100,14 +1111,14 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
|
|||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// No idle worker available: start a new one.
|
// No idle worker available: start a new one.
|
||||||
auto *process = new QProcess();
|
auto *process = new QProcess();
|
||||||
process->setProgram(WorkerProgramPath());
|
process->setProgram(WorkerProgramPath());
|
||||||
process->setArguments({ QStringLiteral("--backend"), gpu_backend_ });
|
process->setArguments({ QStringLiteral("--backend"), gpu_backend_ });
|
||||||
|
|
||||||
const QString worker_stderr_path = QDir(QDir::tempPath()).filePath(
|
const QString worker_stderr_path =
|
||||||
QStringLiteral("oak-render-worker-%1-%2.stderr.log")
|
QDir(QDir::tempPath())
|
||||||
|
.filePath(QStringLiteral("oak-render-worker-%1-%2.stderr.log")
|
||||||
.arg(QCoreApplication::applicationPid())
|
.arg(QCoreApplication::applicationPid())
|
||||||
.arg(QDateTime::currentMSecsSinceEpoch()));
|
.arg(QDateTime::currentMSecsSinceEpoch()));
|
||||||
process->setStandardErrorFile(worker_stderr_path);
|
process->setStandardErrorFile(worker_stderr_path);
|
||||||
@@ -1140,8 +1151,7 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
|
|||||||
|
|
||||||
void RenderWorkerPool::ReturnWorker(
|
void RenderWorkerPool::ReturnWorker(
|
||||||
std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
||||||
std::unique_ptr<PooledWorker> worker,
|
std::unique_ptr<PooledWorker> worker, bool keep_alive)
|
||||||
bool keep_alive)
|
|
||||||
{
|
{
|
||||||
if (!worker || !worker->process) {
|
if (!worker || !worker->process) {
|
||||||
return;
|
return;
|
||||||
@@ -1216,8 +1226,7 @@ void RenderWorkerPool::FinishWithFrame(RenderTicketPtr ticket,
|
|||||||
}
|
}
|
||||||
|
|
||||||
VideoParams params(meta->width, meta->height,
|
VideoParams params(meta->width, meta->height,
|
||||||
PixelFormat::Format(meta->format),
|
PixelFormat::Format(meta->format), meta->channel_count);
|
||||||
meta->channel_count);
|
|
||||||
FramePtr frame = Frame::Create();
|
FramePtr frame = Frame::Create();
|
||||||
frame->set_timestamp(rational(int(meta->time_num), int(meta->time_den)));
|
frame->set_timestamp(rational(int(meta->time_num), int(meta->time_den)));
|
||||||
frame->set_video_params(params);
|
frame->set_video_params(params);
|
||||||
@@ -1281,7 +1290,8 @@ void RenderWorkerPool::SetGraphPathCached(const QString &path, bool cached)
|
|||||||
SetGraphPathCachedLocked(path, cached);
|
SetGraphPathCachedLocked(path, cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWorkerPool::SetGraphPathCachedLocked(const QString &path, bool cached)
|
void RenderWorkerPool::SetGraphPathCachedLocked(const QString &path,
|
||||||
|
bool cached)
|
||||||
{
|
{
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -114,8 +114,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool PrepareJob(RenderTicketPtr ticket,
|
bool PrepareJob(RenderTicketPtr ticket,
|
||||||
const RenderManager::RenderVideoParams ¶ms,
|
const RenderManager::RenderVideoParams ¶ms, Job *job);
|
||||||
Job *job);
|
|
||||||
bool WriteGraphSnapshot(Project *project, QString *path);
|
bool WriteGraphSnapshot(Project *project, QString *path);
|
||||||
bool IsSupported(const RenderManager::RenderVideoParams ¶ms) const;
|
bool IsSupported(const RenderManager::RenderVideoParams ¶ms) const;
|
||||||
|
|
||||||
@@ -124,8 +123,7 @@ private:
|
|||||||
void ProcessJob(const Job &job, int worker_index,
|
void ProcessJob(const Job &job, int worker_index,
|
||||||
std::vector<std::unique_ptr<PooledWorker>> *local_pool);
|
std::vector<std::unique_ptr<PooledWorker>> *local_pool);
|
||||||
JobResult ProcessJobAttempt(const Job &job, int worker_index,
|
JobResult ProcessJobAttempt(const Job &job, int worker_index,
|
||||||
int attempt_index,
|
int attempt_index, PooledWorker *worker);
|
||||||
PooledWorker *worker);
|
|
||||||
void FinishWithFrame(RenderTicketPtr ticket, const ipc::FrameSlotPool &pool,
|
void FinishWithFrame(RenderTicketPtr ticket, const ipc::FrameSlotPool &pool,
|
||||||
uint32_t slot);
|
uint32_t slot);
|
||||||
void CleanupGraphFile(const QString &path);
|
void CleanupGraphFile(const QString &path);
|
||||||
@@ -141,13 +139,14 @@ private:
|
|||||||
void ClearActiveWorker(int worker_index, qint64 process_id);
|
void ClearActiveWorker(int worker_index, qint64 process_id);
|
||||||
int WorkerCount() const;
|
int WorkerCount() const;
|
||||||
|
|
||||||
std::unique_ptr<PooledWorker> AcquireWorker(
|
std::unique_ptr<PooledWorker>
|
||||||
std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
AcquireWorker(std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
||||||
const QString &graph_path);
|
const QString &graph_path);
|
||||||
void ReturnWorker(std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
void ReturnWorker(std::vector<std::unique_ptr<PooledWorker>> *local_pool,
|
||||||
std::unique_ptr<PooledWorker> worker, bool keep_alive);
|
std::unique_ptr<PooledWorker> worker, bool keep_alive);
|
||||||
void ShutdownWorker(PooledWorker *worker);
|
void ShutdownWorker(PooledWorker *worker);
|
||||||
void ShutdownLocalPool(std::vector<std::unique_ptr<PooledWorker>> *local_pool);
|
void
|
||||||
|
ShutdownLocalPool(std::vector<std::unique_ptr<PooledWorker>> *local_pool);
|
||||||
void ClearGraphCache();
|
void ClearGraphCache();
|
||||||
|
|
||||||
DecoderCache *decoder_cache_;
|
DecoderCache *decoder_cache_;
|
||||||
|
|||||||
@@ -164,9 +164,11 @@ public:
|
|||||||
{
|
{
|
||||||
frame_ = ptr;
|
frame_ = ptr;
|
||||||
}
|
}
|
||||||
AVFramePtr frame(){
|
AVFramePtr frame()
|
||||||
|
{
|
||||||
return frame_;
|
return frame_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsRendererAlive() const
|
bool IsRendererAlive() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
#include "render/videoparams.h"
|
#include "render/videoparams.h"
|
||||||
#include "render/vulkan/vulkanrenderer.h"
|
#include "render/vulkan/vulkanrenderer.h"
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
class BackendVulkanRenderer : public olive::VulkanRenderer {
|
class BackendVulkanRenderer : public olive::VulkanRenderer {
|
||||||
public:
|
public:
|
||||||
@@ -38,38 +39,42 @@ const QVariant &VariantRef(const void *variant)
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Creates the Vulkan backend object and returns it as an opaque C handle.
|
// Creates the Vulkan backend object and returns it as an opaque C handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle oak_renderer_create(void *parent)
|
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle
|
||||||
|
oak_renderer_create(void *parent)
|
||||||
{
|
{
|
||||||
return new BackendVulkanRenderer(static_cast<QObject *>(parent));
|
return new BackendVulkanRenderer(static_cast<QObject *>(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the opaque backend object created by oak_renderer_create().
|
// Destroys the opaque backend object created by oak_renderer_create().
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handle)
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
|
oak_renderer_destroy(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
delete Renderer(handle);
|
delete Renderer(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reports Vulkan backend capabilities and runtime availability status.
|
// Reports Vulkan backend capabilities and runtime availability status.
|
||||||
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
|
OAK_RENDER_BACKEND_EXPORT bool
|
||||||
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
|
oak_renderer_get_info(OakRenderBackendHandle handle,
|
||||||
|
OakRenderBackendInfo *out_info)
|
||||||
{
|
{
|
||||||
if (!handle || !out_info) {
|
if (!handle || !out_info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_info->abi_version = 1;
|
out_info->abi_version = 1;
|
||||||
out_info->kind = OAK_RENDER_BACKEND_VULKAN;
|
out_info->kind = OAK_RENDER_BACKEND_VULKAN;
|
||||||
out_info->capabilities = OAK_RENDER_BACKEND_CAP_TEXTURES |
|
out_info->capabilities =
|
||||||
OAK_RENDER_BACKEND_CAP_SHADERS | OAK_RENDER_BACKEND_CAP_BLIT |
|
OAK_RENDER_BACKEND_CAP_TEXTURES | OAK_RENDER_BACKEND_CAP_SHADERS |
|
||||||
OAK_RENDER_BACKEND_CAP_READBACK;
|
OAK_RENDER_BACKEND_CAP_BLIT | OAK_RENDER_BACKEND_CAP_READBACK;
|
||||||
out_info->name = "vulkan";
|
out_info->name = "vulkan";
|
||||||
out_info->status = Renderer(handle)->IsAvailable() ? "available" : "unavailable";
|
out_info->status = Renderer(handle)->IsAvailable() ? "available" :
|
||||||
|
"unavailable";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probes runtime availability by trying Init() once; this lets missing ICDs or
|
// Probes runtime availability by trying Init() once; this lets missing ICDs or
|
||||||
// unusable drivers fall back before normal rendering starts.
|
// unusable drivers fall back before normal rendering starts.
|
||||||
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
|
OAK_RENDER_BACKEND_EXPORT bool
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_is_available(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
auto *r = Renderer(handle);
|
auto *r = Renderer(handle);
|
||||||
if (!r || r->IsAvailable()) {
|
if (!r || r->IsAvailable()) {
|
||||||
@@ -89,38 +94,38 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_init(OakRenderBackendHandle handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vulkan does not use a QOpenGLContext; the argument is accepted for ABI parity.
|
// Vulkan does not use a QOpenGLContext; the argument is accepted for ABI parity.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_init_with_context(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *context)
|
oak_renderer_init_with_context(OakRenderBackendHandle handle, void *context)
|
||||||
{
|
{
|
||||||
Q_UNUSED(context)
|
Q_UNUSED(context)
|
||||||
Renderer(handle)->Init();
|
Renderer(handle)->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates reusable Vulkan resources after device initialization.
|
// Creates reusable Vulkan resources after device initialization.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_init(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_post_init(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->PostInit();
|
Renderer(handle)->PostInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserved for API symmetry; Vulkan cleanup is handled by destroy_internal.
|
// Reserved for API symmetry; Vulkan cleanup is handled by destroy_internal.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_destroy(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_post_destroy(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->PostDestroy();
|
Renderer(handle)->PostDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases all Vulkan resources owned by the renderer.
|
// Releases all Vulkan resources owned by the renderer.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_internal(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_destroy_internal(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyInternal();
|
Renderer(handle)->DestroyInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears a Vulkan texture destination.
|
// Clears a Vulkan texture destination.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_clear_destination(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *texture, double r, double g, double b,
|
oak_renderer_clear_destination(OakRenderBackendHandle handle, void *texture,
|
||||||
double a)
|
double r, double g, double b, double a)
|
||||||
{
|
{
|
||||||
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
|
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
|
||||||
r, g, b, a);
|
r, g, b, a);
|
||||||
@@ -131,51 +136,58 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_texture(
|
|||||||
OakRenderBackendHandle handle, int width, int height, int depth, int format,
|
OakRenderBackendHandle handle, int width, int height, int depth, int format,
|
||||||
int channel_count, const void *data, int linesize, void *out_variant)
|
int channel_count, const void *data, int linesize, void *out_variant)
|
||||||
{
|
{
|
||||||
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeTexture(
|
*static_cast<QVariant *>(out_variant) =
|
||||||
width, height, depth, static_cast<olive::PixelFormat::Format>(format),
|
Renderer(handle)->CreateNativeTexture(
|
||||||
channel_count, data, linesize);
|
width, height, depth,
|
||||||
|
static_cast<olive::PixelFormat::Format>(format), channel_count,
|
||||||
|
data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys a Vulkan texture represented by a QVariant handle.
|
// Destroys a Vulkan texture represented by a QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant)
|
oak_renderer_destroy_native_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *variant)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
|
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiles a Vulkan shader and returns its QVariant handle.
|
// Compiles a Vulkan shader and returns its QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_shader(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *shader_code, void *out_variant)
|
oak_renderer_create_native_shader(OakRenderBackendHandle handle,
|
||||||
|
const void *shader_code, void *out_variant)
|
||||||
{
|
{
|
||||||
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeShader(
|
*static_cast<QVariant *>(out_variant) =
|
||||||
|
Renderer(handle)->CreateNativeShader(
|
||||||
*static_cast<const olive::ShaderCode *>(shader_code));
|
*static_cast<const olive::ShaderCode *>(shader_code));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys a Vulkan shader represented by a QVariant handle.
|
// Destroys a Vulkan shader represented by a QVariant handle.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_shader(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant)
|
oak_renderer_destroy_native_shader(OakRenderBackendHandle handle,
|
||||||
|
const void *variant)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
|
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uploads CPU pixel data into a Vulkan texture.
|
// Uploads CPU pixel data into a Vulkan texture.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_upload_to_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *variant, const void *video_params,
|
oak_renderer_upload_to_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *variant, const void *video_params,
|
||||||
const void *data, int linesize)
|
const void *data, int linesize)
|
||||||
{
|
{
|
||||||
Renderer(handle)->UploadToTexture(
|
Renderer(handle)->UploadToTexture(
|
||||||
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
|
VariantRef(variant),
|
||||||
data, linesize);
|
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downloads a Vulkan texture to CPU memory.
|
// Downloads a Vulkan texture to CPU memory.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
|
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
|
||||||
OakRenderBackendHandle handle, const void *variant, const void *video_params,
|
OakRenderBackendHandle handle, const void *variant,
|
||||||
void *data, int linesize)
|
const void *video_params, void *data, int linesize)
|
||||||
{
|
{
|
||||||
Renderer(handle)->DownloadFromTexture(
|
Renderer(handle)->DownloadFromTexture(
|
||||||
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
|
VariantRef(variant),
|
||||||
data, linesize);
|
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waits for all queued Vulkan work to finish.
|
// Waits for all queued Vulkan work to finish.
|
||||||
@@ -185,18 +197,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_flush(OakRenderBackendHandle handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reads one pixel from a Vulkan texture.
|
// Reads one pixel from a Vulkan texture.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_get_pixel_from_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, void *texture, const void *point,
|
oak_renderer_get_pixel_from_texture(OakRenderBackendHandle handle,
|
||||||
|
void *texture, const void *point,
|
||||||
void *out_color)
|
void *out_color)
|
||||||
{
|
{
|
||||||
*static_cast<olive::Color *>(out_color) = Renderer(handle)->GetPixelFromTexture(
|
*static_cast<olive::Color *>(out_color) =
|
||||||
static_cast<olive::Texture *>(texture), *static_cast<const QPointF *>(point));
|
Renderer(handle)->GetPixelFromTexture(
|
||||||
|
static_cast<olive::Texture *>(texture),
|
||||||
|
*static_cast<const QPointF *>(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes a shader blit through the wrapped Vulkan renderer.
|
// Executes a shader blit through the wrapped Vulkan renderer.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
|
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(OakRenderBackendHandle handle,
|
||||||
OakRenderBackendHandle handle, const void *shader, void *job,
|
const void *shader, void *job,
|
||||||
void *destination, const void *destination_params, bool clear_destination)
|
void *destination,
|
||||||
|
const void *destination_params,
|
||||||
|
bool clear_destination)
|
||||||
{
|
{
|
||||||
Renderer(handle)->Blit(
|
Renderer(handle)->Blit(
|
||||||
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
|
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
|
||||||
@@ -206,16 +223,17 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vulkan has no OpenGL context; return null so callers avoid GL-only paths.
|
// Vulkan has no OpenGL context; return null so callers avoid GL-only paths.
|
||||||
OAK_RENDER_BACKEND_EXPORT void *oak_renderer_opengl_context(
|
OAK_RENDER_BACKEND_EXPORT void *
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_opengl_context(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Q_UNUSED(handle)
|
Q_UNUSED(handle)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OFX OpenGL output attachment is unsupported in Vulkan and intentionally no-op.
|
// OFX OpenGL output attachment is unsupported in Vulkan and intentionally no-op.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle, const void *texture_id)
|
oak_renderer_attach_output_texture(OakRenderBackendHandle handle,
|
||||||
|
const void *texture_id)
|
||||||
{
|
{
|
||||||
Q_UNUSED(handle)
|
Q_UNUSED(handle)
|
||||||
Q_UNUSED(texture_id)
|
Q_UNUSED(texture_id)
|
||||||
@@ -223,8 +241,8 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OFX OpenGL output detachment is unsupported in Vulkan and intentionally no-op.
|
// OFX OpenGL output detachment is unsupported in Vulkan and intentionally no-op.
|
||||||
OAK_RENDER_BACKEND_EXPORT void oak_renderer_detach_output_texture(
|
OAK_RENDER_BACKEND_EXPORT void
|
||||||
OakRenderBackendHandle handle)
|
oak_renderer_detach_output_texture(OakRenderBackendHandle handle)
|
||||||
{
|
{
|
||||||
Q_UNUSED(handle)
|
Q_UNUSED(handle)
|
||||||
// Vulkan does not support OFX OpenGL render output attachment.
|
// Vulkan does not support OFX OpenGL render output attachment.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -90,7 +90,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
// Runs one or more fullscreen shader passes into the destination texture.
|
// Runs one or more fullscreen shader passes into the destination texture.
|
||||||
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
|
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
|
||||||
olive::Texture *destination, VideoParams destination_params,
|
olive::Texture *destination,
|
||||||
|
VideoParams destination_params,
|
||||||
bool clear_destination) override;
|
bool clear_destination) override;
|
||||||
// Creates a Vulkan image/view/memory bundle and optionally uploads initial
|
// Creates a Vulkan image/view/memory bundle and optionally uploads initial
|
||||||
// pixel data.
|
// pixel data.
|
||||||
@@ -172,8 +173,8 @@ private:
|
|||||||
float GetFormatMaxAlpha(PixelFormat format) const;
|
float GetFormatMaxAlpha(PixelFormat format) const;
|
||||||
// Repackages tightly packed pixels when the requested CPU channel count
|
// Repackages tightly packed pixels when the requested CPU channel count
|
||||||
// differs from the selected GPU format channel count.
|
// differs from the selected GPU format channel count.
|
||||||
void CopyPixelsWithChannelConversion(const void *src, void *dst,
|
void CopyPixelsWithChannelConversion(const void *src, void *dst, int width,
|
||||||
int width, int height, int depth,
|
int height, int depth,
|
||||||
int src_channels, int dst_channels,
|
int src_channels, int dst_channels,
|
||||||
PixelFormat format) const;
|
PixelFormat format) const;
|
||||||
// Rounds a size up to the requested alignment.
|
// Rounds a size up to the requested alignment.
|
||||||
@@ -187,11 +188,13 @@ private:
|
|||||||
bool CompileGlslToSpv(const QString &glsl, VkShaderStageFlagBits stage,
|
bool CompileGlslToSpv(const QString &glsl, VkShaderStageFlagBits stage,
|
||||||
QByteArray *out_spv);
|
QByteArray *out_spv);
|
||||||
// Rewrites an Oak GLSL shader into Vulkan-compatible GLSL.
|
// Rewrites an Oak GLSL shader into Vulkan-compatible GLSL.
|
||||||
QString ConvertGlslToVulkan(const QString &glsl, VkShaderStageFlagBits stage);
|
QString ConvertGlslToVulkan(const QString &glsl,
|
||||||
|
VkShaderStageFlagBits stage);
|
||||||
// Ensures a shader declares a Vulkan-compatible GLSL version.
|
// Ensures a shader declares a Vulkan-compatible GLSL version.
|
||||||
QString EnsureGlslVersion450(const QString &glsl) const;
|
QString EnsureGlslVersion450(const QString &glsl) const;
|
||||||
// Extracts uniforms and sampler names from GLSL declarations.
|
// Extracts uniforms and sampler names from GLSL declarations.
|
||||||
void ExtractUniforms(const QString &glsl, QVector<UniformInfo> *out_uniforms,
|
void ExtractUniforms(const QString &glsl,
|
||||||
|
QVector<UniformInfo> *out_uniforms,
|
||||||
QVector<QString> *out_samplers) const;
|
QVector<QString> *out_samplers) const;
|
||||||
// Computes std140 offsets and total UBO size for extracted uniforms.
|
// Computes std140 offsets and total UBO size for extracted uniforms.
|
||||||
void ComputeUniformLayout(QVector<UniformInfo> *uniforms) const;
|
void ComputeUniformLayout(QVector<UniformInfo> *uniforms) const;
|
||||||
@@ -199,7 +202,8 @@ private:
|
|||||||
QString BuildUboBlock(const QVector<UniformInfo> &uniforms) const;
|
QString BuildUboBlock(const QVector<UniformInfo> &uniforms) const;
|
||||||
// Rewrites standalone uniforms and samplers into explicit UBO/sampler
|
// Rewrites standalone uniforms and samplers into explicit UBO/sampler
|
||||||
// bindings accepted by Vulkan GLSL.
|
// bindings accepted by Vulkan GLSL.
|
||||||
QString RewriteShaderWithUbo(const QString &glsl,
|
QString
|
||||||
|
RewriteShaderWithUbo(const QString &glsl,
|
||||||
const QVector<UniformInfo> &all_uniforms,
|
const QVector<UniformInfo> &all_uniforms,
|
||||||
const QHash<QString, int> &sampler_bindings) const;
|
const QHash<QString, int> &sampler_bindings) const;
|
||||||
// Returns std140 storage size for a supported GLSL type.
|
// Returns std140 storage size for a supported GLSL type.
|
||||||
@@ -225,8 +229,8 @@ private:
|
|||||||
void BlitPass(VulkanShader *shader, VulkanTexture *dest_tex,
|
void BlitPass(VulkanShader *shader, VulkanTexture *dest_tex,
|
||||||
const QVector<TextureBinding> &bindings,
|
const QVector<TextureBinding> &bindings,
|
||||||
const QByteArray &ubo_data,
|
const QByteArray &ubo_data,
|
||||||
const VideoParams &destination_params,
|
const VideoParams &destination_params, bool clear_destination,
|
||||||
bool clear_destination, int iteration);
|
int iteration);
|
||||||
|
|
||||||
VkInstance instance_ = VK_NULL_HANDLE;
|
VkInstance instance_ = VK_NULL_HANDLE;
|
||||||
VkDebugUtilsMessengerEXT debug_messenger_ = VK_NULL_HANDLE;
|
VkDebugUtilsMessengerEXT debug_messenger_ = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ public:
|
|||||||
|
|
||||||
bool InitializeRuntime()
|
bool InitializeRuntime()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Create a minimal Core instance so that code paths calling Core::instance()
|
// Create a minimal Core instance so that code paths calling Core::instance()
|
||||||
// (e.g. ViewerOutput::data for timecode display) do not dereference null.
|
// (e.g. ViewerOutput::data for timecode display) do not dereference null.
|
||||||
// The worker is short-lived; leaking this on exit is harmless.
|
// The worker is short-lived; leaking this on exit is harmless.
|
||||||
@@ -141,7 +140,8 @@ public:
|
|||||||
QJsonObject handshake = hs.ToJson();
|
QJsonObject handshake = hs.ToJson();
|
||||||
QOpenGLContext *ctx = nullptr;
|
QOpenGLContext *ctx = nullptr;
|
||||||
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
||||||
if (auto *dynamic_renderer = dynamic_cast<olive::DynamicRenderer *>(renderer_)) {
|
if (auto *dynamic_renderer =
|
||||||
|
dynamic_cast<olive::DynamicRenderer *>(renderer_)) {
|
||||||
ctx = dynamic_renderer->OpenGLContext();
|
ctx = dynamic_renderer->OpenGLContext();
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
@@ -164,7 +164,8 @@ public:
|
|||||||
if (type == QLatin1String(olive::ipc::msgtype::kHandshake)) {
|
if (type == QLatin1String(olive::ipc::msgtype::kHandshake)) {
|
||||||
olive::ipc::HandshakeMsg hs;
|
olive::ipc::HandshakeMsg hs;
|
||||||
if (!olive::ipc::HandshakeMsg::FromJson(message, &hs)) {
|
if (!olive::ipc::HandshakeMsg::FromJson(message, &hs)) {
|
||||||
return Write(ErrorMessage(QStringLiteral("invalid handshake message")));
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("invalid handshake message")));
|
||||||
}
|
}
|
||||||
return AttachOutputPool(hs);
|
return AttachOutputPool(hs);
|
||||||
}
|
}
|
||||||
@@ -172,7 +173,8 @@ public:
|
|||||||
if (type == QLatin1String(olive::ipc::msgtype::kLoadGraph)) {
|
if (type == QLatin1String(olive::ipc::msgtype::kLoadGraph)) {
|
||||||
olive::ipc::LoadGraphMsg load;
|
olive::ipc::LoadGraphMsg load;
|
||||||
if (!olive::ipc::LoadGraphMsg::FromJson(message, &load)) {
|
if (!olive::ipc::LoadGraphMsg::FromJson(message, &load)) {
|
||||||
return Write(ErrorMessage(QStringLiteral("invalid load_graph message")));
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("invalid load_graph message")));
|
||||||
}
|
}
|
||||||
return LoadGraph(load.path);
|
return LoadGraph(load.path);
|
||||||
}
|
}
|
||||||
@@ -180,7 +182,8 @@ public:
|
|||||||
if (type == QLatin1String(olive::ipc::msgtype::kRenderFrame)) {
|
if (type == QLatin1String(olive::ipc::msgtype::kRenderFrame)) {
|
||||||
olive::ipc::RenderFrameMsg render;
|
olive::ipc::RenderFrameMsg render;
|
||||||
if (!olive::ipc::RenderFrameMsg::FromJson(message, &render)) {
|
if (!olive::ipc::RenderFrameMsg::FromJson(message, &render)) {
|
||||||
return Write(ErrorMessage(QStringLiteral("invalid render_frame message")));
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("invalid render_frame message")));
|
||||||
}
|
}
|
||||||
return RenderFrame(render);
|
return RenderFrame(render);
|
||||||
}
|
}
|
||||||
@@ -195,7 +198,8 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Write(ErrorMessage(QStringLiteral("unknown message type: %1").arg(type)));
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("unknown message type: %1").arg(type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shutdown_requested() const
|
bool shutdown_requested() const
|
||||||
@@ -214,18 +218,23 @@ private:
|
|||||||
bool AttachOutputPool(const olive::ipc::HandshakeMsg &hs)
|
bool AttachOutputPool(const olive::ipc::HandshakeMsg &hs)
|
||||||
{
|
{
|
||||||
if (hs.protocol_version != kProtocolVersion) {
|
if (hs.protocol_version != kProtocolVersion) {
|
||||||
return Write(ErrorMessage(QStringLiteral("unsupported protocol version %1")
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("unsupported protocol version %1")
|
||||||
.arg(hs.protocol_version)));
|
.arg(hs.protocol_version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hs.shm_key.isEmpty() || hs.output_slots <= 0 || hs.slot_data_bytes <= 0) {
|
if (hs.shm_key.isEmpty() || hs.output_slots <= 0 ||
|
||||||
return Write(ErrorMessage(QStringLiteral("handshake missing output shared-memory geometry")));
|
hs.slot_data_bytes <= 0) {
|
||||||
|
return Write(ErrorMessage(QStringLiteral(
|
||||||
|
"handshake missing output shared-memory geometry")));
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t bytes = olive::ipc::FrameSlotPool::BytesNeeded(
|
const size_t bytes = olive::ipc::FrameSlotPool::BytesNeeded(
|
||||||
uint32_t(hs.output_slots), size_t(hs.slot_data_bytes));
|
uint32_t(hs.output_slots), size_t(hs.slot_data_bytes));
|
||||||
if (!output_region_.Open(hs.shm_key, bytes, olive::ipc::SharedMemoryRegion::kAttach)) {
|
if (!output_region_.Open(hs.shm_key, bytes,
|
||||||
return Write(ErrorMessage(QStringLiteral("failed to attach shared memory: %1")
|
olive::ipc::SharedMemoryRegion::kAttach)) {
|
||||||
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("failed to attach shared memory: %1")
|
||||||
.arg(output_region_.error())));
|
.arg(output_region_.error())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,29 +242,34 @@ private:
|
|||||||
if (!output_pool_->IsValid()) {
|
if (!output_pool_->IsValid()) {
|
||||||
output_region_.Close();
|
output_region_.Close();
|
||||||
output_pool_.reset();
|
output_pool_.reset();
|
||||||
return Write(ErrorMessage(QStringLiteral("shared memory does not contain a frame slot pool")));
|
return Write(ErrorMessage(QStringLiteral(
|
||||||
|
"shared memory does not contain a frame slot pool")));
|
||||||
}
|
}
|
||||||
|
|
||||||
input_pool_.reset();
|
input_pool_.reset();
|
||||||
input_region_.Close();
|
input_region_.Close();
|
||||||
if (hs.input_slots > 0) {
|
if (hs.input_slots > 0) {
|
||||||
if (hs.input_shm_key.isEmpty() || hs.input_slot_data_bytes <= 0) {
|
if (hs.input_shm_key.isEmpty() || hs.input_slot_data_bytes <= 0) {
|
||||||
return Write(ErrorMessage(QStringLiteral("handshake missing input shared-memory geometry")));
|
return Write(ErrorMessage(QStringLiteral(
|
||||||
|
"handshake missing input shared-memory geometry")));
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t input_bytes = olive::ipc::FrameSlotPool::BytesNeeded(
|
const size_t input_bytes = olive::ipc::FrameSlotPool::BytesNeeded(
|
||||||
uint32_t(hs.input_slots), size_t(hs.input_slot_data_bytes));
|
uint32_t(hs.input_slots), size_t(hs.input_slot_data_bytes));
|
||||||
if (!input_region_.Open(hs.input_shm_key, input_bytes,
|
if (!input_region_.Open(hs.input_shm_key, input_bytes,
|
||||||
olive::ipc::SharedMemoryRegion::kAttach)) {
|
olive::ipc::SharedMemoryRegion::kAttach)) {
|
||||||
return Write(ErrorMessage(QStringLiteral("failed to attach input shared memory: %1")
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("failed to attach input shared memory: %1")
|
||||||
.arg(input_region_.error())));
|
.arg(input_region_.error())));
|
||||||
}
|
}
|
||||||
|
|
||||||
input_pool_ = olive::ipc::FrameSlotPool::Attach(input_region_.data());
|
input_pool_ =
|
||||||
|
olive::ipc::FrameSlotPool::Attach(input_region_.data());
|
||||||
if (!input_pool_->IsValid()) {
|
if (!input_pool_->IsValid()) {
|
||||||
input_region_.Close();
|
input_region_.Close();
|
||||||
input_pool_.reset();
|
input_pool_.reset();
|
||||||
return Write(ErrorMessage(QStringLiteral("input shared memory does not contain a frame slot pool")));
|
return Write(ErrorMessage(QStringLiteral(
|
||||||
|
"input shared memory does not contain a frame slot pool")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,14 +281,20 @@ private:
|
|||||||
{
|
{
|
||||||
QFileInfo fi(path);
|
QFileInfo fi(path);
|
||||||
if (!fi.exists()) {
|
if (!fi.exists()) {
|
||||||
LogError(QStringLiteral("LoadGraph: graph file does not exist: %1").arg(path));
|
LogError(
|
||||||
return Write(ErrorMessage(QStringLiteral("graph file does not exist: %1").arg(path)));
|
QStringLiteral("LoadGraph: graph file does not exist: %1")
|
||||||
|
.arg(path));
|
||||||
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("graph file does not exist: %1").arg(path)));
|
||||||
}
|
}
|
||||||
if (fi.size() == 0) {
|
if (fi.size() == 0) {
|
||||||
LogError(QStringLiteral("LoadGraph: graph file is empty: %1").arg(path));
|
LogError(QStringLiteral("LoadGraph: graph file is empty: %1")
|
||||||
return Write(ErrorMessage(QStringLiteral("graph file is empty: %1").arg(path)));
|
.arg(path));
|
||||||
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("graph file is empty: %1").arg(path)));
|
||||||
}
|
}
|
||||||
LogError(QStringLiteral("LoadGraph: loading %1 (%2 bytes, readable=%3)")
|
LogError(
|
||||||
|
QStringLiteral("LoadGraph: loading %1 (%2 bytes, readable=%3)")
|
||||||
.arg(path)
|
.arg(path)
|
||||||
.arg(fi.size())
|
.arg(fi.size())
|
||||||
.arg(fi.isReadable()));
|
.arg(fi.isReadable()));
|
||||||
@@ -286,9 +306,11 @@ private:
|
|||||||
// Initialize() first triggers Q_ASSERT(!root_) in Project::Load.
|
// Initialize() first triggers Q_ASSERT(!root_) in Project::Load.
|
||||||
|
|
||||||
olive::ProjectSerializer::Result result =
|
olive::ProjectSerializer::Result result =
|
||||||
olive::ProjectSerializer::Load(loaded.get(), path, olive::ProjectSerializer::kProject);
|
olive::ProjectSerializer::Load(loaded.get(), path,
|
||||||
|
olive::ProjectSerializer::kProject);
|
||||||
if (result != olive::ProjectSerializer::kSuccess) {
|
if (result != olive::ProjectSerializer::kSuccess) {
|
||||||
return Write(ErrorMessage(QStringLiteral("failed to load graph %1: %2")
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("failed to load graph %1: %2")
|
||||||
.arg(path, result.GetDetails())));
|
.arg(path, result.GetDetails())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,12 +319,15 @@ private:
|
|||||||
color_processor_cache_.clear();
|
color_processor_cache_.clear();
|
||||||
|
|
||||||
const auto &data = result.GetLoadData();
|
const auto &data = result.GetLoadData();
|
||||||
for (auto it = data.node_ptrs.cbegin(); it != data.node_ptrs.cend(); ++it) {
|
for (auto it = data.node_ptrs.cbegin(); it != data.node_ptrs.cend();
|
||||||
|
++it) {
|
||||||
node_by_token_.insert(QString::number(it.key()), it.value());
|
node_by_token_.insert(QString::number(it.key()), it.value());
|
||||||
}
|
}
|
||||||
for (auto it = data.node_uuids.cbegin(); it != data.node_uuids.cend(); ++it) {
|
for (auto it = data.node_uuids.cbegin(); it != data.node_uuids.cend();
|
||||||
|
++it) {
|
||||||
node_by_token_.insert(it.value().toString(), it.key());
|
node_by_token_.insert(it.value().toString(), it.key());
|
||||||
node_by_token_.insert(it.value().toString(QUuid::WithoutBraces), it.key());
|
node_by_token_.insert(it.value().toString(QUuid::WithoutBraces),
|
||||||
|
it.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject ack;
|
QJsonObject ack;
|
||||||
@@ -329,28 +354,35 @@ private:
|
|||||||
bool RenderFrame(const olive::ipc::RenderFrameMsg &message)
|
bool RenderFrame(const olive::ipc::RenderFrameMsg &message)
|
||||||
{
|
{
|
||||||
if (!project_) {
|
if (!project_) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render_frame received before load_graph"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("render_frame received before load_graph"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
if (!output_pool_ || !output_pool_->IsValid()) {
|
if (!output_pool_ || !output_pool_->IsValid()) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render_frame received before output shm handshake"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral(
|
||||||
|
"render_frame received before output shm handshake"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::Node *node = FindNode(message.node_uuid);
|
olive::Node *node = FindNode(message.node_uuid);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render node not found: %1").arg(message.node_uuid),
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("render node not found: %1")
|
||||||
|
.arg(message.node_uuid),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<int> input_slots;
|
QVector<int> input_slots;
|
||||||
const QVector<int> requested_input_slots =
|
const QVector<int> requested_input_slots =
|
||||||
message.input_slots.isEmpty() && message.input_slot >= 0
|
message.input_slots.isEmpty() && message.input_slot >= 0 ?
|
||||||
? QVector<int>{message.input_slot}
|
QVector<int>{ message.input_slot } :
|
||||||
: message.input_slots;
|
message.input_slots;
|
||||||
if (!requested_input_slots.isEmpty()) {
|
if (!requested_input_slots.isEmpty()) {
|
||||||
if (!input_pool_ || !input_pool_->IsValid()) {
|
if (!input_pool_ || !input_pool_->IsValid()) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render_frame referenced input slot without input pool"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral(
|
||||||
|
"render_frame referenced input slot without input pool"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +392,8 @@ private:
|
|||||||
for (int slot : input_slots) {
|
for (int slot : input_slots) {
|
||||||
input_pool_->Release(uint32_t(slot));
|
input_pool_->Release(uint32_t(slot));
|
||||||
}
|
}
|
||||||
return Write(ErrorMessage(QStringLiteral("input slot index out of range"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("input slot index out of range"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +402,8 @@ private:
|
|||||||
for (int slot : input_slots) {
|
for (int slot : input_slots) {
|
||||||
input_pool_->Release(uint32_t(slot));
|
input_pool_->Release(uint32_t(slot));
|
||||||
}
|
}
|
||||||
return Write(ErrorMessage(QStringLiteral("input slot was not ready"),
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("input slot was not ready"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
if (int(consumed_slot) != requested_slot) {
|
if (int(consumed_slot) != requested_slot) {
|
||||||
@@ -377,7 +411,8 @@ private:
|
|||||||
for (int slot : input_slots) {
|
for (int slot : input_slots) {
|
||||||
input_pool_->Release(uint32_t(slot));
|
input_pool_->Release(uint32_t(slot));
|
||||||
}
|
}
|
||||||
return Write(ErrorMessage(QStringLiteral("input slot order mismatch"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("input slot order mismatch"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
input_slots.append(int(consumed_slot));
|
input_slots.append(int(consumed_slot));
|
||||||
@@ -389,37 +424,37 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::VideoParams vparams(message.width > 0 ? message.width : kDefaultWidth,
|
olive::VideoParams vparams(
|
||||||
|
message.width > 0 ? message.width : kDefaultWidth,
|
||||||
message.height > 0 ? message.height : kDefaultHeight,
|
message.height > 0 ? message.height : kDefaultHeight,
|
||||||
olive::rational(1, kDefaultFrameRate),
|
olive::rational(1, kDefaultFrameRate),
|
||||||
message.format >= 0
|
message.format >= 0 ? olive::PixelFormat::Format(message.format) :
|
||||||
? olive::PixelFormat::Format(message.format)
|
olive::PixelFormat::F32,
|
||||||
: olive::PixelFormat::F32,
|
message.channel_count > 0 ? message.channel_count :
|
||||||
message.channel_count > 0
|
olive::VideoParams::kRGBAChannelCount);
|
||||||
? message.channel_count
|
|
||||||
: olive::VideoParams::kRGBAChannelCount);
|
|
||||||
|
|
||||||
olive::RenderTicketPtr ticket = std::make_shared<olive::RenderTicket>();
|
olive::RenderTicketPtr ticket = std::make_shared<olive::RenderTicket>();
|
||||||
ticket->setProperty("node", olive::QtUtils::PtrToValue(node));
|
ticket->setProperty("node", olive::QtUtils::PtrToValue(node));
|
||||||
ticket->setProperty("time", QVariant::fromValue(
|
ticket->setProperty("time",
|
||||||
olive::rational(int(message.time_num), int(message.time_den))));
|
QVariant::fromValue(olive::rational(
|
||||||
|
int(message.time_num), int(message.time_den))));
|
||||||
ticket->setProperty("size", QSize(message.width, message.height));
|
ticket->setProperty("size", QSize(message.width, message.height));
|
||||||
ticket->setProperty("matrix", QMatrix4x4());
|
ticket->setProperty("matrix", QMatrix4x4());
|
||||||
ticket->setProperty("format",
|
ticket->setProperty("format",
|
||||||
message.format >= 0
|
message.format >= 0 ?
|
||||||
? olive::PixelFormat::Format(message.format)
|
olive::PixelFormat::Format(message.format) :
|
||||||
: olive::PixelFormat::INVALID);
|
olive::PixelFormat::INVALID);
|
||||||
ticket->setProperty("usecache", false);
|
ticket->setProperty("usecache", false);
|
||||||
ticket->setProperty("channelcount", message.channel_count);
|
ticket->setProperty("channelcount", message.channel_count);
|
||||||
ticket->setProperty("mode", olive::RenderMode::Mode(message.mode));
|
ticket->setProperty("mode", olive::RenderMode::Mode(message.mode));
|
||||||
ticket->setProperty("type", olive::RenderManager::kTypeVideo);
|
ticket->setProperty("type", olive::RenderManager::kTypeVideo);
|
||||||
ticket->setProperty("colormanager", olive::QtUtils::PtrToValue(project_->color_manager()));
|
ticket->setProperty("colormanager", olive::QtUtils::PtrToValue(
|
||||||
|
project_->color_manager()));
|
||||||
|
|
||||||
{
|
{
|
||||||
olive::ColorProcessorPtr color_output;
|
olive::ColorProcessorPtr color_output;
|
||||||
if (message.has_color_transform) {
|
if (message.has_color_transform) {
|
||||||
QString cache_key =
|
QString cache_key = QStringLiteral("%1|%2|%3|%4")
|
||||||
QStringLiteral("%1|%2|%3|%4")
|
|
||||||
.arg(message.color_is_display ? 1 : 0)
|
.arg(message.color_is_display ? 1 : 0)
|
||||||
.arg(message.color_output,
|
.arg(message.color_output,
|
||||||
message.color_view,
|
message.color_view,
|
||||||
@@ -449,16 +484,20 @@ private:
|
|||||||
QVariant::fromValue(color_output));
|
QVariant::fromValue(color_output));
|
||||||
}
|
}
|
||||||
ticket->setProperty("vparam", QVariant::fromValue(vparams));
|
ticket->setProperty("vparam", QVariant::fromValue(vparams));
|
||||||
ticket->setProperty("aparam", QVariant::fromValue(olive::AudioParams()));
|
ticket->setProperty("aparam",
|
||||||
|
QVariant::fromValue(olive::AudioParams()));
|
||||||
ticket->setProperty("return", olive::RenderManager::kFrame);
|
ticket->setProperty("return", olive::RenderManager::kFrame);
|
||||||
ticket->setProperty("cache", QString());
|
ticket->setProperty("cache", QString());
|
||||||
ticket->setProperty("cachetimebase", QVariant::fromValue(olive::rational(1)));
|
ticket->setProperty("cachetimebase",
|
||||||
|
QVariant::fromValue(olive::rational(1)));
|
||||||
ticket->setProperty("cacheid", QVariant::fromValue(QUuid()));
|
ticket->setProperty("cacheid", QVariant::fromValue(QUuid()));
|
||||||
ticket->setProperty("multicam", olive::QtUtils::PtrToValue(static_cast<void *>(nullptr)));
|
ticket->setProperty("multicam", olive::QtUtils::PtrToValue(
|
||||||
ticket->setProperty("ipc_input_pool",
|
static_cast<void *>(nullptr)));
|
||||||
olive::QtUtils::PtrToValue(
|
ticket->setProperty(
|
||||||
input_pool_ ? static_cast<void *>(&*input_pool_)
|
"ipc_input_pool",
|
||||||
: static_cast<void *>(nullptr)));
|
olive::QtUtils::PtrToValue(input_pool_ ?
|
||||||
|
static_cast<void *>(&*input_pool_) :
|
||||||
|
static_cast<void *>(nullptr)));
|
||||||
QVariantList input_slot_values;
|
QVariantList input_slot_values;
|
||||||
for (int slot : input_slots) {
|
for (int slot : input_slots) {
|
||||||
input_slot_values.append(slot);
|
input_slot_values.append(slot);
|
||||||
@@ -469,34 +508,42 @@ private:
|
|||||||
input_slots.isEmpty() ? -1 : input_slots.front());
|
input_slots.isEmpty() ? -1 : input_slots.front());
|
||||||
|
|
||||||
ticket->Start();
|
ticket->Start();
|
||||||
olive::RenderProcessor::Process(ticket, renderer_, nullptr, &shader_cache_);
|
olive::RenderProcessor::Process(ticket, renderer_, nullptr,
|
||||||
|
&shader_cache_);
|
||||||
for (int slot : input_slots) {
|
for (int slot : input_slots) {
|
||||||
input_pool_->Release(uint32_t(slot));
|
input_pool_->Release(uint32_t(slot));
|
||||||
}
|
}
|
||||||
if (!ticket->HasResult()) {
|
if (!ticket->HasResult()) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render produced no frame"), message.ticket_id));
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("render produced no frame"), message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::FramePtr frame = ticket->Get().value<olive::FramePtr>();
|
olive::FramePtr frame = ticket->Get().value<olive::FramePtr>();
|
||||||
if (!frame || !frame->is_allocated()) {
|
if (!frame || !frame->is_allocated()) {
|
||||||
return Write(ErrorMessage(QStringLiteral("render result was empty"), message.ticket_id));
|
return Write(ErrorMessage(QStringLiteral("render result was empty"),
|
||||||
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t slot = 0;
|
uint32_t slot = 0;
|
||||||
if (!output_pool_->Acquire(&slot)) {
|
if (!output_pool_->Acquire(&slot)) {
|
||||||
return Write(ErrorMessage(QStringLiteral("no free output frame slot"), message.ticket_id));
|
return Write(
|
||||||
|
ErrorMessage(QStringLiteral("no free output frame slot"),
|
||||||
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int data_size = frame->linesize_bytes() * frame->height();
|
const int data_size = frame->linesize_bytes() * frame->height();
|
||||||
if (data_size > int(output_pool_->slot_data_bytes())) {
|
if (data_size > int(output_pool_->slot_data_bytes())) {
|
||||||
output_pool_->Release(slot);
|
output_pool_->Release(slot);
|
||||||
LogError(QString("Output frame size") + QString::number(data_size));
|
LogError(QString("Output frame size") + QString::number(data_size));
|
||||||
LogError(QString("Slot size")+QString::number(output_pool_->slot_data_bytes()));
|
LogError(QString("Slot size") +
|
||||||
return Write(ErrorMessage(QStringLiteral("rendered frame does not fit output slot "),
|
QString::number(output_pool_->slot_data_bytes()));
|
||||||
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("rendered frame does not fit output slot "),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(output_pool_->SlotData(slot), frame->const_data(), size_t(data_size));
|
std::memcpy(output_pool_->SlotData(slot), frame->const_data(),
|
||||||
|
size_t(data_size));
|
||||||
olive::ipc::FrameSlotMeta *meta = output_pool_->Meta(slot);
|
olive::ipc::FrameSlotMeta *meta = output_pool_->Meta(slot);
|
||||||
meta->id = message.ticket_id;
|
meta->id = message.ticket_id;
|
||||||
meta->time_num = frame->timestamp().numerator();
|
meta->time_num = frame->timestamp().numerator();
|
||||||
@@ -510,7 +557,8 @@ private:
|
|||||||
|
|
||||||
if (!output_pool_->Publish(slot)) {
|
if (!output_pool_->Publish(slot)) {
|
||||||
output_pool_->Release(slot);
|
output_pool_->Release(slot);
|
||||||
return Write(ErrorMessage(QStringLiteral("failed to publish output frame slot"),
|
return Write(ErrorMessage(
|
||||||
|
QStringLiteral("failed to publish output frame slot"),
|
||||||
message.ticket_id));
|
message.ticket_id));
|
||||||
}
|
}
|
||||||
olive::ipc::FrameReadyMsg ready;
|
olive::ipc::FrameReadyMsg ready;
|
||||||
@@ -600,7 +648,8 @@ int main(int argc, char *argv[])
|
|||||||
QOpenGLContext *ctx = nullptr;
|
QOpenGLContext *ctx = nullptr;
|
||||||
if (backend == QStringLiteral("opengl")) {
|
if (backend == QStringLiteral("opengl")) {
|
||||||
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
|
||||||
if (auto *loaded_renderer = dynamic_cast<olive::DynamicRenderer *>(renderer)) {
|
if (auto *loaded_renderer =
|
||||||
|
dynamic_cast<olive::DynamicRenderer *>(renderer)) {
|
||||||
ctx = loaded_renderer->OpenGLContext();
|
ctx = loaded_renderer->OpenGLContext();
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
@@ -639,7 +688,8 @@ int main(int argc, char *argv[])
|
|||||||
if (!olive::ipc::ReadMessage(&buffer, &message, &ok)) {
|
if (!olive::ipc::ReadMessage(&buffer, &message, &ok)) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
olive::ipc::WriteMessage(
|
olive::ipc::WriteMessage(
|
||||||
&out, ErrorMessage(QStringLiteral("malformed control message")));
|
&out, ErrorMessage(QStringLiteral(
|
||||||
|
"malformed control message")));
|
||||||
out.flush();
|
out.flush();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList &filenames,
|
|||||||
|
|
||||||
setWindowTitle(tr("Import Error"));
|
setWindowTitle(tr("Import Error"));
|
||||||
|
|
||||||
layout->addWidget(new QLabel(
|
layout->addWidget(new QLabel(tr(
|
||||||
tr("The following files failed to import. Oak Video Editor likely does not "
|
"The following files failed to import. Oak Video Editor likely does not "
|
||||||
"support their formats.")));
|
"support their formats.")));
|
||||||
|
|
||||||
QListWidget *list_widget = new QListWidget();
|
QListWidget *list_widget = new QListWidget();
|
||||||
|
|||||||
+19
-18
@@ -29,8 +29,7 @@
|
|||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
|
|
||||||
ProxyTask::ProxyTask(const QString &source_filename,
|
ProxyTask::ProxyTask(const QString &source_filename, int stream_index,
|
||||||
int stream_index,
|
|
||||||
const ProxyManager::ProxyParams ¶ms,
|
const ProxyManager::ProxyParams ¶ms,
|
||||||
const QString &output_filename)
|
const QString &output_filename)
|
||||||
: source_filename_(source_filename)
|
: source_filename_(source_filename)
|
||||||
@@ -44,9 +43,11 @@ ProxyTask::ProxyTask(const QString &source_filename,
|
|||||||
|
|
||||||
bool ProxyTask::Run()
|
bool ProxyTask::Run()
|
||||||
{
|
{
|
||||||
const QString ffmpeg = QStandardPaths::findExecutable(QStringLiteral("ffmpeg"));
|
const QString ffmpeg =
|
||||||
|
QStandardPaths::findExecutable(QStringLiteral("ffmpeg"));
|
||||||
if (ffmpeg.isEmpty()) {
|
if (ffmpeg.isEmpty()) {
|
||||||
SetError(tr("Failed to generate proxy: ffmpeg executable was not found"));
|
SetError(
|
||||||
|
tr("Failed to generate proxy: ffmpeg executable was not found"));
|
||||||
qWarning() << "ProxyTask: ffmpeg executable not found";
|
qWarning() << "ProxyTask: ffmpeg executable not found";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -59,13 +60,14 @@ bool ProxyTask::Run()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "ProxyTask: starting ffmpeg proxy generation:"
|
qDebug()
|
||||||
<< source_filename_ << "->" << output_filename_;
|
<< "ProxyTask: starting ffmpeg proxy generation:" << source_filename_
|
||||||
|
<< "->" << output_filename_;
|
||||||
|
|
||||||
QFile::remove(output_filename_);
|
QFile::remove(output_filename_);
|
||||||
|
|
||||||
const QString scale_filter = QStringLiteral(
|
const QString scale_filter =
|
||||||
"scale=w=%1:h=%2:force_original_aspect_ratio=decrease")
|
QStringLiteral("scale=w=%1:h=%2:force_original_aspect_ratio=decrease")
|
||||||
.arg(QString::number(params_.width),
|
.arg(QString::number(params_.width),
|
||||||
QString::number(params_.height));
|
QString::number(params_.height));
|
||||||
|
|
||||||
@@ -73,18 +75,15 @@ bool ProxyTask::Run()
|
|||||||
params_.extension.isEmpty() ? QStringLiteral("mp4") : params_.extension;
|
params_.extension.isEmpty() ? QStringLiteral("mp4") : params_.extension;
|
||||||
|
|
||||||
QStringList args;
|
QStringList args;
|
||||||
args << QStringLiteral("-y")
|
args << QStringLiteral("-y") << QStringLiteral("-i") << source_filename_
|
||||||
<< QStringLiteral("-i") << source_filename_
|
|
||||||
<< QStringLiteral("-map") << QStringLiteral("0:%1").arg(stream_index_)
|
<< QStringLiteral("-map") << QStringLiteral("0:%1").arg(stream_index_)
|
||||||
<< QStringLiteral("-an")
|
<< QStringLiteral("-an") << QStringLiteral("-vf") << scale_filter
|
||||||
<< QStringLiteral("-vf") << scale_filter
|
|
||||||
<< QStringLiteral("-c:v") << QStringLiteral("libx264")
|
<< QStringLiteral("-c:v") << QStringLiteral("libx264")
|
||||||
<< QStringLiteral("-preset") << params_.preset
|
<< QStringLiteral("-preset") << params_.preset
|
||||||
<< QStringLiteral("-crf") << QString::number(params_.crf)
|
<< QStringLiteral("-crf") << QString::number(params_.crf)
|
||||||
<< QStringLiteral("-pix_fmt") << QStringLiteral("yuv420p")
|
<< QStringLiteral("-pix_fmt") << QStringLiteral("yuv420p")
|
||||||
<< QStringLiteral("-movflags") << QStringLiteral("+faststart")
|
<< QStringLiteral("-movflags") << QStringLiteral("+faststart")
|
||||||
<< QStringLiteral("-f") << container_format
|
<< QStringLiteral("-f") << container_format << output_filename_;
|
||||||
<< output_filename_;
|
|
||||||
|
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.setProgram(ffmpeg);
|
process.setProgram(ffmpeg);
|
||||||
@@ -94,7 +93,8 @@ bool ProxyTask::Run()
|
|||||||
|
|
||||||
if (!process.waitForStarted()) {
|
if (!process.waitForStarted()) {
|
||||||
SetError(tr("Failed to start ffmpeg for proxy generation"));
|
SetError(tr("Failed to start ffmpeg for proxy generation"));
|
||||||
qWarning() << "ProxyTask: failed to start ffmpeg" << process.errorString();
|
qWarning()
|
||||||
|
<< "ProxyTask: failed to start ffmpeg" << process.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,12 +108,13 @@ bool ProxyTask::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
|
if (process.exitStatus() != QProcess::NormalExit ||
|
||||||
|
process.exitCode() != 0) {
|
||||||
const QString output = QString::fromUtf8(process.readAll()).trimmed();
|
const QString output = QString::fromUtf8(process.readAll()).trimmed();
|
||||||
QFile::remove(output_filename_);
|
QFile::remove(output_filename_);
|
||||||
SetError(tr("ffmpeg failed to generate proxy: %1").arg(output));
|
SetError(tr("ffmpeg failed to generate proxy: %1").arg(output));
|
||||||
qWarning() << "ProxyTask: ffmpeg failed with exit code" << process.exitCode()
|
qWarning() << "ProxyTask: ffmpeg failed with exit code"
|
||||||
<< "output:" << output;
|
<< process.exitCode() << "output:" << output;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ namespace olive
|
|||||||
class ProxyTask : public Task {
|
class ProxyTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ProxyTask(const QString &source_filename,
|
ProxyTask(const QString &source_filename, int stream_index,
|
||||||
int stream_index,
|
|
||||||
const ProxyManager::ProxyParams ¶ms,
|
const ProxyManager::ProxyParams ¶ms,
|
||||||
const QString &output_filename);
|
const QString &output_filename);
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ private:
|
|||||||
const rational &time, RenderMode::Mode mode,
|
const rational &time, RenderMode::Mode mode,
|
||||||
FrameHashCache *cache, const QSize &force_size,
|
FrameHashCache *cache, const QSize &force_size,
|
||||||
const QMatrix4x4 &force_matrix, PixelFormat force_format,
|
const QMatrix4x4 &force_matrix, PixelFormat force_format,
|
||||||
int force_channel_count, ColorProcessorPtr force_color_output,
|
int force_channel_count,
|
||||||
|
ColorProcessorPtr force_color_output,
|
||||||
const ColorTransform &force_color_transform);
|
const ColorTransform &force_color_transform);
|
||||||
|
|
||||||
ViewerOutput *viewer_;
|
ViewerOutput *viewer_;
|
||||||
|
|||||||
+5302
-1992
File diff suppressed because it is too large
Load Diff
+5305
-1987
File diff suppressed because it is too large
Load Diff
+6014
-1927
File diff suppressed because it is too large
Load Diff
+6238
-1874
File diff suppressed because it is too large
Load Diff
+5128
-1963
File diff suppressed because it is too large
Load Diff
+6194
-1943
File diff suppressed because it is too large
Load Diff
+5532
-1981
File diff suppressed because it is too large
Load Diff
+5273
-1985
File diff suppressed because it is too large
Load Diff
+5312
-1995
File diff suppressed because it is too large
Load Diff
+5218
-1891
File diff suppressed because it is too large
Load Diff
+4989
-1668
File diff suppressed because it is too large
Load Diff
+5354
-1989
File diff suppressed because it is too large
Load Diff
+11809
-4216
File diff suppressed because it is too large
Load Diff
+5308
-1988
File diff suppressed because it is too large
Load Diff
+5331
-1995
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user