double Scene::nextEdge(double pts) { double margin = profile.getVideoFrameDuration() / 4.0; double npts = 0, max = 0; for ( int i = 0; i < tracks.count(); ++i ) { if ( !tracks[ i ]->clipCount() ) continue; Clip *c = tracks[ i ]->clipAt( tracks[ i ]->clipCount() - 1 ); double d = c->position() + c->length(); if ( d > max ) max = d; } npts = max; for ( int i = 0; i < tracks.count(); ++i ) { Track *t = tracks[ i ]; for ( int j = 0; j < t->clipCount(); ++j ) { Clip *c = t->clipAt( j ); double pos = c->position() - margin; if ( pos > pts && pos < npts ) { npts = pos + margin; } else { pos += c->length(); if ( pos > pts && pos < npts ) { npts = pos + margin; } } } } return (qAbs(npts - max) < 1) ? max - profile.getVideoFrameDuration() : npts; }
void ClipBoard::readTrack( QDomElement &element, QList<Clip*> *track, QList<Source*> *sourcesList, Scene *scene ) { bool readError = false; QDomNodeList nodes = element.childNodes(); for ( int i = 0; i < nodes.count(); ++i ) { QDomElement e = nodes.at( i ).toElement(); if ( e.isNull() ) continue; if ( e.tagName() == "Clip" ) { Clip *clip = XMLizer::readClip( e, sourcesList, scene, readError ); if (clip) { int k = 0, tc = track->count(); // sort clips by position while ( k < tc ) { Clip *c = track->at( k ); if ( clip->position() < c->position() ) { track->insert( k, clip ); break; } ++k; } if ( k == tc ) { track->append( clip ); } } } } }
bool Scene::setProfile( Profile &p ) { bool ok = true; double duration = profile.getVideoFrameDuration(); profile = p; double margin = profile.getVideoFrameDuration() / 4.0; if ( duration != profile.getVideoFrameDuration() ) { duration = profile.getVideoFrameDuration(); for ( int i = 0; i < tracks.count(); ++i ) { Track *t = tracks[i]; for ( int j = 0; j < t->clipCount(); ++j ) { Clip *c = t->clipAt( j ); c->setFrameDuration( duration ); double newPos = nearestPTS( c->position(), duration ); if ( !c->getTransition() && j > 0 ) { Clip *prev = t->clipAt( j - 1 ); if ( newPos < prev->position() + prev->length() - margin ) newPos = prev->position() + prev->length(); c->setPosition( newPos ); } else if ( canMove( c, c->length(), newPos, i ) ) move( c, i, newPos, i ); else ok = false; } } } return ok; }
void Scene::removeTransitions( Clip *clip, int oldTrack, int newTrack, int newIndex, double clipPos, double clipLength, double margin, bool multi ) { Track *ot = tracks[oldTrack]; int index = ot->indexOf( clip ); if ( newTrack != oldTrack || index != newIndex ) { clip->removeTransition(); if ( index < ot->clipCount() - 1 ) { Clip *c = ot->clipAt( index + 1 ); c->removeTransition(); } } else { if ( !multi && index < ot->clipCount() - 1 ) { Clip *c = ot->clipAt( index + 1 ); if ( clipPos + clipLength - margin < c->position() ) c->removeTransition(); } if ( index > 0 ) { Clip *c = ot->clipAt( index - 1 ); if ( c->position() + c->length() - margin < clipPos ) clip->removeTransition(); } } }
void Scene::updateTransitions( Clip *clip, int track, double margin ) { Track *t = tracks[track]; int index = t->indexOf( clip ); if ( index > 0 ) { Clip *c = t->clipAt( index - 1 ); if ( clip->position() < c->position() + c->length() - margin ) clip->setTransition( c->position() + c->length() - clip->position() ); } if ( index < t->clipCount() - 1 ) { Clip *c = t->clipAt( index + 1 ); if ( c->position() < clip->position() + clip->length() - margin ) c->setTransition( clip->position() + clip->length() - c->position() ); } }
void Scene::moveMulti( Clip *clip, int clipTrack, double newPos ) { QMutexLocker ml( &mutex ); if ( clip->position() == newPos ) return; double delta = newPos - clip->position(); double margin = profile.getVideoFrameDuration() / 4.0; Track *t = tracks[clipTrack]; int count = t->clipCount(); int clipIndex = 0; int k = 0; while ( k < count ) { Clip *c = t->clipAt( k ); // find clip if ( c == clip ) { clipIndex = k; break; } ++k; } removeTransitions( clip, clipTrack, clipTrack, clipIndex, newPos, clip->length(), margin, true ); clip->setPosition( clip->position() + delta ); while ( ++k < count ) { Clip *c = t->clipAt( k ); c->setPosition( c->position() + delta ); } updateTransitions( clip, clipTrack, margin ); clip->setInput( NULL ); update = true; }
void Scene::move( Clip *clip, int clipTrack, double newPos, int newTrack ) { QMutexLocker ml( &mutex ); if ( clip->position() == newPos && clipTrack == newTrack ) return; double margin = profile.getVideoFrameDuration() / 4.0; int insert, self = 0; Track *t = tracks[newTrack]; insert = t->clipCount(); for ( int i = 0; i < t->clipCount(); ++i ) { Clip *c = t->clipAt( i ); if ( c == clip ) { ++self; continue; } if ( newPos < c->position() ) { insert = i; break; } } insert -= self; removeTransitions( clip, clipTrack, newTrack, insert, newPos, clip->length(), margin ); tracks[clipTrack]->removeClip( clip ); t->insertClipAt( clip, insert ); clip->setPosition( newPos ); updateTransitions( clip, newTrack, margin ); clip->setInput( NULL ); update = true; }
bool Scene::canMoveMulti( Clip *clip, double clipLength, double &newPos, int track ) { newPos = nearestPTS( newPos, profile.getVideoFrameDuration() ); double margin = profile.getVideoFrameDuration() / 4.0; Track *t = tracks[track]; int count = t->clipCount(); if ( newPos >= clip->position() ) return true; if ( t->clipAt( 0 ) == clip ) return true; Clip *c; int k = 0; while ( k < count ) { c = t->clipAt( k ); // find clip if ( c == clip ) { break; } ++k; } if ( k == count ) return false; int clipIndex = k; c = t->clipAt( --k ); if ( newPos - margin < c->position() ) return false; // we are clipB, we can't end before clipA if ( newPos + clipLength < c->position() + c->length() - margin ) return false; // we can't overlap with clip before clipA if ( --k >= 0 ) { Clip *prevA = t->clipAt( k ); if ( newPos < prevA->position() + prevA->length() - margin ) return false; } // and clipC can't overlap with clipA if ( clipIndex < count - 1 ) { Clip *clipC = t->clipAt( clipIndex + 1 ); // clipC has moved with us, calculate its new position double cpos = clipC->position() + ( newPos - clip->position() ); if ( cpos < c->position() + c->length() - margin ) { newPos = c->position() + c->length() + clip->position() - clipC->position(); return true; } } return true; }
void Scene::addClip( Clip *clip, int track ) { QMutexLocker ml( &mutex ); double margin = profile.getVideoFrameDuration() / 4.0; Track *t = tracks[track]; int i = 0, cc = t->clipCount(); while ( i < cc ) { Clip *c = t->clipAt( i ); if ( clip->position() < c->position() ) { t->insertClipAt( clip, i ); updateTransitions( clip, track, margin ); update = true; return; } ++i; } t->insertClipAt( clip, i ); updateTransitions( clip, track, margin ); }
double Scene::previousEdge(double pts) { double margin = profile.getVideoFrameDuration() / 4.0; double npts = 0; for ( int i = 0; i < tracks.count(); ++i ) { Track *t = tracks[ i ]; for ( int j = t->clipCount() -1; j > -1; --j ) { Clip *c = t->clipAt( j ); double pos = c->position() + c->length() + margin; if ( pos < pts && pos > npts ) { npts = pos; } else { pos -= c->length(); if ( pos < pts && pos > npts ) { npts = pos; } } } } return npts; }
void Scene::resizeStart( Clip *clip, double newPos, double newLength, int track ) { QMutexLocker ml( &mutex ); if ( clip->position() == newPos && clip->length() == newLength ) return; double margin = profile.getVideoFrameDuration() / 4.0; int insert, self = 0; Track *t = tracks[track]; insert = t->clipCount(); for ( int i = 0; i < t->clipCount(); ++i ) { Clip *c = t->clipAt( i ); if ( c == clip ) { ++self; continue; } if ( newPos < c->position() ) { insert = i; break; } } insert -= self; double old = clip->position(); removeTransitions( clip, track, track, insert, newPos, newLength, margin ); t->removeClip( clip ); t->insertClipAt( clip, insert ); if ( clip->getSource()->getType() == InputBase::FFMPEG && clip->getSpeed() >= 0 ) clip->setStart( clip->start() + ((clip->length() - newLength) * qAbs(clip->getSpeed())) ); clip->setLength( newLength ); clip->setPosition( newPos ); updateTransitions( clip, track, margin ); clip->setInput( NULL ); update = updateCurrentPosition( qMin( old, clip->position() ), qMax( old, clip->position() ) ); }
bool Scene::checkPlacement( Clip *clip, int track, double clipPos, double clipLength ) { double margin = profile.getVideoFrameDuration() / 4.0; Track *t = tracks[track]; int count = t->clipCount(); // no clip in track yet if ( !count ) return true; if ( count == 1 && t->clipAt( 0 ) == clip ) return true; Clip *c; int k = 0; while ( k < count ) { c = t->clipAt( k ); // obviously, don't check clip against itself if ( clip && c == clip ) { ++k; continue; } // Track is ordered by Clip::position() // so 2 clips can't start at same pts on the same track. if ( qAbs( c->position() - clipPos ) < margin ) return false; if ( !clipLessThan( margin, c->position(), c->length(), clipPos ) ) break; ++k; } // we are the last clip in track and don't overlap with anything if ( k == count ) return true; // we are clipA if ( clipPos < c->position() ) { // we can't end after clipB if ( c->position() + c->length() < clipPos + clipLength - margin ) return false; // and we can't overlap with clipC int j = k + 1; while ( j < count ) { Clip *next = t->clipAt( j++ ); if ( clip && next == clip ) continue; if ( next->position() < clipPos + clipLength - margin ) return false; break; } } else { // we are clipB, we can't end before clipA if ( clipPos + clipLength < c->position() + c->length() - margin ) return false; int j = k + 1; while ( j < count ) { Clip *next = t->clipAt( j++ ); if ( clip && next == clip ) continue; // clipC can't overlap with clipA if ( next->position() < c->position() + c->length() - margin ) return false; // we can't end after clipC if ( next->position() + next->length() < clipPos + clipLength - margin ) return false; // and we can't overlap with clipD if ( j < count ) { Clip *d = t->clipAt( j ); if ( d->position() < clipPos + clipLength - margin ) return false; } break; } } return true; }
Clip* Scene::sceneSplitClip( Clip *clip, int track, double pts ) { pts = nearestPTS( pts, profile.getVideoFrameDuration() ); double start = clip->position(); if (clip->getTransition()) { start += clip->getTransition()->length(); } double end = clip->position() + clip->length(); Track *t = tracks[track]; int cc = t->clipCount(); int index = t->indexOf(clip); Transition *tail = NULL; Clip *next = NULL; if (index > -1 && index < cc - 1) { next = t->clipAt(index + 1); if (next->getTransition()) { end -= next->getTransition()->length() + profile.getVideoFrameDuration(); tail = new Transition(next->getTransition()); } } double oldLength = clip->length(); double newLength = pts - clip->position(); resize( clip, newLength, track ); Clip *nc = createClip( clip->getSource(), pts, clip->start() + newLength, oldLength - newLength ); double newPos = nc->position(); nc->setPosition( newPos ); FilterCollection *fc = FilterCollection::getGlobalInstance(); for ( int i = 0; i < clip->videoFilters.count(); ++i ) { QSharedPointer<GLFilter> f = clip->videoFilters.at( i ); for ( int j = 0; j < fc->videoFilters.count(); ++j ) { if ( fc->videoFilters[ j ].identifier == f->getIdentifier() ) { QSharedPointer<Filter> nf = fc->videoFilters[ j ].create(); GLFilter *gf = (GLFilter*)nf.data(); if ( nf->getIdentifier() == "GLCustom" ) { GLCustom *gc = (GLCustom*)gf; gc->setCustomParams( f->getParameters().last()->value.toString() ); } else if ( nf->getIdentifier() == "GLStabilize" ) { GLStabilize *gs = (GLStabilize*)gf; gs->setSource( nc->getSource() ); } f->splitParameters( gf, newLength ); nf->setPosition( nc->position() ); nf->setLength( nc->length() ); nc->videoFilters.append( nf.staticCast<GLFilter>() ); break; } } } for ( int i = 0; i < clip->audioFilters.count(); ++i ) { QSharedPointer<AudioFilter> f = clip->audioFilters.at( i ); for ( int j = 0; j < fc->audioFilters.count(); ++j ) { if ( fc->audioFilters[ j ].identifier == f->getIdentifier() ) { QSharedPointer<Filter> nf = fc->audioFilters[ j ].create(); AudioFilter *af = (AudioFilter*)nf.data(); f->splitParameters( af, newLength ); nf->setPosition( nc->position() ); nf->setLength( nc->length() ); nc->audioFilters.append( nf.staticCast<AudioFilter>() ); break; } } } addClip( nc, track ); if (tail) { next->setTransition(tail); } return nc; }