~gabriel1984sibiu/mplayer/vaapi

1 by Grevutiu Gabriel
original source code upstream
1
/*
2
 * This file is part of MPlayer.
3
 *
4
 * MPlayer is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * MPlayer is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License along
15
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
 */
18
19
#define _BSD_SOURCE
20
21
#include <stdlib.h>
22
#include <inttypes.h>
23
#include <unistd.h>
24
#include <string.h>
25
#include <strings.h>
26
27
#include "config.h"
28
#include "command.h"
29
#include "input/input.h"
30
#include "stream/stream.h"
31
#include "libmpdemux/demuxer.h"
32
#include "libmpdemux/stheader.h"
33
#include "codec-cfg.h"
34
#include "mp_msg.h"
35
#include "mplayer.h"
36
#include "sub/sub.h"
37
#include "m_option.h"
38
#include "m_property.h"
39
#include "help_mp.h"
40
#include "metadata.h"
41
#include "libmpcodecs/vf.h"
42
#include "libmpcodecs/vd.h"
43
#include "libvo/video_out.h"
44
#include "libvo/aspect.h"
45
#include "sub/font_load.h"
46
#include "playtree.h"
47
#include "libao2/audio_out.h"
48
#include "mpcommon.h"
49
#include "mixer.h"
50
#include "libmpcodecs/dec_video.h"
51
#include "libmpcodecs/dec_teletext.h"
52
#include "osdep/strsep.h"
53
#include "sub/vobsub.h"
54
#include "sub/spudec.h"
55
#include "path.h"
56
#include "stream/tv.h"
57
#include "stream/stream_radio.h"
58
#include "stream/pvr.h"
59
#ifdef CONFIG_DVBIN
60
#include "stream/dvbin.h"
61
#endif
62
#include "stream/stream_bd.h"
63
#ifdef CONFIG_DVDREAD
64
#include "stream/stream_dvd.h"
65
#endif
66
#include "stream/stream_dvdnav.h"
67
#include "sub/ass_mp.h"
68
#include "m_struct.h"
69
#include "libmenu/menu.h"
70
#include "gui/interface.h"
71
#include "sub/eosd.h"
72
#include "pnm_loader.h"
73
74
#include "mp_core.h"
75
#include "mp_fifo.h"
76
#include "libavutil/avstring.h"
77
#include "edl.h"
78
79
#define IS_STREAMTYPE(t) (mpctx->stream && mpctx->stream->type == STREAMTYPE_##t)
80
81
static void rescale_input_coordinates(int ix, int iy, double *dx, double *dy)
82
{
83
    //remove the borders, if any, and rescale to the range [0,1],[0,1]
84
    int w = vo_dwidth, h = vo_dheight;
85
    if (aspect_scaling()) {
86
        aspect(&w, &h, A_WINZOOM);
87
        panscan_calc_windowed();
88
        w += vo_panscan_x;
89
        h += vo_panscan_y;
90
        ix -= (vo_dwidth  - w) / 2;
91
        iy -= (vo_dheight - h) / 2;
92
    }
93
    if (ix < 0 || ix > w || iy < 0 || iy > h) {
94
        // ignore movements outside movie area
95
        *dx = *dy = -1.0;
96
        return;
97
    }
98
99
    *dx = (double) ix / (double) w;
100
    *dy = (double) iy / (double) h;
101
102
    mp_msg(MSGT_CPLAYER, MSGL_V,
103
           "\r\nrescaled coordinates: %.3f, %.3f, screen (%d x %d), vodisplay: (%d, %d), fullscreen: %d\r\n",
104
           *dx, *dy, vo_screenwidth, vo_screenheight, vo_dwidth,
105
           vo_dheight, vo_fs);
106
}
107
108
static int sub_pos_by_source(MPContext *mpctx, int src)
109
{
110
    int i, cnt = 0;
111
    if (src >= SUB_SOURCES || mpctx->sub_counts[src] == 0)
112
        return -1;
113
    for (i = 0; i < src; i++)
114
        cnt += mpctx->sub_counts[i];
115
    return cnt;
116
}
117
118
static int sub_source_and_index_by_pos(MPContext *mpctx, int *pos)
119
{
120
    int start = 0;
121
    int i;
122
    for (i = 0; i < SUB_SOURCES; i++) {
123
        int cnt = mpctx->sub_counts[i];
124
        if (*pos >= start && *pos < start + cnt) {
125
            *pos -= start;
126
            return i;
127
        }
128
        start += cnt;
129
    }
130
    *pos = -1;
131
    return -1;
132
}
133
134
static int sub_source_by_pos(MPContext *mpctx, int pos)
135
{
136
    return sub_source_and_index_by_pos(mpctx, &pos);
137
}
138
139
static int sub_source_pos(MPContext *mpctx)
140
{
141
    int pos = mpctx->global_sub_pos;
142
    sub_source_and_index_by_pos(mpctx, &pos);
143
    return pos;
144
}
145
146
static int sub_source(MPContext *mpctx)
147
{
148
    return sub_source_by_pos(mpctx, mpctx->global_sub_pos);
149
}
150
151
static void update_global_sub_size(MPContext *mpctx)
152
{
153
    int i;
154
    int cnt = 0;
155
156
    // update number of demuxer sub streams
157
    for (i = 0; i < MAX_S_STREAMS; i++)
158
        if (mpctx->demuxer->s_streams[i])
159
            cnt++;
160
    if (cnt > mpctx->sub_counts[SUB_SOURCE_DEMUX])
161
        mpctx->sub_counts[SUB_SOURCE_DEMUX] = cnt;
162
163
    // update global size
164
    mpctx->global_sub_size = 0;
165
    for (i = 0; i < SUB_SOURCES; i++)
166
        mpctx->global_sub_size += mpctx->sub_counts[i];
167
168
    // update global_sub_pos if we auto-detected a demuxer sub
169
    if (mpctx->global_sub_pos == -1) {
170
        int sub_id = -1;
171
        if (mpctx->demuxer->sub)
172
            sub_id = mpctx->demuxer->sub->id;
173
        if (sub_id < 0)
174
            sub_id = dvdsub_id;
175
        if (sub_id >= 0 && sub_id < mpctx->sub_counts[SUB_SOURCE_DEMUX])
176
            mpctx->global_sub_pos = sub_pos_by_source(mpctx, SUB_SOURCE_DEMUX) +
177
                                    sub_id;
178
    }
179
}
180
181
/**
182
 * \brief Log the currently displayed subtitle to a file
183
 *
184
 * Logs the current or last displayed subtitle together with filename
185
 * and time information to ~/.mplayer/subtitle_log
186
 *
187
 * Intended purpose is to allow convenient marking of bogus subtitles
188
 * which need to be fixed while watching the movie.
189
 */
190
191
static void log_sub(void)
192
{
193
    char *fname;
194
    FILE *f;
195
    int i;
196
197
    if (subdata == NULL || vo_sub_last == NULL)
198
        return;
199
    fname = get_path("subtitle_log");
200
    f = fopen(fname, "a");
201
    if (!f)
202
        goto out;
203
    fprintf(f, "----------------------------------------------------------\n");
204
    if (subdata->sub_uses_time) {
205
        fprintf(f,
206
                "N: %s S: %02ld:%02ld:%02ld.%02ld E: %02ld:%02ld:%02ld.%02ld\n",
207
                filename, vo_sub_last->start / 360000,
208
                (vo_sub_last->start / 6000) % 60,
209
                (vo_sub_last->start / 100) % 60, vo_sub_last->start % 100,
210
                vo_sub_last->end / 360000, (vo_sub_last->end / 6000) % 60,
211
                (vo_sub_last->end / 100) % 60, vo_sub_last->end % 100);
212
    } else {
213
        fprintf(f, "N: %s S: %ld E: %ld\n", filename, vo_sub_last->start,
214
                vo_sub_last->end);
215
    }
216
    for (i = 0; i < vo_sub_last->lines; i++) {
217
        fprintf(f, "%s\n", vo_sub_last->text[i]);
218
    }
219
    fclose(f);
220
out:
221
    free(fname);
222
}
223
224
225
/// \defgroup properties Properties
226
///@{
227
228
/// \defgroup GeneralProperties General properties
229
/// \ingroup Properties
230
///@{
231
232
/// OSD level (RW)
233
static int mp_property_osdlevel(m_option_t *prop, int action, void *arg,
234
                                MPContext *mpctx)
235
{
236
    return m_property_choice(prop, action, arg, &osd_level);
237
}
238
239
/// Loop (RW)
240
static int mp_property_loop(m_option_t *prop, int action, void *arg,
241
                            MPContext *mpctx)
242
{
243
    switch (action) {
244
    case M_PROPERTY_PRINT:
245
        if (!arg) return M_PROPERTY_ERROR;
246
        if (mpctx->loop_times < 0)
247
            *(char**)arg = strdup("off");
248
        else if (mpctx->loop_times == 0)
249
            *(char**)arg = strdup("inf");
250
        else
251
            break;
252
        return M_PROPERTY_OK;
253
    }
254
    return m_property_int_range(prop, action, arg, &mpctx->loop_times);
255
}
256
257
/// Playback speed (RW)
258
static int mp_property_playback_speed(m_option_t *prop, int action,
259
                                      void *arg, MPContext *mpctx)
260
{
261
    switch (action) {
262
    case M_PROPERTY_SET:
263
        if (!arg)
264
            return M_PROPERTY_ERROR;
265
        M_PROPERTY_CLAMP(prop, *(float *) arg);
266
        playback_speed = *(float *) arg;
267
        reinit_audio_chain();
268
        return M_PROPERTY_OK;
269
    case M_PROPERTY_STEP_UP:
270
    case M_PROPERTY_STEP_DOWN:
271
        playback_speed += (arg ? *(float *) arg : 0.1) *
272
            (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
273
        M_PROPERTY_CLAMP(prop, playback_speed);
274
        reinit_audio_chain();
275
        return M_PROPERTY_OK;
276
    }
277
    return m_property_float_range(prop, action, arg, &playback_speed);
278
}
279
280
/// filename with path (RO)
281
static int mp_property_path(m_option_t *prop, int action, void *arg,
282
                            MPContext *mpctx)
283
{
284
    return m_property_string_ro(prop, action, arg, filename);
285
}
286
287
/// filename without path (RO)
288
static int mp_property_filename(m_option_t *prop, int action, void *arg,
289
                                MPContext *mpctx)
290
{
291
    char *f;
292
    if (!filename)
293
        return M_PROPERTY_UNAVAILABLE;
294
    f = (char *)mp_basename(filename);
295
    if (!*f)
296
        f = filename;
297
    return m_property_string_ro(prop, action, arg, f);
298
}
299
300
/// Demuxer name (RO)
301
static int mp_property_demuxer(m_option_t *prop, int action, void *arg,
302
                               MPContext *mpctx)
303
{
304
    if (!mpctx->demuxer)
305
        return M_PROPERTY_UNAVAILABLE;
306
    return m_property_string_ro(prop, action, arg,
307
                                (char *) mpctx->demuxer->desc->name);
308
}
309
310
/// Position in the stream (RW)
311
static int mp_property_stream_pos(m_option_t *prop, int action, void *arg,
312
                                  MPContext *mpctx)
313
{
314
    if (!mpctx->demuxer || !mpctx->demuxer->stream)
315
        return M_PROPERTY_UNAVAILABLE;
316
    if (!arg)
317
        return M_PROPERTY_ERROR;
318
    switch (action) {
319
    case M_PROPERTY_GET:
320
        *(off_t *) arg = stream_tell(mpctx->demuxer->stream);
321
        return M_PROPERTY_OK;
322
    case M_PROPERTY_SET:
323
        M_PROPERTY_CLAMP(prop, *(off_t *) arg);
324
        stream_seek(mpctx->demuxer->stream, *(off_t *) arg);
325
        return M_PROPERTY_OK;
326
    }
327
    return M_PROPERTY_NOT_IMPLEMENTED;
328
}
329
330
/// Stream start offset (RO)
331
static int mp_property_stream_start(m_option_t *prop, int action,
332
                                    void *arg, MPContext *mpctx)
333
{
334
    if (!mpctx->demuxer || !mpctx->demuxer->stream)
335
        return M_PROPERTY_UNAVAILABLE;
336
    switch (action) {
337
    case M_PROPERTY_GET:
338
        *(off_t *) arg = mpctx->demuxer->stream->start_pos;
339
        return M_PROPERTY_OK;
340
    }
341
    return M_PROPERTY_NOT_IMPLEMENTED;
342
}
343
344
/// Stream end offset (RO)
345
static int mp_property_stream_end(m_option_t *prop, int action, void *arg,
346
                                  MPContext *mpctx)
347
{
348
    if (!mpctx->demuxer || !mpctx->demuxer->stream)
349
        return M_PROPERTY_UNAVAILABLE;
350
    switch (action) {
351
    case M_PROPERTY_GET:
352
        *(off_t *) arg = mpctx->demuxer->stream->end_pos;
353
        return M_PROPERTY_OK;
354
    }
355
    return M_PROPERTY_NOT_IMPLEMENTED;
356
}
357
358
/// Stream length (RO)
359
static int mp_property_stream_length(m_option_t *prop, int action,
360
                                     void *arg, MPContext *mpctx)
361
{
362
    if (!mpctx->demuxer || !mpctx->demuxer->stream)
363
        return M_PROPERTY_UNAVAILABLE;
364
    switch (action) {
365
    case M_PROPERTY_GET:
366
        *(off_t *) arg =
367
            mpctx->demuxer->stream->end_pos - mpctx->demuxer->stream->start_pos;
368
        return M_PROPERTY_OK;
369
    }
370
    return M_PROPERTY_NOT_IMPLEMENTED;
371
}
372
373
/// Current stream position in seconds (RO)
374
static int mp_property_stream_time_pos(m_option_t *prop, int action,
375
                                       void *arg, MPContext *mpctx)
376
{
377
    if (!mpctx->demuxer || mpctx->demuxer->stream_pts == MP_NOPTS_VALUE)
378
        return M_PROPERTY_UNAVAILABLE;
379
380
    return m_property_time_ro(prop, action, arg, mpctx->demuxer->stream_pts);
381
}
382
383
384
/// Media length in seconds (RO)
385
static int mp_property_length(m_option_t *prop, int action, void *arg,
386
                              MPContext *mpctx)
387
{
388
    double len;
389
390
    if (!mpctx->demuxer ||
391
        !(int) (len = demuxer_get_time_length(mpctx->demuxer)))
392
        return M_PROPERTY_UNAVAILABLE;
393
394
    return m_property_time_ro(prop, action, arg, len);
395
}
396
397
/// Current position in percent (RW)
398
static int mp_property_percent_pos(m_option_t *prop, int action,
399
                                   void *arg, MPContext *mpctx) {
400
    int pos;
401
402
    if (!mpctx->demuxer)
403
        return M_PROPERTY_UNAVAILABLE;
404
405
    switch(action) {
406
    case M_PROPERTY_SET:
407
        if(!arg) return M_PROPERTY_ERROR;
408
        M_PROPERTY_CLAMP(prop, *(int*)arg);
409
        pos = *(int*)arg;
410
        break;
411
    case M_PROPERTY_STEP_UP:
412
    case M_PROPERTY_STEP_DOWN:
413
        pos = demuxer_get_percent_pos(mpctx->demuxer);
414
        pos += (arg ? *(int*)arg : 10) *
415
            (action == M_PROPERTY_STEP_UP ? 1 : -1);
416
        M_PROPERTY_CLAMP(prop, pos);
417
        break;
418
    default:
419
        return m_property_int_ro(prop, action, arg,
420
                                 demuxer_get_percent_pos(mpctx->demuxer));
421
    }
422
423
    abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
424
    rel_seek_secs = pos / 100.0;
425
    return M_PROPERTY_OK;
426
}
427
428
/// Current position in seconds (RW)
429
static int mp_property_time_pos(m_option_t *prop, int action,
430
                                void *arg, MPContext *mpctx) {
431
    if (!(mpctx->sh_video || (mpctx->sh_audio && mpctx->audio_out)))
432
        return M_PROPERTY_UNAVAILABLE;
433
434
    switch(action) {
435
    case M_PROPERTY_SET:
436
        if(!arg) return M_PROPERTY_ERROR;
437
        M_PROPERTY_CLAMP(prop, *(double*)arg);
438
        abs_seek_pos = SEEK_ABSOLUTE;
439
        rel_seek_secs = *(double*)arg;
440
        return M_PROPERTY_OK;
441
    case M_PROPERTY_STEP_UP:
442
    case M_PROPERTY_STEP_DOWN:
443
        rel_seek_secs += (arg ? *(double*)arg : 10.0) *
444
            (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
445
        return M_PROPERTY_OK;
446
    }
447
    return m_property_time_ro(prop, action, arg,
448
                              mpctx->sh_video ? mpctx->sh_video->pts :
449
                              playing_audio_pts(mpctx->sh_audio,
450
                                                mpctx->d_audio,
451
                                                mpctx->audio_out));
452
}
453
454
/// Current chapter (RW)
455
static int mp_property_chapter(m_option_t *prop, int action, void *arg,
456
                               MPContext *mpctx)
457
{
458
    int chapter = -1;
459
    float next_pts = 0;
460
    int chapter_num;
461
    int step_all;
462
    char *chapter_name = NULL;
463
464
    if (mpctx->demuxer)
465
        chapter = demuxer_get_current_chapter(mpctx->demuxer);
466
    if (chapter < 0)
467
        return M_PROPERTY_UNAVAILABLE;
468
469
    switch (action) {
470
    case M_PROPERTY_GET:
471
        if (!arg)
472
            return M_PROPERTY_ERROR;
473
        *(int *) arg = chapter;
474
        return M_PROPERTY_OK;
475
    case M_PROPERTY_PRINT: {
476
        if (!arg)
477
            return M_PROPERTY_ERROR;
478
        chapter_name = demuxer_chapter_display_name(mpctx->demuxer, chapter);
479
        if (!chapter_name)
480
            return M_PROPERTY_UNAVAILABLE;
481
        *(char **) arg = chapter_name;
482
        return M_PROPERTY_OK;
483
    }
484
    case M_PROPERTY_SET:
485
        if (!arg)
486
            return M_PROPERTY_ERROR;
487
        M_PROPERTY_CLAMP(prop, *(int*)arg);
488
        step_all = *(int *)arg - chapter;
489
        chapter += step_all;
490
        break;
491
    case M_PROPERTY_STEP_UP:
492
    case M_PROPERTY_STEP_DOWN: {
493
        step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
494
                   * (action == M_PROPERTY_STEP_UP ? 1 : -1);
495
        chapter += step_all;
496
        if (chapter < 0)
497
            chapter = 0;
498
        break;
499
    }
500
    default:
501
        return M_PROPERTY_NOT_IMPLEMENTED;
502
    }
503
    rel_seek_secs = 0;
504
    abs_seek_pos = 0;
505
    chapter = demuxer_seek_chapter(mpctx->demuxer, chapter, 1,
506
                                   &next_pts, &chapter_num, &chapter_name);
507
    if (chapter >= 0) {
508
        if (next_pts > -1.0) {
509
            abs_seek_pos = SEEK_ABSOLUTE;
510
            rel_seek_secs = next_pts;
511
        }
512
        if (chapter_name)
513
            set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
514
                        MSGTR_OSDChapter, chapter + 1, chapter_name);
515
    }
516
    else if (step_all > 0)
517
        rel_seek_secs = 1000000000.;
518
    else
519
        set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
520
                    MSGTR_OSDChapter, 0, MSGTR_Unknown);
521
    free(chapter_name);
522
    return M_PROPERTY_OK;
523
}
524
525
/// Number of titles in file
526
static int mp_property_titles(m_option_t *prop, int action, void *arg,
527
                              MPContext *mpctx)
