control.c 18.9 KB
Newer Older
Gildas Bazin's avatar
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * control.c
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 1999-2004 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
LGPL  
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
LGPL  
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
LGPL  
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 30 31

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

Laurent Aimar's avatar
Laurent Aimar committed
34
#include "input_internal.h"
35
#include "event.h"
36
#include "resource.h"
37
#include "es_out.h"
38

Gildas Bazin's avatar
Gildas Bazin committed
39

40 41
static void UpdateBookmarksOption( input_thread_t * );

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

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

74 75 76
    char *psz;
    vlc_value_t val;

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

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

        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
91 92
            return VLC_SUCCESS;

93 94 95
        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
96 97
            return VLC_SUCCESS;

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

        case INPUT_GET_RATE:
            pi_int = (int*)va_arg( args, int * );
104
            *pi_int = INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" );
Laurent Aimar's avatar
Laurent Aimar committed
105 106
            return VLC_SUCCESS;

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

        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
115 116
            return VLC_SUCCESS;

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

121 122 123 124
        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;
125

126 127 128 129
        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;
130

131 132 133
        case INPUT_SET_AUDIO_DELAY:
            i_64 = (int64_t)va_arg( args, int64_t );
            return var_SetTime( p_input, "audio-delay", i_64 );
134

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

139 140 141 142 143 144 145 146 147
        case INPUT_NAV_ACTIVATE:
        case INPUT_NAV_UP:
        case INPUT_NAV_DOWN:
        case INPUT_NAV_LEFT:
        case INPUT_NAV_RIGHT:
            input_ControlPush( p_input, i_query - INPUT_NAV_ACTIVATE
                               + INPUT_CONTROL_NAV_ACTIVATE, NULL );
            return VLC_SUCCESS;

148
        case INPUT_ADD_INFO:
149
        {
150 151 152 153
            char *psz_cat = (char *)va_arg( args, char * );
            char *psz_name = (char *)va_arg( args, char * );
            char *psz_format = (char *)va_arg( args, char * );

154
            char *psz_value;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
155

156 157
            if( vasprintf( &psz_value, psz_format, args ) == -1 )
                return VLC_EGENERIC;
158

159
            int i_ret = input_item_AddInfo( p_input->p->p_item,
160
                                            psz_cat, psz_name, "%s", psz_value );
Rémi Duraffort's avatar
Rémi Duraffort committed
161
            free( psz_value );
162

163 164 165
            if( !p_input->b_preparsing && !i_ret )
                input_SendEventMetaInfo( p_input );
            return i_ret;
166
        }
167 168 169 170 171 172 173 174 175 176 177 178 179 180
        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 )
                input_item_ReplaceInfos( p_input->p->p_item, p_cat );
            else
                input_item_MergeInfos( p_input->p->p_item, p_cat );

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

186
            int i_ret = input_item_DelInfo( p_input->p->p_item,
187
                                            psz_cat, psz_name );
188

189 190 191
            if( !p_input->b_preparsing && !i_ret )
                input_SendEventMetaInfo( p_input );
            return i_ret;
192
        }
193 194 195 196 197
        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 ** );
198
            int i_ret = VLC_EGENERIC;
199 200
            *ppsz_value = NULL;

201
            *ppsz_value = input_item_GetInfo( p_input->p->p_item,
202
                                                  psz_cat, psz_name );
203 204 205 206 207 208 209
            return i_ret;
        }

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

210
            if( !psz_name ) return VLC_EGENERIC;
211

212
            input_item_SetName( p_input->p->p_item, psz_name );
213

214
            if( !p_input->b_preparsing )
215
                input_SendEventMetaName( p_input, psz_name );
216
            return VLC_SUCCESS;
217 218
        }

Gildas Bazin's avatar
Gildas Bazin committed
219 220 221
        case INPUT_ADD_BOOKMARK:
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
            p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
222

223
            vlc_mutex_lock( &p_input->p->p_item->lock );
Gildas Bazin's avatar
Gildas Bazin committed
224 225
            if( !p_bkmk->psz_name )
            {
226 227 228
                 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
229
            }
230

