int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Correct ins and outs if necessary if ( in < 0 ) in = 0; else if ( in >= mlt_producer_get_length( self ) ) in = mlt_producer_get_length( self ) - 1; if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( self ) - 1; else if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && mlt_producer_is_blank( self ) ) mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "length", out + 1 ); else if ( out < 0 ) out = 0; // Swap ins and outs if wrong if ( out < in ) { mlt_position t = in; in = out; out = t; } // Set the values mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", in ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", out ); return 0; }
mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ) { mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) ); mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent ); mlt_properties_set_lcnumeric( properties, mlt_properties_get_lcnumeric( MLT_PRODUCER_PROPERTIES( self ) ) ); mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) ); // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) if ( in <= 0 ) in = 0; if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( parent ) - 1; mlt_properties_inc_ref( parent_props ); mlt_properties_set_int( properties, "_cut", 1 ); mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) ); mlt_producer_set_in_and_out( result, in, out ); return result; }
static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child; mlt_position pos = mlt_producer_position( producer ); mlt_position end = mlt_producer_get_playtime( producer ); end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1; // Re-open if needed if ( !decklink && pos < end ) { producer->child = decklink = new DeckLinkProducer(); decklink->setProducer( producer ); decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) ); } // Start if needed if ( decklink ) { decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ); // Get the next frame from the decklink object if ( ( *frame = decklink->getFrame() )) { // Add audio and video getters mlt_frame_push_audio( *frame, (void*) get_audio ); mlt_frame_push_get_image( *frame, get_image ); } } if ( !*frame ) *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); // Close DeckLink if at end if ( pos >= end && decklink ) { decklink->stop(); delete decklink; producer->child = NULL; } return 0; }
static int producerGetImage(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int /*writable*/) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES(frame); mlt_producer producer = (mlt_producer)mlt_properties_get_data(properties, kWebVfxProducerPropertyName, NULL); mlt_properties producer_props = MLT_PRODUCER_PROPERTIES(producer); int size; int bpp; bool hasTransparency = false; { MLTWebVfx::ServiceLocker locker(MLT_PRODUCER_SERVICE(producer)); if (!locker.initialize(*width, *height)) return 1; if (mlt_properties_get_int( producer_props, "transparent") ) { *format = mlt_image_rgb24a; hasTransparency = true; } else { *format = mlt_image_rgb24; } // Get bpp from image format mlt_image_format_size(*format, 0, 0, &bpp); size = *width * *height * bpp; *buffer = (uint8_t*)mlt_pool_alloc(size); // When not using transparency, this will make the background black... memset( *buffer, 255, size ); WebVfx::Image outputImage(*buffer, *width, *height, size, hasTransparency); locker.getManager()->render(&outputImage, mlt_properties_get_position(properties, kWebVfxPositionPropertyName), mlt_producer_get_length(producer), hasTransparency); } mlt_frame_set_image(frame, *buffer, size, mlt_pool_release); if (hasTransparency) { // Create the alpha channel int alpha_size = *width * *height; uint8_t *alpha = (uint8_t *)mlt_pool_alloc( alpha_size ); // Initialise the alpha memset( alpha, 255, alpha_size ); mlt_frame_set_alpha(frame, alpha, alpha_size, mlt_pool_release); } return error; }
int main( int argc, char **argv ) { int i; mlt_consumer consumer = NULL; FILE *store = NULL; char *name = NULL; mlt_profile profile = NULL; int is_progress = 0; int is_silent = 0; mlt_profile backup_profile; // Handle abnormal exit situations. signal( SIGSEGV, abnormal_exit_handler ); signal( SIGILL, abnormal_exit_handler ); signal( SIGABRT, abnormal_exit_handler ); // Construct the factory mlt_repository repo = mlt_factory_init( NULL ); #if defined(WIN32) && !defined(MELT_NOSDL) is_silent = 1; #endif for ( i = 1; i < argc; i ++ ) { // Check for serialisation switch if ( !strcmp( argv[ i ], "-serialise" ) ) { name = argv[ ++ i ]; if ( name != NULL && strstr( name, ".melt" ) ) store = fopen( name, "w" ); else { if ( name == NULL || name[0] == '-' ) store = stdout; name = NULL; } } // Look for the profile option else if ( !strcmp( argv[ i ], "-profile" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) profile = mlt_profile_init( pname ); } else if ( !strcmp( argv[ i ], "-progress" ) ) { is_progress = 1; } else if ( !strcmp( argv[ i ], "-progress2" ) ) { is_progress = 2; } // Look for the query option else if ( !strcmp( argv[ i ], "-query" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) { if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) ) query_services( repo, consumer_type ); else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) ) query_services( repo, filter_type ); else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) ) query_services( repo, producer_type ); else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) ) query_services( repo, transition_type ); else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) ) query_profiles(); else if ( !strcmp( pname, "presets" ) || !strcmp( pname, "preset" ) ) query_presets(); else if ( !strncmp( pname, "format", 6 ) ) query_formats(); else if ( !strncmp( pname, "acodec", 6 ) || !strcmp( pname, "audio_codecs" ) ) query_acodecs(); else if ( !strncmp( pname, "vcodec", 6 ) || !strcmp( pname, "video_codecs" ) ) query_vcodecs(); else if ( !strncmp( pname, "consumer=", 9 ) ) query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "filter=", 7 ) ) query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "producer=", 9 ) ) query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "transition=", 11 ) ) query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "profile=", 8 ) ) query_profile( strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "preset=", 7 ) ) query_preset( strchr( pname, '=' ) + 1 ); else goto query_all; } else { query_all: query_services( repo, consumer_type ); query_services( repo, filter_type ); query_services( repo, producer_type ); query_services( repo, transition_type ); fprintf( stdout, "# You can query the metadata for a specific service using:\n" "# -query <type>=<identifer>\n" "# where <type> is one of: consumer, filter, producer, or transition.\n" ); } goto exit_factory; } else if ( !strcmp( argv[ i ], "-silent" ) ) { is_silent = 1; } else if ( !strcmp( argv[ i ], "-verbose" ) ) { mlt_log_set_level( MLT_LOG_VERBOSE ); } else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) ) { fprintf( stdout, "%s " VERSION "\n" "Copyright (C) 2002-2013 Ushodaya Enterprises Limited\n" "<http://www.mltframework.org/>\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", basename( argv[0] ) ); goto exit_factory; } else if ( !strcmp( argv[ i ], "-debug" ) ) { mlt_log_set_level( MLT_LOG_DEBUG ); } } if ( !is_silent && !isatty( STDIN_FILENO ) && !is_progress ) is_progress = 1; // Create profile if not set explicitly if ( getenv( "MLT_PROFILE" ) ) profile = mlt_profile_init( NULL ); if ( profile == NULL ) profile = mlt_profile_init( NULL ); else profile->is_explicit = 1; // Look for the consumer option to load profile settings from consumer properties backup_profile = mlt_profile_clone( profile ); load_consumer( &consumer, profile, argc, argv ); // If the consumer changed the profile, then it is explicit. if ( backup_profile && !profile->is_explicit && ( profile->width != backup_profile->width || profile->height != backup_profile->height || profile->sample_aspect_num != backup_profile->sample_aspect_num || profile->sample_aspect_den != backup_profile->sample_aspect_den || profile->frame_rate_den != backup_profile->frame_rate_den || profile->frame_rate_num != backup_profile->frame_rate_num || profile->colorspace != backup_profile->colorspace ) ) profile->is_explicit = 1; mlt_profile_close( backup_profile ); // Get melt producer if ( argc > 1 ) melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] ); if ( melt ) { // Generate an automatic profile if needed. if ( ! profile->is_explicit ) { mlt_profile_from_producer( profile, melt ); mlt_producer_close( melt ); melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] ); } // Reload the consumer with the fully qualified profile. // The producer or auto-profile could have changed the profile. load_consumer( &consumer, profile, argc, argv ); // See if producer has consumer already attached if ( !store && !consumer ) { consumer = MLT_CONSUMER( mlt_service_consumer( MLT_PRODUCER_SERVICE( melt ) ) ); if ( consumer ) { mlt_properties_inc_ref( MLT_CONSUMER_PROPERTIES(consumer) ); // because we explicitly close it mlt_properties_set_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_callback", transport_action, 0, NULL, NULL ); } } // If we have no consumer, default to sdl if ( store == NULL && consumer == NULL ) consumer = create_consumer( profile, NULL ); } // Set transport properties on consumer and produder if ( consumer != NULL && melt != NULL ) { mlt_properties_set_data( MLT_CONSUMER_PROPERTIES( consumer ), "transport_producer", melt, 0, NULL, NULL ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( melt ), "transport_consumer", consumer, 0, NULL, NULL ); if ( is_progress ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress", is_progress ); if ( is_silent ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent", is_silent ); } if ( argc > 1 && melt != NULL && mlt_producer_get_length( melt ) > 0 ) { // Parse the arguments for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-jack" ) ) { setup_jack_transport( consumer, profile ); } else if ( !strcmp( argv[ i ], "-serialise" ) ) { if ( store != stdout ) i ++; } else { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i ++; while ( argv[ i ] != NULL && argv[ i ][ 0 ] != '-' ) { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i += 1; } i --; } } if ( consumer != NULL && store == NULL ) { // Get melt's properties mlt_properties melt_props = MLT_PRODUCER_PROPERTIES( melt ); // Get the last group mlt_properties group = mlt_properties_get_data( melt_props, "group", 0 ); // Apply group settings mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_properties_inherit( properties, group ); // Connect consumer to melt mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE( melt ) ); // Start the consumer mlt_events_listen( properties, consumer, "consumer-fatal-error", ( mlt_listener )on_fatal_error ); if ( mlt_consumer_start( consumer ) == 0 ) { // Try to exit gracefully upon these signals signal( SIGINT, stop_handler ); signal( SIGTERM, stop_handler ); #ifndef WIN32 signal( SIGHUP, stop_handler ); signal( SIGPIPE, stop_handler ); #endif // Transport functionality transport( melt, consumer ); // Stop the consumer mlt_consumer_stop( consumer ); } } else if ( store != NULL && store != stdout && name != NULL ) { fprintf( stderr, "Project saved as %s.\n", name ); fclose( store ); } } else { show_usage( argv[0] ); } // Disconnect producer from consumer to prevent ref cycles from closing services if ( consumer ) { mlt_consumer_connect( consumer, NULL ); mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-cleanup", NULL); } // Close the producer if ( melt != NULL ) mlt_producer_close( melt ); // Close the consumer if ( consumer != NULL ) mlt_consumer_close( consumer ); // Close the factory mlt_profile_close( profile ); exit_factory: // Workaround qmelt on OS X from crashing at exit. #if !defined(__MACH__) || !defined(QT_GUI_LIB) mlt_factory_close( ); #endif return 0; }
static void transport( mlt_producer producer, mlt_consumer consumer ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); int silent = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent" ); int progress = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress" ); struct timespec tm = { 0, 40000000 }; int total_length = mlt_producer_get_length( producer ); int last_position = 0; if ( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) ) { if ( !silent && !progress ) { term_init( ); fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" ); fprintf( stderr, "|1=-10| |2= -5| |3= -2| |4= -1| |5= 0| |6= 1| |7= 2| |8= 5| |9= 10|\n" ); fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" ); fprintf( stderr, "+---------------------------------------------------------------------+\n" ); fprintf( stderr, "| H = back 1 minute, L = forward 1 minute |\n" ); fprintf( stderr, "| h = previous frame, l = next frame |\n" ); fprintf( stderr, "| g = start of clip, j = next clip, k = previous clip |\n" ); fprintf( stderr, "| 0 = restart, q = quit, space = play |\n" ); fprintf( stderr, "+---------------------------------------------------------------------+\n" ); } while( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) ) { int value = ( silent || progress )? -1 : term_read( ); if ( value != -1 ) { char string[ 2 ] = { value, 0 }; transport_action( producer, string ); } #if (defined(__DARWIN__) || defined(WIN32)) && !defined(MELT_NOSDL) event_handling( producer, consumer ); #endif if ( !silent && mlt_properties_get_int( properties, "stats_off" ) == 0 ) { if ( progress ) { int current_position = mlt_producer_position( producer ); if ( current_position > last_position ) { fprintf( stderr, "Current Frame: %10d, percentage: %10d%c", current_position, 100 * current_position / total_length, progress == 2 ? '\n' : '\r' ); last_position = current_position; } } else { fprintf( stderr, "Current Position: %10d\r", (int)mlt_consumer_position( consumer ) ); } fflush( stderr ); } if ( silent || progress ) nanosleep( &tm, NULL ); } if ( !silent ) fprintf( stderr, "\n" ); } }
mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { if ( !arg ) return NULL; mlt_producer producer = NULL; producer = calloc( 1, sizeof( struct mlt_producer_s ) ); mlt_producer_init( producer, NULL ); // Wrap loader mlt_producer real_producer; // Check if a speed was specified. /** * Speed must be appended to the filename with '?'. To play your video at 50%: melt framebuffer:my_video.mpg?0.5 * Stroboscope effect can be obtained by adding a stobe=x parameter, where x is the number of frames that will be ignored. * You can play the movie backwards by adding reverse=1 * You can freeze the clip at a determined position by adding freeze=frame_pos add freeze_after=1 to freeze only paste position or freeze_before to freeze before it **/ double speed = 0.0; char *props = strdup( arg ); char *ptr = strrchr( props, '?' ); if ( ptr ) { speed = atof( ptr + 1 ); if ( speed != 0.0 ) // If speed was valid, then strip it and the delimiter. // Otherwise, an invalid speed probably means this '?' was not a delimiter. *ptr = '\0'; } real_producer = mlt_factory_producer( profile, "abnormal", props ); free( props ); if (speed == 0.0) speed = 1.0; if ( producer != NULL && real_producer != NULL) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "resource", arg); // Store the producer and fitler mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Grab some stuff from the real_producer mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "length, width, height, aspect_ratio" ); if ( speed < 0 ) { speed = -speed; mlt_properties_set_int( properties, "reverse", 1 ); } if ( speed != 1.0 ) { double real_length = ( (double) mlt_producer_get_length( real_producer ) ) / speed; mlt_properties_set_position( properties, "length", real_length ); } mlt_properties_set_position( properties, "out", mlt_producer_get_length( producer ) - 1 ); // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( real_producer, 0 ); mlt_producer_set_speed( producer, speed ); // Override the get_frame method producer->get_frame = producer_get_frame; } else { if ( producer ) mlt_producer_close( producer ); if ( real_producer ) mlt_producer_close( real_producer ); producer = NULL; } return producer; }
void VideoScript::pre_judge() throw (Exception) { const ScriptParam* inparam = get_param_info("in"); const ScriptParam* outparam = get_param_info("out"); const ScriptParam* resparam = get_param_info("resource"); if ( !inparam || inparam->param_style != ScriptParams::PosParam || !outparam || outparam->param_style != ScriptParams::PosParam) { throw_error_v(ErrorScriptArgInvalid, "in/out position param is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } if ( !resparam || resparam->param_style != ScriptParams::ScalarParam ) { throw_error_v(ErrorScriptArgInvalid, "resource scalar param is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } json_t* res_arg = get_arg_value("resource"); json_t* in = get_arg_value("in"); json_t* out = get_arg_value("out"); if (!res_arg || !json_is_string(res_arg) || !strlen(json_string_value(res_arg))) { throw_error_v(ErrorScriptArgInvalid, "resource arg is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } if ( !in || !json_is_integer(in) ) { throw_error_v(ErrorScriptArgInvalid, "in arg is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } if ( !out || !json_is_integer(out) ) { throw_error_v(ErrorScriptArgInvalid, "out arg is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } string path(json_string_value(res_arg)); mlt_profile profile = mlt_profile_clone(MltLoader::global_profile); mlt_producer prod = mlt_factory_producer(profile, "loader", path.c_str()); if ( prod == NULL ) { throw_error_v(ErrorScriptArgInvalid, "out arg is required for %s script", Vm::proc_type_names[VIDEO_RESOURCE_SCRIPT]); } uuid = Vm::uuid(); MltLoader::push_mlt_registry(mlt_producer_service(prod), uuid.c_str()); //mlt_producer prod = Vm::get_stream_resource(path); int length = mlt_producer_get_length(prod); int inframe = json_integer_value(in), outframe = json_integer_value(out); json_decref(in); json_decref(out); switch (inparam->pos_type) { case ScriptParams::FramePos: if ( inframe == -1 || inframe >= length) { inframe = length - 1; } else if ( inframe < 0 ) { inframe = length + inframe; if (inframe < 0)inframe = 0; } break; case ScriptParams::TimePos: { int total_time = length * 40; if ( inframe == -1 ) { inframe = length - 1; } else if ( inframe >= 0 ) { if ( inframe > total_time) { inframe = length -1; } else { inframe = (double)inframe / 40 ; } } else { inframe = total_time + inframe; if ( inframe < 0 ) { inframe = length - 1; } else { inframe = (double)inframe/40; } } } break; } switch (outparam->pos_type) { case ScriptParams::FramePos: if ( outframe == -1 || outframe >= length) { outframe = length - 1; } else if ( outframe < 0 ) { outframe = length + outframe; if (outframe < 0)outframe = 0; } break; case ScriptParams::TimePos: { int total_time = length * 40; if ( outframe == -1 ) { outframe = length - 1; } else if ( outframe >= 0 ) { if ( outframe > total_time) { outframe = length -1; } else { outframe = (double)outframe / 40 ; } } else { outframe = total_time + outframe; if ( outframe < 0 ) { outframe = length - 1; } else { outframe = (double)outframe/40; } } } break; } if ( inframe > outframe ) { inframe ^= outframe ^= inframe ^= outframe; } set_frame_range(inframe,outframe); if ( !type_spec_props.get() ) { type_spec_props.reset(new ScriptProps(*this, NULL)); } type_spec_props->add_property("resource", res_arg); json_decref(res_arg); type_spec_props->add_property("uuid", JsonWrap(json_string(uuid.c_str()),1).h); if ( !mlt_props.get()) { mlt_props.reset(new ScriptProps(*this, NULL)); } json_t* jv = json_integer(inframe); mlt_props->add_property("in", jv); json_decref(jv); jv = json_integer(outframe); mlt_props->add_property("out", jv); json_decref(jv); //mlt_producer_set_in_and_out(prod, inframe, outframe); #ifdef DEBUG std::cout << mlt_producer_properties(prod); #endif this->path = path; //todo: check format info return; }
int inigo( int argc, char **argv ) { int i; mlt_consumer consumer = NULL; mlt_producer melt = NULL; FILE *store = NULL; char *name = NULL; mlt_profile profile = NULL; int is_progress = 0; int is_silent = 0; // Construct the factory mlt_repository repo = mlt_factory_init( NULL ); for ( i = 1; i < argc; i ++ ) { // fprintf(stderr, "argv[%d] = %s\n", i, argv[i]); // Check for serialisation switch if ( !strcmp( argv[ i ], "-serialise" ) ) { name = argv[ ++ i ]; if ( name != NULL && strstr( name, ".melt" ) ) store = fopen( name, "w" ); else { if ( name == NULL || name[0] == '-' ) store = stdout; name = NULL; } } // Look for the profile option else if ( !strcmp( argv[ i ], "-profile" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) profile = mlt_profile_init( pname ); } else if ( !strcmp( argv[ i ], "-progress" ) ) { is_progress = 1; } // Look for the query option else if ( !strcmp( argv[ i ], "-query" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) { if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) ) query_services( repo, consumer_type ); else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) ) query_services( repo, filter_type ); else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) ) query_services( repo, producer_type ); else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) ) query_services( repo, transition_type ); else if ( !strncmp( pname, "consumer=", 9 ) ) query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "filter=", 7 ) ) query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "producer=", 9 ) ) query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "transition=", 11 ) ) query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); else goto query_all; } else { query_all: query_services( repo, consumer_type ); query_services( repo, filter_type ); query_services( repo, producer_type ); query_services( repo, transition_type ); fprintf( stderr, "# You can query the metadata for a specific service using:\n" "# -query <type>=<identifer>\n" "# where <type> is one of: consumer, filter, producer, or transition.\n" ); } goto exit_factory; } else if ( !strcmp( argv[ i ], "-silent" ) ) { is_silent = 1; } else if ( !strcmp( argv[ i ], "-verbose" ) ) { mlt_log_set_level( MLT_LOG_VERBOSE ); } else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) ) { fprintf( stderr, "MLT %s 0.5\n" "Copyright (C) 2002-2009 Ushodaya Enterprises Limited\n" "<http://www.mltframework.org/>\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", basename( argv[0] ) ); goto exit_factory; } else if ( !strcmp( argv[ i ], "-debug" ) ) { mlt_log_set_level( MLT_LOG_DEBUG ); } } // Create profile if not set explicitly if ( profile == NULL ) profile = mlt_profile_init( NULL ); // Look for the consumer option for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-consumer" ) ) { consumer = create_consumer( profile, argv[ ++ i ] ); if ( consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); while ( argv[ i + 1 ] != NULL && strstr( argv[ i + 1 ], "=" ) ) mlt_properties_parse( properties, argv[ ++ i ] ); } } } // If we have no consumer, default to sdl if ( store == NULL && consumer == NULL ) consumer = create_consumer( profile, NULL ); // Get melt producer if ( argc > 1 ) melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] ); // Set transport properties on consumer and produder if ( consumer != NULL && melt != NULL ) { mlt_properties_set_data( MLT_CONSUMER_PROPERTIES( consumer ), "transport_producer", melt, 0, NULL, NULL ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( melt ), "transport_consumer", consumer, 0, NULL, NULL ); if ( is_progress ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress", is_progress ); if ( is_silent ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent", is_silent ); } if ( argc > 1 && melt != NULL && mlt_producer_get_length( melt ) > 0 ) { // Parse the arguments for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-serialise" ) ) { if ( store != stdout ) i ++; } else { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i ++; while ( argv[ i ] != NULL && argv[ i ][ 0 ] != '-' ) { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i += 1; } i --; } } if ( consumer != NULL && store == NULL ) { // Get melt's properties mlt_properties melt_props = MLT_PRODUCER_PROPERTIES( melt ); // Get the last group mlt_properties group = mlt_properties_get_data( melt_props, "group", 0 ); // Apply group settings mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_properties_inherit( properties, group ); // Connect consumer to melt mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE( melt ) ); // Start the consumer mlt_consumer_start( consumer ); // Transport functionality transport( melt, consumer ); // Stop the consumer mlt_consumer_stop( consumer ); } else if ( store != NULL && store != stdout && name != NULL ) { fprintf( stderr, "Project saved as %s.\n", name ); fclose( store ); } } else { fprintf( stderr, "Usage: %s [options] [producer [name=value]* ]+\n" "Options:\n" " -attach filter[:arg] [name=value]* Attach a filter to the output\n" " -attach-cut filter[:arg] [name=value]* Attach a filter to a cut\n" " -attach-track filter[:arg] [name=value]* Attach a filter to a track\n" " -attach-clip filter[:arg] [name=value]* Attach a filter to a producer\n" " -audio-track | -hide-video Add an audio-only track\n" " -blank frames Add blank silence to a track\n" " -consumer id[:arg] [name=value]* Set the consumer (sink)\n" " -debug Set the logging level to debug\n" " -filter filter[:arg] [name=value]* Add a filter to the current track\n" " -group [name=value]* Apply properties repeatedly\n" " -help Show this message\n" " -join clips Join multiple clips into one cut\n" " -mix length Add a mix between the last two cuts\n" " -mixer transition Add a transition to the mix\n" " -null-track | -hide-track Add a hidden track\n" " -profile name Set the processing settings\n" " -progress Display progress along with position\n" " -remove Remove the most recent cut\n" " -repeat times Repeat the last cut\n" " -query List all of the registered services\n" " -query \"consumers\" | \"consumer\"=id List consumers or show info about one\n" " -query \"filters\" | \"filter\"=id List filters or show info about one\n" " -query \"producers\" | \"producer\"=id List producers or show info about one\n" " -query \"transitions\" | \"transition\"=id List transitions, show info about one\n" " -serialise [filename] Write the commands to a text file\n" " -silent Do not display position/transport\n" " -split relative-frame Split the last cut into two cuts\n" " -swap Rearrange the last two cuts\n" " -track Add a track\n" " -transition id[:arg] [name=value]* Add a transition\n" " -verbose Set the logging level to verbose\n" " -version Show the version and copyright\n" " -video-track | -hide-audio Add a video-only track\n" "For more help: <http://www.mltframework.org/>\n", basename( argv[0] ) ); } // Close the producer if ( melt != NULL ) mlt_producer_close( melt ); // Close the consumer if ( consumer != NULL ) mlt_consumer_close( consumer ); // Close the factory mlt_profile_close( profile ); exit_factory: mlt_factory_close( ); return 0; }