video.c 26.7 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>
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
38
39
40
#include <vlc_input.h>
#include <vlc_vout.h>

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

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

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

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
98
99
100
101
102
103
104
105
106
    /* 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
107
108
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
109
int libvlc_get_fullscreen( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
110
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
111
    return var_GetBool (p_mi, "fullscreen");
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
112
113
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
114
void libvlc_toggle_fullscreen( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
115
{
116
    bool b_fullscreen = var_ToggleBool (p_mi, "fullscreen");
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
117

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
118
119
120
121
122
123
    /* 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
124

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
125
126
127
128
        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
129
130
}

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
141
142
143
144
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
145
{
146
147
    assert( psz_filepath );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
148
149
150
    vout_thread_t *p_vout = GetVout (p_mi, num);
    if (p_vout == NULL)
        return -1;
151

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
192
193
int libvlc_video_get_height( libvlc_media_player_t *p_mi )
{
194
    unsigned width, height;
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
195

196
    if (libvlc_video_get_size (p_mi, 0, &width, &height))
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
197
        return 0;
198
    return height;
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
199
200
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
201
int libvlc_video_get_width( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
202
{
203
    unsigned width, height;
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
204

205
    if (libvlc_video_get_size (p_mi, 0, &width, &height))
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
206
        return 0;
207
    return width;
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
208
209
}

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

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
232
float libvlc_video_get_scale( libvlc_media_player_t *mp )
233
{
234
    float f_scale = var_GetFloat (mp, "zoom");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
235
    if (var_GetBool (mp, "autoscale"))
236
        f_scale = 0.f;
237
238
239
    return f_scale;
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
240
void libvlc_video_set_scale( libvlc_media_player_t *p_mp, float f_scale )
241
{
242
    if (isfinite(f_scale) && f_scale != 0.f)
243
        var_SetFloat (p_mp, "zoom", f_scale);
244
    var_SetBool (p_mp, "autoscale", f_scale == 0.f);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
245
246
247
248
249
250
251

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

253
        if (isfinite(f_scale) && f_scale != 0.f)
254
            var_SetFloat (p_vout, "zoom", f_scale);
255
        var_SetBool (p_vout, "autoscale", f_scale == 0.f);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
256
257
258
        vlc_object_release (p_vout);
    }
    free (pp_vouts);
259
260
}

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
273
274
275
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
    for (size_t i = 0; i < n; i++)
276
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
277
278
279
280
        vout_thread_t *p_vout = pp_vouts[i];

        var_SetString (p_vout, "aspect-ratio", psz_aspect);
        vlc_object_release (p_vout);
281
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
282
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
283
284
}

285
286
287
288
289
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;
290
    p_vp->f_yaw = p_vp->f_pitch = p_vp->f_roll = p_vp->f_field_of_view = 0.0f;
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
    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 );
315
        return 0;
316
317
318
319
320
    }

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

    return 0;
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
332
int libvlc_video_get_spu( libvlc_media_player_t *p_mi )
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
333
{
334
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
335

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
347
int libvlc_video_get_spu_count( libvlc_media_player_t *p_mi )
348
{
349
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
350
    int i_spu_count;
351
352

    if( !p_input_thread )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
353
        return 0;
354

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

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

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

372
    if( !p_input_thread )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
373
        return -1;
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
374

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

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

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

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

    return ret;
}

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
461
char *libvlc_video_get_crop_geometry (libvlc_media_player_t *p_mi)
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
462
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
463
    return var_GetNonEmptyString (p_mi, "crop");
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
464
465
}

466
void libvlc_video_set_crop_geometry( libvlc_media_player_t *p_mi,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
467
                                     const char *psz_geometry )
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
468
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
469
470
    if (psz_geometry == NULL)
        psz_geometry = "";
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
471

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
472
    var_SetString (p_mi, "crop", psz_geometry);
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
473

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
474
475
    size_t n;
    vout_thread_t **pp_vouts = GetVouts (p_mi, &n);
476

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
477
    for (size_t i = 0; i < n; i++)
478
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
479
        vout_thread_t *p_vout = pp_vouts[i];
480

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
481
482
        var_SetString (p_vout, "crop", psz_geometry);
        vlc_object_release (p_vout);
483
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
484
    free (pp_vouts);
Pierre d'Herbemont's avatar
Oops.    
Pierre d'Herbemont committed
485
486
}

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

492
void libvlc_video_set_teletext( libvlc_media_player_t *p_mi, int i_page )
493
494
495
496
497
{
    input_thread_t *p_input_thread;
    vlc_object_t *p_zvbi = NULL;
    int telx;

498
499
    var_SetInteger (p_mi, "vbi-page", i_page);

500
501
502
503
504
505
506
507
508
509
    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" );
510
    if( telx >= 0 )
511
    {
512
513
514
515
516
517
        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 );
        }
518
519
520
521
    }
    vlc_object_release( p_input_thread );
}

522
void libvlc_toggle_teletext( libvlc_media_player_t *p_mi )
523
{
524
    input_thread_t *p_input_thread;
525

526
    p_input_thread = libvlc_get_input_thread(p_mi);
527
    if( !p_input_thread ) return;
528

529
    if( var_CountChoices( p_input_thread, "teletext-es" ) <= 0 )
530
    {
531
532
533
534
        vlc_object_release( p_input_thread );
        return;
    }
    const bool b_selected = var_GetInteger( p_input_thread, "teletext-es" ) >= 0;
535
    if( b_selected )
536
537
538
    {
        var_SetInteger( p_input_thread, "spu-es", -1 );
    }
539
540
    else
    {
541
        vlc_value_t list;
542
        if( !var_Change( p_input_thread, "teletext-es", VLC_VAR_GETCHOICES, &list, NULL ) )
543
        {
544
545
            if( list.p_list->i_count > 0 )
                var_SetInteger( p_input_thread, "spu-es", list.p_list->p_values[0].i_int );
546

547
            var_FreeList( &list, NULL );
548
549
550
        }
    }
    vlc_object_release( p_input_thread );
551
552
}

553
int libvlc_video_get_track_count( libvlc_media_player_t *p_mi )
554
{
555
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
556
    int i_track_count;
557
558
559
560

    if( !p_input_thread )
        return -1;

561
    i_track_count = var_CountChoices( p_input_thread, "video-es" );
562

563
    vlc_object_release( p_input_thread );
564
    return i_track_count;
565
566
567
}

libvlc_track_description_t *
568
        libvlc_video_get_track_description( libvlc_media_player_t *p_mi )
569
{
570
    return libvlc_get_track_description( p_mi, "video-es" );
571
572
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
573
int libvlc_video_get_track( libvlc_media_player_t *p_mi )
574
{
575
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
576
577
578
579

    if( !p_input_thread )
        return -1;

580
    int id = var_GetInteger( p_input_thread, "video-es" );
581
    vlc_object_release( p_input_thread );
582
    return id;
583
584
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
585
int libvlc_video_set_track( libvlc_media_player_t *p_mi, int i_track )
586
{
587
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
588
589
590
591
    vlc_value_t val_list;
    int i_ret = -1;

    if( !p_input_thread )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
592
        return -1;
593
594

    var_Change( p_input_thread, "video-es", VLC_VAR_GETCHOICES, &val_list, NULL );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
595
    for( int i = 0; i < val_list.p_list->i_count; i++ )
596
    {
597
        if( i_track == val_list.p_list->p_values[i].i_int )
598
        {
599
600
            if( var_SetBool( p_input_thread, "video", true ) < 0)
                break;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
601
            if( var_SetInteger( p_input_thread, "video-es", i_track ) < 0 )
602
                break;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
603
            i_ret = 0;
604
            goto end;
605
606
        }
    }
607
    libvlc_printerr( "Track identifier not found" );
608
end:
609
    var_FreeList( &val_list, NULL );
610
    vlc_object_release( p_input_thread );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
611
    return i_ret;
612
}
613
614
615
616

/******************************************************************************
 * libvlc_video_set_deinterlace : enable deinterlace
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
617
618
619
620
621
622
void libvlc_video_set_deinterlace( libvlc_media_player_t *p_mi,
                                   const char *psz_mode )
{
    if (psz_mode == NULL)
        psz_mode = "";
    if (*psz_mode
Technologicat's avatar
Technologicat committed
623
624
625
626
     && 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")
Technologicat's avatar
Technologicat committed
627
     && strcmp (psz_mode, "phosphor") && strcmp (psz_mode, "ivtc"))
628
629
        return;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
630
    if (*psz_mode)
631
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
632
633
        var_SetString (p_mi, "deinterlace-mode", psz_mode);
        var_SetInteger (p_mi, "deinterlace", 1);
634
635
    }
    else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
636
637
638
639
640
        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++)
641
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
642
        vout_thread_t *p_vout = pp_vouts[i];
643

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
644
645
646
647
648
649
650
651
652
653
        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);
654
}
655

656
657
658
659
/* ************** */
/* module helpers */
/* ************** */

