Commit faf77816 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Implement check and transcoding for non seekable files.

BUG: 371062
parent 543b8cc7
......@@ -33,3 +33,10 @@ DVD PAL 4:3=-f dvd -r 25 -vf scale=720:576 -aspect 4:3 -minrate 0 -maxrate 8000k
DVD PAL 16:9=-f dvd -r 25 -vf scale=720:576 -aspect 16:9 -minrate 0 -maxrate 8000k -muxrate 10080000 -g 15 -bufsize 1835008 -packetsize 2048 -trellis 1 -me_range 63 -acodec ac3 -ab 192k -ar 48000 -vcodec mpeg2video -vb 5000k %1.vob;Dvd PAL wide
DVD NTSC 4:3=-f dvd -r 23.976 -vf scale=720:480 -aspect 4:3 -minrate 0 -maxrate 9000k -muxrate 10080000 -g 18 -bufsize 1835008 -packetsize 2048 -trellis 1 -me_range 63 -acodec ac3 -ab 192k -ar 48000 -vcodec mpeg2video -vb 6000k %1.vob;Dvd NTSC
DVD NTSC 16:9=-f dvd -r 23.976 -vf scale=720:480 -aspect 16:9 -minrate 0 -maxrate 9000k -muxrate 10080000 -g 18 -bufsize 1835008 -packetsize 2048 -trellis 1 -me_range 63 -acodec ac3 -ab 192k -ar 48000 -vcodec mpeg2video -vb 6000k %1.vob;Dvd NTSC wide
[intermediate]
Lossy x264 I frame only=-f mp4 -codec:v libx264 -g 1 -bf 0 -crf 15 -preset medium -codec:a aac -ab 256k %1.mp4
Lossy x264 I frame only (NVidia GPU)=-f mp4 -vsync 0 -c:v %nvcodec -i -codec:v h264_nvenc -g 1 -bf 0 -codec:a aac -ab 256k %1.mp4
Lossy x264 I frame only (NVidia GPU)=-f mp4 -vsync 0 -c:v %nvcodec -i -codec:v h264_nvenc -g 1 -bf 0 -codec:a aac -ab 256k %1.mp4
Intermediate DNxHR HQ (Large files)=-f mov -codec:a alac -codec:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p %1.mov
Lossless (Huge files)=-f matroska -codec:a pcm_f32le -codec:v utvideo -pix_fmt yuv422p %1.mkv
......@@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "doc/kdenlivedoc.h"
#include "effects/effectstack/model/effectstackmodel.hpp"
#include "jobs/audiothumbjob.hpp"
#include "jobs/transcodeclipjob.h"
#include "jobs/jobmanager.h"
#include "jobs/loadjob.hpp"
#include "jobs/thumbjob.hpp"
......@@ -42,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "monitor/monitor.h"
#include "project/dialogs/slideshowclip.h"
#include "project/invaliddialog.h"
#include "project/transcodeseek.h"
#include "project/projectcommands.h"
#include "project/projectmanager.h"
#include "projectclip.h"
......@@ -883,6 +885,7 @@ Bin::Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent)
, m_filterRateGroup(this)
, m_filterTypeGroup(this)
, m_invalidClipDialog(nullptr)
, m_transcodingDialog(nullptr)
, m_gainedFocus(false)
, m_audioDuration(0)
, m_processedAudio(0)
......@@ -4483,3 +4486,22 @@ void Bin::savePlaylist(const QString &binId, QString savePath, QVector<QPoint> z
selectClipById(id);
}
}
void Bin::requestTranscoding(const QString &url, const QString &id)
{
if (m_transcodingDialog == nullptr) {
m_transcodingDialog = new TranscodeSeek(this);
connect(m_transcodingDialog, &QDialog::accepted, this, [=] () {
qDebug()<<"==== STARTING TCODE JOB: "<<m_transcodingDialog->ids().front()<<" = "<<m_transcodingDialog->params();
pCore->jobManager()->startJob<TranscodeJob>(m_transcodingDialog->ids(), -1, QString(), m_transcodingDialog->params(), true);
delete m_transcodingDialog;
m_transcodingDialog = nullptr;
});
connect(m_transcodingDialog, &QDialog::rejected, this, [=] () {
delete m_transcodingDialog;
m_transcodingDialog = nullptr;
});
}
m_transcodingDialog->addUrl(url, id);
m_transcodingDialog->show();
}
......@@ -51,6 +51,7 @@ class BinListItemDelegate;
class ClipController;
class EffectStackModel;
class InvalidDialog;
class TranscodeSeek;
class KdenliveDoc;
class TagWidget;
class Monitor;
......@@ -348,6 +349,8 @@ public:
* @param properties some extra properties that will be set on the producer
* @param createNew if true, the playlist will be added as a new clip in project binId */
void savePlaylist(const QString &binId, QString savePath, QVector<QPoint> zones, QMap<QString, QString> properties, bool createNew);
/** @brief A non seekable clip was added to project, propose transcoding */
void requestTranscoding(const QString &url, const QString &id);
private slots:
void slotAddClip();
......@@ -528,7 +531,10 @@ private:
KMessageWidget *m_infoMessage;
BinMessage::BinCategory m_currentMessage;
QStringList m_errorLog;
/** @brief Dialog listing invalid clips on load. */
InvalidDialog *m_invalidClipDialog;
/** @brief Dialog listing non seekable clips on load. */
TranscodeSeek *m_transcodingDialog;
/** @brief Set to true if widget just gained focus (means we have to update effect stack . */
bool m_gainedFocus;
/** @brief List of Clip Ids that want an audio thumb. */
......
......@@ -491,6 +491,10 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
FileStatus::ClipStatus currentStatus = m_clipStatus;
updateProducer(producer);
emit producerChanged(m_binId, producer);
if (producer->get_int("kdenlive:transcodingrequired") == 1) {
pCore->bin()->requestTranscoding(clipUrl(), clipId());
producer->set("kdenlive:transcodingrequired", nullptr);
}
m_thumbsProducer.reset();
connectEffectStack();
......
......@@ -528,6 +528,12 @@ bool LoadJob::startJob()
m_producer->set("out", fixedLength - 1);
}
} else if (mltService == QLatin1String("avformat")) {
// Check if file is seekable
bool seekable = m_producer->get_int("seekable");
if (!seekable) {
m_producer->set("kdenlive:transcodingrequired", 1);
qDebug()<<"================0\n\nFOUND UNSEEKABLE FILE: "<<m_producer->get("resource")<<"\n\n===================";
}
// check if there are multiple streams
vindex = m_producer->get_int("video_index");
// List streams
......
......@@ -35,13 +35,14 @@
#include <klocalizedstring.h>
TranscodeJob::TranscodeJob(const QString &binId, QString params)
TranscodeJob::TranscodeJob(const QString &binId, QString params, bool replaceProducer)
: AbstractClipJob(TRANSCODEJOB, binId, {ObjectType::BinClip, binId.toInt()})
, m_jobDuration(0)
, m_isFfmpegJob(true)
, m_jobProcess(nullptr)
, m_done(false)
, m_transcodeParams(std::move(params))
, m_replaceProducer(replaceProducer)
{
}
......@@ -242,7 +243,20 @@ bool TranscodeJob::commitResult(Fun &undo, Fun &redo)
return false;
}
m_resultConsumed = true;
QString folderId = QStringLiteral("-1");
auto id = ClipCreator::createClipFromFile(m_destUrl, folderId, pCore->projectItemModel(), undo, redo);
QString id;
if (m_replaceProducer) {
id = m_clipId;
QMap <QString, QString> sourceProps;
QMap <QString, QString> newProps;
auto binClip = pCore->projectItemModel()->getClipByBinID(m_clipId);
sourceProps.insert(QStringLiteral("resource"), binClip->url());
sourceProps.insert(QStringLiteral("kdenlive:clipname"), binClip->clipName());
newProps.insert(QStringLiteral("resource"), m_destUrl);
newProps.insert(QStringLiteral("kdenlive:clipname"), QFileInfo(m_destUrl).fileName());
pCore->bin()->slotEditClipCommand(m_clipId, sourceProps, newProps);
} else {
QString folderId = QStringLiteral("-1");
id = ClipCreator::createClipFromFile(m_destUrl, folderId, pCore->projectItemModel(), undo, redo);
}
return id != QStringLiteral("-1");
}
......@@ -30,7 +30,7 @@ class TranscodeJob : public AbstractClipJob
Q_OBJECT
public:
TranscodeJob(const QString &binId, QString params);
TranscodeJob(const QString &binId, QString params, bool replaceProducer = false);
const QString getDescription() const override;
bool startJob() override;
/** @brief This is to be called after the job finished.
......@@ -47,6 +47,7 @@ private:
bool m_done;
QString m_destUrl;
QString m_transcodeParams;
bool m_replaceProducer;
};
#endif
......@@ -3596,7 +3596,7 @@ void MainWindow::buildDynamicActions()
}
connect(a, &QAction::triggered, [&, a]() {
QStringList transcodeData = a->data().toStringList();
emit pCore->jobManager()->startJob<TranscodeJob>(pCore->bin()->selectedClipsIds(true), -1, QString(), transcodeData.first());
emit pCore->jobManager()->startJob<TranscodeJob>(pCore->bin()->selectedClipsIds(true), -1, QString(), transcodeData.first(), false);
});
if (transList.count() > 2 && transList.at(2) == QLatin1String("audio")) {
// This is an audio transcoding action
......
......@@ -8,4 +8,5 @@ set(kdenlive_SRCS
project/projectmanager.cpp
project/effectsettings.cpp
project/notesplugin.cpp
project/transcodeseek.cpp
PARENT_SCOPE)
/*
Copyright (C) 2021 by Jean-Baptiste Mardelle (jb@kdenlive.org)
*
This file is part of Kdenlive. See www.kdenlive.org.
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 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transcodeseek.h"
#include "kdenlivesettings.h"
#include "kxmlgui_version.h"
#include <QFontDatabase>
#include <QStandardPaths>
#include <KMessageBox>
#include <klocalizedstring.h>
TranscodeSeek::TranscodeSeek(QWidget *parent)
: QDialog(parent)
{
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, false);
setWindowTitle(i18n("Transcode Clip"));
KConfig conf(QStringLiteral("kdenlivetranscodingrc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation);
KConfigGroup group(&conf, "intermediate");
m_encodeParams = group.entryMap();
encodingprofiles->addItems(group.keyList());
}
TranscodeSeek::~TranscodeSeek()
{
}
void TranscodeSeek::addUrl(const QString &file, const QString &id)
{
QListWidgetItem *it = new QListWidgetItem(file, listWidget);
it->setData(Qt::UserRole, id);
}
std::vector<QString> TranscodeSeek::ids() const
{
std::vector<QString> urls;
for (int i = 0; i < listWidget->count(); i++) {
urls.push_back(listWidget->item(i)->data(Qt::UserRole).toString());
}
return urls;
}
QString TranscodeSeek::params() const
{
return m_encodeParams.value(encodingprofiles->currentText());
}
/*
Copyright (C) 2021 by Jean-Baptiste Mardelle (jb@kdenlive.org)
*
This file is part of Kdenlive. See www.kdenlive.org.
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 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRANSCODESEEK_H
#define TRANSCODESEEK_H
#include "ui_transcodeseekable_ui.h"
#include <QUrl>
#include <QProcess>
class TranscodeSeek : public QDialog, public Ui::TranscodeSeekable_UI
{
Q_OBJECT
public:
TranscodeSeek(QWidget *parent = nullptr);
~TranscodeSeek() override;
void addUrl(const QString &file, const QString &id);
std::vector<QString> ids() const;
QString params() const;
private:
QMap<QString, QString> m_encodeParams;
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TranscodeSeekable_UI</class>
<widget class="QDialog" name="TranscodeSeekable_UI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>302</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>The following clips are not usable for editing. Do you want to transcode them in an edit friendly format ? The converted clips will replace the original ones in your project once created.</string>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="listWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Convert to</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="encodingprofiles">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TranscodeSeekable_UI</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>TranscodeSeekable_UI</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment