video.c 29.1 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
#include <vlc/libvlc_renderer_discoverer.h>
34 35 36 37
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_media_player.h>

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

42
#include "media_player_internal.h"
43
#include <math.h>
44
#include <assert.h>
45

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

58 59
    vout_thread_t **pp_vouts;
    if (input_Control( p_input, INPUT_GET_VOUTS, &pp_vouts, n))
60
    {
61 62
        *n = 0;
        pp_vouts = NULL;
63
    }
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    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
87 88 89 90 91 92 93
    return p_vout;
}

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

94
void libvlc_set_fullscreen( libvlc_media_player_t *p_mi, int b_fullscreen )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
95
{
96 97
    /* 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
98

99 100 101 102 103 104 105 106 107
    /* 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
108 109
}

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

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

119 120 121 122 123 124
    /* 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
125

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

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

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

142 143 144 145
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
146
{
147 148
    assert( psz_filepath );

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

153 154 155 156 157
    /* 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 );
158
    var_SetInteger( p_vout, "snapshot-width", i_width);
159
    var_Create( p_vout, "snapshot-height", VLC_VAR_INTEGER );
160
    var_SetInteger( p_vout, "snapshot-height", i_height );
161
    var_Create( p_vout, "snapshot-path", VLC_VAR_STRING );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
162
    var_SetString( p_vout, "snapshot-path", psz_filepath );
163
    var_Create( p_vout, "snapshot-format", VLC_VAR_STRING );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
164
    var_SetString( p_vout, "snapshot-format", "png" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
165 166
    var_TriggerCallback( p_vout, "video-snapshot" );
    vlc_object_release( p_vout );
167
    return 0;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
168 169
}

170 171
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
172
{
173 174
    libvlc_media_track_info_t *info;
    int ret = -1;
Rafaël Carré's avatar
Rafaël Carré committed
175 176
    if (!p_mi->p_md)
        return ret;
177 178 179 180 181 182 183 184 185 186 187 188 189 190
    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;
191
}
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
192

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

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

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

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

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

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

223
unsigned libvlc_media_player_has_vout( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
224
{
225 226 227 228 229 230
    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
231 232
}

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

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

    /* 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];
253

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

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

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

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

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

286 287 288 289 290
libvlc_video_viewpoint_t *libvlc_video_new_viewpoint(void)
{
    libvlc_video_viewpoint_t *p_vp = malloc(sizeof *p_vp);
    if (unlikely(p_vp == NULL))
        return NULL;
291
    p_vp->f_yaw = p_vp->f_pitch = p_vp->f_roll = p_vp->f_field_of_view = 0.0f;
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    return p_vp;
}

int libvlc_video_update_viewpoint( libvlc_media_player_t *p_mi,
                                   const libvlc_video_viewpoint_t *p_viewpoint,
                                   bool b_absolute )
{
    vlc_viewpoint_t update = {
        .yaw   = p_viewpoint->f_yaw,
        .pitch = p_viewpoint->f_pitch,
        .roll  = p_viewpoint->f_roll,
        .fov   = p_viewpoint->f_field_of_view,
    };

    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
    if( p_input_thread != NULL )
    {
        if( input_UpdateViewpoint( p_input_thread, &update,
                                   b_absolute ) != VLC_SUCCESS )
        {
            vlc_object_release( p_input_thread );
            return -1;
        }
        vlc_object_release( p_input_thread );
316
        return 0;
317 318 319 320 321
    }

    /* Save the viewpoint in case the input is not created yet */
    if( !b_absolute )
    {
322 323 324 325
        p_mi->viewpoint.yaw += update.yaw;
        p_mi->viewpoint.pitch += update.pitch;
        p_mi->viewpoint.roll += update.roll;
        p_mi->viewpoint.fov += update.fov;
326 327 328 329 330 331 332
    }
    else
        p_mi->viewpoint = update;

    return 0;
}

333
int libvlc_video_get_spu( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
334
{
335
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
336

337 338 339 340 341
    if( !p_input_thread )
    {
        libvlc_printerr( "No active input" );
        return -1;
    }
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
342

343
    int i_spu = var_GetInteger( p_input_thread, "spu-es" );
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
344 345 346 347
    vlc_object_release( p_input_thread );
    return i_spu;
}

348
int libvlc_video_get_spu_count( libvlc_media_player_t *p_mi )
349
{
350
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
351
    int i_spu_count;
352 353

    if( !p_input_thread )
354
        return 0;
355

356
    i_spu_count = var_CountChoices( p_input_thread, "spu-es" );
357
    vlc_object_release( p_input_thread );
358
    return i_spu_count;
359 360 361
}

libvlc_track_description_t *
362
        libvlc_video_get_spu_description( libvlc_media_player_t *p_mi )
363
{
364
    return libvlc_get_track_description( p_mi, "spu-es" );
365 366
}

367
int libvlc_video_set_spu( libvlc_media_player_t *p_mi, int i_spu )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
368
{
369
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
370
    vlc_value_t list;
371
    int i_ret = -1;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
372

373
    if( !p_input_thread )
374
        return -1;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
375

376
    var_Change (p_input_thread, "spu-es", VLC_VAR_GETCHOICES, &list, NULL);
377
    for (int i = 0; i < list.p_list->i_count; i++)
378
    {
379 380 381 382 383 384 385
        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;
        }
386
    }
387
    libvlc_printerr( "Track identifier not found" );
388
end:
389 390 391
    vlc_object_release (p_input_thread);
    var_FreeList (&list, NULL);
    return i_ret;
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
392 393
}

394
int libvlc_video_set_subtitle_file( libvlc_media_player_t *p_mi,
395
                                    const char *psz_subtitle )
396
{
397
    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
398 399 400 401
    bool b_ret = false;

    if( p_input_thread )
    {
402
        if( !input_AddSubtitle( p_input_thread, psz_subtitle, true ) )
403 404 405 406 407 408
            b_ret = true;
        vlc_object_release( p_input_thread );
    }
    return b_ret;
}

409 410 411 412 413 414 415
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 )
    {
416
        val = var_GetInteger( p_input_thread, "spu-delay" );
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
        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 )
    {
435
        var_SetInteger( p_input_thread, "spu-delay", i_delay );
436 437 438 439 440 441 442 443 444 445 446
        vlc_object_release( p_input_thread );
        ret = 0;
    }
    else
    {
        libvlc_printerr( "No active input" );
    }

    return ret;
}

447
libvlc_track_description_t *
448
        libvlc_video_get_title_description( libvlc_media_player_t *p_mi )
449
{
450
    return libvlc_get_track_description( p_mi, "title" );
451 452 453 454
}

libvlc_track_description_t *
        libvlc_video_get_chapter_description( libvlc_media_player_t *p_mi,
455
                                              int i_title )
456
{
457 458
    char psz_title[sizeof ("title ") + 3 * sizeof (int)];
    sprintf( psz_title,  "title %2u", i_title );
459
    return libvlc_get_track_description( p_mi, psz_title );
460 461
}

462
char *libvlc_video_get_crop_geometry (libvlc_media_player_t *p_mi)
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
463
{
464
    return var_GetNonEmptyString (p_mi, "crop");
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
465 466
}

467
void libvlc_video_set_crop_geometry( libvlc_media_player_t *p_mi,
468
                                     const char *psz_geometry )
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
469
{
470 471
    if (psz_geometry == NULL)
        psz_geometry = "";
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
472

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

475 476
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
477

478
    for (size_t i = 0; i < n; i++)
479
    {
480
        vout_thread_t *p_vout = pp_vouts[i];
481

482 483
        var_SetString (p_vout, "crop", psz_geometry);
        vlc_object_release (p_vout);
484
    }
485
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.  
Pierre d'Herbemont committed
486 487
}