528
{
529
    if (!mpctx->demuxer)
530
        return M_PROPERTY_UNAVAILABLE;
531
    if (mpctx->demuxer->num_titles == 0)
532
        stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_NUM_TITLES, &mpctx->demuxer->num_titles);
533
    return m_property_int_ro(prop, action, arg, mpctx->demuxer->num_titles);
534
}
535
536
/// Number of chapters in file
537
static int mp_property_chapters(m_option_t *prop, int action, void *arg,
538
                               MPContext *mpctx)
539
{
540
    if (!mpctx->demuxer)
541
        return M_PROPERTY_UNAVAILABLE;
542
    if (mpctx->demuxer->num_chapters == 0)
543
        stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &mpctx->demuxer->num_chapters);
544
    return m_property_int_ro(prop, action, arg, mpctx->demuxer->num_chapters);
545
}
546
547
/// Current dvd angle (RW)
548
static int mp_property_angle(m_option_t *prop, int action, void *arg,
549
                               MPContext *mpctx)
550
{
551
    int angle = -1;
552
    int angles;
553
    char *angle_name = NULL;
554
555
    if (mpctx->demuxer)
556
        angle = demuxer_get_current_angle(mpctx->demuxer);
557
    if (angle < 0)
558
        return M_PROPERTY_UNAVAILABLE;
559
    angles = demuxer_angles_count(mpctx->demuxer);
560
    if (angles <= 1)
561
        return M_PROPERTY_UNAVAILABLE;
562
563
    switch (action) {
564
    case M_PROPERTY_GET:
565
        if (!arg)
566
            return M_PROPERTY_ERROR;
567
        *(int *) arg = angle;
568
        return M_PROPERTY_OK;
569
    case M_PROPERTY_PRINT: {
570
        if (!arg)
571
            return M_PROPERTY_ERROR;
572
        angle_name = calloc(1, 64);
573
        if (!angle_name)
574
            return M_PROPERTY_UNAVAILABLE;
575
        snprintf(angle_name, 64, "%d/%d", angle, angles);
576
        *(char **) arg = angle_name;
577
        return M_PROPERTY_OK;
578
    }
579
    case M_PROPERTY_SET:
580
        if (!arg)
581
            return M_PROPERTY_ERROR;
582
        angle = *(int *)arg;
583
        M_PROPERTY_CLAMP(prop, angle);
584
        break;
585
    case M_PROPERTY_STEP_UP:
586
    case M_PROPERTY_STEP_DOWN: {
587
        int step = 0;
588
        if(arg)
589
            step = *(int*)arg;
590
        if(!step)
591
            step = 1;
592
        step *= (action == M_PROPERTY_STEP_UP ? 1 : -1);
593
        angle += step;
594
        if (angle < 1) //cycle
595
            angle = angles;
596
        else if (angle > angles)
597
            angle = 1;
598
        break;
599
    }
600
    default:
601
        return M_PROPERTY_NOT_IMPLEMENTED;
602
    }
603
    angle = demuxer_set_angle(mpctx->demuxer, angle);
604
    set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
605
                        MSGTR_OSDAngle, angle, angles);
606
    free(angle_name);
607
    return M_PROPERTY_OK;
608
}
609
610
/// Demuxer meta data
611
static int mp_property_metadata(m_option_t *prop, int action, void *arg,
612
                                MPContext *mpctx) {
613
    m_property_action_t* ka;
614
    char* meta;
615
    static const m_option_t key_type =
616
        { "metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL };
617
    if (!mpctx->demuxer)
618
        return M_PROPERTY_UNAVAILABLE;
619
620
    switch(action) {
621
    case M_PROPERTY_GET:
622
        if(!arg) return M_PROPERTY_ERROR;
623
        *(char***)arg = mpctx->demuxer->info;
624
        return M_PROPERTY_OK;
625
    case M_PROPERTY_KEY_ACTION:
626
        if(!arg) return M_PROPERTY_ERROR;
627
        ka = arg;
628
        if(!(meta = demux_info_get(mpctx->demuxer,ka->key)))
629
            return M_PROPERTY_UNKNOWN;
630
        switch(ka->action) {
631
        case M_PROPERTY_GET:
632
            if(!ka->arg) return M_PROPERTY_ERROR;
633
            *(char**)ka->arg = meta;
634
            return M_PROPERTY_OK;
635
        case M_PROPERTY_GET_TYPE:
636
            if(!ka->arg) return M_PROPERTY_ERROR;
637
            *(const m_option_t**)ka->arg = &key_type;
638
            return M_PROPERTY_OK;
639
        }
640
    }
641
    return M_PROPERTY_NOT_IMPLEMENTED;
642
}
643
644
static int mp_property_pause(m_option_t *prop, int action, void *arg,
645
                             MPContext *mpctx)
646
{
647
    return m_property_flag_ro(prop, action, arg, mpctx->osd_function == OSD_PAUSE);
648
}
649
650
651
///@}
652
653
/// \defgroup AudioProperties Audio properties
654
/// \ingroup Properties
655
///@{
656
657
/// Volume (RW)
658
static int mp_property_volume(m_option_t *prop, int action, void *arg,
659
                              MPContext *mpctx)
660
{
661
662
    if (!mpctx->sh_audio)
663
        return M_PROPERTY_UNAVAILABLE;
664
665
    switch (action) {
666
    case M_PROPERTY_GET:
667
        if (!arg)
668
            return M_PROPERTY_ERROR;
669
        mixer_getbothvolume(&mpctx->mixer, arg);
670
        return M_PROPERTY_OK;
671
    case M_PROPERTY_PRINT:{
672
            float vol;
673
            if (!arg)
674
                return M_PROPERTY_ERROR;
675
            mixer_getbothvolume(&mpctx->mixer, &vol);
676
            return m_property_float_range(prop, action, arg, &vol);
677
        }
678
    case M_PROPERTY_STEP_UP:
679
    case M_PROPERTY_STEP_DOWN:
680
    case M_PROPERTY_SET:
681
        break;
682
    default:
683
        return M_PROPERTY_NOT_IMPLEMENTED;
684
    }
685
686
    if (mpctx->edl_muted)
687
        return M_PROPERTY_DISABLED;
688
    mpctx->user_muted = 0;
689
690
    switch (action) {
691
    case M_PROPERTY_SET:
692
        if (!arg)
693
            return M_PROPERTY_ERROR;
694
        M_PROPERTY_CLAMP(prop, *(float *) arg);
695
        mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg);
696
        return M_PROPERTY_OK;
697
    case M_PROPERTY_STEP_UP:
698
        if (arg && *(float *) arg <= 0)
699
            mixer_decvolume(&mpctx->mixer);
700
        else
701
            mixer_incvolume(&mpctx->mixer);
702
        return M_PROPERTY_OK;
703
    case M_PROPERTY_STEP_DOWN:
704
        if (arg && *(float *) arg <= 0)
705
            mixer_incvolume(&mpctx->mixer);
706
        else
707
            mixer_decvolume(&mpctx->mixer);
708
        return M_PROPERTY_OK;
709
    }
710
    return M_PROPERTY_NOT_IMPLEMENTED;
711
}
712
713
/// Mute (RW)
714
static int mp_property_mute(m_option_t *prop, int action, void *arg,
715
                            MPContext *mpctx)
716
{
717
718
    if (!mpctx->sh_audio)
719
        return M_PROPERTY_UNAVAILABLE;
720
721
    switch (action) {
722
    case M_PROPERTY_SET:
723
        if (mpctx->edl_muted)
724
            return M_PROPERTY_DISABLED;
725
        if (!arg)
726
            return M_PROPERTY_ERROR;
727
        if ((!!*(int *) arg) != mpctx->mixer.muted)
728
            mixer_mute(&mpctx->mixer);
729
        mpctx->user_muted = mpctx->mixer.muted;
730
        return M_PROPERTY_OK;
731
    case M_PROPERTY_STEP_UP:
732
    case M_PROPERTY_STEP_DOWN:
733
        if (mpctx->edl_muted)
734
            return M_PROPERTY_DISABLED;
735
        mixer_mute(&mpctx->mixer);
736
        mpctx->user_muted = mpctx->mixer.muted;
737
        return M_PROPERTY_OK;
738
    case M_PROPERTY_PRINT:
739
        if (!arg)
740
            return M_PROPERTY_ERROR;
741
        if (mpctx->edl_muted) {
742
            *(char **) arg = strdup(MSGTR_EnabledEdl);
743
            return M_PROPERTY_OK;
744
        }
745
    default:
746
        return m_property_flag(prop, action, arg, &mpctx->mixer.muted);
747
748
    }
749
}
750
751
/// Audio delay (RW)
752
static int mp_property_audio_delay(m_option_t *prop, int action,
753
                                   void *arg, MPContext *mpctx)
754
{
755
    if (!(mpctx->sh_audio && mpctx->sh_video))
756
        return M_PROPERTY_UNAVAILABLE;
757
    switch (action) {
758
    case M_PROPERTY_SET:
759
    case M_PROPERTY_STEP_UP:
760
    case M_PROPERTY_STEP_DOWN: {
761
            int ret;
762
            float delay = audio_delay;
763
            ret = m_property_delay(prop, action, arg, &audio_delay);
764
            if (ret != M_PROPERTY_OK)
765
                return ret;
766
            if (mpctx->sh_audio)
767
                mpctx->delay -= audio_delay - delay;
768
        }
769
        return M_PROPERTY_OK;
770
    default:
771
        return m_property_delay(prop, action, arg, &audio_delay);
772
    }
773
}
774
775
/// Audio codec tag (RO)
776
static int mp_property_audio_format(m_option_t *prop, int action,
777
                                    void *arg, MPContext *mpctx)
778
{
779
    if (!mpctx->sh_audio)
780
        return M_PROPERTY_UNAVAILABLE;
781
    return m_property_int_ro(prop, action, arg, mpctx->sh_audio->format);
782
}
783
784
/// Audio codec name (RO)
785
static int mp_property_audio_codec(m_option_t *prop, int action,
786
                                   void *arg, MPContext *mpctx)
787
{
788
    if (!mpctx->sh_audio || !mpctx->sh_audio->codec)
789
        return M_PROPERTY_UNAVAILABLE;
790
    return m_property_string_ro(prop, action, arg, mpctx->sh_audio->codec->name);
791
}
792
793
/// Audio bitrate (RO)
794
static int mp_property_audio_bitrate(m_option_t *prop, int action,
795
                                     void *arg, MPContext *mpctx)
796
{
797
    if (!mpctx->sh_audio)
798
        return M_PROPERTY_UNAVAILABLE;
799
    return m_property_bitrate(prop, action, arg, mpctx->sh_audio->i_bps);
800
}
801
802
/// Samplerate (RO)
803
static int mp_property_samplerate(m_option_t *prop, int action, void *arg,
804
                                  MPContext *mpctx)
805
{
806
    if (!mpctx->sh_audio)
807
        return M_PROPERTY_UNAVAILABLE;
808
    switch(action) {
809
    case M_PROPERTY_PRINT:
810
        if(!arg) return M_PROPERTY_ERROR;
811
        *(char**)arg = malloc(16);
812
        sprintf(*(char**)arg,"%d kHz",mpctx->sh_audio->samplerate/1000);
813
        return M_PROPERTY_OK;
814
    }
815
    return m_property_int_ro(prop, action, arg, mpctx->sh_audio->samplerate);
816
}
817
818
/// Number of channels (RO)
819
static int mp_property_channels(m_option_t *prop, int action, void *arg,
820
                                MPContext *mpctx)
821
{
822
    if (!mpctx->sh_audio)
823
        return M_PROPERTY_UNAVAILABLE;
824
    switch (action) {
825
    case M_PROPERTY_PRINT:
826
        if (!arg)
827
            return M_PROPERTY_ERROR;
828
        switch (mpctx->sh_audio->channels) {
829
        case 1:
830
            *(char **) arg = strdup("mono");
831
            break;
832
        case 2:
833
            *(char **) arg = strdup("stereo");
834
            break;
835
        default:
836
            *(char **) arg = malloc(32);
837
            sprintf(*(char **) arg, "%d channels", mpctx->sh_audio->channels);
838
        }
839
        return M_PROPERTY_OK;
840
    }
841
    return m_property_int_ro(prop, action, arg, mpctx->sh_audio->channels);
842
}
843
844
/// Balance (RW)
845
static int mp_property_balance(m_option_t *prop, int action, void *arg,
846
                              MPContext *mpctx)
847
{
848
    float bal;
849
850
    if (!mpctx->sh_audio || mpctx->sh_audio->channels < 2)
851
        return M_PROPERTY_UNAVAILABLE;
852
853
    switch (action) {
854
    case M_PROPERTY_GET:
855
        if (!arg)
856
            return M_PROPERTY_ERROR;
857
        mixer_getbalance(&mpctx->mixer, arg);
858
        return M_PROPERTY_OK;
859
    case M_PROPERTY_PRINT: {
860
            char** str = arg;
861
            if (!arg)
862
                return M_PROPERTY_ERROR;
863
            mixer_getbalance(&mpctx->mixer, &bal);
864
            if (bal == 0.f)
865
                *str = strdup("center");
866
            else if (bal == -1.f)
867
                *str = strdup("left only");
868
            else if (bal == 1.f)
869
                *str = strdup("right only");
870
            else {
871
                unsigned right = (bal + 1.f) / 2.f * 100.f;
872
                *str = malloc(sizeof("left xxx%, right xxx%"));
873
                sprintf(*str, "left %d%%, right %d%%", 100 - right, right);
874
            }
875
            return M_PROPERTY_OK;
876
        }
877
    case M_PROPERTY_STEP_UP:
878
    case M_PROPERTY_STEP_DOWN:
879
        mixer_getbalance(&mpctx->mixer, &bal);
880
        bal += (arg ? *(float*)arg : .1f) *
881
            (action == M_PROPERTY_STEP_UP ? 1.f : -1.f);
882
        M_PROPERTY_CLAMP(prop, bal);
883
        mixer_setbalance(&mpctx->mixer, bal);
884
        return M_PROPERTY_OK;
885
    case M_PROPERTY_SET:
886
        if (!arg)
887
            return M_PROPERTY_ERROR;
888
        M_PROPERTY_CLAMP(prop, *(float*)arg);
889
        mixer_setbalance(&mpctx->mixer, *(float*)arg);
890
        return M_PROPERTY_OK;
891
    }
892
    return M_PROPERTY_NOT_IMPLEMENTED;
893
}
894
895
/// Selected audio id (RW)
896
static int mp_property_audio(m_option_t *prop, int action, void *arg,
897
                             MPContext *mpctx)
898
{
899
    int current_id, tmp;
900
    if (!mpctx->demuxer || !mpctx->demuxer->audio)
901
        return M_PROPERTY_UNAVAILABLE;
902
    current_id = mpctx->demuxer->audio->id;
903
    if (current_id >= 0)
904
        audio_id = ((sh_audio_t *)mpctx->demuxer->a_streams[current_id])->aid;
905
906
    switch (action) {
907
    case M_PROPERTY_GET:
908
        if (!arg)
909
            return M_PROPERTY_ERROR;
910
        *(int *) arg = audio_id;
911
        return M_PROPERTY_OK;
912
    case M_PROPERTY_PRINT:
913
        if (!arg)
914
            return M_PROPERTY_ERROR;
915
916
        if (current_id < 0)
917
            *(char **) arg = strdup(MSGTR_Disabled);
918
        else {
919
            char lang[40] = MSGTR_Unknown;
920
            demuxer_audio_lang(mpctx->demuxer, current_id, lang, sizeof(lang));
921
            *(char **) arg = malloc(64);
922
            snprintf(*(char **) arg, 64, "(%d) %s", audio_id, lang);
923
        }
924
        return M_PROPERTY_OK;
925
926
    case M_PROPERTY_STEP_UP:
927
    case M_PROPERTY_SET:
928
        if (action == M_PROPERTY_SET && arg)
929
            tmp = *((int *) arg);
930
        else
931
            tmp = -1;
932
        tmp = demuxer_switch_audio(mpctx->demuxer, tmp);
933
        if (tmp == -2
934
            || (tmp > -1
935
                && mpctx->demuxer->audio->id != current_id && current_id != -2)) {
936
            uninit_player(INITIALIZED_AO | INITIALIZED_ACODEC);
937
            audio_id = tmp;
938
        }
939
        if (tmp > -1 && mpctx->demuxer->audio->id != current_id) {
940
            sh_audio_t *sh2;
941
            sh2 = mpctx->demuxer->a_streams[mpctx->demuxer->audio->id];
942
            if (sh2) {
943
                audio_id = sh2->aid;
944
                sh2->ds = mpctx->demuxer->audio;
945
                mpctx->sh_audio = sh2;
946
                reinit_audio_chain();
947
            }
948
        }
949
        mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_TRACK=%d\n", audio_id);
950
        return M_PROPERTY_OK;
951
    default:
952
        return M_PROPERTY_NOT_IMPLEMENTED;
953
    }
954
955
}
956
957
/// Selected video id (RW)
958
static int mp_property_video(m_option_t *prop, int action, void *arg,
959
                             MPContext *mpctx)
