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;
192 /* will be released in media_instance_release() */
193 vlc_object_yield( p_input );
198 /**************************************************************************
199 * Destroy a Media Instance object (libvlc internal)
201 * Warning: No lock held here, but hey, this is internal.
202 **************************************************************************/
203 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
205 input_thread_t *p_input_thread;
206 libvlc_exception_t p_e;
208 libvlc_exception_init( &p_e );
213 p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
215 if( libvlc_exception_raised( &p_e ) )
216 return; /* no need to worry about no input thread */
218 input_DestroyThread( p_input_thread );
220 libvlc_media_descriptor_destroy( p_mi->p_md );
225 /**************************************************************************
226 * Release a Media Instance object
227 **************************************************************************/
228 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
233 vlc_mutex_lock( &p_mi->object_lock );
237 /* We hold the mutex, as a waiter to make sure pending operations
238 * are finished. We can't hold it longer as the get_input_thread
239 * function holds a lock. */
241 vlc_mutex_unlock( &p_mi->object_lock );
243 if( p_mi->i_refcount > 0 )
246 release_input_thread( p_mi );
248 libvlc_media_descriptor_destroy( p_mi->p_md );
253 /**************************************************************************
254 * Set the Media descriptor associated with the instance
255 **************************************************************************/
256 void libvlc_media_instance_set_media_descriptor(
257 libvlc_media_instance_t *p_mi,
258 libvlc_media_descriptor_t *p_md,
259 libvlc_exception_t *p_e )
266 vlc_mutex_lock( &p_mi->object_lock );
268 release_input_thread( p_mi );
270 libvlc_media_descriptor_destroy( p_mi->p_md );
275 vlc_mutex_unlock( &p_mi->object_lock );
276 return; /* It is ok to pass a NULL md */
279 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
281 /* The policy here is to ignore that we were created using a different
282 * libvlc_instance, because we don't really care */
283 p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
285 vlc_mutex_unlock( &p_mi->object_lock );
288 /**************************************************************************
289 * Set the Media descriptor associated with the instance
290 **************************************************************************/
291 libvlc_media_descriptor_t *
292 libvlc_media_instance_get_media_descriptor(
293 libvlc_media_instance_t *p_mi,
294 libvlc_exception_t *p_e )
301 return libvlc_media_descriptor_duplicate( p_mi->p_md );
304 /**************************************************************************
306 **************************************************************************/
307 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
308 libvlc_exception_t *p_e )
310 input_thread_t * p_input_thread;
312 if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
314 /* A thread alread exists, send it a play message */
316 val.i_int = PLAYING_S;
318 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S );
319 vlc_object_release( p_input_thread );
323 vlc_mutex_lock( &p_mi->object_lock );
327 libvlc_exception_raise( p_e, "no associated media descriptor" );
328 vlc_mutex_unlock( &p_mi->object_lock );
332 p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
333 p_mi->p_md->p_input_item );
334 p_mi->i_input_id = p_input_thread->i_object_id;
336 /* will be released in media_instance_release() */
337 vlc_object_yield( p_input_thread );
339 vlc_mutex_unlock( &p_mi->object_lock );
342 /**************************************************************************
344 **************************************************************************/
345 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
346 libvlc_exception_t *p_e )
348 input_thread_t * p_input_thread;
352 p_input_thread = libvlc_get_input_thread( p_mi, p_e );
354 if( !p_input_thread )
357 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val );
358 vlc_object_release( p_input_thread );
361 /**************************************************************************
362 * Getters for stream information
363 **************************************************************************/
364 vlc_int64_t libvlc_media_instance_get_length(
365 libvlc_media_instance_t *p_mi,
366 libvlc_exception_t *p_e )
368 input_thread_t *p_input_thread;
371 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
372 if( !p_input_thread )
375 var_Get( p_input_thread, "length", &val );
376 vlc_object_release( p_input_thread );
378 return (val.i_time+500LL)/1000LL;
381 vlc_int64_t libvlc_media_instance_get_time(
382 libvlc_media_instance_t *p_mi,
383 libvlc_exception_t *p_e )
385 input_thread_t *p_input_thread;
388 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
389 if( !p_input_thread )
392 var_Get( p_input_thread , "time", &val );
393 vlc_object_release( p_input_thread );
394 return (val.i_time+500LL)/1000LL;
397 void libvlc_media_instance_set_time(
398 libvlc_media_instance_t *p_mi,
400 libvlc_exception_t *p_e )
402 input_thread_t *p_input_thread;
405 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
406 if( !p_input_thread )
409 value.i_time = time*1000LL;
410 var_Set( p_input_thread, "time", value );
411 vlc_object_release( p_input_thread );
414 void libvlc_media_instance_set_position(
415 libvlc_media_instance_t *p_mi,
417 libvlc_exception_t *p_e )
419 input_thread_t *p_input_thread;
421 val.f_float = position;
423 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
424 if( !p_input_thread )
427 var_Set( p_input_thread, "position", val );
428 vlc_object_release( p_input_thread );
431 float libvlc_media_instance_get_position(
432 libvlc_media_instance_t *p_mi,
433 libvlc_exception_t *p_e )
435 input_thread_t *p_input_thread;
438 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
439 if( !p_input_thread )
442 var_Get( p_input_thread, "position", &val );
443 vlc_object_release( p_input_thread );
448 float libvlc_media_instance_get_fps(
449 libvlc_media_instance_t *p_mi,
450 libvlc_exception_t *p_e)
453 input_thread_t *p_input_thread;
455 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
456 if( !p_input_thread )
459 if( (NULL == p_input_thread->p->input.p_demux)
460 || demux2_Control( p_input_thread->p->input.p_demux, DEMUX_GET_FPS, &f_fps )
463 vlc_object_release( p_input_thread );
468 vlc_object_release( p_input_thread );
473 vlc_bool_t libvlc_media_instance_will_play(
474 libvlc_media_instance_t *p_mi,
475 libvlc_exception_t *p_e)
477 input_thread_t *p_input_thread =
478 libvlc_get_input_thread ( p_mi, p_e);
479 if ( !p_input_thread )
482 if ( !p_input_thread->b_die && !p_input_thread->b_dead )
484 vlc_object_release( p_input_thread );
487 vlc_object_release( p_input_thread );
491 void libvlc_media_instance_set_rate(
492 libvlc_media_instance_t *p_mi,
494 libvlc_exception_t *p_e )
496 input_thread_t *p_input_thread;
500 RAISEVOID( "Rate value is invalid" );
502 val.i_int = 1000.0f/rate;
504 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
505 if ( !p_input_thread )
508 var_Set( p_input_thread, "rate", val );
509 vlc_object_release( p_input_thread );
512 float libvlc_media_instance_get_rate(
513 libvlc_media_instance_t *p_mi,
514 libvlc_exception_t *p_e )
516 input_thread_t *p_input_thread;
519 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
520 if ( !p_input_thread )
523 var_Get( p_input_thread, "rate", &val );
524 vlc_object_release( p_input_thread );
526 return (float)1000.0f/val.i_int;
529 int libvlc_media_instance_get_state(
530 libvlc_media_instance_t *p_mi,
531 libvlc_exception_t *p_e )
533 input_thread_t *p_input_thread;
536 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
537 if ( !p_input_thread )
540 var_Get( p_input_thread, "state", &val );
541 vlc_object_release( p_input_thread );