Do not save a vout if there is still an active vout.
[vlc.git] / src / input / ressource.c
1 /*****************************************************************************
2  * ressource.c
3  *****************************************************************************
4  * Copyright (C) 2008 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar < fenrir _AT_ videolan _DOT_ org >
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_vout.h>
33 #include <vlc_aout.h>
34 #include <vlc_sout.h>
35 #include "../libvlc.h"
36 #include "../stream_output/stream_output.h"
37 #include "../audio_output/aout_internal.h"
38 #include "../video_output/vout_control.h"
39 #include "input_interface.h"
40 #include "ressource.h"
41
42 struct input_ressource_t
43 {
44     /* This lock is used to serialize request and protect
45      * our variables */
46     vlc_mutex_t    lock;
47
48     /* */
49     input_thread_t *p_input;
50
51     sout_instance_t *p_sout;
52     vout_thread_t   *p_vout_free;
53     aout_instance_t *p_aout;
54
55     /* This lock is used to protect vout ressources access (for hold)
56      * It is a special case because of embed video (possible deadlock
57      * between vout window request and vout holds in some(qt4) interface) */
58     vlc_mutex_t    lock_vout;
59     int             i_vout;
60     vout_thread_t   **pp_vout;
61 };
62
63 /* */
64 static void DestroySout( input_ressource_t *p_ressource )
65 {
66 #ifdef ENABLE_SOUT
67     if( p_ressource->p_sout )
68         sout_DeleteInstance( p_ressource->p_sout );
69 #endif
70     p_ressource->p_sout = NULL;
71 }
72 static sout_instance_t *RequestSout( input_ressource_t *p_ressource,
73                                      sout_instance_t *p_sout, const char *psz_sout )
74 {
75 #ifdef ENABLE_SOUT
76     if( !p_sout && !psz_sout )
77     {
78         if( p_ressource->p_sout )
79             msg_Dbg( p_ressource->p_sout, "destroying useless sout" );
80         DestroySout( p_ressource );
81         return NULL;
82     }
83
84     assert( p_ressource->p_input );
85     assert( !p_sout || ( !p_ressource->p_sout && !psz_sout ) );
86
87     /* Check the validity of the sout */
88     if( p_ressource->p_sout &&
89         strcmp( p_ressource->p_sout->psz_sout, psz_sout ) )
90     {
91         msg_Dbg( p_ressource->p_input, "destroying unusable sout" );
92         DestroySout( p_ressource );
93     }
94
95     if( psz_sout )
96     {
97         if( p_ressource->p_sout )
98         {
99             /* Reuse it */
100             msg_Dbg( p_ressource->p_input, "reusing sout" );
101             msg_Dbg( p_ressource->p_input, "you probably want to use gather stream_out" );
102             vlc_object_attach( p_ressource->p_sout, p_ressource->p_input );
103         }
104         else
105         {
106             /* Create a new one */
107             p_ressource->p_sout = sout_NewInstance( p_ressource->p_input, psz_sout );
108         }
109
110         p_sout = p_ressource->p_sout;
111         p_ressource->p_sout = NULL;
112
113         return p_sout;
114     }
115     else
116     {
117         vlc_object_detach( p_sout );
118         p_ressource->p_sout = p_sout;
119
120         return NULL;
121     }
122 #else
123     return NULL;
124 #endif
125 }
126
127 /* */
128 static void DestroyVout( input_ressource_t *p_ressource )
129 {
130     assert( p_ressource->i_vout == 0 );
131
132     if( p_ressource->p_vout_free )
133         vout_CloseAndRelease( p_ressource->p_vout_free );
134
135     p_ressource->p_vout_free = NULL;
136 }
137 static void DisplayVoutTitle( input_ressource_t *p_ressource,
138                               vout_thread_t *p_vout )
139 {
140     assert( p_ressource->p_input );
141
142     /* TODO display the title only one time for the same input ? */
143
144     input_item_t *p_item = input_GetItem( p_ressource->p_input );
145
146     char *psz_nowplaying = input_item_GetNowPlaying( p_item );
147     if( psz_nowplaying && *psz_nowplaying )
148     {
149         vout_DisplayTitle( p_vout, psz_nowplaying );
150     }
151     else
152     {
153         char *psz_artist = input_item_GetArtist( p_item );
154         char *psz_name = input_item_GetTitle( p_item );
155
156         if( !psz_name || *psz_name == '\0' )
157         {
158             free( psz_name );
159             psz_name = input_item_GetName( p_item );
160         }
161         if( psz_artist && *psz_artist )
162         {
163             char *psz_string;
164             if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
165             {
166                 vout_DisplayTitle( p_vout, psz_string );
167                 free( psz_string );
168             }
169         }
170         else if( psz_name )
171         {
172             vout_DisplayTitle( p_vout, psz_name );
173         }
174         free( psz_name );
175         free( psz_artist );
176     }
177     free( psz_nowplaying );
178 }
179 static vout_thread_t *RequestVout( input_ressource_t *p_ressource,
180                                    vout_thread_t *p_vout, video_format_t *p_fmt )
181 {
182     if( !p_vout && !p_fmt )
183     {
184         if( p_ressource->p_vout_free )
185         {
186             msg_Dbg( p_ressource->p_vout_free, "destroying useless vout" );
187             vout_CloseAndRelease( p_ressource->p_vout_free );
188             p_ressource->p_vout_free = NULL;
189         }
190         return NULL;
191     }
192
193     assert( p_ressource->p_input );
194     if( p_fmt )
195     {
196         /* */
197         if( !p_vout && p_ressource->p_vout_free )
198         {
199             msg_Dbg( p_ressource->p_input, "trying to reuse free vout" );
200             p_vout = p_ressource->p_vout_free;
201
202             p_ressource->p_vout_free = NULL;
203         }
204         else if( p_vout )
205         {
206             assert( p_vout != p_ressource->p_vout_free );
207
208             vlc_mutex_lock( &p_ressource->lock_vout );
209             TAB_REMOVE( p_ressource->i_vout, p_ressource->pp_vout, p_vout );
210             vlc_mutex_unlock( &p_ressource->lock_vout );
211         }
212
213         /* */
214         p_vout = vout_Request( p_ressource->p_input, p_vout, p_fmt );
215         if( !p_vout )
216             return NULL;
217
218         DisplayVoutTitle( p_ressource, p_vout );
219
220         vlc_mutex_lock( &p_ressource->lock_vout );
221         TAB_APPEND( p_ressource->i_vout, p_ressource->pp_vout, p_vout );
222         vlc_mutex_unlock( &p_ressource->lock_vout );
223
224         return p_vout;
225     }
226     else
227     {
228         assert( p_vout );
229
230         vlc_mutex_lock( &p_ressource->lock_vout );
231         TAB_REMOVE( p_ressource->i_vout, p_ressource->pp_vout, p_vout );
232         const int i_vout_active = p_ressource->i_vout;
233         vlc_mutex_unlock( &p_ressource->lock_vout );
234
235         if( p_ressource->p_vout_free || i_vout_active > 0 )
236         {
237             msg_Dbg( p_ressource->p_input, "detroying vout (already one saved or active)" );
238             vout_CloseAndRelease( p_vout );
239         }
240         else
241         {
242             msg_Dbg( p_ressource->p_input, "saving a free vout" );
243             vout_Flush( p_vout, 1 );
244             p_ressource->p_vout_free = p_vout;
245         }
246         return NULL;
247     }
248 }
249 static vout_thread_t *HoldVout( input_ressource_t *p_ressource )
250 {
251     if( p_ressource->i_vout <= 0 )
252         return NULL;
253
254     /* TODO FIXME: p_ressource->pp_vout order is NOT stable */
255     vlc_mutex_lock( &p_ressource->lock_vout );
256
257     vout_thread_t *p_vout = p_ressource->pp_vout[0];
258
259     vlc_object_hold( p_vout );
260
261     vlc_mutex_unlock( &p_ressource->lock_vout );
262
263     return p_vout;
264 }
265 static void HoldVouts( input_ressource_t *p_ressource, vout_thread_t ***ppp_vout, int *pi_vout )
266 {
267     vout_thread_t **pp_vout;
268
269     *pi_vout = 0;
270     *ppp_vout = NULL;
271
272     vlc_mutex_lock( &p_ressource->lock_vout );
273
274     if( p_ressource->i_vout <= 0 )
275         goto exit;
276
277     pp_vout = calloc( p_ressource->i_vout, sizeof(*pp_vout) );
278     if( !pp_vout )
279         goto exit;
280
281     *ppp_vout = pp_vout;
282     *pi_vout = p_ressource->i_vout;
283
284     for( int i = 0; i < p_ressource->i_vout; i++ )
285     {
286         pp_vout[i] = p_ressource->pp_vout[i];
287         vlc_object_hold( pp_vout[i] );
288     }
289
290 exit:
291     vlc_mutex_unlock( &p_ressource->lock_vout );
292 }
293
294 /* */
295 static void DestroyAout( input_ressource_t *p_ressource )
296 {
297     if( p_ressource->p_aout )
298         vlc_object_release( p_ressource->p_aout );
299     p_ressource->p_aout = NULL;
300 }
301 static aout_instance_t *RequestAout( input_ressource_t *p_ressource, aout_instance_t *p_aout )
302 {
303     assert( p_ressource->p_input );
304
305     if( p_aout )
306     {
307         msg_Dbg( p_ressource->p_input, "releasing aout" );
308         vlc_object_release( p_aout );
309         return NULL;
310     }
311     else
312     {
313         if( !p_ressource->p_aout )
314         {
315             msg_Dbg( p_ressource->p_input, "creating aout" );
316             p_ressource->p_aout = aout_New( p_ressource->p_input );
317         }
318         else
319         {
320             msg_Dbg( p_ressource->p_input, "reusing aout" );
321         }
322
323         if( !p_ressource->p_aout )
324             return NULL;
325
326         vlc_object_detach( p_ressource->p_aout );
327         vlc_object_attach( p_ressource->p_aout, p_ressource->p_input );
328         vlc_object_hold( p_ressource->p_aout );
329         return p_ressource->p_aout;
330     }
331 }
332 static aout_instance_t *HoldAout( input_ressource_t *p_ressource )
333 {
334     if( !p_ressource->p_aout )
335         return NULL;
336
337     aout_instance_t *p_aout = p_ressource->p_aout;
338
339     vlc_object_hold( p_aout );
340
341     return p_aout;
342 }
343
344 /* */
345 input_ressource_t *input_ressource_New( void )
346 {
347     input_ressource_t *p_ressource = calloc( 1, sizeof(*p_ressource) );
348     if( !p_ressource )
349         return NULL;
350
351     vlc_mutex_init( &p_ressource->lock );
352     vlc_mutex_init( &p_ressource->lock_vout );
353     return p_ressource;
354 }
355
356 void input_ressource_Delete( input_ressource_t *p_ressource )
357 {
358     DestroySout( p_ressource );
359     DestroyVout( p_ressource );
360     DestroyAout( p_ressource );
361
362     vlc_mutex_destroy( &p_ressource->lock_vout );
363     vlc_mutex_destroy( &p_ressource->lock );
364     free( p_ressource );
365 }
366
367 void input_ressource_SetInput( input_ressource_t *p_ressource, input_thread_t *p_input )
368 {
369     vlc_mutex_lock( &p_ressource->lock );
370
371     if( p_ressource->p_input && !p_input )
372     {
373         if( p_ressource->p_aout )
374             vlc_object_detach( p_ressource->p_aout );
375
376         assert( p_ressource->i_vout == 0 );
377         if( p_ressource->p_vout_free )
378             vlc_object_detach( p_ressource->p_vout_free );
379
380         if( p_ressource->p_sout )
381             vlc_object_detach( p_ressource->p_sout );
382     }
383
384     /* */
385     p_ressource->p_input = p_input;
386
387     vlc_mutex_unlock( &p_ressource->lock );
388 }
389
390 vout_thread_t *input_ressource_RequestVout( input_ressource_t *p_ressource,
391                                             vout_thread_t *p_vout, video_format_t *p_fmt )
392 {
393     vlc_mutex_lock( &p_ressource->lock );
394     vout_thread_t *p_ret = RequestVout( p_ressource, p_vout, p_fmt );
395     vlc_mutex_unlock( &p_ressource->lock );
396
397     return p_ret;
398 }
399 vout_thread_t *input_ressource_HoldVout( input_ressource_t *p_ressource )
400 {
401     return HoldVout( p_ressource );
402 }
403 void input_ressource_HoldVouts( input_ressource_t *p_ressource, vout_thread_t ***ppp_vout, int *pi_vout )
404 {
405     HoldVouts( p_ressource, ppp_vout, pi_vout );
406 }
407 void input_ressource_TerminateVout( input_ressource_t *p_ressource )
408 {
409     input_ressource_RequestVout( p_ressource, NULL, NULL );
410 }
411 bool input_ressource_HasVout( input_ressource_t *p_ressource )
412 {
413     vlc_mutex_lock( &p_ressource->lock );
414     assert( !p_ressource->p_input );
415     const bool b_vout = p_ressource->p_vout_free != NULL;
416     vlc_mutex_unlock( &p_ressource->lock );
417
418     return b_vout;
419 }
420
421 /* */
422 aout_instance_t *input_ressource_RequestAout( input_ressource_t *p_ressource, aout_instance_t *p_aout )
423 {
424     vlc_mutex_lock( &p_ressource->lock );
425     aout_instance_t *p_ret = RequestAout( p_ressource, p_aout );
426     vlc_mutex_unlock( &p_ressource->lock );
427
428     return p_ret;
429 }
430 aout_instance_t *input_ressource_HoldAout( input_ressource_t *p_ressource )
431 {
432     vlc_mutex_lock( &p_ressource->lock );
433     aout_instance_t *p_ret = HoldAout( p_ressource );
434     vlc_mutex_unlock( &p_ressource->lock );
435
436     return p_ret;
437 }
438 /* */
439 sout_instance_t *input_ressource_RequestSout( input_ressource_t *p_ressource, sout_instance_t *p_sout, const char *psz_sout )
440 {
441     vlc_mutex_lock( &p_ressource->lock );
442     sout_instance_t *p_ret = RequestSout( p_ressource, p_sout, psz_sout );
443     vlc_mutex_unlock( &p_ressource->lock );
444
445     return p_ret;
446 }
447 void input_ressource_TerminateSout( input_ressource_t *p_ressource )
448 {
449     input_ressource_RequestSout( p_ressource, NULL, NULL );
450 }
451