bool TransitionHandler::addTransition(QString tag, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml) { if (in >= out) return false; double fps = m_tractor->get_fps(); QMap<QString, QString> args = getTransitionParamsFromXml(xml); QScopedPointer<Mlt::Field> field(m_tractor->field()); Mlt::Transition transition(*m_tractor->profile(), tag.toUtf8().constData()); if (!transition.is_valid()) return false; if (out != GenTime()) transition.set_in_and_out((int) in.frames(fps), (int) out.frames(fps) - 1); QMap<QString, QString>::Iterator it; QString key; if (xml.attribute(QStringLiteral("automatic")) == QLatin1String("1")) transition.set("automatic", 1); ////qDebug() << " ------ ADDING TRANSITION PARAMs: " << args.count(); if (xml.hasAttribute(QStringLiteral("id"))) transition.set("kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData()); if (xml.hasAttribute(QStringLiteral("force_track"))) transition.set("force_track", xml.attribute(QStringLiteral("force_track")).toInt()); for (it = args.begin(); it != args.end(); ++it) { key = it.key(); if (!it.value().isEmpty()) transition.set(key.toUtf8().constData(), it.value().toUtf8().constData()); ////qDebug() << " ------ ADDING TRANS PARAM: " << key << ": " << it.value(); } // attach transition m_tractor->lock(); plantTransition(field.data(), transition, a_track, b_track); // field->plant_transition(*transition, a_track, b_track); m_tractor->unlock(); return true; }
bool TransitionHandler::moveTransition(QString type, int startTrack, int newTrack, int newTransitionTrack, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut) { double fps = m_tractor->get_fps(); int new_in = (int)newIn.frames(fps); int new_out = (int)newOut.frames(fps) - 1; if (new_in >= new_out) return false; int old_in = (int)oldIn.frames(fps); int old_out = (int)oldOut.frames(fps) - 1; bool doRefresh = true; // Check if clip is visible in monitor int position = mlt_producer_position(m_tractor->get_producer()); int diff = old_out - position; if (diff < 0 || diff > old_out - old_in) doRefresh = false; if (doRefresh) { diff = new_out - position; if (diff < 0 || diff > new_out - new_in) doRefresh = false; } QScopedPointer<Mlt::Field> field(m_tractor->field()); field->lock(); mlt_service nextservice = mlt_service_get_producer(field->get_service()); mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); QString resource = mlt_properties_get(properties, "mlt_service"); int old_pos = (int)(old_in + old_out) / 2; bool found = false; mlt_service_type mlt_type = mlt_service_identify( nextservice ); while (mlt_type == transition_type) { Mlt::Transition transition((mlt_transition) nextservice); nextservice = mlt_service_producer(nextservice); int currentTrack = transition.get_b_track(); int currentIn = (int) transition.get_in(); int currentOut = (int) transition.get_out(); if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) { found = true; if (newTrack - startTrack != 0) { Mlt::Properties trans_props(transition.get_properties()); Mlt::Transition new_transition(*m_tractor->profile(), transition.get("mlt_service")); Mlt::Properties new_trans_props(new_transition.get_properties()); // We cannot use MLT's property inherit because it also clones internal values like _unique_id which messes up the playlist cloneProperties(new_trans_props, trans_props); new_transition.set_in_and_out(new_in, new_out); field->disconnect_service(transition); plantTransition(field.data(), new_transition, newTransitionTrack, newTrack); } else transition.set_in_and_out(new_in, new_out); break; } if (nextservice == NULL) break; properties = MLT_SERVICE_PROPERTIES(nextservice); mlt_type = mlt_service_identify( nextservice ); resource = mlt_properties_get(properties, "mlt_service"); } field->unlock(); if (doRefresh) refresh(); //if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); return found; }
void TransitionHandler::updateTransition(QString oldTag, QString tag, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml, bool force) { if (oldTag == tag && !force) updateTransitionParams(tag, a_track, b_track, in, out, xml); else { ////qDebug()<<"// DELETING TRANS: "<<a_track<<"-"<<b_track; deleteTransition(oldTag, a_track, b_track, in, out, xml, false); addTransition(tag, a_track, b_track, in, out, xml, false); } int position = mlt_producer_position(m_tractor->get_producer()); if (position >= in.frames(m_fps) && position <= out.frames(m_fps)) emit refresh(); }
void AbstractClipItem::updateKeyFramePos(const GenTime &pos, const double value) { if (!m_keyframes.contains(m_editedKeyframe)) return; int newpos = (int) pos.frames(m_fps); int min = (int) cropStart().frames(m_fps) - 1; int max = (int)(cropStart() + cropDuration()).frames(m_fps); QMap<int, int>::const_iterator i = m_keyframes.constBegin(); while (i.key() < m_editedKeyframe) { min = qMax(i.key(), min); ++i; } i = m_keyframes.constEnd() - 1; while (i.key() > m_editedKeyframe) { max = qMin(i.key(), max); --i; } if (newpos <= min) newpos = min + 1; if (newpos >= max) newpos = max - 1; double newval = qMax(value, 0.0); newval = qMin(newval, 100.0); newval = newval / m_keyframeFactor + m_keyframeOffset; if (m_editedKeyframe != newpos) m_keyframes.remove(m_editedKeyframe); m_keyframes[newpos] = (int) newval; m_editedKeyframe = newpos; update(); }
const QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const { int hundredths = (int)(time.seconds() * 100); bool negative = false; if (hundredths < 0) { negative = true; hundredths = qAbs(hundredths); } int seconds = hundredths / 100; hundredths = hundredths % 100; int minutes = seconds / 60; seconds = seconds % 60; int hours = minutes / 60; minutes = minutes % 60; QString text; if (negative) text.append('-'); text.append(QString::number(hours).rightJustified(2, '0', false)); text.append(':'); text.append(QString::number(minutes).rightJustified(2, '0', false)); text.append(':'); text.append(QString::number(seconds).rightJustified(2, '0', false)); if (m_dropFrameTimecode) text.append(','); else text.append(':'); text.append(QString::number(hundredths).rightJustified(2, '0', false)); return text; }
const QString Timecode::getTimecodeHH_MM_SS_FF(const GenTime & time) const { if (m_dropFrameTimecode) { return getTimecodeDropFrame(time); } return getTimecodeHH_MM_SS_FF((int) time.frames(m_realFps)); }
int AbstractClipItem::addKeyFrame(const GenTime &pos, const double value) { QRectF br = sceneBoundingRect(); double maxh = 100.0 / br.height() / m_keyframeFactor; int newval = (br.bottom() - value) * maxh + m_keyframeOffset; //kDebug() << "Rect: " << br << "/ SCENE: " << sceneBoundingRect() << ", VALUE: " << value << ", MAX: " << maxh << ", NEWVAL: " << newval; int newpos = (int) pos.frames(m_fps) ; m_keyframes[newpos] = newval; m_selectedKeyframe = newpos; update(); return newval; }
//static QString Timecode::getEasyTimecode(const GenTime & time, const double &fps) { // Returns the timecode in an easily read display, like 3 min. 5 sec. int frames = (int) time.frames(fps); bool negative = false; if (frames < 0) { negative = true; frames = qAbs(frames); } int seconds = (int)(frames / fps); frames = frames - ((int)(fps * seconds)); int minutes = seconds / 60; seconds = seconds % 60; int hours = minutes / 60; minutes = minutes % 60; QString text; bool trim = false; if (negative) text.append('-'); if (hours != 0) { text.append(QString::number(hours).rightJustified(2, '0', false)); text.append(' ' + i18n("hour") + ' '); trim = true; } if (minutes != 0 || trim) { if (!trim) { text.append(QString::number(minutes)); } else text.append(QString::number(minutes).rightJustified(2, '0', false)); text.append(' ' + i18n("min.") + ' '); trim = true; } if (seconds != 0 || trim) { if (!trim) { text.append(QString::number(seconds)); } else text.append(QString::number(seconds).rightJustified(2, '0', false)); text.append(' ' + i18n("sec.")); trim = true; } if (!trim) { text.append(QString::number(frames)); text.append(' ' + i18n("frames")); } return text; }
void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/) { GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos; if (durationDiff == GenTime()) return; if (type() == AVWidget && hasSizeLimit && (cropStart() + durationDiff < GenTime())) { durationDiff = GenTime() - cropStart(); } else if (durationDiff >= cropDuration()) { return; } m_info.startPos += durationDiff; m_keyframeView.setOffset(durationDiff.frames(m_fps)); // set to true if crop from start is negative (possible for color clips, images as they have no size limit) bool negCropStart = false; if (type() == AVWidget) { m_info.cropStart += durationDiff; if (m_info.cropStart < GenTime()) negCropStart = true; } m_info.cropDuration -= durationDiff; setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); moveBy(durationDiff.frames(m_fps), 0); if (m_info.startPos != GenTime(posx, m_fps)) { GenTime diff = m_info.startPos - GenTime(posx, m_fps); if (type() == AVWidget) m_info.cropStart += diff; m_info.cropDuration -= diff; setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); } // set crop from start to 0 (isn't relevant as this only happens for color clips, images) if (negCropStart) m_info.cropStart = GenTime(); }
void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/) { GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos; if (durationDiff == GenTime()) return; if (type() == AVWIDGET && hasSizeLimit && (cropStart() + durationDiff < GenTime())) { durationDiff = GenTime() - cropStart(); } else if (durationDiff >= cropDuration()) { return; /*if (cropDuration() > GenTime(3, m_fps)) durationDiff = GenTime(3, m_fps); else return;*/ } m_info.startPos += durationDiff; // set to true if crop from start is negative (possible for color clips, images as they have no size limit) bool negCropStart = false; if (type() == AVWIDGET) { m_info.cropStart += durationDiff; if (m_info.cropStart < GenTime()) negCropStart = true; } m_info.cropDuration -= durationDiff; setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); moveBy(durationDiff.frames(m_fps), 0); if (m_info.startPos != GenTime(posx, m_fps)) { //kDebug() << "////// WARNING, DIFF IN XPOS: " << pos().x() << " == " << m_info.startPos.frames(m_fps); GenTime diff = m_info.startPos - GenTime(posx, m_fps); if (type() == AVWIDGET) m_info.cropStart += diff; m_info.cropDuration -= diff; setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); //kDebug()<<"// NEW START: "<<m_startPos.frames(25)<<", NW DUR: "<<m_cropDuration.frames(25); } // set crop from start to 0 (isn't relevant as this only happens for color clips, images) if (negCropStart) m_info.cropStart = GenTime(); //kDebug() << "-- NEW CLIP=" << startPos().frames(25) << "-" << endPos().frames(25); //setRect((double) m_startPos.frames(m_fps) * scale, rect().y(), (double) m_cropDuration.frames(m_fps) * scale, rect().height()); /* if (durationDiff < GenTime()) { QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect); for (int i = 0; i < collisionList.size(); ++i) { QGraphicsItem *item = collisionList.at(i); if (item->type() == type() && item->pos().x() < pos().x()) { kDebug() << "///////// COLLISION DETECTED!!!!!!!!!"; GenTime diff = ((AbstractClipItem *)item)->endPos() + GenTime(1, m_fps) - m_startPos; setRect(0, 0, (m_cropDuration - diff).frames(m_fps) - 0.02, rect().height()); setPos((m_startPos + diff).frames(m_fps), pos().y()); m_startPos += diff; if (type() == AVWIDGET) m_cropStart += diff; m_cropDuration = m_cropDuration - diff; break; } } }*/ }
void TransitionHandler::updateTransitionParams(QString type, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml) { QScopedPointer<Mlt::Field> field(m_tractor->field()); field->lock(); mlt_service nextservice = mlt_service_get_producer(field->get_service()); mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); QString mlt_type = mlt_properties_get(properties, "mlt_type"); QString resource = mlt_properties_get(properties, "mlt_service"); int in_pos = (int) in.frames(m_fps); int out_pos = (int) out.frames(m_fps) - 1; while (mlt_type == QLatin1String("transition")) { mlt_transition tr = (mlt_transition) nextservice; int currentTrack = mlt_transition_get_b_track(tr); int currentBTrack = mlt_transition_get_a_track(tr); int currentIn = (int) mlt_transition_get_in(tr); int currentOut = (int) mlt_transition_get_out(tr); // //qDebug()<<"Looking for transition : " << currentIn <<'x'<<currentOut<< ", OLD oNE: "<<in_pos<<'x'<<out_pos; if (resource == type && b_track == currentTrack && currentIn == in_pos && currentOut == out_pos) { QMap<QString, QString> map = getTransitionParamsFromXml(xml); QMap<QString, QString>::Iterator it; QString key; mlt_properties transproperties = MLT_TRANSITION_PROPERTIES(tr); QString currentId = mlt_properties_get(transproperties, "kdenlive_id"); if (currentId != xml.attribute(QStringLiteral("id"))) { // The transition ID is not the same, so reset all properties mlt_properties_set(transproperties, "kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData()); // Cleanup previous properties QStringList permanentProps; permanentProps << QStringLiteral("factory") << QStringLiteral("kdenlive_id") << QStringLiteral("mlt_service") << QStringLiteral("mlt_type") << QStringLiteral("in"); permanentProps << QStringLiteral("out") << QStringLiteral("a_track") << QStringLiteral("b_track"); for (int i = 0; i < mlt_properties_count(transproperties); ++i) { QString propName = mlt_properties_get_name(transproperties, i); if (!propName.startsWith('_') && ! permanentProps.contains(propName)) { mlt_properties_set(transproperties, propName.toUtf8().constData(), ""); } } } mlt_properties_set_int(transproperties, "force_track", xml.attribute(QStringLiteral("force_track")).toInt()); mlt_properties_set_int(transproperties, "automatic", xml.attribute(QStringLiteral("automatic"), QStringLiteral("0")).toInt()); if (currentBTrack != a_track) { mlt_properties_set_int(transproperties, "a_track", a_track); } for (it = map.begin(); it != map.end(); ++it) { key = it.key(); mlt_properties_set(transproperties, key.toUtf8().constData(), it.value().toUtf8().constData()); ////qDebug() << " ------ UPDATING TRANS PARAM: " << key.toUtf8().constData() << ": " << it.value().toUtf8().constData(); //filter->set("kdenlive_id", id); } break; } nextservice = mlt_service_producer(nextservice); if (nextservice == NULL) break; properties = MLT_SERVICE_PROPERTIES(nextservice); mlt_type = mlt_properties_get(properties, "mlt_type"); resource = mlt_properties_get(properties, "mlt_service"); } field->unlock(); //askForRefresh(); //if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); }
const QString Timecode::getTimecodeDropFrame(const GenTime & time) const { return getTimecodeDropFrame((int)time.frames(m_realFps)); }
const QString Timecode::getTimecodeSeconds(const GenTime & time) const { QLocale locale; locale.setNumberOptions(QLocale::OmitGroupSeparator); return locale.toString(time.seconds()); }
const QString Timecode::getTimecodeFrames(const GenTime & time) const { return QString::number((int) time.frames(m_realFps)); }
QString Timecode::getDisplayTimecode(const GenTime & time, bool frameDisplay) const { if (frameDisplay) return QString::number((int) time.frames(m_realFps)); return getTimecode(time); }