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;
40 if( !p_mi || p_mi->i_input_id == -1 )
43 p_input_thread = (input_thread_t*)vlc_object_get(
44 p_mi->p_libvlc_instance->p_libvlc_int,
47 p_mi->i_input_id = -1;
52 /* release for previous vlc_object_get */
53 vlc_object_release( p_input_thread );
55 should_destroy = p_input_thread->i_refcount == 1;
57 /* release for initial p_input_thread yield (see _new()) */
58 vlc_object_release( p_input_thread );
60 /* No one is tracking this input_thread appart us. Destroy it */
62 input_DestroyThread( p_input_thread );
66 * Retrieve the input thread. Be sure to release the object
67 * once you are done with it. (libvlc Internal)
69 * Object lock is held.
71 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
72 libvlc_exception_t *p_e )
74 input_thread_t *p_input_thread;
76 vlc_mutex_lock( &p_mi->object_lock );
78 if( !p_mi || p_mi->i_input_id == -1 )
80 vlc_mutex_unlock( &p_mi->object_lock );
81 RAISENULL( "Input is NULL" );
84 p_input_thread = (input_thread_t*)vlc_object_get(
85 p_mi->p_libvlc_instance->p_libvlc_int,
89 vlc_mutex_unlock( &p_mi->object_lock );
90 RAISENULL( "Input does not exist" );
93 vlc_mutex_unlock( &p_mi->object_lock );
94 return p_input_thread;
98 /**************************************************************************
99 * Create a Media Instance object
100 **************************************************************************/
101 libvlc_media_instance_t *
102 libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance,
103 libvlc_exception_t *p_e )
105 libvlc_media_instance_t * p_mi;
107 if( !p_libvlc_instance )
109 libvlc_exception_raise( p_e, "invalid libvlc instance" );
113 p_mi = malloc( sizeof(libvlc_media_instance_t) );
115 p_mi->p_libvlc_instance = p_libvlc_instance;
116 p_mi->i_input_id = -1;
117 /* refcount strategy:
118 * - All items created by _new start with a refcount set to 1
119 * - Accessor _release decrease the refcount by 1, if after that
120 * operation the refcount is 0, the object is destroyed.
121 * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
122 p_mi->i_refcount = 1;
123 /* object_lock strategy:
124 * - No lock held in constructor
125 * - Lock when accessing all variable this lock is held
126 * - Lock when attempting to destroy the object the lock is also held */
127 vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
128 &p_mi->object_lock );
133 /**************************************************************************
134 * Create a Media Instance object with a media descriptor
135 **************************************************************************/
136 libvlc_media_instance_t *
137 libvlc_media_instance_new_from_media_descriptor(
138 libvlc_media_descriptor_t * p_md,
139 libvlc_exception_t *p_e )
141 libvlc_media_instance_t * p_mi;
145 libvlc_exception_raise( p_e, "invalid media descriptor" );
149 p_mi = malloc( sizeof(libvlc_media_instance_t) );
150 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
151 p_mi->p_libvlc_instance = p_mi->p_md->p_libvlc_instance;
152 p_mi->i_input_id = -1;
153 /* same strategy as before */
154 p_mi->i_refcount = 1;
155 /* same strategy as before */
156 vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
157 &p_mi->object_lock );
162 /**************************************************************************
163 * Create a new media instance object from an input_thread (Libvlc Internal)
164 **************************************************************************/
165 libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread(
166 struct libvlc_instance_t *p_libvlc_instance,
167 input_thread_t *p_input,
168 libvlc_exception_t *p_e )
170 libvlc_media_instance_t * p_mi;
174 libvlc_exception_raise( p_e, "invalid input thread" );
178 p_mi = malloc( sizeof(libvlc_media_instance_t) );
179 p_mi->p_md = libvlc_media_descriptor_new_from_input_item(
181 p_input->p->input.p_item, p_e );
189 p_mi->p_libvlc_instance = p_libvlc_instance;
190 p_mi->i_input_id = p_input->i_object_id;
191 /* same strategy as before */
192 p_mi->i_refcount = 1;
193 /* same strategy as before */
194 vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
195 &p_mi->object_lock );
197 /* will be released in media_instance_release() */
198 vlc_object_yield( p_input );
203 /**************************************************************************
204 * Destroy a Media Instance object (libvlc internal)
206 * Warning: No lock held here, but hey, this is internal.
207 **************************************************************************/
208 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
210 input_thread_t *p_input_thread;
211 libvlc_exception_t p_e;
213 libvlc_exception_init( &p_e );
218 p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
220 if( libvlc_exception_raised( &p_e ) )
221 return; /* no need to worry about no input thread */
223 input_DestroyThread( p_input_thread );
225 libvlc_media_descriptor_destroy( p_mi->p_md );
230 /**************************************************************************
231 * Release a Media Instance object
232 **************************************************************************/
233 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
238 vlc_mutex_lock( &p_mi->object_lock );
242 /* We hold the mutex, as a waiter to make sure pending operations
243 * are finished. We can't hold it longer as the get_input_thread
244 * function holds a lock. */
246 vlc_mutex_unlock( &p_mi->object_lock );
248 if( p_mi->i_refcount > 0 )
251 release_input_thread( p_mi );
253 libvlc_media_descriptor_destroy( p_mi->p_md );
258 /**************************************************************************
259 * Set the Media descriptor associated with the instance
260 **************************************************************************/
261 void libvlc_media_instance_set_media_descriptor(
262 libvlc_media_instance_t *p_mi,
263 libvlc_media_descriptor_t *p_md,
264 libvlc_exception_t *p_e )
271 vlc_mutex_lock( &p_mi->object_lock );
273 release_input_thread( p_mi );
275 libvlc_media_descriptor_destroy( p_mi->p_md );
280 vlc_mutex_unlock( &p_mi->object_lock );
281 return; /* It is ok to pass a NULL md */
284 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
286 /* The policy here is to ignore that we were created using a different
287 * libvlc_instance, because we don't really care */
288 p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
290 vlc_mutex_unlock( &p_mi->object_lock );
293 /**************************************************************************
294 * Set the Media descriptor associated with the instance
295 **************************************************************************/
296 libvlc_media_descriptor_t *
297 libvlc_media_instance_get_media_descriptor(
298 libvlc_media_instance_t *p_mi,
299 libvlc_exception_t *p_e )
306 return libvlc_media_descriptor_duplicate( p_mi->p_md );
309 /**************************************************************************
311 **************************************************************************/
312 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
313 libvlc_exception_t *p_e )
315 input_thread_t * p_input_thread;
317 if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
319 /* A thread alread exists, send it a play message */
321 val.i_int = PLAYING_S;
323 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S );
324 vlc_object_release( p_input_thread );
328 vlc_mutex_lock( &p_mi->object_lock );
332 libvlc_exception_raise( p_e, "no associated media descriptor" );
333 vlc_mutex_unlock( &p_mi->object_lock );
337 p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
338 p_mi->p_md->p_input_item );
339 p_mi->i_input_id = p_input_thread->i_object_id;
341 /* will be released in media_instance_release() */
342 vlc_object_yield( p_input_thread );
344 vlc_mutex_unlock( &p_mi->object_lock );
347 /**************************************************************************
349 **************************************************************************/
350 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
351 libvlc_exception_t *p_e )
353 input_thread_t * p_input_thread;
357 p_input_thread = libvlc_get_input_thread( p_mi, p_e );
359 if( !p_input_thread )
362 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val );
363 vlc_object_release( p_input_thread );
366 /**************************************************************************
367 * Getters for stream information
368 **************************************************************************/
369 vlc_int64_t libvlc_media_instance_get_length(
370 libvlc_media_instance_t *p_mi,
371 libvlc_exception_t *p_e )
373 input_thread_t *p_input_thread;
376 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
377 if( !p_input_thread )
380 var_Get( p_input_thread, "length", &val );
381 vlc_object_release( p_input_thread );
383 return (val.i_time+500LL)/1000LL;
386 vlc_int64_t libvlc_media_instance_get_time(
387 libvlc_media_instance_t *p_mi,
388 libvlc_exception_t *p_e )
390 input_thread_t *p_input_thread;
393 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
394 if( !p_input_thread )
397 var_Get( p_input_thread , "time", &val );
398 vlc_object_release( p_input_thread );
399 return (val.i_time+500LL)/1000LL;
402 void libvlc_media_instance_set_time(
403 libvlc_media_instance_t *p_mi,
405 libvlc_exception_t *p_e )
407 input_thread_t *p_input_thread;
410 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
411 if( !p_input_thread )
414 value.i_time = time*1000LL;
415 var_Set( p_input_thread, "time", value );
416 vlc_object_release( p_input_thread );
419 void libvlc_media_instance_set_position(
420 libvlc_media_instance_t *p_mi,
422 libvlc_exception_t *p_e )
424 input_thread_t *p_input_thread;
426 val.f_float = position;
428 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
429 if( !p_input_thread )
432 var_Set( p_input_thread, "position", val );
433 vlc_object_release( p_input_thread );
436 float libvlc_media_instance_get_position(
437 libvlc_media_instance_t *p_mi,
438 libvlc_exception_t *p_e )
440 input_thread_t *p_input_thread;
443 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
444 if( !p_input_thread )
447 var_Get( p_input_thread, "position", &val );
448 vlc_object_release( p_input_thread );
453 float libvlc_media_instance_get_fps(
454 libvlc_media_instance_t *p_mi,
455 libvlc_exception_t *p_e)
458 input_thread_t *p_input_thread;
460 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
461 if( !p_input_thread )
464 if( (NULL == p_input_thread->p->input.p_demux)
465 || demux2_Control( p_input_thread->p->input.p_demux, DEMUX_GET_FPS, &f_fps )
468 vlc_object_release( p_input_thread );
473 vlc_object_release( p_input_thread );
478 vlc_bool_t libvlc_media_instance_will_play(
479 libvlc_media_instance_t *p_mi,
480 libvlc_exception_t *p_e)
482 input_thread_t *p_input_thread =
483 libvlc_get_input_thread ( p_mi, p_e);
484 if ( !p_input_thread )
487 if ( !p_input_thread->b_die && !p_input_thread->b_dead )
489 vlc_object_release( p_input_thread );
492 vlc_object_release( p_input_thread );
496 void libvlc_media_instance_set_rate(
497 libvlc_media_instance_t *p_mi,
499 libvlc_exception_t *p_e )
501 input_thread_t *p_input_thread;
505 RAISEVOID( "Rate value is invalid" );
507 val.i_int = 1000.0f/rate;
509 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
510 if ( !p_input_thread )
513 var_Set( p_input_thread, "rate", val );
514 vlc_object_release( p_input_thread );
517 float libvlc_media_instance_get_rate(
518 libvlc_media_instance_t *p_mi,
519 libvlc_exception_t *p_e )
521 input_thread_t *p_input_thread;
524 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
525 if ( !p_input_thread )
528 var_Get( p_input_thread, "rate", &val );
529 vlc_object_release( p_input_thread );
531 return (float)1000.0f/val.i_int;
534 int libvlc_media_instance_get_state(
535 libvlc_media_instance_t *p_mi,
536 libvlc_exception_t *p_e )
538 input_thread_t *p_input_thread;
541 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
542 if ( !p_input_thread )
545 var_Get( p_input_thread, "state", &val );
546 vlc_object_release( p_input_thread );