960
{
961
    int current_id, tmp;
962
    if (!mpctx->demuxer || !mpctx->demuxer->video)
963
        return M_PROPERTY_UNAVAILABLE;
964
    current_id = mpctx->demuxer->video->id;
965
    if (current_id >= 0)
966
        video_id = ((sh_video_t *)mpctx->demuxer->v_streams[current_id])->vid;
967
968
    switch (action) {
969
    case M_PROPERTY_GET:
970
        if (!arg)
971
            return M_PROPERTY_ERROR;
972
        *(int *) arg = video_id;
973
        return M_PROPERTY_OK;
974
    case M_PROPERTY_PRINT:
975
        if (!arg)
976
            return M_PROPERTY_ERROR;
977
978
        if (current_id < 0)
979
            *(char **) arg = strdup(MSGTR_Disabled);
980
        else {
981
            char lang[40] = MSGTR_Unknown;
982
            *(char **) arg = malloc(64);
983
            snprintf(*(char **) arg, 64, "(%d) %s", video_id, lang);
984
        }
985
        return M_PROPERTY_OK;
986
987
    case M_PROPERTY_STEP_UP:
988
    case M_PROPERTY_SET:
989
        if (action == M_PROPERTY_SET && arg)
990
            tmp = *((int *) arg);
991
        else
992
            tmp = -1;
993
        tmp = demuxer_switch_video(mpctx->demuxer, tmp);
994
        if (tmp == -2
995
            || (tmp > -1 && mpctx->demuxer->video->id != current_id
996
                && current_id != -2)) {
997
            uninit_player(INITIALIZED_VCODEC |
998
                          (fixed_vo && tmp != -2 ? 0 : INITIALIZED_VO));
999
            video_id = tmp;
1000
        }
1001
        if (tmp > -1 && mpctx->demuxer->video->id != current_id) {
1002
            sh_video_t *sh2;
1003
            sh2 = mpctx->demuxer->v_streams[mpctx->demuxer->video->id];
1004
            if (sh2) {
1005
                video_id = sh2->vid;
1006
                sh2->ds = mpctx->demuxer->video;
1007
                mpctx->sh_video = sh2;
1008
                reinit_video_chain();
1009
            }
1010
        }
1011
        mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_TRACK=%d\n", video_id);
1012
        return M_PROPERTY_OK;
1013
1014
    default:
1015
        return M_PROPERTY_NOT_IMPLEMENTED;
1016
    }
1017
}
1018
1019
static int mp_property_program(m_option_t *prop, int action, void *arg,
1020
                               MPContext *mpctx)
1021
{
1022
    demux_program_t prog;
1023
1024
    switch (action) {
1025
    case M_PROPERTY_STEP_UP:
1026
    case M_PROPERTY_SET:
1027
        if (action == M_PROPERTY_SET && arg)
1028
            prog.progid = *((int *) arg);
1029
        else
1030
            prog.progid = -1;
1031
        if (demux_control
1032
            (mpctx->demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM,
1033
             &prog) == DEMUXER_CTRL_NOTIMPL)
1034
            return M_PROPERTY_ERROR;
1035
1036
        if (prog.aid < 0 && prog.vid < 0) {
1037
            mp_msg(MSGT_CPLAYER, MSGL_ERR, "Selected program contains no audio or video streams!\n");
1038
            return M_PROPERTY_ERROR;
1039
        }
1040
        mp_property_do("switch_audio", M_PROPERTY_SET, &prog.aid, mpctx);
1041
        mp_property_do("switch_video", M_PROPERTY_SET, &prog.vid, mpctx);
1042
        return M_PROPERTY_OK;
1043
1044
    default:
1045
        return M_PROPERTY_NOT_IMPLEMENTED;
1046
    }
1047
}
1048
1049
///@}
1050
1051
/// \defgroup VideoProperties Video properties
1052
/// \ingroup Properties
1053
///@{
1054
1055
/// Fullscreen state (RW)
1056
static int mp_property_fullscreen(m_option_t *prop, int action, void *arg,
1057
                                  MPContext *mpctx)
1058
{
1059
1060
    if (!mpctx->video_out)
1061
        return M_PROPERTY_UNAVAILABLE;
1062
1063
    switch (action) {
1064
    case M_PROPERTY_SET:
1065
        if (!arg)
1066
            return M_PROPERTY_ERROR;
1067
        M_PROPERTY_CLAMP(prop, *(int *) arg);
1068
        if (vo_fs == !!*(int *) arg)
1069
            return M_PROPERTY_OK;
1070
    case M_PROPERTY_STEP_UP:
1071
    case M_PROPERTY_STEP_DOWN:
1072
#ifdef CONFIG_GUI
1073
        if (use_gui)
1074
            gui(GUI_RUN_COMMAND, (void *) MP_CMD_VO_FULLSCREEN);
1075
        else
1076
#endif
1077
        if (vo_config_count)
1078
            mpctx->video_out->control(VOCTRL_FULLSCREEN, 0);
1079
        return M_PROPERTY_OK;
1080
    default:
1081
        return m_property_flag(prop, action, arg, &vo_fs);
1082
    }
1083
}
1084
1085
static int mp_property_deinterlace(m_option_t *prop, int action,
1086
                                   void *arg, MPContext *mpctx)
1087
{
1088
    int deinterlace, deinterlace_old;
1089
    int result;
1090
    vf_instance_t *vf;
1091
    if (!mpctx->sh_video || !mpctx->sh_video->vfilter)
1092
        return M_PROPERTY_UNAVAILABLE;
1093
    vf = mpctx->sh_video->vfilter;
1094
    switch (action) {
1095
    case M_PROPERTY_GET:
1096
        if (!arg)
1097
            return M_PROPERTY_ERROR;
1098
        vf->control(vf, VFCTRL_GET_DEINTERLACE, arg);
1099
        return M_PROPERTY_OK;
1100
    case M_PROPERTY_SET:
1101
        if (!arg)
1102
            return M_PROPERTY_ERROR;
1103
        M_PROPERTY_CLAMP(prop, *(int *) arg);
1104
        result = vf->control(vf, VFCTRL_SET_DEINTERLACE, arg);
1105
        return (result == CONTROL_OK) ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE;
1106
    case M_PROPERTY_STEP_UP:
1107
    case M_PROPERTY_STEP_DOWN:
1108
        vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace_old);
1109
        deinterlace = !deinterlace_old;
1110
        result = vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace);
1111
        if (result != CONTROL_OK) {
1112
            deinterlace = deinterlace_old;
1113
        }
1114
        set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDDeinterlace,
1115
            deinterlace ? MSGTR_Enabled : MSGTR_Disabled);
1116
        return (result == CONTROL_OK) ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE;
1117
    }
1118
    return M_PROPERTY_NOT_IMPLEMENTED;
1119
}
1120
1121
static int mp_property_capture(m_option_t *prop, int action,
1122
                               void *arg, MPContext *mpctx)
1123
{
1124
    int ret;
1125
    int capturing = mpctx->stream && mpctx->stream->capture_file;
1126
1127
    if (!mpctx->stream)
1128
        return M_PROPERTY_UNAVAILABLE;
1129
    if (!capture_dump) {
1130
        mp_msg(MSGT_GLOBAL, MSGL_ERR,
1131
               "Capturing not enabled (forgot -capture parameter?)\n");
1132
        return M_PROPERTY_ERROR;
1133
    }
1134
1135
    ret = m_property_flag(prop, action, arg, &capturing);
1136
    if (ret == M_PROPERTY_OK && capturing != !!mpctx->stream->capture_file) {
1137
        if (capturing) {
1138
            mpctx->stream->capture_file = fopen(stream_dump_name, "ab");
1139
            if (!mpctx->stream->capture_file) {
1140
                mp_msg(MSGT_GLOBAL, MSGL_ERR,
1141
                       "Error opening capture file: %s\n", strerror(errno));
1142
                ret = M_PROPERTY_ERROR;
1143
            }
1144
        } else {
1145
            fclose(mpctx->stream->capture_file);
1146
            mpctx->stream->capture_file = NULL;
1147
        }
1148
    }
1149
1150
    switch (ret) {
1151
    case M_PROPERTY_ERROR:
1152
        set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDCapturingFailure);
1153
        break;
1154
    case M_PROPERTY_OK:
1155
        set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDCapturing,
1156
                    mpctx->stream->capture_file ? MSGTR_Enabled : MSGTR_Disabled);
1157
        break;
1158
    default:
1159
        break;
1160
    }
1161
1162
    return ret;
1163
}
1164
1165
/// Panscan (RW)
1166
static int mp_property_panscan(m_option_t *prop, int action, void *arg,
1167
                               MPContext *mpctx)
1168
{
1169
1170
    if (!mpctx->video_out
1171
        || mpctx->video_out->control(VOCTRL_GET_PANSCAN, NULL) != VO_TRUE)
1172
        return M_PROPERTY_UNAVAILABLE;
1173
1174
    switch (action) {
1175
    case M_PROPERTY_SET:
1176
        if (!arg)
1177
            return M_PROPERTY_ERROR;
1178
        M_PROPERTY_CLAMP(prop, *(float *) arg);
1179
        vo_panscan = *(float *) arg;
1180
        mpctx->video_out->control(VOCTRL_SET_PANSCAN, NULL);
1181
        return M_PROPERTY_OK;
1182
    case M_PROPERTY_STEP_UP:
1183
    case M_PROPERTY_STEP_DOWN:
1184
        vo_panscan += (arg ? *(float *) arg : 0.1) *
1185
            (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1186
        if (vo_panscan > 1)
1187
            vo_panscan = 1;
1188
        else if (vo_panscan < 0)
1189
            vo_panscan = 0;
1190
        mpctx->video_out->control(VOCTRL_SET_PANSCAN, NULL);
1191
        return M_PROPERTY_OK;
1192
    default:
1193
        return m_property_float_range(prop, action, arg, &vo_panscan);
1194
    }
1195
}
1196
1197
/// Helper to set vo flags.
1198
/** \ingroup PropertyImplHelper
1199
 */
1200
static int mp_property_vo_flag(m_option_t *prop, int action, void *arg,
1201
                               int vo_ctrl, int *vo_var, MPContext *mpctx)
1202
{
1203
1204
    if (!mpctx->video_out)
1205
        return M_PROPERTY_UNAVAILABLE;
1206
1207
    switch (action) {
1208
    case M_PROPERTY_SET:
1209
        if (!arg)
1210
            return M_PROPERTY_ERROR;
1211
        M_PROPERTY_CLAMP(prop, *(int *) arg);
1212
        if (*vo_var == !!*(int *) arg)
1213
            return M_PROPERTY_OK;
1214
    case M_PROPERTY_STEP_UP:
1215
    case M_PROPERTY_STEP_DOWN:
1216
        if (vo_config_count)
1217
            mpctx->video_out->control(vo_ctrl, 0);
1218
        return M_PROPERTY_OK;
1219
    default:
1220
        return m_property_flag(prop, action, arg, vo_var);
1221
    }
1222
}
1223
1224
/// Window always on top (RW)
1225
static int mp_property_ontop(m_option_t *prop, int action, void *arg,
1226
                             MPContext *mpctx)
1227
{
1228
    return mp_property_vo_flag(prop, action, arg, VOCTRL_ONTOP, &vo_ontop,
1229
                               mpctx);
1230
}
1231
1232
/// Display in the root window (RW)
1233
static int mp_property_rootwin(m_option_t *prop, int action, void *arg,
1234
                               MPContext *mpctx)
1235
{
1236
    return mp_property_vo_flag(prop, action, arg, VOCTRL_ROOTWIN,
1237
                               &vo_rootwin, mpctx);
1238
}
1239
1240
/// Show window borders (RW)
1241
static int mp_property_border(m_option_t *prop, int action, void *arg,
1242
                              MPContext *mpctx)
1243
{
1244
    return mp_property_vo_flag(prop, action, arg, VOCTRL_BORDER,
1245
                               &vo_border, mpctx);
1246
}
1247
1248
/// Framedropping state (RW)
1249
static int mp_property_framedropping(m_option_t *prop, int action,
1250
                                     void *arg, MPContext *mpctx)
1251
{
1252
1253
    if (!mpctx->sh_video)
1254
        return M_PROPERTY_UNAVAILABLE;
1255
1256
    switch (action) {
1257
    case M_PROPERTY_PRINT:
1258
        if (!arg)
1259
            return M_PROPERTY_ERROR;
1260
        *(char **) arg = strdup(frame_dropping == 1 ? MSGTR_Enabled :
1261
                                (frame_dropping == 2 ? MSGTR_HardFrameDrop :
1262
                                 MSGTR_Disabled));
1263
        return M_PROPERTY_OK;
1264
    default:
1265
        return m_property_choice(prop, action, arg, &frame_dropping);
1266
    }
1267
}
1268
1269
/// Color settings, try to use vf/vo then fall back on TV. (RW)
1270
static int mp_property_gamma(m_option_t *prop, int action, void *arg,
1271
                             MPContext *mpctx)
1272
{
1273
    int *gamma = prop->priv, r, val;
1274
1275
    if (!mpctx->sh_video)
1276
        return M_PROPERTY_UNAVAILABLE;
1277
1278
    if (gamma[0] == 1000) {
1279
        gamma[0] = 0;
1280
        get_video_colors(mpctx->sh_video, prop->name, gamma);
1281
    }
1282
1283
    switch (action) {
1284
    case M_PROPERTY_SET:
1285
        if (!arg)
1286
            return M_PROPERTY_ERROR;
1287
        M_PROPERTY_CLAMP(prop, *(int *) arg);
1288
        *gamma = *(int *) arg;
1289
        r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1290
        if (r <= 0)
1291
            break;
1292
        return r;
1293
    case M_PROPERTY_GET:
1294
        if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) {
1295
            if (!arg)
1296
                return M_PROPERTY_ERROR;
1297
            *(int *)arg = val;
1298
            return M_PROPERTY_OK;
1299
        }
1300
        break;
1301
    case M_PROPERTY_STEP_UP:
1302
    case M_PROPERTY_STEP_DOWN:
1303
        *gamma += (arg ? *(int *) arg : 1) *
1304
            (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1305
        M_PROPERTY_CLAMP(prop, *gamma);
1306
        r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1307
        if (r <= 0)
1308
            break;
1309
        return r;
1310
    default:
1311
        return M_PROPERTY_NOT_IMPLEMENTED;
1312
    }
1313
1314
#ifdef CONFIG_TV
1315
    if (mpctx->demuxer->type == DEMUXER_TYPE_TV) {
1316
        int l = strlen(prop->name);
1317
        char tv_prop[3 + l + 1];
1318
        sprintf(tv_prop, "tv_%s", prop->name);
1319
        return mp_property_do(tv_prop, action, arg, mpctx);
1320
    }
1321
#endif
1322
1323
    return M_PROPERTY_UNAVAILABLE;
1324
}
1325
1326
/// VSync (RW)
1327
static int mp_property_vsync(m_option_t *prop, int action, void *arg,
1328
                             MPContext *mpctx)
1329
{
1330
    return m_property_flag(prop, action, arg, &vo_vsync);
1331
}
1332
1333
/// Video codec tag (RO)
1334
static int mp_property_video_format(m_option_t *prop, int action,
1335
                                    void *arg, MPContext *mpctx)
1336
{
1337
    char* meta;
1338
    if (!mpctx->sh_video)
1339
        return M_PROPERTY_UNAVAILABLE;
1340
    switch(action) {
1341
    case M_PROPERTY_PRINT:
1342
        if (!arg)
1343
            return M_PROPERTY_ERROR;
1344
        switch(mpctx->sh_video->format) {
1345
        case 0x10000001:
1346
            meta = strdup ("mpeg1"); break;
1347
        case 0x10000002:
1348
            meta = strdup ("mpeg2"); break;
1349
        case 0x10000004:
1350
            meta = strdup ("mpeg4"); break;
1351
        case 0x10000005:
1352
            meta = strdup ("h264"); break;
1353
        default:
1354
            if(mpctx->sh_video->format >= 0x20202020) {
1355
                meta = malloc(5);
1356
                sprintf (meta, "%.4s", (char *) &mpctx->sh_video->format);
1357
            } else   {
1358
                meta = malloc(20);
1359
                sprintf (meta, "0x%08X", mpctx->sh_video->format);
1360
            }
1361
        }
1362
        *(char**)arg = meta;
1363
        return M_PROPERTY_OK;
1364
    }
1365
    return m_property_int_ro(prop, action, arg, mpctx->sh_video->format);
1366
}
1367
1368
/// Video codec name (RO)
1369
static int mp_property_video_codec(m_option_t *prop, int action,
1370
                                   void *arg, MPContext *mpctx)
1371
{
1372
    if (!mpctx->sh_video || !mpctx->sh_video->codec)
1373
        return M_PROPERTY_UNAVAILABLE;
1374
    return m_property_string_ro(prop, action, arg, mpctx->sh_video->codec->name);
1375
}
1376
1377
1378
/// Video bitrate (RO)
1379
static int mp_property_video_bitrate(m_option_t *prop, int action,
1380
                                     void *arg, MPContext *mpctx)
1381
{
1382
    if (!mpctx->sh_video)
1383
        return M_PROPERTY_UNAVAILABLE;
1384
    return m_property_bitrate(prop, action, arg, mpctx->sh_video->i_bps);
1385
}
1386
1387
/// Video display width (RO)
1388
static int mp_property_width(m_option_t *prop, int action, void *arg,
1389
                             MPContext *mpctx)
1390
{
1391
    if (!mpctx->sh_video)
1392
        return M_PROPERTY_UNAVAILABLE;
1393
    return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_w);
1394
}
1395
1396
/// Video display height (RO)
1397
static int mp_property_height(m_option_t *prop, int action, void *arg,
1398
                              MPContext *mpctx)
1399
{
1400
    if (!mpctx->sh_video)
1401
        return M_PROPERTY_UNAVAILABLE;
1402
    return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_h);
1403
}
1404
1405
/// Video fps (RO)
1406
static int mp_property_fps(m_option_t *prop, int action, void *arg,
1407
                           MPContext *mpctx)
1408
{
1409
    if (!mpctx->sh_video)
1410
        return M_PROPERTY_UNAVAILABLE;
1411
    return m_property_float_ro(prop, action, arg, mpctx->sh_video->fps);
1412
}
1413
1414
/// Video aspect (RO)
1415
static int mp_property_aspect(m_option_t *prop, int action, void *arg,
1416
                              MPContext *mpctx)