660
static bool find_sub_source_by_name( libvlc_media_player_t *p_mi, const char *restrict name )
661
{
662
    vout_thread_t *vout = GetVout( p_mi, 0 );
663
664
    if (!vout)
        return false;
665

666
667
    char *psz_sources = var_GetString( vout, "sub-source" );
    if( !psz_sources )
668
    {
669
670
671
        libvlc_printerr( "%s not enabled", name );
        vlc_object_release( vout );
        return false;
672
    }
673

674
675
676
677
678
    /* Find 'name'  */
    char *p = strstr( psz_sources, name );
    free( psz_sources );
    vlc_object_release( vout );
    return (p != NULL);
679
680
}

681
typedef const struct {
682
    const char name[20];
683
    unsigned type;
684
} opt_t;
685

686
static void
687
688
set_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt, int value )
689
{
690
691
    if( !opt ) return;

692
    switch( opt->type )
693
    {
694
        case 0: /* the enabler */
695
        {
696
697
698
699
700
701
702
703
            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;
704
        }
705
706
707
708
709
710
711
712
713
        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;
714
    }
715
716
717
}

static int
718
719
get_int( libvlc_media_player_t *p_mi, const char *restrict name,
         const opt_t *restrict opt )
720
721
{
    if( !opt ) return 0;
ivoire's avatar
ivoire committed
722

723
    switch( opt->type )
724
    {
725
726
        case 0: /* the enabler */
        {
727
728
            bool b_enabled = find_sub_source_by_name( p_mi, name );
            return b_enabled ? 1 : 0;
729
        }
730
    case VLC_VAR_INTEGER:
731
        return var_GetInteger(p_mi, opt->name);
732
733
    case VLC_VAR_FLOAT:
        return lroundf(var_GetFloat(p_mi, opt->name));
734
    default:
735
736
        libvlc_printerr( "Invalid argument to %s in %s", name, "get int" );
        return 0;
737
738
739
    }
}

