2 * producer_consumer.c -- produce as a consumer of an encapsulated producer
3 * Copyright (C) 2008 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <framework/mlt.h>
30 mlt_producer producer
;
31 mlt_consumer consumer
;
35 typedef struct context_s
*context
;
38 static int get_image( mlt_frame frame
, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
40 context cx
= mlt_frame_pop_service( frame
);
41 mlt_frame nested_frame
= mlt_frame_pop_service( frame
);
43 *width
= cx
->profile
->width
;
44 *height
= cx
->profile
->height
;
46 int result
= mlt_frame_get_image( nested_frame
, image
, format
, width
, height
, writable
);
49 int size
= *width
* *height
* ( *format
== mlt_image_yuv422 ?
2 : *format
== mlt_image_rgb24 ?
3 : *format
== mlt_image_rgb24a ?
4 : ( 3 / 2 ) );
50 uint8_t *new_image
= mlt_pool_alloc( size
);
53 mlt_properties properties
= mlt_frame_properties( frame
);
54 mlt_properties_set_data( properties
, "image", new_image
, size
, mlt_pool_release
, NULL
);
55 memcpy( new_image
, *image
, size
);
56 mlt_frame_close( nested_frame
);
59 // mlt_properties_debug( properties, "frame", stderr );
60 // mlt_properties_debug( mlt_frame_properties( nested_frame ), "nested_frame", stderr );
65 static int get_audio( mlt_frame frame
, int16_t **buffer
, mlt_audio_format
*format
, int *frequency
, int *channels
, int *samples
)
67 mlt_frame nested_frame
= mlt_frame_pop_audio( frame
);
68 int result
= mlt_frame_get_audio( nested_frame
, buffer
, format
, frequency
, channels
, samples
);
69 int size
= *channels
* *samples
* sizeof( int16_t );
70 int16_t *new_buffer
= mlt_pool_alloc( size
);
71 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame
), "audio", new_buffer
, size
, mlt_pool_release
, NULL
);
72 memcpy( new_buffer
, *buffer
, size
);
74 mlt_frame_close( nested_frame
);
78 static int get_frame( mlt_producer
this, mlt_frame_ptr frame
, int index
)
80 mlt_properties properties
= MLT_PRODUCER_PROPERTIES(this);
81 context cx
= mlt_properties_get_data( properties
, "context", NULL
);
85 // Allocate and initialize our context
86 cx
= mlt_pool_alloc( sizeof( struct context_s
) );
87 mlt_properties_set_data( properties
, "context", cx
, 0, mlt_pool_release
, NULL
);
89 char *profile_name
= mlt_properties_get( properties
, "profile" );
90 mlt_profile profile
= mlt_service_profile( MLT_PRODUCER_SERVICE( this ) );
94 cx
->profile
= mlt_profile_init( profile_name
);
95 cx
->is_close_profile
= 1;
99 cx
->profile
= profile
;
100 cx
->is_close_profile
= 0;
103 // For now, we must conform the nested network's frame rate to the parent network's
105 cx
->profile
->frame_rate_num
= profile
->frame_rate_num
;
106 cx
->profile
->frame_rate_den
= profile
->frame_rate_den
;
108 // We will encapsulate a consumer
109 cx
->consumer
= mlt_consumer_new( cx
->profile
);
110 // Do not use _pass_list on real_time so that it defaults to 0 in the absence of
111 // an explicit real_time property.
112 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx
->consumer
), "real_time",
113 mlt_properties_get_int( properties
, "real_time" ) );
114 mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx
->consumer
), properties
,
117 // Encapsulate a real producer for the resource
118 cx
->producer
= mlt_factory_producer( cx
->profile
, mlt_environment( "MLT_PRODUCER" ),
119 mlt_properties_get( properties
, "resource" ) );
120 mlt_properties_pass_list( properties
, MLT_PRODUCER_PROPERTIES( cx
->producer
),
121 "in, out, length, resource" );
123 // Since we control the seeking, prevent it from seeking on its own
124 mlt_producer_set_speed( cx
->producer
, 0 );
126 // Connect it all together
127 mlt_consumer_connect( cx
->consumer
, MLT_PRODUCER_SERVICE( cx
->producer
) );
128 mlt_consumer_start( cx
->consumer
);
132 *frame
= mlt_frame_init( MLT_PRODUCER_SERVICE( this ) );
135 // Our "in" needs to be the same, keep it so
136 mlt_properties_pass_list( MLT_PRODUCER_PROPERTIES( cx
->producer
), properties
, "in" );
138 // Seek the producer to the correct place
139 // Calculate our positions
140 double actual_position
= mlt_producer_get_speed( this ) * (double)mlt_producer_position( this );
141 mlt_position need_first
= floor( actual_position
);
142 mlt_producer_seek( cx
->producer
, need_first
);
144 // Get the nested frame
145 mlt_frame nested_frame
= mlt_consumer_rt_frame( cx
->consumer
);
147 // Stack the producer and our methods on the nested frame
148 mlt_frame_push_service( *frame
, nested_frame
);
149 mlt_frame_push_service( *frame
, cx
);
150 mlt_frame_push_get_image( *frame
, get_image
);
151 mlt_frame_push_audio( *frame
, nested_frame
);
152 mlt_frame_push_audio( *frame
, get_audio
);
154 // Give the returned frame temporal identity
155 mlt_frame_set_position( *frame
, mlt_producer_position( this ) );
157 // Put additional references on the frame so both get_image and get_audio
158 // methods can close it.
159 mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( nested_frame
) );
161 // Inform the normalizers about our video properties
162 mlt_properties frame_props
= MLT_FRAME_PROPERTIES( *frame
);
163 mlt_properties_set_double( frame_props
, "aspect_ratio", mlt_profile_sar( cx
->profile
) );
164 mlt_properties_set_int( frame_props
, "width", cx
->profile
->width
);
165 mlt_properties_set_int( frame_props
, "height", cx
->profile
->height
);
166 mlt_properties_set_int( frame_props
, "real_width", cx
->profile
->width
);
167 mlt_properties_set_int( frame_props
, "real_height", cx
->profile
->height
);
168 mlt_properties_set_int( frame_props
, "progressive", cx
->profile
->progressive
);
171 // Calculate the next timecode
172 mlt_producer_prepare_next( this );
177 static void producer_close( mlt_producer
this )
179 context cx
= mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( this ), "context", NULL
);
181 // Shut down all the encapsulated services
184 mlt_consumer_stop( cx
->consumer
);
185 mlt_consumer_close( cx
->consumer
);
186 mlt_producer_close( cx
->producer
);
187 if ( cx
->is_close_profile
)
188 mlt_profile_close( cx
->profile
);
192 mlt_producer_close( this );
196 mlt_producer
producer_consumer_init( mlt_profile profile
, mlt_service_type type
, const char *id
, char *arg
)
198 mlt_producer
this = mlt_producer_new( );
200 // Encapsulate the real producer
201 mlt_producer real_producer
= mlt_factory_producer( profile
, mlt_environment( "MLT_PRODUCER" ), arg
);
203 if ( this && real_producer
)
205 // Override some producer methods
206 this->close
= ( mlt_destructor
)producer_close
;
207 this->get_frame
= get_frame
;
209 // Get the properties of this producer
210 mlt_properties properties
= MLT_PRODUCER_PROPERTIES( this );
211 mlt_properties_set( properties
, "resource", arg
);
212 mlt_properties_pass_list( properties
, MLT_PRODUCER_PROPERTIES( real_producer
), "out, length" );
214 // Done with the producer - will re-open later when we have the profile property
215 mlt_producer_close( real_producer
);
220 mlt_producer_close( this );
222 mlt_producer_close( real_producer
);