Commit 37ddf5ed authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix crash on undo mix deletion, use different producer for subplaylists (fixes slow transitions)

parent 640664e2
......@@ -630,7 +630,7 @@ void ProjectClip::createDisabledMasterProducer()
}
}
std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState state, int audioStream, double speed)
std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState state, int audioStream, double speed, bool secondPlaylist)
{
if (!m_masterProducer) {
return nullptr;
......@@ -660,6 +660,10 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
trackId -= 100 * audioStream;
}
}
// second playlist producers use negative trackId
if (secondPlaylist) {
trackId = -trackId;
}
if (m_audioProducers.count(trackId) == 0) {
m_audioProducers[trackId] = cloneProducer(true);
m_audioProducers[trackId]->set("set.test_audio", 0);
......@@ -689,6 +693,10 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
if (state == PlaylistState::VideoOnly) {
// we return the video producer
// We need to get an video producer, if none exists
// second playlist producers use negative trackId
if (secondPlaylist) {
trackId = -trackId;
}
if (m_videoProducers.count(trackId) == 0) {
m_videoProducers[trackId] = cloneProducer(true);
m_videoProducers[trackId]->set("set.test_audio", 1);
......@@ -753,7 +761,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int trackId, int
return std::shared_ptr<Mlt::Producer>(warpProducer->cut());
}
std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master, PlaylistState::ClipState state, int tid)
std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master, PlaylistState::ClipState state, int tid, bool secondPlaylist)
{
int in = master->get_in();
int out = master->get_out();
......@@ -790,10 +798,12 @@ std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTim
return {master, true};
}
if (state == PlaylistState::AudioOnly) {
int producerId = tid;
int audioStream = master->parent().get_int("audio_index");
if (audioStream > -1) {
producerId += 100 * audioStream;
tid += 100 * audioStream;
}
if (secondPlaylist) {
tid = -tid;
}
m_audioProducers[tid] = std::make_shared<Mlt::Producer>(&master->parent());
m_effectStack->loadService(m_audioProducers[tid]);
......@@ -803,6 +813,9 @@ std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTim
// good, we found a master video producer, and we didn't have any
if (m_clipType != ClipType::Color && m_clipType != ClipType::Image && m_clipType != ClipType::Text) {
// Color, image and text clips always use master producer in timeline
if (secondPlaylist) {
tid = -tid;
}
m_videoProducers[tid] = std::make_shared<Mlt::Producer>(&master->parent());
m_effectStack->loadService(m_videoProducers[tid]);
} else {
......
......@@ -202,7 +202,7 @@ public:
/** @brief This function returns a cut to the master producer associated to the timeline clip with given ID.
Each clip must have a different master producer (see comment of the class)
*/
std::shared_ptr<Mlt::Producer> getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState st, int audioStream = -1, double speed = 1.0);
std::shared_ptr<Mlt::Producer> getTimelineProducer(int trackId, int clipId, PlaylistState::ClipState st, int audioStream = -1, double speed = 1.0, bool secondPlaylist = false);
/* @brief This function should only be used at loading. It takes a producer that was read from mlt, and checks whether the master producer is already in
use. If yes, then we must create a new one, because of the mixing bug. In any case, we return a cut of the master that can be used in the timeline The
......@@ -210,7 +210,7 @@ public:
- if true, then the returned cut still possibly has effect on it. You need to rebuild the effectStack based on this
- if false, then the returned cut don't have effects anymore (it's a fresh one), so you need to reload effects from the old producer
*/
std::pair<std::shared_ptr<Mlt::Producer>, bool> giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master, PlaylistState::ClipState state, int tid);
std::pair<std::shared_ptr<Mlt::Producer>, bool> giveMasterAndGetTimelineProducer(int clipId, std::shared_ptr<Mlt::Producer> master, PlaylistState::ClipState state, int tid, bool secondPlaylist = false);
std::shared_ptr<Mlt::Producer> cloneProducer(bool removeEffects = false);
static std::shared_ptr<Mlt::Producer> cloneProducer(const std::shared_ptr<Mlt::Producer> &producer);
......
......@@ -124,13 +124,13 @@ int ClipModel::construct(const std::shared_ptr<TimelineModel> &parent, const QSt
speed = producer->parent().get_double("warp_speed");
warp_pitch = producer->parent().get_int("warp_pitch");
}
auto result = binClip->giveMasterAndGetTimelineProducer(id, producer, state, tid);
auto result = binClip->giveMasterAndGetTimelineProducer(id, producer, state, tid, playlist == 1);
std::shared_ptr<ClipModel> clip(new ClipModel(parent, result.first, binClipId, id, state, speed));
if (warp_pitch) {
result.first->parent().set("warp_pitch", 1);
}
clip->setClipState_lambda(state)();
clip->setSubPlaylistIndex(playlist);
clip->setSubPlaylistIndex(playlist, -1);
parent->registerClip(clip);
clip->m_effectStack->importEffects(producer, state, result.second, originalDecimalPoint);
clip->m_clipMarkerModel->setReferenceModel(binClip->getMarkerModel(), speed);
......@@ -298,6 +298,7 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
}
return true;
}
qDebug()<<"============\n+++++++++++++++++\nREVRSE TRACK OP FAILED\n\n++++++++++++++++";
return false;
};
qDebug() << "----------\n-----------\n// ADJUSTING EFFECT LENGTH, LOGUNDO " << logUndo << ", " << old_in << "/" << inPoint << ", "
......@@ -451,7 +452,7 @@ bool ClipModel::isAudioOnly() const
return m_currentState == PlaylistState::AudioOnly;
}
void ClipModel::refreshProducerFromBin(int trackId, PlaylistState::ClipState state, int stream, double speed, bool hasPitch)
void ClipModel::refreshProducerFromBin(int trackId, PlaylistState::ClipState state, int stream, double speed, bool hasPitch, bool secondPlaylist)
{
// We require that the producer is not in the track when we refresh the producer, because otherwise the modification will not be propagated. Remove the clip
// first, refresh, and then replant.
......@@ -467,7 +468,7 @@ void ClipModel::refreshProducerFromBin(int trackId, PlaylistState::ClipState sta
qDebug() << "changing speed" << in << out << m_speed;
}
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(m_binClipId);
std::shared_ptr<Mlt::Producer> binProducer = binClip->getTimelineProducer(trackId, m_id, state, stream, m_speed);
std::shared_ptr<Mlt::Producer> binProducer = binClip->getTimelineProducer(trackId, m_id, state, stream, m_speed, secondPlaylist);
m_producer = std::move(binProducer);
m_producer->set_in_and_out(in, out);
if (hasPitch) {
......@@ -493,7 +494,7 @@ void ClipModel::refreshProducerFromBin(int trackId)
hasPitch = m_producer->parent().get_int("warp_pitch") == 1;
}
int stream = m_producer->parent().get_int("audio_index");
refreshProducerFromBin(trackId, m_currentState, stream, 0, hasPitch);
refreshProducerFromBin(trackId, m_currentState, stream, 0, hasPitch, m_subPlaylistIndex == 1);
}
bool ClipModel::useTimewarpProducer(double speed, bool pitchCompensate, bool changeDuration, Fun &undo, Fun &redo)
......@@ -877,9 +878,15 @@ int ClipModel::getSubPlaylistIndex() const
return m_subPlaylistIndex;
}
void ClipModel::setSubPlaylistIndex(int index)
void ClipModel::setSubPlaylistIndex(int index, int trackId)
{
if (m_subPlaylistIndex == index) {
return;
}
m_subPlaylistIndex = index;
if (trackId > -1) {
refreshProducerFromBin(trackId);
}
}
void ClipModel::setOffset(int offset)
......
......@@ -148,7 +148,7 @@ public:
/**@brief Tracks have two sub playlists to enable same track transitions. This returns the index of the sub-playlist containing this clip */
int getSubPlaylistIndex() const;
void setSubPlaylistIndex(int index);
void setSubPlaylistIndex(int index, int trackId);
friend class TrackModel;
friend class TimelineModel;
......@@ -183,7 +183,7 @@ protected:
* @param speed corresponds to the speed we need. Leave to 0 to keep current speed. Warning: this function doesn't notify the model. Unless you know what
* you are doing, better use useTimewarProducer to change the speed
*/
void refreshProducerFromBin(int trackId, PlaylistState::ClipState state, int stream, double speed, bool hasPitch);
void refreshProducerFromBin(int trackId, PlaylistState::ClipState state, int stream, double speed, bool hasPitch, bool secondPlaylist = false);
void refreshProducerFromBin(int trackId);
/* @brief This functions replaces the current producer with a slowmotion one
......
......@@ -669,13 +669,13 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
// We are moving a clip on same track
if (finalMove && position >= mixData.first.firstClipInOut.second) {
int subPlaylist = m_allClips[clipId]->getSubPlaylistIndex();
update_playlist = [this, clipId, subPlaylist]() {
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist == 0 ? 1 : 0);
update_playlist = [this, clipId, trackId, subPlaylist]() {
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist == 0 ? 1 : 0, trackId);
return true;
};
bool isAudio = getTrackById_const(old_trackId)->isAudioTrack();
update_playlist_undo = [this, clipId, subPlaylist, old_trackId, mixData, isAudio]() {
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist);
update_playlist_undo = [this, clipId, subPlaylist, old_trackId, trackId, mixData, isAudio]() {
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist, trackId);
bool result = getTrackById_const(old_trackId)->createMix(mixData.first, isAudio);
return result;
};
......@@ -683,15 +683,15 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
} else if (finalMove) {
// Clip moved to another track, delete mix
int subPlaylist = m_allClips[clipId]->getSubPlaylistIndex();
update_playlist = [this, clipId, old_trackId, finalMove]() {
update_playlist = [this, clipId, old_trackId, trackId, finalMove]() {
m_allClips[clipId]->setMixDuration(0);
m_allClips[clipId]->setSubPlaylistIndex(0);
m_allClips[clipId]->setSubPlaylistIndex(0, trackId);
getTrackById_const(old_trackId)->syncronizeMixes(finalMove);
return true;
};
bool isAudio = getTrackById_const(old_trackId)->isAudioTrack();
update_playlist_undo = [this, clipId, subPlaylist, mixData, old_trackId, isAudio, finalMove]() {
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist);
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist, old_trackId);
bool result = getTrackById_const(old_trackId)->createMix(mixData.first, isAudio);
return result;
};
......
......@@ -140,8 +140,8 @@ bool TrackModel::switchPlaylist(int clipId, int position, int sourcePlaylist, in
m_playlists[sourcePlaylist].consolidate_blanks();
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(clipId);
clip->setSubPlaylistIndex(destPlaylist, m_id);
int index = m_playlists[destPlaylist].insert_at(position, *clip, 1);
clip->setSubPlaylistIndex(destPlaylist);
m_playlists[destPlaylist].consolidate_blanks();
return index != -1;
}
......@@ -177,7 +177,7 @@ Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updat
// update clip position and track
clip->setPosition(position);
if (finalMove) {
clip->setSubPlaylistIndex(subPlaylist);
clip->setSubPlaylistIndex(subPlaylist, m_id);
}
int new_in = clip->getPosition();
int new_out = new_in + clip->getPlaytime();
......@@ -561,7 +561,6 @@ Fun TrackModel::requestClipResize_lambda(int clipId, int in, int out, bool right
if (!isHidden() && !isAudioTrack()) {
checkRefresh = true;
}
auto update_snaps = [old_in, old_out, checkRefresh, right, clipId, this](int new_in, int new_out) {
if (auto ptr = m_parent.lock()) {
if (right) {
......@@ -699,7 +698,7 @@ Fun TrackModel::requestClipResize_lambda(int clipId, int in, int out, bool right
} else {
}
}
return []() { return false; };
return []() { qDebug()<<"=====FULL FAILURE "; return false; };
}
int TrackModel::getId() const
......@@ -1470,7 +1469,7 @@ bool TrackModel::requestRemoveMix(std::pair<int, int> clipIds, Fun &undo, Fun &r
Fun local_redo = []() { return true; };
if (auto ptr = m_parent.lock()) {
// Resize main clip
result = ptr->getClipPtr(clipIds.second)->requestResize(endPos - secondInPos, false, local_undo, local_redo, true, clipHasEndMix);
result = ptr->getClipPtr(clipIds.second)->requestResize(endPos - secondInPos, false, local_undo, local_redo, true, true);
// Resize first part clip
result = result && ptr->getClipPtr(clipIds.first)->requestResize(secondInPos - firstInPos, true, local_undo, local_redo, true, true);
}
......@@ -1503,7 +1502,7 @@ bool TrackModel::requestRemoveMix(std::pair<int, int> clipIds, Fun &undo, Fun &r
Fun reverse = [this, clipIds, mixDuration, mixPosition, mixCutPos, secondInPos, clipHasEndMix, src_track]() {
// First restore correct playlist
if (src_track == 1 && !clipHasEndMix) {
// Revert clip to playlist 0 since it has no mix
// Revert clip to playlist 1
switchPlaylist(clipIds.second, secondInPos, 0, 1);
}
// Build mix
......@@ -1636,8 +1635,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std::unique_ptr<Mlt::Producer> prod(m_playlists[1].replace_with_blank(target_clip));
// Replug
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(i.key());
clip->setSubPlaylistIndex(0, m_id);
int index = m_playlists[0].insert_at(pos, *clip, 1);
clip->setSubPlaylistIndex(0);
m_playlists[0].consolidate_blanks();
}
m_playlists[1].consolidate_blanks();
......@@ -1649,8 +1648,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (i.value() == 0) {
int pos = m_allClips[i.key()]->getPosition();
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(i.key());
clip->setSubPlaylistIndex(1, m_id);
int index = m_playlists[1].insert_at(pos, *clip, 1);
clip->setSubPlaylistIndex(1);
m_playlists[1].consolidate_blanks();
}
if (m_sameCompositions.count(i.key()) > 0) {
......@@ -1685,8 +1684,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std::unique_ptr<Mlt::Producer> prod(m_playlists[0].replace_with_blank(target_clip));
// Replug
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(i.key());
clip->setSubPlaylistIndex(1, m_id);
int index = m_playlists[1].insert_at(pos, *clip, 1);
clip->setSubPlaylistIndex(1);
m_playlists[1].consolidate_blanks();
}
m_playlists[0].consolidate_blanks();
......@@ -1698,8 +1697,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (i.value() == 0) {
int pos = m_allClips[i.key()]->getPosition();
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(i.key());
clip->setSubPlaylistIndex(0, m_id);
int index = m_playlists[0].insert_at(pos, *clip, 1);
clip->setSubPlaylistIndex(0);
m_playlists[0].consolidate_blanks();
}
if (m_sameCompositions.count(i.key()) > 0) {
......@@ -1764,7 +1763,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (res) {
Fun replay = [this, clipIds, dest_track, firstClipPos, secondClipDuration, mixPosition, mixDuration, build_mix, secondClipPos, clipHasEndMix, updateView, finalMove, groupMove, rearrange_playlists]() {
if (auto ptr = m_parent.lock()) {
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(dest_track);
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(dest_track, m_id);
}
rearrange_playlists();
auto op = requestClipInsertion_lambda(clipIds.second, secondClipPos, updateView, finalMove, groupMove);
......@@ -1793,7 +1792,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
}
operation();
if (auto ptr = m_parent.lock()) {
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(source_track);
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(source_track, m_id);
}
rearrange_playlists_undo();
auto op = requestClipInsertion_lambda(clipIds.second, secondClipPos, updateView, finalMove, groupMove);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment