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