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"
14 #include "libvo/sub.h"
16 #include "m_property.h"
19 #include "libmpcodecs/vf.h"
20 #include "libmpcodecs/vd.h"
22 #include "libvo/video_out.h"
23 #include "libvo/font_load.h"
25 #include "libao2/audio_out.h"
28 #include "libmpcodecs/dec_video.h"
33 #include "stream/tv.h"
36 #include "stream/stream_radio.h"
39 #include "stream/pvr.h"
41 #ifdef HAS_DVBIN_SUPPORT
42 #include "stream/dvbin.h"
45 #include "stream/stream_dvd.h"
48 #include "stream/stream_dvdnav.h"
51 #include "libass/ass.h"
52 #include "libass/ass_mp.h"
56 #include "libmenu/menu.h"
59 #include "gui/interface.h"
64 #include "libavutil/avstring.h"
66 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
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
) {
85 } //we are on one of the borders
86 if (iy
< 0 || iy
> vo
->dheight
) {
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
,
101 static int sub_source_by_pos(MPContext
* mpctx
, int pos
)
106 for (i
= 0; i
< SUB_SOURCES
; i
++) {
107 int j
= mpctx
->global_sub_indices
[i
];
108 if ((j
>= 0) && (j
> top
) && (pos
>= j
)) {
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)
137 if (subdata
== NULL
|| vo_sub_last
== NULL
)
139 fname
= get_path("subtitle_log");
140 f
= fopen(fname
, "a");
143 fprintf(f
, "----------------------------------------------------------\n");
144 if (subdata
->sub_uses_time
) {
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);
153 fprintf(f
, "N: %s S: %ld E: %ld\n", filename
, vo_sub_last
->start
,
156 for (i
= 0; i
< vo_sub_last
->lines
; i
++) {
157 fprintf(f
, "%s\n", vo_sub_last
->text
[i
]);
163 /// \defgroup Properties
166 /// \defgroup GeneralProperties General properties
167 /// \ingroup Properties
171 static int mp_property_osdlevel(m_option_t
* prop
, int action
, void *arg
,
174 return m_property_choice(prop
, action
, arg
, &osd_level
);
178 static int mp_property_loop(m_option_t
* prop
, int action
, void *arg
,
181 struct MPOpts
*opts
= &mpctx
->opts
;
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");
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
;
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
,
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
,
233 return M_PROPERTY_UNAVAILABLE
;
234 if (((f
= strrchr(filename
, '/')) || (f
= strrchr(filename
, '\\'))) && f
[1])
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
,
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
,
255 if (!mpctx
->demuxer
|| !mpctx
->demuxer
->stream
)
256 return M_PROPERTY_UNAVAILABLE
;
258 return M_PROPERTY_ERROR
;
261 *(off_t
*) arg
= stream_tell(mpctx
->demuxer
->stream
);
262 return M_PROPERTY_OK
;
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
;
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
,
289 if (!mpctx
->demuxer
|| !mpctx
->demuxer
->stream
)
290 return M_PROPERTY_UNAVAILABLE
;
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
;
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
,
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
) {
333 return M_PROPERTY_UNAVAILABLE
;
337 if(!arg
) return M_PROPERTY_ERROR
;
338 M_PROPERTY_CLAMP(prop
, *(int*)arg
);
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
);
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
;
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
,
390 char *chapter_name
= NULL
;
392 chapter
= demuxer_get_current_chapter(mpctx
->demuxer
);
394 return M_PROPERTY_UNAVAILABLE
;
399 return M_PROPERTY_ERROR
;
400 *(int *) arg
= chapter
;
401 return M_PROPERTY_OK
;
402 case M_PROPERTY_PRINT
: {
404 return M_PROPERTY_ERROR
;
405 chapter_name
= demuxer_chapter_display_name(mpctx
->demuxer
, chapter
);
407 return M_PROPERTY_UNAVAILABLE
;
408 *(char **) arg
= chapter_name
;
409 return M_PROPERTY_OK
;
413 return M_PROPERTY_ERROR
;
414 M_PROPERTY_CLAMP(prop
, *(int*)arg
);
415 step_all
= *(int *)arg
- (chapter
+ 1);
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);
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
);
435 if (next_pts
> -1.0) {
436 mpctx
->abs_seek_pos
= SEEK_ABSOLUTE
;
437 mpctx
->rel_seek_secs
= next_pts
;
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.;
446 set_osd_msg(OSD_MSG_TEXT
, 1, osd_duration
,
447 MSGTR_OSDChapter
, 0, MSGTR_Unknown
);
450 return M_PROPERTY_OK
;
453 /// Current dvd angle (RW)
454 static int mp_property_angle(m_option_t
*prop
, int action
, void *arg
,
459 char *angle_name
= NULL
;
461 angle
= demuxer_get_current_angle(mpctx
->demuxer
);
463 return M_PROPERTY_UNAVAILABLE
;
464 angles
= demuxer_angles_count(mpctx
->demuxer
);
466 return M_PROPERTY_UNAVAILABLE
;
471 return M_PROPERTY_ERROR
;
472 *(int *) arg
= angle
;
473 return M_PROPERTY_OK
;
474 case M_PROPERTY_PRINT
: {
476 return M_PROPERTY_ERROR
;
477 angle_name
= calloc(1, 64);
479 return M_PROPERTY_UNAVAILABLE
;
480 snprintf(angle_name
, 64, "%d/%d", angle
, angles
);
481 *(char **) arg
= angle_name
;
482 return M_PROPERTY_OK
;
486 return M_PROPERTY_ERROR
;
488 M_PROPERTY_CLAMP(prop
, angle
);
490 case M_PROPERTY_STEP_UP
:
491 case M_PROPERTY_STEP_DOWN
: {
497 step
*= (action
== M_PROPERTY_STEP_UP
? 1 : -1);
499 if (angle
< 1) //cycle
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
);
511 return M_PROPERTY_OK
;
514 /// Demuxer meta data
515 static int mp_property_metadata(m_option_t
* prop
, int action
, void *arg
,
517 m_property_action_t
* ka
;
519 static m_option_t key_type
=
520 { "metadata", NULL
, CONF_TYPE_STRING
, 0, 0, 0, NULL
};
522 return M_PROPERTY_UNAVAILABLE
;
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
;
532 if(!(meta
= demux_info_get(mpctx
->demuxer
,ka
->key
)))
533 return M_PROPERTY_UNKNOWN
;
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
;
551 /// \defgroup AudioProperties Audio properties
552 /// \ingroup Properties
556 static int mp_property_volume(m_option_t
* prop
, int action
, void *arg
,
560 if (!mpctx
->sh_audio
)
561 return M_PROPERTY_UNAVAILABLE
;
566 return M_PROPERTY_ERROR
;
567 mixer_getbothvolume(&mpctx
->mixer
, arg
);
568 return M_PROPERTY_OK
;
569 case M_PROPERTY_PRINT
:{
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
:
581 return M_PROPERTY_NOT_IMPLEMENTED
;
584 if (mpctx
->edl_muted
)
585 return M_PROPERTY_DISABLED
;
586 mpctx
->user_muted
= 0;
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
);
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
);
605 mixer_decvolume(&mpctx
->mixer
);
606 return M_PROPERTY_OK
;
608 return M_PROPERTY_NOT_IMPLEMENTED
;
612 static int mp_property_mute(m_option_t
* prop
, int action
, void *arg
,
616 if (!mpctx
->sh_audio
)
617 return M_PROPERTY_UNAVAILABLE
;
621 if (mpctx
->edl_muted
)
622 return M_PROPERTY_DISABLED
;
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
:
638 return M_PROPERTY_ERROR
;
639 if (mpctx
->edl_muted
) {
640 *(char **) arg
= strdup(MSGTR_EnabledEdl
);
641 return M_PROPERTY_OK
;
644 return m_property_flag(prop
, action
, arg
, &mpctx
->mixer
.muted
);
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
;
657 case M_PROPERTY_STEP_UP
:
658 case M_PROPERTY_STEP_DOWN
: {
660 float delay
= audio_delay
;
661 ret
= m_property_delay(prop
, action
, arg
, &audio_delay
);
662 if (ret
!= M_PROPERTY_OK
)
665 mpctx
->delay
-= audio_delay
- delay
;
667 return M_PROPERTY_OK
;
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
);
701 static int mp_property_samplerate(m_option_t
* prop
, int action
, void *arg
,
704 if (!mpctx
->sh_audio
)
705 return M_PROPERTY_UNAVAILABLE
;
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
,
720 if (!mpctx
->sh_audio
)
721 return M_PROPERTY_UNAVAILABLE
;
723 case M_PROPERTY_PRINT
:
725 return M_PROPERTY_ERROR
;
726 switch (mpctx
->sh_audio
->channels
) {
728 *(char **) arg
= strdup("mono");
731 *(char **) arg
= strdup("stereo");
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
);
743 static int mp_property_balance(m_option_t
* prop
, int action
, void *arg
,
748 if (!mpctx
->sh_audio
|| mpctx
->sh_audio
->channels
< 2)
749 return M_PROPERTY_UNAVAILABLE
;
754 return M_PROPERTY_ERROR
;
755 mixer_getbalance(&mpctx
->mixer
, arg
);
756 return M_PROPERTY_OK
;
757 case M_PROPERTY_PRINT
: {
760 return M_PROPERTY_ERROR
;
761 mixer_getbalance(&mpctx
->mixer
, &bal
);
763 *str
= strdup("center");
764 else if (bal
== -1.f
)
765 *str
= strdup("left only");
767 *str
= strdup("right only");
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
;
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
,
797 struct MPOpts
*opts
= &mpctx
->opts
;
798 int current_id
= -1, tmp
;
802 if (!mpctx
->sh_audio
)
803 return M_PROPERTY_UNAVAILABLE
;
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
;
812 return M_PROPERTY_ERROR
;
814 if (opts
->audio_id
< 0)
815 *(char **) arg
= strdup(MSGTR_Disabled
);
817 char lang
[40] = MSGTR_Unknown
;
818 sh_audio_t
* sh
= mpctx
->sh_audio
;
820 av_strlcpy(lang
, sh
->lang
, 40);
822 else if (mpctx
->stream
->type
== STREAMTYPE_DVD
) {
823 int code
= dvd_lang_from_aid(mpctx
->stream
, opts
->audio_id
);
833 else if (mpctx
->stream
->type
== STREAMTYPE_DVDNAV
)
834 dvdnav_lang_from_aid(mpctx
->stream
, opts
->audio_id
, lang
);
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
:
843 if (action
== M_PROPERTY_SET
&& arg
)
844 tmp
= *((int *) arg
);
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
) {
855 sh2
= mpctx
->demuxer
->a_streams
[mpctx
->demuxer
->audio
->id
];
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
;
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
,
874 struct MPOpts
*opts
= &mpctx
->opts
;
875 int current_id
= -1, tmp
;
879 if (!mpctx
->sh_video
)
880 return M_PROPERTY_UNAVAILABLE
;
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
;
889 return M_PROPERTY_ERROR
;
891 if (opts
->video_id
< 0)
892 *(char **) arg
= strdup(MSGTR_Disabled
);
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
:
902 current_id
= mpctx
->demuxer
->video
->id
;
903 if (action
== M_PROPERTY_SET
&& arg
)
904 tmp
= *((int *) arg
);
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
) {
915 sh2
= mpctx
->demuxer
->v_streams
[mpctx
->demuxer
->video
->id
];
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
;
926 return M_PROPERTY_NOT_IMPLEMENTED
;
930 static int mp_property_program(m_option_t
* prop
, int action
, void *arg
,
933 demux_program_t prog
;
936 case M_PROPERTY_STEP_UP
:
938 if (action
== M_PROPERTY_SET
&& arg
)
939 prog
.progid
= *((int *) arg
);
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
;
952 return M_PROPERTY_NOT_IMPLEMENTED
;
958 /// \defgroup VideoProperties Video properties
959 /// \ingroup Properties
962 /// Fullscreen state (RW)
963 static int mp_property_fullscreen(m_option_t
* prop
, int action
, void *arg
,
967 if (!mpctx
->video_out
)
968 return M_PROPERTY_UNAVAILABLE
;
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
:
981 guiGetEvent(guiIEvent
, (char *) MP_CMD_GUI_FULLSCREEN
);
984 if (mpctx
->video_out
->config_ok
)
985 vo_control(mpctx
->video_out
, VOCTRL_FULLSCREEN
, 0);
986 return M_PROPERTY_OK
;
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
)
997 if (!mpctx
->sh_video
|| !mpctx
->sh_video
->vfilter
)
998 return M_PROPERTY_UNAVAILABLE
;
999 vf
= mpctx
->sh_video
->vfilter
;
1001 case M_PROPERTY_GET
:
1003 return M_PROPERTY_ERROR
;
1004 vf
->control(vf
, VFCTRL_GET_DEINTERLACE
, arg
);
1005 return M_PROPERTY_OK
;
1006 case M_PROPERTY_SET
:
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
;
1023 static int mp_property_panscan(m_option_t
* prop
, int action
, void *arg
,
1027 if (!mpctx
->video_out
1028 || vo_control(mpctx
->video_out
, VOCTRL_GET_PANSCAN
, NULL
) != VO_TRUE
)
1029 return M_PROPERTY_UNAVAILABLE
;
1032 case M_PROPERTY_SET
:
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);
1045 else if (vo_panscan
< 0)
1047 vo_control(mpctx
->video_out
, VOCTRL_SET_PANSCAN
, NULL
);
1048 return M_PROPERTY_OK
;
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
;
1065 case M_PROPERTY_SET
:
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
;
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
,
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
,
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
,
1101 return mp_property_vo_flag(prop
, action
, arg
, VOCTRL_BORDER
,
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
;
1114 case M_PROPERTY_PRINT
:
1116 return M_PROPERTY_ERROR
;
1117 *(char **) arg
= strdup(frame_dropping
== 1 ? MSGTR_Enabled
:
1118 (frame_dropping
== 2 ? MSGTR_HardFrameDrop
:
1120 return M_PROPERTY_OK
;
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
,
1130 int *gamma
= prop
->priv
, r
, val
;
1132 if (!mpctx
->sh_video
)
1133 return M_PROPERTY_UNAVAILABLE
;
1135 if (gamma
[0] == 1000) {
1137 get_video_colors(mpctx
->sh_video
, prop
->name
, gamma
);
1141 case M_PROPERTY_SET
:
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
);
1150 case M_PROPERTY_GET
:
1151 if (get_video_colors(mpctx
->sh_video
, prop
->name
, &val
) > 0) {
1153 return M_PROPERTY_ERROR
;
1155 return M_PROPERTY_OK
;
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
);
1168 return M_PROPERTY_NOT_IMPLEMENTED
;
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
);
1180 return M_PROPERTY_UNAVAILABLE
;
1184 static int mp_property_vsync(m_option_t
* prop
, int action
, void *arg
,
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
)
1195 if (!mpctx
->sh_video
)
1196 return M_PROPERTY_UNAVAILABLE
;
1198 case M_PROPERTY_PRINT
:
1200 return M_PROPERTY_ERROR
;
1201 switch(mpctx
->sh_video
->format
) {
1203 meta
= strdup ("mpeg1"); break;
1205 meta
= strdup ("mpeg2"); break;
1207 meta
= strdup ("mpeg4"); break;
1209 meta
= strdup ("h264"); break;
1211 if(mpctx
->sh_video
->format
>= 0x20202020) {
1213 sprintf (meta
, "%.4s", (char *) &mpctx
->sh_video
->format
);
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
,
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
,
1257 if (!mpctx
->sh_video
)
1258 return M_PROPERTY_UNAVAILABLE
;
1259 return m_property_int_ro(prop
, action
, arg
, mpctx
->sh_video
->disp_h
);
1263 static int mp_property_fps(m_option_t
* prop
, int action
, void *arg
,
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
,
1275 if (!mpctx
->sh_video
)
1276 return M_PROPERTY_UNAVAILABLE
;
1277 return m_property_float_ro(prop
, action
, arg
, mpctx
->sh_video
->aspect
);
1282 /// \defgroup SubProprties Subtitles properties
1283 /// \ingroup Properties
1286 /// Text subtitle position (RW)
1287 static int mp_property_sub_pos(m_option_t
* prop
, int action
, void *arg
,
1290 if (!mpctx
->sh_video
)
1291 return M_PROPERTY_UNAVAILABLE
;
1294 case M_PROPERTY_SET
:
1296 return M_PROPERTY_ERROR
;
1297 case M_PROPERTY_STEP_UP
:
1298 case M_PROPERTY_STEP_DOWN
:
1299 vo_osd_changed(OSDTYPE_SUBTITLE
);
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
,
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;
1315 if (global_sub_size
<= 0)
1316 return M_PROPERTY_UNAVAILABLE
;
1319 case M_PROPERTY_GET
:
1321 return M_PROPERTY_ERROR
;
1322 *(int *) arg
= mpctx
->global_sub_pos
;
1323 return M_PROPERTY_OK
;
1324 case M_PROPERTY_PRINT
:
1326 return M_PROPERTY_ERROR
;
1327 *(char **) arg
= malloc(64);
1328 (*(char **) arg
)[63] = 0;
1331 sub_name
= subdata
->filename
;
1333 if (ass_track
&& ass_track
->name
)
1334 sub_name
= ass_track
->name
;
1339 if ((tmp2
= strrchr(tmp
, '/')))
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
;
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
;
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
;
1378 if (vo_spudec
&& mpctx
->stream
->type
== STREAMTYPE_DVD
1379 && opts
->sub_id
>= 0) {
1381 int code
= dvd_lang_from_sid(mpctx
->stream
, opts
->sub_id
);
1382 lang
[0] = code
>> 8;
1385 snprintf(*(char **) arg
, 63, "(%d) %s", opts
->sub_id
, lang
);
1386 return M_PROPERTY_OK
;
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
:
1398 return M_PROPERTY_ERROR
;
1399 if (*(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
;
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;
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;
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",
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;
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
];
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
];
1455 subdata
= mpctx
->set_of_subtitles
[mpctx
->set_of_sub_pos
];
1456 vo_osd_changed(OSDTYPE_SUBTITLE
);
1458 } else if (source
== SUB_SOURCE_DEMUX
) {
1460 mpctx
->global_sub_pos
- mpctx
->global_sub_indices
[SUB_SOURCE_DEMUX
];
1461 if (d_sub
&& opts
->sub_id
< MAX_S_STREAMS
) {
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
) {
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
);
1480 else if (ass_enabled
)
1481 ass_track
= sh
->ass_track
;
1491 && (mpctx
->stream
->type
== STREAMTYPE_DVD
1492 || mpctx
->stream
->type
== STREAMTYPE_DVDNAV
)
1493 && opts
->sub_id
< 0 && reset_spu
) {
1495 d_sub
->id
= opts
->sub_id
;
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
,
1508 if (!mpctx
->sh_video
|| mpctx
->global_sub_size
<= 0)
1509 return M_PROPERTY_UNAVAILABLE
;
1512 case M_PROPERTY_GET
:
1514 return M_PROPERTY_ERROR
;
1515 *(int *) arg
= sub_source(mpctx
);
1516 return M_PROPERTY_OK
;
1517 case M_PROPERTY_PRINT
:
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
);
1527 case SUB_SOURCE_VOBSUB
:
1528 snprintf(*(char **) arg
, 63, MSGTR_SubSourceVobsub
);
1530 case SUB_SOURCE_DEMUX
:
1531 snprintf(*(char **) arg
, 63, MSGTR_SubSourceDemux
);
1534 snprintf(*(char **) arg
, 63, MSGTR_Disabled
);
1536 return M_PROPERTY_OK
;
1537 case M_PROPERTY_SET
:
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
];
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
;
1558 if (source
>= SUB_SOURCES
)
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
]))
1566 if (source
== cur_source
)
1567 return M_PROPERTY_OK
;
1569 mpctx
->global_sub_pos
= -1;
1571 mpctx
->global_sub_pos
= mpctx
->global_sub_indices
[source
];
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
,
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
;
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
;
1604 case M_PROPERTY_GET
:
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
);
1614 return M_PROPERTY_OK
;
1615 case M_PROPERTY_PRINT
:
1617 return M_PROPERTY_ERROR
;
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
:
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;
1639 mpctx
->global_sub_pos
= -1;
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;
1648 mpctx
->global_sub_pos
= -1;
1650 if (mpctx
->global_sub_pos
== -1) {
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
;
1661 mpctx
->global_sub_pos
= max_sub_pos_for_source
;
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;
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
,
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
;
1701 case M_PROPERTY_PRINT
:
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
:
1709 return M_PROPERTY_ERROR
;
1710 case M_PROPERTY_STEP_UP
:
1711 case M_PROPERTY_STEP_DOWN
:
1712 vo_osd_changed(OSDTYPE_SUBTITLE
);
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
;
1726 case M_PROPERTY_SET
:
1728 return M_PROPERTY_ERROR
;
1729 case M_PROPERTY_STEP_UP
:
1730 case M_PROPERTY_STEP_DOWN
:
1731 vo_osd_changed(OSDTYPE_SUBTITLE
);
1733 vo_osd_changed(OSDTYPE_SPU
);
1735 return m_property_flag(prop
, action
, arg
, &sub_visibility
);
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
;
1748 case M_PROPERTY_SET
:
1750 return M_PROPERTY_ERROR
;
1751 case M_PROPERTY_STEP_UP
:
1752 case M_PROPERTY_STEP_DOWN
:
1753 ass_force_reload
= 1;
1755 return m_property_flag(prop
, action
, arg
, &ass_use_margins
);
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
)
1765 return M_PROPERTY_UNAVAILABLE
;
1768 case M_PROPERTY_SET
:
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
;
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
,
1789 case M_PROPERTY_SET
:
1791 return M_PROPERTY_ERROR
;
1792 M_PROPERTY_CLAMP(prop
, *(float *) arg
);
1795 ass_font_scale
= *(float *) arg
;
1796 ass_force_reload
= 1;
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
:
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;
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
;
1820 return m_property_float_ro(prop
, action
, arg
, ass_font_scale
);
1823 return m_property_float_ro(prop
, action
, arg
, text_font_scale_factor
);
1830 /// \defgroup TVProperties TV properties
1831 /// \ingroup Properties
1836 /// TV color settings (RW)
1837 static int mp_property_tv_color(m_option_t
* prop
, int action
, void *arg
,
1841 tvi_handle_t
*tvh
= mpctx
->demuxer
->priv
;
1842 if (mpctx
->demuxer
->type
!= DEMUXER_TYPE_TV
|| !tvh
)
1843 return M_PROPERTY_UNAVAILABLE
;
1846 case M_PROPERTY_SET
:
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) {
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
;
1870 #ifdef HAVE_TV_TELETEXT
1871 static int mp_property_teletext_common(m_option_t
* prop
, int action
, void *arg
,
1875 int base_ioctl
=(int)prop
->priv
;
1877 for teletext's GET,SET,STEP ioctls this is not 0
1881 tvi_handle_t
*tvh
= mpctx
->demuxer
->priv
;
1882 if (mpctx
->demuxer
->type
!= DEMUXER_TYPE_TV
|| !tvh
)
1883 return M_PROPERTY_UNAVAILABLE
;
1885 return M_PROPERTY_ERROR
;
1888 case M_PROPERTY_GET
:
1890 return M_PROPERTY_ERROR
;
1891 result
=tvh
->functions
->control(tvh
->priv
, base_ioctl
, arg
);
1893 case M_PROPERTY_SET
:
1895 return M_PROPERTY_ERROR
;
1896 M_PROPERTY_CLAMP(prop
, *(int *) arg
);
1897 result
=tvh
->functions
->control(tvh
->priv
, base_ioctl
+1, arg
);
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
);
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
,
1915 tvi_handle_t
*tvh
= mpctx
->demuxer
->priv
;
1919 //with tvh==NULL will fail too
1920 result
=mp_property_teletext_common(prop
,action
,arg
,mpctx
);
1921 if(result
!=M_PROPERTY_OK
)
1924 if(tvh
->functions
->control(tvh
->priv
, prop
->priv
, &val
)==TVI_CONTROL_TRUE
&& val
)
1925 mp_input_set_section("teletext");
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
,
1934 tvi_handle_t
*tvh
= mpctx
->demuxer
->priv
;
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
);
1945 result
=mp_property_teletext_common(prop
,action
,arg
,mpctx
);
1951 #endif /* HAVE_TV_TELETEXT */
1955 /// All properties available in MPlayer.
1956 /** \ingroup Properties
1958 static const m_option_t mp_properties
[] = {
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
,
1968 { "path", mp_property_path
, CONF_TYPE_STRING
,
1970 { "demuxer", mp_property_demuxer
, CONF_TYPE_STRING
,
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
,
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
,
2002 { "audio_codec", mp_property_audio_codec
, CONF_TYPE_STRING
,
2004 { "audio_bitrate", mp_property_audio_bitrate
, CONF_TYPE_INT
,
2006 { "samplerate", mp_property_samplerate
, CONF_TYPE_INT
,
2008 { "channels", mp_property_channels
, CONF_TYPE_INT
,
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
},
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
,
2044 { "video_codec", mp_property_video_codec
, CONF_TYPE_STRING
,
2046 { "video_bitrate", mp_property_video_bitrate
, CONF_TYPE_INT
,
2048 { "width", mp_property_width
, CONF_TYPE_INT
,
2050 { "height", mp_property_height
, CONF_TYPE_INT
,
2052 { "fps", mp_property_fps
, CONF_TYPE_FLOAT
,
2054 { "aspect", mp_property_aspect
, CONF_TYPE_FLOAT
,
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
},
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
,
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
},
2087 { "ass_use_margins", mp_property_ass_use_margins
, CONF_TYPE_FLAG
,
2088 M_OPT_RANGE
, 0, 1, NULL
},
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
},
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
},
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
)
2127 if(mp_property_do(name
,M_PROPERTY_PRINT
,&ret
,ctx
) <= 0)
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
);
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
2166 /// List of the commands that can be handled by setting a property.
2172 /// set/adjust or toggle command
2174 /// progressbar type
2176 /// osd msg id if it must be shared
2178 /// osd msg template
2179 const char *osd_msg
;
2180 } set_prop_cmd
[] = {
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
},
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
},
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
},
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
},
2219 { "ass_use_margins", MP_CMD_ASS_USE_MARGINS
, 1, 0, -1, NULL
},
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
},
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
)
2238 // look for the command
2239 for (i
= 0; set_prop_cmd
[i
].name
; i
++)
2240 if (set_prop_cmd
[i
].cmd
== cmd
->id
)
2242 if (!(pname
= set_prop_cmd
[i
].name
))
2245 if (mp_property_do(pname
,M_PROPERTY_GET_TYPE
,&prop
,mpctx
) <= 0 || !prop
)
2249 if (set_prop_cmd
[i
].toggle
) {
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
);
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
);
2258 r
= mp_property_do(pname
, M_PROPERTY_STEP_UP
, &cmd
->args
[0].v
, mpctx
);
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
) {
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
);
2274 mp_msg(MSGT_CPLAYER
, MSGL_ERR
,
2275 "Property use an unsupported type.\n");
2279 if (set_prop_cmd
[i
].osd_msg
) {
2280 char *val
= mp_property_print(pname
, mpctx
);
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
);
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
;
2298 if (!set_property_command(mpctx
, cmd
))
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
;
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
;
2316 mpctx
->osd_function
= OSD_FFW
; // Direction isn't set correctly
2317 mpctx
->rel_seek_secs
= v
/ 100.0;
2319 mpctx
->rel_seek_secs
+= v
;
2320 mpctx
->osd_function
= (v
> 0) ? OSD_FFW
: OSD_REW
;
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
);
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
);
2339 case MP_CMD_STEP_PROPERTY
:{
2344 if (cmd
->args
[1].v
.f
) {
2346 if((r
= mp_property_do(cmd
->args
[0].v
.s
,
2347 M_PROPERTY_GET_TYPE
,
2348 &prop
, mpctx
)) <= 0)
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
;
2361 mp_msg(MSGT_CPLAYER
, MSGL_WARN
,
2362 "Ignoring step size stepping property '%s'.\n",
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
,
2370 if (r
== M_PROPERTY_UNKNOWN
)
2371 mp_msg(MSGT_CPLAYER
, MSGL_WARN
,
2372 "Unknown property: '%s'\n", cmd
->args
[0].v
.s
);
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
);
2380 case MP_CMD_GET_PROPERTY
:{
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",
2389 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_%s=%s\n",
2390 cmd
->args
[0].v
.s
, tmp
);
2395 case MP_CMD_EDL_MARK
:
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
);
2403 if (mpctx
->begin_skip
> v
)
2404 mp_msg(MSGT_CPLAYER
, MSGL_WARN
, MSGTR_EdloutBadStop
);
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
;
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
;
2418 opts
->movie_aspect
= cmd
->args
[0].v
.f
;
2419 mpcodecs_config_vo(sh_video
, sh_video
->disp_w
, sh_video
->disp_h
, 0);
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
);
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
);
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
);
2446 case MP_CMD_FRAME_STEP
:
2452 case MP_CMD_FILE_FILTER
:
2453 file_filter
= cmd
->args
[0].v
.i
;
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
;
2468 for (i
= 0; i
< n
; i
++)
2471 for (i
= 0; i
< -1 * n
; i
++)
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
)
2482 (n
> 0) ? PT_NEXT_ENTRY
: PT_PREV_ENTRY
;
2483 play_tree_iter_free(i
);
2485 mpctx
->eof
= (n
> 0) ? PT_NEXT_ENTRY
: PT_PREV_ENTRY
;
2487 mpctx
->play_tree_step
= n
;
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
);
2504 mpctx
->eof
= (n
> 0) ? PT_UP_NEXT
: PT_UP_PREV
;
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
;
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
;
2522 case MP_CMD_SUB_STEP
:
2524 int movement
= cmd
->args
[0].v
.i
;
2525 step_sub(subdata
, sh_video
->pts
, movement
);
2529 ass_step_sub(ass_track
,
2531 sub_delay
) * 1000 + .5, movement
) / 1000.;
2533 set_osd_msg(OSD_MSG_SUB_DELAY
, 1, osd_duration
,
2534 MSGTR_OSDSubDelay
, ROUND(sub_delay
* 1000));
2538 case MP_CMD_SUB_LOG
:
2543 int v
= cmd
->args
[0].v
.i
;
2545 && !sh_video
) ? MAX_TERM_OSD_LEVEL
: MAX_OSD_LEVEL
;
2546 if (osd_level
> max
)
2549 osd_level
= (osd_level
+ 1) % (max
+ 1);
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
,
2557 osd_level
? MSGTR_OSDenabled
:
2560 rm_osd_msg(OSD_MSG_OSD_STATUS
);
2564 case MP_CMD_OSD_SHOW_TEXT
:
2565 set_osd_msg(OSD_MSG_TEXT
, cmd
->args
[2].v
.i
,
2567 0 ? osd_duration
: cmd
->args
[1].v
.i
),
2568 "%-.63s", cmd
->args
[0].v
.s
);
2571 case MP_CMD_OSD_SHOW_PROPERTY_TEXT
:{
2572 char *txt
= m_properties_expand_string(mp_properties
,
2575 /* if no argument supplied take default osd_duration, else <arg> ms. */
2577 set_osd_msg(OSD_MSG_TEXT
, cmd
->args
[2].v
.i
,
2579 0 ? osd_duration
: cmd
->args
[1].v
.i
),
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
);
2593 // Go back to the starting point.
2594 while (play_tree_iter_up_step
2595 (mpctx
->playtree_iter
, 0, 1) != PLAY_TREE_ITER_END
)
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
;
2606 case MP_CMD_LOADLIST
:{
2607 play_tree_t
*e
= parse_playlist_file(cmd
->args
[0].v
.s
);
2609 mp_msg(MSGT_CPLAYER
, MSGL_ERR
,
2610 MSGTR_PlaylistLoadUnable
, cmd
->args
[0].v
.s
);
2612 if (cmd
->args
[1].v
.i
) // append
2613 play_tree_append_entry(mpctx
->playtree
, e
);
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
)
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
;
2631 case MP_CMD_RADIO_STEP_CHANNEL
:
2632 if (mpctx
->demuxer
->stream
->type
== STREAMTYPE_RADIO
) {
2633 int v
= cmd
->args
[0].v
.i
;
2635 radio_step_channel(mpctx
->demuxer
->stream
,
2636 RADIO_CHANNEL_HIGHER
);
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
,
2643 radio_get_channel_name(mpctx
->demuxer
->stream
));
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
,
2654 radio_get_channel_name(mpctx
->demuxer
->stream
));
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
);
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
);
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);
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);
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 */
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);
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 */
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
),
2709 case MP_CMD_TV_STEP_CHANNEL
:{
2710 if (mpctx
->file_format
== DEMUXER_TYPE_TV
) {
2711 int v
= cmd
->args
[0].v
.i
;
2713 tv_step_channel((tvi_handle_t
*) (mpctx
->
2717 tv_step_channel((tvi_handle_t
*) (mpctx
->
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);
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
) {
2740 int v
= cmd
->args
[0].v
.i
;
2742 mpctx
->last_dvb_step
= v
;
2744 dir
= DVB_CHANNEL_HIGHER
;
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 */
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
),
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);
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 */
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;
2781 (mpctx
->stream
, cmd
->args
[1].v
.i
, cmd
->args
[0].v
.i
))
2782 mpctx
->eof
= mpctx
->dvbin_reopen
= 1;
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);
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 */
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
));
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
));
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
));
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
));
2830 #endif /* HAVE_TV_TELETEXT */
2833 case MP_CMD_SUB_LOAD
:
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
;
2846 case MP_CMD_SUB_REMOVE
:
2848 int v
= cmd
->args
[0].v
.i
;
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
));
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;
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
));
2873 if (mpctx
->set_of_sub_pos
== v
) {
2874 mpctx
->global_sub_pos
= -2;
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
;
2893 case MP_CMD_GET_SUB_VISIBILITY
:
2895 mp_msg(MSGT_GLOBAL
, MSGL_INFO
,
2896 "ANS_SUB_VISIBILITY=%d\n", sub_visibility
);
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");
2904 ((vf_instance_t
*) sh_video
->vfilter
)->
2905 control(sh_video
->vfilter
, VFCTRL_SCREENSHOT
,
2907 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "failed (forgot -vf screenshot?)\n");
2911 case MP_CMD_VF_CHANGE_RECTANGLE
:
2912 set_rectangle(sh_video
, cmd
->args
[0].v
.i
, cmd
->args
[1].v
.i
);
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
));
2921 case MP_CMD_GET_FILENAME
:{
2922 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_FILENAME='%s'\n",
2923 get_metadata(mpctx
, META_NAME
));
2927 case MP_CMD_GET_VIDEO_CODEC
:{
2928 char *inf
= get_metadata(mpctx
, META_VIDEO_CODEC
);
2931 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_VIDEO_CODEC='%s'\n", inf
);
2936 case MP_CMD_GET_VIDEO_BITRATE
:{
2937 char *inf
= get_metadata(mpctx
, META_VIDEO_BITRATE
);
2940 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_VIDEO_BITRATE='%s'\n", inf
);
2945 case MP_CMD_GET_VIDEO_RESOLUTION
:{
2946 char *inf
= get_metadata(mpctx
, META_VIDEO_RESOLUTION
);
2949 mp_msg(MSGT_GLOBAL
, MSGL_INFO
,
2950 "ANS_VIDEO_RESOLUTION='%s'\n", inf
);
2955 case MP_CMD_GET_AUDIO_CODEC
:{
2956 char *inf
= get_metadata(mpctx
, META_AUDIO_CODEC
);
2959 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_AUDIO_CODEC='%s'\n", inf
);
2964 case MP_CMD_GET_AUDIO_BITRATE
:{
2965 char *inf
= get_metadata(mpctx
, META_AUDIO_BITRATE
);
2968 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_AUDIO_BITRATE='%s'\n", inf
);
2973 case MP_CMD_GET_AUDIO_SAMPLES
:{
2974 char *inf
= get_metadata(mpctx
, META_AUDIO_SAMPLES
);
2977 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_AUDIO_SAMPLES='%s'\n", inf
);
2982 case MP_CMD_GET_META_TITLE
:{
2983 char *inf
= get_metadata(mpctx
, META_INFO_TITLE
);
2986 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_TITLE='%s'\n", inf
);
2991 case MP_CMD_GET_META_ARTIST
:{
2992 char *inf
= get_metadata(mpctx
, META_INFO_ARTIST
);
2995 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_ARTIST='%s'\n", inf
);
3000 case MP_CMD_GET_META_ALBUM
:{
3001 char *inf
= get_metadata(mpctx
, META_INFO_ALBUM
);
3004 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_ALBUM='%s'\n", inf
);
3009 case MP_CMD_GET_META_YEAR
:{
3010 char *inf
= get_metadata(mpctx
, META_INFO_YEAR
);
3013 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_YEAR='%s'\n", inf
);
3018 case MP_CMD_GET_META_COMMENT
:{
3019 char *inf
= get_metadata(mpctx
, META_INFO_COMMENT
);
3022 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_COMMENT='%s'\n", inf
);
3027 case MP_CMD_GET_META_TRACK
:{
3028 char *inf
= get_metadata(mpctx
, META_INFO_TRACK
);
3031 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_TRACK='%s'\n", inf
);
3036 case MP_CMD_GET_META_GENRE
:{
3037 char *inf
= get_metadata(mpctx
, META_INFO_GENRE
);
3040 mp_msg(MSGT_GLOBAL
, MSGL_INFO
, "ANS_META_GENRE='%s'\n", inf
);
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
);
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
));
3055 case MP_CMD_GET_TIME_POS
:{
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
);
3068 execl("/bin/sh", "sh", "-c", cmd
->args
[0].v
.s
, NULL
);
3074 case MP_CMD_KEYDOWN_EVENTS
:
3075 mplayer_put_key(cmd
->args
[0].v
.i
);
3078 case MP_CMD_SET_MOUSE_POS
:{
3079 int pointer_x
, pointer_y
;
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
);
3085 if (mpctx
->stream
->type
== STREAMTYPE_DVDNAV
3086 && dx
> 0.0 && dy
> 0.0) {
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
);
3098 if (use_menu
&& dx
>= 0.0 && dy
>= 0.0)
3099 menu_update_mouse_pos(dx
, dy
);
3105 case MP_CMD_DVDNAV
:{
3107 if (mpctx
->stream
->type
!= STREAMTYPE_DVDNAV
)
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
);
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
);
3126 if ((use_gui
) && (cmd
->id
> MP_CMD_GUI_EVENTS
))
3127 guiGetEvent(guiIEvent
, (char *) cmd
->id
);
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
;
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
;
3145 case 2: // "pausing_keep"
3146 if (mpctx
->was_paused
)
3147 mpctx
->osd_function
= OSD_PAUSE
;