+/** Listener for property changes.
+ *
+ * If the in, out, or length properties changed, fire a "producer-changed" event.
+ *
+ * \private \memberof mlt_producer_s
+ * \param owner a service (ignored)
+ * \param self the producer
+ * \param name the property that changed
+ */
+
+static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name )
+{
+ if ( !strcmp( name, "in" ) || !strcmp( name, "out" ) || !strcmp( name, "length" ) )
+ mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL );
+}
+
+/** Listener for service changes.
+ *
+ * Fires the "producer-changed" event.
+ *
+ * \private \memberof mlt_producer_s
+ * \param owner a service (ignored)
+ * \param self the producer
+ */
+
+static void mlt_producer_service_changed( mlt_service owner, mlt_producer self )
+{
+ mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL );
+}
+
+/** Create and initialize a new producer.
+ *
+ * \public \memberof mlt_producer_s
+ * \return the new producer
+ */
+
+mlt_producer mlt_producer_new( mlt_profile profile )
+{
+ mlt_producer self = malloc( sizeof( struct mlt_producer_s ) );
+ if ( self )
+ {
+ if ( mlt_producer_init( self, NULL ) == 0 )
+ {
+ mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL );
+ mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( self ), "aspect_ratio", mlt_profile_sar( profile ) );
+ }
+ else
+ {
+ free( self );
+ return NULL;
+ }
+ }
+ return self;
+}
+
+/** Determine if producer is a cut.
+ *
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \return true if \p self is a "cut" producer
+ * \see mlt_producer_cut
+ */
+
+int mlt_producer_is_cut( mlt_producer self )
+{
+ return mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( self ), "_cut" );
+}
+
+/** Determine if producer is a mix.
+ *
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \return true if \p self is a "mix" producer
+ * \todo Define a mix producer.
+ */
+
+int mlt_producer_is_mix( mlt_producer self )
+{
+ mlt_properties properties = self != NULL ? MLT_PRODUCER_PROPERTIES( self ) : NULL;
+ mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL;
+ return tractor != NULL;
+}
+
+/** Determine if the producer is a blank.
+ *
+ * Blank producers should only appear as an item in a playlist.
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \return true if \p self is a "blank" producer
+ * \see mlt_playlist_insert_blank
+ */
+
+int mlt_producer_is_blank( mlt_producer self )
+{
+ return self == NULL || !strcmp( mlt_properties_get( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "resource" ), "blank" );
+}
+
+/** Obtain the parent producer.
+ *
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \return either the parent producer if \p self is a "cut" producer or \p self otherwise.
+ */
+
+mlt_producer mlt_producer_cut_parent( mlt_producer self )
+{
+ mlt_properties properties = MLT_PRODUCER_PROPERTIES( self );
+ if ( mlt_producer_is_cut( self ) )
+ return mlt_properties_get_data( properties, "_cut_parent", NULL );
+ else
+ return self;
+}
+
+/** Create a cut of this producer.
+ *
+ * A "cut" is a portion of another (parent) producer.
+ *
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \param in the beginning
+ * \param out the end
+ * \return the new producer
+ * \todo Expand on the value of a cut.
+ */
+
+mlt_producer mlt_producer_cut( mlt_producer self, int in, int out )
+{
+ mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) );
+ mlt_producer parent = mlt_producer_cut_parent( self );
+ mlt_properties properties = MLT_PRODUCER_PROPERTIES( result );
+ mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent );
+
+ mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) );
+ // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0)
+ if ( in <= 0 )
+ in = 0;
+ if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) )
+ out = mlt_producer_get_length( parent ) - 1;
+
+ mlt_properties_inc_ref( parent_props );
+ mlt_properties_set_int( properties, "_cut", 1 );
+ mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL );
+ mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) );
+ mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) );
+ mlt_producer_set_in_and_out( result, in, out );
+
+ return result;
+}
+