]> git.sesse.net Git - mlt/blob - src/modules/westley/consumer_westley.c
some bugfixes, westley property handling reorg, make rescale respect the aspect ratio...
[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 1
100                         p = xmlNewChild( node, NULL, "property", NULL );
101                         xmlNewProp( p, "name", mlt_properties_get_name( properties, i ) );
102                         xmlNodeSetContent( p, mlt_properties_get_value( properties, i ) );
103 #else
104                         p = node;
105                         xmlNewProp( p, mlt_properties_get_name( properties, i ), mlt_properties_get_value( properties, i ) );
106 #endif
107                 }
108         }
109 }
110
111 static void serialise_service( serialise_context context, mlt_service service, xmlNode *node )
112 {
113         int i;
114         xmlNode *child = node;
115         char id[ ID_SIZE + 1 ];
116         char key[ 11 ];
117         id[ ID_SIZE ] = '\0';
118         key[ 10 ] = '\0';
119         
120         // Iterate over consumer/producer connections
121         while ( service != NULL )
122         {
123                 mlt_properties properties = mlt_service_properties( service );
124                 char *mlt_type = mlt_properties_get( properties, "mlt_type" );
125                 
126                 // Tell about the producer
127                 if ( strcmp( mlt_type, "producer" ) == 0 )
128                 {
129                         if ( context->pass == 0 )
130                         {
131                                 child = xmlNewChild( node, NULL, "producer", NULL );
132
133                                 // Set the id
134                                 if ( mlt_properties_get( properties, "id" ) == NULL )
135                                 {
136                                         snprintf( id, ID_SIZE, "producer%d", context->producer_count++ );
137                                         xmlNewProp( child, "id", id );
138                                 }
139                                 else
140                                         strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
141                                 serialise_properties( properties, child );
142
143                                 // Add producer to the map
144                                 snprintf( key, 10, "%p", service );
145                                 mlt_properties_set( context->producer_map, key, id );
146                         }
147                         else
148                         {
149                                 snprintf( key, 10, "%p", service );
150                                 xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
151                         }
152                         if ( mlt_properties_get( properties, "westley" ) != NULL )
153                                 break;
154                 }
155
156                 // Tell about the framework container producers
157                 else if ( strcmp( mlt_type, "mlt_producer" ) == 0 )
158                 {
159                         // Recurse on multitrack's tracks
160                         if ( strcmp( mlt_properties_get( properties, "resource" ), "<multitrack>" ) == 0 )
161                         {
162                                 if ( context->pass == 0 )
163                                 {
164                                         // Iterate over the tracks
165                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
166                                         {
167                                                 serialise_service( context, MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ), node );
168                                         }
169                                 }
170                                 else
171                                 {
172                                         // Iterate over the tracks to collect the producers
173                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
174                                         {
175                                                 serialise_service( context, MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ), node );
176                                         }
177
178                                         child = xmlNewChild( node, NULL, "multitrack", NULL );
179                                 
180                                         // Set the id
181                                         if ( mlt_properties_get( properties, "id" ) == NULL )
182                                         {
183                                                 snprintf( id, ID_SIZE, "multitrack%d", context->multitrack_count++ );
184                                                 xmlNewProp( child, "id", id );
185                                         }
186
187                                         // Iterate over the tracks
188                                         for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
189                                         {
190                                                 xmlNode *track = xmlNewChild( child, NULL, "track", NULL );
191                                                 snprintf( key, 10, "%p", MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ) );
192                                                 xmlNewProp( track, "producer", mlt_properties_get( context->producer_map, key ) );
193                                         }
194                                 }
195                                 break;
196                         }
197                         
198                         // Recurse on playlist's clips
199                         else if ( strcmp( mlt_properties_get( properties, "resource" ), "<playlist>" ) == 0 )
200                         {
201                                 mlt_playlist_clip_info info;
202
203                                 if ( context->pass == 0 )
204                                 {
205                                         // Iterate over the playlist entries to collect the producers
206                                         for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
207                                         {
208                                                 if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
209                                                 {
210                                                         if ( strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) != 0 )
211                                                         {
212                                                                 serialise_service( context, MLT_SERVICE( info.producer ), node );
213                                                         }
214                                                 }
215                                         }
216                                         
217                                         child = xmlNewChild( node, NULL, "playlist", NULL );
218
219                                         // Set the id
220                                         if ( mlt_properties_get( properties, "id" ) == NULL )
221                                         {
222                                                 snprintf( id, ID_SIZE, "playlist%d", context->playlist_count++ );
223                                                 xmlNewProp( child, "id", id );
224                                         }
225                                         else
226                                                 strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
227
228                                         xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
229                                         xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
230
231                                         // Add producer to the map
232                                         snprintf( key, 10, "%p", service );
233                                         mlt_properties_set( context->producer_map, key, id );
234                                 
235                                         // Iterate over the playlist entries
236                                         for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
237                                         {
238                                                 if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
239                                                 {
240                                                         if ( strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) == 0 )
241                                                         {
242                                                                 char length[ 20 ];
243                                                                 length[ 19 ] = '\0';
244                                                                 xmlNode *entry = xmlNewChild( child, NULL, "blank", NULL );
245                                                                 snprintf( length, 19, "%lld", info.frame_count );
246                                                                 xmlNewProp( entry, "length", length );
247                                                         }
248                                                         else
249                                                         {
250                                                                 xmlNode *entry = xmlNewChild( child, NULL, "entry", NULL );
251                                                                 snprintf( key, 10, "%p", MLT_SERVICE( info.producer ) );
252                                                                 xmlNewProp( entry, "producer", mlt_properties_get( context->producer_map, key ) );
253                                                         }
254                                                 }
255                                         }
256                                 }
257                                 else if ( strcmp( (const char*) node->name, "tractor" ) != 0 )
258                                 {
259                                         snprintf( key, 10, "%p", service );
260                                         xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
261                                 }
262                         }
263                         
264                         // Recurse on tractor's producer
265                         else if ( strcmp( mlt_properties_get( properties, "resource" ), "<tractor>" ) == 0 )
266                         {
267                                 if ( context->pass == 0 )
268                                 {
269                                         // Recurse on connected producer
270                                         serialise_service( context, mlt_service_get_producer( service ), node );
271                                 }
272                                 else
273                                 {
274                                         child = xmlNewChild( node, NULL, "tractor", NULL );
275
276                                         // Set the id
277                                         if ( mlt_properties_get( properties, "id" ) == NULL )
278                                         {
279                                                 snprintf( id, ID_SIZE, "tractor%d", context->tractor_count++ );
280                                                 xmlNewProp( child, "id", id );
281                                         }
282                                         
283                                         xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
284                                         xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
285
286                                         // Recurse on connected producer
287                                         serialise_service( context, mlt_service_get_producer( service ), child );
288                                 }
289                                 break;
290                         }
291                 }
292                 
293                 // Tell about a filter
294                 else if ( strcmp( mlt_type, "filter" ) == 0 )
295                 {
296                         // Recurse on connected producer
297                         serialise_service( context, MLT_SERVICE( MLT_FILTER( service )->producer ), node );
298
299                         if ( context->pass == 1 )
300                         {
301                                 child = xmlNewChild( node, NULL, "filter", NULL );
302
303                                 // Set the id
304                                 if ( mlt_properties_get( properties, "id" ) == NULL )
305                                 {
306                                         snprintf( id, ID_SIZE, "filter%d", context->filter_count++ );
307                                         xmlNewProp( child, "id", id );
308                                 }
309
310                                 serialise_properties( properties, child );
311                         }
312                         break;
313                 }
314                 
315                 // Tell about a transition
316                 else if ( strcmp( mlt_type, "transition" ) == 0 )
317                 {
318                         // Recurse on connected producer
319                         serialise_service( context, MLT_SERVICE( MLT_TRANSITION( service )->producer ), node );
320
321                         if ( context->pass == 1 )
322                         {
323                                 child = xmlNewChild( node, NULL, "transition", NULL );
324                         
325                                 // Set the id
326                                 if ( mlt_properties_get( properties, "id" ) == NULL )
327                                 {
328                                         snprintf( id, ID_SIZE, "transition%d", context->transition_count++ );
329                                         xmlNewProp( child, "id", id );
330                                 }
331
332                                 serialise_properties( properties, child );
333                         }
334                         break;
335                 }
336                 
337                 // Get the next connected service
338                 service = mlt_service_get_producer( service );
339         }
340 }
341
342 static int consumer_start( mlt_consumer this )
343 {
344         mlt_service inigo = NULL;
345         xmlDoc *doc = xmlNewDoc( "1.0" );
346         xmlNode *root = xmlNewNode( NULL, "westley" );
347         xmlDocSetRootElement( doc, root );
348         
349         // Get the producer service
350         mlt_service service = mlt_service_get_producer( mlt_consumer_service( this ) );
351         if ( service != NULL )
352         {
353                 struct serialise_context_s *context = calloc( 1, sizeof( struct serialise_context_s ) );
354                 context->producer_map = mlt_properties_new();
355                 
356                 // Remember inigo
357                 if ( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ) != NULL &&
358                                 strcmp( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ), "inigo" ) == 0 )
359                         inigo = service;
360                 
361                 // Ensure producer is a framework producer
362                 mlt_properties_set( mlt_service_properties( service ), "mlt_type", "mlt_producer" );
363
364                 // In pass one, we serialise the end producers and playlists,
365                 // adding them to a map keyed by address.
366                 serialise_service( context, service, root );
367
368                 // In pass two, we serialise the tractor and reference the
369                 // producers and playlists
370                 context->pass++;
371                 serialise_service( context, service, root );
372
373                 mlt_properties_close( context->producer_map );
374                 free( context );
375                 
376                 if ( mlt_properties_get( mlt_consumer_properties( this ), "resource" ) == NULL )
377                         xmlDocFormatDump( stdout, doc, 1 );
378                 else
379                         xmlSaveFormatFile( mlt_properties_get( mlt_consumer_properties( this ), "resource" ), doc, 1 );
380         }
381
382         xmlFreeDoc( doc );
383         mlt_consumer_stop( this );
384
385         return 0;
386 }
387
388 static int consumer_is_stopped( mlt_consumer this )
389 {
390         return 1;
391 }
392