diff -Naur orig/configure main/configure --- orig/configure 2006-01-10 22:59:15.000000000 +0100 +++ main/configure 2006-01-08 20:16:01.000000000 +0100 @@ -7941,6 +7941,9 @@ #define X11_FULLSCREEN 1 #endif +/* main language selected - used by profiles.c */ +#define MAIN_LANGUAGE "$_language" + #endif /* MPLAYER_CONFIG_H */ EOF diff -Naur orig/DOCS/man/en/mplayer.1 main/DOCS/man/en/mplayer.1 --- orig/DOCS/man/en/mplayer.1 2006-01-10 22:59:15.000000000 +0100 +++ main/DOCS/man/en/mplayer.1 2006-01-11 00:18:06.850408560 +0100 @@ -530,6 +530,103 @@ ~/.mplayer/ or in the same directory as the file. . .\" -------------------------------------------------------------------------- +.\" Profiles +.\" -------------------------------------------------------------------------- +. +.SH "PROFILES (MENCODER ONLY)" +MEncoder support profiles, options that are loaded from single parts of +profiles file(s) in a way similar to the configuration file. +The sintax is similar to the one needed for the configuration file with +some extension. +A profile is started with the profile name in square bracket, +e.g. "[ profile \]". +After the profile definition you can put a brief description of the profile +itself, with the language of the description with the command +.br +profile-desc lang, "desc" +.br +The last new command that you can put in the profile itself is the command +to reference other profile(s) and is named profile, followed by a comma +separated values of profile to parse. +.br +A simple profile may be: +.sp 1 +.nf +# +# MEncoder profile example +# +[ base ] + profile-desc en, "Base profile" + profile-desc it, "Profilo di base" + oac copy=yes + ovc copy=yes + mc 0 + +[ lavc ] + profile-desc en, "Base lavc mpeg4 encoding" + profile-desc it, "Codifica di base mpeg4" + profile base + lavcopts vcodec=mpeg4 + lavcopts vbitrate=1200 + +[ lavc_hq ] + profile-desc en, "High Quality mpeg4 encoding" + profile-desc it, "Codifica mpeg4 ad alta qualita'" + profile lavc + lavcopts mbd=2 + lavcopts trell=yes + lavcopts v4mv=yes + +[ lavc_hq_p1 ] + profile-desc en, "HQ Mpeg4:pass 1" + profile lavc_hq + lavcopts pass=1 + lavcopts turbo=yes + +[ lavc_hq_p1 ] + profile-desc en, "HQ Mpeg4:pass 2+" + profile lavc_hq + lavcopts pass=2 + +[ mp3 ] + profile-desc en, "Mp3 CBR (128k) audio encoding" + profile-desc it, "Codifica audio MP3 a 128k" + oac mp3lame=yes + lameopts cbr=yes + lameopts br=128 + lameopts aq=7 +.fi +.PP +To use a profile or some profiles you use the profile option followed by the +comma separated list of the profile you want, e.g. \-profile lavc_hq,mp3 +.br +The option recognized by the profile parser module are: +. +.TP +.B \-profile profile_1[,profile_2[,profile_xx]] +Use the specified profile(s), in the order you specify on the command line. +. +.TP +.B \-profile-file file_1[,file_2[,file_xx]][,] +Set the list of the file to look for the profile(s). As soon as a profile is +found the next file(s) or the standard files are not searched, so you can +override a profile with your personal options. +If you put a trailing comma at the end of the list the profile, if not found +in the user file, is searched in the default files. +The default global profile definition file for MEncoder is 'mencoder-profile' +in your configuration directory (e.g.\& /etc/\:mplayer or +/usr/\:local/\:etc/\:mplayer), the user profile one is +'~/\:.mplayer/\:mencoder-profile' (that has precedence over the global one). +You can also put this option in you standard configuration file to always +use the selected file(s). +. +.TP +.B \-profile-list +Dump a list of the profile found by the program (put your \-profile-file +option before this one!) with a small description, if possible in the user +language. +. +.\" -------------------------------------------------------------------------- .\" Options .\" -------------------------------------------------------------------------- . diff -Naur orig/Makefile main/Makefile --- orig/Makefile 2006-01-10 22:59:15.000000000 +0100 +++ main/Makefile 2006-01-10 23:03:18.553733368 +0100 @@ -58,6 +58,7 @@ libvo/sub.c \ parser-mecmd.c \ xvid_vbr.c \ + profiles.c \ SRCS_MPLAYER = mplayer.c \ mp_msg.c \ @@ -493,6 +494,9 @@ endif @if test ! -d $(CONFDIR) ; then mkdir -p $(CONFDIR) ; fi @if test -f $(CONFDIR)/codecs.conf ; then mv -f $(CONFDIR)/codecs.conf $(CONFDIR)/codecs.conf.old ; fi +ifeq ($(MENCODER),yes) + @cp ./mencoder-profile $(CONFDIR)/mencoder-profile +endif ifeq ($(DVDKIT_SHARED),yes) ifeq ($(DVDKIT2),yes) if test ! -d $(LIBDIR) ; then mkdir -p $(LIBDIR) ; fi diff -Naur orig/mencoder.c main/mencoder.c --- orig/mencoder.c 2006-01-10 22:59:15.000000000 +0100 +++ main/mencoder.c 2006-01-08 18:26:25.000000000 +0100 @@ -235,6 +235,9 @@ return m_config_parse_config_file(mconfig, filename); } +// profile handling +extern void profile_register(m_config_t *config, int mplayer); + static char *seek_to_sec=NULL; static off_t seek_to_byte=0; @@ -286,7 +289,7 @@ #include "libao2/audio_out.h" /* FIXME */ -static void mencoder_exit(int level, char *how) +void mencoder_exit(int level, char *how) { if (how) mp_msg(MSGT_MENCODER, MSGL_INFO, MSGTR_ExitingHow, mp_gettext(how)); @@ -460,6 +463,7 @@ mconfig = m_config_new(); m_config_register_options(mconfig,mencoder_opts); + profile_register(mconfig, 0); parse_cfgfiles(mconfig); filelist = m_config_parse_me_command_line(mconfig, argc, argv); if(!filelist) mencoder_exit(1, MSGTR_ErrorParsingCommandLine); diff -Naur orig/mencoder-profile main/mencoder-profile --- orig/mencoder-profile 1970-01-01 01:00:00.000000000 +0100 +++ main/mencoder-profile 2006-01-11 00:18:31.145715112 +0100 @@ -0,0 +1,60 @@ +# MEncoder profile file +# +[ default ] + profile-desc en, "Default profile" + profile-desc it, "Profilo di default" + # default opt + oac copy=yes + ovc copy=yes + of avi=yes + o encoded.avi + mc 0 + +[ mpeg ] + profile-desc en, "Default profile for mpeg2 (DVD)" + profile default + of mpeg=yes + o encoded.mpg + # mpeg out option + mpegopts format=mpeg2 + mpegopts vbitrate=8500 + # encoding option + ovc lavc=yes + lavcopts vcodec=mpeg2video + lavcopts mbd=2 + lavcopts psnr=yes + lavcopts vrc_buf_size=1835 + +[ mpeg4 ] + profile-desc en, "Default profile for mpeg4 (AKA divx, xvid, ...)" + profile default + # encoding option + ovc lavc=yes + lavcopts vcodec=mpeg4 + lavcopts mbd=2 + lavcopts psnr=yes + +[ mpeg4_hq ] + profile-desc en, "High Quality mpeg4 encoding" + profile mpeg4 + # Encoding opt + lavcopts trell=yes + lavcopts v4mv=yes + +[ divx ] + profile-desc en, "Default profile for divx/xvid (for standalone player)" + profile mpeg4 + ffourcc DX50 + +[ divx_hq ] + profile-desc en, "High Quality profile for divx/xvid (for standalone player)" + profile mpeg4_hq + ffourcc DX50 + +[ mp3 ] + profile-desc en, "Mp3 CBR (128k) audio encoding" + oac mp3lame=yes + lameopts cbr=yes + lameopts br=128 + lameopts aq=7 + diff -Naur orig/profiles.c main/profiles.c --- orig/profiles.c 1970-01-01 01:00:00.000000000 +0100 +++ main/profiles.c 2006-01-11 00:03:27.503089672 +0100 @@ -0,0 +1,570 @@ +// include + #include + #include + #include + #include + #include + + #include "version.h" + #include "m_option.h" + #include "m_config.h" + #include "mp_msg.h" + #include "help_mp.h" + +// External reference + extern char *get_path(char *filename); + void mencoder_exit(int level, char *how); + +// define + #define MAX_LINE_LEN 10000 + +// forward declaration + static int profile_list(m_option_t *conf); + static int profile_use(m_option_t *conf, char *prof); + static int profile_find(m_option_t *config, char *prof); + +// local variables + // profiles files list + static char **profile_file = NULL; + // program running (mplayer / mencoder) + static int is_mplayer = 0; + // Local pointer of program config struct + static m_config_t *mconfig = NULL; + + // options definition + static m_option_t profile_opts[] = { + {"profile-list", profile_list, CONF_TYPE_FUNC, CONF_GLOBAL | CONF_NOSAVE, 0, 0, NULL}, + {"profile-file", &profile_file, CONF_TYPE_STRING_LIST, CONF_GLOBAL | CONF_NOSAVE, 0, 0, NULL}, + {"profile", profile_use, CONF_TYPE_FUNC_PARAM, CONF_NOSAVE, 0, 0, NULL}, + + {NULL, NULL, 0, 0, 0, 0, NULL} + }; + +/** + * \brief Return the pointer, in s, of the substring delimitaded by + * a ','. If the first non space character is a " or a ' the matching char + * is searched (ignoring the ',' it found in the while). + * The terminating '\0' is put in the original string + * \param s original string, modified by the function + * \return NULL at end of string, else the substring + */ +static char *profile_get_string(char **s) +{ + + char *t; + char *rt; + + t = *s; + while (isspace(*t)) { + ++t; + } + + if (*t == '\0') { + rt = NULL; + } + else { + char end_ch; + + if ((*t == '"') || (*t == '\'')) { + end_ch = *t++; + } + else { + end_ch = ','; + } + + rt = t; + while (*t != '\0') { + if (*t == end_ch) { + *t = '\0'; + ++t; + break; + } + ++t; + } + + if (end_ch != ',') { + while (*t != '\0') { + if (*t == ',') { + ++t; + break; + } + ++t; + } + } + *s = t; + } + return(rt); +} + +/** + * \brief split the line in an option and one (eventual) parameter or + * in a group [ name ] that start a profile. + * Starting spaces / tabs are omitted, parameter can be separated + * from the option by spaces, tabs or the = character + * + * \param line input line + * \param opt pointer (in line!) of the option or "" if not found + * \param par pointer (in line!) of the parameter or "" if not found + * \return 0 = found nothing, 1 = only option, 3 = option and par, + * 4 = group, < 0 error + */ +static int prof_get_opt(char *line, char **opt, char **par) +{ + + int rt = 0; + + // Skip initial space(s) / tab(s) + while (isspace(*line)) { + ++line; + } + + if ((*line == '#') || (*line == '\0')) { + // empty line + *opt = ""; + *par = ""; + } + else if (*line == '[') { + char *ed; + + // group + ++line; + + // skip space(s) + while (isspace(*line)) { + ++line; + } + + // save option pointer + *opt = line; + // no param + *par = ""; + + while ((!isspace(*line)) && (*line != ']')) { + ++line; + } + // end of opt + ed = line; + + if (*line != ']') { + // Stop not on ], skip all the space(s) + while (isspace(*line)) { + ++line; + } + } + + if (*line == ']') { + // Ok, end the opt + *ed = '\0'; + + rt = 4; + } + else { + // Error on parsing + rt = -2; + } + } + else { + + rt = 1; + *opt = line; + while ((*line != '\0') && + (*line != '=') && + (*line != ' ') && + (*line != '\t') && + (*line != '#') && + (*line != '\n')) { + ++line; + } + + if ((*line == '#') || (*line == '\n') || (*line == '\0')) { + // Comment or end of line -> end + *line = '\0'; + *par = ""; + } + else { + int ne; + + // Look for parameter + if (*line == '=') { + ne = 1; + } + else { + ne = 0; + } + + // end option + *line++ = '\0'; + + while (isspace(*line)) { + ++line; + } + + if (*line == '=') { + if (ne != 0) { + // double '=' -> error + rt = -1; + } + else { + ++line; + while (isspace(*line)) { + ++line; + } + } + } + + if (rt == 1) { + // par + rt |= 0x0002; + if ((*line == '"') || (*line == '\'')) { + char c; + + c = *line++; + *par = line; + + while (*line != '\0') { + if (*line == c) { + *line = '\0'; + ++line; + break; + } + ++line; + } + + if (*line == '\0') { + // Missing closing " or ' + rt = -1; + } + else { + // check end of line + while ((*line == ' ') || (*line == '\t')) { + ++line; + } + + if ((*line != '\n') && (*line != '#')) { + // parse error: something at end + rt = -2; + } + } + + } + else { + // last space found + char *ls = NULL; + + *par = line; + while (*line != '\0') { + if ((*line == '\n') || (*line == '#')) { + *line = '\0'; + break; + } + if (*line == ' ') { + if (ls == NULL) { + ls = line; + } + } + else { + ls = NULL; + } + ++line; + } + if (ls != NULL) { + *ls = '\0'; + } + } + } + } + } + return(rt); +} + +/** + * \brief lookup for a profile or dump all the profile it finds. + * \param file file to parse + * \param prof if NULL prints all the profile(s) it finds, otherwise the + * profile to look for + * \param no_file_err if different from 0 no error is generated if the file + * is not found, used to parse the standard file (.mplayer/[mplayer|mencoder]-profile) + * \return > 0 profile found, < 0 error, 0 profile not found + */ +static int profile_find_single(m_option_t *config, char *file, char *prof, int no_file_err) +{ + + FILE *fi; + int rt; + + // Open file + fi = fopen(file, "r"); + if (fi != NULL) { + char *line; + static int level = 0; + + ++level; + if (prof != NULL) { + mp_msg(MSGT_CFGPARSER, MSGL_DBG3, " %*sprofile file -> %s\n", level * 2, "", file); + mp_msg(MSGT_CFGPARSER, MSGL_DBG3, " %*s(%d)Start: [%s]\n", level * 2, "", level, prof); + } + // Alloc buffer for line + line = (char *)malloc(MAX_LINE_LEN + 1); + if (line == NULL) { + // error -> exit + mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno)); + rt = -2; + } + else { + int line_num = 0; + int parse_on = 0; + char c_desc[128 + 1]; + char c_prof[128 + 1] = ""; + + rt = 0; + if (prof == NULL) { + mp_msg(MSGT_CFGPARSER, MSGL_INFO, " Profile file:%s\n", file); + } + + // Read line ... + while (fgets(line, MAX_LINE_LEN, fi)) { + char *opt; + char *par; + int t; + + line_num++; + mp_msg(MSGT_CFGPARSER, MSGL_DBG4, " %4u %s", line_num, line); + t = prof_get_opt(line, &opt, &par); + if (t < 0) { + // Error -> exit from loop + mp_msg(MSGT_CFGPARSER, MSGL_FATAL, + "Profile parse error: file %s, line:%d\n", file, line_num); + rt = -3; + break; + } + else if (t == 4) { + // Found profile string. + if (prof == NULL) { + // dump -> print last option + if (*c_prof != '\0') { + mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-16s %s\n", c_prof, c_desc); + } + // .. and save profile name + strncpy(c_prof, opt, sizeof(c_prof)); + // reset desc + *c_desc = '\0'; + } + else { + if (parse_on) { + // Exit from parsing + break; + } + else { + if (strcasecmp(prof, opt) == 0) { + // profile found, start to parse + parse_on = 1; + rt = 1; + } + } + } + } + else if (t) { + if (strcasecmp(opt, "profile-desc") == 0) { + char *lang; + + lang = profile_get_string(&par); + if ((*c_desc == '\0') || (strcasecmp(lang, MAIN_LANGUAGE) == 0)) { + // copy desc on buffer + strncpy(c_desc, profile_get_string(&par), sizeof(c_desc)); + } + } + else { + if (parse_on) { + if (strcasecmp(opt, "profile") == 0) { + // Use the profile ... + profile_use(config, par); + } + else { + t = m_config_set_option(mconfig, opt, par); + mp_msg(MSGT_CFGPARSER, MSGL_DBG3," %*sopt:[%s], par=[%s], %d\n", + level * 2, "", opt, par, t); + if (t < 0) { + mp_msg(MSGT_CFGPARSER, MSGL_FATAL, + "Profile parse error: file %s, line:%d\n", file, line_num); + rt = t; + break; + } + } + } + + } + } + + } + if (*c_prof != '\0') { + mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-16s %s\n", c_prof, c_desc); + } + if (prof == NULL) { + mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); + } + + free(line); + } + if (prof != NULL) { + mp_msg(MSGT_CFGPARSER, MSGL_DBG3," %*s(%d)End: [%s]\n", level * 2, "", level, prof); + } + fclose(fi); + --level; + } + else { + if (no_file_err) { + rt = 0; + } + else { + mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"%s (%s): %s\n", + "Error opening profile file", + file, + strerror(errno)); + rt = -1; + } + } + + return(rt); +} + +/** + * \brief look up / dump profile in all the configurated file(s) + * \param prof if NULL prints all the profile(s) it finds, otherwise the + * profile to look for + * \return > 0 profile found, < 0 error, 0 profile not found + */ +static int profile_find(m_option_t *config, char *prof) +{ + + int t = 0; + char tf[128 + 1]; + char *conffile; + + if (profile_file != NULL) { + char **pf; + + pf = profile_file; + for(;;) { + char *ts; + + ts = *pf++; + if (ts == NULL) { + // No , at end -> exit + return(0); + } + else if (*ts == '\0') { + // , at end of list -> check standard file(s) + break; + } + else { + + t = profile_find_single(config, ts, prof, 0); + if (t) { + // error or profile found -> exit + return(t); + } + } + } + } + + // Try in user home dir ... + snprintf(tf, sizeof(tf), "%s-profile", is_mplayer ? "mplayer" : "mencoder"); + conffile = get_path(tf); + if (conffile == NULL) { + mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_GetpathProblem); + } + else { + t = profile_find_single(config, conffile, prof, 1); + free(conffile); + } + + if (t == 0) { + // Try in main configuration dir + snprintf(tf, sizeof(tf), "%s/%s-profile", + MPLAYER_CONFDIR, + is_mplayer ? "mplayer" : "mencoder"); + t = profile_find_single(config, tf, prof, 1); + } + return(t); + +} + +/** + * \brief List all the profiles it found in the profile list + * \param config config structure, from the parser + * \return always ok + */ +static int profile_list(m_option_t *config) +{ + profile_find(config, NULL); + return(1); +} + +/** + * \brief load a series of comma separated profile names. On error + * exits from mplayer/mencoder + * \param prof comma separated list of profile to load + */ +static int profile_find_list(m_option_t *config, char *prof) +{ + + int rt = -1; + char *cp; + int prev_mode = mconfig->mode; + + mconfig->mode = M_CONFIG_FILE; + while ((cp = profile_get_string(&prof)) != NULL) { + rt = profile_find(config, cp); + if (rt <= 0) { + if (rt == 0) { + mp_msg(MSGT_CPLAYER,MSGL_ERR, "Profile not found: [%s]\n", cp); + } + break; + } + } + mconfig->mode = prev_mode; + return(rt); +} + + +/** + * \brief Load the profile(s). If profile not found exit from + * mplayer/mencoder + * \param config config structure, from the parser + * \param prof comma separated names of profile to load + * \return 1 if profile found, -1 if not found + */ +static int profile_use(m_option_t *config, char *prof) +{ + int rt = 1; + char *tp; + + mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "profile entered, par: [%s]\n", prof); + tp = strdup(prof); + if (tp != NULL) { + rt = profile_find_list(config, tp); + if (rt <= 0) { + rt = M_OPT_EXIT; + // Error or profile not found -> exit + // mencoder_exit(1, NULL); + } + free(tp); + } + else { + rt = -1; + } + return(rt); +} + +/** + * \brief Activate the profiles module, adding the option to the + * main list + * \param config config structure + * \param mplayer if != 0 the module is used by mplayer, otherwise by mencoder + */ +void profile_register(m_config_t *config, int mplayer) +{ + mconfig = config; + is_mplayer = mplayer; + m_config_register_options(config, profile_opts); +} diff -Naur orig/user-profile main/user-profile --- orig/user-profile 1970-01-01 01:00:00.000000000 +0100 +++ main/user-profile 2006-01-08 20:32:47.000000000 +0100 @@ -0,0 +1,13 @@ +#Local profile file +# + +[ mpeg4_p1 ] + profile-desc en, "mpeg4: pass 1" + profile mpeg4_hq + lavcopts vpass=1 + lavcopts turbo=yes + +[ mpeg4_p2 ] + profile-desc en, "mpeg4: pass 2" + profile mpeg4_hq + lavcopts vpass=3