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