From 9160790e0c08ee50e6a795accdd2d9d2df4bfad3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Stenac?= Date: Wed, 1 Jun 2005 21:58:13 +0000 Subject: [PATCH] Merge mediacontrol to trunk --- Makefile.am | 4 + include/vlc/control.h | 211 +++++++++++++++++++ src/control/audio_video.c | 422 ++++++++++++++++++++++++++++++++++++++ src/control/core.c | 389 +++++++++++++++++++++++++++++++++++ src/control/init.c | 86 ++++++++ src/control/plugin.c | 26 +++ src/control/util.c | 292 ++++++++++++++++++++++++++ src/libvlc.h | 6 +- vlc-config.in.in | 2 + 9 files changed, 1435 insertions(+), 3 deletions(-) create mode 100644 include/vlc/control.h create mode 100644 src/control/audio_video.c create mode 100644 src/control/core.c create mode 100644 src/control/init.c create mode 100644 src/control/plugin.c create mode 100644 src/control/util.c diff --git a/Makefile.am b/Makefile.am index 0f9f07df43..521c08109f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,6 +60,7 @@ dist_pkginclude_HEADERS = \ include/vlc/decoder.h \ include/vlc/input.h \ include/vlc/intf.h \ + include/vlc/control.h \ $(NULL) noinst_HEADERS = $(HEADERS_include) $(HEADERS_include_built) @@ -412,6 +413,9 @@ SOURCES_libvlc_common = \ src/misc/vlm.c \ src/misc/xml.c \ src/extras/libc.c \ + src/control/core.c \ + src/control/util.c \ + src/control/audio_video.c \ $(NULL) SOURCES_libvlc = \ diff --git a/include/vlc/control.h b/include/vlc/control.h new file mode 100644 index 0000000000..8b727e5759 --- /dev/null +++ b/include/vlc/control.h @@ -0,0 +1,211 @@ +/***************************************************************************** + * control.h: global header for mediacontrol + ***************************************************************************** + * Copyright (C) 2005 VideoLAN + * $Id: vlc.h 10101 2005-03-02 16:47:31Z robux4 $ + * + * Authors: Olivier Aubert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#ifndef _VLC_CONTROL_H +#define _VLC_CONTROL_H 1 + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +#if defined( WIN32 ) +#define WINDOWHANDLE HWND +#else +#define WINDOWHANDLE int +#endif + + +typedef int bool; + +/************************************************************************ + * Position Object Manipulation + *************************************************************************/ +typedef enum { + mediacontrol_AbsolutePosition, + mediacontrol_RelativePosition, + mediacontrol_ModuloPosition +} mediacontrol_PositionOrigin; + +typedef enum { + mediacontrol_ByteCount, + mediacontrol_SampleCount, + mediacontrol_MediaTime +} mediacontrol_PositionKey; + +typedef struct { + mediacontrol_PositionOrigin origin; + mediacontrol_PositionKey key; + long value; +} mediacontrol_Position; + +typedef struct { + int width; + int height; + long type; + long long date; + int size; + char* data; +} mediacontrol_RGBPicture; + +typedef struct { + int size; + char** data; +} mediacontrol_PlaylistSeq; + +typedef struct { + int code; + char* message; +} mediacontrol_Exception; + +/* Exception codes */ +#define mediacontrol_PositionKeyNotSupported 1 +#define mediacontrol_PositionOriginNotSupported 2 +#define mediacontrol_InvalidPosition 3 +#define mediacontrol_PlaylistException 4 +#define mediacontrol_InternalException 5 + +typedef struct { + vlc_object_t *p_vlc; + playlist_t *p_playlist; + intf_thread_t *p_intf; + int vlc_object_id; +} mediacontrol_Instance; + +/* Cf stream_control.h */ +enum mediacontrol_PlayerStatusList + { + mediacontrol_PlayingStatus, mediacontrol_PauseStatus, + mediacontrol_ForwardStatus, mediacontrol_BackwardStatus, + mediacontrol_InitStatus, mediacontrol_EndStatus, + mediacontrol_UndefinedStatus + }; +typedef enum mediacontrol_PlayerStatusList mediacontrol_PlayerStatus; + +typedef struct { + mediacontrol_PlayerStatus streamstatus; + char* url; /* The URL of the current media stream */ + long long position; /* actual location in the stream (in ms) */ + long long length; /* total length of the stream (in ms) */ + } mediacontrol_StreamInformation; + +/************************************************************************** + * Helper functions + ***************************************************************************/ +long long mediacontrol_unit_convert (input_thread_t *p_input, + mediacontrol_PositionKey from, + mediacontrol_PositionKey to, + long long value); +long long +mediacontrol_position2microsecond (input_thread_t* p_input, const mediacontrol_Position * pos); + +mediacontrol_RGBPicture* mediacontrol_RGBPicture__alloc (int datasize); +void mediacontrol_RGBPicture__free (mediacontrol_RGBPicture* pic); +mediacontrol_PlaylistSeq* mediacontrol_PlaylistSeq__alloc (int size); +void mediacontrol_PlaylistSeq__free (mediacontrol_PlaylistSeq* ps); + +mediacontrol_Exception* mediacontrol_exception_init(mediacontrol_Exception *exception); +void mediacontrol_exception_free(mediacontrol_Exception *exception); + +/***************************************************************************** + * Core functions + *****************************************************************************/ +mediacontrol_Instance* mediacontrol_new(char** args, mediacontrol_Exception *exception); +mediacontrol_Instance* mediacontrol_new_from_object(vlc_object_t* p_object, + mediacontrol_Exception *exception); + +mediacontrol_Position* mediacontrol_get_media_position( + mediacontrol_Instance *self, + mediacontrol_PositionOrigin an_origin, + mediacontrol_PositionKey a_key, + mediacontrol_Exception *exception); +void mediacontrol_set_media_position(mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); +void mediacontrol_start( mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); + +void mediacontrol_pause(mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); + +void mediacontrol_resume(mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); + +void mediacontrol_stop(mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); +void mediacontrol_exit(mediacontrol_Instance *self); + +void mediacontrol_playlist_add_item (mediacontrol_Instance *self, + const char* psz_file, + mediacontrol_Exception *exception); +void mediacontrol_playlist_clear (mediacontrol_Instance *self, + mediacontrol_Exception *exception); +mediacontrol_PlaylistSeq* mediacontrol_playlist_get_list ( + mediacontrol_Instance *self, + mediacontrol_Exception *exception); + + +/***************************************************************************** + * A/V functions + *****************************************************************************/ +mediacontrol_RGBPicture* mediacontrol_snapshot (mediacontrol_Instance *self, + const mediacontrol_Position* a_position, + mediacontrol_Exception *exception); + +/* Return a NULL terminated list */ +mediacontrol_RGBPicture** mediacontrol_all_snapshots (mediacontrol_Instance *self, + mediacontrol_Exception *exception); + +// Displays the message string, between "begin" and "end" positions +void mediacontrol_display_text (mediacontrol_Instance *self, + const char* message, + const mediacontrol_Position* begin, + const mediacontrol_Position* end, + mediacontrol_Exception *exception); + +mediacontrol_StreamInformation* +mediacontrol_get_stream_information(mediacontrol_Instance* self, + mediacontrol_PositionKey a_key, + mediacontrol_Exception *exception); + +unsigned short mediacontrol_sound_get_volume(mediacontrol_Instance* self, + mediacontrol_Exception *exception); +void mediacontrol_sound_set_volume(mediacontrol_Instance* self, + const unsigned short volume, + mediacontrol_Exception *exception); + +bool mediacontrol_set_visual(mediacontrol_Instance* self, + WINDOWHANDLE visual_id, + mediacontrol_Exception *exception); + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/src/control/audio_video.c b/src/control/audio_video.c new file mode 100644 index 0000000000..d7d6609223 --- /dev/null +++ b/src/control/audio_video.c @@ -0,0 +1,422 @@ +/***************************************************************************** + * audio_video.c: Audio/Video management : volume, snapshot, OSD + ***************************************************************************** + * Copyright (C) 2005 VideoLAN + * $Id: vlc.c 10786 2005-04-23 23:19:17Z zorglub $ + * + * Authors: Olivier Aubert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#define HAS_SNAPSHOT 1 + +#ifdef HAS_SNAPSHOT +#include +#endif + +#include /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#define RAISE( c, m ) exception->code = c; \ + exception->message = strdup(m); + +mediacontrol_RGBPicture * +mediacontrol_snapshot( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + mediacontrol_RGBPicture *retval = NULL; + input_thread_t* p_input = self->p_playlist->p_input; + vout_thread_t *p_vout = NULL; + int i_datasize; + snapshot_t **pointer; + vlc_value_t val; + int i_index; + snapshot_t *p_best_snapshot; + long searched_date; +#ifdef HAS_SNAPSHOT + int i_cachesize; +#endif + + exception=mediacontrol_exception_init( exception ); + + /* + if( var_Get( self->p_vlc, "snapshot-id", &val ) == VLC_SUCCESS ) + p_vout = vlc_object_get( self->p_vlc, val.i_int ); + */ + + /* FIXME: if in p_libvlc, we cannot have multiple video outputs */ + /* Once corrected, search for snapshot-id to modify all instances */ + if( var_Get( p_input, "snapshot-id", &val ) != VLC_SUCCESS ) + { + RAISE( mediacontrol_InternalException, "No snapshot-id in p_input" ); + return NULL; + } + p_vout = vlc_object_get( self->p_vlc, val.i_int ); + + if( ! p_vout ) + { + RAISE( mediacontrol_InternalException, "No snapshot module" ); + return NULL; + } + +#ifdef HAS_SNAPSHOT + /* We test if the vout is a snapshot module. We cannot test + pvout_psz_object_name( which is NULL ). But we can check if + there are snapshot-specific variables */ + if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS ) + { + RAISE( mediacontrol_InternalException, "No snapshot module" ); + vlc_object_release( p_vout ); + return NULL; + } + i_datasize = val.i_int; + + /* Handle the a_position parameter */ + if( ! ( a_position->origin == mediacontrol_RelativePosition + && a_position->value == 0 ) ) + { + /* The position is not the current one. Go to it. */ + mediacontrol_set_media_position( self, + ( mediacontrol_Position* ) a_position, + exception ); + if( exception->code ) + { + vlc_object_release( p_vout ); + return NULL; + } + } + + /* FIXME: We should not go further until we got past the position + ( which means that we had the possibility to capture the right + picture ). */ + + vlc_mutex_lock( &p_vout->picture_lock ); + + searched_date = mediacontrol_position2microsecond( p_input, + ( mediacontrol_Position * ) a_position ); + + var_Get( p_vout, "snapshot-cache-size", &val ); + i_cachesize = val.i_int ; + + var_Get( p_vout, "snapshot-list-pointer", &val ); + pointer = ( snapshot_t ** )val.p_address; + + if( ! pointer ) + { + RAISE( mediacontrol_InternalException, "No available snapshot" ); + + vlc_mutex_unlock( &p_vout->picture_lock ); + vlc_object_release( p_vout ); + return NULL; + } + + /* Find the more appropriate picture, based on date */ + p_best_snapshot = pointer[0]; + + for( i_index = 1 ; i_index < i_cachesize ; i_index++ ) + { + long l_diff = pointer[i_index]->date - searched_date; + if( l_diff > 0 && l_diff < abs( p_best_snapshot->date - searched_date )) + { + /* This one is closer, and _after_ the requested position */ + p_best_snapshot = pointer[i_index]; + } + } + + /* FIXME: add a test for the case that no picture matched the test + ( we have p_best_snapshot == pointer[0] */ + retval = _mediacontrol_createRGBPicture( p_best_snapshot->i_width, + p_best_snapshot->i_height, + p_vout->output.i_chroma, + p_best_snapshot->date, + p_best_snapshot->p_data, + i_datasize ); + + vlc_mutex_unlock( &p_vout->picture_lock ); + vlc_object_release( p_vout ); + +#endif + + return retval; +} + +mediacontrol_RGBPicture ** +mediacontrol_all_snapshots( mediacontrol_Instance *self, + mediacontrol_Exception *exception ) +{ + mediacontrol_RGBPicture **retval = NULL; + vout_thread_t *p_vout = NULL; + int i_datasize; + int i_cachesize; + vlc_value_t val; + int i_index; +#ifdef HAS_SNAPSHOT + snapshot_t **pointer; +#endif + + exception=mediacontrol_exception_init( exception ); + + if( var_Get( self->p_playlist->p_input, "snapshot-id", &val ) == VLC_SUCCESS ) + p_vout = vlc_object_get( self->p_vlc, val.i_int ); + + if( ! p_vout ) + { + RAISE( mediacontrol_InternalException, "No snapshot module" ); + return NULL; + } +#ifdef HAS_SNAPSHOT + /* We test if the vout is a snapshot module. We cannot test + pvout_psz_object_name( which is NULL ). But we can check if + there are snapshot-specific variables */ + if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS ) + { + RAISE( mediacontrol_InternalException, "No snapshot module" ); + vlc_object_release( p_vout ); + return NULL; + } + i_datasize = val.i_int; + + vlc_mutex_lock( &p_vout->picture_lock ); + + var_Get( p_vout, "snapshot-cache-size", &val ); + i_cachesize = val.i_int ; + + var_Get( p_vout, "snapshot-list-pointer", &val ); + pointer = ( snapshot_t ** )val.p_address; + + if( ! pointer ) + { + RAISE( mediacontrol_InternalException, "No available picture" ); + + vlc_mutex_unlock( &p_vout->picture_lock ); + vlc_object_release( p_vout ); + return NULL; + } + + retval = ( mediacontrol_RGBPicture** )malloc( (i_cachesize + 1 ) * sizeof( char* )); + + for( i_index = 0 ; i_index < i_cachesize ; i_index++ ) + { + snapshot_t *p_s = pointer[i_index]; + mediacontrol_RGBPicture *p_rgb; + + p_rgb = _mediacontrol_createRGBPicture( p_s->i_width, + p_s->i_height, + p_vout->output.i_chroma, + p_s->date, + p_s->p_data, + i_datasize ); + + retval[i_index] = p_rgb; + } + + retval[i_cachesize] = NULL; + + vlc_mutex_unlock( &p_vout->picture_lock ); + vlc_object_release( p_vout ); + +#endif + + return retval; +} + +int mediacontrol_showtext( vout_thread_t *p_vout, int i_channel, + char *psz_string, text_style_t *p_style, + int i_flags, int i_hmargin, int i_vmargin, + mtime_t i_start, mtime_t i_stop ) +{ + subpicture_t *p_spu; + video_format_t fmt; + + if( !psz_string ) return VLC_EGENERIC; + + p_spu = spu_CreateSubpicture( p_vout->p_spu ); + if( !p_spu ) return VLC_EGENERIC; + + /* Create a new subpicture region */ + memset( &fmt, 0, sizeof(video_format_t) ); + fmt.i_chroma = VLC_FOURCC('T','E','X','T'); + fmt.i_aspect = 0; + fmt.i_width = fmt.i_height = 0; + fmt.i_x_offset = fmt.i_y_offset = 0; + p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_vout), &fmt ); + if( !p_spu->p_region ) + { + msg_Err( p_vout, "cannot allocate SPU region" ); + spu_DestroySubpicture( p_vout->p_spu, p_spu ); + return VLC_EGENERIC; + } + + p_spu->p_region->psz_text = strdup( psz_string ); + p_spu->i_start = i_start; + p_spu->i_stop = i_stop; + p_spu->b_ephemer = VLC_FALSE; + p_spu->b_absolute = VLC_FALSE; + + p_spu->i_x = i_hmargin; + p_spu->i_y = i_vmargin; + p_spu->i_flags = i_flags; + p_spu->i_channel = i_channel; + + spu_DisplaySubpicture( p_vout->p_spu, p_spu ); + + return VLC_SUCCESS; +} + + +void +mediacontrol_display_text( mediacontrol_Instance *self, + const char * message, + const mediacontrol_Position * begin, + const mediacontrol_Position * end, + mediacontrol_Exception *exception ) +{ + input_thread_t *p_input = NULL; + vout_thread_t *p_vout = NULL; + char* psz_message; + + psz_message = strdup( message ); + if( !psz_message ) + { + RAISE( mediacontrol_InternalException, "No more memory" ); + return; + } + + p_vout = vlc_object_find( self->p_playlist, VLC_OBJECT_VOUT, FIND_CHILD ); + if( ! p_vout ) + { + RAISE( mediacontrol_InternalException, "No video output" ); + return; + } + + if( begin->origin == mediacontrol_RelativePosition && + begin->value == 0 && + end->origin == mediacontrol_RelativePosition ) + { + mtime_t i_duration = 0; + mtime_t i_now = mdate(); + + i_duration = 1000 * mediacontrol_unit_convert( self->p_playlist->p_input, + end->key, + mediacontrol_MediaTime, + end->value ); + + mediacontrol_showtext( p_vout, DEFAULT_CHAN, psz_message, NULL, + OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 0, 0, + i_now, i_now + i_duration ); + } + else + { + mtime_t i_debut, i_fin, i_now; + + p_input = self->p_playlist->p_input; + if( ! p_input ) + { + RAISE( mediacontrol_InternalException, "No input" ); + vlc_object_release( p_vout ); + return; + } + + /* FIXME */ + /* i_now = input_ClockGetTS( p_input, NULL, 0 ); */ + i_now = mdate(); + + i_debut = mediacontrol_position2microsecond( p_input, + ( mediacontrol_Position* ) begin ); + i_debut += i_now; + + i_fin = mediacontrol_position2microsecond( p_input, + ( mediacontrol_Position * ) end ); + i_fin += i_now; + + vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, psz_message, NULL, + OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 0, 0, + i_debut, i_fin ); + } + + vlc_object_release( p_vout ); +} + +unsigned short +mediacontrol_sound_get_volume( mediacontrol_Instance *self, + mediacontrol_Exception *exception ) +{ + short retval; + audio_volume_t i_volume; + + if( !self->p_intf ) + { + RAISE( mediacontrol_InternalException, "No interface module" ); + return 0; + } + aout_VolumeGet( self->p_intf, &i_volume ); + retval = i_volume; + return retval; +} + +void +mediacontrol_sound_set_volume( mediacontrol_Instance *self, + const unsigned short volume, + mediacontrol_Exception *exception ) +{ + if( !self->p_intf ) + { + RAISE( mediacontrol_InternalException, "No interface module" ); + return; + } + aout_VolumeSet( self->p_intf,( audio_volume_t )volume ); +} + +bool mediacontrol_set_visual(mediacontrol_Instance* self, + WINDOWHANDLE visual_id, + mediacontrol_Exception *exception) +{ + vlc_value_t value; + int ret; + + if( !self->p_vlc ) + { + RAISE( mediacontrol_InternalException, "No vlc reference" ); + return 0; + } + value.i_int=visual_id; + ret = var_Set(self->p_vlc, "drawable", value); + + return (ret == VLC_SUCCESS); +} diff --git a/src/control/core.c b/src/control/core.c new file mode 100644 index 0000000000..202bf54be9 --- /dev/null +++ b/src/control/core.c @@ -0,0 +1,389 @@ +/***************************************************************************** + * core.c: Core functions : init, playlist, stream management + ***************************************************************************** + * Copyright (C) 2005 VideoLAN + * $Id: vlc.c 10786 2005-04-23 23:19:17Z zorglub $ + * + * Authors: Olivier Aubert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#define HAS_SNAPSHOT 1 + +#ifdef HAS_SNAPSHOT +#include +#endif + +#include /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#define RAISE( c, m ) exception->code = c; \ + exception->message = strdup(m); + + +mediacontrol_Instance* mediacontrol_new_from_object( vlc_object_t* p_object, + mediacontrol_Exception *exception ) +{ + mediacontrol_Instance* retval; + vlc_object_t *p_vlc; + + p_vlc = vlc_object_find( p_object, VLC_OBJECT_ROOT, FIND_PARENT ); + if( ! p_vlc ) + { + RAISE( mediacontrol_InternalException, "Unable to initialize VLC" ); + return NULL; + } + retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) ); + retval->p_vlc = p_vlc; + retval->vlc_object_id = p_vlc->i_object_id; + + /* We can keep references on these, which should not change. Is it true ? */ + retval->p_playlist = vlc_object_find( p_vlc, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + retval->p_intf = vlc_object_find( p_vlc, VLC_OBJECT_INTF, FIND_ANYWHERE ); + + if( ! retval->p_playlist || ! retval->p_intf ) + { + RAISE( mediacontrol_InternalException, "No available interface" ); + return NULL; + } + return retval; +}; + + +/************************************************************************** + * Playback management + **************************************************************************/ +mediacontrol_Position* +mediacontrol_get_media_position( mediacontrol_Instance *self, + const mediacontrol_PositionOrigin an_origin, + const mediacontrol_PositionKey a_key, + mediacontrol_Exception *exception ) +{ + mediacontrol_Position* retval; + vlc_value_t val; + input_thread_t * p_input = self->p_playlist->p_input; + + exception = mediacontrol_exception_init( exception ); + + retval = ( mediacontrol_Position* )malloc( sizeof( mediacontrol_Position ) ); + retval->origin = an_origin; + retval->key = a_key; + + if( ! p_input ) + { + /* + RAISE( mediacontrol_InternalException, "No input thread." ); + return( NULL ); + */ + retval->value = 0; + return retval; + } + + if( an_origin == mediacontrol_RelativePosition + || an_origin == mediacontrol_ModuloPosition ) + { + /* Relative or ModuloPosition make no sense */ + retval->value = 0; + return retval; + } + + /* We are asked for an AbsolutePosition. */ + val.i_time = 0; + var_Get( p_input, "time", &val ); + /* FIXME: check val.i_time > 0 */ + + retval->value = mediacontrol_unit_convert( p_input, + mediacontrol_MediaTime, + a_key, + val.i_time / 1000 ); + return retval; +} + +/* Sets the media position */ +void +mediacontrol_set_media_position( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + vlc_value_t val; + input_thread_t * p_input = self->p_playlist->p_input; + + exception=mediacontrol_exception_init( exception ); + if( ! p_input ) + { + RAISE( mediacontrol_InternalException, "No input thread." ); + return; + } + + if( !var_GetBool( p_input, "seekable" ) ) + { + RAISE( mediacontrol_InvalidPosition, "Stream not seekable" ); + return; + } + + val.i_time = mediacontrol_position2microsecond( p_input, a_position ); + var_Set( p_input, "time", val ); + return; +} + +/* Starts playing a stream */ +void +mediacontrol_start( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + playlist_t * p_playlist = self->p_playlist; + + exception = mediacontrol_exception_init( exception ); + if( ! p_playlist ) + { + RAISE( mediacontrol_PlaylistException, "No available playlist" ); + return; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_value_t val; + + vlc_mutex_unlock( &p_playlist->object_lock ); + + /* Set start time */ + val.i_int = mediacontrol_position2microsecond( p_playlist->p_input, a_position ) / 1000000; + var_Set( p_playlist, "start-time", val ); + + playlist_Play( p_playlist ); + } + else + { + RAISE( mediacontrol_PlaylistException, "Empty playlist." ); + vlc_mutex_unlock( &p_playlist->object_lock ); + return; + } + + return; +} + +void +mediacontrol_pause( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + input_thread_t *p_input = self->p_playlist->p_input;; + + /* FIXME: use the a_position parameter */ + exception=mediacontrol_exception_init( exception ); + if( p_input != NULL ) + { + var_SetInteger( p_input, "state", PAUSE_S ); + } + else + { + RAISE( mediacontrol_InternalException, "No input" ); + } + + return; +} + +void +mediacontrol_resume( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + input_thread_t *p_input = self->p_playlist->p_input; + + /* FIXME: use the a_position parameter */ + exception=mediacontrol_exception_init( exception ); + if( p_input != NULL ) + { + var_SetInteger( p_input, "state", PAUSE_S ); + } + else + { + RAISE( mediacontrol_InternalException, "No input" ); + } +} + +void +mediacontrol_stop( mediacontrol_Instance *self, + const mediacontrol_Position * a_position, + mediacontrol_Exception *exception ) +{ + /* FIXME: use the a_position parameter */ + exception=mediacontrol_exception_init( exception ); + if( !self->p_playlist ) + { + RAISE( mediacontrol_PlaylistException, "No playlist" ); + return; + } + + playlist_Stop( self->p_playlist ); +} + +/************************************************************************** + * Playlist management + **************************************************************************/ + +void +mediacontrol_playlist_add_item( mediacontrol_Instance *self, + const char * psz_file, + mediacontrol_Exception *exception ) +{ + exception=mediacontrol_exception_init( exception ); + if( !self->p_playlist ) + { + RAISE( mediacontrol_InternalException, "No playlist" ); + return; + } + + playlist_Add( self->p_playlist, psz_file, psz_file , PLAYLIST_REPLACE, 0 ); +} + +void +mediacontrol_playlist_clear( mediacontrol_Instance *self, + mediacontrol_Exception *exception ) +{ + exception=mediacontrol_exception_init( exception ); + if( !self->p_playlist ) + { + RAISE( mediacontrol_PlaylistException, "No playlist" ); + return; + } + + playlist_Clear( self->p_playlist ); + + return; +} + +mediacontrol_PlaylistSeq * +mediacontrol_playlist_get_list( mediacontrol_Instance *self, + mediacontrol_Exception *exception ) +{ + mediacontrol_PlaylistSeq *retval; + int i_index; + playlist_t * p_playlist = self->p_playlist;; + int i_playlist_size; + + exception=mediacontrol_exception_init( exception ); + if( !p_playlist ) + { + RAISE( mediacontrol_PlaylistException, "No playlist" ); + return NULL; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + i_playlist_size = p_playlist->i_size; + + retval = mediacontrol_PlaylistSeq__alloc( i_playlist_size ); + + for( i_index = 0 ; i_index < i_playlist_size ; i_index++ ) + { + retval->data[i_index] = strdup( p_playlist->pp_items[i_index]->input.psz_uri ); + } + vlc_mutex_unlock( &p_playlist->object_lock ); + + return retval; +} + +/*************************************************************************** + * Status feedback + ***************************************************************************/ + +mediacontrol_StreamInformation * +mediacontrol_get_stream_information( mediacontrol_Instance *self, + mediacontrol_PositionKey a_key, + mediacontrol_Exception *exception ) +{ + mediacontrol_StreamInformation *retval; + input_thread_t *p_input = self->p_playlist->p_input; + vlc_value_t val; + + retval = ( mediacontrol_StreamInformation* )malloc( sizeof( mediacontrol_StreamInformation ) ); + if( ! retval ) + { + RAISE( mediacontrol_InternalException, "Out of memory" ); + return NULL; + } + + if( ! p_input ) + { + /* No p_input defined */ + retval->streamstatus = mediacontrol_UndefinedStatus; + retval->url = strdup( "None" ); + retval->position = 0; + retval->length = 0; + } + else + { + switch( var_GetInteger( p_input, "state" ) ) + { + case PLAYING_S : + retval->streamstatus = mediacontrol_PlayingStatus; + break; + case PAUSE_S : + retval->streamstatus = mediacontrol_PauseStatus; + break; + case INIT_S : + retval->streamstatus = mediacontrol_InitStatus; + break; + case END_S : + retval->streamstatus = mediacontrol_EndStatus; + break; + default : + retval->streamstatus = mediacontrol_UndefinedStatus; + break; + } + + retval->url = strdup( p_input->input.p_item->psz_uri ); + + /* TIME and LENGTH are in microseconds. We want them in ms */ + var_Get( p_input, "time", &val); + retval->position = val.i_time / 1000; + + var_Get( p_input, "length", &val); + retval->length = val.i_time / 1000; + + retval->position = mediacontrol_unit_convert( p_input, + mediacontrol_MediaTime, a_key, + retval->position ); + retval->length = mediacontrol_unit_convert( p_input, + mediacontrol_MediaTime, a_key, + retval->length ); + } + return retval; +} diff --git a/src/control/init.c b/src/control/init.c new file mode 100644 index 0000000000..5ea73bc975 --- /dev/null +++ b/src/control/init.c @@ -0,0 +1,86 @@ +#define __VLC__ +#include + +mediacontrol_Instance* mediacontrol_new( char** args, mediacontrol_Exception *exception ) +{ + mediacontrol_Instance* retval; + vlc_object_t *p_vlc; + int p_vlc_id; + char **ppsz_argv; + int i_count = 0; + int i_index; + char **p_tmp; + + if( args ) + { + for ( p_tmp = args ; *p_tmp != NULL ; p_tmp++ ) + i_count++; + } + + ppsz_argv = malloc( i_count + 2 ); + if( ! ppsz_argv ) + { + exception->code = mediacontrol_InternalException; + exception->message = "Out of memory"; + return NULL; + } + ppsz_argv[0] = "vlc"; + for ( i_index = 0; i_index < i_count; i_index++ ) + { + ppsz_argv[i_index + 1] = strdup( args[i_index] ); + if( ! ppsz_argv[i_index + 1] ) + { + exception->code = mediacontrol_InternalException; + exception->message = "Out of memory"; + return NULL; + } + } + + ppsz_argv[i_count + 1] = NULL; + + p_vlc_id = VLC_Create(); + + p_vlc = ( vlc_object_t* )vlc_current_object( p_vlc_id ); + + if( ! p_vlc ) + { + exception->code = mediacontrol_InternalException; + exception->message = strdup( "Unable to initialize VLC" ); + return NULL; + } + retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) ); + if( ! retval ) + { + exception->code = mediacontrol_InternalException; + exception->message = strdup( "Out of memory" ); + return NULL; + } + + VLC_Init( p_vlc_id, i_count + 1, ppsz_argv ); + + retval->p_vlc = p_vlc; + retval->vlc_object_id = p_vlc_id; + + /* We can keep references on these, which should not change. Is it true ? */ + retval->p_playlist = vlc_object_find( p_vlc, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + retval->p_intf = vlc_object_find( p_vlc, VLC_OBJECT_INTF, FIND_ANYWHERE ); + + if( ! retval->p_playlist || ! retval->p_intf ) + { + exception->code = mediacontrol_InternalException; + exception->message = strdup( "No available interface" ); + return NULL; + } + return retval; +}; + +void +mediacontrol_exit( mediacontrol_Instance *self ) +{ + /* + vlc_object_release( (vlc_object_t* )self->p_playlist ); + vlc_object_release( (vlc_object_t* )self->p_intf ); + */ + VLC_CleanUp( self->vlc_object_id ); + VLC_Destroy( self->vlc_object_id ); +} diff --git a/src/control/plugin.c b/src/control/plugin.c new file mode 100644 index 0000000000..9580aa82cc --- /dev/null +++ b/src/control/plugin.c @@ -0,0 +1,26 @@ +#include "mediacontrol-core.h" +#include + +mediacontrol_Instance* mediacontrol_new( char** args, mediacontrol_Exception *exception ) +{ + exception->code = mediacontrol_InternalException; + exception->message = strdup( "The mediacontrol extension was compiled for plugin use only." ); + return NULL; +}; + +void +mediacontrol_exit( mediacontrol_Instance *self ) +{ + /* + vlc_object_release( self->p_playlist ); + */ + + vlc_mutex_lock( &self->p_intf->change_lock ); + self->p_intf->b_die = 1; + vlc_mutex_unlock( &self->p_intf->change_lock ); + + /* + vlc_object_release( self->p_intf ); + vlc_object_release( self->p_vlc ); + */ +} diff --git a/src/control/util.c b/src/control/util.c new file mode 100644 index 0000000000..edbebbc0c8 --- /dev/null +++ b/src/control/util.c @@ -0,0 +1,292 @@ +/***************************************************************************** + * util.c: Utility functions and exceptions management + ***************************************************************************** + * Copyright (C) 2005 VideoLAN + * $Id: vlc.c 10786 2005-04-23 23:19:17Z zorglub $ + * + * Authors: Olivier Aubert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#define HAS_SNAPSHOT 1 + +#ifdef HAS_SNAPSHOT +#include +#endif + +#include /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#define RAISE( c, m ) exception->code = c; \ + exception->message = strdup(m); + +long long mediacontrol_unit_convert( input_thread_t *p_input, + mediacontrol_PositionKey from, + mediacontrol_PositionKey to, + long long value ) +{ + if( to == from ) + return value; + + /* For all conversions, we need data from p_input */ + if( !p_input ) + return 0; + + switch( from ) + { + case mediacontrol_MediaTime: + if( to == mediacontrol_ByteCount ) + { + /* FIXME */ + /* vlc < 0.8 API */ + /* return value * 50 * p_input->stream.i_mux_rate / 1000; */ + return 0; + } + if( to == mediacontrol_SampleCount ) + { + double f_fps; + + if( demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 ) + return 0; + else + return( value * f_fps / 1000.0 ); + } + /* Cannot happen */ + /* See http://catb.org/~esr/jargon/html/entry/can't-happen.html */ + break; + + case mediacontrol_SampleCount: + { + double f_fps; + + if( demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 ) + return 0; + + if( to == mediacontrol_ByteCount ) + { + /* FIXME */ + /* vlc < 0.8 API */ +/* return ( long long )( value * 50 * p_input->stream.i_mux_rate / f_fps ); */ + return 0; + } + + if( to == mediacontrol_MediaTime ) + return( long long )( value * 1000.0 / ( double )f_fps ); + + /* Cannot happen */ + break; + } + case mediacontrol_ByteCount: + /* FIXME */ + return 0; +/* vlc < 0.8 API: */ + +// if( p_input->stream.i_mux_rate == 0 ) +// return 0; +// +// /* Convert an offset into milliseconds. Taken from input_ext-intf.c. +// The 50 hardcoded constant comes from the definition of i_mux_rate : +// i_mux_rate : the rate we read the stream (in units of 50 bytes/s) ; +// 0 if undef */ +// if( to == mediacontrol_MediaTime ) +// return ( long long )( 1000 * value / 50 / p_input->stream.i_mux_rate ); +// +// if( to == mediacontrol_SampleCount ) +// { +// double f_fps; +// if( demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 ) +// return 0; +// else +// return ( long long )( value * f_fps / 50 / p_input->stream.i_mux_rate ); +// } + /* Cannot happen */ + break; + } + /* Cannot happen */ + return 0; +} + +/* Converts a mediacontrol_Position into a time in microseconds in + movie clock time */ +long long +mediacontrol_position2microsecond( input_thread_t* p_input, const mediacontrol_Position * pos ) +{ + switch( pos->origin ) + { + case mediacontrol_AbsolutePosition: + return ( 1000 * mediacontrol_unit_convert( p_input, + pos->key, /* from */ + mediacontrol_MediaTime, /* to */ + pos->value ) ); + break; + case mediacontrol_RelativePosition: + { + long long l_pos; + vlc_value_t val; + + val.i_time = 0; + if( p_input ) + { + var_Get( p_input, "time", &val ); + } + + l_pos = 1000 * mediacontrol_unit_convert( p_input, + pos->key, + mediacontrol_MediaTime, + pos->value ); + return val.i_time + l_pos; + break; + } + case mediacontrol_ModuloPosition: + { + long long l_pos; + vlc_value_t val; + + val.i_time = 0; + if( p_input ) + { + var_Get( p_input, "length", &val ); + } + + if( val.i_time > 0) + { + l_pos = ( 1000 * mediacontrol_unit_convert( p_input, + pos->key, + mediacontrol_MediaTime, + pos->value ) ); + } + else + l_pos = 0; + + return l_pos % val.i_time; + break; + } + } + return 0; +} + +mediacontrol_RGBPicture* +mediacontrol_RGBPicture__alloc( int datasize ) +{ + mediacontrol_RGBPicture* pic; + + pic = ( mediacontrol_RGBPicture * )malloc( sizeof( mediacontrol_RGBPicture ) ); + if( ! pic ) + return NULL; + + pic->size = datasize; + pic->data = ( char* )malloc( datasize ); + return pic; +} + +void +mediacontrol_RGBPicture__free( mediacontrol_RGBPicture* pic ) +{ + if( pic ) + free( pic->data ); + free( pic ); +} + +mediacontrol_PlaylistSeq* +mediacontrol_PlaylistSeq__alloc( int size ) +{ + mediacontrol_PlaylistSeq* ps; + + ps =( mediacontrol_PlaylistSeq* )malloc( sizeof( mediacontrol_PlaylistSeq ) ); + if( ! ps ) + return NULL; + + ps->size = size; + ps->data = ( char** )malloc( size * sizeof( char* ) ); + return ps; +} + +void +mediacontrol_PlaylistSeq__free( mediacontrol_PlaylistSeq* ps ) +{ + if( ps ) + { + int i; + for( i = 0 ; i < ps->size ; i++ ) + free( ps->data[i] ); + } + free( ps->data ); + free( ps ); +} + +mediacontrol_Exception* +mediacontrol_exception_init( mediacontrol_Exception *exception ) +{ + if( exception == NULL ) + { + exception = ( mediacontrol_Exception* )malloc( sizeof( mediacontrol_Exception ) ); + } + + exception->code = 0; + exception->message = NULL; + return exception; +} + +void +mediacontrol_exception_free( mediacontrol_Exception *exception ) +{ + if( ! exception ) + return; + + free( exception->message ); + free( exception ); +} + +mediacontrol_RGBPicture* +_mediacontrol_createRGBPicture( int i_width, int i_height, long i_chroma, long long l_date, + char* p_data, int i_datasize ) +{ + mediacontrol_RGBPicture *retval; + + retval = mediacontrol_RGBPicture__alloc( i_datasize ); + if( retval ) + { + retval->width = i_width; + retval->height = i_height; + retval->type = i_chroma; + retval->date = l_date; + retval->size = i_datasize; + memcpy( retval->data, p_data, i_datasize ); + } + return retval; +} diff --git a/src/libvlc.h b/src/libvlc.h index a9291dae1b..cf1d1c4707 100644 --- a/src/libvlc.h +++ b/src/libvlc.h @@ -322,9 +322,9 @@ static char *ppsz_clock_descriptions[] = #define INPUT_PROGRAM_TEXT N_("Choose program (SID)") #define INPUT_PROGRAM_LONGTEXT N_( \ - "Choose the program to select by giving its Service ID\n." \ + "Choose the program to select by giving its Service ID.\n" \ "Only use this option if you want to read a multi-program stream " \ - "(like DVB streams for example )" ) + "(ike DVB streams for example)" ) #define INPUT_PROGRAMS_TEXT N_("Choose programs") #define INPUT_PROGRAMS_LONGTEXT N_( \ @@ -927,7 +927,6 @@ vlc_module_begin(); set_subcategory( SUBCAT_AUDIO_AOUT ); add_module( "aout", "audio output", NULL, NULL, AOUT_TEXT, AOUT_LONGTEXT, VLC_TRUE ); - change_short('A'); set_subcategory( SUBCAT_AUDIO_AFILTER ); add_module_list_cat( "audio-filter", SUBCAT_AUDIO_AFILTER, 0, NULL, AUDIO_FILTER_TEXT, @@ -1200,6 +1199,7 @@ vlc_module_begin(); MEMCPY_LONGTEXT, VLC_TRUE ); add_module( "audio-channel-mixer", "audio mixer", NULL, NULL, AUDIO_CHANNEL_MIXER, AUDIO_CHANNEL_MIXER_LONGTEXT, VLC_TRUE ); + change_short('A'); set_section( N_("Plugins" ), NULL ); add_bool( "plugins-cache", VLC_TRUE, NULL, PLUGINS_CACHE_TEXT, diff --git a/vlc-config.in.in b/vlc-config.in.in index 0c90def5a8..95e0b369ef 100644 --- a/vlc-config.in.in +++ b/vlc-config.in.in @@ -82,6 +82,8 @@ if test "@includedir@" != "/usr/include"; then fi if test "${top_builddir}" != ""; then top_builddir="${top_builddir}/" +elif test "${TOP_BUILDDIR}" != ""; then + top_builddir="${TOP_BUILDDIR}/" fi includes="${includes} -I${top_builddir}include" cppflags="${includes}" -- 2.39.5