1417
{
1418
    if (!mpctx->sh_video)
1419
        return M_PROPERTY_UNAVAILABLE;
1420
    return m_property_float_ro(prop, action, arg, mpctx->sh_video->aspect);
1421
}
1422
1423
///@}
1424
1425
/// \defgroup SubProprties Subtitles properties
1426
/// \ingroup Properties
1427
///@{
1428
1429
/// Text subtitle position (RW)
1430
static int mp_property_sub_pos(m_option_t *prop, int action, void *arg,
1431
                               MPContext *mpctx)
1432
{
1433
    switch (action) {
1434
    case M_PROPERTY_SET:
1435
        if (!arg)
1436
            return M_PROPERTY_ERROR;
1437
    case M_PROPERTY_STEP_UP:
1438
    case M_PROPERTY_STEP_DOWN:
1439
        vo_osd_changed(OSDTYPE_SUBTITLE);
1440
    default:
1441
        return m_property_int_range(prop, action, arg, &sub_pos);
1442
    }
1443
}
1444
1445
/// Selected subtitles (RW)
1446
static int mp_property_sub(m_option_t *prop, int action, void *arg,
1447
                           MPContext *mpctx)
1448
{
1449
    demux_stream_t *const d_sub = mpctx->d_sub;
1450
    int global_sub_size;
1451
    int source = -1, reset_spu = 0;
1452
    int source_pos = -1;
1453
    double pts = 0;
1454
    char *sub_name;
1455
1456
    update_global_sub_size(mpctx);
1457
    global_sub_size = mpctx->global_sub_size;
1458
    if (global_sub_size <= 0)
1459
        return M_PROPERTY_UNAVAILABLE;
1460
1461
    switch (action) {
1462
    case M_PROPERTY_GET:
1463
        if (!arg)
1464
            return M_PROPERTY_ERROR;
1465
        *(int *) arg = mpctx->global_sub_pos;
1466
        return M_PROPERTY_OK;
1467
    case M_PROPERTY_PRINT:
1468
        if (!arg)
1469
            return M_PROPERTY_ERROR;
1470
        *(char **) arg = malloc(64);
1471
        (*(char **) arg)[63] = 0;
1472
        sub_name = 0;
1473
        if (subdata)
1474
            sub_name = subdata->filename;
1475
#ifdef CONFIG_ASS
1476
        if (ass_track && ass_track->name)
1477
            sub_name = ass_track->name;
1478
#endif
1479
        if (sub_name) {
1480
            const char *tmp = mp_basename(sub_name);
1481
1482
            snprintf(*(char **) arg, 63, "(%d) %s%s",
1483
                     mpctx->set_of_sub_pos + 1,
1484
                     strlen(tmp) < 20 ? "" : "...",
1485
                     strlen(tmp) < 20 ? tmp : tmp + strlen(tmp) - 19);
1486
            return M_PROPERTY_OK;
1487
        }
1488
1489
        if (vo_vobsub && vobsub_id >= 0) {
1490
            const char *language = MSGTR_Unknown;
1491
            language = vobsub_get_id(vo_vobsub, (unsigned int) vobsub_id);
1492
            snprintf(*(char **) arg, 63, "(%d) %s",
1493
                     vobsub_id, language ? language : MSGTR_Unknown);
1494
            return M_PROPERTY_OK;
1495
        }
1496
        if (dvdsub_id >= 0) {
1497
            char lang[40] = MSGTR_Unknown;
1498
            int id = dvdsub_id;
1499
            // HACK: for DVDs sub->sh/id will be invalid until
1500
            // we actually get the first packet
1501
            if (d_sub && d_sub->sh)
1502
                id = d_sub->id;
1503
            demuxer_sub_lang(mpctx->demuxer, id, lang, sizeof(lang));
1504
            snprintf(*(char **) arg, 63, "(%d) %s", dvdsub_id, lang);
1505
            return M_PROPERTY_OK;
1506
        }
1507
        snprintf(*(char **) arg, 63, MSGTR_Disabled);
1508
        return M_PROPERTY_OK;
1509
1510
    case M_PROPERTY_SET:
1511
        if (!arg)
1512
            return M_PROPERTY_ERROR;
1513
        if (*(int *) arg < -1)
1514
            *(int *) arg = -1;
1515
        else if (*(int *) arg >= global_sub_size)
1516
            *(int *) arg = global_sub_size - 1;
1517
        mpctx->global_sub_pos = *(int *) arg;
1518
        break;
1519
    case M_PROPERTY_STEP_UP:
1520
        mpctx->global_sub_pos += 2;
1521
        mpctx->global_sub_pos =
1522
            (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1523
        break;
1524
    case M_PROPERTY_STEP_DOWN:
1525
        mpctx->global_sub_pos += global_sub_size + 1;
1526
        mpctx->global_sub_pos =
1527
            (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1528
        break;
1529
    default:
1530
        return M_PROPERTY_NOT_IMPLEMENTED;
1531
    }
1532
1533
    if (mpctx->global_sub_pos >= 0) {
1534
        source = sub_source(mpctx);
1535
        source_pos = sub_source_pos(mpctx);
1536
    }
1537
1538
    mp_msg(MSGT_CPLAYER, MSGL_DBG3,
1539
           "subtitles: %d subs, (v@%d s@%d d@%d), @%d, source @%d\n",
1540
           global_sub_size,
1541
           mpctx->sub_counts[SUB_SOURCE_VOBSUB],
1542
           mpctx->sub_counts[SUB_SOURCE_SUBS],
1543
           mpctx->sub_counts[SUB_SOURCE_DEMUX],
1544
           mpctx->global_sub_pos, source);
1545
1546
    mpctx->set_of_sub_pos = -1;
1547
    subdata = NULL;
1548
1549
    vobsub_id = -1;
1550
    dvdsub_id = -1;
1551
    if (d_sub) {
1552
        if (d_sub->id > -2)
1553
            reset_spu = 1;
1554
        d_sub->id = -2;
1555
    }
1556
#ifdef CONFIG_ASS
1557
    ass_track = 0;
1558
#endif
1559
1560
    if (source == SUB_SOURCE_VOBSUB) {
1561
        vobsub_id = vobsub_get_id_by_index(vo_vobsub, source_pos);
1562
    } else if (source == SUB_SOURCE_SUBS) {
1563
        mpctx->set_of_sub_pos = source_pos;
1564
#ifdef CONFIG_ASS
1565
        if (ass_enabled && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos])
1566
            ass_track = mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos];
1567
        else
1568
#endif
1569
        {
1570
            subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos];
1571
            vo_osd_changed(OSDTYPE_SUBTITLE);
1572
        }
1573
    } else if (source == SUB_SOURCE_DEMUX) {
1574
        dvdsub_id = source_pos;
1575
        if (d_sub && dvdsub_id < MAX_S_STREAMS) {
1576
            int i = 0;
1577
            // default: assume 1:1 mapping of sid and stream id
1578
            d_sub->id = dvdsub_id;
1579
            d_sub->sh = mpctx->demuxer->s_streams[d_sub->id];
1580
            ds_free_packs(d_sub);
1581
            for (i = 0; i < MAX_S_STREAMS; i++) {
1582
                sh_sub_t *sh = mpctx->demuxer->s_streams[i];
1583
                if (sh && sh->sid == dvdsub_id) {
1584
                    d_sub->id = i;
1585
                    d_sub->sh = sh;
1586
                    break;
1587
                }
1588
            }
1589
            if (d_sub->sh && d_sub->id >= 0) {
1590
                sh_sub_t *sh = d_sub->sh;
1591
                if (sh->type == 'v')
1592
                    init_vo_spudec(mpctx->stream, mpctx->sh_video, sh);
1593
#ifdef CONFIG_ASS
1594
                else if (ass_enabled)
1595
                    ass_track = sh->ass_track;
1596
#endif
1597
            } else {
1598
              d_sub->id = -2;
1599
              d_sub->sh = NULL;
1600
            }
1601
        }
1602
    }
1603
#ifdef CONFIG_DVDREAD
1604
    if (vo_spudec
1605
        && (IS_STREAMTYPE(DVD)
1606
            || IS_STREAMTYPE(DVDNAV))
1607
        && dvdsub_id < 0 && reset_spu) {
1608
        d_sub->id = -2;
1609
        d_sub->sh = NULL;
1610
    }
1611
#endif
1612
    if (mpctx->sh_audio)
1613
        pts = mpctx->sh_audio->pts;
1614
    if (mpctx->sh_video)
1615
        pts = mpctx->sh_video->pts;
1616
    update_subtitles(mpctx->sh_video, pts, d_sub, 1);
1617
1618
    return M_PROPERTY_OK;
1619
}
1620
1621
/// Selected sub source (RW)
1622
static int mp_property_sub_source(m_option_t *prop, int action, void *arg,
1623
                                  MPContext *mpctx)
1624
{
1625
    int source;
1626
    update_global_sub_size(mpctx);
1627
    if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1628
        return M_PROPERTY_UNAVAILABLE;
1629
1630
    switch (action) {
1631
    case M_PROPERTY_GET:
1632
        if (!arg)
1633
            return M_PROPERTY_ERROR;
1634
        *(int *) arg = sub_source(mpctx);
1635
        return M_PROPERTY_OK;
1636
    case M_PROPERTY_PRINT:
1637
        if (!arg)
1638
            return M_PROPERTY_ERROR;
1639
        *(char **) arg = malloc(64);
1640
        (*(char **) arg)[63] = 0;
1641
        switch (sub_source(mpctx))
1642
        {
1643
        case SUB_SOURCE_SUBS:
1644
            snprintf(*(char **) arg, 63, MSGTR_SubSourceFile);
1645
            break;
1646
        case SUB_SOURCE_VOBSUB:
1647
            snprintf(*(char **) arg, 63, MSGTR_SubSourceVobsub);
1648
            break;
1649
        case SUB_SOURCE_DEMUX:
1650
            snprintf(*(char **) arg, 63, MSGTR_SubSourceDemux);
1651
            break;
1652
        default:
1653
            snprintf(*(char **) arg, 63, MSGTR_Disabled);
1654
        }
1655
        return M_PROPERTY_OK;
1656
    case M_PROPERTY_SET:
1657
        if (!arg)
1658
            return M_PROPERTY_ERROR;
1659
        M_PROPERTY_CLAMP(prop, *(int*)arg);
1660
        if (*(int *) arg < 0)
1661
            mpctx->global_sub_pos = -1;
1662
        else if (*(int *) arg != sub_source(mpctx)) {
1663
            int new_pos = sub_pos_by_source(mpctx, *(int *)arg);
1664
            if (new_pos == -1)
1665
                return M_PROPERTY_UNAVAILABLE;
1666
            mpctx->global_sub_pos = new_pos;
1667
        }
1668
        break;
1669
    case M_PROPERTY_STEP_UP:
1670
    case M_PROPERTY_STEP_DOWN: {
1671
        int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1672
                       * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1673
        int step = (step_all > 0) ? 1 : -1;
1674
        int cur_source = sub_source(mpctx);
1675
        source = cur_source;
1676
        while (step_all) {
1677
            source += step;
1678
            if (source >= SUB_SOURCES)
1679
                source = -1;
1680
            else if (source < -1)
1681
                source = SUB_SOURCES - 1;
1682
            if (source == cur_source || source == -1 ||
1683
                    mpctx->sub_counts[source])
1684
                step_all -= step;
1685
        }
1686
        if (source == cur_source)
1687
            return M_PROPERTY_OK;
1688
        if (source == -1)
1689
            mpctx->global_sub_pos = -1;
1690
        else
1691
            mpctx->global_sub_pos = sub_pos_by_source(mpctx, source);
1692
        break;
1693
    }
1694
    default:
1695
        return M_PROPERTY_NOT_IMPLEMENTED;
1696
    }
1697
    --mpctx->global_sub_pos;
1698
    return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx);
1699
}
1700
1701
/// Selected subtitles from specific source (RW)
1702
static int mp_property_sub_by_type(m_option_t *prop, int action, void *arg,
1703
                                   MPContext *mpctx)
1704
{
1705
    int source, is_cur_source, offset, new_pos;
1706
    update_global_sub_size(mpctx);
1707
    if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1708
        return M_PROPERTY_UNAVAILABLE;
1709
1710
    if (!strcmp(prop->name, "sub_file"))
1711
        source = SUB_SOURCE_SUBS;
1712
    else if (!strcmp(prop->name, "sub_vob"))
1713
        source = SUB_SOURCE_VOBSUB;
1714
    else if (!strcmp(prop->name, "sub_demux"))
1715
        source = SUB_SOURCE_DEMUX;
1716
    else
1717
        return M_PROPERTY_ERROR;
1718
1719
    offset = sub_pos_by_source(mpctx, source);
1720
    if (offset < 0)
1721
        return M_PROPERTY_UNAVAILABLE;
1722
1723
    is_cur_source = sub_source(mpctx) == source;
1724
    new_pos = mpctx->global_sub_pos;
1725
    switch (action) {
1726
    case M_PROPERTY_GET:
1727
        if (!arg)
1728
            return M_PROPERTY_ERROR;
1729
        if (is_cur_source) {
1730
            *(int *) arg = sub_source_pos(mpctx);
1731
            if (source == SUB_SOURCE_VOBSUB)
1732
                *(int *) arg = vobsub_get_id_by_index(vo_vobsub, *(int *) arg);
1733
        }
1734
        else
1735
            *(int *) arg = -1;
1736
        return M_PROPERTY_OK;
1737
    case M_PROPERTY_PRINT:
1738
        if (!arg)
1739
            return M_PROPERTY_ERROR;
1740
        if (is_cur_source)
1741
            return mp_property_sub(prop, M_PROPERTY_PRINT, arg, mpctx);
1742
        *(char **) arg = malloc(64);
1743
        (*(char **) arg)[63] = 0;
1744
        snprintf(*(char **) arg, 63, MSGTR_Disabled);
1745
        return M_PROPERTY_OK;
1746
    case M_PROPERTY_SET:
1747
        if (!arg)
1748
            return M_PROPERTY_ERROR;
1749
        if (*(int *) arg >= 0) {
1750
            int index = *(int *)arg;
1751
            if (source == SUB_SOURCE_VOBSUB)
1752
                index = vobsub_get_index_by_id(vo_vobsub, index);
1753
            new_pos = offset + index;
1754
            if (index < 0 || index > mpctx->sub_counts[source]) {
1755
                new_pos = -1;
1756
                *(int *) arg = -1;
1757
            }
1758
        }
1759
        else
1760
            new_pos = -1;
1761
        break;
1762
    case M_PROPERTY_STEP_UP:
1763
    case M_PROPERTY_STEP_DOWN: {
1764
        int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1765
                       * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1766
        int step = (step_all > 0) ? 1 : -1;
1767
        int max_sub_pos_for_source = -1;
1768
        if (!is_cur_source)
1769
            new_pos = -1;
1770
        while (step_all) {
1771
            if (new_pos == -1) {
1772
                if (step > 0)
1773
                    new_pos = offset;
1774
                else if (max_sub_pos_for_source == -1) {
1775
                    // Find max pos for specific source
1776
                    new_pos = mpctx->global_sub_size - 1;
1777
                    while (new_pos >= 0
1778
                            && sub_source(mpctx) != source)
1779
                        new_pos--;
1780
                    // cache for next time
1781
                    max_sub_pos_for_source = new_pos;
1782
                }
1783
                else
1784
                    new_pos = max_sub_pos_for_source;
1785
            }
1786
            else {
1787
                new_pos += step;
1788
                if (new_pos < offset ||
1789
                        new_pos >= mpctx->global_sub_size ||
1790
                        sub_source(mpctx) != source)
1791
                    new_pos = -1;
1792
            }
1793
            step_all -= step;
1794
        }
1795
        break;
1796
    }
1797
    default:
1798
        return M_PROPERTY_NOT_IMPLEMENTED;
1799
    }
1800
    return mp_property_sub(prop, M_PROPERTY_SET, &new_pos, mpctx);
1801
}
1802
1803
/// Subtitle delay (RW)
1804
static int mp_property_sub_delay(m_option_t *prop, int action, void *arg,
1805
                                 MPContext *mpctx)
1806
{
1807
    if (!mpctx->sh_video)
1808
        return M_PROPERTY_UNAVAILABLE;
1809
    return m_property_delay(prop, action, arg, &sub_delay);
1810
}
1811
1812
/// Alignment of text subtitles (RW)
1813
static int mp_property_sub_alignment(m_option_t *prop, int action,
1814
                                     void *arg, MPContext *mpctx)
1815
{
1816
    char *name[] = { MSGTR_Top, MSGTR_Center, MSGTR_Bottom };
1817
1818
    if (!mpctx->sh_video || mpctx->global_sub_pos < 0
1819
        || sub_source(mpctx) != SUB_SOURCE_SUBS)
1820
        return M_PROPERTY_UNAVAILABLE;
1821
1822
    switch (action) {
1823
    case M_PROPERTY_PRINT:
1824
        if (!arg)
1825
            return M_PROPERTY_ERROR;
1826
        M_PROPERTY_CLAMP(prop, sub_alignment);
1827
        *(char **) arg = strdup(name[sub_alignment]);
1828
        return M_PROPERTY_OK;
1829
    case M_PROPERTY_SET:
1830
        if (!arg)
1831
            return M_PROPERTY_ERROR;
1832
    case M_PROPERTY_STEP_UP:
1833
    case M_PROPERTY_STEP_DOWN:
1834
        vo_osd_changed(OSDTYPE_SUBTITLE);
1835
    default:
1836
        return m_property_choice(prop, action, arg, &sub_alignment);
1837
    }
1838
}
1839
1840
/// Subtitle visibility (RW)
1841
static int mp_property_sub_visibility(m_option_t *prop, int action,
1842
                                      void *arg, MPContext *mpctx)
1843
{
1844
    if (!mpctx->sh_video)
1845
        return M_PROPERTY_UNAVAILABLE;
1846
1847
    switch (action) {
1848
    case M_PROPERTY_SET:
1849
        if (!arg)
1850
            return M_PROPERTY_ERROR;
1851
    case M_PROPERTY_STEP_UP:
1852
    case M_PROPERTY_STEP_DOWN:
1853
        vo_osd_changed(OSDTYPE_SUBTITLE);
1854
        if (vo_spudec)
1855
            vo_osd_changed(OSDTYPE_SPU);
1856
    default:
1857
        return m_property_flag(prop, action, arg, &sub_visibility);
1858
    }
1859
}
1860
1861
#ifdef CONFIG_ASS
1862
/// Use margins for libass subtitles (RW)
1863
static int mp_property_ass_use_margins(m_option_t *prop, int action,
1864
                                      void *arg, MPContext *mpctx)
