1 /*****************************************************************************
2 * media_instance.c: Libvlc API Media Instance management functions
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
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.
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.
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 *****************************************************************************/
24 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
26 #include <vlc_demux.h>
27 #include <vlc_input.h>
28 #include "input/input_internal.h"
31 * Release the associated input thread
33 * Object lock is NOT held.
35 static void release_input_thread( libvlc_media_instance_t *p_mi )
37 input_thread_t *p_input_thread;
38 vlc_bool_t should_destroy;
39 libvlc_exception_t p_e;
41 libvlc_exception_init( &p_e );
43 p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
45 p_mi->i_input_id = -1;
47 if( libvlc_exception_raised( &p_e ) )
50 /* release for previous libvlc_get_input_thread */
51 vlc_object_release( p_input_thread );
53 should_destroy = p_input_thread->i_refcount == 1;
55 /* release for initial p_input_thread yield (see _new()) */
56 vlc_object_release( p_input_thread );
58 /* No one is tracking this input_thread appart us. Destroy it */
60 input_DestroyThread( p_input_thread );
64 * Retrieve the input thread. Be sure to release the object
65 * once you are done with it. (libvlc Internal)
67 * Object lock is held.
69 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
70 libvlc_exception_t *p_e )
72 input_thread_t *p_input_thread;
74 vlc_mutex_lock( &p_mi->object_lock );
76 if( !p_mi || p_mi->i_input_id == -1 )
78 vlc_mutex_unlock( &p_mi->object_lock );
79 RAISENULL( "Input is NULL" );
82 p_input_thread = (input_thread_t*)vlc_object_get(
83 p_mi->p_libvlc_instance->p_libvlc_int,
87 vlc_mutex_unlock( &p_mi->object_lock );
88 RAISENULL( "Input does not exist" );
91 vlc_mutex_unlock( &p_mi->object_lock );
92 return p_input_thread;
96 /**************************************************************************
97 * Create a Media Instance object
98 **************************************************************************/
99 libvlc_media_instance_t *
100 libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance,
101 libvlc_exception_t *p_e )
103 libvlc_media_instance_t * p_mi;
105 if( !p_libvlc_instance )
107 libvlc_exception_raise( p_e, "invalid libvlc instance" );
111 p_mi = malloc( sizeof(libvlc_media_instance_t) );
113 p_mi->p_libvlc_instance = p_libvlc_instance;
114 p_mi->i_input_id = -1;
115 /* refcount strategy:
116 * - All items created by _new start with a refcount set to 1
117 * - Accessor _release decrease the refcount by 1, if after that
118 * operation the refcount is 0, the object is destroyed.
119 * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
120 p_mi->i_refcount = 1;
121 /* object_lock strategy:
122 * - No lock held in constructor
123 * - Lock when accessing all variable this lock is held
124 * - Lock when attempting to destroy the object the lock is also held */
125 vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
126 &p_mi->object_lock );
131 /**************************************************************************
132 * Create a Media Instance object with a media descriptor
133 **************************************************************************/
134 libvlc_media_instance_t *
135 libvlc_media_instance_new_from_media_descriptor(
136 libvlc_media_descriptor_t * p_md,
137 libvlc_exception_t *p_e )
139 libvlc_media_instance_t * p_mi;
143 libvlc_exception_raise( p_e, "invalid media descriptor" );
147 p_mi = malloc( sizeof(libvlc_media_instance_t) );
148 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
149 p_mi->p_libvlc_instance = p_mi->p_md->p_libvlc_instance;
150 p_mi->i_input_id = -1;
151 /* same strategy as before */
152 p_mi->i_refcount = 1;
153 /* same strategy as before */
154 vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
155 &p_mi->object_lock );
160 /**************************************************************************
161 * Create a new media instance object from an input_thread (Libvlc Internal)
162 **************************************************************************/
163 libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread(
164 struct libvlc_instance_t *p_libvlc_instance,
165 input_thread_t *p_input,
166 libvlc_exception_t *p_e )
168 libvlc_media_instance_t * p_mi;
172 libvlc_exception_raise( p_e, "invalid input thread" );
176 p_mi = malloc( sizeof(libvlc_media_instance_t) );
177 p_mi->p_md = libvlc_media_descriptor_new_from_input_item(
179 p_input->p->input.p_item, p_e );
187 p_mi->p_libvlc_instance = p_libvlc_instance;
188 p_mi->i_input_id = p_input->i_object_id;
190 /* will be released in media_instance_release() */
191 vlc_object_yield( p_input );
196 /**************************************************************************
197 * Destroy a Media Instance object (libvlc internal)
199 * Warning: No lock held here, but hey, this is internal.
200 **************************************************************************/
201 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
203 input_thread_t *p_input_thread;
204 libvlc_exception_t p_e;
206 libvlc_exception_init( &p_e );
211 p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
213 if( libvlc_exception_raised( &p_e ) )
214 return; /* no need to worry about no input thread */
216 input_DestroyThread( p_input_thread );
218 libvlc_media_descriptor_destroy( p_mi->p_md );
223 /**************************************************************************
224 * Release a Media Instance object
225 **************************************************************************/
226 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
231 vlc_mutex_lock( &p_mi->object_lock );
235 /* We hold the mutex, as a waiter to make sure pending operations
236 * are finished. We can't hold it longer as the get_input_thread
237 * function holds a lock. */
239 vlc_mutex_unlock( &p_mi->object_lock );
241 if( p_mi->i_refcount > 0 )
244 release_input_thread( p_mi );
246 libvlc_media_descriptor_destroy( p_mi->p_md );
248 vlc_mutex_unlock( &p_mi->object_lock );
252 /**************************************************************************
253 * Set the Media descriptor associated with the instance
254 **************************************************************************/
255 void libvlc_media_instance_set_media_descriptor(
256 libvlc_media_instance_t *p_mi,
257 libvlc_media_descriptor_t *p_md,
258 libvlc_exception_t *p_e )
265 vlc_mutex_lock( &p_mi->object_lock );
267 release_input_thread( p_mi );
269 libvlc_media_descriptor_destroy( p_mi->p_md );
274 vlc_mutex_unlock( &p_mi->object_lock );
275 return; /* It is ok to pass a NULL md */
278 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
280 /* The policy here is to ignore that we were created using a different
281 * libvlc_instance, because we don't really care */
282 p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
284 vlc_mutex_unlock( &p_mi->object_lock );
287 /**************************************************************************
288 * Set the Media descriptor associated with the instance
289 **************************************************************************/
290 libvlc_media_descriptor_t *
291 libvlc_media_instance_get_media_descriptor(
292 libvlc_media_instance_t *p_mi,
293 libvlc_exception_t *p_e )
300 return libvlc_media_descriptor_duplicate( p_mi->p_md );
303 /**************************************************************************
305 **************************************************************************/
306 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
307 libvlc_exception_t *p_e )
309 input_thread_t * p_input_thread;
311 vlc_mutex_lock( &p_mi->object_lock );
313 if( p_input_thread = libvlc_get_input_thread( p_mi, p_e ) )
315 /* A thread alread exists, send it a play message */
317 val.i_int = PLAYING_S;
319 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S );
320 vlc_object_release( p_input_thread );
324 vlc_mutex_lock( &p_mi->object_lock );
328 libvlc_exception_raise( p_e, "no associated media descriptor" );
329 vlc_mutex_unlock( &p_mi->object_lock );
333 p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
334 p_mi->p_md->p_input_item );
335 p_mi->i_input_id = p_input_thread->i_object_id;
337 /* will be released in media_instance_release() */
338 vlc_object_yield( p_input_thread );
340 vlc_mutex_unlock( &p_mi->object_lock );
343 /**************************************************************************
345 **************************************************************************/
346 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
347 libvlc_exception_t *p_e )
349 input_thread_t * p_input_thread;
353 p_input_thread = libvlc_get_input_thread( p_mi, p_e );
355 if( !p_input_thread )
358 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val );
359 vlc_object_release( p_input_thread );
362 /**************************************************************************
363 * Getters for stream information
364 **************************************************************************/
365 vlc_int64_t libvlc_media_instance_get_length(
366 libvlc_media_instance_t *p_mi,
367 libvlc_exception_t *p_e )
369 input_thread_t *p_input_thread;
372 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
373 if( !p_input_thread )
376 var_Get( p_input_thread, "length", &val );
377 vlc_object_release( p_input_thread );
379 return (val.i_time+500LL)/1000LL;
382 vlc_int64_t libvlc_media_instance_get_time(
383 libvlc_media_instance_t *p_mi,
384 libvlc_exception_t *p_e )
386 input_thread_t *p_input_thread;
389 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
390 if( !p_input_thread )
393 var_Get( p_input_thread , "time", &val );
394 vlc_object_release( p_input_thread );
395 return (val.i_time+500LL)/1000LL;
398 void libvlc_media_instance_set_time(
399 libvlc_media_instance_t *p_mi,
401 libvlc_exception_t *p_e )
403 input_thread_t *p_input_thread;
406 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
407 if( !p_input_thread )
410 value.i_time = time*1000LL;
411 var_Set( p_input_thread, "time", value );
412 vlc_object_release( p_input_thread );
415 void libvlc_media_instance_set_position(
416 libvlc_media_instance_t *p_mi,
418 libvlc_exception_t *p_e )
420 input_thread_t *p_input_thread;
422 val.f_float = position;
424 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
425 if( !p_input_thread )
428 var_Set( p_input_thread, "position", val );
429 vlc_object_release( p_input_thread );
432 float libvlc_media_instance_get_position(
433 libvlc_media_instance_t *p_mi,
434 libvlc_exception_t *p_e )
436 input_thread_t *p_input_thread;
439 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
440 if( !p_input_thread )
443 var_Get( p_input_thread, "position", &val );
444 vlc_object_release( p_input_thread );
449 float libvlc_media_instance_get_fps(
450 libvlc_media_instance_t *p_mi,
451 libvlc_exception_t *p_e)
454 input_thread_t *p_input_thread;
456 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
457 if( !p_input_thread )
460 if( (NULL == p_input_thread->p->input.p_demux)
461 || demux2_Control( p_input_thread->p->input.p_demux, DEMUX_GET_FPS, &f_fps )
464 vlc_object_release( p_input_thread );
469 vlc_object_release( p_input_thread );
474 vlc_bool_t libvlc_media_instance_will_play(
475 libvlc_media_instance_t *p_mi,
476 libvlc_exception_t *p_e)
478 input_thread_t *p_input_thread =
479 libvlc_get_input_thread ( p_mi, p_e);
480 if ( !p_input_thread )
483 if ( !p_input_thread->b_die && !p_input_thread->b_dead )
485 vlc_object_release( p_input_thread );
488 vlc_object_release( p_input_thread );
492 void libvlc_media_instance_set_rate(
493 libvlc_media_instance_t *p_mi,
495 libvlc_exception_t *p_e )
497 input_thread_t *p_input_thread;
501 RAISEVOID( "Rate value is invalid" );
503 val.i_int = 1000.0f/rate;
505 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
506 if ( !p_input_thread )
509 var_Set( p_input_thread, "rate", val );
510 vlc_object_release( p_input_thread );
513 float libvlc_media_instance_get_rate(
514 libvlc_media_instance_t *p_mi,
515 libvlc_exception_t *p_e )
517 input_thread_t *p_input_thread;
520 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
521 if ( !p_input_thread )
524 var_Get( p_input_thread, "rate", &val );
525 vlc_object_release( p_input_thread );
527 return (float)1000.0f/val.i_int;
530 int libvlc_media_instance_get_state(
531 libvlc_media_instance_t *p_mi,
532 libvlc_exception_t *p_e )
534 input_thread_t *p_input_thread;
537 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
538 if ( !p_input_thread )
541 var_Get( p_input_thread, "state", &val );
542 vlc_object_release( p_input_thread );