</caption>
</mediaobject>
</screenshot></para>
-<para>Let’s save the work via <menuchoice><guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice>. This saves our project, &ie; where we placed the clips on the timeline, which effects we applied, and so on. It can <emphasis>not</emphasis> be played.<footnote><para>To be correct, it <emphasis>can</emphasis> be played using <screen>melt yourproject.kdenlive</screen>, but this is not the way you would want to present your final video since it is (most likely) too slow. Additionally, it only works if melt is installed.</para></footnote> The process of creating the final video is called <emphasis>Rendering</emphasis>.</para>
+<para>Let’s save the work via <menuchoice><guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice>. This saves our project, &ie; where we placed the clips on the timeline, which effects we applied, and so on. It can <emphasis>not</emphasis> be played.<footnote><para>To be correct, it <emphasis>can</emphasis> be played using <varname>melt yourproject.kdenlive</varname>, but this is not the way you would want to present your final video since it is (most likely) too slow. Additionally, it only works if melt is installed.</para></footnote> The process of creating the final video is called <emphasis>Rendering</emphasis>.</para>
</chapter>
<chapter id="timeline"><title>Timeline</title>
<para>Now comes the actual editing. Project clips are combined to the final result on the timeline. They get there by drag and drop: Drag some Napoli (assuming you are using the files provided above, as in the rest of this quick start tutorial; If not, please make sure your screen is waterproof, and perhaps tomatoproof), and drop it onto the first track in the timeline.</para>
</caption>
</mediaobject>
</screenshot></para>
-<para>Now that the clips overlap, the transition can be added. This is done either by right-clicking on the upper clip and chosing <guilabel>Add Transition</guilabel> or, easier, by clicking the lower right corner of the Spoon clip. The latter by default adds a dissolve transition, which is in this case the best idea anyway since the Spoon is not required for playing anyway.</para>
+<para>Now that the clips overlap, the transition can be added. This is done either by right-clicking on the upper clip and choosing <guilabel>Add Transition</guilabel> or, easier, by clicking the lower right corner of the Spoon clip. The latter by default adds a dissolve transition, which is in this case the best idea anyway since the Spoon is not required for playing anyway.</para>
<para>The dissolve transitions fades the first clip into the second one.</para>
<para>
<screenshot>
}
}
QString id;
+ Mlt::Producer *prod;
+ QStringList brokenClips;
for (int i = 0; i < prods.count(); i++) {
- id = prods.at(i)->get("id");
+ prod = prods.at(i);
+ id = prod->get("id");
if (id.contains('_')) id = id.section('_', 0, 0);
DocClipBase *clip = getClipById(id);
- if (clip) {
- clip->setProducer(prods.at(i), false, true);
+ QString markup = prod->get("markup");
+ if (prod->is_blank() || !prod->is_valid() || !markup.isEmpty()) {
+ // The clip is broken (missing proxy or source clip)
+ kDebug()<<"// WARNING, CLIP "<<id<<" Cannot be loaded";
+ brokenClips << id;
+ }
+ else if (clip) {
+ clip->setProducer(prod, false, true);
}
}
- emit checkAllClips(displayRatioChanged, fpsChanged);
+ emit checkAllClips(displayRatioChanged, fpsChanged, brokenClips);
}
void ClipManager::slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId)
void modifiedClip(const QString &);
void missingClip(const QString &);
void availableClip(const QString &);
- void checkAllClips(bool displayRatioChanged, bool fpsChanged);
+ void checkAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
};
#endif
if (m_thumbProd) m_thumbProd->clearProducer();
}
+void DocClipBase::reloadThumbProducer()
+{
+ if (m_thumbProd && !m_thumbProd->hasProducer())
+ m_thumbProd->setProducer(getProducer());
+}
+
void DocClipBase::deleteProducers()
{
if (m_thumbProd) m_thumbProd->clearProducer();
Mlt::Producer *DocClipBase::cloneProducer(Mlt::Producer *source)
{
Mlt::Producer *result = NULL;
+ QString invalidClip = source->get("markup");
QString url = QString::fromUtf8(source->get("resource"));
if (KIO::NetAccess::exists(KUrl(url), KIO::NetAccess::SourceSide, 0)) {
result = new Mlt::Producer(*(source->profile()), url.toUtf8().constData());
void setPlaceHolder(bool place);
QPixmap extractImage(int frame, int width, int height);
void clearThumbProducer();
+ void reloadThumbProducer();
void cleanupProducers();
bool isClean() const;
GenericName=Video Editor
GenericName[cs]=Editor videí
GenericName[de]=Video-Editor
+GenericName[nl]=Video-bewerker
GenericName[pt]=Editor de Vídeo
GenericName[sv]=Videoeditor
GenericName[uk]=Відеоредактор
GenericName[x-test]=xxVideo Editorxx
Comment=Nonlinear video editor for KDE
Comment[de]=Nichtlinearer Video-Editor für KDE
+Comment[nl]=Niet-lineaire video-bewerker voor KDE
Comment[pt]=Editor de vídeo não-linear para o KDE
Comment[sv]=Icke-linjär videoeditor för KDE
Comment[uk]=Нелінійний редактор відео для KDE
Comment[cs]=Kdenlive
Comment[de]=Kdenlive
Comment[nds]=Kdenlive
+Comment[nl]=Kdenlive
Comment[pt]=Kdenlive
Comment[sv]=Kdenlive
Comment[uk]=Kdenlive
[Event/RenderFinished]
Name=Rendering finished
Name[cs]=Renderování bylo dokončeno
+Name[nl]=Weergave uitwerken beëindigd
Name[pt]=A geração terminou
Name[sv]=Framställning klar
Name[uk]=Обробку завершено
Name[x-test]=xxRendering finishedxx
Comment=Rendering is over
Comment[cs]=Renderování je hotové
+Comment[nl]=Weergave uitwerken is gereed
Comment[pt]=A geração terminou
Comment[sv]=Framställning är gjord
Comment[uk]=Виконання обробки завершено
[Event/RenderStarted]
Name=Rendering started
Name[cs]=Renderování začalo
+Name[nl]=Weergave uitwerken begonnen
Name[pt]=A geração foi iniciada
Name[sv]=Framställning startad
Name[uk]=Обробку розпочато
Name[x-test]=xxRendering startedxx
Comment=Rendering was started
Comment[cs]=Renderování bylo začato
+Comment[nl]=Weergave uitwerken is begonnen
Comment[pt]=A geração foi iniciada
Comment[sv]=Framställning har startats
Comment[uk]=Було розпочато обробку
[Event/FrameCaptured]
Name=Frame captured
+Name[nl]=Frame opgenomen
Name[pt]=Imagem capturada
Name[sv]=Ram lagrad
Name[uk]=Захоплено кадр
Name[x-test]=xxFrame capturedxx
Comment=A frame was captured to disk
+Comment[nl]=Een frame is op schijf opgenomen
Comment[pt]=Foi capturada uma imagem para o disco
Comment[sv]=En ram har lagrats på disk
Comment[uk]=Було захоплено кадр, програма зберегла його на диску
[Event/ReadyToCapture]
Name=Ready to capture
+Name[nl]=Gereed om op te nemen
Name[pt]=Pronto para capturar
Name[sv]=Klar att lagra
Name[uk]=Приготовано до захоплення
Name[uk]=Помилка
Name[x-test]=xxErrorxx
Comment=An error occurred in Kdenlive
-Comment[de]=Es ist ein Fehler in Kdenlive aufgetreten
+Comment[nl]=Er is een fout opgetreden in Kdenlive
Comment[pt]=Ocorreu um erro no Kdenlive
Comment[sv]=Ett fel uppstod i Kdenlive
Comment[uk]=У коді Kdenlive сталася помилка
-Comment[x-test]=xxAn error occured in Kdenlivexx
+Comment[x-test]=xxAn error occurred in Kdenlivexx
Sound=KDE-Sys-Warning.ogg
Action=Sound
else requestClipThumbnail(parentItem->clipId() + '#' + QString::number(pos));
}
-void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged)
+void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips)
{
if (!m_allClipsProcessed) m_listView->setEnabled(false);
m_listView->setSortingEnabled(false);
item = static_cast <ProjectItem *>(*it);
clip = item->referencedClip();
if (item->referencedClip()->getProducer() == NULL) {
+ bool replace = false;
+ if (brokenClips.contains(item->clipId())) {
+ // if this is a proxy clip, disable proxy
+ item->setProxyStatus(NOPROXY);
+ clip->setProperty("proxy", "-");
+ replace = true;
+ }
if (clip->isPlaceHolder() == false && !item->isProxyRunning()) {
QDomElement xml = clip->toXML();
if (fpsChanged) {
xml.removeAttribute("file_hash");
xml.removeAttribute("proxy_out");
}
- bool replace = xml.attribute("replace") == "1";
+ if (!replace) replace = xml.attribute("replace") == "1";
if (replace) resetThumbsProducer(clip);
m_render->getFileProperties(xml, clip->getId(), m_listView->iconSize().height(), replace);
}
{
ProjectItem *item = getItemById(id);
if (item) {
+ kDebug()<<"// Proxy for clip "<<id<<" is invalid, delete";
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
if (durationError) {
kDebug() << "Proxy duration is wrong, try changing transcoding parameters.";
if (proxyFolder.isParentOf(KUrl(path))) {
QFile::remove(path);
}
+ if (item->referencedClip()->getProducer() == NULL) {
+ // Clip has no valid producer, request it
+ slotProxyCurrentItem(false, item);
+ }
+ else {
+ // refresh thumbs producer
+ item->referencedClip()->reloadThumbProducer();
+ }
}
m_processingClips.removeAll(id);
m_thumbnailQueue.removeAll(id);
connect(m_doc->clipManager(), SIGNAL(modifiedClip(const QString &)), this, SLOT(slotModifiedClip(const QString &)));
connect(m_doc->clipManager(), SIGNAL(missingClip(const QString &)), this, SLOT(slotMissingClip(const QString &)));
connect(m_doc->clipManager(), SIGNAL(availableClip(const QString &)), this, SLOT(slotAvailableClip(const QString &)));
- connect(m_doc->clipManager(), SIGNAL(checkAllClips(bool, bool)), this, SLOT(updateAllClips(bool, bool)));
+ connect(m_doc->clipManager(), SIGNAL(checkAllClips(bool, bool, QStringList)), this, SLOT(updateAllClips(bool, bool, QStringList)));
}
QList <DocClipBase*> ProjectList::documentClipList() const
else delete command;
}
-void ProjectList::slotProxyCurrentItem(bool doProxy)
+void ProjectList::slotProxyCurrentItem(bool doProxy, ProjectItem *itemToProxy)
{
- QList<QTreeWidgetItem *> list = m_listView->selectedItems();
+ QList<QTreeWidgetItem *> list;
+ if (itemToProxy == NULL) list = m_listView->selectedItems();
+ else list << itemToProxy;
QTreeWidgetItem *listItem;
QUndoCommand *command = new QUndoCommand();
if (doProxy) command->setText(i18np("Add proxy clip", "Add proxy clips", list.count()));
ProjectItem *item = static_cast <ProjectItem*>(listItem);
CLIPTYPE t = item->clipType();
if ((t == VIDEO || t == AV || t == UNKNOWN || t == IMAGE || t == PLAYLIST) && item->referencedClip()) {
- if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy())) continue;
+ if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy() && item->referencedClip()->getProducer() != NULL)) continue;
DocClipBase *clip = item->referencedClip();
if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) {
kDebug()<<"//// TRYING TO PROXY: "<<item->clipId()<<", but it is busy";
// We need to insert empty proxy so that undo will work
oldProps.insert("proxy", QString());
}
+ else if (item->referencedClip()->getProducer() == NULL) {
+ // Force clip reload
+ newProps.insert("resource", item->referencedClip()->getProperty("resource"));
+ }
new EditClipCommand(this, item->clipId(), oldProps, newProps, true, command);
}
}
public slots:
void setDocument(KdenliveDoc *doc);
- void updateAllClips(bool displayRatioChanged, bool fpsChanged);
+ void updateAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
void slotReplyGetImage(const QString &clipId, const QImage &img);
void slotReplyGetImage(const QString &clipId, const QString &name, int width, int height);
void slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const stringMap &properties, const stringMap &metadata, bool replace);
void slotGotProxy(const QString &proxyPath);
void slotGotProxy(ProjectItem *item);
/** @brief Enable / disable proxy for current clip. */
- void slotProxyCurrentItem(bool doProxy);
+ void slotProxyCurrentItem(bool doProxy, ProjectItem *itemToProxy = NULL);
/** @brief Put clip in the proxy waiting list. */
void slotCreateProxy(const QString id);
/** @brief Stop creation of this clip's proxy. */
<height>300</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="5">
<widget class="QComboBox" name="windowSize"/>
<height>75</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
<height>332</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
<height>85</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="horizontalSpacing">
<number>0</number>
<height>296</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="cbY">
<height>300</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="5">
<widget class="QComboBox" name="windowSize"/>
<height>450</height>
</size>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblPaintMode">
<height>300</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>5</number>
<height>110</height>
</rect>
</property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label">
Name=MLT Playlist
Name[cs]=Seznam skladeb MLT
Name[de]=MLT-Wiedergabeliste
+Name[nl]=MLT-afspeellijst
Name[pt]=Lista de Reprodução MLT
Name[sv]=MLT-spellista
Name[uk]=Список відтворення MLT