control.c 16.6 KB
Newer Older
Gildas Bazin's avatar
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * control.c
 *****************************************************************************
4
 * Copyright (C) 1999-2004 the VideoLAN team
5
 * $Id$
Gildas Bazin's avatar
Gildas Bazin committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
Gildas Bazin committed
22 23
 *****************************************************************************/

24 25 26 27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <vlc_common.h>
29 30 31

#include <stdio.h>
#include <stdlib.h>
Gildas Bazin's avatar
Gildas Bazin committed
32

Laurent Aimar's avatar
Laurent Aimar committed
33
#include "input_internal.h"
34
#include "event.h"
35
#include "ressource.h"
36

Gildas Bazin's avatar
Gildas Bazin committed
37

38 39
static void UpdateBookmarksOption( input_thread_t * );

Gildas Bazin's avatar
Gildas Bazin committed
40 41 42 43 44 45 46
/****************************************************************************
 * input_Control
 ****************************************************************************/
/**
 * Control function for inputs.
 * \param p_input input handle
 * \param i_query query type
47
 * \return VLC_SUCCESS if ok
Gildas Bazin's avatar
Gildas Bazin committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
 */
int input_Control( input_thread_t *p_input, int i_query, ...  )
{
    va_list args;
    int     i_result;

    va_start( args, i_query );
    i_result = input_vaControl( p_input, i_query, args );
    va_end( args );

    return i_result;
}

