Remove global vo_flags
[mplayer.git] / command.c
blobdc23c8cc5e99d1286b00fc6a70cdd8f6f7a22c79
1 #include <stdlib.h>
2 #include <inttypes.h>
3 #include <unistd.h>
4 #include <string.h>
6 #include "config.h"
7 #include "command.h"
8 #include "input/input.h"
9 #include "stream/stream.h"
10 #include "libmpdemux/demuxer.h"
11 #include "libmpdemux/stheader.h"
12 #include "codec-cfg.h"
13 #include "mplayer.h"
14 #include "libvo/sub.h"
15 #include "m_option.h"
16 #include "m_property.h"
17 #include "help_mp.h"
18 #include "metadata.h"
19 #include "libmpcodecs/vf.h"
20 #include "libmpcodecs/vd.h"
21 #include "mp_osd.h"
22 #include "libvo/video_out.h"
23 #include "libvo/font_load.h"
24 #include "playtree.h"
25 #include "libao2/audio_out.h"
26 #include "mpcommon.h"
27 #include "mixer.h"
28 #include "libmpcodecs/dec_video.h"
29 #include "vobsub.h"
30 #include "spudec.h"
31 #include "get_path.h"
32 #ifdef USE_TV
33 #include "stream/tv.h"
34 #endif
35 #ifdef USE_RADIO
36 #include "stream/stream_radio.h"
37 #endif
38 #ifdef HAVE_PVR
39 #include "stream/pvr.h"
40 #endif
41 #ifdef HAS_DVBIN_SUPPORT
42 #include "stream/dvbin.h"
43 #endif
44 #ifdef USE_DVDREAD
45 #include "stream/stream_dvd.h"
46 #endif
47 #ifdef USE_DVDNAV
48 #include "stream/stream_dvdnav.h"
49 #endif
50 #ifdef USE_ASS
51 #include "libass/ass.h"
52 #include "libass/ass_mp.h"
53 #endif
54 #ifdef HAVE_MENU
55 #include "m_struct.h"
56 #include "libmenu/menu.h"
57 #endif
58 #ifdef HAVE_NEW_GUI
59 #include "gui/interface.h"
60 #endif
62 #include "mp_core.h"
63 #include "mp_fifo.h"
64 #include "libavutil/avstring.h"
66 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
68 extern int use_menu;
70 static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy,
71 double *dx, double *dy)
73 struct MPOpts *opts = &mpctx->opts;
74 struct vo *vo = mpctx->video_out;
75 //remove the borders, if any, and rescale to the range [0,1],[0,1]
76 if (vo_fs) { //we are in full-screen mode
77 if (opts->vo_screenwidth > vo->dwidth) //there are borders along the x axis
78 ix -= (opts->vo_screenwidth - vo->dwidth) / 2;
79 if (opts->vo_screenheight > vo->dheight) //there are borders along the y axis (usual way)
80 iy -= (opts->vo_screenheight - vo->dheight) / 2;
82 if (ix < 0 || ix > vo->dwidth) {
83 *dx = *dy = -1.0;
84 return;
85 } //we are on one of the borders
86 if (iy < 0 || iy > vo->dheight) {
87 *dx = *dy = -1.0;
88 return;
89 } //we are on one of the borders
92 *dx = (double) ix / (double) vo->dwidth;
93 *dy = (double) iy / (double) vo->dheight;
95 mp_msg(MSGT_CPLAYER, MSGL_V,
96 "\r\nrescaled coordinates: %.3lf, %.3lf, screen (%d x %d), vodisplay: (%d, %d), fullscreen: %d\r\n",
97 *dx, *dy, opts->vo_screenwidth, opts->vo_screenheight, vo->dwidth,
98 vo->dheight, vo_fs);
101 static int sub_source_by_pos(MPContext * mpctx, int pos)
103 int source = -1;
104 int top = -1;
105 int i;
106 for (i = 0; i < SUB_SOURCES; i++) {
107 int j = mpctx->global_sub_indices[i];
108 if ((j >= 0) && (j > top) && (pos >= j)) {
109 source = i;
110 top = j;
113 return source;
116 static int sub_source(MPContext * mpctx)
118 return sub_source_by_pos(mpctx, mpctx->global_sub_pos);
122 * \brief Log the currently displayed subtitle to a file
124 * Logs the current or last displayed subtitle together with filename
125 * and time information to ~/.mplayer/subtitle_log
127 * Intended purpose is to allow convenient marking of bogus subtitles
128 * which need to be fixed while watching the movie.
131 static void log_sub(void)
133 char *fname;
134 FILE *f;
135 int i;
137 if (subdata == NULL || vo_sub_last == NULL)
138 return;
139 fname = get_path("subtitle_log");
140 f = fopen(fname, "a");
141 if (!f)
142 return;
143 fprintf(f, "----------------------------------------------------------\n");
144 if (subdata->sub_uses_time) {
145 fprintf(f,
146 "N: %s S: %02ld:%02ld:%02ld.%02ld E: %02ld:%02ld:%02ld.%02ld\n",
147 filename, vo_sub_last->start / 360000,
148 (vo_sub_last->start / 6000) % 60,
149 (vo_sub_last->start / 100) % 60, vo_sub_last->start % 100,
150 vo_sub_last->end / 360000, (vo_sub_last->end / 6000) % 60,
151 (vo_sub_last->end / 100) % 60, vo_sub_last->end % 100);
152 } else {
153 fprintf(f, "N: %s S: %ld E: %ld\n", filename, vo_sub_last->start,
154 vo_sub_last->end);
156 for (i = 0; i < vo_sub_last->lines; i++) {
157 fprintf(f, "%s\n", vo_sub_last->text[i]);
159 fclose(f);
163 /// \defgroup Properties
164 ///@{
166 /// \defgroup GeneralProperties General properties
167 /// \ingroup Properties
168 ///@{
170 /// OSD level (RW)
171 static int mp_property_osdlevel(m_option_t * prop, int action, void *arg,
172 MPContext * mpctx)
174 return m_property_choice(prop, action, arg, &osd_level);
177 /// Loop (RW)
178 static int mp_property_loop(m_option_t * prop, int action, void *arg,
179 MPContext * mpctx)
181 struct MPOpts *opts = &mpctx->opts;
182 switch (action) {
183 case M_PROPERTY_PRINT:
184 if (!arg) return M_PROPERTY_ERROR;
185 if (opts->loop_times < 0)
186 *(char**)arg = strdup("off");
187 else if (opts->loop_times == 0)
188 *(char**)arg = strdup("inf");
189 else
190 break;
191 return M_PROPERTY_OK;
193 return m_property_int_range(prop, action, arg, &opts->loop_times);
196 /// Playback speed (RW)
197 static int mp_property_playback_speed(m_option_t * prop, int action,
198 void *arg, MPContext * mpctx)
200 struct MPOpts *opts = &mpctx->opts;
201 switch (action) {
202 case M_PROPERTY_SET:
203 if (!arg)
204 return M_PROPERTY_ERROR;
205 M_PROPERTY_CLAMP(prop, *(float *) arg);
206 opts->playback_speed = *(float *) arg;
207 build_afilter_chain(mpctx, mpctx->sh_audio, &ao_data);
208 return M_PROPERTY_OK;
209 case M_PROPERTY_STEP_UP:
210 case M_PROPERTY_STEP_DOWN:
211 opts->playback_speed += (arg ? *(float *) arg : 0.1) *
212 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
213 M_PROPERTY_CLAMP(prop, opts->playback_speed);
214 build_afilter_chain(mpctx, mpctx->sh_audio, &ao_data);
215 return M_PROPERTY_OK;
217 return m_property_float_range(prop, action, arg, &opts->playback_speed);
220 /// filename with path (RO)
221 static int mp_property_path(m_option_t * prop, int action, void *arg,
222 MPContext * mpctx)
224 return m_property_string_ro(prop, action, arg, filename);
227 /// filename without path (RO)
228 static int mp_property_filename(m_option_t * prop, int action, void *arg,
229 MPContext * mpctx)
231 char *f;
232 if (!filename)
233 return M_PROPERTY_UNAVAILABLE;
234 if (((f = strrchr(filename, '/')) || (f = strrchr(filename, '\\'))) && f[1])
235 f++;
236 else
237 f = filename;
238 return m_property_string_ro(prop, action, arg, f);
241 /// Demuxer name (RO)
242 static int mp_property_demuxer(m_option_t * prop, int action, void *arg,
243 MPContext * mpctx)
245 if (!mpctx->demuxer)
246 return M_PROPERTY_UNAVAILABLE;
247 return m_property_string_ro(prop, action, arg,
248 (char *) mpctx->demuxer->desc->name);
251 /// Position in the stream (RW)
252 static int mp_property_stream_pos(m_option_t * prop, int action, void *arg,
253 MPContext * mpctx)
255 if (!mpctx->demuxer || !mpctx->demuxer->stream)
256 return M_PROPERTY_UNAVAILABLE;
257 if (!arg)
258 return M_PROPERTY_ERROR;
259 switch (action) {
260 case M_PROPERTY_GET:
261 *(off_t *) arg = stream_tell(mpctx->demuxer->stream);
262 return M_PROPERTY_OK;
263 case M_PROPERTY_SET:
264 M_PROPERTY_CLAMP(prop, *(off_t *) arg);
265 stream_seek(mpctx->demuxer->stream, *(off_t *) arg);
266 return M_PROPERTY_OK;
268 return M_PROPERTY_NOT_IMPLEMENTED;
271 /// Stream start offset (RO)
272 static int mp_property_stream_start(m_option_t * prop, int action,
273 void *arg, MPContext * mpctx)
275 if (!mpctx->demuxer || !mpctx->demuxer->stream)
276 return M_PROPERTY_UNAVAILABLE;
277 switch (action) {
278 case M_PROPERTY_GET:
279 *(off_t *) arg = mpctx->demuxer->stream->start_pos;
280 return M_PROPERTY_OK;
282 return M_PROPERTY_NOT_IMPLEMENTED;
285 /// Stream end offset (RO)
286 static int mp_property_stream_end(m_option_t * prop, int action, void *arg,
287 MPContext * mpctx)
289 if (!mpctx->demuxer || !mpctx->demuxer->stream)
290 return M_PROPERTY_UNAVAILABLE;
291 switch (action) {
292 case M_PROPERTY_GET:
293 *(off_t *) arg = mpctx->demuxer->stream->end_pos;
294 return M_PROPERTY_OK;
296 return M_PROPERTY_NOT_IMPLEMENTED;
299 /// Stream length (RO)
300 static int mp_property_stream_length(m_option_t * prop, int action,
301 void *arg, MPContext * mpctx)
303 if (!mpctx->demuxer || !mpctx->demuxer->stream)
304 return M_PROPERTY_UNAVAILABLE;
305 switch (action) {
306 case M_PROPERTY_GET:
307 *(off_t *) arg =
308 mpctx->demuxer->stream->end_pos - mpctx->demuxer->stream->start_pos;
309 return M_PROPERTY_OK;
311 return M_PROPERTY_NOT_IMPLEMENTED;
314 /// Media length in seconds (RO)
315 static int mp_property_length(m_option_t * prop, int action, void *arg,
316 MPContext * mpctx)
318 double len;
320 if (!mpctx->demuxer ||
321 !(int) (len = demuxer_get_time_length(mpctx->demuxer)))
322 return M_PROPERTY_UNAVAILABLE;
324 return m_property_time_ro(prop, action, arg, len);
327 /// Current position in percent (RW)
328 static int mp_property_percent_pos(m_option_t * prop, int action,
329 void *arg, MPContext * mpctx) {
330 int pos;
332 if (!mpctx->demuxer)
333 return M_PROPERTY_UNAVAILABLE;
335 switch(action) {
336 case M_PROPERTY_SET:
337 if(!arg) return M_PROPERTY_ERROR;
338 M_PROPERTY_CLAMP(prop, *(int*)arg);
339 pos = *(int*)arg;
340 break;
341 case M_PROPERTY_STEP_UP:
342 case M_PROPERTY_STEP_DOWN:
343 pos = demuxer_get_percent_pos(mpctx->demuxer);
344 pos += (arg ? *(int*)arg : 10) *
345 (action == M_PROPERTY_STEP_UP ? 1 : -1);
346 M_PROPERTY_CLAMP(prop, pos);
347 break;
348 default:
349 return m_property_int_ro(prop, action, arg,
350 demuxer_get_percent_pos(mpctx->demuxer));
353 mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
354 mpctx->rel_seek_secs = pos / 100.0;
355 return M_PROPERTY_OK;
358 /// Current position in seconds (RW)
359 static int mp_property_time_pos(m_option_t * prop, int action,
360 void *arg, MPContext * mpctx) {
361 if (!(mpctx->sh_video || (mpctx->sh_audio && mpctx->audio_out)))
362 return M_PROPERTY_UNAVAILABLE;
364 switch(action) {
365 case M_PROPERTY_SET:
366 if(!arg) return M_PROPERTY_ERROR;
367 M_PROPERTY_CLAMP(prop, *(double*)arg);
368 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
369 mpctx->rel_seek_secs = *(double*)arg;
370 return M_PROPERTY_OK;
371 case M_PROPERTY_STEP_UP:
372 case M_PROPERTY_STEP_DOWN:
373 mpctx->rel_seek_secs += (arg ? *(double*)arg : 10.0) *
374 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
375 return M_PROPERTY_OK;
377 return m_property_time_ro(prop, action, arg,
378 mpctx->sh_video ? mpctx->sh_video->pts :
379 playing_audio_pts(mpctx));
382 /// Current chapter (RW)
383 static int mp_property_chapter(m_option_t *prop, int action, void *arg,
384 MPContext *mpctx)
386 int chapter;
387 float next_pts = 0;
388 int chapter_num;
389 int step_all;
390 char *chapter_name = NULL;
392 chapter = demuxer_get_current_chapter(mpctx->demuxer);
393 if (chapter < 0)
394 return M_PROPERTY_UNAVAILABLE;
396 switch (action) {
397 case M_PROPERTY_GET:
398 if (!arg)
399 return M_PROPERTY_ERROR;
400 *(int *) arg = chapter;
401 return M_PROPERTY_OK;
402 case M_PROPERTY_PRINT: {
403 if (!arg)
404 return M_PROPERTY_ERROR;
405 chapter_name = demuxer_chapter_display_name(mpctx->demuxer, chapter);
406 if (!chapter_name)
407 return M_PROPERTY_UNAVAILABLE;
408 *(char **) arg = chapter_name;
409 return M_PROPERTY_OK;
411 case M_PROPERTY_SET:
412 if (!arg)
413 return M_PROPERTY_ERROR;
414 M_PROPERTY_CLAMP(prop, *(int*)arg);
415 step_all = *(int *)arg - (chapter + 1);
416 chapter += step_all;
417 break;
418 case M_PROPERTY_STEP_UP:
419 case M_PROPERTY_STEP_DOWN: {
420 step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
421 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
422 chapter += step_all;
423 if (chapter < 0)
424 chapter = 0;
425 break;
427 default:
428 return M_PROPERTY_NOT_IMPLEMENTED;
430 mpctx->rel_seek_secs = 0;
431 mpctx->abs_seek_pos = 0;
432 chapter = demuxer_seek_chapter(mpctx->demuxer, chapter, 1,
433 &next_pts, &chapter_num, &chapter_name);
434 if (chapter >= 0) {
435 if (next_pts > -1.0) {
436 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
437 mpctx->rel_seek_secs = next_pts;
439 if (chapter_name)
440 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
441 MSGTR_OSDChapter, chapter + 1, chapter_name);
443 else if (step_all > 0)
444 mpctx->rel_seek_secs = 1000000000.;
445 else
446 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
447 MSGTR_OSDChapter, 0, MSGTR_Unknown);
448 if (chapter_name)
449 free(chapter_name);
450 return M_PROPERTY_OK;
453 /// Current dvd angle (RW)
454 static int mp_property_angle(m_option_t *prop, int action, void *arg,
455 MPContext *mpctx)
457 int angle;
458 int angles;
459 char *angle_name = NULL;
461 angle = demuxer_get_current_angle(mpctx->demuxer);
462 if (angle < 0)
463 return M_PROPERTY_UNAVAILABLE;
464 angles = demuxer_angles_count(mpctx->demuxer);
465 if (angles <= 1)
466 return M_PROPERTY_UNAVAILABLE;
468 switch (action) {
469 case M_PROPERTY_GET:
470 if (!arg)
471 return M_PROPERTY_ERROR;
472 *(int *) arg = angle;
473 return M_PROPERTY_OK;
474 case M_PROPERTY_PRINT: {
475 if (!arg)
476 return M_PROPERTY_ERROR;
477 angle_name = calloc(1, 64);
478 if (!angle_name)
479 return M_PROPERTY_UNAVAILABLE;
480 snprintf(angle_name, 64, "%d/%d", angle, angles);
481 *(char **) arg = angle_name;
482 return M_PROPERTY_OK;
484 case M_PROPERTY_SET:
485 if (!arg)
486 return M_PROPERTY_ERROR;
487 angle = *(int *)arg;
488 M_PROPERTY_CLAMP(prop, angle);
489 break;
490 case M_PROPERTY_STEP_UP:
491 case M_PROPERTY_STEP_DOWN: {
492 int step = 0;
493 if(arg)
494 step = *(int*)arg;
495 if(!step)
496 step = 1;
497 step *= (action == M_PROPERTY_STEP_UP ? 1 : -1);
498 angle += step;
499 if (angle < 1) //cycle
500 angle = angles;
501 break;
503 default:
504 return M_PROPERTY_NOT_IMPLEMENTED;
506 angle = demuxer_set_angle(mpctx->demuxer, angle);
507 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
508 MSGTR_OSDAngle, angle, angles);
509 if (angle_name)
510 free(angle_name);
511 return M_PROPERTY_OK;
514 /// Demuxer meta data
515 static int mp_property_metadata(m_option_t * prop, int action, void *arg,
516 MPContext * mpctx) {
517 m_property_action_t* ka;
518 char* meta;
519 static m_option_t key_type =
520 { "metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL };
521 if (!mpctx->demuxer)
522 return M_PROPERTY_UNAVAILABLE;
524 switch(action) {
525 case M_PROPERTY_GET:
526 if(!arg) return M_PROPERTY_ERROR;
527 *(char***)arg = mpctx->demuxer->info;
528 return M_PROPERTY_OK;
529 case M_PROPERTY_KEY_ACTION:
530 if(!arg) return M_PROPERTY_ERROR;
531 ka = arg;
532 if(!(meta = demux_info_get(mpctx->demuxer,ka->key)))
533 return M_PROPERTY_UNKNOWN;
534 switch(ka->action) {
535 case M_PROPERTY_GET:
536 if(!ka->arg) return M_PROPERTY_ERROR;
537 *(char**)ka->arg = meta;
538 return M_PROPERTY_OK;
539 case M_PROPERTY_GET_TYPE:
540 if(!ka->arg) return M_PROPERTY_ERROR;
541 *(m_option_t**)ka->arg = &key_type;
542 return M_PROPERTY_OK;
545 return M_PROPERTY_NOT_IMPLEMENTED;
549 ///@}
551 /// \defgroup AudioProperties Audio properties
552 /// \ingroup Properties
553 ///@{
555 /// Volume (RW)
556 static int mp_property_volume(m_option_t * prop, int action, void *arg,
557 MPContext * mpctx)
560 if (!mpctx->sh_audio)
561 return M_PROPERTY_UNAVAILABLE;
563 switch (action) {
564 case M_PROPERTY_GET:
565 if (!arg)
566 return M_PROPERTY_ERROR;
567 mixer_getbothvolume(&mpctx->mixer, arg);
568 return M_PROPERTY_OK;
569 case M_PROPERTY_PRINT:{
570 float vol;
571 if (!arg)
572 return M_PROPERTY_ERROR;
573 mixer_getbothvolume(&mpctx->mixer, &vol);
574 return m_property_float_range(prop, action, arg, &vol);
576 case M_PROPERTY_STEP_UP:
577 case M_PROPERTY_STEP_DOWN:
578 case M_PROPERTY_SET:
579 break;
580 default:
581 return M_PROPERTY_NOT_IMPLEMENTED;
584 if (mpctx->edl_muted)
585 return M_PROPERTY_DISABLED;
586 mpctx->user_muted = 0;
588 switch (action) {
589 case M_PROPERTY_SET:
590 if (!arg)
591 return M_PROPERTY_ERROR;
592 M_PROPERTY_CLAMP(prop, *(float *) arg);
593 mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg);
594 return M_PROPERTY_OK;
595 case M_PROPERTY_STEP_UP:
596 if (arg && *(float *) arg <= 0)
597 mixer_decvolume(&mpctx->mixer);
598 else
599 mixer_incvolume(&mpctx->mixer);
600 return M_PROPERTY_OK;
601 case M_PROPERTY_STEP_DOWN:
602 if (arg && *(float *) arg <= 0)
603 mixer_incvolume(&mpctx->mixer);
604 else
605 mixer_decvolume(&mpctx->mixer);
606 return M_PROPERTY_OK;
608 return M_PROPERTY_NOT_IMPLEMENTED;
611 /// Mute (RW)
612 static int mp_property_mute(m_option_t * prop, int action, void *arg,
613 MPContext * mpctx)
616 if (!mpctx->sh_audio)
617 return M_PROPERTY_UNAVAILABLE;
619 switch (action) {
620 case M_PROPERTY_SET:
621 if (mpctx->edl_muted)
622 return M_PROPERTY_DISABLED;
623 if (!arg)
624 return M_PROPERTY_ERROR;
625 if ((!!*(int *) arg) != mpctx->mixer.muted)
626 mixer_mute(&mpctx->mixer);
627 mpctx->user_muted = mpctx->mixer.muted;
628 return M_PROPERTY_OK;
629 case M_PROPERTY_STEP_UP:
630 case M_PROPERTY_STEP_DOWN:
631 if (mpctx->edl_muted)
632 return M_PROPERTY_DISABLED;
633 mixer_mute(&mpctx->mixer);
634 mpctx->user_muted = mpctx->mixer.muted;
635 return M_PROPERTY_OK;
636 case M_PROPERTY_PRINT:
637 if (!arg)
638 return M_PROPERTY_ERROR;
639 if (mpctx->edl_muted) {
640 *(char **) arg = strdup(MSGTR_EnabledEdl);
641 return M_PROPERTY_OK;
643 default:
644 return m_property_flag(prop, action, arg, &mpctx->mixer.muted);
649 /// Audio delay (RW)
650 static int mp_property_audio_delay(m_option_t * prop, int action,
651 void *arg, MPContext * mpctx)
653 if (!(mpctx->sh_audio && mpctx->sh_video))
654 return M_PROPERTY_UNAVAILABLE;
655 switch (action) {
656 case M_PROPERTY_SET:
657 case M_PROPERTY_STEP_UP:
658 case M_PROPERTY_STEP_DOWN: {
659 int ret;
660 float delay = audio_delay;
661 ret = m_property_delay(prop, action, arg, &audio_delay);
662 if (ret != M_PROPERTY_OK)
663 return ret;
664 if (mpctx->sh_audio)
665 mpctx->delay -= audio_delay - delay;
667 return M_PROPERTY_OK;
668 default:
669 return m_property_delay(prop, action, arg, &audio_delay);
673 /// Audio codec tag (RO)
674 static int mp_property_audio_format(m_option_t * prop, int action,
675 void *arg, MPContext * mpctx)
677 if (!mpctx->sh_audio)
678 return M_PROPERTY_UNAVAILABLE;
679 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->format);
682 /// Audio codec name (RO)
683 static int mp_property_audio_codec(m_option_t * prop, int action,
684 void *arg, MPContext * mpctx)
686 if (!mpctx->sh_audio || !mpctx->sh_audio->codec)
687 return M_PROPERTY_UNAVAILABLE;
688 return m_property_string_ro(prop, action, arg, mpctx->sh_audio->codec->name);
691 /// Audio bitrate (RO)
692 static int mp_property_audio_bitrate(m_option_t * prop, int action,
693 void *arg, MPContext * mpctx)
695 if (!mpctx->sh_audio)
696 return M_PROPERTY_UNAVAILABLE;
697 return m_property_bitrate(prop, action, arg, mpctx->sh_audio->i_bps);
700 /// Samplerate (RO)
701 static int mp_property_samplerate(m_option_t * prop, int action, void *arg,
702 MPContext * mpctx)
704 if (!mpctx->sh_audio)
705 return M_PROPERTY_UNAVAILABLE;
706 switch(action) {
707 case M_PROPERTY_PRINT:
708 if(!arg) return M_PROPERTY_ERROR;
709 *(char**)arg = malloc(16);
710 sprintf(*(char**)arg,"%d kHz",mpctx->sh_audio->samplerate/1000);
711 return M_PROPERTY_OK;
713 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->samplerate);
716 /// Number of channels (RO)
717 static int mp_property_channels(m_option_t * prop, int action, void *arg,
718 MPContext * mpctx)
720 if (!mpctx->sh_audio)
721 return M_PROPERTY_UNAVAILABLE;
722 switch (action) {
723 case M_PROPERTY_PRINT:
724 if (!arg)
725 return M_PROPERTY_ERROR;
726 switch (mpctx->sh_audio->channels) {
727 case 1:
728 *(char **) arg = strdup("mono");
729 break;
730 case 2:
731 *(char **) arg = strdup("stereo");
732 break;
733 default:
734 *(char **) arg = malloc(32);
735 sprintf(*(char **) arg, "%d channels", mpctx->sh_audio->channels);
737 return M_PROPERTY_OK;
739 return m_property_int_ro(prop, action, arg, mpctx->sh_audio->channels);
742 /// Balance (RW)
743 static int mp_property_balance(m_option_t * prop, int action, void *arg,
744 MPContext * mpctx)
746 float bal;
748 if (!mpctx->sh_audio || mpctx->sh_audio->channels < 2)
749 return M_PROPERTY_UNAVAILABLE;
751 switch (action) {
752 case M_PROPERTY_GET:
753 if (!arg)
754 return M_PROPERTY_ERROR;
755 mixer_getbalance(&mpctx->mixer, arg);
756 return M_PROPERTY_OK;
757 case M_PROPERTY_PRINT: {
758 char** str = arg;
759 if (!arg)
760 return M_PROPERTY_ERROR;
761 mixer_getbalance(&mpctx->mixer, &bal);
762 if (bal == 0.f)
763 *str = strdup("center");
764 else if (bal == -1.f)
765 *str = strdup("left only");
766 else if (bal == 1.f)
767 *str = strdup("right only");
768 else {
769 unsigned right = (bal + 1.f) / 2.f * 100.f;
770 *str = malloc(sizeof("left xxx%, right xxx%"));
771 sprintf(*str, "left %d%%, right %d%%", 100 - right, right);
773 return M_PROPERTY_OK;
775 case M_PROPERTY_STEP_UP:
776 case M_PROPERTY_STEP_DOWN:
777 mixer_getbalance(&mpctx->mixer, &bal);
778 bal += (arg ? *(float*)arg : .1f) *
779 (action == M_PROPERTY_STEP_UP ? 1.f : -1.f);
780 M_PROPERTY_CLAMP(prop, bal);
781 mixer_setbalance(&mpctx->mixer, bal);
782 return M_PROPERTY_OK;
783 case M_PROPERTY_SET:
784 if (!arg)
785 return M_PROPERTY_ERROR;
786 M_PROPERTY_CLAMP(prop, *(float*)arg);
787 mixer_setbalance(&mpctx->mixer, *(float*)arg);
788 return M_PROPERTY_OK;
790 return M_PROPERTY_NOT_IMPLEMENTED;
793 /// Selected audio id (RW)
794 static int mp_property_audio(m_option_t * prop, int action, void *arg,
795 MPContext * mpctx)
797 struct MPOpts *opts = &mpctx->opts;
798 int current_id = -1, tmp;
800 switch (action) {
801 case M_PROPERTY_GET:
802 if (!mpctx->sh_audio)
803 return M_PROPERTY_UNAVAILABLE;
804 if (!arg)
805 return M_PROPERTY_ERROR;
806 *(int *) arg = opts->audio_id;
807 return M_PROPERTY_OK;
808 case M_PROPERTY_PRINT:
809 if (!mpctx->sh_audio)
810 return M_PROPERTY_UNAVAILABLE;
811 if (!arg)
812 return M_PROPERTY_ERROR;
814 if (opts->audio_id < 0)
815 *(char **) arg = strdup(MSGTR_Disabled);
816 else {
817 char lang[40] = MSGTR_Unknown;
818 sh_audio_t* sh = mpctx->sh_audio;
819 if (sh && sh->lang)
820 av_strlcpy(lang, sh->lang, 40);
821 #ifdef USE_DVDREAD
822 else if (mpctx->stream->type == STREAMTYPE_DVD) {
823 int code = dvd_lang_from_aid(mpctx->stream, opts->audio_id);
824 if (code) {
825 lang[0] = code >> 8;
826 lang[1] = code;
827 lang[2] = 0;
830 #endif
832 #ifdef USE_DVDNAV
833 else if (mpctx->stream->type == STREAMTYPE_DVDNAV)
834 dvdnav_lang_from_aid(mpctx->stream, opts->audio_id, lang);
835 #endif
836 *(char **) arg = malloc(64);
837 snprintf(*(char **) arg, 64, "(%d) %s", opts->audio_id, lang);
839 return M_PROPERTY_OK;
841 case M_PROPERTY_STEP_UP:
842 case M_PROPERTY_SET:
843 if (action == M_PROPERTY_SET && arg)
844 tmp = *((int *) arg);
845 else
846 tmp = -1;
847 current_id = mpctx->demuxer->audio->id;
848 opts->audio_id = demuxer_switch_audio(mpctx->demuxer, tmp);
849 if (opts->audio_id == -2
850 || (opts->audio_id > -1
851 && mpctx->demuxer->audio->id != current_id && current_id != -2))
852 uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC);
853 if (opts->audio_id > -1 && mpctx->demuxer->audio->id != current_id) {
854 sh_audio_t *sh2;
855 sh2 = mpctx->demuxer->a_streams[mpctx->demuxer->audio->id];
856 if (sh2) {
857 sh2->ds = mpctx->demuxer->audio;
858 mpctx->sh_audio = sh2;
859 reinit_audio_chain(mpctx);
862 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_TRACK=%d\n", opts->audio_id);
863 return M_PROPERTY_OK;
864 default:
865 return M_PROPERTY_NOT_IMPLEMENTED;
870 /// Selected video id (RW)
871 static int mp_property_video(m_option_t * prop, int action, void *arg,
872 MPContext * mpctx)
874 struct MPOpts *opts = &mpctx->opts;
875 int current_id = -1, tmp;
877 switch (action) {
878 case M_PROPERTY_GET:
879 if (!mpctx->sh_video)
880 return M_PROPERTY_UNAVAILABLE;
881 if (!arg)
882 return M_PROPERTY_ERROR;
883 *(int *) arg = opts->video_id;
884 return M_PROPERTY_OK;
885 case M_PROPERTY_PRINT:
886 if (!mpctx->sh_video)
887 return M_PROPERTY_UNAVAILABLE;
888 if (!arg)
889 return M_PROPERTY_ERROR;
891 if (opts->video_id < 0)
892 *(char **) arg = strdup(MSGTR_Disabled);
893 else {
894 char lang[40] = MSGTR_Unknown;
895 *(char **) arg = malloc(64);
896 snprintf(*(char **) arg, 64, "(%d) %s", opts->video_id, lang);
898 return M_PROPERTY_OK;
900 case M_PROPERTY_STEP_UP:
901 case M_PROPERTY_SET:
902 current_id = mpctx->demuxer->video->id;
903 if (action == M_PROPERTY_SET && arg)
904 tmp = *((int *) arg);
905 else
906 tmp = -1;
907 opts->video_id = demuxer_switch_video(mpctx->demuxer, tmp);
908 if (opts->video_id == -2
909 || (opts->video_id > -1 && mpctx->demuxer->video->id != current_id
910 && current_id != -2))
911 uninit_player(mpctx, INITIALIZED_VCODEC |
912 (mpctx->opts.fixed_vo && opts->video_id != -2 ? 0 : INITIALIZED_VO));
913 if (opts->video_id > -1 && mpctx->demuxer->video->id != current_id) {
914 sh_video_t *sh2;
915 sh2 = mpctx->demuxer->v_streams[mpctx->demuxer->video->id];
916 if (sh2) {
917 sh2->ds = mpctx->demuxer->video;
918 mpctx->sh_video = sh2;
919 reinit_video_chain(mpctx);
922 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_TRACK=%d\n", opts->video_id);
923 return M_PROPERTY_OK;
925 default:
926 return M_PROPERTY_NOT_IMPLEMENTED;
930 static int mp_property_program(m_option_t * prop, int action, void *arg,
931 MPContext * mpctx)
933 demux_program_t prog;
935 switch (action) {
936 case M_PROPERTY_STEP_UP:
937 case M_PROPERTY_SET:
938 if (action == M_PROPERTY_SET && arg)
939 prog.progid = *((int *) arg);
940 else
941 prog.progid = -1;
942 if (demux_control
943 (mpctx->demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM,
944 &prog) == DEMUXER_CTRL_NOTIMPL)
945 return M_PROPERTY_ERROR;
947 mp_property_do("switch_audio", M_PROPERTY_SET, &prog.aid, mpctx);
948 mp_property_do("switch_video", M_PROPERTY_SET, &prog.vid, mpctx);
949 return M_PROPERTY_OK;
951 default:
952 return M_PROPERTY_NOT_IMPLEMENTED;
956 ///@}
958 /// \defgroup VideoProperties Video properties
959 /// \ingroup Properties
960 ///@{
962 /// Fullscreen state (RW)
963 static int mp_property_fullscreen(m_option_t * prop, int action, void *arg,
964 MPContext * mpctx)
967 if (!mpctx->video_out)
968 return M_PROPERTY_UNAVAILABLE;
970 switch (action) {
971 case M_PROPERTY_SET:
972 if (!arg)
973 return M_PROPERTY_ERROR;
974 M_PROPERTY_CLAMP(prop, *(int *) arg);
975 if (vo_fs == !!*(int *) arg)
976 return M_PROPERTY_OK;
977 case M_PROPERTY_STEP_UP:
978 case M_PROPERTY_STEP_DOWN:
979 #ifdef HAVE_NEW_GUI
980 if (use_gui)
981 guiGetEvent(guiIEvent, (char *) MP_CMD_GUI_FULLSCREEN);
982 else
983 #endif
984 if (mpctx->video_out->config_ok)
985 vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0);
986 return M_PROPERTY_OK;
987 default:
988 return m_property_flag(prop, action, arg, &vo_fs);
992 static int mp_property_deinterlace(m_option_t * prop, int action,
993 void *arg, MPContext * mpctx)
995 int deinterlace;
996 vf_instance_t *vf;
997 if (!mpctx->sh_video || !mpctx->sh_video->vfilter)
998 return M_PROPERTY_UNAVAILABLE;
999 vf = mpctx->sh_video->vfilter;
1000 switch (action) {
1001 case M_PROPERTY_GET:
1002 if (!arg)
1003 return M_PROPERTY_ERROR;
1004 vf->control(vf, VFCTRL_GET_DEINTERLACE, arg);
1005 return M_PROPERTY_OK;
1006 case M_PROPERTY_SET:
1007 if (!arg)
1008 return M_PROPERTY_ERROR;
1009 M_PROPERTY_CLAMP(prop, *(int *) arg);
1010 vf->control(vf, VFCTRL_SET_DEINTERLACE, arg);
1011 return M_PROPERTY_OK;
1012 case M_PROPERTY_STEP_UP:
1013 case M_PROPERTY_STEP_DOWN:
1014 vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace);
1015 deinterlace = !deinterlace;
1016 vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace);
1017 return M_PROPERTY_OK;
1019 return M_PROPERTY_NOT_IMPLEMENTED;
1022 /// Panscan (RW)
1023 static int mp_property_panscan(m_option_t * prop, int action, void *arg,
1024 MPContext * mpctx)
1027 if (!mpctx->video_out
1028 || vo_control(mpctx->video_out, VOCTRL_GET_PANSCAN, NULL) != VO_TRUE)
1029 return M_PROPERTY_UNAVAILABLE;
1031 switch (action) {
1032 case M_PROPERTY_SET:
1033 if (!arg)
1034 return M_PROPERTY_ERROR;
1035 M_PROPERTY_CLAMP(prop, *(float *) arg);
1036 vo_panscan = *(float *) arg;
1037 vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
1038 return M_PROPERTY_OK;
1039 case M_PROPERTY_STEP_UP:
1040 case M_PROPERTY_STEP_DOWN:
1041 vo_panscan += (arg ? *(float *) arg : 0.1) *
1042 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1043 if (vo_panscan > 1)
1044 vo_panscan = 1;
1045 else if (vo_panscan < 0)
1046 vo_panscan = 0;
1047 vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
1048 return M_PROPERTY_OK;
1049 default:
1050 return m_property_float_range(prop, action, arg, &vo_panscan);
1054 /// Helper to set vo flags.
1055 /** \ingroup PropertyImplHelper
1057 static int mp_property_vo_flag(m_option_t * prop, int action, void *arg,
1058 int vo_ctrl, int *vo_var, MPContext * mpctx)
1061 if (!mpctx->video_out)
1062 return M_PROPERTY_UNAVAILABLE;
1064 switch (action) {
1065 case M_PROPERTY_SET:
1066 if (!arg)
1067 return M_PROPERTY_ERROR;
1068 M_PROPERTY_CLAMP(prop, *(int *) arg);
1069 if (*vo_var == !!*(int *) arg)
1070 return M_PROPERTY_OK;
1071 case M_PROPERTY_STEP_UP:
1072 case M_PROPERTY_STEP_DOWN:
1073 if (mpctx->video_out->config_ok)
1074 vo_control(mpctx->video_out, vo_ctrl, 0);
1075 return M_PROPERTY_OK;
1076 default:
1077 return m_property_flag(prop, action, arg, vo_var);
1081 /// Window always on top (RW)
1082 static int mp_property_ontop(m_option_t * prop, int action, void *arg,
1083 MPContext * mpctx)
1085 return mp_property_vo_flag(prop, action, arg, VOCTRL_ONTOP,
1086 &mpctx->opts.vo_ontop, mpctx);
1089 /// Display in the root window (RW)
1090 static int mp_property_rootwin(m_option_t * prop, int action, void *arg,
1091 MPContext * mpctx)
1093 return mp_property_vo_flag(prop, action, arg, VOCTRL_ROOTWIN,
1094 &vo_rootwin, mpctx);
1097 /// Show window borders (RW)
1098 static int mp_property_border(m_option_t * prop, int action, void *arg,
1099 MPContext * mpctx)
1101 return mp_property_vo_flag(prop, action, arg, VOCTRL_BORDER,
1102 &vo_border, mpctx);
1105 /// Framedropping state (RW)
1106 static int mp_property_framedropping(m_option_t * prop, int action,
1107 void *arg, MPContext * mpctx)
1110 if (!mpctx->sh_video)
1111 return M_PROPERTY_UNAVAILABLE;
1113 switch (action) {
1114 case M_PROPERTY_PRINT:
1115 if (!arg)
1116 return M_PROPERTY_ERROR;
1117 *(char **) arg = strdup(frame_dropping == 1 ? MSGTR_Enabled :
1118 (frame_dropping == 2 ? MSGTR_HardFrameDrop :
1119 MSGTR_Disabled));
1120 return M_PROPERTY_OK;
1121 default:
1122 return m_property_choice(prop, action, arg, &frame_dropping);
1126 /// Color settings, try to use vf/vo then fall back on TV. (RW)
1127 static int mp_property_gamma(m_option_t * prop, int action, void *arg,
1128 MPContext * mpctx)
1130 int *gamma = prop->priv, r, val;
1132 if (!mpctx->sh_video)
1133 return M_PROPERTY_UNAVAILABLE;
1135 if (gamma[0] == 1000) {
1136 gamma[0] = 0;
1137 get_video_colors(mpctx->sh_video, prop->name, gamma);
1140 switch (action) {
1141 case M_PROPERTY_SET:
1142 if (!arg)
1143 return M_PROPERTY_ERROR;
1144 M_PROPERTY_CLAMP(prop, *(int *) arg);
1145 *gamma = *(int *) arg;
1146 r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1147 if (r <= 0)
1148 break;
1149 return r;
1150 case M_PROPERTY_GET:
1151 if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) {
1152 if (!arg)
1153 return M_PROPERTY_ERROR;
1154 *(int *)arg = val;
1155 return M_PROPERTY_OK;
1157 break;
1158 case M_PROPERTY_STEP_UP:
1159 case M_PROPERTY_STEP_DOWN:
1160 *gamma += (arg ? *(int *) arg : 1) *
1161 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1162 M_PROPERTY_CLAMP(prop, *gamma);
1163 r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
1164 if (r <= 0)
1165 break;
1166 return r;
1167 default:
1168 return M_PROPERTY_NOT_IMPLEMENTED;
1171 #ifdef USE_TV
1172 if (mpctx->demuxer->type == DEMUXER_TYPE_TV) {
1173 int l = strlen(prop->name);
1174 char tv_prop[3 + l + 1];
1175 sprintf(tv_prop, "tv_%s", prop->name);
1176 return mp_property_do(tv_prop, action, arg, mpctx);
1178 #endif
1180 return M_PROPERTY_UNAVAILABLE;
1183 /// VSync (RW)
1184 static int mp_property_vsync(m_option_t * prop, int action, void *arg,
1185 MPContext * mpctx)
1187 return m_property_flag(prop, action, arg, &vo_vsync);
1190 /// Video codec tag (RO)
1191 static int mp_property_video_format(m_option_t * prop, int action,
1192 void *arg, MPContext * mpctx)
1194 char* meta;
1195 if (!mpctx->sh_video)
1196 return M_PROPERTY_UNAVAILABLE;
1197 switch(action) {
1198 case M_PROPERTY_PRINT:
1199 if (!arg)
1200 return M_PROPERTY_ERROR;
1201 switch(mpctx->sh_video->format) {
1202 case 0x10000001:
1203 meta = strdup ("mpeg1"); break;
1204 case 0x10000002:
1205 meta = strdup ("mpeg2"); break;
1206 case 0x10000004:
1207 meta = strdup ("mpeg4"); break;
1208 case 0x10000005:
1209 meta = strdup ("h264"); break;
1210 default:
1211 if(mpctx->sh_video->format >= 0x20202020) {
1212 meta = malloc(5);
1213 sprintf (meta, "%.4s", (char *) &mpctx->sh_video->format);
1214 } else {
1215 meta = malloc(20);
1216 sprintf (meta, "0x%08X", mpctx->sh_video->format);
1219 *(char**)arg = meta;
1220 return M_PROPERTY_OK;
1222 return m_property_int_ro(prop, action, arg, mpctx->sh_video->format);
1225 /// Video codec name (RO)
1226 static int mp_property_video_codec(m_option_t * prop, int action,
1227 void *arg, MPContext * mpctx)
1229 if (!mpctx->sh_video || !mpctx->sh_video->codec)
1230 return M_PROPERTY_UNAVAILABLE;
1231 return m_property_string_ro(prop, action, arg, mpctx->sh_video->codec->name);
1235 /// Video bitrate (RO)
1236 static int mp_property_video_bitrate(m_option_t * prop, int action,
1237 void *arg, MPContext * mpctx)
1239 if (!mpctx->sh_video)
1240 return M_PROPERTY_UNAVAILABLE;
1241 return m_property_bitrate(prop, action, arg, mpctx->sh_video->i_bps);
1244 /// Video display width (RO)
1245 static int mp_property_width(m_option_t * prop, int action, void *arg,
1246 MPContext * mpctx)
1248 if (!mpctx->sh_video)
1249 return M_PROPERTY_UNAVAILABLE;
1250 return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_w);
1253 /// Video display height (RO)
1254 static int mp_property_height(m_option_t * prop, int action, void *arg,
1255 MPContext * mpctx)
1257 if (!mpctx->sh_video)
1258 return M_PROPERTY_UNAVAILABLE;
1259 return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_h);
1262 /// Video fps (RO)
1263 static int mp_property_fps(m_option_t * prop, int action, void *arg,
1264 MPContext * mpctx)
1266 if (!mpctx->sh_video)
1267 return M_PROPERTY_UNAVAILABLE;
1268 return m_property_float_ro(prop, action, arg, mpctx->sh_video->fps);
1271 /// Video aspect (RO)
1272 static int mp_property_aspect(m_option_t * prop, int action, void *arg,
1273 MPContext * mpctx)
1275 if (!mpctx->sh_video)
1276 return M_PROPERTY_UNAVAILABLE;
1277 return m_property_float_ro(prop, action, arg, mpctx->sh_video->aspect);
1280 ///@}
1282 /// \defgroup SubProprties Subtitles properties
1283 /// \ingroup Properties
1284 ///@{
1286 /// Text subtitle position (RW)
1287 static int mp_property_sub_pos(m_option_t * prop, int action, void *arg,
1288 MPContext * mpctx)
1290 if (!mpctx->sh_video)
1291 return M_PROPERTY_UNAVAILABLE;
1293 switch (action) {
1294 case M_PROPERTY_SET:
1295 if (!arg)
1296 return M_PROPERTY_ERROR;
1297 case M_PROPERTY_STEP_UP:
1298 case M_PROPERTY_STEP_DOWN:
1299 vo_osd_changed(OSDTYPE_SUBTITLE);
1300 default:
1301 return m_property_int_range(prop, action, arg, &sub_pos);
1305 /// Selected subtitles (RW)
1306 static int mp_property_sub(m_option_t * prop, int action, void *arg,
1307 MPContext * mpctx)
1309 struct MPOpts *opts = &mpctx->opts;
1310 demux_stream_t *const d_sub = mpctx->d_sub;
1311 const int global_sub_size = mpctx->global_sub_size;
1312 int source = -1, reset_spu = 0;
1313 char *sub_name;
1315 if (global_sub_size <= 0)
1316 return M_PROPERTY_UNAVAILABLE;
1318 switch (action) {
1319 case M_PROPERTY_GET:
1320 if (!arg)
1321 return M_PROPERTY_ERROR;
1322 *(int *) arg = mpctx->global_sub_pos;
1323 return M_PROPERTY_OK;
1324 case M_PROPERTY_PRINT:
1325 if (!arg)
1326 return M_PROPERTY_ERROR;
1327 *(char **) arg = malloc(64);
1328 (*(char **) arg)[63] = 0;
1329 sub_name = 0;
1330 if (subdata)
1331 sub_name = subdata->filename;
1332 #ifdef USE_ASS
1333 if (ass_track && ass_track->name)
1334 sub_name = ass_track->name;
1335 #endif
1336 if (sub_name) {
1337 char *tmp, *tmp2;
1338 tmp = sub_name;
1339 if ((tmp2 = strrchr(tmp, '/')))
1340 tmp = tmp2 + 1;
1342 snprintf(*(char **) arg, 63, "(%d) %s%s",
1343 mpctx->set_of_sub_pos + 1,
1344 strlen(tmp) < 20 ? "" : "...",
1345 strlen(tmp) < 20 ? tmp : tmp + strlen(tmp) - 19);
1346 return M_PROPERTY_OK;
1348 #ifdef USE_DVDNAV
1349 if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
1350 if (vo_spudec && opts->sub_id >= 0) {
1351 unsigned char lang[3];
1352 if (dvdnav_lang_from_sid(mpctx->stream, opts->sub_id, lang)) {
1353 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1354 return M_PROPERTY_OK;
1358 #endif
1360 if ((mpctx->demuxer->type == DEMUXER_TYPE_MATROSKA
1361 || mpctx->demuxer->type == DEMUXER_TYPE_LAVF
1362 || mpctx->demuxer->type == DEMUXER_TYPE_OGG)
1363 && d_sub && d_sub->sh && opts->sub_id >= 0) {
1364 const char* lang = ((sh_sub_t*)d_sub->sh)->lang;
1365 if (!lang) lang = MSGTR_Unknown;
1366 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1367 return M_PROPERTY_OK;
1370 if (vo_vobsub && vobsub_id >= 0) {
1371 const char *language = MSGTR_Unknown;
1372 language = vobsub_get_id(vo_vobsub, (unsigned int) vobsub_id);
1373 snprintf(*(char **) arg, 63, "(%d) %s",
1374 vobsub_id, language ? language : MSGTR_Unknown);
1375 return M_PROPERTY_OK;
1377 #ifdef USE_DVDREAD
1378 if (vo_spudec && mpctx->stream->type == STREAMTYPE_DVD
1379 && opts->sub_id >= 0) {
1380 char lang[3];
1381 int code = dvd_lang_from_sid(mpctx->stream, opts->sub_id);
1382 lang[0] = code >> 8;
1383 lang[1] = code;
1384 lang[2] = 0;
1385 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, lang);
1386 return M_PROPERTY_OK;
1388 #endif
1389 if (opts->sub_id >= 0) {
1390 snprintf(*(char **) arg, 63, "(%d) %s", opts->sub_id, MSGTR_Unknown);
1391 return M_PROPERTY_OK;
1393 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1394 return M_PROPERTY_OK;
1396 case M_PROPERTY_SET:
1397 if (!arg)
1398 return M_PROPERTY_ERROR;
1399 if (*(int *) arg < -1)
1400 *(int *) arg = -1;
1401 else if (*(int *) arg >= global_sub_size)
1402 *(int *) arg = global_sub_size - 1;
1403 mpctx->global_sub_pos = *(int *) arg;
1404 break;
1405 case M_PROPERTY_STEP_UP:
1406 mpctx->global_sub_pos += 2;
1407 mpctx->global_sub_pos =
1408 (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1409 break;
1410 case M_PROPERTY_STEP_DOWN:
1411 mpctx->global_sub_pos += global_sub_size + 1;
1412 mpctx->global_sub_pos =
1413 (mpctx->global_sub_pos % (global_sub_size + 1)) - 1;
1414 break;
1415 default:
1416 return M_PROPERTY_NOT_IMPLEMENTED;
1419 if (mpctx->global_sub_pos >= 0)
1420 source = sub_source(mpctx);
1422 mp_msg(MSGT_CPLAYER, MSGL_DBG3,
1423 "subtitles: %d subs, (v@%d s@%d d@%d), @%d, source @%d\n",
1424 global_sub_size,
1425 mpctx->global_sub_indices[SUB_SOURCE_VOBSUB],
1426 mpctx->global_sub_indices[SUB_SOURCE_SUBS],
1427 mpctx->global_sub_indices[SUB_SOURCE_DEMUX],
1428 mpctx->global_sub_pos, source);
1430 mpctx->set_of_sub_pos = -1;
1431 subdata = NULL;
1433 vobsub_id = -1;
1434 opts->sub_id = -1;
1435 if (d_sub) {
1436 if (d_sub->id > -2)
1437 reset_spu = 1;
1438 d_sub->id = -2;
1440 #ifdef USE_ASS
1441 ass_track = 0;
1442 #endif
1444 if (source == SUB_SOURCE_VOBSUB) {
1445 vobsub_id = vobsub_get_id_by_index(vo_vobsub, mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_VOBSUB]);
1446 } else if (source == SUB_SOURCE_SUBS) {
1447 mpctx->set_of_sub_pos =
1448 mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_SUBS];
1449 #ifdef USE_ASS
1450 if (ass_enabled && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos])
1451 ass_track = mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos];
1452 else
1453 #endif
1455 subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos];
1456 vo_osd_changed(OSDTYPE_SUBTITLE);
1458 } else if (source == SUB_SOURCE_DEMUX) {
1459 opts->sub_id =
1460 mpctx->global_sub_pos - mpctx->global_sub_indices[SUB_SOURCE_DEMUX];
1461 if (d_sub && opts->sub_id < MAX_S_STREAMS) {
1462 int i = 0;
1463 // default: assume 1:1 mapping of sid and stream id
1464 d_sub->id = opts->sub_id;
1465 d_sub->sh = mpctx->demuxer->s_streams[d_sub->id];
1466 ds_free_packs(d_sub);
1467 for (i = 0; i < MAX_S_STREAMS; i++) {
1468 sh_sub_t *sh = mpctx->demuxer->s_streams[i];
1469 if (sh && sh->sid == opts->sub_id) {
1470 d_sub->id = i;
1471 d_sub->sh = sh;
1472 break;
1475 if (d_sub->sh && d_sub->id >= 0) {
1476 sh_sub_t *sh = d_sub->sh;
1477 if (sh->type == 'v')
1478 init_vo_spudec(mpctx);
1479 #ifdef USE_ASS
1480 else if (ass_enabled)
1481 ass_track = sh->ass_track;
1482 #endif
1483 } else {
1484 d_sub->id = -2;
1485 d_sub->sh = NULL;
1489 #ifdef USE_DVDREAD
1490 if (vo_spudec
1491 && (mpctx->stream->type == STREAMTYPE_DVD
1492 || mpctx->stream->type == STREAMTYPE_DVDNAV)
1493 && opts->sub_id < 0 && reset_spu) {
1494 opts->sub_id = -2;
1495 d_sub->id = opts->sub_id;
1497 #endif
1498 update_subtitles(mpctx->sh_video, d_sub, 1);
1500 return M_PROPERTY_OK;
1503 /// Selected sub source (RW)
1504 static int mp_property_sub_source(m_option_t * prop, int action, void *arg,
1505 MPContext * mpctx)
1507 int source;
1508 if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1509 return M_PROPERTY_UNAVAILABLE;
1511 switch (action) {
1512 case M_PROPERTY_GET:
1513 if (!arg)
1514 return M_PROPERTY_ERROR;
1515 *(int *) arg = sub_source(mpctx);
1516 return M_PROPERTY_OK;
1517 case M_PROPERTY_PRINT:
1518 if (!arg)
1519 return M_PROPERTY_ERROR;
1520 *(char **) arg = malloc(64);
1521 (*(char **) arg)[63] = 0;
1522 switch (sub_source(mpctx))
1524 case SUB_SOURCE_SUBS:
1525 snprintf(*(char **) arg, 63, MSGTR_SubSourceFile);
1526 break;
1527 case SUB_SOURCE_VOBSUB:
1528 snprintf(*(char **) arg, 63, MSGTR_SubSourceVobsub);
1529 break;
1530 case SUB_SOURCE_DEMUX:
1531 snprintf(*(char **) arg, 63, MSGTR_SubSourceDemux);
1532 break;
1533 default:
1534 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1536 return M_PROPERTY_OK;
1537 case M_PROPERTY_SET:
1538 if (!arg)
1539 return M_PROPERTY_ERROR;
1540 M_PROPERTY_CLAMP(prop, *(int*)arg);
1541 if (*(int *) arg < 0)
1542 mpctx->global_sub_pos = -1;
1543 else if (*(int *) arg != sub_source(mpctx)) {
1544 if (*(int *) arg != sub_source_by_pos(mpctx, mpctx->global_sub_indices[*(int *) arg]))
1545 return M_PROPERTY_UNAVAILABLE;
1546 mpctx->global_sub_pos = mpctx->global_sub_indices[*(int *) arg];
1548 break;
1549 case M_PROPERTY_STEP_UP:
1550 case M_PROPERTY_STEP_DOWN: {
1551 int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1552 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1553 int step = (step_all > 0) ? 1 : -1;
1554 int cur_source = sub_source(mpctx);
1555 source = cur_source;
1556 while (step_all) {
1557 source += step;
1558 if (source >= SUB_SOURCES)
1559 source = -1;
1560 else if (source < -1)
1561 source = SUB_SOURCES - 1;
1562 if (source == cur_source || source == -1 ||
1563 source == sub_source_by_pos(mpctx, mpctx->global_sub_indices[source]))
1564 step_all -= step;
1566 if (source == cur_source)
1567 return M_PROPERTY_OK;
1568 if (source == -1)
1569 mpctx->global_sub_pos = -1;
1570 else
1571 mpctx->global_sub_pos = mpctx->global_sub_indices[source];
1572 break;
1574 default:
1575 return M_PROPERTY_NOT_IMPLEMENTED;
1577 --mpctx->global_sub_pos;
1578 return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx);
1581 /// Selected subtitles from specific source (RW)
1582 static int mp_property_sub_by_type(m_option_t * prop, int action, void *arg,
1583 MPContext * mpctx)
1585 int source, is_cur_source, offset;
1586 if (!mpctx->sh_video || mpctx->global_sub_size <= 0)
1587 return M_PROPERTY_UNAVAILABLE;
1589 if (!strcmp(prop->name, "sub_file"))
1590 source = SUB_SOURCE_SUBS;
1591 else if (!strcmp(prop->name, "sub_vob"))
1592 source = SUB_SOURCE_VOBSUB;
1593 else if (!strcmp(prop->name, "sub_demux"))
1594 source = SUB_SOURCE_DEMUX;
1595 else
1596 return M_PROPERTY_ERROR;
1598 offset = mpctx->global_sub_indices[source];
1599 if (offset < 0 || source != sub_source_by_pos(mpctx, offset))
1600 return M_PROPERTY_UNAVAILABLE;
1602 is_cur_source = sub_source(mpctx) == source;
1603 switch (action) {
1604 case M_PROPERTY_GET:
1605 if (!arg)
1606 return M_PROPERTY_ERROR;
1607 if (is_cur_source) {
1608 *(int *) arg = mpctx->global_sub_pos - offset;
1609 if (source == SUB_SOURCE_VOBSUB)
1610 *(int *) arg = vobsub_get_id_by_index(vo_vobsub, *(int *) arg);
1612 else
1613 *(int *) arg = -1;
1614 return M_PROPERTY_OK;
1615 case M_PROPERTY_PRINT:
1616 if (!arg)
1617 return M_PROPERTY_ERROR;
1618 if (is_cur_source)
1619 return mp_property_sub(prop, M_PROPERTY_PRINT, arg, mpctx);
1620 *(char **) arg = malloc(64);
1621 (*(char **) arg)[63] = 0;
1622 snprintf(*(char **) arg, 63, MSGTR_Disabled);
1623 return M_PROPERTY_OK;
1624 case M_PROPERTY_SET:
1625 if (!arg)
1626 return M_PROPERTY_ERROR;
1627 if (*(int *) arg >= 0) {
1628 int index = *(int *)arg;
1629 if (source == SUB_SOURCE_VOBSUB)
1630 index = vobsub_get_index_by_id(vo_vobsub, index);
1631 mpctx->global_sub_pos = offset + index;
1632 if (index < 0 || mpctx->global_sub_pos >= mpctx->global_sub_size
1633 || sub_source(mpctx) != source) {
1634 mpctx->global_sub_pos = -1;
1635 *(int *) arg = -1;
1638 else
1639 mpctx->global_sub_pos = -1;
1640 break;
1641 case M_PROPERTY_STEP_UP:
1642 case M_PROPERTY_STEP_DOWN: {
1643 int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1)
1644 * (action == M_PROPERTY_STEP_UP ? 1 : -1);
1645 int step = (step_all > 0) ? 1 : -1;
1646 int max_sub_pos_for_source = -1;
1647 if (!is_cur_source)
1648 mpctx->global_sub_pos = -1;
1649 while (step_all) {
1650 if (mpctx->global_sub_pos == -1) {
1651 if (step > 0)
1652 mpctx->global_sub_pos = offset;
1653 else if (max_sub_pos_for_source == -1) {
1654 // Find max pos for specific source
1655 mpctx->global_sub_pos = mpctx->global_sub_size - 1;
1656 while (mpctx->global_sub_pos >= 0
1657 && sub_source(mpctx) != source)
1658 --mpctx->global_sub_pos;
1660 else
1661 mpctx->global_sub_pos = max_sub_pos_for_source;
1663 else {
1664 mpctx->global_sub_pos += step;
1665 if (mpctx->global_sub_pos < offset ||
1666 mpctx->global_sub_pos >= mpctx->global_sub_size ||
1667 sub_source(mpctx) != source)
1668 mpctx->global_sub_pos = -1;
1670 step_all -= step;
1672 break;
1674 default:
1675 return M_PROPERTY_NOT_IMPLEMENTED;
1677 --mpctx->global_sub_pos;
1678 return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx);
1681 /// Subtitle delay (RW)
1682 static int mp_property_sub_delay(m_option_t * prop, int action, void *arg,
1683 MPContext * mpctx)
1685 if (!mpctx->sh_video)
1686 return M_PROPERTY_UNAVAILABLE;
1687 return m_property_delay(prop, action, arg, &sub_delay);
1690 /// Alignment of text subtitles (RW)
1691 static int mp_property_sub_alignment(m_option_t * prop, int action,
1692 void *arg, MPContext * mpctx)
1694 char *name[] = { MSGTR_Top, MSGTR_Center, MSGTR_Bottom };
1696 if (!mpctx->sh_video || mpctx->global_sub_pos < 0
1697 || sub_source(mpctx) != SUB_SOURCE_SUBS)
1698 return M_PROPERTY_UNAVAILABLE;
1700 switch (action) {
1701 case M_PROPERTY_PRINT:
1702 if (!arg)
1703 return M_PROPERTY_ERROR;
1704 M_PROPERTY_CLAMP(prop, sub_alignment);
1705 *(char **) arg = strdup(name[sub_alignment]);
1706 return M_PROPERTY_OK;
1707 case M_PROPERTY_SET:
1708 if (!arg)
1709 return M_PROPERTY_ERROR;
1710 case M_PROPERTY_STEP_UP:
1711 case M_PROPERTY_STEP_DOWN:
1712 vo_osd_changed(OSDTYPE_SUBTITLE);
1713 default:
1714 return m_property_choice(prop, action, arg, &sub_alignment);
1718 /// Subtitle visibility (RW)
1719 static int mp_property_sub_visibility(m_option_t * prop, int action,
1720 void *arg, MPContext * mpctx)
1722 if (!mpctx->sh_video)
1723 return M_PROPERTY_UNAVAILABLE;
1725 switch (action) {
1726 case M_PROPERTY_SET:
1727 if (!arg)
1728 return M_PROPERTY_ERROR;
1729 case M_PROPERTY_STEP_UP:
1730 case M_PROPERTY_STEP_DOWN:
1731 vo_osd_changed(OSDTYPE_SUBTITLE);
1732 if (vo_spudec)
1733 vo_osd_changed(OSDTYPE_SPU);
1734 default:
1735 return m_property_flag(prop, action, arg, &sub_visibility);
1739 #ifdef USE_ASS
1740 /// Use margins for libass subtitles (RW)
1741 static int mp_property_ass_use_margins(m_option_t * prop, int action,
1742 void *arg, MPContext * mpctx)
1744 if (!mpctx->sh_video)
1745 return M_PROPERTY_UNAVAILABLE;
1747 switch (action) {
1748 case M_PROPERTY_SET:
1749 if (!arg)
1750 return M_PROPERTY_ERROR;
1751 case M_PROPERTY_STEP_UP:
1752 case M_PROPERTY_STEP_DOWN:
1753 ass_force_reload = 1;
1754 default:
1755 return m_property_flag(prop, action, arg, &ass_use_margins);
1758 #endif
1760 /// Show only forced subtitles (RW)
1761 static int mp_property_sub_forced_only(m_option_t * prop, int action,
1762 void *arg, MPContext * mpctx)
1764 if (!vo_spudec)
1765 return M_PROPERTY_UNAVAILABLE;
1767 switch (action) {
1768 case M_PROPERTY_SET:
1769 if (!arg)
1770 return M_PROPERTY_ERROR;
1771 case M_PROPERTY_STEP_UP:
1772 case M_PROPERTY_STEP_DOWN:
1773 m_property_flag(prop, action, arg, &forced_subs_only);
1774 spudec_set_forced_subs_only(vo_spudec, forced_subs_only);
1775 return M_PROPERTY_OK;
1776 default:
1777 return m_property_flag(prop, action, arg, &forced_subs_only);
1782 #ifdef HAVE_FREETYPE
1783 /// Subtitle scale (RW)
1784 static int mp_property_sub_scale(m_option_t * prop, int action, void *arg,
1785 MPContext * mpctx)
1788 switch (action) {
1789 case M_PROPERTY_SET:
1790 if (!arg)
1791 return M_PROPERTY_ERROR;
1792 M_PROPERTY_CLAMP(prop, *(float *) arg);
1793 #ifdef USE_ASS
1794 if (ass_enabled) {
1795 ass_font_scale = *(float *) arg;
1796 ass_force_reload = 1;
1798 #endif
1799 text_font_scale_factor = *(float *) arg;
1800 force_load_font = 1;
1801 return M_PROPERTY_OK;
1802 case M_PROPERTY_STEP_UP:
1803 case M_PROPERTY_STEP_DOWN:
1804 #ifdef USE_ASS
1805 if (ass_enabled) {
1806 ass_font_scale += (arg ? *(float *) arg : 0.1)*
1807 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1808 M_PROPERTY_CLAMP(prop, ass_font_scale);
1809 ass_force_reload = 1;
1811 #endif
1812 text_font_scale_factor += (arg ? *(float *) arg : 0.1)*
1813 (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
1814 M_PROPERTY_CLAMP(prop, text_font_scale_factor);
1815 force_load_font = 1;
1816 return M_PROPERTY_OK;
1817 default:
1818 #ifdef USE_ASS
1819 if (ass_enabled)
1820 return m_property_float_ro(prop, action, arg, ass_font_scale);
1821 else
1822 #endif
1823 return m_property_float_ro(prop, action, arg, text_font_scale_factor);
1826 #endif
1828 ///@}
1830 /// \defgroup TVProperties TV properties
1831 /// \ingroup Properties
1832 ///@{
1834 #ifdef USE_TV
1836 /// TV color settings (RW)
1837 static int mp_property_tv_color(m_option_t * prop, int action, void *arg,
1838 MPContext * mpctx)
1840 int r, val;
1841 tvi_handle_t *tvh = mpctx->demuxer->priv;
1842 if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1843 return M_PROPERTY_UNAVAILABLE;
1845 switch (action) {
1846 case M_PROPERTY_SET:
1847 if (!arg)
1848 return M_PROPERTY_ERROR;
1849 M_PROPERTY_CLAMP(prop, *(int *) arg);
1850 return tv_set_color_options(tvh, (int) prop->priv, *(int *) arg);
1851 case M_PROPERTY_GET:
1852 return tv_get_color_options(tvh, (int) prop->priv, arg);
1853 case M_PROPERTY_STEP_UP:
1854 case M_PROPERTY_STEP_DOWN:
1855 if ((r = tv_get_color_options(tvh, (int) prop->priv, &val)) >= 0) {
1856 if (!r)
1857 return M_PROPERTY_ERROR;
1858 val += (arg ? *(int *) arg : 1) *
1859 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1860 M_PROPERTY_CLAMP(prop, val);
1861 return tv_set_color_options(tvh, (int) prop->priv, val);
1863 return M_PROPERTY_ERROR;
1865 return M_PROPERTY_NOT_IMPLEMENTED;
1868 #endif
1870 #ifdef HAVE_TV_TELETEXT
1871 static int mp_property_teletext_common(m_option_t * prop, int action, void *arg,
1872 MPContext * mpctx)
1874 int val,result;
1875 int base_ioctl=(int)prop->priv;
1877 for teletext's GET,SET,STEP ioctls this is not 0
1878 SET is GET+1
1879 STEP is GET+2
1881 tvi_handle_t *tvh = mpctx->demuxer->priv;
1882 if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh)
1883 return M_PROPERTY_UNAVAILABLE;
1884 if(!base_ioctl)
1885 return M_PROPERTY_ERROR;
1887 switch (action) {
1888 case M_PROPERTY_GET:
1889 if (!arg)
1890 return M_PROPERTY_ERROR;
1891 result=tvh->functions->control(tvh->priv, base_ioctl, arg);
1892 break;
1893 case M_PROPERTY_SET:
1894 if (!arg)
1895 return M_PROPERTY_ERROR;
1896 M_PROPERTY_CLAMP(prop, *(int *) arg);
1897 result=tvh->functions->control(tvh->priv, base_ioctl+1, arg);
1898 break;
1899 case M_PROPERTY_STEP_UP:
1900 case M_PROPERTY_STEP_DOWN:
1901 result=tvh->functions->control(tvh->priv, base_ioctl, &val);
1902 val += (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1903 result=tvh->functions->control(tvh->priv, base_ioctl+1, &val);
1904 break;
1905 default:
1906 return M_PROPERTY_NOT_IMPLEMENTED;
1909 return (result==TVI_CONTROL_TRUE?M_PROPERTY_OK:M_PROPERTY_ERROR);
1912 static int mp_property_teletext_mode(m_option_t * prop, int action, void *arg,
1913 MPContext * mpctx)
1915 tvi_handle_t *tvh = mpctx->demuxer->priv;
1916 int result;
1917 int val;
1919 //with tvh==NULL will fail too
1920 result=mp_property_teletext_common(prop,action,arg,mpctx);
1921 if(result!=M_PROPERTY_OK)
1922 return result;
1924 if(tvh->functions->control(tvh->priv, prop->priv, &val)==TVI_CONTROL_TRUE && val)
1925 mp_input_set_section("teletext");
1926 else
1927 mp_input_set_section("tv");
1928 return M_PROPERTY_OK;
1931 static int mp_property_teletext_page(m_option_t * prop, int action, void *arg,
1932 MPContext * mpctx)
1934 tvi_handle_t *tvh = mpctx->demuxer->priv;
1935 int result;
1936 int val;
1937 switch(action){
1938 case M_PROPERTY_STEP_UP:
1939 case M_PROPERTY_STEP_DOWN:
1940 //This should be handled separately
1941 val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
1942 result=tvh->functions->control(tvh->priv, TV_VBI_CONTROL_STEP_PAGE, &val);
1943 break;
1944 default:
1945 result=mp_property_teletext_common(prop,action,arg,mpctx);
1947 return result;
1951 #endif /* HAVE_TV_TELETEXT */
1953 ///@}
1955 /// All properties available in MPlayer.
1956 /** \ingroup Properties
1958 static const m_option_t mp_properties[] = {
1959 // General
1960 { "osdlevel", mp_property_osdlevel, CONF_TYPE_INT,
1961 M_OPT_RANGE, 0, 3, NULL },
1962 { "loop", mp_property_loop, CONF_TYPE_INT,
1963 M_OPT_MIN, -1, 0, NULL },
1964 { "speed", mp_property_playback_speed, CONF_TYPE_FLOAT,
1965 M_OPT_RANGE, 0.01, 100.0, NULL },
1966 { "filename", mp_property_filename, CONF_TYPE_STRING,
1967 0, 0, 0, NULL },
1968 { "path", mp_property_path, CONF_TYPE_STRING,
1969 0, 0, 0, NULL },
1970 { "demuxer", mp_property_demuxer, CONF_TYPE_STRING,
1971 0, 0, 0, NULL },
1972 { "stream_pos", mp_property_stream_pos, CONF_TYPE_POSITION,
1973 M_OPT_MIN, 0, 0, NULL },
1974 { "stream_start", mp_property_stream_start, CONF_TYPE_POSITION,
1975 M_OPT_MIN, 0, 0, NULL },
1976 { "stream_end", mp_property_stream_end, CONF_TYPE_POSITION,
1977 M_OPT_MIN, 0, 0, NULL },
1978 { "stream_length", mp_property_stream_length, CONF_TYPE_POSITION,
1979 M_OPT_MIN, 0, 0, NULL },
1980 { "length", mp_property_length, CONF_TYPE_TIME,
1981 M_OPT_MIN, 0, 0, NULL },
1982 { "percent_pos", mp_property_percent_pos, CONF_TYPE_INT,
1983 M_OPT_RANGE, 0, 100, NULL },
1984 { "time_pos", mp_property_time_pos, CONF_TYPE_TIME,
1985 M_OPT_MIN, 0, 0, NULL },
1986 { "chapter", mp_property_chapter, CONF_TYPE_INT,
1987 M_OPT_MIN, 1, 0, NULL },
1988 { "angle", mp_property_angle, CONF_TYPE_INT,
1989 CONF_RANGE, -2, 10, NULL },
1990 { "metadata", mp_property_metadata, CONF_TYPE_STRING_LIST,
1991 0, 0, 0, NULL },
1993 // Audio
1994 { "volume", mp_property_volume, CONF_TYPE_FLOAT,
1995 M_OPT_RANGE, 0, 100, NULL },
1996 { "mute", mp_property_mute, CONF_TYPE_FLAG,
1997 M_OPT_RANGE, 0, 1, NULL },
1998 { "audio_delay", mp_property_audio_delay, CONF_TYPE_FLOAT,
1999 M_OPT_RANGE, -100, 100, NULL },
2000 { "audio_format", mp_property_audio_format, CONF_TYPE_INT,
2001 0, 0, 0, NULL },
2002 { "audio_codec", mp_property_audio_codec, CONF_TYPE_STRING,
2003 0, 0, 0, NULL },
2004 { "audio_bitrate", mp_property_audio_bitrate, CONF_TYPE_INT,
2005 0, 0, 0, NULL },
2006 { "samplerate", mp_property_samplerate, CONF_TYPE_INT,
2007 0, 0, 0, NULL },
2008 { "channels", mp_property_channels, CONF_TYPE_INT,
2009 0, 0, 0, NULL },
2010 { "switch_audio", mp_property_audio, CONF_TYPE_INT,
2011 CONF_RANGE, -2, MAX_A_STREAMS - 1, NULL },
2012 { "balance", mp_property_balance, CONF_TYPE_FLOAT,
2013 M_OPT_RANGE, -1, 1, NULL },
2015 // Video
2016 { "fullscreen", mp_property_fullscreen, CONF_TYPE_FLAG,
2017 M_OPT_RANGE, 0, 1, NULL },
2018 { "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG,
2019 M_OPT_RANGE, 0, 1, NULL },
2020 { "ontop", mp_property_ontop, CONF_TYPE_FLAG,
2021 M_OPT_RANGE, 0, 1, NULL },
2022 { "rootwin", mp_property_rootwin, CONF_TYPE_FLAG,
2023 M_OPT_RANGE, 0, 1, NULL },
2024 { "border", mp_property_border, CONF_TYPE_FLAG,
2025 M_OPT_RANGE, 0, 1, NULL },
2026 { "framedropping", mp_property_framedropping, CONF_TYPE_INT,
2027 M_OPT_RANGE, 0, 2, NULL },
2028 { "gamma", mp_property_gamma, CONF_TYPE_INT,
2029 M_OPT_RANGE, -100, 100, &vo_gamma_gamma },
2030 { "brightness", mp_property_gamma, CONF_TYPE_INT,
2031 M_OPT_RANGE, -100, 100, &vo_gamma_brightness },
2032 { "contrast", mp_property_gamma, CONF_TYPE_INT,
2033 M_OPT_RANGE, -100, 100, &vo_gamma_contrast },
2034 { "saturation", mp_property_gamma, CONF_TYPE_INT,
2035 M_OPT_RANGE, -100, 100, &vo_gamma_saturation },
2036 { "hue", mp_property_gamma, CONF_TYPE_INT,
2037 M_OPT_RANGE, -100, 100, &vo_gamma_hue },
2038 { "panscan", mp_property_panscan, CONF_TYPE_FLOAT,
2039 M_OPT_RANGE, 0, 1, NULL },
2040 { "vsync", mp_property_vsync, CONF_TYPE_FLAG,
2041 M_OPT_RANGE, 0, 1, NULL },
2042 { "video_format", mp_property_video_format, CONF_TYPE_INT,
2043 0, 0, 0, NULL },
2044 { "video_codec", mp_property_video_codec, CONF_TYPE_STRING,
2045 0, 0, 0, NULL },
2046 { "video_bitrate", mp_property_video_bitrate, CONF_TYPE_INT,
2047 0, 0, 0, NULL },
2048 { "width", mp_property_width, CONF_TYPE_INT,
2049 0, 0, 0, NULL },
2050 { "height", mp_property_height, CONF_TYPE_INT,
2051 0, 0, 0, NULL },
2052 { "fps", mp_property_fps, CONF_TYPE_FLOAT,
2053 0, 0, 0, NULL },
2054 { "aspect", mp_property_aspect, CONF_TYPE_FLOAT,
2055 0, 0, 0, NULL },
2056 { "switch_video", mp_property_video, CONF_TYPE_INT,
2057 CONF_RANGE, -2, MAX_V_STREAMS - 1, NULL },
2058 { "switch_program", mp_property_program, CONF_TYPE_INT,
2059 CONF_RANGE, -1, 65535, NULL },
2061 // Subs
2062 { "sub", mp_property_sub, CONF_TYPE_INT,
2063 M_OPT_MIN, -1, 0, NULL },
2064 { "sub_source", mp_property_sub_source, CONF_TYPE_INT,
2065 M_OPT_RANGE, -1, SUB_SOURCES - 1, NULL },
2066 { "sub_vob", mp_property_sub_by_type, CONF_TYPE_INT,
2067 M_OPT_MIN, -1, 0, NULL },
2068 { "sub_demux", mp_property_sub_by_type, CONF_TYPE_INT,
2069 M_OPT_MIN, -1, 0, NULL },
2070 { "sub_file", mp_property_sub_by_type, CONF_TYPE_INT,
2071 M_OPT_MIN, -1, 0, NULL },
2072 { "sub_delay", mp_property_sub_delay, CONF_TYPE_FLOAT,
2073 0, 0, 0, NULL },
2074 { "sub_pos", mp_property_sub_pos, CONF_TYPE_INT,
2075 M_OPT_RANGE, 0, 100, NULL },
2076 { "sub_alignment", mp_property_sub_alignment, CONF_TYPE_INT,
2077 M_OPT_RANGE, 0, 2, NULL },
2078 { "sub_visibility", mp_property_sub_visibility, CONF_TYPE_FLAG,
2079 M_OPT_RANGE, 0, 1, NULL },
2080 { "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG,
2081 M_OPT_RANGE, 0, 1, NULL },
2082 #ifdef HAVE_FREETYPE
2083 { "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT,
2084 M_OPT_RANGE, 0, 100, NULL },
2085 #endif
2086 #ifdef USE_ASS
2087 { "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG,
2088 M_OPT_RANGE, 0, 1, NULL },
2089 #endif
2091 #ifdef USE_TV
2092 { "tv_brightness", mp_property_tv_color, CONF_TYPE_INT,
2093 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_BRIGHTNESS },
2094 { "tv_contrast", mp_property_tv_color, CONF_TYPE_INT,
2095 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_CONTRAST },
2096 { "tv_saturation", mp_property_tv_color, CONF_TYPE_INT,
2097 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_SATURATION },
2098 { "tv_hue", mp_property_tv_color, CONF_TYPE_INT,
2099 M_OPT_RANGE, -100, 100, (void *) TV_COLOR_HUE },
2100 #endif
2102 #ifdef HAVE_TV_TELETEXT
2103 { "teletext_page", mp_property_teletext_page, CONF_TYPE_INT,
2104 M_OPT_RANGE, 100, 899, (void*)TV_VBI_CONTROL_GET_PAGE },
2105 { "teletext_subpage", mp_property_teletext_common, CONF_TYPE_INT,
2106 M_OPT_RANGE, 0, 64, (void*)TV_VBI_CONTROL_GET_SUBPAGE },
2107 { "teletext_mode", mp_property_teletext_mode, CONF_TYPE_FLAG,
2108 M_OPT_RANGE, 0, 1, (void*)TV_VBI_CONTROL_GET_MODE },
2109 { "teletext_format", mp_property_teletext_common, CONF_TYPE_INT,
2110 M_OPT_RANGE, 0, 3, (void*)TV_VBI_CONTROL_GET_FORMAT },
2111 { "teletext_half_page", mp_property_teletext_common, CONF_TYPE_INT,
2112 M_OPT_RANGE, 0, 2, (void*)TV_VBI_CONTROL_GET_HALF_PAGE },
2113 #endif
2115 { NULL, NULL, NULL, 0, 0, 0, NULL }
2119 int mp_property_do(const char *name, int action, void *val, void *ctx)
2121 return m_property_do(mp_properties, name, action, val, ctx);
2124 char* mp_property_print(const char *name, void* ctx)
2126 char* ret = NULL;
2127 if(mp_property_do(name,M_PROPERTY_PRINT,&ret,ctx) <= 0)
2128 return NULL;
2129 return ret;
2132 char *property_expand_string(MPContext * mpctx, char *str)
2134 return m_properties_expand_string(mp_properties, str, mpctx);
2137 void property_print_help(void)
2139 m_properties_print_help_list(mp_properties);
2143 ///@}
2144 // Properties group
2148 * \defgroup Command2Property Command to property bridge
2150 * It is used to handle most commands that just set a property
2151 * and optionally display something on the OSD.
2152 * Two kinds of commands are handled: adjust or toggle.
2154 * Adjust commands take 1 or 2 parameters: <value> <abs>
2155 * If <abs> is non-zero the property is set to the given value
2156 * otherwise it is adjusted.
2158 * Toggle commands take 0 or 1 parameters. With no parameter
2159 * or a value less than the property minimum it just steps the
2160 * property to its next value. Otherwise it sets it to the given
2161 * value.
2166 /// List of the commands that can be handled by setting a property.
2167 static struct {
2168 /// property name
2169 const char *name;
2170 /// cmd id
2171 int cmd;
2172 /// set/adjust or toggle command
2173 int toggle;
2174 /// progressbar type
2175 int osd_progbar;
2176 /// osd msg id if it must be shared
2177 int osd_id;
2178 /// osd msg template
2179 const char *osd_msg;
2180 } set_prop_cmd[] = {
2181 // general
2182 { "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus },
2183 { "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL },
2184 { "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL },
2185 // audio
2186 { "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume },
2187 { "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus },
2188 { "audio_delay", MP_CMD_AUDIO_DELAY, 0, 0, -1, MSGTR_AVDelayStatus },
2189 { "switch_audio", MP_CMD_SWITCH_AUDIO, 1, 0, -1, MSGTR_OSDAudio },
2190 { "balance", MP_CMD_BALANCE, 0, OSD_BALANCE, -1, MSGTR_Balance },
2191 // video
2192 { "fullscreen", MP_CMD_VO_FULLSCREEN, 1, 0, -1, NULL },
2193 { "panscan", MP_CMD_PANSCAN, 0, OSD_PANSCAN, -1, MSGTR_Panscan },
2194 { "ontop", MP_CMD_VO_ONTOP, 1, 0, -1, MSGTR_OnTopStatus },
2195 { "rootwin", MP_CMD_VO_ROOTWIN, 1, 0, -1, MSGTR_RootwinStatus },
2196 { "border", MP_CMD_VO_BORDER, 1, 0, -1, MSGTR_BorderStatus },
2197 { "framedropping", MP_CMD_FRAMEDROPPING, 1, 0, -1, MSGTR_FramedroppingStatus },
2198 { "gamma", MP_CMD_GAMMA, 0, OSD_BRIGHTNESS, -1, MSGTR_Gamma },
2199 { "brightness", MP_CMD_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2200 { "contrast", MP_CMD_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2201 { "saturation", MP_CMD_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2202 { "hue", MP_CMD_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2203 { "vsync", MP_CMD_SWITCH_VSYNC, 1, 0, -1, MSGTR_VSyncStatus },
2204 // subs
2205 { "sub", MP_CMD_SUB_SELECT, 1, 0, -1, MSGTR_SubSelectStatus },
2206 { "sub_source", MP_CMD_SUB_SOURCE, 1, 0, -1, MSGTR_SubSourceStatus },
2207 { "sub_vob", MP_CMD_SUB_VOB, 1, 0, -1, MSGTR_SubSelectStatus },
2208 { "sub_demux", MP_CMD_SUB_DEMUX, 1, 0, -1, MSGTR_SubSelectStatus },
2209 { "sub_file", MP_CMD_SUB_FILE, 1, 0, -1, MSGTR_SubSelectStatus },
2210 { "sub_pos", MP_CMD_SUB_POS, 0, 0, -1, MSGTR_SubPosStatus },
2211 { "sub_alignment", MP_CMD_SUB_ALIGNMENT, 1, 0, -1, MSGTR_SubAlignStatus },
2212 { "sub_delay", MP_CMD_SUB_DELAY, 0, 0, OSD_MSG_SUB_DELAY, MSGTR_SubDelayStatus },
2213 { "sub_visibility", MP_CMD_SUB_VISIBILITY, 1, 0, -1, MSGTR_SubVisibleStatus },
2214 { "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1, 0, -1, MSGTR_SubForcedOnlyStatus },
2215 #ifdef HAVE_FREETYPE
2216 { "sub_scale", MP_CMD_SUB_SCALE, 0, 0, -1, MSGTR_SubScale},
2217 #endif
2218 #ifdef USE_ASS
2219 { "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1, 0, -1, NULL },
2220 #endif
2221 #ifdef USE_TV
2222 { "tv_brightness", MP_CMD_TV_SET_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness },
2223 { "tv_hue", MP_CMD_TV_SET_HUE, 0, OSD_HUE, -1, MSGTR_Hue },
2224 { "tv_saturation", MP_CMD_TV_SET_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation },
2225 { "tv_contrast", MP_CMD_TV_SET_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast },
2226 #endif
2227 { NULL, 0, 0, 0, -1, NULL }
2231 /// Handle commands that set a property.
2232 static int set_property_command(MPContext * mpctx, mp_cmd_t * cmd)
2234 int i, r;
2235 m_option_t* prop;
2236 const char *pname;
2238 // look for the command
2239 for (i = 0; set_prop_cmd[i].name; i++)
2240 if (set_prop_cmd[i].cmd == cmd->id)
2241 break;
2242 if (!(pname = set_prop_cmd[i].name))
2243 return 0;
2245 if (mp_property_do(pname,M_PROPERTY_GET_TYPE,&prop,mpctx) <= 0 || !prop)
2246 return 0;
2248 // toggle command
2249 if (set_prop_cmd[i].toggle) {
2250 // set to value
2251 if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min)
2252 r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx);
2253 else
2254 r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx);
2255 } else if (cmd->args[1].v.i) //set
2256 r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx);
2257 else // adjust
2258 r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx);
2260 if (r <= 0)
2261 return 1;
2263 if (set_prop_cmd[i].osd_progbar) {
2264 if (prop->type == CONF_TYPE_INT) {
2265 if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0)
2266 set_osd_bar(mpctx, set_prop_cmd[i].osd_progbar,
2267 set_prop_cmd[i].osd_msg, prop->min, prop->max, r);
2268 } else if (prop->type == CONF_TYPE_FLOAT) {
2269 float f;
2270 if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0)
2271 set_osd_bar(mpctx, set_prop_cmd[i].osd_progbar,
2272 set_prop_cmd[i].osd_msg, prop->min, prop->max, f);
2273 } else
2274 mp_msg(MSGT_CPLAYER, MSGL_ERR,
2275 "Property use an unsupported type.\n");
2276 return 1;
2279 if (set_prop_cmd[i].osd_msg) {
2280 char *val = mp_property_print(pname, mpctx);
2281 if (val) {
2282 set_osd_msg(set_prop_cmd[i].osd_id >=
2283 0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i,
2284 1, osd_duration, set_prop_cmd[i].osd_msg, val);
2285 free(val);
2288 return 1;
2292 int run_command(MPContext * mpctx, mp_cmd_t * cmd)
2294 struct MPOpts *opts = &mpctx->opts;
2295 sh_audio_t * const sh_audio = mpctx->sh_audio;
2296 sh_video_t * const sh_video = mpctx->sh_video;
2297 int brk_cmd = 0;
2298 if (!set_property_command(mpctx, cmd))
2299 switch (cmd->id) {
2300 case MP_CMD_SEEK:{
2301 float v;
2302 int abs;
2303 if (sh_video)
2304 mpctx->osd_show_percentage = sh_video->fps;
2305 v = cmd->args[0].v.f;
2306 abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
2307 if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */
2308 mpctx->abs_seek_pos = SEEK_ABSOLUTE;
2309 if (sh_video)
2310 mpctx->osd_function =
2311 (v > sh_video->pts) ? OSD_FFW : OSD_REW;
2312 mpctx->rel_seek_secs = v;
2313 } else if (abs) { /* Absolute seek by percentage */
2314 mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
2315 if (sh_video)
2316 mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
2317 mpctx->rel_seek_secs = v / 100.0;
2318 } else {
2319 mpctx->rel_seek_secs += v;
2320 mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
2322 brk_cmd = 1;
2324 break;
2326 case MP_CMD_SET_PROPERTY:{
2327 int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE,
2328 cmd->args[1].v.s, mpctx);
2329 if (r == M_PROPERTY_UNKNOWN)
2330 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2331 "Unknown property: '%s'\n", cmd->args[0].v.s);
2332 else if (r <= 0)
2333 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2334 "Failed to set property '%s' to '%s'.\n",
2335 cmd->args[0].v.s, cmd->args[1].v.s);
2337 break;
2339 case MP_CMD_STEP_PROPERTY:{
2340 void* arg = NULL;
2341 int r,i;
2342 double d;
2343 off_t o;
2344 if (cmd->args[1].v.f) {
2345 m_option_t* prop;
2346 if((r = mp_property_do(cmd->args[0].v.s,
2347 M_PROPERTY_GET_TYPE,
2348 &prop, mpctx)) <= 0)
2349 goto step_prop_err;
2350 if(prop->type == CONF_TYPE_INT ||
2351 prop->type == CONF_TYPE_FLAG)
2352 i = cmd->args[1].v.f, arg = &i;
2353 else if(prop->type == CONF_TYPE_FLOAT)
2354 arg = &cmd->args[1].v.f;
2355 else if(prop->type == CONF_TYPE_DOUBLE ||
2356 prop->type == CONF_TYPE_TIME)
2357 d = cmd->args[1].v.f, arg = &d;
2358 else if(prop->type == CONF_TYPE_POSITION)
2359 o = cmd->args[1].v.f, arg = &o;
2360 else
2361 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2362 "Ignoring step size stepping property '%s'.\n",
2363 cmd->args[0].v.s);
2365 r = mp_property_do(cmd->args[0].v.s,
2366 cmd->args[2].v.i < 0 ?
2367 M_PROPERTY_STEP_DOWN : M_PROPERTY_STEP_UP,
2368 arg, mpctx);
2369 step_prop_err:
2370 if (r == M_PROPERTY_UNKNOWN)
2371 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2372 "Unknown property: '%s'\n", cmd->args[0].v.s);
2373 else if (r <= 0)
2374 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2375 "Failed to increment property '%s' by %f.\n",
2376 cmd->args[0].v.s, cmd->args[1].v.f);
2378 break;
2380 case MP_CMD_GET_PROPERTY:{
2381 char *tmp;
2382 if (mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING,
2383 &tmp, mpctx) <= 0) {
2384 mp_msg(MSGT_CPLAYER, MSGL_WARN,
2385 "Failed to get value of property '%s'.\n",
2386 cmd->args[0].v.s);
2387 break;
2389 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n",
2390 cmd->args[0].v.s, tmp);
2391 free(tmp);
2393 break;
2395 case MP_CMD_EDL_MARK:
2396 if (edl_fd) {
2397 float v = sh_video ? sh_video->pts :
2398 playing_audio_pts(mpctx);
2399 if (mpctx->begin_skip == MP_NOPTS_VALUE) {
2400 mpctx->begin_skip = v;
2401 mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutStartSkip);
2402 } else {
2403 if (mpctx->begin_skip > v)
2404 mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_EdloutBadStop);
2405 else {
2406 fprintf(edl_fd, "%f %f %d\n", mpctx->begin_skip, v, 0);
2407 mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutEndSkip);
2409 mpctx->begin_skip = MP_NOPTS_VALUE;
2412 break;
2414 case MP_CMD_SWITCH_RATIO:
2415 if (cmd->nargs == 0 || cmd->args[0].v.f == -1)
2416 opts->movie_aspect = (float) sh_video->disp_w / sh_video->disp_h;
2417 else
2418 opts->movie_aspect = cmd->args[0].v.f;
2419 mpcodecs_config_vo(sh_video, sh_video->disp_w, sh_video->disp_h, 0);
2420 break;
2422 case MP_CMD_SPEED_INCR:{
2423 float v = cmd->args[0].v.f;
2424 opts->playback_speed += v;
2425 build_afilter_chain(mpctx, sh_audio, &ao_data);
2426 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2427 opts->playback_speed);
2428 } break;
2430 case MP_CMD_SPEED_MULT:{
2431 float v = cmd->args[0].v.f;
2432 opts->playback_speed *= v;
2433 build_afilter_chain(mpctx, sh_audio, &ao_data);
2434 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2435 opts->playback_speed);
2436 } break;
2438 case MP_CMD_SPEED_SET:{
2439 float v = cmd->args[0].v.f;
2440 opts->playback_speed = v;
2441 build_afilter_chain(mpctx, sh_audio, &ao_data);
2442 set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
2443 opts->playback_speed);
2444 } break;
2446 case MP_CMD_FRAME_STEP:
2447 case MP_CMD_PAUSE:
2448 cmd->pausing = 1;
2449 brk_cmd = 1;
2450 break;
2452 case MP_CMD_FILE_FILTER:
2453 file_filter = cmd->args[0].v.i;
2454 break;
2456 case MP_CMD_QUIT:
2457 exit_player_with_rc(mpctx, MSGTR_Exit_quit,
2458 (cmd->nargs > 0) ? cmd->args[0].v.i : 0);
2460 case MP_CMD_PLAY_TREE_STEP:{
2461 int n = cmd->args[0].v.i == 0 ? 1 : cmd->args[0].v.i;
2462 int force = cmd->args[1].v.i;
2464 #ifdef HAVE_NEW_GUI
2465 if (use_gui) {
2466 int i = 0;
2467 if (n > 0)
2468 for (i = 0; i < n; i++)
2469 mplNext();
2470 else
2471 for (i = 0; i < -1 * n; i++)
2472 mplPrev();
2473 } else
2474 #endif
2476 if (!force && mpctx->playtree_iter) {
2477 play_tree_iter_t *i =
2478 play_tree_iter_new_copy(mpctx->playtree_iter);
2479 if (play_tree_iter_step(i, n, 0) ==
2480 PLAY_TREE_ITER_ENTRY)
2481 mpctx->eof =
2482 (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2483 play_tree_iter_free(i);
2484 } else
2485 mpctx->eof = (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
2486 if (mpctx->eof)
2487 mpctx->play_tree_step = n;
2488 brk_cmd = 1;
2491 break;
2493 case MP_CMD_PLAY_TREE_UP_STEP:{
2494 int n = cmd->args[0].v.i > 0 ? 1 : -1;
2495 int force = cmd->args[1].v.i;
2497 if (!force && mpctx->playtree_iter) {
2498 play_tree_iter_t *i =
2499 play_tree_iter_new_copy(mpctx->playtree_iter);
2500 if (play_tree_iter_up_step(i, n, 0) == PLAY_TREE_ITER_ENTRY)
2501 mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2502 play_tree_iter_free(i);
2503 } else
2504 mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV;
2505 brk_cmd = 1;
2507 break;
2509 case MP_CMD_PLAY_ALT_SRC_STEP:
2510 if (mpctx->playtree_iter && mpctx->playtree_iter->num_files > 1) {
2511 int v = cmd->args[0].v.i;
2512 if (v > 0
2513 && mpctx->playtree_iter->file <
2514 mpctx->playtree_iter->num_files)
2515 mpctx->eof = PT_NEXT_SRC;
2516 else if (v < 0 && mpctx->playtree_iter->file > 1)
2517 mpctx->eof = PT_PREV_SRC;
2519 brk_cmd = 1;
2520 break;
2522 case MP_CMD_SUB_STEP:
2523 if (sh_video) {
2524 int movement = cmd->args[0].v.i;
2525 step_sub(subdata, sh_video->pts, movement);
2526 #ifdef USE_ASS
2527 if (ass_track)
2528 sub_delay +=
2529 ass_step_sub(ass_track,
2530 (sh_video->pts +
2531 sub_delay) * 1000 + .5, movement) / 1000.;
2532 #endif
2533 set_osd_msg(OSD_MSG_SUB_DELAY, 1, osd_duration,
2534 MSGTR_OSDSubDelay, ROUND(sub_delay * 1000));
2536 break;
2538 case MP_CMD_SUB_LOG:
2539 log_sub();
2540 break;
2542 case MP_CMD_OSD:{
2543 int v = cmd->args[0].v.i;
2544 int max = (term_osd
2545 && !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL;
2546 if (osd_level > max)
2547 osd_level = max;
2548 if (v < 0)
2549 osd_level = (osd_level + 1) % (max + 1);
2550 else
2551 osd_level = v > max ? max : v;
2552 /* Show OSD state when disabled, but not when an explicit
2553 argument is given to the OSD command, i.e. in slave mode. */
2554 if (v == -1 && osd_level <= 1)
2555 set_osd_msg(OSD_MSG_OSD_STATUS, 0, osd_duration,
2556 MSGTR_OSDosd,
2557 osd_level ? MSGTR_OSDenabled :
2558 MSGTR_OSDdisabled);
2559 else
2560 rm_osd_msg(OSD_MSG_OSD_STATUS);
2562 break;
2564 case MP_CMD_OSD_SHOW_TEXT:
2565 set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2566 (cmd->args[1].v.i <
2567 0 ? osd_duration : cmd->args[1].v.i),
2568 "%-.63s", cmd->args[0].v.s);
2569 break;
2571 case MP_CMD_OSD_SHOW_PROPERTY_TEXT:{
2572 char *txt = m_properties_expand_string(mp_properties,
2573 cmd->args[0].v.s,
2574 mpctx);
2575 /* if no argument supplied take default osd_duration, else <arg> ms. */
2576 if (txt) {
2577 set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i,
2578 (cmd->args[1].v.i <
2579 0 ? osd_duration : cmd->args[1].v.i),
2580 "%-.63s", txt);
2581 free(txt);
2584 break;
2586 case MP_CMD_LOADFILE:{
2587 play_tree_t *e = play_tree_new();
2588 play_tree_add_file(e, cmd->args[0].v.s);
2590 if (cmd->args[1].v.i) // append
2591 play_tree_append_entry(mpctx->playtree, e);
2592 else {
2593 // Go back to the starting point.
2594 while (play_tree_iter_up_step
2595 (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END)
2596 /* NOP */ ;
2597 play_tree_free_list(mpctx->playtree->child, 1);
2598 play_tree_set_child(mpctx->playtree, e);
2599 play_tree_iter_step(mpctx->playtree_iter, 0, 0);
2600 mpctx->eof = PT_NEXT_SRC;
2602 brk_cmd = 1;
2604 break;
2606 case MP_CMD_LOADLIST:{
2607 play_tree_t *e = parse_playlist_file(cmd->args[0].v.s);
2608 if (!e)
2609 mp_msg(MSGT_CPLAYER, MSGL_ERR,
2610 MSGTR_PlaylistLoadUnable, cmd->args[0].v.s);
2611 else {
2612 if (cmd->args[1].v.i) // append
2613 play_tree_append_entry(mpctx->playtree, e);
2614 else {
2615 // Go back to the starting point.
2616 while (play_tree_iter_up_step
2617 (mpctx->playtree_iter, 0, 1)
2618 != PLAY_TREE_ITER_END)
2619 /* NOP */ ;
2620 play_tree_free_list(mpctx->playtree->child, 1);
2621 play_tree_set_child(mpctx->playtree, e);
2622 play_tree_iter_step(mpctx->playtree_iter, 0, 0);
2623 mpctx->eof = PT_NEXT_SRC;
2626 brk_cmd = 1;
2628 break;
2630 #ifdef USE_RADIO
2631 case MP_CMD_RADIO_STEP_CHANNEL:
2632 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
2633 int v = cmd->args[0].v.i;
2634 if (v > 0)
2635 radio_step_channel(mpctx->demuxer->stream,
2636 RADIO_CHANNEL_HIGHER);
2637 else
2638 radio_step_channel(mpctx->demuxer->stream,
2639 RADIO_CHANNEL_LOWER);
2640 if (radio_get_channel_name(mpctx->demuxer->stream)) {
2641 set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2642 MSGTR_OSDChannel,
2643 radio_get_channel_name(mpctx->demuxer->stream));
2646 break;
2648 case MP_CMD_RADIO_SET_CHANNEL:
2649 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO) {
2650 radio_set_channel(mpctx->demuxer->stream, cmd->args[0].v.s);
2651 if (radio_get_channel_name(mpctx->demuxer->stream)) {
2652 set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
2653 MSGTR_OSDChannel,
2654 radio_get_channel_name(mpctx->demuxer->stream));
2657 break;
2659 case MP_CMD_RADIO_SET_FREQ:
2660 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
2661 radio_set_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2662 break;
2664 case MP_CMD_RADIO_STEP_FREQ:
2665 if (mpctx->demuxer->stream->type == STREAMTYPE_RADIO)
2666 radio_step_freq(mpctx->demuxer->stream, cmd->args[0].v.f);
2667 break;
2668 #endif
2670 #ifdef USE_TV
2671 case MP_CMD_TV_START_SCAN:
2672 if (mpctx->file_format == DEMUXER_TYPE_TV)
2673 tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv),1);
2674 break;
2675 case MP_CMD_TV_SET_FREQ:
2676 if (mpctx->file_format == DEMUXER_TYPE_TV)
2677 tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
2678 cmd->args[0].v.f * 16.0);
2679 #ifdef HAVE_PVR
2680 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2681 pvr_set_freq (mpctx->stream, ROUND (cmd->args[0].v.f));
2682 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2683 pvr_get_current_channelname (mpctx->stream),
2684 pvr_get_current_stationname (mpctx->stream));
2686 #endif /* HAVE_PVR */
2687 break;
2689 case MP_CMD_TV_STEP_FREQ:
2690 if (mpctx->file_format == DEMUXER_TYPE_TV)
2691 tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
2692 cmd->args[0].v.f * 16.0);
2693 #ifdef HAVE_PVR
2694 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2695 pvr_force_freq_step (mpctx->stream, ROUND (cmd->args[0].v.f));
2696 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d",
2697 pvr_get_current_channelname (mpctx->stream),
2698 pvr_get_current_frequency (mpctx->stream));
2700 #endif /* HAVE_PVR */
2701 break;
2703 case MP_CMD_TV_SET_NORM:
2704 if (mpctx->file_format == DEMUXER_TYPE_TV)
2705 tv_set_norm((tvi_handle_t *) (mpctx->demuxer->priv),
2706 cmd->args[0].v.s);
2707 break;
2709 case MP_CMD_TV_STEP_CHANNEL:{
2710 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2711 int v = cmd->args[0].v.i;
2712 if (v > 0) {
2713 tv_step_channel((tvi_handle_t *) (mpctx->
2714 demuxer->priv),
2715 TV_CHANNEL_HIGHER);
2716 } else {
2717 tv_step_channel((tvi_handle_t *) (mpctx->
2718 demuxer->priv),
2719 TV_CHANNEL_LOWER);
2721 if (tv_channel_list) {
2722 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2723 MSGTR_OSDChannel, tv_channel_current->name);
2724 //vo_osd_changed(OSDTYPE_SUBTITLE);
2727 #ifdef HAVE_PVR
2728 else if (mpctx->stream &&
2729 mpctx->stream->type == STREAMTYPE_PVR) {
2730 pvr_set_channel_step (mpctx->stream, cmd->args[0].v.i);
2731 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2732 pvr_get_current_channelname (mpctx->stream),
2733 pvr_get_current_stationname (mpctx->stream));
2735 #endif /* HAVE_PVR */
2737 #ifdef HAS_DVBIN_SUPPORT
2738 if (mpctx->stream->type == STREAMTYPE_DVB) {
2739 int dir;
2740 int v = cmd->args[0].v.i;
2742 mpctx->last_dvb_step = v;
2743 if (v > 0)
2744 dir = DVB_CHANNEL_HIGHER;
2745 else
2746 dir = DVB_CHANNEL_LOWER;
2749 if (dvb_step_channel(mpctx->stream, dir))
2750 mpctx->eof = mpctx->dvbin_reopen = 1;
2752 #endif /* HAS_DVBIN_SUPPORT */
2753 break;
2755 case MP_CMD_TV_SET_CHANNEL:
2756 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2757 tv_set_channel((tvi_handle_t *) (mpctx->demuxer->priv),
2758 cmd->args[0].v.s);
2759 if (tv_channel_list) {
2760 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2761 MSGTR_OSDChannel, tv_channel_current->name);
2762 //vo_osd_changed(OSDTYPE_SUBTITLE);
2765 #ifdef HAVE_PVR
2766 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2767 pvr_set_channel (mpctx->stream, cmd->args[0].v.s);
2768 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2769 pvr_get_current_channelname (mpctx->stream),
2770 pvr_get_current_stationname (mpctx->stream));
2772 #endif /* HAVE_PVR */
2773 break;
2775 #ifdef HAS_DVBIN_SUPPORT
2776 case MP_CMD_DVB_SET_CHANNEL:
2777 if (mpctx->stream->type == STREAMTYPE_DVB) {
2778 mpctx->last_dvb_step = 1;
2780 if (dvb_set_channel
2781 (mpctx->stream, cmd->args[1].v.i, cmd->args[0].v.i))
2782 mpctx->eof = mpctx->dvbin_reopen = 1;
2784 break;
2785 #endif /* HAS_DVBIN_SUPPORT */
2787 case MP_CMD_TV_LAST_CHANNEL:
2788 if (mpctx->file_format == DEMUXER_TYPE_TV) {
2789 tv_last_channel((tvi_handle_t *) (mpctx->demuxer->priv));
2790 if (tv_channel_list) {
2791 set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration,
2792 MSGTR_OSDChannel, tv_channel_current->name);
2793 //vo_osd_changed(OSDTYPE_SUBTITLE);
2796 #ifdef HAVE_PVR
2797 else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
2798 pvr_set_lastchannel (mpctx->stream);
2799 set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
2800 pvr_get_current_channelname (mpctx->stream),
2801 pvr_get_current_stationname (mpctx->stream));
2803 #endif /* HAVE_PVR */
2804 break;
2806 case MP_CMD_TV_STEP_NORM:
2807 if (mpctx->file_format == DEMUXER_TYPE_TV)
2808 tv_step_norm((tvi_handle_t *) (mpctx->demuxer->priv));
2809 break;
2811 case MP_CMD_TV_STEP_CHANNEL_LIST:
2812 if (mpctx->file_format == DEMUXER_TYPE_TV)
2813 tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv));
2814 break;
2815 #ifdef HAVE_TV_TELETEXT
2816 case MP_CMD_TV_TELETEXT_ADD_DEC:
2818 tvi_handle_t* tvh=(tvi_handle_t *)(mpctx->demuxer->priv);
2819 if (mpctx->file_format == DEMUXER_TYPE_TV)
2820 tvh->functions->control(tvh->priv,TV_VBI_CONTROL_ADD_DEC,&(cmd->args[0].v.s));
2821 break;
2823 case MP_CMD_TV_TELETEXT_GO_LINK:
2825 tvi_handle_t* tvh=(tvi_handle_t *)(mpctx->demuxer->priv);
2826 if (mpctx->file_format == DEMUXER_TYPE_TV)
2827 tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GO_LINK,&(cmd->args[0].v.i));
2828 break;
2830 #endif /* HAVE_TV_TELETEXT */
2831 #endif /* USE_TV */
2833 case MP_CMD_SUB_LOAD:
2834 if (sh_video) {
2835 int n = mpctx->set_of_sub_size;
2836 add_subtitles(mpctx, cmd->args[0].v.s, sh_video->fps, 0);
2837 if (n != mpctx->set_of_sub_size) {
2838 if (mpctx->global_sub_indices[SUB_SOURCE_SUBS] < 0)
2839 mpctx->global_sub_indices[SUB_SOURCE_SUBS] =
2840 mpctx->global_sub_size;
2841 ++mpctx->global_sub_size;
2844 break;
2846 case MP_CMD_SUB_REMOVE:
2847 if (sh_video) {
2848 int v = cmd->args[0].v.i;
2849 sub_data *subd;
2850 if (v < 0) {
2851 for (v = 0; v < mpctx->set_of_sub_size; ++v) {
2852 subd = mpctx->set_of_subtitles[v];
2853 mp_msg(MSGT_CPLAYER, MSGL_STATUS,
2854 MSGTR_RemovedSubtitleFile, v + 1,
2855 filename_recode(subd->filename));
2856 sub_free(subd);
2857 mpctx->set_of_subtitles[v] = NULL;
2859 mpctx->global_sub_indices[SUB_SOURCE_SUBS] = -1;
2860 mpctx->global_sub_size -= mpctx->set_of_sub_size;
2861 mpctx->set_of_sub_size = 0;
2862 if (mpctx->set_of_sub_pos >= 0) {
2863 mpctx->global_sub_pos = -2;
2864 subdata = NULL;
2865 mp_input_queue_cmd(mp_input_parse_cmd("sub_select"));
2867 } else if (v < mpctx->set_of_sub_size) {
2868 subd = mpctx->set_of_subtitles[v];
2869 mp_msg(MSGT_CPLAYER, MSGL_STATUS,
2870 MSGTR_RemovedSubtitleFile, v + 1,
2871 filename_recode(subd->filename));
2872 sub_free(subd);
2873 if (mpctx->set_of_sub_pos == v) {
2874 mpctx->global_sub_pos = -2;
2875 subdata = NULL;
2876 mp_input_queue_cmd(mp_input_parse_cmd("sub_select"));
2877 } else if (mpctx->set_of_sub_pos > v) {
2878 --mpctx->set_of_sub_pos;
2879 --mpctx->global_sub_pos;
2881 while (++v < mpctx->set_of_sub_size)
2882 mpctx->set_of_subtitles[v - 1] =
2883 mpctx->set_of_subtitles[v];
2884 --mpctx->set_of_sub_size;
2885 --mpctx->global_sub_size;
2886 if (mpctx->set_of_sub_size <= 0)
2887 mpctx->global_sub_indices[SUB_SOURCE_SUBS] = -1;
2888 mpctx->set_of_subtitles[mpctx->set_of_sub_size] = NULL;
2891 break;
2893 case MP_CMD_GET_SUB_VISIBILITY:
2894 if (sh_video) {
2895 mp_msg(MSGT_GLOBAL, MSGL_INFO,
2896 "ANS_SUB_VISIBILITY=%d\n", sub_visibility);
2898 break;
2900 case MP_CMD_SCREENSHOT:
2901 if (mpctx->video_out && mpctx->video_out->config_ok) {
2902 mp_msg(MSGT_CPLAYER, MSGL_INFO, "sending VFCTRL_SCREENSHOT!\n");
2903 if (CONTROL_OK !=
2904 ((vf_instance_t *) sh_video->vfilter)->
2905 control(sh_video->vfilter, VFCTRL_SCREENSHOT,
2906 &cmd->args[0].v.i))
2907 mp_msg(MSGT_CPLAYER, MSGL_INFO, "failed (forgot -vf screenshot?)\n");
2909 break;
2911 case MP_CMD_VF_CHANGE_RECTANGLE:
2912 set_rectangle(sh_video, cmd->args[0].v.i, cmd->args[1].v.i);
2913 break;
2915 case MP_CMD_GET_TIME_LENGTH:{
2916 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_LENGTH=%.2lf\n",
2917 demuxer_get_time_length(mpctx->demuxer));
2919 break;
2921 case MP_CMD_GET_FILENAME:{
2922 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_FILENAME='%s'\n",
2923 get_metadata(mpctx, META_NAME));
2925 break;
2927 case MP_CMD_GET_VIDEO_CODEC:{
2928 char *inf = get_metadata(mpctx, META_VIDEO_CODEC);
2929 if (!inf)
2930 inf = strdup("");
2931 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_CODEC='%s'\n", inf);
2932 free(inf);
2934 break;
2936 case MP_CMD_GET_VIDEO_BITRATE:{
2937 char *inf = get_metadata(mpctx, META_VIDEO_BITRATE);
2938 if (!inf)
2939 inf = strdup("");
2940 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_BITRATE='%s'\n", inf);
2941 free(inf);
2943 break;
2945 case MP_CMD_GET_VIDEO_RESOLUTION:{
2946 char *inf = get_metadata(mpctx, META_VIDEO_RESOLUTION);
2947 if (!inf)
2948 inf = strdup("");
2949 mp_msg(MSGT_GLOBAL, MSGL_INFO,
2950 "ANS_VIDEO_RESOLUTION='%s'\n", inf);
2951 free(inf);
2953 break;
2955 case MP_CMD_GET_AUDIO_CODEC:{
2956 char *inf = get_metadata(mpctx, META_AUDIO_CODEC);
2957 if (!inf)
2958 inf = strdup("");
2959 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_CODEC='%s'\n", inf);
2960 free(inf);
2962 break;
2964 case MP_CMD_GET_AUDIO_BITRATE:{
2965 char *inf = get_metadata(mpctx, META_AUDIO_BITRATE);
2966 if (!inf)
2967 inf = strdup("");
2968 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_BITRATE='%s'\n", inf);
2969 free(inf);
2971 break;
2973 case MP_CMD_GET_AUDIO_SAMPLES:{
2974 char *inf = get_metadata(mpctx, META_AUDIO_SAMPLES);
2975 if (!inf)
2976 inf = strdup("");
2977 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_SAMPLES='%s'\n", inf);
2978 free(inf);
2980 break;
2982 case MP_CMD_GET_META_TITLE:{
2983 char *inf = get_metadata(mpctx, META_INFO_TITLE);
2984 if (!inf)
2985 inf = strdup("");
2986 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TITLE='%s'\n", inf);
2987 free(inf);
2989 break;
2991 case MP_CMD_GET_META_ARTIST:{
2992 char *inf = get_metadata(mpctx, META_INFO_ARTIST);
2993 if (!inf)
2994 inf = strdup("");
2995 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ARTIST='%s'\n", inf);
2996 free(inf);
2998 break;
3000 case MP_CMD_GET_META_ALBUM:{
3001 char *inf = get_metadata(mpctx, META_INFO_ALBUM);
3002 if (!inf)
3003 inf = strdup("");
3004 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ALBUM='%s'\n", inf);
3005 free(inf);
3007 break;
3009 case MP_CMD_GET_META_YEAR:{
3010 char *inf = get_metadata(mpctx, META_INFO_YEAR);
3011 if (!inf)
3012 inf = strdup("");
3013 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_YEAR='%s'\n", inf);
3014 free(inf);
3016 break;
3018 case MP_CMD_GET_META_COMMENT:{
3019 char *inf = get_metadata(mpctx, META_INFO_COMMENT);
3020 if (!inf)
3021 inf = strdup("");
3022 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_COMMENT='%s'\n", inf);
3023 free(inf);
3025 break;
3027 case MP_CMD_GET_META_TRACK:{
3028 char *inf = get_metadata(mpctx, META_INFO_TRACK);
3029 if (!inf)
3030 inf = strdup("");
3031 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TRACK='%s'\n", inf);
3032 free(inf);
3034 break;
3036 case MP_CMD_GET_META_GENRE:{
3037 char *inf = get_metadata(mpctx, META_INFO_GENRE);
3038 if (!inf)
3039 inf = strdup("");
3040 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_GENRE='%s'\n", inf);
3041 free(inf);
3043 break;
3045 case MP_CMD_GET_VO_FULLSCREEN:
3046 if (mpctx->video_out && mpctx->video_out->config_ok)
3047 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VO_FULLSCREEN=%d\n", vo_fs);
3048 break;
3050 case MP_CMD_GET_PERCENT_POS:
3051 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_PERCENT_POSITION=%d\n",
3052 demuxer_get_percent_pos(mpctx->demuxer));
3053 break;
3055 case MP_CMD_GET_TIME_POS:{
3056 float pos = 0;
3057 if (sh_video)
3058 pos = sh_video->pts;
3059 else if (sh_audio && mpctx->audio_out)
3060 pos = playing_audio_pts(mpctx);
3061 mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_TIME_POSITION=%.1f\n", pos);
3063 break;
3065 case MP_CMD_RUN:
3066 #ifndef __MINGW32__
3067 if (!fork()) {
3068 execl("/bin/sh", "sh", "-c", cmd->args[0].v.s, NULL);
3069 exit(0);
3071 #endif
3072 break;
3074 case MP_CMD_KEYDOWN_EVENTS:
3075 mplayer_put_key(cmd->args[0].v.i);
3076 break;
3078 case MP_CMD_SET_MOUSE_POS:{
3079 int pointer_x, pointer_y;
3080 double dx, dy;
3081 pointer_x = cmd->args[0].v.i;
3082 pointer_y = cmd->args[1].v.i;
3083 rescale_input_coordinates(mpctx, pointer_x, pointer_y, &dx, &dy);
3084 #ifdef USE_DVDNAV
3085 if (mpctx->stream->type == STREAMTYPE_DVDNAV
3086 && dx > 0.0 && dy > 0.0) {
3087 int button = -1;
3088 pointer_x = (int) (dx * (double) sh_video->disp_w);
3089 pointer_y = (int) (dy * (double) sh_video->disp_h);
3090 mp_dvdnav_update_mouse_pos(mpctx->stream,
3091 pointer_x, pointer_y, &button);
3092 if (osd_level > 1 && button > 0)
3093 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3094 "Selected button number %d", button);
3096 #endif
3097 #ifdef HAVE_MENU
3098 if (use_menu && dx >= 0.0 && dy >= 0.0)
3099 menu_update_mouse_pos(dx, dy);
3100 #endif
3102 break;
3104 #ifdef USE_DVDNAV
3105 case MP_CMD_DVDNAV:{
3106 int button = -1;
3107 if (mpctx->stream->type != STREAMTYPE_DVDNAV)
3108 break;
3110 mp_dvdnav_handle_input(mpctx->stream,cmd->args[0].v.i,&button);
3111 if (osd_level > 1 && button > 0)
3112 set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
3113 "Selected button number %d", button);
3115 break;
3117 case MP_CMD_SWITCH_TITLE:
3118 if (mpctx->stream->type == STREAMTYPE_DVDNAV)
3119 mp_dvdnav_switch_title(mpctx->stream, cmd->args[0].v.i);
3120 break;
3122 #endif
3124 default:
3125 #ifdef HAVE_NEW_GUI
3126 if ((use_gui) && (cmd->id > MP_CMD_GUI_EVENTS))
3127 guiGetEvent(guiIEvent, (char *) cmd->id);
3128 else
3129 #endif
3130 mp_msg(MSGT_CPLAYER, MSGL_V,
3131 "Received unknown cmd %s\n", cmd->name);
3134 switch (cmd->pausing) {
3135 case 1: // "pausing"
3136 mpctx->osd_function = OSD_PAUSE;
3137 break;
3138 case 3: // "pausing_toggle"
3139 mpctx->was_paused = !mpctx->was_paused;
3140 if (mpctx->was_paused)
3141 mpctx->osd_function = OSD_PAUSE;
3142 else if (mpctx->osd_function == OSD_PAUSE)
3143 mpctx->osd_function = OSD_PLAY;
3144 break;
3145 case 2: // "pausing_keep"
3146 if (mpctx->was_paused)
3147 mpctx->osd_function = OSD_PAUSE;
3149 return brk_cmd;