From 7ccf4830263c1d7eaaf42a50dd7a602a6b6e8a31 Mon Sep 17 00:00:00 2001 From: albeu Date: Wed, 22 Mar 2006 00:19:02 +0000 Subject: [PATCH] Add the new property API and implement a couple properties. Move the volume and mute command to the command to property bridge. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@17912 b3059339-0415-0410-9bf9-f77b7e298cf2 --- Makefile | 1 + cfg-mplayer.h | 1 + help/help_mp-en.h | 12 +- input/input.c | 6 +- input/input.h | 2 + m_property.c | 278 +++++++++++++++++++++++++++++++++++ m_property.h | 78 ++++++++++ mplayer.c | 360 +++++++++++++++++++++++++++++++++++++++++----- 8 files changed, 699 insertions(+), 39 deletions(-) create mode 100644 m_property.c create mode 100644 m_property.h diff --git a/Makefile b/Makefile index caae378da3..f56a5a35c1 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ SRCS_MENCODER = mencoder.c \ xvid_vbr.c \ SRCS_MPLAYER = mplayer.c \ + m_property.c \ mp_msg.c \ $(SRCS_COMMON) \ mixer.c \ diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 10ca937753..1671463581 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -383,6 +383,7 @@ m_option_t mplayer_opts[]={ {"term-osd", &term_osd, CONF_TYPE_FLAG, 0, 0, 1, NULL}, {"noterm-osd", &term_osd, CONF_TYPE_FLAG, 0, 0, 0, NULL}, {"term-osd-esc", &term_osd_esc, CONF_TYPE_STRING, 0, 0, 1, NULL}, + {"playing-msg", &playing_msg, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"slave", &slave_mode, CONF_TYPE_FLAG,CONF_GLOBAL , 0, 1, NULL}, {"idle", &player_idle_mode, CONF_TYPE_FLAG,CONF_GLOBAL , 0, 1, NULL}, diff --git a/help/help_mp-en.h b/help/help_mp-en.h index 16e7a6a638..07d24b8aaf 100644 --- a/help/help_mp-en.h +++ b/help/help_mp-en.h @@ -227,7 +227,17 @@ static char help_text[]= #define MSGTR_OSDSubBottom "bottom" #define MSGTR_OSDSubCenter "center" #define MSGTR_OSDSubTop "top" -#define MSGTR_OSDMute "Mute: %s" + +// property values +#define MSGTR_Enabled "enabled" +#define MSGTR_EnabledEdl "enabled (edl)" +#define MSGTR_Disabled "disabled" + +// osd bar names +#define MSGTR_Volume "Volume" + +// property state +#define MSGTR_MuteStatus "Mute: %s" // mencoder.c: diff --git a/input/input.c b/input/input.c index 4fd0dfe8d0..efbc06f895 100644 --- a/input/input.c +++ b/input/input.c @@ -66,9 +66,9 @@ static mp_cmd_t mp_cmds[] = { { MP_CMD_SUB_STEP, "sub_step",1, { { MP_CMD_ARG_INT,{0} }, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_OSD, "osd",0, { {MP_CMD_ARG_INT,{-1}}, {-1,{0}} } }, { MP_CMD_OSD_SHOW_TEXT, "osd_show_text", 1, { {MP_CMD_ARG_STRING, {0}}, {-1,{0}} } }, - { MP_CMD_VOLUME, "volume", 1, { { MP_CMD_ARG_INT,{0} }, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, + { MP_CMD_VOLUME, "volume", 1, { { MP_CMD_ARG_FLOAT,{0} }, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_MIXER_USEMASTER, "use_master", 0, { {-1,{0}} } }, - { MP_CMD_MUTE, "mute", 0, { {-1,{0}} } }, + { MP_CMD_MUTE, "mute", 0, { {MP_CMD_ARG_INT,{-1}}, {-1,{0}} } }, { MP_CMD_CONTRAST, "contrast",1, { {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_GAMMA, "gamma", 1, { {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, { MP_CMD_BRIGHTNESS, "brightness",1, { {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, @@ -144,6 +144,8 @@ static mp_cmd_t mp_cmds[] = { { MP_CMD_GET_VO_FULLSCREEN, "get_vo_fullscreen", 0, { {-1,{0}} } }, { MP_CMD_GET_SUB_VISIBILITY, "get_sub_visibility", 0, { {-1,{0}} } }, { MP_CMD_KEYDOWN_EVENTS, "key_down_event", 1, { {MP_CMD_ARG_INT,{0}}, {-1,{0}} } }, + { MP_CMD_SET_PROPERTY, "set_property", 2, { {MP_CMD_ARG_STRING, {0}}, {MP_CMD_ARG_STRING, {0}}, {-1,{0}} } }, + { MP_CMD_GET_PROPERTY, "get_property", 1, { {MP_CMD_ARG_STRING, {0}}, {-1,{0}} } }, { 0, NULL, 0, {} } }; diff --git a/input/input.h b/input/input.h index 006c3ea991..378bc17624 100644 --- a/input/input.h +++ b/input/input.h @@ -69,6 +69,8 @@ #define MP_CMD_SUB_REMOVE 65 #define MP_CMD_KEYDOWN_EVENTS 66 #define MP_CMD_VO_BORDER 67 +#define MP_CMD_SET_PROPERTY 68 +#define MP_CMD_GET_PROPERTY 69 #define MP_CMD_GUI_EVENTS 5000 #define MP_CMD_GUI_LOADFILE 5001 diff --git a/m_property.c b/m_property.c new file mode 100644 index 0000000000..14f5c7943f --- /dev/null +++ b/m_property.c @@ -0,0 +1,278 @@ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "m_option.h" +#include "m_property.h" +#include "help_mp.h" + +#define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5)) + +int m_property_do(m_option_t* prop, int action, void* arg) { + if(!prop) return M_PROPERTY_UNKNOWN; + return ((m_property_ctrl_f)prop->p)(prop,action,arg); +} + + +char* m_property_print(m_option_t* prop) { + m_property_ctrl_f ctrl; + void* val; + char* ret; + + if(!prop) return NULL; + + ctrl = prop->p; + // look if the property have it's own print func + if(ctrl(prop,M_PROPERTY_PRINT,&ret) >= 0) + return ret; + // fallback on the default print for this type + val = calloc(1,prop->type->size); + if(ctrl(prop,M_PROPERTY_GET,val) <= 0) { + free(val); + return NULL; + } + ret = m_option_print(prop,val); + free(val); + return ret == (char*)-1 ? NULL : ret; +} + +int m_property_parse(m_option_t* prop, char* txt) { + m_property_ctrl_f ctrl; + void* val; + int r; + + if(!prop) return M_PROPERTY_UNKNOWN; + + ctrl = prop->p; + // try the property own parsing func + if((r = ctrl(prop,M_PROPERTY_PARSE,txt)) != M_PROPERTY_NOT_IMPLEMENTED) + return r; + // fallback on the default + val = calloc(1,prop->type->size); + if((r = m_option_parse(prop,prop->name,txt,val,M_CONFIG_FILE)) <= 0) { + free(val); + return r; + } + r = ctrl(prop,M_PROPERTY_SET,val); + m_option_free(prop,val); + free(val); + return r; +} + +char* m_properties_expand_string(m_option_t* prop_list,char* str) { + int l,fr=0,pos=0,size=strlen(str)+512; + char *p = NULL,*e,*ret = malloc(size), num_val; + int skip = 0, lvl = 0, skip_lvl = 0; + + while(str[0]) { + if(str[0] == '\\') { + int sl = 1; + switch(str[1]) { + case 'e': + p = "\x1b", l = 1; break; + case 'n': + p = "\n", l = 1; break; + case 'r': + p = "\r", l = 1; break; + case 't': + p = "\t", l = 1; break; + case 'x': + if(str[2]) { + char num[3] = { str[2], str[3], 0 }; + char* end = num; + num_val = strtol(num,&end,16); + sl = end-num; + l = 1; + p = &num_val; + } else + l = 0; + break; + default: + p = str+1, l = 1; + } + str+=1+sl; + } else if(lvl > 0 && str[0] == ')') { + if(skip && lvl <= skip_lvl) skip = 0; + lvl--, str++, l = 0; + } else if(str[0] == '$' && str[1] == '{' && (e = strchr(str+2,'}'))) { + int pl = e-str-2; + char pname[pl+1]; + m_option_t* prop; + memcpy(pname,str+2,pl); + pname[pl] = 0; + if((prop = m_option_list_find(prop_list,pname)) && + (p = m_property_print(prop))) + l = strlen(p), fr = 1; + else + l = 0; + str = e+1; + } else if(str[0] == '?' && str[1] == '(' && (e = strchr(str+2,':'))) { + int pl = e-str-2; + char pname[pl+1]; + m_option_t* prop; + lvl++; + if(!skip) { + memcpy(pname,str+2,pl); + pname[pl] = 0; + if(!(prop = m_option_list_find(prop_list,pname)) || + m_property_do(prop,M_PROPERTY_GET,NULL) < 0) + skip = 1, skip_lvl = lvl; + } + str = e+1, l = 0; + } else + p = str, l = 1, str++; + + if(skip || l <= 0) continue; + + if(pos+l+1 > size) { + size = pos+l+512; + ret = realloc(ret,size); + } + memcpy(ret+pos,p,l); + pos += l; + if(fr) free(p), fr = 0; + } + + ret[pos] = 0; + return ret; +} + +// Some generic property implementations + +int m_property_int_ro(m_option_t* prop,int action, + void* arg,int var) { + switch(action) { + case M_PROPERTY_GET: + if(!arg) return 0; + *(int*)arg = var; + return 1; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + +int m_property_int_range(m_option_t* prop,int action, + void* arg,int* var) { + switch(action) { + case M_PROPERTY_SET: + if(!arg) return 0; + M_PROPERTY_CLAMP(prop,*(int*)arg); + *var = *(int*)arg; + return 1; + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + *var += (arg ? *(int*)arg : 1) * + (action == M_PROPERTY_STEP_DOWN ? -1 : 1); + M_PROPERTY_CLAMP(prop,*var); + return 1; + } + return m_property_int_ro(prop,action,arg,*var); +} + +int m_property_choice(m_option_t* prop,int action, + void* arg,int* var) { + switch(action) { + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max; + *var %= (int)prop->max+1; + return 1; + } + return m_property_int_range(prop,action,arg,var); +} + +int m_property_flag(m_option_t* prop,int action, + void* arg,int* var) { + switch(action) { + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + *var = *var == prop->min ? prop->max : prop->min; + return 1; + case M_PROPERTY_PRINT: + if(!arg) return 0; + *(char**)arg = strdup((*var > prop->min) ? MSGTR_Enabled : MSGTR_Disabled); + return 1; + } + return m_property_int_range(prop,action,arg,var); +} + +int m_property_float_ro(m_option_t* prop,int action, + void* arg,float var) { + switch(action) { + case M_PROPERTY_GET: + if(!arg) return 0; + *(float*)arg = var; + return 1; + case M_PROPERTY_PRINT: + if(!arg) return 0; + *(char**)arg = malloc(20); + sprintf(*(char**)arg,"%.2f",var); + return 1; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + +int m_property_float_range(m_option_t* prop,int action, + void* arg,float* var) { + switch(action) { + case M_PROPERTY_SET: + if(!arg) return 0; + M_PROPERTY_CLAMP(prop,*(float*)arg); + *var = *(float*)arg; + return 1; + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + *var += (arg ? *(float*)arg : 0.1) * + (action == M_PROPERTY_STEP_DOWN ? -1 : 1); + M_PROPERTY_CLAMP(prop,*var); + return 1; + } + return m_property_float_ro(prop,action,arg,*var); +} + +int m_property_delay(m_option_t* prop,int action, + void* arg,float* var) { + switch(action) { + case M_PROPERTY_PRINT: + if(!arg) return 0; + *(char**)arg = malloc(20); + sprintf(*(char**)arg,"%d ms",ROUND((*var)*1000)); + return 1; + default: + return m_property_float_range(prop,action,arg,var); + } +} + +int m_property_double_ro(m_option_t* prop,int action, + void* arg,double var) { + switch(action) { + case M_PROPERTY_GET: + if(!arg) return 0; + *(double*)arg = var; + return 1; + case M_PROPERTY_PRINT: + if(!arg) return 0; + *(char**)arg = malloc(20); + sprintf(*(char**)arg,"%.2f",var); + return 1; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + +int m_property_string_ro(m_option_t* prop,int action,void* arg,char* str) { + switch(action) { + case M_PROPERTY_GET: + if(!arg) return 0; + *(char**)arg = str; + return 1; + case M_PROPERTY_PRINT: + if(!arg) return 0; + *(char**)arg = str ? strdup(str) : NULL; + return 1; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} diff --git a/m_property.h b/m_property.h new file mode 100644 index 0000000000..775f9d566b --- /dev/null +++ b/m_property.h @@ -0,0 +1,78 @@ + +// Get the current value +#define M_PROPERTY_GET 0 +// Get a string representing the current value +#define M_PROPERTY_PRINT 1 +// Set a new value +#define M_PROPERTY_SET 2 +// Set a new value from a string +#define M_PROPERTY_PARSE 3 +// Increment the property +#define M_PROPERTY_STEP_UP 4 +// Decrement the property +#define M_PROPERTY_STEP_DOWN 5 + +// Return values for the control function +#define M_PROPERTY_OK 1 +#define M_PROPERTY_ERROR 0 +// Returned when the property can't be used, for ex something about +// the subs while playing audio only +#define M_PROPERTY_UNAVAILABLE -1 +// Returned if the requested action is not implemented +#define M_PROPERTY_NOT_IMPLEMENTED -2 +// Returned when asking for a property that doesn't exist +#define M_PROPERTY_UNKNOWN -3 +// Returned when the action can't be done (like setting the volume when edl mute) +#define M_PROPERTY_DISABLED -4 + +typedef int(*m_property_ctrl_f)(m_option_t* prop,int action,void* arg); + +int m_property_do(m_option_t* prop, int action, void* arg); + +char* m_property_print(m_option_t* prop); + +int m_property_parse(m_option_t* prop, char* txt); + +char* m_properties_expand_string(m_option_t* prop_list,char* str); + +#define M_PROPERTY_CLAMP(prop,val) do { \ + if(((prop)->flags & M_OPT_MIN) && (val) < (prop)->min) \ + (val) = (prop)->min; \ + else if(((prop)->flags & M_OPT_MAX) && (val) > (prop)->max) \ + (val) = (prop)->max; \ + } while(0) + +// Implement get +int m_property_int_ro(m_option_t* prop,int action, + void* arg,int var); + +// Implement set, get and step up/down +int m_property_int_range(m_option_t* prop,int action, + void* arg,int* var); + +// Same but cycle +int m_property_choice(m_option_t* prop,int action, + void* arg,int* var); + +// Switch betwen min and max +int m_property_flag(m_option_t* prop,int action, + void* arg,int* var); + +// Implement get, print +int m_property_float_ro(m_option_t* prop,int action, + void* arg,float var); + +// Implement set, get and step up/down +int m_property_float_range(m_option_t* prop,int action, + void* arg,float* var); + +// float with a print function which print the time in ms +int m_property_delay(m_option_t* prop,int action, + void* arg,float* var); + +// Implement get, print +int m_property_double_ro(m_option_t* prop,int action, + void* arg,double var); + +// get/print the string +int m_property_string_ro(m_option_t* prop,int action,void* arg, char* str); diff --git a/mplayer.c b/mplayer.c index 25a9773b9c..fd996dcf72 100644 --- a/mplayer.c +++ b/mplayer.c @@ -42,6 +42,7 @@ extern int mp_input_win32_slave_cmd_func(int fd,char* dest,int size); #include "m_option.h" #include "m_config.h" +#include "m_property.h" #include "cfg-mplayer-def.h" @@ -238,6 +239,7 @@ static int osd_duration = 1000; static int term_osd = 1; static char* term_osd_esc = "\x1b[A\r\x1b[K"; +static char* playing_msg = NULL; // seek: static char *seek_to_sec=NULL; static off_t seek_to_byte=0; @@ -1056,7 +1058,9 @@ static void log_sub(void){ #define OSD_MSG_OSD_STATUS 4 #define OSD_MSG_BAR 5 #define OSD_MSG_PAUSE 6 -#define OSD_MSG_MUTE 7 +// Base id for the messages generated from the commmand to property bridge +#define OSD_MSG_PROPERTY 0x100 + // These will later be implemented via properties and removed #define OSD_MSG_AV_DELAY 100 @@ -1302,6 +1306,288 @@ static void update_osd_msg(void) { } +// General properties + +static int mp_property_osdlevel(m_option_t* prop,int action,void* arg) { + return m_property_choice(prop,action,arg,&osd_level); +} + +static int mp_property_playback_speed(m_option_t* prop,int action,void* arg) { + switch(action) { + case M_PROPERTY_SET: + if(!arg) return 0; + M_PROPERTY_CLAMP(prop,*(float*)arg); + playback_speed = *(float*)arg; + build_afilter_chain(sh_audio, &ao_data); + return 1; + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + playback_speed += (arg ? *(float*)arg : 0.1) * + (action == M_PROPERTY_STEP_DOWN ? -1 : 1); + M_PROPERTY_CLAMP(prop,playback_speed); + build_afilter_chain(sh_audio, &ao_data); + return 1; + } + return m_property_float_range(prop,action,arg,&playback_speed); +} + +static int mp_property_path(m_option_t* prop,int action,void* arg) { + return m_property_string_ro(prop,action,arg,filename); +} + +static int mp_property_filename(m_option_t* prop,int action,void* arg) { + char* f; + if(!filename) return M_PROPERTY_UNAVAILABLE; + if(((f = strrchr(filename,'/')) || (f = strrchr(filename,'\\'))) && f[1]) + f++; + else + f = filename; + return m_property_string_ro(prop,action,arg,f); +} + + +static int mp_property_demuxer(m_option_t* prop,int action,void* arg) { + if(!demuxer) return M_PROPERTY_UNAVAILABLE; + return m_property_string_ro(prop,action,arg,(char*)demuxer->desc->name); +} + +static int mp_property_length(m_option_t* prop,int action,void* arg) { + double len; + + if(!demuxer || + !(int)(len = demuxer_get_time_length(demuxer))) + return M_PROPERTY_UNAVAILABLE; + + switch(action) { + case M_PROPERTY_PRINT: + if(!arg) return 0; + else { + int h, m, s = len; + h = s/3600; + s -= h*3600; + m = s/60; + s -= m*60; + *(char**)arg = malloc(20); + if(h > 0) sprintf(*(char**)arg,"%d:%02d:%02d",h,m,s); + else if(m > 0) sprintf(*(char**)arg,"%d:%02d",m,s); + else sprintf(*(char**)arg,"%d",s); + return 1; + } + break; + } + return m_property_double_ro(prop,action,arg,len); +} + +// Audio properties + +static int mp_property_volume(m_option_t* prop,int action,void* arg) { + + if(!sh_audio) return M_PROPERTY_UNAVAILABLE; + + switch(action) { + case M_PROPERTY_GET: + if(!arg) return 0; + mixer_getbothvolume(&mixer,arg); + return 1; + case M_PROPERTY_PRINT:{ + float vol; + if(!arg) return 0; + mixer_getbothvolume(&mixer,&vol); + return m_property_float_range(prop,action,arg,&vol); + } + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + case M_PROPERTY_SET: + break; + default: + return M_PROPERTY_NOT_IMPLEMENTED; + } + +#ifdef USE_EDL + if (edl_muted) return M_PROPERTY_DISABLED; + user_muted = 0; +#endif + + switch(action) { + case M_PROPERTY_SET: + if(!arg) return 0; + M_PROPERTY_CLAMP(prop,*(float*)arg); + mixer_setvolume(&mixer,*(float*)arg,*(float*)arg); + return 1; + case M_PROPERTY_STEP_UP: + if(arg && *(float*)arg <= 0) + mixer_decvolume(&mixer); + else + mixer_incvolume(&mixer); + return 1; + case M_PROPERTY_STEP_DOWN: + if(arg && *(float*)arg <= 0) + mixer_incvolume(&mixer); + else + mixer_decvolume(&mixer); + return 1; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + + +static int mp_property_mute(m_option_t* prop,int action,void* arg) { + + if(!sh_audio) return M_PROPERTY_UNAVAILABLE; + + switch(action) { + case M_PROPERTY_SET: +#ifdef USE_EDL + if(edl_muted) return M_PROPERTY_DISABLED; +#endif + if(!arg) return 0; + if((!!*(int*)arg) != mixer.muted) + mixer_mute(&mixer); + return 1; + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: +#ifdef USE_EDL + if(edl_muted) return M_PROPERTY_DISABLED; +#endif + mixer_mute(&mixer); + return 1; + case M_PROPERTY_PRINT: + if(!arg) return 0; +#ifdef USE_EDL + if(edl_muted) { + *(char**)arg = strdup(MSGTR_EnabledEdl); + return 1; + } +#endif + default: + return m_property_flag(prop,action,arg,&mixer.muted); + + } +} + + +static m_option_t mp_properties[] = { + // General + { "osdlevel", mp_property_osdlevel, CONF_TYPE_INT, + M_OPT_RANGE, 0, 3, NULL }, + { "speed", mp_property_playback_speed, CONF_TYPE_FLOAT, + M_OPT_RANGE, 0.01, 100.0, NULL }, + { "filename", mp_property_filename, CONF_TYPE_STRING, + 0, 0, 0, NULL }, + { "path", mp_property_path, CONF_TYPE_STRING, + 0, 0, 0, NULL }, + { "demuxer", mp_property_demuxer, CONF_TYPE_STRING, + 0, 0, 0, NULL }, + { "length", mp_property_length, CONF_TYPE_DOUBLE, + 0, 0, 0, NULL }, + + // Audio + { "volume", mp_property_volume, CONF_TYPE_FLOAT, + M_OPT_RANGE, 0, 100, NULL }, + { "mute", mp_property_mute, CONF_TYPE_FLAG, + M_OPT_RANGE, 0, 1, NULL }, + { NULL, NULL, NULL, 0, 0, 0, NULL } +}; + +m_option_t* mp_property_find(char* name) { + return m_option_list_find(mp_properties,name); +} + +int mp_property_do(char* name,int action, void* val) { + m_option_t* p = mp_property_find(name); + if(!p) return M_PROPERTY_UNAVAILABLE; + return m_property_do(p,action,val); +} + + +/* + * \brief Commands to property bridge. + * + * It is used to handle most commands that just set a property + * and optionaly display something on the OSD. + * Two kinds of commands are handled: adjust or toggle. + * + * Adjust commands take 1 or 2 paramter: + * If is none zero the property is set to the given value + * otherwise it is adjusted. + * + * Toggle commands take 0 or 1 parameter. With no parameter + * or a value less than the property minimum it just step the + * property to it's next value. Otherwise it set it to the given + * value. + * + */ + +static struct { + char* name; // property name + int cmd; // cmd id + int toggle; // set/adjust or toggle command + int osd_progbar; // progbar type + int osd_id; // osd msg id if it must be shared + char* osd_msg; // osd msg template +} set_prop_cmd[] = { + // audio + { "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume }, + { "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus }, + + { NULL, 0, 0, 0, -1, NULL } +}; + +static int set_property_command(mp_cmd_t* cmd) { + int i,r; + m_option_t* prop; + + // look for the command + for(i = 0 ; set_prop_cmd[i].name ; i++) + if(set_prop_cmd[i].cmd == cmd->id) break; + if(!set_prop_cmd[i].name) return 0; + + // get the property + prop = mp_property_find(set_prop_cmd[i].name); + if(!prop) return 0; + + // toggle command + if(set_prop_cmd[i].toggle) { + // set to value + if(cmd->nargs > 0 && cmd->args[0].v.i >= prop->min) + r = m_property_do(prop,M_PROPERTY_SET,&cmd->args[0].v.i); + else + r = m_property_do(prop,M_PROPERTY_STEP_UP,NULL); + } else if(cmd->args[1].v.i) //set + r = m_property_do(prop,M_PROPERTY_SET,&cmd->args[0].v); + else // adjust + r = m_property_do(prop,M_PROPERTY_STEP_UP,&cmd->args[0].v); + + if(r <= 0) return 1; + + if(set_prop_cmd[i].osd_progbar) { + if(prop->type == CONF_TYPE_INT) { + if(m_property_do(prop,M_PROPERTY_GET,&r) > 0) + set_osd_bar(set_prop_cmd[i].osd_progbar, + set_prop_cmd[i].osd_msg, + prop->min,prop->max,r); + } else if(prop->type == CONF_TYPE_FLOAT) { + float f; + if(m_property_do(prop,M_PROPERTY_GET,&f) > 0) + set_osd_bar(set_prop_cmd[i].osd_progbar,set_prop_cmd[i].osd_msg, + prop->min,prop->max,f); + } else + mp_msg(MSGT_CPLAYER,MSGL_ERR, "Property use an unsupported type.\n"); + return 1; + } + + if(set_prop_cmd[i].osd_msg) { + char* val = m_property_print(prop); + if(val) { + set_osd_msg(set_prop_cmd[i].osd_id >= 0 ? set_prop_cmd[i].osd_id : + OSD_MSG_PROPERTY+i,1,osd_duration, + set_prop_cmd[i].osd_msg,val); + free(val); + } + } + return 1; +} + int main(int argc,char* argv[]){ @@ -2421,6 +2707,13 @@ current_module="init_vo"; main: current_module="main"; + if(playing_msg) { + char* msg = m_properties_expand_string(mp_properties,playing_msg); + mp_msg(MSGT_CPLAYER,MSGL_INFO,"%s",msg); + free(msg); + } + + // Disable the term osd in verbose mode if(verbose) term_osd = 0; fflush(stdout); @@ -3115,6 +3408,7 @@ if (stream->type==STREAMTYPE_DVDNAV && dvd_nav_still) mp_cmd_t* cmd; int brk_cmd = 0; while( !brk_cmd && (cmd = mp_input_get_cmd(0,0,0)) != NULL) { + if(!set_property_command(cmd)) switch(cmd->id) { case MP_CMD_SEEK : { float v; @@ -3141,6 +3435,35 @@ if (stream->type==STREAMTYPE_DVDNAV && dvd_nav_still) } brk_cmd = 1; } break; + case MP_CMD_SET_PROPERTY: { + m_option_t* prop = mp_property_find(cmd->args[0].v.s); + if(!prop) mp_msg(MSGT_CPLAYER,MSGL_WARN,"Unkown property: '%s'\n",cmd->args[0].v.s); + else if(m_property_parse(prop,cmd->args[1].v.s) <= 0) + mp_msg(MSGT_CPLAYER,MSGL_WARN,"Failed to set property '%s' to '%s'.\n", + cmd->args[0].v.s,cmd->args[1].v.s); + + } break; + case MP_CMD_GET_PROPERTY: { + m_option_t* prop; + void* val; + prop = mp_property_find(cmd->args[0].v.s); + if(!prop) mp_msg(MSGT_CPLAYER,MSGL_WARN,"Unkown property: '%s'\n",cmd->args[0].v.s); + // use m_option_print directly to get easily parsable values + val = calloc(1,prop->type->size); + if(m_property_do(prop,M_PROPERTY_GET,val) <= 0) { + mp_msg(MSGT_CPLAYER,MSGL_WARN,"Failed to get value of property '%s'.\n", + cmd->args[0].v.s); + break; + } + tmp = m_option_print(prop,val); + if(!tmp || tmp == (char*)-1) { + mp_msg(MSGT_CPLAYER,MSGL_WARN,"Failed to print value of property '%s'.\n", + cmd->args[0].v.s); + break; + } + mp_msg(MSGT_GLOBAL,MSGL_INFO, "ANS_%s=%s\n",cmd->args[0].v.s,tmp); + free(tmp); + } break; #ifdef USE_EDL case MP_CMD_EDL_MARK: if( edl_fd ) { @@ -3292,41 +3615,6 @@ if (stream->type==STREAMTYPE_DVDNAV && dvd_nav_still) case MP_CMD_OSD_SHOW_TEXT : { set_osd_msg(OSD_MSG_TEXT,1,osd_duration,"%64s",cmd->args[0].v.s); } break; - case MP_CMD_VOLUME : { - int v = cmd->args[0].v.i; - - // start change for absolute volume value - int abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0; - -#ifdef USE_EDL - if (edl_muted) break; - user_muted = 0; -#endif - if( abs ) - { - mixer_setvolume(&mixer, (float)v, (float)v ); - } else { - if(v > 0) - mixer_incvolume(&mixer); - else - mixer_decvolume(&mixer); - } - - if(1){ - float vol; - mixer_getbothvolume(&mixer, &vol); - set_osd_bar(OSD_VOLUME,"Volume",0,100,vol); - } - } break; - case MP_CMD_MUTE: -#ifdef USE_EDL - user_muted = !user_muted; - if ((edl_muted | user_muted) != mixer.muted) -#endif - mixer_mute(&mixer); - set_osd_msg(OSD_MSG_MUTE,1,osd_duration, MSGTR_OSDMute, - mixer.muted ? MSGTR_OSDenabled : MSGTR_OSDdisabled); - break; case MP_CMD_LOADFILE : { play_tree_t* e = play_tree_new(); play_tree_add_file(e,cmd->args[0].v.s);