<description>Adjust audio volume with keyframes</description>
<author>Dan Dennedy</author>
<properties id="volume" tag="volume" type="audio" />
- <parameter type="double" name="gain" starttag="gain" max="300" min="0" default="100" factor="100">
+ <parameter type="keyframe" name="gain" starttag="gain" max="300" min="0" default="100" factor="100">
<name>Gain</name>
</parameter>
</effect>
void AbstractClipItem::drawKeyFrames(QPainter *painter, QRectF exposedRect) {
QRectF br = rect();
- double maxw = br.width() / 100.0;
+ double maxw = br.width() / m_cropDuration.frames(m_fps);
double maxh = br.height() / 100.0;
if (m_keyframes.count() > 1) {
- QMap<int, int>::const_iterator i = m_keyframes.constBegin();
+ QMap<int, double>::const_iterator i = m_keyframes.constBegin();
double x1;
double y1;
double x2;
double y2;
QColor color(Qt::blue);
- x1 = br.x() + maxw * i.key();
+ x1 = br.x() + maxw * (i.key() - m_cropStart.frames(m_fps));
y1 = br.bottom() - i.value() * maxh;
while (i != m_keyframes.constEnd()) {
if (i.key() == m_selectedKeyframe) color = QColor(Qt::red);
else color = QColor(Qt::blue);
++i;
if (i == m_keyframes.constEnd()) break;
- x2 = br.x() + maxw * i.key();
+ x2 = br.x() + maxw * (i.key() - m_cropStart.frames(m_fps));
y2 = br.bottom() - i.value() * maxh;
QLineF l(x1, y1, x2, y2);
painter->drawLine(l);
int AbstractClipItem::mouseOverKeyFrames(QPointF pos) {
QRectF br = rect();
- double maxw = br.width() / 100.0;
+ double maxw = br.width() / m_cropDuration.frames(m_fps);
double maxh = br.height() / 100.0;
if (m_keyframes.count() > 1) {
- QMap<int, int>::const_iterator i = m_keyframes.constBegin();
+ QMap<int, double>::const_iterator i = m_keyframes.constBegin();
double x1;
double y1;
while (i != m_keyframes.constEnd()) {
- x1 = br.x() + maxw * i.key();
+ x1 = br.x() + maxw * (i.key() - m_cropStart.frames(m_fps));
y1 = br.bottom() - i.value() * maxh;
if (qAbs(pos.x() - x1) < 6 && qAbs(pos.y() - y1) < 6) {
setToolTip("[" + QString::number(i.key()) + "x" + QString::number(i.value()) + "]");
void AbstractClipItem::updateSelectedKeyFrame() {
if (m_editedKeyframe == -1) return;
QRectF br = rect();
- double maxw = br.width() / 100.0;
+ double maxw = br.width() / m_cropDuration.frames(m_fps);
double maxh = br.height() / 100.0;
- update(br.x() + maxw * m_selectedKeyframe - 3, br.bottom() - m_keyframes[m_selectedKeyframe] * maxh - 3, 12, 12);
+ update(br.x() + maxw * (m_selectedKeyframe - m_cropStart.frames(m_fps)) - 3, br.bottom() - m_keyframes[m_selectedKeyframe] * maxh - 3, 12, 12);
m_selectedKeyframe = m_editedKeyframe;
- update(br.x() + maxw * m_selectedKeyframe - 3, br.bottom() - m_keyframes[m_selectedKeyframe] * maxh - 3, 12, 12);
+ update(br.x() + maxw * (m_selectedKeyframe - m_cropStart.frames(m_fps)) - 3, br.bottom() - m_keyframes[m_selectedKeyframe] * maxh - 3, 12, 12);
}
-void AbstractClipItem::updateKeyFramePos(const QPoint pos) {
+void AbstractClipItem::updateKeyFramePos(const GenTime pos, const int value) {
if (m_selectedKeyframe == -1) return;
QRectF br = rect();
- double maxw = br.width() / 100.0;
double maxh = br.height() / 100.0;
- int newval = (int)((br.bottom() - pos.y()) / maxh);
- int newpos = (int)((pos.x() - br.x()) / maxw);
- if (newval < -50 && m_selectedKeyframe != 0 && m_selectedKeyframe != 100) {
+ double newval = (br.bottom() - value) / maxh;
+ int newpos = (int) pos.frames(m_fps);
+ if (newval < -50 && m_selectedKeyframe != m_cropStart.frames(m_fps) && m_selectedKeyframe != (m_cropStart + m_cropDuration).frames(m_fps)) {
// remove kexframe if it is dragged outside
m_keyframes.remove(m_selectedKeyframe);
m_selectedKeyframe = -1;
update();
return;
}
- if (newval > 150 && m_selectedKeyframe != 0 && m_selectedKeyframe != 100) {
+ if (newval > 150 && m_selectedKeyframe != m_cropStart.frames(m_fps) && m_selectedKeyframe != (m_cropStart + m_cropDuration).frames(m_fps)) {
// remove kexframe if it is dragged outside
m_keyframes.remove(m_selectedKeyframe);
m_selectedKeyframe = -1;
}
if (newval < 0) newval = 0;
else if (newval > 100) newval = 100;
- if (m_selectedKeyframe == 0 || m_selectedKeyframe == 100) {
+ if (m_selectedKeyframe == m_cropStart.frames(m_fps) || m_selectedKeyframe == (m_cropStart + m_cropDuration).frames(m_fps)) {
// start and end keyframes should stay in place
m_keyframes[m_selectedKeyframe] = newval;
} else {
update();
}
-void AbstractClipItem::addKeyFrame(const QPoint pos) {
+void AbstractClipItem::addKeyFrame(const GenTime pos, const int value) {
QRectF br = rect();
- double maxw = br.width() / 100.0;
double maxh = br.height() / 100.0;
- int newval = (int)((br.bottom() - pos.y()) / maxh);
- int newpos = (int)((pos.x() - br.x()) / maxw);
+ double newval = (br.bottom() - value) / maxh;
+ int newpos = (int) pos.frames(m_fps) ;
m_keyframes[newpos] = newval;
m_selectedKeyframe = newpos;
update();
}
-bool AbstractClipItem::hasKeyFrames() {
+bool AbstractClipItem::hasKeyFrames() const {
return !m_keyframes.isEmpty();
}
public:
AbstractClipItem(const ItemInfo info, const QRectF& rect, double fps);
void updateSelectedKeyFrame();
- void updateKeyFramePos(const QPoint pos);
- void addKeyFrame(const QPoint pos);
- bool hasKeyFrames();
+ void updateKeyFramePos(const GenTime pos, const int value);
+ void addKeyFrame(const GenTime pos, const int value);
+ bool hasKeyFrames() const;
virtual OPERATIONTYPE operationMode(QPointF pos, double scale) = 0;
virtual GenTime startPos() const ;
virtual int track() const ;
virtual void moveTo(int x, double scale, int offset, int newTrack);
virtual GenTime cropStart() const ;
- virtual void resizeStart(int posx, double scale);
+ virtual void resizeStart(int posx, double scale);
virtual void resizeEnd(int posx, double scale);
virtual GenTime duration() const;
virtual double fps() const;
GenTime m_cropDuration;
GenTime m_startPos;
GenTime m_maxDuration;
- QMap <int, int> m_keyframes;
+ QMap <int, double> m_keyframes;
double m_fps;
QPainterPath upperRectPart(QRectF);
QPainterPath lowerRectPart(QRectF);
return m_selectedEffect;
}
+
void ClipItem::setSelectedEffect(int ix) {
//if (ix == m_selectedEffect) return;
m_selectedEffect = ix;
// Effect has a keyframe type parameter, we need to set the values
if (e.attribute("keyframes").isEmpty()) {
// no keyframes defined, set up 2 keyframes (start and end) with default value.
- m_keyframes[0] = 100 * def / (max - min);
- m_keyframes[100] = 100 * def / (max - min);
+ m_keyframes[m_cropStart.frames(m_fps)] = 100 * def / (max - min);
+ m_keyframes[(m_cropStart + m_cropDuration).frames(m_fps)] = 100 * def / (max - min);
} else {
// parse keyframes
- QStringList keyframes = e.attribute("keyframes").split(";");
+ QStringList keyframes = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
foreach(QString str, keyframes) {
- if (!str.isEmpty()) {
- int pos = str.section(":", 0, 0).toInt();
- int val = str.section(":", 1, 1).toInt();
- /*int frame = (int) (pos * 100 / m_cropDuration.frames(m_fps));
- int value = (int) (((val * factor) - min) * 100 * factor / (max - min));*/
- m_keyframes[pos] = val;
- }
+ int pos = str.section(":", 0, 0).toInt();
+ double val = str.section(":", 1, 1).toDouble();
+ m_keyframes[pos] = val;
}
}
update();
QString keyframes;
if (m_keyframes.count() > 1) {
- QMap<int, int>::const_iterator i = m_keyframes.constBegin();
+ QMap<int, double>::const_iterator i = m_keyframes.constBegin();
double x1;
double y1;
while (i != m_keyframes.constEnd()) {
effectParams["max"] = e.attribute("max");
effectParams["min"] = e.attribute("min");
effectParams["factor"] = e.attribute("factor");
- effectParams["starttag"] = e.attribute("starttag");
- effectParams["endtag"] = e.attribute("endtag");
+ effectParams["starttag"] = e.attribute("starttag", "start");
+ effectParams["endtag"] = e.attribute("endtag", "end");
} else if (e.attribute("namedesc").contains(";")) {
QString format = e.attribute("format");
QStringList separators = format.split("%d", QString::SkipEmptyParts);
int pos = (int)(mapToScene(event->pos()).x() / m_scale);
((ClipItem*) m_dragItem)->setFadeOut((int)(m_dragItem->endPos().frames(m_document->fps()) - pos), m_scale);
} else if (m_operationMode == KEYFRAME) {
- m_dragItem->updateKeyFramePos(event->pos());
+ GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x() / m_scale), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
+ m_dragItem->updateKeyFramePos(keyFramePos, mapToScene(event->pos()).toPoint().y());
}
if (m_animation) delete m_animation;
void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) {
if (m_dragItem && m_dragItem->hasKeyFrames()) {
- m_dragItem->addKeyFrame(event->pos());
+ GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x() / m_scale), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
+ m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
ClipItem * item = (ClipItem *) m_dragItem;
item->updateKeyframeEffect();
updateEffect(m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect());
Mlt::Producer producer(*m_profile, "westley-xml", tmp);
delete[] tmp;
- int twidth = (int)(KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio());
+ int twidth = (int)(KdenliveSettings::trackheight() * m_profile->dar());
if (producer.is_blank()) {
QPixmap pix(twidth, KdenliveSettings::trackheight());
pix.fill(Qt::black);
return;
}
if (frame != -1) {
- QPixmap pix = getFrame(&producer, frame, twidth, KdenliveSettings::trackheight());
+ QPixmap pix = getFrame(producer, frame, twidth, KdenliveSettings::trackheight());
emit thumbReady(frame, pix);
}
if (frame2 != -1) {
- QPixmap pix = getFrame(&producer, frame2, twidth , KdenliveSettings::trackheight());
+ QPixmap pix = getFrame(producer, frame2, twidth , KdenliveSettings::trackheight());
emit thumbReady(frame2, pix);
}
-
}
//static
pix.fill(Qt::black);
return pix;
}
- return getFrame(&producer, frame, width, height);
+ return getFrame(producer, frame, width, height);
}
//static
pix.fill(Qt::black);
return pix;
}
- return getFrame(&producer, frame, width, height);
+ return getFrame(producer, frame, width, height);
}
//static
-QPixmap KThumb::getFrame(Mlt::Producer* producer, int framepos, int width, int height) {
+QPixmap KThumb::getFrame(Mlt::Producer producer, int framepos, int width, int height) {
if (framepos > 0)
- producer->seek(framepos);
- Mlt::Frame *frame = producer->get_frame();
+ producer.seek(framepos);
+ Mlt::Frame *frame = producer.get_frame();
mlt_image_format format = mlt_image_yuv422;
- uint8_t* data;
int frame_width = 0;
int frame_height = 0;
- //frame->set("rescale.interp", "nearest");
- frame->set("normalised_height", height);
- frame->set("normalised_width", width);
- mlt_frame_get_image(frame->get_frame(), &data, &format, &frame_width, &frame_height, 0);
+ frame->set("normalised_height", height);
+ frame->set("normalised_width", width);
QPixmap pix(width, height);
+
+ uint8_t *data = frame->get_image(format, frame_width, frame_height, 0);
uint8_t *new_image = (uint8_t *)mlt_pool_alloc(frame_width * (frame_height + 1) * 4);
mlt_convert_yuv422_to_rgb24a((uint8_t *)data, new_image, frame_width * frame_height);
QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
if (!image.isNull()) {
- //QImage scale = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation).rgbSwapped();
- image = image.rgbSwapped();
- pix = pix.fromImage(image);
- } else pix.fill(Qt::black);
- mlt_pool_release(new_image);
- if (frame) delete frame;
+ pix = pix.fromImage(image.rgbSwapped());
+ } else
+ pix.fill(Qt::black);
+
+ mlt_pool_release(new_image);
+ delete frame;
+
return pix;
}
/*
void removeAudioThumb();
void getAudioThumbs(int channel, double frame, double frameLength, int arrayWidth);
static QPixmap getImage(KUrl url, int frame, int width, int height);
- static QPixmap getFrame(Mlt::Producer* producer, int framepos, int width, int height);
+ static QPixmap getFrame(Mlt::Producer producer, int framepos, int width, int height);
protected:
virtual void customEvent(QEvent * event);
void ProjectList::slotRefreshClipThumbnail(ProjectItem *item) {
if (item) {
- int height = 50;
- int width = (int)(height * m_render->dar());
+ int height = 50;
+ int width = (int)(height * m_render->dar());
QPixmap pix = KThumb::getImage(item->toXml(), item->referencedClip()->getProjectThumbFrame(), width, height);
//QPixmap pix = KThumb::getFrame(item->toXml()), 0, width, height);
item->setIcon(0, pix);
}
const double Render::dar() const {
- return m_mltProfile->dar();
+ return m_mltProfile->dar();
}
void Render::getFileProperties(const QDomElement &xml, int clipId) {
Mlt::Producer producer(*m_mltProfile, "westley-xml", tmp);
delete[] tmp;
-/* Mlt::Filter filter(*m_mltProfile, "rescale");
- producer.attach(filter);*/
- //mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_fezzik", 1 );
-
if (producer.is_blank()) {
return;
}
filePropertyMap["type"] = "video";
mlt_image_format format = mlt_image_yuv422;
- uint8_t* data;
int frame_width = 0;
int frame_height = 0;
- //frame->set("rescale.interp", "hyper");
- frame->set("normalised_height", height);
- frame->set("normalised_width", width);
- mlt_frame_get_image(frame->get_frame(), &data, &format, &frame_width, &frame_height, 0);
- //kDebug()<<"/// GOT TUMB, SIZE: "<<frame_width<<"x"<<frame_height;
+ //frame->set("rescale.interp", "hyper");
+ frame->set("normalised_height", height);
+ frame->set("normalised_width", width);
QPixmap pix(width, height);
+
+ uint8_t *data = frame->get_image(format, frame_width, frame_height, 0);
uint8_t *new_image = (uint8_t *)mlt_pool_alloc(frame_width * (frame_height + 1) * 4);
mlt_convert_yuv422_to_rgb24a((uint8_t *)data, new_image, frame_width * frame_height);
QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
if (!image.isNull()) {
- image = image.rgbSwapped();// = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation).rgbSwapped();
- pix = pix.fromImage(image);
- } else pix.fill(Qt::black);
- mlt_pool_release(new_image);
+ pix = pix.fromImage(image.rgbSwapped());
+ } else
+ pix.fill(Qt::black);
+
+ mlt_pool_release(new_image);
emit replyGetImage(clipId, 0, pix, width, height);
} else if (frame->get_int("test_audio") == 0) {
char *filterId = decodedString(args.value("id"));
QMap<QString, QString>::Iterator it;
QString kfr = args.value("keyframes");
-
+
if (!kfr.isEmpty()) {
- QStringList keyFrames = kfr.split(";");
+ QStringList keyFrames = kfr.split(";", QString::SkipEmptyParts);
kDebug() << "// ADDING KEYFRAME EFFECT: " << args.value("keyframes");
char *starttag = decodedString(args.value("starttag"));
char *endtag = decodedString(args.value("endtag", "end"));
+ kDebug() << "// ADDING KEYFRAME TAGS: " << starttag << ", " << endtag;
int duration = clip->get_playtime();
int max = args.value("max").toInt();
int min = args.value("min").toInt();
- int factor = args.value("factor").toInt();
+ int factor = args.value("factor", "1").toInt();
args.remove("starttag");
args.remove("endtag");
args.remove("keyframes");
Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
filter->set("kdenlive_id", filterId);
int x1 = keyFrames.at(i).section(":", 0, 0).toInt();
- int y1 = keyFrames.at(i).section(":", 1, 1).toInt();
+ double y1 = keyFrames.at(i).section(":", 1, 1).toDouble();
int x2 = keyFrames.at(i + 1).section(":", 0, 0).toInt();
- int y2 = keyFrames.at(i + 1).section(":", 1, 1).toInt();
-
+ double y2 = keyFrames.at(i + 1).section(":", 1, 1).toDouble();
+ if (x2 == -1) x2 = duration;
for (it = args.begin(); it != args.end(); ++it) {
char *name = decodedString(it.key());
char *value = decodedString(it.value());
delete[] value;
}
- filter->set("in", duration / 100 * x1);
- filter->set("out", duration / 100 * x2);
- filter->set(starttag, (min + y1 * 100 / (max - min)) / factor);
- filter->set(endtag, (min + y2 * 100 / (max - min)) / factor);
- kDebug() << "// SETTING FILT VALS: " << duration / 100 * x1 << " to " << duration / 100 * x2 << ", STAT:" << (min + y1 * 100 / (max - min)) / factor << "end: " << (min + y2 * 100 / (max - min)) / factor;
+ filter->set("in", x1);
+ filter->set("out", x2);
+ //kDebug() << "// ADDING KEYFRAME vals: " << min<<" / "<<max<<", "<<y1<<", factor: "<<factor;
+ filter->set(starttag, QString::number((min + y1 * (max - min) / 100.0) / factor).toUtf8().data());
+ filter->set(endtag, QString::number((min + y2 * (max - min) / 100.0) / factor).toUtf8().data());
clipService.attach(*filter);
}
const double fps() const;
const int renderWidth() const;
const int renderHeight() const;
- /** get display aspect ratio */
+ /** get display aspect ratio */
const double dar() const;
/** Playlist manipulation */