2 * producer_ffmpeg.c -- simple ffmpeg test case
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
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.
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.
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.
21 #include "producer_ffmpeg.h"
22 #include <framework/mlt_frame.h>
26 typedef struct producer_ffmpeg_s
*producer_ffmpeg
;
28 struct producer_ffmpeg_s
30 struct mlt_producer_s parent
;
42 static int producer_get_frame( mlt_producer producer
, mlt_frame_ptr frame
, int index
);
43 static void producer_close( mlt_producer parent
);
45 /** Consutruct an ffmpeg producer.
48 mlt_producer
producer_ffmpeg_init( char *file
)
50 producer_ffmpeg
this = calloc( sizeof( struct producer_ffmpeg_s
), 1 );
51 if ( this != NULL
&& mlt_producer_init( &this->parent
, this ) == 0 )
54 mlt_producer producer
= &this->parent
;
56 // Get the properties of the producer
57 mlt_properties properties
= mlt_producer_properties( producer
);
59 // Override get_frame and close methods
60 producer
->get_frame
= producer_get_frame
;
61 producer
->close
= producer_close
;
64 mlt_properties_set( properties
, "mlt_type", "producer_ffmpeg" );
65 mlt_properties_set_int( properties
, "known_length", 0 );
66 mlt_properties_set( properties
, "video_type", file
);
67 if ( file
!= NULL
&& !strcmp( file
, "v4l" ) )
69 mlt_properties_set( properties
, "video_file", "/dev/video0" );
70 mlt_properties_set( properties
, "audio_file", "/dev/dsp" );
74 mlt_properties_set( properties
, "video_file", file
);
75 mlt_properties_set( properties
, "audio_file", file
);
78 this->buffer
= malloc( 1024 * 1024 * 2 );
86 static int producer_get_image( mlt_frame
this, uint8_t **buffer
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
88 // Get the frames properties
89 mlt_properties properties
= mlt_frame_properties( this );
91 if ( mlt_properties_get_int( properties
, "has_image" ) )
93 // Get width and height
94 *format
= mlt_image_yuv422
;
95 *width
= mlt_properties_get_int( properties
, "width" );
96 *height
= mlt_properties_get_int( properties
, "height" );
98 // Specify format and image
99 *buffer
= mlt_properties_get_data( properties
, "image", NULL
);
103 mlt_frame_get_image( this, buffer
, format
, width
, height
, writable
);
109 FILE *producer_ffmpeg_run_video( producer_ffmpeg
this )
112 mlt_producer producer
= &this->parent
;
114 // Get the properties of the producer
115 mlt_properties properties
= mlt_producer_properties( producer
);
117 char *video_type
= mlt_properties_get( properties
, "video_type" );
118 char *video_file
= mlt_properties_get( properties
, "video_file" );
119 int video_loop
= mlt_properties_get_int( properties
, "video_loop" );
121 if ( this->video
== NULL
)
123 if ( !this->open
|| video_loop
)
125 char command
[ 1024 ] = "";
126 float fps
= mlt_producer_get_fps( &this->parent
);
127 float position
= mlt_producer_position( &this->parent
);
129 if ( video_loop
) position
= 0;
131 if ( video_type
!= NULL
&& !strcmp( video_type
, "v4l" ) )
132 sprintf( command
, "ffmpeg -r %f -s 640x480 -vd \"%s\" -f imagepipe -f yuv4mpegpipe - 2>/dev/null", fps
, video_file
);
133 else if ( video_file
!= NULL
&& strcmp( video_file
, "" ) )
134 sprintf( command
, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -f yuv4mpegpipe - 2>/dev/null", video_file
, position
, fps
);
136 if ( strcmp( command
, "" ) )
137 this->video
= popen( command
, "r" );
143 FILE *producer_ffmpeg_run_audio( producer_ffmpeg
this )
146 mlt_producer producer
= &this->parent
;
148 // Get the properties of the producer
149 mlt_properties properties
= mlt_producer_properties( producer
);
151 char *video_type
= mlt_properties_get( properties
, "video_type" );
152 char *audio_file
= mlt_properties_get( properties
, "audio_file" );
153 int audio_loop
= mlt_properties_get_int( properties
, "audio_loop" );
155 if ( this->audio
== NULL
)
157 if ( !this->open
|| audio_loop
)
159 char command
[ 1024 ] = "";
160 float position
= mlt_producer_position( &this->parent
);
162 if ( audio_loop
) position
= 0;
164 if ( video_type
!= NULL
&& !strcmp( video_type
, "v4l" ) )
165 sprintf( command
, "ffmpeg -ad \"%s\" -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file
);
166 else if ( audio_file
!= NULL
)
167 sprintf( command
, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file
, position
);
169 if ( strcmp( command
, "" ) )
170 this->audio
= popen( command
, "r" );
176 static void producer_ffmpeg_position( producer_ffmpeg
this, uint64_t requested
, int *skip
)
178 if ( this->open
&& requested
> this->expected
)
180 // Skip the following n frames
181 *skip
= requested
- this->expected
;
183 else if ( requested
!= this->expected
)
185 // Close the video pipe
186 if ( this->video
!= NULL
)
187 pclose( this->video
);
190 // Close the audio pipe
191 if ( this->audio
!= NULL
)
192 pclose( this->audio
);
195 // We should not be open now
197 this->end_of_video
= 0;
198 this->end_of_audio
= 0;
201 // This is the next frame we expect
202 this->expected
= mlt_producer_frame( &this->parent
) + 1;
205 this->video
= producer_ffmpeg_run_video( this );
207 // Open the audio pipe
208 this->audio
= producer_ffmpeg_run_audio( this );
210 // We should be open now
214 static int producer_get_audio( mlt_frame
this, int16_t **buffer
, mlt_audio_format
*format
, int *frequency
, int *channels
, int *samples
)
216 // Get the frames properties
217 mlt_properties properties
= mlt_frame_properties( this );
219 producer_ffmpeg producer
= mlt_properties_get_data( properties
, "producer_ffmpeg", NULL
);
221 int skip
= mlt_properties_get_int( properties
, "skip" );
228 int size
= *samples
* *channels
* 2;
231 *buffer
= malloc( size
);
234 if ( producer
->audio
!= NULL
)
238 if ( fread( *buffer
, size
, 1, producer
->audio
) != 1 )
240 pclose( producer
->audio
);
241 producer
->audio
= NULL
;
242 producer
->end_of_audio
= 1;
249 memset( *buffer
, 0, size
);
252 // Pass the data on the frame properties
253 mlt_properties_set_data( properties
, "audio", *buffer
, size
, free
, NULL
);
258 static int read_ffmpeg_header( producer_ffmpeg
this, int *width
, int *height
)
262 FILE *video
= this->video
;
264 if ( fgets( temp
, 132, video
) )
266 if ( strncmp( temp
, "FRAME", 5 ) )
268 if ( strstr( temp
, " W" ) != NULL
)
269 *width
= atoi( strstr( temp
, " W" ) + 2 );
270 if ( strstr( temp
, " H" ) != NULL
)
271 *height
= atoi( strstr( temp
, " H" ) + 2 );
273 fgets( temp
, 132, video
);
274 this->width
= *width
;
275 this->height
= *height
;
279 *width
= this->width
;
280 *height
= this->height
;
287 static int producer_get_frame( mlt_producer producer
, mlt_frame_ptr frame
, int index
)
289 producer_ffmpeg
this = producer
->child
;
294 // Construct a test frame
295 *frame
= mlt_frame_init( );
297 // Are we at the position expected?
298 producer_ffmpeg_position( this, mlt_producer_frame( producer
), &skip
);
300 // Get the frames properties
301 mlt_properties properties
= mlt_frame_properties( *frame
);
303 FILE *video
= this->video
;
305 mlt_properties_set_int( properties
, "skip", skip
);
308 if ( video
!= NULL
&& read_ffmpeg_header( this, &width
, &height
) == 2 )
311 uint8_t *image
= malloc( width
* height
* 2 );
316 fread( this->buffer
, width
* height
* 3 / 2, 1, video
);
317 read_ffmpeg_header( this, &width
, &height
);
320 fread( this->buffer
, width
* height
* 3 / 2, 1, video
);
323 mlt_convert_yuv420p_to_yuv422( this->buffer
, width
, height
, width
, image
);
325 // Pass the data on the frame properties
326 mlt_properties_set_data( properties
, "image", image
, width
* height
* 2, free
, NULL
);
327 mlt_properties_set_int( properties
, "width", width
);
328 mlt_properties_set_int( properties
, "height", height
);
329 mlt_properties_set_int( properties
, "has_image", 1 );
331 // Push the image callback
332 mlt_frame_push_get_image( *frame
, producer_get_image
);
338 if ( this->video
!= NULL
)
340 // Inform caller that end of clip is reached
341 this->end_of_video
= 1;
342 pclose( this->video
);
346 // Push the image callback
347 mlt_frame_push_get_image( *frame
, producer_get_image
);
350 // Set the audio pipe
351 mlt_properties_set_data( properties
, "producer_ffmpeg", this, 0, NULL
, NULL
);
352 mlt_properties_set_int( properties
, "end_of_clip", this->end_of_video
&& this->end_of_audio
);
354 // Hmm - register audio callback
355 ( *frame
)->get_audio
= producer_get_audio
;
357 // Get properties objects
358 mlt_properties producer_properties
= mlt_producer_properties( &this->parent
);
360 // Get the additional properties
361 double aspect_ratio
= mlt_properties_get_double( producer_properties
, "aspect_ratio" );
362 double speed
= mlt_properties_get_double( producer_properties
, "speed" );
364 // Set them on the frame
365 mlt_properties_set_double( properties
, "aspect_ratio", aspect_ratio
);
366 mlt_properties_set_double( properties
, "speed", speed
);
368 // Set the out point on the producer
369 mlt_producer_set_in_and_out( &this->parent
, mlt_producer_get_in( &this->parent
), mlt_producer_position( &this->parent
) + 0.1 );
371 // Update timecode on the frame we're creating
372 mlt_frame_set_timecode( *frame
, mlt_producer_position( producer
) );
374 // Calculate the next timecode
375 mlt_producer_prepare_next( producer
);
380 static void producer_close( mlt_producer parent
)
382 producer_ffmpeg
this = parent
->child
;
384 pclose( this->video
);
386 pclose( this->audio
);
387 parent
->close
= NULL
;
388 mlt_producer_close( parent
);
389 free( this->buffer
);