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
)
180 if ( this->open
&& requested
> this->expected
)
182 // Skip the following n frames
183 *skip
= requested
- this->expected
;
185 else if ( requested
!= this->expected
)
187 // Close the video pipe
188 if ( this->video
!= NULL
)
189 pclose( this->video
);
192 // Close the audio pipe
193 if ( this->audio
!= NULL
)
194 pclose( this->audio
);
197 // We should not be open now
199 this->end_of_video
= 0;
200 this->end_of_audio
= 0;
203 // This is the next frame we expect
204 this->expected
= mlt_producer_frame( &this->parent
) + 1;
207 this->video
= producer_ffmpeg_run_video( this );
209 // Open the audio pipe
210 this->audio
= producer_ffmpeg_run_audio( this );
212 // We should be open now
216 static int producer_get_audio( mlt_frame
this, int16_t **buffer
, mlt_audio_format
*format
, int *frequency
, int *channels
, int *samples
)
218 // Get the frames properties
219 mlt_properties properties
= mlt_frame_properties( this );
221 producer_ffmpeg producer
= mlt_properties_get_data( properties
, "producer_ffmpeg", NULL
);
222 mlt_properties producer_properties
= mlt_producer_properties( &producer
->parent
);
224 int skip
= mlt_properties_get_int( properties
, "skip" );
231 int size
= *samples
* *channels
* 2;
234 *buffer
= malloc( size
);
237 if ( producer
->audio
!= NULL
)
241 if ( fread( *buffer
, size
, 1, producer
->audio
) != 1 )
243 pclose( producer
->audio
);
244 producer
->audio
= NULL
;
245 producer
->end_of_audio
= 1;
248 while( producer
->audio
!= NULL
&& skip
-- );
252 memset( *buffer
, 0, size
);
255 // Pass the data on the frame properties
256 mlt_properties_set_data( properties
, "audio", *buffer
, size
, free
, NULL
);
258 // Set the producer properties
259 mlt_properties_set_int( producer_properties
, "end_of_clip", producer
->end_of_video
&& producer
->end_of_audio
);
264 static int read_ffmpeg_header( producer_ffmpeg
this, int *width
, int *height
)
268 FILE *video
= this->video
;
270 if ( fgets( temp
, 132, video
) )
272 if ( strncmp( temp
, "FRAME", 5 ) )
274 if ( strstr( temp
, " W" ) != NULL
)
275 *width
= atoi( strstr( temp
, " W" ) + 2 );
276 if ( strstr( temp
, " H" ) != NULL
)
277 *height
= atoi( strstr( temp
, " H" ) + 2 );
279 fgets( temp
, 132, video
);
280 this->width
= *width
;
281 this->height
= *height
;
285 *width
= this->width
;
286 *height
= this->height
;
293 static int producer_get_frame( mlt_producer producer
, mlt_frame_ptr frame
, int index
)
295 producer_ffmpeg
this = producer
->child
;
300 // Construct a test frame
301 *frame
= mlt_frame_init( );
303 // Are we at the position expected?
304 producer_ffmpeg_position( this, mlt_producer_frame( producer
), &skip
);
306 // Get the frames properties
307 mlt_properties properties
= mlt_frame_properties( *frame
);
309 FILE *video
= this->video
;
311 mlt_properties_set_int( properties
, "skip", skip
);
314 if ( video
!= NULL
&& read_ffmpeg_header( this, &width
, &height
) == 2 )
317 uint8_t *image
= malloc( width
* height
* 2 );
322 if ( fread( this->buffer
, width
* height
* 3 / 2, 1, video
) == 1 )
323 read_ffmpeg_header( this, &width
, &height
);
328 fread( this->buffer
, width
* height
* 3 / 2, 1, video
);
331 mlt_convert_yuv420p_to_yuv422( this->buffer
, width
, height
, width
, image
);
333 // Pass the data on the frame properties
334 mlt_properties_set_data( properties
, "image", image
, width
* height
* 2, free
, NULL
);
335 mlt_properties_set_int( properties
, "width", width
);
336 mlt_properties_set_int( properties
, "height", height
);
337 mlt_properties_set_int( properties
, "has_image", 1 );
339 // Push the image callback
340 mlt_frame_push_get_image( *frame
, producer_get_image
);
346 if ( this->video
!= NULL
)
348 // Inform caller that end of clip is reached
349 this->end_of_video
= 1;
350 pclose( this->video
);
354 // Push the image callback
355 mlt_frame_push_get_image( *frame
, producer_get_image
);
358 // Set the audio pipe
359 mlt_properties_set_data( properties
, "producer_ffmpeg", this, 0, NULL
, NULL
);
360 mlt_properties_set_int( properties
, "end_of_clip", this->end_of_video
&& this->end_of_audio
);
362 // Hmm - register audio callback
363 ( *frame
)->get_audio
= producer_get_audio
;
365 // Get properties objects
366 mlt_properties producer_properties
= mlt_producer_properties( &this->parent
);
368 // Get the additional properties
369 double aspect_ratio
= mlt_properties_get_double( producer_properties
, "aspect_ratio" );
370 double speed
= mlt_properties_get_double( producer_properties
, "speed" );
372 // Set them on the frame
373 mlt_properties_set_double( properties
, "aspect_ratio", aspect_ratio
);
374 mlt_properties_set_double( properties
, "speed", speed
);
376 // Set the out point on the producer
377 if ( !this->end_of_video
|| !this->end_of_audio
)
378 mlt_producer_set_in_and_out( &this->parent
, mlt_producer_get_in( &this->parent
), mlt_producer_position( &this->parent
) + 1 );
380 mlt_producer_set_in_and_out( &this->parent
, mlt_producer_get_in( &this->parent
), mlt_producer_position( &this->parent
) );
382 // Update timecode on the frame we're creating
383 mlt_frame_set_timecode( *frame
, mlt_producer_position( producer
) );
385 // Calculate the next timecode
386 mlt_producer_prepare_next( producer
);
391 static void producer_close( mlt_producer parent
)
393 producer_ffmpeg
this = parent
->child
;
395 pclose( this->video
);
397 pclose( this->audio
);
398 parent
->close
= NULL
;
399 mlt_producer_close( parent
);
400 free( this->buffer
);