video.c 25.6 KB
Newer Older
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
1 2 3
/*****************************************************************************
 * video.c: libvlc new API video functions
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2005-2010 VLC authors and VideoLAN
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
5
 *
6
 * $Id$
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
7
 *
8
 * Authors: Clément Stenac <zorglub@videolan.org>
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
9 10 11 12
 *          Filippo Carone <littlejohn@videolan.org>
 *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
 *          Damien Fouilleul <damienf a_t videolan dot org>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
13 14 15
 * 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
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
16 17 18 19
 * (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
20 21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
22
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
23 24 25
 * 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.
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
26 27
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
32
#include <vlc/libvlc.h>
33 34 35 36
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_media_player.h>

#include <vlc_common.h>
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
37 38 39
#include <vlc_input.h>
#include <vlc_vout.h>

40
#include "media_player_internal.h"
41
#include <math.h>
42
#include <assert.h>
43

Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
44
/*
45
 * Remember to release the returned vout_thread_t.
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
46
 */
47
static vout_thread_t **GetVouts( libvlc_media_player_t *p_mi, size_t *n )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
48
{
49
    input_thread_t *p_input = libvlc_get_input_thread( p_mi );
50
    if( !p_input )
51 52
    {
        *n = 0;
53
        return NULL;
54
    }
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
55

56 57
    vout_thread_t **pp_vouts;
    if (input_Control( p_input, INPUT_GET_VOUTS, &pp_vouts, n))
58
    {
59 60
        *n = 0;
        pp_vouts = NULL;
61
    }
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    vlc_object_release (p_input);
    return pp_vouts;
}

static vout_thread_t *GetVout (libvlc_media_player_t *mp, size_t num)
{
    vout_thread_t *p_vout = NULL;
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (mp, &n);
    if (pp_vouts == NULL)
        goto err;

    if (num < n)
        p_vout = pp_vouts[num];

    for (size_t i = 0; i < n; i++)
        if (i != num)
            vlc_object_release (pp_vouts[i]);
    free (pp_vouts);

    if (p_vout == NULL)
err:
        libvlc_printerr ("Video output not active");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
85 86 87 88 89 90 91
    return p_vout;
}

/**********************************************************************
 * Exported functions
 **********************************************************************/

92
void libvlc_set_fullscreen( libvlc_media_player_t *p_mi, int b_fullscreen )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
93
{
94 95
    /* This will work even if the video is not currently active */
    var_SetBool (p_mi, "fullscreen", !!b_fullscreen);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
96

97 98 99 100 101 102 103 104 105
    /* Apply to current video outputs (if any) */
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
    {
        var_SetBool (pp_vouts[i], "fullscreen", b_fullscreen);
        vlc_object_release (pp_vouts[i]);
    }
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
106 107
}