1865
{
1866
    if (!mpctx->sh_video)
1867
        return M_PROPERTY_UNAVAILABLE;
1868
1869
    switch (action) {
1870
    case M_PROPERTY_SET:
1871
        if (!arg)
1872
            return M_PROPERTY_ERROR;
1873
    case M_PROPERTY_STEP_UP:
1874
    case M_PROPERTY_STEP_DOWN:
1875
        ass_force_reload = 1;
1876
    default:
1877
        return m_property_flag(prop, action, arg, &ass_use_margins);
1878
    }
1879
}
1880
#endif
1881
1882
/// Show only forced subtitles (RW)
1883
static int mp_property_sub_forced_only(m_option_t *prop, int action,
1884
                                       void *arg, MPContext *mpctx)
1885
{
1886
    if (!vo_spudec)
1887
        return M_PROPERTY_UNAVAILABLE;
1888
1889
    switch (action) {
1890
    case M_PROPERTY_SET:
1891
        if (!arg)
1892
            return M_PROPERTY_ERROR;
1893
    case M_PROPERTY_STEP_UP:
1894
    case M_PROPERTY_STEP_DOWN:
1895
        m_property_flag(prop, action, arg, &forced_subs_only);
1896
        spudec_set_forced_subs_only(vo_spudec, forced_subs_only);
1897
        return M_PROPERTY_OK;
1898
    default:
1899
        return m_property_flag(prop, action, arg, &forced_subs_only);
1900
    }
1901
1902
}
1903
1904
#ifdef CONFIG_FREETYPE
1905
/// Subtitle scale (RW)
1906
static int mp_property_sub_scale(m_option_t *prop, int action, void *arg,
1907
                              MPContext *mpctx)
