From b5cb5c59a3ca953f43cf200d9e94f227fc72948e Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Fri, 2 Nov 2012 01:30:15 +0100 Subject: [PATCH] Final changes to the DVD wizard rewrite. Allow transcoding of non compliant files, allow drag & drop clips into DVD wizard --- src/cliptranscode.cpp | 26 ++- src/cliptranscode.h | 5 +- src/dvdwizardvob.cpp | 381 +++++++++++++++++++++++++-------- src/dvdwizardvob.h | 31 ++- src/kdenlivetranscodingrc | 4 + src/mainwindow.cpp | 2 +- src/widgets/dvdwizardvob_ui.ui | 142 ++++++------ 7 files changed, 417 insertions(+), 174 deletions(-) diff --git a/src/cliptranscode.cpp b/src/cliptranscode.cpp index c91ec598..eace784d 100644 --- a/src/cliptranscode.cpp +++ b/src/cliptranscode.cpp @@ -27,8 +27,8 @@ #include -ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, const QString &description, QWidget * parent) : - QDialog(parent), m_urls(urls), m_duration(0) +ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, const QStringList &postParams, const QString &description, bool automaticMode, QWidget * parent) : + QDialog(parent), m_urls(urls), m_duration(0), m_automaticMode(automaticMode), m_postParams(postParams) { setFont(KGlobalSettings::toolBarFont()); setupUi(this); @@ -42,6 +42,9 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, const QStri #endif log_text->setHidden(true); setWindowTitle(i18n("Transcode Clip")); + if (m_automaticMode) { + auto_add->setHidden(true); + } auto_add->setText(i18np("Add clip to project", "Add clips to project", m_urls.count())); auto_add->setChecked(KdenliveSettings::add_new_clip()); @@ -98,6 +101,7 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, const QStri ffmpeg_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5); adjustSize(); + if (m_automaticMode) slotStartTransCode(); } ClipTranscode::~ClipTranscode() @@ -143,8 +147,19 @@ void ClipTranscode::slotStartTransCode() if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", destination + extension)) == KMessageBox::No) return; parameters << "-y"; } - foreach(QString s, params.split(' ')) + + bool replaceVfParams = false; + foreach(QString s, params.split(' ')) { + if (replaceVfParams) { + s= m_postParams.at(1); + replaceVfParams = false; + } parameters << s.replace("%1", destination); + if (s == "-vf") { + replaceVfParams = true; + } + } + buttonBox->button(QDialogButtonBox::Abort)->setText(i18n("Abort")); m_destination = destination + extension; @@ -200,14 +215,15 @@ void ClipTranscode::slotTranscodeFinished(int exitCode, QProcess::ExitStatus exi } if (exitCode == 0 && exitStatus == QProcess::NormalExit) { log_text->setHtml(log_text->toPlainText() + "
" + i18n("Transcoding finished.")); - if (auto_add->isChecked()) { + if (auto_add->isChecked() || m_automaticMode) { KUrl url; if (urls_list->count() > 0) { QString params = ffmpeg_params->toPlainText().simplified(); QString extension = params.section("%1", 1, 1).section(' ', 0, 0); url = KUrl(dest_url->url().path(KUrl::AddTrailingSlash) + source_url->url().fileName() + extension); } else url = dest_url->url(); - emit addClip(url); + if (m_automaticMode) emit transcodedClip(source_url->url(), url); + else emit addClip(url); } if (urls_list->count() > 0 && m_urls.count() > 0) { m_transcodeProcess.close(); diff --git a/src/cliptranscode.h b/src/cliptranscode.h index 8de1db82..05d0841c 100644 --- a/src/cliptranscode.h +++ b/src/cliptranscode.h @@ -37,7 +37,7 @@ class ClipTranscode : public QDialog, public Ui::ClipTranscode_UI Q_OBJECT public: - ClipTranscode(KUrl::List urls, const QString ¶ms, const QString &description, QWidget * parent = 0); + ClipTranscode(KUrl::List urls, const QString ¶ms, const QStringList &postParams, const QString &description, bool automaticMode = false, QWidget * parent = 0); ~ClipTranscode(); @@ -51,8 +51,10 @@ private: QProcess m_transcodeProcess; KUrl::List m_urls; int m_duration; + bool m_automaticMode; /** @brief The path for destination transcoded file. */ QString m_destination; + QStringList m_postParams; #if KDE_IS_VERSION(4,7,0) KMessageWidget *m_infoMessage; @@ -60,6 +62,7 @@ private: signals: void addClip(KUrl url); + void transcodedClip(KUrl source, KUrl result); }; diff --git a/src/dvdwizardvob.cpp b/src/dvdwizardvob.cpp index 73d9a64a..4f058e2b 100644 --- a/src/dvdwizardvob.cpp +++ b/src/dvdwizardvob.cpp @@ -20,6 +20,7 @@ #include "dvdwizardvob.h" #include "kthumb.h" #include "timecode.h" +#include "cliptranscode.h" #include @@ -34,8 +35,38 @@ #include #include +DvdTreeWidget::DvdTreeWidget(QWidget *parent) : + QTreeWidget(parent) +{ + setAcceptDrops(true); +} + +void DvdTreeWidget::dragEnterEvent(QDragEnterEvent * event ) { + if (event->mimeData()->hasUrls()) { + event->setDropAction(Qt::CopyAction); + event->setAccepted(true); + } + else QTreeWidget::dragEnterEvent(event); +} + +void DvdTreeWidget::dragMoveEvent(QDragMoveEvent * event) { + event->acceptProposedAction(); +} + +void DvdTreeWidget::mouseDoubleClickEvent( QMouseEvent * ) +{ + emit addNewClip(); +} + +void DvdTreeWidget::dropEvent(QDropEvent * event ) { + QList clips = event->mimeData()->urls(); + event->accept(); + emit addClips(clips); +} + DvdWizardVob::DvdWizardVob(QWidget *parent) : - QWizardPage(parent) + QWizardPage(parent), + m_installCheck(true) { m_view.setupUi(this); m_view.intro_vob->setEnabled(false); @@ -44,43 +75,63 @@ DvdWizardVob::DvdWizardVob(QWidget *parent) : m_view.button_delete->setIcon(KIcon("list-remove")); m_view.button_up->setIcon(KIcon("go-up")); m_view.button_down->setIcon(KIcon("go-down")); + m_vobList = new DvdTreeWidget(this); + QVBoxLayout *lay1 = new QVBoxLayout; + lay1->addWidget(m_vobList); + m_view.list_frame->setLayout(lay1); + m_vobList->setColumnCount(3); + m_vobList->setHeaderHidden(true); + + connect(m_vobList, SIGNAL(addClips(QList)), this, SLOT(slotAddVobList(QList))); + connect(m_vobList, SIGNAL(addNewClip()), this, SLOT(slotAddVobFile())); + connect(m_view.use_intro, SIGNAL(toggled(bool)), m_view.intro_vob, SLOT(setEnabled(bool))); connect(m_view.button_add, SIGNAL(clicked()), this, SLOT(slotAddVobFile())); connect(m_view.button_delete, SIGNAL(clicked()), this, SLOT(slotDeleteVobFile())); connect(m_view.button_up, SIGNAL(clicked()), this, SLOT(slotItemUp())); connect(m_view.button_down, SIGNAL(clicked()), this, SLOT(slotItemDown())); - connect(m_view.vobs_list, SIGNAL(itemSelectionChanged()), this, SLOT(slotCheckVobList())); + connect(m_vobList, SIGNAL(itemSelectionChanged()), this, SLOT(slotCheckVobList())); - m_view.vobs_list->setIconSize(QSize(60, 45)); + m_vobList->setIconSize(QSize(60, 45)); if (KStandardDirs::findExe("dvdauthor").isEmpty()) m_errorMessage.append(i18n("Program %1 is required for the DVD wizard.", i18n("dvdauthor"))); if (KStandardDirs::findExe("mkisofs").isEmpty() && KStandardDirs::findExe("genisoimage").isEmpty()) m_errorMessage.append(i18n("Program %1 or %2 is required for the DVD wizard.", i18n("mkisofs"), i18n("genisoimage"))); if (m_errorMessage.isEmpty()) m_view.error_message->setVisible(false); - else m_view.error_message->setText(m_errorMessage); + else { + m_view.error_message->setText(m_errorMessage); + m_installCheck = false; + } m_view.dvd_profile->addItems(QStringList() << i18n("PAL 4:3") << i18n("PAL 16:9") << i18n("NTSC 4:3") << i18n("NTSC 16:9")); - connect(m_view.dvd_profile, SIGNAL(activated(int)), this, SLOT(changeFormat())); connect(m_view.dvd_profile, SIGNAL(activated(int)), this, SLOT(slotCheckProfiles())); - m_view.vobs_list->header()->setStretchLastSection(false); - m_view.vobs_list->header()->setResizeMode(0, QHeaderView::Stretch); - m_view.vobs_list->header()->setResizeMode(1, QHeaderView::Custom); - m_view.vobs_list->header()->setResizeMode(2, QHeaderView::Custom); + m_vobList->header()->setStretchLastSection(false); + m_vobList->header()->setResizeMode(0, QHeaderView::Stretch); + m_vobList->header()->setResizeMode(1, QHeaderView::Custom); + m_vobList->header()->setResizeMode(2, QHeaderView::Custom); m_capacityBar = new KCapacityBar(KCapacityBar::DrawTextInline, this); QHBoxLayout *lay = new QHBoxLayout; lay->addWidget(m_capacityBar); m_view.size_box->setLayout(lay); - m_view.vobs_list->setItemDelegate(new DvdViewDelegate(m_view.vobs_list)); + m_vobList->setItemDelegate(new DvdViewDelegate(m_vobList)); + m_transcodeAction = new QAction(i18n("Transcode"), this); + connect(m_transcodeAction, SIGNAL(triggered()), this, SLOT(slotTranscodeFiles())); #if KDE_IS_VERSION(4,7,0) m_warnMessage = new KMessageWidget; - m_warnMessage->setText(i18n("Conflicting video standards, check DVD profile and clips")); m_warnMessage->setMessageType(KMessageWidget::Warning); + m_warnMessage->setText(i18n("Your clips do not match selected DVD format, transcoding required.")); + m_warnMessage->setCloseButtonVisible(false); + m_warnMessage->addAction(m_transcodeAction); QGridLayout *s = static_cast (layout()); s->addWidget(m_warnMessage, 3, 0, 1, -1); m_warnMessage->hide(); + m_view.button_transcode->setHidden(true); +#else + m_view.button_transcode->setDefaultAction(m_transcodeAction); + m_view.button_transcode->setEnabled(false); #endif slotCheckVobList(); @@ -93,25 +144,38 @@ DvdWizardVob::~DvdWizardVob() void DvdWizardVob::slotCheckProfiles() { -#if KDE_IS_VERSION(4,7,0) bool conflict = false; int comboProfile = m_view.dvd_profile->currentIndex(); - for (int i = 0; i < m_view.vobs_list->topLevelItemCount(); i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); + for (int i = 0; i < m_vobList->topLevelItemCount(); i++) { + QTreeWidgetItem *item = m_vobList->topLevelItem(i); if (item->data(0, Qt::UserRole + 1).toInt() != comboProfile) { conflict = true; break; } } - + m_transcodeAction->setEnabled(conflict); if (conflict) { - m_warnMessage->animatedShow(); + showProfileError(); } - else m_warnMessage->animatedHide(); + else { +#if KDE_IS_VERSION(4,7,0) + m_warnMessage->animatedHide(); +#else + if (m_installCheck) m_view.error_message->setVisible(false); #endif + } } -void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters) +void DvdWizardVob::slotAddVobList(QList list) +{ + foreach (const QUrl url, list) { + slotAddVobFile(KUrl(url), QString(), false); + } + slotCheckVobList(); + slotCheckProfiles(); +} + +void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters, bool checkFormats) { if (url.isEmpty()) url = KFileDialog::getOpenUrl(KUrl("kfiledialog:///projectfolder"), "video/mpeg", this, i18n("Add new video file")); if (url.isEmpty()) return; @@ -120,12 +184,14 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters) Mlt::Profile profile; profile.set_explicit(false); - QTreeWidgetItem *item = new QTreeWidgetItem(m_view.vobs_list, QStringList() << url.path() << QString() << KIO::convertSize(fileSize)); - item->setData(0, Qt::UserRole, fileSize); + QTreeWidgetItem *item = new QTreeWidgetItem(m_vobList, QStringList() << url.path() << QString() << KIO::convertSize(fileSize)); + item->setData(2, Qt::UserRole, fileSize); item->setData(0, Qt::DecorationRole, KIcon("video-x-generic").pixmap(60, 45)); item->setToolTip(0, url.path()); - - Mlt::Producer *producer = new Mlt::Producer(profile, url.path().toUtf8().data()); + + QString resource = url.path(); + resource.prepend("avformat:"); + Mlt::Producer *producer = new Mlt::Producer(profile, resource.toUtf8().data()); if (producer && producer->is_valid() && !producer->is_blank()) { //Mlt::Frame *frame = producer->get_frame(); //delete frame; @@ -166,7 +232,8 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters) } item->setData(0, Qt::UserRole, standardName); item->setData(0, Qt::UserRole + 1, standard); - if (m_view.vobs_list->topLevelItemCount() == 1) { + item->setData(0, Qt::UserRole + 2, QSize(profile.dar() * profile.height(), profile.height())); + if (m_vobList->topLevelItemCount() == 1) { // This is the first added movie, auto select DVD format if (standard >= 0) { m_view.dvd_profile->blockSignals(true); @@ -176,6 +243,10 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters) } } + else { + // Cannot load movie, reject + showError(i18n("The clip %1 is invalid.", url.fileName())); + } if (producer) delete producer; if (chapters.isEmpty() == false) { @@ -201,54 +272,15 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters) } else // Explicitly add a chapter at 00:00:00:00 item->setData(1, Qt::UserRole + 1, "0"); - slotCheckVobList(); - slotCheckProfiles(); -} - -void DvdWizardVob::changeFormat() -{ - int max = m_view.vobs_list->topLevelItemCount(); - QString profilename; - switch (m_view.dvd_profile->currentIndex()) { - case 1: - profilename = "dv_pal_wide"; - break; - case 2: - profilename = "dv_ntsc"; - break; - case 3: - profilename = "dv_ntsc_wide"; - break; - default: - profilename = "dv_pal"; - break; - } - - Mlt::Profile profile(profilename.toUtf8().constData()); - QPixmap pix(180, 135); - - for (int i = 0; i < max; i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); - Mlt::Producer *producer = new Mlt::Producer(profile, item->text(0).toUtf8().data()); - - if (producer->is_blank() == false) { - //pix = KThumb::getFrame(producer, 0, 135 * profile.dar(), 135); - //item->setIcon(0, pix); - item->setText(1, Timecode::getStringTimecode(producer->get_playtime(), profile.fps())); - } - delete producer; - int submax = item->childCount(); - for (int j = 0; j < submax; j++) { - QTreeWidgetItem *subitem = item->child(j); - subitem->setText(1, Timecode::getStringTimecode(subitem->data(1, Qt::UserRole).toInt(), profile.fps())); - } + if (checkFormats) { + slotCheckVobList(); + slotCheckProfiles(); } - slotCheckVobList(); } void DvdWizardVob::slotDeleteVobFile() { - QTreeWidgetItem *item = m_view.vobs_list->currentItem(); + QTreeWidgetItem *item = m_vobList->currentItem(); if (item == NULL) return; delete item; slotCheckVobList(); @@ -259,8 +291,8 @@ void DvdWizardVob::slotDeleteVobFile() // virtual bool DvdWizardVob::isComplete() const { - if (!m_view.error_message->text().isEmpty()) return false; - if (m_view.vobs_list->topLevelItemCount() == 0) return false; + if (!m_installCheck) return false; + if (m_vobList->topLevelItemCount() == 0) return false; return true; } @@ -273,9 +305,9 @@ QStringList DvdWizardVob::selectedUrls() const { QStringList result; QString path; - int max = m_view.vobs_list->topLevelItemCount(); + int max = m_vobList->topLevelItemCount(); for (int i = 0; i < max; i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); + QTreeWidgetItem *item = m_vobList->topLevelItem(i); if (item) result.append(item->text(0)); } return result; @@ -286,9 +318,9 @@ QStringList DvdWizardVob::durations() const { QStringList result; QString path; - int max = m_view.vobs_list->topLevelItemCount(); + int max = m_vobList->topLevelItemCount(); for (int i = 0; i < max; i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); + QTreeWidgetItem *item = m_vobList->topLevelItem(i); if (item) result.append(QString::number(item->data(1, Qt::UserRole).toInt())); } return result; @@ -298,9 +330,9 @@ QStringList DvdWizardVob::chapters() const { QStringList result; QString path; - int max = m_view.vobs_list->topLevelItemCount(); + int max = m_vobList->topLevelItemCount(); for (int i = 0; i < max; i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); + QTreeWidgetItem *item = m_vobList->topLevelItem(i); if (item) { result.append(item->data(1, Qt::UserRole + 1).toString()); } @@ -310,9 +342,9 @@ QStringList DvdWizardVob::chapters() const void DvdWizardVob::updateChapters(QMap chaptersdata) { - int max = m_view.vobs_list->topLevelItemCount(); + int max = m_vobList->topLevelItemCount(); for (int i = 0; i < max; i++) { - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(i); + QTreeWidgetItem *item = m_vobList->topLevelItem(i); if (chaptersdata.contains(item->text(0))) item->setData(1, Qt::UserRole + 1, chaptersdata.value(item->text(0))); } } @@ -320,7 +352,7 @@ void DvdWizardVob::updateChapters(QMap chaptersdata) int DvdWizardVob::duration(int ix) const { int result = -1; - QTreeWidgetItem *item = m_view.vobs_list->topLevelItem(ix); + QTreeWidgetItem *item = m_vobList->topLevelItem(ix); if (item) { result = item->data(1, Qt::UserRole).toInt(); } @@ -344,20 +376,20 @@ void DvdWizardVob::setIntroMovie(const QString& path) void DvdWizardVob::slotCheckVobList() { emit completeChanged(); - int max = m_view.vobs_list->topLevelItemCount(); - QTreeWidgetItem *item = m_view.vobs_list->currentItem(); + int max = m_vobList->topLevelItemCount(); + QTreeWidgetItem *item = m_vobList->currentItem(); bool hasItem = true; if (item == NULL) hasItem = false; m_view.button_delete->setEnabled(hasItem); - if (hasItem && m_view.vobs_list->indexOfTopLevelItem(item) == 0) m_view.button_up->setEnabled(false); + if (hasItem && m_vobList->indexOfTopLevelItem(item) == 0) m_view.button_up->setEnabled(false); else m_view.button_up->setEnabled(hasItem); - if (hasItem && m_view.vobs_list->indexOfTopLevelItem(item) == max - 1) m_view.button_down->setEnabled(false); + if (hasItem && m_vobList->indexOfTopLevelItem(item) == max - 1) m_view.button_down->setEnabled(false); else m_view.button_down->setEnabled(hasItem); qint64 totalSize = 0; for (int i = 0; i < max; i++) { - item = m_view.vobs_list->topLevelItem(i); - if (item) totalSize += (qint64) item->data(0, Qt::UserRole).toInt(); + item = m_vobList->topLevelItem(i); + if (item) totalSize += (qint64) item->data(2, Qt::UserRole).toInt(); } qint64 maxSize = (qint64) 47000 * 100000; @@ -367,21 +399,21 @@ void DvdWizardVob::slotCheckVobList() void DvdWizardVob::slotItemUp() { - QTreeWidgetItem *item = m_view.vobs_list->currentItem(); + QTreeWidgetItem *item = m_vobList->currentItem(); if (item == NULL) return; - int index = m_view.vobs_list->indexOfTopLevelItem(item); + int index = m_vobList->indexOfTopLevelItem(item); if (index == 0) return; - m_view.vobs_list->insertTopLevelItem(index - 1, m_view.vobs_list->takeTopLevelItem(index)); + m_vobList->insertTopLevelItem(index - 1, m_vobList->takeTopLevelItem(index)); } void DvdWizardVob::slotItemDown() { - int max = m_view.vobs_list->topLevelItemCount(); - QTreeWidgetItem *item = m_view.vobs_list->currentItem(); + int max = m_vobList->topLevelItemCount(); + QTreeWidgetItem *item = m_vobList->currentItem(); if (item == NULL) return; - int index = m_view.vobs_list->indexOfTopLevelItem(item); + int index = m_vobList->indexOfTopLevelItem(item); if (index == max - 1) return; - m_view.vobs_list->insertTopLevelItem(index + 1, m_view.vobs_list->takeTopLevelItem(index)); + m_vobList->insertTopLevelItem(index + 1, m_vobList->takeTopLevelItem(index)); } DVDFORMAT DvdWizardVob::dvdFormat() const @@ -430,13 +462,176 @@ QString DvdWizardVob::getDvdProfile(DVDFORMAT format) void DvdWizardVob::setProfile(const QString& profile) { - if (profile == "dv_pal") m_view.dvd_profile->setCurrentIndex(PAL); - else if (profile == "dv_pal_wide") m_view.dvd_profile->setCurrentIndex(PAL_WIDE); + if (profile == "dv_pal_wide") m_view.dvd_profile->setCurrentIndex(PAL_WIDE); else if (profile == "dv_ntsc") m_view.dvd_profile->setCurrentIndex(NTSC); else if (profile == "dv_ntsc_wide") m_view.dvd_profile->setCurrentIndex(NTSC_WIDE); + else m_view.dvd_profile->setCurrentIndex(PAL); } void DvdWizardVob::clear() { - m_view.vobs_list->clear(); + m_vobList->clear(); } + +void DvdWizardVob::slotTranscodeFiles() +{ + // Find transcoding infos related to selected DVD profile + KSharedConfigPtr config = KSharedConfig::openConfig("kdenlivetranscodingrc"); + KConfigGroup transConfig(config, "Transcoding"); + // read the entries + QString profileEasyName; + QSize destSize; + QSize finalSize; + switch (m_view.dvd_profile->currentIndex()) { + case PAL_WIDE: + profileEasyName = "DVD PAL 16:9"; + destSize = QSize(1024, 576); + finalSize = QSize(720, 576); + break; + case NTSC: + profileEasyName = "DVD NTSC 4:3"; + destSize = QSize(640, 480); + finalSize = QSize(720, 480); + break; + case NTSC_WIDE: + profileEasyName = "DVD NTSC 16:9"; + destSize = QSize(853, 480); + finalSize = QSize(720, 480); + break; + default: + profileEasyName = "DVD PAL 4:3"; + destSize = QSize(768, 576); + finalSize = QSize(720, 576); + } + QString params = transConfig.readEntry(profileEasyName); + + // Transcode files that do not match selected profile + int max = m_vobList->topLevelItemCount(); + int format = m_view.dvd_profile->currentIndex(); + for (int i = 0; i < max; i++) { + QTreeWidgetItem *item = m_vobList->topLevelItem(i); + if (item->data(0, Qt::UserRole + 1).toInt() != format) { + // File needs to be transcoded + m_transcodeAction->setEnabled(false); + QSize original = item->data(0, Qt::UserRole + 2).toSize(); + double input_aspect= (double) original.width() / original.height(); + QStringList postParams; + if (input_aspect > (double) destSize.width() / destSize.height()) { + // letterboxing + int conv_height = (int) (destSize.width() / input_aspect); + int conv_pad = (int) (((double) (destSize.height() - conv_height)) / 2.0); + if (conv_pad %2 == 1) conv_pad --; + postParams << "-vf" << QString("scale=%1:%2,pad=%3:%4:0:%5,setdar=%6").arg(finalSize.width()).arg(destSize.height() - 2 * conv_pad).arg(finalSize.width()).arg(finalSize.height()).arg(conv_pad).arg(input_aspect); + } else { + // pillarboxing + int conv_width = (int) (destSize.height() * input_aspect); + int conv_pad = (int) (((double) (destSize.width() - conv_width)) / destSize.width() * finalSize.width() / 2.0); + if (conv_pad %2 == 1) conv_pad --; + postParams << "-vf" << QString("scale=%1:%2,pad=%3:%4:%5:0,setdar=%6").arg(finalSize.width() - 2 * conv_pad).arg(destSize.height()).arg(finalSize.width()).arg(finalSize.height()).arg(conv_pad).arg(input_aspect); + } + ClipTranscode *d = new ClipTranscode(KUrl::List () << KUrl(item->text(0)), params.section(';', 0, 0), postParams, i18n("Transcoding to DVD format"), true, this); + connect(d, SIGNAL(transcodedClip(KUrl,KUrl)), this, SLOT(slotTranscodedClip(KUrl, KUrl))); + d->show(); + } + } +} + +void DvdWizardVob::slotTranscodedClip(KUrl src, KUrl transcoded) +{ + int max = m_vobList->topLevelItemCount(); + for (int i = 0; i < max; i++) { + QTreeWidgetItem *item = m_vobList->topLevelItem(i); + if (KUrl(item->text(0)).path() == src.path()) { + // Replace movie with transcoded version + item->setText(0, transcoded.path()); + + QFile f(transcoded.path()); + qint64 fileSize = f.size(); + + Mlt::Profile profile; + profile.set_explicit(false); + item->setText(2, KIO::convertSize(fileSize)); + item->setData(2, Qt::UserRole, fileSize); + item->setData(0, Qt::DecorationRole, KIcon("video-x-generic").pixmap(60, 45)); + item->setToolTip(0, transcoded.path()); + + QString resource = transcoded.path(); + resource.prepend("avformat:"); + Mlt::Producer *producer = new Mlt::Producer(profile, resource.toUtf8().data()); + if (producer && producer->is_valid() && !producer->is_blank()) { + profile.from_producer(*producer); + int width = 45.0 * profile.dar(); + int swidth = 45.0 * profile.width() / profile.height(); + if (width % 2 == 1) width++; + item->setData(0, Qt::DecorationRole, QPixmap::fromImage(KThumb::getFrame(producer, 0, swidth, width, 45))); + int playTime = producer->get_playtime(); + item->setText(1, Timecode::getStringTimecode(playTime, profile.fps())); + item->setData(1, Qt::UserRole, playTime); + int standard = -1; + int aspect = profile.dar() * 100; + if (profile.height() == 576) { + if (aspect > 150) standard = 1; + else standard = 0; + } + else if (profile.height() == 480) { + if (aspect > 150) standard = 3; + else standard = 2; + } + QString standardName; + switch (standard) { + case 3: + standardName = i18n("NTSC 16:9"); + break; + case 2: + standardName = i18n("NTSC 4:3"); + break; + case 1: + standardName = i18n("PAL 16:9"); + break; + case 0: + standardName = i18n("PAL 4:3"); + break; + default: + standardName = i18n("Unknown"); + } + item->setData(0, Qt::UserRole, standardName); + item->setData(0, Qt::UserRole + 1, standard); + item->setData(0, Qt::UserRole + 2, QSize(profile.dar() * profile.height(), profile.height())); + } + else { + // Cannot load movie, reject + showError(i18n("The clip %1 is invalid.", transcoded.fileName())); + } + if (producer) delete producer; + slotCheckVobList(); + slotCheckProfiles(); + break; + } + } +} + +void DvdWizardVob::showProfileError() +{ +#if KDE_IS_VERSION(4,7,0) + m_warnMessage->setText(i18n("Your clips do not match selected DVD format, transcoding required.")); + m_warnMessage->setCloseButtonVisible(false); + m_warnMessage->addAction(m_transcodeAction); + m_warnMessage->animatedShow(); +#else + m_view.error_message->setText(i18n("Your clips do not match selected DVD format, transcoding required.")); + m_view.error_message->setVisible(true); +#endif +} + +void DvdWizardVob::showError(const QString error) +{ +#if KDE_IS_VERSION(4,7,0) + m_warnMessage->setText(error); + m_warnMessage->setCloseButtonVisible(true); + m_warnMessage->removeAction(m_transcodeAction); + m_warnMessage->animatedShow(); +#else + m_view.error_message->setText(error); + m_view.error_message->setVisible(true); +#endif +} \ No newline at end of file diff --git a/src/dvdwizardvob.h b/src/dvdwizardvob.h index 1208ff39..6f3ad2a4 100644 --- a/src/dvdwizardvob.h +++ b/src/dvdwizardvob.h @@ -34,9 +34,29 @@ #include #include #include +#include +#include +#include enum DVDFORMAT { PAL, PAL_WIDE, NTSC, NTSC_WIDE }; +class DvdTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + DvdTreeWidget(QWidget *parent); + +protected: + virtual void dragEnterEvent(QDragEnterEvent * event ); + virtual void dropEvent(QDropEvent * event ); + virtual void mouseDoubleClickEvent( QMouseEvent * ); + virtual void dragMoveEvent(QDragMoveEvent * event); + +signals: + void addNewClip(); + void addClips(QList); +}; + class DvdViewDelegate : public QStyledItemDelegate { Q_OBJECT @@ -101,14 +121,20 @@ public: private: Ui::DvdWizardVob_UI m_view; + DvdTreeWidget *m_vobList; QString m_errorMessage; KCapacityBar *m_capacityBar; + QAction *m_transcodeAction; + bool m_installCheck; #if KDE_IS_VERSION(4,7,0) KMessageWidget *m_warnMessage; #endif + void showProfileError(); + void showError(const QString error); public slots: - void slotAddVobFile(KUrl url = KUrl(), const QString &chapters = QString()); + void slotAddVobFile(KUrl url = KUrl(), const QString &chapters = QString(), bool checkFormats = true); + void slotAddVobList(QList list); void slotCheckProfiles(); private slots: @@ -116,7 +142,8 @@ private slots: void slotDeleteVobFile(); void slotItemUp(); void slotItemDown(); - void changeFormat(); + void slotTranscodeFiles(); + void slotTranscodedClip(KUrl, KUrl); }; #endif diff --git a/src/kdenlivetranscodingrc b/src/kdenlivetranscodingrc index b4d54169..852a308e 100644 --- a/src/kdenlivetranscodingrc +++ b/src/kdenlivetranscodingrc @@ -19,3 +19,7 @@ Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vo Lossless Matroska=-sn -vcodec huffyuv -acodec flac %1.mkv;High quality lossless encoding Wav 48000Hz=-vn -ar 48000 %1.wav;Extract audio as WAV file;audio Remux with MKV=-vcodec copy -acodec copy -sn %1.mkv +DVD PAL 4:3=-f dvd -r 25 -vf scale=720:576 -aspect 4:3 -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 +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 PAL +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 PAL wide \ No newline at end of file diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d896068c..3ad959b1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4018,7 +4018,7 @@ void MainWindow::slotTranscode(KUrl::List urls) m_messageLabel->setMessage(i18n("No clip to transcode"), ErrorMessage); return; } - ClipTranscode *d = new ClipTranscode(urls, params, desc); + ClipTranscode *d = new ClipTranscode(urls, params, QStringList(), desc); connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl))); d->show(); } diff --git a/src/widgets/dvdwizardvob_ui.ui b/src/widgets/dvdwizardvob_ui.ui index c7080ea0..804d84a0 100644 --- a/src/widgets/dvdwizardvob_ui.ui +++ b/src/widgets/dvdwizardvob_ui.ui @@ -6,77 +6,67 @@ 0 0 - 319 - 248 + 404 + 261 0 - - - - Intro movie - - + + - - + + - + 0 0 + + + 0 + 20 + + + + QFrame::NoFrame + + + QFrame::Raised + - - - - true - - - true - - - false - - - true - - - - File - - - - - Duration - - - - - Size - - - - - - + + ... - - + + + + + 0 + 0 + + - ... + - + + + + + + + + Qt::Horizontal @@ -89,23 +79,31 @@ - - - - + + + + ... - - - - - 0 - 0 - + + + + Intro movie + + + + - + Add movie file + + + + + + + ... @@ -116,10 +114,13 @@ - - - - Add movie file + + + + + 0 + 0 + @@ -130,22 +131,19 @@ - - - - - KUrlRequester - QFrame -
kurlrequester.h
-
KComboBox QComboBox
kcombobox.h
+ + KUrlRequester + QFrame +
kurlrequester.h
+
-- 2.39.2