+ int result = 0;
+
+ // Lock the service
+ mlt_service_lock( this );
+
+ // Ensure that the frame is NULL
+ *frame = NULL;
+
+ // Only process if we have a valid service
+ if ( this != NULL && this->get_frame != NULL )
+ {
+ mlt_properties properties = MLT_SERVICE_PROPERTIES( this );
+ mlt_position in = mlt_properties_get_position( properties, "in" );
+ mlt_position out = mlt_properties_get_position( properties, "out" );
+
+ result = this->get_frame( this, 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( this, *frame, 1 );
+ mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), this );
+ }
+ }
+
+ // Make sure we return a frame
+ if ( *frame == NULL )
+ *frame = mlt_frame_init( this );
+
+ // Unlock the service
+ mlt_service_unlock( this );
+
+ return result;
+}
+
+/** The service-changed event handler.
+ *
+ * \private \memberof mlt_service_s
+ * \param owner ignored
+ * \param this the service on which the "service-changed" event is fired
+ */
+
+static void mlt_service_filter_changed( mlt_service owner, mlt_service this )
+{
+ mlt_events_fire( MLT_SERVICE_PROPERTIES( this ), "service-changed", NULL );
+}
+
+/** Attach a filter.
+ *
+ * \public \memberof mlt_service_s
+ * \param this a service
+ * \param filter the filter to attach
+ * \return true if there was an error
+ */
+
+int mlt_service_attach( mlt_service this, mlt_filter filter )
+{
+ int error = this == NULL || filter == NULL;
+ if ( error == 0 )
+ {
+ int i = 0;
+ mlt_properties properties = MLT_SERVICE_PROPERTIES( this );
+ mlt_service_base *base = this->local;
+
+ for ( i = 0; error == 0 && i < base->filter_count; i ++ )
+ if ( base->filters[ i ] == filter )
+ error = 1;
+
+ if ( error == 0 )
+ {
+ if ( base->filter_count == base->filter_size )
+ {
+ base->filter_size += 10;
+ base->filters = realloc( base->filters, base->filter_size * sizeof( mlt_filter ) );
+ }
+
+ if ( base->filters != NULL )
+ {
+ mlt_properties props = MLT_FILTER_PROPERTIES( filter );
+ mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter ) );
+ base->filters[ base->filter_count ++ ] = filter;
+ mlt_events_fire( properties, "service-changed", NULL );
+ mlt_events_listen( props, this, "service-changed", ( mlt_listener )mlt_service_filter_changed );
+ mlt_events_listen( props, this, "property-changed", ( mlt_listener )mlt_service_filter_changed );
+ }
+ else
+ {
+ error = 2;
+ }
+ }
+ }
+ return error;
+}
+
+/** Detach a filter.
+ *
+ * \public \memberof mlt_service_s
+ * \param this a service
+ * \param filter the filter to detach
+ * \return true if there was an error
+ */
+
+int mlt_service_detach( mlt_service this, mlt_filter filter )
+{
+ int error = this == NULL || filter == NULL;
+ if ( error == 0 )
+ {
+ int i = 0;
+ mlt_service_base *base = this->local;
+ mlt_properties properties = MLT_SERVICE_PROPERTIES( this );
+
+ for ( i = 0; i < base->filter_count; i ++ )
+ if ( base->filters[ i ] == filter )
+ break;
+
+ if ( i < base->filter_count )
+ {
+ base->filters[ i ] = NULL;
+ for ( i ++ ; i < base->filter_count; i ++ )
+ base->filters[ i - 1 ] = base->filters[ i ];
+ base->filter_count --;
+ mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), this );
+ mlt_filter_close( filter );
+ mlt_events_fire( properties, "service-changed", NULL );
+ }
+ }
+ return error;
+}
+
+/** Retrieve a filter.
+ *
+ * \public \memberof mlt_service_s
+ * \param this a service
+ * \param index which one of potentially multiple filters
+ * \return the filter or null if there was an error
+ */
+
+mlt_filter mlt_service_filter( mlt_service this, int index )
+{
+ mlt_filter filter = NULL;