]> git.sesse.net Git - kdenlive/commitdiff
* Allow transcoding of several clips (selected in project tree):
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Sun, 3 Jan 2010 20:50:45 +0000 (20:50 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Sun, 3 Jan 2010 20:50:45 +0000 (20:50 +0000)
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

12 files changed:
src/clipproperties.cpp
src/cliptranscode.cpp
src/cliptranscode.h
src/docclipbase.cpp
src/docclipbase.h
src/kdenlive.notifyrc
src/kdenlivetranscodingrc
src/mainwindow.cpp
src/projectlist.cpp
src/projectlist.h
src/statusbarmessagelabel.cpp
src/widgets/cliptranscode_ui.ui

index 423a2814828349da2a40954ca0fb907d62f3963a..708f19462c5c46bf3b0c88ce9aaf369ddce35c03 100644 (file)
@@ -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 <QString, QString> 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;
index e81b4b5479f417e90bf6d12c94633d927332cd37..1d9e29fa601a4a8ce0f7e3e43e9e35f0534c8888 100644 (file)
@@ -26,7 +26,7 @@
 #include <KFileDialog>
 
 
-ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, QWidget * parent) :
+ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, const QString &description, QWidget * parent) :
         QDialog(parent), m_urls(urls)
 {
     setFont(KGlobalSettings::toolBarFont());
@@ -57,6 +57,9 @@ ClipTranscode::ClipTranscode(KUrl::List urls, const QString &params, 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 &params, QWidget * p
         // read the entries
         QMap< QString, QString > profiles = transConfig.entryMap();
         QMapIterator<QString, QString> 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);
index 9933da5864bb148c18b756578e8459816252f0a6..5988fb0e7dab55e3c03b59be3ce18314a692c10c 100644 (file)
@@ -33,7 +33,7 @@ class ClipTranscode : public QDialog, public Ui::ClipTranscode_UI
     Q_OBJECT
 
 public:
-    ClipTranscode(KUrl::List urls, const QString &params, QWidget * parent = 0);
+    ClipTranscode(KUrl::List urls, const QString &params, const QString &description, QWidget * parent = 0);
     ~ClipTranscode();
 
 
index 7b7574c6404ab171e1763970fccb401d2dcb99d5..9dfa1d7a06e610ec70c67f893f58acfc775957be 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <QCryptographicHash>
 
+#include <cstdio>
+
 DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) :
         QObject(),
         m_audioFrameCache(),
@@ -929,3 +931,38 @@ QList <CutZoneInfo> 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;
+}
+
index f016c18d497aab8a215e8e2a1239d03c7eb19ff9..9b76a2e72c8e11f8dce673866f5a47f104807dc4 100644 (file)
@@ -197,6 +197,9 @@ Q_OBJECT public:
     QList <CutZoneInfo> 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
index 55f28bc1ab7044c55275f72f162ee99e79ca53e9..6a63a94a7ffb1a789ecb740dc4f7cb5d1d2fcf68 100644 (file)
@@ -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
index e2278fab66d6e2661e3eaaf5403670cd23afa1b8..04d7a50d7f051c183362881e11ba4a3d70281dc7 100644 (file)
@@ -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
index 192b417e9da665de41d623d4667947abfca452da..7edb8a6e7527a4187be5a7e56debeceb3a390456 100644 (file)
@@ -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 <QString, QString> 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<QString, QString> 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<QAction *>(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);
index a064933a8b8b78544ade74cec1a6efeb328429bf..b61b8ca1fc78b2ba56fa6aefce10c6fe61198714 100644 (file)
@@ -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<QTreeWidgetItem *> 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 <ProjectItem*>(list.at(i)->parent());
+        } else item = static_cast <ProjectItem*>(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);
index 4747c377892fa6234c323ddabfad5e6d604bcc9e..2a1a03d56d88c39533722a0d066573ef2bd77515 100644 (file)
@@ -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();
index 814d6ef0d05779fdbf45fad33a99b8042eb4ea43..8bddbd63ad23857091079d93fe94697488676439 100644 (file)
@@ -26,6 +26,7 @@
 #include <kiconloader.h>
 #include <kicon.h>
 #include <klocale.h>
+#include <KNotification>
 
 #include <QFontMetrics>
 #include <QPainter>
@@ -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:
index a31d86e2f3c1525785811a2223ddabe96b85f326..74a2b54dc9fd10aa0026000581020f19cf4d32f7 100644 (file)
    <item row="1" column="1" colspan="2">
     <widget class="KUrlRequester" name="dest_url"/>
    </item>
-   <item row="4" column="0" colspan="3">
+   <item row="5" column="0" colspan="3">
     <widget class="QLabel" name="label_3">
      <property name="text">
       <string>FFmpeg parameters</string>
      </property>
     </widget>
    </item>
-   <item row="5" column="0" colspan="3">
+   <item row="6" column="0" colspan="3">
     <widget class="QTextEdit" name="ffmpeg_params">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Maximum">
      </property>
     </widget>
    </item>
-   <item row="6" column="0">
+   <item row="7" column="0">
     <widget class="QLabel" name="label_4">
      <property name="text">
       <string>Job status</string>
      </property>
     </widget>
    </item>
-   <item row="7" column="0" colspan="3">
+   <item row="8" column="0" colspan="3">
     <widget class="QTextEdit" name="log_text">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@@ -71,7 +71,7 @@
      </property>
     </widget>
    </item>
-   <item row="10" column="2">
+   <item row="11" column="2">
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
-   <item row="10" column="0">
+   <item row="11" column="0">
     <widget class="QPushButton" name="button_start">
      <property name="text">
       <string>Start</string>
      </property>
     </widget>
    </item>
-   <item row="8" column="0" colspan="2">
+   <item row="9" column="0" colspan="2">
     <widget class="QCheckBox" name="auto_add">
      <property name="text">
       <string>Add clip to project</string>
      </property>
     </widget>
    </item>
-   <item row="8" column="2">
+   <item row="9" column="2">
     <widget class="QCheckBox" name="auto_close">
      <property name="text">
       <string>Close after transcode</string>
      </property>
     </widget>
    </item>
-   <item row="10" column="1">
+   <item row="11" column="1">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
+   <item row="4" column="0" colspan="3">
+    <widget class="QLabel" name="transcode_info">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>