diff --git a/app/render/renderworkerpool.cpp b/app/render/renderworkerpool.cpp index cb859c0bb..b67ba2ad9 100644 --- a/app/render/renderworkerpool.cpp +++ b/app/render/renderworkerpool.cpp @@ -145,6 +145,17 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache, { VideoParams stream_data = input.job.video_params(); QString filename = input.job.filename(); + QString decoder_id = input.job.decoder(); + int stream_index = stream_data.stream_index(); + + // Use generated proxy if one is attached to the job. The Footage node only + // attaches a proxy when it is enabled, ready, and matches this stream. + if (input.job.has_proxy()) { + filename = input.job.proxy_filename(); + decoder_id = input.job.proxy_decoder(); + stream_index = input.job.proxy_stream_index(); + } + DecoderPtr decoder; switch (stream_data.video_type()) { @@ -152,17 +163,17 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache, case VideoParams::kVideoTypeStill: decoder = ResolveDecoderFromCache( decoder_cache, - input.job.decoder(), - Decoder::CodecStream(filename, stream_data.stream_index(), nullptr)); + decoder_id, + Decoder::CodecStream(filename, stream_index, nullptr)); break; case VideoParams::kVideoTypeImageSequence: { const int64_t frame_number = stream_data.get_time_in_timebase_units(input.time); filename = Decoder::TransformImageSequenceFileName(filename, frame_number); - decoder = Decoder::CreateFromID(input.job.decoder()); + decoder = Decoder::CreateFromID(decoder_id); if (decoder && !decoder->Open(Decoder::CodecStream(filename, - stream_data.stream_index(), + stream_index, nullptr))) { decoder = nullptr; } diff --git a/app/task/proxy/proxy.cpp b/app/task/proxy/proxy.cpp index 42a1e0b4c..475bf51ad 100644 --- a/app/task/proxy/proxy.cpp +++ b/app/task/proxy/proxy.cpp @@ -1,20 +1,22 @@ -/* - * Oak Video Editor - Non-Linear Video Editor - * Copyright (C) 2026 Oak Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/*** + + Oak - Non-Linear Video Editor + Copyright (C) 2026 Oak Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ #include "proxy.h" @@ -45,21 +47,27 @@ bool ProxyTask::Run() const QString ffmpeg = QStandardPaths::findExecutable(QStringLiteral("ffmpeg")); if (ffmpeg.isEmpty()) { SetError(tr("Failed to generate proxy: ffmpeg executable was not found")); + qWarning() << "ProxyTask: ffmpeg executable not found"; return false; } QDir output_dir = QFileInfo(output_filename_).dir(); if (!output_dir.exists() && !output_dir.mkpath(QStringLiteral("."))) { SetError(tr("Failed to create proxy output directory")); + qWarning() << "ProxyTask: failed to create output directory" + << output_dir.absolutePath(); return false; } + qDebug() << "ProxyTask: starting ffmpeg proxy generation:" + << source_filename_ << "->" << output_filename_; + QFile::remove(output_filename_); const QString scale_filter = QStringLiteral( "scale=w=%1:h=%2:force_original_aspect_ratio=decrease") - .arg(QString::number(params_.width), - QString::number(params_.height)); + .arg(QString::number(params_.width), + QString::number(params_.height)); QStringList args; args << QStringLiteral("-y") @@ -82,6 +90,7 @@ bool ProxyTask::Run() if (!process.waitForStarted()) { SetError(tr("Failed to start ffmpeg for proxy generation")); + qWarning() << "ProxyTask: failed to start ffmpeg" << process.errorString(); return false; } @@ -99,14 +108,19 @@ bool ProxyTask::Run() const QString output = QString::fromUtf8(process.readAll()).trimmed(); QFile::remove(output_filename_); SetError(tr("ffmpeg failed to generate proxy: %1").arg(output)); + qWarning() << "ProxyTask: ffmpeg failed with exit code" << process.exitCode() + << "output:" << output; return false; } if (!QFileInfo::exists(output_filename_)) { SetError(tr("ffmpeg finished but proxy file was not created")); + qWarning() << "ProxyTask: ffmpeg finished but output file missing" + << output_filename_; return false; } + qDebug() << "ProxyTask: proxy generation succeeded:" << output_filename_; emit ProgressChanged(1.0); return true; } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 09a13e6c1..b228686d5 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1182,13 +1182,16 @@ void TimelineWidget::SynchronizeSelectedClipsByWaveform() void TimelineWidget::GenerateProxiesForSelectedClips() { if (!ProxyManager::instance() || !sequence()) { + qWarning() << "GenerateProxiesForSelectedClips: ProxyManager or sequence unavailable"; return; } const QVector footage = GetSelectedProxyFootage(selected_blocks_); + qDebug() << "GenerateProxiesForSelectedClips: starting proxy generation for" << footage.size() << "footage item(s)"; for (Footage *item : footage) { const VideoParams video = item->GetFirstEnabledVideoStream(); if (!video.is_valid()) { + qWarning() << "GenerateProxiesForSelectedClips: skipping item with no valid video stream" << item->filename(); continue; } @@ -1197,6 +1200,9 @@ void TimelineWidget::GenerateProxiesForSelectedClips() ProxyManager::instance()->GetOrStartProxy( item->project()->cache_path(), item->filename(), video.stream_index(), params); + qDebug() << "GenerateProxiesForSelectedClips: proxy state=" << ProxyManager::ProxyStateToString(proxy.state) + << "file=" << proxy.filename + << "cache=" << item->project()->cache_path(); item->SetProxy(proxy.filename, proxy.state, video.stream_index(), params.version, true); item->InvalidateAll(Footage::kFilenameInput);