1908
{
1909
1910
    switch (action) {
1911
        case M_PROPERTY_SET:
1912
            if (!arg)
1913
                return M_PROPERTY_ERROR;
1914
            M_PROPERTY_CLAMP(prop, *(float *) arg);
1915
#ifdef CONFIG_ASS
1916
            if (ass_enabled) {
1917
                ass_font_scale = *(float *) arg;
1918
                ass_force_reload = 1;
1919
            }
1920
#endif
1921
            text_font_scale_factor = *(float *) arg;
1922
            force_load_font = 1;
1923
            vo_osd_changed(OSDTYPE_SUBTITLE);
1924
            return M_PROPERTY_OK;
1925
        case M_PROPERTY_STEP_UP:
1926
        case M_PROPERTY_STEP_DOWN:
1927
#ifdef CONFIG_ASS
1928
            if (ass_enabled) {
1929
                ass_font_scale += (arg ? *(float *) arg : 0.1)*
1930
                  (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1931
                M_PROPERTY_CLAMP(prop, ass_font_scale);
1932
                ass_force_reload = 1;
1933
            }
1934
#endif
1935
            text_font_scale_factor += (arg ? *(float *) arg : 0.1)*
1936
              (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1937
            M_PROPERTY_CLAMP(prop, text_font_scale_factor);
1938
            force_load_font = 1;
1939
            vo_osd_changed(OSDTYPE_SUBTITLE);
1940
            return M_PROPERTY_OK;
1941
        default:
1942
#ifdef CONFIG_ASS
1943
            if (ass_enabled)
1944
                return m_property_float_ro(prop, action, arg, ass_font_scale);
1945
            else
1946
#endif
1947
                return m_property_float_ro(prop, action, arg, text_font_scale_factor);
1948
    }
1949
}
1950
#endif
1951
1952
///@}
1953
1954
/// \defgroup TVProperties TV properties
1955
/// \ingroup Properties
1956
///@{
1957
1958
#ifdef CONFIG_TV
1959
1960
/// TV color settings (RW)
1961
static int mp_property_tv_color(m_option_t *prop, int action, void *arg,
1962
                                MPContext *mpctx)
1963
{
1964
    int r, val;
1965
    tvi_handle_t *tvh = mpctx->demuxer->priv;
1966
    if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1967
        return M_PROPERTY_UNAVAILABLE;
1968
1969
    switch (action) {
1970
    case M_PROPERTY_SET:
1971
        if (!arg)
1972
            return M_PROPERTY_ERROR;
1973
        M_PROPERTY_CLAMP(prop, *(int *) arg);
1974
        return tv_set_color_options(tvh, (intptr_t) prop->priv, *(int *) arg);
1975
    case M_PROPERTY_GET:
1976
        return tv_get_color_options(tvh, (intptr_t) prop->priv, arg);
1977
    case M_PROPERTY_STEP_UP:
1978
    case M_PROPERTY_STEP_DOWN:
1979
        if ((r = tv_get_color_options(tvh, (intptr_t) prop->priv, &val)) >= 0) {
1980
            if (!r)
1981
                return M_PROPERTY_ERROR;
1982
            val += (arg ? *(int *) arg : 1) *
1983
                (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1984
            M_PROPERTY_CLAMP(prop, val);
1985
            return tv_set_color_options(tvh, (intptr_t) prop->priv, val);
1986
        }
1987
        return M_PROPERTY_ERROR;
1988
    }
1989
    return M_PROPERTY_NOT_IMPLEMENTED;
1990
}
1991
1992
#endif
1993
1994
static int mp_property_teletext_common(m_option_t *prop, int action, void *arg,
1995
                  MPContext *mpctx)
1996
{
1997
    int val,result;
1998
    int base_ioctl=(intptr_t)prop->priv;
1999
    /*
2000
      for teletext's GET,SET,STEP ioctls this is not 0
2001
      SET is GET+1
2002
      STEP is GET+2
2003
    */
2004
    if (!mpctx->demuxer || !mpctx->demuxer->teletext)
2005
        return M_PROPERTY_UNAVAILABLE;
2006
    if(!base_ioctl)
2007
        return M_PROPERTY_ERROR;
2008
2009
    switch (action) {
2010
    case M_PROPERTY_GET:
2011
        if (!arg)
2012
            return M_PROPERTY_ERROR;
2013
        result=teletext_control(mpctx->demuxer->teletext, base_ioctl, arg);
2014
        break;
2015
    case M_PROPERTY_SET:
2016
        if (!arg)
2017
            return M_PROPERTY_ERROR;
2018
        M_PROPERTY_CLAMP(prop, *(int *) arg);
2019
        result=teletext_control(mpctx->demuxer->teletext, base_ioctl+1, arg);
2020
        break;
2021
    case M_PROPERTY_STEP_UP:
2022
    case M_PROPERTY_STEP_DOWN:
2023
        result=teletext_control(mpctx->demuxer->teletext, base_ioctl, &val);
2024
        val += (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
2025
        result=teletext_control(mpctx->demuxer->teletext, base_ioctl+1, &val);
2026
        break;
2027
    default:
2028
        return M_PROPERTY_NOT_IMPLEMENTED;
2029
    }
2030
2031
    return result == VBI_CONTROL_TRUE ? M_PROPERTY_OK : M_PROPERTY_ERROR;
2032
}
2033
2034
static int mp_property_teletext_mode(m_option_t *prop, int action, void *arg,
2035
                  MPContext *mpctx)
2036
{
2037
    int result;
2038
    int val;
2039
2040
    //with tvh==NULL will fail too
2041
    result=mp_property_teletext_common(prop,action,arg,mpctx);
2042
    if(result!=M_PROPERTY_OK)
2043
        return result;
2044
2045
    if(teletext_control(mpctx->demuxer->teletext,
2046
                        (intptr_t)prop->priv, &val)==VBI_CONTROL_TRUE && val)
2047
        mp_input_set_section("teletext");
2048
    else
2049
        mp_input_set_section("tv");
2050
    return M_PROPERTY_OK;
2051
}
2052
2053
static int mp_property_teletext_page(m_option_t *prop, int action, void *arg,
2054
                  MPContext *mpctx)
2055
{
2056
    int result;
2057
    int val;
2058
    if (!mpctx->demuxer->teletext)
2059
        return M_PROPERTY_UNAVAILABLE;
2060
    switch(action){
2061
    case M_PROPERTY_STEP_UP:
2062
    case M_PROPERTY_STEP_DOWN:
2063
        //This should be handled separately
2064
        val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
2065
        result=teletext_control(mpctx->demuxer->teletext,
2066
                                TV_VBI_CONTROL_STEP_PAGE, &val);
2067
        break;
2068
    default:
2069
        result=mp_property_teletext_common(prop,action,arg,mpctx);
2070
    }
2071
    return result;
2072
}
2073
2074
///@}
2075
2076
/// All properties available in MPlayer.
2077
/** \ingroup Properties
2078
 */
2079
static const m_option_t mp_properties[] = {
2080
    // General
2081
    { "osdlevel", mp_property_osdlevel, CONF_TYPE_INT,
2082
     M_OPT_RANGE, 0, 3, NULL },
2083
    { "loop", mp_property_loop, CONF_TYPE_INT,
2084
     M_OPT_MIN, -1, 0, NULL },
2085
    { "speed", mp_property_playback_speed, CONF_TYPE_FLOAT,
2086
     M_OPT_RANGE, 0.01, 100.0, NULL },
2087
    { "filename", mp_property_filename, CONF_TYPE_STRING,
2088
     0, 0, 0, NULL },
2089
    { "path", mp_property_path, CONF_TYPE_STRING,
2090
     0, 0, 0, NULL },
2091
    { "demuxer", mp_property_demuxer, CONF_TYPE_STRING,
2092
     0, 0, 0, NULL },
2093
    { "stream_pos", mp_property_stream_pos, CONF_TYPE_POSITION,
2094
     M_OPT_MIN, 0, 0, NULL },
2095
    { "stream_start", mp_property_stream_start, CONF_TYPE_POSITION,
2096
     M_OPT_MIN, 0, 0, NULL },
2097
    { "stream_end", mp_property_stream_end, CONF_TYPE_POSITION,
2098
     M_OPT_MIN, 0, 0, NULL },
2099
    { "stream_length", mp_property_stream_length, CONF_TYPE_POSITION,
2100
     M_OPT_MIN, 0, 0, NULL },
2101
    { "stream_time_pos", mp_property_stream_time_pos, CONF_TYPE_TIME,
2102
     M_OPT_MIN, 0, 0, NULL },
2103
    { "length", mp_property_length, CONF_TYPE_TIME,
2104
     M_OPT_MIN, 0, 0, NULL },
2105
    { "percent_pos", mp_property_percent_pos, CONF_TYPE_INT,
2106
     M_OPT_RANGE, 0, 100, NULL },
2107
    { "time_pos", mp_property_time_pos, CONF_TYPE_TIME,
2108
     M_OPT_MIN, 0, 0, NULL },
2109
    { "chapter", mp_property_chapter, CONF_TYPE_INT,
2110
     M_OPT_MIN, 0, 0, NULL },
2111
    { "titles", mp_property_titles, CONF_TYPE_INT,
2112
     0, 0, 0, NULL },
2113
    { "chapters", mp_property_chapters, CONF_TYPE_INT,
2114
     0, 0, 0, NULL },
2115
    { "angle", mp_property_angle, CONF_TYPE_INT,
2116
     CONF_RANGE, -2, 10, NULL },
2117
    { "metadata", mp_property_metadata, CONF_TYPE_STRING_LIST,
2118
     0, 0, 0, NULL },
2119
    { "pause", mp_property_pause, CONF_TYPE_FLAG,
2120
     M_OPT_RANGE, 0, 1, NULL },
2121
    { "capturing", mp_property_capture, CONF_TYPE_FLAG,
2122
     M_OPT_RANGE, 0, 1, NULL },
2123
2124
    // Audio
2125
    { "volume", mp_property_volume, CONF_TYPE_FLOAT,
2126
     M_OPT_RANGE, 0, 100, NULL },
2127
    { "mute", mp_property_mute, CONF_TYPE_FLAG,
2128
     M_OPT_RANGE, 0, 1, NULL },
2129
    { "audio_delay", mp_property_audio_delay, CONF_TYPE_FLOAT,
2130
     M_OPT_RANGE, -100, 100, NULL },
2131
    { "audio_format", mp_property_audio_format, CONF_TYPE_INT,
2132
     0, 0, 0, NULL },
2133
    { "audio_codec", mp_property_audio_codec, CONF_TYPE_STRING,
2134
     0, 0, 0, NULL },
2135
    { "audio_bitrate", mp_property_audio_bitrate, CONF_TYPE_INT,
2136
     0, 0, 0, NULL },
2137
    { "samplerate", mp_property_samplerate, CONF_TYPE_INT,
2138
     0, 0, 0, NULL },
2139
    { "channels", mp_property_channels, CONF_TYPE_INT,
2140
     0, 0, 0, NULL },
2141
    { "switch_audio", mp_property_audio, CONF_TYPE_INT,
2142
     CONF_RANGE, -2, 65535, NULL },
2143
    { "balance", mp_property_balance, CONF_TYPE_FLOAT,
2144
     M_OPT_RANGE, -1, 1, NULL },
2145
2146
    // Video
2147
    { "fullscreen", mp_property_fullscreen, CONF_TYPE_FLAG,
2148
     M_OPT_RANGE, 0, 1, NULL },
2149
    { "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG,
2150
     M_OPT_RANGE, 0, 1, NULL },
2151
    { "ontop", mp_property_ontop, CONF_TYPE_FLAG,
2152
     M_OPT_RANGE, 0, 1, NULL },
2153
    { "rootwin", mp_property_rootwin, CONF_TYPE_FLAG,
2154
     M_OPT_RANGE, 0, 1, NULL },
2155
    { "border", mp_property_border, CONF_TYPE_FLAG,
2156
     M_OPT_RANGE, 0, 1, NULL },
2157
    { "framedropping", mp_property_framedropping, CONF_TYPE_INT,
2158
     M_OPT_RANGE, 0, 2, NULL },
2159
    { "gamma", mp_property_gamma, CONF_TYPE_INT,
2160
     M_OPT_RANGE, -100, 100, &vo_gamma_gamma },
2161
    { "brightness", mp_property_gamma, CONF_TYPE_INT,
2162
     M_OPT_RANGE, -100, 100, &vo_gamma_brightness },
2163
    { "contrast", mp_property_gamma, CONF_TYPE_INT,
2164
     M_OPT_RANGE, -100, 100, &vo_gamma_contrast },
2165
    { "saturation", mp_property_gamma, CONF_TYPE_INT,
2166
     M_OPT_RANGE, -100, 100, &vo_gamma_saturation },
2167
    { "hue", mp_property_gamma, CONF_TYPE_INT,
2168
     M_OPT_RANGE, -100, 100, &vo_gamma_hue },
2169
    { "panscan", mp_property_panscan, CONF_TYPE_FLOAT,
2170
     M_OPT_RANGE, 0, 1, NULL },
2171
    { "vsync", mp_property_vsync, CONF_TYPE_FLAG,
2172
     M_OPT_RANGE, 0, 1, NULL },
2173
    { "video_format", mp_property_video_format, CONF_TYPE_INT,
2174
     0, 0, 0, NULL },
2175
    { "video_codec", mp_property_video_codec, CONF_TYPE_STRING,
2176
     0, 0, 0, NULL },
2177
    { "video_bitrate", mp_property_video_bitrate, CONF_TYPE_INT,
2178
     0, 0, 0, NULL },
2179
    { "width", mp_property_width, CONF_TYPE_INT,
2180
     0, 0, 0, NULL },
2181
    { "height", mp_property_height, CONF_TYPE_INT,
2182
     0, 0, 0, NULL },
2183
    { "fps", mp_property_fps, CONF_TYPE_FLOAT,
2184
     0, 0, 0, NULL },
2185
    { "aspect", mp_property_aspect, CONF_TYPE_FLOAT,
2186
     0, 0, 0, NULL },
2187
    { "switch_video", mp_property_video, CONF_TYPE_INT,
2188
     CONF_RANGE, -2, 65535, NULL },
2189
    { "switch_program", mp_property_program, CONF_TYPE_INT,
2190
     CONF_RANGE, -1, 65535, NULL },
2191
2192
    // Subs
2193
    { "sub", mp_property_sub, CONF_TYPE_INT,
2194
     M_OPT_MIN, -1, 0, NULL },
2195
    { "sub_source", mp_property_sub_source, CONF_TYPE_INT,
2196
     M_OPT_RANGE, -1, SUB_SOURCES - 1, NULL },
2197
    { "sub_vob", mp_property_sub_by_type, CONF_TYPE_INT,
2198
     M_OPT_MIN, -1, 0, NULL },
2199
    { "sub_demux", mp_property_sub_by_type, CONF_TYPE_INT,
2200
     M_OPT_MIN, -1, 0, NULL },
2201
    { "sub_file", mp_property_sub_by_type, CONF_TYPE_INT,
2202
     M_OPT_MIN, -1, 0, NULL },
2203
    { "sub_delay", mp_property_sub_delay, CONF_TYPE_FLOAT,
2204
     0, 0, 0, NULL },
2205
    { "sub_pos", mp_property_sub_pos, CONF_TYPE_INT,
2206
     M_OPT_RANGE, 0, 100, NULL },
2207
    { "sub_alignment", mp_property_sub_alignment, CONF_TYPE_INT,
2208
     M_OPT_RANGE, 0, 2, NULL },
2209
    { "sub_visibility", mp_property_sub_visibility, CONF_TYPE_FLAG,
2210
     M_OPT_RANGE, 0, 1, NULL },
2211
    { "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG,
2212
     M_OPT_RANGE, 0, 1, NULL },
2213
#ifdef CONFIG_FREETYPE
2214
    { "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT,
2215
     M_OPT_RANGE, 0, 100, NULL },
2216
#endif
2217
#ifdef CONFIG_ASS
2218
    { "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG,
2219
     M_OPT_RANGE, 0, 1, NULL },
2220
#endif
2221
2222
#ifdef CONFIG_TV
2223
    { "tv_brightness", mp_property_tv_color, CONF_TYPE_INT,
2224
     M_OPT_RANGE, -100, 100, (void *) TV_COLOR_BRIGHTNESS },
2225
    { "tv_contrast", mp_property_tv_color, CONF_TYPE_INT,
2226
     M_OPT_RANGE, -100, 100, (void *) TV_COLOR_CONTRAST },
2227
    { "tv_saturation", mp_property_tv_color, CONF_TYPE_INT,
2228
     M_OPT_RANGE, -100, 100, (void *) TV_COLOR_SATURATION },
2229
    { "tv_hue", mp_property_tv_color, CONF_TYPE_INT,
2230
     M_OPT_RANGE, -100, 100, (void *) TV_COLOR_HUE },
2231
#endif
2232
    { "teletext_page", mp_property_teletext_page, CONF_TYPE_INT,
2233
     M_OPT_RANGE, 100, 899,  (void*)TV_VBI_CONTROL_GET_PAGE },
2234
    { "teletext_subpage", mp_property_teletext_common, CONF_TYPE_INT,
2235
     M_OPT_RANGE, 0, 64, (void*)TV_VBI_CONTROL_GET_SUBPAGE },
2236
    { "teletext_mode", mp_property_teletext_mode, CONF_TYPE_FLAG,
2237
     M_OPT_RANGE, 0, 1, (void*)TV_VBI_CONTROL_GET_MODE },
2238
    { "teletext_format", mp_property_teletext_common, CONF_TYPE_INT,
2239
     M_OPT_RANGE, 0, 3, (void*)TV_VBI_CONTROL_GET_FORMAT },
2240
    { "teletext_half_page", mp_property_teletext_common, CONF_TYPE_INT,
2241
     M_OPT_RANGE, 0, 2, (void*)TV_VBI_CONTROL_GET_HALF_PAGE },
2242
    { NULL, NULL, NULL, 0, 0, 0, NULL }
2243
};
2244
2245
2246
int mp_property_do(const char *name, int action, void *val, void *ctx)
2247
{
2248
    return m_property_do(mp_properties, name, action, val, ctx);
2249
}
2250
2251
char* mp_property_print(const char *name, void* ctx)
2252
{
2253
    char* ret = NULL;
2254
    if(mp_property_do(name,M_PROPERTY_PRINT,&ret,ctx) <= 0)
2255
        return NULL;
2256
    return ret;
2257
}
2258
2259
char *property_expand_string(MPContext *mpctx, char *str)
2260
{
2261
    return m_properties_expand_string(mp_properties, str, mpctx);
2262
}
2263
2264
void property_print_help(void)
2265
{
2266
    m_properties_print_help_list(mp_properties);
2267
}
2268
2269
2270
///@}
2271
// Properties group
2272
2273
2274
/**
2275
 * \defgroup Command2Property Command to property bridge
2276
 *
2277
 * It is used to handle most commands that just set a property
2278
 * and optionally display something on the OSD.
2279
 * Two kinds of commands are handled: adjust or toggle.
2280
 *
2281
 * Adjust commands take 1 or 2 parameters: <value> <abs>
2282
 * If <abs> is non-zero the property is set to the given value
2283
 * otherwise it is adjusted.
2284
 *
2285
 * Toggle commands take 0 or 1 parameters. With no parameter
2286
 * or a value less than the property minimum it just steps the
2287
 * property to its next or previous value respectively.
2288
 * Otherwise it sets it to the given value.
2289
 *
2290
 *@{
2291
 */
2292
2293
/// List of the commands that can be handled by setting a property.
2294
static struct {
2295
    /// property name
2296
    const char *name;
2297
    /// cmd id
2298
    int cmd;
2299
    /// set/adjust or toggle command
2300
    int toggle;
2301
    /// progressbar type
2302
    int osd_progbar;
2303
    /// osd msg id if it must be shared
2304
    int osd_id;
2305
    /// osd msg template
2306
    const char *osd_msg;
2307
} set_prop_cmd[] = {
2308
    // general
2309
    { "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus },
2310
    { "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL },
2311
    { "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL },
2312
    { "capturing", MP_CMD_CAPTURING, 1, 0, -1, NULL },
2313
    // audio
2314
    { "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume },
2315
    { "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus },
2316
    { "audio_delay", MP_CMD_AUDIO_DELAY, 0, 0, -1, MSGTR_AVDelayStatus },
2317
    { "switch_audio", MP_CMD_SWITCH_AUDIO, 1, 0, -1, MSGTR_OSDAudio },
2318
    { "balance", MP_CMD_BALANCE, 0, OSD_BALANCE, -1, MSGTR_Balance },
2319
    // video
2320
    { "fullscreen", MP_CMD_VO_FULLSCREEN, 1, 0, -1, NULL },
2321
    { "panscan", MP_CMD_PANSCAN, 0, OSD_PANSCAN, -1, MSGTR_Panscan },
2322
    { "ontop", MP_CMD_VO_ONTOP, 1, 0, -1, MSGTR_OnTopStatus },
2323
    { "rootwin", MP_CMD_VO_ROOTWIN, 1, 0, -1, MSGTR_RootwinStatus },
2324
    { "border", MP_CMD_VO_BORDER, 1, 0, -1, MSGTR_BorderStatus },
2325
    { "framedropping", MP_CMD_FRAMEDROPPING, 1, 0, -1, MSGTR_FramedroppingStatus },
2326
    { "gamma", MP_CMD_GAMMA, 0, OSD_BRIGHTNESS, -1, MSGTR_Gamma },
2327
    { "brightness", MP_CMD_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2328
    { "contrast", MP_CMD_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2329
    { "saturation", MP_CMD_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2330
    { "hue", MP_CMD_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2331
    { "vsync", MP_CMD_SWITCH_VSYNC, 1, 0, -1, MSGTR_VSyncStatus },
2332
        // subs
2333
    { "sub", MP_CMD_SUB_SELECT, 1, 0, -1, MSGTR_SubSelectStatus },
2334
    { "sub_source", MP_CMD_SUB_SOURCE, 1, 0, -1, MSGTR_SubSourceStatus },
2335
    { "sub_vob", MP_CMD_SUB_VOB, 1, 0, -1, MSGTR_SubSelectStatus },
2336
    { "sub_demux", MP_CMD_SUB_DEMUX, 1, 0, -1, MSGTR_SubSelectStatus },
2337
    { "sub_file", MP_CMD_SUB_FILE, 1, 0, -1, MSGTR_SubSelectStatus },
2338
    { "sub_pos", MP_CMD_SUB_POS, 0, 0, -1, MSGTR_SubPosStatus },
2339
    { "sub_alignment", MP_CMD_SUB_ALIGNMENT, 1, 0, -1, MSGTR_SubAlignStatus },
2340
    { "sub_delay", MP_CMD_SUB_DELAY, 0, 0, OSD_MSG_SUB_DELAY, MSGTR_SubDelayStatus },
2341
    { "sub_visibility", MP_CMD_SUB_VISIBILITY, 1, 0, -1, MSGTR_SubVisibleStatus },
2342
    { "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1, 0, -1, MSGTR_SubForcedOnlyStatus },
2343
#ifdef CONFIG_FREETYPE
2344
    { "sub_scale", MP_CMD_SUB_SCALE, 0, 0, -1, MSGTR_SubScale},
2345
#endif
2346
#ifdef CONFIG_ASS
2347
    { "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1, 0, -1, NULL },
2348
#endif
2349
#ifdef CONFIG_TV
2350
    { "tv_brightness", MP_CMD_TV_SET_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2351
    { "tv_hue", MP_CMD_TV_SET_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2352
    { "tv_saturation", MP_CMD_TV_SET_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2353
    { "tv_contrast", MP_CMD_TV_SET_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2354
#endif
2355
    { NULL, 0, 0, 0, -1, NULL }
2356
};
2357
2358
2359
/// Handle commands that set a property.
2360
static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd)
2361
{
2362
    int i, r;
2363
    m_option_t *prop;
2364
    const char *pname;
2365
2366
    // look for the command
2367
    for (i = 0; set_prop_cmd[i].name; i++)
2368
        if (set_prop_cmd[i].cmd == cmd->id)
2369
            break;
2370
    if (!(pname = set_prop_cmd[i].name))
2371
        return 0;
2372
2373
    if (mp_property_do(pname,M_PROPERTY_GET_TYPE,&prop,mpctx) <= 0 || !prop)
2374
        return 0;
2375
2376
    // toggle command
2377
    if (set_prop_cmd[i].toggle) {
2378
        // set to value
2379
        if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min)
2380
            r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx);
2381
        else if (cmd->nargs > 0)
2382
            r = mp_property_do(pname, M_PROPERTY_STEP_DOWN, NULL, mpctx);
2383
        else
2384
            r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx);
2385
    } else if (cmd->args[1].v.i)        //set
2386
        r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx);
2387
    else                        // adjust
2388
        r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx);
2389
2390
    if (r <= 0)
2391
        return 1;
2392
2393
    if (set_prop_cmd[i].osd_progbar) {
2394
        if (prop->type == CONF_TYPE_INT) {
2395
            if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0)
2396
                set_osd_bar(set_prop_cmd[i].osd_progbar,
2397
                            set_prop_cmd[i].osd_msg, prop->min, prop->max, r);
2398
        } else if (prop->type == CONF_TYPE_FLOAT) {
2399
            float f;
2400
            if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0)
2401
                set_osd_bar(set_prop_cmd[i].osd_progbar,
2402
                            set_prop_cmd[i].osd_msg, prop->min, prop->max, f);
2403
        } else
2404
            mp_msg(MSGT_CPLAYER, MSGL_ERR,
2405
                   "Property use an unsupported type.\n");
2406
        return 1;
2407
    }
2408
2409
    if (set_prop_cmd[i].osd_msg) {
2410
        char *val = mp_property_print(pname, mpctx);
2411
        if (val) {
2412
            set_osd_msg(set_prop_cmd[i].osd_id >=
2413
                        0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i,
2414
                        1, osd_duration, set_prop_cmd[i].osd_msg, val);
2415
            free(val);
2416
        }
2417
    }
2418
    return 1;
2419
}
2420
2421
#ifdef CONFIG_DVDNAV
2422
static const struct {
2423
  const char *name;
2424
  const mp_command_type cmd;
2425
} mp_dvdnav_bindings[] = {
2426
  { "up",       MP_CMD_DVDNAV_UP              },
2427
  { "down",     MP_CMD_DVDNAV_DOWN            },
2428
  { "left",     MP_CMD_DVDNAV_LEFT            },
2429
  { "right",    MP_CMD_DVDNAV_RIGHT           },
2430
  { "menu",     MP_CMD_DVDNAV_MENU            },
2431
  { "select",   MP_CMD_DVDNAV_SELECT          },
2432
  { "prev",     MP_CMD_DVDNAV_PREVMENU        },
2433
  { "mouse",    MP_CMD_DVDNAV_MOUSECLICK      },
2434
2435
  /*
2436
   * keep old dvdnav sub-command options for a while in order not to
2437
   *  break slave-mode API too suddenly.
2438
   */
2439
  { "1",        MP_CMD_DVDNAV_UP              },
2440
  { "2",        MP_CMD_DVDNAV_DOWN            },
2441
  { "3",        MP_CMD_DVDNAV_LEFT            },
2442
  { "4",        MP_CMD_DVDNAV_RIGHT           },
2443
  { "5",        MP_CMD_DVDNAV_MENU            },
2444
  { "6",        MP_CMD_DVDNAV_SELECT          },
2445
  { "7",        MP_CMD_DVDNAV_PREVMENU        },
2446
  { "8",        MP_CMD_DVDNAV_MOUSECLICK      },
2447
  { NULL,       0                             }
2448
};
2449
#endif
2450
2451
static const char *property_error_string(int error_value)
2452
{
2453
    switch (error_value) {
2454
    case M_PROPERTY_ERROR:
2455
        return "ERROR";
2456
    case M_PROPERTY_UNAVAILABLE:
2457
        return "PROPERTY_UNAVAILABLE";
2458
    case M_PROPERTY_NOT_IMPLEMENTED:
2459
        return "NOT_IMPLEMENTED";
2460
    case M_PROPERTY_UNKNOWN:
2461
        return "PROPERTY_UNKNOWN";
2462
    case M_PROPERTY_DISABLED:
2463
        return "DISABLED";
2464
    }
2465
    return "UNKNOWN";
2466
}
2467
///@}
2468
2469
static void remove_subtitle_range(MPContext *mpctx, int start, int count)
2470
{
2471
    int idx;
2472
    int end = start + count;
2473
    int after = mpctx->set_of_sub_size - end;
2474
    sub_data **subs = mpctx->set_of_subtitles;
2475
#ifdef CONFIG_ASS
2476
    ASS_Track **ass_tracks = mpctx->set_of_ass_tracks;
2477
#endif
2478
    if (count < 0 || count > mpctx->set_of_sub_size ||
2479
        start < 0 || start > mpctx->set_of_sub_size - count) {
2480
        mp_msg(MSGT_CPLAYER, MSGL_ERR,
2481
               "Cannot remove invalid subtitle range %i +%i\n", start, count);
2482
        return;
2483
    }
2484
    for (idx = start; idx < end; idx++) {
2485
        sub_data *subd = subs[idx];
2486
        mp_msg(MSGT_CPLAYER, MSGL_STATUS,
2487
               MSGTR_RemovedSubtitleFile, idx + 1,
2488
               filename_recode(subd->filename));
2489
        sub_free(subd);
2490
        subs[idx] = NULL;
2491
#ifdef CONFIG_ASS
2492
        if (ass_tracks[idx])
2493
            ass_free_track(ass_tracks[idx]);
2494
        ass_tracks[idx] = NULL;
2495
#endif
2496
    }
2497
2498
    mpctx->global_sub_size -= count;
2499
    mpctx->set_of_sub_size -= count;
2500
    if (mpctx->set_of_sub_size <= 0)
2501
        mpctx->sub_counts[SUB_SOURCE_SUBS] = 0;
2502
2503
    memmove(subs + start, subs + end, after * sizeof(*subs));
2504
    memset(subs + start + after, 0, count * sizeof(*subs));
2505
#ifdef CONFIG_ASS
2506
    memmove(ass_tracks + start, ass_tracks + end, after * sizeof(*ass_tracks));
2507
    memset(ass_tracks + start + after, 0, count * sizeof(*ass_tracks));
2508
#endif
2509
2510
    if (mpctx->set_of_sub_pos >= start && mpctx->set_of_sub_pos < end) {
2511
        mpctx->global_sub_pos = -2;
2512
        subdata = NULL;
2513
#ifdef CONFIG_ASS
2514
        ass_track = NULL;
2515
#endif
2516
        mp_input_queue_cmd(mp_input_parse_cmd("sub_select"));
2517
    } else if (mpctx->set_of_sub_pos >= end) {
2518
        mpctx->set_of_sub_pos -= count;
2519
        mpctx->global_sub_pos -= count;
2520
    }
2521
}
2522
2523
static int overlay_source_registered = 0;
2524
static struct mp_eosd_source overlay_source = {
2525
    .z_index = 5,
2526
};
2527
2528
static void overlay_add(char *file, int id, int x, int y, unsigned col)
2529
{
2530
    FILE *f;
2531
    int w, h, bpp, maxval;
2532
    uint8_t *data;
2533
    struct mp_eosd_image *img;
2534
2535
    f = fopen(file, "rb");
2536
    if (!f) {
2537
        mp_msg(MSGT_CPLAYER, MSGL_ERR, "overlay_add: unable to open file.\n");
2538
        return;
2539
    }
2540
    data = read_pnm(f, &w, &h, &bpp, &maxval);
2541
    fclose(f);
2542
    if (!data) {
2543
        mp_msg(MSGT_CPLAYER, MSGL_ERR, "overlay_add: unable to load file.\n");
2544
        return;
2545
    }
2546
    if (bpp != 1 || maxval != 255) {
2547
        mp_msg(MSGT_CPLAYER, MSGL_ERR,
2548
               "overlay_add: file format not supported.\n");
2549
        return;
2550
    }
2551
    if (!overlay_source_registered) {
2552
        eosd_register(&overlay_source);
2553
        eosd_image_remove_all(&overlay_source);
2554
        overlay_source_registered = 1;
2555
    }
2556
    img = eosd_image_alloc();
2557
    img->w      = w;
2558
    img->h      = h;
2559
    img->stride = w;
2560
    img->bitmap = data;
2561
    img->color  = col ^ 0xFF; /* col is RGBA, img->color is RGBT */
2562
    img->dst_x  = x;
2563
    img->dst_y  = y;
2564
    img->opaque = (void *)(intptr_t)id;
2565
    eosd_image_append(&overlay_source, img);
2566
    overlay_source.changed = EOSD_CHANGED_BITMAP;
2567
}
2568
2569
static void overlay_remove(int id)
2570
{
2571
    struct mp_eosd_image *img, **prev, *next;
2572
    prev = &overlay_source.images;
2573
    img  = overlay_source.images;
2574
    while (img) {
2575
        next = img->next;
2576
        if ((intptr_t)img->opaque == id) {
2577
            free(img->bitmap);
2578
            eosd_image_remove(&overlay_source, img, prev);
2579
            overlay_source.changed = EOSD_CHANGED_BITMAP;
2580
        } else {
2581
            prev = &img->next;
2582
        }
2583
        img  = next;
2584
    }
2585
}
2586
2587
int run_command(MPContext *mpctx, mp_cmd_t *cmd)
2588
{
2589
    sh_audio_t * const sh_audio = mpctx->sh_audio;
2590
    sh_video_t * const sh_video = mpctx->sh_video;
2591
    int brk_cmd = 0;
2592
    if (!set_property_command(mpctx, cmd))
2593
        switch (cmd->id) {
2594
        case MP_CMD_SEEK:{
2595
                float v;
2596
                int abs;
2597
                if (sh_video)
2598
                    mpctx->osd_show_percentage = sh_video->fps;
2599
                v = cmd->args[0].v.f;
2600
                abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
2601
                if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */
2602
                    abs_seek_pos = SEEK_ABSOLUTE;
2603
                    if (sh_video)
2604
                        mpctx->osd_function =
2605
                            (v > sh_video->pts) ? OSD_FFW : OSD_REW;
2606
                    rel_seek_secs = v;
2607
                } else if (abs) {       /* Absolute seek by percentage */
2608
                    abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
2609
                    if (sh_video)
2610
                        mpctx->osd_function = OSD_FFW;  // Direction isn't set correctly
2611
                    rel_seek_secs = v / 100.0;
2612
                } else {
2613
                    rel_seek_secs += v;
2614
                    mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
2615
                }
2616
                brk_cmd = 1;
2617
            }
2618
            break;
2619
2620
        case MP_CMD_SET_PROPERTY:{
2621
                int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE,
2622
                                       cmd->args[1].v.s, mpctx);
2623
                if (r == M_PROPERTY_UNKNOWN)
2624
                    mp_msg(MSGT_CPLAYER, MSGL_WARN,
2625
                           "Unknown property: '%s'\n", cmd->args[0].v.s);
2626
                else if (r <= 0)
2627
                    mp_msg(MSGT_CPLAYER, MSGL_WARN,
2628
                           "Failed to set property '%s' to '%s'.\n",
2629
                           cmd->args[0].v.s, cmd->args[1].v.s);
2630
                if (r <= 0)
2631
                    mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r));
2632
            }
2633
            break;
2634
2635
        case MP_CMD_STEP_PROPERTY:{
2636
                void* arg = NULL;
2637
                int r,i;
2638
                double d;
2639
                off_t o;
2640
                if (cmd->args[1].v.f) {
2641
                    m_option_t *prop;
2642
                    if((r = mp_property_do(cmd->args[0].v.s,
2643
                                           M_PROPERTY_GET_TYPE,
2644
                                           &prop, mpctx)) <= 0)
2645
                        goto step_prop_err;
2646
                    if(prop->type == CONF_TYPE_INT ||
2647
                       prop->type == CONF_TYPE_FLAG)
2648
                        i = cmd->args[1].v.f, arg = &i;
2649
                    else if(prop->type == CONF_TYPE_FLOAT)
2650
                        arg = &cmd->args[1].v.f;
2651
                    else if(prop->type == CONF_TYPE_DOUBLE ||
2652
                            prop->type == CONF_TYPE_TIME)
2653
                        d = cmd->args[1].v.f, arg = &d;
2654
                    else if(prop->type == CONF_TYPE_POSITION)
2655
                        o = cmd->args[1].v.f, arg = &o;
2656
                    else
2657
                        mp_msg(MSGT_CPLAYER, MSGL_WARN,
2658
                               "Ignoring step size stepping property '%s'.\n",
2659
                               cmd->args[0].v.s);
2660
                }
2661
                r = mp_property_do(cmd->args[0].v.s,
2662
                                   cmd->args[2].v.i < 0 ?
2663
                                   M_PROPERTY_STEP_DOWN : M_PROPERTY_STEP_UP,
2664
                                   arg, mpctx);
2665
            step_prop_err:
2666
                if (r == M_PROPERTY_UNKNOWN)
2667
                    mp_msg(MSGT_CPLAYER, MSGL_WARN,
2668
                           "Unknown property: '%s'\n", cmd->args[0].v.s);
2669
                else if (r <= 0)
2670
                    mp_msg(MSGT_CPLAYER, MSGL_WARN,
2671
                           "Failed to increment property '%s' by %f.\n",
2672
                           cmd->args[0].v.s, cmd->args[1].v.f);
2673
                if (r <= 0)
2674
                    mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r));
2675
            }
2676
            break;
2677
2678
        case MP_CMD_GET_PROPERTY:{
2679
                char *tmp;
2680
                int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING,
2681
                                       &tmp, mpctx);
2682
                if (r <= 0) {
2683
                    mp_msg(MSGT_CPLAYER, MSGL_WARN,
2684
                           "Failed to get value of property '%s'.\n",
2685
                           cmd->args[0].v.s);
2686
                    mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r));
2687
                    break;
2688
                }
2689
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n",
2690
                       cmd->args[0].v.s, tmp);
2691
                free(tmp);
2692
            }
2693
            break;
2694
2695
        case MP_CMD_EDL_MARK:
2696
            if (edl_fd) {
2697
                float v = sh_video ? sh_video->pts :
2698
                    playing_audio_pts(sh_audio, mpctx->d_audio,
2699
                                      mpctx->audio_out);
2700
2701
                if (mpctx->begin_skip == MP_NOPTS_VALUE) {
2702
                    mpctx->begin_skip = v;
2703
                    mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutStartSkip);
2704
                } else {
2705
                    if (mpctx->begin_skip > v)
2706
                        mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_EdloutBadStop);
2707
                    else {
2708
                        double pts = edl_start_pts ? start_pts : 0;
2709
                        fprintf(edl_fd, "%f %f %d\n", mpctx->begin_skip - pts, v - pts, 0);
2710
                        mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutEndSkip);
2711
                    }
2712
                    mpctx->begin_skip = MP_NOPTS_VALUE;
2713
                }
2714
            }