488 489
int libvlc_video_get_teletext( libvlc_media_player_t *p_mi )
{
490
    return var_GetInteger (p_mi, "vbi-page");
491 492
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
static void teletext_enable( input_thread_t *p_input_thread, bool b_enable )
{
    if( b_enable )
    {
        vlc_value_t list;
        if( !var_Change( p_input_thread, "teletext-es", VLC_VAR_GETCHOICES,
                         &list, NULL ) )
        {
            if( list.p_list->i_count > 0 )
                var_SetInteger( p_input_thread, "spu-es",
                                list.p_list->p_values[0].i_int );

            var_FreeList( &list, NULL );
        }
    }
    else
        var_SetInteger( p_input_thread, "spu-es", -1 );
}

512
void libvlc_video_set_teletext( libvlc_media_player_t *p_mi, int i_page )
513 514 515 516 517
{
    input_thread_t *p_input_thread;
    vlc_object_t *p_zvbi = NULL;
    int telx;

518 519
    var_SetInteger (p_mi, "vbi-page", i_page);

520 521 522 523 524 525 526 527 528 529
    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" );
530
    if( telx >= 0 )
531
    {
532 533 534 535 536 537
        if( input_GetEsObjects( p_input_thread, telx, &p_zvbi, NULL, NULL )
            == VLC_SUCCESS )
        {
            var_SetInteger( p_zvbi, "vbi-page", i_page );
            vlc_object_release( p_zvbi );
        }
538 539 540 541
    }
    vlc_object_release( p_input_thread );
}

542
void libvlc_toggle_teletext( libvlc_media_player_t *p_mi )
543
{
544
    input_thread_t *p_input_thread;
545

546
    p_input_thread = libvlc_get_input_thread(p_mi);
547
    if( !p_input_thread ) return;
548

549
    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
550
    {
551 552 553 554
        vlc_object_release( p_input_thread );
        return;
    }
    const bool b_selected = var_GetInteger( p_input_thread, "teletext-es" ) >= 0;
555
    teletext_enable( p_input_thread, !b_selected );
556
    vlc_object_release( p_input_thread );
557 558
}

559
int libvlc_video_get_track_count( libvlc_media_player_t *p_mi )
560
{
561
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
562
    int i_track_count;
563 564 565 566

    if( !p_input_thread )
        return -1;

567
    i_track_count = var_CountChoices( p_input_thread, "video-es" );
568

569
    vlc_object_release( p_input_thread );
570
    return i_track_count;
571 572 573
}

libvlc_track_description_t *
574
        libvlc_video_get_track_description( libvlc_media_player_t *p_mi )
575
{
576
    return libvlc_get_track_description( p_mi, "video-es" );
577 578
}

579
int libvlc_video_get_track( libvlc_media_player_t *p_mi )
580
{
581
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
582 583 584 585

    if( !p_input_thread )
        return -1;

586
    int id = var_GetInteger( p_input_thread, "video-es" );
587
    vlc_object_release( p_input_thread );
588
    return id;
589 590
}

591
int libvlc_video_set_track( libvlc_media_player_t *p_mi, int i_track )
592
{
593
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
594 595 596 597
    vlc_value_t val_list;
    int i_ret = -1;

    if( !p_input_thread )
598
        return -1;
599 600

    var_Change( p_input_thread, "video-es", VLC_VAR_GETCHOICES, &val_list, NULL );
601
    for( int i = 0; i < val_list.p_list->i_count; i++ )
602
    {
603
        if( i_track == val_list.p_list->p_values[i].i_int )
604
        {
605 606
            if( var_SetBool( p_input_thread, "video", true ) < 0)
                break;
607
            if( var_SetInteger( p_input_thread, "video-es", i_track ) < 0 )
608
                break;
609
            i_ret = 0;
610
            goto end;
611 612
        }
    }
613
    libvlc_printerr( "Track identifier not found" );
614
end:
615
    var_FreeList( &val_list, NULL );
616
    vlc_object_release( p_input_thread );
617
    return i_ret;
618
}
619 620 621 622

/******************************************************************************
 * libvlc_video_set_deinterlace : enable deinterlace
 *****************************************************************************/
623 624 625 626 627 628
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
629 630 631 632
     && 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
633
     && strcmp (psz_mode, "phosphor") && strcmp (psz_mode, "ivtc"))
634 635
        return;

636
    if (*psz_mode)
637
    {
638 639
        var_SetString (p_mi, "deinterlace-mode", psz_mode);
        var_SetInteger (p_mi, "deinterlace", 1);
640 641
    }
    else
642 643 644 645 646
        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++)
647
    {
648
        vout_thread_t *p_vout = pp_vouts[i];
649

650 651 652 653 654 655 656 657 658 659
        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);
660
}
661

662 663 664 665
/* ************** */
/* module helpers */
/* ************** */

666
static void vout_EnableFilter( vlc_object_t *p_parent, const char *psz_name,
667
                               bool b_add )
