void TransitionHandler::deleteTransition(QString tag, int /*a_track*/, int b_track, GenTime in, GenTime out, QDomElement /*xml*/, bool /*do_refresh*/) { 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"); const int old_pos = (int)((in + out).frames(m_fps) / 2); ////qDebug() << " del trans pos: " << in.frames(25) << '-' << out.frames(25); while (mlt_type == QLatin1String("transition")) { mlt_transition tr = (mlt_transition) nextservice; int currentTrack = mlt_transition_get_b_track(tr); int currentIn = (int) mlt_transition_get_in(tr); int currentOut = (int) mlt_transition_get_out(tr); ////qDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack; if (resource == tag && b_track == currentTrack && currentIn <= old_pos && currentOut >= old_pos) { mlt_field_disconnect_service(field->get_field(), nextservice); 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); }
int mlt_consumer_put_frame( mlt_consumer self, mlt_frame frame ) { int error = 1; // Get the service assoicated to the consumer mlt_service service = MLT_CONSUMER_SERVICE( self ); if ( mlt_service_producer( service ) == NULL ) { struct timeval now; struct timespec tm; pthread_mutex_lock( &self->put_mutex ); while ( self->put_active && self->put != NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &self->put_cond, &self->put_mutex, &tm ); } if ( self->put_active && self->put == NULL ) self->put = frame; else mlt_frame_close( frame ); pthread_cond_broadcast( &self->put_cond ); pthread_mutex_unlock( &self->put_mutex ); } else { mlt_frame_close( frame ); } return error; }
static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { mlt_filter self = service->child; // Get coords in/out/track int track = mlt_filter_get_track( self ); int in = mlt_filter_get_in( self ); int out = mlt_filter_get_out( self ); // Get the producer this is connected to mlt_service producer = mlt_service_producer( &self->parent ); // If the frame request is for this filters track, we need to process it if ( index == track || track == -1 ) { int ret = mlt_service_get_frame( producer, frame, index ); if ( ret == 0 ) { mlt_position position = mlt_frame_get_position( *frame ); if ( position >= in && ( out == 0 || position <= out ) ) *frame = mlt_filter_process( self, *frame ); return 0; } else { *frame = mlt_frame_init( service ); return 0; } } else { return mlt_service_get_frame( producer, frame, index ); } }
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; }
int mlt_tractor_remove_track( mlt_tractor self, int index ) { int error = mlt_multitrack_disconnect( mlt_tractor_multitrack( self ), index ); if ( !error ) { // Update the track indices of transitions and track filters. mlt_service service = mlt_service_producer( MLT_TRACTOR_SERVICE( self ) ); while ( service ) { mlt_service_type type = mlt_service_identify( service ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( type == transition_type ) { mlt_transition transition = MLT_TRANSITION( service ); int a_track = mlt_transition_get_a_track( transition ); int b_track = mlt_transition_get_b_track( transition ); if ( a_track >= index || b_track >= index ) { a_track = MAX( a_track >= index ? a_track - 1 : a_track, 0 ); b_track = MAX( b_track >= index ? b_track - 1 : b_track, 0 ); mlt_transition_set_tracks( transition, a_track, b_track ); } } else if ( type == filter_type ) { int current_track = mlt_properties_get_int( properties, "track" ); if ( current_track >= index ) mlt_properties_set_int( properties, "track", MAX( current_track - 1, 0 ) ); } service = mlt_service_producer( service ); } } return error; }
void TransitionHandler::deleteTrackTransitions(int ix) { QScopedPointer<Mlt::Field> field(m_tractor->field()); mlt_service nextservice = mlt_service_get_producer(field->get_service()); mlt_service_type type = mlt_service_identify( nextservice ); while (type == transition_type) { Mlt::Transition transition((mlt_transition) nextservice); nextservice = mlt_service_producer(nextservice); int currentTrack = transition.get_b_track(); if (ix == currentTrack) { field->disconnect_service(transition); } if (nextservice == NULL) break; type = mlt_service_identify(nextservice ); } }
// adds the transition by keeping the instance order from topmost track down to background void TransitionHandler::plantTransition(Mlt::Field *field, Mlt::Transition &tr, int a_track, int b_track) { 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"); QList <Mlt::Transition *> trList; mlt_properties insertproperties = tr.get_properties(); QString insertresource = mlt_properties_get(insertproperties, "mlt_service"); bool isMixTransition = insertresource == QLatin1String("mix"); while (mlt_type == QLatin1String("transition")) { Mlt::Transition transition((mlt_transition) nextservice); nextservice = mlt_service_producer(nextservice); int aTrack = transition.get_a_track(); int bTrack = transition.get_b_track(); int internal = transition.get_int("internal_added"); if ((isMixTransition || resource != QLatin1String("mix")) && (internal > 0 || aTrack < a_track || (aTrack == a_track && bTrack > b_track))) { Mlt::Properties trans_props(transition.get_properties()); Mlt::Transition *cp = new Mlt::Transition(*m_tractor->profile(), transition.get("mlt_service")); Mlt::Properties new_trans_props(cp->get_properties()); //new_trans_props.inherit(trans_props); cloneProperties(new_trans_props, trans_props); trList.append(cp); field->disconnect_service(transition); } //else qDebug() << "// FOUND TRANS OK, "<<resource<< ", A_: " << aTrack << ", B_ "<<bTrack; 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->plant_transition(tr, a_track, b_track); // re-add upper transitions for (int i = trList.count() - 1; i >= 0; --i) { ////qDebug()<< "REPLANT ON TK: "<<trList.at(i)->get_a_track()<<", "<<trList.at(i)->get_b_track(); field->plant_transition(*trList.at(i), trList.at(i)->get_a_track(), trList.at(i)->get_b_track()); } qDeleteAll(trList); }
void mlt_field_disconnect_service( mlt_field self, mlt_service service ) { mlt_service p = mlt_service_producer( service ); mlt_service c = mlt_service_consumer( service); int i; switch ( mlt_service_identify(c) ) { case filter_type: i = mlt_filter_get_track( MLT_FILTER(c) ); mlt_service_connect_producer( c, p, i ); break; case transition_type: i = mlt_transition_get_a_track ( MLT_TRANSITION(c) ); mlt_service_connect_producer( c, p, i ); MLT_TRANSITION(c)->producer = p; break; case tractor_type: self->producer = p; mlt_tractor_connect( MLT_TRACTOR(c), p ); default: break; } mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); }
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); }
mlt_frame mlt_consumer_get_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the service assoicated to the consumer mlt_service service = MLT_CONSUMER_SERVICE( self ); // Get the consumer properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the frame if ( mlt_service_producer( service ) == NULL && mlt_properties_get_int( properties, "put_mode" ) ) { struct timeval now; struct timespec tm; pthread_mutex_lock( &self->put_mutex ); while ( self->put_active && self->put == NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &self->put_cond, &self->put_mutex, &tm ); } frame = self->put; self->put = NULL; pthread_cond_broadcast( &self->put_cond ); pthread_mutex_unlock( &self->put_mutex ); if ( frame != NULL ) mlt_service_apply_filters( service, frame, 0 ); } else if ( mlt_service_producer( service ) != NULL ) { mlt_service_get_frame( service, &frame, 0 ); } else { frame = mlt_frame_init( service ); } if ( frame != NULL ) { // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the test card producer mlt_producer test_card = mlt_properties_get_data( properties, "test_card_producer", NULL ); // Attach the test frame producer to it. if ( test_card != NULL ) mlt_properties_set_data( frame_properties, "test_card_producer", test_card, 0, NULL, NULL ); // Pass along the interpolation and deinterlace options // TODO: get rid of consumer_deinterlace and use profile.progressive mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) ); mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) ); mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "top_field_first" ) ); } // Return the frame return frame; }
void TransitionHandler::enableMultiTrack(bool enable) { int tracks = m_tractor->count(); if (tracks < 3) { // we need at leas 3 tracks (black bg track + 2 tracks to use this) return; } QScopedPointer<Mlt::Service> service(m_tractor->field()); QScopedPointer<Mlt::Field> field(m_tractor->field()); field->lock(); if (enable) { // disable track composition (frei0r.cairoblend) QScopedPointer<Mlt::Field> field(m_tractor->field()); mlt_service nextservice = mlt_service_get_producer(field->get_service()); mlt_service_type type = mlt_service_identify( nextservice ); while (type == transition_type) { Mlt::Transition transition((mlt_transition) nextservice); nextservice = mlt_service_producer(nextservice); int added = transition.get_int("internal_added"); if (added == 237) { QString mlt_service = transition.get("mlt_service"); if (mlt_service == QLatin1String("frei0r.cairoblend") && transition.get_int("disable") == 0) { transition.set("disable", 1); transition.set("split_disable", 1); } } if (nextservice == NULL) break; type = mlt_service_identify(nextservice); } for (int i = 1, screen = 0; i < tracks && screen < 4; ++i) { Mlt::Producer trackProducer(m_tractor->track(i)); if (QString(trackProducer.get("hide")).toInt() != 1) { Mlt::Transition transition(*m_tractor->profile(), "composite"); transition.set("mlt_service", "composite"); transition.set("a_track", 0); transition.set("b_track", i); transition.set("distort", 0); transition.set("aligned", 0); // 200 is an arbitrary number so we can easily remove these transition later transition.set("internal_added", 200); QString geometry; switch (screen) { case 0: geometry = QStringLiteral("0/0:50%x50%"); break; case 1: geometry = QStringLiteral("50%/0:50%x50%"); break; case 2: geometry = QStringLiteral("0/50%:50%x50%"); break; case 3: default: geometry = QStringLiteral("50%/50%:50%x50%"); break; } transition.set("geometry", geometry.toUtf8().constData()); transition.set("always_active", 1); field->plant_transition(transition, 0, i); screen++; } } } else { QScopedPointer<Mlt::Field> field(m_tractor->field()); mlt_service nextservice = mlt_service_get_producer(field->get_service()); mlt_service_type type = mlt_service_identify( nextservice ); while (type == transition_type) { Mlt::Transition transition((mlt_transition) nextservice); nextservice = mlt_service_producer(nextservice); int added = transition.get_int("internal_added"); if (added == 200) { field->disconnect_service(transition); } else if (added == 237) { // re-enable track compositing QString mlt_service = transition.get("mlt_service"); if (mlt_service == QLatin1String("frei0r.cairoblend") && transition.get_int("split_disable") == 1) { transition.set("disable", 0); transition.set("split_disable", (char*) NULL); } } if (nextservice == NULL) break; type = mlt_service_identify(nextservice); } } field->unlock(); emit refresh(); }
int mlt_parser_start( mlt_parser self, mlt_service object ) { int error = 0; mlt_service_type type = mlt_service_identify( object ); switch( type ) { case invalid_type: error = self->on_invalid( self, object ); break; case unknown_type: error = self->on_unknown( self, object ); break; case producer_type: if ( mlt_producer_is_cut( ( mlt_producer )object ) ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); error = self->on_start_producer( self, ( mlt_producer )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_producer( self, ( mlt_producer )object ); break; case playlist_type: error = self->on_start_playlist( self, ( mlt_playlist )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && i < mlt_playlist_count( ( mlt_playlist )object ) ) mlt_parser_start( self, ( mlt_service )mlt_playlist_get_clip( ( mlt_playlist )object, i ++ ) ); i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_playlist( self, ( mlt_playlist )object ); break; case tractor_type: error = self->on_start_tractor( self, ( mlt_tractor )object ); if ( error == 0 ) { int i = 0; mlt_service next = mlt_service_producer( object ); mlt_parser_start( self, ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ); while ( next != ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ) { mlt_parser_start( self, next ); next = mlt_service_producer( next ); } while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_tractor( self, ( mlt_tractor )object ); break; case multitrack_type: error = self->on_start_multitrack( self, ( mlt_multitrack )object ); if ( error == 0 ) { int i = 0; while ( i < mlt_multitrack_count( ( mlt_multitrack )object ) ) { self->on_start_track( self ); mlt_parser_start( self, ( mlt_service )mlt_multitrack_track( ( mlt_multitrack )object , i ++ ) ); self->on_end_track( self ); } i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_multitrack( self, ( mlt_multitrack )object ); break; case filter_type: error = self->on_start_filter( self, ( mlt_filter )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_filter( self, ( mlt_filter )object ); break; case transition_type: error = self->on_start_transition( self, ( mlt_transition )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_transition( self, ( mlt_transition )object ); break; case field_type: break; case consumer_type: break; } return error; }