Merge svn changes up to r28310
[mplayer.git] / command.c
blob6487a8b346281422ecee1d162ae927364cb737c4
1 #include <stdlib.h>
2 #include <inttypes.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <stdbool.h>
7 #include "config.h"
8 #include "command.h"
9 #include "input/input.h"
10 #include "stream/stream.h"
11 #include "libmpdemux/demuxer.h"
12 #include "libmpdemux/stheader.h"
13 #include "codec-cfg.h"
14 #include "mplayer.h"
15 #include "libvo/sub.h"
16 #include "m_option.h"
17 #include "m_property.h"
18 #include "help_mp.h"
19 #include "metadata.h"
20 #include "libmpcodecs/vf.h"
21 #include "libmpcodecs/vd.h"
22 #include "mp_osd.h"
23 #include "libvo/video_out.h"
24 #include "libvo/font_load.h"
25 #include "playtree.h"
26 #include "libao2/audio_out.h"
27 #include "mpcommon.h"
28 #include "mixer.h"
29 #include "libmpcodecs/dec_video.h"
30 #include "vobsub.h"
31 #include "spudec.h"
32 #include "get_path.h"
33 #ifdef CONFIG_TV
34 #include "stream/tv.h"
35 #endif
36 #ifdef CONFIG_RADIO
37 #include "stream/stream_radio.h"
38 #endif
39 #ifdef CONFIG_PVR
40 #include "stream/pvr.h"
41 #endif
42 #ifdef CONFIG_DVBIN
43 #include "stream/dvbin.h"
44 #endif
45 #ifdef CONFIG_DVDREAD
46 #include "stream/stream_dvd.h"
47 #endif
48 #ifdef CONFIG_DVDNAV
49 #include "stream/stream_dvdnav.h"
50 #endif
51 #ifdef CONFIG_ASS
52 #include "libass/ass.h"
53 #include "libass/ass_mp.h"
54 #endif
55 #ifdef CONFIG_MENU
56 #include "m_struct.h"
57 #include "libmenu/menu.h"
58 #endif
59 #ifdef CONFIG_GUI
60 #include "gui/interface.h"
61 #endif
63 #include "mp_core.h"
64 #include "mp_fifo.h"
65 #include "libavutil/avstring.h"
67 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
69 extern int use_menu;
71 static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy,
72 double *dx, double *dy)
74 struct MPOpts *opts = &mpctx->opts;
75 struct vo *vo = mpctx->video_out;
76 //remove the borders, if any, and rescale to the range [0,1],[0,1]
77 if (vo_fs) { //we are in full-screen mode
78 if (opts->vo_screenwidth > vo->dwidth) //there are borders along the x axis
79 ix -= (opts->vo_screenwidth - vo->dwidth) / 2;
80 if (opts->vo_screenheight > vo->dheight) //there are borders along the y axis (usual way)
81 iy -= (opts->vo_screenheight - vo->dheight) / 2;
83 if (ix < 0 || ix > vo->dwidth) {
84 *dx = *dy = -1.0;
85 return;
86 } //we are on one of the borders
87 if (iy < 0 || iy > vo->dheight) {
88 *dx = *dy = -1.0;
89 return;
90 } //we are on one of the borders
93 *dx = (double) ix / (double) vo->dwidth;
94 *dy = (double) iy / (double) vo->dheight;
96 mp_msg(MSGT_CPLAYER, MSGL_V,
97 "\r\nrescaled coordinates: %.3lf, %.3lf, screen (%d x %d), vodisplay: (%d, %d), fullscreen: %d\r\n",
98 *dx, *dy, opts->vo_screenwidth, opts->vo_screenheight, vo->dwidth,
99 vo->dheight, vo_fs);
102 static int sub_source_by_pos(MPContext *mpctx, int pos)
104 int source = -1;
105 int top = -1;
106 int i;
107 for (i = 0; i < SUB_SOURCES; i++) {
108 int j = mpctx->global_sub_indices[i];
109 if ((j >= 0) && (j > top) && (pos >= j)) {
110 source = i;
111 top = j;
114 return source;
117 static int sub_source(MPContext *mpctx)
119 return sub_source_by_pos(mpctx, mpctx->global_sub_pos);
123 * \brief Log the currently displayed subtitle to a file
125 * Logs the current or last displayed subtitle together with filename
126 * and time information to ~/.mplayer/subtitle_log
128 * Intended purpose is to allow convenient marking of bogus subtitles
129 * which need to be fixed while watching the movie.
132 static void log_sub(struct MPContext *mpctx)
134 char *fname;
135 FILE *f;
136 int i;
138 if (subdata == NULL || vo_sub_last == NULL)
139 return;
140 fname = get_path("subtitle_log");
141 f = fopen(fname, "a");
142 if (!f)
143 return;
144 fprintf(f, "----------------------------------------------------------\n");
145 if (subdata->sub_uses_time) {
146 fprintf(f,
147 "N: %s S: %02ld:%02ld:%02ld.%02ld E: %02ld:%02ld:%02ld.%02ld\n",
148 mpctx->filename, vo_sub_last->start / 360000,
149 (vo_sub_last->start / 6000) % 60,
150 (vo_sub_last->start / 100) % 60, vo_sub_last->start % 100,
151 vo_sub_last->end / 360000, (vo_sub_last->end / 6000) % 60,
152 (vo_sub_last->end / 100) % 60, vo_sub_last->end % 100);
153 } else {
154 fprintf(f, "N: %s S: %ld E: %ld\n", mpctx->filename,
155 vo_sub_last->start, vo_sub_last->end);
157 for (i = 0; i < vo_sub_last->lines; i++) {
158 fprintf(f, "%s\n", vo_sub_last->text[i]);
160 fclose(f);
164 /// \defgroup Properties
165 ///@{
167 /// \defgroup GeneralProperties General properties
168 /// \ingroup Properties
169 ///@{
171 /// OSD level (RW)
172 static int mp_property_osdlevel(m_option_t *prop, int action, void *arg,
173 MPContext *mpctx)
175 return m_property_choice(prop, action, arg, &osd_level);
178 /// Loop (RW)
179 static int mp_property_loop(m_option_t *prop, int action, void *arg,
180 MPContext *mpctx)
182 struct MPOpts *opts = &mpctx->opts;
183 switch (action) {
184 case M_PROPERTY_PRINT:
185 if (!arg) return M_PROPERTY_ERROR;
186 if (opts->loop_times < 0)
187 *(char**)arg = strdup("off");
188 else if (opts->loop_times == 0)
189 *(char**)arg = strdup("inf");
190 else
191 break;
192 return M_PROPERTY_OK;
194 return m_property_int_range(prop, action, arg, &opts->loop_times);
197 /// Playback speed (RW)
198 static int mp_property_playback_speed(m_option_t *prop, int action,
199 void *arg, MPContext *mpctx)
201 struct MPOpts *opts = &mpctx->opts;
202 switch (action) {
203 case M_PROPERTY_SET:
204 if (!arg)
205 return M_PROPERTY_ERROR;
206 M_PROPERTY_CLAMP(prop, *(float *) arg);
207 opts->playback_speed = *(float *) arg;
208 build_afilter_chain(mpctx, mpctx->sh_audio, &ao_data);
209 return M_PROPERTY_OK;
210 case M_PROPERTY_STEP_UP:
211 case M_PROPERTY_STEP_DOWN:
212 opts->playback_speed += (arg ? *(float *) arg : 0.1) *
213 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
214 M_PROPERTY_CLAMP(prop, opts->playback_speed);
215 build_afilter_chain(mpctx, mpctx->sh_audio, &ao_data);
216 return M_PROPERTY_OK;
218 return m_property_float_range(prop, action, arg, &opts->playback_speed);
221 /// filename with path (RO)
222 static int mp_property_path(m_option_t *prop, int action, void *arg,
223 MPContext *mpctx)
225 return m_property_string_ro(prop, action, arg, mpctx->filename);
228 /// filename without path (RO)
229 static int mp_property_filename(m_option_t *prop, int action, void *arg,
230 MPContext *mpctx)
232 char *f;
233 if (!mpctx->filename)
234 return M_PROPERTY_UNAVAILABLE;
235 if (((f = strrchr(mpctx->filename, '/'))
236 || (f = strrchr(mpctx->filename, '\\'))) && f[1])
237 f++;
238 else
239 f = mpctx->filename;
240 return m_property_string_ro(prop, action, arg, f);
243 /// Demuxer name (RO)
244 static int mp_property_demuxer(m_option_t *prop, int action, void *arg,
245 MPContext *mpctx)
247 if (!mpctx->demuxer)
248 return M_PROPERTY_UNAVAILABLE;
249 return m_property_string_ro(prop, action, arg,
250 (char *) mpctx->demuxer->desc->name);
253 /// Position in the stream (RW)
254 static int mp_property_stream_pos(m_option_t *prop, int action, void *arg,
255 MPContext *mpctx)
257 if (!mpctx->demuxer || !mpctx->demuxer->stream)
258 return M_PROPERTY_UNAVAILABLE;
259 if (!arg)
260 return M_PROPERTY_ERROR;
261 switch (action) {
262 case M_PROPERTY_GET:
263 *(off_t *) arg = stream_tell(mpctx->demuxer->stream);
264 return M_PROPERTY_OK;
265 case M_PROPERTY_SET:
266 M_PROPERTY_CLAMP(prop, *(off_t *) arg);
267 stream_seek(mpctx->demuxer->stream, *(off_t *) arg);
268 return M_PROPERTY_OK;
270 return M_PROPERTY_NOT_IMPLEMENTED;
273 /// Stream start offset (RO)
274 static int mp_property_stream_start(m_option_t *prop, int action,
275 void *arg, MPContext *mpctx)
277 if (!mpctx->demuxer || !mpctx->demuxer->stream)
278 return M_PROPERTY_UNAVAILABLE;
279 switch (action) {
280 case M_PROPERTY_GET:
281 *(off_t *) arg = mpctx->demuxer->stream->start_pos;
282 return M_PROPERTY_OK;
284 return M_PROPERTY_NOT_IMPLEMENTED;
287 /// Stream end offset (RO)
288 static int mp_property_stream_end(m_option_t *prop, int action, void *arg,
289 MPContext *mpctx)
291 if (!mpctx->demuxer || !mpctx->demuxer->stream)
292 return M_PROPERTY_UNAVAILABLE;
293 switch (action) {
294 case M_PROPERTY_GET:
295 *(off_t *) arg = mpctx->demuxer->stream->end_pos;
296 return M_PROPERTY_OK;
298 return M_PROPERTY_NOT_IMPLEMENTED;
301 /// Stream length (RO)
302 static int mp_property_stream_length(m_option_t *prop, int action,
303 void *arg, MPContext *mpctx)
305 if (!mpctx->demuxer || !mpctx->demuxer->stream)
306 return M_PROPERTY_UNAVAILABLE;
307 switch (action) {
308 case M_PROPERTY_GET:
309 *(off_t *) arg =
310 mpctx->demuxer->stream->end_pos - mpctx->demuxer->stream->start_pos;
311 return M_PROPERTY_OK;
313 return M_PROPERTY_NOT_IMPLEMENTED;
316 /// Media length in seconds (RO)
317 static int mp_property_length(m_option_t *prop, int action, void *arg,
318 MPContext *mpctx)
320 double len;
322 if (!mpctx->demuxer ||
323 !(int) (len = demuxer_get_time_length(mpctx->demuxer)))
324 return M_PROPERTY_UNAVAILABLE;
326 return m_property_time_ro(prop, action, arg, len);
329 /// Current position in percent (RW)
330 static int mp_property_percent_pos(m_option_t *prop, int action,
331 void *arg, MPContext *mpctx) {
332 int pos;
334 if (!mpctx->demuxer)
335 return M_PROPERTY_UNAVAILABLE;
337 switch(action) {
338 case M_PROPERTY_SET:
339 if(!arg) return M_PROPERTY_ERROR;
340 M_PROPERTY_CLAMP(prop, *(int*)arg);
341 pos = *(int*)arg;
342 break;
343 case M_PROPERTY_STEP_UP:
344 case M_PROPERTY_STEP_DOWN:
345 pos = demuxer_get_percent_pos(mpctx->demuxer);
346 pos += (arg ? *(int*)arg : 10) *
347 (action == M_PROPERTY_STEP_UP ? 1 : -1);
348 M_PROPERTY_CLAMP(prop, pos);
349 break;
350 default:
351 return m_property_int_ro(prop, action, arg,
352 demuxer_get_percent_pos(mpctx->demuxer));
355 mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
356 mpctx->rel_seek_secs = pos / 100.0;
357 return M_PROPERTY_OK;
360 /// Current position in seconds (RW)
361 static int mp_property_time_pos(m_option_t *prop, int action,
362 void *arg, MPContext *mpctx) {
363 if (!(mpctx->sh_video || (mpctx->sh_audio && mpctx->audio_out)))
364 return M_PROPERTY_UNAVAILABLE;
366 switch(action) {
367 case M_PROPERTY_SET:
368 if(!arg) return M_PROPERTY_ERROR;
369 M_PROPERTY_CLAMP(prop, *(double*)arg);
370 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
371 mpctx->rel_seek_secs = *(double*)arg;
372 return M_PROPERTY_OK;
373 case M_PROPERTY_STEP_UP:
374 case M_PROPERTY_STEP_DOWN:
375 mpctx->rel_seek_secs += (arg ? *(double*)arg : 10.0) *
376 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
377 return M_PROPERTY_OK;
379 return m_property_time_ro(prop, action, arg,
380 mpctx->sh_video ? mpctx->sh_video->pts :
381 playing_audio_pts(mpctx));
384 /// Current chapter (RW)
385 static int mp_property_chapter(m_option_t *prop, int action, void *arg,
386 MPContext *mpctx)
388 int chapter = -1;
389 float next_pts = 0;
390 int chapter_num;
391 int step_all;
392 char *chapter_name = NULL;
394 if (mpctx->demuxer)
395 chapter = demuxer_get_current_chapter(mpctx->demuxer);
396 if (chapter < 0)
397 return M_PROPERTY_UNAVAILABLE;
399 switch (action) {
400 case M_PROPERTY_GET:
401 if (!arg)
402 return M_PROPERTY_ERROR;
403 *(int *) arg = chapter;
404 return M_PROPERTY_OK;
405 case M_PROPERTY_PRINT: {
406 if (!arg)
407 return M_PROPERTY_ERROR;
408 chapter_name = demuxer_chapter_display_name(mpctx->demuxer, chapter);
409 if (!chapter_name)
410 return M_PROPERTY_UNAVAILABLE;
411 *(char **) arg = chapter_name;
412 return M_PROPERTY_OK;
414 case M_PROPERTY_SET:
415 if (!arg)
416 return M_PROPERTY_ERROR;
417 M_PROPERTY_CLAMP(prop, *(int*)arg);
418 step_all = *(int *)arg - (chapter + 1);
419 chapter += step_all;
420 break;
421 case M_PROPERTY_STEP_UP:
422 case M_PROPERTY_STEP_DOWN: {
423 step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
424 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
425 chapter += step_all;
426 if (chapter < 0)
427 chapter = 0;
428 break;
430 default:
431 return M_PROPERTY_NOT_IMPLEMENTED;
433 mpctx->rel_seek_secs = 0;
434 mpctx->abs_seek_pos = 0;
435 chapter = demuxer_seek_chapter(mpctx->demuxer, chapter, 1,
436 &next_pts, &chapter_num, &chapter_name);
437 if (chapter >= 0) {
438 if (next_pts > -1.0) {
439 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
440 mpctx->rel_seek_secs = next_pts;
442 if (chapter_name)
443 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
444 MSGTR_OSDChapter, chapter + 1, chapter_name);
446 else if (step_all > 0)
447 mpctx->rel_seek_secs = 1000000000.;
448 else
449 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
450 MSGTR_OSDChapter, 0, MSGTR_Unknown);
451 if (chapter_name)
452 free(chapter_name);
453 return M_PROPERTY_OK;
456 /// Number of chapters in file
457 static int mp_property_chapters(m_option_t *prop, int action, void *arg,
458 MPContext *mpctx)
460 if (!mpctx->demuxer)
461 return M_PROPERTY_UNAVAILABLE;
462 if (mpctx->demuxer->num_chapters == 0)
463 stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &mpctx->demuxer->num_chapters);
464 return m_property_int_ro(prop, action, arg, mpctx->demuxer->num_chapters);
467 /// Current dvd angle (RW)
468 static int mp_property_angle(m_option_t *prop, int action, void *arg,
469 MPContext *mpctx)
471 int angle = -1;
472 int angles;
473 char *angle_name = NULL;
475 if (mpctx->demuxer)
476 angle = demuxer_get_current_angle(mpctx->demuxer);
477 if (angle < 0)
478 return M_PROPERTY_UNAVAILABLE;
479 angles = demuxer_angles_count(mpctx->demuxer);
480 if (angles <= 1)
481 return M_PROPERTY_UNAVAILABLE;
483 switch (action) {
484 case M_PROPERTY_GET:
485 if (!arg)
486 return M_PROPERTY_ERROR;
487 *(int *) arg = angle;
488 return M_PROPERTY_OK;
489 case M_PROPERTY_PRINT: {
490 if (!arg)
491 return M_PROPERTY_ERROR;
492 angle_name = calloc(1, 64);
493 if (!angle_name)
494 return M_PROPERTY_UNAVAILABLE;
495 snprintf(angle_name, 64, "%d/%d", angle, angles);
496 *(char **) arg = angle_name;
497 return M_PROPERTY_OK;
499 case M_PROPERTY_SET:
500 if (!arg)
501 return M_PROPERTY_ERROR;
502 angle = *(int *)arg;
503 M_PROPERTY_CLAMP(prop, angle);
504 break;
505 case M_PROPERTY_STEP_UP:
506 case M_PROPERTY_STEP_DOWN: {
507 int step = 0;
508 if(arg)
509 step = *(int*)arg;
510 if(!step)
511 step = 1;
512 step *= (action == M_PROPERTY_STEP_UP ? 1 : -1);
513 angle += step;
514 if (angle < 1) //cycle
515 angle = angles;
516 break;
518 default:
519 return M_PROPERTY_NOT_IMPLEMENTED;
521 angle = demuxer_set_angle(mpctx->demuxer, angle);
522 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
523 MSGTR_OSDAngle, angle, angles);
524 if (angle_name)
525 free(angle_name);
526 return M_PROPERTY_OK;
529 /// Demuxer meta data
530 static int mp_property_metadata(m_option_t *prop, int action, void *arg,
531 MPContext *mpctx) {
532 m_property_action_t* ka;
533 char* meta;
534 static const m_option_t key_type =
535 { "metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL };
536 if (!mpctx->demuxer)
537 return M_PROPERTY_UNAVAILABLE;
539 switch(action) {
540 case M_PROPERTY_GET:
541 if(!arg) return M_PROPERTY_ERROR;
542 *(char***)arg = mpctx->demuxer->info;
543 return M_PROPERTY_OK;
544 case M_PROPERTY_KEY_ACTION:
545 if(!arg) return M_PROPERTY_ERROR;
546 ka = arg;
547 if(!(meta = demux_info_get(mpctx->demuxer,ka->key)))
548 return M_PROPERTY_UNKNOWN;
549 switch(ka->action) {
550 case M_PROPERTY_GET:
551 if(!ka->arg) return M_PROPERTY_ERROR;
552 *(char**)ka->arg = meta;
553 return M_PROPERTY_OK;
554 case M_PROPERTY_GET_TYPE:
555 if(!ka->arg) return M_PROPERTY_ERROR;
556 *(m_option_t**)ka->arg = &key_type;
557 return M_PROPERTY_OK;
560 return M_PROPERTY_NOT_IMPLEMENTED;
563 static int mp_property_pause(m_option_t *prop, int action, void *arg,
564 void *ctx)
566 MPContext *mpctx = ctx;
568 switch (action) {
569 case M_PROPERTY_SET:
570 if (!arg)
571 return M_PROPERTY_ERROR;
572 if (mpctx->paused == (bool)*(int *) arg)
573 return M_PROPERTY_OK;
574 case M_PROPERTY_STEP_UP:
575 case M_PROPERTY_STEP_DOWN:
576 if (mpctx->paused) {
577 unpause_player(mpctx);
578 mpctx->osd_function = OSD_PLAY;
580 else {
581 pause_player(mpctx);
582 mpctx->osd_function = OSD_PAUSE;
584 return M_PROPERTY_OK;
585 default:
586 return m_property_flag(prop, action, arg, &mpctx->paused);
591 ///@}
593 /// \defgroup AudioProperties Audio properties
594 /// \ingroup Properties
595 ///@{
597 /// Volume (RW)
598 static int mp_property_volume(m_option_t *prop, int action, void *arg,
599 MPContext *mpctx)
602 if (!mpctx->sh_audio)
603 return M_PROPERTY_UNAVAILABLE;
605 switch (action) {
606 case M_PROPERTY_GET:
607 if (!arg)
608 return M_PROPERTY_ERROR;
609 mixer_getbothvolume(&mpctx->mixer, arg);
610 return M_PROPERTY_OK;
611 case M_PROPERTY_PRINT:{
612 float vol;
613 if (!arg)
614 return M_PROPERTY_ERROR;
615 mixer_getbothvolume(&mpctx->mixer, &vol);
616 return m_property_float_range(prop, action, arg, &vol);
618 case M_PROPERTY_STEP_UP:
619 case M_PROPERTY_STEP_DOWN:
620 case M_PROPERTY_SET:
621 break;
622 default:
623 return M_PROPERTY_NOT_IMPLEMENTED;
626 if (mpctx->edl_muted)
627 return M_PROPERTY_DISABLED;
628 mpctx->user_muted = 0;
630 switch (action) {
631 case M_PROPERTY_SET:
632 if (!arg)
633 return M_PROPERTY_ERROR;
634 M_PROPERTY_CLAMP(prop, *(float *) arg);
635 mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg);
636 return M_PROPERTY_OK;
637 case M_PROPERTY_STEP_UP:
638 if (arg && *(float *) arg <= 0)
639 mixer_decvolume(&mpctx->mixer);
640 else
641 mixer_incvolume(&mpctx->mixer);
642 return M_PROPERTY_OK;
643 case M_PROPERTY_STEP_DOWN:
644 if (arg && *(float *) arg <= 0)
645 mixer_incvolume(&mpctx->mixer);
646 else
647 mixer_decvolume(&mpctx->mixer);
648 return M_PROPERTY_OK;
650 return M_PROPERTY_NOT_IMPLEMENTED;
653 /// Mute (RW)
654 static int mp_property_mute(m_option_t *prop, int action, void *arg,
655 MPContext *mpctx)
658 if (!mpctx->sh_audio)
659 return M_PROPERTY_UNAVAILABLE;
661 switch (action) {
662 case M_PROPERTY_SET:
663 if (mpctx->edl_muted)
664 return M_PROPERTY_DISABLED;
665 if (!arg)
666 return M_PROPERTY_ERROR;
667 if ((!!*(int *) arg) != mpctx->mixer.muted)
668 mixer_mute(&mpctx->mixer);
669 mpctx->user_muted = mpctx->mixer.muted;
670 return M_PROPERTY_OK;
671 case M_PROPERTY_STEP_UP:
672 case M_PROPERTY_STEP_DOWN:
673 if (mpctx->edl_muted)
674 return M_PROPERTY_DISABLED;
675 mixer_mute(&mpctx->mixer);
676 mpctx->user_muted = mpctx->mixer.muted;
677 return M_PROPERTY_OK;
678 case M_PROPERTY_PRINT:
679 if (!arg)
680 return M_PROPERTY_ERROR;
681 if (mpctx->edl_muted) {
682 *(char **) arg = strdup(MSGTR_EnabledEdl);
683 return M_PROPERTY_OK;
685 default:
686 return m_property_flag(prop, action, arg, &mpctx->mixer.muted);
691 /// Audio delay (RW)
692 static int mp_property_audio_delay(m_option_t *prop, int action,
693 void *arg, MPContext *mpctx)
695 if (!(mpctx->sh_audio && mpctx->sh_video))
696 return M_PROPERTY_UNAVAILABLE;
697 switch (action) {
698 case M_PROPERTY_SET:
699 case M_PROPERTY_STEP_UP:
700 case M_PROPERTY_STEP_DOWN: {
701 int ret;
702 float delay = audio_delay;
703 ret = m_property_delay(prop, action, arg, &audio_delay);
704 if (ret != M_PROPERTY_OK)
705 return ret;
706 if (mpctx->sh_audio)
707 mpctx->delay -= audio_delay - delay;
709 return M_PROPERTY_OK;
710 default:
711 return m_property_delay(prop, action, arg, &audio_delay);
715 /// Audio codec tag (RO)
716 static int mp_property_audio_format(m_option_t *prop, int action,
717 void *arg, MPContext *mpctx)
719 if (!mpctx->sh_audio)
720 return M_PROPERTY_UNAVAILABLE;
721 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->format);
724 /// Audio codec name (RO)
725 static int mp_property_audio_codec(m_option_t *prop, int action,
726 void *arg, MPContext *mpctx)
728 if (!mpctx->sh_audio || !mpctx->sh_audio->codec)
729 return M_PROPERTY_UNAVAILABLE;
730 return m_property_string_ro(prop, action, arg, mpctx->sh_audio->codec->name);
733 /// Audio bitrate (RO)
734 static int mp_property_audio_bitrate(m_option_t *prop, int action,
735 void *arg, MPContext *mpctx)
737 if (!mpctx->sh_audio)
738 return M_PROPERTY_UNAVAILABLE;
739 return m_property_bitrate(prop, action, arg, mpctx->sh_audio->i_bps);
742 /// Samplerate (RO)
743 static int mp_property_samplerate(m_option_t *prop, int action, void *arg,
744 MPContext *mpctx)
746 if (!mpctx->sh_audio)
747 return M_PROPERTY_UNAVAILABLE;
748 switch(action) {
749 case M_PROPERTY_PRINT:
750 if(!arg) return M_PROPERTY_ERROR;
751 *(char**)arg = malloc(16);
752 sprintf(*(char**)arg,"%d kHz",mpctx->sh_audio->samplerate/1000);
753 return M_PROPERTY_OK;
755 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->samplerate);
758 /// Number of channels (RO)
759 static int mp_property_channels(m_option_t *prop, int action, void *arg,
760 MPContext *mpctx)
762 if (!mpctx->sh_audio)
763 return M_PROPERTY_UNAVAILABLE;
764 switch (action) {
765 case M_PROPERTY_PRINT:
766 if (!arg)
767 return M_PROPERTY_ERROR;
768 switch (mpctx->sh_audio->channels) {
769 case 1:
770 *(char **) arg = strdup("mono");
771 break;
772 case 2:
773 *(char **) arg = strdup("stereo");
774 break;
775 default:
776 *(char **) arg = malloc(32);
777 sprintf(*(char **) arg, "%d channels", mpctx->sh_audio->channels);
779 return M_PROPERTY_OK;
781 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->channels);
784 /// Balance (RW)
785 static int mp_property_balance(m_option_t *prop, int action, void *arg,
786 MPContext *mpctx)
788 float bal;
790 if (!mpctx->sh_audio || mpctx->sh_audio->channels < 2)
791 return M_PROPERTY_UNAVAILABLE;
793 switch (action) {
794 case M_PROPERTY_GET:
795 if (!arg)
796 return M_PROPERTY_ERROR;
797 mixer_getbalance(&mpctx->mixer, arg);
798 return M_PROPERTY_OK;
799 case M_PROPERTY_PRINT: {
800 char** str = arg;
801 if (!arg)
802 return M_PROPERTY_ERROR;
803 mixer_getbalance(&mpctx->mixer, &bal);
804 if (bal == 0.f)
805 *str = strdup("center");
806 else if (bal == -1.f)
807 *str = strdup("left only");
808 else if (bal == 1.f)
809 *str = strdup("right only");
810 else {
811 unsigned right = (bal + 1.f) / 2.f * 100.f;
812 *str = malloc(sizeof("left xxx%, right xxx%"));
813 sprintf(*str, "left %d%%, right %d%%", 100 - right, right);
815 return M_PROPERTY_OK;
817 case M_PROPERTY_STEP_UP:
818 case M_PROPERTY_STEP_DOWN:
819 mixer_getbalance(&mpctx->mixer, &bal);
820 bal += (arg ? *(float*)arg : .1f) *
821 (action == M_PROPERTY_STEP_UP ? 1.f : -1.f);
822 M_PROPERTY_CLAMP(prop, bal);
823 mixer_setbalance(&mpctx->mixer, bal);
824 return M_PROPERTY_OK;
825 case M_PROPERTY_SET:
826 if (!arg)
827 return M_PROPERTY_ERROR;
828 M_PROPERTY_CLAMP(prop, *(float*)arg);
829 mixer_setbalance(&mpctx->mixer, *(float*)arg);
830 return M_PROPERTY_OK;
832 return M_PROPERTY_NOT_IMPLEMENTED;
835 /// Selected audio id (RW)
836 static int mp_property_audio(m_option_t *prop, int action, void *arg,
837 MPContext *mpctx)
839 struct MPOpts *opts = &mpctx->opts;
840 int current_id = -1, tmp;
842 switch (action) {
843 case M_PROPERTY_GET:
844 if (!mpctx->sh_audio)
845 return M_PROPERTY_UNAVAILABLE;
846 if (!arg)
847 return M_PROPERTY_ERROR;
848 *(int *) arg = opts->audio_id;
849 return M_PROPERTY_OK;
850 case M_PROPERTY_PRINT:
851 if (!mpctx->sh_audio)
852 return M_PROPERTY_UNAVAILABLE;
853 if (!arg)
854 return M_PROPERTY_ERROR;
856 if (opts->audio_id < 0)
857 *(char **) arg = strdup(MSGTR_Disabled);
858 else {
859 char lang[40] = MSGTR_Unknown;
860 sh_audio_t* sh = mpctx->sh_audio;
861 if (sh && sh->lang)
862 av_strlcpy(lang, sh->lang, 40);
863 #ifdef CONFIG_DVDREAD
864 else if (mpctx->stream->type == STREAMTYPE_DVD) {
865 int code = dvd_lang_from_aid(mpctx->stream, opts->audio_id);
866 if (code) {
867 lang[0] = code >> 8;
868 lang[1] = code;
869 lang[2] = 0;
872 #endif
874 #ifdef CONFIG_DVDNAV
875 else if (mpctx->stream->type == STREAMTYPE_DVDNAV)
876 mp_dvdnav_lang_from_aid(mpctx->stream, opts->audio_id, lang);
877 #endif
878 *(char **) arg = malloc(64);
879 snprintf(*(char **) arg, 64, "(%d) %s", opts->audio_id, lang);
881 return M_PROPERTY_OK;
883 case M_PROPERTY_STEP_UP:
884 case M_PROPERTY_SET:
885 if (!mpctx->demuxer)
886 return M_PROPERTY_UNAVAILABLE;
887 if (action == M_PROPERTY_SET && arg)
888 tmp = *((int *) arg);
889 else
890 tmp = -1;
891 current_id = mpctx->demuxer->audio->id;
892 opts->audio_id = demuxer_switch_audio(mpctx->demuxer, tmp);
893 if (opts->audio_id == -2
894 || (opts->audio_id > -1
895 && mpctx->demuxer->audio->id != current_id && current_id != -2))
896 uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC);
897 if (opts->audio_id > -1 && mpctx->demuxer->audio->id != current_id) {
898 sh_audio_t *sh2;
899 sh2 = mpctx->demuxer->a_streams[mpctx->demuxer->audio->id];
900 if (sh2) {
901 sh2->ds = mpctx->demuxer->audio;
902 mpctx->sh_audio = sh2;
903 reinit_audio_chain(mpctx);
906 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_TRACK=%d\n", opts->audio_id);
907 return M_PROPERTY_OK;
908 default:
909 return M_PROPERTY_NOT_IMPLEMENTED;
914 /// Selected video id (RW)
915 static int mp_property_video(m_option_t *prop, int action, void *arg,
916 MPContext *mpctx)
918 struct MPOpts *opts = &mpctx->opts;
919 int current_id = -1, tmp;
921 switch (action) {
922 case M_PROPERTY_GET:
923 if (!mpctx->sh_video)
924 return M_PROPERTY_UNAVAILABLE;
925 if (!arg)
926 return M_PROPERTY_ERROR;
927 *(int *) arg = opts->video_id;
928 return M_PROPERTY_OK;
929 case M_PROPERTY_PRINT:
930 if (!mpctx->sh_video)
931 return M_PROPERTY_UNAVAILABLE;
932 if (!arg)
933 return M_PROPERTY_ERROR;
935 if (opts->video_id < 0)
936 *(char **) arg = strdup(MSGTR_Disabled);
937 else {
938 char lang[40] = MSGTR_Unknown;
939 *(char **) arg = malloc(64);
940 snprintf(*(char **) arg, 64, "(%d) %s", opts->video_id, lang);
942 return M_PROPERTY_OK;
944 case M_PROPERTY_STEP_UP:
945 case M_PROPERTY_SET:
946 current_id = mpctx->demuxer->video->id;
947 if (action == M_PROPERTY_SET && arg)
948 tmp = *((int *) arg);
949 else
950 tmp = -1;
951 opts->video_id = demuxer_switch_video(mpctx->demuxer, tmp);
952 if (opts->video_id == -2
953 || (opts->video_id > -1 && mpctx->demuxer->video->id != current_id
954 && current_id != -2))
955 uninit_player(mpctx, INITIALIZED_VCODEC |
956 (mpctx->opts.fixed_vo && opts->video_id != -2 ? 0 : INITIALIZED_VO));
957 if (opts->video_id > -1 && mpctx->demuxer->video->id != current_id) {
958 sh_video_t *sh2;
959 sh2 = mpctx->demuxer->v_streams[mpctx->demuxer->video->id];
960 if (sh2) {
961 sh2->ds = mpctx->demuxer->video;
962 mpctx->sh_video = sh2;
963 reinit_video_chain(mpctx);
966 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_TRACK=%d\n", opts->video_id);
967 return M_PROPERTY_OK;
969 default:
970 return M_PROPERTY_NOT_IMPLEMENTED;
974 static int mp_property_program(m_option_t *prop, int action, void *arg,
975 MPContext *mpctx)
977 demux_program_t prog;
979 switch (action) {
980 case M_PROPERTY_STEP_UP:
981 case M_PROPERTY_SET:
982 if (action == M_PROPERTY_SET && arg)
983 prog.progid = *((int *) arg);
984 else
985 prog.progid = -1;
986 if (demux_control
987 (mpctx->demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM,
988 &prog) == DEMUXER_CTRL_NOTIMPL)
989 return M_PROPERTY_ERROR;
991 mp_property_do("switch_audio", M_PROPERTY_SET, &prog.aid, mpctx);
992 mp_property_do("switch_video", M_PROPERTY_SET, &prog.vid, mpctx);
993 return M_PROPERTY_OK;
995 default:
996 return M_PROPERTY_NOT_IMPLEMENTED;
1000 ///@}
1002 /// \defgroup VideoProperties Video properties
1003 /// \ingroup Properties
1004 ///@{
1006 /// Fullscreen state (RW)
1007 static int mp_property_fullscreen(m_option_t *prop, int action, void *arg,
1008 MPContext *mpctx)
1011 if (!mpctx->video_out)
1012 return M_PROPERTY_UNAVAILABLE;
1014 switch (action) {
1015 case M_PROPERTY_SET:
1016 if (!arg)
1017 return M_PROPERTY_ERROR;
1018 M_PROPERTY_CLAMP(prop, *(int *) arg);
1019 if (vo_fs == !!*(int *) arg)
1020 return M_PROPERTY_OK;
1021 case M_PROPERTY_STEP_UP:
1022 case M_PROPERTY_STEP_DOWN:
1023 #ifdef CONFIG_GUI
1024 if (use_gui)
1025 guiGetEvent(guiIEvent, (char *) MP_CMD_GUI_FULLSCREEN);
1026 else
1027 #endif
1028 if (mpctx->video_out->config_ok)
1029 vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0);
1030 return M_PROPERTY_OK;
1031 default:
1032 return m_property_flag(prop, action, arg, &vo_fs);
1036 static int mp_property_deinterlace(m_option_t *prop, int action,
1037 void *arg, MPContext *mpctx)
1039 int deinterlace;
1040 vf_instance_t *vf;
1041 if (!mpctx->sh_video || !mpctx->sh_video->vfilter)
1042 return M_PROPERTY_UNAVAILABLE;
1043 vf = mpctx->sh_video->vfilter;
1044 switch (action) {
1045 case M_PROPERTY_GET:
1046 if (!arg)
1047 return M_PROPERTY_ERROR;
1048 vf->control(vf, VFCTRL_GET_DEINTERLACE, arg);
1049 return M_PROPERTY_OK;
1050 case M_PROPERTY_SET:
1051 if (!arg)
1052 return M_PROPERTY_ERROR;
1053 M_PROPERTY_CLAMP(prop, *(int *) arg);
1054 vf->control(vf, VFCTRL_SET_DEINTERLACE, arg);
1055 return M_PROPERTY_OK;
1056 case M_PROPERTY_STEP_UP:
1057 case M_PROPERTY_STEP_DOWN:
1058 vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace);
1059 deinterlace = !deinterlace;
1060 vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace);
1061 return M_PROPERTY_OK;
1063 return M_PROPERTY_NOT_IMPLEMENTED;
1066 /// Panscan (RW)
1067 static int mp_property_panscan(m_option_t *prop, int action, void *arg,
1068 MPContext *mpctx)
1071 if (!mpctx->video_out
1072 || vo_control(mpctx->video_out, VOCTRL_GET_PANSCAN, NULL) != VO_TRUE)
1073 return M_PROPERTY_UNAVAILABLE;
1075 switch (action) {
1076 case M_PROPERTY_SET:
1077 if (!arg)
1078 return M_PROPERTY_ERROR;
1079 M_PROPERTY_CLAMP(prop, *(float *) arg);
1080 vo_panscan = *(float *) arg;
1081 vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
1082 return M_PROPERTY_OK;
1083 case M_PROPERTY_STEP_UP:
1084 case M_PROPERTY_STEP_DOWN:
1085 vo_panscan += (arg ? *(float *) arg : 0.1) *
1086 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1087 if (vo_panscan > 1)
1088 vo_panscan = 1;
1089 else if (vo_panscan < 0)
1090 vo_panscan = 0;
1091 vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
1092 return M_PROPERTY_OK;
1093 default:
1094 return m_property_float_range(prop, action, arg, &vo_panscan);
1098 /// Helper to set vo flags.
1099 /** \ingroup PropertyImplHelper
1101 static int mp_property_vo_flag(m_option_t *prop, int action, void *arg,
1102 int vo_ctrl, int *vo_var, MPContext *mpctx)
1105 if (!mpctx->video_out)
1106 return M_PROPERTY_UNAVAILABLE;
1108 switch (action) {
1109 case M_PROPERTY_SET:
1110 if (!arg)
1111 return M_PROPERTY_ERROR;
1112 M_PROPERTY_CLAMP(prop, *(int *) arg);
1113 if (*vo_var == !!*(int *) arg)
1114 return M_PROPERTY_OK;
1115 case M_PROPERTY_STEP_UP:
1116 case M_PROPERTY_STEP_DOWN:
1117 if (mpctx->video_out->config_ok)
1118 vo_control(mpctx->video_out, vo_ctrl, 0);
1119 return M_PROPERTY_OK;
1120 default:
1121 return m_property_flag(prop, action, arg, vo_var);
1125 /// Window always on top (RW)
1126 static int mp_property_ontop(m_option_t *prop, int action, void *arg,
1127 MPContext *mpctx)
1129 return mp_property_vo_flag(prop, action, arg, VOCTRL_ONTOP,
1130 &mpctx->opts.vo_ontop, mpctx);
1133 /// Display in the root window (RW)
1134 static int mp_property_rootwin(m_option_t *prop, int action, void *arg,
1135 MPContext *mpctx)
1137 return mp_property_vo_flag(prop, action, arg, VOCTRL_ROOTWIN,
1138 &vo_rootwin, mpctx);
1141 /// Show window borders (RW)
1142 static int mp_property_border(m_option_t *prop, int action, void *arg,
1143 MPContext *mpctx)
1145 return mp_property_vo_flag(prop, action, arg, VOCTRL_BORDER,
1146 &vo_border, mpctx);
1149 /// Framedropping state (RW)
1150 static int mp_property_framedropping(m_option_t *prop, int action,
1151 void *arg, MPContext *mpctx)
1154 if (!mpctx->sh_video)
1155 return M_PROPERTY_UNAVAILABLE;
1157 switch (action) {
1158 case M_PROPERTY_PRINT:
1159 if (!arg)
1160 return M_PROPERTY_ERROR;
1161 *(char **) arg = strdup(frame_dropping == 1 ? MSGTR_Enabled :
1162 (frame_dropping == 2 ? MSGTR_HardFrameDrop :
1163 MSGTR_Disabled));
1164 return M_PROPERTY_OK;
1165 default:
1166 return m_property_choice(prop, action, arg, &frame_dropping);
1170 /// Color settings, try to use vf/vo then fall back on TV. (RW)
1171 static int mp_property_gamma(m_option_t *prop, int action, void *arg,
1172 MPContext *mpctx)
1174 int *gamma = (int *)((char *)&mpctx->opts + (int)prop->priv);
1175 int r, val;
1177 if (!mpctx->sh_video)
1178 return M_PROPERTY_UNAVAILABLE;
1180 if (gamma[0] == 1000) {
1181 gamma[0] = 0;
1182 get_video_colors(mpctx->sh_video, prop->name, gamma);
1185 switch (action) {
1186 case M_PROPERTY_SET:
1187 if (!arg)
1188 return M_PROPERTY_ERROR;
1189 M_PROPERTY_CLAMP(prop, *(int *) arg);
1190 *gamma = *(int *) arg;
1191 r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1192 if (r <= 0)
1193 break;
1194 return r;
1195 case M_PROPERTY_GET:
1196 if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) {
1197 if (!arg)
1198 return M_PROPERTY_ERROR;
1199 *(int *)arg = val;
1200 return M_PROPERTY_OK;
1202 break;
1203 case M_PROPERTY_STEP_UP:
1204 case M_PROPERTY_STEP_DOWN:
1205 *gamma += (arg ? *(int *) arg : 1) *
1206 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1207 M_PROPERTY_CLAMP(prop, *gamma);
1208 r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1209 if (r <= 0)
1210 break;
1211 return r;
1212 default:
1213 return M_PROPERTY_NOT_IMPLEMENTED;
1216 #ifdef CONFIG_TV
1217 if (mpctx->demuxer->type == DEMUXER_TYPE_TV) {
1218 int l = strlen(prop->name);
1219 char tv_prop[3 + l + 1];
1220 sprintf(tv_prop, "tv_%s", prop->name);
1221 return mp_property_do(tv_prop, action, arg, mpctx);
1223 #endif
1225 return M_PROPERTY_UNAVAILABLE;
1228 /// VSync (RW)
1229 static int mp_property_vsync(m_option_t *prop, int action, void *arg,
1230 MPContext *mpctx)
1232 return m_property_flag(prop, action, arg, &vo_vsync);
1235 /// Video codec tag (RO)
1236 static int mp_property_video_format(m_option_t *prop, int action,
1237 void *arg, MPContext *mpctx)
1239 char* meta;
1240 if (!mpctx->sh_video)
1241 return M_PROPERTY_UNAVAILABLE;
1242 switch(action) {
1243 case M_PROPERTY_PRINT:
1244 if (!arg)
1245 return M_PROPERTY_ERROR;
1246 switch(mpctx->sh_video->format) {
1247 case 0x10000001:
1248 meta = strdup ("mpeg1"); break;
1249 case 0x10000002:
1250 meta = strdup ("mpeg2"); break;
1251 case 0x10000004:
1252 meta = strdup ("mpeg4"); break;
1253 case 0x10000005:
1254 meta = strdup ("h264"); break;
1255 default:
1256 if(mpctx->sh_video->format >= 0x20202020) {
1257 meta = malloc(5);
1258 sprintf (meta, "%.4s", (char *) &mpctx->sh_video->format);
1259 } else {
1260 meta = malloc(20);
1261 sprintf (meta, "0x%08X", mpctx->sh_video->format);
1264 *(char**)arg = meta;
1265 return M_PROPERTY_OK;
1267 return m_property_int_ro(prop, action, arg, mpctx->sh_video->format);
1270 /// Video codec name (RO)
1271 static int mp_property_video_codec(m_option_t *prop, int action,
1272 void *arg, MPContext *mpctx)
1274 if (!mpctx->sh_video || !mpctx->sh_video->codec)
1275 return M_PROPERTY_UNAVAILABLE;
1276 return m_property_string_ro(prop, action, arg, mpctx->sh_video->codec->name);
1280 /// Video bitrate (RO)
1281 static int mp_property_video_bitrate(m_option_t *prop, int action,
1282 void *arg, MPContext *mpctx)
1284 if (!mpctx->sh_video)
1285 return M_PROPERTY_UNAVAILABLE;
1286 return m_property_bitrate(prop, action, arg, mpctx->sh_video->i_bps);
1289 /// Video display width (RO)
1290 static int mp_property_width(m_option_t *prop, int action, void *arg,
1291 MPContext *mpctx)
1293 if (!mpctx->sh_video)
1294 return M_PROPERTY_UNAVAILABLE;
1295 return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_w);
1298 /// Video display height (RO)
1299 static int mp_property_height(m_option_t *prop, int action, void *arg,
1300 MPContext *mpctx)
1302 if (!mpctx->sh_video)
1303 return M_PROPERTY_UNAVAILABLE;
1304 return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_h);
1307 /// Video fps (RO)
1308 static int mp_property_fps(m_option_t *prop, int action, void *arg,
1309 MPContext *mpctx)
1311 if (!mpctx->sh_video)
1312 return M_PROPERTY_UNAVAILABLE;
1313 return m_property_float_ro(prop, action, arg, mpctx->sh_video->fps);
1316 /// Video aspect (RO)
1317 static int mp_property_aspect(m_option_t *prop, int action, void *arg,
1318 MPContext *mpctx)
1320 if (!mpctx->sh_video)
1321 return M_PROPERTY_UNAVAILABLE;
1322 return m_property_float_ro(prop, action, arg, mpctx->sh_video->aspect);
1325 ///@}
1327 /// \defgroup SubProprties Subtitles properties
1328 /// \ingroup Properties
1329 ///@{
1331 /// Text subtitle position (RW)
1332 static int mp_property_sub_pos(m_option_t *prop, int action, void *arg,
1333 MPContext *mpctx)
1335 if (!mpctx->sh_video)
1336 return M_PROPERTY_UNAVAILABLE;
1338 switch (action) {
1339 case M_PROPERTY_SET:
1340 if (!arg)
1341 return M_PROPERTY_ERROR;
1342 case M_PROPERTY_STEP_UP:
1343 case M_PROPERTY_STEP_DOWN:
1344 vo_osd_changed(OSDTYPE_SUBTITLE);
1345 default:
1346 return m_property_int_range(prop, action, arg, &sub_pos);
1350 /// Selected subtitles (RW)
1351 static int mp_property_sub(m_option_t *prop, int action, void *arg,
1352 MPContext *mpctx)
1354 struct MPOpts *opts = &mpctx->opts;
1355 demux_stream_t *const d_sub = mpctx->d_sub;
1356 const int global_sub_size = mpctx->global_sub_size;
1357 int source = -1, reset_spu = 0;
1358 char *sub_name;
1360 if (global_sub_size <= 0)
1361 return M_PROPERTY_UNAVAILABLE;
1363 switch (action) {
1364 case M_PROPERTY_GET:
1365 if (!arg)
1366 return M_PROPERTY_ERROR;
1367 *(int *) arg = mpctx->global_sub_pos;
1368 return M_PROPERTY_OK;
1369 case M_PROPERTY_PRINT:
1370 if (!arg)
1371 return M_PROPERTY_ERROR;
1372 *(char **) arg = malloc(64);
1373 (*(char **) arg)[63] = 0;
1374 sub_name = 0;
1375 if (subdata)
1376 sub_name = subdata->filename;
1377 #ifdef CONFIG_ASS
1378 if (ass_track && ass_track->name)
1379 sub_name = ass_track->name;
1380 #endif
1381 if (sub_name) {
1382 char *tmp, *tmp2;
1383 tmp = sub_name;
1384 if ((tmp2 = strrchr(tmp, '/')))
1385 tmp = tmp2 + 1;
1387 snprintf(*(char **) arg, 63, "(%d) %s%s",
1388 mpctx->set_of_sub_pos + 1,
1389 strlen(tmp) < 20 ? "" : "...",
1390 strlen(tmp) < 20 ? tmp : tmp + strlen(tmp) - 19);
1391 return M_PROPERTY_OK;
1393 #ifdef CONFIG_DVDNAV
1394 if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
1395 if (vo_spudec && opts->sub_id >= 0) {
1396 unsigned char lang[3];
1397 if (mp_dvdnav_lang_from_sid(mpctx->stream, opts->sub_id, lang)) {
1398 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1399 return M_PROPERTY_OK;
1403 #endif
1405 if ((mpctx->demuxer->type == DEMUXER_TYPE_MATROSKA
1406 || mpctx->demuxer->type == DEMUXER_TYPE_LAVF
1407 || mpctx->demuxer->type == DEMUXER_TYPE_LAVF_PREFERRED
1408 || mpctx->demuxer->type == DEMUXER_TYPE_OGG)
1409 && d_sub && d_sub->sh && opts->sub_id >= 0) {
1410 const char* lang = ((sh_sub_t*)d_sub->sh)->lang;
1411 if (!lang) lang = MSGTR_Unknown;
1412 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1413 return M_PROPERTY_OK;
1416 if (vo_vobsub && vobsub_id >= 0) {
1417 const char *language = MSGTR_Unknown;
1418 language = vobsub_get_id(vo_vobsub, (unsigned int) vobsub_id);
1419 snprintf(*(char **) arg, 63, "(%d) %s",
1420 vobsub_id, language ? language : MSGTR_Unknown);
1421 return M_PROPERTY_OK;
1423 #ifdef CONFIG_DVDREAD
1424 if (vo_spudec && mpctx->stream->type == STREAMTYPE_DVD
1425 && opts->sub_id >= 0) {
1426 char lang[3];
1427 int code = dvd_lang_from_sid(mpctx->stream, opts->sub_id);
1428 lang[0] = code >> 8;
1429 lang[1] = code;
1430 lang[2] = 0;
1431 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1432 return M_PROPERTY_OK;
1434 #endif
1435 if (opts->sub_id >= 0) {
1436 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, MSGTR_Unknown);
1437 return M_PROPERTY_OK;
1439 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1440 return M_PROPERTY_OK;
1442 case M_PROPERTY_SET:
1443 if (!arg)
1444 return M_PROPERTY_ERROR;
1445 if (*(int *) arg < -1)
1446 *(int *) arg = -1;
1447 else if (*(int *) arg >= global_sub_size)
1448 *(int *) arg = global_sub_size - 1;
1449 mpctx->global_sub_pos = *(int *) arg;
1450 break;
1451 case M_PROPERTY_STEP_UP:
1452 mpctx->global_sub_pos += 2;
1453 mpctx->global_sub_pos =
1454 (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1455 break;
1456 case M_PROPERTY_STEP_DOWN:
1457 mpctx->global_sub_pos += global_sub_size + 1;
1458 mpctx->global_sub_pos =
1459 (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1460 break;
1461 default:
1462 return M_PROPERTY_NOT_IMPLEMENTED;
1465 if (mpctx->global_sub_pos >= 0)
1466 source = sub_source(mpctx);
1468 mp_msg(MSGT_CPLAYER, MSGL_DBG3,
1469 "subtitles: %d subs, (v@%d s@%d d@%d), @%d, source @%d\n",
1470 global_sub_size,
1471 mpctx->global_sub_indices[SUB_SOURCE_VOBSUB],
1472 mpctx->global_sub_indices[SUB_SOURCE_SUBS],
1473 mpctx->global_sub_indices[SUB_SOURCE_DEMUX],
1474 mpctx->global_sub_pos, source);
1476 mpctx->set_of_sub_pos = -1;
1477 subdata = NULL;
1479 vobsub_id = -1;
1480 opts->sub_id = -1;
1481 if (d_sub) {
1482 if (d_sub->id > -2)
1483 reset_spu = 1;
1484 d_sub->id = -2;
1486 #ifdef CONFIG_ASS
1487 ass_track = 0;
1488 #endif
1490 if (source == SUB_SOURCE_VOBSUB) {
1491 vobsub_id = vobsub_get_id_by_index(vo_vobsub, mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_VOBSUB]);
1492 } else if (source == SUB_SOURCE_SUBS) {
1493 mpctx->set_of_sub_pos =
1494 mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_SUBS];
1495 #ifdef CONFIG_ASS
1496 if (ass_enabled && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos])
1497 ass_track = mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos];
1498 else
1499 #endif
1501 subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos];
1502 vo_osd_changed(OSDTYPE_SUBTITLE);
1504 } else if (source == SUB_SOURCE_DEMUX) {
1505 opts->sub_id =
1506 mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_DEMUX];
1507 if (d_sub && opts->sub_id < MAX_S_STREAMS) {
1508 int i = 0;
1509 // default: assume 1:1 mapping of sid and stream id
1510 d_sub->id = opts->sub_id;
1511 d_sub->sh = mpctx->demuxer->s_streams[d_sub->id];
1512 ds_free_packs(d_sub);
1513 for (i = 0; i < MAX_S_STREAMS; i++) {
1514 sh_sub_t *sh = mpctx->demuxer->s_streams[i];
1515 if (sh && sh->sid == opts->sub_id) {
1516 d_sub->id = i;
1517 d_sub->sh = sh;
1518 break;
1521 if (d_sub->sh && d_sub->id >= 0) {
1522 sh_sub_t *sh = d_sub->sh;
1523 if (sh->type == 'v')
1524 init_vo_spudec(mpctx);
1525 #ifdef CONFIG_ASS
1526 else if (ass_enabled)
1527 ass_track = sh->ass_track;
1528 #endif
1529 } else {
1530 d_sub->id = -2;
1531 d_sub->sh = NULL;
1535 #ifdef CONFIG_DVDREAD
1536 if (vo_spudec
1537 && (mpctx->stream->type == STREAMTYPE_DVD
1538 || mpctx->stream->type == STREAMTYPE_DVDNAV)
1539 && opts->sub_id < 0 && reset_spu) {
1540 opts->sub_id = -2;
1541 d_sub->id = opts->sub_id;
1543 #endif
1544 update_subtitles(mpctx->sh_video, d_sub, 1);
1546 return M_PROPERTY_OK;
1549 /// Selected sub source (RW)
1550 static int mp_property_sub_source(m_option_t *prop, int action, void *arg,
1551 MPContext *mpctx)
1553 int source;
1554 if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1555 return M_PROPERTY_UNAVAILABLE;
1557 switch (action) {
1558 case M_PROPERTY_GET:
1559 if (!arg)
1560 return M_PROPERTY_ERROR;
1561 *(int *) arg = sub_source(mpctx);
1562 return M_PROPERTY_OK;
1563 case M_PROPERTY_PRINT:
1564 if (!arg)
1565 return M_PROPERTY_ERROR;
1566 *(char **) arg = malloc(64);
1567 (*(char **) arg)[63] = 0;
1568 switch (sub_source(mpctx))
1570 case SUB_SOURCE_SUBS:
1571 snprintf(*(char **) arg, 63, MSGTR_SubSourceFile);
1572 break;
1573 case SUB_SOURCE_VOBSUB:
1574 snprintf(*(char **) arg, 63, MSGTR_SubSourceVobsub);
1575 break;
1576 case SUB_SOURCE_DEMUX:
1577 snprintf(*(char **) arg, 63, MSGTR_SubSourceDemux);
1578 break;
1579 default:
1580 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1582 return M_PROPERTY_OK;
1583 case M_PROPERTY_SET:
1584 if (!arg)
1585 return M_PROPERTY_ERROR;
1586 M_PROPERTY_CLAMP(prop, *(int*)arg);
1587 if (*(int *) arg < 0)
1588 mpctx->global_sub_pos = -1;
1589 else if (*(int *) arg != sub_source(mpctx)) {
1590 if (*(int *) arg != sub_source_by_pos(mpctx, mpctx->global_sub_indices[*(int *) arg]))
1591 return M_PROPERTY_UNAVAILABLE;
1592 mpctx->global_sub_pos = mpctx->global_sub_indices[*(int *) arg];
1594 break;
1595 case M_PROPERTY_STEP_UP:
1596 case M_PROPERTY_STEP_DOWN: {
1597 int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1598 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1599 int step = (step_all > 0) ? 1 : -1;
1600 int cur_source = sub_source(mpctx);
1601 source = cur_source;
1602 while (step_all) {
1603 source += step;
1604 if (source >= SUB_SOURCES)
1605 source = -1;
1606 else if (source < -1)
1607 source = SUB_SOURCES - 1;
1608 if (source == cur_source || source == -1 ||
1609 source == sub_source_by_pos(mpctx, mpctx->global_sub_indices[source]))
1610 step_all -= step;
1612 if (source == cur_source)
1613 return M_PROPERTY_OK;
1614 if (source == -1)
1615 mpctx->global_sub_pos = -1;
1616 else
1617 mpctx->global_sub_pos = mpctx->global_sub_indices[source];
1618 break;
1620 default:
1621 return M_PROPERTY_NOT_IMPLEMENTED;
1623 --mpctx->global_sub_pos;
1624 return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx);
1627 /// Selected subtitles from specific source (RW)
1628 static int mp_property_sub_by_type(m_option_t *prop, int action, void *arg,
1629 MPContext *mpctx)
1631 int source, is_cur_source, offset;
1632 if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1633 return M_PROPERTY_UNAVAILABLE;
1635 if (!strcmp(prop->name, "sub_file"))
1636 source = SUB_SOURCE_SUBS;
1637 else if (!strcmp(prop->name, "sub_vob"))
1638 source = SUB_SOURCE_VOBSUB;
1639 else if (!strcmp(prop->name, "sub_demux"))
1640 source = SUB_SOURCE_DEMUX;
1641 else
1642 return M_PROPERTY_ERROR;
1644 offset = mpctx->global_sub_indices[source];
1645 if (offset < 0 || source != sub_source_by_pos(mpctx, offset))
1646 return M_PROPERTY_UNAVAILABLE;
1648 is_cur_source = sub_source(mpctx) == source;
1649 switch (action) {
1650 case M_PROPERTY_GET:
1651 if (!arg)
1652 return M_PROPERTY_ERROR;
1653 if (is_cur_source) {
1654 *(int *) arg = mpctx->global_sub_pos - offset;
1655 if (source == SUB_SOURCE_VOBSUB)
1656 *(int *) arg = vobsub_get_id_by_index(vo_vobsub, *(int *) arg);
1658 else
1659 *(int *) arg = -1;
1660 return M_PROPERTY_OK;
1661 case M_PROPERTY_PRINT:
1662 if (!arg)
1663 return M_PROPERTY_ERROR;
1664 if (is_cur_source)
1665 return mp_property_sub(prop, M_PROPERTY_PRINT, arg, mpctx);
1666 *(char **) arg = malloc(64);
1667 (*(char **) arg)[63] = 0;
1668 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1669 return M_PROPERTY_OK;
1670 case M_PROPERTY_SET:
1671 if (!arg)
1672 return M_PROPERTY_ERROR;
1673 if (*(int *) arg >= 0) {
1674 int index = *(int *)arg;
1675 if (source == SUB_SOURCE_VOBSUB)
1676 index = vobsub_get_index_by_id(vo_vobsub, index);
1677 mpctx->global_sub_pos = offset + index;
1678 if (index < 0 || mpctx->global_sub_pos >= mpctx->global_sub_size
1679 || sub_source(mpctx) != source) {
1680 mpctx->global_sub_pos = -1;
1681 *(int *) arg = -1;
1684 else
1685 mpctx->global_sub_pos = -1;
1686 break;
1687 case M_PROPERTY_STEP_UP:
1688 case M_PROPERTY_STEP_DOWN: {
1689 int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1690 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1691 int step = (step_all > 0) ? 1 : -1;
1692 int max_sub_pos_for_source = -1;
1693 if (!is_cur_source)
1694 mpctx->global_sub_pos = -1;
1695 while (step_all) {
1696 if (mpctx->global_sub_pos == -1) {
1697 if (step > 0)
1698 mpctx->global_sub_pos = offset;
1699 else if (max_sub_pos_for_source == -1) {
1700 // Find max pos for specific source
1701 mpctx->global_sub_pos = mpctx->global_sub_size - 1;
1702 while (mpctx->global_sub_pos >= 0
1703 && sub_source(mpctx) != source)
1704 --mpctx->global_sub_pos;
1706 else
1707 mpctx->global_sub_pos = max_sub_pos_for_source;
1709 else {
1710 mpctx->global_sub_pos += step;
1711 if (mpctx->global_sub_pos < offset ||
1712 mpctx->global_sub_pos >= mpctx->global_sub_size ||
1713 sub_source(mpctx) != source)
1714 mpctx->global_sub_pos = -1;
1716 step_all -= step;
1718 break;
1720 default:
1721 return M_PROPERTY_NOT_IMPLEMENTED;
1723 --mpctx->global_sub_pos;
1724 return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx);
1727 /// Subtitle delay (RW)
1728 static int mp_property_sub_delay(m_option_t *prop, int action, void *arg,
1729 MPContext *mpctx)
1731 if (!mpctx->sh_video)
1732 return M_PROPERTY_UNAVAILABLE;
1733 return m_property_delay(prop, action, arg, &sub_delay);
1736 /// Alignment of text subtitles (RW)
1737 static int mp_property_sub_alignment(m_option_t *prop, int action,
1738 void *arg, MPContext *mpctx)
1740 char *name[] = { MSGTR_Top, MSGTR_Center, MSGTR_Bottom };
1742 if (!mpctx->sh_video || mpctx->global_sub_pos < 0
1743 || sub_source(mpctx) != SUB_SOURCE_SUBS)
1744 return M_PROPERTY_UNAVAILABLE;
1746 switch (action) {
1747 case M_PROPERTY_PRINT:
1748 if (!arg)
1749 return M_PROPERTY_ERROR;
1750 M_PROPERTY_CLAMP(prop, sub_alignment);
1751 *(char **) arg = strdup(name[sub_alignment]);
1752 return M_PROPERTY_OK;
1753 case M_PROPERTY_SET:
1754 if (!arg)
1755 return M_PROPERTY_ERROR;
1756 case M_PROPERTY_STEP_UP:
1757 case M_PROPERTY_STEP_DOWN:
1758 vo_osd_changed(OSDTYPE_SUBTITLE);
1759 default:
1760 return m_property_choice(prop, action, arg, &sub_alignment);
1764 /// Subtitle visibility (RW)
1765 static int mp_property_sub_visibility(m_option_t *prop, int action,
1766 void *arg, MPContext *mpctx)
1768 if (!mpctx->sh_video)
1769 return M_PROPERTY_UNAVAILABLE;
1771 switch (action) {
1772 case M_PROPERTY_SET:
1773 if (!arg)
1774 return M_PROPERTY_ERROR;
1775 case M_PROPERTY_STEP_UP:
1776 case M_PROPERTY_STEP_DOWN:
1777 vo_osd_changed(OSDTYPE_SUBTITLE);
1778 if (vo_spudec)
1779 vo_osd_changed(OSDTYPE_SPU);
1780 default:
1781 return m_property_flag(prop, action, arg, &sub_visibility);
1785 #ifdef CONFIG_ASS
1786 /// Use margins for libass subtitles (RW)
1787 static int mp_property_ass_use_margins(m_option_t *prop, int action,
1788 void *arg, MPContext *mpctx)
1790 if (!mpctx->sh_video)
1791 return M_PROPERTY_UNAVAILABLE;
1793 switch (action) {
1794 case M_PROPERTY_SET:
1795 if (!arg)
1796 return M_PROPERTY_ERROR;
1797 case M_PROPERTY_STEP_UP:
1798 case M_PROPERTY_STEP_DOWN:
1799 ass_force_reload = 1;
1800 default:
1801 return m_property_flag(prop, action, arg, &ass_use_margins);
1804 #endif
1806 /// Show only forced subtitles (RW)
1807 static int mp_property_sub_forced_only(m_option_t *prop, int action,
1808 void *arg, MPContext *mpctx)
1810 if (!vo_spudec)
1811 return M_PROPERTY_UNAVAILABLE;
1813 switch (action) {
1814 case M_PROPERTY_SET:
1815 if (!arg)
1816 return M_PROPERTY_ERROR;
1817 case M_PROPERTY_STEP_UP:
1818 case M_PROPERTY_STEP_DOWN:
1819 m_property_flag(prop, action, arg, &forced_subs_only);
1820 spudec_set_forced_subs_only(vo_spudec, forced_subs_only);
1821 return M_PROPERTY_OK;
1822 default:
1823 return m_property_flag(prop, action, arg, &forced_subs_only);
1828 #ifdef CONFIG_FREETYPE
1829 /// Subtitle scale (RW)
1830 static int mp_property_sub_scale(m_option_t *prop, int action, void *arg,
1831 MPContext *mpctx)
1834 switch (action) {
1835 case M_PROPERTY_SET:
1836 if (!arg)
1837 return M_PROPERTY_ERROR;
1838 M_PROPERTY_CLAMP(prop, *(float *) arg);
1839 #ifdef CONFIG_ASS
1840 if (ass_enabled) {
1841 ass_font_scale = *(float *) arg;
1842 ass_force_reload = 1;
1844 #endif
1845 text_font_scale_factor = *(float *) arg;
1846 force_load_font = 1;
1847 return M_PROPERTY_OK;
1848 case M_PROPERTY_STEP_UP:
1849 case M_PROPERTY_STEP_DOWN:
1850 #ifdef CONFIG_ASS
1851 if (ass_enabled) {
1852 ass_font_scale += (arg ? *(float *) arg : 0.1)*
1853 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1854 M_PROPERTY_CLAMP(prop, ass_font_scale);
1855 ass_force_reload = 1;
1857 #endif
1858 text_font_scale_factor += (arg ? *(float *) arg : 0.1)*
1859 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1860 M_PROPERTY_CLAMP(prop, text_font_scale_factor);
1861 force_load_font = 1;
1862 return M_PROPERTY_OK;
1863 default:
1864 #ifdef CONFIG_ASS
1865 if (ass_enabled)
1866 return m_property_float_ro(prop, action, arg, ass_font_scale);
1867 else
1868 #endif
1869 return m_property_float_ro(prop, action, arg, text_font_scale_factor);
1872 #endif
1874 ///@}
1876 /// \defgroup TVProperties TV properties
1877 /// \ingroup Properties
1878 ///@{
1880 #ifdef CONFIG_TV
1882 /// TV color settings (RW)
1883 static int mp_property_tv_color(m_option_t *prop, int action, void *arg,
1884 MPContext *mpctx)
1886 int r, val;
1887 tvi_handle_t *tvh = mpctx->demuxer->priv;
1888 if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1889 return M_PROPERTY_UNAVAILABLE;
1891 switch (action) {
1892 case M_PROPERTY_SET:
1893 if (!arg)
1894 return M_PROPERTY_ERROR;
1895 M_PROPERTY_CLAMP(prop, *(int *) arg);
1896 return tv_set_color_options(tvh, (int) prop->priv, *(int *) arg);
1897 case M_PROPERTY_GET:
1898 return tv_get_color_options(tvh, (int) prop->priv, arg);
1899 case M_PROPERTY_STEP_UP:
1900 case M_PROPERTY_STEP_DOWN:
1901 if ((r = tv_get_color_options(tvh, (int) prop->priv, &val)) >= 0) {
1902 if (!r)
1903 return M_PROPERTY_ERROR;
1904 val += (arg ? *(int *) arg : 1) *
1905 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1906 M_PROPERTY_CLAMP(prop, val);
1907 return tv_set_color_options(tvh, (int) prop->priv, val);
1909 return M_PROPERTY_ERROR;
1911 return M_PROPERTY_NOT_IMPLEMENTED;
1914 #endif
1916 #ifdef CONFIG_TV_TELETEXT
1917 static int mp_property_teletext_common(m_option_t *prop, int action, void *arg,
1918 MPContext *mpctx)
1920 int val,result;
1921 int base_ioctl=(int)prop->priv;
1923 for teletext's GET,SET,STEP ioctls this is not 0
1924 SET is GET+1
1925 STEP is GET+2
1927 tvi_handle_t *tvh = mpctx->demuxer->priv;
1928 if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1929 return M_PROPERTY_UNAVAILABLE;
1930 if(!base_ioctl)
1931 return M_PROPERTY_ERROR;
1933 switch (action) {
1934 case M_PROPERTY_GET:
1935 if (!arg)
1936 return M_PROPERTY_ERROR;
1937 result=tvh->functions->control(tvh->priv, base_ioctl, arg);
1938 break;
1939 case M_PROPERTY_SET:
1940 if (!arg)
1941 return M_PROPERTY_ERROR;
1942 M_PROPERTY_CLAMP(prop, *(int *) arg);
1943 result=tvh->functions->control(tvh->priv, base_ioctl+1, arg);
1944 break;
1945 case M_PROPERTY_STEP_UP:
1946 case M_PROPERTY_STEP_DOWN:
1947 result=tvh->functions->control(tvh->priv, base_ioctl, &val);
1948 val += (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1949 result=tvh->functions->control(tvh->priv, base_ioctl+1, &val);
1950 break;
1951 default:
1952 return M_PROPERTY_NOT_IMPLEMENTED;
1955 return result == TVI_CONTROL_TRUE ? M_PROPERTY_OK : M_PROPERTY_ERROR;
1958 static int mp_property_teletext_mode(m_option_t *prop, int action, void *arg,
1959 MPContext *mpctx)
1961 tvi_handle_t *tvh = mpctx->demuxer->priv;
1962 int result;
1963 int val;
1965 //with tvh==NULL will fail too
1966 result=mp_property_teletext_common(prop,action,arg,mpctx);
1967 if(result!=M_PROPERTY_OK)
1968 return result;
1970 if(tvh->functions->control(tvh->priv, prop->priv, &val)==TVI_CONTROL_TRUE && val)
1971 mp_input_set_section(mpctx->input, "teletext");
1972 else
1973 mp_input_set_section(mpctx->input, "tv");
1974 return M_PROPERTY_OK;
1977 static int mp_property_teletext_page(m_option_t *prop, int action, void *arg,
1978 MPContext *mpctx)
1980 tvi_handle_t *tvh = mpctx->demuxer->priv;
1981 int result;
1982 int val;
1983 if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1984 return M_PROPERTY_UNAVAILABLE;
1985 switch(action){
1986 case M_PROPERTY_STEP_UP:
1987 case M_PROPERTY_STEP_DOWN:
1988 //This should be handled separately
1989 val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1990 result=tvh->functions->control(tvh->priv, TV_VBI_CONTROL_STEP_PAGE, &val);
1991 break;
1992 default:
1993 result=mp_property_teletext_common(prop,action,arg,mpctx);
1995 return result;
1999 #endif /* CONFIG_TV_TELETEXT */
2001 ///@}
2003 /// All properties available in MPlayer.
2004 /** \ingroup Properties
2006 static const m_option_t mp_properties[] = {
2007 // General
2008 { "osdlevel", mp_property_osdlevel, CONF_TYPE_INT,
2009 M_OPT_RANGE, 0, 3, NULL },
2010 { "loop", mp_property_loop, CONF_TYPE_INT,
2011 M_OPT_MIN, -1, 0, NULL },
2012 { "speed", mp_property_playback_speed, CONF_TYPE_FLOAT,
2013 M_OPT_RANGE, 0.01, 100.0, NULL },
2014 { "filename", mp_property_filename, CONF_TYPE_STRING,
2015 0, 0, 0, NULL },
2016 { "path", mp_property_path, CONF_TYPE_STRING,
2017 0, 0, 0, NULL },
2018 { "demuxer", mp_property_demuxer, CONF_TYPE_STRING,
2019 0, 0, 0, NULL },
2020 { "stream_pos", mp_property_stream_pos, CONF_TYPE_POSITION,
2021 M_OPT_MIN, 0, 0, NULL },
2022 { "stream_start", mp_property_stream_start, CONF_TYPE_POSITION,
2023 M_OPT_MIN, 0, 0, NULL },
2024 { "stream_end", mp_property_stream_end, CONF_TYPE_POSITION,
2025 M_OPT_MIN, 0, 0, NULL },
2026 { "stream_length", mp_property_stream_length, CONF_TYPE_POSITION,
2027 M_OPT_MIN, 0, 0, NULL },
2028 { "length", mp_property_length, CONF_TYPE_TIME,
2029 M_OPT_MIN, 0, 0, NULL },
2030 { "percent_pos", mp_property_percent_pos, CONF_TYPE_INT,
2031 M_OPT_RANGE, 0, 100, NULL },
2032 { "time_pos", mp_property_time_pos, CONF_TYPE_TIME,
2033 M_OPT_MIN, 0, 0, NULL },
2034 { "chapter", mp_property_chapter, CONF_TYPE_INT,
2035 M_OPT_MIN, 1, 0, NULL },
2036 { "chapters", mp_property_chapters, CONF_TYPE_INT,
2037 0, 0, 0, NULL },
2038 { "angle", mp_property_angle, CONF_TYPE_INT,
2039 CONF_RANGE, -2, 10, NULL },
2040 { "metadata", mp_property_metadata, CONF_TYPE_STRING_LIST,
2041 0, 0, 0, NULL },
2042 { "pause", mp_property_pause, CONF_TYPE_FLAG,
2043 M_OPT_RANGE, 0, 1, NULL },
2045 // Audio
2046 { "volume", mp_property_volume, CONF_TYPE_FLOAT,
2047 M_OPT_RANGE, 0, 100, NULL },
2048 { "mute", mp_property_mute, CONF_TYPE_FLAG,
2049 M_OPT_RANGE, 0, 1, NULL },
2050 { "audio_delay", mp_property_audio_delay, CONF_TYPE_FLOAT,
2051 M_OPT_RANGE, -100, 100, NULL },
2052 { "audio_format", mp_property_audio_format, CONF_TYPE_INT,
2053 0, 0, 0, NULL },
2054 { "audio_codec", mp_property_audio_codec, CONF_TYPE_STRING,
2055 0, 0, 0, NULL },
2056 { "audio_bitrate", mp_property_audio_bitrate, CONF_TYPE_INT,
2057 0, 0, 0, NULL },
2058 { "samplerate", mp_property_samplerate, CONF_TYPE_INT,
2059 0, 0, 0, NULL },
2060 { "channels", mp_property_channels, CONF_TYPE_INT,
2061 0, 0, 0, NULL },
2062 { "switch_audio", mp_property_audio, CONF_TYPE_INT,
2063 CONF_RANGE, -2, MAX_A_STREAMS - 1, NULL },
2064 { "balance", mp_property_balance, CONF_TYPE_FLOAT,
2065 M_OPT_RANGE, -1, 1, NULL },
2067 // Video
2068 { "fullscreen", mp_property_fullscreen, CONF_TYPE_FLAG,
2069 M_OPT_RANGE, 0, 1, NULL },
2070 { "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG,
2071 M_OPT_RANGE, 0, 1, NULL },
2072 { "ontop", mp_property_ontop, CONF_TYPE_FLAG,
2073 M_OPT_RANGE, 0, 1, NULL },
2074 { "rootwin", mp_property_rootwin, CONF_TYPE_FLAG,
2075 M_OPT_RANGE, 0, 1, NULL },
2076 { "border", mp_property_border, CONF_TYPE_FLAG,
2077 M_OPT_RANGE, 0, 1, NULL },
2078 { "framedropping", mp_property_framedropping, CONF_TYPE_INT,
2079 M_OPT_RANGE, 0, 2, NULL },
2080 { "gamma", mp_property_gamma, CONF_TYPE_INT,
2081 M_OPT_RANGE, -100, 100, (void *)offsetof(struct MPOpts, vo_gamma_gamma)},
2082 { "brightness", mp_property_gamma, CONF_TYPE_INT,
2083 M_OPT_RANGE, -100, 100, (void *)offsetof(struct MPOpts, vo_gamma_brightness) },
2084 { "contrast", mp_property_gamma, CONF_TYPE_INT,
2085 M_OPT_RANGE, -100, 100, (void *)offsetof(struct MPOpts, vo_gamma_contrast) },
2086 { "saturation", mp_property_gamma, CONF_TYPE_INT,
2087 M_OPT_RANGE, -100, 100, (void *)offsetof(struct MPOpts, vo_gamma_saturation) },
2088 { "hue", mp_property_gamma, CONF_TYPE_INT,
2089 M_OPT_RANGE, -100, 100, (void *)offsetof(struct MPOpts, vo_gamma_hue) },
2090 { "panscan", mp_property_panscan, CONF_TYPE_FLOAT,
2091 M_OPT_RANGE, 0, 1, NULL },
2092 { "vsync", mp_property_vsync, CONF_TYPE_FLAG,
2093 M_OPT_RANGE, 0, 1, NULL },
2094 { "video_format", mp_property_video_format, CONF_TYPE_INT,
2095 0, 0, 0, NULL },
2096 { "video_codec", mp_property_video_codec, CONF_TYPE_STRING,
2097 0, 0, 0, NULL },
2098 { "video_bitrate", mp_property_video_bitrate, CONF_TYPE_INT,
2099 0, 0, 0, NULL },
2100 { "width", mp_property_width, CONF_TYPE_INT,
2101 0, 0, 0, NULL },
2102 { "height", mp_property_height, CONF_TYPE_INT,
2103 0, 0, 0, NULL },
2104 { "fps", mp_property_fps, CONF_TYPE_FLOAT,
2105 0, 0, 0, NULL },
2106 { "aspect", mp_property_aspect, CONF_TYPE_FLOAT,
2107 0, 0, 0, NULL },
2108 { "switch_video", mp_property_video, CONF_TYPE_INT,
2109 CONF_RANGE, -2, MAX_V_STREAMS - 1, NULL },
2110 { "switch_program", mp_property_program, CONF_TYPE_INT,
2111 CONF_RANGE, -1, 65535, NULL },
2113 // Subs
2114 { "sub", mp_property_sub, CONF_TYPE_INT,
2115 M_OPT_MIN, -1, 0, NULL },
2116 { "sub_source", mp_property_sub_source, CONF_TYPE_INT,
2117 M_OPT_RANGE, -1, SUB_SOURCES - 1, NULL },
2118 { "sub_vob", mp_property_sub_by_type, CONF_TYPE_INT,
2119 M_OPT_MIN, -1, 0, NULL },
2120 { "sub_demux", mp_property_sub_by_type, CONF_TYPE_INT,
2121 M_OPT_MIN, -1, 0, NULL },
2122 { "sub_file", mp_property_sub_by_type, CONF_TYPE_INT,
2123 M_OPT_MIN, -1, 0, NULL },
2124 { "sub_delay", mp_property_sub_delay, CONF_TYPE_FLOAT,
2125 0, 0, 0, NULL },
2126 { "sub_pos", mp_property_sub_pos, CONF_TYPE_INT,
2127 M_OPT_RANGE, 0, 100, NULL },
2128 { "sub_alignment", mp_property_sub_alignment, CONF_TYPE_INT,
2129 M_OPT_RANGE, 0, 2, NULL },
2130 { "sub_visibility", mp_property_sub_visibility, CONF_TYPE_FLAG,
2131 M_OPT_RANGE, 0, 1, NULL },
2132 { "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG,
2133 M_OPT_RANGE, 0, 1, NULL },
2134 #ifdef CONFIG_FREETYPE
2135 { "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT,
2136 M_OPT_RANGE, 0, 100, NULL },
2137 #endif
2138 #ifdef CONFIG_ASS
2139 { "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG,
2140 M_OPT_RANGE, 0, 1, NULL },
2141 #endif
2143 #ifdef CONFIG_TV
2144 { "tv_brightness", mp_property_tv_color, CONF_TYPE_INT,
2145 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_BRIGHTNESS },
2146 { "tv_contrast", mp_property_tv_color, CONF_TYPE_INT,
2147 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_CONTRAST },
2148 { "tv_saturation", mp_property_tv_color, CONF_TYPE_INT,
2149 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_SATURATION },
2150 { "tv_hue", mp_property_tv_color, CONF_TYPE_INT,
2151 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_HUE },
2152 #endif
2154 #ifdef CONFIG_TV_TELETEXT
2155 { "teletext_page", mp_property_teletext_page, CONF_TYPE_INT,
2156 M_OPT_RANGE, 100, 899, (void*)TV_VBI_CONTROL_GET_PAGE },
2157 { "teletext_subpage", mp_property_teletext_common, CONF_TYPE_INT,
2158 M_OPT_RANGE, 0, 64, (void*)TV_VBI_CONTROL_GET_SUBPAGE },
2159 { "teletext_mode", mp_property_teletext_mode, CONF_TYPE_FLAG,
2160 M_OPT_RANGE, 0, 1, (void*)TV_VBI_CONTROL_GET_MODE },
2161 { "teletext_format", mp_property_teletext_common, CONF_TYPE_INT,
2162 M_OPT_RANGE, 0, 3, (void*)TV_VBI_CONTROL_GET_FORMAT },
2163 { "teletext_half_page", mp_property_teletext_common, CONF_TYPE_INT,
2164 M_OPT_RANGE, 0, 2, (void*)TV_VBI_CONTROL_GET_HALF_PAGE },
2165 #endif
2167 { NULL, NULL, NULL, 0, 0, 0, NULL }
2171 int mp_property_do(const char *name, int action, void *val, void *ctx)
2173 return m_property_do(mp_properties, name, action, val, ctx);
2176 char* mp_property_print(const char *name, void* ctx)
2178 char* ret = NULL;
2179 if(mp_property_do(name,M_PROPERTY_PRINT,&ret,ctx) <= 0)
2180 return NULL;
2181 return ret;
2184 char *property_expand_string(MPContext *mpctx, char *str)
2186 return m_properties_expand_string(mp_properties, str, mpctx);
2189 void property_print_help(void)
2191 m_properties_print_help_list(mp_properties);
2195 ///@}
2196 // Properties group
2200 * \defgroup Command2Property Command to property bridge
2202 * It is used to handle most commands that just set a property
2203 * and optionally display something on the OSD.
2204 * Two kinds of commands are handled: adjust or toggle.
2206 * Adjust commands take 1 or 2 parameters: <value> <abs>
2207 * If <abs> is non-zero the property is set to the given value
2208 * otherwise it is adjusted.
2210 * Toggle commands take 0 or 1 parameters. With no parameter
2211 * or a value less than the property minimum it just steps the
2212 * property to its next value. Otherwise it sets it to the given
2213 * value.
2218 /// List of the commands that can be handled by setting a property.
2219 static struct {
2220 /// property name
2221 const char *name;
2222 /// cmd id
2223 int cmd;
2224 /// set/adjust or toggle command
2225 int toggle;
2226 /// progressbar type
2227 int osd_progbar;
2228 /// osd msg id if it must be shared
2229 int osd_id;
2230 /// osd msg template
2231 const char *osd_msg;
2232 } set_prop_cmd[] = {
2233 // general
2234 { "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus },
2235 { "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL },
2236 { "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL },
2237 { "pause", MP_CMD_PAUSE, 0, 0, -1, NULL },
2238 // audio
2239 { "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume },
2240 { "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus },
2241 { "audio_delay", MP_CMD_AUDIO_DELAY, 0, 0, -1, MSGTR_AVDelayStatus },
2242 { "switch_audio", MP_CMD_SWITCH_AUDIO, 1, 0, -1, MSGTR_OSDAudio },
2243 { "balance", MP_CMD_BALANCE, 0, OSD_BALANCE, -1, MSGTR_Balance },
2244 // video
2245 { "fullscreen", MP_CMD_VO_FULLSCREEN, 1, 0, -1, NULL },
2246 { "panscan", MP_CMD_PANSCAN, 0, OSD_PANSCAN, -1, MSGTR_Panscan },
2247 { "ontop", MP_CMD_VO_ONTOP, 1, 0, -1, MSGTR_OnTopStatus },
2248 { "rootwin", MP_CMD_VO_ROOTWIN, 1, 0, -1, MSGTR_RootwinStatus },
2249 { "border", MP_CMD_VO_BORDER, 1, 0, -1, MSGTR_BorderStatus },
2250 { "framedropping", MP_CMD_FRAMEDROPPING, 1, 0, -1, MSGTR_FramedroppingStatus },
2251 { "gamma", MP_CMD_GAMMA, 0, OSD_BRIGHTNESS, -1, MSGTR_Gamma },
2252 { "brightness", MP_CMD_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2253 { "contrast", MP_CMD_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2254 { "saturation", MP_CMD_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2255 { "hue", MP_CMD_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2256 { "vsync", MP_CMD_SWITCH_VSYNC, 1, 0, -1, MSGTR_VSyncStatus },
2257 // subs
2258 { "sub", MP_CMD_SUB_SELECT, 1, 0, -1, MSGTR_SubSelectStatus },
2259 { "sub_source", MP_CMD_SUB_SOURCE, 1, 0, -1, MSGTR_SubSourceStatus },
2260 { "sub_vob", MP_CMD_SUB_VOB, 1, 0, -1, MSGTR_SubSelectStatus },
2261 { "sub_demux", MP_CMD_SUB_DEMUX, 1, 0, -1, MSGTR_SubSelectStatus },
2262 { "sub_file", MP_CMD_SUB_FILE, 1, 0, -1, MSGTR_SubSelectStatus },
2263 { "sub_pos", MP_CMD_SUB_POS, 0, 0, -1, MSGTR_SubPosStatus },
2264 { "sub_alignment", MP_CMD_SUB_ALIGNMENT, 1, 0, -1, MSGTR_SubAlignStatus },
2265 { "sub_delay", MP_CMD_SUB_DELAY, 0, 0, OSD_MSG_SUB_DELAY, MSGTR_SubDelayStatus },
2266 { "sub_visibility", MP_CMD_SUB_VISIBILITY, 1, 0, -1, MSGTR_SubVisibleStatus },
2267 { "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1, 0, -1, MSGTR_SubForcedOnlyStatus },
2268 #ifdef CONFIG_FREETYPE
2269 { "sub_scale", MP_CMD_SUB_SCALE, 0, 0, -1, MSGTR_SubScale},
2270 #endif
2271 #ifdef CONFIG_ASS
2272 { "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1, 0, -1, NULL },
2273 #endif
2274 #ifdef CONFIG_TV
2275 { "tv_brightness", MP_CMD_TV_SET_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2276 { "tv_hue", MP_CMD_TV_SET_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2277 { "tv_saturation", MP_CMD_TV_SET_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2278 { "tv_contrast", MP_CMD_TV_SET_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2279 #endif
2280 { NULL, 0, 0, 0, -1, NULL }
2284 /// Handle commands that set a property.
2285 static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd)
2287 int i, r;
2288 m_option_t* prop;
2289 const char *pname;
2291 // look for the command
2292 for (i = 0; set_prop_cmd[i].name; i++)
2293 if (set_prop_cmd[i].cmd == cmd->id)
2294 break;
2295 if (!(pname = set_prop_cmd[i].name))
2296 return 0;
2298 if (mp_property_do(pname,M_PROPERTY_GET_TYPE,&prop,mpctx) <= 0 || !prop)
2299 return 0;
2301 // toggle command
2302 if (set_prop_cmd[i].toggle) {
2303 // set to value
2304 if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min)
2305 r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx);
2306 else
2307 r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx);
2308 } else if (cmd->args[1].v.i) //set
2309 r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx);
2310 else // adjust
2311 r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx);
2313 if (r <= 0)
2314 return 1;
2316 if (set_prop_cmd[i].osd_progbar) {
2317 if (prop->type == CONF_TYPE_INT) {
2318 if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0)
2319 set_osd_bar(mpctx, set_prop_cmd[i].osd_progbar,
2320 set_prop_cmd[i].osd_msg, prop->min, prop->max, r);
2321 } else if (prop->type == CONF_TYPE_FLOAT) {
2322 float f;
2323 if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0)
2324 set_osd_bar(mpctx, set_prop_cmd[i].osd_progbar,
2325 set_prop_cmd[i].osd_msg, prop->min, prop->max, f);
2326 } else
2327 mp_msg(MSGT_CPLAYER, MSGL_ERR,
2328 "Property use an unsupported type.\n");
2329 return 1;
2332 if (set_prop_cmd[i].osd_msg) {
2333 char *val = mp_property_print(pname, mpctx);
2334 if (val) {
2335 set_osd_msg(set_prop_cmd[i].osd_id >=
2336 0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i,
2337 1, osd_duration, set_prop_cmd[i].osd_msg, val);
2338 free(val);
2341 return 1;
2344 #ifdef CONFIG_DVDNAV
2345 static const struct {
2346 const char *name;
2347 const mp_command_type cmd;
2348 } mp_dvdnav_bindings[] = {
2349 { "up", MP_CMD_DVDNAV_UP },
2350 { "down", MP_CMD_DVDNAV_DOWN },
2351 { "left", MP_CMD_DVDNAV_LEFT },
2352 { "right", MP_CMD_DVDNAV_RIGHT },
2353 { "menu", MP_CMD_DVDNAV_MENU },
2354 { "select", MP_CMD_DVDNAV_SELECT },
2355 { "prev", MP_CMD_DVDNAV_PREVMENU },
2356 { "mouse", MP_CMD_DVDNAV_MOUSECLICK },
2359 * keep old dvdnav sub-command options for a while in order not to
2360 * break slave-mode API too suddenly.
2362 { "1", MP_CMD_DVDNAV_UP },
2363 { "2", MP_CMD_DVDNAV_DOWN },
2364 { "3", MP_CMD_DVDNAV_LEFT },
2365 { "4", MP_CMD_DVDNAV_RIGHT },
2366 { "5", MP_CMD_DVDNAV_MENU },
2367 { "6", MP_CMD_DVDNAV_SELECT },
2368 { "7", MP_CMD_DVDNAV_PREVMENU },
2369 { "8", MP_CMD_DVDNAV_MOUSECLICK },
2370 { NULL, 0 }
2372 #endif
2374 void run_command(MPContext *mpctx, mp_cmd_t *cmd)
2376 struct MPOpts *opts = &mpctx->opts;
2377 sh_audio_t * const sh_audio = mpctx->sh_audio;
2378 sh_video_t * const sh_video = mpctx->sh_video;
2379 if (!set_property_command(mpctx, cmd))
2380 switch (cmd->id) {
2381 case MP_CMD_SEEK:{
2382 float v;
2383 int abs;
2384 if (sh_video)
2385 mpctx->osd_show_percentage = sh_video->fps;
2386 v = cmd->args[0].v.f;
2387 abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
2388 if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */
2389 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
2390 if (sh_video)
2391 mpctx->osd_function =
2392 (v > sh_video->pts) ? OSD_FFW : OSD_REW;
2393 mpctx->rel_seek_secs = v;
2394 } else if (abs) { /* Absolute seek by percentage */
2395 mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
2396 if (sh_video)
2397 mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
2398 mpctx->rel_seek_secs = v / 100.0;
2399 } else {
2400 mpctx->rel_seek_secs += v;
2401 mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
2404 break;
2406 case MP_CMD_SET_PROPERTY:{
2407 int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE,
2408 cmd->args[1].v.s, mpctx);
2409 if (r == M_PROPERTY_UNKNOWN)
2410 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2411 "Unknown property: '%s'\n", cmd->args[0].v.s);
2412 else if (r <= 0)
2413 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2414 "Failed to set property '%s' to '%s'.\n",
2415 cmd->args[0].v.s, cmd->args[1].v.s);
2417 break;
2419 case MP_CMD_STEP_PROPERTY:{
2420 void* arg = NULL;
2421 int r,i;
2422 double d;
2423 off_t o;
2424 if (cmd->args[1].v.f) {
2425 m_option_t* prop;
2426 if((r = mp_property_do(cmd->args[0].v.s,
2427 M_PROPERTY_GET_TYPE,
2428 &prop, mpctx)) <= 0)
2429 goto step_prop_err;
2430 if(prop->type == CONF_TYPE_INT ||
2431 prop->type == CONF_TYPE_FLAG)
2432 i = cmd->args[1].v.f, arg = &i;
2433 else if(prop->type == CONF_TYPE_FLOAT)
2434 arg = &cmd->args[1].v.f;
2435 else if(prop->type == CONF_TYPE_DOUBLE ||
2436 prop->type == CONF_TYPE_TIME)
2437 d = cmd->args[1].v.f, arg = &d;
2438 else if(prop->type == CONF_TYPE_POSITION)
2439 o = cmd->args[1].v.f, arg = &o;
2440 else
2441 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2442 "Ignoring step size stepping property '%s'.\n",
2443 cmd->args[0].v.s);
2445 r = mp_property_do(cmd->args[0].v.s,
2446 cmd->args[2].v.i < 0 ?
2447 M_PROPERTY_STEP_DOWN : M_PROPERTY_STEP_UP,
2448 arg, mpctx);
2449 step_prop_err:
2450 if (r == M_PROPERTY_UNKNOWN)
2451 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2452 "Unknown property: '%s'\n", cmd->args[0].v.s);
2453 else if (r <= 0)
2454 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2455 "Failed to increment property '%s' by %f.\n",
2456 cmd->args[0].v.s, cmd->args[1].v.f);
2458 break;
2460 case MP_CMD_GET_PROPERTY:{
2461 char *tmp;
2462 if (mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING,
2463 &tmp, mpctx) <= 0) {
2464 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2465 "Failed to get value of property '%s'.\n",
2466 cmd->args[0].v.s);
2467 break;
2469 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n",
2470 cmd->args[0].v.s, tmp);
2471 free(tmp);
2473 break;
2475 case MP_CMD_EDL_MARK:
2476 if (edl_fd) {
2477 float v = sh_video ? sh_video->pts :
2478 playing_audio_pts(mpctx);
2479 if (mpctx->begin_skip == MP_NOPTS_VALUE) {
2480 mpctx->begin_skip = v;
2481 mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutStartSkip);
2482 } else {
2483 if (mpctx->begin_skip > v)
2484 mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_EdloutBadStop);
2485 else {
2486 fprintf(edl_fd, "%f %f %d\n", mpctx->begin_skip, v, 0);
2487 mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutEndSkip);
2489 mpctx->begin_skip = MP_NOPTS_VALUE;
2492 break;
2494 case MP_CMD_SWITCH_RATIO:
2495 if (cmd->nargs == 0 || cmd->args[0].v.f == -1)
2496 opts->movie_aspect = (float) sh_video->disp_w / sh_video->disp_h;
2497 else
2498 opts->movie_aspect = cmd->args[0].v.f;
2499 mpcodecs_config_vo(sh_video, sh_video->disp_w, sh_video->disp_h, 0);
2500 break;
2502 case MP_CMD_SPEED_INCR:{
2503 float v = cmd->args[0].v.f;
2504 opts->playback_speed += v;
2505 build_afilter_chain(mpctx, sh_audio, &ao_data);
2506 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2507 opts->playback_speed);
2508 } break;
2510 case MP_CMD_SPEED_MULT:{
2511 float v = cmd->args[0].v.f;
2512 opts->playback_speed *= v;
2513 build_afilter_chain(mpctx, sh_audio, &ao_data);
2514 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2515 opts->playback_speed);
2516 } break;
2518 case MP_CMD_SPEED_SET:{
2519 float v = cmd->args[0].v.f;
2520 opts->playback_speed = v;
2521 build_afilter_chain(mpctx, sh_audio, &ao_data);
2522 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2523 opts->playback_speed);
2524 } break;
2526 case MP_CMD_FRAME_STEP:
2527 add_step_frame(mpctx);
2528 break;
2530 case MP_CMD_FILE_FILTER:
2531 file_filter = cmd->args[0].v.i;
2532 break;
2534 case MP_CMD_QUIT:
2535 exit_player_with_rc(mpctx, EXIT_QUIT,
2536 (cmd->nargs > 0) ? cmd->args[0].v.i : 0);
2538 case MP_CMD_PLAY_TREE_STEP:{
2539 int n = cmd->args[0].v.i == 0 ? 1 : cmd->args[0].v.i;
2540 int force = cmd->args[1].v.i;
2542 #ifdef CONFIG_GUI
2543 if (use_gui) {
2544 int i = 0;
2545 if (n > 0)
2546 for (i = 0; i < n; i++)
2547 mplNext();
2548 else
2549 for (i = 0; i < -1 * n; i++)
2550 mplPrev();
2551 } else
2552 #endif
2554 if (!force && mpctx->playtree_iter) {
2555 play_tree_iter_t *i =
2556 play_tree_iter_new_copy(mpctx->playtree_iter);
2557 if (play_tree_iter_step(i, n, 0) ==
2558 PLAY_TREE_ITER_ENTRY)
2559 mpctx->stop_play =
2560 (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2561 play_tree_iter_free(i);
2562 } else
2563 mpctx->stop_play = (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2564 if (mpctx->stop_play)
2565 mpctx->play_tree_step = n;
2568 break;
2570 case MP_CMD_PLAY_TREE_UP_STEP:{
2571 int n = cmd->args[0].v.i > 0 ? 1 : -1;
2572 int force = cmd->args[1].v.i;
2574 if (!force && mpctx->playtree_iter) {
2575 play_tree_iter_t *i =
2576 play_tree_iter_new_copy(mpctx->playtree_iter);
2577 if (play_tree_iter_up_step(i, n, 0) == PLAY_TREE_ITER_ENTRY)
2578 mpctx->stop_play = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2579 play_tree_iter_free(i);
2580 } else
2581 mpctx->stop_play = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2583 break;
2585 case MP_CMD_PLAY_ALT_SRC_STEP:
2586 if (mpctx->playtree_iter && mpctx->playtree_iter->num_files > 1) {
2587 int v = cmd->args[0].v.i;
2588 if (v > 0
2589 && mpctx->playtree_iter->file <
2590 mpctx->playtree_iter->num_files)
2591 mpctx->stop_play = PT_NEXT_SRC;
2592 else if (v < 0 && mpctx->playtree_iter->file > 1)
2593 mpctx->stop_play = PT_PREV_SRC;
2595 break;
2597 case MP_CMD_SUB_STEP:
2598 if (sh_video) {
2599 int movement = cmd->args[0].v.i;
2600 step_sub(subdata, sh_video->pts, movement);
2601 #ifdef CONFIG_ASS
2602 if (ass_track)
2603 sub_delay +=
2604 ass_step_sub(ass_track,
2605 (sh_video->pts +
2606 sub_delay) * 1000 + .5, movement) / 1000.;
2607 #endif
2608 set_osd_msg(OSD_MSG_SUB_DELAY, 1, osd_duration,
2609 MSGTR_OSDSubDelay, ROUND(sub_delay * 1000));
2611 break;
2613 case MP_CMD_SUB_LOG:
2614 log_sub(mpctx);
2615 break;
2617 case MP_CMD_OSD:{
2618 int v = cmd->args[0].v.i;
2619 int max = (term_osd
2620 && !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL;
2621 if (osd_level > max)
2622 osd_level = max;
2623 if (v < 0)
2624 osd_level = (osd_level + 1) % (max + 1);
2625 else
2626 osd_level = v > max ? max : v;
2627 /* Show OSD state when disabled, but not when an explicit
2628 argument is given to the OSD command, i.e. in slave mode. */
2629 if (v == -1 && osd_level <= 1)
2630 set_osd_msg(OSD_MSG_OSD_STATUS, 0, osd_duration,
2631 MSGTR_OSDosd,
2632 osd_level ? MSGTR_OSDenabled :
2633 MSGTR_OSDdisabled);
2634 else
2635 rm_osd_msg(OSD_MSG_OSD_STATUS);
2637 break;
2639 case MP_CMD_OSD_SHOW_TEXT:
2640 set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2641 (cmd->args[1].v.i <
2642 0 ? osd_duration : cmd->args[1].v.i),
2643 "%-.63s", cmd->args[0].v.s);
2644 break;
2646 case MP_CMD_OSD_SHOW_PROPERTY_TEXT:{
2647 char *txt = m_properties_expand_string(mp_properties,
2648 cmd->args[0].v.s,
2649 mpctx);
2650 /* if no argument supplied take default osd_duration, else <arg> ms. */
2651 if (txt) {
2652 set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2653 (cmd->args[1].v.i <
2654 0 ? osd_duration : cmd->args[1].v.i),
2655 "%-.63s", txt);
2656 free(txt);
2659 break;
2661 case MP_CMD_LOADFILE:{
2662 play_tree_t *e = play_tree_new();
2663 play_tree_add_file(e, cmd->args[0].v.s);
2665 if (cmd->args[1].v.i) // append
2666 play_tree_append_entry(mpctx->playtree->child, e);
2667 else {
2668 // Go back to the starting point.
2669 while (play_tree_iter_up_step
2670 (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END)
2671 /* NOP */ ;
2672 play_tree_free_list(mpctx->playtree->child, 1);
2673 play_tree_set_child(mpctx->playtree, e);
2674 pt_iter_goto_head(mpctx->playtree_iter);
2675 mpctx->stop_play = PT_NEXT_SRC;
2678 break;
2680 case MP_CMD_LOADLIST:{
2681 play_tree_t *e = parse_playlist_file(mpctx->mconfig, cmd->args[0].v.s);
2682 if (!e)
2683 mp_msg(MSGT_CPLAYER, MSGL_ERR,
2684 MSGTR_PlaylistLoadUnable, cmd->args[0].v.s);
2685 else {
2686 if (cmd->args[1].v.i) // append
2687 play_tree_append_entry(mpctx->playtree->child, e);
2688 else {
2689 // Go back to the starting point.
2690 while (play_tree_iter_up_step
2691 (mpctx->playtree_iter, 0, 1)
2692 != PLAY_TREE_ITER_END)
2693 /* NOP */ ;
2694 play_tree_free_list(mpctx->playtree->child, 1);
2695 play_tree_set_child(mpctx->playtree, e);
2696 pt_iter_goto_head(mpctx->playtree_iter);
2697 mpctx->stop_play = PT_NEXT_SRC;
2701 break;
2703 case MP_CMD_STOP:
2704 // Go back to the starting point.
2705 while (play_tree_iter_up_step
2706 (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END)
2707 /* NOP */ ;
2708 mpctx->stop_play = PT_STOP;
2709 break;
2711 #ifdef CONFIG_RADIO
2712 case MP_CMD_RADIO_STEP_CHANNEL:
2713 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
2714 int v = cmd->args[0].v.i;
2715 if (v > 0)
2716 radio_step_channel(mpctx->demuxer->stream,
2717 RADIO_CHANNEL_HIGHER);
2718 else
2719 radio_step_channel(mpctx->demuxer->stream,
2720 RADIO_CHANNEL_LOWER);
2721 if (radio_get_channel_name(mpctx->demuxer->stream)) {
2722 set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2723 MSGTR_OSDChannel,
2724 radio_get_channel_name(mpctx->demuxer->stream));
2727 break;
2729 case MP_CMD_RADIO_SET_CHANNEL:
2730 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
2731 radio_set_channel(mpctx->demuxer->stream, cmd->args[0].v.s);
2732 if (radio_get_channel_name(mpctx->demuxer->stream)) {
2733 set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2734 MSGTR_OSDChannel,
2735 radio_get_channel_name(mpctx->demuxer->stream));
2738 break;
2740 case MP_CMD_RADIO_SET_FREQ:
2741 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
2742 radio_set_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2743 break;
2745 case MP_CMD_RADIO_STEP_FREQ:
2746 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
2747 radio_step_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2748 break;
2749 #endif
2751 #ifdef CONFIG_TV
2752 case MP_CMD_TV_START_SCAN:
2753 if (mpctx->file_format == DEMUXER_TYPE_TV)
2754 tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv),1);
2755 break;
2756 case MP_CMD_TV_SET_FREQ:
2757 if (mpctx->file_format == DEMUXER_TYPE_TV)
2758 tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
2759 cmd->args[0].v.f * 16.0);
2760 #ifdef CONFIG_PVR
2761 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2762 pvr_set_freq (mpctx->stream, ROUND (cmd->args[0].v.f));
2763 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2764 pvr_get_current_channelname (mpctx->stream),
2765 pvr_get_current_stationname (mpctx->stream));
2767 #endif /* CONFIG_PVR */
2768 break;
2770 case MP_CMD_TV_STEP_FREQ:
2771 if (mpctx->file_format == DEMUXER_TYPE_TV)
2772 tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
2773 cmd->args[0].v.f * 16.0);
2774 #ifdef CONFIG_PVR
2775 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2776 pvr_force_freq_step (mpctx->stream, ROUND (cmd->args[0].v.f));
2777 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d",
2778 pvr_get_current_channelname (mpctx->stream),
2779 pvr_get_current_frequency (mpctx->stream));
2781 #endif /* CONFIG_PVR */
2782 break;
2784 case MP_CMD_TV_SET_NORM:
2785 if (mpctx->file_format == DEMUXER_TYPE_TV)
2786 tv_set_norm((tvi_handle_t *) (mpctx->demuxer->priv),
2787 cmd->args[0].v.s);
2788 break;
2790 case MP_CMD_TV_STEP_CHANNEL:{
2791 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2792 int v = cmd->args[0].v.i;
2793 if (v > 0) {
2794 tv_step_channel((tvi_handle_t *) (mpctx->
2795 demuxer->priv),
2796 TV_CHANNEL_HIGHER);
2797 } else {
2798 tv_step_channel((tvi_handle_t *) (mpctx->
2799 demuxer->priv),
2800 TV_CHANNEL_LOWER);
2802 if (tv_channel_list) {
2803 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2804 MSGTR_OSDChannel, tv_channel_current->name);
2805 //vo_osd_changed(OSDTYPE_SUBTITLE);
2808 #ifdef CONFIG_PVR
2809 else if (mpctx->stream &&
2810 mpctx->stream->type == STREAMTYPE_PVR) {
2811 pvr_set_channel_step (mpctx->stream, cmd->args[0].v.i);
2812 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2813 pvr_get_current_channelname (mpctx->stream),
2814 pvr_get_current_stationname (mpctx->stream));
2816 #endif /* CONFIG_PVR */
2818 #ifdef CONFIG_DVBIN
2819 if (mpctx->stream->type == STREAMTYPE_DVB) {
2820 int dir;
2821 int v = cmd->args[0].v.i;
2823 mpctx->last_dvb_step = v;
2824 if (v > 0)
2825 dir = DVB_CHANNEL_HIGHER;
2826 else
2827 dir = DVB_CHANNEL_LOWER;
2830 if (dvb_step_channel(mpctx->stream, dir)) {
2831 mpctx->stop_play = PT_NEXT_ENTRY;
2832 mpctx->dvbin_reopen = 1;
2835 #endif /* CONFIG_DVBIN */
2836 break;
2838 case MP_CMD_TV_SET_CHANNEL:
2839 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2840 tv_set_channel((tvi_handle_t *) (mpctx->demuxer->priv),
2841 cmd->args[0].v.s);
2842 if (tv_channel_list) {
2843 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2844 MSGTR_OSDChannel, tv_channel_current->name);
2845 //vo_osd_changed(OSDTYPE_SUBTITLE);
2848 #ifdef CONFIG_PVR
2849 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2850 pvr_set_channel (mpctx->stream, cmd->args[0].v.s);
2851 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2852 pvr_get_current_channelname (mpctx->stream),
2853 pvr_get_current_stationname (mpctx->stream));
2855 #endif /* CONFIG_PVR */
2856 break;
2858 #ifdef CONFIG_DVBIN
2859 case MP_CMD_DVB_SET_CHANNEL:
2860 if (mpctx->stream->type == STREAMTYPE_DVB) {
2861 mpctx->last_dvb_step = 1;
2863 if (dvb_set_channel(mpctx->stream, cmd->args[1].v.i,
2864 cmd->args[0].v.i)) {
2865 mpctx->stop_play = PT_NEXT_ENTRY;
2866 mpctx->dvbin_reopen = 1;
2869 break;
2870 #endif /* CONFIG_DVBIN */
2872 case MP_CMD_TV_LAST_CHANNEL:
2873 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2874 tv_last_channel((tvi_handle_t *) (mpctx->demuxer->priv));
2875 if (tv_channel_list) {
2876 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2877 MSGTR_OSDChannel, tv_channel_current->name);
2878 //vo_osd_changed(OSDTYPE_SUBTITLE);
2881 #ifdef CONFIG_PVR
2882 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2883 pvr_set_lastchannel (mpctx->stream);
2884 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2885 pvr_get_current_channelname (mpctx->stream),
2886 pvr_get_current_stationname (mpctx->stream));
2888 #endif /* CONFIG_PVR */
2889 break;
2891 case MP_CMD_TV_STEP_NORM:
2892 if (mpctx->file_format == DEMUXER_TYPE_TV)
2893 tv_step_norm((tvi_handle_t *) (mpctx->demuxer->priv));
2894 break;
2896 case MP_CMD_TV_STEP_CHANNEL_LIST:
2897 if (mpctx->file_format == DEMUXER_TYPE_TV)
2898 tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv));
2899 break;
2900 #ifdef CONFIG_TV_TELETEXT
2901 case MP_CMD_TV_TELETEXT_ADD_DEC:
2903 tvi_handle_t* tvh=(tvi_handle_t *)(mpctx->demuxer->priv);
2904 if (mpctx->file_format == DEMUXER_TYPE_TV)
2905 tvh->functions->control(tvh->priv,TV_VBI_CONTROL_ADD_DEC,&(cmd->args[0].v.s));
2906 break;
2908 case MP_CMD_TV_TELETEXT_GO_LINK:
2910 tvi_handle_t* tvh=(tvi_handle_t *)(mpctx->demuxer->priv);
2911 if (mpctx->file_format == DEMUXER_TYPE_TV)
2912 tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GO_LINK,&(cmd->args[0].v.i));
2913 break;
2915 #endif /* CONFIG_TV_TELETEXT */
2916 #endif /* CONFIG_TV */
2918 case MP_CMD_SUB_LOAD:
2919 if (sh_video) {
2920 int n = mpctx->set_of_sub_size;
2921 add_subtitles(mpctx, cmd->args[0].v.s, sh_video->fps, 0);
2922 if (n != mpctx->set_of_sub_size) {
2923 if (mpctx->global_sub_indices[SUB_SOURCE_SUBS] < 0)
2924 mpctx->global_sub_indices[SUB_SOURCE_SUBS] =
2925 mpctx->global_sub_size;
2926 ++mpctx->global_sub_size;
2929 break;
2931 case MP_CMD_SUB_REMOVE:
2932 if (sh_video) {
2933 int v = cmd->args[0].v.i;
2934 sub_data *subd;
2935 if (v < 0) {
2936 for (v = 0; v < mpctx->set_of_sub_size; ++v) {
2937 subd = mpctx->set_of_subtitles[v];
2938 mp_msg(MSGT_CPLAYER, MSGL_STATUS,
2939 MSGTR_RemovedSubtitleFile, v + 1,
2940 filename_recode(subd->filename));
2941 sub_free(subd);
2942 mpctx->set_of_subtitles[v] = NULL;
2944 mpctx->global_sub_indices[SUB_SOURCE_SUBS] = -1;
2945 mpctx->global_sub_size -= mpctx->set_of_sub_size;
2946 mpctx->set_of_sub_size = 0;
2947 if (mpctx->set_of_sub_pos >= 0) {
2948 mpctx->global_sub_pos = -2;
2949 subdata = NULL;
2950 mp_input_queue_cmd(mpctx->input,
2951 mp_input_parse_cmd("sub_select"));
2953 } else if (v < mpctx->set_of_sub_size) {
2954 subd = mpctx->set_of_subtitles[v];
2955 mp_msg(MSGT_CPLAYER, MSGL_STATUS,
2956 MSGTR_RemovedSubtitleFile, v + 1,
2957 filename_recode(subd->filename));
2958 sub_free(subd);
2959 if (mpctx->set_of_sub_pos == v) {
2960 mpctx->global_sub_pos = -2;
2961 subdata = NULL;
2962 mp_input_queue_cmd(mpctx->input,
2963 mp_input_parse_cmd("sub_select"));
2964 } else if (mpctx->set_of_sub_pos > v) {
2965 --mpctx->set_of_sub_pos;
2966 --mpctx->global_sub_pos;
2968 while (++v < mpctx->set_of_sub_size)
2969 mpctx->set_of_subtitles[v - 1] =
2970 mpctx->set_of_subtitles[v];
2971 --mpctx->set_of_sub_size;
2972 --mpctx->global_sub_size;
2973 if (mpctx->set_of_sub_size <= 0)
2974 mpctx->global_sub_indices[SUB_SOURCE_SUBS] = -1;
2975 mpctx->set_of_subtitles[mpctx->set_of_sub_size] = NULL;
2978 break;
2980 case MP_CMD_GET_SUB_VISIBILITY:
2981 if (sh_video) {
2982 mp_msg(MSGT_GLOBAL, MSGL_INFO,
2983 "ANS_SUB_VISIBILITY=%d\n", sub_visibility);
2985 break;
2987 case MP_CMD_SCREENSHOT:
2988 if (mpctx->video_out && mpctx->video_out->config_ok) {
2989 mp_msg(MSGT_CPLAYER, MSGL_INFO, "sending VFCTRL_SCREENSHOT!\n");
2990 if (CONTROL_OK !=
2991 ((vf_instance_t *) sh_video->vfilter)->
2992 control(sh_video->vfilter, VFCTRL_SCREENSHOT,
2993 &cmd->args[0].v.i))
2994 mp_msg(MSGT_CPLAYER, MSGL_INFO, "failed (forgot -vf screenshot?)\n");
2996 break;
2998 case MP_CMD_VF_CHANGE_RECTANGLE:
2999 set_rectangle(sh_video, cmd->args[0].v.i, cmd->args[1].v.i);
3000 break;
3002 case MP_CMD_GET_TIME_LENGTH:{
3003 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_LENGTH=%.2lf\n",
3004 demuxer_get_time_length(mpctx->demuxer));
3006 break;
3008 case MP_CMD_GET_FILENAME:{
3009 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_FILENAME='%s'\n",
3010 get_metadata(mpctx, META_NAME));
3012 break;
3014 case MP_CMD_GET_VIDEO_CODEC:{
3015 char *inf = get_metadata(mpctx, META_VIDEO_CODEC);
3016 if (!inf)
3017 inf = strdup("");
3018 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_CODEC='%s'\n", inf);
3019 free(inf);
3021 break;
3023 case MP_CMD_GET_VIDEO_BITRATE:{
3024 char *inf = get_metadata(mpctx, META_VIDEO_BITRATE);
3025 if (!inf)
3026 inf = strdup("");
3027 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_BITRATE='%s'\n", inf);
3028 free(inf);
3030 break;
3032 case MP_CMD_GET_VIDEO_RESOLUTION:{
3033 char *inf = get_metadata(mpctx, META_VIDEO_RESOLUTION);
3034 if (!inf)
3035 inf = strdup("");
3036 mp_msg(MSGT_GLOBAL, MSGL_INFO,
3037 "ANS_VIDEO_RESOLUTION='%s'\n", inf);
3038 free(inf);
3040 break;
3042 case MP_CMD_GET_AUDIO_CODEC:{
3043 char *inf = get_metadata(mpctx, META_AUDIO_CODEC);
3044 if (!inf)
3045 inf = strdup("");
3046 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_CODEC='%s'\n", inf);
3047 free(inf);
3049 break;
3051 case MP_CMD_GET_AUDIO_BITRATE:{
3052 char *inf = get_metadata(mpctx, META_AUDIO_BITRATE);
3053 if (!inf)
3054 inf = strdup("");
3055 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_BITRATE='%s'\n", inf);
3056 free(inf);
3058 break;
3060 case MP_CMD_GET_AUDIO_SAMPLES:{
3061 char *inf = get_metadata(mpctx, META_AUDIO_SAMPLES);
3062 if (!inf)
3063 inf = strdup("");
3064 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_SAMPLES='%s'\n", inf);
3065 free(inf);
3067 break;
3069 case MP_CMD_GET_META_TITLE:{
3070 char *inf = get_metadata(mpctx, META_INFO_TITLE);
3071 if (!inf)
3072 inf = strdup("");
3073 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TITLE='%s'\n", inf);
3074 free(inf);
3076 break;
3078 case MP_CMD_GET_META_ARTIST:{
3079 char *inf = get_metadata(mpctx, META_INFO_ARTIST);
3080 if (!inf)
3081 inf = strdup("");
3082 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ARTIST='%s'\n", inf);
3083 free(inf);
3085 break;
3087 case MP_CMD_GET_META_ALBUM:{
3088 char *inf = get_metadata(mpctx, META_INFO_ALBUM);
3089 if (!inf)
3090 inf = strdup("");
3091 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ALBUM='%s'\n", inf);
3092 free(inf);
3094 break;
3096 case MP_CMD_GET_META_YEAR:{
3097 char *inf = get_metadata(mpctx, META_INFO_YEAR);
3098 if (!inf)
3099 inf = strdup("");
3100 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_YEAR='%s'\n", inf);
3101 free(inf);
3103 break;
3105 case MP_CMD_GET_META_COMMENT:{
3106 char *inf = get_metadata(mpctx, META_INFO_COMMENT);
3107 if (!inf)
3108 inf = strdup("");
3109 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_COMMENT='%s'\n", inf);
3110 free(inf);
3112 break;
3114 case MP_CMD_GET_META_TRACK:{
3115 char *inf = get_metadata(mpctx, META_INFO_TRACK);
3116 if (!inf)
3117 inf = strdup("");
3118 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TRACK='%s'\n", inf);
3119 free(inf);
3121 break;
3123 case MP_CMD_GET_META_GENRE:{
3124 char *inf = get_metadata(mpctx, META_INFO_GENRE);
3125 if (!inf)
3126 inf = strdup("");
3127 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_GENRE='%s'\n", inf);
3128 free(inf);
3130 break;
3132 case MP_CMD_GET_VO_FULLSCREEN:
3133 if (mpctx->video_out && mpctx->video_out->config_ok)
3134 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VO_FULLSCREEN=%d\n", vo_fs);
3135 break;
3137 case MP_CMD_GET_PERCENT_POS:
3138 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_PERCENT_POSITION=%d\n",
3139 demuxer_get_percent_pos(mpctx->demuxer));
3140 break;
3142 case MP_CMD_GET_TIME_POS:{
3143 float pos = 0;
3144 if (sh_video)
3145 pos = sh_video->pts;
3146 else if (sh_audio && mpctx->audio_out)
3147 pos = playing_audio_pts(mpctx);
3148 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_TIME_POSITION=%.1f\n", pos);
3150 break;
3152 case MP_CMD_RUN:
3153 #ifndef __MINGW32__
3154 if (!fork()) {
3155 execl("/bin/sh", "sh", "-c", cmd->args[0].v.s, NULL);
3156 exit(0);
3158 #endif
3159 break;
3161 case MP_CMD_KEYDOWN_EVENTS:
3162 mplayer_put_key(mpctx->key_fifo, cmd->args[0].v.i);
3163 break;
3165 case MP_CMD_SET_MOUSE_POS:{
3166 int pointer_x, pointer_y;
3167 double dx, dy;
3168 pointer_x = cmd->args[0].v.i;
3169 pointer_y = cmd->args[1].v.i;
3170 rescale_input_coordinates(mpctx, pointer_x, pointer_y, &dx, &dy);
3171 #ifdef CONFIG_DVDNAV
3172 if (mpctx->stream->type == STREAMTYPE_DVDNAV
3173 && dx > 0.0 && dy > 0.0) {
3174 int button = -1;
3175 pointer_x = (int) (dx * (double) sh_video->disp_w);
3176 pointer_y = (int) (dy * (double) sh_video->disp_h);
3177 mp_dvdnav_update_mouse_pos(mpctx->stream,
3178 pointer_x, pointer_y, &button);
3179 if (osd_level > 1 && button > 0)
3180 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3181 "Selected button number %d", button);
3183 #endif
3184 #ifdef CONFIG_MENU
3185 if (use_menu && dx >= 0.0 && dy >= 0.0)
3186 menu_update_mouse_pos(dx, dy);
3187 #endif
3189 break;
3191 #ifdef CONFIG_DVDNAV
3192 case MP_CMD_DVDNAV:{
3193 int button = -1;
3194 int i;
3195 mp_command_type command = 0;
3196 if (mpctx->stream->type != STREAMTYPE_DVDNAV)
3197 break;
3199 for (i = 0; mp_dvdnav_bindings[i].name; i++)
3200 if (cmd->args[0].v.s &&
3201 !strcasecmp (cmd->args[0].v.s,
3202 mp_dvdnav_bindings[i].name))
3203 command = mp_dvdnav_bindings[i].cmd;
3205 mp_dvdnav_handle_input(mpctx->stream,command,&button);
3206 if (osd_level > 1 && button > 0)
3207 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3208 "Selected button number %d", button);
3210 break;
3212 case MP_CMD_SWITCH_TITLE:
3213 if (mpctx->stream->type == STREAMTYPE_DVDNAV)
3214 mp_dvdnav_switch_title(mpctx->stream, cmd->args[0].v.i);
3215 break;
3217 #endif
3219 default:
3220 #ifdef CONFIG_GUI
3221 if ((use_gui) && (cmd->id > MP_CMD_GUI_EVENTS))
3222 guiGetEvent(guiIEvent, (char *) cmd->id);
3223 else
3224 #endif
3225 mp_msg(MSGT_CPLAYER, MSGL_V,
3226 "Received unknown cmd %s\n", cmd->name);
3229 switch (cmd->pausing) {
3230 case 1: // "pausing"
3231 pause_player(mpctx);
3232 break;
3233 case 3: // "pausing_toggle"
3234 if (mpctx->paused)
3235 unpause_player(mpctx);
3236 else
3237 pause_player(mpctx);
3238 break;