2 * producer_framebuffer.c -- create subspeed frames
3 * Author: Jean-Baptiste Mardelle, based on the code of motion_est by Zachary Drew
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "producer_framebuffer.h"
21 #include <framework/mlt.h>
30 // Image stack(able) method
31 static int framebuffer_get_image( mlt_frame
this, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
34 // Get the filter object and properties
35 mlt_producer producer
= mlt_frame_pop_service( this );
36 mlt_frame first_frame
= mlt_frame_pop_service( this );
38 mlt_properties producer_properties
= MLT_PRODUCER_PROPERTIES( producer
);
41 // Frame properties objects
42 mlt_properties frame_properties
= MLT_FRAME_PROPERTIES( this );
43 mlt_properties first_frame_properties
= MLT_FRAME_PROPERTIES( first_frame
);
46 int size
, xstride
, ystride
;
48 case mlt_image_yuv422
:
49 size
= *width
* *height
* 2;
54 fprintf(stderr
, "Unsupported image format\n");
58 uint8_t *output
= mlt_properties_get_data( producer_properties
, "output_buffer", 0 );
61 output
= mlt_pool_alloc( size
);
63 // Let someone else clean up
64 mlt_properties_set_data( producer_properties
, "output_buffer", output
, size
, mlt_pool_release
, NULL
);
67 uint8_t *first_image
= mlt_properties_get_data( first_frame_properties
, "image", NULL
);
69 // which frames are buffered?
73 if( first_image
== NULL
)
75 error
= mlt_frame_get_image( first_frame
, &first_image
, format
, width
, height
, writable
);
78 fprintf(stderr
, "first_image == NULL get image died\n");
83 // Start with a base image
84 memcpy( output
, first_image
, size
);
87 mlt_properties_set_data( frame_properties
, "image", output
, size
, NULL
, NULL
);
89 // Make sure that no further scaling is done
90 mlt_properties_set( frame_properties
, "rescale.interps", "none" );
91 mlt_properties_set( frame_properties
, "scale", "off" );
93 mlt_frame_close( first_frame
);
98 static int framebuffer_get_frame( mlt_producer
this, mlt_frame_ptr frame
, int index
)
100 // Construct a new frame
101 *frame
= mlt_frame_init( );
102 mlt_properties properties
= MLT_PRODUCER_PROPERTIES(this);
106 mlt_frame first_frame
= mlt_properties_get_data( properties
, "first_frame", NULL
);
108 mlt_position first_position
= (first_frame
!= NULL
) ?
mlt_frame_get_position( first_frame
) : -1;
110 // Get the real producer
111 mlt_producer real_producer
= mlt_properties_get_data( properties
, "producer", NULL
);
113 // Our "in" needs to be the same, keep it so
114 mlt_properties_pass_list( MLT_PRODUCER_PROPERTIES( real_producer
), properties
, "in" );
117 int strobe
= mlt_properties_get_int( MLT_PRODUCER_PROPERTIES (this), "strobe");
118 double freeze
= mlt_properties_get_double( MLT_PRODUCER_PROPERTIES (this), "freeze");
119 int freeze_after
= mlt_properties_get_int( MLT_PRODUCER_PROPERTIES (this), "freeze_after");
120 int freeze_before
= mlt_properties_get_int( MLT_PRODUCER_PROPERTIES (this), "freeze_before");
122 mlt_position need_first
;
124 if (!freeze
|| freeze_after
|| freeze_before
) {
125 double prod_speed
= mlt_properties_get_double( properties
, "_speed");
126 double prod_end_speed
= mlt_properties_get_double( properties
, "end_speed");
128 // calculate actual speed and position
129 double actual_speed
= prod_speed
+ ((double)mlt_producer_position( this ) / (double)mlt_producer_get_length(this)) * (prod_end_speed
- prod_speed
);
130 double actual_position
= actual_speed
* (double)mlt_producer_position( this );
131 if (mlt_properties_get_int( properties
, "reverse")) actual_position
= mlt_producer_get_length(this) - actual_position
;
135 need_first
= floor( actual_position
);
139 // Strobe effect wanted, calculate frame position
140 need_first
= floor( actual_position
);
141 need_first
-= need_first
%strobe
;
145 if (freeze_after
&& need_first
> freeze
) need_first
= freeze
;
146 else if (freeze_before
&& need_first
< freeze
) need_first
= freeze
;
149 else need_first
= freeze
;
151 if( need_first
!= first_position
)
153 mlt_frame_close( first_frame
);
158 if( first_frame
== NULL
)
160 // Seek the producer to the correct place
161 mlt_producer_seek( real_producer
, need_first
);
164 mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer
), &first_frame
, index
);
168 // Make sure things are in their place
169 mlt_properties_set_data( properties
, "first_frame", first_frame
, 0, NULL
, NULL
);
171 // Stack the producer and producer's get image
172 mlt_frame_push_service( *frame
, first_frame
);
173 mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( first_frame
) );
175 mlt_frame_push_service( *frame
, this );
176 mlt_frame_push_service( *frame
, framebuffer_get_image
);
178 // Give the returned frame temporal identity
179 mlt_frame_set_position( *frame
, mlt_producer_position( this ) );
187 mlt_producer
producer_framebuffer_init( char *arg
)
189 mlt_producer
this = mlt_producer_new( );
192 mlt_producer real_producer
;
194 // Check if a speed was specified.
197 * Speed must be appended to the filename with ':'. To play your video at 50%:
198 inigo framebuffer:my_video.mpg:0.5
200 * You can have a variabl speed by specifying a start and an end speed:
201 inigo framebuffer:my_video.mpg:0.5:1.0
203 * Stroboscope effect can be obtained by adding a stobe=x parameter, where
204 x is the number of frames that will be ignored.
206 * You can play the movie backwards by adding reverse=1
208 * You can freeze the clip at a determined position by adding freeze=frame_pos
209 add freeze_after=1 to freeze only paste position or freeze_before to freeze before it
216 char *props
= strdup( arg
);
218 count
= strcspn( ptr
, ":" );
220 real_producer
= mlt_factory_producer( "fezzik", ptr
);
223 ptr
+= strspn( ptr
, ":" );
224 count
= strcspn( ptr
, ":" );
229 ptr
+= strspn( ptr
, ":" );
230 count
= strcspn( ptr
, ":" );
232 end_speed
= atof(ptr
);
235 // If no end speed specified, use constant speed
236 if (speed
== 0.0) speed
= 1.0;
237 if (end_speed
== 0.0) end_speed
= speed
;
240 if ( this != NULL
&& real_producer
!= NULL
)
242 // Get the properties of this producer
243 mlt_properties properties
= MLT_PRODUCER_PROPERTIES( this );
245 // Fezzik normalised it for us already
246 mlt_properties_set_int( properties
, "fezzik_normalised", 1);
248 // Store the producer and fitler
249 mlt_properties_set_data( properties
, "producer", real_producer
, 0, ( mlt_destructor
)mlt_producer_close
, NULL
);
251 // Grap some stuff from the real_producer
252 mlt_properties_pass_list( properties
, MLT_PRODUCER_PROPERTIES( real_producer
),
253 "in, out, length, resource" );
255 if (speed
!= 1.0 || end_speed
!=1.0)
257 // Speed is not 1.0, so adjust the clip length
258 mlt_position real_out
= mlt_properties_get_position(properties
, "out");
259 mlt_properties_set_position( properties
, "out", real_out
* 2 / (speed
+ end_speed
));
260 mlt_properties_set_position( properties
, "length", real_out
* 2 / (speed
+ end_speed
) + 1);
261 mlt_properties_set_double( properties
, "_speed", speed
);
262 mlt_properties_set_double( properties
, "end_speed", end_speed
);
264 else mlt_properties_set_double( properties
, "end_speed", 1.0);
266 // Since we control the seeking, prevent it from seeking on its own
267 mlt_producer_set_speed( real_producer
, 0 );
268 mlt_producer_set_speed( this, speed
);
270 // Override the get_frame method
271 this->get_frame
= framebuffer_get_frame
;
277 mlt_producer_close( this );
279 mlt_producer_close( real_producer
);