231
            TAB_APPEND( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
232
            vlc_mutex_unlock( &p_input->p->p_item->lock );
Gildas Bazin's avatar
Gildas Bazin committed
233

234 235
            UpdateBookmarksOption( p_input );

236
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
237

238
        case INPUT_CHANGE_BOOKMARK:
239 240 241
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
            i_bkmk = (int)va_arg( args, int );

242
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
243
            if( i_bkmk < p_input->p->i_bookmark )
244
            {
245 246
                vlc_seekpoint_Delete( p_input->p->pp_bookmark[i_bkmk] );
                p_input->p->pp_bookmark[i_bkmk] = vlc_seekpoint_Duplicate( p_bkmk );
247
            }
248
            vlc_mutex_unlock( &p_input->p->p_item->lock );
249 250 251 252

            UpdateBookmarksOption( p_input );

            return VLC_SUCCESS;
253

Gildas Bazin's avatar
Gildas Bazin committed
254
        case INPUT_DEL_BOOKMARK:
255
            i_bkmk = (int)va_arg( args, int );
256

257
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
258
            if( i_bkmk < p_input->p->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
259
            {
260
                p_bkmk = p_input->p->pp_bookmark[i_bkmk];
261
                TAB_REMOVE( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
262 263
                vlc_seekpoint_Delete( p_bkmk );

264
                vlc_mutex_unlock( &p_input->p->p_item->lock );
265 266 267

                UpdateBookmarksOption( p_input );

268
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
269
            }
270
            vlc_mutex_unlock( &p_input->p->p_item->lock );
271 272

            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
273 274 275 276

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

278
            vlc_mutex_lock( &p_input->p->p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
279
            if( p_input->p->i_bookmark )
Gildas Bazin's avatar
Gildas Bazin committed
280 281 282
            {
                int i;

Clément Stenac's avatar
Clément Stenac committed
283
                *pi_bkmk = p_input->p->i_bookmark;
Gildas Bazin's avatar
Gildas Bazin committed
284
                *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
Clément Stenac's avatar
Clément Stenac committed
285 286
                                    p_input->p->i_bookmark );
                for( i = 0; i < p_input->p->i_bookmark; i++ )
Gildas Bazin's avatar
Gildas Bazin committed
287 288
                {
                    (*ppp_bkmk)[i] =
289
                        vlc_seekpoint_Duplicate( p_input->p->pp_bookmark[i] );
Gildas Bazin's avatar
Gildas Bazin committed
290
                }
291

292
                vlc_mutex_unlock( &p_input->p->p_item->lock );
293
                return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
294 295 296 297 298
            }
            else
            {
                *ppp_bkmk = NULL;
                *pi_bkmk = 0;
299

300
                vlc_mutex_unlock( &p_input->p->p_item->lock );
301
                return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
302 303 304 305
            }
            break;

        case INPUT_CLEAR_BOOKMARKS:
306

307
            vlc_mutex_lock( &p_input->p->p_item->lock );
308
            while( p_input->p->i_bookmark > 0 )
Gildas Bazin's avatar
Gildas Bazin committed
309
            {
310
                p_bkmk = p_input->p->pp_bookmark[p_input->p->i_bookmark-1];
Gildas Bazin's avatar
Gildas Bazin committed
311

312 313 314
                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
315
            }
316
            vlc_mutex_unlock( &p_input->p->p_item->lock );
317 318

            UpdateBookmarksOption( p_input );
319
            return VLC_SUCCESS;
Gildas Bazin's avatar
Gildas Bazin committed
320 321 322

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

324 325
            val.i_int = i_bkmk;
            input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
326

327
            return VLC_SUCCESS;
328

329 330 331
        case INPUT_GET_BOOKMARK:
            p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );

332 333 334
            vlc_mutex_lock( &p_input->p->p_item->lock );
            *p_bkmk = p_input->p->bookmark;
            vlc_mutex_unlock( &p_input->p->p_item->lock );
335 336
            return VLC_SUCCESS;

337 338 339 340 341 342 343
        case INPUT_GET_TITLE_INFO:
        {
            input_title_t **p_title = (input_title_t **)va_arg( args, input_title_t ** );
            int *pi_req_title_offset = (int *) va_arg( args, int * );

            vlc_mutex_lock( &p_input->p->p_item->lock );

344 345 346
            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;
347 348 349 350 351 352 353 354 355 356 357 358 359 360

            if( p_input->p->i_title && p_input->p->i_title > *pi_req_title_offset )
            {
                *p_title = vlc_input_title_Duplicate( p_input->p->title[*pi_req_title_offset] );
                vlc_mutex_unlock( &p_input->p->p_item->lock );
                return VLC_SUCCESS;
            }
            else
            {
                vlc_mutex_unlock( &p_input->p->p_item->lock );
                return VLC_EGENERIC;
            }
        }

361 362
        case INPUT_GET_VIDEO_FPS:
            pf = (double*)va_arg( args, double * );
363

364
            vlc_mutex_lock( &p_input->p->p_item->lock );
365
            *pf = p_input->p->f_fps;
366
            vlc_mutex_unlock( &p_input->p->p_item->lock );
367 368
            return VLC_SUCCESS;

369 370 371 372 373 374 375 376
        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
377

378 379 380 381 382 383 384 385 386 387 388 389 390
        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;

391 392 393 394 395 396
        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;

397
            vlc_mutex_lock( &p_input->p->p_item->lock );
398 399
            if( p_input->p->i_attachment <= 0 )
            {
400
                vlc_mutex_unlock( &p_input->p->p_item->lock );
401 402 403 404 405 406 407 408 409
                *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] );

410
            vlc_mutex_unlock( &p_input->p->p_item->lock );
411
            return VLC_SUCCESS;
412 413 414 415 416 417 418 419
        }

        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;