668 669 670 671 672 673 674 675
{
    char *psz_parser;
    char *psz_string;
    const char *psz_filter_type;

    module_t *p_obj = module_find( psz_name );
    if( !p_obj )
    {
676
        msg_Err( p_parent, "Unable to find filter module \"%s\".", psz_name );
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
        return;
    }

    if( module_provides( p_obj, "video filter" ) )
    {
        psz_filter_type = "video-filter";
    }
    else if( module_provides( p_obj, "sub source" ) )
    {
        psz_filter_type = "sub-source";
    }
    else if( module_provides( p_obj, "sub filter" ) )
    {
        psz_filter_type = "sub-filter";
    }
    else
    {
694
        msg_Err( p_parent, "Unknown video filter type." );
695 696 697
        return;
    }

698
    psz_string = var_GetString( p_parent, psz_filter_type );
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 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743

    /* Todo : Use some generic chain manipulation functions */
    if( !psz_string ) psz_string = strdup("");

    psz_parser = strstr( psz_string, psz_name );
    if( b_add )
    {
        if( !psz_parser )
        {
            psz_parser = psz_string;
            if( asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
                          psz_string, psz_name ) == -1 )
            {
                free( psz_parser );
                return;
            }
            free( psz_parser );
        }
        else
        {
            free( psz_string );
            return;
        }
    }
    else
    {
        if( psz_parser )
        {
            memmove( psz_parser, psz_parser + strlen(psz_name) +
                            (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
                            strlen(psz_parser + strlen(psz_name)) + 1 );

            /* Remove trailing : : */
            if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
            {
                *(psz_string+strlen(psz_string ) -1 ) = '\0';
            }
         }
         else
         {
             free( psz_string );
             return;
         }
    }

744
    var_SetString( p_parent, psz_filter_type, psz_string );
745 746 747 748

    free( psz_string );
}

749
static bool find_sub_source_by_name( libvlc_media_player_t *p_mi, const char *restrict name )
750
{
751
    vout_thread_t *vout = GetVout( p_mi, 0 );
752 753
    if (!vout)
        return false;
754

755 756
    char *psz_sources = var_GetString( vout, "sub-source" );
    if( !psz_sources )
757
    {
758 759 760
        libvlc_printerr( "%s not enabled", name );
        vlc_object_release( vout );
        return false;
761
    }
762

763 764 765 766 767
    /* Find 'name'  */
    char *p = strstr( psz_sources, name );
    free( psz_sources );
    vlc_object_release( vout );
    return (p != NULL);
768 769
}

770
typedef const struct {
771
    const char name[20];
772
    unsigned type;
773
} opt_t;
774

775
static void
776 777
set_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt, int value )
778
{
779 780
    if( !opt ) return;

781
    switch( opt->type )
782
    {
783
        case 0: /* the enabler */
784
        {
785
            vout_thread_t *vout = GetVout( p_mi, 0 );
786 787 788
            vlc_object_t *p_parent = vout ? VLC_OBJECT( vout ) :
                                            VLC_OBJECT( p_mi );
            vout_EnableFilter( p_parent, opt->name, value );
789 790 791 792 793 794
            if (vout != NULL)
            {   /* Fill sub-source */
                var_TriggerCallback( vout, "sub-source" );
                vlc_object_release( vout );
            }
            break;
795
        }
796 797 798 799 800 801 802 803 804
        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;
805
    }
806 807 808
}

static int
809 810
get_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt )
811 812
{
    if( !opt ) return 0;
813

814
    switch( opt->type )
815
    {
816 817
        case 0: /* the enabler */
        {
818 819
            bool b_enabled = find_sub_source_by_name( p_mi, name );
            return b_enabled ? 1 : 0;
820
        }
821
    case VLC_VAR_INTEGER:
822
        return var_GetInteger(p_mi, opt->name);
823 824
    case VLC_VAR_FLOAT:
        return lroundf(var_GetFloat(p_mi, opt->name));
825
    default:
826 827
        libvlc_printerr( "Invalid argument to %s in %s", name, "get int" );
        return 0;
828 829 830
    }
}

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
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 );
}

861
static void
862 863
set_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt, const char *restrict psz_value )
864
{
865 866
    if( !opt ) return;

867
    if( opt->type != VLC_VAR_STRING )
868
    {
869 870 871 872 873
        libvlc_printerr( "Invalid argument to %s in %s", name, "set string" );
        return;
    }

    var_SetString( p_mi, opt->name, psz_value );
874
}
875

