format: reformatting files

This commit is contained in:
2026-07-13 15:30:43 +08:00
parent 7522543c48
commit e5eeaddf2f
511 changed files with 274803 additions and 207140 deletions
+4 -3
View File
@@ -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;
} }
+4 -5
View File
@@ -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;
+4 -4
View File
@@ -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);
}; };
+3 -3
View File
@@ -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;
+2 -2
View File
@@ -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,
+77 -60
View File
@@ -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 &timestamp) const rational &timestamp)
{ {
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;
} }
+2 -1
View File
@@ -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 &params, const AudioParams &params,
CancelAtom *cancelled) override; CancelAtom *cancelled) override;
+2 -1
View File
@@ -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;
} }
+2 -1
View File
@@ -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
View File
@@ -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 &params) const QString &source_filename, int stream_index,
const ProxyParams &params)
{ {
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));
+1 -2
View File
@@ -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 &params); const ProxyParams &params);
signals: signals:
+9 -8
View File
@@ -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(
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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()) {
+2 -2
View File
@@ -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);
+2 -1
View File
@@ -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."),
+2 -1
View File
@@ -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()
-1
View File
@@ -26,7 +26,6 @@
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
namespace olive namespace olive
{ {
-1
View File
@@ -24,7 +24,6 @@
#include <QGridLayout> #include <QGridLayout>
#include <QLabel> #include <QLabel>
namespace olive namespace olive
{ {
+6 -3
View File
@@ -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
{ {
-1
View File
@@ -27,7 +27,6 @@
#include <QPushButton> #include <QPushButton>
#include <QVBoxLayout> #include <QVBoxLayout>
namespace olive namespace olive
{ {
+6 -8
View File
@@ -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) {
+10 -8
View File
@@ -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(
+4 -7
View File
@@ -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
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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 *> &params) const std::map<std::string, OFX::Host::Param::Instance *> &params)
{ {
QHash<QString, QVariant> defaults; QHash<QString, QVariant> defaults;
for (const auto &param : params) { for (const auto &param : 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 *) {}));
} }
+2 -5
View File
@@ -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
+5 -7
View File
@@ -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();
+5 -9
View File
@@ -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"),
+2 -5
View File
@@ -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);
} }
+5 -4
View File
@@ -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
+3 -1
View File
@@ -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 &params, SampleBuffer CreateSampleBuffer(const AudioParams &params,
const rational &length) const rational &length)
{ {
+1 -2
View File
@@ -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();
} }
} }
+1
View File
@@ -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
+60 -68
View File
@@ -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 &params) const olive::VideoParams &params)
{ {
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 &params)
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;
+10 -8
View File
@@ -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 &params) OFX::Host::ImageEffect::ClipDescriptor &desc,
VideoParams &params)
: 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 &params); void setParams(const VideoParams &params);
#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
+26 -18
View File
@@ -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;
+32 -26
View File
@@ -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
+23 -24
View File
@@ -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
View File
@@ -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 &params, const VideoParams &params, 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 &params, void Image::AllocateFromParams(const VideoParams &params,
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 &params, void Image::EnsureAllocatedFromParams(const VideoParams &params,
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 &params,
} }
} }
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
View File
@@ -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 &params, const VideoParams &params, 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 &params, void AllocateFromParams(const VideoParams &params, const OfxRectI &bounds,
const OfxRectI &bounds, const OfxRectI &rod, bool clear = true);
const OfxRectI &rod,
bool clear = true);
void EnsureAllocatedFromParams(const VideoParams &params, void EnsureAllocatedFromParams(const VideoParams &params,
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_;
+1 -3
View File
@@ -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;
+105 -82
View File
@@ -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
+21 -16
View File
@@ -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 &params, const void *data, const VideoParams &params,
int linesize) const void *data, int linesize)
{ {
upload_to_texture_(handle_, &handle, &params, data, linesize); upload_to_texture_(handle_, &handle, &params, 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;
+3 -3
View File
@@ -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
View File
@@ -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,
+11 -8
View File
@@ -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,
+4 -2
View File
@@ -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)
+12 -6
View File
@@ -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;
+2 -2
View File
@@ -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;
+10 -5
View File
@@ -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.
+13 -7
View File
@@ -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;
+2 -1
View File
@@ -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");
}; };
+4 -2
View File
@@ -19,7 +19,9 @@
#include "pluginjob.h" #include "pluginjob.h"
namespace olive { namespace olive
namespace plugin { {
namespace plugin
{
} // plugin } // plugin
} // olive } // olive
+10 -5
View File
@@ -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_;
} }
+69 -50
View File
@@ -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();
} }
+49 -36
View File
@@ -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
+13 -7
View File
@@ -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 &params); int BytesToPixels(int byte_linesize, const olive::VideoParams &params);
@@ -46,9 +48,15 @@ int BytesToPixels(int byte_linesize, const olive::VideoParams &params);
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
+6 -3
View File
@@ -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();
+7 -4
View File
@@ -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(),
+7 -5
View File
@@ -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,
+13 -8
View File
@@ -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 &params)
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();
} }
+42 -40
View File
@@ -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());
+2 -1
View File
@@ -32,7 +32,8 @@
namespace olive namespace olive
{ {
namespace plugin { namespace plugin
{
class PluginRenderer; class PluginRenderer;
} }
+129 -119
View File
@@ -62,8 +62,8 @@ struct FootageInput {
class FootageInputCollector : public NodeTraverser { class FootageInputCollector : public NodeTraverser {
public: public:
QVector<FootageInput> Collect(const RenderManager::RenderVideoParams &params, QVector<FootageInput>
CancelAtom *cancel) Collect(const RenderManager::RenderVideoParams &params, 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 &params, const RenderManager::RenderVideoParams &params,
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 &params) RenderTicketPtr ticket, const RenderManager::RenderVideoParams &params)
{ {
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 &params) const bool RenderWorkerPool::IsSupported(
const RenderManager::RenderVideoParams &params) 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;
+6 -7
View File
@@ -114,8 +114,7 @@ private:
}; };
bool PrepareJob(RenderTicketPtr ticket, bool PrepareJob(RenderTicketPtr ticket,
const RenderManager::RenderVideoParams &params, const RenderManager::RenderVideoParams &params, Job *job);
Job *job);
bool WriteGraphSnapshot(Project *project, QString *path); bool WriteGraphSnapshot(Project *project, QString *path);
bool IsSupported(const RenderManager::RenderVideoParams &params) const; bool IsSupported(const RenderManager::RenderVideoParams &params) 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_;
+3 -1
View File
@@ -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
{ {
+71 -53
View File
@@ -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
+12 -8
View File
@@ -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;
+118 -68
View File
@@ -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
View File
@@ -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 &params, const ProxyManager::ProxyParams &params,
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;
} }
+1 -2
View File
@@ -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 &params, const ProxyManager::ProxyParams &params,
const QString &output_filename); const QString &output_filename);
+2 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+5305 -1987
View File
File diff suppressed because it is too large Load Diff
+6014 -1927
View File
File diff suppressed because it is too large Load Diff
+6238 -1874
View File
File diff suppressed because it is too large Load Diff
+5128 -1963
View File
File diff suppressed because it is too large Load Diff
+6194 -1943
View File
File diff suppressed because it is too large Load Diff
+5532 -1981
View File
File diff suppressed because it is too large Load Diff
+5273 -1985
View File
File diff suppressed because it is too large Load Diff
+5312 -1995
View File
File diff suppressed because it is too large Load Diff
+5218 -1891
View File
File diff suppressed because it is too large Load Diff
+4989 -1668
View File
File diff suppressed because it is too large Load Diff
+5354 -1989
View File
File diff suppressed because it is too large Load Diff
+11809 -4216
View File
File diff suppressed because it is too large Load Diff
+5308 -1988
View File
File diff suppressed because it is too large Load Diff
+5331 -1995
View File
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