input: rename vlc_input_event_times variables
[vlc.git] / src / input / resource.c
blob7c4716251c0dedce82ce6146073d2aa8c2495311
1 /*****************************************************************************
2 * resource.c
3 *****************************************************************************
4 * Copyright (C) 2008 Laurent Aimar
6 * Authors: Laurent Aimar < fenrir _AT_ videolan _DOT_ org >
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <assert.h>
32 #include <vlc_common.h>
33 #include <vlc_atomic.h>
34 #include <vlc_decoder.h>
35 #include <vlc_vout.h>
36 #include <vlc_spu.h>
37 #include <vlc_aout.h>
38 #include <vlc_sout.h>
39 #include "../libvlc.h"
40 #include "../stream_output/stream_output.h"
41 #include "../audio_output/aout_internal.h"
42 #include "../video_output/vout_internal.h"
43 #include "input_interface.h"
44 #include "event.h"
45 #include "resource.h"
47 struct vout_resource
49 vout_thread_t *vout;
50 enum vlc_vout_order order;
51 bool started;
53 struct vlc_list node;
56 struct input_resource_t
58 vlc_atomic_rc_t rc;
60 vlc_object_t *p_parent;
62 /* This lock is used to serialize request and protect
63 * our variables */
64 vlc_mutex_t lock;
66 /* */
67 input_thread_t *p_input;
69 sout_instance_t *p_sout;
70 vout_thread_t *p_vout_dummy;
71 struct vout_resource *vout_rsc_free;
73 /* This lock is used to protect vout resources access (for hold)
74 * It is a special case because of embed video (possible deadlock
75 * between vout window request and vout holds in some(qt) interface)
77 vlc_mutex_t lock_hold;
79 /* You need lock+lock_hold to write to the following variables and
80 * only lock or lock_hold to read them */
81 struct vlc_list vout_rscs;
83 bool b_aout_busy;
84 audio_output_t *p_aout;
87 #define resource_GetFirstVoutRsc(resource) \
88 vlc_list_first_entry_or_null(&resource->vout_rscs, struct vout_resource, node)
90 static inline struct vout_resource *
91 resource_GetVoutRsc(input_resource_t *resource, vout_thread_t *vout)
93 struct vout_resource *vout_rsc;
95 vlc_list_foreach(vout_rsc, &resource->vout_rscs, node)
96 if (vout_rsc->vout == vout)
97 return vout_rsc;
99 vlc_assert_unreachable();
102 static inline struct vout_resource *
103 vout_resource_Create(vout_thread_t *vout)
105 struct vout_resource *vout_rsc = malloc(sizeof(*vout_rsc));
106 if (unlikely(vout_rsc == NULL))
107 return NULL;
109 vout_rsc->started = false;
110 vout_rsc->vout = vout;
111 return vout_rsc;
114 static inline void
115 vout_resource_Add(struct vout_resource *vout_rsc, input_resource_t *resource)
117 vlc_list_append(&vout_rsc->node, &resource->vout_rscs);
120 static inline vout_thread_t *
121 vout_resource_Remove(struct vout_resource *vout_rsc)
123 vlc_list_remove(&vout_rsc->node);
124 vout_thread_t *vout = vout_rsc->vout;
125 free(vout_rsc);
127 assert(vout);
128 return vout;
131 /* */
132 static void DestroySout( input_resource_t *p_resource )
134 #ifdef ENABLE_SOUT
135 if( p_resource->p_sout )
137 msg_Dbg( p_resource->p_parent, "destroying stream output" );
138 sout_DeleteInstance( p_resource->p_sout );
140 #endif
141 p_resource->p_sout = NULL;
144 /* */
145 static void DestroyVout( input_resource_t *p_resource )
147 assert( vlc_list_is_empty( &p_resource->vout_rscs )
148 || p_resource->vout_rsc_free == resource_GetFirstVoutRsc( p_resource ) );
150 if( p_resource->vout_rsc_free )
152 vlc_mutex_lock(&p_resource->lock_hold);
153 vout_thread_t *vout = vout_resource_Remove( p_resource->vout_rsc_free );
154 vlc_mutex_unlock(&p_resource->lock_hold);
156 vout_Close( vout );
157 p_resource->vout_rsc_free = NULL;
161 static void DisplayVoutTitle( input_resource_t *p_resource,
162 vout_thread_t *p_vout )
164 if( p_resource->p_input == NULL )
165 return;
167 /* TODO display the title only one time for the same input ? */
169 input_item_t *p_item = input_GetItem( p_resource->p_input );
171 char *psz_nowplaying = input_item_GetNowPlayingFb( p_item );
172 if( psz_nowplaying && *psz_nowplaying )
174 vout_DisplayTitle( p_vout, psz_nowplaying );
176 else
178 char *psz_artist = input_item_GetArtist( p_item );
179 char *psz_name = input_item_GetTitle( p_item );
181 if( !psz_name || *psz_name == '\0' )
183 free( psz_name );
184 psz_name = input_item_GetName( p_item );
186 if( psz_artist && *psz_artist )
188 char *psz_string;
189 if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
191 vout_DisplayTitle( p_vout, psz_string );
192 free( psz_string );
195 else if( psz_name )
197 vout_DisplayTitle( p_vout, psz_name );
199 free( psz_name );
200 free( psz_artist );
202 free( psz_nowplaying );
205 /* Audio output */
206 audio_output_t *input_resource_GetAout( input_resource_t *p_resource )
208 audio_output_t *p_aout;
210 vlc_mutex_lock( &p_resource->lock_hold );
211 p_aout = p_resource->p_aout;
213 if( p_aout == NULL || p_resource->b_aout_busy )
215 msg_Dbg( p_resource->p_parent, "creating audio output" );
216 vlc_mutex_unlock( &p_resource->lock_hold );
218 p_aout = aout_New( p_resource->p_parent );
219 if( p_aout == NULL )
220 return NULL; /* failed */
222 vlc_mutex_lock( &p_resource->lock_hold );
223 if( p_resource->p_aout == NULL )
224 p_resource->p_aout = p_aout;
226 else
227 msg_Dbg( p_resource->p_parent, "reusing audio output" );
229 if( p_resource->p_aout == p_aout )
231 assert( !p_resource->b_aout_busy );
232 p_resource->b_aout_busy = true;
234 vlc_mutex_unlock( &p_resource->lock_hold );
235 return p_aout;
238 void input_resource_PutAout( input_resource_t *p_resource,
239 audio_output_t *p_aout )
241 assert( p_aout != NULL );
243 vlc_mutex_lock( &p_resource->lock_hold );
244 if( p_aout == p_resource->p_aout )
246 assert( p_resource->b_aout_busy );
247 p_resource->b_aout_busy = false;
248 msg_Dbg( p_resource->p_parent, "keeping audio output" );
249 p_aout = NULL;
251 else
252 msg_Dbg( p_resource->p_parent, "destroying extra audio output" );
253 vlc_mutex_unlock( &p_resource->lock_hold );
255 if( p_aout != NULL )
256 aout_Destroy( p_aout );
259 audio_output_t *input_resource_HoldAout( input_resource_t *p_resource )
261 audio_output_t *p_aout;
263 vlc_mutex_lock( &p_resource->lock_hold );
264 p_aout = p_resource->p_aout;
265 if( p_aout != NULL )
266 aout_Hold(p_aout);
267 vlc_mutex_unlock( &p_resource->lock_hold );
269 return p_aout;
272 void input_resource_ResetAout( input_resource_t *p_resource )
274 audio_output_t *p_aout = NULL;
276 vlc_mutex_lock( &p_resource->lock_hold );
277 if( !p_resource->b_aout_busy )
278 p_aout = p_resource->p_aout;
280 p_resource->p_aout = NULL;
281 p_resource->b_aout_busy = false;
282 vlc_mutex_unlock( &p_resource->lock_hold );
284 if( p_aout != NULL )
285 aout_Destroy( p_aout );
288 /* Common */
289 input_resource_t *input_resource_New( vlc_object_t *p_parent )
291 input_resource_t *p_resource = calloc( 1, sizeof(*p_resource) );
292 if( !p_resource )
293 return NULL;
295 p_resource->p_vout_dummy = vout_CreateDummy(p_parent);
296 if( !p_resource->p_vout_dummy )
298 free( p_resource );
299 return NULL;
302 vlc_list_init( &p_resource->vout_rscs );
304 vlc_atomic_rc_init( &p_resource->rc );
305 p_resource->p_parent = p_parent;
306 vlc_mutex_init( &p_resource->lock );
307 vlc_mutex_init( &p_resource->lock_hold );
308 return p_resource;
311 void input_resource_Release( input_resource_t *p_resource )
313 if( !vlc_atomic_rc_dec( &p_resource->rc ) )
314 return;
316 DestroySout( p_resource );
317 DestroyVout( p_resource );
318 if( p_resource->p_aout != NULL )
319 aout_Destroy( p_resource->p_aout );
321 vout_Release( p_resource->p_vout_dummy );
322 free( p_resource );
325 input_resource_t *input_resource_Hold( input_resource_t *p_resource )
327 vlc_atomic_rc_inc( &p_resource->rc );
328 return p_resource;
331 void input_resource_SetInput( input_resource_t *p_resource, input_thread_t *p_input )
333 vlc_mutex_lock( &p_resource->lock );
335 if( p_resource->p_input && !p_input )
336 assert( vlc_list_is_empty( &p_resource->vout_rscs )
337 || p_resource->vout_rsc_free == resource_GetFirstVoutRsc( p_resource ) );
339 /* */
340 p_resource->p_input = p_input;
342 vlc_mutex_unlock( &p_resource->lock );
345 static void input_resource_PutVoutLocked(input_resource_t *p_resource,
346 vout_thread_t *vout, bool *has_stopped)
348 assert(vout != NULL);
349 struct vout_resource *vout_rsc = resource_GetVoutRsc(p_resource, vout);
350 assert(vout_rsc != NULL);
352 if (has_stopped != NULL)
353 *has_stopped = vout_rsc->started;
355 if (vout_rsc->started)
357 vout_StopDisplay(vout_rsc->vout);
358 vout_rsc->started = false;
361 if (vout_rsc == resource_GetFirstVoutRsc(p_resource))
363 assert(p_resource->vout_rsc_free == NULL || p_resource->vout_rsc_free == vout_rsc);
365 msg_Dbg(p_resource->p_parent, "saving a free vout");
366 p_resource->vout_rsc_free = vout_rsc;
368 else
370 msg_Dbg(p_resource->p_parent, "destroying vout (already one saved or active)");
372 vlc_mutex_lock(&p_resource->lock_hold);
373 vout_resource_Remove(vout_rsc);
374 vlc_mutex_unlock(&p_resource->lock_hold);
376 vout_Stop(vout);
377 vout_Close(vout);
381 void input_resource_PutVout(input_resource_t *p_resource,
382 vout_thread_t *vout, bool *stopped)
384 vlc_mutex_lock( &p_resource->lock );
385 input_resource_PutVoutLocked( p_resource, vout, stopped );
386 vlc_mutex_unlock( &p_resource->lock );
389 static struct vout_resource *
390 RequestVoutRsc(input_resource_t *p_resource)
392 struct vout_resource *vout_rsc = NULL;
394 if( p_resource->vout_rsc_free != NULL )
396 /* The free vout is always the first one */
397 msg_Dbg(p_resource->p_parent, "trying to reuse free vout");
399 vout_rsc = p_resource->vout_rsc_free;
400 p_resource->vout_rsc_free = NULL;
402 else
404 /* Use the dummy vout as the parent of the future main vout. This
405 * will allow the future vout to inherit all parameters
406 * pre-configured on this dummy vout. */
407 vlc_object_t *parent = vlc_list_is_empty( &p_resource->vout_rscs ) ?
408 VLC_OBJECT(p_resource->p_vout_dummy) : p_resource->p_parent;
409 vout_thread_t *vout = vout_Create(parent);
410 if (vout == NULL)
411 return NULL;
413 vout_rsc = vout_resource_Create(vout);
414 if (vout_rsc == NULL)
416 vout_Close(vout);
417 return NULL;
420 vout_rsc->order = vlc_list_is_empty( &p_resource->vout_rscs ) ?
421 VLC_VOUT_ORDER_PRIMARY : VLC_VOUT_ORDER_SECONDARY;
423 vlc_mutex_lock(&p_resource->lock_hold);
424 vout_resource_Add(vout_rsc, p_resource);
425 vlc_mutex_unlock(&p_resource->lock_hold);
428 return vout_rsc;
431 vout_thread_t *input_resource_RequestVout(input_resource_t *p_resource,
432 vlc_video_context *vctx,
433 const vout_configuration_t *cfg,
434 enum vlc_vout_order *order,
435 bool *has_started)
437 vlc_mutex_lock( &p_resource->lock );
438 struct vout_resource *vout_rsc = NULL;
440 if (has_started != NULL)
441 *has_started = false;
443 vout_configuration_t dcfg = *cfg;
444 if (dcfg.vout == NULL)
446 vout_rsc = RequestVoutRsc(p_resource);
447 if (vout_rsc == NULL)
449 vlc_mutex_unlock( &p_resource->lock );
450 return NULL;
452 dcfg.vout = vout_rsc->vout;
454 else
456 vout_rsc = resource_GetVoutRsc(p_resource, dcfg.vout);
457 assert(vout_rsc != NULL);
459 /* the caller is going to reuse the free vout, it's not free anymore */
460 if (p_resource->vout_rsc_free == vout_rsc)
461 p_resource->vout_rsc_free = NULL;
464 if (order != NULL)
465 *order = vout_rsc->order;
467 if (dcfg.fmt == NULL)
469 /* A NULL fmt means that only the vout creation is requested, do not
470 * start it with vout_Request(). */
471 vlc_mutex_unlock(&p_resource->lock);
472 return dcfg.vout;
475 if (vout_rsc->started)
477 assert(cfg->vout != NULL);
478 int ret = vout_ChangeSource(dcfg.vout, dcfg.fmt);
479 if (ret == 0)
481 vlc_mutex_unlock(&p_resource->lock);
482 return dcfg.vout;
486 if (vout_Request(&dcfg, vctx, p_resource->p_input)) {
487 input_resource_PutVoutLocked(p_resource, dcfg.vout, NULL);
488 vlc_mutex_unlock(&p_resource->lock);
489 return NULL;
492 vout_rsc->started = true;
493 if (has_started != NULL)
494 *has_started = true;
496 DisplayVoutTitle(p_resource, cfg->vout);
498 /* Send original viewpoint to the input in order to update other ESes */
499 if (p_resource->p_input != NULL)
501 input_control_param_t param = { .viewpoint = cfg->fmt->pose };
502 input_ControlPush(p_resource->p_input, INPUT_CONTROL_SET_INITIAL_VIEWPOINT,
503 &param);
505 vlc_mutex_unlock( &p_resource->lock );
507 return dcfg.vout;
510 vout_thread_t *input_resource_HoldVout( input_resource_t *p_resource )
512 vlc_mutex_lock( &p_resource->lock_hold );
514 struct vout_resource *vout_rsc = resource_GetFirstVoutRsc( p_resource );
515 vout_thread_t *p_vout = vout_rsc != NULL ? vout_rsc->vout : NULL;
516 if( p_vout )
517 vout_Hold(p_vout);
519 vlc_mutex_unlock( &p_resource->lock_hold );
521 return p_vout;
524 vout_thread_t *input_resource_HoldDummyVout( input_resource_t *p_resource )
526 return vout_Hold(p_resource->p_vout_dummy);
529 void input_resource_HoldVouts( input_resource_t *p_resource, vout_thread_t ***ppp_vout,
530 size_t *pi_vout )
532 vout_thread_t **pp_vout;
534 *pi_vout = 0;
535 *ppp_vout = NULL;
537 vlc_mutex_lock( &p_resource->lock_hold );
539 if( vlc_list_is_empty( &p_resource->vout_rscs ) )
540 goto exit;
542 size_t count = 0;
543 struct vout_resource *vout_rsc;
544 vlc_list_foreach( vout_rsc, &p_resource->vout_rscs, node )
545 count ++;
547 pp_vout = vlc_alloc( count, sizeof(*pp_vout) );
548 if( !pp_vout )
549 goto exit;
551 *ppp_vout = pp_vout;
552 *pi_vout = count;;
554 count = 0;
555 vlc_list_foreach( vout_rsc, &p_resource->vout_rscs, node )
556 pp_vout[count++] = vout_Hold( vout_rsc->vout );
558 exit:
559 vlc_mutex_unlock( &p_resource->lock_hold );
562 void input_resource_StopFreeVout(input_resource_t *p_resource)
564 vlc_mutex_lock(&p_resource->lock);
565 if (p_resource->vout_rsc_free != NULL)
567 msg_Dbg(p_resource->vout_rsc_free->vout, "stop free vout");
568 vout_Stop(p_resource->vout_rsc_free->vout);
570 vlc_mutex_unlock(&p_resource->lock);
573 /* */
574 sout_instance_t *input_resource_RequestSout( input_resource_t *p_resource, const char *psz_sout )
576 sout_instance_t *sout;
578 assert(psz_sout != NULL);
579 vlc_mutex_lock( &p_resource->lock );
580 #ifdef ENABLE_SOUT
581 /* Check the validity of the sout */
582 if (p_resource->p_sout != NULL
583 && strcmp(p_resource->p_sout->psz_sout, psz_sout) != 0)
585 msg_Dbg(p_resource->p_parent, "destroying unusable sout");
586 DestroySout(p_resource);
589 sout = p_resource->p_sout;
591 if (sout != NULL)
593 /* Reuse it */
594 msg_Dbg(p_resource->p_parent, "reusing sout");
595 msg_Dbg(p_resource->p_parent, "you probably want to use gather stream_out");
596 p_resource->p_sout = NULL;
598 else
600 /* Create a new one */
601 sout = sout_NewInstance(p_resource->p_parent, psz_sout);
603 #else
604 sout = NULL;
605 #endif
606 vlc_mutex_unlock( &p_resource->lock );
607 return sout;
610 void input_resource_PutSout(input_resource_t *resource, sout_instance_t *sout)
612 if (sout == NULL)
614 input_resource_TerminateSout(resource);
615 return;
618 vlc_mutex_lock(&resource->lock);
619 assert(resource->p_sout == NULL);
620 resource->p_sout = sout;
621 vlc_mutex_unlock(&resource->lock);
624 void input_resource_TerminateSout( input_resource_t *p_resource )
626 vlc_mutex_lock( &p_resource->lock );
627 DestroySout(p_resource);
628 vlc_mutex_unlock( &p_resource->lock );