int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
{
63
    seekpoint_t *p_bkmk, ***ppp_bkmk;
64 65
    int i_bkmk = 0;
    int *pi_bkmk;
66

67
    int i_int, *pi_int;
68
    bool b_bool, *pb_bool;
69 70
    double f, *pf;
    int64_t i_64, *pi_64;
Gildas Bazin's avatar
Gildas Bazin committed
71

72 73 74
    char *psz;
    vlc_value_t val;

Gildas Bazin's avatar
Gildas Bazin committed
75 76
    switch( i_query )
    {
77 78 79
        case INPUT_GET_POSITION:
            pf = (double*)va_arg( args, double * );
            *pf = var_GetFloat( p_input, "position" );
Laurent Aimar's avatar
Laurent Aimar committed
80 81
            return VLC_SUCCESS;

82 83
        case INPUT_SET_POSITION:
            f = (double)va_arg( args, double );
Laurent Aimar's avatar
Laurent Aimar committed
84
            return var_SetFloat( p_input, "position", f );
85 86 87 88

        case INPUT_GET_LENGTH:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
            *pi_64 = var_GetTime( p_input, "length" );
Laurent Aimar's avatar
Laurent Aimar committed
89 90
            return VLC_SUCCESS;

91 92 93
        case INPUT_GET_TIME:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
            *pi_64 = var_GetTime( p_input, "time" );
Laurent Aimar's avatar
Laurent Aimar committed
94 95
            return VLC_SUCCESS;

96 97
        case INPUT_SET_TIME:
            i_64 = (int64_t)va_arg( args, int64_t );
Laurent Aimar's avatar
Laurent Aimar committed
98
            return var_SetTime( p_input, "time", i_64 );
99 100 101 102

        case INPUT_GET_RATE:
            pi_int = (int*)va_arg( args, int * );
            *pi_int = var_GetInteger( p_input, "rate" );
Laurent Aimar's avatar
Laurent Aimar committed
103 104
            return VLC_SUCCESS;

105 106
        case INPUT_SET_RATE:
            i_int = (int)va_arg( args, int );
Laurent Aimar's avatar
Laurent Aimar committed
107
            return var_SetInteger( p_input, "rate", i_int );
108 109 110 111

        case INPUT_GET_STATE:
            pi_int = (int*)va_arg( args, int * );
            *pi_int = var_GetInteger( p_input, "state" );
Laurent Aimar's avatar
Laurent Aimar committed
112 113
            return VLC_SUCCESS;

114 115
        case INPUT_SET_STATE:
            i_int = (int)va_arg( args, int );
Laurent Aimar's avatar
Laurent Aimar committed
116
            return var_SetInteger( p_input, "state", i_int );
117

118 119 120 121
        case INPUT_GET_AUDIO_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
            *pi_64 = var_GetTime( p_input, "audio-delay" );
            return VLC_SUCCESS;
122

123 124 125 126
        case INPUT_GET_SPU_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
            *pi_64 = var_GetTime( p_input, "spu-delay" );
            return VLC_SUCCESS;
127

128 129 130
        case INPUT_SET_AUDIO_DELAY:
            i_64 = (int64_t)va_arg( args, int64_t );
            return var_SetTime( p_input, "audio-delay", i_64 );
131

132 133 134
        case INPUT_SET_SPU_DELAY:
            i_64 = (int64_t)va_arg( args, int64_t );
            return var_SetTime( p_input, "spu-delay", i_64 );
135 136

        case INPUT_ADD_INFO:
137
        {
138 139 140 141
            char *psz_cat = (char *)va_arg( args, char * );
            char *psz_name = (char *)va_arg( args, char * );
            char *psz_format = (char *)va_arg( args, char * );

142 143 144 145
            char *psz_value;
            
            if( vasprintf( &psz_value, psz_format, args ) == -1 )
                return VLC_EGENERIC;
146

147
            int i_ret = input_item_AddInfo( p_input->p->p_item,
148
                                            psz_cat, psz_name, "%s", psz_value );
Rémi Duraffort's avatar
Rémi Duraffort committed
149
            free( psz_value );
150

151 152 153
            if( !p_input->b_preparsing && !i_ret )
                input_SendEventMetaInfo( p_input );
            return i_ret;
154
        }
155 156 157 158 159
        case INPUT_DEL_INFO:
        {
            char *psz_cat = (char *)va_arg( args, char * );
            char *psz_name = (char *)va_arg( args, char * );

160
            int i_ret = input_item_DelInfo( p_input->p->p_item,
161
                                            psz_cat, psz_name );
162

163 164 165
            if( !p_input->b_preparsing && !i_ret )
                input_SendEventMetaInfo( p_input );
            return i_ret;
166
        }
167 168 169 170 171
        case INPUT_GET_INFO:
        {
            char *psz_cat = (char *)va_arg( args, char * );
            char *psz_name = (char *)va_arg( args, char * );
            char **ppsz_value = (char **)va_arg( args, char ** );
172
            int i_ret = VLC_EGENERIC;
173 174
            *ppsz_value = NULL;

175
            *ppsz_value = input_item_GetInfo( p_input->p->p_item,
176
                                                  psz_cat, psz_name );
177 178 179 180 181 182 183
            return i_ret;
        }

        case INPUT_SET_NAME:
        {
            char *psz_name = (char *)va_arg( args, char * );

184
            if( !psz_name ) return VLC_EGENERIC;
185

186
            input_item_SetName( p_input->p->p_item, psz_name );
187

188
            if( !p_input->b_preparsing )
189
                input_SendEventMetaName( p_input, psz_name );
190
            return VLC_SUCCESS;
191 192
        }

Gildas Bazin's avatar
Gildas Bazin committed
193 194 195
        case INPUT_ADD_BOOKMARK:
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
            p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
196

197
            vlc_mutex_lock( &p_input->p->p_item->lock );
Gildas Bazin's avatar
Gildas Bazin committed
198 199
            if( !p_bkmk->psz_name )
            {
200 201 202
                 if( asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
                               p_input->p->i_bookmark ) == -1 )
                     p_bkmk->psz_name = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
203
            }
204

205
            TAB_APPEND( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
206
            vlc_mutex_unlock( &p_input->p->p_item->lock );
Gildas Bazin's avatar
Gildas Bazin committed
207

208 209
            UpdateBookmarksOption( p_input );

210
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
211

212
        case INPUT_CHANGE_BOOKMARK:
213 214 215
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
            i_bkmk = (int)va_arg( args, int );

216
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
217
            if( i_bkmk < p_input->p->i_bookmark )
218
            {
219 220
                vlc_seekpoint_Delete( p_input->p->pp_bookmark[i_bkmk] );
                p_input->p->pp_bookmark[i_bkmk] = vlc_seekpoint_Duplicate( p_bkmk );
221
            }
222
            vlc_mutex_unlock( &p_input->p->p_item->lock );
223 224 225 226

            UpdateBookmarksOption( p_input );

            return VLC_SUCCESS;
227

Gildas Bazin's avatar
Gildas Bazin committed
228
        case INPUT_DEL_BOOKMARK:
229
            i_bkmk = (int)va_arg( args, int );
230

231
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
232
            if( i_bkmk < p_input->p->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
233
            {
234
                p_bkmk = p_input->p->pp_bookmark[i_bkmk];
235
                TAB_REMOVE( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
236 237
                vlc_seekpoint_Delete( p_bkmk );

238
                vlc_mutex_unlock( &p_input->p->p_item->lock );
239 240 241

                UpdateBookmarksOption( p_input );

242
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
243
            }
244
            vlc_mutex_unlock( &p_input->p->p_item->lock );
245 246

            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
247 248 249 250

        case INPUT_GET_BOOKMARKS:
            ppp_bkmk = (seekpoint_t ***)va_arg( args, seekpoint_t *** );
            pi_bkmk = (int *)va_arg( args, int * );
251

252
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
253
            if( p_input->p->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
254 255 256
            {
                int i;

Clément Stenac's avatar
Clément Stenac committed
257
                *pi_bkmk = p_input->p->i_bookmark;
Gildas Bazin's avatar
Gildas Bazin committed
258
                *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
Clément Stenac's avatar
Clément Stenac committed
259 260
                                    p_input->p->i_bookmark );
                for( i = 0; i < p_input->p->i_bookmark; i++ )
Gildas Bazin's avatar
Gildas Bazin committed
261 262
                {
                    (*ppp_bkmk)[i] =
263
                        vlc_seekpoint_Duplicate( p_input->p->pp_bookmark[i] );
Gildas Bazin's avatar
Gildas Bazin committed
264
                }
265

266
                vlc_mutex_unlock( &p_input->p->p_item->lock );
267
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
268 269 270 271 272
            }
            else
            {
                *ppp_bkmk = NULL;
                *pi_bkmk = 0;
273

274
                vlc_mutex_unlock( &p_input->p->p_item->lock );
275
                return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
276 277 278 279
            }
            break;

        case INPUT_CLEAR_BOOKMARKS:
280

281
            vlc_mutex_lock( &p_input->p->p_item->lock );
282
            while( p_input->p->i_bookmark > 0 )
Gildas Bazin's avatar
Gildas Bazin committed
283
            {
284
                p_bkmk = p_input->p->pp_bookmark[p_input->p->i_bookmark-1];
Gildas Bazin's avatar
Gildas Bazin committed
285

286 287 288
                TAB_REMOVE( p_input->p->i_bookmark, p_input->p->pp_bookmark,
                            p_bkmk );
                vlc_seekpoint_Delete( p_bkmk );
Gildas Bazin's avatar
Gildas Bazin committed
289
            }
290
            vlc_mutex_unlock( &p_input->p->p_item->lock );
291 292

            UpdateBookmarksOption( p_input );
293
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
294 295 296

        case INPUT_SET_BOOKMARK:
            i_bkmk = (int)va_arg( args, int );
297

298 299
            val.i_int = i_bkmk;
            input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
300

301
            return VLC_SUCCESS;
302

303 304 305
        case INPUT_GET_BOOKMARK:
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );

306 307 308
            vlc_mutex_lock( &p_input->p->p_item->lock );
            *p_bkmk = p_input->p->bookmark;
            vlc_mutex_unlock( &p_input->p->p_item->lock );
309 310
            return VLC_SUCCESS;

311 312
        case INPUT_ADD_OPTION:
        {
313 314 315
            const char *psz_option = va_arg( args, const char * );
            const char *psz_value = va_arg( args, const char * );
            char *str;
316 317
            int i;

318 319
            if( asprintf( &str, "%s=%s", psz_option, psz_value ) == -1 )
                return VLC_ENOMEM;
320

321 322
            i = input_item_AddOption( p_input->p->p_item, str,
                                      VLC_INPUT_OPTION_UNIQUE );
323 324
            free( str );
            return i;
325 326
        }

327 328
        case INPUT_GET_VIDEO_FPS:
            pf = (double*)va_arg( args, double * );
329

330
            vlc_mutex_lock( &p_input->p->p_item->lock );
331
            *pf = p_input->p->f_fps;
332
            vlc_mutex_unlock( &p_input->p->p_item->lock );
333 334
            return VLC_SUCCESS;

335 336 337 338 339 340 341 342
        case INPUT_ADD_SLAVE:
            psz = (char*)va_arg( args, char * );
            if( psz && *psz )
            {
                val.psz_string = strdup( psz );
                input_ControlPush( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
            }
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
343

344 345 346 347 348 349 350 351 352 353 354 355 356
        case INPUT_ADD_SUBTITLE:
            psz = (char*)va_arg( args, char * );
            b_bool = (bool)va_arg( args, int );

            if( !psz || *psz == '\0' )
                return VLC_EGENERIC;
            if( b_bool && !subtitles_Filter( psz ) )
                return VLC_EGENERIC;

            val.psz_string = strdup( psz );
            input_ControlPush( p_input, INPUT_CONTROL_ADD_SUBTITLE, &val );
            return VLC_SUCCESS;

357 358 359 360 361 362
        case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int*  res=can fail */
        {
            input_attachment_t ***ppp_attachment = (input_attachment_t***)va_arg( args, input_attachment_t *** );
            int *pi_attachment = (int*)va_arg( args, int * );
            int i;

363
            vlc_mutex_lock( &p_input->p->p_item->lock );
364 365
            if( p_input->p->i_attachment <= 0 )
            {
366
                vlc_mutex_unlock( &p_input->p->p_item->lock );
367 368 369 370 371 372 373 374 375
                *ppp_attachment = NULL;
                *pi_attachment = 0;
                return VLC_EGENERIC;
            }
            *pi_attachment = p_input->p->i_attachment;
            *ppp_attachment = malloc( sizeof(input_attachment_t**) * p_input->p->i_attachment );
            for( i = 0; i < p_input->p->i_attachment; i++ )
                (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );

376
            vlc_mutex_unlock( &p_input->p->p_item->lock );
377
            return VLC_SUCCESS;
378 379 380 381 382 383 384 385
        }

        case INPUT_GET_ATTACHMENT:  /* arg1=input_attachment_t**, arg2=char*  res=can fail */
        {
            input_attachment_t **pp_attachment = (input_attachment_t**)va_arg( args, input_attachment_t ** );
            const char *psz_name = (const char*)va_arg( args, const char * );
            int i;

386
            vlc_mutex_lock( &p_input->p->p_item->lock );
387 388 389 390 391
            for( i = 0; i < p_input->p->i_attachment; i++ )
            {
                if( !strcmp( p_input->p->attachment[i]->psz_name, psz_name ) )
                {
                    *pp_attachment = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );
392
                    vlc_mutex_unlock( &p_input->p->p_item->lock );
393 394 395 396
                    return VLC_SUCCESS;
                }
            }
            *pp_attachment = NULL;
397
            vlc_mutex_unlock( &p_input->p->p_item->lock );
398 399 400
            return VLC_EGENERIC;
        }

401 402 403 404 405 406 407 408 409
        case INPUT_SET_RECORD_STATE:
            b_bool = (bool)va_arg( args, int );
            var_SetBool( p_input, "record", b_bool );
            return VLC_SUCCESS;

        case INPUT_GET_RECORD_STATE:
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = var_GetBool( p_input, "record" );
            return VLC_SUCCESS;
410

411 412 413 414 415
        case INPUT_RESTART_ES:
            val.i_int = (int)va_arg( args, int );
            input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
            return VLC_SUCCESS;

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
        case INPUT_GET_AOUT:
        {
            aout_instance_t *p_aout = input_ressource_HoldAout( p_input->p->p_ressource );
            if( !p_aout )
                return VLC_EGENERIC;

            aout_instance_t **pp_aout = (aout_instance_t**)va_arg( args, aout_instance_t** );
            *pp_aout = p_aout;
            return VLC_SUCCESS;
        }

        case INPUT_GET_VOUTS:
        {
            vout_thread_t ***ppp_vout = (vout_thread_t***)va_arg( args, vout_thread_t*** );
            int           *pi_vout = (int*)va_arg( args, int* );

            input_ressource_HoldVouts( p_input->p->p_ressource, ppp_vout, pi_vout );
            if( *pi_vout <= 0 )
                return VLC_EGENERIC;
            return VLC_SUCCESS;
        }

Gildas Bazin's avatar
Gildas Bazin committed
438 439
        default:
            msg_Err( p_input, "unknown query in input_vaControl" );
Laurent Aimar's avatar
Laurent Aimar committed
440
            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
441 442
    }
}
443 444 445

static void UpdateBookmarksOption( input_thread_t *p_input )
{
446
    vlc_mutex_lock( &p_input->p->p_item->lock );
447 448 449 450

    /* Update the "bookmark" list */
    var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
    for( int i = 0; i < p_input->p->i_bookmark; i++ )
451
    {
452
        vlc_value_t val, text;
453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
        val.i_int = i;
        text.psz_string = p_input->p->pp_bookmark[i]->psz_name;
        var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
                    &val, &text );
    }

    /* Create the "bookmarks" option value */
    const char *psz_format = "{name=%s,bytes=%"PRId64",time=%"PRId64"}";
    int i_len = strlen( "bookmarks=" );
    for( int i = 0; i < p_input->p->i_bookmark; i++ )
    {
        const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[i];

        i_len += snprintf( NULL, 0, psz_format,
                           p_bookmark->psz_name,
                           p_bookmark->i_byte_offset,
                           p_bookmark->i_time_offset/1000000 );
    }

    char *psz_value = malloc( i_len + p_input->p->i_bookmark + 1 );
    char *psz_next = psz_value;

    psz_next += sprintf( psz_next, "bookmarks=" );
    for( int i = 0; i < p_input->p->i_bookmark && psz_value != NULL; i++ )
    {
        const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[i];

        psz_next += sprintf( psz_next, psz_format,
                             p_bookmark->psz_name,
                             p_bookmark->i_byte_offset,
                             p_bookmark->i_time_offset/1000000 );

        if( i < p_input->p->i_bookmark - 1)
            *psz_next++ = ',';
488
    }
489
    vlc_mutex_unlock( &p_input->p->p_item->lock );
490

491
    if( psz_value )
492
        input_item_AddOption( p_input->p->p_item, psz_value, VLC_INPUT_OPTION_UNIQUE );
493

Rémi Duraffort's avatar
Rémi Duraffort committed
494
    free( psz_value );
495 496

    input_SendEventBookmark( p_input );
497
}
Rémi Duraffort's avatar
Rémi Duraffort committed
498