]> git.sesse.net Git - mlt/blob - src/modules/sdl/consumer_sdl_audio.c
Fix compile error on Windows.
[mlt] / src / modules / sdl / consumer_sdl_audio.c
1 /*
2  * consumer_sdl_audio.c -- A Simple DirectMedia Layer audio-only consumer
3  * Copyright (C) 2009-2012 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <framework/mlt_consumer.h>
22 #include <framework/mlt_frame.h>
23 #include <framework/mlt_deque.h>
24 #include <framework/mlt_factory.h>
25 #include <framework/mlt_filter.h>
26 #include <framework/mlt_log.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <pthread.h>
31 #include <SDL.h>
32 #include <sys/time.h>
33
34 extern pthread_mutex_t mlt_sdl_mutex;
35
36 /** This classes definition.
37 */
38
39 typedef struct consumer_sdl_s *consumer_sdl;
40
41 struct consumer_sdl_s
42 {
43         struct mlt_consumer_s parent;
44         mlt_properties properties;
45         mlt_deque queue;
46         pthread_t thread;
47         int joined;
48         int running;
49         uint8_t audio_buffer[ 4096 * 10 ];
50         int audio_avail;
51         pthread_mutex_t audio_mutex;
52         pthread_cond_t audio_cond;
53         pthread_mutex_t video_mutex;
54         pthread_cond_t video_cond;
55         int playing;
56
57         pthread_cond_t refresh_cond;
58         pthread_mutex_t refresh_mutex;
59         int refresh_count;
60         int is_purge;
61 };
62
63 /** Forward references to static functions.
64 */
65
66 static int consumer_start( mlt_consumer parent );
67 static int consumer_stop( mlt_consumer parent );
68 static int consumer_is_stopped( mlt_consumer parent );
69 static void consumer_purge( mlt_consumer parent );
70 static void consumer_close( mlt_consumer parent );
71 static void *consumer_thread( void * );
72 static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name );
73
74 /** This is what will be called by the factory - anything can be passed in
75         via the argument, but keep it simple.
76 */
77
78 mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
79 {
80         // Create the consumer object
81         consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) );
82
83         // If no malloc'd and consumer init ok
84         if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 )
85         {
86                 // Create the queue
87                 self->queue = mlt_deque_init( );
88
89                 // Get the parent consumer object
90                 mlt_consumer parent = &self->parent;
91
92                 // We have stuff to clean up, so override the close method
93                 parent->close = consumer_close;
94
95                 // get a handle on properties
96                 mlt_service service = MLT_CONSUMER_SERVICE( parent );
97                 self->properties = MLT_SERVICE_PROPERTIES( service );
98
99                 // Set the default volume
100                 mlt_properties_set_double( self->properties, "volume", 1.0 );
101
102                 // This is the initialisation of the consumer
103                 pthread_mutex_init( &self->audio_mutex, NULL );
104                 pthread_cond_init( &self->audio_cond, NULL);
105                 pthread_mutex_init( &self->video_mutex, NULL );
106                 pthread_cond_init( &self->video_cond, NULL);
107
108                 // Default scaler (for now we'll use nearest)
109                 mlt_properties_set( self->properties, "rescale", "nearest" );
110                 mlt_properties_set( self->properties, "deinterlace_method", "onefield" );
111                 mlt_properties_set_int( self->properties, "top_field_first", -1 );
112
113                 // Default buffer for low latency
114                 mlt_properties_set_int( self->properties, "buffer", 1 );
115
116                 // Default audio buffer
117                 mlt_properties_set_int( self->properties, "audio_buffer", 2048 );
118
119                 // Ensure we don't join on a non-running object
120                 self->joined = 1;
121                 
122                 // Allow thread to be started/stopped
123                 parent->start = consumer_start;
124                 parent->stop = consumer_stop;
125                 parent->is_stopped = consumer_is_stopped;
126                 parent->purge = consumer_purge;
127
128                 // Initialize the refresh handler
129                 pthread_cond_init( &self->refresh_cond, NULL );
130                 pthread_mutex_init( &self->refresh_mutex, NULL );
131                 mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb );
132
133                 // Return the consumer produced
134                 return parent;
135         }
136
137         // malloc or consumer init failed
138         free( self );
139
140         // Indicate failure
141         return NULL;
142 }
143
144 static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name )
145 {
146         if ( !strcmp( name, "refresh" ) )
147         {
148                 consumer_sdl self = parent->child;
149                 pthread_mutex_lock( &self->refresh_mutex );
150                 if ( self->refresh_count < 2 )
151                         self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1;
152                 pthread_cond_broadcast( &self->refresh_cond );
153                 pthread_mutex_unlock( &self->refresh_mutex );
154         }
155 }
156
157 int consumer_start( mlt_consumer parent )
158 {
159         consumer_sdl self = parent->child;
160
161         if ( !self->running )
162         {
163                 consumer_stop( parent );
164
165                 pthread_mutex_lock( &mlt_sdl_mutex );
166                 int ret = SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE );
167                 pthread_mutex_unlock( &mlt_sdl_mutex );
168                 if ( ret < 0 )
169                 {
170                         mlt_log_error( MLT_CONSUMER_SERVICE(parent), "Failed to initialize SDL: %s\n", SDL_GetError() );
171                         return -1;
172                 }
173
174                 self->running = 1;
175                 self->joined = 0;
176                 pthread_create( &self->thread, NULL, consumer_thread, self );
177         }
178
179         return 0;
180 }
181
182 int consumer_stop( mlt_consumer parent )
183 {
184         // Get the actual object
185         consumer_sdl self = parent->child;
186
187         if ( self->running && !self->joined )
188         {
189                 // Kill the thread and clean up
190                 self->joined = 1;
191                 self->running = 0;
192
193                 // Unlatch the consumer thread
194                 pthread_mutex_lock( &self->refresh_mutex );
195                 pthread_cond_broadcast( &self->refresh_cond );
196                 pthread_mutex_unlock( &self->refresh_mutex );
197
198                 // Cleanup the main thread
199 #ifndef WIN32
200                 if ( self->thread )
201 #endif
202                         pthread_join( self->thread, NULL );
203
204                 // Unlatch the video thread
205                 pthread_mutex_lock( &self->video_mutex );
206                 pthread_cond_broadcast( &self->video_cond );
207                 pthread_mutex_unlock( &self->video_mutex );
208
209                 // Unlatch the audio callback
210                 pthread_mutex_lock( &self->audio_mutex );
211                 pthread_cond_broadcast( &self->audio_cond );
212                 pthread_mutex_unlock( &self->audio_mutex );
213
214                 SDL_QuitSubSystem( SDL_INIT_AUDIO );
215         }
216
217         return 0;
218 }
219
220 int consumer_is_stopped( mlt_consumer parent )
221 {
222         consumer_sdl self = parent->child;
223         return !self->running;
224 }
225
226 void consumer_purge( mlt_consumer parent )
227 {
228         consumer_sdl self = parent->child;
229         if ( self->running )
230         {
231                 pthread_mutex_lock( &self->video_mutex );
232                 mlt_frame frame = MLT_FRAME( mlt_deque_peek_back( self->queue ) );
233                 // When playing rewind or fast forward then we need to keep one
234                 // frame in the queue to prevent playback stalling.
235                 double speed = frame? mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ) : 0;
236                 int n = ( speed == 0.0 || speed == 1.0 ) ? 0 : 1;
237                 while ( mlt_deque_count( self->queue ) > n )
238                         mlt_frame_close( mlt_deque_pop_back( self->queue ) );
239                 self->is_purge = 1;
240                 pthread_cond_broadcast( &self->video_cond );
241                 pthread_mutex_unlock( &self->video_mutex );
242         }
243 }
244
245 static void sdl_fill_audio( void *udata, uint8_t *stream, int len )
246 {
247         consumer_sdl self = udata;
248
249         // Get the volume
250         double volume = mlt_properties_get_double( self->properties, "volume" );
251
252         pthread_mutex_lock( &self->audio_mutex );
253
254         // Block until audio received
255 #ifdef __DARWIN__
256         while ( self->running && len > self->audio_avail )
257                 pthread_cond_wait( &self->audio_cond, &self->audio_mutex );
258 #endif
259
260         if ( self->audio_avail >= len )
261         {
262                 // Place in the audio buffer
263                 if ( volume != 1.0 )
264                         SDL_MixAudio( stream, self->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
265                 else
266                         memcpy( stream, self->audio_buffer, len );
267
268                 // Remove len from the audio available
269                 self->audio_avail -= len;
270
271                 // Remove the samples
272                 memmove( self->audio_buffer, self->audio_buffer + len, self->audio_avail );
273         }
274         else
275         {
276                 // Just to be safe, wipe the stream first
277                 memset( stream, 0, len );
278
279                 // Mix the audio
280                 SDL_MixAudio( stream, self->audio_buffer, self->audio_avail,
281                         ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
282
283                 // No audio left
284                 self->audio_avail = 0;
285         }
286
287         // We're definitely playing now
288         self->playing = 1;
289
290         pthread_cond_broadcast( &self->audio_cond );
291         pthread_mutex_unlock( &self->audio_mutex );
292 }
293
294 static int consumer_play_audio( consumer_sdl self, mlt_frame frame, int init_audio, int *duration )
295 {
296         // Get the properties of this consumer
297         mlt_properties properties = self->properties;
298         mlt_audio_format afmt = mlt_audio_s16;
299
300         // Set the preferred params of the test card signal
301         int channels = mlt_properties_get_int( properties, "channels" );
302         int frequency = mlt_properties_get_int( properties, "frequency" );
303         int scrub = mlt_properties_get_int( properties, "scrub_audio" );
304         static int counter = 0;
305
306         int samples = mlt_sample_calculator( mlt_properties_get_double( self->properties, "fps" ), frequency, counter++ );
307         
308         int16_t *pcm;
309         int bytes;
310
311         mlt_frame_get_audio( frame, (void**) &pcm, &afmt, &frequency, &channels, &samples );
312         *duration = ( ( samples * 1000 ) / frequency );
313
314         if ( mlt_properties_get_int( properties, "audio_off" ) )
315         {
316                 self->playing = 1;
317                 init_audio = 1;
318                 return init_audio;
319         }
320
321         if ( init_audio == 1 )
322         {
323                 SDL_AudioSpec request;
324                 SDL_AudioSpec got;
325
326                 int audio_buffer = mlt_properties_get_int( properties, "audio_buffer" );
327
328                 // specify audio format
329                 memset( &request, 0, sizeof( SDL_AudioSpec ) );
330                 self->playing = 0;
331                 request.freq = frequency;
332                 request.format = AUDIO_S16SYS;
333                 request.channels = channels;
334                 request.samples = audio_buffer;
335                 request.callback = sdl_fill_audio;
336                 request.userdata = (void *)self;
337                 if ( SDL_OpenAudio( &request, &got ) != 0 )
338                 {
339                         mlt_log_error( MLT_CONSUMER_SERVICE( self ), "SDL failed to open audio: %s\n", SDL_GetError() );
340                         init_audio = 2;
341                 }
342                 else if ( got.size != 0 )
343                 {
344                         SDL_PauseAudio( 0 );
345                         init_audio = 0;
346                 }
347         }
348
349         if ( init_audio == 0 )
350         {
351                 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
352                 bytes = ( samples * channels * 2 );
353                 pthread_mutex_lock( &self->audio_mutex );
354                 while ( self->running && bytes > ( sizeof( self->audio_buffer) - self->audio_avail ) )
355                         pthread_cond_wait( &self->audio_cond, &self->audio_mutex );
356                 if ( self->running )
357                 {
358                         if ( scrub || mlt_properties_get_double( properties, "_speed" ) == 1 )
359                                 memcpy( &self->audio_buffer[ self->audio_avail ], pcm, bytes );
360                         else
361                                 memset( &self->audio_buffer[ self->audio_avail ], 0, bytes );
362                         self->audio_avail += bytes;
363                 }
364                 pthread_cond_broadcast( &self->audio_cond );
365                 pthread_mutex_unlock( &self->audio_mutex );
366         }
367         else
368         {
369                 self->playing = 1;
370         }
371
372         return init_audio;
373 }
374
375 static int consumer_play_video( consumer_sdl self, mlt_frame frame )
376 {
377         // Get the properties of this consumer
378         mlt_properties properties = self->properties;
379         if ( self->running && !mlt_consumer_is_stopped( &self->parent ) )
380                 mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
381         return 0;
382 }
383
384 static void *video_thread( void *arg )
385 {
386         // Identify the arg
387         consumer_sdl self = arg;
388
389         // Obtain time of thread start
390         struct timeval now;
391         int64_t start = 0;
392         int64_t elapsed = 0;
393         struct timespec tm;
394         mlt_frame next = NULL;
395         mlt_properties properties = NULL;
396         double speed = 0;
397
398         // Get real time flag
399         int real_time = mlt_properties_get_int( self->properties, "real_time" );
400
401         // Get the current time
402         gettimeofday( &now, NULL );
403
404         // Determine start time
405         start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec;
406
407         while ( self->running )
408         {
409                 // Pop the next frame
410                 pthread_mutex_lock( &self->video_mutex );
411                 next = mlt_deque_pop_front( self->queue );
412                 while ( next == NULL && self->running )
413                 {
414                         pthread_cond_wait( &self->video_cond, &self->video_mutex );
415                         next = mlt_deque_pop_front( self->queue );
416                 }
417                 pthread_mutex_unlock( &self->video_mutex );
418
419                 if ( !self->running || next == NULL ) break;
420
421                 // Get the properties
422                 properties =  MLT_FRAME_PROPERTIES( next );
423
424                 // Get the speed of the frame
425                 speed = mlt_properties_get_double( properties, "_speed" );
426
427                 // Get the current time
428                 gettimeofday( &now, NULL );
429
430                 // Get the elapsed time
431                 elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start;
432
433                 // See if we have to delay the display of the current frame
434                 if ( mlt_properties_get_int( properties, "rendered" ) == 1 && self->running )
435                 {
436                         // Obtain the scheduled playout time
437                         int64_t scheduled = mlt_properties_get_int( properties, "playtime" );
438
439                         // Determine the difference between the elapsed time and the scheduled playout time
440                         int64_t difference = scheduled - elapsed;
441
442                         // Smooth playback a bit
443                         if ( real_time && ( difference > 20000 && speed == 1.0 ) )
444                         {
445                                 tm.tv_sec = difference / 1000000;
446                                 tm.tv_nsec = ( difference % 1000000 ) * 500;
447                                 nanosleep( &tm, NULL );
448                         }
449
450                         // Show current frame if not too old
451                         if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) )
452                                 consumer_play_video( self, next );
453
454                         // If the queue is empty, recalculate start to allow build up again
455                         if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) )
456                         {
457                                 gettimeofday( &now, NULL );
458                                 start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000;
459                         }
460                 }
461
462                 // This frame can now be closed
463                 mlt_frame_close( next );
464                 next = NULL;
465         }
466
467         if ( next != NULL )
468                 mlt_frame_close( next );
469
470         mlt_consumer_stopped( &self->parent );
471
472         return NULL;
473 }
474
475 /** Threaded wrapper for pipe.
476 */
477
478 static void *consumer_thread( void *arg )
479 {
480         // Identify the arg
481         consumer_sdl self = arg;
482
483         // Get the consumer
484         mlt_consumer consumer = &self->parent;
485
486         // Get the properties
487         mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer );
488
489         // Video thread
490         pthread_t thread;
491
492         // internal intialization
493         int init_audio = 1;
494         int init_video = 1;
495         mlt_frame frame = NULL;
496         mlt_properties properties = NULL;
497         int duration = 0;
498         int64_t playtime = 0;
499         struct timespec tm = { 0, 100000 };
500 //      int last_position = -1;
501
502         pthread_mutex_lock( &self->refresh_mutex );
503         self->refresh_count = 0;
504         pthread_mutex_unlock( &self->refresh_mutex );
505
506         // Loop until told not to
507         while( self->running )
508         {
509                 // Get a frame from the attached producer
510                 frame = mlt_consumer_rt_frame( consumer );
511
512                 // Ensure that we have a frame
513                 if ( frame )
514                 {
515                         // Get the frame properties
516                         properties =  MLT_FRAME_PROPERTIES( frame );
517
518                         // Get the speed of the frame
519                         double speed = mlt_properties_get_double( properties, "_speed" );
520
521                         // Get refresh request for the current frame
522                         int refresh = mlt_properties_get_int( consumer_props, "refresh" );
523
524                         // Clear refresh
525                         mlt_events_block( consumer_props, consumer_props );
526                         mlt_properties_set_int( consumer_props, "refresh", 0 );
527                         mlt_events_unblock( consumer_props, consumer_props );
528
529                         // Play audio
530                         init_audio = consumer_play_audio( self, frame, init_audio, &duration );
531
532                         // Determine the start time now
533                         if ( self->playing && init_video )
534                         {
535                                 // Create the video thread
536                                 pthread_create( &thread, NULL, video_thread, self );
537
538                                 // Video doesn't need to be initialised any more
539                                 init_video = 0;
540                         }
541
542                         // Set playtime for this frame
543                         mlt_properties_set_int( properties, "playtime", playtime );
544
545                         while ( self->running && speed != 0 && mlt_deque_count( self->queue ) > 15 )
546                                 nanosleep( &tm, NULL );
547
548                         // Push this frame to the back of the queue
549                         if ( self->running && speed )
550                         {
551                                 pthread_mutex_lock( &self->video_mutex );
552                                 if ( self->is_purge && speed == 1.0 )
553                                 {
554                                         mlt_frame_close( frame );
555                                         self->is_purge = 0;
556                                 }
557                                 else
558                                 {
559                                         mlt_deque_push_back( self->queue, frame );
560                                         pthread_cond_broadcast( &self->video_cond );
561                                 }
562                                 pthread_mutex_unlock( &self->video_mutex );
563
564                                 // Calculate the next playtime
565                                 playtime += ( duration * 1000 );
566                         }
567                         else if ( self->running )
568                         {
569                                 pthread_mutex_lock( &self->refresh_mutex );
570                                 if ( ( refresh == 0 && self->refresh_count <= 0 ) || self->refresh_count > 1 )
571                                 {
572                                         consumer_play_video( self, frame );
573                                         pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex );
574                                 }
575                                 mlt_frame_close( frame );
576                                 self->refresh_count --;
577                                 pthread_mutex_unlock( &self->refresh_mutex );
578                         }
579                         else
580                         {
581                                 mlt_frame_close( frame );
582                                 frame = NULL;
583                         }
584
585                         // Optimisation to reduce latency
586                         if ( frame && speed == 1.0 )
587                         {
588                 // TODO: disabled due to misbehavior on parallel-consumer
589 //                              if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) )
590 //                                      mlt_consumer_purge( consumer );
591 //                              last_position = mlt_frame_get_position( frame );
592                         }
593                         else
594                         {
595                                 mlt_consumer_purge( consumer );
596 //                              last_position = -1;
597                         }
598                 }
599         }
600
601         // Kill the video thread
602         if ( init_video == 0 )
603         {
604                 pthread_mutex_lock( &self->video_mutex );
605                 pthread_cond_broadcast( &self->video_cond );
606                 pthread_mutex_unlock( &self->video_mutex );
607                 pthread_join( thread, NULL );
608         }
609
610         while( mlt_deque_count( self->queue ) )
611                 mlt_frame_close( mlt_deque_pop_back( self->queue ) );
612
613         self->audio_avail = 0;
614
615         return NULL;
616 }
617
618 /** Callback to allow override of the close method.
619 */
620
621 static void consumer_close( mlt_consumer parent )
622 {
623         // Get the actual object
624         consumer_sdl self = parent->child;
625
626         // Stop the consumer
627         mlt_consumer_stop( parent );
628
629         // Now clean up the rest
630         mlt_consumer_close( parent );
631
632         // Close the queue
633         mlt_deque_close( self->queue );
634
635         // Destroy mutexes
636         pthread_mutex_destroy( &self->audio_mutex );
637         pthread_cond_destroy( &self->audio_cond );
638         pthread_mutex_destroy( &self->video_mutex );
639         pthread_cond_destroy( &self->video_cond );
640         pthread_mutex_destroy( &self->refresh_mutex );
641         pthread_cond_destroy( &self->refresh_cond );
642
643         // Finally clean up this
644         free( self );
645 }