<parameter type="bool" name="obscure" default="1">
<name>Obscure</name>
</parameter>
- <parameter type="filterjob" filtertag="autotrack_rectangle" filterparams="_serialize=1 motion_vector_list=0 %params" consumer="null" consumerparams="all=1 terminate_on_pause=1">
+ <parameter type="filterjob" filtertag="autotrack_rectangle" filterparams="_serialize=1 motion_vector_list=0 %params in=%position" consumer="null" consumerparams="all=1 terminate_on_pause=1">
<jobparam name="storedata" />
<jobparam name="projecttreefilter" />
<jobparam name="key">motion_vector_list</jobparam>
m_selectedKeyframe(0),
m_keyframeFactor(1),
m_keyframeOffset(0),
- m_fps(fps)
+ m_fps(fps),
+ m_isMainSelectedClip(false)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
}
-void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit)
+void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/)
{
GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos;
if (durationDiff == GenTime()) return;
}*/
}
-void AbstractClipItem::resizeEnd(int posx)
+void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/)
{
GenTime durationDiff = GenTime(posx, m_fps) - endPos();
if (durationDiff == GenTime()) return;
return 0;
}
+void AbstractClipItem::setMainSelectedClip(bool selected)
+{
+ if (selected == m_isMainSelectedClip) return;
+ m_isMainSelectedClip = selected;
+ update();
+}
+
+bool AbstractClipItem::isMainSelectedClip()
+{
+ return m_isMainSelectedClip;
+}
/** @brief Resizes the clip from the start.
* @param posx Absolute position of new in point
* @param hasSizeLimit (optional) Whether the clip has a maximum size */
- virtual void resizeStart(int posx, bool hasSizeLimit = true);
+ virtual void resizeStart(int posx, bool hasSizeLimit = true, bool emitChange = true);
/** @brief Resizes the clip from the end.
* @param posx Absolute position of new out point */
- virtual void resizeEnd(int posx);
+ virtual void resizeEnd(int posx, bool emitChange = true);
virtual double fps() const;
virtual void updateFps(double fps);
virtual GenTime maxDuration() const;
virtual void setCropStart(GenTime pos);
+ /** @brief Set this clip as the main selected clip (or not). */
+ void setMainSelectedClip(bool selected);
+ /** @brief Is this clip selected as the main clip. */
+ bool isMainSelectedClip();
+
protected:
ItemInfo m_info;
/** The position of the current keyframe when it has moved */
/** The (keyframe) parameter that is visible and editable in timeline (on the clip) */
int m_visibleParam;
double m_fps;
+ /** @brief True if this is the last clip the user selected */
+ bool m_isMainSelectedClip;
/** @brief Draw the keyframes of a clip
* @param painter The painter device for the clip
* @param limitedKeyFrames The keyframes can be of type "keyframe" or "simplekeyframe". In the
m_speed(speed),
m_strobe(strobe),
m_framePixelWidth(0),
- m_limitedKeyFrames(false),
- m_isMainSelectedClip(false)
+ m_limitedKeyFrames(false)
{
setZValue(2);
m_effectList = EffectsList(true);
}
*/
-void ClipItem::resizeStart(int posx, bool /*size*/)
+void ClipItem::resizeStart(int posx, bool /*size*/, bool emitChange)
{
bool sizeLimit = false;
if (clipType() != IMAGE && clipType() != COLOR && clipType() != TEXT) {
m_startThumbTimer.start(150);
}
}
+ if (m_isMainSelectedClip && emitChange) emit updateRange();
}
-void ClipItem::resizeEnd(int posx)
+void ClipItem::resizeEnd(int posx, bool emitChange)
{
const int max = (startPos() - cropStart() + maxDuration()).frames(m_fps);
if (posx > max && maxDuration() != GenTime()) posx = max;
m_endThumbTimer.start(150);
}
}
+ if (m_isMainSelectedClip && emitChange) emit updateRange();
}
//virtual
update();
}
-void ClipItem::setMainSelectedClip(bool selected)
-{
- if (selected == m_isMainSelectedClip) return;
- m_isMainSelectedClip = selected;
- update();
-}
-
-bool ClipItem::isMainSelectedClip()
-{
- return m_isMainSelectedClip;
-}
#include "clipitem.moc"
const QStyleOptionGraphicsItem *option,
QWidget *);
virtual int type() const;
- void resizeStart(int posx, bool size = true);
- void resizeEnd(int posx);
+ void resizeStart(int posx, bool size = true, bool emitChange = true);
+ void resizeEnd(int posx, bool emitChange = true);
OPERATIONTYPE operationMode(QPointF pos);
static int itemHeight();
const QString clipProducer() const;
/** @brief Get a free index value for effect group. */
int nextFreeEffectGroupIndex() const;
- /** @brief Set this clip as the main selected clip (or not). */
- void setMainSelectedClip(bool selected);
- /** @brief Is this clip selected as the main clip. */
- bool isMainSelectedClip();
protected:
//virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
/** @brief Keyframes type can be "keyframe" or "simplekeyframe" which have to be painted differently.
* True if keyframe type is "keyframe" */
bool m_limitedKeyFrames;
- /** @brief True if this is the last clip the user selected */
- bool m_isMainSelectedClip;
private slots:
void slotGetStartThumb();
void slotSetEndThumb(const QPixmap pix);
signals:
- void getThumb(int, int);
void prepareAudioThumb(double, int, int, int);
+ void updateRange();
};
#endif
keyframe_list->selectRow(row);
}
+
#include "cornerswidget.moc"
if (parent)
parent->resizeStart((int)(snappedPos - m_dragItemInfo.startPos.frames(m_document->fps())));
} else {
- m_dragItem->resizeStart((int)(snappedPos));
+ m_dragItem->resizeStart((int)(snappedPos), true, false);
}
QString crop = m_document->timecode().getDisplayTimecode(m_dragItem->cropStart(), KdenliveSettings::frametimecode());
QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode());
if (parent)
parent->resizeEnd((int)(snappedPos - m_dragItemInfo.endPos.frames(m_document->fps())));
} else {
- m_dragItem->resizeEnd((int)(snappedPos));
+ m_dragItem->resizeEnd((int)(snappedPos), false);
}
QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode());
QString offset = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration() - m_dragItemInfo.cropDuration, KdenliveSettings::frametimecode());
new RazorClipCommand(this, clipInfo, info.startPos, false, command);
new ResizeClipCommand(this, dupInfo, newdupInfo, false, false, command);
ClipItem *dup = cutClip(clipInfo, info.startPos, true, false);
- if (dup) dup->resizeStart(info.endPos.frames(m_document->fps()));
+ if (dup) {
+ dup->resizeStart(info.endPos.frames(m_document->fps()));
+ }
} else {
ItemInfo newclipInfo = clip->info();
newclipInfo.endPos = info.startPos;
ItemInfo clipinfo = item->info();
clipinfo.track = m_document->tracksCount() - clipinfo.track;
bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - clipinfo.startPos);
- if (success)
+ if (success) {
item->resizeStart((int) end.startPos.frames(m_document->fps()));
+ }
else
emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
} else {
#include <KIO/NetAccess>
#include <KStandardDirs>
+#include <KApplication>
#include <KDebug>
#include <QCryptographicHash>
#include <QtConcurrentRun>
#include <cstdio>
+#include <kmessagebox.h>
DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) :
QObject(),
return m_thumbProd->extractImage(frame, width, height);
}
-void DocClipBase::setAnalysisData(const QString &name, const QString &data)
+void DocClipBase::setAnalysisData(const QString &name, const QString &data, int offset)
{
if (data.isEmpty()) m_analysisdata.remove(name);
else {
if (m_analysisdata.contains(name)) {
- int i = 1;
- QString newname = name + " " + QString::number(i);
- while (m_analysisdata.contains(newname)) {
- i++;
- newname = name + " " + QString::number(i);
+ if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("Clip already contains analysis data %1", name), QString(), KGuiItem(i18n("Merge")), KGuiItem(i18n("Add"))) == KMessageBox::Yes) {
+ // Merge data
+ Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile();
+ Mlt::Geometry geometry(m_analysisdata.value(name).toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::Geometry newGeometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::GeometryItem item;
+ int pos = 0;
+ while (!newGeometry.next_key(&item, pos)) {
+ pos = item.frame();
+ item.frame(pos + offset);
+ pos++;
+ geometry.insert(item);
+ }
+ m_analysisdata.insert(name, geometry.serialise());
+ }
+ else {
+ // Add data with another name
+ int i = 1;
+ QString newname = name + " " + QString::number(i);
+ while (m_analysisdata.contains(newname)) {
+ i++;
+ newname = name + " " + QString::number(i);
+ }
+ m_analysisdata.insert(newname, geometryWithOffset(data, offset));
}
- m_analysisdata.insert(newname, data);
}
- else m_analysisdata.insert(name, data);
+ else m_analysisdata.insert(name, geometryWithOffset(data, offset));
+ }
+}
+
+const QString DocClipBase::geometryWithOffset(QString data, int offset)
+{
+ if (offset == 0) return data;
+ Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile();
+ Mlt::Geometry geometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::Geometry newgeometry("", m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::GeometryItem item;
+ int pos = 0;
+ while (!geometry.next_key(&item, pos)) {
+ pos = item.frame();
+ item.frame(pos + offset);
+ pos++;
+ newgeometry.insert(item);
}
+ return newgeometry.serialise();
}
QMap <QString, QString> DocClipBase::analysisData() const
void cleanupProducers();
bool isClean() const;
bool getAudioThumbs();
- void setAnalysisData(const QString &name, const QString &data);
+ void setAnalysisData(const QString &name, const QString &data, int offset = 0);
QMap <QString, QString> analysisData() const;
int lastSeekPosition;
/** Cache for every audio Frame with 10 Bytes */
void adjustProducerProperties(Mlt::Producer *prod, const QString &id, bool mute, bool blind);
/** @brief Create another instance of a producer. */
Mlt::Producer *cloneProducer(Mlt::Producer *source);
+ /** @brief Offset all keyframes of a geometry. */
+ const QString geometryWithOffset(QString data, int offset);
public slots:
return m_paramWidget->needsMonitorEffectScene();
}
-
+void CollapsibleEffect::setRange(int inPoint , int outPoint)
+{
+ m_paramWidget->setRange(inPoint, outPoint);
+}
void adjustButtons(int ix, int max);
/** @brief Returns true of this effect requires an on monitor adjustable effect scene. */
bool needsMonitorEffectScene() const;
+ /** @brief Set clip in / out points. */
+ void setRange(int inPoint , int outPoint);
public slots:
void slotSyncEffectsPos(int pos);
m_effects.at(i)->slotSyncEffectsPos(pos);
}
+void EffectStackView2::slotClipItemUpdate()
+{
+ int inPoint = m_clipref->cropStart().frames(KdenliveSettings::project_fps());
+ int outPoint = m_clipref->cropDuration().frames(KdenliveSettings::project_fps()) - inPoint;
+ CollapsibleEffect *effectToMove = NULL;
+ for (int i = 0; i < m_effects.count(); i++) {
+ m_effects.at(i)->setRange(inPoint, outPoint);
+ }
+}
+
void EffectStackView2::slotClipItemSelected(ClipItem* c)
{
if (c && !c->isEnabled()) return;
if (c && c == m_clipref) {
} else {
+ if (m_clipref) disconnect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate()));
m_clipref = c;
if (c) {
+ connect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate()));
QString cname = m_clipref->clipName();
if (cname.length() > 30) {
m_ui.checkAll->setToolTip(i18n("Effects for %1", cname));
* @param c Clip whose effect list should be managed */
void slotClipItemSelected(ClipItem* c);
+ /** @brief Update the clip range (in-out points)
+ * @param c Clip whose effect list should be managed */
+ void slotClipItemUpdate();
+
void slotTrackItemSelected(int ix, const TrackInfo info);
/** @brief Check if the mouse wheel events should be used for scrolling the widget view. */
m_geometryWidget = new GeometryWidget(m_metaInfo->monitor, m_metaInfo->timecode, 0, true, effect.hasAttribute("showrotation"), parent);
m_geometryWidget->setFrameSize(m_metaInfo->frameSize);
connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
- if (minFrame == maxFrame)
+ if (minFrame == maxFrame) {
m_geometryWidget->setupParam(pa, m_in, m_out);
+ connect(this, SIGNAL(updateRange(int,int)), m_geometryWidget, SLOT(slotUpdateRange(int,int)));
+ }
else
m_geometryWidget->setupParam(pa, minFrame, maxFrame);
m_vbox->addWidget(m_geometryWidget);
connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int)));
} else {
Geometryval *geo = new Geometryval(m_metaInfo->profile, m_metaInfo->timecode, m_metaInfo->frameSize, 0);
- if (minFrame == maxFrame)
+ if (minFrame == maxFrame) {
geo->setupParam(pa, m_in, m_out);
+ connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int)));
+ }
else
geo->setupParam(pa, minFrame, maxFrame);
m_vbox->addWidget(geo);
if (pa.attribute("widget") == "corners") {
// we want a corners-keyframe-widget
CornersWidget *corners = new CornersWidget(m_metaInfo->monitor, pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt(), parent);
+ connect(this, SIGNAL(updateRange(int,int)), corners, SLOT(slotUpdateRange(int,int)));
m_needsMonitorEffectScene = true;
connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int)));
geo = static_cast<KeyframeEdit *>(corners);
} else {
geo = new KeyframeEdit(pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt());
+ connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int)));
}
m_vbox->addWidget(geo);
m_valueItems[paramName+"keyframe"] = geo;
pos = m_out - pos;
}
PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_metaInfo->timecode);
+ connect(this, SIGNAL(updateRange(int,int)), posedit, SLOT(setRange(int,int)));
m_vbox->addWidget(posedit);
m_valueItems[paramName+"position"] = posedit;
connect(posedit, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters()));
QDomElement pa = namenode.item(i).toElement();
QString type = pa.attribute("type");
if (type == "filterjob") {
+ kDebug()<<"// FILTER POSE: "<<m_geometryWidget->currentPosition();
QString filterparams = pa.attribute("filterparams");
+ if (filterparams.contains("%position")) {
+ if (m_geometryWidget) filterparams.replace("%position", QString::number(m_geometryWidget->currentPosition()));
+ }
if (filterparams.contains("%params")) {
// Replace with current geometry
EffectsParameterList parameters;
QDomElement e = jobparams.item(j).toElement();
extraParams.insert(e.attribute("name"), e.text().toUtf8());
}
+ kDebug()<<"+++++++++++++++++ CLIP IN: "<<m_in;
+ extraParams.insert("offset", QString::number(m_in));
emit startFilterJob(pa.attribute("filtertag"), filterparams, pa.attribute("consumer"), pa.attribute("consumerparams"), extraParams);
kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< filterparams<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("extraparams");
break;
}
+void ParameterContainer::setRange(int inPoint, int outPoint)
+{
+ m_in = inPoint;
+ m_out = outPoint;
+ emit updateRange(m_in, m_out);
+}
+
+
bool needsMonitorEffectScene() const;
/** @brief Set keyframes for this param. */
void setKeyframes(const QString &data, int maximum);
+ /** @brief Update the in / out for the clip. */
+ void setRange(int inPoint, int outPoint);
private slots:
void slotCollectAllParameters();
void startFilterJob(QString filterName, QString filterParams, QString consumer, QString consumerParams, const QMap <QString, QString>extra);
/** @brief Request import of keyframes from clip data. */
void importClipKeyframes();
+ /** @brief Master clip was resized, update effect. */
+ void updateRange(int inPoint, int outPoint);
};
#endif
}
-
+void Geometryval::slotUpdateRange(int inPoint, int outPoint)
+{
+ m_helper->setKeyGeometry(m_geom, outPoint - inPoint - 1);
+ m_helper->update();
+ m_timePos.setRange(0, outPoint - inPoint - 1);
+}
void setFrameSize(QPoint p);
/** @brief Updates the timecode display according to settings (frame number or hh:mm:ss:ff) */
void updateTimecodeFormat();
+ void slotUpdateRange(int inPoint, int outPoint);
private:
MltVideoProfile m_profile;
} else {
m_ui.widgetTimeWrapper->setHidden(false);
m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint);
- m_timePos->setRange(0, m_outPoint - m_inPoint);
}
+ m_timePos->setRange(0, m_outPoint - m_inPoint);
// no opacity
if (elem.attribute("opacity") == "false") {
}
}
+int GeometryWidget::currentPosition() const
+{
+ return m_inPoint + m_timePos->getValue();
+}
+
void GeometryWidget::slotRequestSeek(int pos)
{
if (KdenliveSettings::transitionfollowcursor())
emit parameterChanged();
}
+void GeometryWidget::slotUpdateRange(int inPoint, int outPoint)
+{
+ m_inPoint = inPoint;
+ m_outPoint = outPoint;
+ m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint);
+ m_timePos->setRange(0, m_outPoint - m_inPoint);
+}
#include "geometrywidget.moc"
void setFrameSize(QPoint size);
void addParameter(const QDomElement elem);
void importKeyframes(const QString &data, int maximum);
+ int currentPosition() const;
public slots:
/** @brief Sets up the rect and the geometry object.
/** @brief Updates position of the local timeline to @param relTimelinePos. */
void slotSyncPosition(int relTimelinePos);
void slotResetKeyframes();
+ void slotUpdateRange(int inPoint, int outPoint);
private:
Ui::GeometryWidget_UI m_ui;
slotUpdateVisibleParameter(0);
}
+void KeyframeEdit::slotUpdateRange(int inPoint, int outPoint)
+{
+ m_min = inPoint;
+ m_max = outPoint;
+}
+
#include "keyframeedit.moc"
/** @brief Makes the first parameter visible in timeline if no parameter is selected. */
void checkVisibleParam();
+public slots:
+
+ void slotUpdateRange(int inPoint, int outPoint);
+
protected:
/** @brief Gets the position of a keyframe from the table.
* @param row Row of the keyframe in the table */
int getPosition() const;
void setPosition(int pos);
void updateTimecodeFormat();
- void setRange(int min, int max);
+public slots:
+ void setRange(int min, int max);
+
private:
TimecodeDisplay *m_display;
QSlider *m_slider;
}
if (!dataProcessed || filterInfo.contains("storedata")) {
// Store returned data as clip extra data
- clip->referencedClip()->setAnalysisData(filterInfo.contains("displaydataname") ? filterInfo.value("displaydataname") : key, results.value(key));
+ clip->referencedClip()->setAnalysisData(filterInfo.contains("displaydataname") ? filterInfo.value("displaydataname") : key, results.value(key), filterInfo.value("offset").toInt());
emit updateAnalysisData(clip->referencedClip());
}
}