From d7e79e1131d5355bc606522988b8de301b4b7004 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Sun, 3 Jan 2010 20:50:45 +0000 Subject: [PATCH] * Allow transcoding of several clips (selected in project tree): http://www.kdenlive.org/mantis/view.php?id=1362 * Don't allow to transcode a clip if it does not match transcoding profile * Default sound on error svn path=/trunk/kdenlive/; revision=4197 --- src/clipproperties.cpp | 13 ++++++++---- src/cliptranscode.cpp | 17 ++++++++++++--- src/cliptranscode.h | 2 +- src/docclipbase.cpp | 37 +++++++++++++++++++++++++++++++++ src/docclipbase.h | 3 +++ src/kdenlive.notifyrc | 5 +++++ src/kdenlivetranscodingrc | 16 +++++++------- src/mainwindow.cpp | 35 +++++++++++++++++++++++-------- src/projectlist.cpp | 23 ++++++++++++++++++++ src/projectlist.h | 1 + src/statusbarmessagelabel.cpp | 3 +++ src/widgets/cliptranscode_ui.ui | 28 +++++++++++++++++-------- 12 files changed, 149 insertions(+), 34 deletions(-) diff --git a/src/clipproperties.cpp b/src/clipproperties.cpp index 423a2814..708f1946 100644 --- a/src/clipproperties.cpp +++ b/src/clipproperties.cpp @@ -255,8 +255,13 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg m_view.clip_thumb->setHidden(true); } - KFileItem f(KFileItem::Unknown, KFileItem::Unknown, url, true); - m_view.clip_filesize->setText(KIO::convertSize(f.size())); + if (t != SLIDESHOW && t != COLOR) { + KFileItem f(KFileItem::Unknown, KFileItem::Unknown, url, true); + m_view.clip_filesize->setText(KIO::convertSize(f.size())); + } else { + m_view.clip_filesize->setHidden(true); + m_view.label_size->setHidden(true); + } m_view.clip_duration->setText(tc.getTimecode(m_clip->duration())); if (t != IMAGE && t != COLOR && t != TEXT) m_view.clip_duration->setReadOnly(true); else connect(m_view.clip_duration, SIGNAL(editingFinished()), this, SLOT(slotCheckMaxLength())); @@ -555,9 +560,9 @@ QMap ClipProperties::properties() props["ttl"] = QString::number(duration); props["out"] = QString::number(duration * m_count); } - if (duration * m_count != m_old_props.value("out").toInt()) { + if (duration * m_count - 1 != m_old_props.value("out").toInt()) { m_clipNeedsRefresh = true; - props["out"] = QString::number(duration * m_count); + props["out"] = QString::number(duration * m_count - 1); } if (m_view.slide_fade->isChecked()) { int luma_duration; diff --git a/src/cliptranscode.cpp b/src/cliptranscode.cpp index e81b4b54..1d9e29fa 100644 --- a/src/cliptranscode.cpp +++ b/src/cliptranscode.cpp @@ -26,7 +26,7 @@ #include -ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, QWidget * parent) : +ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, const QString &description, QWidget * parent) : QDialog(parent), m_urls(urls) { setFont(KGlobalSettings::toolBarFont()); @@ -57,6 +57,9 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, QWidget * p label_profile->setHidden(true); profile_list->setHidden(true); ffmpeg_params->setPlainText(params.simplified()); + if (!description.isEmpty()) { + transcode_info->setText(description); + } else transcode_info->setHidden(true); } else { // load Profiles KSharedConfigPtr config = KSharedConfig::openConfig("kdenlivetranscodingrc"); @@ -64,11 +67,14 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString ¶ms, QWidget * p // read the entries QMap< QString, QString > profiles = transConfig.entryMap(); QMapIterator i(profiles); - connect(profile_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateParams(int))); while (i.hasNext()) { i.next(); - profile_list->addItem(i.key(), i.value()); + QStringList data = i.value().split(";", QString::SkipEmptyParts); + profile_list->addItem(i.key(), data.at(0)); + profile_list->setItemData(profile_list->count() - 1, data.at(1), Qt::UserRole + 1); } + connect(profile_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateParams(int))); + slotUpdateParams(0); } connect(button_start, SIGNAL(clicked()), this, SLOT(slotStartTransCode())); @@ -166,6 +172,11 @@ void ClipTranscode::slotUpdateParams(int ix) if (ix != -1) { QString params = profile_list->itemData(ix).toString(); ffmpeg_params->setPlainText(params.simplified()); + QString desc = profile_list->itemData(ix, Qt::UserRole + 1).toString(); + if (!desc.isEmpty()) { + transcode_info->setText(desc); + transcode_info->setHidden(false); + } else transcode_info->setHidden(true); } if (urls_list->count() == 0) { QString newFile = ffmpeg_params->toPlainText().simplified().section(' ', -1).replace("%1", fileName); diff --git a/src/cliptranscode.h b/src/cliptranscode.h index 9933da58..5988fb0e 100644 --- a/src/cliptranscode.h +++ b/src/cliptranscode.h @@ -33,7 +33,7 @@ class ClipTranscode : public QDialog, public Ui::ClipTranscode_UI Q_OBJECT public: - ClipTranscode(KUrl::List urls, const QString ¶ms, QWidget * parent = 0); + ClipTranscode(KUrl::List urls, const QString ¶ms, const QString &description, QWidget * parent = 0); ~ClipTranscode(); diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 7b7574c6..9dfa1d7a 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -34,6 +34,8 @@ #include +#include + DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) : QObject(), m_audioFrameCache(), @@ -929,3 +931,38 @@ QList DocClipBase::cutZones() const return m_cutZones; } +bool DocClipBase::hasVideoCodec(const QString &codec) const +{ + Mlt::Producer *prod = NULL; + if (m_baseTrackProducers.count() == 0) return false; + for (int i = 0; i < m_baseTrackProducers.count(); i++) { + if (m_baseTrackProducers.at(i) != NULL) { + prod = m_baseTrackProducers.at(i); + break; + } + } + + if (!prod) return false; + int default_video = prod->get_int("video_index"); + char property[200]; + snprintf(property, sizeof(property), "meta.media.%d.codec.name", default_video); + return prod->get(property) == codec; +} + +bool DocClipBase::hasAudioCodec(const QString &codec) const +{ + Mlt::Producer *prod = NULL; + if (m_baseTrackProducers.count() == 0) return false; + for (int i = 0; i < m_baseTrackProducers.count(); i++) { + if (m_baseTrackProducers.at(i) != NULL) { + prod = m_baseTrackProducers.at(i); + break; + } + } + if (!prod) return false; + int default_video = prod->get_int("audio_index"); + char property[200]; + snprintf(property, sizeof(property), "meta.media.%d.codec.name", default_video); + return prod->get(property) == codec; +} + diff --git a/src/docclipbase.h b/src/docclipbase.h index f016c18d..9b76a2e7 100644 --- a/src/docclipbase.h +++ b/src/docclipbase.h @@ -197,6 +197,9 @@ Q_OBJECT public: QList cutZones() const; void updateCutZone(int oldin, int oldout, int in, int out, QString desc = QString()); + bool hasVideoCodec(const QString &codec) const; + bool hasAudioCodec(const QString &codec) const; + private: // Private attributes /** The number of times this clip is used in the project - the number of references to this clip diff --git a/src/kdenlive.notifyrc b/src/kdenlive.notifyrc index 55f28bc1..6a63a94a 100644 --- a/src/kdenlive.notifyrc +++ b/src/kdenlive.notifyrc @@ -24,3 +24,8 @@ Comment[it]=È iniziata l'esportazione di un filmato Comment[uk]=Розпочато обробку проекту Action=Popup +[Event/ErrorMessage] +Name=Error +Comment=An error occured in Kdenlive +Action=Sound +Sound=KDE-Sys-Warning.ogg diff --git a/src/kdenlivetranscodingrc b/src/kdenlivetranscodingrc index e2278fab..04d7a50d 100644 --- a/src/kdenlivetranscodingrc +++ b/src/kdenlivetranscodingrc @@ -1,9 +1,9 @@ [Transcoding] -DNxHD 1920x1080 50i/25p 185 Mb/s=-s 1920x1080 -r pal -b 185000k -threads 2 -vcodec dnxhd -acodec copy %1.mov -DNxHD 1920x1080 50i/25p 120 Mb/s=-s 1920x1080 -r pal -b 120000k -threads 2 -vcodec dnxhd -acodec copy %1.mov -DNxHD 1920x1080 60i/30p 220 Mb/s=-s 1920x1080 -r ntsc -b 220000k -threads 2 -vcodec dnxhd -acodec copy %1.mov -DNxHD 1920x1080 60i/30p 145 Mb/s=-s 1920x1080 -r ntsc -b 145000k -threads 2 -vcodec dnxhd -acodec copy %1.mov -Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg -Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv -Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg -Lossless Matroska=-sn -vcodec huffyuv -acodec flac %1.mkv +DNxHD 1920x1080 50i/25p 185 Mb/s=-s 1920x1080 -r pal -b 185000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding +DNxHD 1920x1080 50i/25p 120 Mb/s=-s 1920x1080 -r pal -b 120000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding +DNxHD 1920x1080 60i/30p 220 Mb/s=-s 1920x1080 -r ntsc -b 220000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding +DNxHD 1920x1080 60i/30p 145 Mb/s=-s 1920x1080 -r ntsc -b 145000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding +Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg;Fix unplayable MPEG-1 files;vcodec=mpeg1video +Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv;Fix unplayable OGG Theora files;vcodec=theora +Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vob files;vcodec=mpeg2video +Lossless Matroska=-sn -vcodec huffyuv -acodec flac %1.mkv;High quality lossless encoding diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 192b417e..7edb8a6e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2552,10 +2552,12 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip) if (description.isEmpty()) description = clip->getProperty("description"); else newprops.insert("templatetext", description); //newprops.insert("xmldata", m_projectList->generateTemplateXml(newtemplate, description).toString()); - - EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newprops, true); - m_activeDocument->commandStack()->push(command); + if (!newprops.isEmpty()) { + EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newprops, true); + m_activeDocument->commandStack()->push(command); + } } + delete dia; return; } QString path = clip->getProperty("resource"); @@ -2583,7 +2585,9 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip) ClipProperties dia(clip, m_activeDocument->timecode(), m_activeDocument->fps(), this); connect(&dia, SIGNAL(addMarker(const QString &, GenTime, QString)), m_activeTimeline->projectView(), SLOT(slotAddClipMarker(const QString &, GenTime, QString))); if (dia.exec() == QDialog::Accepted) { - EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), dia.properties(), true); + QMap newprops = dia.properties(); + if (newprops.isEmpty()) return; + EditClipCommand *command = new EditClipCommand(m_projectList, clip->getId(), clip->properties(), newprops, true); m_activeDocument->commandStack()->push(command); if (dia.needsTimelineRefresh()) { @@ -3016,8 +3020,12 @@ void MainWindow::loadTranscoders() QMapIterator i(profiles); while (i.hasNext()) { i.next(); + QStringList data = i.value().split(";", QString::SkipEmptyParts); QAction *a = transMenu->addAction(i.key()); - a->setData(i.value()); + a->setData(data); + if (data.count() > 1) { + a->setToolTip(data.at(1)); + } connect(a, SIGNAL(triggered()), this, SLOT(slotTranscode())); } } @@ -3025,13 +3033,22 @@ void MainWindow::loadTranscoders() void MainWindow::slotTranscode(KUrl::List urls) { QString params; + QString desc; + QString condition; if (urls.isEmpty()) { - urls.append(m_projectList->currentClipUrl()); QAction *action = qobject_cast(sender()); - params = action->data().toString(); + QStringList data = action->data().toStringList(); + params = data.at(0); + if (data.count() > 1) desc = data.at(1); + if (data.count() > 2) condition = data.at(2); + urls << m_projectList->getConditionalUrls(condition); + urls.removeAll(KUrl()); } - if (urls.isEmpty()) return; - ClipTranscode *d = new ClipTranscode(urls, params); + if (urls.isEmpty()) { + m_messageLabel->setMessage(i18n("No clip to transcode"), ErrorMessage); + return; + } + ClipTranscode *d = new ClipTranscode(urls, params, desc); connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl))); d->show(); //QProcess::startDetached("ffmpeg", parameters); diff --git a/src/projectlist.cpp b/src/projectlist.cpp index a064933a..b61b8ca1 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -1284,6 +1284,29 @@ QString ProjectList::currentClipUrl() const return item->clipUrl().path(); } +KUrl::List ProjectList::getConditionalUrls(const QString &condition) const +{ + KUrl::List result; + ProjectItem *item; + QList list = m_listView->selectedItems(); + for (int i = 0; i < list.count(); i++) { + if (list.at(i)->type() == PROJECTFOLDERTYPE) continue; + if (list.at(i)->type() == PROJECTSUBCLIPTYPE) { + // subitem + item = static_cast (list.at(i)->parent()); + } else item = static_cast (list.at(i)); + if (item == NULL) continue; + if (item->type() == COLOR || item->type() == SLIDESHOW || item->type() == TEXT) continue; + DocClipBase *clip = item->referencedClip(); + if (!condition.isEmpty()) { + if (condition.startsWith("vcodec") && !clip->hasVideoCodec(condition.section("=", 1, 1))) continue; + else if (condition.startsWith("acodec") && !clip->hasAudioCodec(condition.section("=", 1, 1))) continue; + } + result.append(item->clipUrl()); + } + return result; +} + void ProjectList::regenerateTemplate(const QString &id) { ProjectItem *clip = getItemById(id); diff --git a/src/projectlist.h b/src/projectlist.h index 4747c377..2a1a03d5 100644 --- a/src/projectlist.h +++ b/src/projectlist.h @@ -136,6 +136,7 @@ public: void setupMenu(QMenu *addMenu, QAction *defaultAction); void setupGeneratorMenu(QMenu *addMenu, QMenu *transcodeMenu); QString currentClipUrl() const; + KUrl::List getConditionalUrls(const QString &condition) const; void reloadClipThumbnails(); QDomDocument generateTemplateXml(QString data, const QString &replaceString); void cleanup(); diff --git a/src/statusbarmessagelabel.cpp b/src/statusbarmessagelabel.cpp index 814d6ef0..8bddbd63 100644 --- a/src/statusbarmessagelabel.cpp +++ b/src/statusbarmessagelabel.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ void StatusBarMessageLabel::setMessage(const QString& text, MessageType type) { if ((text == m_text) && (type == m_type)) { + if (type == ErrorMessage) KNotification::event("ErrorMessage", m_text); return; } @@ -102,6 +104,7 @@ void StatusBarMessageLabel::setMessage(const QString& text, m_timer.start(100); m_state = Illuminate; m_closeButton->hide(); + KNotification::event("ErrorMessage", m_text); break; case MltError: diff --git a/src/widgets/cliptranscode_ui.ui b/src/widgets/cliptranscode_ui.ui index a31d86e2..74a2b54d 100644 --- a/src/widgets/cliptranscode_ui.ui +++ b/src/widgets/cliptranscode_ui.ui @@ -34,14 +34,14 @@ - + FFmpeg parameters - + @@ -51,14 +51,14 @@ - + Job status - + @@ -71,7 +71,7 @@ - + Qt::Horizontal @@ -81,21 +81,21 @@ - + Start - + Add clip to project - + Close after transcode @@ -105,7 +105,7 @@ - + Qt::Horizontal @@ -135,6 +135,16 @@ + + + + QFrame::StyledPanel + + + QFrame::Raised + + + -- 2.39.2