2715
            break;
2716
2717
        case MP_CMD_SWITCH_RATIO:
2718
            if (!sh_video)
2719
                break;
2720
            if (cmd->nargs == 0 || cmd->args[0].v.f == -1)
2721
                movie_aspect = (float) sh_video->disp_w / sh_video->disp_h;
2722
            else
2723
                movie_aspect = cmd->args[0].v.f;
2724
            mpcodecs_config_vo(sh_video, sh_video->disp_w, sh_video->disp_h, 0);
2725
            break;
2726
2727
        case MP_CMD_SPEED_INCR:{
2728
                float v = cmd->args[0].v.f;
2729
                playback_speed += v;
2730
                reinit_audio_chain();
2731
                set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2732
                            playback_speed);
2733
            } break;
2734
2735
        case MP_CMD_SPEED_MULT:{
2736
                float v = cmd->args[0].v.f;
2737
                playback_speed *= v;
2738
                reinit_audio_chain();
2739
                set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2740
                            playback_speed);
2741
            } break;
2742
2743
        case MP_CMD_SPEED_SET:{
2744
                float v = cmd->args[0].v.f;
2745
                playback_speed = v;
2746
                reinit_audio_chain();
2747
                set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2748
                            playback_speed);
2749
            } break;
2750
2751
        case MP_CMD_FRAME_STEP:
2752
        case MP_CMD_PAUSE:
2753
            cmd->pausing = 1;
2754
            brk_cmd = 1;
2755
            break;
2756
2757
        case MP_CMD_FILE_FILTER:
2758
            file_filter = cmd->args[0].v.i;
2759
            break;
2760
2761
        case MP_CMD_QUIT:
2762
            exit_player_with_rc(EXIT_QUIT,
2763
                                (cmd->nargs > 0) ? cmd->args[0].v.i : 0);
2764
2765
        case MP_CMD_PLAY_TREE_STEP:{
2766
                int n = cmd->args[0].v.i == 0 ? 1 : cmd->args[0].v.i;
2767
                int force = cmd->args[1].v.i;
2768
2769
#ifdef CONFIG_GUI
2770
                if (use_gui) {
2771
                    int i = 0;
2772
                    if (n > 0)
2773
                        for (i = 0; i < n; i++)
2774
                            gui(GUI_RUN_COMMAND, (void *)MP_CMD_PLAY_TREE_STEP);
2775
                    else
2776
                        for (i = 0; i < -1 * n; i++)
2777
                            gui(GUI_RUN_COMMAND, (void *)-MP_CMD_PLAY_TREE_STEP);
2778
                } else
2779
#endif
2780
                {
2781
                    if (!force && mpctx->playtree_iter) {
2782
                        play_tree_iter_t *i =
2783
                            play_tree_iter_new_copy(mpctx->playtree_iter);
2784
                        if (play_tree_iter_step(i, n, 0) ==
2785
                            PLAY_TREE_ITER_ENTRY)
2786
                            mpctx->eof =
2787
                                (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2788
                        play_tree_iter_free(i);
2789
                    } else
2790
                        mpctx->eof = (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2791
                    if (mpctx->eof)
2792
                        mpctx->play_tree_step = n;
2793
                    brk_cmd = 1;
2794
                }
2795
            }
2796
            break;
2797
2798
        case MP_CMD_PLAY_TREE_UP_STEP:{
2799
                int n = cmd->args[0].v.i > 0 ? 1 : -1;
2800
                int force = cmd->args[1].v.i;
2801
2802
                if (!force && mpctx->playtree_iter) {
2803
                    play_tree_iter_t *i =
2804
                        play_tree_iter_new_copy(mpctx->playtree_iter);
2805
                    if (play_tree_iter_up_step(i, n, 0) == PLAY_TREE_ITER_ENTRY)
2806
                        mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2807
                    play_tree_iter_free(i);
2808
                } else
2809
                    mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2810
                brk_cmd = 1;
2811
            }
2812
            break;
2813
2814
        case MP_CMD_PLAY_ALT_SRC_STEP:
2815
            if (mpctx->playtree_iter && mpctx->playtree_iter->num_files > 1) {
2816
                int v = cmd->args[0].v.i;
2817
                if (v > 0
2818
                    && mpctx->playtree_iter->file <
2819
                    mpctx->playtree_iter->num_files)
2820
                    mpctx->eof = PT_NEXT_SRC;
2821
                else if (v < 0 && mpctx->playtree_iter->file > 1)
2822
                    mpctx->eof = PT_PREV_SRC;
2823
            }
2824
            brk_cmd = 1;
2825
            break;
2826
2827
        case MP_CMD_SUB_STEP:
2828
            if (sh_video) {
2829
                int movement = cmd->args[0].v.i;
2830
                step_sub(subdata, sh_video->pts, movement);
2831
#ifdef CONFIG_ASS
2832
                if (ass_track)
2833
                    sub_delay +=
2834
                        ass_step_sub(ass_track,
2835
                                     (sh_video->pts +
2836
                                      sub_delay) * 1000 + .5, movement) / 1000.;
2837
#endif
2838
                set_osd_msg(OSD_MSG_SUB_DELAY, 1, osd_duration,
2839
                            MSGTR_OSDSubDelay, ROUND(sub_delay * 1000));
2840
            }
2841
            break;
2842
2843
        case MP_CMD_SUB_LOG:
2844
            log_sub();
2845
            break;
2846
2847
        case MP_CMD_OSD:{
2848
                int v = cmd->args[0].v.i;
2849
                int max = (term_osd
2850
                           && !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL;
2851
                if (osd_level > max)
2852
                    osd_level = max;
2853
                if (v < 0)
2854
                    osd_level = (osd_level + 1) % (max + 1);
2855
                else
2856
                    osd_level = v > max ? max : v;
2857
                /* Show OSD state when disabled, but not when an explicit
2858
                   argument is given to the OSD command, i.e. in slave mode. */
2859
                if (v == -1 && osd_level <= 1)
2860
                    set_osd_msg(OSD_MSG_OSD_STATUS, 0, osd_duration,
2861
                                MSGTR_OSDosd,
2862
                                osd_level ? MSGTR_OSDenabled :
2863
                                MSGTR_OSDdisabled);
2864
                else
2865
                    rm_osd_msg(OSD_MSG_OSD_STATUS);
2866
            }
2867
            break;
2868
2869
        case MP_CMD_OSD_SHOW_TEXT:
2870
            set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2871
                        (cmd->args[1].v.i <
2872
                         0 ? osd_duration : cmd->args[1].v.i),
2873
                        "%-.63s", cmd->args[0].v.s);
2874
            break;
2875
2876
        case MP_CMD_OSD_SHOW_PROPERTY_TEXT:{
2877
                char *txt = m_properties_expand_string(mp_properties,
2878
                                                       cmd->args[0].v.s,
2879
                                                       mpctx);
2880
                /* if no argument supplied take default osd_duration, else <arg> ms. */
2881
                if (txt) {
2882
                    set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2883
                                (cmd->args[1].v.i <
2884
                                 0 ? osd_duration : cmd->args[1].v.i),
2885
                                "%-.63s", txt);
2886
                    free(txt);
2887
                }
2888
            }
2889
            break;
2890
2891
        case MP_CMD_LOADFILE:{
2892
                play_tree_t *e = play_tree_new();
2893
                play_tree_add_file(e, cmd->args[0].v.s);
2894
2895
                if (cmd->args[1].v.i)   // append
2896
                    play_tree_append_entry(mpctx->playtree->child, e);
2897
                else {
2898
                    // Go back to the starting point.
2899
                    while (play_tree_iter_up_step
2900
                           (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END)
2901
                        /* NOP */ ;
2902
                    play_tree_free_list(mpctx->playtree->child, 1);
2903
                    play_tree_set_child(mpctx->playtree, e);
2904
                    pt_iter_goto_head(mpctx->playtree_iter);
2905
                    mpctx->eof = PT_NEXT_SRC;
2906
                }
2907
                brk_cmd = 1;
2908
            }
2909
            break;
2910
2911
        case MP_CMD_LOADLIST:{
2912
                play_tree_t *e = parse_playlist_file(cmd->args[0].v.s);
2913
                if (!e)
2914
                    mp_msg(MSGT_CPLAYER, MSGL_ERR,
2915
                           MSGTR_PlaylistLoadUnable, cmd->args[0].v.s);
2916
                else {
2917
                    if (cmd->args[1].v.i)       // append
2918
                        play_tree_append_entry(mpctx->playtree->child, e);
2919
                    else {
2920
                        // Go back to the starting point.
2921
                        while (play_tree_iter_up_step
2922
                               (mpctx->playtree_iter, 0, 1)
2923
                               != PLAY_TREE_ITER_END)
2924
                            /* NOP */ ;
2925
                        play_tree_free_list(mpctx->playtree->child, 1);
2926
                        play_tree_set_child(mpctx->playtree, e);
2927
                        pt_iter_goto_head(mpctx->playtree_iter);
2928
                        mpctx->eof = PT_NEXT_SRC;
2929
                    }
2930
                }
2931
                brk_cmd = 1;
2932
            }
2933
            break;
2934
2935
        case MP_CMD_STOP:
2936
#ifdef CONFIG_GUI
2937
            // playtree_iter isn't used by the GUI
2938
            if (use_gui)
2939
                gui(GUI_RUN_COMMAND, (void *)MP_CMD_STOP);
2940
            else
2941
#endif
2942
            // Go back to the starting point.
2943
            while (play_tree_iter_up_step
2944
                   (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END)
2945
                /* NOP */ ;
2946
            mpctx->eof = PT_STOP;
2947
            brk_cmd = 1;
2948
            break;
2949
2950
        case MP_CMD_OSD_SHOW_PROGRESSION:{
2951
                int len = demuxer_get_time_length(mpctx->demuxer);
2952
                int pts = demuxer_get_current_time(mpctx->demuxer);
2953
                set_osd_bar(0, "Position", 0, 100, demuxer_get_percent_pos(mpctx->demuxer));
2954
                set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
2955
                            "%c %02d:%02d:%02d / %02d:%02d:%02d",
2956
                            mpctx->osd_function, pts/3600, (pts/60)%60, pts%60,
2957
                            len/3600, (len/60)%60, len%60);
2958
            }
2959
            break;
2960
2961
#ifdef CONFIG_RADIO
2962
        case MP_CMD_RADIO_STEP_CHANNEL:
2963
            if (IS_STREAMTYPE(RADIO)) {
2964
                int v = cmd->args[0].v.i;
2965
                if (v > 0)
2966
                    radio_step_channel(mpctx->demuxer->stream,
2967
                                       RADIO_CHANNEL_HIGHER);
2968
                else
2969
                    radio_step_channel(mpctx->demuxer->stream,
2970
                                       RADIO_CHANNEL_LOWER);
2971
                if (radio_get_channel_name(mpctx->demuxer->stream)) {
2972
                    set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2973
                                MSGTR_OSDChannel,
2974
                                radio_get_channel_name(mpctx->demuxer->stream));
2975
                }
2976
            }
2977
            break;
2978
2979
        case MP_CMD_RADIO_SET_CHANNEL:
2980
            if (IS_STREAMTYPE(RADIO)) {
2981
                radio_set_channel(mpctx->demuxer->stream, cmd->args[0].v.s);
2982
                if (radio_get_channel_name(mpctx->demuxer->stream)) {
2983
                    set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2984
                                MSGTR_OSDChannel,
2985
                                radio_get_channel_name(mpctx->demuxer->stream));
2986
                }
2987
            }
2988
            break;
2989
2990
        case MP_CMD_RADIO_SET_FREQ:
2991
            if (IS_STREAMTYPE(RADIO))
2992
                radio_set_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2993
            break;
2994
2995
        case MP_CMD_RADIO_STEP_FREQ:
2996
            if (IS_STREAMTYPE(RADIO))
2997
                radio_step_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2998
            break;
2999
#endif
3000
3001
#ifdef CONFIG_TV
3002
        case MP_CMD_TV_START_SCAN:
3003
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3004
                tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv),1);
3005
            break;
3006
        case MP_CMD_TV_SET_FREQ:
3007
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3008
                tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
3009
                            cmd->args[0].v.f * 16.0);
3010
#ifdef CONFIG_PVR
3011
            else if (IS_STREAMTYPE(PVR)) {
3012
              pvr_set_freq (mpctx->stream, ROUND (cmd->args[0].v.f));
3013
              set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
3014
                           pvr_get_current_channelname (mpctx->stream),
3015
                           pvr_get_current_stationname (mpctx->stream));
3016
            }
3017
#endif /* CONFIG_PVR */
3018
            break;
3019
3020
        case MP_CMD_TV_STEP_FREQ:
3021
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3022
                tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
3023
                            cmd->args[0].v.f * 16.0);
3024
#ifdef CONFIG_PVR
3025
            else if (IS_STREAMTYPE(PVR)) {
3026
              pvr_force_freq_step (mpctx->stream, ROUND (cmd->args[0].v.f));
3027
              set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d",
3028
                           pvr_get_current_channelname (mpctx->stream),
3029
                           pvr_get_current_frequency (mpctx->stream));
3030
            }
3031
#endif /* CONFIG_PVR */
3032
            break;
3033
3034
        case MP_CMD_TV_SET_NORM:
3035
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3036
                tv_set_norm((tvi_handle_t *) (mpctx->demuxer->priv),
3037
                            cmd->args[0].v.s);
3038
            break;
3039
3040
        case MP_CMD_TV_STEP_CHANNEL:{
3041
                if (mpctx->file_format == DEMUXER_TYPE_TV) {
3042
                    int v = cmd->args[0].v.i;
3043
                    if (v > 0) {
3044
                        tv_step_channel((tvi_handle_t *) (mpctx->
3045
                                                          demuxer->priv),
3046
                                        TV_CHANNEL_HIGHER);
3047
                    } else {
3048
                        tv_step_channel((tvi_handle_t *) (mpctx->
3049
                                                          demuxer->priv),
3050
                                        TV_CHANNEL_LOWER);
3051
                    }
3052
                    if (tv_channel_list) {
3053
                        set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
3054
                                    MSGTR_OSDChannel, tv_channel_current->name);
3055
                        //vo_osd_changed(OSDTYPE_SUBTITLE);
3056
                    }
3057
                }
