service.unlock();
}*/
- kDebug() << "// // // CLOSE RENDERER " << m_name;
+ //kDebug() << "// // // CLOSE RENDERER " << m_name;
if (m_blackClip) delete m_blackClip;
//delete m_osdInfo;
}
xmlConsumer.start();
}
+
+bool Render::saveClip(int track, GenTime position, KUrl url, QString desc)
+{
+ // find clip
+ Mlt::Service service(m_mltProducer->parent().get_service());
+ Mlt::Tractor tractor(service);
+ Mlt::Producer trackProducer(tractor.track(track));
+ Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+
+ int clipIndex = trackPlaylist.get_clip_index_at((int) position.frames(m_fps));
+ Mlt::Producer *clip = trackPlaylist.get_clip(clipIndex);
+ if (!clip) {
+ kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps);
+ return false;
+ }
+
+ Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData());
+ xmlConsumer.set("terminate_on_pause", 1);
+ Mlt::Playlist list;
+ list.insert_at(0, clip, 0);
+ //delete clip;
+ list.set("title", desc.toUtf8().constData());
+ xmlConsumer.connect(list);
+ xmlConsumer.run();
+ kDebug()<<"// SAVED: "<<url;
+ return true;
+}
+
double Render::fps() const
{
return m_fps;
}
}
+void Render::disablePreview(bool disable)
+{
+ if (m_mltConsumer) {
+ m_mltConsumer->stop();
+ m_mltConsumer->set("preview_off", (int) disable);
+ m_mltConsumer->set("refresh", 0);
+ m_mltConsumer->start();
+ }
+}
+
void Render::showAudio(Mlt::Frame& frame)
{
if (!frame.is_valid() || frame.get_int("test_audio") != 0) {
return;
}
mlt_audio_format audio_format = mlt_audio_s16;
- int freq = 0;
- int num_channels = 0;
+ //FIXME: should not be hardcoded..
+ int freq = 48000;
+ int num_channels = 2;
int samples = 0;
int16_t* data = (int16_t*)frame.get_audio(audio_format, freq, num_channels, samples);
{
bool updateIndex = false;
const int filter_ix = params.paramValue("kdenlive_ix").toInt();
- const QString region = params.paramValue("region");
int ct = 0;
service.lock();
filter = service.filter(ct);
}
- // create filter
+ addFilterToService(service, params, duration);
+
+ // re-add following filters
+ for (int i = 0; i < filtersList.count(); i++) {
+ Mlt::Filter *filter = filtersList.at(i);
+ if (updateIndex)
+ filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") + 1);
+ service.attach(*filter);
+ }
+ service.unlock();
+ if (doRefresh) refresh();
+ return true;
+}
+
+
+bool Render::addFilterToService(Mlt::Service service, EffectsParameterList params, int duration)
+{
+ // create filter
QString tag = params.paramValue("tag");
//kDebug() << " / / INSERTING EFFECT: " << tag << ", REGI: " << region;
char *filterTag = qstrdup(tag.toUtf8().constData());
char *filterId = qstrdup(params.paramValue("id").toUtf8().constData());
- QHash<QString, QString>::Iterator it;
QString kfr = params.paramValue("keyframes");
-
- if (!kfr.isEmpty()) {
+ if (!kfr.isEmpty()) {
QStringList keyFrames = kfr.split(';', QString::SkipEmptyParts);
//kDebug() << "// ADDING KEYFRAME EFFECT: " << params.paramValue("keyframes");
char *starttag = qstrdup(params.paramValue("starttag", "start").toUtf8().constData());
} else {
Mlt::Filter *filter;
QString prefix;
- if (!region.isEmpty()) {
- filter = new Mlt::Filter(*m_mltProfile, "region");
- } else filter = new Mlt::Filter(*m_mltProfile, filterTag);
+ filter = new Mlt::Filter(*m_mltProfile, filterTag);
if (filter && filter->is_valid()) {
filter->set("kdenlive_id", filterId);
- if (!region.isEmpty()) {
- filter->set("resource", region.toUtf8().constData());
- filter->set("kdenlive_ix", params.paramValue("kdenlive_ix").toUtf8().constData());
- filter->set("filter0", filterTag);
- prefix = "filter0.";
- params.removeParam("id");
- params.removeParam("region");
- params.removeParam("kdenlive_ix");
- }
} else {
kDebug() << "filter is NULL";
service.unlock();
//kDebug() << "SOX EFFECTS: " << effectArgs.simplified();
filter->set("effect", effectArgs.simplified().toUtf8().constData());
}
-
// attach filter to the clip
service.attach(*filter);
}
+
delete[] filterId;
delete[] filterTag;
-
- // re-add following filters
- for (int i = 0; i < filtersList.count(); i++) {
- Mlt::Filter *filter = filtersList.at(i);
- if (updateIndex)
- filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") + 1);
- service.attach(*filter);
- }
- service.unlock();
- if (doRefresh) refresh();
return true;
}
refresh();
return true;
-
}
bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList params)
int index = params.paramValue("kdenlive_ix").toInt();
QString tag = params.paramValue("tag");
- if (!params.paramValue("keyframes").isEmpty() || /*it.key().startsWith("#") || */tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle" || params.hasParam("region")) {
+ if (!params.paramValue("keyframes").isEmpty() || (tag == "affine" && params.hasParam("background")) || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") {
// This is a keyframe effect, to edit it, we remove it and re-add it.
bool success = mltRemoveEffect(track, position, index, false);
// if (!success) kDebug() << "// ERROR Removing effect : " << index;
bool success = mltAddEffect(track, position, params);
return success;
}
- QString prefix;
+ ct = 0;
QString ser = filter->get("mlt_service");
- if (ser == "region") prefix = "filter0.";
+ QList <Mlt::Filter *> filtersList;
+ service.lock();
+ if (ser != tag) {
+ // Effect service changes, delete effect and re-add it
+ clip->detach(*filter);
+
+ // Delete all effects after deleted one
+ filter = clip->filter(ct);
+ while (filter) {
+ if (filter->get_int("kdenlive_ix") > index) {
+ filtersList.append(filter);
+ clip->detach(*filter);
+ }
+ else ct++;
+ filter = clip->filter(ct);
+ }
+
+ // re-add filter
+ addFilterToService(*clip, params, clip->get_playtime());
+ delete clip;
+ service.unlock();
+
+ if (doRefresh) refresh();
+ return true;
+ }
if (params.hasParam("_sync_in_out")) {
// This effect must sync in / out with parent clip
params.removeParam("_sync_in_out");
filter->set_in_and_out(clip->get_in(), clip->get_out());
}
- service.lock();
+
for (int j = 0; j < params.count(); j++) {
- filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData());
+ filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData());
+ }
+
+ for (int j = 0; j < filtersList.count(); j++) {
+ clip->attach(*(filtersList.at(j)));
}
delete clip;
return true;
}
+bool Render::mltEnableEffects(int track, GenTime position, QList <int> effectIndexes, bool disable)
+{
+ if (position < GenTime()) {
+ return mltEnableTrackEffects(track, effectIndexes, disable);
+ }
+ // find filter
+ Mlt::Service service(m_mltProducer->parent().get_service());
+ Mlt::Tractor tractor(service);
+ Mlt::Producer trackProducer(tractor.track(track));
+ Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+
+ int clipIndex = trackPlaylist.get_clip_index_at((int) position.frames(m_fps));
+ Mlt::Producer *clip = trackPlaylist.get_clip(clipIndex);
+ if (!clip) {
+ kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps);
+ return false;
+ }
+
+ int duration = clip->get_playtime();
+ bool doRefresh = true;
+ // Check if clip is visible in monitor
+ int diff = trackPlaylist.clip_start(clipIndex) + duration - m_mltProducer->position();
+ if (diff < 0 || diff > duration)
+ doRefresh = false;
+ int ct = 0;
+
+ Mlt::Filter *filter = clip->filter(ct);
+ while (filter) {
+ if (effectIndexes.contains(filter->get_int("kdenlive_ix"))) {
+ filter->set("disable", (int) disable);
+ }
+ ct++;
+ filter = clip->filter(ct);
+ }
+
+ delete clip;
+ service.unlock();
+
+ if (doRefresh) refresh();
+ return true;
+}
+
+bool Render::mltEnableTrackEffects(int track, QList <int> effectIndexes, bool disable)
+{
+ Mlt::Service service(m_mltProducer->parent().get_service());
+ Mlt::Tractor tractor(service);
+ Mlt::Producer trackProducer(tractor.track(track));
+ Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+ Mlt::Service clipService(trackPlaylist.get_service());
+ int ct = 0;
+
+ Mlt::Filter *filter = clipService.filter(ct);
+ while (filter) {
+ if (effectIndexes.contains(filter->get_int("kdenlive_ix"))) {
+ filter->set("disable", (int) disable);
+ }
+ ct++;
+ filter = clipService.filter(ct);
+ }
+ service.unlock();
+
+ refresh();
+ return true;
+}
+
void Render::mltUpdateEffectPosition(int track, GenTime position, int oldPos, int newPos)
{
Mlt::Service service(m_mltProducer->parent().get_service());
mlt_service_unlock(serv);
}
-bool Render::mltResizeClipCrop(ItemInfo info, GenTime diff)
+bool Render::mltResizeClipCrop(ItemInfo info, GenTime newCropStart)
{
Mlt::Service service(m_mltProducer->parent().get_service());
- int frameOffset = (int) diff.frames(m_fps);
+ int newCropFrame = (int) newCropStart.frames(m_fps);
Mlt::Tractor tractor(service);
Mlt::Producer trackProducer(tractor.track(info.track));
Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
int previousStart = clip->get_in();
int previousOut = clip->get_out();
delete clip;
- trackPlaylist.resize_clip(clipIndex, previousStart + frameOffset, previousOut + frameOffset);
+ if (previousStart == newCropFrame) {
+ kDebug() << "//////// No ReSIZING Required";
+ service.unlock();
+ return true;
+ }
+ int frameOffset = newCropFrame - previousStart;
+ trackPlaylist.resize_clip(clipIndex, newCropFrame, previousOut + frameOffset);
service.unlock();
m_mltConsumer->set("refresh", 1);
return true;
Mlt::Producer trackProducer(tractor.track(startTrack));
Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
int clipIndex = trackPlaylist.get_clip_index_at(moveStart);
- //kDebug() << "////// LOOKING FOR CLIP TO MOVE, INDEX: " << clipIndex;
+ int clipDuration = trackPlaylist.clip_length(clipIndex);
bool checkLength = false;
if (endTrack == startTrack) {
Mlt::Producer *clipProducer = trackPlaylist.replace_with_blank(clipIndex);
- if ((!overwrite && !trackPlaylist.is_blank_at(moveEnd)) || !clipProducer || !clipProducer->is_valid() || clipProducer->is_blank()) {
- // error, destination is not empty
- if (clipProducer) {
- if (!trackPlaylist.is_blank_at(moveEnd) && clipProducer->is_valid()) trackPlaylist.insert_at(moveStart, clipProducer, 1);
- delete clipProducer;
+ if (!overwrite) {
+ bool success = true;
+ if (!trackPlaylist.is_blank_at(moveEnd) || !clipProducer || !clipProducer->is_valid() || clipProducer->is_blank()) {
+ success = false;
+ }
+ else {
+ // Check that the destination region is empty
+ trackPlaylist.consolidate_blanks(0);
+ int destinationIndex = trackPlaylist.get_clip_index_at(moveEnd);
+ if (destinationIndex < trackPlaylist.count() - 1) {
+ // We are not at the end of the track
+ int blankSize = trackPlaylist.blanks_from(destinationIndex, 1);
+ // Make sure we have enough place to insert clip
+ if (blankSize - clipDuration - (moveEnd - trackPlaylist.clip_start(destinationIndex)) < 0) success = false;
+ }
}
- //int ix = trackPlaylist.get_clip_index_at(moveEnd);
- kDebug() << "// ERROR MOVING CLIP TO : " << moveEnd;
- service.unlock();
- return false;
- } else {
- trackPlaylist.consolidate_blanks(0);
- if (overwrite) {
- trackPlaylist.remove_region(moveEnd, clipProducer->get_playtime());
- int clipIndex = trackPlaylist.get_clip_index_at(moveEnd);
- trackPlaylist.insert_blank(clipIndex, clipProducer->get_playtime() - 1);
+ if (!success) {
+ if (clipProducer) {
+ trackPlaylist.insert_at(moveStart, clipProducer, 1);
+ delete clipProducer;
+ }
+ kDebug() << "// ERROR MOVING CLIP TO : " << moveEnd;
+ service.unlock();
+ return false;
}
- int newIndex = trackPlaylist.insert_at(moveEnd, clipProducer, 1);
- trackPlaylist.consolidate_blanks(1);
+ }
+
+ if (overwrite) {
+ trackPlaylist.remove_region(moveEnd, clipProducer->get_playtime());
+ int clipIndex = trackPlaylist.get_clip_index_at(moveEnd);
+ trackPlaylist.insert_blank(clipIndex, clipProducer->get_playtime() - 1);
+ }
+ int newIndex = trackPlaylist.insert_at(moveEnd, clipProducer, 1);
+ if (newIndex == -1) {
+ kDebug()<<"// CANNOT MOVE CLIP TO: "<<moveEnd;
+ trackPlaylist.insert_at(moveStart, clipProducer, 1);
delete clipProducer;
- /*if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
- mltMoveTransparency(moveStart, moveEnd, startTrack, endTrack, QString(clipProducer.parent().get("id")).toInt());
- }*/
- if (newIndex + 1 == trackPlaylist.count()) checkLength = true;
+ service.unlock();
+ return false;
}
- //service.unlock();
+ trackPlaylist.consolidate_blanks(1);
+ delete clipProducer;
+ if (newIndex + 1 == trackPlaylist.count()) checkLength = true;
} else {
Mlt::Producer destTrackProducer(tractor.track(endTrack));
Mlt::Playlist destTrackPlaylist((mlt_playlist) destTrackProducer.get_service());
if (!overwrite && !destTrackPlaylist.is_blank_at(moveEnd)) {
// error, destination is not empty
+ kDebug() << "Cannot move: Destination is not empty";
service.unlock();
return false;
} else {
}
}
-void Render::mltInsertTrack(int ix, bool videoTrack)
+QList <TransitionInfo> Render::mltInsertTrack(int ix, bool videoTrack)
{
- blockSignals(true);
-
Mlt::Service service(m_mltProducer->parent().get_service());
- service.lock();
if (service.type() != tractor_type) {
kWarning() << "// TRACTOR PROBLEM";
- return;
+ return QList <TransitionInfo> ();
}
-
+ blockSignals(true);
+ service.lock();
Mlt::Tractor tractor(service);
-
+ QList <TransitionInfo> transitionInfos;
Mlt::Playlist playlist;
int ct = tractor.count();
if (ix > ct) {
nextservice = mlt_service_producer(nextservice);
int currentbTrack = transition.get_b_track();
int currentaTrack = transition.get_a_track();
-
bool trackChanged = false;
+ bool forceTransitionTrack = false;
if (currentbTrack >= ix) {
+ if (currentbTrack == ix && currentaTrack < ix) forceTransitionTrack = true;
currentbTrack++;
trackChanged = true;
}
currentaTrack++;
trackChanged = true;
}
+ kDebug()<<"// Newtrans: "<<currentaTrack<<"/"<<currentbTrack;
// disconnect all transitions
Mlt::Properties trans_props(transition.get_properties());
new_trans_props.inherit(trans_props);
if (trackChanged) {
- // Transition track needs to be adjusted
+ // Transition track needs to be adjusted
cp->set("a_track", currentaTrack);
cp->set("b_track", currentbTrack);
+ // Check if transition track was changed and needs to be forced
+ if (forceTransitionTrack) cp->set("force_track", 1);
+ TransitionInfo trInfo;
+ trInfo.startPos = GenTime(transition.get_in(), m_fps);
+ trInfo.a_track = currentaTrack;
+ trInfo.b_track = currentbTrack;
+ trInfo.forceTrack = cp->get_int("force_track");
+ transitionInfos.append(trInfo);
}
trList.append(cp);
field->disconnect_service(transition);
service.unlock();
blockSignals(false);
+ return transitionInfos;
}