]> git.sesse.net Git - mlt/blob - src/modules/westley/consumer_westley.c
adding the rock thrower...
[mlt] / src / modules / westley / consumer_westley.c
1 /*
2  * consumer_westley.c -- a libxml2 serialiser of mlt service networks
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "consumer_westley.h"
22 #include <framework/mlt.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <pthread.h>
27 #include <libxml/tree.h>
28
29 #define ID_SIZE 128
30
31 /** Forward references to static functions.
32 */
33
34 static int consumer_start( mlt_consumer parent );
35 static int consumer_is_stopped( mlt_consumer this );
36
37 /** This is what will be called by the factory - anything can be passed in
38         via the argument, but keep it simple.
39 */
40
41 mlt_consumer consumer_westley_init( char *arg )
42 {
43         // Create the consumer object
44         mlt_consumer this = calloc( sizeof( struct mlt_consumer_s ), 1 );
45
46         // If no malloc'd and consumer init ok
47         if ( this != NULL && mlt_consumer_init( this, NULL ) == 0 )
48         {
49                 // We have stuff to clean up, so override the close method
50                 //parent->close = consumer_close;
51
52                 // Allow thread to be started/stopped
53                 this->start = consumer_start;
54                 this->is_stopped = consumer_is_stopped;
55
56                 mlt_properties_set( mlt_consumer_properties( this ), "resource", arg );
57
58                 // Return the consumer produced
59                 return this;
60         }
61
62         // malloc or consumer init failed
63         free( this );
64
65         // Indicate failure
66         return NULL;
67 }
68
69
70 // This maintains counters for adding ids to elements
71 struct serialise_context_s
72 {
73         int producer_count;
74         int multitrack_count;
75         int playlist_count;
76         int tractor_count;
77         int filter_count;
78         int transition_count;
79         int pass;
80         mlt_properties producer_map;
81 };
82 typedef struct serialise_context_s* serialise_context;
83
84
85 static inline void serialise_properties( mlt_properties properties, xmlNode *node )
86 {
87         int i;
88         xmlNode *p;
89         
90         // Enumerate the properties
91         for ( i = 0; i < mlt_properties_count( properties ); i++ )
92         {
93                 char *name = mlt_properties_get_name( properties, i );
94                 if ( name != NULL &&
95                          name[ 0 ] != '_' &&
96                          mlt_properties_get_value( properties, i ) != NULL &&
97                          strcmp( name, "westley" ) != 0 )
98                 {
99 #if 0
100                         p = xmlNewChild( node, NULL, "prop", NULL );
101 #else
102                         p = node;
103 #endif
104                         xmlNewProp( p, mlt_properties_get_name( properties, i ), mlt_properties_get_value( properties, i ) );
105                 }
106         }
107 }
108
109 static void serialise_service( serialise_context context, mlt_service service, xmlNode *node )
110 {
111         int i;
112         xmlNode *child = node;
113         char id[ ID_SIZE + 1 ];
114         char key[ 11 ];
115         id[ ID_SIZE ] = '\0';
116         key[ 10 ] = '\0';
117         
118         // Iterate over consumer/producer connections
119         while ( service != NULL )
120         {
121                 mlt_properties properties = mlt_service_properties( service );
122                 char *mlt_type = mlt_properties_get( properties, "mlt_type" );
123                 
124                 // Tell about the producer
125                 if ( strcmp( mlt_type, "producer" ) == 0 )
126                 {
127                         if ( context->pass == 0 )
128                         {
129                                 child = xmlNewChild( node, NULL, "producer", NULL );
130
131                                 // Set the id
132                                 if ( mlt_properties_get( properties, "id" ) == NULL )
133                                 {
134                                         snprintf( id, ID_SIZE, "producer%d", context->producer_count++ );
135                                         xmlNewProp( child, "id", id );
136                                 }
137                                 else
138                                         strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
139                                 serialise_properties( properties, child );
140
141                                 // Add producer to the map
142                                 snprintf( key, 10, "%p", service );
143                                 mlt_properties_set( context->producer_map, key, id );
144                         }
145                         else
146                         {
147                                 snprintf( key, 10, "%p", service );
148                                 xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
149                         }
150                         if ( mlt_properties_get( properties, "westley" ) != NULL )
151                                 break;
152                 }
153
154                 // Tell about the framework container producers
155                 else if ( strcmp( mlt_type, "mlt_producer" ) == 0 )
156                 {
157                         // Recurse on multitrack's tracks
158                         if ( strcmp( mlt_properties_get( properties, "resource" ), "<multitrack>" ) == 0 )
159                         {
160                                 if ( context->pass == 0 )
161                                 {
162                                         // Iterate over the tracks
163                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
164                                         {
165                                                 serialise_service( context, MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ), node );
166                                         }
167                                 }
168                                 else
169                                 {
170                                         // Iterate over the tracks to collect the producers
171                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
172                                         {
173                                                 serialise_service( context, MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ), node );
174                                         }
175
176                                         child = xmlNewChild( node, NULL, "multitrack", NULL );
177                                 
178                                         // Set the id
179                                         if ( mlt_properties_get( properties, "id" ) == NULL )
180                                         {
181                                                 snprintf( id, ID_SIZE, "multitrack%d", context->multitrack_count++ );
182                                                 xmlNewProp( child, "id", id );
183                                         }
184
185                                         // Iterate over the tracks
186                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
187                                         {
188                                                 xmlNode *track = xmlNewChild( child, NULL, "track", NULL );
189                                                 snprintf( key, 10, "%p", MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ) );
190                                                 xmlNewProp( track, "producer", mlt_properties_get( context->producer_map, key ) );
191                                         }
192                                 }
193                                 break;
194                         }
195                         
196                         // Recurse on playlist's clips
197                         else if ( strcmp( mlt_properties_get( properties, "resource" ), "<playlist>" ) == 0 )
198                         {
199                                 mlt_playlist_clip_info info;
200
201                                 if ( context->pass == 0 )
202                                 {
203                                         // Iterate over the playlist entries to collect the producers
204                                         for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
205                                         {
206                                                 if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
207                                                 {
208                                                         if ( strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) != 0 )
209                                                         {
210                                                                 serialise_service( context, MLT_SERVICE( info.producer ), node );
211                                                         }
212                                                 }
213                                         }
214                                         
215                                         child = xmlNewChild( node, NULL, "playlist", NULL );
216
217                                         // Set the id
218                                         if ( mlt_properties_get( properties, "id" ) == NULL )
219                                         {
220                                                 snprintf( id, ID_SIZE, "playlist%d", context->playlist_count++ );
221                                                 xmlNewProp( child, "id", id );
222                                         }
223                                         else
224                                                 strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
225
226                                         xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
227                                         xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
228
229                                         // Add producer to the map
230                                         snprintf( key, 10, "%p", service );
231                                         mlt_properties_set( context->producer_map, key, id );
232                                 
233                                         // Iterate over the playlist entries
234                                         for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
235                                         {
236                                                 if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
237                                                 {
238                                                         if ( strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) == 0 )
239                                                         {
240                                                                 char length[ 20 ];
241                                                                 length[ 19 ] = '\0';
242                                                                 xmlNode *entry = xmlNewChild( child, NULL, "blank", NULL );
243                                                                 snprintf( length, 19, "%lld", info.frame_count );
244                                                                 xmlNewProp( entry, "length", length );
245                                                         }
246                                                         else
247                                                         {
248                                                                 xmlNode *entry = xmlNewChild( child, NULL, "entry", NULL );
249                                                                 snprintf( key, 10, "%p", MLT_SERVICE( info.producer ) );
250                                                                 xmlNewProp( entry, "producer", mlt_properties_get( context->producer_map, key ) );
251                                                         }
252                                                 }
253                                         }
254                                 }
255                                 else if ( strcmp( (const char*) node->name, "tractor" ) != 0 )
256                                 {
257                                         snprintf( key, 10, "%p", service );
258                                         xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
259                                 }
260                         }
261                         
262                         // Recurse on tractor's producer
263                         else if ( strcmp( mlt_properties_get( properties, "resource" ), "<tractor>" ) == 0 )
264                         {
265                                 if ( context->pass == 0 )
266                                 {
267                                         // Recurse on connected producer
268                                         serialise_service( context, mlt_service_get_producer( service ), node );
269                                 }
270                                 else
271                                 {
272                                         child = xmlNewChild( node, NULL, "tractor", NULL );
273
274                                         // Set the id
275                                         if ( mlt_properties_get( properties, "id" ) == NULL )
276                                         {
277                                                 snprintf( id, ID_SIZE, "tractor%d", context->tractor_count++ );
278                                                 xmlNewProp( child, "id", id );
279                                         }
280                                         
281                                         xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
282                                         xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
283
284                                         // Recurse on connected producer
285                                         serialise_service( context, mlt_service_get_producer( service ), child );
286                                 }
287                                 break;
288                         }
289                 }
290                 
291                 // Tell about a filter
292                 else if ( strcmp( mlt_type, "filter" ) == 0 )
293                 {
294                         // Recurse on connected producer
295                         serialise_service( context, MLT_SERVICE( MLT_FILTER( service )->producer ), node );
296
297                         if ( context->pass == 1 )
298                         {
299                                 child = xmlNewChild( node, NULL, "filter", NULL );
300
301                                 // Set the id
302                                 if ( mlt_properties_get( properties, "id" ) == NULL )
303                                 {
304                                         snprintf( id, ID_SIZE, "filter%d", context->filter_count++ );
305                                         xmlNewProp( child, "id", id );
306                                 }
307
308                                 serialise_properties( properties, child );
309                         }
310                         break;
311                 }
312                 
313                 // Tell about a transition
314                 else if ( strcmp( mlt_type, "transition" ) == 0 )
315                 {
316                         // Recurse on connected producer
317                         serialise_service( context, MLT_SERVICE( MLT_TRANSITION( service )->producer ), node );
318
319                         if ( context->pass == 1 )
320                         {
321                                 child = xmlNewChild( node, NULL, "transition", NULL );
322                         
323                                 // Set the id
324                                 if ( mlt_properties_get( properties, "id" ) == NULL )
325                                 {
326                                         snprintf( id, ID_SIZE, "transition%d", context->transition_count++ );
327                                         xmlNewProp( child, "id", id );
328                                 }
329
330                                 serialise_properties( properties, child );
331                         }
332                         break;
333                 }
334                 
335                 // Get the next connected service
336                 service = mlt_service_get_producer( service );
337         }
338 }
339
340 static int consumer_start( mlt_consumer this )
341 {
342         mlt_service inigo = NULL;
343         xmlDoc *doc = xmlNewDoc( "1.0" );
344         xmlNode *root = xmlNewNode( NULL, "westley" );
345         xmlDocSetRootElement( doc, root );
346         
347         // Get the producer service
348         mlt_service service = mlt_service_get_producer( mlt_consumer_service( this ) );
349         if ( service != NULL )
350         {
351                 struct serialise_context_s *context = calloc( 1, sizeof( struct serialise_context_s ) );
352                 context->producer_map = mlt_properties_new();
353                 
354                 // Remember inigo
355                 if ( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ) != NULL &&
356                                 strcmp( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ), "inigo" ) == 0 )
357                         inigo = service;
358                 
359                 // Ensure producer is a framework producer
360                 mlt_properties_set( mlt_service_properties( service ), "mlt_type", "mlt_producer" );
361
362                 // In pass one, we serialise the end producers and playlists,
363                 // adding them to a map keyed by address.
364                 serialise_service( context, service, root );
365
366                 // In pass two, we serialise the tractor and reference the
367                 // producers and playlists
368                 context->pass++;
369                 serialise_service( context, service, root );
370
371                 mlt_properties_close( context->producer_map );
372                 free( context );
373                 
374                 if ( mlt_properties_get( mlt_consumer_properties( this ), "resource" ) == NULL )
375                         xmlDocFormatDump( stdout, doc, 1 );
376                 else
377                         xmlSaveFormatFile( mlt_properties_get( mlt_consumer_properties( this ), "resource" ), doc, 1 );
378         }
379
380         xmlFreeDoc( doc );
381         mlt_consumer_stop( this );
382
383         return 0;
384 }
385
386 static int consumer_is_stopped( mlt_consumer this )
387 {
388         return 1;
389 }
390