2 * consumer_ffmpeg.c -- an ffmpeg consumer
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 "consumer_ffmpeg.h"
22 #include <framework/mlt_frame.h>
28 /** This classes definition.
31 typedef struct consumer_ffmpeg_s *consumer_ffmpeg;
33 struct consumer_ffmpeg_s
35 struct mlt_consumer_s parent;
36 mlt_properties properties;
41 uint8_t audio_buffer[ 4096 * 3 ];
43 pthread_mutex_t audio_mutex;
44 pthread_cond_t audio_cond;
57 /** Forward references to static functions.
60 static void consumer_close( mlt_consumer parent );
61 static void *consumer_thread( void * );
63 /** This is what will be called by the factory - anything can be passed in
64 via the argument, but keep it simple.
67 mlt_consumer consumer_ffmpeg_init( char *arg )
69 // Create the consumer object
70 consumer_ffmpeg this = calloc( sizeof( struct consumer_ffmpeg_s ), 1 );
72 // If no malloc'd and consumer init ok
73 if ( this != NULL && mlt_consumer_init( &this->parent, this ) == 0 )
75 // Get the parent consumer object
76 mlt_consumer parent = &this->parent;
78 // We have stuff to clean up, so override the close method
79 parent->close = consumer_close;
81 // get a handle on properties
82 mlt_service service = mlt_consumer_service( parent );
83 this->properties = mlt_service_properties( service );
85 // This is the initialisation of the consumer
87 pthread_mutex_init( &this->audio_mutex, NULL );
88 pthread_cond_init( &this->audio_cond, NULL);
90 // process actual param
91 if ( arg == NULL || !strcmp( arg, "-" ) )
93 mlt_properties_set( this->properties, "video_file", "-" );
94 mlt_properties_set( this->properties, "video_format", "dv" );
98 mlt_properties_set( this->properties, "video_file", arg );
99 mlt_properties_set( this->properties, "video_format", "" );
102 // Create the the thread
103 pthread_create( &this->thread, NULL, consumer_thread, this );
105 // Return the consumer produced
109 // malloc or consumer init failed
116 static void sdl_fill_audio( void *udata, uint8_t *stream, int len )
118 consumer_ffmpeg this = udata;
120 pthread_mutex_lock( &this->audio_mutex );
122 // Block until audio received
123 while ( this->running && len > this->audio_avail )
124 pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
126 if ( this->audio_avail >= len )
128 // Remove len from the audio available
129 this->audio_avail -= len;
131 // Remove the samples
132 memmove( this->audio_buffer, this->audio_buffer + len, this->audio_avail );
136 // Just to be safe, wipe the stream first
137 memset( stream, 0, len );
139 // Copy what we have into the stream
140 memcpy( stream, this->audio_buffer, this->audio_avail );
143 this->audio_avail = 0;
146 pthread_cond_broadcast( &this->audio_cond );
147 pthread_mutex_unlock( &this->audio_mutex );
150 static int consumer_play_audio( consumer_ffmpeg this, mlt_frame frame, int init_audio )
152 // Get the properties of this consumer
153 mlt_properties properties = this->properties;
154 mlt_audio_format afmt = mlt_audio_pcm;
161 mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
163 if ( mlt_properties_get_int( properties, "audio_off" ) )
166 if ( init_audio == 0 )
168 bytes = ( samples * channels * 2 );
169 pthread_mutex_lock( &this->audio_mutex );
170 while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) )
171 pthread_cond_wait( &this->audio_cond, &this->audio_mutex );
172 mlt_properties properties = mlt_frame_properties( frame );
173 if ( mlt_properties_get_double( properties, "speed" ) == 1 )
174 memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes );
176 memset( &this->audio_buffer[ this->audio_avail ], 0, bytes );
177 this->audio_avail += bytes;
178 pthread_cond_broadcast( &this->audio_cond );
179 pthread_mutex_unlock( &this->audio_mutex );
189 static int consumer_play_video( consumer_ffmpeg this, mlt_frame frame )
191 // Get the properties of this consumer
192 mlt_properties properties = this->properties;
194 if ( mlt_properties_get_int( properties, "video_off" ) )
196 mlt_frame_close( frame );
200 if ( this->count == this->size )
203 this->queue = realloc( this->queue, sizeof( mlt_frame ) * this->size );
205 this->queue[ this->count ++ ] = frame;
207 // We're working on the oldest frame now
208 frame = this->queue[ 0 ];
210 // Shunt the frames in the queue down
212 for ( i = 1; i < this->count; i ++ )
213 this->queue[ i - 1 ] = this->queue[ i ];
219 /** Threaded wrapper for pipe.
222 static void *consumer_thread( void *arg )
225 consumer_ffmpeg this = arg;
228 mlt_consumer consumer = &this->parent;
230 // Get the service assoicated to the consumer
231 mlt_service service = mlt_consumer_service( consumer );
233 // Define a frame pointer
236 // internal intialization
239 // Loop until told not to
240 while( this->running )
242 // Get a frame from the service (should never return anything other than 0)
243 if ( mlt_service_get_frame( service, &frame, 0 ) == 0 )
245 init_audio = consumer_play_audio( this, frame, init_audio );
246 consumer_play_video( this, frame );
253 /** Callback to allow override of the close method.
256 static void consumer_close( mlt_consumer parent )
258 // Get the actual object
259 consumer_ffmpeg this = parent->child;
261 // Kill the thread and clean up
264 pthread_mutex_lock( &this->audio_mutex );
265 pthread_cond_broadcast( &this->audio_cond );
266 pthread_mutex_unlock( &this->audio_mutex );
268 pthread_join( this->thread, NULL );
269 pthread_mutex_destroy( &this->audio_mutex );
270 pthread_cond_destroy( &this->audio_cond );
272 // Now clean up the rest (the close = NULL is a bit nasty but needed for now)
273 parent->close = NULL;
274 mlt_consumer_close( parent );
276 // Finally clean up this