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 );
234 if( p_mi->i_refcount > 0 )
236 vlc_mutex_unlock( &p_mi->object_lock );
240 release_input_thread( p_mi );
242 libvlc_media_descriptor_destroy( p_mi->p_md );
244 vlc_mutex_unlock( &p_mi->object_lock );
248 /**************************************************************************
249 * Set the Media descriptor associated with the instance
250 **************************************************************************/
251 void libvlc_media_instance_set_media_descriptor(
252 libvlc_media_instance_t *p_mi,
253 libvlc_media_descriptor_t *p_md,
254 libvlc_exception_t *p_e )
261 vlc_mutex_lock( &p_mi->object_lock );
263 release_input_thread( p_mi );
265 libvlc_media_descriptor_destroy( p_mi->p_md );
270 vlc_mutex_unlock( &p_mi->object_lock );
271 return; /* It is ok to pass a NULL md */
274 p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
276 /* The policy here is to ignore that we were created using a different
277 * libvlc_instance, because we don't really care */
278 p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
280 vlc_mutex_unlock( &p_mi->object_lock );
283 /**************************************************************************
284 * Set the Media descriptor associated with the instance
285 **************************************************************************/
286 libvlc_media_descriptor_t *
287 libvlc_media_instance_get_media_descriptor(
288 libvlc_media_instance_t *p_mi,
289 libvlc_exception_t *p_e )
296 return libvlc_media_descriptor_duplicate( p_mi->p_md );
299 /**************************************************************************
301 **************************************************************************/
302 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
303 libvlc_exception_t *p_e )
305 input_thread_t * p_input_thread;
307 vlc_mutex_lock( &p_mi->object_lock );
309 if( p_input_thread = libvlc_get_input_thread( p_mi, p_e ) )
311 /* A thread alread exists, send it a play message */
313 val.i_int = PLAYING_S;
315 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S );
316 vlc_object_release( p_input_thread );
320 vlc_mutex_lock( &p_mi->object_lock );
324 libvlc_exception_raise( p_e, "no associated media descriptor" );
325 vlc_mutex_unlock( &p_mi->object_lock );
329 p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
330 p_mi->p_md->p_input_item );
331 p_mi->i_input_id = p_input_thread->i_object_id;
333 /* will be released in media_instance_release() */
334 vlc_object_yield( p_input_thread );
336 vlc_mutex_unlock( &p_mi->object_lock );
339 /**************************************************************************
341 **************************************************************************/
342 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
343 libvlc_exception_t *p_e )
345 input_thread_t * p_input_thread;
349 p_input_thread = libvlc_get_input_thread( p_mi, p_e );
351 if( !p_input_thread )
354 input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val );
355 vlc_object_release( p_input_thread );
358 /**************************************************************************
359 * Getters for stream information
360 **************************************************************************/
361 vlc_int64_t libvlc_media_instance_get_length(
362 libvlc_media_instance_t *p_mi,
363 libvlc_exception_t *p_e )
365 input_thread_t *p_input_thread;
368 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
369 if( !p_input_thread )
372 var_Get( p_input_thread, "length", &val );
373 vlc_object_release( p_input_thread );
375 return (val.i_time+500LL)/1000LL;
378 vlc_int64_t libvlc_media_instance_get_time(
379 libvlc_media_instance_t *p_mi,
380 libvlc_exception_t *p_e )
382 input_thread_t *p_input_thread;
385 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
386 if( !p_input_thread )
389 var_Get( p_input_thread , "time", &val );
390 vlc_object_release( p_input_thread );
391 return (val.i_time+500LL)/1000LL;
394 void libvlc_media_instance_set_time(
395 libvlc_media_instance_t *p_mi,
397 libvlc_exception_t *p_e )
399 input_thread_t *p_input_thread;
402 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
403 if( !p_input_thread )
406 value.i_time = time*1000LL;
407 var_Set( p_input_thread, "time", value );
408 vlc_object_release( p_input_thread );
411 void libvlc_media_instance_set_position(
412 libvlc_media_instance_t *p_mi,
414 libvlc_exception_t *p_e )
416 input_thread_t *p_input_thread;
418 val.f_float = position;
420 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
421 if( !p_input_thread )
424 var_Set( p_input_thread, "position", val );
425 vlc_object_release( p_input_thread );
428 float libvlc_media_instance_get_position(
429 libvlc_media_instance_t *p_mi,
430 libvlc_exception_t *p_e )
432 input_thread_t *p_input_thread;
435 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
436 if( !p_input_thread )
439 var_Get( p_input_thread, "position", &val );
440 vlc_object_release( p_input_thread );
445 float libvlc_media_instance_get_fps(
446 libvlc_media_instance_t *p_mi,
447 libvlc_exception_t *p_e)
450 input_thread_t *p_input_thread;
452 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
453 if( !p_input_thread )
456 if( (NULL == p_input_thread->p->input.p_demux)
457 || demux2_Control( p_input_thread->p->input.p_demux, DEMUX_GET_FPS, &f_fps )
460 vlc_object_release( p_input_thread );
465 vlc_object_release( p_input_thread );
470 vlc_bool_t libvlc_media_instance_will_play(
471 libvlc_media_instance_t *p_mi,
472 libvlc_exception_t *p_e)
474 input_thread_t *p_input_thread =
475 libvlc_get_input_thread ( p_mi, p_e);
476 if ( !p_input_thread )
479 if ( !p_input_thread->b_die && !p_input_thread->b_dead )
481 vlc_object_release( p_input_thread );
484 vlc_object_release( p_input_thread );
488 void libvlc_media_instance_set_rate(
489 libvlc_media_instance_t *p_mi,
491 libvlc_exception_t *p_e )
493 input_thread_t *p_input_thread;
497 RAISEVOID( "Rate value is invalid" );
499 val.i_int = 1000.0f/rate;
501 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
502 if ( !p_input_thread )
505 var_Set( p_input_thread, "rate", val );
506 vlc_object_release( p_input_thread );
509 float libvlc_media_instance_get_rate(
510 libvlc_media_instance_t *p_mi,
511 libvlc_exception_t *p_e )
513 input_thread_t *p_input_thread;
516 p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
517 if ( !p_input_thread )
520 var_Get( p_input_thread, "rate", &val );
521 vlc_object_release( p_input_thread );
523 return (float)1000.0f/val.i_int;
526 int libvlc_media_instance_get_state(
527 libvlc_media_instance_t *p_mi,
528 libvlc_exception_t *p_e )
530 input_thread_t *p_input_thread;
533 p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
534 if ( !p_input_thread )
537 var_Get( p_input_thread, "state", &val );
538 vlc_object_release( p_input_thread );