876
static char *
877 878
get_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt )
879 880 881
{
    if( !opt ) return NULL;

882
    if( opt->type != VLC_VAR_STRING )
883
    {
884 885
        libvlc_printerr( "Invalid argument to %s in %s", name, "get string" );
        return NULL;
886 887
    }

888 889
    return var_GetString( p_mi, opt->name );
}
890 891

static const opt_t *
892
marq_option_bynumber(unsigned option)
893
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
894
    static const opt_t optlist[] =
895 896 897 898 899 900 901 902 903 904 905 906 907
    {
        { "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) };
908

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
909
    const opt_t *r = option < num_opts ? optlist+option : NULL;
910 911 912
    if( !r )
        libvlc_printerr( "Unknown marquee option" );
    return r;
913 914 915
}

/*****************************************************************************
916
 * libvlc_video_get_marquee_int : get a marq option value
917
 *****************************************************************************/
918
int libvlc_video_get_marquee_int( libvlc_media_player_t *p_mi,
919
                                  unsigned option )
920
{
921
    return get_int( p_mi, "marq", marq_option_bynumber(option) );
922
}
923

924 925 926 927
/*****************************************************************************
 * libvlc_video_get_marquee_string : get a marq option value
 *****************************************************************************/
char * libvlc_video_get_marquee_string( libvlc_media_player_t *p_mi,
928
                                        unsigned option )
929
{
930
    return get_string( p_mi, "marq", marq_option_bynumber(option) );
931
}
932

933 934 935 936
/*****************************************************************************
 * libvlc_video_set_marquee_int: enable, disable or set an int option
 *****************************************************************************/
void libvlc_video_set_marquee_int( libvlc_media_player_t *p_mi,
937
                         unsigned option, int value )
938
{
939
    set_int( p_mi, "marq", marq_option_bynumber(option), value );
940
}
941

942 943 944 945
/*****************************************************************************
 * libvlc_video_set_marquee_string: set a string option
 *****************************************************************************/
void libvlc_video_set_marquee_string( libvlc_media_player_t *p_mi,
946
                unsigned option, const char * value )
947
{
948
    set_string( p_mi, "marq", marq_option_bynumber(option), value );
949 950 951
}


952
/* logo module support */
953

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
954
static const opt_t *
955
logo_option_bynumber( unsigned option )
956
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
957 958
    static const opt_t vlogo_optlist[] =
    /* depends on libvlc_video_logo_option_t */
959 960 961 962 963 964 965 966 967 968 969 970
    {
        { "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
971
    const opt_t *r = option < num_vlogo_opts ? vlogo_optlist+option : NULL;
972
    if( !r )
973
        libvlc_printerr( "Unknown logo option" );
974 975 976 977
    return r;
}

void libvlc_video_set_logo_string( libvlc_media_player_t *p_mi,
978
                                   unsigned option, const char *psz_value )
979
{
980
    set_string( p_mi,"logo",logo_option_bynumber(option), psz_value );
981 982 983 984
}


void libvlc_video_set_logo_int( libvlc_media_player_t *p_mi,
985
                                unsigned option, int value )
986
{
987
    set_int( p_mi, "logo", logo_option_bynumber(option), value );
988 989 990 991
}


int libvlc_video_get_logo_int( libvlc_media_player_t *p_mi,
992
                               unsigned option )
993
{
994
    return get_int( p_mi, "logo", logo_option_bynumber(option) );
995
}
996 997


998 999 1000
/* adjust module support */


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1001
static const opt_t *
1002 1003 1004 1005
adjust_option_bynumber( unsigned option )
{
    static const opt_t optlist[] =
    {
1006 1007 1008
        { "adjust",     0 },
        { "contrast",   VLC_VAR_FLOAT },
        { "brightness", VLC_VAR_FLOAT },
1009
        { "hue",        VLC_VAR_FLOAT },
1010 1011
        { "saturation", VLC_VAR_FLOAT },
        { "gamma",      VLC_VAR_FLOAT },
1012 1013 1014
    };
    enum { num_opts = sizeof(optlist) / sizeof(*optlist) };

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1015
    const opt_t *r = option < num_opts ? optlist+option : NULL;
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
    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) );
}