420
            vlc_mutex_lock( &p_input->p->p_item->lock );
421 422 423 424 425
            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] );
426
                    vlc_mutex_unlock( &p_input->p->p_item->lock );
427 428 429 430
                    return VLC_SUCCESS;
                }
            }
            *pp_attachment = NULL;
431
            vlc_mutex_unlock( &p_input->p->p_item->lock );
432 433 434
            return VLC_EGENERIC;
        }

435 436 437 438 439 440 441 442 443
        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;
444

445 446 447 448 449
        case INPUT_RESTART_ES:
            val.i_int = (int)va_arg( args, int );
            input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
            return VLC_SUCCESS;

450 451
        case INPUT_GET_AOUT:
        {
452
            audio_output_t *p_aout = input_resource_HoldAout( p_input->p->p_resource );
453 454 455
            if( !p_aout )
                return VLC_EGENERIC;

456
            audio_output_t **pp_aout = (audio_output_t**)va_arg( args, audio_output_t** );
457 458 459 460 461 462 463
            *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*** );
464
            size_t        *pi_vout = va_arg( args, size_t * );
465

466
            input_resource_HoldVouts( p_input->p->p_resource, ppp_vout, pi_vout );
467 468 469 470 471
            if( *pi_vout <= 0 )
                return VLC_EGENERIC;
            return VLC_SUCCESS;
        }

472 473 474 475 476
        case INPUT_GET_ES_OBJECTS:
        {
            const int i_id = va_arg( args, int );
            vlc_object_t    **pp_decoder = va_arg( args, vlc_object_t ** );
            vout_thread_t   **pp_vout    = va_arg( args, vout_thread_t ** );
477
            audio_output_t **pp_aout    = va_arg( args, audio_output_t ** );
478 479 480 481 482

            return es_out_Control( p_input->p->p_es_out_display, ES_OUT_GET_ES_OBJECTS_BY_ID, i_id,
                                   pp_decoder, pp_vout, pp_aout );
        }

483 484 485
        case INPUT_GET_PCR_SYSTEM:
        {
            mtime_t *pi_system = va_arg( args, mtime_t * );
486 487
            mtime_t *pi_delay  = va_arg( args, mtime_t * );
            return es_out_ControlGetPcrSystem( p_input->p->p_es_out_display, pi_system, pi_delay );
488 489 490 491 492 493 494 495 496
        }

        case INPUT_MODIFY_PCR_SYSTEM:
        {
            bool b_absolute = va_arg( args, int );
            mtime_t i_system = va_arg( args, mtime_t );
            return es_out_ControlModifyPcrSystem( p_input->p->p_es_out_display, b_absolute, i_system );
        }

Gildas Bazin's avatar
Gildas Bazin committed
497 498
        default:
            msg_Err( p_input, "unknown query in input_vaControl" );
Laurent Aimar's avatar
Laurent Aimar committed
499
            return VLC_EGENERIC;
Gildas Bazin's avatar
Gildas Bazin committed
500 501
    }
}
502 503 504

static void UpdateBookmarksOption( input_thread_t *p_input )
{
505
    vlc_mutex_lock( &p_input->p->p_item->lock );
506 507 508 509

    /* 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++ )
510
    {
511
        vlc_value_t val, text;
512

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
        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++ = ',';
547
    }
548
    vlc_mutex_unlock( &p_input->p->p_item->lock );
549

550
    if( psz_value )
551
        input_item_AddOption( p_input->p->p_item, psz_value, VLC_INPUT_OPTION_UNIQUE );
552

Rémi Duraffort's avatar
Rémi Duraffort committed
553
    free( psz_value );
554 555

    input_SendEventBookmark( p_input );
556
}
Rémi Duraffort's avatar
Rémi Duraffort committed
557