//m_hover(false),
m_speed(speed),
m_strobe(strobe),
- m_framePixelWidth(0)
+ m_framePixelWidth(0),
+ m_limitedKeyFrames(false)
{
setZValue(2);
setRect(0, 0, (info.endPos - info.startPos).frames(fps) - 0.02, (double) itemHeight());
m_endThumbTimer.setSingleShot(true);
connect(&m_endThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetEndThumb()));
- connect(this, SIGNAL(getThumb(int, int)), m_clip->thumbProducer(), SLOT(extractImage(int, int)));
+ connect(this, SIGNAL(getThumb(int, int)), m_clip, SLOT(slotExtractImage(int, int)));
connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
connect(m_clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
} else if (m_clipType == IMAGE || m_clipType == TEXT) {
m_baseColor = QColor(141, 166, 215);
if (m_clipType == TEXT) {
- connect(this, SIGNAL(getThumb(int, int)), m_clip->thumbProducer(), SLOT(extractImage(int, int)));
+ connect(this, SIGNAL(getThumb(int, int)), m_clip, SLOT(slotExtractImage(int, int)));
connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
}
//m_startPix = KThumb::getImage(KUrl(clip->getProperty("resource")), (int)(KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio()), KdenliveSettings::trackheight());
continue;
// Check if this effect has a variable parameter
- if (e.attribute("default").startsWith('%')) {
+ if (e.attribute("default").contains('%')) {
double evaluatedValue = ProfilesDialog::getStringEval(projectScene()->profile(), e.attribute("default"));
e.setAttribute("default", evaluatedValue);
if (e.hasAttribute("value") && e.attribute("value").startsWith('%')) {
QDomElement e = params.item(i).toElement();
if (!e.isNull() && (e.attribute("type") == "keyframe" || e.attribute("type") == "simplekeyframe") && e.attribute("intimeline") == "1") {
m_keyframes.clear();
+ m_limitedKeyFrames = e.attribute("type") == "keyframe";
m_visibleParam = i;
double max = e.attribute("max").toDouble();
double min = e.attribute("min").toDouble();
m_endPix = QPixmap();
m_audioThumbCachePic.clear();
}
+ kDebug()<<"........... RESET THMBS";
slotFetchThumbs();
}
QLineF l2(mapped.left() + m_startPix.width(), mapped.top(), mapped.left() + m_startPix.width(), mapped.bottom());
painter->drawLine(l2);
}
- if (painter->matrix().m11() == FRAME_SIZE) {
+ if (painter->matrix().m11() == FRAME_SIZE && m_clip->thumbProducer() && clipType() != COLOR && clipType() != AUDIO && !m_audioOnly) {
int offset = (m_info.startPos - m_info.cropStart).frames(m_fps);
- int left = qMax((int) m_info.startPos.frames(m_fps) + 1, (int) mapToScene(exposed.left(), 0).x());
- int right = qMin((int)(m_info.startPos + m_info.cropDuration).frames(m_fps) - 1, (int) mapToScene(exposed.right(), 0).x());
- doGetIntraThumbs(painter, mapped.topLeft(), m_info.cropStart.frames(m_fps), left - offset, right - offset);
+ int left = qMax((int) m_info.startPos.frames(m_fps) + 1, (int) mapToScene(exposed.left(), 0).x()) - offset;
+ int right = qMin((int)(m_info.startPos + m_info.cropDuration).frames(m_fps) - 1, (int) mapToScene(exposed.right(), 0).x()) - offset;
+ QPointF startPos = mapped.topLeft();
+ int twidth = FRAME_SIZE;
+ int startOffset = m_info.cropStart.frames(m_fps);
+ if (clipType() == IMAGE || clipType() == TEXT) {
+ for (int i = left; i <= right; i++) {
+ painter->drawPixmap(startPos + QPointF(twidth *(i - startOffset), 0), m_startPix);
+ }
+ }
+ else {
+#if KDE_IS_VERSION(4,5,0)
+ if (m_clip && m_clip->thumbProducer()) {
+ m_clip->thumbProducer()->queryIntraThumbs(left, right);
+ connect(m_clip->thumbProducer(), SIGNAL(thumbsCached()), this, SLOT(slotGotThumbsCache()));
+ QString path = m_clip->fileURL().path() + "_";
+ for (int i = left; i <= right; i++) {
+ painter->drawImage(startPos + QPointF(twidth *(i - startOffset), 0), m_clip->thumbProducer()->findCachedThumb(path + QString::number(i)));
+ }
+ }
+#endif
+ }
}
painter->setPen(Qt::black);
}
painter->setPen(QPen(Qt::lightGray));
// draw effect or transition keyframes
- if (mapped.width() > 20) drawKeyFrames(painter, exposed);
+ if (mapped.width() > 20) drawKeyFrames(painter, m_limitedKeyFrames);
//painter->setMatrixEnabled(true);
parameters.addParam("id", effectId);
// special case: the affine effect needs in / out points
- if (effectId == "pan_zoom") {
- parameters.addParam("in", QString::number(cropStart().frames(m_fps)));
- parameters.addParam("out", QString::number((cropStart() + cropDuration()).frames(m_fps)));
- }
QDomNodeList params = effect.elementsByTagName("parameter");
int fade = 0;
+ bool needInOutSync = false;
for (int i = 0; i < params.count(); i++) {
QDomElement e = params.item(i).toElement();
if (!e.isNull()) {
+ if (e.attribute("type") == "geometry" && !e.hasAttribute("fixed")) {
+ // Effects with a geometry parameter need to sync in / out with parent clip
+ needInOutSync = true;
+ }
if (e.attribute("type") == "simplekeyframe") {
QStringList values = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
double factor = e.attribute("factor", "1").toDouble();
}
} else {
double fact;
- if (e.attribute("factor").startsWith('%')) {
+ if (e.attribute("factor").contains('%')) {
fact = ProfilesDialog::getStringEval(projectScene()->profile(), e.attribute("factor"));
} else fact = e.attribute("factor", "1").toDouble();
parameters.addParam(e.attribute("name"), QString::number(e.attribute("value").toDouble() / fact));
}
}
}
+ if (needInOutSync) {
+ parameters.addParam("in", QString::number(cropStart().frames(m_fps)));
+ parameters.addParam("out", QString::number((cropStart() + cropDuration()).frames(m_fps) - 1));
+ parameters.addParam("_sync_in_out", "1");
+ }
m_effectNames = m_effectList.effectNames().join(" / ");
if (fade > 0) m_startFade = fade;
else if (fade < 0) m_endFade = -fade;
setSelectedEffect(m_selectedEffect);
return;
}
+ m_limitedKeyFrames = e.attribute("type") == "keyframe";
const QStringList keyframes = e.attribute("keyframes").split(';', QString::SkipEmptyParts);
foreach(const QString &str, keyframes) {
int pos = str.section(':', 0, 0).toInt();
if (!m_keyframes.contains(m_selectedKeyframe)) m_selectedKeyframe = -1;
}
-void ClipItem::doGetIntraThumbs(QPainter *painter, const QPointF startPos, int offset, int start, int end)
-{
- if (!m_clip->thumbProducer() || clipType() == COLOR) return;
- if (scene() && scene()->views().isEmpty()) return;
- CustomTrackView *view = (CustomTrackView *) scene()->views()[0];
- if (view == NULL) return;
- const int theight = KdenliveSettings::trackheight();
- const int twidth = FRAME_SIZE;
-
- if (clipType() == IMAGE || clipType() == TEXT) {
- for (int i = start; i <= end; i++)
- painter->drawPixmap(startPos + QPointF(twidth *(i - offset), 0), m_startPix);
- }
- QPixmap p;
- for (int i = start; i <= end; i++) {
-#if KDE_IS_VERSION(4,5,0)
- if (!view->m_pixmapCache->findPixmap(m_clip->fileURL().path() + "%" + QString::number(i), &p)) {
- p = m_clip->thumbProducer()->extractImage(i, twidth, theight);
- view->m_pixmapCache->insertPixmap(m_clip->fileURL().path() + "%" + QString::number(i), p);
- }
-#else
- if (!view->m_pixmapCache->find(m_clip->fileURL().path() + "%" + QString::number(i), p)) {
- p = m_clip->thumbProducer()->extractImage(i, twidth, theight);
- view->m_pixmapCache->insert(m_clip->fileURL().path() + "%" + QString::number(i), p);
- }
-#endif
- painter->drawPixmap(startPos + QPointF(twidth *(i - offset), 0), p);
- }
-}
-
-QList <int> ClipItem::updatePanZoom(int width, int height, int cut)
-{
- QList <int> effectPositions;
- for (int i = 0; i < m_effectList.count(); i++) {
- QDomElement effect = m_effectList.at(i);
- QDomNodeList params = effect.elementsByTagName("parameter");
- for (int j = 0; j < params.count(); j++) {
- QDomElement e = params.item(j).toElement();
- if (e.isNull())
- continue;
- if (e.attribute("type") == "geometry" && !e.hasAttribute("fixed")) {
- effectPositions << i;
-// updateGeometryKeyframes(effect, j, width, height, cut);
- }
- }
- }
-
- return effectPositions;
-}
-
Mlt::Producer *ClipItem::getProducer(int track, bool trackSpecific)
{
if (isAudioOnly())
QString id = effect.attribute("id");
int in = EffectsList::parameter(effect, "in").toInt();
int out = EffectsList::parameter(effect, "out").toInt();
- int clipEnd = (cropStart() + cropDuration()).frames(m_fps);
+ int clipEnd = (cropStart() + cropDuration()).frames(m_fps) - 1;
if (id == "fade_from_black" || id == "fadein") {
if (in != cropStart().frames(m_fps)) {
effects[i] = effect.cloneNode().toElement();
if (out != clipEnd) {
effects[i] = effect.cloneNode().toElement();
int diff = out - clipEnd;
- in -= diff;
+ in = qMax(in - diff, (int) cropStart().frames(m_fps));
out -= diff;
EffectsList::setParameter(effect, "in", QString::number(in));
EffectsList::setParameter(effect, "out", QString::number(out));
void ClipItem::updateGeometryKeyframes(QDomElement effect, int paramIndex, int width, int height, ItemInfo oldInfo)
{
- QDomElement param = effect.elementsByTagName("parameter").item(paramIndex).toElement();
-
- Mlt::Geometry geometry(param.attribute("value").toUtf8().data(), oldInfo.cropDuration.frames(m_fps), width, height);
+ QDomElement param = effect.elementsByTagName("parameter").item(paramIndex).toElement();
+ int offset = oldInfo.cropStart.frames(m_fps);
+ QString data = param.attribute("value");
+ if (offset > 0) {
+ QStringList kfrs = data.split(';');
+ data.clear();
+ foreach (QString keyframe, kfrs) {
+ if (keyframe.contains('=')) {
+ int pos = keyframe.section('=', 0, 0).toInt();
+ pos += offset;
+ data.append(QString::number(pos) + "=" + keyframe.section('=', 1) + ";");
+ }
+ else data.append(keyframe + ";");
+ }
+ }
+ Mlt::Geometry geometry(data.toUtf8().data(), oldInfo.cropDuration.frames(m_fps), width, height);
param.setAttribute("value", geometry.serialise(cropStart().frames(m_fps), (cropStart() + cropDuration()).frames(m_fps) - 1));
}
+void ClipItem::slotGotThumbsCache()
+{
+ disconnect(m_clip->thumbProducer(), SIGNAL(thumbsCached()), this, SLOT(slotGotThumbsCache()));
+ update();
+}
+
#include "clipitem.moc"