8320e9057df167ef894f986931eabf6a76385042
[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         vlc_mutex_unlock( &p_ressource->lock_vout );
233
234         if( p_ressource->p_vout_free )
235         {
236             msg_Dbg( p_ressource->p_input, "detroying vout (already one saved)" );
237             vout_CloseAndRelease( p_vout );
238         }
239         else
240         {
241             msg_Dbg( p_ressource->p_input, "saving a free vout" );
242             vout_Flush( p_vout, 1 );
243             p_ressource->p_vout_free = p_vout;
244         }
245         return NULL;
246     }
247 }
248 static vout_thread_t *HoldVout( input_ressource_t *p_ressource )
249 {
250     if( p_ressource->i_vout <= 0 )
251         return NULL;
252
253     /* TODO FIXME: p_ressource->pp_vout order is NOT stable */
254     vlc_mutex_lock( &p_ressource->lock_vout );
255
256     vout_thread_t *p_vout = p_ressource->pp_vout[0];
257
258     vlc_object_hold( p_vout );
259
260     vlc_mutex_unlock( &p_ressource->lock_vout );
261
262     return p_vout;
263 }
264 static void HoldVouts( input_ressource_t *p_ressource, vout_thread_t ***ppp_vout, int *pi_vout )
265 {
266     vout_thread_t **pp_vout;
267
268     *pi_vout = 0;
269     *ppp_vout = NULL;
270
271     vlc_mutex_lock( &p_ressource->lock_vout );
272
273     if( p_ressource->i_vout <= 0 )
274         goto exit;
275
276     pp_vout = calloc( p_ressource->i_vout, sizeof(*pp_vout) );
277     if( !pp_vout )
278         goto exit;
279
280     *ppp_vout = pp_vout;
281     *pi_vout = p_ressource->i_vout;
282
283     for( int i = 0; i < p_ressource->i_vout; i++ )
284     {
285         pp_vout[i] = p_ressource->pp_vout[i];
286         vlc_object_hold( pp_vout[i] );
287     }
288
289 exit:
290     vlc_mutex_unlock( &p_ressource->lock_vout );
291 }
292
293 /* */
294 static void DestroyAout( input_ressource_t *p_ressource )
295 {
296     if( p_ressource->p_aout )
297         vlc_object_release( p_ressource->p_aout );
298     p_ressource->p_aout = NULL;
299 }
300 static aout_instance_t *RequestAout( input_ressource_t *p_ressource, aout_instance_t *p_aout )
301 {
302     assert( p_ressource->p_input );
303
304     if( p_aout )
305     {
306         msg_Dbg( p_ressource->p_input, "releasing aout" );
307         vlc_object_release( p_aout );
308         return NULL;
309     }
310     else
311     {
312         if( !p_ressource->p_aout )
313         {
314             msg_Dbg( p_ressource->p_input, "creating aout" );
315             p_ressource->p_aout = aout_New( p_ressource->p_input );
316         }
317         else
318         {
319             msg_Dbg( p_ressource->p_input, "reusing aout" );
320         }
321
322         if( !p_ressource->p_aout )
323             return NULL;
324
325         vlc_object_detach( p_ressource->p_aout );
326         vlc_object_attach( p_ressource->p_aout, p_ressource->p_input );
327         vlc_object_hold( p_ressource->p_aout );
328         return p_ressource->p_aout;
329     }
330 }
331 static aout_instance_t *HoldAout( input_ressource_t *p_ressource )
332 {
333     if( !p_ressource->p_aout )
334         return NULL;
335
336     aout_instance_t *p_aout = p_ressource->p_aout;
337
338     vlc_object_hold( p_aout );
339
340     return p_aout;
341 }
342
343 /* */
344 input_ressource_t *input_ressource_New( void )
345 {
346     input_ressource_t *p_ressource = calloc( 1, sizeof(*p_ressource) );
347     if( !p_ressource )
348         return NULL;
349
350     vlc_mutex_init( &p_ressource->lock );
351     vlc_mutex_init( &p_ressource->lock_vout );
352     return p_ressource;
353 }
354
355 void input_ressource_Delete( input_ressource_t *p_ressource )
356 {
357     DestroySout( p_ressource );
358     DestroyVout( p_ressource );
359     DestroyAout( p_ressource );
360
361     vlc_mutex_destroy( &p_ressource->lock_vout );
362     vlc_mutex_destroy( &p_ressource->lock );
363     free( p_ressource );
364 }
365
366 void input_ressource_SetInput( input_ressource_t *p_ressource, input_thread_t *p_input )
367 {
368     vlc_mutex_lock( &p_ressource->lock );
369
370     if( p_ressource->p_input && !p_input )
371     {
372         if( p_ressource->p_aout )
373             vlc_object_detach( p_ressource->p_aout );
374
375         assert( p_ressource->i_vout == 0 );
376         if( p_ressource->p_vout_free )
377             vlc_object_detach( p_ressource->p_vout_free );
378
379         if( p_ressource->p_sout )
380             vlc_object_detach( p_ressource->p_sout );
381     }
382
383     /* */
384     p_ressource->p_input = p_input;
385
386     vlc_mutex_unlock( &p_ressource->lock );
387 }
388
389 vout_thread_t *input_ressource_RequestVout( input_ressource_t *p_ressource,
390                                             vout_thread_t *p_vout, video_format_t *p_fmt )
391 {
392     vlc_mutex_lock( &p_ressource->lock );
393     vout_thread_t *p_ret = RequestVout( p_ressource, p_vout, p_fmt );
394     vlc_mutex_unlock( &p_ressource->lock );
395
396     return p_ret;
397 }
398 vout_thread_t *input_ressource_HoldVout( input_ressource_t *p_ressource )
399 {
400     return HoldVout( p_ressource );
401 }
402 void input_ressource_HoldVouts( input_ressource_t *p_ressource, vout_thread_t ***ppp_vout, int *pi_vout )
403 {
404     HoldVouts( p_ressource, ppp_vout, pi_vout );
405 }
406 void input_ressource_TerminateVout( input_ressource_t *p_ressource )
407 {
408     input_ressource_RequestVout( p_ressource, NULL, NULL );
409 }
410 bool input_ressource_HasVout( input_ressource_t *p_ressource )
411 {
412     vlc_mutex_lock( &p_ressource->lock );
413     assert( !p_ressource->p_input );
414     const bool b_vout = p_ressource->p_vout_free != NULL;
415     vlc_mutex_unlock( &p_ressource->lock );
416
417     return b_vout;
418 }
419
420 /* */
421 aout_instance_t *input_ressource_RequestAout( input_ressource_t *p_ressource, aout_instance_t *p_aout )
422 {
423     vlc_mutex_lock( &p_ressource->lock );
424     aout_instance_t *p_ret = RequestAout( p_ressource, p_aout );
425     vlc_mutex_unlock( &p_ressource->lock );
426
427     return p_ret;
428 }
429 aout_instance_t *input_ressource_HoldAout( input_ressource_t *p_ressource )
430 {
431     vlc_mutex_lock( &p_ressource->lock );
432     aout_instance_t *p_ret = HoldAout( p_ressource );
433     vlc_mutex_unlock( &p_ressource->lock );
434
435     return p_ret;
436 }
437 /* */
438 sout_instance_t *input_ressource_RequestSout( input_ressource_t *p_ressource, sout_instance_t *p_sout, const char *psz_sout )
439 {
440     vlc_mutex_lock( &p_ressource->lock );
441     sout_instance_t *p_ret = RequestSout( p_ressource, p_sout, psz_sout );
442     vlc_mutex_unlock( &p_ressource->lock );
443
444     return p_ret;
445 }
446 void input_ressource_TerminateSout( input_ressource_t *p_ressource )
447 {
448     input_ressource_RequestSout( p_ressource, NULL, NULL );
449 }
450