int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_frei0r", producer, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Check that we created a frame and initialize it if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Save the producer to be used in get_audio mlt_properties_set_data( frame_properties, "_producer_ladspa", producer, 0, NULL, NULL ); // Push the get_audio method mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; }
static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { mlt_filter self = service->child; // Get coords in/out/track int track = mlt_filter_get_track( self ); int in = mlt_filter_get_in( self ); int out = mlt_filter_get_out( self ); // Get the producer this is connected to mlt_service producer = mlt_service_producer( &self->parent ); // If the frame request is for this filters track, we need to process it if ( index == track || track == -1 ) { int ret = mlt_service_get_frame( producer, frame, index ); if ( ret == 0 ) { mlt_position position = mlt_frame_get_position( *frame ); if ( position >= in && ( out == 0 || position <= out ) ) *frame = mlt_filter_process( self, *frame ); return 0; } else { *frame = mlt_frame_init( service ); return 0; } } else { return mlt_service_get_frame( producer, frame, index ); } }
static int getFrame(mlt_producer producer, mlt_frame_ptr frame, int /*index*/) { // Generate a frame *frame = mlt_frame_init(MLT_PRODUCER_SERVICE(producer)); if (*frame) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES(*frame); // Set the producer on the frame properties mlt_properties_set_data(properties, kWebVfxProducerPropertyName, producer, 0, NULL, NULL); // Update timecode on the frame we're creating mlt_position position = mlt_producer_position(producer); mlt_frame_set_position(*frame, position); mlt_properties_set_position(properties, kWebVfxPositionPropertyName, position); // Set producer-specific frame properties mlt_properties_set_int(properties, "progressive", 1); // Push the get_image method mlt_frame_push_get_image(*frame, producerGetImage); } // Calculate the next timecode mlt_producer_prepare_next(producer); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_frame( producer ) ); mlt_properties_set_int( frame_properties, "progressive", 1 ); mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( frame_properties, "meta.media.width", profile->width ); mlt_properties_set_int( frame_properties, "meta.media.height", profile->height ); // Configure callbacks mlt_frame_push_service( *frame, producer ); mlt_frame_push_get_image( *frame, producer_get_image ); mlt_frame_push_audio( *frame, producer ); mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; }
static void foreach_consumer_stop( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; struct timespec tm = { 0, 1000 * 1000 }; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { // Let consumer with terminate_on_pause stop on their own if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(nested), "terminate_on_pause" ) ) { // Send additional dummy frame to unlatch nested consumer's threads mlt_consumer_put_frame( nested, mlt_frame_init( MLT_CONSUMER_SERVICE(consumer) ) ); // wait for stop while ( !mlt_consumer_is_stopped( nested ) ) nanosleep( &tm, NULL ); } else { mlt_consumer_stop( nested ); } } } while ( nested ); }
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) { // Get the mutiltrack object mlt_multitrack self = parent->child; // Check if we have a track for this index if ( index >= 0 && index < self->count && self->list[ index ] != NULL ) { // Get the producer for this track mlt_producer producer = self->list[ index ]->producer; // Get the track hide property int hide = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ), "hide" ); // Obtain the current position mlt_position position = mlt_producer_frame( parent ); // Get the parent properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the speed double speed = mlt_properties_get_double( producer_properties, "_speed" ); // Make sure we're at the same point mlt_producer_seek( producer, position ); // Get the frame from the producer mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), frame, 0 ); // Indicate speed of this producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_double( properties, "_speed", speed ); mlt_frame_set_position( *frame, position ); mlt_properties_set_int( properties, "hide", hide ); } else { // Generate a test frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); // Update position on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( parent ) ); // Move on to the next frame if ( index >= self->count ) { // Let tractor know if we've reached the end mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "last_track", 1 ); // Move to the next frame mlt_producer_prepare_next( parent ); } } return 0; }
static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { mlt_service_base *base = self->local; if ( index < base->count ) { mlt_service producer = base->in[ index ]; if ( producer != NULL ) return mlt_service_get_frame( producer, frame, index ); } *frame = mlt_frame_init( self ); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_qimage self = producer->child; // Fetch the producers properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL ) load_filenames( self, producer_properties ); // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL && self->count > 0 ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_qimage", self, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Ensure that we have a way to obtain the position in the get_image mlt_properties_set_position( properties, "qimage_position", mlt_producer_position( producer ) ); // Refresh the image self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage = mlt_cache_item_data( self->qimage_cache, NULL ); refresh_qimage( self, *frame ); mlt_cache_item_close( self->qimage_cache ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { producer_qimage self = calloc( sizeof( struct producer_qimage_s ), 1 ); if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 ) { mlt_producer producer = &self->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); // Callback registration #ifdef USE_KDE init_qimage(); #endif producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "seekable", 1 ); // Validate the resource if ( filename ) load_filenames( self, properties ); if ( self->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_data( frame_properties, "producer_qimage", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); mlt_properties_set_position( frame_properties, "qimage_position", mlt_producer_position( producer ) ); refresh_qimage( self, frame ); mlt_cache_item_close( self->qimage_cache ); mlt_frame_close( frame ); } } if ( self->current_width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Regenerate the QPainterPath if necessary if( check_qpath( producer_properties ) ) { generate_qpath( producer_properties ); } // Give the frame a copy of the painter path QPainterPath* prodPath = static_cast<QPainterPath*>( mlt_properties_get_data( producer_properties, "_qpath", NULL ) ); QPainterPath* framePath = new QPainterPath( *prodPath ); mlt_properties_set_data( frame_properties, "_qpath", static_cast<void*>( framePath ), 0, close_qpath, NULL ); // Pass properties to the frame that will be needed to render the path mlt_properties_set( frame_properties, "_path_sig", mlt_properties_get( producer_properties, "_path_sig" ) ); mlt_properties_set( frame_properties, "_bgcolour", mlt_properties_get( producer_properties, "bgcolour" ) ); mlt_properties_set( frame_properties, "_fgcolour", mlt_properties_get( producer_properties, "fgcolour" ) ); mlt_properties_set( frame_properties, "_olcolour", mlt_properties_get( producer_properties, "olcolour" ) ); mlt_properties_set( frame_properties, "_outline", mlt_properties_get( producer_properties, "outline" ) ); mlt_properties_set_data( frame_properties, "_producer_qtext", static_cast<void*>( producer ), 0, NULL, NULL ); // Set frame properties mlt_properties_set_int( frame_properties, "progressive", 1 ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( frame_properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( frame_properties, "aspect_ratio", 1.0); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Configure callbacks mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; }
mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf self = calloc( 1, sizeof( struct producer_pixbuf_s ) ); if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 ) { mlt_producer producer = &self->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "seekable", 1 ); mlt_properties_set_int( properties, "loop", 1 ); // Validate the resource if ( filename ) load_filenames( self, properties ); if ( self->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_data( frame_properties, "producer_pixbuf", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); refresh_pixbuf( self, frame ); mlt_cache_item_close( self->pixbuf_cache ); mlt_frame_close( frame ); } } if ( self->width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { if ( frame ) { // Construct a new frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Stack the producer and producer's get image mlt_frame_push_service_int( *frame, index ); mlt_frame_push_service( *frame, producer ); mlt_frame_push_service( *frame, framebuffer_get_image ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES(*frame); // Get frame from the real producer mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); 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, mlt_producer_position( producer ) ); // 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_inherit( frame_properties, MLT_FRAME_PROPERTIES(first_frame) ); double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); if ( force_aspect_ratio <= 0.0 ) force_aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); mlt_properties_set_double( frame_properties, "aspect_ratio", force_aspect_ratio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); mlt_properties_set_int( frame_properties, "meta.media.width", mlt_properties_get_int( properties, "width" ) ); mlt_properties_set_int( frame_properties, "meta.media.height", mlt_properties_get_int( properties, "height" ) ); mlt_properties_pass_list( frame_properties, properties, "width, height" ); } return 0; }
mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); // Validate the resource if ( filename ) load_filenames( this, properties ); if ( this->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); pthread_mutex_init( &this->mutex, NULL ); mlt_properties_set_data( frame_properties, "producer_pixbuf", this, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); mlt_properties_set_position( frame_properties, "pixbuf_position", mlt_producer_position( producer ) ); refresh_image( this, frame, 0, 0 ); mlt_frame_close( frame ); } } if ( this->width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( this ); return NULL; }
static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child; mlt_position pos = mlt_producer_position( producer ); mlt_position end = mlt_producer_get_playtime( producer ); end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1; // Re-open if needed if ( !decklink && pos < end ) { producer->child = decklink = new DeckLinkProducer(); decklink->setProducer( producer ); decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) ); } // Start if needed if ( decklink ) { decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ); // Get the next frame from the decklink object if ( ( *frame = decklink->getFrame() )) { // Add audio and video getters mlt_frame_push_audio( *frame, (void*) get_audio ); mlt_frame_push_get_image( *frame, get_image ); } } if ( !*frame ) *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); // Close DeckLink if at end if ( pos >= end && decklink ) { decklink->stop(); delete decklink; producer->child = NULL; } return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_kino this = producer->child; uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Obtain the current frame number uint64_t position = mlt_producer_frame( producer ); // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Seek and fetch if ( kino_wrapper_get_frame( this->wrapper, data, position ) ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Determine if we're PAL or NTSC int is_pal = kino_wrapper_is_pal( this->wrapper ); // Pass the dv data mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); // Update other info on the frame mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); } else { mlt_pool_release( data ); } // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; }
static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_ktitle this = producer->child; /* Generate a frame */ *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { /* Obtain properties of frame and producer */ mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); /* Set the producer on the frame properties */ mlt_properties_set_data( properties, "producer_kdenlivetitle", this, 0, NULL, NULL ); /* Update timecode on the frame we're creating */ mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_props, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_props, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); /* Push the get_image method */ mlt_frame_push_get_image( *frame, producer_get_image ); } /* Calculate the next timecode */ mlt_producer_prepare_next( producer ); return 0; }
int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { int result = 0; // Lock the service mlt_service_lock( self ); // Ensure that the frame is NULL *frame = NULL; // Only process if we have a valid service if ( self != NULL && self->get_frame != NULL ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); mlt_position position = mlt_service_identify( self ) == producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1; result = self->get_frame( self, frame, index ); if ( result == 0 ) { mlt_properties_inc_ref( properties ); properties = MLT_FRAME_PROPERTIES( *frame ); if ( in >=0 && out > 0 ) { mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } mlt_service_apply_filters( self, *frame, 1 ); mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), self ); if ( mlt_service_identify( self ) == producer_type && mlt_properties_get_int( MLT_SERVICE_PROPERTIES( self ), "_need_previous_next" ) ) { // Save the new position from self->get_frame mlt_position new_position = mlt_producer_position( MLT_PRODUCER( self ) ); // Get the preceding frame, unfiltered mlt_frame previous_frame; mlt_producer_seek( MLT_PRODUCER(self), position - 1 ); result = self->get_frame( self, &previous_frame, index ); if ( !result ) mlt_properties_set_data( properties, "previous frame", previous_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL ); // Get the following frame, unfiltered mlt_frame next_frame; mlt_producer_seek( MLT_PRODUCER(self), position + 1 ); result = self->get_frame( self, &next_frame, index ); if ( !result ) { mlt_properties_set_data( properties, "next frame", next_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL ); } // Restore the new position mlt_producer_seek( MLT_PRODUCER(self), new_position ); } } } // Make sure we return a frame if ( *frame == NULL ) *frame = mlt_frame_init( self ); // Unlock the service mlt_service_unlock( self ); return result; }
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; }
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; }
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; } }
static int get_frame( mlt_producer self, mlt_frame_ptr frame, int index ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES(self); context cx = mlt_properties_get_data( properties, "context", NULL ); if ( !cx ) { // Allocate and initialize our context cx = mlt_pool_alloc( sizeof( struct context_s ) ); memset( cx, 0, sizeof( *cx ) ); mlt_properties_set_data( properties, "context", cx, 0, mlt_pool_release, NULL ); cx->self = self; char *profile_name = mlt_properties_get( properties, "profile" ); if ( !profile_name ) profile_name = mlt_properties_get( properties, "mlt_profile" ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); if ( profile_name ) { cx->profile = mlt_profile_init( profile_name ); cx->profile->is_explicit = 1; } else { cx->profile = mlt_profile_clone( profile ); cx->profile->is_explicit = 0; } // Encapsulate a real producer for the resource cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); if ( ( profile_name && !strcmp( profile_name, "auto" ) ) || mlt_properties_get_int( properties, "autoprofile" ) ) { mlt_profile_from_producer( cx->profile, cx->producer ); mlt_producer_close( cx->producer ); cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); } // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( cx->producer, 0 ); cx->audio_position = -1; // We will encapsulate a consumer cx->consumer = mlt_consumer_new( cx->profile ); // Do not use _pass_list on real_time so that it defaults to 0 in the absence of // an explicit real_time property. mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx->consumer ), "real_time", mlt_properties_get_int( properties, "real_time" ) ); mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, "buffer, prefill, deinterlace_method, rescale" ); // Connect it all together mlt_consumer_connect( cx->consumer, MLT_PRODUCER_SERVICE( cx->producer ) ); mlt_consumer_start( cx->consumer ); } // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( self ) ); if ( *frame ) { // Seek the producer to the correct place // Calculate our positions double actual_position = (double) mlt_producer_frame( self ); if ( mlt_producer_get_speed( self ) != 0 ) actual_position *= mlt_producer_get_speed( self ); mlt_position need_first = floor( actual_position ); mlt_producer_seek( cx->producer, lrint( need_first * mlt_profile_fps( cx->profile ) / mlt_producer_get_fps( self ) ) ); // Get the nested frame mlt_frame nested_frame = mlt_consumer_rt_frame( cx->consumer ); // Stack the producer and our methods on the nested frame mlt_frame_push_service( *frame, nested_frame ); mlt_frame_push_service( *frame, cx ); mlt_frame_push_get_image( *frame, get_image ); mlt_frame_push_audio( *frame, nested_frame ); mlt_frame_push_audio( *frame, cx ); mlt_frame_push_audio( *frame, get_audio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( self ) ); // Store the nested frame on the produced frame for destruction mlt_properties frame_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_data( frame_props, "_producer_consumer.frame", nested_frame, 0, (mlt_destructor) mlt_frame_close, NULL ); // Inform the normalizers about our video properties mlt_properties_set_double( frame_props, "aspect_ratio", mlt_profile_sar( cx->profile ) ); mlt_properties_set_int( frame_props, "width", cx->profile->width ); mlt_properties_set_int( frame_props, "height", cx->profile->height ); mlt_properties_set_int( frame_props, "meta.media.width", cx->profile->width ); mlt_properties_set_int( frame_props, "meta.media.height", cx->profile->height ); mlt_properties_set_int( frame_props, "progressive", cx->profile->progressive ); } // Calculate the next timecode mlt_producer_prepare_next( self ); return 0; }
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; }
mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ) { mlt_frame new_frame = mlt_frame_init( NULL ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame ); void *data, *copy; int size; mlt_properties_inherit( new_props, properties ); // Carry over some special data properties for the multi consumer. mlt_properties_set_data( new_props, "_producer", mlt_frame_get_original_producer( self ), 0, NULL, NULL ); mlt_properties_set_data( new_props, "movit.convert", mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL ); if ( is_deep ) { data = mlt_properties_get_data( properties, "audio", &size ); if ( data ) { if ( !size ) size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ), mlt_properties_get_int( properties, "audio_samples" ), mlt_properties_get_int( properties, "audio_channels" ) ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL ); } data = mlt_properties_get_data( properties, "image", &size ); if ( data ) { if ( ! size ) size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ), mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" ), NULL ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); if ( data ) { if ( ! size ) size = mlt_properties_get_int( properties, "width" ) * mlt_properties_get_int( properties, "height" ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL ); }; } } else { // This frame takes a reference on the original frame since the data is a shallow copy. mlt_properties_inc_ref( properties ); mlt_properties_set_data( new_props, "_cloned_frame", self, 0, (mlt_destructor) mlt_frame_close, NULL ); // Copy properties data = mlt_properties_get_data( properties, "audio", &size ); mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "image", &size ); mlt_properties_set_data( new_props, "image", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL ); } return new_frame; }