740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
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 );
}

770
static void
771
772
set_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt, const char *restrict psz_value )
773
{
774
775
    if( !opt ) return;

776
    if( opt->type != VLC_VAR_STRING )
777
    {
778
779
780
781
782
        libvlc_printerr( "Invalid argument to %s in %s", name, "set string" );
        return;
    }

    var_SetString( p_mi, opt->name, psz_value );
783
}
ivoire's avatar
ivoire committed
784

785
static char *
786
787
get_string( libvlc_media_player_t *p_mi, const char *restrict name,
            const opt_t *restrict opt )
788
789
790
{
    if( !opt ) return NULL;

791
    if( opt->type != VLC_VAR_STRING )
792
    {
793
794
        libvlc_printerr( "Invalid argument to %s in %s", name, "get string" );
        return NULL;
795
796
    }

797
798
    return var_GetString( p_mi, opt->name );
}
799
800

static const opt_t *
801
marq_option_bynumber(unsigned option)
802
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
803
    static const opt_t optlist[] =
804
805
806
807
808
809
810
811
812
813
814
815
816
    {
        { "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) };
817

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
818
    const opt_t *r = option < num_opts ? optlist+option : NULL;
819
820
821
    if( !r )
        libvlc_printerr( "Unknown marquee option" );
    return r;
822
823
824
}

/*****************************************************************************
825
 * libvlc_video_get_marquee_int : get a marq option value
826
 *****************************************************************************/
827
int libvlc_video_get_marquee_int( libvlc_media_player_t *p_mi,
828
                                  unsigned option )
829
{
830
    return get_int( p_mi, "marq", marq_option_bynumber(option) );
831
}
832

833
834
835
836
/*****************************************************************************
 * libvlc_video_get_marquee_string : get a marq option value
 *****************************************************************************/
char * libvlc_video_get_marquee_string( libvlc_media_player_t *p_mi,
837
                                        unsigned option )
838
{
839
    return get_string( p_mi, "marq", marq_option_bynumber(option) );
840
}
841

842
843
844
845
/*****************************************************************************
 * libvlc_video_set_marquee_int: enable, disable or set an int option
 *****************************************************************************/
void libvlc_video_set_marquee_int( libvlc_media_player_t *p_mi,
846
                         unsigned option, int value )
847
{
848
    set_int( p_mi, "marq", marq_option_bynumber(option), value );
849
}
850

851
852
853
854
/*****************************************************************************
 * libvlc_video_set_marquee_string: set a string option
 *****************************************************************************/
void libvlc_video_set_marquee_string( libvlc_media_player_t *p_mi,
855
                unsigned option, const char * value )
856
{
857
    set_string( p_mi, "marq", marq_option_bynumber(option), value );
858
859
860
}


861
/* logo module support */
862

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
863
static const opt_t *
864
logo_option_bynumber( unsigned option )
865
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
866
867
    static const opt_t vlogo_optlist[] =
    /* depends on libvlc_video_logo_option_t */
868
869
870
871
872
873
874
875
876
877
878
879
    {
        { "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
880
    const opt_t *r = option < num_vlogo_opts ? vlogo_optlist+option : NULL;
881
    if( !r )
882
        libvlc_printerr( "Unknown logo option" );
883
884
885
886
    return r;
}

void libvlc_video_set_logo_string( libvlc_media_player_t *p_mi,
887
                                   unsigned option, const char *psz_value )
888
{
889
    set_string( p_mi,"logo",logo_option_bynumber(option), psz_value );
890
891
892
893
}


void libvlc_video_set_logo_int( libvlc_media_player_t *p_mi,
894
                                unsigned option, int value )
895
{
896
    set_int( p_mi, "logo", logo_option_bynumber(option), value );
897
898
899
900
}


int libvlc_video_get_logo_int( libvlc_media_player_t *p_mi,
901
                               unsigned option )
902
{
903
    return get_int( p_mi, "logo", logo_option_bynumber(option) );
904
}
905
906


907
908
909
/* adjust module support */


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
910
static const opt_t *
911
912
913
914
adjust_option_bynumber( unsigned option )
{
    static const opt_t optlist[] =
    {
915
916
917
        { "adjust",     0 },
        { "contrast",   VLC_VAR_FLOAT },
        { "brightness", VLC_VAR_FLOAT },
918
        { "hue",        VLC_VAR_FLOAT },
919
920
        { "saturation", VLC_VAR_FLOAT },
        { "gamma",      VLC_VAR_FLOAT },