control.c 21.4 KB
Newer Older
Gildas Bazin's avatar
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * control.c
 *****************************************************************************
4
 * Copyright (C) 1999-2015 VLC authors and VideoLAN
5
 * $Id$
Gildas Bazin's avatar
Gildas Bazin committed
6 7 8
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Gildas Bazin's avatar
Gildas Bazin committed
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Gildas Bazin's avatar
Gildas Bazin committed
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software 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
#include <vlc_memstream.h>
30 31 32

#include <stdio.h>
#include <stdlib.h>
33
#include <assert.h>
Gildas Bazin's avatar
Gildas Bazin committed
34

35
#include "input_internal.h"
36
#include "event.h"
37
#include "resource.h"
38
#include "es_out.h"
39

Gildas Bazin's avatar
Gildas Bazin committed
40

41 42
static void UpdateBookmarksOption( input_thread_t * );

Gildas Bazin's avatar
Gildas Bazin committed
43 44 45 46 47 48 49
/****************************************************************************
 * input_Control
 ****************************************************************************/
/**
 * Control function for inputs.
 * \param p_input input handle
 * \param i_query query type
50
 * \return VLC_SUCCESS if ok
Gildas Bazin's avatar
Gildas Bazin committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 */
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 )
{
66
    input_thread_private_t *priv = input_priv(p_input);
67
    seekpoint_t *p_bkmk, ***ppp_bkmk;
68 69
    int i_bkmk = 0;
    int *pi_bkmk;
70

71
    int i_int, *pi_int;
72
    bool b_bool, *pb_bool;
73 74
    double f, *pf;
    int64_t i_64, *pi_64;
Gildas Bazin's avatar
Gildas Bazin committed
75

76 77 78
    char *psz;
    vlc_value_t val;

Gildas Bazin's avatar
Gildas Bazin committed
79 80
    switch( i_query )
    {
81
        case INPUT_GET_POSITION:
82
            pf = va_arg( args, double * );
83
            *pf = var_GetFloat( p_input, "position" );
84 85
            return VLC_SUCCESS;

86
        case INPUT_SET_POSITION:
87
            f = va_arg( args, double );
88
            return var_SetFloat( p_input, "position", f );
89 90

        case INPUT_GET_LENGTH:
91
            pi_64 = va_arg( args, int64_t * );
92
            *pi_64 = var_GetInteger( p_input, "length" );
93 94
            return VLC_SUCCESS;

95
        case INPUT_GET_TIME:
96
            pi_64 = va_arg( args, int64_t * );
97
            *pi_64 = var_GetInteger( p_input, "time" );
98 99
            return VLC_SUCCESS;

100
        case INPUT_SET_TIME:
101
            i_64 = va_arg( args, int64_t );
102
            return var_SetInteger( p_input, "time", i_64 );
103 104

        case INPUT_GET_RATE:
105
            pi_int = va_arg( args, int * );
106
            *pi_int = INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" );
107 108
            return VLC_SUCCESS;

109
        case INPUT_SET_RATE:
110
            i_int = va_arg( args, int );
111 112
            return var_SetFloat( p_input, "rate",
                                 (float)INPUT_RATE_DEFAULT / (float)i_int );
113 114

        case INPUT_GET_STATE:
115
            pi_int = va_arg( args, int * );
116
            *pi_int = var_GetInteger( p_input, "state" );
117 118
            return VLC_SUCCESS;

119
        case INPUT_SET_STATE:
120
            i_int = va_arg( args, int );
121
            return var_SetInteger( p_input, "state", i_int );
122

123
        case INPUT_GET_AUDIO_DELAY:
124
            pi_64 = va_arg( args, int64_t * );
125
            *pi_64 = var_GetInteger( p_input, "audio-delay" );
126
            return VLC_SUCCESS;
127

128
        case INPUT_GET_SPU_DELAY:
129
            pi_64 = va_arg( args, int64_t * );
130
            *pi_64 = var_GetInteger( p_input, "spu-delay" );
131
            return VLC_SUCCESS;
132

133
        case INPUT_SET_AUDIO_DELAY:
134
            i_64 = va_arg( args, int64_t );
135
            return var_SetInteger( p_input, "audio-delay", i_64 );
136

137
        case INPUT_SET_SPU_DELAY:
138
            i_64 = va_arg( args, int64_t );
139
            return var_SetInteger( p_input, "spu-delay", i_64 );
140

141 142 143 144 145
        case INPUT_NAV_ACTIVATE:
        case INPUT_NAV_UP:
        case INPUT_NAV_DOWN:
        case INPUT_NAV_LEFT:
        case INPUT_NAV_RIGHT:
146
        case INPUT_NAV_POPUP:
147
        case INPUT_NAV_MENU:
148 149 150 151
            input_ControlPush( p_input, i_query - INPUT_NAV_ACTIVATE
                               + INPUT_CONTROL_NAV_ACTIVATE, NULL );
            return VLC_SUCCESS;

152
        case INPUT_ADD_INFO:
153
        {
154 155 156
            char *psz_cat = va_arg( args, char * );
            char *psz_name = va_arg( args, char * );
            char *psz_format = va_arg( args, char * );
157

158
            char *psz_value;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
159

160 161
            if( vasprintf( &psz_value, psz_format, args ) == -1 )
                return VLC_EGENERIC;
162

163 164
            int i_ret = input_item_AddInfo( priv->p_item, psz_cat, psz_name,
                                            "%s", psz_value );
165
            free( psz_value );
166

167
            if( !priv->b_preparsing && !i_ret )
168 169
                input_SendEventMetaInfo( p_input );
            return i_ret;
170
        }
171 172 173 174 175 176
        case INPUT_REPLACE_INFOS:
        case INPUT_MERGE_INFOS:
        {
            info_category_t *p_cat = va_arg( args, info_category_t * );

            if( i_query == INPUT_REPLACE_INFOS )
177
                input_item_ReplaceInfos( priv->p_item, p_cat );
178
            else
179
                input_item_MergeInfos( priv->p_item, p_cat );
180

181
            if( !priv->b_preparsing )
182 183 184
                input_SendEventMetaInfo( p_input );
            return VLC_SUCCESS;
        }
185 186
        case INPUT_DEL_INFO:
        {
187 188
            char *psz_cat = va_arg( args, char * );
            char *psz_name = va_arg( args, char * );
189

190
            int i_ret = input_item_DelInfo( priv->p_item, psz_cat, psz_name );
191

192
            if( !priv->b_preparsing && !i_ret )
193 194
                input_SendEventMetaInfo( p_input );
            return i_ret;
195
        }
Gildas Bazin's avatar
Gildas Bazin committed
196
        case INPUT_ADD_BOOKMARK:
197
            p_bkmk = va_arg( args, seekpoint_t * );
Gildas Bazin's avatar
Gildas Bazin committed
198
            p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
199

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

208 209 210 211 212 213 214
            if( p_bkmk->psz_name )
                TAB_APPEND( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
            else
            {
                vlc_seekpoint_Delete( p_bkmk );
                p_bkmk = NULL;
            }
215
            vlc_mutex_unlock( &priv->p_item->lock );
Gildas Bazin's avatar
Gildas Bazin committed
216

217 218
            UpdateBookmarksOption( p_input );

219
            return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
220

221
        case INPUT_CHANGE_BOOKMARK:
222 223 224
            p_bkmk = va_arg( args, seekpoint_t * );
            i_bkmk = va_arg( args, int );

225 226
            vlc_mutex_lock( &priv->p_item->lock );
            if( i_bkmk < priv->i_bookmark )
227
            {
228 229 230 231 232 233
                p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
                if( p_bkmk )
                {
                    vlc_seekpoint_Delete( priv->pp_bookmark[i_bkmk] );
                    priv->pp_bookmark[i_bkmk] = p_bkmk;
                }
234
            }
235
            else p_bkmk = NULL;
236
            vlc_mutex_unlock( &priv->p_item->lock );
237 238 239

            UpdateBookmarksOption( p_input );

240
            return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
241

Gildas Bazin's avatar
Gildas Bazin committed
242
        case INPUT_DEL_BOOKMARK:
243
            i_bkmk = va_arg( args, int );
244

245 246
            vlc_mutex_lock( &priv->p_item->lock );
            if( i_bkmk < priv->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
247
            {
248 249
                p_bkmk = priv->pp_bookmark[i_bkmk];
                TAB_REMOVE( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
250 251
                vlc_seekpoint_Delete( p_bkmk );

252
                vlc_mutex_unlock( &priv->p_item->lock );
253 254 255

                UpdateBookmarksOption( p_input );

256
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
257
            }
258
            vlc_mutex_unlock( &priv->p_item->lock );
259 260

            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
261 262

        case INPUT_GET_BOOKMARKS:
263 264
            ppp_bkmk = va_arg( args, seekpoint_t *** );
            pi_bkmk = va_arg( args, int * );
265

266 267
            vlc_mutex_lock( &priv->p_item->lock );
            if( priv->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
268 269 270
            {
                int i;

271
                *pi_bkmk = priv->i_bookmark;
272
                *ppp_bkmk = vlc_alloc( priv->i_bookmark, sizeof(seekpoint_t *) );
273
                for( i = 0; i < priv->i_bookmark; i++ )
Gildas Bazin's avatar
Gildas Bazin committed
274 275
                {
                    (*ppp_bkmk)[i] =
276
                        vlc_seekpoint_Duplicate( input_priv(p_input)->pp_bookmark[i] );
Gildas Bazin's avatar
Gildas Bazin committed
277
                }
278

279
                vlc_mutex_unlock( &priv->p_item->lock );
280
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
281 282 283 284 285
            }
            else
            {
                *ppp_bkmk = NULL;
                *pi_bkmk = 0;
286

287
                vlc_mutex_unlock( &priv->p_item->lock );
288
                return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
289 290 291 292
            }
            break;

        case INPUT_CLEAR_BOOKMARKS:
293
            vlc_mutex_lock( &priv->p_item->lock );
294 295
            for( int i = 0; i < priv->i_bookmark; ++i )
                vlc_seekpoint_Delete( priv->pp_bookmark[i] );
Gildas Bazin's avatar
Gildas Bazin committed
296

297
            TAB_CLEAN( priv->i_bookmark, priv->pp_bookmark );
298
            vlc_mutex_unlock( &priv->p_item->lock );
299 300

            UpdateBookmarksOption( p_input );
301
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
302 303

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

306 307
            val.i_int = i_bkmk;
            input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
308

309
            return VLC_SUCCESS;
310

311
        case INPUT_GET_BOOKMARK:
312
            p_bkmk = va_arg( args, seekpoint_t * );
313

314 315 316
            vlc_mutex_lock( &priv->p_item->lock );
            *p_bkmk = priv->bookmark;
            vlc_mutex_unlock( &priv->p_item->lock );
317 318
            return VLC_SUCCESS;

319 320
        case INPUT_GET_TITLE_INFO:
        {
321 322
            input_title_t **p_title = va_arg( args, input_title_t ** );
            int *pi_req_title_offset = va_arg( args, int * );
323

324
            vlc_mutex_lock( &priv->p_item->lock );
325

326 327 328
            int i_current_title = var_GetInteger( p_input, "title" );
            if ( *pi_req_title_offset < 0 ) /* return current title if -1 */
                *pi_req_title_offset = i_current_title;
329

330
            if( priv->i_title && priv->i_title > *pi_req_title_offset )
331
            {
332
                *p_title = vlc_input_title_Duplicate( priv->title[*pi_req_title_offset] );
333
                vlc_mutex_unlock( &priv->p_item->lock );
334 335 336 337
                return VLC_SUCCESS;
            }
            else
            {
338
                vlc_mutex_unlock( &priv->p_item->lock );
339 340 341 342
                return VLC_EGENERIC;
            }
        }

343 344
        case INPUT_GET_FULL_TITLE_INFO:
        {
345
            vlc_mutex_lock( &priv->p_item->lock );
346
            unsigned count = priv->i_title;
347
            input_title_t **array = vlc_alloc( count, sizeof (*array) );
348

349
            if( count > 0 && unlikely(array == NULL) )
350
            {
351
                vlc_mutex_unlock( &priv->p_item->lock );
352 353 354
                return VLC_ENOMEM;
            }

355
            for( unsigned i = 0; i < count; i++ )
356
                array[i] = vlc_input_title_Duplicate( priv->title[i] );
357

358
            vlc_mutex_unlock( &priv->p_item->lock );
359

360 361
            *va_arg( args, input_title_t *** ) = array;
            *va_arg( args, int * ) = count;
362 363 364
            return VLC_SUCCESS;
        }

365 366
        case INPUT_GET_SEEKPOINTS:
        {
367 368
            seekpoint_t ***array = va_arg( args, seekpoint_t *** );
            int *pi_title_to_fetch = va_arg( args, int * );
369

370
            vlc_mutex_lock( &priv->p_item->lock );
371 372 373 374

            if ( *pi_title_to_fetch < 0 ) /* query current title if -1 */
                *pi_title_to_fetch = var_GetInteger( p_input, "title" );

375
            if( priv->i_title == 0 || priv->i_title <= *pi_title_to_fetch )
376
            {
377
                vlc_mutex_unlock( &priv->p_item->lock );
378 379 380
                return VLC_EGENERIC;
            }

381
            const input_title_t *p_title = priv->title[*pi_title_to_fetch];
382 383 384 385 386 387 388

            /* set arg2 to the number of seekpoints we found */
            const int i_chapters = p_title->i_seekpoint;
            *pi_title_to_fetch = i_chapters;

            if ( i_chapters == 0 )
            {
389
                vlc_mutex_unlock( &priv->p_item->lock );
390 391 392 393
                return VLC_SUCCESS;
            }

            *array = calloc( p_title->i_seekpoint, sizeof(**array) );
394
            if( unlikely(array == NULL) )
395
            {
396
                vlc_mutex_unlock( &priv->p_item->lock );
397 398 399 400 401 402 403
                return VLC_ENOMEM;
            }
            for( int i = 0; i < i_chapters; i++ )
            {
                (*array)[i] = vlc_seekpoint_Duplicate( p_title->seekpoint[i] );
            }

404
            vlc_mutex_unlock( &priv->p_item->lock );
405 406 407 408

            return VLC_SUCCESS;
        }

409
        case INPUT_ADD_SLAVE:
410 411
        {
            enum slave_type type =  (enum slave_type) va_arg( args, enum slave_type );
412 413
            psz = va_arg( args, char * );
            b_bool = va_arg( args, int );
414
            bool b_notify = va_arg( args, int );
415
            bool b_check_ext = va_arg( args, int );
416 417 418

            if( !psz || ( type != SLAVE_TYPE_SPU && type != SLAVE_TYPE_AUDIO ) )
                return VLC_EGENERIC;
419 420 421
            if( b_check_ext && type == SLAVE_TYPE_SPU &&
                !subtitles_Filter( psz ) )
                return VLC_EGENERIC;
422 423 424 425 426

            input_item_slave_t *p_slave =
                input_item_slave_New( psz, type, SLAVE_PRIORITY_USER );
            if( !p_slave )
                return VLC_ENOMEM;
427
            p_slave->b_forced = b_bool;
428 429 430

            val.p_address = p_slave;
            input_ControlPush( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
            if( b_notify )
            {
                vout_thread_t *p_vout = input_GetVout( p_input );
                if( p_vout )
                {
                    switch( type )
                    {
                        case SLAVE_TYPE_AUDIO:
                            vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
                                            vlc_gettext("Audio track added"));
                            break;
                        case SLAVE_TYPE_SPU:
                            vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
                                            vlc_gettext("Subtitle track added"));
                            break;
                    }
                    vlc_object_release( (vlc_object_t *)p_vout );
                }
            }
450
            return VLC_SUCCESS;
451
        }
Gildas Bazin's avatar
Gildas Bazin committed
452

453 454
        case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int*  res=can fail */
        {
455 456
            input_attachment_t ***ppp_attachment = va_arg( args, input_attachment_t *** );
            int *pi_attachment = va_arg( args, int * );
457

458 459
            vlc_mutex_lock( &priv->p_item->lock );
            if( priv->i_attachment <= 0 )
460
            {
461
                vlc_mutex_unlock( &priv->p_item->lock );
462 463 464 465
                *ppp_attachment = NULL;
                *pi_attachment = 0;
                return VLC_EGENERIC;
            }
466
            *pi_attachment = priv->i_attachment;
467
            *ppp_attachment = vlc_alloc( priv->i_attachment, sizeof(input_attachment_t*));
468
            for( int i = 0; i < priv->i_attachment; i++ )
469
                (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( priv->attachment[i] );
470

471
            vlc_mutex_unlock( &priv->p_item->lock );
472
            return VLC_SUCCESS;
473 474 475 476
        }

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

480
            vlc_mutex_lock( &priv->p_item->lock );
481
            for( int i = 0; i < priv->i_attachment; i++ )
482
            {
483
                if( !strcmp( priv->attachment[i]->psz_name, psz_name ) )
484
                {
485 486
                    *pp_attachment = vlc_input_attachment_Duplicate(priv->attachment[i] );
                    vlc_mutex_unlock( &priv->p_item->lock );
487 488 489 490
                    return VLC_SUCCESS;
                }
            }
            *pp_attachment = NULL;
491
            vlc_mutex_unlock( &priv->p_item->lock );
492 493 494
            return VLC_EGENERIC;
        }

495
        case INPUT_SET_RECORD_STATE:
496
            b_bool = va_arg( args, int );
497 498 499 500
            var_SetBool( p_input, "record", b_bool );
            return VLC_SUCCESS;

        case INPUT_GET_RECORD_STATE:
501
            pb_bool = va_arg( args, bool* );
502 503
            *pb_bool = var_GetBool( p_input, "record" );
            return VLC_SUCCESS;
504

505
        case INPUT_RESTART_ES:
506
            val.i_int = va_arg( args, int );
507 508 509
            input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
            return VLC_SUCCESS;

510
        case INPUT_UPDATE_VIEWPOINT:
511
        case INPUT_SET_INITIAL_VIEWPOINT:
512 513 514 515 516 517
        {
            vlc_viewpoint_t *p_viewpoint = malloc( sizeof(*p_viewpoint) );
            if( unlikely(p_viewpoint == NULL) )
                return VLC_ENOMEM;
            val.p_address = p_viewpoint;
            *p_viewpoint = *va_arg( args, const vlc_viewpoint_t* );
518 519 520 521
            if ( i_query == INPUT_SET_INITIAL_VIEWPOINT )
                input_ControlPush( p_input, INPUT_CONTROL_SET_INITIAL_VIEWPOINT,
                                   &val );
            else if ( va_arg( args, int ) )
522 523 524 525 526 527
                input_ControlPush( p_input, INPUT_CONTROL_SET_VIEWPOINT, &val );
            else
                input_ControlPush( p_input, INPUT_CONTROL_UPDATE_VIEWPOINT, &val );
            return VLC_SUCCESS;
        }

528 529
        case INPUT_GET_AOUT:
        {
530
            audio_output_t *p_aout = input_resource_HoldAout( priv->p_resource );
531 532 533
            if( !p_aout )
                return VLC_EGENERIC;

534
            audio_output_t **pp_aout = va_arg( args, audio_output_t** );
535 536 537 538 539 540
            *pp_aout = p_aout;
            return VLC_SUCCESS;
        }

        case INPUT_GET_VOUTS:
        {
541 542
            vout_thread_t ***ppp_vout = va_arg( args, vout_thread_t*** );
            size_t *pi_vout = va_arg( args, size_t * );
543

544
            input_resource_HoldVouts( priv->p_resource, ppp_vout, pi_vout );
545 546 547 548 549
            if( *pi_vout <= 0 )
                return VLC_EGENERIC;
            return VLC_SUCCESS;
        }

550 551 552
        case INPUT_GET_ES_OBJECTS:
        {
            const int i_id = va_arg( args, int );
553 554 555
            vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
            vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
            audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
556

557 558
            return es_out_Control( priv->p_es_out_display,
                                   ES_OUT_GET_ES_OBJECTS_BY_ID, i_id,
559 560 561
                                   pp_decoder, pp_vout, pp_aout );
        }

562 563 564
        case INPUT_GET_PCR_SYSTEM:
        {
            mtime_t *pi_system = va_arg( args, mtime_t * );
565
            mtime_t *pi_delay  = va_arg( args, mtime_t * );
566
            return es_out_ControlGetPcrSystem( priv->p_es_out_display, pi_system, pi_delay );
567 568 569 570 571 572
        }

        case INPUT_MODIFY_PCR_SYSTEM:
        {
            bool b_absolute = va_arg( args, int );
            mtime_t i_system = va_arg( args, mtime_t );
573
            return es_out_ControlModifyPcrSystem( priv->p_es_out_display, b_absolute, i_system );
574 575
        }

576 577 578 579 580
        case INPUT_SET_RENDERER:
        {
            vlc_renderer_item_t* p_item = va_arg( args, vlc_renderer_item_t* );
            val.p_address = p_item;
            input_ControlPush( p_input, INPUT_CONTROL_SET_RENDERER, &val );
581
            return VLC_SUCCESS;
582 583
        }

Gildas Bazin's avatar
Gildas Bazin committed
584
        default:
585
            msg_Err( p_input, "unknown query 0x%x in %s", i_query, __func__ );
586
            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
587 588
    }
}
589 590 591

static void UpdateBookmarksOption( input_thread_t *p_input )
{
592 593
    input_thread_private_t *priv = input_priv(p_input);
    struct vlc_memstream vstr;
594

595 596
    vlc_memstream_open( &vstr );
    vlc_memstream_puts( &vstr, "bookmarks=" );
597

598
    vlc_mutex_lock( &priv->p_item->lock );
599
    var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
600

601
    for( int i = 0; i < priv->i_bookmark; i++ )
602
    {
603
        seekpoint_t const* sp = priv->pp_bookmark[i];
604

605
        /* Add bookmark to choice-list */
606
        var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
607 608
                    &(vlc_value_t){ .i_int = i },
                    &(vlc_value_t){ .psz_string = sp->psz_name } );
609

610 611
        /* Append bookmark to option-buffer */
        /* TODO: escape inappropriate values */
612 613
        vlc_memstream_printf( &vstr, "%s{name=%s,time=%.3f}",
            i > 0 ? "," : "", sp->psz_name, ( 1. * sp->i_time_offset ) / CLOCK_FREQ );
614 615
    }

616
    vlc_mutex_unlock( &priv->p_item->lock );
617

618
    if( vlc_memstream_close( &vstr ) == VLC_SUCCESS )
619
    {
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
        bool b_overwritten = false;

        for( int i = 0; i < priv->p_item->i_options; ++i )
        {
            char** ppsz_option = &priv->p_item->ppsz_options[i];

            if( strncmp( *ppsz_option, "bookmarks=", 10 ) == 0 )
            {
                free( *ppsz_option );
                *ppsz_option = vstr.ptr;
                b_overwritten = true;
            }
        }

        if( !b_overwritten )
        {
            input_item_AddOption( priv->p_item, vstr.ptr,
                                  VLC_INPUT_OPTION_UNIQUE );
            free( vstr.ptr );
        }
640
    }
641

642
    input_SendEventBookmark( p_input );
643
}
644