3058
#ifdef CONFIG_PVR
3059
                else if (IS_STREAMTYPE(PVR)) {
3060
                  pvr_set_channel_step (mpctx->stream, cmd->args[0].v.i);
3061
                  set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
3062
                               pvr_get_current_channelname (mpctx->stream),
3063
                               pvr_get_current_stationname (mpctx->stream));
3064
                }
3065
#endif /* CONFIG_PVR */
3066
            }
3067
#ifdef CONFIG_DVBIN
3068
            if (IS_STREAMTYPE(DVB)) {
3069
                    int dir;
3070
                    int v = cmd->args[0].v.i;
3071
3072
                    mpctx->last_dvb_step = v;
3073
                    if (v > 0)
3074
                        dir = DVB_CHANNEL_HIGHER;
3075
                    else
3076
                        dir = DVB_CHANNEL_LOWER;
3077
3078
3079
                    if (dvb_step_channel(mpctx->stream, dir))
3080
                        mpctx->eof = mpctx->dvbin_reopen = 1;
3081
            }
3082
#endif /* CONFIG_DVBIN */
3083
            break;
3084
3085
        case MP_CMD_TV_SET_CHANNEL:
3086
            if (mpctx->file_format == DEMUXER_TYPE_TV) {
3087
                tv_set_channel((tvi_handle_t *) (mpctx->demuxer->priv),
3088
                               cmd->args[0].v.s);
3089
                if (tv_channel_list) {
3090
                    set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
3091
                                MSGTR_OSDChannel, tv_channel_current->name);
3092
                    //vo_osd_changed(OSDTYPE_SUBTITLE);
3093
                }
3094
            }
3095
#ifdef CONFIG_PVR
3096
            else if (IS_STREAMTYPE(PVR)) {
3097
              pvr_set_channel (mpctx->stream, cmd->args[0].v.s);
3098
              set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
3099
                           pvr_get_current_channelname (mpctx->stream),
3100
                           pvr_get_current_stationname (mpctx->stream));
3101
            }
3102
#endif /* CONFIG_PVR */
3103
            break;
3104
3105
#ifdef CONFIG_DVBIN
3106
        case MP_CMD_DVB_SET_CHANNEL:
3107
            if (IS_STREAMTYPE(DVB)) {
3108
                        mpctx->last_dvb_step = 1;
3109
3110
                    if (dvb_set_channel
3111
                        (mpctx->stream, cmd->args[1].v.i, cmd->args[0].v.i))
3112
                        mpctx->eof = mpctx->dvbin_reopen = 1;
3113
            }
3114
            break;
3115
#endif /* CONFIG_DVBIN */
3116
3117
        case MP_CMD_TV_LAST_CHANNEL:
3118
            if (mpctx->file_format == DEMUXER_TYPE_TV) {
3119
                tv_last_channel((tvi_handle_t *) (mpctx->demuxer->priv));
3120
                if (tv_channel_list) {
3121
                    set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
3122
                                MSGTR_OSDChannel, tv_channel_current->name);
3123
                    //vo_osd_changed(OSDTYPE_SUBTITLE);
3124
                }
3125
            }
3126
#ifdef CONFIG_PVR
3127
            else if (IS_STREAMTYPE(PVR)) {
3128
              pvr_set_lastchannel (mpctx->stream);
3129
              set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
3130
                           pvr_get_current_channelname (mpctx->stream),
3131
                           pvr_get_current_stationname (mpctx->stream));
3132
            }
3133
#endif /* CONFIG_PVR */
3134
            break;
3135
3136
        case MP_CMD_TV_STEP_NORM:
3137
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3138
                tv_step_norm((tvi_handle_t *) (mpctx->demuxer->priv));
3139
            break;
3140
3141
        case MP_CMD_TV_STEP_CHANNEL_LIST:
3142
            if (mpctx->file_format == DEMUXER_TYPE_TV)
3143
                tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv));
3144
            break;
3145
#endif /* CONFIG_TV */
3146
        case MP_CMD_TV_TELETEXT_ADD_DEC:
3147
            if (mpctx->demuxer->teletext)
3148
                teletext_control(mpctx->demuxer->teletext,TV_VBI_CONTROL_ADD_DEC,
3149
                                 &(cmd->args[0].v.s));
3150
            break;
3151
        case MP_CMD_TV_TELETEXT_GO_LINK:
3152
            if (mpctx->demuxer->teletext)
3153
                teletext_control(mpctx->demuxer->teletext,TV_VBI_CONTROL_GO_LINK,
3154
                                 &(cmd->args[0].v.i));
3155
            break;
3156
3157
        case MP_CMD_OVERLAY_ADD:
3158
            overlay_add(cmd->args[0].v.s, cmd->args[1].v.i,
3159
                        cmd->args[2].v.i, cmd->args[3].v.i, cmd->args[4].v.i);
3160
            break;
3161
        case MP_CMD_OVERLAY_REMOVE:
3162
            overlay_remove(cmd->args[0].v.i);
3163
            break;
3164
3165
        case MP_CMD_SUB_LOAD:
3166
            if (sh_video) {
3167
                int n = mpctx->set_of_sub_size;
3168
                add_subtitles(cmd->args[0].v.s, sh_video->fps, 0);
3169
                if (n != mpctx->set_of_sub_size) {
3170
                    mpctx->sub_counts[SUB_SOURCE_SUBS]++;
3171
                    ++mpctx->global_sub_size;
3172
                }
3173
            }
3174
            break;
3175
3176
        case MP_CMD_SUB_REMOVE:
3177
            if (sh_video) {
3178
                int v = cmd->args[0].v.i;
3179
                if (v < 0) {
3180
                    remove_subtitle_range(mpctx, 0, mpctx->set_of_sub_size);
3181
                } else if (v < mpctx->set_of_sub_size) {
3182
                    remove_subtitle_range(mpctx, v, 1);
3183
                }
3184
            }
3185
            break;
3186
3187
        case MP_CMD_GET_SUB_VISIBILITY:
3188
            if (sh_video) {
3189
                mp_msg(MSGT_GLOBAL, MSGL_INFO,
3190
                       "ANS_SUB_VISIBILITY=%d\n", sub_visibility);
3191
            }
3192
            break;
3193
3194
        case MP_CMD_SCREENSHOT:
3195
            if (vo_config_count) {
3196
                mp_msg(MSGT_CPLAYER, MSGL_INFO, "sending VFCTRL_SCREENSHOT!\n");
3197
                if (CONTROL_OK !=
3198
                    ((vf_instance_t *) sh_video->vfilter)->
3199
                    control(sh_video->vfilter, VFCTRL_SCREENSHOT,
3200
                            &cmd->args[0].v.i))
3201
                    mp_msg(MSGT_CPLAYER, MSGL_INFO, "failed (forgot -vf screenshot?)\n");
3202
            }
3203
            break;
3204
3205
        case MP_CMD_VF_CHANGE_RECTANGLE:
3206
            if (!sh_video)
3207
                break;
3208
            set_rectangle(sh_video, cmd->args[0].v.i, cmd->args[1].v.i);
3209
            break;
3210
3211
        case MP_CMD_GET_TIME_LENGTH:{
3212
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_LENGTH=%.2f\n",
3213
                       demuxer_get_time_length(mpctx->demuxer));
3214
            }
3215
            break;
3216
3217
        case MP_CMD_GET_FILENAME:{
3218
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_FILENAME='%s'\n",
3219
                       get_metadata(META_NAME));
3220
            }
3221
            break;
3222
3223
        case MP_CMD_GET_VIDEO_CODEC:{
3224
                char *inf = get_metadata(META_VIDEO_CODEC);
3225
                if (!inf)
3226
                    inf = strdup("");
3227
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_CODEC='%s'\n", inf);
3228
                free(inf);
3229
            }
3230
            break;
3231
3232
        case MP_CMD_GET_VIDEO_BITRATE:{
3233
                char *inf = get_metadata(META_VIDEO_BITRATE);
3234
                if (!inf)
3235
                    inf = strdup("");
3236
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_BITRATE='%s'\n", inf);
3237
                free(inf);
3238
            }
3239
            break;
3240
3241
        case MP_CMD_GET_VIDEO_RESOLUTION:{
3242
                char *inf = get_metadata(META_VIDEO_RESOLUTION);
3243
                if (!inf)
3244
                    inf = strdup("");
3245
                mp_msg(MSGT_GLOBAL, MSGL_INFO,
3246
                       "ANS_VIDEO_RESOLUTION='%s'\n", inf);
3247
                free(inf);
3248
            }
3249
            break;
3250
3251
        case MP_CMD_GET_AUDIO_CODEC:{
3252
                char *inf = get_metadata(META_AUDIO_CODEC);
3253
                if (!inf)
3254
                    inf = strdup("");
3255
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_CODEC='%s'\n", inf);
3256
                free(inf);
3257
            }
3258
            break;
3259
3260
        case MP_CMD_GET_AUDIO_BITRATE:{
3261
                char *inf = get_metadata(META_AUDIO_BITRATE);
3262
                if (!inf)
3263
                    inf = strdup("");
3264
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_BITRATE='%s'\n", inf);
3265
                free(inf);
3266
            }
3267
            break;
3268
3269
        case MP_CMD_GET_AUDIO_SAMPLES:{
3270
                char *inf = get_metadata(META_AUDIO_SAMPLES);
3271
                if (!inf)
3272
                    inf = strdup("");
3273
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_SAMPLES='%s'\n", inf);
3274
                free(inf);
3275
            }
3276
            break;
3277
3278
        case MP_CMD_GET_META_TITLE:{
3279
                char *inf = get_metadata(META_INFO_TITLE);
3280
                if (!inf)
3281
                    inf = strdup("");
3282
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TITLE='%s'\n", inf);
3283
                free(inf);
3284
            }
3285
            break;
3286
3287
        case MP_CMD_GET_META_ARTIST:{
3288
                char *inf = get_metadata(META_INFO_ARTIST);
3289
                if (!inf)
3290
                    inf = strdup("");
3291
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ARTIST='%s'\n", inf);
3292
                free(inf);
3293
            }
3294
            break;
3295
3296
        case MP_CMD_GET_META_ALBUM:{
3297
                char *inf = get_metadata(META_INFO_ALBUM);
3298
                if (!inf)
3299
                    inf = strdup("");
3300
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ALBUM='%s'\n", inf);
3301
                free(inf);
3302
            }
3303
            break;
3304
3305
        case MP_CMD_GET_META_YEAR:{
3306
                char *inf = get_metadata(META_INFO_YEAR);
3307
                if (!inf)
3308
                    inf = strdup("");
3309
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_YEAR='%s'\n", inf);
3310
                free(inf);
3311
            }
3312
            break;
3313
3314
        case MP_CMD_GET_META_COMMENT:{
3315
                char *inf = get_metadata(META_INFO_COMMENT);
3316
                if (!inf)
3317
                    inf = strdup("");
3318
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_COMMENT='%s'\n", inf);
3319
                free(inf);
3320
            }
3321
            break;
3322
3323
        case MP_CMD_GET_META_TRACK:{
3324
                char *inf = get_metadata(META_INFO_TRACK);
3325
                if (!inf)
3326
                    inf = strdup("");
3327
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TRACK='%s'\n", inf);
3328
                free(inf);
3329
            }
3330
            break;
3331
3332
        case MP_CMD_GET_META_GENRE:{
3333
                char *inf = get_metadata(META_INFO_GENRE);
3334
                if (!inf)
3335
                    inf = strdup("");
3336
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_GENRE='%s'\n", inf);
3337
                free(inf);
3338
            }
3339
            break;
3340
3341
        case MP_CMD_GET_VO_FULLSCREEN:
3342
            if (mpctx->video_out && vo_config_count)
3343
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VO_FULLSCREEN=%d\n", vo_fs);
3344
            break;
3345
3346
        case MP_CMD_GET_PERCENT_POS:
3347
            mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_PERCENT_POSITION=%d\n",
3348
                   demuxer_get_percent_pos(mpctx->demuxer));
3349
            break;
3350
3351
        case MP_CMD_GET_TIME_POS:{
3352
                float pos = 0;
3353
                if (sh_video)
3354
                    pos = sh_video->pts;
3355
                else if (sh_audio && mpctx->audio_out)
3356
                    pos =
3357
                        playing_audio_pts(sh_audio, mpctx->d_audio,
3358
                                          mpctx->audio_out);
3359
                mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_TIME_POSITION=%.1f\n", pos);
3360
            }
3361
            break;
3362
3363
        case MP_CMD_RUN:
3364
#ifndef __MINGW32__
3365
            if (!fork()) {
3366
                char *exp_cmd = property_expand_string(mpctx, cmd->args[0].v.s);
3367
                if (exp_cmd) {
3368
                    execl("/bin/sh", "sh", "-c", exp_cmd, NULL);
3369
                    free(exp_cmd);
3370
                }
3371
                exit(0);
3372
            }
3373
#endif
3374
            break;
3375
3376
        case MP_CMD_KEYDOWN_EVENTS:
3377
            mplayer_put_key(cmd->args[0].v.i);
3378
            break;
3379
3380
        case MP_CMD_SET_MOUSE_POS:{
3381
                int pointer_x, pointer_y;
3382
                double dx, dy;
3383
                pointer_x = cmd->args[0].v.i;
3384
                pointer_y = cmd->args[1].v.i;
3385
                rescale_input_coordinates(pointer_x, pointer_y, &dx, &dy);
3386
#ifdef CONFIG_DVDNAV
3387
                if (IS_STREAMTYPE(DVDNAV)
3388
                    && dx > 0.0 && dy > 0.0) {
3389
                    int button = -1;
3390
                    pointer_x = (int) (dx * (double) sh_video->disp_w);
3391
                    pointer_y = (int) (dy * (double) sh_video->disp_h);
3392
                    mp_dvdnav_update_mouse_pos(mpctx->stream,
3393
                                               pointer_x, pointer_y, &button);
3394
                    if (osd_level > 1 && button > 0)
3395
                        set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3396
                                    "Selected button number %d", button);
3397
                }
3398
#endif
3399
#ifdef CONFIG_MENU
3400
                if (use_menu && dx >= 0.0 && dy >= 0.0)
3401
                    menu_update_mouse_pos(dx, dy);
3402
#endif
3403
            }
3404
            break;
3405
3406
#ifdef CONFIG_DVDNAV
3407
        case MP_CMD_DVDNAV:{
3408
                int button = -1;
3409
                int i;
3410
                mp_command_type command = 0;
3411
                if (!IS_STREAMTYPE(DVDNAV))
3412
                    break;
3413
3414
                for (i = 0; mp_dvdnav_bindings[i].name; i++)
3415
                  if (cmd->args[0].v.s &&
3416
                      !strcasecmp (cmd->args[0].v.s,
3417
                                   mp_dvdnav_bindings[i].name))
3418
                    command = mp_dvdnav_bindings[i].cmd;
3419
3420
                mp_dvdnav_handle_input(mpctx->stream,command,&button);
3421
                if (osd_level > 1 && button > 0)
3422
                    set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3423
                                "Selected button number %d", button);
3424
            }
3425
            break;
3426
3427
        case MP_CMD_SWITCH_TITLE:
3428
            if (IS_STREAMTYPE(DVDNAV))
3429
                mp_dvdnav_switch_title(mpctx->stream, cmd->args[0].v.i);
3430
            break;
3431
3432
#endif
3433
3434
    case MP_CMD_AF_SWITCH:
3435
        if (sh_audio)
3436
        {
3437
            af_uninit(mpctx->mixer.afilter);
3438
            af_init(mpctx->mixer.afilter);
3439
        }
3440
    case MP_CMD_AF_ADD:
3441
    case MP_CMD_AF_DEL:
3442
        if (!sh_audio)
3443
            break;
3444
        {
3445
            char* af_args = strdup(cmd->args[0].v.s);
3446
            char* af_commands = af_args;
3447
            char* af_command;
3448
            af_instance_t* af;
3449
            while ((af_command = strsep(&af_commands, ",")) != NULL)
3450
            {
3451
                if (cmd->id == MP_CMD_AF_DEL)
3452
                {
3453
                    af = af_get(mpctx->mixer.afilter, af_command);
3454
                    if (af != NULL)
3455
                        af_remove(mpctx->mixer.afilter, af);
3456
                }
3457
                else
3458
                    af_add(mpctx->mixer.afilter, af_command);
3459
            }
3460
            reinit_audio_chain();
3461
            free(af_args);
3462
        }
3463
        break;
3464
    case MP_CMD_AF_CLR:
3465
        if (!sh_audio)
3466
            break;
3467
        af_uninit(mpctx->mixer.afilter);
3468
        af_init(mpctx->mixer.afilter);
3469
        reinit_audio_chain();
3470
        break;
3471
    case MP_CMD_AF_CMDLINE:
3472
        if (sh_audio) {
3473
            af_instance_t *af = af_get(sh_audio->afilter, cmd->args[0].v.s);
3474
            if (!af) {
3475
                mp_msg(MSGT_CPLAYER, MSGL_WARN,
3476
                       "Filter '%s' not found in chain.\n", cmd->args[0].v.s);
3477
                break;
3478
            }
3479
            af->control(af, AF_CONTROL_COMMAND_LINE, cmd->args[1].v.s);
3480
            af_reinit(sh_audio->afilter, af);
3481
        }
3482
        break;
3483
3484
        default:
3485
#ifdef CONFIG_GUI
3486
                if (use_gui && cmd->id == MP_CMD_GUI)
3487
                    gui(GUI_RUN_MESSAGE, cmd->args[0].v.s);
3488
                else
3489
#endif
3490
                mp_msg(MSGT_CPLAYER, MSGL_V,
3491
                       "Received unknown cmd %s\n", cmd->name);
3492
        }
3493
3494
    switch (cmd->pausing) {
3495
    case 1:     // "pausing"
3496
        mpctx->osd_function = OSD_PAUSE;
3497
        break;
3498
    case 3:     // "pausing_toggle"
3499
        mpctx->was_paused = !mpctx->was_paused;
3500
        if (mpctx->was_paused)
3501
            mpctx->osd_function = OSD_PAUSE;
3502
        else if (mpctx->osd_function == OSD_PAUSE)
3503
            mpctx->osd_function = OSD_PLAY;
3504
        break;
3505
    case 2:     // "pausing_keep"
3506
        if (mpctx->was_paused)
3507
            mpctx->osd_function = OSD_PAUSE;
3508
    }
3509
    return brk_cmd;
3510
}