108
int libvlc_get_fullscreen( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
109
{
110
    return var_GetBool (p_mi, "fullscreen");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
111 112
}

113
void libvlc_toggle_fullscreen( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
114
{
115
    bool b_fullscreen = var_ToggleBool (p_mi, "fullscreen");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
116

117 118 119 120 121 122
    /* Apply to current video outputs (if any) */
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
    {
        vout_thread_t *p_vout = pp_vouts[i];
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
123

124 125 126 127
        var_SetBool (p_vout, "fullscreen", b_fullscreen);
        vlc_object_release (p_vout);
    }
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
128 129
}

130 131
void libvlc_video_set_key_input( libvlc_media_player_t *p_mi, unsigned on )
{
132
    var_SetBool (p_mi, "keyboard-events", !!on);
133 134 135 136
}

void libvlc_video_set_mouse_input( libvlc_media_player_t *p_mi, unsigned on )
{
137
    var_SetBool (p_mi, "mouse-events", !!on);
138 139
}

140 141 142 143
int
libvlc_video_take_snapshot( libvlc_media_player_t *p_mi, unsigned num,
                            const char *psz_filepath,
                            unsigned int i_width, unsigned int i_height )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
144
{
145 146
    assert( psz_filepath );

147 148 149
    vout_thread_t *p_vout = GetVout (p_mi, num);
    if (p_vout == NULL)
        return -1;
150

151 152 153 154 155
    /* FIXME: This is not atomic. All parameters should be passed at once
     * (obviously _not_ with var_*()). Also, the libvlc object should not be
     * used for the callbacks: that breaks badly if there are concurrent
     * media players in the instance. */
    var_Create( p_vout, "snapshot-width", VLC_VAR_INTEGER );
156
    var_SetInteger( p_vout, "snapshot-width", i_width);
157
    var_Create( p_vout, "snapshot-height", VLC_VAR_INTEGER );
158
    var_SetInteger( p_vout, "snapshot-height", i_height );
159
    var_Create( p_vout, "snapshot-path", VLC_VAR_STRING );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
160
    var_SetString( p_vout, "snapshot-path", psz_filepath );
161
    var_Create( p_vout, "snapshot-format", VLC_VAR_STRING );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
162
    var_SetString( p_vout, "snapshot-format", "png" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
163 164
    var_TriggerCallback( p_vout, "video-snapshot" );
    vlc_object_release( p_vout );
165
    return 0;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
166 167
}

168 169
int libvlc_video_get_size( libvlc_media_player_t *p_mi, unsigned num,
                           unsigned *restrict px, unsigned *restrict py )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
170
{
171 172
    libvlc_media_track_info_t *info;
    int ret = -1;
Rafaël Carré's avatar
Rafaël Carré committed
173 174
    if (!p_mi->p_md)
        return ret;
175 176 177 178 179 180 181 182 183 184 185 186 187 188
    int infos = libvlc_media_get_tracks_info(p_mi->p_md, &info);
    if (infos <= 0)
        return ret;

    for (int i = 0; i < infos; i++)
        if (info[i].i_type == libvlc_track_video && num-- == 0) {
            *px = info[i].u.video.i_width;
            *py = info[i].u.video.i_height;
            ret = 0;
            break;
        }

    free(info);
    return ret;
189
}
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
190

191 192
int libvlc_video_get_height( libvlc_media_player_t *p_mi )
{
193
    unsigned width, height;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
194

195
    if (libvlc_video_get_size (p_mi, 0, &width, &height))
196
        return 0;
197
    return height;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
198 199
}

200
int libvlc_video_get_width( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
201
{
202
    unsigned width, height;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
203

204
    if (libvlc_video_get_size (p_mi, 0, &width, &height))
205
        return 0;
206
    return width;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
207 208
}

209
int libvlc_video_get_cursor( libvlc_media_player_t *mp, unsigned num,
210
                             int *restrict px, int *restrict py )
211 212 213 214 215
{
    vout_thread_t *p_vout = GetVout (mp, num);
    if (p_vout == NULL)
        return -1;

216
    var_GetCoords (p_vout, "mouse-moved", px, py);
217 218 219 220
    vlc_object_release (p_vout);
    return 0;
}

221
unsigned libvlc_media_player_has_vout( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
222
{
223 224 225 226 227 228
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
        vlc_object_release (pp_vouts[i]);
    free (pp_vouts);
    return n;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
229 230
}

231
float libvlc_video_get_scale( libvlc_media_player_t *mp )
232
{
233
    float f_scale = var_GetFloat (mp, "zoom");
234
    if (var_GetBool (mp, "autoscale"))
235
        f_scale = 0.f;
236 237 238
    return f_scale;
}

239
void libvlc_video_set_scale( libvlc_media_player_t *p_mp, float f_scale )
240
{
241
    if (isfinite(f_scale) && f_scale != 0.f)
242
        var_SetFloat (p_mp, "zoom", f_scale);
243
    var_SetBool (p_mp, "autoscale", f_scale == 0.f);
244 245 246 247 248 249 250

    /* Apply to current video outputs (if any) */
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mp, &n);
    for (size_t i = 0; i < n; i++)
    {
        vout_thread_t *p_vout = pp_vouts[i];
251

252
        if (isfinite(f_scale) && f_scale != 0.f)
253
            var_SetFloat (p_vout, "zoom", f_scale);
254
        var_SetBool (p_vout, "autoscale", f_scale == 0.f);
255 256 257
        vlc_object_release (p_vout);
    }
    free (pp_vouts);
258 259
}

260
char *libvlc_video_get_aspect_ratio( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
261
{
262
    return var_GetNonEmptyString (p_mi, "aspect-ratio");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
263 264
}

265
void libvlc_video_set_aspect_ratio( libvlc_media_player_t *p_mi,
266
                                    const char *psz_aspect )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
267
{
268 269 270
    if (psz_aspect == NULL)
        psz_aspect = "";
    var_SetString (p_mi, "aspect-ratio", psz_aspect);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
271

272 273 274
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
275
    {
276 277 278 279
        vout_thread_t *p_vout = pp_vouts[i];

        var_SetString (p_vout, "aspect-ratio", psz_aspect);
        vlc_object_release (p_vout);
280
    }
281
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
282 283
}

284
int libvlc_video_get_spu( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
285
{
286
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
287

288 289 290 291 292
    if( !p_input_thread )
    {
        libvlc_printerr( "No active input" );
        return -1;
    }
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
293

294
    int i_spu = var_GetInteger( p_input_thread, "spu-es" );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
295 296 297 298
    vlc_object_release( p_input_thread );
    return i_spu;
}

299
int libvlc_video_get_spu_count( libvlc_media_player_t *p_mi )
300
{
301
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
302
    int i_spu_count;
303 304

    if( !p_input_thread )
305
        return 0;
306

307
    i_spu_count = var_CountChoices( p_input_thread, "spu-es" );
308
    vlc_object_release( p_input_thread );
309
    return i_spu_count;
310 311 312
}

libvlc_track_description_t *
313
        libvlc_video_get_spu_description( libvlc_media_player_t *p_mi )
314
{
315
    return libvlc_get_track_description( p_mi, "spu-es" );
316 317
}

318
int libvlc_video_set_spu( libvlc_media_player_t *p_mi, int i_spu )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
319
{
320
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
321
    vlc_value_t list;
322
    int i_ret = -1;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
323

324
    if( !p_input_thread )
325
        return -1;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
326

327
    var_Change (p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &list, NULL);
328
    for (int i = 0; i < list.p_list->i_count; i++)
329
    {
330 331 332 333 334 335 336
        if( i_spu == list.p_list->p_values[i].i_int )
        {
            if( var_SetInteger( p_input_thread, "spu-es", i_spu ) < 0 )
                break;
            i_ret = 0;
            goto end;
        }
337
    }
338
    libvlc_printerr( "Track identifier not found" );
339
end:
340 341 342
    vlc_object_release (p_input_thread);
    var_FreeList (&list, NULL);
    return i_ret;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
343 344
}

345
int libvlc_video_set_subtitle_file( libvlc_media_player_t *p_mi,
346
                                    const char *psz_subtitle )
347
{
348
    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
349 350 351 352
    bool b_ret = false;

    if( p_input_thread )
    {
353
        if( !input_AddSubtitle( p_input_thread, psz_subtitle, true ) )
354 355 356 357 358 359
            b_ret = true;
        vlc_object_release( p_input_thread );
    }
    return b_ret;
}

360 361 362 363 364 365 366
int64_t libvlc_video_get_spu_delay( libvlc_media_player_t *p_mi )
{
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
    int64_t val = 0;

    if( p_input_thread )
    {
367
        val = var_GetInteger( p_input_thread, "spu-delay" );
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        vlc_object_release( p_input_thread );
    }
    else
    {
        libvlc_printerr( "No active input" );
    }

    return val;
}

int libvlc_video_set_spu_delay( libvlc_media_player_t *p_mi,
                                int64_t i_delay )
{
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
    int ret = -1;

    if( p_input_thread )
    {
386
        var_SetInteger( p_input_thread, "spu-delay", i_delay );
387 388 389 390 391 392 393 394 395 396 397
        vlc_object_release( p_input_thread );
        ret = 0;
    }
    else
    {
        libvlc_printerr( "No active input" );
    }

    return ret;
}

398
libvlc_track_description_t *
399
        libvlc_video_get_title_description( libvlc_media_player_t *p_mi )
400
{
401
    return libvlc_get_track_description( p_mi, "title" );
402 403 404 405
}

libvlc_track_description_t *
        libvlc_video_get_chapter_description( libvlc_media_player_t *p_mi,
406
                                              int i_title )
407
{
408 409
    char psz_title[sizeof ("title ") + 3 * sizeof (int)];
    sprintf( psz_title,  "title %2u", i_title );
410
    return libvlc_get_track_description( p_mi, psz_title );
411 412
}

413
char *libvlc_video_get_crop_geometry (libvlc_media_player_t *p_mi)
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
414
{
415
    return var_GetNonEmptyString (p_mi, "crop");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
416 417
}

418
void libvlc_video_set_crop_geometry( libvlc_media_player_t *p_mi,
419
                                     const char *psz_geometry )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
420
{
421 422
    if (psz_geometry == NULL)
        psz_geometry = "";
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
423

424
    var_SetString (p_mi, "crop", psz_geometry);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
425

426 427
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
428

429
    for (size_t i = 0; i < n; i++)
430
    {
431
        vout_thread_t *p_vout = pp_vouts[i];
432 433 434 435 436 437 438 439
        vlc_value_t val;

        /* Make sure the geometry is in the choice list */
        /* Earlier choices are removed to not grow a long list over time. */
        /* FIXME: not atomic - lock? */
        val.psz_string = (char *)psz_geometry;
        var_Change (p_vout, "crop", VLC_VAR_CLEARCHOICES, NULL, NULL);
        var_Change (p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &val);
440 441
        var_SetString (p_vout, "crop", psz_geometry);
        vlc_object_release (p_vout);
442
    }
443
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
444 445
}

446 447
int libvlc_video_get_teletext( libvlc_media_player_t *p_mi )
{
448
    return var_GetInteger (p_mi, "vbi-page");
449 450
}

451
void libvlc_video_set_teletext( libvlc_media_player_t *p_mi, int i_page )
452 453 454 455 456
{
    input_thread_t *p_input_thread;
    vlc_object_t *p_zvbi = NULL;
    int telx;

457 458
    var_SetInteger (p_mi, "vbi-page", i_page);

459 460 461 462 463 464 465 466 467 468 469
    p_input_thread = libvlc_get_input_thread( p_mi );
    if( !p_input_thread ) return;

    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
    {
        vlc_object_release( p_input_thread );
        return;
    }

    telx = var_GetInteger( p_input_thread, "teletext-es" );
    if( input_GetEsObjects( p_input_thread, telx, &p_zvbi, NULL, NULL )
470
        == VLC_SUCCESS )
471
    {
472
        var_SetInteger( p_zvbi, "vbi-page", i_page );
473 474 475 476 477
        vlc_object_release( p_zvbi );
    }
    vlc_object_release( p_input_thread );
}

478
void libvlc_toggle_teletext( libvlc_media_player_t *p_mi )
479
{
480
    input_thread_t *p_input_thread;
481

482
    p_input_thread = libvlc_get_input_thread(p_mi);
483
    if( !p_input_thread ) return;
484

485
    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
486
    {
487 488 489 490
        vlc_object_release( p_input_thread );
        return;
    }
    const bool b_selected = var_GetInteger( p_input_thread, "teletext-es" ) >= 0;
491
    if( b_selected )
492 493 494
    {
        var_SetInteger( p_input_thread, "spu-es", -1 );
    }
495 496
    else
    {
497
        vlc_value_t list;
498
        if( !var_Change( p_input_thread, "teletext-es", VLC_VAR_GETCHOICES, &list, NULL ) )
499
        {
500 501
            if( list.p_list->i_count > 0 )
                var_SetInteger( p_input_thread, "spu-es", list.p_list->p_values[0].i_int );
502

503
            var_FreeList( &list, NULL );
504 505 506
        }
    }
    vlc_object_release( p_input_thread );
507 508
}

509
int libvlc_video_get_track_count( libvlc_media_player_t *p_mi )
510
{
511
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
512
    int i_track_count;
513 514 515 516

    if( !p_input_thread )
        return -1;

517
    i_track_count = var_CountChoices( p_input_thread, "video-es" );
518

519
    vlc_object_release( p_input_thread );
520
    return i_track_count;
521 522 523
}

libvlc_track_description_t *
524
        libvlc_video_get_track_description( libvlc_media_player_t *p_mi )
525
{
526
    return libvlc_get_track_description( p_mi, "video-es" );
527 528
}

529
int libvlc_video_get_track( libvlc_media_player_t *p_mi )
530
{
531
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
532 533 534 535

    if( !p_input_thread )
        return -1;

536
    int id = var_GetInteger( p_input_thread, "video-es" );
537
    vlc_object_release( p_input_thread );
538
    return id;
539 540
}

541
int libvlc_video_set_track( libvlc_media_player_t *p_mi, int i_track )
542
{
543
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
544 545 546 547
    vlc_value_t val_list;
    int i_ret = -1;

    if( !p_input_thread )
548
        return -1;
549 550

    var_Change( p_input_thread, "video-es", VLC_VAR_GETCHOICES, &val_list, NULL );
551
    for( int i = 0; i < val_list.p_list->i_count; i++ )
552
    {
553
        if( i_track == val_list.p_list->p_values[i].i_int )
554
        {
555 556
            if( var_SetBool( p_input_thread, "video", true ) < 0)
                break;
557
            if( var_SetInteger( p_input_thread, "video-es", i_track ) < 0 )
558
                break;
559
            i_ret = 0;
560
            goto end;
561 562
        }
    }
563
    libvlc_printerr( "Track identifier not found" );
564
end:
565
    var_FreeList( &val_list, NULL );
566
    vlc_object_release( p_input_thread );
567
    return i_ret;
568
}
569 570 571 572

/******************************************************************************
 * libvlc_video_set_deinterlace : enable deinterlace
 *****************************************************************************/
573 574 575 576 577 578
void libvlc_video_set_deinterlace( libvlc_media_player_t *p_mi,
                                   const char *psz_mode )
{
    if (psz_mode == NULL)
        psz_mode = "";
    if (*psz_mode
Juha Jeronen's avatar
Juha Jeronen committed
579 580 581 582
     && strcmp (psz_mode, "blend")    && strcmp (psz_mode, "bob")
     && strcmp (psz_mode, "discard")  && strcmp (psz_mode, "linear")
     && strcmp (psz_mode, "mean")     && strcmp (psz_mode, "x")
     && strcmp (psz_mode, "yadif")    && strcmp (psz_mode, "yadif2x")
Juha Jeronen's avatar
Juha Jeronen committed
583
     && strcmp (psz_mode, "phosphor") && strcmp (psz_mode, "ivtc"))
584 585
        return;

586
    if (*psz_mode)
587
    {
588 589
        var_SetString (p_mi, "deinterlace-mode", psz_mode);
        var_SetInteger (p_mi, "deinterlace", 1);
590 591
    }
    else
592 593 594 595 596
        var_SetInteger (p_mi, "deinterlace", 0);

    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
597
    {
598
        vout_thread_t *p_vout = pp_vouts[i];
599

600 601 602 603 604 605 606 607 608 609
        if (*psz_mode)
        {
            var_SetString (p_vout, "deinterlace-mode", psz_mode);
            var_SetInteger (p_vout, "deinterlace", 1);
        }
        else
            var_SetInteger (p_vout, "deinterlace", 0);
        vlc_object_release (p_vout);
    }
    free (pp_vouts);
610
}
611

612 613 614 615
/* ************** */
/* module helpers */
/* ************** */

616
static bool find_sub_source_by_name( libvlc_media_player_t *p_mi, const char *restrict name )
617
{
618
    vout_thread_t *vout = GetVout( p_mi, 0 );
619 620
    if (!vout)
        return false;
621

622 623
    char *psz_sources = var_GetString( vout, "sub-source" );
    if( !psz_sources )
624
    {
625 626 627
        libvlc_printerr( "%s not enabled", name );
        vlc_object_release( vout );
        return false;
628
    }
629

630 631 632 633 634
    /* Find 'name'  */
    char *p = strstr( psz_sources, name );
    free( psz_sources );
    vlc_object_release( vout );
    return (p != NULL);
635 636
}

637
typedef const struct {
638
    const char name[20];
639
    unsigned type;
640
} opt_t;
641

642
static void
643 644
set_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt, int value )
645
{
646 647
    if( !opt ) return;

648
    switch( opt->type )
649
    {
650
        case 0: /* the enabler */
651
        {
652 653 654 655 656 657 658 659
            vout_thread_t *vout = GetVout( p_mi, 0 );
            if (vout != NULL)
            {   /* Fill sub-source */
                vout_EnableFilter( vout, opt->name, value, false );
                var_TriggerCallback( vout, "sub-source" );
                vlc_object_release( vout );
            }
            break;
660
        }
661 662 663 664 665 666 667 668 669
        case VLC_VAR_INTEGER:
            var_SetInteger( p_mi, opt->name, value );
            break;
        case VLC_VAR_FLOAT:
            var_SetFloat( p_mi, opt->name, value );
            break;
        default:
            libvlc_printerr( "Invalid argument to %s in %s", name, "set int" );
            return;
670
    }
671 672 673
}

static int
674 675
get_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt )
676 677
{
    if( !opt ) return 0;
678

679
    switch( opt->type )
680
    {
681 682
        case 0: /* the enabler */
        {
683 684
            bool b_enabled = find_sub_source_by_name( p_mi, name );
            return b_enabled ? 1 : 0;
685
        }
686
    case VLC_VAR_INTEGER:
687
        return var_GetInteger(p_mi, opt->name);
688 689
    case VLC_VAR_FLOAT:
        return lroundf(var_GetFloat(p_mi, opt->name));
690
    default:
691 692
        libvlc_printerr( "Invalid argument to %s in %s", name, "get int" );
        return 0;
693 694 695
    }
}

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
static void
set_float( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt, float value )
{
    if( !opt ) return;

    if( opt->type != VLC_VAR_FLOAT )
    {
        libvlc_printerr( "Invalid argument to %s in %s", name, "set float" );
        return;
    }

    var_SetFloat( p_mi, opt->name, value );
}

static float
get_float( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt )
{
    if( !opt ) return 0.0;

    if( opt->type != VLC_VAR_FLOAT )
    {
        libvlc_printerr( "Invalid argument to %s in %s", name, "get float" );
        return 0.0;
    }

    return var_GetFloat( p_mi, opt->name );
}

726
static void
727 728
set_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt, const char *restrict psz_value )
729
{
730 731
    if( !opt ) return;

732
    if( opt->type != VLC_VAR_STRING )
733
    {
734 735 736 737 738
        libvlc_printerr( "Invalid argument to %s in %s", name, "set string" );
        return;
    }

    var_SetString( p_mi, opt->name, psz_value );
739
}
740

741
static char *
742 743
get_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt )
744 745 746
{
    if( !opt ) return NULL;

747
    if( opt->type != VLC_VAR_STRING )
748
    {
749 750
        libvlc_printerr( "Invalid argument to %s in %s", name, "get string" );
        return NULL;
751 752
    }

753 754
    return var_GetString( p_mi, opt->name );
}
755 756

static const opt_t *
757
marq_option_bynumber(unsigned option)
758
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
759
    static const opt_t optlist[] =
760 761 762 763 764 765 766 767 768 769 770 771 772
    {
        { "marq",          0 },
        { "marq-marquee",  VLC_VAR_STRING },
        { "marq-color",    VLC_VAR_INTEGER },
        { "marq-opacity",  VLC_VAR_INTEGER },
        { "marq-position", VLC_VAR_INTEGER },
        { "marq-refresh",  VLC_VAR_INTEGER },
        { "marq-size",     VLC_VAR_INTEGER },
        { "marq-timeout",  VLC_VAR_INTEGER },
        { "marq-x",        VLC_VAR_INTEGER },
        { "marq-y",        VLC_VAR_INTEGER },
    };
    enum { num_opts = sizeof(optlist) / sizeof(*optlist) };
773

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
774
    const opt_t *r = option < num_opts ? optlist+option : NULL;
775 776 777
    if( !r )
        libvlc_printerr( "Unknown marquee option" );
    return r;
778 779 780
}

/*****************************************************************************
781
 * libvlc_video_get_marquee_int : get a marq option value
782
 *****************************************************************************/
783
int libvlc_video_get_marquee_int( libvlc_media_player_t *p_mi,
784
                                  unsigned option )
785
{
786
    return get_int( p_mi, "marq", marq_option_bynumber(option) );
787
}
788

789 790 791 792
/*****************************************************************************
 * libvlc_video_get_marquee_string : get a marq option value
 *****************************************************************************/
char * libvlc_video_get_marquee_string( libvlc_media_player_t *p_mi,
793
                                        unsigned option )
794
{
795
    return get_string( p_mi, "marq", marq_option_bynumber(option) );
796
}
797

798 799 800 801
/*****************************************************************************
 * libvlc_video_set_marquee_int: enable, disable or set an int option
 *****************************************************************************/
void libvlc_video_set_marquee_int( libvlc_media_player_t *p_mi,
802
                         unsigned option, int value )
803
{
804
    set_int( p_mi, "marq", marq_option_bynumber(option), value );
805
}
806

807 808 809 810
/*****************************************************************************
 * libvlc_video_set_marquee_string: set a string option
 *****************************************************************************/
void libvlc_video_set_marquee_string( libvlc_media_player_t *p_mi,
811
                unsigned option, const char * value )
812
{
813
    set_string( p_mi, "marq", marq_option_bynumber(option), value );
814 815 816
}


817
/* logo module support */
818

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
819
static const opt_t *
820
logo_option_bynumber( unsigned option )
821
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
822 823
    static const opt_t vlogo_optlist[] =
    /* depends on libvlc_video_logo_option_t */
824 825 826 827 828 829 830 831 832 833 834 835
    {
        { "logo",          0 },
        { "logo-file",     VLC_VAR_STRING },
        { "logo-x",        VLC_VAR_INTEGER },
        { "logo-y",        VLC_VAR_INTEGER },
        { "logo-delay",    VLC_VAR_INTEGER },
        { "logo-repeat",   VLC_VAR_INTEGER },
        { "logo-opacity",  VLC_VAR_INTEGER },
        { "logo-position", VLC_VAR_INTEGER },
    };
    enum { num_vlogo_opts = sizeof(vlogo_optlist) / sizeof(*vlogo_optlist) };

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
836
    const opt_t *r = option < num_vlogo_opts ? vlogo_optlist+option : NULL;
837
    if( !r )
838
        libvlc_printerr( "Unknown logo option" );
839 840 841 842
    return r;
}

