int main( int argc, char **argv ) { char temp[ 132 ]; char *file1 = NULL; char *file2 = NULL; char *wipe = NULL; mlt_factory_init( "../modules" ); if ( argc < 4 ) { fprintf( stderr, "usage: luma file1.mpeg file2.mpeg wipe.pgm\n" ); return 1; } else { file1 = argv[ 1 ]; file2 = argv[ 2 ]; wipe = argv[ 3 ]; } // Start the consumer... mlt_consumer consumer = mlt_factory_consumer( "bluefish", "NTSC" ); // Create the producer(s) mlt_producer dv1 = mlt_factory_producer( "mcmpeg", file1 ); mlt_producer dv2 = mlt_factory_producer( "mcmpeg", file2 ); mlt_playlist playlist1 = mlt_playlist_init(); mlt_playlist_append_io( playlist1, dv1, 0.0, 5.0 ); mlt_playlist playlist2 = mlt_playlist_init(); mlt_playlist_blank( playlist2, 2.9 ); mlt_playlist_append( playlist2, dv2 ); // Register producers(s) with a multitrack object mlt_multitrack multitrack = mlt_multitrack_init( ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist1 ), 0 ); mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist2 ), 1 ); // Define a transition mlt_transition transition = mlt_factory_transition( "luma", wipe ); mlt_properties_set( mlt_transition_properties( transition ), "filename", wipe ); mlt_properties_set_double( mlt_transition_properties( transition ), "softness", 0.1 ); mlt_transition_connect( transition, mlt_multitrack_service( multitrack ), 0, 1 ); mlt_transition_set_in_and_out( transition, 3.0, 5.0 ); // Buy a tractor and connect it to the filter mlt_tractor tractor = mlt_tractor_init( ); mlt_tractor_connect( tractor, mlt_transition_service( transition ) ); // Connect the tractor to the consumer mlt_consumer_connect( consumer, mlt_tractor_service( tractor ) ); // Do stuff until we're told otherwise... fprintf( stderr, "Press return to continue\n" ); fgets( temp, 132, stdin ); // Close everything... mlt_consumer_close( consumer ); mlt_tractor_close( tractor ); mlt_transition_close( transition ); mlt_multitrack_close( multitrack ); mlt_playlist_close( playlist1 ); mlt_playlist_close( playlist2 ); mlt_producer_close( dv1 ); mlt_producer_close( dv2 ); return 0; }
static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object and properties mlt_producer producer = mlt_frame_pop_service( frame ); int index = ( int )mlt_frame_pop_service( frame ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Frame properties objects mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); // Get producer parameters int strobe = mlt_properties_get_int( properties, "strobe" ); int freeze = mlt_properties_get_int( properties, "freeze" ); int freeze_after = mlt_properties_get_int( properties, "freeze_after" ); int freeze_before = mlt_properties_get_int( properties, "freeze_before" ); int in = mlt_properties_get_position( properties, "in" ); // Determine the position mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1; mlt_position need_first = freeze; if ( !freeze || freeze_after || freeze_before ) { double prod_speed = mlt_properties_get_double( properties, "_speed" ); double actual_position = in + prod_speed * (double) mlt_producer_position( producer ); if ( mlt_properties_get_int( properties, "reverse" ) ) actual_position = mlt_producer_get_playtime( producer ) - actual_position; if ( strobe < 2 ) { need_first = floor( actual_position ); } else { // Strobe effect wanted, calculate frame position need_first = floor( actual_position ); need_first -= need_first % strobe; } if ( freeze ) { if ( freeze_after && need_first > freeze ) need_first = freeze; else if ( freeze_before && need_first < freeze ) need_first = freeze; } } // Determine output buffer size *width = mlt_properties_get_int( frame_properties, "width" ); *height = mlt_properties_get_int( frame_properties, "height" ); int size = mlt_image_format_size( *format, *width, *height, NULL ); // Get output buffer int buffersize = 0; int alphasize = *width * *height; uint8_t *output = mlt_properties_get_data( properties, "output_buffer", &buffersize ); uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL ); if( buffersize == 0 || buffersize != size ) { // invalidate cached frame first_position = -1; } if ( need_first != first_position ) { // invalidate cached frame first_position = -1; // Bust the cached frame mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL ); first_frame = NULL; } if ( output && first_position != -1 ) { // Using the cached frame uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, output, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, output_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, image_copy, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); *width = mlt_properties_get_int( properties, "_output_width" ); *height = mlt_properties_get_int( properties, "_output_height" ); *format = mlt_properties_get_int( properties, "_output_format" ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return 0; } // Get the cached frame if ( first_frame == NULL ) { // Get the frame to cache from the real producer mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); // Seek the producer to the correct place mlt_producer_seek( real_producer, need_first ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); // Cache the frame mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame ); // Which frames are buffered? uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL ); if ( !first_image ) { mlt_properties_set( first_frame_properties, "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); if ( error != 0 ) { mlt_log_error( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return error; } output = mlt_pool_alloc( size ); memcpy( output, first_image, size ); // Let someone else clean up mlt_properties_set_data( properties, "output_buffer", output, size, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_output_width", *width ); mlt_properties_set_int( properties, "_output_height", *height ); mlt_properties_set_int( properties, "_output_format", *format ); } if ( !first_alpha ) { alphasize = *width * *height; first_alpha = mlt_frame_get_alpha_mask( first_frame ); output_alpha = mlt_pool_alloc( alphasize ); memcpy( output_alpha, first_alpha, alphasize ); mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create a copy uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, first_image, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, first_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, *image, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); return 0; }
static void load_consumer( mlt_consumer *consumer, mlt_profile profile, int argc, char **argv ) { int i; int multi = 0; int qglsl = 0; for ( i = 1; i < argc; i ++ ) { // See if we need multi consumer. multi += !strcmp( argv[i], "-consumer" ); // Seee if we need the qglsl variant of multi consumer. if ( !strncmp( argv[i], "glsl.", 5 ) || !strncmp( argv[i], "movit.", 6 ) ) qglsl = 1; } // Disable qglsl if xgl is being used! for ( i = 1; qglsl && i < argc; i ++ ) if ( !strcmp( argv[i], "xgl" ) ) qglsl = 0; if ( multi > 1 || qglsl ) { // If there is more than one -consumer use the 'multi' consumer. int k = 0; char key[20]; if ( *consumer ) mlt_consumer_close( *consumer ); *consumer = create_consumer( profile, ( qglsl? "qglsl" : "multi" ) ); mlt_properties properties = MLT_CONSUMER_PROPERTIES( *consumer ); for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-consumer" ) && argv[ i + 1 ]) { // Create a properties object for each sub-consumer mlt_properties new_props = mlt_properties_new(); snprintf( key, sizeof(key), "%d", k++ ); mlt_properties_set_data( properties, key, new_props, 0, (mlt_destructor) mlt_properties_close, NULL ); if ( strchr( argv[i + 1], ':' ) ) { char *temp = strdup( argv[++i] ); char *service = temp; char *target = strchr( temp, ':' ); *target++ = 0; mlt_properties_set( new_props, "mlt_service", service ); mlt_properties_set( new_props, "target", target ); } else { mlt_properties_set( new_props, "mlt_service", argv[ ++i ] ); } while ( argv[ i + 1 ] && strchr( argv[ i + 1 ], '=' ) ) mlt_properties_parse( new_props, argv[ ++ i ] ); } } } else for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-consumer" ) ) { if ( *consumer ) mlt_consumer_close( *consumer ); *consumer = create_consumer( profile, argv[ ++ i ] ); if ( *consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( *consumer ); while ( argv[ i + 1 ] != NULL && strchr( argv[ i + 1 ], '=' ) ) mlt_properties_parse( properties, argv[ ++ i ] ); } } } }
void AsisScript::pre_judge() throw (Exception) { ScriptProps::Property& service_prop = type_spec_props->get_property("service"); if (!service_prop.Evaluable::finished()) throw_error_v(ErrorScriptFmtError,"asis producer script service should be determinated"); ScriptProps::Property& resource_prop = type_spec_props->get_property("resource"); if (!resource_prop.Evaluable::finished()) throw_error_v(ErrorScriptFmtError,"asis producer script resource should be determinated"); json_t* svc_value = service_prop.compile(); json_t* res_value = resource_prop.compile(); JsonWrap svc_wrap(svc_value,1); JsonWrap res_wrap(res_value,1); if ( !svc_value || !json_is_string(svc_value) || !strlen(json_string_value(svc_value))) throw_error_v(ErrorScriptFmtError,"asis producer script service should be string value"); if ( !res_value || !json_is_string(res_value) || !strlen(json_string_value(res_value))) throw_error_v(ErrorScriptFmtError,"asis producer script resource should be string value"); mlt_profile prof = mlt_profile_clone(MltLoader::global_profile); mlt_producer tmp_prod = mlt_factory_producer(prof, json_string_value(svc_value), json_string_value(res_value)); MltSvcWrap prod_wrap(mlt_producer_service(tmp_prod), 1); if (tmp_prod == NULL) { throw_error_v(ErrorRuntimeLoadFailed, "producer %s load failed", json_string_value(svc_value)); } if ( mlt_props ) { ScriptProps::PropIter it = mlt_props->begin(); for ( ; it!=mlt_props->end(); it++) { if ( it->second->Evaluable::finished() ) { json_t* prop_v = it->second->compile(); JsonWrap prop_wrap(prop_v, 1); switch(prop_v->type) { case JSON_INTEGER: mlt_properties_set_int64(mlt_producer_properties(tmp_prod), it->first.c_str(), json_integer_value(prop_v)); break; case JSON_REAL: mlt_properties_set_double(mlt_producer_properties(tmp_prod), it->first.c_str(), json_real_value(prop_v)); break; case JSON_STRING: mlt_properties_set(mlt_producer_properties(tmp_prod), it->first.c_str(), json_string_value(prop_v)); break; case JSON_TRUE: mlt_properties_set_int(mlt_producer_properties(tmp_prod), it->first.c_str(), 1); break; case JSON_FALSE: mlt_properties_set_int(mlt_producer_properties(tmp_prod), it->first.c_str(), 0); break; default: throw_error_v(ErrorRuntimeLoadFailed, "producer %s load failed. %s prop invalid", json_string_value(svc_value), it->first.c_str()); } } } } int in = mlt_producer_get_in(tmp_prod); int out = mlt_producer_get_out(tmp_prod); set_frame_range(in, out); if ( !mlt_props.get()) { mlt_props.reset(new ScriptProps(*this, NULL)); } json_t* jv = json_integer(in); mlt_props->add_property("in", jv); json_decref(jv); jv = json_integer(out); mlt_props->add_property("out", jv); json_decref(jv); string uuid = Vm::uuid(); type_spec_props->add_property("uuid", JsonWrap(json_string(uuid.c_str()),1).h); prod_wrap.obj = NULL; MltLoader::push_mlt_registry(mlt_producer_service(tmp_prod), uuid.c_str()); }
static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int result = 1; mlt_producer self = service != NULL ? service->child : NULL; if ( self != NULL && !mlt_producer_is_cut( self ) ) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine eof handling char *eof = mlt_properties_get( MLT_PRODUCER_PROPERTIES( self ), "eof" ); // Get the speed of the producer double speed = mlt_producer_get_speed( self ); // We need to use the clone if it's specified mlt_producer clone = mlt_properties_get_data( properties, "use_clone", NULL ); // If no clone is specified, use self clone = clone == NULL ? self : clone; // A properly instatiated producer will have a get_frame method... if ( self->get_frame == NULL || ( eof && !strcmp( eof, "continue" ) && mlt_producer_position( self ) > mlt_producer_get_out( self ) ) ) { // Generate a test frame *frame = mlt_frame_init( service ); // Set the position result = mlt_frame_set_position( *frame, mlt_producer_position( self ) ); // Mark as a test card mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 1 ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", 1 ); // Calculate the next position mlt_producer_prepare_next( self ); } else { // Get the frame from the implementation result = self->get_frame( clone, frame, index ); } // Copy the fps and speed of the producer onto the frame properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_double( properties, "_speed", speed ); mlt_properties_set_int( properties, "test_audio", mlt_frame_is_test_audio( *frame ) ); mlt_properties_set_int( properties, "test_image", mlt_frame_is_test_card( *frame ) ); if ( mlt_properties_get_data( properties, "_producer", NULL ) == NULL ) mlt_properties_set_data( properties, "_producer", service, 0, NULL, NULL ); } else if ( self != NULL ) { // Get the speed of the cut double speed = mlt_producer_get_speed( self ); // Get the parent of the cut mlt_producer parent = mlt_producer_cut_parent( self ); // Get the properties of the parent mlt_properties parent_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the properties of the cut mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine the clone index int clone_index = mlt_properties_get_int( properties, "_clone" ); // Determine the clone to use mlt_producer clone = self; if ( clone_index > 0 ) { char key[ 25 ]; sprintf( key, "_clone.%d", clone_index - 1 ); clone = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), key, NULL ); if ( clone == NULL ) mlt_log( service, MLT_LOG_ERROR, "requested clone doesn't exist %d\n", clone_index ); clone = clone == NULL ? self : clone; } else { clone = parent; } // We need to seek to the correct position in the clone mlt_producer_seek( clone, mlt_producer_get_in( self ) + mlt_properties_get_int( properties, "_position" ) ); // Assign the clone property to the parent mlt_properties_set_data( parent_properties, "use_clone", clone, 0, NULL, NULL ); // Now get the frame from the parents service result = mlt_service_get_frame( MLT_PRODUCER_SERVICE( parent ), frame, index ); // We're done with the clone now mlt_properties_set_data( parent_properties, "use_clone", NULL, 0, NULL, NULL ); // This is useful and required by always_active transitions to determine in/out points of the cut if ( mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", NULL ) == MLT_PRODUCER_SERVICE( parent ) ) mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", self, 0, NULL, NULL ); mlt_properties_set_double( MLT_FRAME_PROPERTIES( *frame ), "_speed", speed ); mlt_producer_prepare_next( self ); } else { *frame = mlt_frame_init( service ); result = 0; } // Pass on all meta properties from the producer/cut on to the frame if ( *frame != NULL && self != NULL ) { int i = 0; mlt_properties p_props = MLT_PRODUCER_PROPERTIES( self ); mlt_properties f_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_lock( p_props ); int count = mlt_properties_count( p_props ); for ( i = 0; i < count; i ++ ) { char *name = mlt_properties_get_name( p_props, i ); if ( !strncmp( name, "meta.", 5 ) ) mlt_properties_set( f_props, name, mlt_properties_get_value( p_props, i ) ); else if ( !strncmp( name, "set.", 4 ) ) mlt_properties_set( f_props, name + 4, mlt_properties_get_value( p_props, i ) ); } mlt_properties_unlock( p_props ); } return result; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Error we will return int error = 0; // Get the watermark filter object mlt_filter this = mlt_frame_pop_service( frame ); // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_service_lock( MLT_FILTER_SERVICE( this ) ); // Get the producer from the filter mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Get the composite from the filter mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Get the resource to use char *resource = mlt_properties_get( properties, "resource" ); // Get the old resource char *old_resource = mlt_properties_get( properties, "_old_resource" ); // Create a composite if we don't have one if ( composite == NULL ) { // Create composite via the factory mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); composite = mlt_factory_transition( profile, "composite", NULL ); // Register the composite for reuse/destruction if ( composite != NULL ) mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); } // If we have one if ( composite != NULL ) { // Get the properties mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); // Pass all the composite. properties on the filter down mlt_properties_pass( composite_properties, properties, "composite." ); if ( mlt_properties_get( properties, "composite.out" ) == NULL ) mlt_properties_set_int( composite_properties, "out", mlt_properties_get_int( properties, "_out" ) ); // Force a refresh mlt_properties_set_int( composite_properties, "refresh", 1 ); } // Create a producer if don't have one if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Create the producer mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Register the producer for reuse/destruction mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Set the old resource mlt_properties_set( properties, "_old_resource", resource ); } } if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Now pass all producer. properties on the filter down mlt_properties_pass( producer_properties, properties, "producer." ); } mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); // Only continue if we have both producer and composite if ( composite != NULL && producer != NULL ) { // Get the service of the producer mlt_service service = MLT_PRODUCER_SERVICE( producer ); // We will get the 'b frame' from the producer mlt_frame b_frame = NULL; // Get the original producer position mlt_position position = mlt_filter_get_position( this, frame ); // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); // Resetting position to appease the composite transition mlt_frame_set_position( frame, position ); // Get the b frame and process with composite if successful if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 ) { // Get the a and b frame properties mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); mlt_profile profile = mlt_service_profile( service ); // Set the b frame to be in the same position and have same consumer requirements mlt_frame_set_position( b_frame, position ); mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); // Check for the special case - no aspect ratio means no problem :-) if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( profile ) ); if ( mlt_frame_get_aspect_ratio( frame ) == 0 ) mlt_frame_set_aspect_ratio( frame, mlt_profile_sar( profile ) ); if ( mlt_properties_get_int( properties, "distort" ) ) { mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( composite ), "distort", 1 ); mlt_properties_set_int( a_props, "distort", 1 ); mlt_properties_set_int( b_props, "distort", 1 ); } *format = mlt_image_yuv422; if ( mlt_properties_get_int( properties, "reverse" ) == 0 ) { // Apply all filters that are attached to this filter to the b frame mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); // Process the frame mlt_transition_process( composite, frame, b_frame ); // Get the image error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } else { char temp[ 132 ]; int count = 0; uint8_t *alpha = NULL; const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( rescale == NULL || !strcmp( rescale, "none" ) ) rescale = "hyper"; mlt_transition_process( composite, b_frame, frame ); mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); mlt_properties_set( a_props, "rescale.interp", rescale ); mlt_properties_set( b_props, "rescale.interp", rescale ); mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); error = mlt_frame_get_image( b_frame, image, format, width, height, 1 ); alpha = mlt_frame_get_alpha_mask( b_frame ); mlt_frame_set_image( frame, *image, *width * *height * 2, NULL ); mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); mlt_properties_set_int( a_props, "progressive", 1 ); mlt_properties_inc_ref( b_props ); strcpy( temp, "_b_frame" ); while( mlt_properties_get_data( a_props, temp, NULL ) != NULL ) sprintf( temp, "_b_frame%d", count ++ ); mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } } // Close the b frame mlt_frame_close( b_frame ); } else { // Get the image from the frame without running fx error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } return error; }
mlt_producer producer_pango_init( const char *filename ) { producer_pango this = calloc( sizeof( struct producer_pango_s ), 1 ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; pthread_mutex_lock( &pango_mutex ); if ( fontmap == NULL ) fontmap = (PangoFT2FontMap*) pango_ft2_font_map_new(); g_type_init(); pthread_mutex_unlock( &pango_mutex ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); // Set the default properties mlt_properties_set( properties, "fgcolour", "0xffffffff" ); mlt_properties_set( properties, "bgcolour", "0x00000000" ); mlt_properties_set( properties, "olcolour", "0x00000000" ); mlt_properties_set_int( properties, "align", pango_align_left ); mlt_properties_set_int( properties, "pad", 0 ); mlt_properties_set_int( properties, "outline", 0 ); mlt_properties_set( properties, "text", "" ); mlt_properties_set( properties, "font", NULL ); mlt_properties_set( properties, "family", "Sans" ); mlt_properties_set_int( properties, "size", 48 ); mlt_properties_set( properties, "style", "normal" ); mlt_properties_set( properties, "encoding", "UTF-8" ); mlt_properties_set_int( properties, "weight", PANGO_WEIGHT_NORMAL ); mlt_properties_set_int( properties, "seekable", 1 ); if ( filename == NULL || ( filename && ( !strcmp( filename, "" ) // workaround for old kdenlive countdown generator || strstr( filename, "<producer>" ) ) ) ) { mlt_properties_set( properties, "markup", "" ); } else if ( filename[ 0 ] == '+' || strstr( filename, "/+" ) ) { char *copy = strdup( filename + 1 ); char *markup = copy; if ( strstr( markup, "/+" ) ) markup = strstr( markup, "/+" ) + 2; ( *strrchr( markup, '.' ) ) = '\0'; while ( strchr( markup, '~' ) ) ( *strchr( markup, '~' ) ) = '\n'; mlt_properties_set( properties, "resource", filename ); mlt_properties_set( properties, "markup", markup ); free( copy ); } else if ( strstr( filename, ".mpl" ) ) { int i = 0; mlt_properties contents = mlt_properties_load( filename ); mlt_geometry key_frames = mlt_geometry_init( ); struct mlt_geometry_item_s item; mlt_properties_set( properties, "resource", filename ); mlt_properties_set_data( properties, "contents", contents, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set_data( properties, "key_frames", key_frames, 0, ( mlt_destructor )mlt_geometry_close, NULL ); // Make sure we have at least one entry if ( mlt_properties_get( contents, "0" ) == NULL ) mlt_properties_set( contents, "0", "" ); for ( i = 0; i < mlt_properties_count( contents ); i ++ ) { char *name = mlt_properties_get_name( contents, i ); char *value = mlt_properties_get_value( contents, i ); while ( value != NULL && strchr( value, '~' ) ) ( *strchr( value, '~' ) ) = '\n'; item.frame = atoi( name ); mlt_geometry_insert( key_frames, &item ); } mlt_geometry_interpolate( key_frames ); } else { FILE *f = fopen( filename, "r" ); if ( f != NULL ) { char line[81]; char *markup = NULL; size_t size = 0; line[80] = '\0'; while ( fgets( line, 80, f ) ) { size += strlen( line ) + 1; if ( markup ) { markup = realloc( markup, size ); strcat( markup, line ); } else { markup = strdup( line ); } } fclose( f ); if ( markup[ strlen( markup ) - 1 ] == '\n' ) markup[ strlen( markup ) - 1 ] = '\0'; mlt_properties_set( properties, "resource", filename ); mlt_properties_set( properties, "markup", ( markup == NULL ? "" : markup ) ); free( markup ); } else { producer->close = NULL; mlt_producer_close( producer ); producer = NULL; free( this ); } } return producer; } free( this ); return NULL; }
static mlt_properties metadata( mlt_service_type type, const char *id, char *data ) { char file[ PATH_MAX ]; if( type == filter_type ) { snprintf( file, PATH_MAX, "%s/jackrack/%s", mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "filter_ladspa.yml" ); } else { snprintf( file, PATH_MAX, "%s/jackrack/%s", mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "producer_ladspa.yml" ); } mlt_properties result = mlt_properties_parse_yaml( file ); #ifdef GPL if ( !strncmp( id, "ladspa.", 7 ) ) { // Annotate the yaml properties with ladspa control port info. plugin_desc_t *desc = plugin_mgr_get_any_desc( g_jackrack_plugin_mgr, strtol( id + 7, NULL, 10 ) ); if ( desc ) { mlt_properties params = mlt_properties_new(); mlt_properties p; char key[20]; int i; mlt_properties_set( result, "identifier", id ); mlt_properties_set( result, "title", desc->name ); mlt_properties_set( result, "creator", desc->maker ? desc->maker : "unknown" ); mlt_properties_set( result, "description", "LADSPA plugin" ); mlt_properties_set_data( result, "parameters", params, 0, (mlt_destructor) mlt_properties_close, NULL ); for ( i = 0; i < desc->control_port_count; i++ ) { int j = desc->control_port_indicies[i]; p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); snprintf( key, sizeof(key), "%d", j ); mlt_properties_set( p, "identifier", key ); add_port_to_metadata( p, desc, j ); mlt_properties_set( p, "mutable", "yes" ); } for ( i = 0; i < desc->status_port_count; i++ ) { int j = desc->status_port_indicies[i]; p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); snprintf( key, sizeof(key), "%d[*]", j ); mlt_properties_set( p, "identifier", key ); add_port_to_metadata( p, desc, j ); mlt_properties_set( p, "readonly", "yes" ); } p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set( p, "identifier", "instances" ); mlt_properties_set( p, "title", "Instances" ); mlt_properties_set( p, "description", "The number of instances of the plugin that are in use.\n" "MLT will create the number of plugins that are required " "to support the number of audio channels.\n" "Status parameters (readonly) are provided for each instance " "and are accessed by specifying the instance number after the " "identifier (starting at zero).\n" "e.g. 9[0] provides the value of status 9 for the first instance." ); mlt_properties_set( p, "type", "integer" ); mlt_properties_set( p, "readonly", "yes" ); if( type == filter_type ) { p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set( p, "identifier", "wetness" ); mlt_properties_set( p, "title", "Wet/Dry" ); mlt_properties_set( p, "type", "float" ); mlt_properties_set_double( p, "default", 1 ); mlt_properties_set_double( p, "minimum", 0 ); mlt_properties_set_double( p, "maximum", 1 ); mlt_properties_set( p, "mutable", "yes" ); } } } #endif return result; }
static mlt_properties find_default_streams( mlt_properties meta_media, AVFormatContext *context, int *audio_index, int *video_index ) { int i; char key[200]; mlt_properties_set_int( meta_media, "meta.media.nb_streams", context->nb_streams ); // Allow for multiple audio and video streams in the file and select first of each (if available) for( i = 0; i < context->nb_streams; i++ ) { // Get the codec context AVStream *stream = context->streams[ i ]; if ( ! stream ) continue; AVCodecContext *codec_context = stream->codec; if ( ! codec_context ) continue; AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); if ( ! codec ) continue; snprintf( key, sizeof(key), "meta.media.%d.stream.type", i ); // Determine the type and obtain the first index of each type switch( codec_context->codec_type ) { case CODEC_TYPE_VIDEO: if ( *video_index < 0 ) *video_index = i; mlt_properties_set( meta_media, key, "video" ); snprintf( key, sizeof(key), "meta.media.%d.stream.frame_rate", i ); mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->r_frame_rate ) ); #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(21<<8)+0) snprintf( key, sizeof(key), "meta.media.%d.stream.sample_aspect_ratio", i ); mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->sample_aspect_ratio ) ); #endif snprintf( key, sizeof(key), "meta.media.%d.codec.pix_fmt", i ); mlt_properties_set( meta_media, key, avcodec_get_pix_fmt_name( codec_context->pix_fmt ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.sample_aspect_ratio", i ); mlt_properties_set_double( meta_media, key, av_q2d( codec_context->sample_aspect_ratio ) ); break; case CODEC_TYPE_AUDIO: if ( *audio_index < 0 ) *audio_index = i; mlt_properties_set( meta_media, key, "audio" ); #if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) snprintf( key, sizeof(key), "meta.media.%d.codec.sample_fmt", i ); mlt_properties_set( meta_media, key, avcodec_get_sample_fmt_name( codec_context->sample_fmt ) ); #endif snprintf( key, sizeof(key), "meta.media.%d.codec.sample_rate", i ); mlt_properties_set_int( meta_media, key, codec_context->sample_rate ); snprintf( key, sizeof(key), "meta.media.%d.codec.channels", i ); mlt_properties_set_int( meta_media, key, codec_context->channels ); break; default: break; } // snprintf( key, sizeof(key), "meta.media.%d.stream.time_base", i ); // mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->time_base ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.name", i ); mlt_properties_set( meta_media, key, codec->name ); #if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(55<<8)+0)) snprintf( key, sizeof(key), "meta.media.%d.codec.long_name", i ); mlt_properties_set( meta_media, key, codec->long_name ); #endif snprintf( key, sizeof(key), "meta.media.%d.codec.bit_rate", i ); mlt_properties_set_int( meta_media, key, codec_context->bit_rate ); // snprintf( key, sizeof(key), "meta.media.%d.codec.time_base", i ); // mlt_properties_set_double( meta_media, key, av_q2d( codec_context->time_base ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.profile", i ); mlt_properties_set_int( meta_media, key, codec_context->profile ); snprintf( key, sizeof(key), "meta.media.%d.codec.level", i ); mlt_properties_set_int( meta_media, key, codec_context->level ); } return meta_media; }
mlt_filter filter_audiospectrum_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); if ( filter && pdata && createQApplicationIfNeeded( MLT_FILTER_SERVICE(filter) ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_int( properties, "_filter_private", 1 ); mlt_properties_set_int( properties, "frequency_low", 20 ); mlt_properties_set_int( properties, "frequency_high", 20000 ); mlt_properties_set( properties, "type", "line" ); mlt_properties_set( properties, "bgcolor", "0x00000000" ); mlt_properties_set( properties, "color.1", "0xffffffff" ); mlt_properties_set( properties, "rect", "0% 0% 100% 100%" ); mlt_properties_set( properties, "thickness", "0" ); mlt_properties_set( properties, "fill", "0" ); mlt_properties_set( properties, "mirror", "0" ); mlt_properties_set( properties, "reverse", "0" ); mlt_properties_set( properties, "tension", "0.4" ); mlt_properties_set( properties, "angle", "0" ); mlt_properties_set( properties, "gorient", "v" ); mlt_properties_set_int( properties, "bands", 31 ); mlt_properties_set_double( properties, "threshold", -60.0 ); mlt_properties_set_int( properties, "window_size", 8192 ); // Create a unique ID for storing data on the frame pdata->fft_prop_name = (char*)calloc( 1, 20 ); snprintf( pdata->fft_prop_name, 20, "fft.%p", filter ); pdata->fft_prop_name[20 - 1] = '\0'; pdata->fft = 0; filter->close = filter_close; filter->process = filter_process; filter->child = pdata; } else { mlt_log_error( MLT_FILTER_SERVICE(filter), "Filter audio spectrum failed\n" ); if( filter ) { mlt_filter_close( filter ); } if( pdata ) { free( pdata ); } filter = NULL; } return filter; }
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ) { mlt_tractor self = parent->child; // We only respond to the first track requests if ( track == 0 && self->producer != NULL ) { int i = 0; int done = 0; mlt_frame temp = NULL; int count = 0; int image_count = 0; // Get the properties of the parent producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent ); // Try to obtain the multitrack associated to the tractor mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL ); // Or a specific producer mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Determine whether this tractor feeds to the consumer or stops here int global_feed = mlt_properties_get_int( properties, "global_feed" ); // If we don't have one, we're in trouble... if ( multitrack != NULL ) { // The output frame will hold the 'global' data feeds (ie: those which are targetted for the final frame) mlt_deque data_queue = mlt_deque_init( ); // Used to garbage collect all frames char label[ 30 ]; // Get the id of the tractor char *id = mlt_properties_get( properties, "_unique_id" ); // Will be used to store the frame properties object mlt_properties frame_properties = NULL; // We'll store audio and video frames to use here mlt_frame audio = NULL; mlt_frame video = NULL; mlt_frame first_video = NULL; // Temporary properties mlt_properties temp_properties = NULL; // Get the multitrack's producer mlt_producer target = MLT_MULTITRACK_PRODUCER( multitrack ); mlt_producer_seek( target, mlt_producer_frame( parent ) ); mlt_producer_set_speed( target, mlt_producer_get_speed( parent ) ); // We will create one frame and attach everything to it *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); // Get the properties of the frame frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Loop through each of the tracks we're harvesting for ( i = 0; !done; i ++ ) { // Get a frame from the producer mlt_service_get_frame( self->producer, &temp, i ); // Get the temporary properties temp_properties = MLT_FRAME_PROPERTIES( temp ); // Pass all unique meta properties from the producer's frame to the new frame mlt_properties_lock( temp_properties ); int props_count = mlt_properties_count( temp_properties ); int j; for ( j = 0; j < props_count; j ++ ) { char *name = mlt_properties_get_name( temp_properties, j ); if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) ) mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) ); } mlt_properties_unlock( temp_properties ); // Copy the format conversion virtual functions if ( ! (*frame)->convert_image && temp->convert_image ) (*frame)->convert_image = temp->convert_image; if ( ! (*frame)->convert_audio && temp->convert_audio ) (*frame)->convert_audio = temp->convert_audio; // Check for last track done = mlt_properties_get_int( temp_properties, "last_track" ); // Handle fx only tracks if ( mlt_properties_get_int( temp_properties, "fx_cut" ) ) { int hide = ( video == NULL ? 1 : 0 ) | ( audio == NULL ? 2 : 0 ); mlt_properties_set_int( temp_properties, "hide", hide ); } // We store all frames with a destructor on the output frame sprintf( label, "_%s_%d", id, count ++ ); mlt_properties_set_data( frame_properties, label, temp, 0, ( mlt_destructor )mlt_frame_close, NULL ); // We want to append all 'final' feeds to the global queue if ( !done && mlt_properties_get_data( temp_properties, "data_queue", NULL ) != NULL ) { // Move the contents of this queue on to the output frames data queue mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "data_queue", NULL ); mlt_deque temp = mlt_deque_init( ); while ( global_feed && mlt_deque_count( sub_queue ) ) { mlt_properties p = mlt_deque_pop_back( sub_queue ); if ( mlt_properties_get_int( p, "final" ) ) mlt_deque_push_back( data_queue, p ); else mlt_deque_push_back( temp, p ); } while( mlt_deque_count( temp ) ) mlt_deque_push_front( sub_queue, mlt_deque_pop_back( temp ) ); mlt_deque_close( temp ); } // Now do the same with the global queue but without the conditional behaviour if ( mlt_properties_get_data( temp_properties, "global_queue", NULL ) != NULL ) { mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "global_queue", NULL ); while ( mlt_deque_count( sub_queue ) ) { mlt_properties p = mlt_deque_pop_back( sub_queue ); mlt_deque_push_back( data_queue, p ); } } // Pick up first video and audio frames if ( !done && !mlt_frame_is_test_audio( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 2 ) ) { // Order of frame creation is starting to get problematic if ( audio != NULL ) { mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), producer_get_audio ); mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), audio ); } audio = temp; } if ( !done && !mlt_frame_is_test_card( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 1 ) ) { if ( video != NULL ) { mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), producer_get_image ); mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), video ); } video = temp; if ( first_video == NULL ) first_video = temp; mlt_properties_set_int( MLT_FRAME_PROPERTIES( temp ), "image_count", ++ image_count ); image_count = 1; } } // Now stack callbacks if ( audio != NULL ) { mlt_frame_push_audio( *frame, audio ); mlt_frame_push_audio( *frame, producer_get_audio ); } if ( video != NULL ) { mlt_properties video_properties = MLT_FRAME_PROPERTIES( first_video ); mlt_frame_push_service( *frame, video ); mlt_frame_push_service( *frame, producer_get_image ); if ( global_feed ) mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL ); mlt_properties_set_data( video_properties, "global_queue", data_queue, 0, destroy_data_queue, NULL ); mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) ); mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) ); mlt_properties_pass_list( frame_properties, video_properties, "meta.media.width, meta.media.height" ); mlt_properties_set_int( frame_properties, "progressive", mlt_properties_get_int( video_properties, "progressive" ) ); mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( video_properties, "aspect_ratio" ) ); mlt_properties_set_int( frame_properties, "image_count", image_count ); mlt_properties_set_data( frame_properties, "_producer", mlt_frame_get_original_producer( first_video ), 0, NULL, NULL ); } else { destroy_data_queue( data_queue ); } mlt_frame_set_position( *frame, mlt_producer_frame( parent ) ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", video == NULL ); } else if ( producer != NULL ) { mlt_producer_seek( producer, mlt_producer_frame( parent ) ); mlt_producer_set_speed( producer, mlt_producer_get_speed( parent ) ); mlt_service_get_frame( self->producer, frame, track ); } else { mlt_log( MLT_PRODUCER_SERVICE( parent ), MLT_LOG_ERROR, "tractor without a multitrack!!\n" ); mlt_service_get_frame( self->producer, frame, track ); } // Prepare the next frame mlt_producer_prepare_next( parent ); // Indicate our found status return 0; } else { // Generate a test card *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); return 0; } }
int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_get_audio get_audio = mlt_frame_pop_audio( self ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); int hide = mlt_properties_get_int( properties, "test_audio" ); mlt_audio_format requested_format = *format; if ( hide == 0 && get_audio != NULL ) { get_audio( self, buffer, format, frequency, channels, samples ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) { *buffer = mlt_properties_get_data( properties, "audio", NULL ); *format = mlt_properties_get_int( properties, "audio_format" ); *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else { int size = 0; *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); switch( *format ) { case mlt_image_none: size = 0; *buffer = NULL; break; case mlt_audio_s16: size = *samples * *channels * sizeof( int16_t ); break; case mlt_audio_s32: size = *samples * *channels * sizeof( int32_t ); break; case mlt_audio_float: size = *samples * *channels * sizeof( float ); break; default: break; } if ( size ) *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 0, size ); mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_audio", 1 ); } // TODO: This does not belong here if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) ) { double value = mlt_properties_get_double( properties, "meta.volume" ); if ( value == 0.0 ) { memset( *buffer, 0, *samples * *channels * 2 ); } else if ( value != 1.0 ) { int total = *samples * *channels; int16_t *p = *buffer; while ( total -- ) { *p = *p * value; p ++; } } mlt_properties_set( properties, "meta.volume", NULL ); } return 0; }
static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; int error = 1; if ( producer ) { mlt_frame test_frame = NULL; mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 ); if ( test_frame ) { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); if ( !error && buffer && *buffer ) { mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); if ( test_frame->convert_image && requested_format != mlt_image_none ) test_frame->convert_image( test_frame, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } } else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); } } if ( error && buffer && *format != mlt_image_none ) { int size = 0; *width = *width == 0 ? 720 : *width; *height = *height == 0 ? 576 : *height; size = *width * *height; mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); switch( *format ) { case mlt_image_rgb24: size *= 3; size += *width * 3; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_rgb24a: case mlt_image_opengl: size *= 4; size += *width * 4; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_yuv422: size *= 2; size += *width * 2; *buffer = mlt_pool_alloc( size ); if ( *buffer ) { register uint8_t *p = *buffer; register uint8_t *q = p + size; while ( p != NULL && p != q ) { *p ++ = 235; *p ++ = 128; } } break; case mlt_image_yuv420p: *buffer = mlt_pool_alloc( size * 3 / 2 ); if ( *buffer ) { memset( *buffer, 235, size ); memset( *buffer + size, 128, size / 2 ); } break; default: size = 0; break; } mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); error = 0; } return error; }
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio ) { if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "preview" ) && mlt_producer_get_speed( getProducer() ) == 0.0 && !mlt_deque_count( m_queue )) { pthread_cond_broadcast( &m_condition ); return S_OK; } // Create mlt_frame mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) ); // Copy video if ( video ) { if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) ) { int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines ); void* image = mlt_pool_alloc( size ); void* buffer = 0; unsigned char* p = (unsigned char*) image; int n = size / 2; \ // Initialize VANC lines to nominal black while ( --n ) { *p ++ = 16; *p ++ = 128; } // Capture VANC if ( m_vancLines > 0 ) { IDeckLinkVideoFrameAncillary* vanc = 0; if ( video->GetAncillaryData( &vanc ) == S_OK && vanc ) { for ( int i = 1; i < m_vancLines + 1; i++ ) { if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK ) swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() ); else mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i ); } SAFE_RELEASE(vanc); } } // Capture image video->GetBytes( &buffer ); if ( image && buffer ) { size = video->GetRowBytes() * video->GetHeight(); swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size ); mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release ); } else if ( image ) { mlt_log_verbose( getProducer(), "no video\n" ); mlt_pool_release( image ); } } else { mlt_log_verbose( getProducer(), "no signal\n" ); mlt_frame_close( frame ); frame = 0; } // Get timecode IDeckLinkTimecode* timecode = 0; if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode ) { DLString timecodeString = 0; if ( timecode->GetString( &timecodeString ) == S_OK ) { char* s = getCString( timecodeString ); mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", s ); mlt_log_debug( getProducer(), "timecode %s\n", s ); freeCString( s ); } freeDLString( timecodeString ); SAFE_RELEASE( timecode ); } } else { mlt_log_verbose( getProducer(), "no video\n" ); mlt_frame_close( frame ); frame = 0; } // Copy audio if ( frame && audio ) { int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t); mlt_audio_format format = mlt_audio_s16; void* pcm = mlt_pool_alloc( size ); void* buffer = 0; audio->GetBytes( &buffer ); if ( buffer ) { memcpy( pcm, buffer, size ); mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() ); } else { mlt_log_verbose( getProducer(), "no audio\n" ); mlt_pool_release( pcm ); } } else { mlt_log_verbose( getProducer(), "no audio\n" ); } // Put frame in queue if ( frame ) { int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); pthread_mutex_lock( &m_mutex ); if ( mlt_deque_count( m_queue ) < queueMax ) { mlt_deque_push_back( m_queue, frame ); pthread_cond_broadcast( &m_condition ); } else { mlt_frame_close( frame ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped ); mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped ); } pthread_mutex_unlock( &m_mutex ); } return S_OK; }
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); }
static double get_aspect_ratio( AVStream *stream, AVCodecContext *codec_context, AVPacket *pkt ) { double aspect_ratio = 1.0; if ( codec_context->codec_id == CODEC_ID_DVVIDEO ) { if ( pkt ) { if ( dv_is_pal( pkt ) ) { aspect_ratio = dv_is_wide( pkt ) ? 64.0/45.0 // 16:9 PAL : 16.0/15.0; // 4:3 PAL } else { aspect_ratio = dv_is_wide( pkt ) ? 32.0/27.0 // 16:9 NTSC : 8.0/9.0; // 4:3 NTSC } } else { AVRational ar = #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(21<<8)+0) stream->sample_aspect_ratio; #else codec_context->sample_aspect_ratio; #endif // Override FFmpeg's notion of DV aspect ratios, which are // based upon a width of 704. Since we do not have a normaliser // that crops (nor is cropping 720 wide ITU-R 601 video always desirable) // we just coerce the values to facilitate a passive behaviour through // the rescale normaliser when using equivalent producers and consumers. // = display_aspect / (width * height) if ( ar.num == 10 && ar.den == 11 ) aspect_ratio = 8.0/9.0; // 4:3 NTSC else if ( ar.num == 59 && ar.den == 54 ) aspect_ratio = 16.0/15.0; // 4:3 PAL else if ( ar.num == 40 && ar.den == 33 ) aspect_ratio = 32.0/27.0; // 16:9 NTSC else if ( ar.num == 118 && ar.den == 81 ) aspect_ratio = 64.0/45.0; // 16:9 PAL } } else { AVRational codec_sar = codec_context->sample_aspect_ratio; AVRational stream_sar = #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(21<<8)+0) stream->sample_aspect_ratio; #else { 0, 1 }; #endif if ( codec_sar.num > 0 ) aspect_ratio = av_q2d( codec_sar ); else if ( stream_sar.num > 0 ) aspect_ratio = av_q2d( stream_sar ); } return aspect_ratio; } /** Open the file. */ static int producer_open( mlt_producer this, mlt_profile profile, char *file ) { // Return an error code (0 == no error) int error = 0; // Context for avformat AVFormatContext *context = NULL; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // We will treat everything with the producer fps double fps = mlt_profile_fps( profile ); // Lock the mutex now avformat_lock( ); // If "MRL", then create AVInputFormat AVInputFormat *format = NULL; AVFormatParameters *params = NULL; char *standard = NULL; char *mrl = strchr( file, ':' ); // AV option (0 = both, 1 = video, 2 = audio) int av = 0; // Only if there is not a protocol specification that avformat can handle if ( mrl && !url_exist( file ) ) { // 'file' becomes format abbreviation mrl[0] = 0; // Lookup the format format = av_find_input_format( file ); // Eat the format designator file = ++mrl; if ( format ) { // Allocate params params = calloc( sizeof( AVFormatParameters ), 1 ); // These are required by video4linux (defaults) params->width = 640; params->height = 480; params->time_base= (AVRational){1,25}; // params->device = file; params->channels = 2; params->sample_rate = 48000; } // XXX: this does not work anymore since avdevice // TODO: make producer_avddevice? // Parse out params mrl = strchr( file, '?' ); while ( mrl ) { mrl[0] = 0; char *name = strdup( ++mrl ); char *value = strchr( name, ':' ); if ( value ) { value[0] = 0; value++; char *t = strchr( value, '&' ); if ( t ) t[0] = 0; if ( !strcmp( name, "frame_rate" ) ) params->time_base.den = atoi( value ); else if ( !strcmp( name, "frame_rate_base" ) ) params->time_base.num = atoi( value ); else if ( !strcmp( name, "sample_rate" ) ) params->sample_rate = atoi( value ); else if ( !strcmp( name, "channels" ) ) params->channels = atoi( value ); else if ( !strcmp( name, "width" ) ) params->width = atoi( value ); else if ( !strcmp( name, "height" ) ) params->height = atoi( value ); else if ( !strcmp( name, "standard" ) ) { standard = strdup( value ); params->standard = standard; } else if ( !strcmp( name, "av" ) ) av = atoi( value ); } free( name ); mrl = strchr( mrl, '&' ); } } // Now attempt to open the file error = av_open_input_file( &context, file, format, 0, params ) < 0; // Cleanup AVFormatParameters free( standard ); free( params ); // If successful, then try to get additional info if ( error == 0 ) { // Get the stream info error = av_find_stream_info( context ) < 0; // Continue if no error if ( error == 0 ) { // We will default to the first audio and video streams found int audio_index = -1; int video_index = -1; int av_bypass = 0; // Now set properties where we can (use default unknowns if required) if ( context->duration != AV_NOPTS_VALUE ) { // This isn't going to be accurate for all formats mlt_position frames = ( mlt_position )( ( ( double )context->duration / ( double )AV_TIME_BASE ) * fps + 0.5 ); mlt_properties_set_position( properties, "out", frames - 1 ); mlt_properties_set_position( properties, "length", frames ); } // Find default audio and video streams find_default_streams( properties, context, &audio_index, &video_index ); if ( context->start_time != AV_NOPTS_VALUE ) mlt_properties_set_double( properties, "_start_time", context->start_time ); // Check if we're seekable (something funny about mpeg here :-/) if ( strcmp( file, "pipe:" ) && strncmp( file, "http://", 6 ) && strncmp( file, "udp:", 4 ) && strncmp( file, "tcp:", 4 ) && strncmp( file, "rtsp:", 5 ) && strncmp( file, "rtp:", 4 ) ) { mlt_properties_set_int( properties, "seekable", av_seek_frame( context, -1, mlt_properties_get_double( properties, "_start_time" ), AVSEEK_FLAG_BACKWARD ) >= 0 ); mlt_properties_set_data( properties, "dummy_context", context, 0, producer_file_close, NULL ); av_open_input_file( &context, file, NULL, 0, NULL ); av_find_stream_info( context ); } else av_bypass = 1; // Store selected audio and video indexes on properties mlt_properties_set_int( properties, "_audio_index", audio_index ); mlt_properties_set_int( properties, "_video_index", video_index ); mlt_properties_set_int( properties, "_last_position", -1 ); // Fetch the width, height and aspect ratio if ( video_index != -1 ) { AVCodecContext *codec_context = context->streams[ video_index ]->codec; mlt_properties_set_int( properties, "width", codec_context->width ); mlt_properties_set_int( properties, "height", codec_context->height ); if ( codec_context->codec_id == CODEC_ID_DVVIDEO ) { // Fetch the first frame of DV so we can read it directly AVPacket pkt; int ret = 0; while ( ret >= 0 ) { ret = av_read_frame( context, &pkt ); if ( ret >= 0 && pkt.stream_index == video_index && pkt.size > 0 ) { mlt_properties_set_double( properties, "aspect_ratio", get_aspect_ratio( context->streams[ video_index ], codec_context, &pkt ) ); break; } } } else { mlt_properties_set_double( properties, "aspect_ratio", get_aspect_ratio( context->streams[ video_index ], codec_context, NULL ) ); } } // Read Metadata if (context->title != NULL) mlt_properties_set(properties, "meta.attr.title.markup", context->title ); if (context->author != NULL) mlt_properties_set(properties, "meta.attr.author.markup", context->author ); if (context->copyright != NULL) mlt_properties_set(properties, "meta.attr.copyright.markup", context->copyright ); if (context->comment != NULL) mlt_properties_set(properties, "meta.attr.comment.markup", context->comment ); if (context->album != NULL) mlt_properties_set(properties, "meta.attr.album.markup", context->album ); if (context->year != 0) mlt_properties_set_int(properties, "meta.attr.year.markup", context->year ); if (context->track != 0) mlt_properties_set_int(properties, "meta.attr.track.markup", context->track ); // We're going to cheat here - for a/v files, we will have two contexts (reasoning will be clear later) if ( av == 0 && audio_index != -1 && video_index != -1 ) { // We'll use the open one as our video_context mlt_properties_set_data( properties, "video_context", context, 0, producer_file_close, NULL ); // And open again for our audio context av_open_input_file( &context, file, NULL, 0, NULL ); av_find_stream_info( context ); // Audio context mlt_properties_set_data( properties, "audio_context", context, 0, producer_file_close, NULL ); } else if ( av != 2 && video_index != -1 ) { // We only have a video context mlt_properties_set_data( properties, "video_context", context, 0, producer_file_close, NULL ); } else if ( audio_index != -1 ) { // We only have an audio context mlt_properties_set_data( properties, "audio_context", context, 0, producer_file_close, NULL ); } else { // Something has gone wrong error = -1; } mlt_properties_set_int( properties, "av_bypass", av_bypass ); } } // Unlock the mutex now avformat_unlock( ); return error; } /** Convert a frame position to a time code. */ static double producer_time_of_frame( mlt_producer this, mlt_position position ) { return ( double )position / mlt_producer_get_fps( this ); } static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt, mlt_image_format format, int width, int height ) { #ifdef SWSCALE if ( format == mlt_image_yuv420p ) { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL); AVPicture output; output.data[0] = buffer; output.data[1] = buffer + width * height; output.data[2] = buffer + ( 3 * width * height ) / 2; output.linesize[0] = width; output.linesize[1] = width >> 1; output.linesize[2] = width >> 1; sws_scale( context, frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } else if ( format == mlt_image_rgb24 ) { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL); AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGB24, width, height ); sws_scale( context, frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } else { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_YUYV422, SWS_FAST_BILINEAR, NULL, NULL, NULL); AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_YUYV422, width, height ); sws_scale( context, frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } #else if ( format == mlt_image_yuv420p ) { AVPicture pict; pict.data[0] = buffer; pict.data[1] = buffer + width * height; pict.data[2] = buffer + ( 3 * width * height ) / 2; pict.linesize[0] = width; pict.linesize[1] = width >> 1; pict.linesize[2] = width >> 1; img_convert( &pict, PIX_FMT_YUV420P, (AVPicture *)frame, pix_fmt, width, height ); }
static void foreach_consumer_init( mlt_consumer consumer ) { const char *resource = mlt_properties_get( MLT_CONSUMER_PROPERTIES(consumer), "resource" ); mlt_properties properties = mlt_properties_parse_yaml( resource ); char key[20]; int index = 0; if ( mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "0", NULL ) ) { // Properties set directly by application mlt_properties p; if ( properties ) mlt_properties_close( properties ); properties = MLT_CONSUMER_PROPERTIES(consumer); do { snprintf( key, sizeof(key), "%d", index ); if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) ) generate_consumer( consumer, p, index++ ); } while ( p ); } else if ( properties && mlt_properties_get_data( properties, "0", NULL ) ) { // YAML file supplied mlt_properties p; do { snprintf( key, sizeof(key), "%d", index ); if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) ) generate_consumer( consumer, p, index++ ); } while ( p ); mlt_properties_close( properties ); } else { // properties file supplied or properties on this consumer const char *s; if ( properties ) mlt_properties_close( properties ); if ( resource ) properties = mlt_properties_load( resource ); else properties = MLT_CONSUMER_PROPERTIES( consumer ); do { snprintf( key, sizeof(key), "%d", index ); if ( ( s = mlt_properties_get( properties, key ) ) ) { mlt_properties p = mlt_properties_new(); int i, count; if ( !p ) break; mlt_properties_set( p, "mlt_service", mlt_properties_get( properties, key ) ); snprintf( key, sizeof(key), "%d.", index ); count = mlt_properties_count( properties ); for ( i = 0; i < count; i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( !strncmp( name, key, strlen(key) ) ) mlt_properties_set( p, name + strlen(key), mlt_properties_get_value( properties, i ) ); } generate_consumer( consumer, p, index++ ); mlt_properties_close( p ); } } while ( s ); if ( resource ) mlt_properties_close( properties ); } }
mlt_producer producer_avformat_init( mlt_profile profile, char *file ) { int error = 0; // Report information about available demuxers and codecs as YAML Tiny if ( file && strstr( file, "f-list" ) ) { fprintf( stderr, "---\nformats:\n" ); AVInputFormat *format = NULL; while ( ( format = av_iformat_next( format ) ) ) fprintf( stderr, " - %s\n", format->name ); fprintf( stderr, "...\n" ); error = 1; } if ( file && strstr( file, "acodec-list" ) ) { fprintf( stderr, "---\naudio_codecs:\n" ); AVCodec *codec = NULL; while ( ( codec = av_codec_next( codec ) ) ) if ( codec->decode && codec->type == CODEC_TYPE_AUDIO ) fprintf( stderr, " - %s\n", codec->name ); fprintf( stderr, "...\n" ); error = 1; } if ( file && strstr( file, "vcodec-list" ) ) { fprintf( stderr, "---\nvideo_codecs:\n" ); AVCodec *codec = NULL; while ( ( codec = av_codec_next( codec ) ) ) if ( codec->decode && codec->type == CODEC_TYPE_VIDEO ) fprintf( stderr, " - %s\n", codec->name ); fprintf( stderr, "...\n" ); error = 1; } if ( error ) return NULL; mlt_producer this = NULL; // Check that we have a non-NULL argument if ( file != NULL ) { // Construct the producer this = calloc( 1, sizeof( struct mlt_producer_s ) ); // Initialise it if ( mlt_producer_init( this, NULL ) == 0 ) { // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // Set the resource property (required for all producers) mlt_properties_set( properties, "resource", file ); // Register our get_frame implementation this->get_frame = producer_get_frame; // Open the file if ( producer_open( this, profile, file ) != 0 ) { // Clean up mlt_producer_close( this ); this = NULL; } else { // Close the file to release resources for large playlists - reopen later as needed mlt_properties_set_data( properties, "dummy_context", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "audio_context", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "video_context", NULL, 0, NULL, NULL ); // Default the user-selectable indices from the auto-detected indices mlt_properties_set_int( properties, "audio_index", mlt_properties_get_int( properties, "_audio_index" ) ); mlt_properties_set_int( properties, "video_index", mlt_properties_get_int( properties, "_video_index" ) ); } } } return this; }
static void initialise_jack_ports( mlt_properties properties ) { int i; char mlt_name[67], rack_name[30]; jack_port_t **port = NULL; jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_nframes_t jack_buffer_size = jack_get_buffer_size( jack_client ); // Propagate these for the Jack processing callback int channels = mlt_properties_get_int( properties, "channels" ); // Start JackRack if ( mlt_properties_get( properties, "src" ) ) { snprintf( rack_name, sizeof( rack_name ), "jackrack%d", getpid() ); jack_rack_t *jackrack = jack_rack_new( rack_name, mlt_properties_get_int( properties, "channels" ) ); jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) ); mlt_properties_set_data( properties, "jackrack", jackrack, 0, (mlt_destructor) jack_rack_destroy, NULL ); mlt_properties_set( properties, "_rack_client_name", rack_name ); } else { // We have to set this to something to prevent re-initialization. mlt_properties_set_data( properties, "jackrack", jack_client, 0, NULL, NULL ); } // Allocate buffers and ports jack_ringbuffer_t **output_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels ); jack_ringbuffer_t **input_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels ); jack_port_t **jack_output_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels ); jack_port_t **jack_input_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels ); float **jack_output_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); float **jack_input_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); // Set properties - released inside filter_close mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, sizeof( float *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, sizeof( float *) * channels, mlt_pool_release, NULL ); // Register Jack ports for ( i = 0; i < channels; i++ ) { int in; output_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); input_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); for ( in = 0; in < 2; in++ ) { snprintf( mlt_name, sizeof( mlt_name ), "%s_%d", in ? "in" : "out", i + 1); port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] ); *port = jack_port_register( jack_client, mlt_name, JACK_DEFAULT_AUDIO_TYPE, ( in ? JackPortIsInput : JackPortIsOutput ) | JackPortIsTerminal, 0 ); } } // Start Jack processing pthread_mutex_lock( &g_activate_mutex ); jack_activate( jack_client ); pthread_mutex_unlock( &g_activate_mutex ); // Establish connections for ( i = 0; i < channels; i++ ) { int in; for ( in = 0; in < 2; in++ ) { port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] ); snprintf( mlt_name, sizeof( mlt_name ), "%s", jack_port_name( *port ) ); snprintf( rack_name, sizeof( rack_name ), "%s_%d", in ? "in" : "out", i + 1 ); if ( mlt_properties_get( properties, "_rack_client_name" ) ) snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "_rack_client_name" ), in ? "out" : "in", i + 1); else if ( mlt_properties_get( properties, rack_name ) ) snprintf( rack_name, sizeof( rack_name ), "%s", mlt_properties_get( properties, rack_name ) ); else snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "client_name" ), in ? "out" : "in", i + 1); if ( in ) { mlt_log_verbose( NULL, "JACK connect %s to %s\n", rack_name, mlt_name ); jack_connect( jack_client, rack_name, mlt_name ); } else { mlt_log_verbose( NULL, "JACK connect %s to %s\n", mlt_name, rack_name ); jack_connect( jack_client, mlt_name, rack_name ); } } } }
static int process_feed( mlt_properties feed, mlt_filter filter, mlt_frame frame ) { // Error return int error = 1; // Get the properties of the data show filter mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the type requested by the feeding filter char *type = mlt_properties_get( feed, "type" ); // Fetch the filter associated to this type mlt_filter requested = mlt_properties_get_data( filter_properties, type, NULL ); // If it doesn't exist, then create it now if ( requested == NULL ) { // Source filter from profile requested = obtain_filter( filter, type ); // Store it on the properties for subsequent retrieval/destruction mlt_properties_set_data( filter_properties, type, requested, 0, ( mlt_destructor )mlt_filter_close, NULL ); } // If we have one, then process it now... if ( requested != NULL ) { int i = 0; mlt_properties properties = MLT_FILTER_PROPERTIES( requested ); static const char *prefix = "properties."; int len = strlen( prefix ); // Determine if this is an absolute or relative feed int absolute = mlt_properties_get_int( feed, "absolute" ); // Make do with what we have int length = !absolute ? mlt_properties_get_int( feed, "out" ) - mlt_properties_get_int( feed, "in" ) + 1 : mlt_properties_get_int( feed, "out" ) + 1; // Repeat period int period = mlt_properties_get_int( properties, "period" ); period = period == 0 ? 1 : period; // Pass properties from feed into requested for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { char *name = mlt_properties_get_name( properties, i ); char *key = mlt_properties_get_value( properties, i ); if ( !strncmp( name, prefix, len ) ) { if ( !strncmp( name + len, "length[", 7 ) ) { mlt_properties_set_position( properties, key, ( length - period ) / period ); } else { char *value = mlt_properties_get( feed, name + len ); if ( value != NULL ) { // check for metadata keywords in metadata markup if user requested so if ( mlt_properties_get_int( filter_properties, "dynamic" ) == 1 && !strcmp( name + strlen( name ) - 6, "markup") ) { // Find keywords which should be surrounded by '#', like: #title# char* keywords = strtok( value, "#" ); char result[512] = ""; // XXX: how much is enough? int ct = 0; int fromStart = ( value[0] == '#' ) ? 1 : 0; while ( keywords != NULL ) { if ( ct % 2 == fromStart ) { // backslash in front of # suppresses substitution if ( keywords[ strlen( keywords ) -1 ] == '\\' ) { // keep characters except backslash strncat( result, keywords, sizeof( result ) - strlen( result ) - 2 ); strcat( result, "#" ); ct++; } else { strncat( result, keywords, sizeof( result ) - strlen( result ) - 1 ); } } else if ( !strcmp( keywords, "timecode" ) ) { // special case: replace #timecode# with current frame timecode mlt_position frames = mlt_properties_get_position( feed, "position" ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); char *s = mlt_properties_frames_to_time( properties, frames, mlt_time_smpte_df ); if ( s ) strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); } else if ( !strcmp( keywords, "frame" ) ) { // special case: replace #frame# with current frame number int pos = mlt_properties_get_int( feed, "position" ); char s[12]; snprintf( s, sizeof(s) - 1, "%d", pos ); s[sizeof( s ) - 1] = '\0'; strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); } else { // replace keyword with metadata value char *metavalue = metadata_value( MLT_FRAME_PROPERTIES( frame ), keywords ); strncat( result, metavalue ? metavalue : "-", sizeof( result ) - strlen( result ) -1 ); } keywords = strtok( NULL, "#" ); ct++; } mlt_properties_set( properties, key, (char*) result ); } else mlt_properties_set( properties, key, value ); } } } } // Set the original position on the frame if ( absolute == 0 ) mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) - mlt_properties_get_int( feed, "in" ) ); else mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) ); // Process the filter mlt_filter_process( requested, frame ); // Should be ok... error = 0; } return error; }
mlt_service SingleResourceLoader::get_asis_producer(JsonWrap js) throw (Exception) { json_t* defines = js.h; defines_tmp=js; json_t* je = json_object_get(defines, "resource"); json_t* uuid_je = json_object_get(defines, "uuid"); json_t* svc_je = json_object_get(defines, "service"); assert( je && json_is_string(je) && strlen(json_string_value(je))); assert( svc_je && json_is_string(svc_je) && strlen(json_string_value(svc_je))); assert( uuid_je && json_is_string(uuid_je) && strlen(json_string_value(uuid_je))); mlt_producer obj = MLT_PRODUCER(MltLoader::pop_mlt_registry(json_string_value(uuid_je))); if (obj == NULL) { mlt_profile profile = mlt_profile_clone(global_profile); obj = mlt_factory_producer(profile, json_string_value(svc_je), json_string_value(je)); #ifdef DEBUG std::cout << mlt_producer_properties(obj); #endif } if ( !obj ) { throw_error_v(ErrorRuntimeLoadFailed, "video producer load failed:%s", json_string_value(je)); } mlt_properties props = mlt_producer_properties(obj); je = json_object_get(defines, "props"); if (je && json_is_object(je) && json_object_size(je)) { json_t* inj = json_object_get(je,"in"), *outj = json_object_get(je,"out"); assert(inj && outj && json_is_integer(inj) && json_is_integer(outj)); mlt_producer_set_in_and_out(obj,json_integer_value(inj), json_integer_value(outj)); void* it = json_object_iter(je); while(it) { const char* k = json_object_iter_key(it); json_t* prop_je = json_object_iter_value(it); it = json_object_iter_next(je, it); if ( json_is_object(prop_je) || json_is_array(prop_je)) continue; if ( !strcmp(k,"in") || !strcmp(k,"out")) continue; switch(prop_je->type) { case JSON_INTEGER: mlt_properties_set_int64(props, k, json_integer_value(prop_je)); break; case JSON_REAL: mlt_properties_set_double(props, k, json_real_value(prop_je)); break; case JSON_STRING: mlt_properties_set(props, k, json_string_value(prop_je)); break; case JSON_TRUE: mlt_properties_set_int(props,k, 1); break; case JSON_FALSE: mlt_properties_set_int(props,k, 0); break; default: break; } } } MltSvcWrap wrap(mlt_producer_service(obj), 1); producer_tmp = obj; parse_filters(); wrap.obj = NULL; return mlt_producer_service(obj); }
int mlt_consumer_start( mlt_consumer self ) { if ( !mlt_consumer_is_stopped( self ) ) return 0; // Stop listening to the property-changed event mlt_event_block( self->event_listener ); // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Determine if there's a test card producer char *test_card = mlt_properties_get( properties, "test_card" ); // Just to make sure nothing is hanging around... pthread_mutex_lock( &self->put_mutex ); self->put = NULL; self->put_active = 1; pthread_mutex_unlock( &self->put_mutex ); // Deal with it now. if ( test_card != NULL ) { if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL ) { // Create a test card producer mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); mlt_producer producer = mlt_factory_producer( profile, NULL, test_card ); // Do we have a producer if ( producer != NULL ) { // Test card should loop I guess... mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); //mlt_producer_set_speed( producer, 0 ); //mlt_producer_set_in_and_out( producer, 0, 0 ); // Set the test card on the consumer mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } } else { // Allow the hash table to speed things up mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); } // The profile could have changed between a stop and a restart. apply_profile_properties( self, mlt_service_profile( MLT_CONSUMER_SERVICE(self) ), properties ); // Set the frame duration in microseconds for the frame-dropping heuristic int frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" ); int frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" ); int frame_duration = 0; if ( frame_rate_num && frame_rate_den ) { frame_duration = 1000000 / frame_rate_num * frame_rate_den; } mlt_properties_set_int( properties, "frame_duration", frame_duration ); // Check and run an ante command if ( mlt_properties_get( properties, "ante" ) ) if ( system( mlt_properties_get( properties, "ante" ) ) == -1 ) mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) ); // Set the real_time preference self->real_time = mlt_properties_get_int( properties, "real_time" ); // For worker threads implementation, buffer must be at least # threads if ( abs( self->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( self->real_time ) ) mlt_properties_set_int( properties, "_buffer", abs( self->real_time ) + 1 ); // Get the image format to use for rendering threads const char* format = mlt_properties_get( properties, "mlt_image_format" ); if ( format ) { if ( !strcmp( format, "rgb24" ) ) self->format = mlt_image_rgb24; else if ( !strcmp( format, "rgb24a" ) ) self->format = mlt_image_rgb24a; else if ( !strcmp( format, "yuv420p" ) ) self->format = mlt_image_yuv420p; else if ( !strcmp( format, "none" ) ) self->format = mlt_image_none; else self->format = mlt_image_yuv422; } // Start the service if ( self->start != NULL ) return self->start( self ); return 0; }
int mlt_producer_seek_time( mlt_producer self, const char* time ) { mlt_properties_set( MLT_PRODUCER_PROPERTIES(self), "_seek_time", time ); mlt_position position = mlt_properties_get_position( MLT_PRODUCER_PROPERTIES(self), "_seek_time" ); return mlt_producer_seek( self, position ); }
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; }
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; }
static void setup_producer( mlt_filter filter, mlt_producer producer, mlt_frame frame ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); char* dynamic_text = mlt_properties_get( my_properties, "argument" ); char* read_file = mlt_properties_get( my_properties, "read_file" ); char result[MAX_TEXT_LEN] = ""; // Check for keywords in dynamic text if ( dynamic_text ) { // Apply keyword substitution before passing the text to the filter. char result[MAX_TEXT_LEN] = ""; substitute_keywords( filter, result, dynamic_text, frame ); mlt_properties_set( producer_properties, "text", (char*)result ); } if ( read_file ) { FILE *f = fopen(read_file, "r"); if (f) { char result[4096]; size_t r = fread(result, 1, sizeof(result), f); result[r - 1] = '\0'; if (r > 1) mlt_properties_set( watermark_properties, "producer.markup", (char*) result ); fclose(f); } } // Pass the properties to the pango producer mlt_properties_set( producer_properties, "family", mlt_properties_get( my_properties, "family" ) ); mlt_properties_set( producer_properties, "size", mlt_properties_get( my_properties, "size" ) ); mlt_properties_set( producer_properties, "weight", mlt_properties_get( my_properties, "weight" ) ); mlt_properties_set( producer_properties, "fgcolour", mlt_properties_get( my_properties, "fgcolour" ) ); mlt_properties_set( producer_properties, "bgcolour", mlt_properties_get( my_properties, "bgcolour" ) ); mlt_properties_set( producer_properties, "olcolour", mlt_properties_get( my_properties, "olcolour" ) ); mlt_properties_set( producer_properties, "pad", mlt_properties_get( my_properties, "pad" ) ); mlt_properties_set( producer_properties, "outline", mlt_properties_get( my_properties, "outline" ) ); mlt_properties_set( producer_properties, "align", mlt_properties_get( my_properties, "halign" ) ); }
static mlt_properties fill_param_info ( mlt_service_type type, const char *service_name, char *name ) { char file[ PATH_MAX ]; char servicetype[ 1024 ]=""; struct stat stat_buff; switch ( type ) { case producer_type: strcpy ( servicetype , "producer" ); break; case filter_type: strcpy ( servicetype , "filter" ); break; case transition_type: strcpy ( servicetype , "transition" ) ; break; default: strcpy ( servicetype , "" ); }; snprintf( file, PATH_MAX, "%s/frei0r/%s_%s.yml", mlt_environment( "MLT_DATA" ), servicetype, service_name ); stat(file,&stat_buff); if (S_ISREG(stat_buff.st_mode)){ return mlt_properties_parse_yaml( file ); } void* handle=dlopen(name,RTLD_LAZY); if (!handle) return NULL; void (*plginfo)(f0r_plugin_info_t*)=dlsym(handle,"f0r_get_plugin_info"); void (*param_info)(f0r_param_info_t*,int param_index)=dlsym(handle,"f0r_get_param_info"); if (!plginfo || !param_info) { dlclose(handle); return NULL; } mlt_properties metadata = mlt_properties_new(); f0r_plugin_info_t info; char string[48]; int j=0; plginfo(&info); snprintf ( string, sizeof(string) , "%d.%d" , info.major_version , info.minor_version ); mlt_properties_set ( metadata, "schema_version" , "0.1" ); mlt_properties_set ( metadata, "title" , info.name ); mlt_properties_set ( metadata, "version", string ); mlt_properties_set ( metadata, "identifier" , service_name ); mlt_properties_set ( metadata, "description" , info.explanation ); mlt_properties_set ( metadata, "creator" , info.author ); switch (type){ case producer_type: mlt_properties_set ( metadata, "type" , "producer" ); break; case filter_type: mlt_properties_set ( metadata, "type" , "filter" ); break; case transition_type: mlt_properties_set ( metadata, "type" , "transition" ); break; default: break; } mlt_properties parameter = mlt_properties_new ( ); mlt_properties_set_data ( metadata , "parameters" , parameter , 0 , ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties tags = mlt_properties_new ( ); mlt_properties_set_data ( metadata , "tags" , tags , 0 , ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set ( tags , "0" , "Video" ); for (j=0;j<info.num_params;j++){ snprintf ( string , sizeof(string), "%d" , j ); mlt_properties pnum = mlt_properties_new ( ); mlt_properties_set_data ( parameter , string , pnum , 0 , ( mlt_destructor )mlt_properties_close, NULL ); f0r_param_info_t paraminfo; param_info(¶minfo,j); mlt_properties_set ( pnum , "identifier" , paraminfo.name ); mlt_properties_set ( pnum , "title" , paraminfo.name ); mlt_properties_set ( pnum , "description" , paraminfo.explanation); if ( paraminfo.type == F0R_PARAM_DOUBLE ){ mlt_properties_set ( pnum , "type" , "float" ); mlt_properties_set ( pnum , "minimum" , "0" ); mlt_properties_set ( pnum , "maximum" , "1" ); mlt_properties_set ( pnum , "readonly" , "no" ); mlt_properties_set ( pnum , "widget" , "spinner" ); }else if ( paraminfo.type == F0R_PARAM_BOOL ){ mlt_properties_set ( pnum , "type" , "boolean" ); mlt_properties_set ( pnum , "minimum" , "0" ); mlt_properties_set ( pnum , "maximum" , "1" ); mlt_properties_set ( pnum , "readonly" , "no" ); }else if ( paraminfo.type == F0R_PARAM_COLOR ){ mlt_properties_set ( pnum , "type" , "color" ); mlt_properties_set ( pnum , "readonly" , "no" ); }else if ( paraminfo.type == F0R_PARAM_STRING ){ mlt_properties_set ( pnum , "type" , "string" ); mlt_properties_set ( pnum , "readonly" , "no" ); } } dlclose(handle); free(name); return metadata; }
/** Constructor for the filter. */ mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); mlt_transition transition = mlt_factory_transition( profile, "composite", NULL ); mlt_producer producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "qtext:" ); // Use pango if qtext is not available. if( !producer ) producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "pango:" ); if ( filter && transition && producer ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); // Register the transition for reuse/destruction mlt_properties_set_data( my_properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Register the producer for reuse/destruction mlt_properties_set_data( my_properties, "_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Assign default values mlt_properties_set( my_properties, "argument", arg ? arg: "#timecode#" ); mlt_properties_set( my_properties, "geometry", "0%/0%:100%x100%:100" ); mlt_properties_set( my_properties, "family", "Sans" ); mlt_properties_set( my_properties, "size", "48" ); mlt_properties_set( my_properties, "weight", "400" ); mlt_properties_set( my_properties, "fgcolour", "0x000000ff" ); mlt_properties_set( my_properties, "bgcolour", "0x00000020" ); mlt_properties_set( my_properties, "olcolour", "0x00000000" ); mlt_properties_set( my_properties, "pad", "0" ); mlt_properties_set( my_properties, "halign", "left" ); mlt_properties_set( my_properties, "valign", "top" ); mlt_properties_set( my_properties, "outline", "0" ); mlt_properties_set_int( my_properties, "_filter_private", 1 ); filter->process = filter_process; } else { if( filter ) { mlt_filter_close( filter ); } if( transition ) { mlt_transition_close( transition ); } if( producer ) { mlt_producer_close( producer ); } filter = NULL; } return filter; }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_colour", NULL ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Get the current and previous colour strings char *now = mlt_properties_get( producer_props, "resource" ); char *then = mlt_properties_get( producer_props, "_resource" ); // Get the current image and dimensions cached in the producer int size = 0; uint8_t *image = mlt_properties_get_data( producer_props, "image", &size ); int current_width = mlt_properties_get_int( producer_props, "_width" ); int current_height = mlt_properties_get_int( producer_props, "_height" ); mlt_image_format current_format = mlt_properties_get_int( producer_props, "_format" ); // Parse the colour if ( now && strchr( now, '/' ) ) { now = strdup( strrchr( now, '/' ) + 1 ); mlt_properties_set( producer_props, "resource", now ); free( now ); now = mlt_properties_get( producer_props, "resource" ); } mlt_color color = mlt_properties_get_color( producer_props, "resource" ); if ( mlt_properties_get( producer_props, "mlt_image_format") ) *format = mlt_image_format_id( mlt_properties_get( producer_props, "mlt_image_format") ); // Choose suitable out values if nothing specific requested if ( *format == mlt_image_none || *format == mlt_image_glsl ) *format = mlt_image_rgb24a; if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Choose default image format if specific request is unsupported if (*format!=mlt_image_yuv420p && *format!=mlt_image_yuv422 && *format!=mlt_image_rgb24 && *format!= mlt_image_glsl && *format!= mlt_image_glsl_texture) *format = mlt_image_rgb24a; // See if we need to regenerate if ( !now || ( then && strcmp( now, then ) ) || *width != current_width || *height != current_height || *format != current_format ) { // Color the image int i = *width * *height + 1; int bpp; // Allocate the image size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = image = mlt_pool_alloc( size ); // Update the producer mlt_properties_set_data( producer_props, "image", image, size, mlt_pool_release, NULL ); mlt_properties_set_int( producer_props, "_width", *width ); mlt_properties_set_int( producer_props, "_height", *height ); mlt_properties_set_int( producer_props, "_format", *format ); mlt_properties_set( producer_props, "_resource", now ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); switch ( *format ) { case mlt_image_yuv420p: { int plane_size = *width * *height; uint8_t y, u, v; RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v ); memset(p + 0, y, plane_size); memset(p + plane_size, u, plane_size/4); memset(p + plane_size + plane_size/4, v, plane_size/4); mlt_properties_set_int( properties, "colorspace", 601 ); break; } case mlt_image_yuv422: { int uneven = *width % 2; int count = ( *width - uneven ) / 2 + 1; uint8_t y, u, v; RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v ); i = *height + 1; while ( --i ) { int j = count; while ( --j ) { *p ++ = y; *p ++ = u; *p ++ = y; *p ++ = v; } if ( uneven ) { *p ++ = y; *p ++ = u; } } mlt_properties_set_int( properties, "colorspace", 601 ); break; } case mlt_image_rgb24: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; } break; case mlt_image_glsl: case mlt_image_glsl_texture: memset(p, 0, size); break; case mlt_image_rgb24a: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; *p ++ = color.a; } break; default: mlt_log_error( MLT_PRODUCER_SERVICE( producer ), "invalid image format %s\n", mlt_image_format_name( *format ) ); } } else { mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); } // Create the alpha channel int alpha_size = 0; uint8_t *alpha = NULL; // Initialise the alpha if (color.a < 255 || *format == mlt_image_rgb24a) { alpha_size = *width * *height; alpha = mlt_pool_alloc( alpha_size ); if ( alpha ) memset( alpha, color.a, alpha_size ); else alpha_size = 0; } // Clone our image if (buffer && image && size > 0) { *buffer = mlt_pool_alloc( size ); memcpy( *buffer, image, size ); } // Now update properties so we free the copy after mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); mlt_properties_set_int( properties, "meta.media.width", *width ); mlt_properties_set_int( properties, "meta.media.height", *height ); return 0; }
static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = mlt_frame_pop_service( a_frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Image, format, width, height and image for the b frame uint8_t *b_image = NULL; mlt_image_format b_format = mlt_image_rgb24a; int b_width = mlt_properties_get_int( b_props, "meta.media.width" ); int b_height = mlt_properties_get_int( b_props, "meta.media.height" ); double b_ar = mlt_frame_get_aspect_ratio( b_frame ); double b_dar = b_ar * b_width / b_height; // Assign the current position mlt_position position = mlt_transition_get_position( transition, a_frame ); int mirror = mlt_properties_get_position( properties, "mirror" ); int length = mlt_transition_get_length( transition ); if ( mlt_properties_get_int( properties, "always_active" ) ) { mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL ); mlt_position in = mlt_properties_get_int( props, "in" ); mlt_position out = mlt_properties_get_int( props, "out" ); length = out - in + 1; } // Obtain the normalised width and height from the a_frame mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); int normalised_width = profile->width; int normalised_height = profile->height; double consumer_ar = mlt_profile_sar( profile ); if ( mirror && position > length / 2 ) position = abs( position - length ); // Fetch the a frame image *format = mlt_image_rgb24a; int error = mlt_frame_get_image( a_frame, image, format, width, height, 1 ); if (error || !image) return error; // Calculate the region now mlt_rect result = {0, 0, normalised_width, normalised_height, 1.0}; mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); if (mlt_properties_get(properties, "geometry")) { // Structures for geometry struct mlt_geometry_item_s geometry; composite_calculate( transition, &geometry, normalised_width, normalised_height, ( double )position ); result.x = geometry.x; result.y = geometry.y; result.w = geometry.w; result.h = geometry.h; result.o = geometry.mix / 100.0f; } else if (mlt_properties_get(properties, "rect")) { // Determine length and obtain cycle double cycle = mlt_properties_get_double( properties, "cycle" ); // Allow a repeat cycle if ( cycle >= 1 ) length = cycle; else if ( cycle > 0 ) length *= cycle; mlt_position anim_pos = repeat_position(properties, "rect", position, length); result = mlt_properties_anim_get_rect(properties, "rect", anim_pos, length); if (mlt_properties_get(properties, "rect") && strchr(mlt_properties_get(properties, "rect"), '%')) { result.x *= normalised_width; result.y *= normalised_height; result.w *= normalised_width; result.h *= normalised_height; } result.o = (result.o == DBL_MIN)? 1.0 : MIN(result.o, 1.0); } mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); double geometry_w = result.w; double geometry_h = result.h; if ( !mlt_properties_get_int( properties, "fill" ) ) { double geometry_dar = result.w * consumer_ar / result.h; if ( b_dar > geometry_dar ) { result.w = MIN( result.w, b_width * b_ar / consumer_ar ); result.h = result.w * consumer_ar / b_dar; } else { result.h = MIN( result.h, b_height ); result.w = result.h * b_dar / consumer_ar; } } // Fetch the b frame image result.w = ( result.w * *width / normalised_width ); result.h = ( result.h * *height / normalised_height ); result.x = ( result.x * *width / normalised_width ); result.y = ( result.y * *height / normalised_height ); if (mlt_properties_get_int(properties, "b_scaled")) { // Request b frame image size just what is needed. b_width = result.w; b_height = result.h; // Set the rescale interpolation to match the frame mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) ); } else { // Request full resolution of b frame image. mlt_properties_set_int( b_props, "rescale_width", b_width ); mlt_properties_set_int( b_props, "rescale_height", b_height ); // Suppress padding and aspect normalization. mlt_properties_set( b_props, "rescale.interp", "none" ); } // This is not a field-aware transform. mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); error = mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 ); if (error || !b_image) { // Remove potentially large image on the B frame. mlt_frame_set_image( b_frame, NULL, 0, NULL ); return error; } // Check that both images are of the correct format and process if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a ) { double sw, sh; // Get values from the transition double scale_x = mlt_properties_anim_get_double( properties, "scale_x", position, length ); double scale_y = mlt_properties_anim_get_double( properties, "scale_y", position, length ); int scale = mlt_properties_get_int( properties, "scale" ); double geom_scale_x = (double) b_width / result.w; double geom_scale_y = (double) b_height / result.h; struct sliced_desc desc = { .a_image = *image, .b_image = b_image, .interp = interpBL_b32, .a_width = *width, .a_height = *height, .b_width = b_width, .b_height = b_height, .lower_x = -(result.x + result.w / 2.0), // center .lower_y = -(result.y + result.h / 2.0), // middle .mix = result.o, .x_offset = (double) b_width / 2.0, .y_offset = (double) b_height / 2.0, .b_alpha = mlt_properties_get_int( properties, "b_alpha" ), // Affine boundaries .minima = 0, .xmax = b_width - 1, .ymax = b_height - 1 }; // Recalculate vars if alignment supplied. if ( mlt_properties_get( properties, "halign" ) || mlt_properties_get( properties, "valign" ) ) { double halign = alignment_parse( mlt_properties_get( properties, "halign" ) ); double valign = alignment_parse( mlt_properties_get( properties, "valign" ) ); desc.x_offset = halign * b_width / 2.0; desc.y_offset = valign * b_height / 2.0; desc.lower_x = -(result.x + geometry_w * halign / 2.0f); desc.lower_y = -(result.y + geometry_h * valign / 2.0f); } affine_init( desc.affine.matrix ); // Compute the affine transform get_affine( &desc.affine, transition, ( double )position, length ); desc.dz = MapZ( desc.affine.matrix, 0, 0 ); if ( (int) fabs( desc.dz * 1000 ) < 25 ) return 0; // Factor scaling into the transformation based on output resolution. if ( mlt_properties_get_int( properties, "distort" ) ) { scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y ); } else { // Determine scale with respect to aspect ratio. double consumer_dar = consumer_ar * normalised_width / normalised_height; if ( b_dar > consumer_dar ) { scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_x * ( scale_y == 0 ? 1 : scale_y ); scale_y *= b_ar / consumer_ar; } else { scale_x = geom_scale_y * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y ); scale_x *= consumer_ar / b_ar; } } if ( scale ) { affine_max_output( desc.affine.matrix, &sw, &sh, desc.dz, *width, *height ); affine_scale( desc.affine.matrix, sw * MIN( geom_scale_x, geom_scale_y ), sh * MIN( geom_scale_x, geom_scale_y ) ); } else if ( scale_x != 0 && scale_y != 0 ) { affine_scale( desc.affine.matrix, scale_x, scale_y ); } char *interps = mlt_properties_get( a_props, "rescale.interp" ); // Copy in case string is changed. if ( interps ) interps = strdup( interps ); // Set the interpolation function if ( interps == NULL || strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 || strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) { desc.interp = interpNN_b32; // uses lrintf. Values should be >= -0.5 and < max + 0.5 desc.minima -= 0.5; desc.xmax += 0.49; desc.ymax += 0.49; } else if ( strcmp( interps, "bilinear" ) == 0 ) { desc.interp = interpBL_b32; // uses floorf. } else if ( strcmp( interps, "bicubic" ) == 0 || strcmp( interps, "hyper" ) == 0 || strcmp( interps, "sinc" ) == 0 || strcmp( interps, "lanczos" ) == 0 || strcmp( interps, "spline" ) == 0 ) { // TODO: lanczos 8x8 // TODO: spline 4x4 or 6x6 desc.interp = interpBC_b32; // uses ceilf. Values should be > -1 and <= max. desc.minima -= 1; } free( interps ); // Do the transform with interpolation int threads = mlt_properties_get_int(properties, "threads"); threads = CLAMP(threads, 0, mlt_slices_count_normal()); if (threads == 1) sliced_proc(0, 0, 1, &desc); else mlt_slices_run_normal(threads, sliced_proc, &desc); // Remove potentially large image on the B frame. mlt_frame_set_image( b_frame, NULL, 0, NULL ); } return 0; }