From efa3eb3a43aeaee3a66956e5fe791260739b8aaf Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Sat, 9 Feb 2013 16:53:31 +0100 Subject: [PATCH] Allow retrieval of metadata created by Magic Lantern for canon cams --- data/CMakeLists.txt | 2 +- data/meta_ffmpeg.png | Bin 0 -> 855 bytes data/meta_libav.png | Bin 0 -> 442 bytes data/meta_magiclantern.png | Bin 0 -> 3049 bytes src/clipproperties.cpp | 38 ++++++- src/docclipbase.cpp | 16 +-- src/docclipbase.h | 14 +-- src/kdenlivesettings.kcfg | 5 + src/projectlist.cpp | 80 ++++++++++---- src/renderwidget.cpp | 1 - src/widgets/clipproperties_ui.ui | 4 +- src/widgets/configmisc_ui.ui | 173 ++++++++++++++++--------------- 12 files changed, 206 insertions(+), 127 deletions(-) create mode 100644 data/meta_ffmpeg.png create mode 100644 data/meta_libav.png create mode 100644 data/meta_magiclantern.png diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index b593105c..77c42817 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -1,4 +1,4 @@ -install(FILES banner.png timeline_nothumbs.png timeline_athumbs.png timeline_vthumbs.png timeline_avthumbs.png metadata.properties blacklisted_effects.txt blacklisted_transitions.txt encodingprofiles.rc DESTINATION ${DATA_INSTALL_DIR}/kdenlive ) +install(FILES banner.png timeline_nothumbs.png timeline_athumbs.png timeline_vthumbs.png timeline_avthumbs.png metadata.properties blacklisted_effects.txt blacklisted_transitions.txt encodingprofiles.rc meta_ffmpeg.png meta_libav.png meta_magiclantern.png DESTINATION ${DATA_INSTALL_DIR}/kdenlive ) install( FILES kdenliveeffectscategory.rc DESTINATION ${CONFIG_INSTALL_DIR} ) install (FILES kdenlive.xpm DESTINATION share/pixmaps) install (FILES kdenlive.menu DESTINATION share/menu RENAME kdenlive) diff --git a/data/meta_ffmpeg.png b/data/meta_ffmpeg.png new file mode 100644 index 0000000000000000000000000000000000000000..a46ff7fa273f4219b2675c9178203e2399afecfc GIT binary patch literal 855 zcmV-d1E~CoP)Lca(ZIwM~wNeK(5IbF@om#yvY<=owSI(O1Qzj`kBaJiiS?|;t!c@83kzAc#YN5CX!;z-?v2_G3F@ z4y5KXyw-r6+inRt-;Hg8kbcXgFSlh&oDFE8=X>a!f~Oxn&>@$li}Om>g>@2&L|}2&5o$Vp2EAK+MKBRS=gk6rI@{P@Zh8J>=>E|-KpDQE4|q-s zX@=ApArgdzuPcH2T640^G2-`z0-)J6fFVPFxvi{y&^mrI2uaAJ=+yrK5`FlBOc1aD z%k$2yx|%9}YSrfTggrX!N`SP?gsV*@t&gZUf(T;iX<-*2EQKir!Paq~m#cn=jbEFhXEvj-5s9@topIO;0Rc_T~j-P__8Cpcx$@|w2B zqUM)W9Hq{xcmv2gTZm_1|GEC7?xZ>I_1ue9yKgal!$Cvi*oK(c)I6|1b^yKTf7Qg6}@9hLn`0Trl0a1rJb95Z=D(?9-;V_C`e~%28S3> h$0~yMd!7FYFaQo3OLD0b*?#~4002ovPDHLkV1i@qfL;Iq literal 0 HcmV?d00001 diff --git a/data/meta_libav.png b/data/meta_libav.png new file mode 100644 index 0000000000000000000000000000000000000000..c7991da0de5e4869e9c83df8083b03a82fc3fa70 GIT binary patch literal 442 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 literal 0 HcmV?d00001 diff --git a/src/clipproperties.cpp b/src/clipproperties.cpp index c3562a93..ea758539 100644 --- a/src/clipproperties.cpp +++ b/src/clipproperties.cpp @@ -196,12 +196,42 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg connect(m_view.clip_full_luma, SIGNAL(toggled(bool)), this, SLOT(slotModified())); // Check for Metadata - QMap meta = m_clip->metadata(); - QMap::const_iterator i = meta.constBegin(); + QMap meta = m_clip->metadata(); + QMap::const_iterator i = meta.constBegin(); while (i != meta.constEnd()) { - QTreeWidgetItem *metaitem = new QTreeWidgetItem(m_view.metadata_list); + QStringList values = i.value(); + QString parentName; + QString iconName; + if (values.count() > 1 && !values.at(1).isEmpty()) parentName = values.at(1); + else { + if (KdenliveSettings::ffmpegpath().endsWith("avconv")) { + parentName = i18n("Libav"); + iconName = "meta_libav.png"; + } + else { + parentName = i18n("FFmpeg"); + iconName = "meta_ffmpeg.png"; + } + } + QTreeWidgetItem *parent = NULL; + QList matches = m_view.metadata_list->findItems(parentName, Qt::MatchExactly); + if (!matches.isEmpty()) parent = matches.at(0); + else { + if (parentName == "Magic Lantern") iconName = "meta_magiclantern.png"; + parent = new QTreeWidgetItem(m_view.metadata_list, QStringList() << parentName); + if (!iconName.isEmpty()) { + KIcon icon(KStandardDirs::locate("appdata", iconName)); + parent->setIcon(0, icon); + } + } + QTreeWidgetItem *metaitem = NULL; + if (parent) { + metaitem = new QTreeWidgetItem(parent); + parent->setExpanded(true); + } + else metaitem = new QTreeWidgetItem(m_view.metadata_list); metaitem->setText(0, i.key()); //i18n(i.key().section('.', 2, 3).toUtf8().data())); - metaitem->setText(1, i.value()); + metaitem->setText(1, values.at(0)); ++i; } diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 85730560..1a2dda8f 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -64,14 +64,14 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin for (int i = 0; i < attributes.count(); i++) { QString name = attributes.item(i).nodeName(); if (name.startsWith("meta.attr.")) { - m_metadata.insert(name.section('.', 2), attributes.item(i).nodeValue()); + m_metadata.insert(name.section('.', 2), QStringList() << attributes.item(i).nodeValue()); } else m_properties.insert(name, attributes.item(i).nodeValue()); } QDomNodeList metas = xml.elementsByTagName("metaproperty"); for (int i = 0; i < metas.count(); i++) { QDomElement e = metas.item(i).toElement(); if (!e.isNull()) { - m_metadata.insert(e.attribute("name").section('.', 2), e.firstChild().nodeValue()); + m_metadata.insert(e.attribute("name").section('.', 2), QStringList() << e.firstChild().nodeValue() << e.attribute("tool")); } } @@ -263,14 +263,16 @@ QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const if (!i.value().isEmpty()) clip.setAttribute(i.key(), i.value()); } - QMapIterator j(m_metadata); + QMapIterator j(m_metadata); // Metadata name can have special chars so we cannot pass it as simple attribute while (j.hasNext()) { j.next(); if (!j.value().isEmpty()) { QDomElement property = doc.createElement("metaproperty"); property.setAttribute("name", "meta.attr." + j.key()); - QDomText value = doc.createTextNode(j.value()); + QStringList values = j.value(); + QDomText value = doc.createTextNode(values.at(0)); + if (values.count() > 1) property.setAttribute("tool", values.at(1)); property.appendChild(value); clip.appendChild(property); } @@ -996,7 +998,7 @@ void DocClipBase::setProperties(QMap properties) if (refreshProducer) slotRefreshProducer(); } -void DocClipBase::setMetadata(QMap properties) +void DocClipBase::setMetadata(QMap properties, QString tool) { QMapIterator i(properties); while (i.hasNext()) { @@ -1004,12 +1006,12 @@ void DocClipBase::setMetadata(QMap properties) if (i.value().isEmpty() && m_metadata.contains(i.key())) { m_metadata.remove(i.key()); } else { - m_metadata.insert(i.key(), i.value()); + m_metadata.insert(i.key(), QStringList() << i.value() << tool); } } } -QMap DocClipBase::metadata() const +QMap DocClipBase::metadata() const { return m_metadata; } diff --git a/src/docclipbase.h b/src/docclipbase.h index 6ac74221..9eb12719 100644 --- a/src/docclipbase.h +++ b/src/docclipbase.h @@ -206,6 +206,11 @@ Q_OBJECT public: /** Cache for every audio Frame with 10 Bytes */ /** format is frame -> channel ->bytes */ QMap > audioFrameCache; + /** Returns all current properties for this clip */ + QMap properties() const; + /** Return the current values for a set of properties */ + QMap currentProperties(QMap props); + QMap metadata() const; private: // Private attributes /** The number of times this clip is used in the project - the number of references to this clip @@ -236,7 +241,7 @@ private: // Private attributes /** Holds clip infos like fps, size,... */ QMap m_properties; /** Holds clip metadata like author, copyright,... */ - QMap m_metadata; + QMap m_metadata; /** Holds clip analysis data that can be used later to create markers or keyframes */ QMap m_analysisdata; @@ -275,12 +280,7 @@ public slots: void setClipThumbFrame(const uint &ix); uint getClipThumbFrame() const; void setProperties(QMap properties); - void setMetadata(QMap properties); - /** Returns all current properties for this clip */ - QMap properties() const; - /** Return the current values for a set of properties */ - QMap currentProperties(QMap props); - QMap metadata() const; + void setMetadata(QMap properties, QString tool = QString()); void slotExtractImage(QList frames); signals: diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index a50e3d39..b00e5914 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -70,6 +70,11 @@ false + + + false + + 00:00:05:00 diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 0d6c5eb5..6564238a 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -2199,31 +2199,67 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) void ProjectList::extractMetadata(DocClipBase *clip) { QMap props = clip->properties(); - if (props.contains("exiftool")) { - // metadata was already extracted - return; + if (KdenliveSettings::use_exiftool() && !props.contains("exiftool")) { + QString codecid = props.value("videocodecid").simplified(); + if (codecid == "h264") { + QProcess p; + QStringList args; + args << "-g" << "-args" << clip->fileURL().encodedPathAndQuery(); + p.start("exiftool", args); + p.waitForFinished(); + QString res = p.readAllStandardOutput(); + QStringList list = res.split("\n"); + QMap meta; + foreach(QString tagline, list) { + if (!tagline.startsWith("-H264")) continue; + QString tag = tagline.section(':', 1); + if (tag.startsWith("ImageWidth") || tag.startsWith("ImageHeight")) continue; + meta.insert(tag.section('=', 0, 0), tag.section('=', 1)); + } + clip->setProperty("exiftool", "1"); + if (!meta.isEmpty()) { + clip->setMetadata(meta, "ExifTool"); + //checkCamcorderFilters(clip, meta); + } + } } - QString codecid = props.value("videocodecid").simplified(); - if (codecid == "h264") { - QProcess p; - QStringList args; - args << "-g" << "-args" << clip->fileURL().encodedPathAndQuery(); - p.start("exiftool", args); - p.waitForFinished(); - QString res = p.readAllStandardOutput(); - QStringList list = res.split("\n"); + if (KdenliveSettings::use_magicLantern() && !props.contains("magiclantern")) { QMap meta; - foreach(QString tagline, list) { - if (!tagline.startsWith("-H264")) continue; - QString tag = tagline.section(':', 1); - if (tag.startsWith("ImageWidth") || tag.startsWith("ImageHeight")) continue; - meta.insert(tag.section('=', 0, 0), tag.section('=', 1)); + QString url = clip->fileURL().path(); + url = url.section('.', 0, -2) + ".LOG"; + if (QFile::exists(url)) { + QFile file(url); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QString line = file.readLine().simplified(); + if (line.startsWith('#') || line.isEmpty() || !line.contains(':')) continue; + if (line.startsWith("CSV data")) break; + meta.insert(line.section(':', 0, 0).simplified(), line.section(':', 1).simplified()); + } + } } - clip->setProperty("exiftool", "1"); - if (!meta.isEmpty()) { - clip->setMetadata(meta); - //checkCamcorderFilters(clip, meta); + url = url.section('.', 0, -2) + ".THM"; + if (QFile::exists(url) && KdenliveSettings::use_exiftool()) { + // Read the exif metadata embeded in the THM file + QProcess p; + QStringList args; + args << "-g" << "-args" << url; + p.start("exiftool", args); + p.waitForFinished(); + QString res = p.readAllStandardOutput(); + QStringList list = res.split("\n"); + foreach(QString tagline, list) { + if (tagline.startsWith("-File") || tagline.startsWith("-ExifTool")) continue; + QString tag = tagline.section(':', 1).simplified(); + if (tag.startsWith("ImageWidth") || tag.startsWith("ImageHeight")) continue; + if (!tag.section('=', 0, 0).isEmpty() && !tag.section('=', 1).simplified().isEmpty()) + meta.insert(tag.section('=', 0, 0), tag.section('=', 1).simplified()); + } } + + if (!meta.isEmpty()) + clip->setMetadata(meta, "Magic Lantern"); + clip->setProperty("magiclantern", "1"); } } @@ -2245,7 +2281,7 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } item->setProperties(properties, metadata); clip->setProducer(producer, replace); - if (KdenliveSettings::use_exiftool()) extractMetadata(clip); + extractMetadata(clip); m_render->processingDone(clipId); // Proxy stuff diff --git a/src/renderwidget.cpp b/src/renderwidget.cpp index 1e470779..c800c043 100644 --- a/src/renderwidget.cpp +++ b/src/renderwidget.cpp @@ -2116,7 +2116,6 @@ void RenderWidget::missingClips(bool hasMissing) void RenderWidget::errorMessage(const QString &message) { if (!message.isEmpty()) { - kDebug()<<"// ERROR MESS: "<setMessageType(KMessageWidget::Warning); m_infoMessage->setText(message); diff --git a/src/widgets/clipproperties_ui.ui b/src/widgets/clipproperties_ui.ui index eee6c775..8ae184d2 100644 --- a/src/widgets/clipproperties_ui.ui +++ b/src/widgets/clipproperties_ui.ui @@ -7,7 +7,7 @@ 0 0 323 - 556 + 557 @@ -528,7 +528,7 @@ false - false + true false diff --git a/src/widgets/configmisc_ui.ui b/src/widgets/configmisc_ui.ui index 16987b46..166f9da6 100644 --- a/src/widgets/configmisc_ui.ui +++ b/src/widgets/configmisc_ui.ui @@ -17,7 +17,91 @@ 0 - + + + + Use KDE job tracking for render jobs + + + + + + + Check if first added clip matches project profile + + + + + + + Crash recovery (automatic backup) + + + + + + + Automatically import all streams in multi stream clips + + + + + + + Disable parameters when the effect is disabled + + + + + + + Bypass codec verification + + + + + + + Automatically import image sequences + + + + + + + Do not validate the video files when loading a project (faster) + + + + + + + Use on-monitor effects + + + + + + + Open projects in new tabs + + + + + + + Get clip metadata with exiftool + + + + + + + Open last project on startup + + + + Default Durations @@ -85,56 +169,14 @@ - - - - Bypass codec verification - - - - - - - Use on-monitor effects - - - - - - - Crash recovery (automatic backup) - - - - - - - Check if first added clip matches project profile - - - - - - - Open last project on startup - - - - - - - Automatically import image sequences - - - - + Transparent background for imported images - + Qt::Vertical @@ -147,45 +189,10 @@ - - + + - Use KDE job tracking for render jobs - - - - - - - Automatically import all streams in multi stream clips - - - - - - - Disable parameters when the effect is disabled - - - - - - - Do not validate the video files when loading a project (faster) - - - - - - - Open projects in new tabs - - - - - - - Get clip metadata with exiftool + Get clip metadata created by Magic Lantern -- 2.39.2