void libvlc_video_set_logo_string( libvlc_media_player_t *p_mi,
843
                                   unsigned option, const char *psz_value )
844
{
845
    set_string( p_mi,"logo",logo_option_bynumber(option), psz_value );
846 847 848 849
}


void libvlc_video_set_logo_int( libvlc_media_player_t *p_mi,
850
                                unsigned option, int value )
851
{
852
    set_int( p_mi, "logo", logo_option_bynumber(option), value );
853 854 855 856
}


int libvlc_video_get_logo_int( libvlc_media_player_t *p_mi,
857
                               unsigned option )
858
{
859
    return get_int( p_mi, "logo", logo_option_bynumber(option) );
860
}
861 862


863 864 865
/* adjust module support */


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
866
static const opt_t *
867 868 869 870
adjust_option_bynumber( unsigned option )
{
    static const opt_t optlist[] =
    {
871 872 873
        { "adjust",     0 },
        { "contrast",   VLC_VAR_FLOAT },
        { "brightness", VLC_VAR_FLOAT },
874
        { "hue",        VLC_VAR_FLOAT },
875 876
        { "saturation", VLC_VAR_FLOAT },
        { "gamma",      VLC_VAR_FLOAT },
877 878 879
    };
    enum { num_opts = sizeof(optlist) / sizeof(*optlist) };

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
880
    const opt_t *r = option < num_opts ? optlist+option : NULL;
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
    if( !r )
        libvlc_printerr( "Unknown adjust option" );
    return r;
}


void libvlc_video_set_adjust_int( libvlc_media_player_t *p_mi,
                                  unsigned option, int value )
{
    set_int( p_mi, "adjust", adjust_option_bynumber(option), value );
}


int libvlc_video_get_adjust_int( libvlc_media_player_t *p_mi,
                                 unsigned option )
{
    return get_int( p_mi, "adjust", adjust_option_bynumber(option) );
}


void libvlc_video_set_adjust_float( libvlc_media_player_t *p_mi,
                                    unsigned option, float value )
{
    set_float( p_mi, "adjust", adjust_option_bynumber(option), value );
}


float libvlc_video_get_adjust_float( libvlc_media_player_t *p_mi,
                                     unsigned option )
{
    return get_float( p_mi, "adjust", adjust_option_bynumber(option) );
}