From bc27f946c27e33933a3a696cade78a04902c8dce Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 6 Aug 2013 22:34:12 +0200 Subject: core: move contents to mpvcore (1/2) core is used in many unix systems for core dumps. For that reason some tools work under the assumption that the file is indeed a core dump (for example autoconf does this). This commit just renames the files. The following one will change all the includes to fix compilation. This is done this way because git has a easier time tracing file changes if there is a pure rename commit. --- core/asxparser.c | 590 ----- core/asxparser.h | 27 - core/av_common.c | 123 -- core/av_common.h | 33 - core/av_log.c | 161 -- core/av_log.h | 2 - core/av_opts.c | 55 - core/av_opts.h | 30 - core/bstr.c | 314 --- core/bstr.h | 183 -- core/charset_conv.c | 266 --- core/charset_conv.h | 17 - core/codecs.c | 147 -- core/codecs.h | 43 - core/command.c | 2673 ---------------------- core/command.h | 33 - core/cpudetect.c | 56 - core/cpudetect.h | 40 - core/encode.h | 22 - core/encode_lavc.c | 1115 ---------- core/encode_lavc.h | 101 - core/input/input.c | 2284 ------------------- core/input/input.h | 273 --- core/input/joystick.c | 162 -- core/input/joystick.h | 26 - core/input/keycodes.h | 247 --- core/input/lirc.c | 123 -- core/input/lirc.h | 30 - core/m_config.c | 777 ------- core/m_config.h | 217 -- core/m_option.c | 2407 -------------------- core/m_option.h | 646 ------ core/m_property.c | 369 ---- core/m_property.h | 142 -- core/mp_common.c | 125 -- core/mp_common.h | 66 - core/mp_core.h | 343 --- core/mp_memory_barrier.h | 23 - core/mp_msg.c | 471 ---- core/mp_msg.h | 178 -- core/mp_osd.h | 52 - core/mp_ring.c | 155 -- core/mp_ring.h | 130 -- core/mp_talloc.h | 61 - core/mplayer.c | 4747 ---------------------------------------- core/mpv_global.h | 12 - core/options.c | 838 ------- core/options.h | 276 --- core/parser-cfg.c | 249 --- core/parser-cfg.h | 27 - core/parser-mpcmd.c | 314 --- core/parser-mpcmd.h | 33 - core/path.c | 229 -- core/path.h | 66 - core/playlist.c | 246 --- core/playlist.h | 74 - core/playlist_parser.c | 777 ------- core/playlist_parser.h | 34 - core/resolve.h | 53 - core/resolve_quvi.c | 93 - core/resolve_quvi9.c | 150 -- core/screenshot.c | 390 ---- core/screenshot.h | 46 - core/timeline/tl_cue.c | 419 ---- core/timeline/tl_edl.c | 392 ---- core/timeline/tl_matroska.c | 374 ---- core/version.c | 26 - mpvcore/asxparser.c | 590 +++++ mpvcore/asxparser.h | 27 + mpvcore/av_common.c | 123 ++ mpvcore/av_common.h | 33 + mpvcore/av_log.c | 161 ++ mpvcore/av_log.h | 2 + mpvcore/av_opts.c | 55 + mpvcore/av_opts.h | 30 + mpvcore/bstr.c | 314 +++ mpvcore/bstr.h | 183 ++ mpvcore/charset_conv.c | 266 +++ mpvcore/charset_conv.h | 17 + mpvcore/codecs.c | 147 ++ mpvcore/codecs.h | 43 + mpvcore/command.c | 2673 ++++++++++++++++++++++ mpvcore/command.h | 33 + mpvcore/cpudetect.c | 56 + mpvcore/cpudetect.h | 40 + mpvcore/encode.h | 22 + mpvcore/encode_lavc.c | 1115 ++++++++++ mpvcore/encode_lavc.h | 101 + mpvcore/input/input.c | 2284 +++++++++++++++++++ mpvcore/input/input.h | 273 +++ mpvcore/input/joystick.c | 162 ++ mpvcore/input/joystick.h | 26 + mpvcore/input/keycodes.h | 247 +++ mpvcore/input/lirc.c | 123 ++ mpvcore/input/lirc.h | 30 + mpvcore/m_config.c | 777 +++++++ mpvcore/m_config.h | 217 ++ mpvcore/m_option.c | 2407 ++++++++++++++++++++ mpvcore/m_option.h | 646 ++++++ mpvcore/m_property.c | 369 ++++ mpvcore/m_property.h | 142 ++ mpvcore/mp_common.c | 125 ++ mpvcore/mp_common.h | 66 + mpvcore/mp_core.h | 343 +++ mpvcore/mp_memory_barrier.h | 23 + mpvcore/mp_msg.c | 471 ++++ mpvcore/mp_msg.h | 178 ++ mpvcore/mp_osd.h | 52 + mpvcore/mp_ring.c | 155 ++ mpvcore/mp_ring.h | 130 ++ mpvcore/mp_talloc.h | 61 + mpvcore/mplayer.c | 4747 ++++++++++++++++++++++++++++++++++++++++ mpvcore/mpv_global.h | 12 + mpvcore/options.c | 838 +++++++ mpvcore/options.h | 276 +++ mpvcore/parser-cfg.c | 249 +++ mpvcore/parser-cfg.h | 27 + mpvcore/parser-mpcmd.c | 314 +++ mpvcore/parser-mpcmd.h | 33 + mpvcore/path.c | 229 ++ mpvcore/path.h | 66 + mpvcore/playlist.c | 246 +++ mpvcore/playlist.h | 74 + mpvcore/playlist_parser.c | 777 +++++++ mpvcore/playlist_parser.h | 34 + mpvcore/resolve.h | 53 + mpvcore/resolve_quvi.c | 93 + mpvcore/resolve_quvi9.c | 150 ++ mpvcore/screenshot.c | 390 ++++ mpvcore/screenshot.h | 46 + mpvcore/timeline/tl_cue.c | 419 ++++ mpvcore/timeline/tl_edl.c | 392 ++++ mpvcore/timeline/tl_matroska.c | 374 ++++ mpvcore/version.c | 26 + 134 files changed, 25203 insertions(+), 25203 deletions(-) delete mode 100644 core/asxparser.c delete mode 100644 core/asxparser.h delete mode 100644 core/av_common.c delete mode 100644 core/av_common.h delete mode 100644 core/av_log.c delete mode 100644 core/av_log.h delete mode 100644 core/av_opts.c delete mode 100644 core/av_opts.h delete mode 100644 core/bstr.c delete mode 100644 core/bstr.h delete mode 100644 core/charset_conv.c delete mode 100644 core/charset_conv.h delete mode 100644 core/codecs.c delete mode 100644 core/codecs.h delete mode 100644 core/command.c delete mode 100644 core/command.h delete mode 100644 core/cpudetect.c delete mode 100644 core/cpudetect.h delete mode 100644 core/encode.h delete mode 100644 core/encode_lavc.c delete mode 100644 core/encode_lavc.h delete mode 100644 core/input/input.c delete mode 100644 core/input/input.h delete mode 100644 core/input/joystick.c delete mode 100644 core/input/joystick.h delete mode 100644 core/input/keycodes.h delete mode 100644 core/input/lirc.c delete mode 100644 core/input/lirc.h delete mode 100644 core/m_config.c delete mode 100644 core/m_config.h delete mode 100644 core/m_option.c delete mode 100644 core/m_option.h delete mode 100644 core/m_property.c delete mode 100644 core/m_property.h delete mode 100644 core/mp_common.c delete mode 100644 core/mp_common.h delete mode 100644 core/mp_core.h delete mode 100644 core/mp_memory_barrier.h delete mode 100644 core/mp_msg.c delete mode 100644 core/mp_msg.h delete mode 100644 core/mp_osd.h delete mode 100644 core/mp_ring.c delete mode 100644 core/mp_ring.h delete mode 100644 core/mp_talloc.h delete mode 100644 core/mplayer.c delete mode 100644 core/mpv_global.h delete mode 100644 core/options.c delete mode 100644 core/options.h delete mode 100644 core/parser-cfg.c delete mode 100644 core/parser-cfg.h delete mode 100644 core/parser-mpcmd.c delete mode 100644 core/parser-mpcmd.h delete mode 100644 core/path.c delete mode 100644 core/path.h delete mode 100644 core/playlist.c delete mode 100644 core/playlist.h delete mode 100644 core/playlist_parser.c delete mode 100644 core/playlist_parser.h delete mode 100644 core/resolve.h delete mode 100644 core/resolve_quvi.c delete mode 100644 core/resolve_quvi9.c delete mode 100644 core/screenshot.c delete mode 100644 core/screenshot.h delete mode 100644 core/timeline/tl_cue.c delete mode 100644 core/timeline/tl_edl.c delete mode 100644 core/timeline/tl_matroska.c delete mode 100644 core/version.c create mode 100644 mpvcore/asxparser.c create mode 100644 mpvcore/asxparser.h create mode 100644 mpvcore/av_common.c create mode 100644 mpvcore/av_common.h create mode 100644 mpvcore/av_log.c create mode 100644 mpvcore/av_log.h create mode 100644 mpvcore/av_opts.c create mode 100644 mpvcore/av_opts.h create mode 100644 mpvcore/bstr.c create mode 100644 mpvcore/bstr.h create mode 100644 mpvcore/charset_conv.c create mode 100644 mpvcore/charset_conv.h create mode 100644 mpvcore/codecs.c create mode 100644 mpvcore/codecs.h create mode 100644 mpvcore/command.c create mode 100644 mpvcore/command.h create mode 100644 mpvcore/cpudetect.c create mode 100644 mpvcore/cpudetect.h create mode 100644 mpvcore/encode.h create mode 100644 mpvcore/encode_lavc.c create mode 100644 mpvcore/encode_lavc.h create mode 100644 mpvcore/input/input.c create mode 100644 mpvcore/input/input.h create mode 100644 mpvcore/input/joystick.c create mode 100644 mpvcore/input/joystick.h create mode 100644 mpvcore/input/keycodes.h create mode 100644 mpvcore/input/lirc.c create mode 100644 mpvcore/input/lirc.h create mode 100644 mpvcore/m_config.c create mode 100644 mpvcore/m_config.h create mode 100644 mpvcore/m_option.c create mode 100644 mpvcore/m_option.h create mode 100644 mpvcore/m_property.c create mode 100644 mpvcore/m_property.h create mode 100644 mpvcore/mp_common.c create mode 100644 mpvcore/mp_common.h create mode 100644 mpvcore/mp_core.h create mode 100644 mpvcore/mp_memory_barrier.h create mode 100644 mpvcore/mp_msg.c create mode 100644 mpvcore/mp_msg.h create mode 100644 mpvcore/mp_osd.h create mode 100644 mpvcore/mp_ring.c create mode 100644 mpvcore/mp_ring.h create mode 100644 mpvcore/mp_talloc.h create mode 100644 mpvcore/mplayer.c create mode 100644 mpvcore/mpv_global.h create mode 100644 mpvcore/options.c create mode 100644 mpvcore/options.h create mode 100644 mpvcore/parser-cfg.c create mode 100644 mpvcore/parser-cfg.h create mode 100644 mpvcore/parser-mpcmd.c create mode 100644 mpvcore/parser-mpcmd.h create mode 100644 mpvcore/path.c create mode 100644 mpvcore/path.h create mode 100644 mpvcore/playlist.c create mode 100644 mpvcore/playlist.h create mode 100644 mpvcore/playlist_parser.c create mode 100644 mpvcore/playlist_parser.h create mode 100644 mpvcore/resolve.h create mode 100644 mpvcore/resolve_quvi.c create mode 100644 mpvcore/resolve_quvi9.c create mode 100644 mpvcore/screenshot.c create mode 100644 mpvcore/screenshot.h create mode 100644 mpvcore/timeline/tl_cue.c create mode 100644 mpvcore/timeline/tl_edl.c create mode 100644 mpvcore/timeline/tl_matroska.c create mode 100644 mpvcore/version.c diff --git a/core/asxparser.c b/core/asxparser.c deleted file mode 100644 index ec15313547..0000000000 --- a/core/asxparser.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "playlist.h" -#include "playlist_parser.h" -#include "stream/stream.h" -#include "asxparser.h" -#include "core/mp_msg.h" - - -typedef struct ASX_Parser_t ASX_Parser_t; - -typedef struct { - char* buffer; - int line; -} ASX_LineSave_t; - -struct ASX_Parser_t { - int line; // Curent line - ASX_LineSave_t *ret_stack; - int ret_stack_size; - char* last_body; - int deep; - struct playlist *pl; -}; - -ASX_Parser_t *asx_parser_new(struct playlist *pl); - -void -asx_parser_free(ASX_Parser_t* parser); - -/* - * Return -1 on error, 0 when nothing is found, 1 on sucess - */ -int -asx_get_element(ASX_Parser_t* parser,char** _buffer, - char** _element,char** _body,char*** _attribs); - -int -asx_parse_attribs(ASX_Parser_t* parser,char* buffer,char*** _attribs); - -/////// Attribs utils - -char* -asx_get_attrib(const char* attrib,char** attribs); - -#define asx_free_attribs(a) asx_list_free(&a,free) - -////// List utils - -typedef void (*ASX_FreeFunc)(void* arg); - -void -asx_list_free(void* list_ptr,ASX_FreeFunc free_func); - - -////// List utils - -void -asx_list_free(void* list_ptr,ASX_FreeFunc free_func) { - void** ptr = *(void***)list_ptr; - if(ptr == NULL) return; - if(free_func != NULL) { - for( ; *ptr != NULL ; ptr++) - free_func(*ptr); - } - free(*(void**)list_ptr); - *(void**)list_ptr = NULL; -} - -/////// Attribs utils - -char* -asx_get_attrib(const char* attrib,char** attribs) { - char** ptr; - - if(attrib == NULL || attribs == NULL) return NULL; - for(ptr = attribs; ptr[0] != NULL; ptr += 2){ - if(strcasecmp(ptr[0],attrib) == 0) - return strdup(ptr[1]); - } - return NULL; -} - -#define asx_warning_attrib_required(p,e,a) mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : element %s don't have the required attribute %s",p->line,e,a) -#define asx_warning_body_parse_error(p,e) mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : error while parsing %s body",p->line,e) - -ASX_Parser_t *asx_parser_new(struct playlist *pl) -{ - ASX_Parser_t* parser = calloc(1,sizeof(ASX_Parser_t)); - parser->pl = pl; - return parser; -} - -void -asx_parser_free(ASX_Parser_t* parser) { - if(!parser) return; - free(parser->ret_stack); - free(parser); - -} - -#define LETTER "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define SPACE " \n\t\r" - -int -asx_parse_attribs(ASX_Parser_t* parser,char* buffer,char*** _attribs) { - char *ptr1, *ptr2, *ptr3; - int n_attrib = 0; - char **attribs = NULL; - char *attrib, *val; - - ptr1 = buffer; - while(1) { - for( ; strchr(SPACE,*ptr1) != NULL; ptr1++) { // Skip space - if(*ptr1 == '\0') break; - } - ptr3 = strchr(ptr1,'='); - if(ptr3 == NULL) break; - for(ptr2 = ptr3-1; strchr(SPACE,*ptr2) != NULL; ptr2--) { - if (ptr2 == ptr1) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : this should never append, back to attribute begin while skipping end space",parser->line); - break; - } - } - attrib = malloc(ptr2-ptr1+2); - strncpy(attrib,ptr1,ptr2-ptr1+1); - attrib[ptr2-ptr1+1] = '\0'; - - ptr1 = strchr(ptr3,'"'); - if(ptr1 == NULL || ptr1[1] == '\0') ptr1 = strchr(ptr3,'\''); - if(ptr1 == NULL || ptr1[1] == '\0') { - mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : can't find attribute %s value",parser->line,attrib); - free(attrib); - break; - } - ptr2 = strchr(ptr1+1,ptr1[0]); - if (ptr2 == NULL) { - mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : value of attribute %s isn't finished",parser->line,attrib); - free(attrib); - break; - } - ptr1++; - val = malloc(ptr2-ptr1+1); - strncpy(val,ptr1,ptr2-ptr1); - val[ptr2-ptr1] = '\0'; - n_attrib++; - - attribs = realloc(attribs, (2 * n_attrib + 1) * sizeof(char*)); - attribs[n_attrib*2-2] = attrib; - attribs[n_attrib*2-1] = val; - - ptr1 = ptr2+1; - } - - if(n_attrib > 0) - attribs[n_attrib*2] = NULL; - - *_attribs = attribs; - - return n_attrib; -} - -/* - * Return -1 on error, 0 when nothing is found, 1 on sucess - */ -int -asx_get_element(ASX_Parser_t* parser,char** _buffer, - char** _element,char** _body,char*** _attribs) { - char *ptr1,*ptr2, *ptr3, *ptr4; - char *attribs = NULL; - char *element = NULL, *body = NULL, *ret = NULL, *buffer; - int n_attrib = 0; - int body_line = 0,attrib_line,ret_line,in = 0; - int quotes = 0; - - if(_buffer == NULL || _element == NULL || _body == NULL || _attribs == NULL) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : asx_get_element called with invalid value",parser->line); - return -1; - } - - *_body = *_element = NULL; - *_attribs = NULL; - buffer = *_buffer; - - if(buffer == NULL) return 0; - - if(parser->ret_stack && /*parser->last_body && */buffer != parser->last_body) { - ASX_LineSave_t* ls = parser->ret_stack; - int i; - for(i = 0 ; i < parser->ret_stack_size ; i++) { - if(buffer == ls[i].buffer) { - parser->line = ls[i].line; - break; - } - - } - if( i < parser->ret_stack_size) { - i++; - if( i < parser->ret_stack_size) - memmove(parser->ret_stack,parser->ret_stack+i, (parser->ret_stack_size - i)*sizeof(ASX_LineSave_t)); - parser->ret_stack_size -= i; - if(parser->ret_stack_size > 0) - parser->ret_stack = realloc(parser->ret_stack,parser->ret_stack_size*sizeof(ASX_LineSave_t)); - else { - free(parser->ret_stack); - parser->ret_stack = NULL; - } - } - } - - ptr1 = buffer; - while(1) { - for( ; ptr1[0] != '<' ; ptr1++) { - if(ptr1[0] == '\0') { - ptr1 = NULL; - break; - } - if(ptr1[0] == '\n') parser->line++; - } - //ptr1 = strchr(ptr1,'<'); - if(!ptr1 || ptr1[1] == '\0') return 0; // Nothing found - - if(strncmp(ptr1,"",3) != 0 ; ptr1++) { - if(ptr1[0] == '\0') { - ptr1 = NULL; - break; - } - if(ptr1[0] == '\n') parser->line++; - } - //ptr1 = strstr(ptr1,"-->"); - if(!ptr1) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : unfinished comment",parser->line); - return -1; - } - } else { - break; - } - } - - // Is this space skip very useful ?? - for(ptr1++; strchr(SPACE,ptr1[0]) != NULL; ptr1++) { // Skip space - if(ptr1[0] == '\0') { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); - return -1; - } - if(ptr1[0] == '\n') parser->line++; - } - - for(ptr2 = ptr1; strchr(LETTER,*ptr2) != NULL;ptr2++) { // Go to end of name - if(*ptr2 == '\0'){ - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); - return -1; - } - if(ptr2[0] == '\n') parser->line++; - } - - element = malloc(ptr2-ptr1+1); - strncpy(element,ptr1,ptr2-ptr1); - element[ptr2-ptr1] = '\0'; - - for( ; strchr(SPACE,*ptr2) != NULL; ptr2++) { // Skip space - if(ptr2[0] == '\0') { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); - free(element); - return -1; - } - if(ptr2[0] == '\n') parser->line++; - } - attrib_line = parser->line; - - - - for(ptr3 = ptr2; ptr3[0] != '\0'; ptr3++) { // Go to element end - if(ptr3[0] == '"') quotes ^= 1; - if(!quotes && (ptr3[0] == '>' || strncmp(ptr3,"/>",2) == 0)) - break; - if(ptr3[0] == '\n') parser->line++; - } - if(ptr3[0] == '\0' || ptr3[1] == '\0') { // End of file - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); - free(element); - return -1; - } - - // Save attribs string - if(ptr3-ptr2 > 0) { - attribs = malloc(ptr3-ptr2+1); - strncpy(attribs,ptr2,ptr3-ptr2); - attribs[ptr3-ptr2] = '\0'; - } - //bs_line = parser->line; - if(ptr3[0] != '/') { // Not Self closed element - ptr3++; - for( ; strchr(SPACE,*ptr3) != NULL; ptr3++) { // Skip space on body begin - if(*ptr3 == '\0') { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing %s element body",parser->line,element); - free(element); - free(attribs); - return -1; - } - if(ptr3[0] == '\n') parser->line++; - } - ptr4 = ptr3; - body_line = parser->line; - while(1) { // Find closing element - for( ; ptr4[0] != '<' ; ptr4++) { - if(ptr4[0] == '\0') { - ptr4 = NULL; - break; - } - if(ptr4[0] == '\n') parser->line++; - } - if(ptr4 && strncmp(ptr4,"",3) != 0 ; ptr4++) { - if(ptr4[0] == '\0') { - ptr4 = NULL; - break; - } - if(ptr1[0] == '\n') parser->line++; - } - continue; - } - if(ptr4 == NULL || ptr4[1] == '\0') { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing %s element body",parser->line,element); - free(element); - free(attribs); - return -1; - } - if(ptr4[1] != '/' && strncasecmp(element,ptr4+1,strlen(element)) == 0) { - in++; - ptr4+=2; - continue; - } else if(strncasecmp(element,ptr4+2,strlen(element)) == 0) { // Extract body - if(in > 0) { - in--; - ptr4 += 2+strlen(element); - continue; - } - ret = ptr4+strlen(element)+3; - if(ptr4 != ptr3) { - ptr4--; - for( ; ptr4 != ptr3 && strchr(SPACE,*ptr4) != NULL; ptr4--) ;// Skip space on body end - // if(ptr4[0] == '\0') parser->line--; - //} - ptr4++; - body = malloc(ptr4-ptr3+1); - strncpy(body,ptr3,ptr4-ptr3); - body[ptr4-ptr3] = '\0'; - } - break; - } else { - ptr4 += 2; - } - } - } else { - ret = ptr3 + 2; // 2 is for /> - } - - for( ; ret[0] != '\0' && strchr(SPACE,ret[0]) != NULL; ret++) { // Skip space - if(ret[0] == '\n') parser->line++; - } - - ret_line = parser->line; - - if(attribs) { - parser->line = attrib_line; - n_attrib = asx_parse_attribs(parser,attribs,_attribs); - free(attribs); - if(n_attrib < 0) { - mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : error while parsing element %s attributes",parser->line,element); - free(element); - free(body); - return -1; - } - } else - *_attribs = NULL; - - *_element = element; - *_body = body; - - parser->last_body = body; - parser->ret_stack_size++; - parser->ret_stack = realloc(parser->ret_stack,parser->ret_stack_size*sizeof(ASX_LineSave_t)); - if(parser->ret_stack_size > 1) - memmove(parser->ret_stack+1,parser->ret_stack,(parser->ret_stack_size-1)*sizeof(ASX_LineSave_t)); - parser->ret_stack[0].buffer = ret; - parser->ret_stack[0].line = ret_line; - parser->line = body ? body_line : ret_line; - - *_buffer = ret; - return 1; - -} - -static void -asx_parse_ref(ASX_Parser_t* parser, char** attribs) { - char *href; - - href = asx_get_attrib("HREF",attribs); - if(href == NULL) { - asx_warning_attrib_required(parser,"REF" ,"HREF" ); - return; - } -#if 0 - // replace http my mmshttp to avoid infinite loops - // disabled since some playlists for e.g. WinAMP use asx as well - // "-user-agent NSPlayer/4.1.0.3856" is a possible workaround - if (strncmp(href, "http://", 7) == 0) { - char *newref = malloc(3 + strlen(href) + 1); - strcpy(newref, "mms"); - strcpy(newref + 3, href); - free(href); - href = newref; - } -#endif - - playlist_add_file(parser->pl, href); - - mp_msg(MSGT_PLAYTREE,MSGL_V,"Adding file %s to element entry\n",href); - - free(href); - -} - -static void asx_parse_entryref(ASX_Parser_t* parser,char* buffer,char** _attribs) { - char *href; - stream_t* stream; - - if(parser->deep > 0) - return; - - href = asx_get_attrib("HREF",_attribs); - if(href == NULL) { - asx_warning_attrib_required(parser,"ENTRYREF" ,"HREF" ); - return; - } - stream=stream_open(href, NULL); - if(!stream) { - mp_msg(MSGT_PLAYTREE,MSGL_WARN,"Can't open playlist %s\n",href); - free(href); - return; - } - - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Not recursively loading playlist %s\n",href); - - free_stream(stream); - free(href); - //mp_msg(MSGT_PLAYTREE,MSGL_INFO,"Need to implement entryref\n"); -} - -static void asx_parse_entry(ASX_Parser_t* parser,char* buffer,char** _attribs) { - char *element,*body,**attribs; - int r; - - while(buffer && buffer[0] != '\0') { - r = asx_get_element(parser,&buffer,&element,&body,&attribs); - if(r < 0) { - asx_warning_body_parse_error(parser,"ENTRY"); - return; - } else if (r == 0) { // No more element - break; - } - if(strcasecmp(element,"REF") == 0) { - asx_parse_ref(parser,attribs); - mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to entry\n",element); - } else - mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); - free(body); - asx_free_attribs(attribs); - } - -} - - -static void asx_parse_repeat(ASX_Parser_t* parser,char* buffer,char** _attribs) { - char *element,*body,**attribs; - int r; - - asx_get_attrib("COUNT",_attribs); - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Ignoring repeated playlist entries\n"); - - while(buffer && buffer[0] != '\0') { - r = asx_get_element(parser,&buffer,&element,&body,&attribs); - if(r < 0) { - asx_warning_body_parse_error(parser,"REPEAT"); - return; - } else if (r == 0) { // No more element - break; - } - if(strcasecmp(element,"ENTRY") == 0) { - asx_parse_entry(parser,body,attribs); - } else if(strcasecmp(element,"ENTRYREF") == 0) { - asx_parse_entryref(parser,body,attribs); - } else if(strcasecmp(element,"REPEAT") == 0) { - asx_parse_repeat(parser,body,attribs); - } else - mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); - free(body); - asx_free_attribs(attribs); - } - -} - - -bool asx_parse(char* buffer, struct playlist *pl) -{ - char *element,*asx_body,**asx_attribs,*body = NULL, **attribs; - int r; - ASX_Parser_t* parser = asx_parser_new(pl); - - parser->line = 1; - parser->deep = 0; - - r = asx_get_element(parser,&buffer,&element,&asx_body,&asx_attribs); - if(r < 0) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : Syntax error ???",parser->line); - asx_parser_free(parser); - return false; - } else if(r == 0) { // No contents - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"empty asx element"); - asx_parser_free(parser); - return false; - } - - if(strcasecmp(element,"ASX") != 0) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"first element isn't ASX, it's %s\n",element); - asx_free_attribs(asx_attribs); - asx_parser_free(parser); - return false; - } - - if(!asx_body) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"ASX element is empty"); - asx_free_attribs(asx_attribs); - asx_parser_free(parser); - return false; - } - - buffer = asx_body; - while(buffer && buffer[0] != '\0') { - r = asx_get_element(parser,&buffer,&element,&body,&attribs); - if(r < 0) { - asx_warning_body_parse_error(parser,"ASX"); - asx_parser_free(parser); - return false; - } else if (r == 0) { // No more element - break; - } - if(strcasecmp(element,"ENTRY") == 0) { - asx_parse_entry(parser,body,attribs); - } else if(strcasecmp(element,"ENTRYREF") == 0) { - asx_parse_entryref(parser,body,attribs); - } else if(strcasecmp(element,"REPEAT") == 0) { - asx_parse_repeat(parser,body,attribs); - } else - mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); - free(body); - asx_free_attribs(attribs); - } - - free(asx_body); - asx_free_attribs(asx_attribs); - asx_parser_free(parser); - return true; -} diff --git a/core/asxparser.h b/core/asxparser.h deleted file mode 100644 index e49a2cedc0..0000000000 --- a/core/asxparser.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_ASXPARSER_H -#define MPLAYER_ASXPARSER_H - -#include - -struct playlist; -bool asx_parse(char* buffer, struct playlist *pl); - -#endif /* MPLAYER_ASXPARSER_H */ diff --git a/core/av_common.c b/core/av_common.c deleted file mode 100644 index a4dc525aa9..0000000000 --- a/core/av_common.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include - -#include -#include - -#include "core/mp_talloc.h" -#include "demux/demux_packet.h" -#include "av_common.h" -#include "codecs.h" - - -// Copy the codec-related fields from st into avctx. This does not set the -// codec itself, only codec related header data provided by libavformat. -// The goal is to initialize a new decoder with the header data provided by -// libavformat, and unlike avcodec_copy_context(), allow the user to create -// a clean AVCodecContext for a manually selected AVCodec. -// This is strictly for decoding only. -void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st) -{ - if (st->extradata_size) { - av_free(avctx->extradata); - avctx->extradata_size = 0; - avctx->extradata = - av_mallocz(st->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (avctx->extradata) { - avctx->extradata_size = st->extradata_size; - memcpy(avctx->extradata, st->extradata, st->extradata_size); - } - } - avctx->codec_tag = st->codec_tag; - avctx->stream_codec_tag = st->stream_codec_tag; - avctx->bit_rate = st->bit_rate; - avctx->width = st->width; - avctx->height = st->height; - avctx->pix_fmt = st->pix_fmt; - avctx->sample_aspect_ratio = st->sample_aspect_ratio; - avctx->chroma_sample_location = st->chroma_sample_location; - avctx->sample_rate = st->sample_rate; - avctx->channels = st->channels; - avctx->block_align = st->block_align; - avctx->channel_layout = st->channel_layout; - avctx->audio_service_type = st->audio_service_type; - avctx->bits_per_coded_sample = st->bits_per_coded_sample; -} - -// Set dst from mpkt. Note that dst is not refcountable. -// mpkt can be NULL to generate empty packets (used to flush delayed data). -// Does not set pts or duration fields. -void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt) -{ - av_init_packet(dst); - dst->data = mpkt ? mpkt->buffer : NULL; - dst->size = mpkt ? mpkt->len : 0; - /* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info - * from demuxer. */ - if (mpkt && mpkt->keyframe) - dst->flags |= AV_PKT_FLAG_KEY; - if (mpkt && mpkt->avpacket) { - dst->side_data = mpkt->avpacket->side_data; - dst->side_data_elems = mpkt->avpacket->side_data_elems; - } -} - -void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) -{ - AVCodec *cur = NULL; - for (;;) { - cur = av_codec_next(cur); - if (!cur) - break; - if (av_codec_is_decoder(cur) && cur->type == type) { - mp_add_decoder(list, "lavc", mp_codec_from_av_codec_id(cur->id), - cur->name, cur->long_name); - } - } -} - -int mp_codec_to_av_codec_id(const char *codec) -{ - int id = AV_CODEC_ID_NONE; - if (codec) { - const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(codec); - if (desc) - id = desc->id; - if (id == AV_CODEC_ID_NONE) { - AVCodec *avcodec = avcodec_find_decoder_by_name(codec); - if (avcodec) - id = avcodec->id; - } - } - return id; -} - -const char *mp_codec_from_av_codec_id(int codec_id) -{ - const char *name = NULL; - const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id); - if (desc) - name = desc->name; - if (!name) { - AVCodec *avcodec = avcodec_find_decoder(codec_id); - if (avcodec) - name = avcodec->name; - } - return name; -} diff --git a/core/av_common.h b/core/av_common.h deleted file mode 100644 index 2fa8f127b0..0000000000 --- a/core/av_common.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MP_AVCOMMON_H -#define MP_AVCOMMON_H - -#include -#include - -struct mp_decoder_list; -struct demux_packet; - -void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st); -void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt); -void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type); -int mp_codec_to_av_codec_id(const char *codec); -const char *mp_codec_from_av_codec_id(int codec_id); - -#endif diff --git a/core/av_log.c b/core/av_log.c deleted file mode 100644 index 1331a1fb26..0000000000 --- a/core/av_log.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * av_log to mp_msg converter - * Copyright (C) 2006 Michael Niedermayer - * Copyright (C) 2009 Uoti Urpala - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -#include "av_log.h" -#include "config.h" -#include "core/mp_msg.h" -#include -#include - -#include -#include -#include - -#ifdef CONFIG_LIBAVDEVICE -#include -#endif - -#ifdef CONFIG_LIBAVFILTER -#include -#endif - -static int av_log_level_to_mp_level(int av_level) -{ - if (av_level > AV_LOG_VERBOSE) - return MSGL_DBG2; - if (av_level > AV_LOG_INFO) - return MSGL_V; - if (av_level > AV_LOG_WARNING) - return MSGL_INFO; - if (av_level > AV_LOG_ERROR) - return MSGL_WARN; - if (av_level > AV_LOG_FATAL) - return MSGL_ERR; - return MSGL_FATAL; -} - -static int extract_msg_type_from_ctx(void *ptr) -{ - if (!ptr) - return MSGT_FIXME; - - AVClass *avc = *(AVClass **)ptr; - if (!avc) { - mp_msg(MSGT_FIXME, MSGL_WARN, - "av_log callback called with bad parameters (NULL AVClass).\n" - "This is a bug in one of Libav/FFmpeg libraries used.\n"); - return MSGT_FIXME; - } - - if (!strcmp(avc->class_name, "AVCodecContext")) { - AVCodecContext *s = ptr; - if (s->codec) { - if (s->codec->type == AVMEDIA_TYPE_AUDIO) { - if (s->codec->decode) - return MSGT_DECAUDIO; - } else if (s->codec->type == AVMEDIA_TYPE_VIDEO) { - if (s->codec->decode) - return MSGT_DECVIDEO; - } - // FIXME subtitles, encoders - // What msgt for them? There is nothing appropriate... - } - return MSGT_FIXME; - } - - if (!strcmp(avc->class_name, "AVFormatContext")) { - AVFormatContext *s = ptr; - if (s->iformat) - return MSGT_DEMUXER; - else if (s->oformat) - return MSGT_MUXER; - return MSGT_FIXME; - } - - return MSGT_FIXME; -} - -#if LIBAVCODEC_VERSION_MICRO >= 100 -#define LIB_PREFIX "ffmpeg" -#else -#define LIB_PREFIX "libav" -#endif - -static bool print_prefix = true; - -static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt, - va_list vl) -{ - AVClass *avc = ptr ? *(AVClass **)ptr : NULL; - int mp_level = av_log_level_to_mp_level(level); - int type = extract_msg_type_from_ctx(ptr); - - if (!mp_msg_test(type, mp_level)) - return; - - if (print_prefix) { - mp_msg(type, mp_level, "[%s/%s] ", LIB_PREFIX, - avc ? avc->item_name(ptr) : "?"); - } - print_prefix = fmt[strlen(fmt) - 1] == '\n'; - - mp_msg_va(type, mp_level, fmt, vl); -} - -void init_libav(void) -{ - av_log_set_callback(mp_msg_av_log_callback); - avcodec_register_all(); - av_register_all(); - avformat_network_init(); - -#ifdef CONFIG_LIBAVFILTER - avfilter_register_all(); -#endif -#ifdef CONFIG_LIBAVDEVICE - avdevice_register_all(); -#endif -} - -#define V(x) (x)>>16, (x)>>8 & 255, (x) & 255 -static void print_version(char *name, unsigned buildv, unsigned runv) -{ - - if (buildv == runv) - mp_msg(MSGT_CPLAYER, MSGL_V, "Compiled against %s version %d.%d.%d\n", - name, V(buildv)); - else - mp_msg(MSGT_CPLAYER, MSGL_V, "Compiled against %s version %d.%d.%d " - "(runtime %d.%d.%d)\n", name, V(buildv), V(runv)); -} -#undef V - -void print_libav_versions(void) -{ - print_version("libavutil", LIBAVUTIL_VERSION_INT, avutil_version()); - print_version("libavcodec", LIBAVCODEC_VERSION_INT, avcodec_version()); - print_version("libavformat", LIBAVFORMAT_VERSION_INT, avformat_version()); - print_version("libswscale", LIBSWSCALE_VERSION_INT, swscale_version()); -} diff --git a/core/av_log.h b/core/av_log.h deleted file mode 100644 index 833a7af03b..0000000000 --- a/core/av_log.h +++ /dev/null @@ -1,2 +0,0 @@ -void init_libav(void); -void print_libav_versions(void); diff --git a/core/av_opts.c b/core/av_opts.c deleted file mode 100644 index 777a1eec5a..0000000000 --- a/core/av_opts.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * AVOption parsing helper - * Copyright (C) 2008 Michael Niedermayer - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -#include - -#include "av_opts.h" - -int parse_avopts(void *v, char *str){ - char *start; - - if (!str) - return 0; - - start= str= strdup(str); - - while(str && *str){ - char *next_opt, *arg; - - next_opt= strchr(str, ','); - if(next_opt) *next_opt++= 0; - - arg = strchr(str, '='); - if(arg) *arg++= 0; - - if (av_opt_set(v, str, arg, AV_OPT_SEARCH_CHILDREN) < 0) { - free(start); - return -1; - } - str= next_opt; - } - - free(start); - return 0; -} diff --git a/core/av_opts.h b/core/av_opts.h deleted file mode 100644 index 640443a352..0000000000 --- a/core/av_opts.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * AVOption parsing helper - * Copyright (C) 2008 Michael Niedermayer - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_AV_OPTS_H -#define MPLAYER_AV_OPTS_H - -/** - * Parses str and sets AVOptions in v accordingly. - */ -int parse_avopts(void *v, char *str); - -#endif /* MPLAYER_AV_OPTS_H */ diff --git a/core/bstr.c b/core/bstr.c deleted file mode 100644 index 16da0993ea..0000000000 --- a/core/bstr.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include - -#include - -#include "talloc.h" - -#include "core/bstr.h" - -int bstrcmp(struct bstr str1, struct bstr str2) -{ - int ret = memcmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); - - if (!ret) { - if (str1.len == str2.len) - return 0; - else if (str1.len > str2.len) - return 1; - else - return -1; - } - return ret; -} - -int bstrcasecmp(struct bstr str1, struct bstr str2) -{ - int ret = strncasecmp(str1.start, str2.start, FFMIN(str1.len, str2.len)); - - if (!ret) { - if (str1.len == str2.len) - return 0; - else if (str1.len > str2.len) - return 1; - else - return -1; - } - return ret; -} - -int bstrchr(struct bstr str, int c) -{ - for (int i = 0; i < str.len; i++) - if (str.start[i] == c) - return i; - return -1; -} - -int bstrrchr(struct bstr str, int c) -{ - for (int i = str.len - 1; i >= 0; i--) - if (str.start[i] == c) - return i; - return -1; -} - -int bstrcspn(struct bstr str, const char *reject) -{ - int i; - for (i = 0; i < str.len; i++) - if (strchr(reject, str.start[i])) - break; - return i; -} - -int bstrspn(struct bstr str, const char *accept) -{ - int i; - for (i = 0; i < str.len; i++) - if (!strchr(accept, str.start[i])) - break; - return i; -} - -int bstr_find(struct bstr haystack, struct bstr needle) -{ - for (int i = 0; i < haystack.len; i++) - if (bstr_startswith(bstr_splice(haystack, i, haystack.len), needle)) - return i; - return -1; -} - -struct bstr bstr_lstrip(struct bstr str) -{ - while (str.len && isspace(*str.start)) { - str.start++; - str.len--; - } - return str; -} - -struct bstr bstr_strip(struct bstr str) -{ - str = bstr_lstrip(str); - while (str.len && isspace(str.start[str.len - 1])) - str.len--; - return str; -} - -struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest) -{ - int start; - for (start = 0; start < str.len; start++) - if (!strchr(sep, str.start[start])) - break; - str = bstr_cut(str, start); - int end = bstrcspn(str, sep); - if (rest) { - *rest = bstr_cut(str, end); - } - return bstr_splice(str, 0, end); -} - -// Unlike with bstr_split(), tok is a string, and not a set of char. -// If tok is in str, return true, and: concat(out_left, tok, out_right) == str -// Otherwise, return false, and set out_left==str, out_right=="" -bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right) -{ - bstr bsep = bstr0(tok); - int pos = bstr_find(str, bsep); - if (pos < 0) - pos = str.len; - *out_left = bstr_splice(str, 0, pos); - *out_right = bstr_cut(str, pos + bsep.len); - return pos != str.len; -} - -struct bstr bstr_splice(struct bstr str, int start, int end) -{ - if (start < 0) - start += str.len; - if (end < 0) - end += str.len; - end = FFMIN(end, str.len); - start = FFMAX(start, 0); - end = FFMAX(end, start); - str.start += start; - str.len = end - start; - return str; -} - -long long bstrtoll(struct bstr str, struct bstr *rest, int base) -{ - str = bstr_lstrip(str); - char buf[51]; - int len = FFMIN(str.len, 50); - memcpy(buf, str.start, len); - buf[len] = 0; - char *endptr; - long long r = strtoll(buf, &endptr, base); - if (rest) - *rest = bstr_cut(str, endptr - buf); - return r; -} - -double bstrtod(struct bstr str, struct bstr *rest) -{ - str = bstr_lstrip(str); - char buf[101]; - int len = FFMIN(str.len, 100); - memcpy(buf, str.start, len); - buf[len] = 0; - char *endptr; - double r = strtod(buf, &endptr); - if (rest) - *rest = bstr_cut(str, endptr - buf); - return r; -} - -struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str) -{ - if (str.len == 0) - return NULL; - int count = 0; - for (int i = 0; i < str.len; i++) - if (str.start[i] == '\n') - count++; - if (str.start[str.len - 1] != '\n') - count++; - struct bstr *r = talloc_array_ptrtype(talloc_ctx, r, count); - unsigned char *p = str.start; - for (int i = 0; i < count - 1; i++) { - r[i].start = p; - while (*p++ != '\n'); - r[i].len = p - r[i].start; - } - r[count - 1].start = p; - r[count - 1].len = str.start + str.len - p; - return r; -} - -struct bstr bstr_getline(struct bstr str, struct bstr *rest) -{ - int pos = bstrchr(str, '\n'); - if (pos < 0) - pos = str.len; - if (rest) - *rest = bstr_cut(str, pos + 1); - return bstr_splice(str, 0, pos + 1); -} - -struct bstr bstr_strip_linebreaks(struct bstr str) -{ - if (bstr_endswith0(str, "\r\n")) { - str = bstr_splice(str, 0, str.len - 2); - } else if (bstr_endswith0(str, "\n")) { - str = bstr_splice(str, 0, str.len - 1); - } - return str; -} - -bool bstr_eatstart(struct bstr *s, struct bstr prefix) -{ - if (!bstr_startswith(*s, prefix)) - return false; - *s = bstr_cut(*s, prefix.len); - return true; -} - -void bstr_lower(struct bstr str) -{ - for (int i = 0; i < str.len; i++) - str.start[i] = tolower(str.start[i]); -} - -int bstr_sscanf(struct bstr str, const char *format, ...) -{ - char *ptr = bstrdup0(NULL, str); - va_list va; - va_start(va, format); - int ret = vsscanf(ptr, format, va); - va_end(va); - talloc_free(ptr); - return ret; -} - -int bstr_parse_utf8_code_length(unsigned char b) -{ - if (b < 128) - return 1; - int bytes = 7 - av_log2(b ^ 255); - return (bytes >= 2 && bytes <= 4) ? bytes : -1; -} - -int bstr_decode_utf8(struct bstr s, struct bstr *out_next) -{ - if (s.len == 0) - return -1; - unsigned int codepoint = s.start[0]; - s.start++; s.len--; - if (codepoint >= 128) { - int bytes = bstr_parse_utf8_code_length(codepoint); - if (bytes < 0 || s.len < bytes - 1) - return -1; - codepoint &= 127 >> bytes; - for (int n = 1; n < bytes; n++) { - int tmp = s.start[0]; - if ((tmp & 0xC0) != 0x80) - return -1; - codepoint = (codepoint << 6) | (tmp & ~0xC0); - s.start++; s.len--; - } - } - if (out_next) - *out_next = s; - return codepoint; -} - -bool bstr_case_startswith(struct bstr s, struct bstr prefix) -{ - struct bstr start = bstr_splice(s, 0, prefix.len); - return start.len == prefix.len && bstrcasecmp(start, prefix) == 0; -} - -bool bstr_case_endswith(struct bstr s, struct bstr suffix) -{ - struct bstr end = bstr_cut(s, -suffix.len); - return end.len == suffix.len && bstrcasecmp(end, suffix) == 0; -} - -struct bstr bstr_strip_ext(struct bstr str) -{ - int dotpos = bstrrchr(str, '.'); - if (dotpos < 0) - return str; - return (struct bstr){str.start, dotpos}; -} - -struct bstr bstr_get_ext(struct bstr s) -{ - int dotpos = bstrrchr(s, '.'); - if (dotpos < 0) - return (struct bstr){NULL, 0}; - return bstr_splice(s, dotpos + 1, s.len); -} diff --git a/core/bstr.h b/core/bstr.h deleted file mode 100644 index ce9e029ea5..0000000000 --- a/core/bstr.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_BSTR_H -#define MPLAYER_BSTR_H - -#include -#include -#include -#include - -#include "talloc.h" - -/* NOTE: 'len' is size_t, but most string-handling functions below assume - * that input size has been sanity checked and len fits in an int. - */ -typedef struct bstr { - unsigned char *start; - size_t len; -} bstr; - -// If str.start is NULL, return NULL. -static inline char *bstrdup0(void *talloc_ctx, struct bstr str) -{ - return talloc_strndup(talloc_ctx, (char *)str.start, str.len); -} - -// Like bstrdup0(), but always return a valid C-string. -static inline char *bstrto0(void *talloc_ctx, struct bstr str) -{ - return str.start ? bstrdup0(talloc_ctx, str) : talloc_strdup(talloc_ctx, ""); -} - -// Return start = NULL iff that is true for the original. -static inline struct bstr bstrdup(void *talloc_ctx, struct bstr str) -{ - struct bstr r = { NULL, str.len }; - if (str.start) - r.start = (unsigned char *)talloc_memdup(talloc_ctx, str.start, str.len); - return r; -} - -static inline struct bstr bstr0(const char *s) -{ - return (struct bstr){(unsigned char *)s, s ? strlen(s) : 0}; -} - -int bstrcmp(struct bstr str1, struct bstr str2); -int bstrcasecmp(struct bstr str1, struct bstr str2); -int bstrchr(struct bstr str, int c); -int bstrrchr(struct bstr str, int c); -int bstrspn(struct bstr str, const char *accept); -int bstrcspn(struct bstr str, const char *reject); - -int bstr_find(struct bstr haystack, struct bstr needle); -struct bstr *bstr_splitlines(void *talloc_ctx, struct bstr str); -struct bstr bstr_lstrip(struct bstr str); -struct bstr bstr_strip(struct bstr str); -struct bstr bstr_split(struct bstr str, const char *sep, struct bstr *rest); -bool bstr_split_tok(bstr str, const char *tok, bstr *out_left, bstr *out_right); -struct bstr bstr_splice(struct bstr str, int start, int end); -long long bstrtoll(struct bstr str, struct bstr *rest, int base); -double bstrtod(struct bstr str, struct bstr *rest); -void bstr_lower(struct bstr str); -int bstr_sscanf(struct bstr str, const char *format, ...); - -// Decode the UTF-8 code point at the start of the string,, and return the -// character. -// After calling this function, *out_next will point to the next character. -// out_next can be NULL. -// On error, -1 is returned, and *out_next is not modified. -int bstr_decode_utf8(struct bstr str, struct bstr *out_next); - -// Return the length of the UTF-8 sequence that starts with the given byte. -// Given a string char *s, the next UTF-8 code point is to be expected at -// s + bstr_parse_utf8_code_length(s[0]) -// On error, -1 is returned. On success, it returns a value in the range [1, 4]. -int bstr_parse_utf8_code_length(unsigned char b); - -// Return the text before the next line break, and return it. Change *rest to -// point to the text following this line break. (rest can be NULL.) -// Line break characters are not stripped. -struct bstr bstr_getline(struct bstr str, struct bstr *rest); - -// Strip one trailing line break. This is intended for use with bstr_getline, -// and will remove the trailing \n or \r\n sequence. -struct bstr bstr_strip_linebreaks(struct bstr str); - -// If s starts with prefix, return true and return the rest of the string in s. -bool bstr_eatstart(struct bstr *s, struct bstr prefix); - -bool bstr_case_startswith(struct bstr s, struct bstr prefix); -bool bstr_case_endswith(struct bstr s, struct bstr suffix); -struct bstr bstr_strip_ext(struct bstr str); -struct bstr bstr_get_ext(struct bstr s); - -static inline struct bstr bstr_cut(struct bstr str, int n) -{ - if (n < 0) { - n += str.len; - if (n < 0) - n = 0; - } - if (((size_t)n) > str.len) - n = str.len; - return (struct bstr){str.start + n, str.len - n}; -} - -static inline bool bstr_startswith(struct bstr str, struct bstr prefix) -{ - if (str.len < prefix.len) - return false; - return !memcmp(str.start, prefix.start, prefix.len); -} - -static inline bool bstr_startswith0(struct bstr str, const char *prefix) -{ - return bstr_startswith(str, bstr0(prefix)); -} - -static inline bool bstr_endswith(struct bstr str, struct bstr suffix) -{ - if (str.len < suffix.len) - return false; - return !memcmp(str.start + str.len - suffix.len, suffix.start, suffix.len); -} - -static inline bool bstr_endswith0(struct bstr str, const char *suffix) -{ - return bstr_endswith(str, bstr0(suffix)); -} - -static inline int bstrcmp0(struct bstr str1, const char *str2) -{ - return bstrcmp(str1, bstr0(str2)); -} - -static inline bool bstr_equals(struct bstr str1, struct bstr str2) -{ - return bstrcmp(str1, str2) == 0; -} - -static inline bool bstr_equals0(struct bstr str1, const char *str2) -{ - return bstrcmp(str1, bstr0(str2)) == 0; -} - -static inline int bstrcasecmp0(struct bstr str1, const char *str2) -{ - return bstrcasecmp(str1, bstr0(str2)); -} - -static inline int bstr_find0(struct bstr haystack, const char *needle) -{ - return bstr_find(haystack, bstr0(needle)); -} - -static inline int bstr_eatstart0(struct bstr *s, const char *prefix) -{ - return bstr_eatstart(s, bstr0(prefix)); -} - -// create a pair (not single value!) for "%.*s" printf syntax -#define BSTR_P(bstr) (int)((bstr).len), (bstr).start - -#define WHITESPACE " \f\n\r\t\v" - -#endif /* MPLAYER_BSTR_H */ diff --git a/core/charset_conv.c b/core/charset_conv.c deleted file mode 100644 index 680c8f83f9..0000000000 --- a/core/charset_conv.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * This file is part of mpv. - * - * Based on code taken from libass (ISC license), which was originally part - * of MPlayer (GPL). - * Copyright (C) 2006 Evgeniy Stepanov - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include - -#include "config.h" - -#include "core/mp_msg.h" - -#ifdef CONFIG_ENCA -#include -#endif - -#ifdef CONFIG_LIBGUESS -#include -#endif - -#ifdef CONFIG_ICONV -#include -#endif - -#include "charset_conv.h" - -// Split the string on ':' into components. -// out_arr is at least max entries long. -// Return number of out_arr entries filled. -static int split_colon(const char *user_cp, int max, bstr *out_arr) -{ - if (!user_cp || max < 1) - return 0; - - int count = 0; - while (1) { - const char *next = strchr(user_cp, ':'); - if (next && max - count > 1) { - out_arr[count++] = (bstr){(char *)user_cp, next - user_cp}; - user_cp = next + 1; - } else { - out_arr[count++] = (bstr){(char *)user_cp, strlen(user_cp)}; - break; - } - } - return count; -} - -// Returns true if user_cp implies that calling mp_charset_guess() on the -// input data is required to determine the real codepage. This is the case -// if user_cp is not a real iconv codepage, but a magic value that requests -// for example ENCA charset auto-detection. -bool mp_charset_requires_guess(const char *user_cp) -{ - bstr res[2] = {{0}}; - split_colon(user_cp, 2, res); - return bstrcasecmp0(res[0], "enca") == 0 || - bstrcasecmp0(res[0], "guess") == 0; -} - -#ifdef CONFIG_ENCA -static const char *enca_guess(bstr buf, const char *language) -{ - if (!language || !language[0]) - language = "__"; // neutral language - - const char *detected_cp = NULL; - - EncaAnalyser analyser = enca_analyser_alloc(language); - if (analyser) { - enca_set_termination_strictness(analyser, 0); - EncaEncoding enc = enca_analyse_const(analyser, buf.start, buf.len); - const char *tmp = enca_charset_name(enc.charset, ENCA_NAME_STYLE_ICONV); - if (tmp && enc.charset != ENCA_CS_UNKNOWN) - detected_cp = tmp; - enca_analyser_free(analyser); - } else { - mp_msg(MSGT_SUBREADER, MSGL_ERR, "ENCA doesn't know language '%s'\n", - language); - size_t langcnt; - const char **languages = enca_get_languages(&langcnt); - mp_msg(MSGT_SUBREADER, MSGL_ERR, "ENCA supported languages:"); - for (int i = 0; i < langcnt; i++) - mp_msg(MSGT_SUBREADER, MSGL_ERR, " %s", languages[i]); - mp_msg(MSGT_SUBREADER, MSGL_ERR, "\n"); - free(languages); - } - - return detected_cp; -} -#endif - -#ifdef CONFIG_LIBGUESS -static const char *libguess_guess(bstr buf, const char *language) -{ - if (libguess_validate_utf8(buf.start, buf.len)) - return "UTF-8"; - - if (!language || !language[0] || strcmp(language, "help") == 0) { - mp_msg(MSGT_SUBREADER, MSGL_ERR, "libguess needs a language: " - "japanese taiwanese chinese korean russian arabic turkish " - "greek hebrew polish baltic\n"); - return NULL; - } - - return libguess_determine_encoding(buf.start, buf.len, language); -} -#endif - -// Runs charset auto-detection on the input buffer, and returns the result. -// If auto-detection fails, NULL is returned. -// If user_cp doesn't refer to any known auto-detection (for example because -// it's a real iconv codepage), user_cp is returned without even looking at -// the buf data. -const char *mp_charset_guess(bstr buf, const char *user_cp) -{ - if (!mp_charset_requires_guess(user_cp)) - return user_cp; - - bstr params[3] = {{0}}; - split_colon(user_cp, 3, params); - - bstr type = params[0]; - char lang[100]; - snprintf(lang, sizeof(lang), "%.*s", BSTR_P(params[1])); - const char *fallback = params[2].start; // last item, already 0-terminated - - const char *res = NULL; - -#ifdef CONFIG_ENCA - if (bstrcasecmp0(type, "enca") == 0) - res = enca_guess(buf, lang); -#endif -#ifdef CONFIG_LIBGUESS - if (bstrcasecmp0(type, "guess") == 0) - res = libguess_guess(buf, lang); -#endif - - if (res) { - mp_msg(MSGT_SUBREADER, MSGL_DBG2, "%.*s detected charset: '%s'\n", - BSTR_P(type), res); - } else { - res = fallback; - mp_msg(MSGT_SUBREADER, MSGL_DBG2, - "Detection with %.*s failed: fallback to %s\n", - BSTR_P(type), res && res[0] ? res : "no conversion"); - } - - return res; -} - -// Convert the data in buf to UTF-8. The charset argument can be an iconv -// codepage, a value returned by mp_charset_conv_guess(), or a special value -// that triggers autodetection of the charset (e.g. using ENCA). -// The auto-detection is the only difference to mp_iconv_to_utf8(). -// buf: same as mp_iconv_to_utf8() -// user_cp: iconv codepage, special value, NULL -// flags: same as mp_iconv_to_utf8() -// returns: same as mp_iconv_to_utf8() -bstr mp_charset_guess_and_conv_to_utf8(bstr buf, const char *user_cp, int flags) -{ - return mp_iconv_to_utf8(buf, mp_charset_guess(buf, user_cp), flags); -} - -// Use iconv to convert buf to UTF-8. -// Returns buf.start==NULL on error. Returns buf if cp is NULL, or if there is -// obviously no conversion required (e.g. if cp is "UTF-8"). -// Returns a newly allocated buffer if conversion is done and succeeds. The -// buffer will be terminated with 0 for convenience (the terminating 0 is not -// included in the returned length). -// Free the returned buffer with talloc_free(). -// buf: input data -// cp: iconv codepage (or NULL) -// flags: combination of MP_ICONV_* flags -// returns: buf (no conversion), .start==NULL (error), or allocated buffer -bstr mp_iconv_to_utf8(bstr buf, const char *cp, int flags) -{ -#ifdef CONFIG_ICONV - const char *tocp = "UTF-8"; - - if (!cp || !cp[0] || strcasecmp(cp, tocp) == 0) - return buf; - - if (strcasecmp(cp, "ASCII") == 0) - return buf; - - iconv_t icdsc; - if ((icdsc = iconv_open(tocp, cp)) == (iconv_t) (-1)) { - if (flags & MP_ICONV_VERBOSE) - mp_msg(MSGT_SUBREADER, MSGL_ERR, - "Error opening iconv with codepage '%s'\n", cp); - goto failure; - } - - size_t size = buf.len; - size_t osize = size; - size_t ileft = size; - size_t oleft = size - 1; - - char *outbuf = talloc_size(NULL, osize); - char *ip = buf.start; - char *op = outbuf; - - while (1) { - int clear = 0; - size_t rc; - if (ileft) - rc = iconv(icdsc, &ip, &ileft, &op, &oleft); - else { - clear = 1; // clear the conversion state and leave - rc = iconv(icdsc, NULL, NULL, &op, &oleft); - } - if (rc == (size_t) (-1)) { - if (errno == E2BIG) { - size_t offset = op - outbuf; - outbuf = talloc_realloc_size(NULL, outbuf, osize + size); - op = outbuf + offset; - osize += size; - oleft += size; - } else { - if (errno == EINVAL && (flags & MP_ICONV_ALLOW_CUTOFF)) { - // This is intended for cases where the input buffer is cut - // at a random byte position. If this happens in the middle - // of the buffer, it should still be an error. We say it's - // fine if the error is within 10 bytes of the end. - if (ileft <= 10) - break; - } - if (flags & MP_ICONV_VERBOSE) { - mp_msg(MSGT_SUBREADER, MSGL_ERR, - "Error recoding text with codepage '%s'\n", cp); - } - talloc_free(outbuf); - iconv_close(icdsc); - goto failure; - } - } else if (clear) - break; - } - - iconv_close(icdsc); - - outbuf[osize - oleft - 1] = 0; - return (bstr){outbuf, osize - oleft - 1}; -#endif - -failure: - return (bstr){0}; -} diff --git a/core/charset_conv.h b/core/charset_conv.h deleted file mode 100644 index 00a2658da3..0000000000 --- a/core/charset_conv.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MP_CHARSET_CONV_H -#define MP_CHARSET_CONV_H - -#include -#include "core/bstr.h" - -enum { - MP_ICONV_VERBOSE = 1, // print errors instead of failing silently - MP_ICONV_ALLOW_CUTOFF = 2, // allow partial input data -}; - -bool mp_charset_requires_guess(const char *user_cp); -const char *mp_charset_guess(bstr buf, const char *user_cp); -bstr mp_charset_guess_and_conv_to_utf8(bstr buf, const char *user_cp, int flags); -bstr mp_iconv_to_utf8(bstr buf, const char *cp, int flags); - -#endif diff --git a/core/codecs.c b/core/codecs.c deleted file mode 100644 index 943860a70b..0000000000 --- a/core/codecs.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include "core/mp_talloc.h" -#include "core/bstr.h" -#include "core/mp_msg.h" -#include "codecs.h" - -void mp_add_decoder(struct mp_decoder_list *list, const char *family, - const char *codec, const char *decoder, const char *desc) -{ - struct mp_decoder_entry entry = { - .family = talloc_strdup(list, family), - .codec = talloc_strdup(list, codec), - .decoder = talloc_strdup(list, decoder), - .desc = talloc_strdup(list, desc), - }; - MP_TARRAY_APPEND(list, list->entries, list->num_entries, entry); -} - -static void mp_add_decoder_entry(struct mp_decoder_list *list, - struct mp_decoder_entry *entry) -{ - mp_add_decoder(list, entry->family, entry->codec, entry->decoder, - entry->desc); -} - -static struct mp_decoder_entry *find_decoder(struct mp_decoder_list *list, - bstr family, bstr decoder) -{ - for (int n = 0; n < list->num_entries; n++) { - struct mp_decoder_entry *cur = &list->entries[n]; - if (bstr_equals0(decoder, cur->decoder) && - bstr_equals0(family, cur->family)) - return cur; - } - return NULL; -} - -// Add entry, but only if it's not yet on the list, and if the codec matches. -// If codec == NULL, don't compare codecs. -static void add_new(struct mp_decoder_list *to, struct mp_decoder_entry *entry, - const char *codec) -{ - if (!entry || (codec && strcmp(entry->codec, codec) != 0)) - return; - if (!find_decoder(to, bstr0(entry->family), bstr0(entry->decoder))) - mp_add_decoder_entry(to, entry); -} - -// Select a decoder from the given list for the given codec. The selection -// can be influenced by the selection string, which can specify a priority -// list of preferred decoders. -// This returns a list of decoders to try, with the preferred decoders first. -// The selection string corresponds to --vd/--ad directly, and has the -// following syntax: -// selection = [ ("," )*] -// entry = ":" // prefer decoder -// entry = ":*" // prefer all decoders -// entry = "+" ":" // force a decoder -// entry = "-" ":" // exclude a decoder -// entry = "-" // don't add fallback decoders -// Forcing a decoder means it's added even if the codec mismatches. -struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, - const char *codec, - const char *selection) -{ - struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); - struct mp_decoder_list *remove = talloc_zero(NULL, struct mp_decoder_list); - if (!codec) - codec = "unknown"; - bool stop = false; - bstr sel = bstr0(selection); - while (sel.len) { - bstr entry; - bstr_split_tok(sel, ",", &entry, &sel); - if (bstr_equals0(entry, "-")) { - stop = true; - break; - } - bool force = bstr_eatstart0(&entry, "+"); - bool exclude = !force && bstr_eatstart0(&entry, "-"); - struct mp_decoder_list *dest = exclude ? remove : list; - bstr family, decoder; - if (!bstr_split_tok(entry, ":", &family, &decoder)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Decoders must be specified as " - "'family:decoder' for the --ad/--vd options.\n"); - break; - } - if (bstr_equals0(decoder, "*")) { - for (int n = 0; n < all->num_entries; n++) { - struct mp_decoder_entry *cur = &all->entries[n]; - if (bstr_equals0(family, cur->family)) - add_new(dest, cur, codec); - } - } else { - add_new(dest, find_decoder(all, family, decoder), - force ? NULL : codec); - } - } - if (!stop) { - // Add the remaining codecs which haven't been added yet - for (int n = 0; n < all->num_entries; n++) - add_new(list, &all->entries[n], codec); - } - for (int n = 0; n < remove->num_entries; n++) { - struct mp_decoder_entry *ex = &remove->entries[n]; - struct mp_decoder_entry *del = - find_decoder(list, bstr0(ex->family), bstr0(ex->decoder)); - if (del) { - int index = del - &list->entries[0]; - MP_TARRAY_REMOVE_AT(list->entries, list->num_entries, index); - } - } - talloc_free(remove); - return list; -} - -void mp_print_decoders(int msgt, int msgl, const char *header, - struct mp_decoder_list *list) -{ - mp_msg(msgt, msgl, "%s\n", header); - for (int n = 0; n < list->num_entries; n++) { - struct mp_decoder_entry *entry = &list->entries[n]; - mp_msg(msgt, msgl, " %s:%s", entry->family, entry->decoder); - if (strcmp(entry->decoder, entry->codec) != 0) - mp_msg(msgt, msgl, " (%s)", entry->codec); - mp_msg(msgt, msgl, " - %s\n", entry->desc); - } - if (list->num_entries == 0) - mp_msg(msgt, msgl, " (no decoders)\n"); -} diff --git a/core/codecs.h b/core/codecs.h deleted file mode 100644 index 21ff284617..0000000000 --- a/core/codecs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MP_CODECS_H -#define MP_CODECS_H - -struct mp_decoder_entry { - const char *family; // decoder module (e.g. ad_lavc => "lavc") - const char *codec; // name of the codec (e.g. "mp3") - const char *decoder; // decoder name (e.g. "mp3float") - const char *desc; // human readable description -}; - -struct mp_decoder_list { - struct mp_decoder_entry *entries; - int num_entries; -}; - -void mp_add_decoder(struct mp_decoder_list *list, const char *family, - const char *codec, const char *decoder, const char *desc); - -struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, - const char *codec, - const char *selection); - -void mp_print_decoders(int msgt, int msgl, const char *header, - struct mp_decoder_list *list); - -#endif diff --git a/core/command.c b/core/command.c deleted file mode 100644 index b7718e41b7..0000000000 --- a/core/command.c +++ /dev/null @@ -1,2673 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "config.h" -#include "talloc.h" -#include "command.h" -#include "input/input.h" -#include "stream/stream.h" -#include "demux/demux.h" -#include "demux/stheader.h" -#include "resolve.h" -#include "playlist.h" -#include "playlist_parser.h" -#include "sub/sub.h" -#include "sub/dec_sub.h" -#include "core/m_option.h" -#include "m_property.h" -#include "m_config.h" -#include "video/filter/vf.h" -#include "video/decode/vd.h" -#include "mp_osd.h" -#include "video/out/vo.h" -#include "video/csputils.h" -#include "playlist.h" -#include "audio/mixer.h" -#include "audio/out/ao.h" -#include "core/mp_common.h" -#include "audio/filter/af.h" -#include "video/decode/dec_video.h" -#include "audio/decode/dec_audio.h" -#include "core/path.h" -#include "stream/tv.h" -#include "stream/stream_radio.h" -#include "stream/pvr.h" -#ifdef CONFIG_DVBIN -#include "stream/dvbin.h" -#endif -#ifdef CONFIG_DVDREAD -#include "stream/stream_dvd.h" -#endif -#include "screenshot.h" - -#include "core/mp_core.h" - -static void change_video_filters(MPContext *mpctx, const char *cmd, - const char *arg); -static int set_filters(struct MPContext *mpctx, enum stream_type mediatype, - struct m_obj_settings *new_chain); - -static char *format_bitrate(int rate) -{ - return talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000); -} - -static char *format_delay(double time) -{ - return talloc_asprintf(NULL, "%d ms", ROUND(time * 1000)); -} - -// Get current mouse position in OSD coordinate space. -void mp_get_osd_mouse_pos(struct MPContext *mpctx, float *x, float *y) -{ - int wx, wy; - mp_input_get_mouse_pos(mpctx->input, &wx, &wy); - float p[2] = {wx, wy}; - // Raw window coordinates (VO mouse events) to OSD resolution. - if (mpctx->video_out) - vo_control(mpctx->video_out, VOCTRL_WINDOW_TO_OSD_COORDS, p); - *x = p[0]; - *y = p[1]; -} - -// Property-option bridge. -static int mp_property_generic_option(struct m_option *prop, int action, - void *arg, MPContext *mpctx) -{ - char *optname = prop->priv; - struct m_config_option *opt = m_config_get_co(mpctx->mconfig, - bstr0(optname)); - void *valptr = opt->data; - - switch (action) { - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = *(opt->opt); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - m_option_copy(opt->opt, arg, valptr); - return M_PROPERTY_OK; - case M_PROPERTY_SET: - m_option_copy(opt->opt, valptr, arg); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Playback speed (RW) -static int mp_property_playback_speed(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct MPOpts *opts = mpctx->opts; - double orig_speed = opts->playback_speed; - switch (action) { - case M_PROPERTY_SET: { - opts->playback_speed = *(double *) arg; - // Adjust time until next frame flip for nosound mode - mpctx->time_frame *= orig_speed / opts->playback_speed; - if (mpctx->sh_audio) - reinit_audio_chain(mpctx); - return M_PROPERTY_OK; - } - case M_PROPERTY_PRINT: - *(char **)arg = talloc_asprintf(NULL, "x %6.2f", orig_speed); - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// filename with path (RO) -static int mp_property_path(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->filename) - return M_PROPERTY_UNAVAILABLE; - return m_property_strdup_ro(prop, action, arg, mpctx->filename); -} - -static int mp_property_filename(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->filename) - return M_PROPERTY_UNAVAILABLE; - char *f = (char *)mp_basename(mpctx->filename); - return m_property_strdup_ro(prop, action, arg, (*f) ? f : mpctx->filename); -} - -static int mp_property_media_title(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - char *name = NULL; - if (mpctx->resolve_result) - name = mpctx->resolve_result->title; - if (name && name[0]) - return m_property_strdup_ro(prop, action, arg, name); - if (mpctx->master_demuxer) { - name = demux_info_get(mpctx->master_demuxer, "title"); - if (name && name[0]) - return m_property_strdup_ro(prop, action, arg, name); - } - return mp_property_filename(prop, action, arg, mpctx); -} - -static int mp_property_stream_path(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct stream *stream = mpctx->stream; - if (!stream || !stream->url) - return M_PROPERTY_UNAVAILABLE; - return m_property_strdup_ro(prop, action, arg, stream->url); -} - -static int mp_property_stream_capture(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->stream) - return M_PROPERTY_UNAVAILABLE; - - if (action == M_PROPERTY_SET) { - char *filename = *(char **)arg; - stream_set_capture_file(mpctx->stream, filename); - // fall through to mp_property_generic_option - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Demuxer name (RO) -static int mp_property_demuxer(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - return m_property_strdup_ro(prop, action, arg, demuxer->desc->name); -} - -/// Position in the stream (RW) -static int mp_property_stream_pos(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct stream *stream = mpctx->stream; - if (!stream) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_GET: - *(int64_t *) arg = stream_tell(stream); - return M_PROPERTY_OK; - case M_PROPERTY_SET: - stream_seek(stream, *(int64_t *) arg); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Stream start offset (RO) -static int mp_property_stream_start(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct stream *stream = mpctx->stream; - if (!stream) - return M_PROPERTY_UNAVAILABLE; - return m_property_int64_ro(prop, action, arg, stream->start_pos); -} - -/// Stream end offset (RO) -static int mp_property_stream_end(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct stream *stream = mpctx->stream; - if (!stream) - return M_PROPERTY_UNAVAILABLE; - return m_property_int64_ro(prop, action, arg, stream->end_pos); -} - -/// Stream length (RO) -static int mp_property_stream_length(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct stream *stream = mpctx->stream; - if (!stream) - return M_PROPERTY_UNAVAILABLE; - return m_property_int64_ro(prop, action, arg, - stream->end_pos - stream->start_pos); -} - -// Does some magic to handle "/full" as time formatted with milliseconds. -// Assumes prop is the type of the actual property. -static int property_time(m_option_t *prop, int action, void *arg, double time) -{ - switch (action) { - case M_PROPERTY_GET: - *(double *)arg = time; - return M_PROPERTY_OK; - case M_PROPERTY_KEY_ACTION: { - struct m_property_action_arg *ka = arg; - - if (strcmp(ka->key, "full") != 0) - return M_PROPERTY_UNKNOWN; - - switch (ka->action) { - case M_PROPERTY_GET: - *(double *)ka->arg = time; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: - *(char **)ka->arg = mp_format_time(time, true); - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: - *(struct m_option *)ka->arg = *prop; - return M_PROPERTY_OK; - } - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Current stream position in seconds (RO) -static int mp_property_stream_time_pos(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - double pts = demuxer->stream_pts; - if (pts == MP_NOPTS_VALUE) - return M_PROPERTY_UNAVAILABLE; - - return property_time(prop, action, arg, pts); -} - - -/// Media length in seconds (RO) -static int mp_property_length(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - double len; - - if (!(int) (len = get_time_length(mpctx))) - return M_PROPERTY_UNAVAILABLE; - - return property_time(prop, action, arg, len); -} - -static int mp_property_avsync(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_audio || !mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - return m_property_double_ro(prop, action, arg, mpctx->last_av_difference); -} - -/// Current position in percent (RW) -static int mp_property_percent_pos(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->num_sources) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SET: ; - double pos = *(double *)arg; - queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(double *)arg = get_current_pos_ratio(mpctx, false) * 100.0; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: - *(char **)arg = talloc_asprintf(NULL, "%d", get_percent_pos(mpctx)); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Current position in seconds (RW) -static int mp_property_time_pos(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->num_sources) - return M_PROPERTY_UNAVAILABLE; - - if (action == M_PROPERTY_SET) { - queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0); - return M_PROPERTY_OK; - } - return property_time(prop, action, arg, get_current_time(mpctx)); -} - -static int mp_property_remaining(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - double len = get_time_length(mpctx); - double pos = get_current_time(mpctx); - double start = get_start_time(mpctx); - - if (!(int)len) - return M_PROPERTY_UNAVAILABLE; - - return property_time(prop, action, arg, len - (pos - start)); -} - -/// Current chapter (RW) -static int mp_property_chapter(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - int chapter = get_current_chapter(mpctx); - if (chapter < -1) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: - *(int *) arg = chapter; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: { - char *chapter_name = chapter_display_name(mpctx, chapter); - if (!chapter_name) - return M_PROPERTY_UNAVAILABLE; - *(char **) arg = chapter_name; - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: ; - int step_all = *(int *)arg - chapter; - chapter += step_all; - if (chapter >= get_chapter_count(mpctx) && step_all > 0) { - mpctx->stop_play = PT_NEXT_ENTRY; - } else { - mp_seek_chapter(mpctx, chapter); - } - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_list_chapters(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action == M_PROPERTY_GET) { - int count = get_chapter_count(mpctx); - int cur = mpctx->num_sources ? get_current_chapter(mpctx) : -1; - char *res = NULL; - int n; - - if (count < 1) { - res = talloc_asprintf_append(res, "No chapters."); - } - - for (n = 0; n < count; n++) { - char *name = chapter_display_name(mpctx, n); - double t = chapter_start_time(mpctx, n); - char* time = mp_format_time(t, false); - res = talloc_asprintf_append(res, "%s", time); - talloc_free(time); - char *m1 = "> ", *m2 = " <"; - if (n != cur) - m1 = m2 = ""; - res = talloc_asprintf_append(res, " %s%s%s\n", m1, name, m2); - talloc_free(name); - } - - *(char **)arg = res; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_edition(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct MPOpts *opts = mpctx->opts; - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - if (demuxer->num_editions <= 0) - return M_PROPERTY_UNAVAILABLE; - - int edition = demuxer->edition; - - switch (action) { - case M_PROPERTY_GET: - *(int *)arg = edition; - return M_PROPERTY_OK; - case M_PROPERTY_SET: { - edition = *(int *)arg; - if (edition != demuxer->edition) { - opts->edition_id = edition; - mpctx->stop_play = PT_RESTART; - } - return M_PROPERTY_OK; - } - case M_PROPERTY_GET_TYPE: { - struct m_option opt = { - .name = prop->name, - .type = CONF_TYPE_INT, - .flags = CONF_RANGE, - .min = 0, - .max = demuxer->num_editions - 1, - }; - *(struct m_option *)arg = opt; - return M_PROPERTY_OK; - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static struct mp_resolve_src *find_source(struct mp_resolve_result *res, - char *url) -{ - if (res->num_srcs == 0) - return NULL; - - int src = 0; - for (int n = 0; n < res->num_srcs; n++) { - if (strcmp(res->srcs[n]->url, res->url) == 0) { - src = n; - break; - } - } - return res->srcs[src]; -} - -static int mp_property_quvi_format(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct mp_resolve_result *res = mpctx->resolve_result; - if (!res || !res->num_srcs) - return M_PROPERTY_UNAVAILABLE; - - struct mp_resolve_src *cur = find_source(res, res->url); - if (!cur) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: - *(char **)arg = talloc_strdup(NULL, cur->encid); - return M_PROPERTY_OK; - case M_PROPERTY_SET: { - mpctx->stop_play = PT_RESTART; - break; - } - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sarg = arg; - int pos = 0; - for (int n = 0; n < res->num_srcs; n++) { - if (res->srcs[n] == cur) { - pos = n; - break; - } - } - pos += sarg->inc; - if (pos < 0 || pos >= res->num_srcs) { - if (sarg->wrap) { - pos = (res->num_srcs + pos) % res->num_srcs; - } else { - pos = av_clip(pos, 0, res->num_srcs); - } - } - char *fmt = res->srcs[pos]->encid; - return mp_property_quvi_format(prop, M_PROPERTY_SET, &fmt, mpctx); - } - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Number of titles in file -static int mp_property_titles(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - int num_titles = 0; - stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_TITLES, &num_titles); - return m_property_int_ro(prop, action, arg, num_titles); -} - -/// Number of chapters in file -static int mp_property_chapters(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->num_sources) - return M_PROPERTY_UNAVAILABLE; - int count = get_chapter_count(mpctx); - return m_property_int_ro(prop, action, arg, count); -} - -static int mp_property_editions(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - if (demuxer->num_editions <= 0) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(prop, action, arg, demuxer->num_editions); -} - -/// Current dvd angle (RW) -static int mp_property_angle(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->master_demuxer; - int angle = -1; - int angles; - - if (demuxer) - angle = demuxer_get_current_angle(demuxer); - if (angle < 0) - return M_PROPERTY_UNAVAILABLE; - angles = demuxer_angles_count(demuxer); - if (angles <= 1) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: - *(int *) arg = angle; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: { - *(char **) arg = talloc_asprintf(NULL, "%d/%d", angle, angles); - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: - angle = demuxer_set_angle(demuxer, *(int *)arg); - if (angle >= 0) { - if (mpctx->sh_video) - resync_video_stream(mpctx->sh_video); - - if (mpctx->sh_audio) - resync_audio_stream(mpctx->sh_audio); - } - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: { - struct m_option opt = { - .name = prop->name, - .type = CONF_TYPE_INT, - .flags = CONF_RANGE, - .min = 1, - .max = angles, - }; - *(struct m_option *)arg = opt; - return M_PROPERTY_OK; - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Demuxer meta data -static int mp_property_metadata(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - - static const m_option_t key_type = - { - "metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL - }; - - switch (action) { - case M_PROPERTY_GET: { - char **slist = NULL; - m_option_copy(prop, &slist, &demuxer->info); - *(char ***)arg = slist; - return M_PROPERTY_OK; - } - case M_PROPERTY_PRINT: { - char **list = demuxer->info; - char *res = NULL; - for (int n = 0; list && list[n]; n += 2) { - res = talloc_asprintf_append_buffer(res, "%s: %s\n", - list[n], list[n + 1]); - } - *(char **)arg = res; - return res ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE; - } - case M_PROPERTY_KEY_ACTION: { - struct m_property_action_arg *ka = arg; - char *meta = demux_info_get(demuxer, ka->key); - if (!meta) - return M_PROPERTY_UNKNOWN; - switch (ka->action) { - case M_PROPERTY_GET: - *(char **)ka->arg = talloc_strdup(NULL, meta); - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: - *(struct m_option *)ka->arg = key_type; - return M_PROPERTY_OK; - } - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_pause(m_option_t *prop, int action, void *arg, - void *ctx) -{ - MPContext *mpctx = ctx; - - if (action == M_PROPERTY_SET) { - if (*(int *)arg) { - pause_player(mpctx); - } else { - unpause_player(mpctx); - } - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, ctx); -} - -static int mp_property_cache(m_option_t *prop, int action, void *arg, - void *ctx) -{ - MPContext *mpctx = ctx; - int cache = mp_get_cache_percent(mpctx); - if (cache < 0) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(prop, action, arg, cache); -} - -static int mp_property_clock(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - char outstr[6]; - time_t t = time(NULL); - struct tm *tmp = localtime(&t); - - if ((tmp != NULL) && (strftime(outstr, sizeof(outstr), "%H:%M", tmp) == 5)) - return m_property_strdup_ro(prop, action, arg, outstr); - return M_PROPERTY_UNAVAILABLE; -} - -/// Volume (RW) -static int mp_property_volume(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - - if (!mpctx->sh_audio) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: - mixer_getbothvolume(&mpctx->mixer, arg); - return M_PROPERTY_OK; - case M_PROPERTY_SET: - mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg); - return M_PROPERTY_OK; - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sarg = arg; - if (sarg->inc <= 0) - mixer_decvolume(&mpctx->mixer); - else - mixer_incvolume(&mpctx->mixer); - return M_PROPERTY_OK; - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Mute (RW) -static int mp_property_mute(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - - if (!mpctx->sh_audio) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SET: - mixer_setmute(&mpctx->mixer, *(int *) arg); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = mixer_getmute(&mpctx->mixer); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Audio delay (RW) -static int mp_property_audio_delay(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!(mpctx->sh_audio && mpctx->sh_video)) - return M_PROPERTY_UNAVAILABLE; - float delay = mpctx->opts->audio_delay; - switch (action) { - case M_PROPERTY_PRINT: - *(char **)arg = format_delay(delay); - return M_PROPERTY_OK; - case M_PROPERTY_SET: - mpctx->audio_delay = mpctx->opts->audio_delay = *(float *)arg; - mpctx->delay -= mpctx->audio_delay - delay; - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Audio codec tag (RO) -static int mp_property_audio_format(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - const char *c = mpctx->sh_audio ? mpctx->sh_audio->gsh->codec : NULL; - return m_property_strdup_ro(prop, action, arg, c); -} - -/// Audio codec name (RO) -static int mp_property_audio_codec(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - const char *c = mpctx->sh_audio ? mpctx->sh_audio->gsh->decoder_desc : NULL; - return m_property_strdup_ro(prop, action, arg, c); -} - -/// Audio bitrate (RO) -static int mp_property_audio_bitrate(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->sh_audio) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_PRINT: - *(char **)arg = format_bitrate(mpctx->sh_audio->i_bps); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = mpctx->sh_audio->i_bps; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Samplerate (RO) -static int mp_property_samplerate(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_audio) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_PRINT: - *(char **)arg = talloc_asprintf(NULL, "%d kHz", - mpctx->sh_audio->samplerate / 1000); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = mpctx->sh_audio->samplerate; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Number of channels (RO) -static int mp_property_channels(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_audio) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_PRINT: - *(char **) arg = mp_chmap_to_str(&mpctx->sh_audio->channels); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = mpctx->sh_audio->channels.num; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Balance (RW) -static int mp_property_balance(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - float bal; - - switch (action) { - case M_PROPERTY_GET: - mixer_getbalance(&mpctx->mixer, arg); - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: { - char **str = arg; - mixer_getbalance(&mpctx->mixer, &bal); - if (bal == 0.f) - *str = talloc_strdup(NULL, "center"); - else if (bal == -1.f) - *str = talloc_strdup(NULL, "left only"); - else if (bal == 1.f) - *str = talloc_strdup(NULL, "right only"); - else { - unsigned right = (bal + 1.f) / 2.f * 100.f; - *str = talloc_asprintf(NULL, "left %d%%, right %d%%", - 100 - right, right); - } - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: - mixer_setbalance(&mpctx->mixer, *(float *)arg); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static struct track* track_next(struct MPContext *mpctx, enum stream_type type, - int direction, struct track *track) -{ - assert(direction == -1 || direction == +1); - struct track *prev = NULL, *next = NULL; - bool seen = track == NULL; - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *cur = mpctx->tracks[n]; - if (cur->type == type) { - if (cur == track) { - seen = true; - } else { - if (seen && !next) { - next = cur; - } - if (!seen || !track) { - prev = cur; - } - } - } - } - return direction > 0 ? next : prev; -} - -static int property_switch_track(m_option_t *prop, int action, void *arg, - MPContext *mpctx, enum stream_type type) -{ - if (!mpctx->num_sources) - return M_PROPERTY_UNAVAILABLE; - struct track *track = mpctx->current_track[type]; - - switch (action) { - case M_PROPERTY_GET: - *(int *) arg = track ? track->user_tid : -2; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: - if (!track) - *(char **) arg = talloc_strdup(NULL, "no"); - else { - char *lang = track->lang; - if (!lang) - lang = mp_gtext("unknown"); - - if (track->title) - *(char **)arg = talloc_asprintf(NULL, "(%d) %s (\"%s\")", - track->user_tid, lang, track->title); - else - *(char **)arg = talloc_asprintf(NULL, "(%d) %s", - track->user_tid, lang); - } - return M_PROPERTY_OK; - - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sarg = arg; - mp_switch_track(mpctx, type, - track_next(mpctx, type, sarg->inc >= 0 ? +1 : -1, track)); - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: - mp_switch_track(mpctx, type, mp_track_by_tid(mpctx, type, *(int *)arg)); - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -static const char *track_type_name(enum stream_type t) -{ - switch (t) { - case STREAM_VIDEO: return "Video"; - case STREAM_AUDIO: return "Audio"; - case STREAM_SUB: return "Sub"; - } - return NULL; -} - -static int property_list_tracks(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action == M_PROPERTY_GET) { - char *res = NULL; - - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *track = mpctx->tracks[n]; - if (track->type != type) - continue; - - bool selected = mpctx->current_track[track->type] == track; - res = talloc_asprintf_append(res, "%s: ", - track_type_name(track->type)); - if (selected) - res = talloc_asprintf_append(res, "> "); - res = talloc_asprintf_append(res, "(%d) ", track->user_tid); - if (track->title) - res = talloc_asprintf_append(res, "'%s' ", track->title); - if (track->lang) - res = talloc_asprintf_append(res, "(%s) ", track->lang); - if (track->is_external) - res = talloc_asprintf_append(res, "(external) "); - if (selected) - res = talloc_asprintf_append(res, "<"); - res = talloc_asprintf_append(res, "\n"); - } - - res = talloc_asprintf_append(res, "\n"); - } - - struct demuxer *demuxer = mpctx->master_demuxer; - if (demuxer && demuxer->num_editions > 1) - res = talloc_asprintf_append(res, "\nEdition: %d of %d\n", - demuxer->edition + 1, - demuxer->num_editions); - - *(char **)arg = res; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// Selected audio id (RW) -static int mp_property_audio(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_switch_track(prop, action, arg, mpctx, STREAM_AUDIO); -} - -/// Selected video id (RW) -static int mp_property_video(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_switch_track(prop, action, arg, mpctx, STREAM_VIDEO); -} - -static struct track *find_track_by_demuxer_id(MPContext *mpctx, - enum stream_type type, - int demuxer_id) -{ - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *track = mpctx->tracks[n]; - if (track->type == type && track->demuxer_id == demuxer_id) - return track; - } - return NULL; -} - -static int mp_property_program(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - demux_program_t prog; - - struct demuxer *demuxer = mpctx->master_demuxer; - if (!demuxer) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SWITCH: - case M_PROPERTY_SET: - if (action == M_PROPERTY_SET && arg) - prog.progid = *((int *) arg); - else - prog.progid = -1; - if (demux_control(demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM, &prog) == - DEMUXER_CTRL_NOTIMPL) - return M_PROPERTY_ERROR; - - if (prog.aid < 0 && prog.vid < 0) { - mp_msg(MSGT_CPLAYER, MSGL_ERR, - "Selected program contains no audio or video streams!\n"); - return M_PROPERTY_ERROR; - } - mp_switch_track(mpctx, STREAM_VIDEO, - find_track_by_demuxer_id(mpctx, STREAM_VIDEO, prog.vid)); - mp_switch_track(mpctx, STREAM_AUDIO, - find_track_by_demuxer_id(mpctx, STREAM_AUDIO, prog.aid)); - mp_switch_track(mpctx, STREAM_SUB, - find_track_by_demuxer_id(mpctx, STREAM_VIDEO, prog.sid)); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - - -/// Fullscreen state (RW) -static int mp_property_fullscreen(m_option_t *prop, - int action, - void *arg, - MPContext *mpctx) -{ - if (!mpctx->video_out) - return M_PROPERTY_UNAVAILABLE; - struct mp_vo_opts *opts = mpctx->video_out->opts; - - if (action == M_PROPERTY_SET) { - int val = *(int *)arg; - opts->fullscreen = val; - if (mpctx->video_out->config_ok) - vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0); - return opts->fullscreen == val ? M_PROPERTY_OK : M_PROPERTY_ERROR; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -#define VF_DEINTERLACE_LABEL "deinterlace" - -#ifdef CONFIG_VF_LAVFI -#define VF_DEINTERLACE "@" VF_DEINTERLACE_LABEL ":lavfi=yadif" -#else -#define VF_DEINTERLACE "@" VF_DEINTERLACE_LABEL ":yadif" -#endif - -static int get_deinterlacing(struct MPContext *mpctx) -{ - vf_instance_t *vf = mpctx->sh_video->vfilter; - int enabled = 0; - if (vf->control(vf, VFCTRL_GET_DEINTERLACE, &enabled) != CONTROL_OK) - enabled = -1; - if (enabled < 0) { - // vf_lavfi doesn't support VFCTRL_GET_DEINTERLACE - if (vf_find_by_label(vf, VF_DEINTERLACE_LABEL)) - enabled = 1; - } - return enabled; -} - -static void set_deinterlacing(struct MPContext *mpctx, bool enable) -{ - vf_instance_t *vf = mpctx->sh_video->vfilter; - if (vf_find_by_label(vf, VF_DEINTERLACE_LABEL)) { - if (!enable) - change_video_filters(mpctx, "del", VF_DEINTERLACE); - } else { - int arg = enable; - if (vf->control(vf, VFCTRL_SET_DEINTERLACE, &arg) != CONTROL_OK) - change_video_filters(mpctx, "add", VF_DEINTERLACE); - } -} - -static int mp_property_deinterlace(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->sh_video || !mpctx->sh_video->vfilter) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_GET: - *(int *)arg = get_deinterlacing(mpctx) > 0; - return M_PROPERTY_OK; - case M_PROPERTY_SET: - set_deinterlacing(mpctx, *(int *)arg); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -// Generic option + requires hard refresh to make changes take effect. -static int video_refresh_property_helper(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - int r = mp_property_generic_option(prop, action, arg, mpctx); - if (action == M_PROPERTY_SET) { - if (mpctx->sh_video) { - reinit_video_filters(mpctx); - mp_force_video_refresh(mpctx); - } - } - return r; -} - -static int mp_property_colormatrix(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action != M_PROPERTY_PRINT) - return video_refresh_property_helper(prop, action, arg, mpctx); - - struct MPOpts *opts = mpctx->opts; - - struct mp_csp_details vo_csp = {0}; - if (mpctx->sh_video && mpctx->sh_video->vfilter) - vf_control(mpctx->sh_video->vfilter, VFCTRL_GET_YUV_COLORSPACE, &vo_csp); - - struct mp_image_params vd_csp = {0}; - if (mpctx->sh_video) - vd_control(mpctx->sh_video, VDCTRL_GET_PARAMS, &vd_csp); - - char *res = talloc_asprintf(NULL, "%s", - mp_csp_names[opts->requested_colorspace]); - if (!vo_csp.format) { - res = talloc_asprintf_append(res, " (VO: unknown)"); - } else if (vo_csp.format != opts->requested_colorspace) { - res = talloc_asprintf_append(res, " (VO: %s)", - mp_csp_names[vo_csp.format]); - } - if (!vd_csp.colorspace) { - res = talloc_asprintf_append(res, " (VD: unknown)"); - } else if (!vo_csp.format || vd_csp.colorspace != vo_csp.format) { - res = talloc_asprintf_append(res, " (VD: %s)", - mp_csp_names[vd_csp.colorspace]); - } - *(char **)arg = res; - return M_PROPERTY_OK; -} - -static int mp_property_colormatrix_input_range(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (action != M_PROPERTY_PRINT) - return video_refresh_property_helper(prop, action, arg, mpctx); - - struct MPOpts *opts = mpctx->opts; - - struct mp_csp_details vo_csp = {0}; - if (mpctx->sh_video && mpctx->sh_video->vfilter) - vf_control(mpctx->sh_video->vfilter, VFCTRL_GET_YUV_COLORSPACE, &vo_csp ); - - struct mp_image_params vd_csp = {0}; - if (mpctx->sh_video) - vd_control(mpctx->sh_video, VDCTRL_GET_PARAMS, &vd_csp); - - char *res = talloc_asprintf(NULL, "%s", - mp_csp_levels_names[opts->requested_input_range]); - if (!vo_csp.levels_in) { - res = talloc_asprintf_append(res, " (VO: unknown)"); - } else if (vo_csp.levels_in != opts->requested_input_range) { - res = talloc_asprintf_append(res, " (VO: %s)", - mp_csp_levels_names[vo_csp.levels_in]); - } - if (!vd_csp.colorlevels) { - res = talloc_asprintf_append(res, " (VD: unknown)"); - } else if (!vo_csp.levels_in || vd_csp.colorlevels != vo_csp.levels_in) { - res = talloc_asprintf_append(res, " (VD: %s)", - mp_csp_levels_names[vd_csp.colorlevels]); - } - *(char **)arg = res; - return M_PROPERTY_OK; -} - -static int mp_property_colormatrix_output_range(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (action != M_PROPERTY_PRINT) { - int r = mp_property_generic_option(prop, action, arg, mpctx); - if (action == M_PROPERTY_SET) { - if (mpctx->sh_video) - set_video_output_levels(mpctx->sh_video); - } - return r; - } - - struct MPOpts *opts = mpctx->opts; - - int req = opts->requested_output_range; - struct mp_csp_details actual = {0}; - if (mpctx->sh_video && mpctx->sh_video->vfilter) - vf_control(mpctx->sh_video->vfilter, VFCTRL_GET_YUV_COLORSPACE, &actual); - - char *res = talloc_asprintf(NULL, "%s", mp_csp_levels_names[req]); - if (!actual.levels_out) { - res = talloc_asprintf_append(res, " (Actual: unknown)"); - } else if (actual.levels_out != req) { - res = talloc_asprintf_append(res, " (Actual: %s)", - mp_csp_levels_names[actual.levels_out]); - } - *(char **)arg = res; - return M_PROPERTY_OK; -} - -/// Panscan (RW) -static int mp_property_panscan(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - - if (!mpctx->video_out - || vo_control(mpctx->video_out, VOCTRL_GET_PANSCAN, NULL) != VO_TRUE) - return M_PROPERTY_UNAVAILABLE; - - int r = mp_property_generic_option(prop, action, arg, mpctx); - if (action == M_PROPERTY_SET) - vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL); - return r; -} - -/// Helper to set vo flags. -/** \ingroup PropertyImplHelper - */ -static int mp_property_vo_flag(m_option_t *prop, int action, void *arg, - int vo_ctrl, int *vo_var, MPContext *mpctx) -{ - - if (!mpctx->video_out) - return M_PROPERTY_UNAVAILABLE; - - if (action == M_PROPERTY_SET) { - if (*vo_var == !!*(int *) arg) - return M_PROPERTY_OK; - if (mpctx->video_out->config_ok) - vo_control(mpctx->video_out, vo_ctrl, 0); - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Window always on top (RW) -static int mp_property_ontop(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return mp_property_vo_flag(prop, action, arg, VOCTRL_ONTOP, - &mpctx->opts->vo.ontop, mpctx); -} - -/// Show window borders (RW) -static int mp_property_border(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return mp_property_vo_flag(prop, action, arg, VOCTRL_BORDER, - &mpctx->opts->vo.border, mpctx); -} - -static int mp_property_framedrop(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Color settings, try to use vf/vo then fall back on TV. (RW) -static int mp_property_gamma(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - int *gamma = (int *)((char *)mpctx->opts + prop->offset); - int r, val; - - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - - if (gamma[0] == 1000) { - gamma[0] = 0; - get_video_colors(mpctx->sh_video, prop->name, gamma); - } - - switch (action) { - case M_PROPERTY_SET: - *gamma = *(int *) arg; - r = set_video_colors(mpctx->sh_video, prop->name, *gamma); - if (r <= 0) - break; - return r; - case M_PROPERTY_GET: - if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) { - *(int *)arg = val; - return M_PROPERTY_OK; - } - break; - default: - return mp_property_generic_option(prop, action, arg, mpctx); - } - -#ifdef CONFIG_TV - if (mpctx->sh_video->gsh->demuxer->type == DEMUXER_TYPE_TV) { - int l = strlen(prop->name); - char tv_prop[3 + l + 1]; - sprintf(tv_prop, "tv-%s", prop->name); - return mp_property_do(tv_prop, action, arg, mpctx); - } -#endif - - return M_PROPERTY_UNAVAILABLE; -} - -/// Video codec tag (RO) -static int mp_property_video_format(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - const char *c = mpctx->sh_video ? mpctx->sh_video->gsh->codec : NULL; - return m_property_strdup_ro(prop, action, arg, c); -} - -/// Video codec name (RO) -static int mp_property_video_codec(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - const char *c = mpctx->sh_video ? mpctx->sh_video->gsh->decoder_desc : NULL; - return m_property_strdup_ro(prop, action, arg, c); -} - - -/// Video bitrate (RO) -static int mp_property_video_bitrate(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - if (action == M_PROPERTY_PRINT) { - *(char **)arg = format_bitrate(mpctx->sh_video->i_bps); - return M_PROPERTY_OK; - } - return m_property_int_ro(prop, action, arg, mpctx->sh_video->i_bps); -} - -/// Video display width (RO) -static int mp_property_width(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_w); -} - -/// Video display height (RO) -static int mp_property_height(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_h); -} - -static int property_vo_wh(m_option_t *prop, int action, void *arg, - MPContext *mpctx, bool get_w) -{ - struct vo *vo = mpctx->video_out; - if (!mpctx->sh_video && !vo || !vo->hasframe) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(prop, action, arg, - get_w ? vo->aspdat.prew : vo->aspdat.preh); -} - -static int mp_property_dwidth(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_vo_wh(prop, action, arg, mpctx, true); -} - -static int mp_property_dheight(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_vo_wh(prop, action, arg, mpctx, false); -} - -/// Video fps (RO) -static int mp_property_fps(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - return m_property_float_ro(prop, action, arg, mpctx->sh_video->fps); -} - -/// Video aspect (RO) -static int mp_property_aspect(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_SET: { - float f = *(float *)arg; - if (f < 0.1) - f = (float)mpctx->sh_video->disp_w / mpctx->sh_video->disp_h; - mpctx->opts->movie_aspect = f; - video_reinit_vo(mpctx->sh_video); - return M_PROPERTY_OK; - } - case M_PROPERTY_GET: - *(float *)arg = mpctx->sh_video->aspect; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -// For OSD and subtitle related properties using the generic option bridge. -// - Fail as unavailable if no video is active -// - Trigger OSD state update when property is set -static int property_osd_helper(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - if (action == M_PROPERTY_SET) - osd_changed_all(mpctx->osd); - return mp_property_generic_option(prop, action, arg, mpctx); -} - -/// Selected subtitles (RW) -static int mp_property_sub(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_switch_track(prop, action, arg, mpctx, STREAM_SUB); -} - -/// Subtitle delay (RW) -static int mp_property_sub_delay(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct MPOpts *opts = mpctx->opts; - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - switch (action) { - case M_PROPERTY_PRINT: - *(char **)arg = format_delay(opts->sub_delay); - return M_PROPERTY_OK; - } - return property_osd_helper(prop, action, arg, mpctx); -} - -static int mp_property_sub_pos(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct MPOpts *opts = mpctx->opts; - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - if (action == M_PROPERTY_PRINT) { - *(char **)arg = talloc_asprintf(NULL, "%d/100", opts->sub_pos); - return M_PROPERTY_OK; - } - return property_osd_helper(prop, action, arg, mpctx); -} - -#ifdef CONFIG_TV - -static tvi_handle_t *get_tvh(struct MPContext *mpctx) -{ - if (!(mpctx->master_demuxer && mpctx->master_demuxer->type == DEMUXER_TYPE_TV)) - return NULL; - return mpctx->master_demuxer->priv; -} - -/// TV color settings (RW) -static int mp_property_tv_color(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - tvi_handle_t *tvh = get_tvh(mpctx); - if (!tvh) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SET: - return tv_set_color_options(tvh, prop->offset, *(int *) arg); - case M_PROPERTY_GET: - return tv_get_color_options(tvh, prop->offset, arg); - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -#endif - -static int mp_property_playlist_pos(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - struct playlist *pl = mpctx->playlist; - if (!pl->first) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: { - int pos = playlist_entry_to_index(pl, pl->current); - if (pos < 0) - return M_PROPERTY_UNAVAILABLE; - *(int *)arg = pos; - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: { - struct playlist_entry *e = playlist_entry_from_index(pl, *(int *)arg); - if (!e) - return M_PROPERTY_ERROR; - mp_set_playlist_entry(mpctx, e); - return M_PROPERTY_OK; - } - case M_PROPERTY_GET_TYPE: { - struct m_option opt = { - .name = prop->name, - .type = CONF_TYPE_INT, - .flags = CONF_RANGE, - .min = 0, - .max = playlist_entry_count(pl) - 1, - }; - *(struct m_option *)arg = opt; - return M_PROPERTY_OK; - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_playlist_count(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action == M_PROPERTY_GET) { - *(int *)arg = playlist_entry_count(mpctx->playlist); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_playlist(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action == M_PROPERTY_GET) { - char *res = talloc_strdup(NULL, ""); - - for (struct playlist_entry *e = mpctx->playlist->first; e; e = e->next) - { - if (mpctx->playlist->current == e) { - res = talloc_asprintf_append(res, "> %s <\n", e->filename); - } else { - res = talloc_asprintf_append(res, "%s\n", e->filename); - } - } - - *(char **)arg = res; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static char *print_obj_osd_list(struct m_obj_settings *list) -{ - char *res = NULL; - for (int n = 0; list && list[n].name; n++) { - res = talloc_asprintf_append(res, "%s [", list[n].name); - for (int i = 0; list[n].attribs && list[n].attribs[i]; i += 2) { - res = talloc_asprintf_append(res, "%s%s=%s", i > 0 ? " " : "", - list[n].attribs[i], - list[n].attribs[i + 1]); - } - res = talloc_asprintf_append(res, "]\n"); - } - if (!res) - res = talloc_strdup(NULL, "(empty)"); - return res; -} - -static int property_filter(m_option_t *prop, int action, void *arg, - MPContext *mpctx, enum stream_type mt) -{ - switch (action) { - case M_PROPERTY_PRINT: { - struct m_config_option *opt = m_config_get_co(mpctx->mconfig, - bstr0(prop->name)); - *(char **)arg = print_obj_osd_list(*(struct m_obj_settings **)opt->data); - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: - return set_filters(mpctx, mt, *(struct m_obj_settings **)arg) >= 0 - ? M_PROPERTY_OK : M_PROPERTY_ERROR; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - -static int mp_property_vf(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_filter(prop, action, arg, mpctx, STREAM_VIDEO); -} - -static int mp_property_af(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - return property_filter(prop, action, arg, mpctx, STREAM_AUDIO); -} - -static int mp_property_alias(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - const char *real_property = prop->priv; - int r = mp_property_do(real_property, action, arg, mpctx); - if (action == M_PROPERTY_GET_TYPE && r >= 0) { - // Fix the property name - struct m_option *type = arg; - type->name = prop->name; - } - return r; -} - -static int mp_property_options(m_option_t *prop, int action, void *arg, - MPContext *mpctx) -{ - if (action != M_PROPERTY_KEY_ACTION) - return M_PROPERTY_NOT_IMPLEMENTED; - - struct m_property_action_arg *ka = arg; - - struct m_config_option *opt = m_config_get_co(mpctx->mconfig, - bstr0(ka->key)); - if (!opt) - return M_PROPERTY_UNKNOWN; - if (!opt->data) - return M_PROPERTY_UNAVAILABLE; - - switch (ka->action) { - case M_PROPERTY_GET: - m_option_copy(opt->opt, ka->arg, opt->data); - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: - *(struct m_option *)ka->arg = *opt->opt; - return M_PROPERTY_OK; - } - - return M_PROPERTY_NOT_IMPLEMENTED; -} - -// Use option-to-property-bridge. (The property and option have the same names.) -#define M_OPTION_PROPERTY(name) \ - {(name), mp_property_generic_option, &m_option_type_dummy, 0, 0, 0, (name)} - -// OPTION_PROPERTY(), but with a custom property handler. The custom handler -// must let unknown operations fall back to mp_property_generic_option(). -#define M_OPTION_PROPERTY_CUSTOM(name, handler) \ - {(name), (handler), &m_option_type_dummy, 0, 0, 0, (name)} -#define M_OPTION_PROPERTY_CUSTOM_(name, handler, ...) \ - {(name), (handler), &m_option_type_dummy, 0, 0, 0, (name), __VA_ARGS__} - -// Redirect a property name to another -#define M_PROPERTY_ALIAS(name, real_property) \ - {(name), mp_property_alias, &m_option_type_dummy, 0, 0, 0, (real_property)} - -/// All properties available in MPlayer. -/** \ingroup Properties - */ -static const m_option_t mp_properties[] = { - // General - M_OPTION_PROPERTY("osd-level"), - M_OPTION_PROPERTY_CUSTOM("osd-scale", property_osd_helper), - M_OPTION_PROPERTY("loop"), - M_OPTION_PROPERTY_CUSTOM("speed", mp_property_playback_speed), - { "filename", mp_property_filename, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "path", mp_property_path, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "media-title", mp_property_media_title, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "stream-path", mp_property_stream_path, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - M_OPTION_PROPERTY_CUSTOM("stream-capture", mp_property_stream_capture), - { "demuxer", mp_property_demuxer, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "stream-pos", mp_property_stream_pos, CONF_TYPE_INT64, - M_OPT_MIN, 0, 0, NULL }, - { "stream-start", mp_property_stream_start, CONF_TYPE_INT64, - M_OPT_MIN, 0, 0, NULL }, - { "stream-end", mp_property_stream_end, CONF_TYPE_INT64, - M_OPT_MIN, 0, 0, NULL }, - { "stream-length", mp_property_stream_length, CONF_TYPE_INT64, - M_OPT_MIN, 0, 0, NULL }, - { "stream-time-pos", mp_property_stream_time_pos, CONF_TYPE_TIME, - M_OPT_MIN, 0, 0, NULL }, - { "length", mp_property_length, CONF_TYPE_TIME, - M_OPT_MIN, 0, 0, NULL }, - { "avsync", mp_property_avsync, CONF_TYPE_DOUBLE }, - { "percent-pos", mp_property_percent_pos, CONF_TYPE_DOUBLE, - M_OPT_RANGE, 0, 100, NULL }, - { "time-pos", mp_property_time_pos, CONF_TYPE_TIME, - M_OPT_MIN, 0, 0, NULL }, - { "time-remaining", mp_property_remaining, CONF_TYPE_TIME }, - { "chapter", mp_property_chapter, CONF_TYPE_INT, - M_OPT_MIN, 0, 0, NULL }, - M_OPTION_PROPERTY_CUSTOM("edition", mp_property_edition), - M_OPTION_PROPERTY_CUSTOM("quvi-format", mp_property_quvi_format), - { "titles", mp_property_titles, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "chapters", mp_property_chapters, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "editions", mp_property_editions, CONF_TYPE_INT }, - { "angle", mp_property_angle, &m_option_type_dummy }, - { "metadata", mp_property_metadata, CONF_TYPE_STRING_LIST, - 0, 0, 0, NULL }, - M_OPTION_PROPERTY_CUSTOM("pause", mp_property_pause), - { "cache", mp_property_cache, CONF_TYPE_INT }, - M_OPTION_PROPERTY("pts-association-mode"), - M_OPTION_PROPERTY("hr-seek"), - { "clock", mp_property_clock, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - - { "chapter-list", mp_property_list_chapters, CONF_TYPE_STRING }, - { "track-list", property_list_tracks, CONF_TYPE_STRING }, - - { "playlist", mp_property_playlist, CONF_TYPE_STRING }, - { "playlist-pos", mp_property_playlist_pos, CONF_TYPE_INT }, - { "playlist-count", mp_property_playlist_count, CONF_TYPE_INT }, - - // 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 }, - M_OPTION_PROPERTY_CUSTOM("audio-delay", mp_property_audio_delay), - { "audio-format", mp_property_audio_format, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "audio-codec", mp_property_audio_codec, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "audio-bitrate", mp_property_audio_bitrate, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "samplerate", mp_property_samplerate, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "channels", mp_property_channels, CONF_TYPE_INT, - 0, 0, 0, NULL }, - M_OPTION_PROPERTY_CUSTOM("aid", mp_property_audio), - { "balance", mp_property_balance, CONF_TYPE_FLOAT, - M_OPT_RANGE, -1, 1, NULL }, - - // Video - M_OPTION_PROPERTY_CUSTOM("fullscreen", mp_property_fullscreen), - { "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG, - M_OPT_RANGE, 0, 1, NULL }, - M_OPTION_PROPERTY_CUSTOM("colormatrix", mp_property_colormatrix), - M_OPTION_PROPERTY_CUSTOM("colormatrix-input-range", - mp_property_colormatrix_input_range), - M_OPTION_PROPERTY_CUSTOM("colormatrix-output-range", - mp_property_colormatrix_output_range), - M_OPTION_PROPERTY_CUSTOM("ontop", mp_property_ontop), - M_OPTION_PROPERTY_CUSTOM("border", mp_property_border), - M_OPTION_PROPERTY_CUSTOM("framedrop", mp_property_framedrop), - M_OPTION_PROPERTY_CUSTOM_("gamma", mp_property_gamma, - .offset = offsetof(struct MPOpts, gamma_gamma)), - M_OPTION_PROPERTY_CUSTOM_("brightness", mp_property_gamma, - .offset = offsetof(struct MPOpts, gamma_brightness)), - M_OPTION_PROPERTY_CUSTOM_("contrast", mp_property_gamma, - .offset = offsetof(struct MPOpts, gamma_contrast)), - M_OPTION_PROPERTY_CUSTOM_("saturation", mp_property_gamma, - .offset = offsetof(struct MPOpts, gamma_saturation)), - M_OPTION_PROPERTY_CUSTOM_("hue", mp_property_gamma, - .offset = offsetof(struct MPOpts, gamma_hue)), - M_OPTION_PROPERTY_CUSTOM("panscan", mp_property_panscan), - { "video-format", mp_property_video_format, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "video-codec", mp_property_video_codec, CONF_TYPE_STRING, - 0, 0, 0, NULL }, - { "video-bitrate", mp_property_video_bitrate, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "width", mp_property_width, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "height", mp_property_height, CONF_TYPE_INT, - 0, 0, 0, NULL }, - { "dwidth", mp_property_dwidth, CONF_TYPE_INT }, - { "dheight", mp_property_dheight, CONF_TYPE_INT }, - { "fps", mp_property_fps, CONF_TYPE_FLOAT, - 0, 0, 0, NULL }, - { "aspect", mp_property_aspect, CONF_TYPE_FLOAT, - CONF_RANGE, 0, 10, NULL }, - M_OPTION_PROPERTY_CUSTOM("vid", mp_property_video), - { "program", mp_property_program, CONF_TYPE_INT, - CONF_RANGE, -1, 65535, NULL }, - - // Subs - M_OPTION_PROPERTY_CUSTOM("sid", mp_property_sub), - M_OPTION_PROPERTY_CUSTOM("sub-delay", mp_property_sub_delay), - M_OPTION_PROPERTY_CUSTOM("sub-pos", mp_property_sub_pos), - M_OPTION_PROPERTY_CUSTOM("sub-visibility", property_osd_helper), - M_OPTION_PROPERTY_CUSTOM("sub-forced-only", property_osd_helper), - M_OPTION_PROPERTY_CUSTOM("sub-scale", property_osd_helper), -#ifdef CONFIG_ASS - M_OPTION_PROPERTY_CUSTOM("ass-use-margins", property_osd_helper), - M_OPTION_PROPERTY_CUSTOM("ass-vsfilter-aspect-compat", property_osd_helper), - M_OPTION_PROPERTY_CUSTOM("ass-style-override", property_osd_helper), -#endif - - M_OPTION_PROPERTY_CUSTOM("vf*", mp_property_vf), - M_OPTION_PROPERTY_CUSTOM("af*", mp_property_af), - -#ifdef CONFIG_TV - { "tv-brightness", mp_property_tv_color, CONF_TYPE_INT, - M_OPT_RANGE, -100, 100, .offset = TV_COLOR_BRIGHTNESS }, - { "tv-contrast", mp_property_tv_color, CONF_TYPE_INT, - M_OPT_RANGE, -100, 100, .offset = TV_COLOR_CONTRAST }, - { "tv-saturation", mp_property_tv_color, CONF_TYPE_INT, - M_OPT_RANGE, -100, 100, .offset = TV_COLOR_SATURATION }, - { "tv-hue", mp_property_tv_color, CONF_TYPE_INT, - M_OPT_RANGE, -100, 100, .offset = TV_COLOR_HUE }, -#endif - - M_PROPERTY_ALIAS("video", "vid"), - M_PROPERTY_ALIAS("audio", "aid"), - M_PROPERTY_ALIAS("sub", "sid"), - - { "options", mp_property_options, &m_option_type_dummy }, - - {0}, -}; - -int mp_property_do(const char *name, int action, void *val, - struct MPContext *ctx) -{ - return m_property_do(mp_properties, name, action, val, ctx); -} - -char *mp_property_expand_string(struct MPContext *mpctx, char *str) -{ - return m_properties_expand_string(mp_properties, str, mpctx); -} - -void property_print_help(void) -{ - m_properties_print_help_list(mp_properties); -} - - -/* List of default ways to show a property on OSD. - * - * If osd_progbar is set, a bar showing the current position between min/max - * values of the property is shown. In this case osd_msg is only used for - * terminal output if there is no video; it'll be a label shown together with - * percentage. - */ -static struct property_osd_display { - // property name - const char *name; - // name used on OSD - const char *osd_name; - // progressbar type - int osd_progbar; - // osd msg id if it must be shared - int osd_id; - // Needs special ways to display the new value (seeks are delayed) - int seek_msg, seek_bar; - // Separator between option name and value (default: ": ") - const char *sep; -} property_osd_display[] = { - // general - { "loop", _("Loop") }, - { "chapter", .seek_msg = OSD_SEEK_INFO_CHAPTER_TEXT, - .seek_bar = OSD_SEEK_INFO_BAR }, - { "edition", .seek_msg = OSD_SEEK_INFO_EDITION }, - { "pts-association-mode", "PTS association mode" }, - { "hr-seek", "hr-seek" }, - { "speed", _("Speed") }, - { "clock", _("Clock") }, - // audio - { "volume", _("Volume"), .osd_progbar = OSD_VOLUME }, - { "mute", _("Mute") }, - { "audio-delay", _("A-V delay") }, - { "audio", _("Audio") }, - { "balance", _("Balance"), .osd_progbar = OSD_BALANCE }, - // video - { "panscan", _("Panscan"), .osd_progbar = OSD_PANSCAN }, - { "ontop", _("Stay on top") }, - { "border", _("Border") }, - { "framedrop", _("Framedrop") }, - { "deinterlace", _("Deinterlace") }, - { "colormatrix", _("YUV colormatrix") }, - { "colormatrix-input-range", _("YUV input range") }, - { "colormatrix-output-range", _("RGB output range") }, - { "gamma", _("Gamma"), .osd_progbar = OSD_BRIGHTNESS }, - { "brightness", _("Brightness"), .osd_progbar = OSD_BRIGHTNESS }, - { "contrast", _("Contrast"), .osd_progbar = OSD_CONTRAST }, - { "saturation", _("Saturation"), .osd_progbar = OSD_SATURATION }, - { "hue", _("Hue"), .osd_progbar = OSD_HUE }, - { "angle", _("Angle") }, - // subs - { "sub", _("Subtitles") }, - { "sub-pos", _("Sub position") }, - { "sub-delay", _("Sub delay"), .osd_id = OSD_MSG_SUB_DELAY }, - { "sub-visibility", _("Subtitles") }, - { "sub-forced-only", _("Forced sub only") }, - { "sub-scale", _("Sub Scale")}, - { "ass-vsfilter-aspect-compat", _("Subtitle VSFilter aspect compat")}, - { "ass-style-override", _("ASS subtitle style override")}, - { "vf*", _("Video filters"), .sep = ":\n"}, - { "af*", _("Audio filters"), .sep = ":\n"}, -#ifdef CONFIG_TV - { "tv-brightness", _("Brightness"), .osd_progbar = OSD_BRIGHTNESS }, - { "tv-hue", _("Hue"), .osd_progbar = OSD_HUE}, - { "tv-saturation", _("Saturation"), .osd_progbar = OSD_SATURATION }, - { "tv-contrast", _("Contrast"), .osd_progbar = OSD_CONTRAST }, -#endif - {0} -}; - -static void show_property_osd(MPContext *mpctx, const char *pname, - enum mp_on_osd osd_mode) -{ - struct MPOpts *opts = mpctx->opts; - struct m_option prop = {0}; - struct property_osd_display *p; - - if (mp_property_do(pname, M_PROPERTY_GET_TYPE, &prop, mpctx) <= 0) - return; - - int osd_progbar = 0; - const char *osd_name = NULL; - - // look for the command - for (p = property_osd_display; p->name; p++) { - if (!strcmp(p->name, prop.name)) { - osd_progbar = p->seek_bar ? 1 : p->osd_progbar; - osd_name = p->seek_msg ? "" : mp_gtext(p->osd_name); - break; - } - } - if (!p->name) - p = NULL; - - if (osd_mode != MP_ON_OSD_AUTO) { - osd_name = osd_name ? osd_name : prop.name; - if (!(osd_mode & MP_ON_OSD_MSG)) - osd_name = NULL; - osd_progbar = osd_progbar ? osd_progbar : ' '; - if (!(osd_mode & MP_ON_OSD_BAR)) - osd_progbar = 0; - } - - if (p && (p->seek_msg || p->seek_bar)) { - mpctx->add_osd_seek_info |= - (osd_name ? p->seek_msg : 0) | (osd_progbar ? p->seek_bar : 0); - return; - } - - if (osd_progbar && (prop.flags & CONF_RANGE) == CONF_RANGE) { - bool ok = false; - if (prop.type == CONF_TYPE_INT) { - int i; - ok = mp_property_do(prop.name, M_PROPERTY_GET, &i, mpctx) > 0; - if (ok) - set_osd_bar(mpctx, osd_progbar, osd_name, prop.min, prop.max, i); - } else if (prop.type == CONF_TYPE_FLOAT) { - float f; - ok = mp_property_do(prop.name, M_PROPERTY_GET, &f, mpctx) > 0; - if (ok) - set_osd_bar(mpctx, osd_progbar, osd_name, prop.min, prop.max, f); - } - if (ok && osd_mode == MP_ON_OSD_AUTO && opts->osd_bar_visible) - return; - } - - if (osd_name) { - char *val = NULL; - int r = mp_property_do(prop.name, M_PROPERTY_PRINT, &val, mpctx); - if (r == M_PROPERTY_UNAVAILABLE) { - set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, opts->osd_duration, - "%s: (unavailable)", osd_name); - } else if (r >= 0 && val) { - int osd_id = 0; - const char *sep = NULL; - if (p) { - int index = p - property_osd_display; - osd_id = p->osd_id ? p->osd_id : OSD_MSG_PROPERTY + index; - sep = p->sep; - } - if (!sep) - sep = ": "; - set_osd_tmsg(mpctx, osd_id, 1, opts->osd_duration, - "%s%s%s", osd_name, sep, val); - talloc_free(val); - } - } -} - -static const char *property_error_string(int error_value) -{ - switch (error_value) { - case M_PROPERTY_ERROR: - return "ERROR"; - case M_PROPERTY_UNAVAILABLE: - return "PROPERTY_UNAVAILABLE"; - case M_PROPERTY_NOT_IMPLEMENTED: - return "NOT_IMPLEMENTED"; - case M_PROPERTY_UNKNOWN: - return "PROPERTY_UNKNOWN"; - } - return "UNKNOWN"; -} - -static bool reinit_filters(MPContext *mpctx, enum stream_type mediatype) -{ - switch (mediatype) { - case STREAM_VIDEO: - return reinit_video_filters(mpctx) >= 0; - case STREAM_AUDIO: - return reinit_audio_filters(mpctx) >= 0; - } - return false; -} - -static const char *filter_opt[STREAM_TYPE_COUNT] = { - [STREAM_VIDEO] = "vf", - [STREAM_AUDIO] = "af", -}; - -static int set_filters(struct MPContext *mpctx, enum stream_type mediatype, - struct m_obj_settings *new_chain) -{ - bstr option = bstr0(filter_opt[mediatype]); - struct m_config_option *co = m_config_get_co(mpctx->mconfig, option); - if (!co) - return -1; - - struct m_obj_settings **list = co->data; - struct m_obj_settings *old_settings = *list; - *list = NULL; - m_option_copy(co->opt, list, &new_chain); - - bool success = reinit_filters(mpctx, mediatype); - - if (success) { - m_option_free(co->opt, &old_settings); - } else { - m_option_free(co->opt, list); - *list = old_settings; - reinit_filters(mpctx, mediatype); - } - - if (mediatype == STREAM_VIDEO) - mp_force_video_refresh(mpctx); - - return success ? 0 : -1; -} - -static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype, - const char *cmd, const char *arg) -{ - bstr option = bstr0(filter_opt[mediatype]); - struct m_config_option *co = m_config_get_co(mpctx->mconfig, option); - if (!co) - return -1; - - // The option parser is used to modify the filter list itself. - char optname[20]; - snprintf(optname, sizeof(optname), "%.*s-%s", BSTR_P(option), cmd); - - struct m_obj_settings *new_chain = NULL; - m_option_copy(co->opt, &new_chain, co->data); - - int r = m_option_parse(co->opt, bstr0(optname), bstr0(arg), &new_chain); - if (r >= 0) - r = set_filters(mpctx, mediatype, new_chain); - - m_option_free(co->opt, &new_chain); - - return r >= 0 ? 0 : -1; -} - -static int edit_filters_osd(struct MPContext *mpctx, enum stream_type mediatype, - const char *cmd, const char *arg, bool on_osd) -{ - int r = edit_filters(mpctx, mediatype, cmd, arg); - if (on_osd) { - if (r >= 0) { - const char *prop = filter_opt[mediatype]; - show_property_osd(mpctx, prop, MP_ON_OSD_MSG); - } else { - set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, mpctx->opts->osd_duration, - "Changing filters failed!"); - } - } - return r; -} - -static void change_video_filters(MPContext *mpctx, const char *cmd, - const char *arg) -{ - edit_filters(mpctx, STREAM_VIDEO, cmd, arg); -} - -void run_command(MPContext *mpctx, mp_cmd_t *cmd) -{ - struct MPOpts *opts = mpctx->opts; - sh_video_t *const sh_video = mpctx->sh_video; - int osd_duration = opts->osd_duration; - bool auto_osd = cmd->on_osd == MP_ON_OSD_AUTO; - bool msg_osd = auto_osd || (cmd->on_osd & MP_ON_OSD_MSG); - bool bar_osd = auto_osd || (cmd->on_osd & MP_ON_OSD_BAR); - int osdl = msg_osd ? 1 : OSD_LEVEL_INVISIBLE; - - if (!cmd->raw_args) { - for (int n = 0; n < cmd->nargs; n++) { - if (cmd->args[n].type.type == CONF_TYPE_STRING) { - cmd->args[n].v.s = - mp_property_expand_string(mpctx, cmd->args[n].v.s); - if (!cmd->args[n].v.s) - return; - talloc_steal(cmd, cmd->args[n].v.s); - } - } - } - - switch (cmd->id) { - case MP_CMD_SEEK: { - double v = cmd->args[0].v.d; - int abs = cmd->args[1].v.i; - int exact = cmd->args[2].v.i; - if (abs == 2) { // Absolute seek to a timestamp in seconds - queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact); - set_osd_function(mpctx, - v > get_current_time(mpctx) ? OSD_FFW : OSD_REW); - } else if (abs) { /* Absolute seek by percentage */ - queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact); - set_osd_function(mpctx, OSD_FFW); // Direction isn't set correctly - } else { - queue_seek(mpctx, MPSEEK_RELATIVE, v, exact); - set_osd_function(mpctx, (v > 0) ? OSD_FFW : OSD_REW); - } - if (bar_osd) - mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR; - if (msg_osd && !(auto_osd && opts->osd_bar_visible)) - mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT; - break; - } - - case MP_CMD_SET: { - int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_SET_STRING, - cmd->args[1].v.s, mpctx); - if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) { - show_property_osd(mpctx, cmd->args[0].v.s, cmd->on_osd); - } else if (r == M_PROPERTY_UNKNOWN) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Unknown property: '%s'\n", cmd->args[0].v.s); - } else if (r <= 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_ADD: - case MP_CMD_CYCLE: - { - struct m_property_switch_arg s = { - .inc = 1, - .wrap = cmd->id == MP_CMD_CYCLE, - }; - if (cmd->args[1].v.d) - s.inc = cmd->args[1].v.d; - int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_SWITCH, &s, mpctx); - if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) { - show_property_osd(mpctx, cmd->args[0].v.s, cmd->on_osd); - } else if (r == M_PROPERTY_UNKNOWN) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Unknown property: '%s'\n", cmd->args[0].v.s); - } else if (r <= 0) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Failed to increment property '%s' by %g.\n", - cmd->args[0].v.s, s.inc); - } - break; - } - - case MP_CMD_GET_PROPERTY: { - char *tmp; - int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_GET_STRING, - &tmp, mpctx); - if (r <= 0) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Failed to get value of property '%s'.\n", - cmd->args[0].v.s); - mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", - property_error_string(r)); - break; - } - mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n", - cmd->args[0].v.s, tmp); - talloc_free(tmp); - break; - } - - case MP_CMD_SPEED_MULT: { - double v = cmd->args[0].v.d; - v *= mpctx->opts->playback_speed; - mp_property_do("speed", M_PROPERTY_SET, &v, mpctx); - show_property_osd(mpctx, "speed", cmd->on_osd); - break; - } - - case MP_CMD_FRAME_STEP: - add_step_frame(mpctx, 1); - break; - - case MP_CMD_FRAME_BACK_STEP: - add_step_frame(mpctx, -1); - break; - - case MP_CMD_QUIT: - mpctx->stop_play = PT_QUIT; - mpctx->quit_custom_rc = cmd->args[0].v.i; - mpctx->has_quit_custom_rc = true; - break; - - case MP_CMD_QUIT_WATCH_LATER: - mp_write_watch_later_conf(mpctx); - mpctx->stop_play = PT_QUIT; - mpctx->quit_player_rc = 0; - break; - - case MP_CMD_PLAYLIST_NEXT: - case MP_CMD_PLAYLIST_PREV: - { - int dir = cmd->id == MP_CMD_PLAYLIST_PREV ? -1 : +1; - int force = cmd->args[0].v.i; - - struct playlist_entry *e = mp_next_file(mpctx, dir); - if (!e && !force) - break; - mpctx->playlist->current = e; - mpctx->playlist->current_was_replaced = false; - mpctx->stop_play = PT_CURRENT_ENTRY; - break; - } - - case MP_CMD_SUB_STEP: - if (mpctx->osd->dec_sub) { - double a[2]; - a[0] = mpctx->video_pts - mpctx->osd->video_offset + opts->sub_delay; - a[1] = cmd->args[0].v.i; - if (sub_control(mpctx->osd->dec_sub, SD_CTRL_SUB_STEP, a) > 0) { - opts->sub_delay += a[0]; - - osd_changed_all(mpctx->osd); - set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration, - "Sub delay: %d ms", ROUND(opts->sub_delay * 1000)); - } - } - break; - - case MP_CMD_OSD: { - int v = cmd->args[0].v.i; - int max = (opts->term_osd - && !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL; - if (opts->osd_level > max) - opts->osd_level = max; - if (v < 0) - opts->osd_level = (opts->osd_level + 1) % (max + 1); - else - opts->osd_level = v > max ? max : v; - if (msg_osd && opts->osd_level <= 1) - set_osd_tmsg(mpctx, OSD_MSG_OSD_STATUS, 0, osd_duration, - "OSD: %s", opts->osd_level ? "yes" : "no"); - else - rm_osd_msg(mpctx, OSD_MSG_OSD_STATUS); - break; - } - - case MP_CMD_PRINT_TEXT: { - mp_msg(MSGT_GLOBAL, MSGL_INFO, "%s\n", cmd->args[0].v.s); - break; - } - - case MP_CMD_SHOW_TEXT: { - // if no argument supplied use default osd_duration, else ms. - set_osd_msg(mpctx, OSD_MSG_TEXT, cmd->args[2].v.i, - (cmd->args[1].v.i < 0 ? osd_duration : cmd->args[1].v.i), - "%s", cmd->args[0].v.s); - break; - } - - case MP_CMD_LOADFILE: { - char *filename = cmd->args[0].v.s; - bool append = cmd->args[1].v.i; - - if (!append) - playlist_clear(mpctx->playlist); - - playlist_add(mpctx->playlist, playlist_entry_new(filename)); - - if (!append) - mp_set_playlist_entry(mpctx, mpctx->playlist->first); - break; - } - - case MP_CMD_LOADLIST: { - char *filename = cmd->args[0].v.s; - bool append = cmd->args[1].v.i; - struct playlist *pl = playlist_parse_file(filename); - if (pl) { - if (!append) - playlist_clear(mpctx->playlist); - playlist_transfer_entries(mpctx->playlist, pl); - talloc_free(pl); - - if (!append && mpctx->playlist->first) - mp_set_playlist_entry(mpctx, mpctx->playlist->first); - } else { - mp_tmsg(MSGT_CPLAYER, MSGL_ERR, - "\nUnable to load playlist %s.\n", filename); - } - break; - } - - case MP_CMD_PLAYLIST_CLEAR: { - // Supposed to clear the playlist, except the currently played item. - if (mpctx->playlist->current_was_replaced) - mpctx->playlist->current = NULL; - while (mpctx->playlist->first) { - struct playlist_entry *e = mpctx->playlist->first; - if (e == mpctx->playlist->current) { - e = e->next; - if (!e) - break; - } - playlist_remove(mpctx->playlist, e); - } - break; - } - - case MP_CMD_PLAYLIST_REMOVE: { - struct playlist_entry *e = playlist_entry_from_index(mpctx->playlist, - cmd->args[0].v.i); - if (e) { - // Can't play a removed entry - if (mpctx->playlist->current == e) - mpctx->stop_play = PT_CURRENT_ENTRY; - playlist_remove(mpctx->playlist, e); - } - break; - } - - case MP_CMD_PLAYLIST_MOVE: { - struct playlist_entry *e1 = playlist_entry_from_index(mpctx->playlist, - cmd->args[0].v.i); - struct playlist_entry *e2 = playlist_entry_from_index(mpctx->playlist, - cmd->args[1].v.i); - if (e1) { - playlist_move(mpctx->playlist, e1, e2); - } - break; - } - - case MP_CMD_STOP: - // Go back to the starting point. - mpctx->stop_play = PT_STOP; - break; - - case MP_CMD_SHOW_PROGRESS: - mpctx->add_osd_seek_info |= - (msg_osd ? OSD_SEEK_INFO_TEXT : 0) | - (bar_osd ? OSD_SEEK_INFO_BAR : 0); - break; - -#ifdef CONFIG_RADIO - case MP_CMD_RADIO_STEP_CHANNEL: - if (mpctx->stream && mpctx->stream->type == STREAMTYPE_RADIO) { - int v = cmd->args[0].v.i; - if (v > 0) - radio_step_channel(mpctx->stream, RADIO_CHANNEL_HIGHER); - else - radio_step_channel(mpctx->stream, RADIO_CHANNEL_LOWER); - if (radio_get_channel_name(mpctx->stream)) { - set_osd_tmsg(mpctx, OSD_MSG_RADIO_CHANNEL, osdl, osd_duration, - "Channel: %s", - radio_get_channel_name(mpctx->stream)); - } - } - break; - - case MP_CMD_RADIO_SET_CHANNEL: - if (mpctx->stream && mpctx->stream->type == STREAMTYPE_RADIO) { - radio_set_channel(mpctx->stream, cmd->args[0].v.s); - if (radio_get_channel_name(mpctx->stream)) { - set_osd_tmsg(mpctx, OSD_MSG_RADIO_CHANNEL, osdl, osd_duration, - "Channel: %s", - radio_get_channel_name(mpctx->stream)); - } - } - break; - - case MP_CMD_RADIO_SET_FREQ: - if (mpctx->stream && mpctx->stream->type == STREAMTYPE_RADIO) - radio_set_freq(mpctx->stream, cmd->args[0].v.f); - break; - - case MP_CMD_RADIO_STEP_FREQ: - if (mpctx->stream && mpctx->stream->type == STREAMTYPE_RADIO) - radio_step_freq(mpctx->stream, cmd->args[0].v.f); - break; -#endif - -#ifdef CONFIG_TV - case MP_CMD_TV_START_SCAN: - if (get_tvh(mpctx)) - tv_start_scan(get_tvh(mpctx), 1); - break; - case MP_CMD_TV_SET_FREQ: - if (get_tvh(mpctx)) - tv_set_freq(get_tvh(mpctx), cmd->args[0].v.f * 16.0); -#ifdef CONFIG_PVR - else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) { - pvr_set_freq(mpctx->stream, ROUND(cmd->args[0].v.f)); - set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s", - pvr_get_current_channelname(mpctx->stream), - pvr_get_current_stationname(mpctx->stream)); - } -#endif /* CONFIG_PVR */ - break; - - case MP_CMD_TV_STEP_FREQ: - if (get_tvh(mpctx)) - tv_step_freq(get_tvh(mpctx), cmd->args[0].v.f * 16.0); -#ifdef CONFIG_PVR - else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) { - pvr_force_freq_step(mpctx->stream, ROUND(cmd->args[0].v.f)); - set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: f %d", - pvr_get_current_channelname(mpctx->stream), - pvr_get_current_frequency(mpctx->stream)); - } -#endif /* CONFIG_PVR */ - break; - - case MP_CMD_TV_SET_NORM: - if (get_tvh(mpctx)) - tv_set_norm(get_tvh(mpctx), cmd->args[0].v.s); - break; - - case MP_CMD_TV_STEP_CHANNEL: - if (get_tvh(mpctx)) { - int v = cmd->args[0].v.i; - if (v > 0) { - tv_step_channel(get_tvh(mpctx), TV_CHANNEL_HIGHER); - } else { - tv_step_channel(get_tvh(mpctx), TV_CHANNEL_LOWER); - } - if (tv_channel_list) { - set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, - "Channel: %s", tv_channel_current->name); - } - } -#ifdef CONFIG_PVR - else if (mpctx->stream && - mpctx->stream->type == STREAMTYPE_PVR) { - pvr_set_channel_step(mpctx->stream, cmd->args[0].v.i); - set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s", - pvr_get_current_channelname(mpctx->stream), - pvr_get_current_stationname(mpctx->stream)); - } -#endif /* CONFIG_PVR */ -#ifdef CONFIG_DVBIN - if (mpctx->stream->type == STREAMTYPE_DVB) { - int dir; - int v = cmd->args[0].v.i; - - mpctx->last_dvb_step = v; - if (v > 0) - dir = DVB_CHANNEL_HIGHER; - else - dir = DVB_CHANNEL_LOWER; - - - if (dvb_step_channel(mpctx->stream, dir)) { - mpctx->stop_play = PT_NEXT_ENTRY; - mpctx->dvbin_reopen = 1; - } - } -#endif /* CONFIG_DVBIN */ - break; - - case MP_CMD_TV_SET_CHANNEL: - if (get_tvh(mpctx)) { - tv_set_channel(get_tvh(mpctx), cmd->args[0].v.s); - if (tv_channel_list) { - set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, - "Channel: %s", tv_channel_current->name); - } - } -#ifdef CONFIG_PVR - else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) { - pvr_set_channel(mpctx->stream, cmd->args[0].v.s); - set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s", - pvr_get_current_channelname(mpctx->stream), - pvr_get_current_stationname(mpctx->stream)); - } -#endif /* CONFIG_PVR */ - break; - -#ifdef CONFIG_DVBIN - case MP_CMD_DVB_SET_CHANNEL: - if (mpctx->stream->type == STREAMTYPE_DVB) { - mpctx->last_dvb_step = 1; - - if (dvb_set_channel(mpctx->stream, cmd->args[1].v.i, - cmd->args[0].v.i)) { - mpctx->stop_play = PT_NEXT_ENTRY; - mpctx->dvbin_reopen = 1; - } - } - break; -#endif /* CONFIG_DVBIN */ - - case MP_CMD_TV_LAST_CHANNEL: - if (get_tvh(mpctx)) { - tv_last_channel(get_tvh(mpctx)); - if (tv_channel_list) { - set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, - "Channel: %s", tv_channel_current->name); - } - } -#ifdef CONFIG_PVR - else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) { - pvr_set_lastchannel(mpctx->stream); - set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s", - pvr_get_current_channelname(mpctx->stream), - pvr_get_current_stationname(mpctx->stream)); - } -#endif /* CONFIG_PVR */ - break; - - case MP_CMD_TV_STEP_NORM: - if (get_tvh(mpctx)) - tv_step_norm(get_tvh(mpctx)); - break; - - case MP_CMD_TV_STEP_CHANNEL_LIST: - if (get_tvh(mpctx)) - tv_step_chanlist(get_tvh(mpctx)); - break; -#endif /* CONFIG_TV */ - - case MP_CMD_SUB_ADD: - if (sh_video) { - mp_add_subtitles(mpctx, cmd->args[0].v.s, 0); - } - break; - - case MP_CMD_SUB_REMOVE: { - struct track *sub = mp_track_by_tid(mpctx, STREAM_SUB, cmd->args[0].v.i); - if (sub) - mp_remove_track(mpctx, sub); - break; - } - - case MP_CMD_SUB_RELOAD: { - struct track *sub = mp_track_by_tid(mpctx, STREAM_SUB, cmd->args[0].v.i); - if (sh_video && sub && sub->is_external && sub->external_filename) - { - struct track *nsub = mp_add_subtitles(mpctx, sub->external_filename, 0); - if (nsub) { - mp_remove_track(mpctx, sub); - mp_switch_track(mpctx, nsub->type, nsub); - } - } - break; - } - - case MP_CMD_SCREENSHOT: - screenshot_request(mpctx, cmd->args[0].v.i, cmd->args[1].v.i, msg_osd); - break; - - case MP_CMD_SCREENSHOT_TO_FILE: - screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, msg_osd); - break; - - case MP_CMD_RUN: -#ifndef __MINGW32__ - if (!fork()) { - execl("/bin/sh", "sh", "-c", cmd->args[0].v.s, NULL); - exit(0); - } -#endif - break; - - case MP_CMD_KEYDOWN_EVENTS: - mp_input_put_key(mpctx->input, cmd->args[0].v.i); - break; - - case MP_CMD_ENABLE_INPUT_SECTION: - mp_input_enable_section(mpctx->input, cmd->args[0].v.s, - cmd->args[1].v.i == 1 ? MP_INPUT_EXCLUSIVE : 0); - break; - - case MP_CMD_DISABLE_INPUT_SECTION: - mp_input_disable_section(mpctx->input, cmd->args[0].v.s); - break; - - case MP_CMD_VO_CMDLINE: - if (mpctx->video_out) { - char *s = cmd->args[0].v.s; - mp_msg(MSGT_CPLAYER, MSGL_INFO, "Setting vo cmd line to '%s'.\n", - s); - if (vo_control(mpctx->video_out, VOCTRL_SET_COMMAND_LINE, s) > 0) { - set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, "vo='%s'", s); - } else { - set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, "Failed!"); - } - } - break; - - case MP_CMD_AF: - edit_filters_osd(mpctx, STREAM_AUDIO, cmd->args[0].v.s, - cmd->args[1].v.s, msg_osd); - break; - - case MP_CMD_VF: - edit_filters_osd(mpctx, STREAM_VIDEO, cmd->args[0].v.s, - cmd->args[1].v.s, msg_osd); - break; - - case MP_CMD_COMMAND_LIST: { - for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next) - run_command(mpctx, sub); - break; - } - - default: - mp_msg(MSGT_CPLAYER, MSGL_V, - "Received unknown cmd %s\n", cmd->name); - } - - switch (cmd->pausing) { - case 1: // "pausing" - pause_player(mpctx); - break; - case 3: // "pausing_toggle" - if (opts->pause) - unpause_player(mpctx); - else - pause_player(mpctx); - break; - } -} diff --git a/core/command.h b/core/command.h deleted file mode 100644 index dbe1f638e2..0000000000 --- a/core/command.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_COMMAND_H -#define MPLAYER_COMMAND_H - -struct MPContext; -struct mp_cmd; - -void mp_get_osd_mouse_pos(struct MPContext *mpctx, float *x, float *y); - -void run_command(struct MPContext *mpctx, struct mp_cmd *cmd); -char *mp_property_expand_string(struct MPContext *mpctx, char *str); -void property_print_help(void); -int mp_property_do(const char* name, int action, void* val, - struct MPContext *mpctx); - -#endif /* MPLAYER_COMMAND_H */ diff --git a/core/cpudetect.c b/core/cpudetect.c deleted file mode 100644 index 62cb03008d..0000000000 --- a/core/cpudetect.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -#include -#include "compat/libav.h" - -#include "config.h" -#include "core/cpudetect.h" -#include "core/mp_msg.h" - -CpuCaps gCpuCaps; - -static void dump_flag(const char *name, bool val) -{ - mp_msg(MSGT_CPUDETECT, MSGL_V, "CPU: %s: %s\n", name, - val ? "enabled" : "disabled"); -} - -void GetCpuCaps(CpuCaps *c) -{ - memset(c, 0, sizeof(*c)); - int flags = av_get_cpu_flags(); -#if ARCH_X86 - c->hasMMX = flags & AV_CPU_FLAG_MMX; - c->hasMMX2 = flags & AV_CPU_FLAG_MMX2; - c->hasSSE = flags & AV_CPU_FLAG_SSE; - c->hasSSE2 = (flags & AV_CPU_FLAG_SSE2) && !(flags & AV_CPU_FLAG_SSE2SLOW); - c->hasSSE3 = (flags & AV_CPU_FLAG_SSE3) && !(flags & AV_CPU_FLAG_SSE3SLOW); - c->hasSSSE3 = flags & AV_CPU_FLAG_SSSE3; -#endif - dump_flag("MMX", c->hasMMX); - dump_flag("MMX2", c->hasMMX2); - dump_flag("SSE", c->hasSSE); - dump_flag("SSE2", c->hasSSE2); - dump_flag("SSE3", c->hasSSE3); - dump_flag("SSSE3", c->hasSSSE3); -} diff --git a/core/cpudetect.h b/core/cpudetect.h deleted file mode 100644 index d3d9206c65..0000000000 --- a/core/cpudetect.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_CPUDETECT_H -#define MPLAYER_CPUDETECT_H - -#include -#include "config.h" - -#include "compat/x86_cpu.h" - -typedef struct cpucaps_s { - bool hasMMX; - bool hasMMX2; - bool hasSSE; - bool hasSSE2; - bool hasSSE3; - bool hasSSSE3; -} CpuCaps; - -extern CpuCaps gCpuCaps; - -void GetCpuCaps(CpuCaps *caps); - -#endif /* MPLAYER_CPUDETECT_H */ diff --git a/core/encode.h b/core/encode.h deleted file mode 100644 index acdb75c5a3..0000000000 --- a/core/encode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MPLAYER_ENCODE_H -#define MPLAYER_ENCODE_H - -#include -#include - -struct MPOpts; -struct encode_lavc_context; -struct encode_output_conf; - -// interface for mplayer.c -struct encode_lavc_context *encode_lavc_init(struct encode_output_conf *options); -void encode_lavc_finish(struct encode_lavc_context *ctx); -void encode_lavc_free(struct encode_lavc_context *ctx); -void encode_lavc_discontinuity(struct encode_lavc_context *ctx); -bool encode_lavc_showhelp(struct MPOpts *opts); -int encode_lavc_getstatus(struct encode_lavc_context *ctx, char *buf, int bufsize, float relative_position); -void encode_lavc_expect_stream(struct encode_lavc_context *ctx, enum AVMediaType mt); -void encode_lavc_set_video_fps(struct encode_lavc_context *ctx, float fps); -bool encode_lavc_didfail(struct encode_lavc_context *ctx); // check if encoding failed - -#endif diff --git a/core/encode_lavc.c b/core/encode_lavc.c deleted file mode 100644 index 75e57a2443..0000000000 --- a/core/encode_lavc.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * muxing using libavformat - * Copyright (C) 2010 Nicolas George - * Copyright (C) 2011-2012 Rudolf Polzer - * - * This file is part of mpv. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - - -#include "encode_lavc.h" -#include "core/mp_msg.h" -#include "video/vfcap.h" -#include "core/options.h" -#include "osdep/timer.h" -#include "video/out/vo.h" -#include "talloc.h" -#include "stream/stream.h" - -static int set_to_avdictionary(AVDictionary **dictp, const char *key, - const char *val) -{ - char keybuf[1024]; - char valuebuf[1024]; - - if (key == NULL) { - // we need to split at equals sign - const char *equals = strchr(val, '='); - if (!equals || equals - val >= sizeof(keybuf)) { - mp_msg(MSGT_ENCODE, MSGL_WARN, - "encode-lavc: option '%s' does not contain an equals sign\n", - val); - return 0; - } - memcpy(keybuf, val, equals - val); - keybuf[equals - val] = 0; - key = keybuf; - val = equals + 1; - } - - // hack: support "qscale" key as virtual "global_quality" key that multiplies by QP2LAMBDA - if (!strcmp(key, "qscale")) { - key = "global_quality"; - snprintf(valuebuf, sizeof(valuebuf), - "%.1s(%s)*QP2LAMBDA", - (val[0] == '+' || val[0] == '-') ? val : "", - (val[0] == '+' || val[0] == '-') ? val + 1 : val); - valuebuf[sizeof(valuebuf) - 1] = 0; - val = valuebuf; - } - - mp_msg(MSGT_ENCODE, MSGL_V, - "encode-lavc: setting value '%s' for key '%s'\n", - val, - key); - - if (av_dict_set(dictp, key, *val ? val : NULL, - (val[0] == '+' || val[0] == '-') ? AV_DICT_APPEND : 0) >= 0) - return 1; - - return 0; -} - -static bool value_has_flag(const char *value, const char *flag) -{ - bool state = true; - bool ret = false; - while (*value) { - size_t l = strcspn(value, "+-"); - if (l == 0) { - state = (*value == '+'); - ++value; - } else { - if (l == strlen(flag)) - if (!memcmp(value, flag, l)) - ret = state; - value += l; - } - } - return ret; -} - -#define CHECK_FAIL(ctx, val) \ - if (ctx && (ctx->failed || ctx->finished)) { \ - mp_msg(MSGT_ENCODE, MSGL_ERR, \ - "Called a function on a %s encoding context. Bailing out.\n", \ - ctx->failed ? "failed" : "finished"); \ - return val; \ - } - -int encode_lavc_available(struct encode_lavc_context *ctx) -{ - CHECK_FAIL(ctx, 0); - return ctx && ctx->avc; -} - -int encode_lavc_oformat_flags(struct encode_lavc_context *ctx) -{ - CHECK_FAIL(ctx, 0); - return ctx->avc ? ctx->avc->oformat->flags : 0; -} - -struct encode_lavc_context *encode_lavc_init(struct encode_output_conf *options) -{ - struct encode_lavc_context *ctx; - const char *filename = options->file; - - // STUPID STUPID STUPID STUPID avio - // does not support "-" as file name to mean stdin/stdout - // ffmpeg.c works around this too, the same way - if (!strcmp(filename, "-")) - filename = "pipe:1"; - - if (filename && ( - !strcmp(filename, "/dev/stdout") || - !strcmp(filename, "pipe:") || - !strcmp(filename, "pipe:1"))) - mp_msg_stdout_in_use = 1; - - ctx = talloc_zero(NULL, struct encode_lavc_context); - encode_lavc_discontinuity(ctx); - ctx->options = options; - - ctx->avc = avformat_alloc_context(); - - if (ctx->options->format) { - char *tok; - const char *in = ctx->options->format; - while (*in) { - tok = av_get_token(&in, ","); - ctx->avc->oformat = av_guess_format(tok, filename, NULL); - av_free(tok); - if (ctx->avc->oformat) - break; - if (*in) - ++in; - } - } else - ctx->avc->oformat = av_guess_format(NULL, filename, NULL); - - if (!ctx->avc->oformat) { - encode_lavc_fail(ctx, "encode-lavc: format not found\n"); - return NULL; - } - - av_strlcpy(ctx->avc->filename, filename, - sizeof(ctx->avc->filename)); - - ctx->foptions = NULL; - if (ctx->options->fopts) { - char **p; - for (p = ctx->options->fopts; *p; ++p) { - if (!set_to_avdictionary(&ctx->foptions, NULL, *p)) - mp_msg(MSGT_ENCODE, MSGL_WARN, - "encode-lavc: could not set option %s\n", *p); - } - } - - if (ctx->options->vcodec) { - char *tok; - const char *in = ctx->options->vcodec; - while (*in) { - tok = av_get_token(&in, ","); - ctx->vc = avcodec_find_encoder_by_name(tok); - av_free(tok); - if (ctx->vc && ctx->vc->type != AVMEDIA_TYPE_VIDEO) - ctx->vc = NULL; - if (ctx->vc) - break; - if (*in) - ++in; - } - } else - ctx->vc = avcodec_find_encoder(av_guess_codec(ctx->avc->oformat, NULL, - ctx->avc->filename, NULL, - AVMEDIA_TYPE_VIDEO)); - - if (ctx->options->acodec) { - char *tok; - const char *in = ctx->options->acodec; - while (*in) { - tok = av_get_token(&in, ","); - ctx->ac = avcodec_find_encoder_by_name(tok); - av_free(tok); - if (ctx->ac && ctx->ac->type != AVMEDIA_TYPE_AUDIO) - ctx->ac = NULL; - if (ctx->ac) - break; - if (*in) - ++in; - } - } else - ctx->ac = avcodec_find_encoder(av_guess_codec(ctx->avc->oformat, NULL, - ctx->avc->filename, NULL, - AVMEDIA_TYPE_AUDIO)); - - if (!ctx->vc && !ctx->ac) { - encode_lavc_fail( - ctx, "encode-lavc: neither audio nor video codec was found\n"); - return NULL; - } - - /* taken from ffmpeg unchanged - * TODO turn this into an option if anyone needs this */ - - ctx->avc->max_delay = 0.7 * AV_TIME_BASE; - - ctx->abytes = 0; - ctx->vbytes = 0; - ctx->frames = 0; - - if (options->video_first) - ctx->video_first = true; - if (options->audio_first) - ctx->audio_first = true; - - return ctx; -} - -int encode_lavc_start(struct encode_lavc_context *ctx) -{ - AVDictionaryEntry *de; - unsigned i; - - if (ctx->header_written < 0) - return 0; - if (ctx->header_written > 0) - return 1; - - CHECK_FAIL(ctx, 0); - - if (ctx->expect_video) { - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) - break; - if (i >= ctx->avc->nb_streams) { - encode_lavc_fail(ctx, - "encode-lavc: video stream missing, invalid codec?\n"); - return 0; - } - } - if (ctx->expect_audio) { - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - break; - if (i >= ctx->avc->nb_streams) { - encode_lavc_fail(ctx, - "encode-lavc: audio stream missing, invalid codec?\n"); - return 0; - } - } - - ctx->header_written = -1; - - if (!(ctx->avc->oformat->flags & AVFMT_NOFILE)) { - mp_msg(MSGT_ENCODE, MSGL_INFO, "Opening output file: %s\n", - ctx->avc->filename); - - if (avio_open(&ctx->avc->pb, ctx->avc->filename, - AVIO_FLAG_WRITE) < 0) { - encode_lavc_fail(ctx, "encode-lavc: could not open '%s'\n", - ctx->avc->filename); - return 0; - } - } - - ctx->t0 = mp_time_sec(); - - mp_msg(MSGT_ENCODE, MSGL_INFO, "Opening muxer: %s [%s]\n", - ctx->avc->oformat->long_name, ctx->avc->oformat->name); - - if (avformat_write_header(ctx->avc, &ctx->foptions) < 0) { - encode_lavc_fail(ctx, "encode-lavc: could not write header\n"); - return 0; - } - - for (de = NULL; (de = av_dict_get(ctx->foptions, "", de, - AV_DICT_IGNORE_SUFFIX));) - mp_msg(MSGT_ENCODE, MSGL_WARN, "ofopts: key '%s' not found.\n", de->key); - av_dict_free(&ctx->foptions); - - ctx->header_written = 1; - return 1; -} - -void encode_lavc_free(struct encode_lavc_context *ctx) -{ - if (!ctx) - return; - - if (!ctx->finished) - encode_lavc_fail(ctx, - "called encode_lavc_free without encode_lavc_finish\n"); - - talloc_free(ctx); -} - -void encode_lavc_finish(struct encode_lavc_context *ctx) -{ - unsigned i; - - if (!ctx) - return; - - if (ctx->finished) - return; - - if (ctx->avc) { - if (ctx->header_written > 0) - av_write_trailer(ctx->avc); // this is allowed to fail - - for (i = 0; i < ctx->avc->nb_streams; i++) { - switch (ctx->avc->streams[i]->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (ctx->twopass_bytebuffer_v) { - char *stats = ctx->avc->streams[i]->codec->stats_out; - if (stats) - stream_write_buffer(ctx->twopass_bytebuffer_v, - stats, strlen(stats)); - } - break; - case AVMEDIA_TYPE_AUDIO: - if (ctx->twopass_bytebuffer_a) { - char *stats = ctx->avc->streams[i]->codec->stats_out; - if (stats) - stream_write_buffer(ctx->twopass_bytebuffer_a, - stats, strlen(stats)); - } - break; - default: - break; - } - avcodec_close(ctx->avc->streams[i]->codec); - talloc_free(ctx->avc->streams[i]->codec->stats_in); - av_free(ctx->avc->streams[i]->codec); - av_free(ctx->avc->streams[i]->info); - av_free(ctx->avc->streams[i]); - } - - if (ctx->twopass_bytebuffer_v) { - free_stream(ctx->twopass_bytebuffer_v); - ctx->twopass_bytebuffer_v = NULL; - } - - if (ctx->twopass_bytebuffer_a) { - free_stream(ctx->twopass_bytebuffer_a); - ctx->twopass_bytebuffer_a = NULL; - } - - mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: encoded %lld bytes\n", - ctx->vbytes); - mp_msg(MSGT_ENCODE, MSGL_INFO, "ao-lavc: encoded %lld bytes\n", - ctx->abytes); - if (ctx->avc->pb) { - mp_msg(MSGT_ENCODE, MSGL_INFO, - "encode-lavc: muxing overhead %lld bytes\n", - (long long) (avio_size(ctx->avc->pb) - ctx->vbytes - - ctx->abytes)); - avio_close(ctx->avc->pb); - } - - av_free(ctx->avc); - } - - ctx->finished = true; -} - -void encode_lavc_set_video_fps(struct encode_lavc_context *ctx, float fps) -{ - ctx->vo_fps = fps; -} - -static void encode_2pass_prepare(struct encode_lavc_context *ctx, - AVDictionary **dictp, - AVStream *stream, struct stream **bytebuf, - const char *prefix) -{ - if (!*bytebuf) { - char buf[sizeof(ctx->avc->filename) + 12]; - AVDictionaryEntry *de = av_dict_get(ctx->voptions, "flags", NULL, 0); - - snprintf(buf, sizeof(buf), "%s-%s-pass1.log", ctx->avc->filename, - prefix); - buf[sizeof(buf) - 1] = 0; - - if (value_has_flag(de ? de->value : "", "pass2")) { - if (!(*bytebuf = stream_open(buf, NULL))) { - mp_msg(MSGT_ENCODE, MSGL_WARN, "%s: could not open '%s', " - "disabling 2-pass encoding at pass 2\n", prefix, buf); - stream->codec->flags &= ~CODEC_FLAG_PASS2; - set_to_avdictionary(dictp, "flags", "-pass2"); - } else { - struct bstr content = stream_read_complete(*bytebuf, NULL, - 1000000000); - if (content.start == NULL) { - mp_msg(MSGT_ENCODE, MSGL_WARN, "%s: could not read '%s', " - "disabling 2-pass encoding at pass 1\n", - prefix, ctx->avc->filename); - } else { - content.start[content.len] = 0; - stream->codec->stats_in = content.start; - } - free_stream(*bytebuf); - *bytebuf = NULL; - } - } - - if (value_has_flag(de ? de->value : "", "pass1")) { - if (!(*bytebuf = open_output_stream(buf, NULL))) { - mp_msg( - MSGT_ENCODE, MSGL_WARN, - "%s: could not open '%s', disabling " - "2-pass encoding at pass 1\n", - prefix, ctx->avc->filename); - set_to_avdictionary(dictp, "flags", "-pass1"); - } - } - } -} - -AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, - enum AVMediaType mt) -{ - AVDictionaryEntry *de; - AVStream *stream = NULL; - char **p; - int i; - - CHECK_FAIL(ctx, NULL); - - if (ctx->header_written) - return NULL; - - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == mt) - // already have a stream of that type, this cannot really happen - return NULL; - - if (ctx->avc->nb_streams == 0) { - // if this stream isn't stream #0, allocate a dummy stream first for - // the next loop to use - if (mt == AVMEDIA_TYPE_VIDEO && ctx->audio_first) { - mp_msg(MSGT_ENCODE, MSGL_INFO, - "vo-lavc: preallocated audio stream for later use\n"); - avformat_new_stream(ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now - } - if (mt == AVMEDIA_TYPE_AUDIO && ctx->video_first) { - mp_msg(MSGT_ENCODE, MSGL_INFO, - "ao-lavc: preallocated video stream for later use\n"); - avformat_new_stream(ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now - } - } else { - // find possibly preallocated stream - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_UNKNOWN) // preallocated stream - stream = ctx->avc->streams[i]; - } - if (!stream) - stream = avformat_new_stream(ctx->avc, NULL); - - if (ctx->timebase.den == 0) { - AVRational r; - - if (ctx->options->fps > 0) - r = av_d2q(ctx->options->fps, ctx->options->fps * 1001 + 2); - else if (ctx->options->autofps && ctx->vo_fps > 0) { - r = av_d2q(ctx->vo_fps, ctx->vo_fps * 1001 + 2); - mp_msg( - MSGT_ENCODE, MSGL_INFO, "vo-lavc: option --ofps not specified " - "but --oautofps is active, using guess of %u/%u\n", - (unsigned)r.num, (unsigned)r.den); - } else { - // we want to handle: - // 1/25 - // 1001/24000 - // 1001/30000 - // for this we would need 120000fps... - // however, mpeg-4 only allows 16bit values - // so let's take 1001/30000 out - r.num = 24000; - r.den = 1; - mp_msg( - MSGT_ENCODE, MSGL_INFO, "vo-lavc: option --ofps not specified " - "and fps could not be inferred, using guess of %u/%u\n", - (unsigned)r.num, (unsigned)r.den); - } - - if (ctx->vc && ctx->vc->supported_framerates) - r = ctx->vc->supported_framerates[av_find_nearest_q_idx(r, - ctx->vc->supported_framerates)]; - - ctx->timebase.num = r.den; - ctx->timebase.den = r.num; - } - - switch (mt) { - case AVMEDIA_TYPE_VIDEO: - if (!ctx->vc) { - encode_lavc_fail(ctx, "vo-lavc: encoder not found\n"); - return NULL; - } - avcodec_get_context_defaults3(stream->codec, ctx->vc); - - // stream->time_base = ctx->timebase; - // doing this breaks mpeg2ts in ffmpeg - // which doesn't properly force the time base to be 90000 - // furthermore, ffmpeg.c doesn't do this either and works - - stream->codec->time_base = ctx->timebase; - - ctx->voptions = NULL; - - if (ctx->options->vopts) - for (p = ctx->options->vopts; *p; ++p) - if (!set_to_avdictionary(&ctx->voptions, NULL, *p)) - mp_msg(MSGT_ENCODE, MSGL_WARN, - "vo-lavc: could not set option %s\n", *p); - - de = av_dict_get(ctx->voptions, "global_quality", NULL, 0); - if (de) - set_to_avdictionary(&ctx->voptions, "flags", "+qscale"); - - if (ctx->avc->oformat->flags & AVFMT_GLOBALHEADER) - set_to_avdictionary(&ctx->voptions, "flags", "+global_header"); - - encode_2pass_prepare(ctx, &ctx->voptions, stream, - &ctx->twopass_bytebuffer_v, - "vo-lavc"); - break; - - case AVMEDIA_TYPE_AUDIO: - if (!ctx->ac) { - encode_lavc_fail(ctx, "ao-lavc: encoder not found\n"); - return NULL; - } - avcodec_get_context_defaults3(stream->codec, ctx->ac); - - stream->codec->time_base = ctx->timebase; - - ctx->aoptions = NULL; - - if (ctx->options->aopts) - for (p = ctx->options->aopts; *p; ++p) - if (!set_to_avdictionary(&ctx->aoptions, NULL, *p)) - mp_msg(MSGT_ENCODE, MSGL_WARN, - "ao-lavc: could not set option %s\n", *p); - - de = av_dict_get(ctx->aoptions, "global_quality", NULL, 0); - if (de) - set_to_avdictionary(&ctx->aoptions, "flags", "+qscale"); - - if (ctx->avc->oformat->flags & AVFMT_GLOBALHEADER) - set_to_avdictionary(&ctx->aoptions, "flags", "+global_header"); - - encode_2pass_prepare(ctx, &ctx->aoptions, stream, - &ctx->twopass_bytebuffer_a, - "ao-lavc"); - break; - - default: - encode_lavc_fail(ctx, "encode-lavc: requested invalid stream type\n"); - return NULL; - } - - return stream; -} - -AVCodec *encode_lavc_get_codec(struct encode_lavc_context *ctx, - AVStream *stream) -{ - CHECK_FAIL(ctx, NULL); - - switch (stream->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - return ctx->vc; - case AVMEDIA_TYPE_AUDIO: - return ctx->ac; - default: - break; - } - return NULL; -} - -int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) -{ - AVDictionaryEntry *de; - int ret; - - CHECK_FAIL(ctx, -1); - - switch (stream->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - mp_msg(MSGT_ENCODE, MSGL_INFO, "Opening video encoder: %s [%s]\n", - ctx->vc->long_name, ctx->vc->name); - - if (ctx->vc->capabilities & CODEC_CAP_EXPERIMENTAL) { - stream->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - mp_msg(MSGT_ENCODE, MSGL_WARN, _( - "\n\n" - " ********************************************\n" - " **** Experimental VIDEO codec selected! ****\n" - " ********************************************\n\n" - "This means the output file may be broken or bad.\n" - "Possible reasons, problems, workarounds:\n" - "- Codec implementation in ffmpeg/libav is not finished yet.\n" - " Try updating ffmpeg or libav.\n" - "- Bad picture quality, blocks, blurriness.\n" - " Experiment with codec settings (--ovcopts) to maybe still get the\n" - " desired quality output at the expense of bitrate.\n" - "- Slow compression.\n" - " Bear with it.\n" - "- Crashes.\n" - " Happens. Try varying options to work around.\n" - "If none of this helps you, try another codec in place of %s.\n\n"), - ctx->vc->name); - } - - ret = avcodec_open2(stream->codec, ctx->vc, &ctx->voptions); - - // complain about all remaining options, then free the dict - for (de = NULL; (de = av_dict_get(ctx->voptions, "", de, - AV_DICT_IGNORE_SUFFIX));) - mp_msg(MSGT_ENCODE, MSGL_WARN, "ovcopts: key '%s' not found.\n", - de->key); - av_dict_free(&ctx->voptions); - - break; - case AVMEDIA_TYPE_AUDIO: - mp_msg(MSGT_ENCODE, MSGL_INFO, "Opening audio encoder: %s [%s]\n", - ctx->ac->long_name, ctx->ac->name); - - if (ctx->ac->capabilities & CODEC_CAP_EXPERIMENTAL) { - stream->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - mp_msg(MSGT_ENCODE, MSGL_WARN, _( - "\n\n" - " ********************************************\n" - " **** Experimental AUDIO codec selected! ****\n" - " ********************************************\n\n" - "This means the output file may be broken or bad.\n" - "Possible reasons, problems, workarounds:\n" - "- Codec implementation in ffmpeg/libav is not finished yet.\n" - " Try updating ffmpeg or libav.\n" - "- Bad sound quality, noise, clicking, whistles, choppiness.\n" - " Experiment with codec settings (--oacopts) to maybe still get the\n" - " desired quality output at the expense of bitrate.\n" - "- Slow compression.\n" - " Bear with it.\n" - "- Crashes.\n" - " Happens. Try varying options to work around.\n" - "If none of this helps you, try another codec in place of %s.\n\n"), - ctx->ac->name); - } - ret = avcodec_open2(stream->codec, ctx->ac, &ctx->aoptions); - - // complain about all remaining options, then free the dict - for (de = NULL; (de = av_dict_get(ctx->aoptions, "", de, - AV_DICT_IGNORE_SUFFIX));) - mp_msg(MSGT_ENCODE, MSGL_WARN, "oacopts: key '%s' not found.\n", - de->key); - av_dict_free(&ctx->aoptions); - - break; - default: - ret = -1; - break; - } - - if (ret < 0) - encode_lavc_fail(ctx, - "unable to open encoder (see above for the cause)"); - - return ret; -} - -void encode_lavc_write_stats(struct encode_lavc_context *ctx, AVStream *stream) -{ - CHECK_FAIL(ctx, ); - - switch (stream->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (ctx->twopass_bytebuffer_v) - if (stream->codec->stats_out) - stream_write_buffer(ctx->twopass_bytebuffer_v, - stream->codec->stats_out, - strlen(stream->codec->stats_out)); - break; - case AVMEDIA_TYPE_AUDIO: - if (ctx->twopass_bytebuffer_a) - if (stream->codec->stats_out) - stream_write_buffer(ctx->twopass_bytebuffer_a, - stream->codec->stats_out, - strlen(stream->codec->stats_out)); - break; - default: - break; - } -} - -int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVPacket *packet) -{ - int r; - - CHECK_FAIL(ctx, -1); - - if (ctx->header_written <= 0) - return -1; - - mp_msg( - MSGT_ENCODE, MSGL_DBG2, - "encode-lavc: write frame: stream %d ptsi %d (%f) dtsi %d (%f) size %d\n", - (int)packet->stream_index, - (int)packet->pts, - packet->pts - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den, - (int)packet->dts, - packet->dts - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den, - (int)packet->size); - - switch (ctx->avc->streams[packet->stream_index]->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - ctx->vbytes += packet->size; - ++ctx->frames; - break; - case AVMEDIA_TYPE_AUDIO: - ctx->abytes += packet->size; - ctx->audioseconds += packet->duration - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den; - break; - default: - break; - } - - r = av_interleaved_write_frame(ctx->avc, packet); - - return r; -} - -int encode_lavc_supports_pixfmt(struct encode_lavc_context *ctx, - enum PixelFormat pix_fmt) -{ - CHECK_FAIL(ctx, 0); - - if (!ctx->vc) - return 0; - if (pix_fmt == PIX_FMT_NONE) - return 0; - - if (!ctx->vc->pix_fmts) - return VFCAP_CSP_SUPPORTED; - else { - const enum PixelFormat *p; - for (p = ctx->vc->pix_fmts; *p >= 0; ++p) { - if (pix_fmt == *p) - return VFCAP_CSP_SUPPORTED; - } - } - return 0; -} - -void encode_lavc_discontinuity(struct encode_lavc_context *ctx) -{ - if (!ctx) - return; - - CHECK_FAIL(ctx, ); - - ctx->audio_pts_offset = MP_NOPTS_VALUE; - ctx->last_video_in_pts = MP_NOPTS_VALUE; - ctx->discontinuity_pts_offset = MP_NOPTS_VALUE; -} - -static void encode_lavc_printoptions(void *obj, const char *indent, - const char *subindent, const char *unit, - int filter_and, int filter_eq) -{ - const AVOption *opt = NULL; - char optbuf[32]; - while ((opt = av_opt_next(obj, opt))) { - // if flags are 0, it simply hasn't been filled in yet and may be - // potentially useful - if (opt->flags) - if ((opt->flags & filter_and) != filter_eq) - continue; - /* Don't print CONST's on level one. - * Don't print anything but CONST's on level two. - * Only print items from the requested unit. - */ - if (!unit && opt->type == AV_OPT_TYPE_CONST) - continue; - else if (unit && opt->type != AV_OPT_TYPE_CONST) - continue; - else if (unit && opt->type == AV_OPT_TYPE_CONST - && strcmp(unit, opt->unit)) - continue; - else if (unit && opt->type == AV_OPT_TYPE_CONST) - mp_msg(MSGT_ENCODE, MSGL_INFO, "%s", subindent); - else - mp_msg(MSGT_ENCODE, MSGL_INFO, "%s", indent); - - switch (opt->type) { - case AV_OPT_TYPE_FLAGS: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_INT: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_INT64: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_DOUBLE: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_FLOAT: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_STRING: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_RATIONAL: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_BINARY: - snprintf(optbuf, sizeof(optbuf), "%s=", opt->name); - break; - case AV_OPT_TYPE_CONST: - snprintf(optbuf, sizeof(optbuf), " [+-]%s", opt->name); - break; - default: - snprintf(optbuf, sizeof(optbuf), "%s", opt->name); - break; - } - optbuf[sizeof(optbuf) - 1] = 0; - mp_msg(MSGT_ENCODE, MSGL_INFO, "%-32s ", optbuf); - if (opt->help) - mp_msg(MSGT_ENCODE, MSGL_INFO, " %s", opt->help); - mp_msg(MSGT_ENCODE, MSGL_INFO, "\n"); - if (opt->unit && opt->type != AV_OPT_TYPE_CONST) - encode_lavc_printoptions(obj, indent, subindent, opt->unit, - filter_and, filter_eq); - } -} - -bool encode_lavc_showhelp(struct MPOpts *opts) -{ - bool help_output = false; - if (av_codec_next(NULL) == NULL) - mp_msg(MSGT_ENCODE, MSGL_ERR, "NO CODECS\n"); -#define CHECKS(str) ((str) && \ - strcmp((str), "help") == 0 ? (help_output |= 1) : 0) -#define CHECKV(strv) ((strv) && (strv)[0] && \ - strcmp((strv)[0], "help") == 0 ? (help_output |= 1) : 0) - if (CHECKS(opts->encode_output.format)) { - AVOutputFormat *c = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, "Available output formats:\n"); - while ((c = av_oformat_next(c))) - mp_msg(MSGT_ENCODE, MSGL_INFO, " --of=%-13s %s\n", c->name, - c->long_name ? c->long_name : ""); - av_free(c); - } - if (CHECKV(opts->encode_output.fopts)) { - AVFormatContext *c = avformat_alloc_context(); - AVOutputFormat *format = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, - "Available output format ctx->options:\n"); - encode_lavc_printoptions(c, " --ofopts=", " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM, - AV_OPT_FLAG_ENCODING_PARAM); - av_free(c); - while ((format = av_oformat_next(format))) { - if (format->priv_class) { - mp_msg(MSGT_ENCODE, MSGL_INFO, "Additionally, for --of=%s:\n", - format->name); - encode_lavc_printoptions(&format->priv_class, " --ofopts=", - " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM, - AV_OPT_FLAG_ENCODING_PARAM); - } - } - } - if (CHECKV(opts->encode_output.vopts)) { - AVCodecContext *c = avcodec_alloc_context3(NULL); - AVCodec *codec = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, - "Available output video codec ctx->options:\n"); - encode_lavc_printoptions( - c, " --ovcopts=", " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_VIDEO_PARAM, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_VIDEO_PARAM); - av_free(c); - while ((codec = av_codec_next(codec))) { - if (!av_codec_is_encoder(codec)) - continue; - if (codec->type != AVMEDIA_TYPE_VIDEO) - continue; - if (opts->encode_output.vcodec && opts->encode_output.vcodec[0] && - strcmp(opts->encode_output.vcodec, codec->name) != 0) - continue; - if (codec->priv_class) { - mp_msg(MSGT_ENCODE, MSGL_INFO, "Additionally, for --ovc=%s:\n", - codec->name); - encode_lavc_printoptions( - &codec->priv_class, " --ovcopts=", - " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_VIDEO_PARAM, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_VIDEO_PARAM); - } - } - } - if (CHECKV(opts->encode_output.aopts)) { - AVCodecContext *c = avcodec_alloc_context3(NULL); - AVCodec *codec = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, - "Available output audio codec ctx->options:\n"); - encode_lavc_printoptions( - c, " --oacopts=", " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_AUDIO_PARAM, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_AUDIO_PARAM); - av_free(c); - while ((codec = av_codec_next(codec))) { - if (!av_codec_is_encoder(codec)) - continue; - if (codec->type != AVMEDIA_TYPE_AUDIO) - continue; - if (opts->encode_output.acodec && opts->encode_output.acodec[0] && - strcmp(opts->encode_output.acodec, codec->name) != 0) - continue; - if (codec->priv_class) { - mp_msg(MSGT_ENCODE, MSGL_INFO, "Additionally, for --oac=%s:\n", - codec->name); - encode_lavc_printoptions( - &codec->priv_class, " --oacopts=", - " ", NULL, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_AUDIO_PARAM, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_AUDIO_PARAM); - } - } - } - if (CHECKS(opts->encode_output.vcodec)) { - AVCodec *c = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, "Available output video codecs:\n"); - while ((c = av_codec_next(c))) { - if (!av_codec_is_encoder(c)) - continue; - if (c->type != AVMEDIA_TYPE_VIDEO) - continue; - mp_msg(MSGT_ENCODE, MSGL_INFO, " --ovc=%-12s %s\n", c->name, - c->long_name ? c->long_name : ""); - } - av_free(c); - } - if (CHECKS(opts->encode_output.acodec)) { - AVCodec *c = NULL; - mp_msg(MSGT_ENCODE, MSGL_INFO, "Available output audio codecs:\n"); - while ((c = av_codec_next(c))) { - if (!av_codec_is_encoder(c)) - continue; - if (c->type != AVMEDIA_TYPE_AUDIO) - continue; - mp_msg(MSGT_ENCODE, MSGL_INFO, " --oac=%-12s %s\n", c->name, - c->long_name ? c->long_name : ""); - } - av_free(c); - } - return help_output; -} - -double encode_lavc_getoffset(struct encode_lavc_context *ctx, AVStream *stream) -{ - CHECK_FAIL(ctx, 0); - - switch (stream->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - return ctx->options->voffset; - case AVMEDIA_TYPE_AUDIO: - return ctx->options->aoffset; - default: - break; - } - return 0; -} - -int encode_lavc_getstatus(struct encode_lavc_context *ctx, - char *buf, int bufsize, - float relative_position) -{ - double now = mp_time_sec(); - float minutes, megabytes, fps, x; - float f = FFMAX(0.0001, relative_position); - if (!ctx) - return -1; - - CHECK_FAIL(ctx, -1); - - minutes = (now - ctx->t0) / 60.0 * (1 - f) / f; - megabytes = ctx->avc->pb ? (avio_size(ctx->avc->pb) / 1048576.0 / f) : 0; - fps = ctx->frames / (now - ctx->t0); - x = ctx->audioseconds / (now - ctx->t0); - if (ctx->frames) - snprintf(buf, bufsize, "{%.1fmin %.1ffps %.1fMB}", - minutes, fps, megabytes); - else if (ctx->audioseconds) - snprintf(buf, bufsize, "{%.1fmin %.2fx %.1fMB}", - minutes, x, megabytes); - else - snprintf(buf, bufsize, "{%.1fmin %.1fMB}", - minutes, megabytes); - buf[bufsize - 1] = 0; - return 0; -} - -void encode_lavc_expect_stream(struct encode_lavc_context *ctx, - enum AVMediaType mt) -{ - CHECK_FAIL(ctx, ); - - switch (mt) { - case AVMEDIA_TYPE_VIDEO: - ctx->expect_video = true; - break; - case AVMEDIA_TYPE_AUDIO: - ctx->expect_audio = true; - break; - } -} - -bool encode_lavc_didfail(struct encode_lavc_context *ctx) -{ - return ctx && ctx->failed; -} - -void encode_lavc_fail(struct encode_lavc_context *ctx, const char *format, ...) -{ - va_list va; - va_start(va, format); - mp_msg_va(MSGT_ENCODE, MSGL_ERR, format, va); - if (ctx->failed) - return; - ctx->failed = true; - encode_lavc_finish(ctx); -} - -bool encode_lavc_set_csp(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp csp) -{ - CHECK_FAIL(ctx, NULL); - - if (ctx->header_written) { - if (stream->codec->colorspace != mp_csp_to_avcol_spc(csp)) - mp_msg(MSGT_ENCODE, MSGL_WARN, - "encode-lavc: can not change color space during encoding\n"); - return false; - } - - stream->codec->colorspace = mp_csp_to_avcol_spc(csp); - return true; -} - -bool encode_lavc_set_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp_levels lev) -{ - CHECK_FAIL(ctx, NULL); - - if (ctx->header_written) { - if (stream->codec->color_range != mp_csp_levels_to_avcol_range(lev)) - mp_msg(MSGT_ENCODE, MSGL_WARN, - "encode-lavc: can not change color space during encoding\n"); - return false; - } - - stream->codec->color_range = mp_csp_levels_to_avcol_range(lev); - return true; -} - -enum mp_csp encode_lavc_get_csp(struct encode_lavc_context *ctx, - AVStream *stream) -{ - CHECK_FAIL(ctx, 0); - - return avcol_spc_to_mp_csp(stream->codec->colorspace); -} - -enum mp_csp_levels encode_lavc_get_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream) -{ - CHECK_FAIL(ctx, 0); - - return avcol_range_to_mp_csp_levels(stream->codec->color_range); -} - -// vim: ts=4 sw=4 et diff --git a/core/encode_lavc.h b/core/encode_lavc.h deleted file mode 100644 index f47825e1d7..0000000000 --- a/core/encode_lavc.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * muxing using libavformat - * Copyright (C) 2011 Rudolf Polzer - * - * This file is part of mpv. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_ENCODE_LAVC_H -#define MPLAYER_ENCODE_LAVC_H - -#include -#include -#include -#include -#include -#include - -#include "encode.h" -#include "video/csputils.h" - -struct encode_lavc_context { - struct encode_output_conf *options; - - float vo_fps; - - // these are processed from the options - AVFormatContext *avc; - AVRational timebase; - AVCodec *vc; - AVCodec *ac; - AVDictionary *foptions; - AVDictionary *aoptions; - AVDictionary *voptions; - - // values created during encoding - int header_written; // -1 means currently writing - - // sync to audio mode - double audio_pts_offset; - double last_video_in_pts; - - // anti discontinuity mode - double next_in_pts; - double discontinuity_pts_offset; - - long long abytes; - long long vbytes; - struct stream *twopass_bytebuffer_a; - struct stream *twopass_bytebuffer_v; - double t0; - unsigned int frames; - double audioseconds; - - bool expect_video; - bool expect_audio; - bool video_first; - bool audio_first; - - // has encoding failed? - bool failed; - bool finished; -}; - -// interface for vo/ao drivers -AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, enum AVMediaType mt); -void encode_lavc_write_stats(struct encode_lavc_context *ctx, AVStream *stream); -int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVPacket *packet); -int encode_lavc_supports_pixfmt(struct encode_lavc_context *ctx, enum PixelFormat format); -AVCodec *encode_lavc_get_codec(struct encode_lavc_context *ctx, AVStream *stream); -int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream); -int encode_lavc_available(struct encode_lavc_context *ctx); -int encode_lavc_timesyncfailed(struct encode_lavc_context *ctx); -int encode_lavc_start(struct encode_lavc_context *ctx); // returns 1 on success -int encode_lavc_oformat_flags(struct encode_lavc_context *ctx); -double encode_lavc_getoffset(struct encode_lavc_context *ctx, AVStream *stream); -void encode_lavc_fail(struct encode_lavc_context *ctx, const char *format, ...); // report failure of encoding - -bool encode_lavc_set_csp(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp csp); -bool encode_lavc_set_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp_levels lev); -enum mp_csp encode_lavc_get_csp(struct encode_lavc_context *ctx, - AVStream *stream); -enum mp_csp_levels encode_lavc_get_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream); - -#endif diff --git a/core/input/input.c b/core/input/input.c deleted file mode 100644 index ae1358a76d..0000000000 --- a/core/input/input.c +++ /dev/null @@ -1,2284 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "osdep/io.h" -#include "osdep/getch2.h" - -#include "input.h" -#include "keycodes.h" -#include "osdep/timer.h" -#include "core/mp_msg.h" -#include "core/m_config.h" -#include "core/m_option.h" -#include "core/path.h" -#include "talloc.h" -#include "core/options.h" -#include "core/bstr.h" -#include "stream/stream.h" -#include "core/mp_common.h" - -#include "joystick.h" - -#ifdef CONFIG_LIRC -#include "lirc.h" -#endif - -#ifdef CONFIG_LIRCC -#include -#endif - -#ifdef CONFIG_COCOA -#include "osdep/macosx_events.h" -#endif - -#define MP_MAX_KEY_DOWN 4 - -struct cmd_bind { - int keys[MP_MAX_KEY_DOWN]; - int num_keys; - char *cmd; - char *location; // filename/line number of definition - bool is_builtin; - struct cmd_bind_section *owner; -}; - -struct key_name { - int key; - char *name; -}; - -/* This array defines all known commands. - * The first field is an id used to recognize the command. - * The second is the command name used in slave mode and input.conf. - * Then comes the definition of each argument, first mandatory arguments - * (ARG_INT, ARG_FLOAT, ARG_STRING) if any, then optional arguments - * (OARG_INT(default), etc) if any. The command will be given the default - * argument value if the user didn't give enough arguments to specify it. - * A command can take a maximum of MP_CMD_MAX_ARGS arguments (10). - */ - -#define ARG_INT { .type = {"", NULL, &m_option_type_int} } -#define ARG_FLOAT { .type = {"", NULL, &m_option_type_float} } -#define ARG_DOUBLE { .type = {"", NULL, &m_option_type_double} } -#define ARG_STRING { .type = {"", NULL, &m_option_type_string} } -#define ARG_CHOICE(c) { .type = {"", NULL, &m_option_type_choice, \ - M_CHOICES(c)} } -#define ARG_TIME { .type = {"", NULL, &m_option_type_time} } - -#define OARG_DOUBLE(def) { .type = {"", NULL, &m_option_type_double}, \ - .optional = true, .v.d = def } -#define OARG_INT(def) { .type = {"", NULL, &m_option_type_int}, \ - .optional = true, .v.i = def } -#define OARG_CHOICE(def, c) { .type = {"", NULL, &m_option_type_choice, \ - M_CHOICES(c)}, \ - .optional = true, .v.i = def } - -static int parse_cycle_dir(const struct m_option *opt, struct bstr name, - struct bstr param, void *dst); -static const struct m_option_type m_option_type_cycle_dir = { - .name = "up|down", - .parse = parse_cycle_dir, -}; - -static const mp_cmd_t mp_cmds[] = { - { MP_CMD_IGNORE, "ignore", }, - - { MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", { ARG_INT } }, - { MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", { ARG_STRING } }, - { MP_CMD_RADIO_SET_FREQ, "radio_set_freq", { ARG_FLOAT } }, - { MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", {ARG_FLOAT } }, - - { MP_CMD_SEEK, "seek", { - ARG_TIME, - OARG_CHOICE(0, ({"relative", 0}, {"0", 0}, - {"absolute-percent", 1}, {"1", 1}, - {"absolute", 2}, {"2", 2})), - OARG_CHOICE(0, ({"default-precise", 0}, {"0", 0}, - {"exact", 1}, {"1", 1}, - {"keyframes", -1}, {"-1", -1})), - }}, - { MP_CMD_SPEED_MULT, "speed_mult", { ARG_DOUBLE } }, - { MP_CMD_QUIT, "quit", { OARG_INT(0) } }, - { MP_CMD_QUIT_WATCH_LATER, "quit_watch_later", }, - { MP_CMD_STOP, "stop", }, - { MP_CMD_FRAME_STEP, "frame_step", }, - { MP_CMD_FRAME_BACK_STEP, "frame_back_step", }, - { MP_CMD_PLAYLIST_NEXT, "playlist_next", { - OARG_CHOICE(0, ({"weak", 0}, {"0", 0}, - {"force", 1}, {"1", 1})), - }}, - { MP_CMD_PLAYLIST_PREV, "playlist_prev", { - OARG_CHOICE(0, ({"weak", 0}, {"0", 0}, - {"force", 1}, {"1", 1})), - }}, - { MP_CMD_SUB_STEP, "sub_step", { ARG_INT } }, - { MP_CMD_OSD, "osd", { OARG_INT(-1) } }, - { MP_CMD_PRINT_TEXT, "print_text", { ARG_STRING } }, - { MP_CMD_SHOW_TEXT, "show_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } }, - { MP_CMD_SHOW_PROGRESS, "show_progress", }, - { MP_CMD_SUB_ADD, "sub_add", { ARG_STRING } }, - { MP_CMD_SUB_REMOVE, "sub_remove", { OARG_INT(-1) } }, - { MP_CMD_SUB_RELOAD, "sub_reload", { OARG_INT(-1) } }, - - { MP_CMD_TV_START_SCAN, "tv_start_scan", }, - { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", { ARG_INT } }, - { MP_CMD_TV_STEP_NORM, "tv_step_norm", }, - { MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", }, - { MP_CMD_TV_SET_CHANNEL, "tv_set_channel", { ARG_STRING } }, - { MP_CMD_TV_LAST_CHANNEL, "tv_last_channel", }, - { MP_CMD_TV_SET_FREQ, "tv_set_freq", { ARG_FLOAT } }, - { MP_CMD_TV_STEP_FREQ, "tv_step_freq", { ARG_FLOAT } }, - { MP_CMD_TV_SET_NORM, "tv_set_norm", { ARG_STRING } }, - - { MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", { ARG_INT, ARG_INT } }, - - { MP_CMD_SCREENSHOT, "screenshot", { - OARG_CHOICE(2, ({"video", 0}, - {"window", 1}, - {"subtitles", 2})), - OARG_CHOICE(0, ({"single", 0}, - {"each-frame", 1})), - }}, - { MP_CMD_SCREENSHOT_TO_FILE, "screenshot_to_file", { - ARG_STRING, - OARG_CHOICE(2, ({"video", 0}, - {"window", 1}, - {"subtitles", 2})), - }}, - { MP_CMD_LOADFILE, "loadfile", { - ARG_STRING, - OARG_CHOICE(0, ({"replace", 0}, {"0", 0}, - {"append", 1}, {"1", 1})), - }}, - { MP_CMD_LOADLIST, "loadlist", { - ARG_STRING, - OARG_CHOICE(0, ({"replace", 0}, {"0", 0}, - {"append", 1}, {"1", 1})), - }}, - { MP_CMD_PLAYLIST_CLEAR, "playlist_clear", }, - { MP_CMD_PLAYLIST_REMOVE, "playlist_remove", { ARG_INT } }, - { MP_CMD_PLAYLIST_MOVE, "playlist_move", { ARG_INT, ARG_INT } }, - { MP_CMD_RUN, "run", { ARG_STRING } }, - - { MP_CMD_KEYDOWN_EVENTS, "key_down_event", { ARG_INT } }, - { MP_CMD_SET, "set", { ARG_STRING, ARG_STRING } }, - { MP_CMD_GET_PROPERTY, "get_property", { ARG_STRING } }, - { MP_CMD_ADD, "add", { ARG_STRING, OARG_DOUBLE(0) } }, - { MP_CMD_CYCLE, "cycle", { - ARG_STRING, - { .type = {"", NULL, &m_option_type_cycle_dir}, - .optional = true, - .v.d = 1 }, - }}, - - { MP_CMD_ENABLE_INPUT_SECTION, "enable_section", { - ARG_STRING, - OARG_CHOICE(0, ({"default", 0}, - {"exclusive", 1})), - }}, - { MP_CMD_DISABLE_INPUT_SECTION, "disable_section", { ARG_STRING } }, - - { MP_CMD_AF, "af", { ARG_STRING, ARG_STRING } }, - - { MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } }, - - { MP_CMD_VO_CMDLINE, "vo_cmdline", { ARG_STRING } }, - - {0} -}; - -// Map legacy commands to proper commands -struct legacy_cmd { - const char *old, *new; -}; -static const struct legacy_cmd legacy_cmds[] = { - {"loop", "cycle loop"}, - {"seek_chapter", "add chapter"}, - {"switch_angle", "cycle angle"}, - {"pause", "cycle pause"}, - {"volume", "add volume"}, - {"mute", "cycle mute"}, - {"audio_delay", "add audio-delay"}, - {"switch_audio", "cycle audio"}, - {"balance", "add balance"}, - {"vo_fullscreen", "cycle fullscreen"}, - {"panscan", "add panscan"}, - {"vo_ontop", "cycle ontop"}, - {"vo_border", "cycle border"}, - {"frame_drop", "cycle framedrop"}, - {"gamma", "add gamma"}, - {"brightness", "add brightness"}, - {"contrast", "add contrast"}, - {"saturation", "add saturation"}, - {"hue", "add hue"}, - {"switch_vsync", "cycle vsync"}, - {"sub_load", "sub_add"}, - {"sub_select", "cycle sub"}, - {"sub_pos", "add sub-pos"}, - {"sub_delay", "add sub-delay"}, - {"sub_visibility", "cycle sub-visibility"}, - {"forced_subs_only", "cycle sub-forced-only"}, - {"sub_scale", "add sub-scale"}, - {"ass_use_margins", "cycle ass-use-margins"}, - {"tv_set_brightness", "add tv-brightness"}, - {"tv_set_hue", "add tv-hue"}, - {"tv_set_saturation", "add tv-saturation"}, - {"tv_set_contrast", "add tv-contrast"}, - {"step_property_osd", "cycle"}, - {"step_property", "no-osd cycle"}, - {"set_property", "no-osd set"}, - {"set_property_osd", "set"}, - {"speed_set", "set speed"}, - {"osd_show_text", "show_text"}, - {"osd_show_property_text", "show_text"}, - {"osd_show_progression", "show_progress"}, - {"show_chapters_osd", "show_text ${chapter-list}"}, - {"!show_chapters", "show_text ${chapter-list}"}, - {"show_tracks_osd", "show_text ${track-list}"}, - {"!show_tracks", "show_text ${track-list}"}, - {"!show_playlist", "show_text ${playlist}"}, - - // Approximate (can fail if user added additional whitespace) - {"pt_step 1", "playlist_next"}, - {"pt_step -1", "playlist_prev"}, - // Switch_ratio without argument resets aspect ratio - {"switch_ratio ", "set aspect "}, - {"switch_ratio", "set aspect 0"}, - {0} -}; - - -/// The names of the keys as used in input.conf -/// If you add some new keys, you also need to add them here - -static const struct key_name key_names[] = { - { ' ', "SPACE" }, - { '#', "SHARP" }, - { MP_KEY_ENTER, "ENTER" }, - { MP_KEY_TAB, "TAB" }, - { MP_KEY_BACKSPACE, "BS" }, - { MP_KEY_DELETE, "DEL" }, - { MP_KEY_INSERT, "INS" }, - { MP_KEY_HOME, "HOME" }, - { MP_KEY_END, "END" }, - { MP_KEY_PAGE_UP, "PGUP" }, - { MP_KEY_PAGE_DOWN, "PGDWN" }, - { MP_KEY_ESC, "ESC" }, - { MP_KEY_PRINT, "PRINT" }, - { MP_KEY_RIGHT, "RIGHT" }, - { MP_KEY_LEFT, "LEFT" }, - { MP_KEY_DOWN, "DOWN" }, - { MP_KEY_UP, "UP" }, - { MP_KEY_F+1, "F1" }, - { MP_KEY_F+2, "F2" }, - { MP_KEY_F+3, "F3" }, - { MP_KEY_F+4, "F4" }, - { MP_KEY_F+5, "F5" }, - { MP_KEY_F+6, "F6" }, - { MP_KEY_F+7, "F7" }, - { MP_KEY_F+8, "F8" }, - { MP_KEY_F+9, "F9" }, - { MP_KEY_F+10, "F10" }, - { MP_KEY_F+11, "F11" }, - { MP_KEY_F+12, "F12" }, - { MP_KEY_KP0, "KP0" }, - { MP_KEY_KP1, "KP1" }, - { MP_KEY_KP2, "KP2" }, - { MP_KEY_KP3, "KP3" }, - { MP_KEY_KP4, "KP4" }, - { MP_KEY_KP5, "KP5" }, - { MP_KEY_KP6, "KP6" }, - { MP_KEY_KP7, "KP7" }, - { MP_KEY_KP8, "KP8" }, - { MP_KEY_KP9, "KP9" }, - { MP_KEY_KPDEL, "KP_DEL" }, - { MP_KEY_KPDEC, "KP_DEC" }, - { MP_KEY_KPINS, "KP_INS" }, - { MP_KEY_KPENTER, "KP_ENTER" }, - { MP_MOUSE_BTN0, "MOUSE_BTN0" }, - { MP_MOUSE_BTN1, "MOUSE_BTN1" }, - { MP_MOUSE_BTN2, "MOUSE_BTN2" }, - { MP_MOUSE_BTN3, "MOUSE_BTN3" }, - { MP_MOUSE_BTN4, "MOUSE_BTN4" }, - { MP_MOUSE_BTN5, "MOUSE_BTN5" }, - { MP_MOUSE_BTN6, "MOUSE_BTN6" }, - { MP_MOUSE_BTN7, "MOUSE_BTN7" }, - { MP_MOUSE_BTN8, "MOUSE_BTN8" }, - { MP_MOUSE_BTN9, "MOUSE_BTN9" }, - { MP_MOUSE_BTN10, "MOUSE_BTN10" }, - { MP_MOUSE_BTN11, "MOUSE_BTN11" }, - { MP_MOUSE_BTN12, "MOUSE_BTN12" }, - { MP_MOUSE_BTN13, "MOUSE_BTN13" }, - { MP_MOUSE_BTN14, "MOUSE_BTN14" }, - { MP_MOUSE_BTN15, "MOUSE_BTN15" }, - { MP_MOUSE_BTN16, "MOUSE_BTN16" }, - { MP_MOUSE_BTN17, "MOUSE_BTN17" }, - { MP_MOUSE_BTN18, "MOUSE_BTN18" }, - { MP_MOUSE_BTN19, "MOUSE_BTN19" }, - { MP_MOUSE_BTN0_DBL, "MOUSE_BTN0_DBL" }, - { MP_MOUSE_BTN1_DBL, "MOUSE_BTN1_DBL" }, - { MP_MOUSE_BTN2_DBL, "MOUSE_BTN2_DBL" }, - { MP_MOUSE_BTN3_DBL, "MOUSE_BTN3_DBL" }, - { MP_MOUSE_BTN4_DBL, "MOUSE_BTN4_DBL" }, - { MP_MOUSE_BTN5_DBL, "MOUSE_BTN5_DBL" }, - { MP_MOUSE_BTN6_DBL, "MOUSE_BTN6_DBL" }, - { MP_MOUSE_BTN7_DBL, "MOUSE_BTN7_DBL" }, - { MP_MOUSE_BTN8_DBL, "MOUSE_BTN8_DBL" }, - { MP_MOUSE_BTN9_DBL, "MOUSE_BTN9_DBL" }, - { MP_MOUSE_BTN10_DBL, "MOUSE_BTN10_DBL" }, - { MP_MOUSE_BTN11_DBL, "MOUSE_BTN11_DBL" }, - { MP_MOUSE_BTN12_DBL, "MOUSE_BTN12_DBL" }, - { MP_MOUSE_BTN13_DBL, "MOUSE_BTN13_DBL" }, - { MP_MOUSE_BTN14_DBL, "MOUSE_BTN14_DBL" }, - { MP_MOUSE_BTN15_DBL, "MOUSE_BTN15_DBL" }, - { MP_MOUSE_BTN16_DBL, "MOUSE_BTN16_DBL" }, - { MP_MOUSE_BTN17_DBL, "MOUSE_BTN17_DBL" }, - { MP_MOUSE_BTN18_DBL, "MOUSE_BTN18_DBL" }, - { MP_MOUSE_BTN19_DBL, "MOUSE_BTN19_DBL" }, - { MP_JOY_AXIS1_MINUS, "JOY_UP" }, - { MP_JOY_AXIS1_PLUS, "JOY_DOWN" }, - { MP_JOY_AXIS0_MINUS, "JOY_LEFT" }, - { MP_JOY_AXIS0_PLUS, "JOY_RIGHT" }, - - { MP_JOY_AXIS0_PLUS, "JOY_AXIS0_PLUS" }, - { MP_JOY_AXIS0_MINUS, "JOY_AXIS0_MINUS" }, - { MP_JOY_AXIS1_PLUS, "JOY_AXIS1_PLUS" }, - { MP_JOY_AXIS1_MINUS, "JOY_AXIS1_MINUS" }, - { MP_JOY_AXIS2_PLUS, "JOY_AXIS2_PLUS" }, - { MP_JOY_AXIS2_MINUS, "JOY_AXIS2_MINUS" }, - { MP_JOY_AXIS3_PLUS, "JOY_AXIS3_PLUS" }, - { MP_JOY_AXIS3_MINUS, "JOY_AXIS3_MINUS" }, - { MP_JOY_AXIS4_PLUS, "JOY_AXIS4_PLUS" }, - { MP_JOY_AXIS4_MINUS, "JOY_AXIS4_MINUS" }, - { MP_JOY_AXIS5_PLUS, "JOY_AXIS5_PLUS" }, - { MP_JOY_AXIS5_MINUS, "JOY_AXIS5_MINUS" }, - { MP_JOY_AXIS6_PLUS, "JOY_AXIS6_PLUS" }, - { MP_JOY_AXIS6_MINUS, "JOY_AXIS6_MINUS" }, - { MP_JOY_AXIS7_PLUS, "JOY_AXIS7_PLUS" }, - { MP_JOY_AXIS7_MINUS, "JOY_AXIS7_MINUS" }, - { MP_JOY_AXIS8_PLUS, "JOY_AXIS8_PLUS" }, - { MP_JOY_AXIS8_MINUS, "JOY_AXIS8_MINUS" }, - { MP_JOY_AXIS9_PLUS, "JOY_AXIS9_PLUS" }, - { MP_JOY_AXIS9_MINUS, "JOY_AXIS9_MINUS" }, - - { MP_JOY_BTN0, "JOY_BTN0" }, - { MP_JOY_BTN1, "JOY_BTN1" }, - { MP_JOY_BTN2, "JOY_BTN2" }, - { MP_JOY_BTN3, "JOY_BTN3" }, - { MP_JOY_BTN4, "JOY_BTN4" }, - { MP_JOY_BTN5, "JOY_BTN5" }, - { MP_JOY_BTN6, "JOY_BTN6" }, - { MP_JOY_BTN7, "JOY_BTN7" }, - { MP_JOY_BTN8, "JOY_BTN8" }, - { MP_JOY_BTN9, "JOY_BTN9" }, - - { MP_AR_PLAY, "AR_PLAY" }, - { MP_AR_PLAY_HOLD, "AR_PLAY_HOLD" }, - { MP_AR_CENTER, "AR_CENTER" }, - { MP_AR_CENTER_HOLD, "AR_CENTER_HOLD" }, - { MP_AR_NEXT, "AR_NEXT" }, - { MP_AR_NEXT_HOLD, "AR_NEXT_HOLD" }, - { MP_AR_PREV, "AR_PREV" }, - { MP_AR_PREV_HOLD, "AR_PREV_HOLD" }, - { MP_AR_MENU, "AR_MENU" }, - { MP_AR_MENU_HOLD, "AR_MENU_HOLD" }, - { MP_AR_VUP, "AR_VUP" }, - { MP_AR_VUP_HOLD, "AR_VUP_HOLD" }, - { MP_AR_VDOWN, "AR_VDOWN" }, - { MP_AR_VDOWN_HOLD, "AR_VDOWN_HOLD" }, - - { MP_MK_PLAY, "MK_PLAY" }, - { MP_MK_PREV, "MK_PREV" }, - { MP_MK_NEXT, "MK_NEXT" }, - - { MP_KEY_POWER, "POWER" }, - { MP_KEY_MENU, "MENU" }, - { MP_KEY_PLAY, "PLAY" }, - { MP_KEY_PAUSE, "PAUSE" }, - { MP_KEY_PLAYPAUSE, "PLAYPAUSE" }, - { MP_KEY_STOP, "STOP" }, - { MP_KEY_FORWARD, "FORWARD" }, - { MP_KEY_REWIND, "REWIND" }, - { MP_KEY_NEXT, "NEXT" }, - { MP_KEY_PREV, "PREV" }, - { MP_KEY_VOLUME_UP, "VOLUME_UP" }, - { MP_KEY_VOLUME_DOWN, "VOLUME_DOWN" }, - { MP_KEY_MUTE, "MUTE" }, - - // These are kept for backward compatibility - { MP_KEY_PAUSE, "XF86_PAUSE" }, - { MP_KEY_STOP, "XF86_STOP" }, - { MP_KEY_PREV, "XF86_PREV" }, - { MP_KEY_NEXT, "XF86_NEXT" }, - - { MP_KEY_CLOSE_WIN, "CLOSE_WIN" }, - { MP_KEY_MOUSE_MOVE, "MOUSE_MOVE" }, - { MP_KEY_MOUSE_LEAVE, "MOUSE_LEAVE" }, - - { 0, NULL } -}; - -struct key_name modifier_names[] = { - { MP_KEY_MODIFIER_SHIFT, "Shift" }, - { MP_KEY_MODIFIER_CTRL, "Ctrl" }, - { MP_KEY_MODIFIER_ALT, "Alt" }, - { MP_KEY_MODIFIER_META, "Meta" }, - { 0 } -}; - -#define MP_MAX_FDS 10 - -struct input_fd { - int fd; - int (*read_key)(void *ctx, int fd); - int (*read_cmd)(int fd, char *dest, int size); - int (*close_func)(int fd); - void *ctx; - unsigned eof : 1; - unsigned drop : 1; - unsigned dead : 1; - unsigned got_cmd : 1; - unsigned select : 1; - // These fields are for the cmd fds. - char *buffer; - int pos, size; -}; - -struct cmd_bind_section { - struct cmd_bind *binds; - int num_binds; - char *section; - struct mp_rect mouse_area; // set at runtime, if at all - bool mouse_area_set; // mouse_area is valid and should be tested - struct cmd_bind_section *next; -}; - -#define MAX_ACTIVE_SECTIONS 5 - -struct active_section { - char *name; - int flags; -}; - -struct cmd_queue { - struct mp_cmd *first; -}; - -struct input_ctx { - bool using_ar; - bool using_cocoa_media_keys; - - // Autorepeat stuff - short ar_state; - int64_t last_ar; - // Autorepeat config - unsigned int ar_delay; - unsigned int ar_rate; - // Maximum number of queued commands from keypresses (limit to avoid - // repeated slow commands piling up) - int key_fifo_size; - - // these are the keys currently down - int key_down[MP_MAX_KEY_DOWN]; - unsigned int num_key_down; - int64_t last_key_down; - struct mp_cmd *current_down_cmd; - - int doubleclick_time; - int last_doubleclick_key_down; - double last_doubleclick_time; - - // Mouse position on the consumer side (as command.c sees it) - int mouse_x, mouse_y; - char *mouse_section; // last section to receive mouse event - - // Mouse position on the producer side (as the VO sees it) - // Unlike mouse_x/y, this can be used to resolve mouse click bindings. - int mouse_vo_x, mouse_vo_y; - - bool test; - - bool default_bindings; - // List of command binding sections - struct cmd_bind_section *cmd_bind_sections; - - // List currently active command sections - struct active_section active_sections[MAX_ACTIVE_SECTIONS]; - int num_active_sections; - - // Used to track whether we managed to read something while checking - // events sources. If yes, the sources may have more queued. - bool got_new_events; - - unsigned int mouse_event_counter; - - struct input_fd fds[MP_MAX_FDS]; - unsigned int num_fds; - - struct cmd_queue key_cmd_queue; - struct cmd_queue control_cmd_queue; - - int wakeup_pipe[2]; -}; - - -int async_quit_request; - -static int print_key_list(m_option_t *cfg, char *optname, char *optparam); -static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam); - -#define OPT_BASE_STRUCT struct MPOpts - -// Our command line options -static const m_option_t input_config[] = { - OPT_STRING("conf", input.config_file, CONF_GLOBAL), - OPT_INT("ar-delay", input.ar_delay, CONF_GLOBAL), - OPT_INT("ar-rate", input.ar_rate, CONF_GLOBAL), - { "keylist", print_key_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG }, - { "cmdlist", print_cmd_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG }, - OPT_STRING("js-dev", input.js_dev, CONF_GLOBAL), - OPT_STRING("file", input.in_file, CONF_GLOBAL), - OPT_FLAG("default-bindings", input.default_bindings, CONF_GLOBAL), - OPT_FLAG("test", input.test, CONF_GLOBAL), - { NULL, NULL, 0, 0, 0, 0, NULL} -}; - -const m_option_t mp_input_opts[] = { - { "input", (void *)&input_config, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, - OPT_INTRANGE("doubleclick-time", input.doubleclick_time, 0, 0, 1000), - OPT_FLAG("joystick", input.use_joystick, CONF_GLOBAL), - OPT_FLAG("lirc", input.use_lirc, CONF_GLOBAL), - OPT_FLAG("lircc", input.use_lircc, CONF_GLOBAL), -#ifdef CONFIG_COCOA - OPT_FLAG("ar", input.use_ar, CONF_GLOBAL), - OPT_FLAG("media-keys", input.use_media_keys, CONF_GLOBAL), -#endif - { NULL, NULL, 0, 0, 0, 0, NULL} -}; - -static int default_cmd_func(int fd, char *buf, int l); - -static const char builtin_input_conf[] = -#include "core/input/input_conf.h" -; - -static bool test_rect(struct mp_rect *rc, int x, int y) -{ - return x >= rc->x0 && y >= rc->y0 && x < rc->x1 && y < rc->y1; -} - -static char *get_key_name(int key, char *ret) -{ - for (int i = 0; modifier_names[i].name; i++) { - if (modifier_names[i].key & key) { - ret = talloc_asprintf_append_buffer(ret, "%s+", - modifier_names[i].name); - key -= modifier_names[i].key; - } - } - for (int i = 0; key_names[i].name != NULL; i++) { - if (key_names[i].key == key) - return talloc_asprintf_append_buffer(ret, "%s", key_names[i].name); - } - - // printable, and valid unicode range - if (key >= 32 && key <= 0x10FFFF) - return mp_append_utf8_buffer(ret, key); - - // Print the hex key code - return talloc_asprintf_append_buffer(ret, "%#-8x", key); -} - -static char *get_key_combo_name(int *keys, int max) -{ - char *ret = talloc_strdup(NULL, ""); - while (max > 0) { - ret = get_key_name(*keys, ret); - if (--max && *++keys) - ret = talloc_asprintf_append_buffer(ret, "-"); - else - break; - } - return ret; -} - -bool mp_input_is_abort_cmd(int cmd_id) -{ - switch (cmd_id) { - case MP_CMD_QUIT: - case MP_CMD_PLAYLIST_NEXT: - case MP_CMD_PLAYLIST_PREV: - return true; - } - return false; -} - -static int queue_count_cmds(struct cmd_queue *queue) -{ - int res = 0; - for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next) - res++; - return res; -} - -static bool queue_has_abort_cmds(struct cmd_queue *queue) -{ - for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next) { - if (mp_input_is_abort_cmd(cmd->id)) - return true; - } - return false; -} - -static void queue_remove(struct cmd_queue *queue, struct mp_cmd *cmd) -{ - struct mp_cmd **p_prev = &queue->first; - while (*p_prev != cmd) { - p_prev = &(*p_prev)->queue_next; - } - // if this fails, cmd was not in the queue - assert(*p_prev == cmd); - *p_prev = cmd->queue_next; -} - -static void queue_add(struct cmd_queue *queue, struct mp_cmd *cmd, - bool at_head) -{ - if (at_head) { - cmd->queue_next = queue->first; - queue->first = cmd; - } else { - struct mp_cmd **p_prev = &queue->first; - while (*p_prev) - p_prev = &(*p_prev)->queue_next; - *p_prev = cmd; - cmd->queue_next = NULL; - } -} - -static struct input_fd *mp_input_add_fd(struct input_ctx *ictx) -{ - if (ictx->num_fds == MP_MAX_FDS) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many file descriptors.\n"); - return NULL; - } - - struct input_fd *fd = &ictx->fds[ictx->num_fds]; - *fd = (struct input_fd){ - .fd = -1, - }; - ictx->num_fds++; - - return fd; -} - -int mp_input_add_cmd_fd(struct input_ctx *ictx, int unix_fd, int select, - int read_func(int fd, char *dest, int size), - int close_func(int fd)) -{ - if (select && unix_fd < 0) { - mp_msg(MSGT_INPUT, MSGL_ERR, - "Invalid fd %d in mp_input_add_cmd_fd", unix_fd); - return 0; - } - - struct input_fd *fd = mp_input_add_fd(ictx); - if (!fd) - return 0; - fd->fd = unix_fd; - fd->select = select; - fd->read_cmd = read_func ? read_func : default_cmd_func; - fd->close_func = close_func; - return 1; -} - -int mp_input_add_key_fd(struct input_ctx *ictx, int unix_fd, int select, - int read_func(void *ctx, int fd), - int close_func(int fd), void *ctx) -{ - if (select && unix_fd < 0) { - mp_msg(MSGT_INPUT, MSGL_ERR, - "Invalid fd %d in mp_input_add_key_fd", unix_fd); - return 0; - } - assert(read_func); - - struct input_fd *fd = mp_input_add_fd(ictx); - if (!fd) - return 0; - fd->fd = unix_fd; - fd->select = select; - fd->read_key = read_func; - fd->close_func = close_func; - fd->ctx = ctx; - return 1; -} - - -static void mp_input_rm_fd(struct input_ctx *ictx, int fd) -{ - struct input_fd *fds = ictx->fds; - unsigned int i; - - for (i = 0; i < ictx->num_fds; i++) { - if (fds[i].fd == fd) - break; - } - if (i == ictx->num_fds) - return; - if (fds[i].close_func) - fds[i].close_func(fds[i].fd); - talloc_free(fds[i].buffer); - - if (i + 1 < ictx->num_fds) - memmove(&fds[i], &fds[i + 1], - (ictx->num_fds - i - 1) * sizeof(struct input_fd)); - ictx->num_fds--; -} - -void mp_input_rm_key_fd(struct input_ctx *ictx, int fd) -{ - mp_input_rm_fd(ictx, fd); -} - -static int parse_cycle_dir(const struct m_option *opt, struct bstr name, - struct bstr param, void *dst) -{ - double val; - if (bstrcmp0(param, "up") == 0) { - val = +1; - } else if (bstrcmp0(param, "down") == 0) { - val = -1; - } else { - return m_option_type_double.parse(opt, name, param, dst); - } - *(double *)dst = val; - return 1; -} - -static bool read_token(bstr str, bstr *out_rest, bstr *out_token) -{ - bstr t = bstr_lstrip(str); - int next = bstrcspn(t, WHITESPACE "#"); - // Handle comments - if (t.len && t.start[next] == '#') - t = bstr_splice(t, 0, next); - if (!t.len) - return false; - *out_token = bstr_splice(t, 0, next); - *out_rest = bstr_cut(t, next); - return true; -} - -static bool eat_token(bstr *str, const char *tok) -{ - bstr rest, token; - if (read_token(*str, &rest, &token) && bstrcmp0(token, tok) == 0) { - *str = rest; - return true; - } - return false; -} - -static bool read_escaped_string(void *talloc_ctx, bstr *str, bstr *literal) -{ - bstr t = *str; - char *new = talloc_strdup(talloc_ctx, ""); - while (t.len) { - if (t.start[0] == '"') - break; - if (t.start[0] == '\\') { - t = bstr_cut(t, 1); - if (!mp_parse_escape(&t, &new)) - goto error; - } else { - new = talloc_strndup_append_buffer(new, t.start, 1); - t = bstr_cut(t, 1); - } - } - int len = str->len - t.len; - *literal = new ? bstr0(new) : bstr_splice(*str, 0, len); - *str = bstr_cut(*str, len); - return true; -error: - talloc_free(new); - return false; -} - -// If dest is non-NULL when calling this function, append the command to the -// list formed by dest->queue_next, otherwise just set *dest = new_cmd; -static int parse_cmd(struct mp_cmd **dest, bstr str, const char *loc) -{ - int pausing = 0; - int on_osd = MP_ON_OSD_AUTO; - bool raw_args = false; - struct mp_cmd *cmd = NULL; - bstr start = str; - bstr next = {0}; - void *tmp = talloc_new(NULL); - - str = bstr_lstrip(str); - for (const struct legacy_cmd *entry = legacy_cmds; entry->old; entry++) { - bstr old = bstr0(entry->old); - bool silent = bstr_eatstart0(&old, "!"); - if (bstrcasecmp(bstr_splice(str, 0, old.len), old) == 0) { - if (!silent) { - mp_tmsg(MSGT_INPUT, MSGL_WARN, "Warning: command '%.*s' is " - "deprecated, replaced with '%s' at %s.\n", - BSTR_P(old), entry->new, loc); - } - bstr s = bstr_cut(str, old.len); - str = bstr0(talloc_asprintf(tmp, "%s%.*s", entry->new, BSTR_P(s))); - start = str; - break; - } - } - - while (1) { - if (eat_token(&str, "pausing")) { - pausing = 1; - } else if (eat_token(&str, "pausing_keep")) { - pausing = 2; - } else if (eat_token(&str, "pausing_toggle")) { - pausing = 3; - } else if (eat_token(&str, "pausing_keep_force")) { - pausing = 4; - } else if (eat_token(&str, "no-osd")) { - on_osd = MP_ON_OSD_NO; - } else if (eat_token(&str, "osd-bar")) { - on_osd = MP_ON_OSD_BAR; - } else if (eat_token(&str, "osd-msg")) { - on_osd = MP_ON_OSD_MSG; - } else if (eat_token(&str, "osd-msg-bar")) { - on_osd = MP_ON_OSD_MSG | MP_ON_OSD_BAR; - } else if (eat_token(&str, "osd-auto")) { - // default - } else if (eat_token(&str, "raw")) { - raw_args = true; - } else if (eat_token(&str, "expand-properties")) { - // default - } else { - break; - } - } - - int cmd_idx = 0; - while (mp_cmds[cmd_idx].name != NULL) { - if (eat_token(&str, mp_cmds[cmd_idx].name)) - break; - cmd_idx++; - } - - if (mp_cmds[cmd_idx].name == NULL) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command '%.*s' not found.\n", - BSTR_P(str)); - goto error; - } - - cmd = talloc_ptrtype(NULL, cmd); - *cmd = mp_cmds[cmd_idx]; - cmd->pausing = pausing; - cmd->on_osd = on_osd; - cmd->raw_args = raw_args; - - for (int i = 0; i < MP_CMD_MAX_ARGS; i++) { - struct mp_cmd_arg *cmdarg = &cmd->args[i]; - if (!cmdarg->type.type) - break; - str = bstr_lstrip(str); - if (eat_token(&str, ";")) { - next = str; - str.len = 0; - break; - } - cmd->nargs++; - bstr arg = {0}; - if (bstr_eatstart0(&str, "\"")) { - if (!read_escaped_string(tmp, &str, &arg)) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d " - "has broken string escapes.\n", cmd->name, i + 1); - goto error; - } - if (!bstr_eatstart0(&str, "\"")) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is " - "unterminated.\n", cmd->name, i + 1); - goto error; - } - } else { - if (!read_token(str, &str, &arg)) - break; - if (cmdarg->optional && bstrcmp0(arg, "-") == 0) - continue; - } - // Prevent option API from trying to deallocate static strings - cmdarg->v = ((struct mp_cmd_arg) {{0}}).v; - int r = m_option_parse(&cmdarg->type, bstr0(cmd->name), arg, &cmdarg->v); - if (r < 0) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d " - "can't be parsed: %s.\n", cmd->name, i + 1, - m_option_strerror(r)); - goto error; - } - if (cmdarg->type.type == &m_option_type_string) - cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s); - } - - if (eat_token(&str, ";")) { - next = str; - str.len = 0; - } - - bstr dummy; - if (read_token(str, &dummy, &dummy)) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s has trailing unused " - "arguments: '%.*s'.\n", cmd->name, BSTR_P(str)); - // Better make it fatal to make it clear something is wrong. - goto error; - } - - int min_args = 0; - while (min_args < MP_CMD_MAX_ARGS && cmd->args[min_args].type.type - && !cmd->args[min_args].optional) - { - min_args++; - } - if (cmd->nargs < min_args) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s requires at least %d " - "arguments, we found only %d so far.\n", cmd->name, min_args, - cmd->nargs); - goto error; - } - - bstr orig = (bstr) {start.start, str.start - start.start}; - cmd->original = bstrdup(cmd, bstr_strip(orig)); - - while (*dest) - dest = &(*dest)->queue_next; - *dest = cmd; - - next = bstr_strip(next); - if (next.len) { - if (parse_cmd(dest, next, loc) < 0) { - *dest = NULL; - goto error; - } - } - - talloc_free(tmp); - return 1; - -error: - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command was defined at %s.\n", loc); - talloc_free(cmd); - talloc_free(tmp); - return -1; -} - -mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc) -{ - struct mp_cmd *cmd = NULL; - if (parse_cmd(&cmd, str, loc) < 0) { - assert(!cmd); - } - // Other input.c code uses queue_next for its own purposes, so explicitly - // wrap lists in a pseudo-command. - if (cmd && cmd->queue_next) { - struct mp_cmd *list = talloc_ptrtype(NULL, list); - *list = (struct mp_cmd) { - .id = MP_CMD_COMMAND_LIST, - .name = "list", - .original = bstrdup(list, str), - }; - list->args[0].v.p = cmd; - while (cmd) { - talloc_steal(list, cmd); - cmd = cmd->queue_next; - } - cmd = list; - } - return cmd; -} - -#define MP_CMD_MAX_SIZE 4096 - -static int read_cmd(struct input_fd *mp_fd, char **ret) -{ - char *end; - *ret = NULL; - - // Allocate the buffer if it doesn't exist - if (!mp_fd->buffer) { - mp_fd->buffer = talloc_size(NULL, MP_CMD_MAX_SIZE); - mp_fd->pos = 0; - mp_fd->size = MP_CMD_MAX_SIZE; - } - - // Get some data if needed/possible - while (!mp_fd->got_cmd && !mp_fd->eof && (mp_fd->size - mp_fd->pos > 1)) { - int r = mp_fd->read_cmd(mp_fd->fd, mp_fd->buffer + mp_fd->pos, - mp_fd->size - 1 - mp_fd->pos); - // Error ? - if (r < 0) { - switch (r) { - case MP_INPUT_ERROR: - case MP_INPUT_DEAD: - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error while reading " - "command file descriptor %d: %s\n", - mp_fd->fd, strerror(errno)); - case MP_INPUT_NOTHING: - return r; - case MP_INPUT_RETRY: - continue; - } - // EOF ? - } else if (r == 0) { - mp_fd->eof = 1; - break; - } - mp_fd->pos += r; - break; - } - - mp_fd->got_cmd = 0; - - while (1) { - int l = 0; - // Find the cmd end - mp_fd->buffer[mp_fd->pos] = '\0'; - end = strchr(mp_fd->buffer, '\r'); - if (end) - *end = '\n'; - end = strchr(mp_fd->buffer, '\n'); - // No cmd end ? - if (!end) { - // If buffer is full we must drop all until the next \n - if (mp_fd->size - mp_fd->pos <= 1) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command buffer of file " - "descriptor %d is full: dropping content.\n", - mp_fd->fd); - mp_fd->pos = 0; - mp_fd->drop = 1; - } - break; - } - // We already have a cmd : set the got_cmd flag - else if ((*ret)) { - mp_fd->got_cmd = 1; - break; - } - - l = end - mp_fd->buffer; - - // Not dropping : put the cmd in ret - if (!mp_fd->drop) - *ret = talloc_strndup(NULL, mp_fd->buffer, l); - else - mp_fd->drop = 0; - mp_fd->pos -= l + 1; - memmove(mp_fd->buffer, end + 1, mp_fd->pos); - } - - if (*ret) - return 1; - else - return MP_INPUT_NOTHING; -} - -static int default_cmd_func(int fd, char *buf, int l) -{ - while (1) { - int r = read(fd, buf, l); - // Error ? - if (r < 0) { - if (errno == EINTR) - continue; - else if (errno == EAGAIN) - return MP_INPUT_NOTHING; - return MP_INPUT_ERROR; - // EOF ? - } - return r; - } -} - -#ifndef __MINGW32__ -static int read_wakeup(void *ctx, int fd) -{ - char buf[100]; - read(fd, buf, sizeof(buf)); - return MP_INPUT_NOTHING; -} -#endif - -static bool bind_matches_key(struct cmd_bind *bind, int n, const int *keys); - -static void append_bind_info(char **pmsg, struct cmd_bind *bind) -{ - char *msg = *pmsg; - struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(bind->cmd), bind->location); - bstr stripped = cmd ? cmd->original : bstr0(bind->cmd); - msg = talloc_asprintf_append(msg, " '%.*s'", BSTR_P(stripped)); - if (!cmd) - msg = talloc_asprintf_append(msg, " (invalid)"); - if (strcmp(bind->owner->section, "default") != 0) - msg = talloc_asprintf_append(msg, " in section {%s}", - bind->owner->section); - msg = talloc_asprintf_append(msg, " in %s", bind->location); - if (bind->is_builtin) - msg = talloc_asprintf_append(msg, " (default)"); - talloc_free(cmd); - *pmsg = msg; -} - -static mp_cmd_t *handle_test(struct input_ctx *ictx, int n, int *keys) -{ - char *key_buf = get_key_combo_name(keys, n); - // "$>" to disable property substitution when invoking "show_text" - char *msg = talloc_asprintf(NULL, "$>Key %s is bound to:\n", key_buf); - talloc_free(key_buf); - - int count = 0; - for (struct cmd_bind_section *bs = ictx->cmd_bind_sections; - bs; bs = bs->next) - { - for (int i = 0; i < bs->num_binds; i++) { - if (bind_matches_key(&bs->binds[i], n, keys)) { - count++; - msg = talloc_asprintf_append(msg, "%d. ", count); - append_bind_info(&msg, &bs->binds[i]); - msg = talloc_asprintf_append(msg, "\n"); - } - } - } - - if (!count) - msg = talloc_asprintf_append(msg, "(nothing)"); - - mp_msg(MSGT_INPUT, MSGL_V, "[input] %s\n", msg); - - mp_cmd_t *res = mp_input_parse_cmd(bstr0("show_text \"\""), ""); - res->args[0].v.s = talloc_steal(res, msg); - return res; -} - -static bool bind_matches_key(struct cmd_bind *bind, int num_keys, const int *keys) -{ - if (bind->num_keys != num_keys) - return false; - for (int i = 0; i < num_keys; i++) { - if (bind->keys[i] != keys[i]) - return false; - } - return true; -} - -static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx, - bstr section) -{ - struct cmd_bind_section *bind_section = ictx->cmd_bind_sections; - - if (section.len == 0) - section = bstr0("default"); - while (bind_section) { - if (bstrcmp0(section, bind_section->section) == 0) - return bind_section; - if (bind_section->next == NULL) - break; - bind_section = bind_section->next; - } - if (bind_section) { - bind_section->next = talloc_ptrtype(ictx, bind_section->next); - bind_section = bind_section->next; - } else { - ictx->cmd_bind_sections = talloc_ptrtype(ictx, ictx->cmd_bind_sections); - bind_section = ictx->cmd_bind_sections; - } - *bind_section = (struct cmd_bind_section) { - .section = bstrdup0(bind_section, section), - }; - return bind_section; -} - -static struct cmd_bind *find_bind_for_key_section(struct input_ctx *ictx, - char *section, - int num_keys, int *keys) -{ - struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(section)); - - if (!num_keys || !bs->num_binds) - return NULL; - - // Prefer user-defined keys over builtin bindings - for (int builtin = 0; builtin < 2; builtin++) { - for (int n = 0; n < bs->num_binds; n++) { - if (bs->binds[n].is_builtin == (bool)builtin && - bind_matches_key(&bs->binds[n], num_keys, keys)) - return &bs->binds[n]; - } - } - return NULL; -} - -static struct cmd_bind *find_any_bind_for_key(struct input_ctx *ictx, - char *force_section, - int n, int *keys) -{ - if (force_section) - return find_bind_for_key_section(ictx, force_section, n, keys); - - for (int i = ictx->num_active_sections - 1; i >= 0; i--) { - struct active_section *s = &ictx->active_sections[i]; - struct cmd_bind *bind = find_bind_for_key_section(ictx, s->name, n, keys); - if (bind) { - struct cmd_bind_section *bs = bind->owner; - for (int x = 0; x < n; x++) { - if (MP_KEY_DEPENDS_ON_MOUSE_POS(keys[x]) && bs->mouse_area_set && - !test_rect(&bs->mouse_area, ictx->mouse_vo_x, ictx->mouse_vo_y)) - goto skip; - } - return bind; - } - skip: ; - if (s->flags & MP_INPUT_EXCLUSIVE) - break; - } - - return NULL; -} - -static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, char *force_section, - int n, int *keys) -{ - if (ictx->test) - return handle_test(ictx, n, keys); - - struct cmd_bind *cmd = find_any_bind_for_key(ictx, force_section, n, keys); - if (cmd == NULL && n > 1) { - // Hitting two keys at once, and if there's no binding for this - // combination, the key hit last should be checked. - cmd = find_any_bind_for_key(ictx, force_section, 1, (int[]){keys[n - 1]}); - } - - if (cmd == NULL) { - char *key_buf = get_key_combo_name(keys, n); - mp_tmsg(MSGT_INPUT, MSGL_WARN, - "No bind found for key '%s'.\n", key_buf); - talloc_free(key_buf); - return NULL; - } - mp_cmd_t *ret = mp_input_parse_cmd(bstr0(cmd->cmd), cmd->location); - if (ret) { - ret->input_section = cmd->owner->section; - } else { - char *key_buf = get_key_combo_name(keys, n); - mp_tmsg(MSGT_INPUT, MSGL_ERR, - "Invalid command for bound key '%s': '%s'\n", key_buf, cmd->cmd); - talloc_free(key_buf); - } - return ret; -} - -static void release_down_cmd(struct input_ctx *ictx) -{ - if (ictx->current_down_cmd && ictx->current_down_cmd->key_up_follows) { - ictx->current_down_cmd->key_up_follows = false; - queue_add(&ictx->key_cmd_queue, ictx->current_down_cmd, false); - } else { - talloc_free(ictx->current_down_cmd); - } - ictx->current_down_cmd = NULL; - ictx->last_key_down = 0; - ictx->ar_state = -1; -} - -static int find_key_down(struct input_ctx *ictx, int code) -{ - code &= ~(MP_KEY_STATE_UP | MP_KEY_STATE_DOWN); - for (int j = 0; j < ictx->num_key_down; j++) { - if (ictx->key_down[j] == code) - return j; - } - return -1; -} - -static void remove_key_down(struct input_ctx *ictx, int code) -{ - int index = find_key_down(ictx, code); - if (index >= 0) { - memmove(&ictx->key_down[index], &ictx->key_down[index + 1], - (ictx->num_key_down - (index + 1)) * sizeof(int)); - ictx->num_key_down -= 1; - } -} - -static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) -{ - /* On normal keyboards shift changes the character code of non-special - * keys, so don't count the modifier separately for those. In other words - * we want to have "a" and "A" instead of "a" and "Shift+A"; but a separate - * shift modifier is still kept for special keys like arrow keys. - */ - int unmod = code & ~MP_KEY_MODIFIER_MASK; - if (unmod >= 32 && unmod < MP_KEY_BASE) - code &= ~MP_KEY_MODIFIER_SHIFT; - - if (!(code & MP_KEY_STATE_UP) && ictx->num_key_down >= MP_MAX_KEY_DOWN) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many key down events " - "at the same time\n"); - return NULL; - } - - bool key_was_down = find_key_down(ictx, code) >= 0; - - if (code & MP_KEY_STATE_DOWN) { - // Check if we don't already have this key as pushed - if (key_was_down) - return NULL; - // Cancel current down-event (there can be only one) - release_down_cmd(ictx); - ictx->key_down[ictx->num_key_down] = code & ~MP_KEY_STATE_DOWN; - ictx->num_key_down++; - ictx->last_key_down = mp_time_us(); - ictx->ar_state = 0; - ictx->current_down_cmd = get_cmd_from_keys(ictx, NULL, ictx->num_key_down, - ictx->key_down); - if (ictx->current_down_cmd && (code & MP_KEY_EMIT_ON_UP)) - ictx->current_down_cmd->key_up_follows = true; - return mp_cmd_clone(ictx->current_down_cmd); - } else if (code & MP_KEY_STATE_UP) { - if (key_was_down) { - remove_key_down(ictx, code); - release_down_cmd(ictx); - } - return NULL; - } else { - // Press of key with no separate down/up events - if (key_was_down) { - // Mixing press events and up/down with the same key is not allowed - mp_tmsg(MSGT_INPUT, MSGL_WARN, "Mixing key presses and up/down.\n"); - } - // Add temporarily (include ongoing down/up events) - int num_key_down = ictx->num_key_down; - int key_down[MP_MAX_KEY_DOWN]; - memcpy(key_down, ictx->key_down, num_key_down * sizeof(int)); - // Assume doubleclick events never use down/up, while button events do - if (MP_KEY_IS_MOUSE_BTN_DBL(code)) { - // Don't emit "MOUSE_BTN0+MOUSE_BTN0_DBL", just "MOUSE_BTN0_DBL" - int btn = code - MP_MOUSE_BTN0_DBL + MP_MOUSE_BTN0; - if (!num_key_down || key_down[num_key_down - 1] != btn) - return NULL; - key_down[num_key_down - 1] = code; - } else { - key_down[num_key_down] = code; - num_key_down++; - } - return get_cmd_from_keys(ictx, NULL, num_key_down, key_down); - } -} - -static mp_cmd_t *check_autorepeat(struct input_ctx *ictx) -{ - // No input : autorepeat ? - if (ictx->ar_rate > 0 && ictx->ar_state >= 0 && ictx->num_key_down > 0 - && !(ictx->key_down[ictx->num_key_down - 1] & MP_NO_REPEAT_KEY)) { - int64_t t = mp_time_us(); - if (ictx->last_ar + 2000000 < t) - ictx->last_ar = t; - // First time : wait delay - if (ictx->ar_state == 0 - && (t - ictx->last_key_down) >= ictx->ar_delay * 1000) - { - if (!ictx->current_down_cmd) { - ictx->ar_state = -1; - return NULL; - } - ictx->ar_state = 1; - ictx->last_ar = ictx->last_key_down + ictx->ar_delay * 1000; - return mp_cmd_clone(ictx->current_down_cmd); - // Then send rate / sec event - } else if (ictx->ar_state == 1 - && (t - ictx->last_ar) >= 1000000 / ictx->ar_rate) { - ictx->last_ar += 1000000 / ictx->ar_rate; - return mp_cmd_clone(ictx->current_down_cmd); - } - } - return NULL; -} - -static void add_key_cmd(struct input_ctx *ictx, struct mp_cmd *cmd) -{ - struct cmd_queue *queue = &ictx->key_cmd_queue; - if (queue_count_cmds(queue) >= ictx->key_fifo_size && - (!mp_input_is_abort_cmd(cmd->id) || queue_has_abort_cmds(queue))) - { - talloc_free(cmd); - return; - } - queue_add(queue, cmd, false); -} - -// Whether a command can deal with redundant key up events. -static bool key_updown_ok(enum mp_command_type cmd) -{ - switch (cmd) { - default: - return false; - } -} - -static void mp_input_feed_key(struct input_ctx *ictx, int code) -{ - ictx->got_new_events = true; - if (code == MP_INPUT_RELEASE_ALL) { - mp_msg(MSGT_INPUT, MSGL_V, "input: release all\n"); - ictx->num_key_down = 0; - release_down_cmd(ictx); - return; - } - int unmod = code & ~MP_KEY_MODIFIER_MASK; - if (MP_KEY_DEPENDS_ON_MOUSE_POS(unmod)) - ictx->mouse_event_counter++; - mp_msg(MSGT_INPUT, MSGL_V, "input: key code=%#x\n", code); - struct mp_cmd *cmd = interpret_key(ictx, code); - if (!cmd) - return; - // Prevent redundant key-down events from being added to the queue. In some - // cases (like MP_CMD_SEEK commands), duplicated events might severely - // confuse the frontend. - if (cmd->key_up_follows && !key_updown_ok(cmd->id)) { - talloc_free(cmd); - return; - } - add_key_cmd(ictx, cmd); -} - -void mp_input_put_key(struct input_ctx *ictx, int code) -{ - double now = mp_time_sec(); - int doubleclick_time = ictx->doubleclick_time; - // ignore system-doubleclick if we generate these events ourselves - int unmod = code & ~MP_KEY_MODIFIER_MASK; - if (doubleclick_time && MP_KEY_IS_MOUSE_BTN_DBL(unmod)) - return; - mp_input_feed_key(ictx, code); - if (code & MP_KEY_STATE_DOWN) { - code &= ~MP_KEY_STATE_DOWN; - if (ictx->last_doubleclick_key_down == code - && now - ictx->last_doubleclick_time < doubleclick_time / 1000.0) - { - if (code >= MP_MOUSE_BTN0 && code <= MP_MOUSE_BTN2) - mp_input_feed_key(ictx, code - MP_MOUSE_BTN0 + MP_MOUSE_BTN0_DBL); - } - ictx->last_doubleclick_key_down = code; - ictx->last_doubleclick_time = now; - } -} - -void mp_input_put_key_utf8(struct input_ctx *ictx, int mods, struct bstr t) -{ - while (t.len) { - int code = bstr_decode_utf8(t, &t); - if (code < 0) - break; - mp_input_put_key(ictx, code | mods); - } -} - -static void trigger_mouse_leave(struct input_ctx *ictx, char *new_section) -{ - if (!new_section) - new_section = "default"; - - char *old = ictx->mouse_section; - ictx->mouse_section = new_section; - - if (old && strcmp(old, ictx->mouse_section) != 0) { - struct mp_cmd *cmd = - get_cmd_from_keys(ictx, old, 1, (int[]){MP_KEY_MOUSE_LEAVE}); - if (cmd) - add_key_cmd(ictx, cmd); - } -} - - -void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) -{ - // we're already there - if (ictx->mouse_vo_x == x && ictx->mouse_vo_y == y) - return; - - ictx->mouse_event_counter++; - ictx->mouse_vo_x = x; - ictx->mouse_vo_y = y; - - struct mp_cmd *cmd = - get_cmd_from_keys(ictx, NULL, 1, (int[]){MP_KEY_MOUSE_MOVE}); - - trigger_mouse_leave(ictx, cmd ? cmd->input_section : NULL); - - if (!cmd) - return; - cmd->mouse_move = true; - cmd->mouse_x = x; - cmd->mouse_y = y; - add_key_cmd(ictx, cmd); -} - -static void read_cmd_fd(struct input_ctx *ictx, struct input_fd *cmd_fd) -{ - int r; - char *text; - while ((r = read_cmd(cmd_fd, &text)) >= 0) { - ictx->got_new_events = true; - struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(text), ""); - talloc_free(text); - if (cmd) - queue_add(&ictx->control_cmd_queue, cmd, false); - if (!cmd_fd->got_cmd) - return; - } - if (r == MP_INPUT_ERROR) - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error on command file descriptor %d\n", - cmd_fd->fd); - else if (r == MP_INPUT_DEAD) - cmd_fd->dead = true; -} - -static void read_key_fd(struct input_ctx *ictx, struct input_fd *key_fd) -{ - int code = key_fd->read_key(key_fd->ctx, key_fd->fd); - if (code >= 0 || code == MP_INPUT_RELEASE_ALL) { - mp_input_feed_key(ictx, code); - return; - } - - if (code == MP_INPUT_ERROR) - mp_tmsg(MSGT_INPUT, MSGL_ERR, - "Error on key input file descriptor %d\n", key_fd->fd); - else if (code == MP_INPUT_DEAD) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, - "Dead key input on file descriptor %d\n", key_fd->fd); - key_fd->dead = true; - } -} - -static void read_fd(struct input_ctx *ictx, struct input_fd *fd) -{ - if (fd->read_cmd) { - read_cmd_fd(ictx, fd); - } else { - read_key_fd(ictx, fd); - } -} - -static void remove_dead_fds(struct input_ctx *ictx) -{ - for (int i = 0; i < ictx->num_fds; i++) { - if (ictx->fds[i].dead) { - mp_input_rm_fd(ictx, ictx->fds[i].fd); - i--; - } - } -} - -#ifdef HAVE_POSIX_SELECT - -static void input_wait_read(struct input_ctx *ictx, int time) -{ - fd_set fds; - FD_ZERO(&fds); - int max_fd = 0; - for (int i = 0; i < ictx->num_fds; i++) { - if (!ictx->fds[i].select) - continue; - if (ictx->fds[i].fd > max_fd) - max_fd = ictx->fds[i].fd; - FD_SET(ictx->fds[i].fd, &fds); - } - struct timeval tv, *time_val; - tv.tv_sec = time / 1000; - tv.tv_usec = (time % 1000) * 1000; - time_val = &tv; - if (select(max_fd + 1, &fds, NULL, NULL, time_val) < 0) { - if (errno != EINTR) - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Select error: %s\n", - strerror(errno)); - FD_ZERO(&fds); - } - for (int i = 0; i < ictx->num_fds; i++) { - if (ictx->fds[i].select && !FD_ISSET(ictx->fds[i].fd, &fds)) - continue; - read_fd(ictx, &ictx->fds[i]); - } -} - -#else - -static void input_wait_read(struct input_ctx *ictx, int time) -{ - if (time > 0) - mp_sleep_us(time * 1000); - - for (int i = 0; i < ictx->num_fds; i++) - read_fd(ictx, &ictx->fds[i]); -} - -#endif - -/** - * \param time time to wait at most for an event in milliseconds - */ -static void read_events(struct input_ctx *ictx, int time) -{ - if (ictx->num_key_down) { - time = FFMIN(time, 1000 / ictx->ar_rate); - time = FFMIN(time, ictx->ar_delay); - } - time = FFMAX(time, 0); - - while (1) { - if (ictx->got_new_events) - time = 0; - ictx->got_new_events = false; - - remove_dead_fds(ictx); - - if (time) { - for (int i = 0; i < ictx->num_fds; i++) { - if (!ictx->fds[i].select) - read_fd(ictx, &ictx->fds[i]); - } - } - - if (ictx->got_new_events) - time = 0; - - input_wait_read(ictx, time); - - // Read until all input FDs are empty - if (!ictx->got_new_events) - break; - } -} - -static void read_all_events(struct input_ctx *ictx, int time) -{ - getch2_poll(); -#ifdef CONFIG_COCOA - cocoa_check_events(); -#endif - read_events(ictx, time); -} - -int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd) -{ - ictx->got_new_events = true; - if (!cmd) - return 0; - queue_add(&ictx->control_cmd_queue, cmd, false); - return 1; -} - -/** - * \param peek_only when set, the returned command stays in the queue. - * Do not free the returned cmd whe you set this! - */ -mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only) -{ - if (async_quit_request) { - struct mp_cmd *cmd = mp_input_parse_cmd(bstr0("quit 1"), ""); - queue_add(&ictx->control_cmd_queue, cmd, true); - } - - if (ictx->control_cmd_queue.first || ictx->key_cmd_queue.first) - time = 0; - read_all_events(ictx, time); - struct cmd_queue *queue = &ictx->control_cmd_queue; - if (!queue->first) - queue = &ictx->key_cmd_queue; - if (!queue->first) { - struct mp_cmd *repeated = check_autorepeat(ictx); - if (repeated) - queue_add(queue, repeated, false); - } - struct mp_cmd *ret = queue->first; - if (!ret) - return NULL; - - if (!peek_only) { - queue_remove(queue, ret); - if (ret->mouse_move) { - ictx->mouse_x = ret->mouse_x; - ictx->mouse_y = ret->mouse_y; - } - } - - return ret; -} - -void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y) -{ - *x = ictx->mouse_x; - *y = ictx->mouse_y; -} - -void mp_cmd_free(mp_cmd_t *cmd) -{ - talloc_free(cmd); -} - -mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd) -{ - mp_cmd_t *ret; - int i; - - if (!cmd) - return NULL; - - ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t)); - ret->name = talloc_strdup(ret, cmd->name); - for (i = 0; i < MP_CMD_MAX_ARGS; i++) { - if (cmd->args[i].type.type == &m_option_type_string) - ret->args[i].v.s = talloc_strdup(ret, cmd->args[i].v.s); - } - - if (cmd->id == MP_CMD_COMMAND_LIST) { - struct mp_cmd *prev = NULL; - for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next) { - sub = mp_cmd_clone(sub); - talloc_steal(ret, sub); - if (prev) { - prev->queue_next = sub; - } else { - ret->args[0].v.p = sub; - } - prev = sub; - } - } - - return ret; -} - -int mp_input_get_key_from_name(const char *name) -{ - int modifiers = 0; - const char *p; - while ((p = strchr(name, '+'))) { - for (struct key_name *m = modifier_names; m->name; m++) - if (!bstrcasecmp(bstr0(m->name), - (struct bstr){(char *)name, p - name})) { - modifiers |= m->key; - goto found; - } - if (!strcmp(name, "+")) - return '+' + modifiers; - return -1; -found: - name = p + 1; - } - - struct bstr bname = bstr0(name); - - struct bstr rest; - int code = bstr_decode_utf8(bname, &rest); - if (code >= 0 && rest.len == 0) - return code + modifiers; - - if (bstr_startswith0(bname, "0x")) - return strtol(name, NULL, 16) + modifiers; - - for (int i = 0; key_names[i].name != NULL; i++) { - if (strcasecmp(key_names[i].name, name) == 0) - return key_names[i].key + modifiers; - } - - return -1; -} - -static int get_input_from_name(char *name, int *out_num_keys, int *keys) -{ - char *end, *ptr; - int n = 0; - - ptr = name; - n = 0; - for (end = strchr(ptr, '-'); ptr != NULL; end = strchr(ptr, '-')) { - if (end && end[1] != '\0') { - if (end[1] == '-') - end = &end[1]; - end[0] = '\0'; - } - keys[n] = mp_input_get_key_from_name(ptr); - if (keys[n] < 0) - return 0; - n++; - if (end && end[1] != '\0' && n < MP_MAX_KEY_DOWN) - ptr = &end[1]; - else - break; - } - *out_num_keys = n; - return 1; -} - -static void bind_dealloc(struct cmd_bind *bind) -{ - talloc_free(bind->cmd); - talloc_free(bind->location); -} - -static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section, - const int *keys, int num_keys, bstr command, - const char *loc) -{ - struct cmd_bind_section *bs = get_bind_section(ictx, section); - struct cmd_bind *bind = NULL; - - assert(num_keys <= MP_MAX_KEY_DOWN); - - for (int n = 0; n < bs->num_binds; n++) { - struct cmd_bind *b = &bs->binds[n]; - if (bind_matches_key(b, num_keys, keys) && b->is_builtin == builtin) { - bind = b; - break; - } - } - - if (!bind) { - struct cmd_bind empty = {{0}}; - MP_TARRAY_APPEND(bs, bs->binds, bs->num_binds, empty); - bind = &bs->binds[bs->num_binds - 1]; - } - - bind_dealloc(bind); - - *bind = (struct cmd_bind) { - .cmd = bstrdup0(bs->binds, command), - .location = talloc_strdup(bs->binds, loc), - .owner = bs, - .is_builtin = builtin, - .num_keys = num_keys, - }; - memcpy(bind->keys, keys, num_keys * sizeof(bind->keys[0])); -} - -// restrict_section: every entry is forced to this section name -// if NULL, load normally and allow any sections -static int parse_config(struct input_ctx *ictx, bool builtin, bstr data, - const char *location, const char *restrict_section) -{ - int n_binds = 0; - int line_no = 0; - char *cur_loc = NULL; - - while (data.len) { - line_no++; - if (cur_loc) - talloc_free(cur_loc); - cur_loc = talloc_asprintf(NULL, "%s:%d", location, line_no); - - bstr line = bstr_strip_linebreaks(bstr_getline(data, &data)); - line = bstr_lstrip(line); - if (line.len == 0 || bstr_startswith0(line, "#")) - continue; - struct bstr command; - // Find the key name starting a line - struct bstr keyname = bstr_split(line, WHITESPACE, &command); - command = bstr_strip(command); - if (command.len == 0) { - mp_tmsg(MSGT_INPUT, MSGL_ERR, - "Unfinished key binding: %.*s at %s\n", BSTR_P(line), - cur_loc); - continue; - } - char *name = bstrdup0(NULL, keyname); - int keys[MP_MAX_KEY_DOWN]; - int num_keys = 0; - if (!get_input_from_name(name, &num_keys, keys)) { - talloc_free(name); - mp_tmsg(MSGT_INPUT, MSGL_ERR, - "Unknown key '%.*s' at %s\n", BSTR_P(keyname), cur_loc); - continue; - } - talloc_free(name); - - bstr section = bstr0(restrict_section); - if (!section.len) { - if (bstr_startswith0(command, "{")) { - int p = bstrchr(command, '}'); - if (p != -1) { - section = bstr_strip(bstr_splice(command, 1, p)); - command = bstr_lstrip(bstr_cut(command, p + 1)); - } - } - } - - bind_keys(ictx, builtin, section, keys, num_keys, command, cur_loc); - n_binds++; - - // Print warnings if invalid commands are encountered. - talloc_free(mp_input_parse_cmd(command, cur_loc)); - } - - talloc_free(cur_loc); - - return n_binds; -} - -static int parse_config_file(struct input_ctx *ictx, char *file, bool warn) -{ - if (!mp_path_exists(file)) { - mp_msg(MSGT_INPUT, warn ? MSGL_ERR : MSGL_V, - "Input config file %s not found.\n", file); - return 0; - } - stream_t *s = stream_open(file, NULL); - if (!s) { - mp_msg(MSGT_INPUT, MSGL_ERR, "Can't open input config file %s.\n", file); - return 0; - } - bstr res = stream_read_complete(s, NULL, 1000000); - free_stream(s); - mp_msg(MSGT_INPUT, MSGL_V, "Parsing input config file %s\n", file); - int n_binds = parse_config(ictx, false, res, file, NULL); - talloc_free(res.start); - mp_msg(MSGT_INPUT, MSGL_V, "Input config file %s parsed: %d binds\n", - file, n_binds); - return 1; -} - -// If name is NULL, return "default". -// Return a statically allocated name of the section (i.e. return value never -// gets deallocated). -static char *normalize_section(struct input_ctx *ictx, char *name) -{ - return get_bind_section(ictx, bstr0(name))->section; -} - -void mp_input_disable_section(struct input_ctx *ictx, char *name) -{ - name = normalize_section(ictx, name); - - // Remove old section, or make sure it's on top if re-enabled - for (int i = ictx->num_active_sections - 1; i >= 0; i--) { - struct active_section *as = &ictx->active_sections[i]; - if (strcmp(as->name, name) == 0) { - for (int x = i; i < ictx->num_active_sections - 1; i++) - ictx->active_sections[x] = ictx->active_sections[x + 1]; - ictx->num_active_sections--; - } - } -} - -void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags) -{ - name = normalize_section(ictx, name); - - mp_input_disable_section(ictx, name); - - if (ictx->num_active_sections < MAX_ACTIVE_SECTIONS) { - ictx->active_sections[ictx->num_active_sections++] = - (struct active_section) {name, flags}; - } -} - -void mp_input_disable_all_sections(struct input_ctx *ictx) -{ - ictx->num_active_sections = 0; -} - -void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name, - int x0, int y0, int x1, int y1) -{ - struct cmd_bind_section *s = get_bind_section(ictx, bstr0(name)); - s->mouse_area = (struct mp_rect){x0, y0, x1, y1}; - s->mouse_area_set = x0 != x1 && y0 != y1; -} - -bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y) -{ - for (int i = 0; i < ictx->num_active_sections; i++) { - char *name = ictx->active_sections[i].name; - struct cmd_bind_section *s = get_bind_section(ictx, bstr0(name)); - if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) - return true; - } - return false; -} - -bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y) -{ - return mp_input_test_mouse_active(ictx, x, y); -} - -// builtin: if true, remove all builtin binds, else remove all user binds -static void remove_binds(struct cmd_bind_section *bs, bool builtin) -{ - for (int n = bs->num_binds - 1; n >= 0; n--) { - if (bs->binds[n].is_builtin == builtin) { - bind_dealloc(&bs->binds[n]); - assert(bs->num_binds >= 1); - bs->binds[n] = bs->binds[bs->num_binds - 1]; - bs->num_binds--; - } - } -} - -void mp_input_define_section(struct input_ctx *ictx, char *name, char *location, - char *contents, bool builtin) -{ - if (!name || !name[0]) - return; // parse_config() changes semantics with restrict_section==empty - if (contents) { - parse_config(ictx, builtin, bstr0(contents), location, name); - } else { - // Disable: - mp_input_disable_section(ictx, name); - // Delete: - struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(name)); - remove_binds(bs, builtin); - } -} - -struct input_ctx *mp_input_init(struct MPOpts *opts) -{ - struct input_conf *input_conf = &opts->input; - - struct input_ctx *ictx = talloc_ptrtype(NULL, ictx); - *ictx = (struct input_ctx){ - .key_fifo_size = input_conf->key_fifo_size, - .doubleclick_time = input_conf->doubleclick_time, - .ar_state = -1, - .ar_delay = input_conf->ar_delay, - .ar_rate = input_conf->ar_rate, - .default_bindings = input_conf->default_bindings, - .test = input_conf->test, - .wakeup_pipe = {-1, -1}, - }; - mp_input_enable_section(ictx, NULL, 0); - - parse_config(ictx, true, bstr0(builtin_input_conf), "", NULL); - -#ifndef __MINGW32__ - long ret = pipe(ictx->wakeup_pipe); - for (int i = 0; i < 2 && ret >= 0; i++) { - ret = fcntl(ictx->wakeup_pipe[i], F_GETFL); - if (ret < 0) - break; - ret = fcntl(ictx->wakeup_pipe[i], F_SETFL, ret | O_NONBLOCK); - } - if (ret < 0) - mp_msg(MSGT_INPUT, MSGL_ERR, - "Failed to initialize wakeup pipe: %s\n", strerror(errno)); - else - mp_input_add_key_fd(ictx, ictx->wakeup_pipe[0], true, read_wakeup, - NULL, NULL); -#endif - - bool config_ok = false; - if (input_conf->config_file) - config_ok = parse_config_file(ictx, input_conf->config_file, true); - if (!config_ok && opts->load_config) { - // Try global conf dir - char *file = mp_find_config_file("input.conf"); - config_ok = file && parse_config_file(ictx, file, false); - talloc_free(file); - } - if (!config_ok) { - mp_msg(MSGT_INPUT, MSGL_V, "Falling back on default (hardcoded) " - "input config\n"); - } - -#ifdef CONFIG_JOYSTICK - if (input_conf->use_joystick) { - int fd = mp_input_joystick_init(input_conf->js_dev); - if (fd < 0) - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Can't init input joystick\n"); - else - mp_input_add_key_fd(ictx, fd, 1, mp_input_joystick_read, - close, NULL); - } -#endif - -#ifdef CONFIG_LIRC - if (input_conf->use_lirc) { - int fd = mp_input_lirc_init(); - if (fd > 0) - mp_input_add_cmd_fd(ictx, fd, 0, mp_input_lirc_read, - mp_input_lirc_close); - } -#endif - -#ifdef CONFIG_LIRCC - if (input_conf->use_lircc) { - int fd = lircc_init("mpv", NULL); - if (fd >= 0) - mp_input_add_cmd_fd(ictx, fd, 1, NULL, lircc_cleanup); - } -#endif - -#ifdef CONFIG_COCOA - if (input_conf->use_ar) { - cocoa_init_apple_remote(); - ictx->using_ar = true; - } - - if (input_conf->use_media_keys) { - cocoa_init_media_keys(); - ictx->using_cocoa_media_keys = true; - } -#endif - - if (input_conf->in_file) { - int mode = O_RDONLY; -#ifndef __MINGW32__ - // Use RDWR for FIFOs to ensure they stay open over multiple accesses. - // Note that on Windows due to how the API works, using RDONLY should - // be ok. - struct stat st; - if (stat(input_conf->in_file, &st) == 0 && S_ISFIFO(st.st_mode)) - mode = O_RDWR; - mode |= O_NONBLOCK; -#endif - int in_file_fd = open(input_conf->in_file, mode); - if (in_file_fd >= 0) - mp_input_add_cmd_fd(ictx, in_file_fd, 1, NULL, close); - else - mp_tmsg(MSGT_INPUT, MSGL_ERR, "Can't open %s: %s\n", - input_conf->in_file, strerror(errno)); - } - - return ictx; -} - -static void clear_queue(struct cmd_queue *queue) -{ - while (queue->first) { - struct mp_cmd *item = queue->first; - queue_remove(queue, item); - talloc_free(item); - } -} - -void mp_input_uninit(struct input_ctx *ictx) -{ - if (!ictx) - return; - -#ifdef CONFIG_COCOA - if (ictx->using_ar) { - cocoa_uninit_apple_remote(); - } - - if (ictx->using_cocoa_media_keys) { - cocoa_uninit_media_keys(); - } -#endif - - for (int i = 0; i < ictx->num_fds; i++) { - if (ictx->fds[i].close_func) - ictx->fds[i].close_func(ictx->fds[i].fd); - } - for (int i = 0; i < 2; i++) { - if (ictx->wakeup_pipe[i] != -1) - close(ictx->wakeup_pipe[i]); - } - clear_queue(&ictx->key_cmd_queue); - clear_queue(&ictx->control_cmd_queue); - talloc_free(ictx->current_down_cmd); - talloc_free(ictx); -} - -static int print_key_list(m_option_t *cfg, char *optname, char *optparam) -{ - int i; - printf("\n"); - for (i = 0; key_names[i].name != NULL; i++) - printf("%s\n", key_names[i].name); - return M_OPT_EXIT; -} - -static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam) -{ - const mp_cmd_t *cmd; - int i, j; - - for (i = 0; (cmd = &mp_cmds[i])->name != NULL; i++) { - printf("%-20.20s", cmd->name); - for (j = 0; j < MP_CMD_MAX_ARGS && cmd->args[j].type.type; j++) { - const char *type = cmd->args[j].type.type->name; - if (cmd->args[j].optional) - printf(" [%s]", type); - else - printf(" %s", type); - } - printf("\n"); - } - return M_OPT_EXIT; -} - -void mp_input_wakeup(struct input_ctx *ictx) -{ - if (ictx->wakeup_pipe[1] >= 0) - write(ictx->wakeup_pipe[1], &(char){0}, 1); -} - -/** - * \param time time to wait for an interruption in milliseconds - */ -int mp_input_check_interrupt(struct input_ctx *ictx, int time) -{ - for (int i = 0; ; i++) { - if (async_quit_request || queue_has_abort_cmds(&ictx->key_cmd_queue) || - queue_has_abort_cmds(&ictx->control_cmd_queue)) { - mp_tmsg(MSGT_INPUT, MSGL_WARN, "Received command to move to " - "another file. Aborting current processing.\n"); - return true; - } - if (i) - return false; - read_all_events(ictx, time); - } -} - -unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx) -{ - // Make the frontend always display the mouse cursor (as long as it's not - // forced invisible) if mouse input is desired. - if (mp_input_test_mouse_active(ictx, ictx->mouse_x, ictx->mouse_y)) - ictx->mouse_event_counter++; - return ictx->mouse_event_counter; -} diff --git a/core/input/input.h b/core/input/input.h deleted file mode 100644 index 92e2a32c4f..0000000000 --- a/core/input/input.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_INPUT_H -#define MPLAYER_INPUT_H - -#include -#include "core/bstr.h" -#include "core/m_option.h" - -// All command IDs -enum mp_command_type { - MP_CMD_IGNORE, - MP_CMD_SEEK, - MP_CMD_QUIT, - MP_CMD_QUIT_WATCH_LATER, - MP_CMD_PLAYLIST_NEXT, - MP_CMD_PLAYLIST_PREV, - MP_CMD_OSD, - MP_CMD_TV_STEP_CHANNEL, - MP_CMD_TV_STEP_NORM, - MP_CMD_TV_STEP_CHANNEL_LIST, - MP_CMD_SCREENSHOT, - MP_CMD_SCREENSHOT_TO_FILE, - MP_CMD_LOADFILE, - MP_CMD_LOADLIST, - MP_CMD_PLAYLIST_CLEAR, - MP_CMD_PLAYLIST_REMOVE, - MP_CMD_PLAYLIST_MOVE, - MP_CMD_SUB_STEP, - MP_CMD_TV_SET_CHANNEL, - MP_CMD_TV_LAST_CHANNEL, - MP_CMD_TV_SET_FREQ, - MP_CMD_TV_SET_NORM, - MP_CMD_FRAME_STEP, - MP_CMD_FRAME_BACK_STEP, - MP_CMD_SPEED_MULT, - MP_CMD_RUN, - MP_CMD_SUB_ADD, - MP_CMD_SUB_REMOVE, - MP_CMD_SUB_RELOAD, - MP_CMD_KEYDOWN_EVENTS, - MP_CMD_SET, - MP_CMD_GET_PROPERTY, - MP_CMD_PRINT_TEXT, - MP_CMD_SHOW_TEXT, - MP_CMD_SHOW_PROGRESS, - MP_CMD_RADIO_STEP_CHANNEL, - MP_CMD_RADIO_SET_CHANNEL, - MP_CMD_RADIO_SET_FREQ, - MP_CMD_ADD, - MP_CMD_CYCLE, - MP_CMD_RADIO_STEP_FREQ, - MP_CMD_TV_STEP_FREQ, - MP_CMD_TV_START_SCAN, - MP_CMD_STOP, - - MP_CMD_ENABLE_INPUT_SECTION, - MP_CMD_DISABLE_INPUT_SECTION, - - /// DVB commands - MP_CMD_DVB_SET_CHANNEL = 5101, - - /// Audio Filter commands - MP_CMD_AF, - - /// Video filter commands - MP_CMD_VF, - - /// Video output commands - MP_CMD_VO_CMDLINE, - - // Internal - MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p -}; - -#define MP_CMD_MAX_ARGS 10 - -// Error codes for the drivers - -// An error occurred but we can continue -#define MP_INPUT_ERROR -1 -// A fatal error occurred, this driver should be removed -#define MP_INPUT_DEAD -2 -// No input was available -#define MP_INPUT_NOTHING -3 -//! Input will be available if you try again -#define MP_INPUT_RETRY -4 -// Key FIFO was full - release events may be lost, zero button-down status -#define MP_INPUT_RELEASE_ALL -5 - -enum mp_on_osd { - MP_ON_OSD_NO = 0, // prefer not using OSD - MP_ON_OSD_AUTO = 1, // use default behavior of the specific command - MP_ON_OSD_BAR = 2, // force a bar, if applicable - MP_ON_OSD_MSG = 4, // force a message, if applicable -}; - -enum mp_input_section_flags { - // If a key binding is not defined in the current section, do not search the - // other sections for it (like the default section). Instead, an unbound - // key warning will be printed. - MP_INPUT_EXCLUSIVE = 1, -}; - -struct input_ctx; - -struct mp_cmd_arg { - struct m_option type; - bool optional; - union { - int i; - float f; - double d; - char *s; - void *p; - } v; -}; - -typedef struct mp_cmd { - int id; - char *name; - struct mp_cmd_arg args[MP_CMD_MAX_ARGS]; - int nargs; - int pausing; - bool raw_args; - enum mp_on_osd on_osd; - bstr original; - char *input_section; - bool key_up_follows; - bool mouse_move; - int mouse_x, mouse_y; - struct mp_cmd *queue_next; -} mp_cmd_t; - - -// Executing this command will abort playback (play something else, or quit). -bool mp_input_is_abort_cmd(int cmd_id); - -/* Add a new command input source. - * "fd" is a file descriptor (use a negative value if you don't use any fd) - * "select" tells whether to use select() on the fd to determine when to - * try reading. - * "read_func" is optional. If NULL a default function which reads data - * directly from the fd will be used. It must return either text data - * or one of the MP_INPUT error codes above. - * "close_func" will be called when closing. Can be NULL. Its return value - * is ignored (it's only there to allow using standard close() as the func). - */ -int mp_input_add_cmd_fd(struct input_ctx *ictx, int fd, int select, - int read_func(int fd, char *dest, int size), - int close_func(int fd)); - -/* The args are similar to the cmd version above, except you must give - * a read_func, and it should return key codes (ASCII plus keycodes.h). - */ -int mp_input_add_key_fd(struct input_ctx *ictx, int fd, int select, - int read_func(void *ctx, int fd), - int close_func(int fd), void *ctx); - -// Process keyboard input. code is a key code from keycodes.h, possibly -// with modifiers applied. MP_INPUT_RELEASE_ALL is also a valid value. -void mp_input_put_key(struct input_ctx *ictx, int code); - -// Like mp_input_put_key(), but process all UTF-8 characters in the given -// string as key events. -void mp_input_put_key_utf8(struct input_ctx *ictx, int mods, struct bstr t); - -// Update mouse position (in window coordinates). -void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y); - -void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y); - -// As for the cmd one you usually don't need this function. -void mp_input_rm_key_fd(struct input_ctx *ictx, int fd); - -// Get input key from its name. -int mp_input_get_key_from_name(const char *name); - -// Add a command to the command queue. -int mp_input_queue_cmd(struct input_ctx *ictx, struct mp_cmd *cmd); - -/* Return next available command, or sleep up to "time" ms if none is - * available. If "peek_only" is true return a reference to the command - * but leave it queued. - */ -struct mp_cmd *mp_input_get_cmd(struct input_ctx *ictx, int time, - int peek_only); - -// Parse text and return corresponding struct mp_cmd. -// The location parameter is for error messages. -struct mp_cmd *mp_input_parse_cmd(bstr str, const char *location); - -// After getting a command from mp_input_get_cmd you need to free it using this -// function -void mp_cmd_free(struct mp_cmd *cmd); - -// This creates a copy of a command (used by the auto repeat stuff). -struct mp_cmd *mp_cmd_clone(struct mp_cmd *cmd); - -// Set current input section. The section is appended on top of the list of -// active sections, so its bindings are considered first. If the section was -// already active, it's moved to the top as well. -// name==NULL will behave as if name=="default" -// flags is a bitfield of enum mp_input_section_flags values -void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags); - -// Undo mp_input_enable_section(). -// name==NULL will behave as if name=="default" -void mp_input_disable_section(struct input_ctx *ictx, char *name); - -// Like mp_input_set_section(ictx, ..., 0) for all sections. -void mp_input_disable_all_sections(struct input_ctx *ictx); - -// Set the contents of an input section. -// name: name of the section, for mp_input_set_section() etc. -// location: location string (like filename) for error reporting -// contents: list of keybindings, like input.conf -// a value of NULL deletes the section -// builtin: create as builtin section; this means if the user defines bindings -// using "{name}", they won't be ignored or overwritten - instead, -// they are preferred to the bindings defined with this call -// If the section already exists, its bindings are removed and replaced. -void mp_input_define_section(struct input_ctx *ictx, char *name, char *location, - char *contents, bool builtin); - -// Define where on the screen the named input section should receive. -// Setting a rectangle of size 0 unsets the mouse area. -// A rectangle with negative size disables mouse input for this section. -void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name, - int x0, int y0, int x1, int y1); - -// Used to detect mouse movement. -unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx); - -// Test whether there is any input section which wants to receive events. -// Note that the mouse event is always delivered, even if this returns false. -bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y); - -// Whether input.c wants mouse drag events at this mouse position. If this -// returns false, some VOs will initiate window dragging. -bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y); - -// Initialize the input system -struct MPOpts; -struct input_ctx *mp_input_init(struct MPOpts *opts); - -void mp_input_uninit(struct input_ctx *ictx); - -// Wake up sleeping input loop from another thread. -void mp_input_wakeup(struct input_ctx *ictx); - -// Interruptible usleep: (used by demux) -int mp_input_check_interrupt(struct input_ctx *ictx, int time); - -extern int async_quit_request; - -#endif /* MPLAYER_INPUT_H */ diff --git a/core/input/joystick.c b/core/input/joystick.c deleted file mode 100644 index e8330ffaeb..0000000000 --- a/core/input/joystick.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include "joystick.h" -#include "input.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/mp_msg.h" -#include "keycodes.h" - -#ifndef JOY_AXIS_DELTA -#define JOY_AXIS_DELTA 500 -#endif - -#ifndef JS_DEV -#define JS_DEV "/dev/input/js0" -#endif - -#include - -int axis[256]; -int btns = 0; - -int mp_input_joystick_init(char* dev) { - int fd,l=0; - int initialized = 0; - struct js_event ev; - - mp_tmsg(MSGT_INPUT,MSGL_V,"Opening joystick device %s\n",dev ? dev : JS_DEV); - - fd = open( dev ? dev : JS_DEV , O_RDONLY | O_NONBLOCK ); - if(fd < 0) { - mp_tmsg(MSGT_INPUT,MSGL_ERR,"Can't open joystick device %s: %s\n",dev ? dev : JS_DEV,strerror(errno)); - return -1; - } - - while(! initialized) { - l = 0; - while((unsigned int)l < sizeof(struct js_event)) { - int r = read(fd,((char*)&ev)+l,sizeof(struct js_event)-l); - if(r < 0) { - if(errno == EINTR) - continue; - else if(errno == EAGAIN) { - initialized = 1; - break; - } - mp_tmsg(MSGT_INPUT,MSGL_ERR,"Error while reading joystick device: %s\n",strerror(errno)); - close(fd); - return -1; - } - l += r; - } - if((unsigned int)l < sizeof(struct js_event)) { - if(l > 0) - mp_tmsg(MSGT_INPUT,MSGL_WARN,"Joystick: We lose %d bytes of data\n",l); - break; - } - if(ev.type == JS_EVENT_BUTTON) - btns |= (ev.value << ev.number); - if(ev.type == JS_EVENT_AXIS) - axis[ev.number] = ev.value; - } - - return fd; -} - -int mp_input_joystick_read(void *ctx, int fd) { - struct js_event ev; - int l=0; - - while((unsigned int)l < sizeof(struct js_event)) { - int r = read(fd,&ev+l,sizeof(struct js_event)-l); - if(r <= 0) { - if(errno == EINTR) - continue; - else if(errno == EAGAIN) - return MP_INPUT_NOTHING; - if( r < 0) - mp_tmsg(MSGT_INPUT,MSGL_ERR,"Error while reading joystick device: %s\n",strerror(errno)); - else - mp_tmsg(MSGT_INPUT,MSGL_ERR,"Error while reading joystick device: %s\n","EOF"); - return MP_INPUT_DEAD; - } - l += r; - } - - if((unsigned int)l < sizeof(struct js_event)) { - if(l > 0) - mp_tmsg(MSGT_INPUT,MSGL_WARN,"Joystick: We lose %d bytes of data\n",l); - return MP_INPUT_NOTHING; - } - - if(ev.type & JS_EVENT_INIT) { - mp_tmsg(MSGT_INPUT,MSGL_WARN,"Joystick: warning init event, we have lost sync with driver.\n"); - ev.type &= ~JS_EVENT_INIT; - if(ev.type == JS_EVENT_BUTTON) { - int s = (btns >> ev.number) & 1; - if(s == ev.value) // State is the same : ignore - return MP_INPUT_NOTHING; - } - if(ev.type == JS_EVENT_AXIS) { - if( ( axis[ev.number] == 1 && ev.value > JOY_AXIS_DELTA) || - (axis[ev.number] == -1 && ev.value < -JOY_AXIS_DELTA) || - (axis[ev.number] == 0 && ev.value >= -JOY_AXIS_DELTA && ev.value <= JOY_AXIS_DELTA) - ) // State is the same : ignore - return MP_INPUT_NOTHING; - } - } - - if(ev.type & JS_EVENT_BUTTON) { - btns &= ~(1 << ev.number); - btns |= (ev.value << ev.number); - if(ev.value == 1) - return (MP_JOY_BTN0 + ev.number) | MP_KEY_STATE_DOWN; - else - return (MP_JOY_BTN0 + ev.number) | MP_KEY_STATE_UP; - } else if(ev.type & JS_EVENT_AXIS) { - if(ev.value < -JOY_AXIS_DELTA && axis[ev.number] != -1) { - axis[ev.number] = -1; - return (MP_JOY_AXIS0_MINUS+(2*ev.number)) | MP_KEY_STATE_DOWN; - } else if(ev.value > JOY_AXIS_DELTA && axis[ev.number] != 1) { - axis[ev.number] = 1; - return (MP_JOY_AXIS0_PLUS+(2*ev.number)) | MP_KEY_STATE_DOWN; - } else if(ev.value <= JOY_AXIS_DELTA && ev.value >= -JOY_AXIS_DELTA && axis[ev.number] != 0) { - int r = axis[ev.number] == 1 ? MP_JOY_AXIS0_PLUS+(2*ev.number) : MP_JOY_AXIS0_MINUS+(2*ev.number); - axis[ev.number] = 0; - return r | MP_KEY_STATE_UP; - } else - return MP_INPUT_NOTHING; - } else { - mp_tmsg(MSGT_INPUT,MSGL_WARN,"Joystick warning unknown event type %d\n",ev.type); - return MP_INPUT_ERROR; - } - - return MP_INPUT_NOTHING; -} diff --git a/core/input/joystick.h b/core/input/joystick.h deleted file mode 100644 index b9480eb686..0000000000 --- a/core/input/joystick.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_JOYSTICK_H -#define MPLAYER_JOYSTICK_H - -int mp_input_joystick_init(char* dev); - -int mp_input_joystick_read(void *ctx, int fd); - -#endif /* MPLAYER_JOYSTICK_H */ diff --git a/core/input/keycodes.h b/core/input/keycodes.h deleted file mode 100644 index d91465f3be..0000000000 --- a/core/input/keycodes.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * KEY code definitions for keys/events not passed by ASCII value - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_KEYCODES_H -#define MPLAYER_KEYCODES_H - -#define MP_KEY_BASE (1<<21) - -#define MP_KEY_ENTER 13 -#define MP_KEY_TAB 9 - -/* Control keys */ -#define MP_KEY_BACKSPACE (MP_KEY_BASE+0) -#define MP_KEY_DELETE (MP_KEY_BASE+1) -#define MP_KEY_INSERT (MP_KEY_BASE+2) -#define MP_KEY_HOME (MP_KEY_BASE+3) -#define MP_KEY_END (MP_KEY_BASE+4) -#define MP_KEY_PAGE_UP (MP_KEY_BASE+5) -#define MP_KEY_PAGE_DOWN (MP_KEY_BASE+6) -#define MP_KEY_ESC (MP_KEY_BASE+7) -#define MP_KEY_PRINT (MP_KEY_BASE+8) - -/* Control keys short name */ -#define MP_KEY_BS MP_KEY_BACKSPACE -#define MP_KEY_DEL MP_KEY_DELETE -#define MP_KEY_INS MP_KEY_INSERT -#define MP_KEY_PGUP MP_KEY_PAGE_UP -#define MP_KEY_PGDOWN MP_KEY_PAGE_DOWN -#define MP_KEY_PGDWN MP_KEY_PAGE_DOWN - -/* Cursor movement */ -#define MP_KEY_CRSR (MP_KEY_BASE+0x10) -#define MP_KEY_RIGHT (MP_KEY_CRSR+0) -#define MP_KEY_LEFT (MP_KEY_CRSR+1) -#define MP_KEY_DOWN (MP_KEY_CRSR+2) -#define MP_KEY_UP (MP_KEY_CRSR+3) - -/* Multimedia keyboard/remote keys */ -#define MP_KEY_MM_BASE (MP_KEY_BASE+0x20) -#define MP_KEY_POWER (MP_KEY_MM_BASE+0) -#define MP_KEY_MENU (MP_KEY_MM_BASE+1) -#define MP_KEY_PLAY (MP_KEY_MM_BASE+2) -#define MP_KEY_PAUSE (MP_KEY_MM_BASE+3) -#define MP_KEY_PLAYPAUSE (MP_KEY_MM_BASE+4) -#define MP_KEY_STOP (MP_KEY_MM_BASE+5) -#define MP_KEY_FORWARD (MP_KEY_MM_BASE+6) -#define MP_KEY_REWIND (MP_KEY_MM_BASE+7) -#define MP_KEY_NEXT (MP_KEY_MM_BASE+8) -#define MP_KEY_PREV (MP_KEY_MM_BASE+9) -#define MP_KEY_VOLUME_UP (MP_KEY_MM_BASE+10) -#define MP_KEY_VOLUME_DOWN (MP_KEY_MM_BASE+11) -#define MP_KEY_MUTE (MP_KEY_MM_BASE+12) - -/* Function keys */ -#define MP_KEY_F (MP_KEY_BASE+0x40) - -/* Keypad keys */ -#define MP_KEY_KEYPAD (MP_KEY_BASE+0x60) -#define MP_KEY_KP0 (MP_KEY_KEYPAD+0) -#define MP_KEY_KP1 (MP_KEY_KEYPAD+1) -#define MP_KEY_KP2 (MP_KEY_KEYPAD+2) -#define MP_KEY_KP3 (MP_KEY_KEYPAD+3) -#define MP_KEY_KP4 (MP_KEY_KEYPAD+4) -#define MP_KEY_KP5 (MP_KEY_KEYPAD+5) -#define MP_KEY_KP6 (MP_KEY_KEYPAD+6) -#define MP_KEY_KP7 (MP_KEY_KEYPAD+7) -#define MP_KEY_KP8 (MP_KEY_KEYPAD+8) -#define MP_KEY_KP9 (MP_KEY_KEYPAD+9) -#define MP_KEY_KPDEC (MP_KEY_KEYPAD+10) -#define MP_KEY_KPINS (MP_KEY_KEYPAD+11) -#define MP_KEY_KPDEL (MP_KEY_KEYPAD+12) -#define MP_KEY_KPENTER (MP_KEY_KEYPAD+13) - - -// Joystick input module -#define MP_JOY_BASE (MP_KEY_BASE+0x70) -#define MP_JOY_AXIS0_PLUS (MP_JOY_BASE+0) -#define MP_JOY_AXIS0_MINUS (MP_JOY_BASE+1) -#define MP_JOY_AXIS1_PLUS (MP_JOY_BASE+2) -#define MP_JOY_AXIS1_MINUS (MP_JOY_BASE+3) -#define MP_JOY_AXIS2_PLUS (MP_JOY_BASE+4) -#define MP_JOY_AXIS2_MINUS (MP_JOY_BASE+5) -#define MP_JOY_AXIS3_PLUS (MP_JOY_BASE+6) -#define MP_JOY_AXIS3_MINUS (MP_JOY_BASE+7) -#define MP_JOY_AXIS4_PLUS (MP_JOY_BASE+8) -#define MP_JOY_AXIS4_MINUS (MP_JOY_BASE+9) -#define MP_JOY_AXIS5_PLUS (MP_JOY_BASE+10) -#define MP_JOY_AXIS5_MINUS (MP_JOY_BASE+11) -#define MP_JOY_AXIS6_PLUS (MP_JOY_BASE+12) -#define MP_JOY_AXIS6_MINUS (MP_JOY_BASE+13) -#define MP_JOY_AXIS7_PLUS (MP_JOY_BASE+14) -#define MP_JOY_AXIS7_MINUS (MP_JOY_BASE+15) -#define MP_JOY_AXIS8_PLUS (MP_JOY_BASE+16) -#define MP_JOY_AXIS8_MINUS (MP_JOY_BASE+17) -#define MP_JOY_AXIS9_PLUS (MP_JOY_BASE+18) -#define MP_JOY_AXIS9_MINUS (MP_JOY_BASE+19) - -#define MP_JOY_BTN_BASE ((MP_KEY_BASE+0x90)|MP_NO_REPEAT_KEY) -#define MP_JOY_BTN0 (MP_JOY_BTN_BASE+0) -#define MP_JOY_BTN1 (MP_JOY_BTN_BASE+1) -#define MP_JOY_BTN2 (MP_JOY_BTN_BASE+2) -#define MP_JOY_BTN3 (MP_JOY_BTN_BASE+3) -#define MP_JOY_BTN4 (MP_JOY_BTN_BASE+4) -#define MP_JOY_BTN5 (MP_JOY_BTN_BASE+5) -#define MP_JOY_BTN6 (MP_JOY_BTN_BASE+6) -#define MP_JOY_BTN7 (MP_JOY_BTN_BASE+7) -#define MP_JOY_BTN8 (MP_JOY_BTN_BASE+8) -#define MP_JOY_BTN9 (MP_JOY_BTN_BASE+9) - - -// Mouse events from VOs -#define MP_MOUSE_BASE ((MP_KEY_BASE+0xA0)|MP_NO_REPEAT_KEY|MP_KEY_EMIT_ON_UP) -#define MP_MOUSE_BTN0 (MP_MOUSE_BASE+0) -#define MP_MOUSE_BTN1 (MP_MOUSE_BASE+1) -#define MP_MOUSE_BTN2 (MP_MOUSE_BASE+2) -#define MP_MOUSE_BTN3 (MP_MOUSE_BASE+3) -#define MP_MOUSE_BTN4 (MP_MOUSE_BASE+4) -#define MP_MOUSE_BTN5 (MP_MOUSE_BASE+5) -#define MP_MOUSE_BTN6 (MP_MOUSE_BASE+6) -#define MP_MOUSE_BTN7 (MP_MOUSE_BASE+7) -#define MP_MOUSE_BTN8 (MP_MOUSE_BASE+8) -#define MP_MOUSE_BTN9 (MP_MOUSE_BASE+9) -#define MP_MOUSE_BTN10 (MP_MOUSE_BASE+10) -#define MP_MOUSE_BTN11 (MP_MOUSE_BASE+11) -#define MP_MOUSE_BTN12 (MP_MOUSE_BASE+12) -#define MP_MOUSE_BTN13 (MP_MOUSE_BASE+13) -#define MP_MOUSE_BTN14 (MP_MOUSE_BASE+14) -#define MP_MOUSE_BTN15 (MP_MOUSE_BASE+15) -#define MP_MOUSE_BTN16 (MP_MOUSE_BASE+16) -#define MP_MOUSE_BTN17 (MP_MOUSE_BASE+17) -#define MP_MOUSE_BTN18 (MP_MOUSE_BASE+18) -#define MP_MOUSE_BTN19 (MP_MOUSE_BASE+19) -#define MP_MOUSE_BTN_END (MP_MOUSE_BASE+20) - -#define MP_KEY_IS_MOUSE_BTN_SINGLE(code) \ - ((code) >= MP_MOUSE_BASE && (code) < MP_MOUSE_BTN_END) - -#define MP_MOUSE_BASE_DBL ((MP_KEY_BASE+0xC0)|MP_NO_REPEAT_KEY) -#define MP_MOUSE_BTN0_DBL (MP_MOUSE_BASE_DBL+0) -#define MP_MOUSE_BTN1_DBL (MP_MOUSE_BASE_DBL+1) -#define MP_MOUSE_BTN2_DBL (MP_MOUSE_BASE_DBL+2) -#define MP_MOUSE_BTN3_DBL (MP_MOUSE_BASE_DBL+3) -#define MP_MOUSE_BTN4_DBL (MP_MOUSE_BASE_DBL+4) -#define MP_MOUSE_BTN5_DBL (MP_MOUSE_BASE_DBL+5) -#define MP_MOUSE_BTN6_DBL (MP_MOUSE_BASE_DBL+6) -#define MP_MOUSE_BTN7_DBL (MP_MOUSE_BASE_DBL+7) -#define MP_MOUSE_BTN8_DBL (MP_MOUSE_BASE_DBL+8) -#define MP_MOUSE_BTN9_DBL (MP_MOUSE_BASE_DBL+9) -#define MP_MOUSE_BTN10_DBL (MP_MOUSE_BASE_DBL+10) -#define MP_MOUSE_BTN11_DBL (MP_MOUSE_BASE_DBL+11) -#define MP_MOUSE_BTN12_DBL (MP_MOUSE_BASE_DBL+12) -#define MP_MOUSE_BTN13_DBL (MP_MOUSE_BASE_DBL+13) -#define MP_MOUSE_BTN14_DBL (MP_MOUSE_BASE_DBL+14) -#define MP_MOUSE_BTN15_DBL (MP_MOUSE_BASE_DBL+15) -#define MP_MOUSE_BTN16_DBL (MP_MOUSE_BASE_DBL+16) -#define MP_MOUSE_BTN17_DBL (MP_MOUSE_BASE_DBL+17) -#define MP_MOUSE_BTN18_DBL (MP_MOUSE_BASE_DBL+18) -#define MP_MOUSE_BTN19_DBL (MP_MOUSE_BASE_DBL+19) -#define MP_MOUSE_BTN_DBL_END (MP_MOUSE_BASE_DBL+20) - -#define MP_KEY_IS_MOUSE_BTN_DBL(code) \ - ((code) >= MP_MOUSE_BTN0_DBL && (code) < MP_MOUSE_BTN_DBL_END) - -// Apple Remote input module -#define MP_AR_BASE (MP_KEY_BASE+0xE0) -#define MP_AR_PLAY (MP_AR_BASE + 0) -#define MP_AR_PLAY_HOLD (MP_AR_BASE + 1) -#define MP_AR_CENTER (MP_AR_BASE + 2) -#define MP_AR_CENTER_HOLD (MP_AR_BASE + 3) -#define MP_AR_NEXT (MP_AR_BASE + 4) -#define MP_AR_NEXT_HOLD (MP_AR_BASE + 5) -#define MP_AR_PREV (MP_AR_BASE + 6) -#define MP_AR_PREV_HOLD (MP_AR_BASE + 7) -#define MP_AR_MENU (MP_AR_BASE + 8) -#define MP_AR_MENU_HOLD (MP_AR_BASE + 9) -#define MP_AR_VUP (MP_AR_BASE + 10) -#define MP_AR_VUP_HOLD (MP_AR_BASE + 11) -#define MP_AR_VDOWN (MP_AR_BASE + 12) -#define MP_AR_VDOWN_HOLD (MP_AR_BASE + 13) - -// Apple Media Keys input module -#define MP_MK_BASE (MP_KEY_BASE+0xF0) -#define MP_MK_PLAY (MP_MK_BASE + 0) -#define MP_MK_PREV (MP_MK_BASE + 1) -#define MP_MK_NEXT (MP_MK_BASE + 2) - -/* Special keys */ -#define MP_KEY_INTERN (MP_KEY_BASE+0x1000) -#define MP_KEY_CLOSE_WIN (MP_KEY_INTERN+0) -// Generated by input.c (VOs use mp_input_set_mouse_pos()) -#define MP_KEY_MOUSE_MOVE ((MP_KEY_INTERN+1)|MP_NO_REPEAT_KEY) -#define MP_KEY_MOUSE_LEAVE ((MP_KEY_INTERN+2)|MP_NO_REPEAT_KEY) - - -#define MP_KEY_DEPENDS_ON_MOUSE_POS(code) \ - (MP_KEY_IS_MOUSE_BTN_SINGLE(code) || MP_KEY_IS_MOUSE_BTN_DBL(code) || \ - (code) == MP_KEY_MOUSE_MOVE) - -/* Modifiers added to individual keys */ -#define MP_KEY_MODIFIER_SHIFT (1<<22) -#define MP_KEY_MODIFIER_CTRL (1<<23) -#define MP_KEY_MODIFIER_ALT (1<<24) -#define MP_KEY_MODIFIER_META (1<<25) - -#define MP_KEY_MODIFIER_MASK (MP_KEY_MODIFIER_SHIFT | MP_KEY_MODIFIER_CTRL | \ - MP_KEY_MODIFIER_ALT | MP_KEY_MODIFIER_META | \ - MP_KEY_STATE_DOWN | MP_KEY_STATE_UP) - -// Flag for key events. Multiple down events are idempotent. Release keys by -// sending the key code with KEY_STATE_UP set, or by sending -// MP_INPUT_RELEASE_ALL as key code. -#define MP_KEY_STATE_DOWN (1<<26) - -// Flag for key events. Releases a key previously held down with -// MP_KEY_STATE_DOWN. Do not sending redundant UP events and do not forget to -// release keys at all with UP. If input is unreliable, use MP_INPUT_RELEASE_ALL -// or don't use MP_KEY_STATE_DOWN in the first place. -#define MP_KEY_STATE_UP (1<<27) - -// The following flags are not modifiers, but are part of the keycode itself. - -// Emit a command even on key-up (normally key-up is ignored). The command -// handling code has to ignore unwanted commands specifically. -#define MP_KEY_EMIT_ON_UP (1<<28) - -// Use this when the key shouldn't be auto-repeated (like mouse buttons) -// Also means both key-down key-up events produce emit bound commands. -#define MP_NO_REPEAT_KEY (1<<29) - -#endif /* MPLAYER_KEYCODES_H */ diff --git a/core/input/lirc.c b/core/input/lirc.c deleted file mode 100644 index 699168d239..0000000000 --- a/core/input/lirc.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "core/mp_msg.h" -#include "input.h" -#include "lirc.h" - -static struct lirc_config *lirc_config; -char *lirc_configfile; - -static char* cmd_buf = NULL; - -int -mp_input_lirc_init(void) { - int lirc_sock; - int mode; - - mp_tmsg(MSGT_LIRC,MSGL_V,"Setting up LIRC support...\n"); - if((lirc_sock=lirc_init("mpv",0))==-1){ - mp_tmsg(MSGT_LIRC,MSGL_V,"Failed to open LIRC support. You will not be able to use your remote control.\n"); - return -1; - } - - mode = fcntl(lirc_sock, F_GETFL); - if (mode < 0 || fcntl(lirc_sock, F_SETFL, mode | O_NONBLOCK) < 0) { - mp_msg(MSGT_LIRC, MSGL_ERR, "setting non-blocking mode failed: %s\n", - strerror(errno)); - lirc_deinit(); - return -1; - } - - if(lirc_readconfig( lirc_configfile,&lirc_config,NULL )!=0 ){ - mp_tmsg(MSGT_LIRC,MSGL_ERR,"Failed to read LIRC config file %s.\n", - lirc_configfile == NULL ? "~/.lircrc" : lirc_configfile); - lirc_deinit(); - return -1; - } - - return lirc_sock; -} - -int mp_input_lirc_read(int fd,char* dest, int s) { - int r,cl = 0; - char *code = NULL,*c = NULL; - - // We have something in the buffer return it - if(cmd_buf != NULL) { - int l = strlen(cmd_buf), w = l > s ? s : l; - memcpy(dest,cmd_buf,w); - l -= w; - if(l > 0) - memmove(cmd_buf,&cmd_buf[w],l+1); - else { - free(cmd_buf); - cmd_buf = NULL; - } - return w; - } - - // Nothing in the buffer, poll the lirc fd - if(lirc_nextcode(&code) != 0) { - mp_msg(MSGT_LIRC,MSGL_ERR,"Lirc error :(\n"); - return MP_INPUT_DEAD; - } - - if(!code) return MP_INPUT_NOTHING; - - // We put all cmds in a single buffer separated by \n - while((r = lirc_code2char(lirc_config,code,&c))==0 && c!=NULL) { - int l = strlen(c); - if(l <= 0) - continue; - cmd_buf = realloc(cmd_buf,cl+l+2); - memcpy(&cmd_buf[cl],c,l); - cl += l+1; - cmd_buf[cl-1] = '\n'; - cmd_buf[cl] = '\0'; - } - - free(code); - - if(r < 0) - return MP_INPUT_DEAD; - else if(cmd_buf) // return the first command in the buffer - return mp_input_lirc_read(fd,dest,s); - else - return MP_INPUT_RETRY; - -} - -int mp_input_lirc_close(int fd) -{ - free(cmd_buf); - cmd_buf = NULL; - lirc_freeconfig(lirc_config); - lirc_deinit(); - return 0; -} diff --git a/core/input/lirc.h b/core/input/lirc.h deleted file mode 100644 index ac1937f91d..0000000000 --- a/core/input/lirc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_LIRC_H -#define MPLAYER_LIRC_H - -int -mp_input_lirc_init(void); - -int -mp_input_lirc_read(int fd,char* dest, int s); - -int mp_input_lirc_close(int fd); - -#endif /* MPLAYER_LIRC_H */ diff --git a/core/m_config.c b/core/m_config.c deleted file mode 100644 index f362b43836..0000000000 --- a/core/m_config.c +++ /dev/null @@ -1,777 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/// \file -/// \ingroup Config - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "talloc.h" - -#include "m_config.h" -#include "core/m_option.h" -#include "core/mp_msg.h" - -// Profiles allow to predefine some sets of options that can then -// be applied later on with the internal -profile option. -#define MAX_PROFILE_DEPTH 20 - -struct m_profile { - struct m_profile *next; - char *name; - char *desc; - int num_opts; - // Option/value pair array. - char **opts; -}; - -// In the file local case, this contains the old global value. -struct m_opt_backup { - struct m_opt_backup *next; - struct m_config_option *co; - void *backup; -}; - -static int parse_include(struct m_config *config, struct bstr param, bool set, - int flags) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - if (!set) - return 1; - char *filename = bstrdup0(NULL, param); - config->includefunc(config, filename, flags); - talloc_free(filename); - return 1; -} - -static int parse_profile(struct m_config *config, const struct m_option *opt, - struct bstr name, struct bstr param, bool set, int flags) -{ - if (!bstrcmp0(param, "help")) { - struct m_profile *p; - if (!config->profiles) { - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, - "No profiles have been defined.\n"); - return M_OPT_EXIT - 1; - } - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "Available profiles:\n"); - for (p = config->profiles; p; p = p->next) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\t%s\t%s\n", p->name, - p->desc ? p->desc : ""); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - return M_OPT_EXIT - 1; - } - - char **list = NULL; - int r = m_option_type_string_list.parse(opt, name, param, &list); - if (r < 0) - return r; - if (!list || !list[0]) - return M_OPT_INVALID; - for (int i = 0; list[i]; i++) { - struct m_profile *p = m_config_get_profile0(config, list[i]); - if (!p) { - mp_tmsg(MSGT_CFGPARSER, MSGL_WARN, "Unknown profile '%s'.\n", - list[i]); - r = M_OPT_INVALID; - } else if (set) - m_config_set_profile(config, p, flags); - } - m_option_free(opt, &list); - return r; -} - -static int show_profile(struct m_config *config, bstr param) -{ - struct m_profile *p; - int i, j; - if (!param.len) - return M_OPT_MISSING_PARAM; - if (!(p = m_config_get_profile(config, param))) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Unknown profile '%.*s'.\n", - BSTR_P(param)); - return M_OPT_EXIT - 1; - } - if (!config->profile_depth) - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "Profile %s: %s\n", p->name, - p->desc ? p->desc : ""); - config->profile_depth++; - for (i = 0; i < p->num_opts; i++) { - char spc[config->profile_depth + 1]; - for (j = 0; j < config->profile_depth; j++) - spc[j] = ' '; - spc[config->profile_depth] = '\0'; - - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s%s=%s\n", spc, - p->opts[2 * i], p->opts[2 * i + 1]); - - if (config->profile_depth < MAX_PROFILE_DEPTH - && !strcmp(p->opts[2*i], "profile")) { - char *e, *list = p->opts[2 * i + 1]; - while ((e = strchr(list, ','))) { - int l = e - list; - char tmp[l+1]; - if (!l) - continue; - memcpy(tmp, list, l); - tmp[l] = '\0'; - show_profile(config, bstr0(tmp)); - list = e + 1; - } - if (list[0] != '\0') - show_profile(config, bstr0(list)); - } - } - config->profile_depth--; - if (!config->profile_depth) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - return M_OPT_EXIT - 1; -} - -static int list_options(struct m_config *config) -{ - m_config_print_option_list(config); - return M_OPT_EXIT; -} - -// The memcpys are supposed to work around the struct aliasing violation, -// that would result if we just dereferenced a void** (where the void** is -// actually casted from struct some_type* ). -static void *substruct_read_ptr(void *ptr) -{ - void *res; - memcpy(&res, ptr, sizeof(void*)); - return res; -} -static void substruct_write_ptr(void *ptr, void *val) -{ - memcpy(ptr, &val, sizeof(void*)); -} - -static struct m_config_option *m_config_add_option(struct m_config *config, - const char *prefix, - struct m_config_option *parent, - const struct m_option *arg); - -static void add_options(struct m_config *config, - struct m_config_option *parent, - const struct m_option *defs); - -static int config_destroy(void *p) -{ - struct m_config *config = p; - m_config_restore_backups(config); - for (struct m_config_option *copt = config->opts; copt; copt = copt->next) - m_option_free(copt->opt, copt->data); - return 0; -} - -struct m_config *m_config_new(void *talloc_parent, size_t size, - const void *defaults, - const struct m_option *options, - const char *suboptinit) -{ - struct m_config *config = talloc(talloc_parent, struct m_config); - talloc_set_destructor(config, config_destroy); - *config = (struct m_config) { - .optstruct_size = size, - .optstruct_defaults = defaults, - .options = options, - .suboptinit = suboptinit, - }; - if (size) { // size==0 means a dummy object is created - config->optstruct = talloc_zero_size(config, size); - if (defaults) - memcpy(config->optstruct, defaults, size); - if (options) - add_options(config, NULL, options); - } - if (suboptinit) { - bstr s = bstr0(suboptinit); - int r = m_obj_parse_sub_config(bstr0("internal"), bstr0("-"), &s, - config, 0, NULL); - if (r < 0 || s.len > 0) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Internal error: preset broken\n"); - } - return config; -} - -struct m_config *m_config_from_obj_desc(void *talloc_parent, - struct m_obj_desc *desc) -{ - return m_config_new(talloc_parent, desc->priv_size, desc->priv_defaults, - desc->options, desc->init_options); -} - -int m_config_set_obj_params(struct m_config *conf, char **args) -{ - for (int n = 0; args && args[n * 2 + 0]; n++) { - int r = m_config_set_option(conf, bstr0(args[n * 2 + 0]), - bstr0(args[n * 2 + 1])); - if (r < 0) - return r; - } - return 0; -} - -int m_config_initialize_obj(struct m_config *config, struct m_obj_desc *desc, - void **ppriv, char ***pargs) -{ - if (desc->priv_size) { - int r = m_config_set_obj_params(config, *pargs); - if (r < 0) - return r; - *ppriv = config->optstruct; - *pargs = NULL; - } else if (*pargs && !strcmp((*pargs)[0], "_oldargs_")) { - // Handle things which still use the old subopt parser - *pargs = (char **)((*pargs)[1]); - } else { - *pargs = NULL; - } - return 0; -} - -static void ensure_backup(struct m_config *config, struct m_config_option *co) -{ - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) - return; - if (co->opt->flags & M_OPT_GLOBAL) - return; - if (!co->data) - return; - for (struct m_opt_backup *cur = config->backup_opts; cur; cur = cur->next) { - if (cur->co->data == co->data) // comparing data ptr catches aliases - return; - } - struct m_opt_backup *bc = talloc_ptrtype(NULL, bc); - *bc = (struct m_opt_backup) { - .co = co, - .backup = talloc_zero_size(bc, co->opt->type->size), - }; - m_option_copy(co->opt, bc->backup, co->data); - bc->next = config->backup_opts; - config->backup_opts = bc; -} - -void m_config_restore_backups(struct m_config *config) -{ - while (config->backup_opts) { - struct m_opt_backup *bc = config->backup_opts; - config->backup_opts = bc->next; - - m_option_copy(bc->co->opt, bc->co->data, bc->backup); - m_option_free(bc->co->opt, bc->backup); - talloc_free(bc); - } -} - -void m_config_backup_opt(struct m_config *config, const char *opt) -{ - struct m_config_option *co = m_config_get_co(config, bstr0(opt)); - if (co) { - ensure_backup(config, co); - } else { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Option %s not found.\n", opt); - } -} - -void m_config_backup_all_opts(struct m_config *config) -{ - for (struct m_config_option *co = config->opts; co; co = co->next) - ensure_backup(config, co); -} - -// Given an option --opt, add --no-opt (if applicable). -static void add_negation_option(struct m_config *config, - struct m_config_option *parent, - const struct m_option *opt) -{ - int value; - if (opt->type == CONF_TYPE_FLAG) { - value = opt->min; - } else if (opt->type == CONF_TYPE_CHOICE) { - // Find out whether there's a "no" choice. - // m_option_parse() should be used for this, but it prints - // unsilenceable error messages. - struct m_opt_choice_alternatives *alt = opt->priv; - for ( ; alt->name; alt++) { - if (strcmp(alt->name, "no") == 0) - break; - } - if (!alt->name) - return; - value = alt->value; - } else { - return; - } - struct m_option *no_opt = talloc_ptrtype(config, no_opt); - *no_opt = (struct m_option) { - .name = talloc_asprintf(no_opt, "no-%s", opt->name), - .type = CONF_TYPE_STORE, - .flags = opt->flags & (M_OPT_NOCFG | M_OPT_GLOBAL | M_OPT_PRE_PARSE), - .new = opt->new, - .p = opt->p, - .offset = opt->offset, - .max = value, - }; - struct m_config_option *co = m_config_add_option(config, "", parent, no_opt); - co->is_generated = true; - // Consider a parent option "--sub" and a subopt "opt". Then the above - // call will add "no-opt". Add "--no-sub-opt" too. (This former call will - // also generate "--sub-no-opt", which is not really needed or wanted, but - // is a consequence of supporting "--sub=...:no-opt".) - if (parent && parent->name && strlen(parent->name)) { - no_opt = talloc_memdup(config, no_opt, sizeof(*no_opt)); - no_opt->name = opt->name; - co = m_config_add_option(config, "no-", parent, no_opt); - co->is_generated = true; - } -} - -static void add_options(struct m_config *config, - struct m_config_option *parent, - const struct m_option *defs) -{ - for (int i = 0; defs[i].name; i++) - m_config_add_option(config, "", parent, defs + i); -} - -// Sub-config that adds all its children to the parent. -static bool is_merge_opt(const struct m_option *opt) -{ - return (opt->type->flags & M_OPT_TYPE_HAS_CHILD) && strlen(opt->name) == 0; -} - -static struct m_config_option *m_config_add_option(struct m_config *config, - const char *prefix, - struct m_config_option *parent, - const struct m_option *arg) -{ - assert(config != NULL); - assert(arg != NULL); - - // Allocate a new entry for this option - struct m_config_option *co = talloc_zero(config, struct m_config_option); - co->opt = arg; - - void *optstruct = config->optstruct; - if (parent && (parent->opt->type->flags & M_OPT_TYPE_USE_SUBSTRUCT)) - optstruct = substruct_read_ptr(parent->data); - co->data = arg->new ? (char *)optstruct + arg->offset : arg->p; - - if (parent) { - // Merge case: pretend it has no parent (note that we still must follow - // the "real" parent for accessing struct fields) - co->parent = is_merge_opt(parent->opt) ? parent->parent : parent; - } - - // Fill in the full name - if (co->parent) { - co->name = talloc_asprintf(co, "%s-%s", co->parent->name, arg->name); - } else { - co->name = (char *)arg->name; - } - co->name = talloc_asprintf(co, "%s%s", prefix, co->name); - - // Option with children -> add them - if (arg->type->flags & M_OPT_TYPE_HAS_CHILD) { - if (arg->type->flags & M_OPT_TYPE_USE_SUBSTRUCT) { - const struct m_sub_options *subopts = arg->priv; - if (!substruct_read_ptr(co->data)) { - void *subdata = m_config_alloc_struct(config, subopts); - substruct_write_ptr(co->data, subdata); - } - add_options(config, co, subopts->opts); - } else { - const struct m_option *sub = arg->p; - add_options(config, co, sub); - } - } else { - // Initialize options - if (co->data) { - if (arg->defval) { - // Target data in optstruct is supposed to be cleared (consider - // m_option freeing previously set dynamic data). - m_option_copy(arg, co->data, arg->defval); - } else if (arg->type->flags & M_OPT_TYPE_DYNAMIC) { - // Initialize dynamically managed fields from static data (like - // string options): copy the option into temporary memory, - // clear the original option (to stop m_option from freeing the - // static data), copy it back. - // This would leak memory when done on aliased options. - bool aliased = false; - for (struct m_config_option *i = config->opts; i; i = i->next) { - if (co->data == i->data) { - aliased = true; - break; - } - } - if (!aliased) { - union m_option_value temp = {0}; - m_option_copy(arg, &temp, co->data); - memset(co->data, 0, arg->type->size); - m_option_copy(arg, co->data, &temp); - m_option_free(arg, &temp); - } - } - } - } - - // pretend that merge options don't exist (only their children matter) - if (!is_merge_opt(co->opt)) { - struct m_config_option **last = &config->opts; - while (*last) - last = &(*last)->next; - *last = co; - } - - add_negation_option(config, parent, arg); - - return co; -} - -struct m_config_option *m_config_get_co(const struct m_config *config, - struct bstr name) -{ - struct m_config_option *co; - - for (co = config->opts; co; co = co->next) { - struct bstr coname = bstr0(co->name); - if ((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) - && bstr_endswith0(coname, "*")) { - coname.len--; - if (bstrcmp(bstr_splice(name, 0, coname.len), coname) == 0) - return co; - } else if (bstrcmp(coname, name) == 0) - return co; - } - return NULL; -} - -const char *m_config_get_positional_option(const struct m_config *config, int n) -{ - int pos = 0; - for (struct m_config_option *co = config->opts; co; co = co->next) { - if (!co->is_generated) { - if (pos == n) - return co->name; - pos++; - } - } - return NULL; -} - -static int parse_subopts(struct m_config *config, char *name, char *prefix, - struct bstr param, int flags); - -static int m_config_parse_option(struct m_config *config, struct bstr name, - struct bstr param, int flags) -{ - assert(config != NULL); - assert(name.len != 0); - bool set = !(flags & M_SETOPT_CHECK_ONLY); - - struct m_config_option *co = m_config_get_co(config, name); - if (!co) - return M_OPT_UNKNOWN; - - // This is the only mandatory function - assert(co->opt->type->parse); - - if ((flags & M_SETOPT_PRE_PARSE_ONLY) && !(co->opt->flags & M_OPT_PRE_PARSE)) - return 0; - - // Check if this option isn't forbidden in the current mode - if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option can't be used in a config file.\n", - BSTR_P(name)); - return M_OPT_INVALID; - } - if (flags & M_SETOPT_BACKUP) { - if (co->opt->flags & M_OPT_GLOBAL) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option is global and can't be set per-file.\n", - BSTR_P(name)); - return M_OPT_INVALID; - } - if (set) - ensure_backup(config, co); - } - - if (config->includefunc && bstr_equals0(name, "include")) - return parse_include(config, param, set, flags); - if (config->use_profiles && bstr_equals0(name, "profile")) - return parse_profile(config, co->opt, name, param, set, flags); - if (config->use_profiles && bstr_equals0(name, "show-profile")) - return show_profile(config, param); - if (bstr_equals0(name, "list-options")) - return list_options(config); - - // Option with children are a bit different to parse - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { - char prefix[110]; - assert(strlen(co->name) < 100); - sprintf(prefix, "%s-", co->name); - return parse_subopts(config, co->name, prefix, param, flags); - } - - return m_option_parse(co->opt, name, param, set ? co->data : NULL); -} - -static int parse_subopts(struct m_config *config, char *name, char *prefix, - struct bstr param, int flags) -{ - char **lst = NULL; - // Split the argument into child options - int r = m_option_type_subconfig.parse(NULL, bstr0(""), param, &lst); - if (r < 0) - return r; - // Parse the child options - for (int i = 0; lst && lst[2 * i]; i++) { - // Build the full name - char n[110]; - if (snprintf(n, 110, "%s%s", prefix, lst[2 * i]) > 100) - abort(); - r = m_config_parse_option(config,bstr0(n), bstr0(lst[2 * i + 1]), flags); - if (r < 0) { - if (r > M_OPT_EXIT) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Error parsing suboption %s/%s (%s)\n", - name, lst[2 * i], m_option_strerror(r)); - r = M_OPT_INVALID; - } - break; - } - } - talloc_free(lst); - return r; -} - -int m_config_parse_suboptions(struct m_config *config, char *name, - char *subopts) -{ - if (!subopts || !*subopts) - return 0; - int r = parse_subopts(config, name, "", bstr0(subopts), 0); - if (r < 0 && r > M_OPT_EXIT) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Error parsing suboption %s (%s)\n", - name, m_option_strerror(r)); - r = M_OPT_INVALID; - } - return r; -} - -int m_config_set_option_ext(struct m_config *config, struct bstr name, - struct bstr param, int flags) -{ - int r = m_config_parse_option(config, name, param, flags); - if (r < 0 && r > M_OPT_EXIT) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Error parsing option %.*s (%s)\n", - BSTR_P(name), m_option_strerror(r)); - r = M_OPT_INVALID; - } - return r; -} - -int m_config_set_option(struct m_config *config, struct bstr name, - struct bstr param) -{ - return m_config_set_option_ext(config, name, param, 0); -} - -const struct m_option *m_config_get_option(const struct m_config *config, - struct bstr name) -{ - struct m_config_option *co; - - assert(config != NULL); - - co = m_config_get_co(config, name); - if (co) - return co->opt; - else - return NULL; -} - -int m_config_option_requires_param(struct m_config *config, bstr name) -{ - const struct m_option *opt = m_config_get_option(config, name); - if (opt) { - if (bstr_endswith0(name, "-clr")) - return 0; - return m_option_required_params(opt); - } - return M_OPT_UNKNOWN; -} - -static struct m_config *get_defaults(const struct m_config *config) -{ - return m_config_new(NULL, config->optstruct_size, - config->optstruct_defaults, config->options, - config->suboptinit); -} - -static char *get_option_value_string(const struct m_config *config, - const char *name) -{ - struct m_config_option *co = m_config_get_co(config, bstr0(name)); - if (!co || !co->data) - return NULL; - return m_option_print(co->opt, co->data); -} - -void m_config_print_option_list(const struct m_config *config) -{ - char min[50], max[50]; - struct m_config_option *co; - int count = 0; - - if (!config->opts) - return; - - struct m_config *defaults = get_defaults(config); - - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "Options:\n\n"); - for (co = config->opts; co; co = co->next) { - const struct m_option *opt = co->opt; - if (opt->type->flags & M_OPT_TYPE_HAS_CHILD) - continue; - if (co->is_generated) - continue; - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-30.30s", co->name); - if (opt->type == &m_option_type_choice) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " Choices:"); - struct m_opt_choice_alternatives *alt = opt->priv; - for (int n = 0; alt[n].name; n++) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", alt[n].name); - if (opt->flags & (M_OPT_MIN | M_OPT_MAX)) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " (or an integer)"); - } else { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", co->opt->type->name); - } - if (opt->flags & (M_OPT_MIN | M_OPT_MAX)) { - snprintf(min, sizeof(min), "any"); - snprintf(max, sizeof(max), "any"); - if (opt->flags & M_OPT_MIN) - snprintf(min, sizeof(min), "%.14g", opt->min); - if (opt->flags & M_OPT_MAX) - snprintf(max, sizeof(max), "%.14g", opt->max); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " (%s to %s)", min, max); - } - char *def = get_option_value_string(defaults, co->name); - if (def) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " (default: %s)", def); - talloc_free(def); - } - if (opt->flags & CONF_GLOBAL) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " [global]"); - if (opt->flags & CONF_NOCFG) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " [nocfg]"); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - count++; - } - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d options\n", count); - - talloc_free(defaults); -} - -struct m_profile *m_config_get_profile(const struct m_config *config, bstr name) -{ - for (struct m_profile *p = config->profiles; p; p = p->next) { - if (bstr_equals0(name, p->name)) - return p; - } - return NULL; -} - -struct m_profile *m_config_get_profile0(const struct m_config *config, - char *name) -{ - return m_config_get_profile(config, bstr0(name)); -} - -struct m_profile *m_config_add_profile(struct m_config *config, char *name) -{ - struct m_profile *p = m_config_get_profile0(config, name); - if (p) - return p; - p = talloc_zero(config, struct m_profile); - p->name = talloc_strdup(p, name); - p->next = config->profiles; - config->profiles = p; - return p; -} - -void m_profile_set_desc(struct m_profile *p, char *desc) -{ - talloc_free(p->desc); - p->desc = talloc_strdup(p, desc); -} - -int m_config_set_profile_option(struct m_config *config, struct m_profile *p, - bstr name, bstr val) -{ - int i = m_config_set_option_ext(config, name, val, - M_SETOPT_CHECK_ONLY | - M_SETOPT_FROM_CONFIG_FILE); - if (i < 0) - return i; - p->opts = talloc_realloc(p, p->opts, char *, 2 * (p->num_opts + 2)); - p->opts[p->num_opts * 2] = bstrdup0(p, name); - p->opts[p->num_opts * 2 + 1] = bstrdup0(p, val); - p->num_opts++; - p->opts[p->num_opts * 2] = p->opts[p->num_opts * 2 + 1] = NULL; - return 1; -} - -void m_config_set_profile(struct m_config *config, struct m_profile *p, - int flags) -{ - if (config->profile_depth > MAX_PROFILE_DEPTH) { - mp_tmsg(MSGT_CFGPARSER, MSGL_WARN, - "WARNING: Profile inclusion too deep.\n"); - return; - } - config->profile_depth++; - for (int i = 0; i < p->num_opts; i++) { - m_config_set_option_ext(config, - bstr0(p->opts[2 * i]), - bstr0(p->opts[2 * i + 1]), - flags | M_SETOPT_FROM_CONFIG_FILE); - } - config->profile_depth--; -} - -void *m_config_alloc_struct(void *talloc_parent, - const struct m_sub_options *subopts) -{ - void *substruct = talloc_zero_size(talloc_parent, subopts->size); - if (subopts->defaults) - memcpy(substruct, subopts->defaults, subopts->size); - return substruct; -} diff --git a/core/m_config.h b/core/m_config.h deleted file mode 100644 index c2f88dfe65..0000000000 --- a/core/m_config.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_M_CONFIG_H -#define MPLAYER_M_CONFIG_H - -#include -#include - -#include "core/bstr.h" - -// m_config provides an API to manipulate the config variables in MPlayer. -// It makes use of the Options API to provide a context stack that -// allows saving and later restoring the state of all variables. - -typedef struct m_profile m_profile_t; -struct m_option; -struct m_option_type; -struct m_sub_options; -struct m_obj_desc; - -// Config option -struct m_config_option { - struct m_config_option *next; - bool is_generated : 1; - // Full name (ie option-subopt). - char *name; - // Option description. - const struct m_option *opt; - // Raw value of the option. - void *data; - // If this is a suboption, the option that contains this option. - struct m_config_option *parent; -}; - -// Config object -/** \ingroup Config */ -typedef struct m_config { - // Registered options. - struct m_config_option *opts; // all options, even suboptions - - // List of defined profiles. - struct m_profile *profiles; - // Depth when recursively including profiles. - int profile_depth; - - struct m_opt_backup *backup_opts; - - bool use_profiles; - int (*includefunc)(struct m_config *conf, char *filename, int flags); - - const void *optstruct_defaults; - size_t optstruct_size; - const struct m_option *options; // top-level options - const char *suboptinit; - - void *optstruct; // struct mpopts or other -} m_config_t; - -// Create a new config object. -// talloc_parent: talloc parent context for the m_config allocation -// size: size of the optstruct (where option values are stored) -// defaults: if not NULL, points to a struct of same type as optstruct, which -// contains default values for all options -// options: list of options. Each option defines a member of the optstruct -// and a corresponding option switch or sub-option field. -// suboptinit: if not NULL, initialize the suboption string (used for presets) -// Note that the m_config object will keep pointers to defaults and options. -struct m_config *m_config_new(void *talloc_parent, size_t size, - const void *defaults, - const struct m_option *options, - const char *suboptinit); - -struct m_config *m_config_from_obj_desc(void *talloc_parent, - struct m_obj_desc *desc); - -int m_config_set_obj_params(struct m_config *conf, char **args); - -// Initialize an object (VO/VF/...) in one go, including legacy handling. -// This is pretty specialized, and is just for convenience. -int m_config_initialize_obj(struct m_config *config, struct m_obj_desc *desc, - void **ppriv, char ***pargs); - -// Make sure the option is backed up. If it's already backed up, do nothing. -// All backed up options can be restored with m_config_restore_backups(). -void m_config_backup_opt(struct m_config *config, const char *opt); - -// Call m_config_backup_opt() on all options. -void m_config_backup_all_opts(struct m_config *config); - -// Restore all options backed up with m_config_backup_opt(), and delete the -// backups afterwards. -void m_config_restore_backups(struct m_config *config); - -enum { - M_SETOPT_PRE_PARSE_ONLY = 1, // Silently ignore non-M_OPT_PRE_PARSE opt. - M_SETOPT_CHECK_ONLY = 2, // Don't set, just check name/value - M_SETOPT_FROM_CONFIG_FILE = 4, // Reject M_OPT_NOCFG opt. (print error) - M_SETOPT_BACKUP = 8, // Call m_config_backup_opt() before -}; - -// Set the named option to the given string. -// flags: combination of M_SETOPT_* flags (0 for normal operation) -// Returns >= 0 on success, otherwise see OptionParserReturn. -int m_config_set_option_ext(struct m_config *config, struct bstr name, - struct bstr param, int flags); - -/* Set an option. (Like: m_config_set_option_ext(config, name, param, 0)) - * \param config The config object. - * \param name The option's name. - * \param param The value of the option, can be NULL. - * \return See \ref OptionParserReturn. - */ -int m_config_set_option(struct m_config *config, struct bstr name, - struct bstr param); - -static inline int m_config_set_option0(struct m_config *config, - const char *name, const char *param) -{ - return m_config_set_option(config, bstr0(name), bstr0(param)); -} - -int m_config_parse_suboptions(struct m_config *config, char *name, - char *subopts); - - -/* Get the option matching the given name. - * \param config The config object. - * \param name The option's name. - */ -const struct m_option *m_config_get_option(const struct m_config *config, - struct bstr name); - -struct m_config_option *m_config_get_co(const struct m_config *config, - struct bstr name); - -// Return the n-th option by position. n==0 is the first option. If there are -// less than (n + 1) options, return NULL. -const char *m_config_get_positional_option(const struct m_config *config, int n); - -// Return a hint to the option parser whether a parameter is/may be required. -// The option may still accept empty/non-empty parameters independent from -// this, and this function is useful only for handling ambiguous options like -// flags (e.g. "--a" is ok, "--a=yes" is also ok). -// Returns: error code (<0), or number of expected params (0, 1) -int m_config_option_requires_param(struct m_config *config, bstr name); - -/* Print a list of all registered options. - * \param config The config object. - */ -void m_config_print_option_list(const struct m_config *config); - - -/* Find the profile with the given name. - * \param config The config object. - * \param arg The profile's name. - * \return The profile object or NULL. - */ -struct m_profile *m_config_get_profile0(const struct m_config *config, - char *name); -struct m_profile *m_config_get_profile(const struct m_config *config, bstr name); - -/* Get the profile with the given name, creating it if necessary. - * \param config The config object. - * \param arg The profile's name. - * \return The profile object. - */ -struct m_profile *m_config_add_profile(struct m_config *config, char *name); - -/* Set the description of a profile. - * Used by the config file parser when defining a profile. - * - * \param p The profile object. - * \param arg The profile's name. - */ -void m_profile_set_desc(struct m_profile *p, char *desc); - -/* Add an option to a profile. - * Used by the config file parser when defining a profile. - * - * \param config The config object. - * \param p The profile object. - * \param name The option's name. - * \param val The option's value. - */ -int m_config_set_profile_option(struct m_config *config, struct m_profile *p, - bstr name, bstr val); - -/* Enables profile usage - * Used by the config file parser when loading a profile. - * - * \param config The config object. - * \param p The profile object. - * \param flags M_SETOPT_* bits - */ -void m_config_set_profile(struct m_config *config, struct m_profile *p, - int flags); - -void *m_config_alloc_struct(void *talloc_parent, - const struct m_sub_options *subopts); - -#endif /* MPLAYER_M_CONFIG_H */ diff --git a/core/m_option.c b/core/m_option.c deleted file mode 100644 index 41916befeb..0000000000 --- a/core/m_option.c +++ /dev/null @@ -1,2407 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/// \file -/// \ingroup Options - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "talloc.h" -#include "core/mp_common.h" -#include "core/m_option.h" -#include "core/m_config.h" -#include "core/mp_msg.h" - -char *m_option_strerror(int code) -{ - switch (code) { - case M_OPT_UNKNOWN: - return mp_gtext("option not found"); - case M_OPT_MISSING_PARAM: - return mp_gtext("option requires parameter"); - case M_OPT_INVALID: - return mp_gtext("option parameter could not be parsed"); - case M_OPT_OUT_OF_RANGE: - return mp_gtext("parameter is outside values allowed for option"); - case M_OPT_DISALLOW_PARAM: - return mp_gtext("option doesn't take a parameter"); - case M_OPT_PARSER_ERR: - default: - return mp_gtext("parser error"); - } -} - -int m_option_required_params(const m_option_t *opt) -{ - if (((opt->flags & M_OPT_OPTIONAL_PARAM) || - (opt->type->flags & M_OPT_TYPE_OPTIONAL_PARAM))) - return 0; - return 1; -} - -static const struct m_option *m_option_list_findb(const struct m_option *list, - struct bstr name) -{ - for (int i = 0; list[i].name; i++) { - struct bstr lname = bstr0(list[i].name); - if ((list[i].type->flags & M_OPT_TYPE_ALLOW_WILDCARD) - && bstr_endswith0(lname, "*")) { - lname.len--; - if (bstrcmp(bstr_splice(name, 0, lname.len), lname) == 0) - return &list[i]; - } else if (bstrcmp(lname, name) == 0) - return &list[i]; - } - return NULL; -} - -const m_option_t *m_option_list_find(const m_option_t *list, const char *name) -{ - return m_option_list_findb(list, bstr0(name)); -} - -// Default function that just does a memcpy - -static void copy_opt(const m_option_t *opt, void *dst, const void *src) -{ - if (dst && src) - memcpy(dst, src, opt->type->size); -} - -// Flag - -#define VAL(x) (*(int *)(x)) - -static int clamp_flag(const m_option_t *opt, void *val) -{ - if (VAL(val) == opt->min || VAL(val) == opt->max) - return 0; - VAL(val) = opt->min; - return M_OPT_OUT_OF_RANGE; -} - -static int parse_flag(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len) { - if (!bstrcmp0(param, "yes")) { - if (dst) - VAL(dst) = opt->max; - return 1; - } - if (!bstrcmp0(param, "no")) { - if (dst) - VAL(dst) = opt->min; - return 1; - } - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid parameter for %.*s flag: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } else { - if (dst) - VAL(dst) = opt->max; - return 0; - } -} - -static char *print_flag(const m_option_t *opt, const void *val) -{ - if (VAL(val) == opt->min) - return talloc_strdup(NULL, "no"); - else - return talloc_strdup(NULL, "yes"); -} - -static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) -{ - if (fabs(add) < 0.5) - return; - bool state = VAL(val) != opt->min; - state = wrap ? !state : add > 0; - VAL(val) = state ? opt->max : opt->min; -} - -const m_option_type_t m_option_type_flag = { - // need yes or no in config files - .name = "Flag", - .size = sizeof(int), - .flags = M_OPT_TYPE_OPTIONAL_PARAM, - .parse = parse_flag, - .print = print_flag, - .copy = copy_opt, - .add = add_flag, - .clamp = clamp_flag, -}; - -// Single-value, write-only flag - -static int parse_store(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0 || bstrcmp0(param, "yes") == 0) { - if (dst) - VAL(dst) = opt->max; - return 0; - } else { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid parameter for %.*s flag: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_DISALLOW_PARAM; - } -} - -const m_option_type_t m_option_type_store = { - // can only be activated - .name = "Flag", - .size = sizeof(int), - .flags = M_OPT_TYPE_OPTIONAL_PARAM, - .parse = parse_store, -}; - -// Same for float types - -#undef VAL -#define VAL(x) (*(float *)(x)) - -static int parse_store_float(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0 || bstrcmp0(param, "yes") == 0) { - if (dst) - VAL(dst) = opt->max; - return 0; - } else { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid parameter for %.*s flag: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_DISALLOW_PARAM; - } -} - -const m_option_type_t m_option_type_float_store = { - // can only be activated - .name = "Flag", - .size = sizeof(float), - .flags = M_OPT_TYPE_OPTIONAL_PARAM, - .parse = parse_store_float, -}; - -// Integer - -#undef VAL - -static int clamp_longlong(const m_option_t *opt, void *val) -{ - long long v = *(long long *)val; - int r = 0; - if ((opt->flags & M_OPT_MAX) && (v > opt->max)) { - v = opt->max; - r = M_OPT_OUT_OF_RANGE; - } - if ((opt->flags & M_OPT_MIN) && (v < opt->min)) { - v = opt->min; - r = M_OPT_OUT_OF_RANGE; - } - *(long long *)val = v; - return r; -} - -static int parse_longlong(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr rest; - long long tmp_int = bstrtoll(param, &rest, 10); - if (rest.len) - tmp_int = bstrtoll(param, &rest, 0); - if (rest.len) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be an integer: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - - if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be >= %d: %.*s\n", - BSTR_P(name), (int) opt->min, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be <= %d: %.*s\n", - BSTR_P(name), (int) opt->max, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if (dst) - *(long long *)dst = tmp_int; - - return 1; -} - -static int clamp_int(const m_option_t *opt, void *val) -{ - long long tmp = *(int *)val; - int r = clamp_longlong(opt, &tmp); - *(int *)val = tmp; - return r; -} - -static int clamp_int64(const m_option_t *opt, void *val) -{ - long long tmp = *(int64_t *)val; - int r = clamp_longlong(opt, &tmp); - *(int64_t *)val = tmp; - return r; -} - -static int parse_int(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - long long tmp; - int r = parse_longlong(opt, name, param, &tmp); - if (r >= 0 && dst) - *(int *)dst = tmp; - return r; -} - -static int parse_int64(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - long long tmp; - int r = parse_longlong(opt, name, param, &tmp); - if (r >= 0 && dst) - *(int64_t *)dst = tmp; - return r; -} - -static char *print_int(const m_option_t *opt, const void *val) -{ - if (opt->type->size == sizeof(int64_t)) - return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val); - return talloc_asprintf(NULL, "%d", *(const int *)val); -} - -static void add_int64(const m_option_t *opt, void *val, double add, bool wrap) -{ - int64_t v = *(int64_t *)val; - - v = v + add; - - bool is64 = opt->type->size == sizeof(int64_t); - int64_t nmin = is64 ? INT64_MIN : INT_MIN; - int64_t nmax = is64 ? INT64_MAX : INT_MAX; - - int64_t min = (opt->flags & M_OPT_MIN) ? opt->min : nmin; - int64_t max = (opt->flags & M_OPT_MAX) ? opt->max : nmax; - - if (v < min) - v = wrap ? max : min; - if (v > max) - v = wrap ? min : max; - - *(int64_t *)val = v; -} - -static void add_int(const m_option_t *opt, void *val, double add, bool wrap) -{ - int64_t tmp = *(int *)val; - add_int64(opt, &tmp, add, wrap); - *(int *)val = tmp; -} - -const m_option_type_t m_option_type_int = { - .name = "Integer", - .size = sizeof(int), - .parse = parse_int, - .print = print_int, - .copy = copy_opt, - .add = add_int, - .clamp = clamp_int, -}; - -const m_option_type_t m_option_type_int64 = { - .name = "Integer64", - .size = sizeof(int64_t), - .parse = parse_int64, - .print = print_int, - .copy = copy_opt, - .add = add_int64, - .clamp = clamp_int64, -}; - -static int parse_intpair(const struct m_option *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr s = param; - int end = -1; - int start = bstrtoll(s, &s, 10); - if (s.len == param.len) - goto bad; - if (s.len > 0) { - if (!bstr_startswith0(s, "-")) - goto bad; - s = bstr_cut(s, 1); - } - if (s.len > 0) - end = bstrtoll(s, &s, 10); - if (s.len > 0) - goto bad; - - if (dst) { - int *p = dst; - p[0] = start; - p[1] = end; - } - - return 1; - -bad: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid integer range " - "specification for option %.*s: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; -} - -const struct m_option_type m_option_type_intpair = { - .name = "Int[-Int]", - .size = sizeof(int[2]), - .parse = parse_intpair, - .copy = copy_opt, -}; - -static int clamp_choice(const m_option_t *opt, void *val) -{ - int v = *(int *)val; - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - if (v >= opt->min && v <= opt->max) - return 0; - } - ; - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { - if (alt->value == v) - return 0; - } - return M_OPT_INVALID; -} - -static int parse_choice(const struct m_option *opt, struct bstr name, - struct bstr param, void *dst) -{ - struct m_opt_choice_alternatives *alt = opt->priv; - for ( ; alt->name; alt++) - if (!bstrcmp0(param, alt->name)) - break; - if (!alt->name) { - if (param.len == 0) - return M_OPT_MISSING_PARAM; - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - long long val; - if (parse_longlong(opt, name, param, &val) == 1) { - if (dst) - *(int *)dst = val; - return 1; - } - } - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid value for option %.*s: %.*s\n", - BSTR_P(name), BSTR_P(param)); - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Valid values are:"); - for (alt = opt->priv; alt->name; alt++) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", alt->name); - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %g-%g", opt->min, opt->max); - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n"); - return M_OPT_INVALID; - } - if (dst) - *(int *)dst = alt->value; - - return 1; -} - -static char *print_choice(const m_option_t *opt, const void *val) -{ - int v = *(int *)val; - struct m_opt_choice_alternatives *alt; - for (alt = opt->priv; alt->name; alt++) - if (alt->value == v) - return talloc_strdup(NULL, alt->name); - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - if (v >= opt->min && v <= opt->max) - return talloc_asprintf(NULL, "%d", v); - } - abort(); -} - -static void choice_get_min_max(const struct m_option *opt, int *min, int *max) -{ - assert(opt->type == &m_option_type_choice); - *min = INT_MAX; - *max = INT_MIN; - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { - *min = FFMIN(*min, alt->value); - *max = FFMAX(*max, alt->value); - } - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - *min = FFMIN(*min, opt->min); - *max = FFMAX(*max, opt->max); - } -} - -static void check_choice(int dir, int val, bool *found, int *best, int choice) -{ - if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) || - (dir == +1 && (!(*found) || choice < (*best)) && choice > val)) - { - *found = true; - *best = choice; - } -} - -static void add_choice(const m_option_t *opt, void *val, double add, bool wrap) -{ - assert(opt->type == &m_option_type_choice); - int dir = add > 0 ? +1 : -1; - bool found = false; - int ival = *(int *)val; - int best = 0; // init. value unused - - if (fabs(add) < 0.5) - return; - - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { - int newval = ival + add; - if (ival >= opt->min && ival <= opt->max && - newval >= opt->min && newval <= opt->max) - { - found = true; - best = newval; - } else { - check_choice(dir, ival, &found, &best, opt->min); - check_choice(dir, ival, &found, &best, opt->max); - } - } - - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) - check_choice(dir, ival, &found, &best, alt->value); - - if (!found) { - int min, max; - choice_get_min_max(opt, &min, &max); - best = (dir == -1) ^ wrap ? min : max; - } - - *(int *)val = best; -} - -const struct m_option_type m_option_type_choice = { - .name = "String", // same as arbitrary strings in option list for now - .size = sizeof(int), - .parse = parse_choice, - .print = print_choice, - .copy = copy_opt, - .add = add_choice, - .clamp = clamp_choice, -}; - -// Float - -#undef VAL -#define VAL(x) (*(double *)(x)) - -static int clamp_double(const m_option_t *opt, void *val) -{ - double v = VAL(val); - int r = 0; - if ((opt->flags & M_OPT_MAX) && (v > opt->max)) { - v = opt->max; - r = M_OPT_OUT_OF_RANGE; - } - if ((opt->flags & M_OPT_MIN) && (v < opt->min)) { - v = opt->min; - r = M_OPT_OUT_OF_RANGE; - } - if (!isfinite(v)) { - v = opt->min; - r = M_OPT_OUT_OF_RANGE; - } - VAL(val) = v; - return r; -} - -static int parse_double(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr rest; - double tmp_float = bstrtod(param, &rest); - - if (bstr_eatstart0(&rest, ":") || bstr_eatstart0(&rest, "/")) - tmp_float /= bstrtod(rest, &rest); - - if (rest.len) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be a floating point number or a " - "ratio (numerator[:/]denominator): %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - - if (opt->flags & M_OPT_MIN) - if (tmp_float < opt->min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be >= %f: %.*s\n", - BSTR_P(name), opt->min, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if (opt->flags & M_OPT_MAX) - if (tmp_float > opt->max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be <= %f: %.*s\n", - BSTR_P(name), opt->max, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if (!isfinite(tmp_float)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %.*s option must be a finite number: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if (dst) - VAL(dst) = tmp_float; - return 1; -} - -static char *print_double(const m_option_t *opt, const void *val) -{ - return talloc_asprintf(NULL, "%f", VAL(val)); -} - -static char *print_double_f3(const m_option_t *opt, const void *val) -{ - return talloc_asprintf(NULL, "%.3f", VAL(val)); -} - -static void add_double(const m_option_t *opt, void *val, double add, bool wrap) -{ - double v = VAL(val); - - v = v + add; - - double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY; - double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY; - - if (v < min) - v = wrap ? max : min; - if (v > max) - v = wrap ? min : max; - - VAL(val) = v; -} - -const m_option_type_t m_option_type_double = { - // double precision float or ratio (numerator[:/]denominator) - .name = "Double", - .size = sizeof(double), - .parse = parse_double, - .print = print_double, - .pretty_print = print_double_f3, - .copy = copy_opt, - .clamp = clamp_double, -}; - -#undef VAL -#define VAL(x) (*(float *)(x)) - -static int clamp_float(const m_option_t *opt, void *val) -{ - double tmp = VAL(val); - int r = clamp_double(opt, &tmp); - VAL(val) = tmp; - return r; -} - -static int parse_float(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - double tmp; - int r = parse_double(opt, name, param, &tmp); - if (r == 1 && dst) - VAL(dst) = tmp; - return r; -} - -static char *print_float(const m_option_t *opt, const void *val) -{ - return talloc_asprintf(NULL, "%f", VAL(val)); -} - -static char *print_float_f3(const m_option_t *opt, const void *val) -{ - return talloc_asprintf(NULL, "%.3f", VAL(val)); -} - -static void add_float(const m_option_t *opt, void *val, double add, bool wrap) -{ - double tmp = VAL(val); - add_double(opt, &tmp, add, wrap); - VAL(val) = tmp; -} - -const m_option_type_t m_option_type_float = { - // floating point number or ratio (numerator[:/]denominator) - .name = "Float", - .size = sizeof(float), - .parse = parse_float, - .print = print_float, - .pretty_print = print_float_f3, - .copy = copy_opt, - .add = add_float, - .clamp = clamp_float, -}; - -///////////// String - -#undef VAL -#define VAL(x) (*(char **)(x)) - -static char *unescape_string(void *talloc_ctx, bstr str) -{ - char *res = talloc_strdup(talloc_ctx, ""); - while (str.len) { - bstr rest; - bool esc = bstr_split_tok(str, "\\", &str, &rest); - res = talloc_strndup_append_buffer(res, str.start, str.len); - if (esc) { - if (!mp_parse_escape(&rest, &res)) { - talloc_free(res); - return NULL; - } - } - str = rest; - } - return res; -} - -static char *escape_string(char *str0) -{ - char *res = talloc_strdup(NULL, ""); - bstr str = bstr0(str0); - while (str.len) { - bstr rest; - bool esc = bstr_split_tok(str, "\\", &str, &rest); - res = talloc_strndup_append_buffer(res, str.start, str.len); - if (esc) - res = talloc_strdup_append_buffer(res, "\\\\"); - str = rest; - } - return res; -} - -static int clamp_str(const m_option_t *opt, void *val) -{ - char *v = VAL(val); - int len = v ? strlen(v) : 0; - if ((opt->flags & M_OPT_MIN) && (len < opt->min)) - return M_OPT_OUT_OF_RANGE; - if ((opt->flags & M_OPT_MAX) && (len > opt->max)) - return M_OPT_OUT_OF_RANGE; - return 0; -} - -static int parse_str(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - int r = 1; - void *tmp = talloc_new(NULL); - - if (param.start == NULL) { - r = M_OPT_MISSING_PARAM; - goto exit; - } - - m_opt_string_validate_fn validate = opt->priv; - if (validate) { - r = validate(opt, name, param); - if (r < 0) - goto exit; - } - - if (opt->flags & M_OPT_PARSE_ESCAPES) { - char *res = unescape_string(tmp, param); - if (!res) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Parameter has broken escapes: %.*s\n", BSTR_P(param)); - r = M_OPT_INVALID; - goto exit; - } - param = bstr0(res); - } - - if ((opt->flags & M_OPT_MIN) && (param.len < opt->min)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Parameter must be >= %d chars: %.*s\n", - (int) opt->min, BSTR_P(param)); - r = M_OPT_OUT_OF_RANGE; - goto exit; - } - - if ((opt->flags & M_OPT_MAX) && (param.len > opt->max)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Parameter must be <= %d chars: %.*s\n", - (int) opt->max, BSTR_P(param)); - r = M_OPT_OUT_OF_RANGE; - goto exit; - } - - if (dst) { - talloc_free(VAL(dst)); - VAL(dst) = bstrdup0(NULL, param); - } - -exit: - talloc_free(tmp); - return r; -} - -static char *print_str(const m_option_t *opt, const void *val) -{ - bool need_escape = opt->flags & M_OPT_PARSE_ESCAPES; - char *s = val ? VAL(val) : NULL; - return s ? (need_escape ? escape_string(s) : talloc_strdup(NULL, s)) : NULL; -} - -static void copy_str(const m_option_t *opt, void *dst, const void *src) -{ - if (dst && src) { - talloc_free(VAL(dst)); - VAL(dst) = talloc_strdup(NULL, VAL(src)); - } -} - -static void free_str(void *src) -{ - if (src && VAL(src)) { - talloc_free(VAL(src)); - VAL(src) = NULL; - } -} - -const m_option_type_t m_option_type_string = { - .name = "String", - .size = sizeof(char *), - .flags = M_OPT_TYPE_DYNAMIC, - .parse = parse_str, - .print = print_str, - .copy = copy_str, - .free = free_str, - .clamp = clamp_str, -}; - -//////////// String list - -#undef VAL -#define VAL(x) (*(char ***)(x)) - -#define OP_NONE 0 -#define OP_ADD 1 -#define OP_PRE 2 -#define OP_DEL 3 -#define OP_CLR 4 -#define OP_TOGGLE 5 - -static void free_str_list(void *dst) -{ - char **d; - int i; - - if (!dst || !VAL(dst)) - return; - d = VAL(dst); - - for (i = 0; d[i] != NULL; i++) - talloc_free(d[i]); - talloc_free(d); - VAL(dst) = NULL; -} - -static int str_list_add(char **add, int n, void *dst, int pre) -{ - if (!dst) - return M_OPT_PARSER_ERR; - char **lst = VAL(dst); - - int ln; - for (ln = 0; lst && lst[ln]; ln++) - /**/; - - lst = talloc_realloc(NULL, lst, char *, n + ln + 1); - - if (pre) { - memmove(&lst[n], lst, ln * sizeof(char *)); - memcpy(lst, add, n * sizeof(char *)); - } else - memcpy(&lst[ln], add, n * sizeof(char *)); - // (re-)add NULL-termination - lst[ln + n] = NULL; - - talloc_free(add); - - VAL(dst) = lst; - - return 1; -} - -static int str_list_del(char **del, int n, void *dst) -{ - char **lst, *ep; - int i, ln, s; - long idx; - - if (!dst) - return M_OPT_PARSER_ERR; - lst = VAL(dst); - - for (ln = 0; lst && lst[ln]; ln++) - /**/; - s = ln; - - for (i = 0; del[i] != NULL; i++) { - idx = strtol(del[i], &ep, 0); - if (*ep) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n", del[i]); - talloc_free(del[i]); - continue; - } - talloc_free(del[i]); - if (idx < 0 || idx >= ln) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Index %ld is out of range.\n", idx); - continue; - } else if (!lst[idx]) - continue; - talloc_free(lst[idx]); - lst[idx] = NULL; - s--; - } - talloc_free(del); - - if (s == 0) { - talloc_free(lst); - VAL(dst) = NULL; - return 1; - } - - // Don't bother shrinking the list allocation - for (i = 0, n = 0; i < ln; i++) { - if (!lst[i]) - continue; - lst[n] = lst[i]; - n++; - } - lst[s] = NULL; - - return 1; -} - -static struct bstr get_nextsep(struct bstr *ptr, char sep, bool modify) -{ - struct bstr str = *ptr; - struct bstr orig = str; - for (;;) { - int idx = bstrchr(str, sep); - if (idx > 0 && str.start[idx - 1] == '\\') { - if (modify) { - memmove(str.start + idx - 1, str.start + idx, str.len - idx); - str.len--; - str = bstr_cut(str, idx); - } else - str = bstr_cut(str, idx + 1); - } else { - str = bstr_cut(str, idx < 0 ? str.len : idx); - break; - } - } - *ptr = str; - return bstr_splice(orig, 0, str.start - orig.start); -} - -static int parse_str_list(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - char **res; - int op = OP_NONE; - int len = strlen(opt->name); - if (opt->name[len - 1] == '*' && (name.len > len - 1)) { - struct bstr suffix = bstr_cut(name, len - 1); - if (bstrcmp0(suffix, "-add") == 0) - op = OP_ADD; - else if (bstrcmp0(suffix, "-pre") == 0) - op = OP_PRE; - else if (bstrcmp0(suffix, "-del") == 0) - op = OP_DEL; - else if (bstrcmp0(suffix, "-clr") == 0) - op = OP_CLR; - else - return M_OPT_UNKNOWN; - } - - // Clear the list ?? - if (op == OP_CLR) { - if (dst) - free_str_list(dst); - return 0; - } - - // All other ops need a param - if (param.len == 0 && op != OP_NONE) - return M_OPT_MISSING_PARAM; - - // custom type for "profile" calls this but uses ->priv for something else - char separator = opt->type == &m_option_type_string_list && opt->priv ? - *(char *)opt->priv : OPTION_LIST_SEPARATOR; - int n = 0; - struct bstr str = param; - while (str.len) { - get_nextsep(&str, separator, 0); - str = bstr_cut(str, 1); - n++; - } - if (n == 0 && op != OP_NONE) - return M_OPT_INVALID; - if (((opt->flags & M_OPT_MIN) && (n < opt->min)) || - ((opt->flags & M_OPT_MAX) && (n > opt->max))) - return M_OPT_OUT_OF_RANGE; - - if (!dst) - return 1; - - res = talloc_array(NULL, char *, n + 2); - str = bstrdup(NULL, param); - char *ptr = str.start; - n = 0; - - while (1) { - struct bstr el = get_nextsep(&str, separator, 1); - res[n] = bstrdup0(NULL, el); - n++; - if (!str.len) - break; - str = bstr_cut(str, 1); - } - res[n] = NULL; - talloc_free(ptr); - - switch (op) { - case OP_ADD: - return str_list_add(res, n, dst, 0); - case OP_PRE: - return str_list_add(res, n, dst, 1); - case OP_DEL: - return str_list_del(res, n, dst); - } - - if (VAL(dst)) - free_str_list(dst); - VAL(dst) = res; - - if (!res[0]) - free_str_list(dst); - - return 1; -} - -static void copy_str_list(const m_option_t *opt, void *dst, const void *src) -{ - int n; - char **d, **s; - - if (!(dst && src)) - return; - s = VAL(src); - - if (VAL(dst)) - free_str_list(dst); - - if (!s) { - VAL(dst) = NULL; - return; - } - - for (n = 0; s[n] != NULL; n++) - /* NOTHING */; - d = talloc_array(NULL, char *, n + 1); - for (; n >= 0; n--) - d[n] = talloc_strdup(NULL, s[n]); - - VAL(dst) = d; -} - -static char *print_str_list(const m_option_t *opt, const void *src) -{ - char **lst = NULL; - char *ret = NULL; - - if (!(src && VAL(src))) - return NULL; - lst = VAL(src); - - for (int i = 0; lst[i]; i++) { - if (ret) - ret = talloc_strdup_append_buffer(ret, ","); - ret = talloc_strdup_append_buffer(ret, lst[i]); - } - return ret; -} - -const m_option_type_t m_option_type_string_list = { - /* A list of strings separated by ','. - * Option with a name ending in '*' permits using the following suffixes: - * -add: Add the given parameters at the end of the list. - * -pre: Add the given parameters at the beginning of the list. - * -del: Remove the entry at the given indices. - * -clr: Clear the list. - * e.g: -vf-add flip,mirror -vf-del 2,5 - */ - .name = "String list", - .size = sizeof(char **), - .flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, - .parse = parse_str_list, - .print = print_str_list, - .copy = copy_str_list, - .free = free_str_list, -}; - - -/////////////////// Print - -static int parse_print(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (opt->type == CONF_TYPE_PRINT) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", mp_gtext(opt->p)); - } else { - char *name0 = bstrdup0(NULL, name); - char *param0 = bstrdup0(NULL, param); - int r = ((m_opt_func_full_t) opt->p)(opt, name0, param0); - talloc_free(name0); - talloc_free(param0); - return r; - } - - if (opt->priv == NULL) - return M_OPT_EXIT; - return 0; -} - -const m_option_type_t m_option_type_print = { - .name = "Print", - .flags = M_OPT_TYPE_OPTIONAL_PARAM, - .parse = parse_print, -}; - -const m_option_type_t m_option_type_print_func_param = { - .name = "Print", - .flags = M_OPT_TYPE_ALLOW_WILDCARD, - .parse = parse_print, -}; - -const m_option_type_t m_option_type_print_func = { - .name = "Print", - .flags = M_OPT_TYPE_ALLOW_WILDCARD | M_OPT_TYPE_OPTIONAL_PARAM, - .parse = parse_print, -}; - - -/////////////////////// Subconfig -#undef VAL -#define VAL(x) (*(char ***)(x)) - -// Read s sub-option name, or a positional sub-opt value. -// Return 0 on succes, M_OPT_ error code otherwise. -// optname is for error reporting. -static int read_subparam(bstr optname, bstr *str, bstr *out_subparam) -{ - bstr p = *str; - bstr subparam = {0}; - - if (bstr_eatstart0(&p, "\"")) { - int optlen = bstrcspn(p, "\""); - subparam = bstr_splice(p, 0, optlen); - p = bstr_cut(p, optlen); - if (!bstr_startswith0(p, "\"")) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Terminating '\"' missing for '%.*s'\n", - BSTR_P(optname)); - return M_OPT_INVALID; - } - p = bstr_cut(p, 1); - } else if (bstr_eatstart0(&p, "[")) { - if (!bstr_split_tok(p, "]", &subparam, &p)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Terminating ']' missing for '%.*s'\n", - BSTR_P(optname)); - return M_OPT_INVALID; - } - } else if (bstr_eatstart0(&p, "%")) { - int optlen = bstrtoll(p, &p, 0); - if (!bstr_startswith0(p, "%") || (optlen > p.len - 1)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid length %d for '%.*s'\n", - optlen, BSTR_P(optname)); - return M_OPT_INVALID; - } - subparam = bstr_splice(p, 1, optlen + 1); - p = bstr_cut(p, optlen + 1); - } else { - // Skip until the next character that could possibly be a meta - // character in option parsing. - int optlen = bstrcspn(p, ":=,\\%\"'[]"); - subparam = bstr_splice(p, 0, optlen); - p = bstr_cut(p, optlen); - } - - *str = p; - *out_subparam = subparam; - return 0; -} - -// Return 0 on success, otherwise error code -// On success, set *out_name and *out_val, and advance *str -// out_val.start is NULL if there was no parameter. -// optname is for error reporting. -static int split_subconf(bstr optname, bstr *str, bstr *out_name, bstr *out_val) -{ - bstr p = *str; - bstr subparam = {0}; - bstr subopt; - int r = read_subparam(optname, &p, &subopt); - if (r < 0) - return r; - if (bstr_eatstart0(&p, "=")) { - r = read_subparam(subopt, &p, &subparam); - if (r < 0) - return r; - } - *str = p; - *out_name = subopt; - *out_val = subparam; - return 0; -} - -static int parse_subconf(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - int nr = 0; - char **lst = NULL; - - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr p = param; - - while (p.len) { - bstr subopt, subparam; - int r = split_subconf(name, &p, &subopt, &subparam); - if (r < 0) - return r; - if (bstr_startswith0(p, ":")) - p = bstr_cut(p, 1); - else if (p.len > 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Incorrect termination for '%.*s'\n", BSTR_P(subopt)); - return M_OPT_INVALID; - } - - if (dst) { - lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2)); - lst[2 * nr] = bstrto0(lst, subopt); - lst[2 * nr + 1] = bstrto0(lst, subparam); - memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *)); - nr++; - } - } - - if (dst) - VAL(dst) = lst; - - return 1; -} - -const m_option_type_t m_option_type_subconfig = { - // The syntax is -option opt1=foo:flag:opt2=blah - .name = "Subconfig", - .flags = M_OPT_TYPE_HAS_CHILD, - .parse = parse_subconf, -}; - -const m_option_type_t m_option_type_subconfig_struct = { - .name = "Subconfig", - .flags = M_OPT_TYPE_HAS_CHILD | M_OPT_TYPE_USE_SUBSTRUCT, - .parse = parse_subconf, -}; - -static int parse_color(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - bstr val = param; - struct m_color color = {0}; - - if (bstr_eatstart0(&val, "#")) { - // #[AA]RRGGBB - if (val.len != 6 && val.len != 8) - goto error; - bool has_alpha = val.len == 8; - uint32_t c = bstrtoll(val, &val, 16); - if (val.len) - goto error; - color = (struct m_color) { - (c >> 16) & 0xFF, - (c >> 8) & 0xFF, - c & 0xFF, - has_alpha ? (c >> 24) & 0xFF : 0xFF, - }; - } else { - goto error; - } - - if (dst) - *((struct m_color *)dst) = color; - - return 1; - -error: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: invalid color: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Valid colors must be in the form #RRRGGBB or #AARRGGBB (in hex)\n"); - return M_OPT_INVALID; -} - -const m_option_type_t m_option_type_color = { - .name = "Color", - .size = sizeof(struct m_color), - .parse = parse_color, -}; - - -// Parse a >=0 number starting at s. Set s to the string following the number. -// If the number ends with '%', eat that and set *out_per to true, but only -// if the number is between 0-100; if not, don't eat anything, even the number. -static bool eat_num_per(bstr *s, int *out_num, bool *out_per) -{ - bstr rest; - long long v = bstrtoll(*s, &rest, 10); - if (s->len == rest.len || v < INT_MIN || v > INT_MAX) - return false; - *out_num = v; - *out_per = false; - *s = rest; - if (bstr_eatstart0(&rest, "%") && v >= 0 && v <= 100) { - *out_per = true; - *s = rest; - } - return true; -} - -static bool parse_geometry_str(struct m_geometry *gm, bstr s) -{ - *gm = (struct m_geometry) { .x = INT_MIN, .y = INT_MIN }; - if (s.len == 0) - return true; - // Approximate grammar: - // [W[xH]][{+-}X{+-}Y] | [X:Y] - // (meaning: [optional] {one character of} one|alternative) - // Every number can be followed by '%' - int num; - bool per; - -#define READ_NUM(F, F_PER) do { \ - if (!eat_num_per(&s, &num, &per)) \ - goto error; \ - gm->F = num; \ - gm->F_PER = per; \ -} while(0) - -#define READ_SIGN(F) do { \ - if (bstr_eatstart0(&s, "+")) { \ - gm->F = false; \ - } else if (bstr_eatstart0(&s, "-")) {\ - gm->F = true; \ - } else goto error; \ -} while(0) - - if (bstrchr(s, ':') < 0) { - gm->wh_valid = true; - if (!bstr_startswith0(s, "+") && !bstr_startswith0(s, "-")) { - READ_NUM(w, w_per); - if (bstr_eatstart0(&s, "x")) - READ_NUM(h, h_per); - } - if (s.len > 0) { - gm->xy_valid = true; - READ_SIGN(x_sign); - READ_NUM(x, x_per); - READ_SIGN(y_sign); - READ_NUM(y, y_per); - } - } else { - gm->xy_valid = true; - READ_NUM(x, x_per); - if (!bstr_eatstart0(&s, ":")) - goto error; - READ_NUM(y, y_per); - } - - return s.len == 0; - -error: - return false; -} - -#undef READ_NUM -#undef READ_SIGN - -// xpos,ypos: position of the left upper corner -// widw,widh: width and height of the window -// scrw,scrh: width and height of the current screen -// The input parameters should be set to a centered window (default fallbacks). -void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh, - int scrw, int scrh, struct m_geometry *gm) -{ - if (gm->wh_valid) { - int prew = *widw, preh = *widh; - if (gm->w > 0) - *widw = gm->w_per ? scrw * (gm->w / 100.0) : gm->w; - if (gm->h > 0) - *widh = gm->h_per ? scrh * (gm->h / 100.0) : gm->h; - // keep aspect if the other value is not set - double asp = (double)prew / preh; - if (gm->w > 0 && !(gm->h > 0)) { - *widh = *widw / asp; - } else if (!(gm->w > 0) && gm->h > 0) { - *widw = *widh * asp; - } - } - - if (gm->xy_valid) { - if (gm->x != INT_MIN) { - *xpos = gm->x; - if (gm->x_per) - *xpos = (scrw - *widw) * (*xpos / 100.0); - if (gm->x_sign) - *xpos = scrw - *widw - *xpos; - } - if (gm->y != INT_MIN) { - *ypos = gm->y; - if (gm->y_per) - *ypos = (scrh - *widh) * (*ypos / 100.0); - if (gm->y_sign) - *ypos = scrh - *widh - *ypos; - } - } -} - -static int parse_geometry(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - struct m_geometry gm; - if (!parse_geometry_str(&gm, param)) - goto error; - - if (dst) - *((struct m_geometry *)dst) = gm; - - return 1; - -error: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: invalid geometry: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Valid format: [W[%%][xH[%%]]][{+-}X[%%]{+-}Y[%%]] | [X[%%]:Y[%%]]\n"); - return M_OPT_INVALID; -} - -const m_option_type_t m_option_type_geometry = { - .name = "Window geometry", - .size = sizeof(struct m_geometry), - .parse = parse_geometry, -}; - -static int parse_size_box(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - struct m_geometry gm; - if (!parse_geometry_str(&gm, param)) - goto error; - - if (gm.xy_valid) - goto error; - - if (dst) - *((struct m_geometry *)dst) = gm; - - return 1; - -error: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: invalid size: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Valid format: W[%%][xH[%%]] or empty string\n"); - return M_OPT_INVALID; -} - -const m_option_type_t m_option_type_size_box = { - .name = "Window size", - .size = sizeof(struct m_geometry), - .parse = parse_size_box, -}; - - -#include "video/img_format.h" - -static int parse_imgfmt(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - if (!bstrcmp0(param, "help")) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:"); - for (int i = 0; mp_imgfmt_list[i].name; i++) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_imgfmt_list[i].name); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - return M_OPT_EXIT - 1; - } - - unsigned int fmt = mp_imgfmt_from_name(param, false); - if (!fmt) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: unknown format name: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - - if (dst) - *((uint32_t *)dst) = fmt; - - return 1; -} - -const m_option_type_t m_option_type_imgfmt = { - // Please report any missing colorspaces - .name = "Image format", - .size = sizeof(uint32_t), - .parse = parse_imgfmt, - .copy = copy_opt, -}; - -static int parse_fourcc(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - unsigned int value; - - if (param.len == 4) { - uint8_t *s = param.start; - value = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); - } else { - bstr rest; - value = bstrtoll(param, &rest, 16); - if (rest.len != 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: invalid FourCC: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - } - - if (dst) - *((unsigned int *)dst) = value; - - return 1; -} - -const m_option_type_t m_option_type_fourcc = { - .name = "FourCC", - .size = sizeof(unsigned int), - .parse = parse_fourcc, - .copy = copy_opt, -}; - -#include "audio/format.h" - -static int parse_afmt(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - if (!bstrcmp0(param, "help")) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:"); - for (int i = 0; af_fmtstr_table[i].name; i++) - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", af_fmtstr_table[i].name); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - return M_OPT_EXIT - 1; - } - - int fmt = af_str2fmt_short(param); - if (fmt == -1) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: unknown format name: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - - if (dst) - *((uint32_t *)dst) = fmt; - - return 1; -} - -const m_option_type_t m_option_type_afmt = { - // Please report any missing formats - .name = "Audio format", - .size = sizeof(uint32_t), - .parse = parse_afmt, - .copy = copy_opt, -}; - -#include "audio/chmap.h" - -static int parse_chmap(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - // min>0: at least min channels, min=0: empty ok, min=-1: invalid ok - int min_ch = (opt->flags & M_OPT_MIN) ? opt->min : 1; - - if (bstr_equals0(param, "help")) { - mp_chmap_print_help(MSGT_CFGPARSER, MSGL_INFO); - return M_OPT_EXIT - 1; - } - - if (param.len == 0 && min_ch >= 1) - return M_OPT_MISSING_PARAM; - - struct mp_chmap res = {0}; - if (!mp_chmap_from_str(&res, param)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Error parsing channel layout: %.*s\n", BSTR_P(param)); - return M_OPT_INVALID; - } - - if ((min_ch > 0 && !mp_chmap_is_valid(&res)) || - (min_ch >= 0 && mp_chmap_is_empty(&res))) - { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid channel layout: %.*s\n", BSTR_P(param)); - return M_OPT_INVALID; - } - - if (dst) - *(struct mp_chmap *)dst = res; - - return 1; -} - -const m_option_type_t m_option_type_chmap = { - .name = "Audio channels or channel map", - .size = sizeof(struct mp_chmap *), - .parse = parse_chmap, - .copy = copy_opt, -}; - -static int parse_timestring(struct bstr str, double *time, char endchar) -{ - int a, b, len; - double d; - *time = 0; /* ensure initialization for error cases */ - if (bstr_sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3) - *time = 3600 * a + 60 * b + d; - else if (bstr_sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2) - *time = 60 * a + d; - else if (bstr_sscanf(str, "%lf%n", &d, &len) >= 1) - *time = d; - else - return 0; /* unsupported time format */ - if (len < str.len && str.start[len] != endchar) - return 0; /* invalid extra characters at the end */ - if (!isfinite(*time)) - return 0; - return len; -} - - -static int parse_time(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - double time; - - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - if (!parse_timestring(param, &time, 0)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: invalid time: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - } - - if (dst) - *(double *)dst = time; - return 1; -} - -static char *pretty_print_time(const m_option_t *opt, const void *val) -{ - return mp_format_time(*(double *)val, false); -} - -const m_option_type_t m_option_type_time = { - .name = "Time", - .size = sizeof(double), - .parse = parse_time, - .print = print_double, - .pretty_print = pretty_print_time, - .copy = copy_opt, - .add = add_double, - .clamp = clamp_double, -}; - - -// Relative time - -static int parse_rel_time(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - struct m_rel_time t = {0}; - - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - // Percent pos - if (bstr_endswith0(param, "%")) { - double percent = bstrtod(bstr_splice(param, 0, -1), ¶m); - if (param.len == 0 && percent >= 0 && percent <= 100) { - t.type = REL_TIME_PERCENT; - t.pos = percent; - goto out; - } - } - - // Chapter pos - if (bstr_startswith0(param, "#")) { - int chapter = bstrtoll(bstr_cut(param, 1), ¶m, 10); - if (param.len == 0 && chapter >= 1) { - t.type = REL_TIME_CHAPTER; - t.pos = chapter - 1; - goto out; - } - } - - bool sign = bstr_eatstart0(¶m, "-"); - double time; - if (parse_timestring(param, &time, 0)) { - t.type = sign ? REL_TIME_NEGATIVE : REL_TIME_ABSOLUTE; - t.pos = time; - goto out; - } - - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: invalid time or position: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; - -out: - if (dst) - *(struct m_rel_time *)dst = t; - return 1; -} - -const m_option_type_t m_option_type_rel_time = { - .name = "Relative time or percent position", - .size = sizeof(struct m_rel_time), - .parse = parse_rel_time, - .copy = copy_opt, -}; - - -//// Objects (i.e. filters, etc) settings - -#undef VAL -#define VAL(x) (*(m_obj_settings_t **)(x)) - -bool m_obj_list_find(struct m_obj_desc *dst, const struct m_obj_list *l, - bstr name) -{ - for (int i = 0; ; i++) { - if (!l->get_desc(dst, i)) - break; - if (bstr_equals0(name, dst->name)) - return true; - } - if (l->aliases) { - for (int i = 0; l->aliases[i][0]; i++) { - const char *aname = l->aliases[i][0]; - const char *alias = l->aliases[i][1]; - const char *opts = l->aliases[i][2]; - if (bstr_equals0(name, aname) && - m_obj_list_find(dst, l, bstr0(alias))) - { - if (opts) { - dst->init_options = opts; - } else { - // Assume it's deprecated in this case. - // Also, it's used by the VO code only, so whatever. - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "VO driver '%s' has been replaced with '%s'!\n", - aname, alias); - } - return true; - } - } - } - return false; -} - -static void obj_setting_free(m_obj_settings_t *item) -{ - talloc_free(item->name); - talloc_free(item->label); - free_str_list(&(item->attribs)); -} - -// If at least one item has a label, compare labels only - otherwise ignore them. -static bool obj_setting_equals(m_obj_settings_t *a, m_obj_settings_t *b) -{ - bstr la = bstr0(a->label), lb = bstr0(b->label); - if (la.len || lb.len) - return bstr_equals(la, lb); - if (strcmp(a->name, b->name) != 0) - return false; - - int a_attr_count = 0; - while (a->attribs && a->attribs[a_attr_count]) - a_attr_count++; - int b_attr_count = 0; - while (b->attribs && b->attribs[b_attr_count]) - b_attr_count++; - if (a_attr_count != b_attr_count) - return false; - for (int n = 0; n < a_attr_count; n++) { - if (strcmp(a->attribs[n], b->attribs[n]) != 0) - return false; - } - return true; -} - -static int obj_settings_list_num_items(m_obj_settings_t *obj_list) -{ - int num = 0; - while (obj_list && obj_list[num].name) - num++; - return num; -} - -static void obj_settings_list_del_at(m_obj_settings_t **p_obj_list, int idx) -{ - m_obj_settings_t *obj_list = *p_obj_list; - int num = obj_settings_list_num_items(obj_list); - - assert(idx >= 0 && idx < num); - - obj_setting_free(&obj_list[idx]); - - // Note: the NULL-terminating element is moved down as part of this - memmove(&obj_list[idx], &obj_list[idx + 1], - sizeof(m_obj_settings_t) * (num - idx)); - - *p_obj_list = talloc_realloc(NULL, obj_list, struct m_obj_settings, num); -} - -// Insert such that *p_obj_list[idx] is set to item. -// If idx < 0, set idx = count + idx + 1 (i.e. -1 inserts it as last element). -// Memory referenced by *item is not copied. -static void obj_settings_list_insert_at(m_obj_settings_t **p_obj_list, int idx, - m_obj_settings_t *item) -{ - int num = obj_settings_list_num_items(*p_obj_list); - if (idx < 0) - idx = num + idx + 1; - assert(idx >= 0 && idx <= num); - *p_obj_list = talloc_realloc(NULL, *p_obj_list, struct m_obj_settings, - num + 2); - memmove(*p_obj_list + idx + 1, *p_obj_list + idx, - (num - idx) * sizeof(m_obj_settings_t)); - (*p_obj_list)[idx] = *item; - (*p_obj_list)[num + 1] = (m_obj_settings_t){0}; -} - -static int obj_settings_list_find_by_label(m_obj_settings_t *obj_list, - bstr label) -{ - for (int n = 0; obj_list && obj_list[n].name; n++) { - if (label.len && bstr_equals0(label, obj_list[n].label)) - return n; - } - return -1; -} - -static int obj_settings_list_find_by_label0(m_obj_settings_t *obj_list, - const char *label) -{ - return obj_settings_list_find_by_label(obj_list, bstr0(label)); -} - -static int obj_settings_find_by_content(m_obj_settings_t *obj_list, - m_obj_settings_t *item) -{ - for (int n = 0; obj_list && obj_list[n].name; n++) { - if (obj_setting_equals(&obj_list[n], item)) - return n; - } - return -1; -} - -static void free_obj_settings_list(void *dst) -{ - int n; - m_obj_settings_t *d; - - if (!dst || !VAL(dst)) - return; - - d = VAL(dst); - for (n = 0; d[n].name; n++) - obj_setting_free(&d[n]); - talloc_free(d); - VAL(dst) = NULL; -} - -static void copy_obj_settings_list(const m_option_t *opt, void *dst, - const void *src) -{ - m_obj_settings_t *d, *s; - int n; - - if (!(dst && src)) - return; - - s = VAL(src); - - if (VAL(dst)) - free_obj_settings_list(dst); - if (!s) - return; - - for (n = 0; s[n].name; n++) - /* NOP */; - d = talloc_array(NULL, struct m_obj_settings, n + 1); - for (n = 0; s[n].name; n++) { - d[n].name = talloc_strdup(NULL, s[n].name); - d[n].label = talloc_strdup(NULL, s[n].label); - d[n].attribs = NULL; - copy_str_list(NULL, &(d[n].attribs), &(s[n].attribs)); - } - d[n].name = NULL; - d[n].label = NULL; - d[n].attribs = NULL; - VAL(dst) = d; -} - -// Consider -vf a=b=c:d=e. This verifies "b"="c" and "d"="e" and that the -// option names/values are correct. Try to determine whether an option -// without '=' sets a flag, or whether it's a positional argument. -static int get_obj_param(bstr opt_name, bstr obj_name, struct m_config *config, - bstr name, bstr val, int flags, int *nold, - bstr *out_name, bstr *out_val) -{ - int r; - - if (!config) - return 0; // skip - - // va.start != NULL => of the form name=val (not positional) - // If it's just "name", and the associated option exists and is a flag, - // don't accept it as positional argument. - if (val.start || m_config_option_requires_param(config, name) == 0) { - r = m_config_set_option_ext(config, name, val, flags); - if (r < 0) { - if (r == M_OPT_UNKNOWN) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: %.*s doesn't have a %.*s parameter.\n", - BSTR_P(opt_name), BSTR_P(obj_name), BSTR_P(name)); - return M_OPT_UNKNOWN; - } - if (r > M_OPT_EXIT) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: " - "Error while parsing %.*s parameter %.*s (%.*s)\n", - BSTR_P(opt_name), BSTR_P(obj_name), BSTR_P(name), - BSTR_P(val)); - return r; - } - *out_name = name; - *out_val = val; - return 1; - } else { - val = name; - // positional fields - if (val.len == 0) { // Empty field, count it and go on - (*nold)++; - return 0; - } - const char *opt = m_config_get_positional_option(config, *nold); - if (!opt) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: %.*s has only %d " - "params, so you can't give more than %d unnamed params.\n", - BSTR_P(opt_name), BSTR_P(obj_name), *nold, *nold); - return M_OPT_OUT_OF_RANGE; - } - r = m_config_set_option_ext(config, bstr0(opt), val, flags); - if (r < 0) { - if (r > M_OPT_EXIT) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: " - "Error while parsing %.*s parameter %s (%.*s)\n", - BSTR_P(opt_name), BSTR_P(obj_name), opt, BSTR_P(val)); - return r; - } - *out_name = bstr0(opt); - *out_val = val; - (*nold)++; - return 1; - } -} - -// Consider -vf a=b:c:d. This parses "b:c:d" into name/value pairs, stored as -// linear array in *_ret. In particular, config contains what options a the -// object takes, and verifies the option values as well. -// If config is NULL, all parameters are accepted without checking. -// _ret set to NULL can be used for checking-only. -// flags can contain any M_SETOPT_* flag. -int m_obj_parse_sub_config(struct bstr opt_name, struct bstr name, - struct bstr *pstr, struct m_config *config, - int flags, char ***ret) -{ - int nold = 0; - char **args = NULL; - int num_args = 0; - int r = 1; - - if (ret) { - args = *ret; - while (args && args[num_args]) - num_args++; - } - - while (pstr->len > 0) { - bstr fname, fval; - r = split_subconf(opt_name, pstr, &fname, &fval); - if (r < 0) - goto exit; - if (bstr_equals0(fname, "help")) - goto print_help; - r = get_obj_param(opt_name, name, config, fname, fval, flags, &nold, - &fname, &fval); - if (r < 0) - goto exit; - - if (r > 0 && ret) { - MP_TARRAY_APPEND(NULL, args, num_args, bstrto0(NULL, fname)); - MP_TARRAY_APPEND(NULL, args, num_args, bstrto0(NULL, fval)); - MP_TARRAY_APPEND(NULL, args, num_args, NULL); - MP_TARRAY_APPEND(NULL, args, num_args, NULL); - num_args -= 2; - } - - if (!bstr_eatstart0(pstr, ":")) - break; - } - - if (ret) { - if (num_args > 0) { - *ret = args; - args = NULL; - } else { - *ret = NULL; - } - } - - goto exit; - -print_help: ; - if (config) { - m_config_print_option_list(config); - } else { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %.*s doesn't exist.\n", - BSTR_P(opt_name)); - } - r = M_OPT_EXIT - 1; - -exit: - free_str_list(&args); - return r; -} - -// Characters which may appear in a filter name -#define NAMECH "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" - -// Parse one item, e.g. -vf a=b:c:d,e=f:g => parse a=b:c:d into "a" and "b:c:d" -static int parse_obj_settings(struct bstr opt, struct bstr *pstr, - const struct m_obj_list *list, - m_obj_settings_t **_ret) -{ - int r; - char **plist = NULL; - struct m_obj_desc desc; - bstr label = {0}; - - if (bstr_eatstart0(pstr, "@")) { - if (!bstr_split_tok(*pstr, ":", &label, pstr)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: ':' expected after label.\n", BSTR_P(opt)); - return M_OPT_INVALID; - } - } - - bool has_param = false; - int idx = bstrspn(*pstr, NAMECH); - bstr str = bstr_splice(*pstr, 0, idx); - *pstr = bstr_cut(*pstr, idx); - // video filters use "=", VOs use ":" - if (bstr_eatstart0(pstr, "=") || bstr_eatstart0(pstr, ":")) - has_param = true; - - bool legacy = false; - bool skip = false; - if (m_obj_list_find(&desc, list, str)) { - legacy = !desc.priv_size && list->legacy_hacks; - } else { - if (!list->allow_unknown_entries) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: %.*s doesn't exist.\n", - BSTR_P(opt), BSTR_P(str)); - return M_OPT_INVALID; - } - desc = (struct m_obj_desc){0}; - skip = true; - } - - if (has_param) { - if (legacy) { - // Should perhaps be parsed as escape-able string. But this is a - // compatibility path, so it's not worth the trouble. - int next = bstrcspn(*pstr, ","); - bstr param = bstr_splice(*pstr, 0, next); - *pstr = bstr_cut(*pstr, next); - if (!bstrcmp0(param, "help")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: %.*s has no option description.\n", - BSTR_P(opt), BSTR_P(str)); - return M_OPT_EXIT - 1; - } - if (_ret) { - plist = talloc_zero_array(NULL, char *, 4); - plist[0] = talloc_strdup(NULL, "_oldargs_"); - plist[1] = bstrto0(NULL, param); - } - } else { - struct m_config *config = NULL; - if (!skip) - config = m_config_from_obj_desc(NULL, &desc); - r = m_obj_parse_sub_config(opt, str, pstr, config, - M_SETOPT_CHECK_ONLY, - _ret ? &plist : NULL); - talloc_free(config); - if (r < 0) - return r; - } - } - if (!_ret) - return 1; - - m_obj_settings_t item = { - .name = bstrto0(NULL, str), - .label = bstrdup0(NULL, label), - .attribs = plist, - }; - obj_settings_list_insert_at(_ret, -1, &item); - return 1; -} - -// Parse a single entry for -vf-del (return 0 if not applicable) -// mark_del is bounded by the number of items in dst -static int parse_obj_settings_del(struct bstr opt_name, struct bstr *param, - void *dst, bool *mark_del) -{ - bstr s = *param; - if (bstr_eatstart0(&s, "@")) { - // '@name:' -> parse as normal filter entry - // '@name,' or '@name' -> parse here - int idx = bstrspn(s, NAMECH); - bstr label = bstr_splice(s, 0, idx); - s = bstr_cut(s, idx); - if (bstr_startswith0(s, ":")) - return 0; - if (dst) { - int label_index = obj_settings_list_find_by_label(VAL(dst), label); - if (label_index >= 0) { - mark_del[label_index] = true; - } else { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: item label @%.*s not found.\n", - BSTR_P(opt_name), BSTR_P(label)); - } - } - *param = s; - return 1; - } - - bstr rest; - long long id = bstrtoll(s, &rest, 0); - if (rest.len == s.len) - return 0; - - if (dst) { - int num = obj_settings_list_num_items(VAL(dst)); - if (id < 0) - id = num + id; - - if (id >= 0 && id < num) { - mark_del[id] = true; - } else { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: Index %lld is out of range.\n", - BSTR_P(opt_name), id); - } - } - - *param = rest; - return 1; -} - -static int parse_obj_settings_list(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - int len = strlen(opt->name); - m_obj_settings_t *res = NULL; - int op = OP_NONE; - bool *mark_del = NULL; - int num_items = obj_settings_list_num_items(dst ? VAL(dst) : 0); - struct m_obj_list *ol = opt->priv; - - assert(opt->priv); - - if (opt->name[len - 1] == '*' && (name.len > len - 1)) { - struct bstr suffix = bstr_cut(name, len - 1); - if (bstrcmp0(suffix, "-add") == 0) - op = OP_ADD; - else if (bstrcmp0(suffix, "-set") == 0) - op = OP_NONE; - else if (bstrcmp0(suffix, "-pre") == 0) - op = OP_PRE; - else if (bstrcmp0(suffix, "-del") == 0) - op = OP_DEL; - else if (bstrcmp0(suffix, "-clr") == 0) - op = OP_CLR; - else if (bstrcmp0(suffix, "-toggle") == 0) - op = OP_TOGGLE; - else { - char prefix[len]; - strncpy(prefix, opt->name, len - 1); - prefix[len - 1] = '\0'; - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: unknown postfix %.*s\n" - "Supported postfixes are:\n" - " %s-set\n" - " Overwrite the old list with the given list\n\n" - " %s-add\n" - " Append the given list to the current list\n\n" - " %s-pre\n" - " Prepend the given list to the current list\n\n" - " %s-del x,y,...\n" - " Remove the given elements. Take the list element index (starting from 0).\n" - " Negative index can be used (i.e. -1 is the last element).\n" - " Filter names work as well.\n\n" - " %s-clr\n" - " Clear the current list.\n", - BSTR_P(name), BSTR_P(suffix), prefix, prefix, prefix, prefix, prefix); - - return M_OPT_UNKNOWN; - } - } - - if (!bstrcmp0(param, "help")) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available %s:\n", ol->description); - for (int n = 0; ; n++) { - struct m_obj_desc desc; - if (!ol->get_desc(&desc, n)) - break; - if (!desc.hidden) { - mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-15s: %s\n", - desc.name, desc.description); - } - } - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); - return M_OPT_EXIT - 1; - } - - if (op == OP_CLR) { - if (dst) - free_obj_settings_list(dst); - return 0; - } else if (op == OP_DEL) { - mark_del = talloc_zero_array(NULL, bool, num_items + 1); - } - - if (op != OP_NONE && param.len == 0) - return M_OPT_MISSING_PARAM; - - while (param.len > 0) { - int r = 0; - if (op == OP_DEL) - r = parse_obj_settings_del(name, ¶m, dst, mark_del); - if (r == 0) { - r = parse_obj_settings(name, ¶m, ol, dst ? &res : NULL); - } - if (r < 0) - return r; - if (param.len > 0) { - const char sep[2] = {OPTION_LIST_SEPARATOR, 0}; - if (!bstr_eatstart0(¶m, sep)) - return M_OPT_INVALID; - if (param.len == 0) { - if (!ol->allow_trailer) - return M_OPT_INVALID; - if (dst) { - m_obj_settings_t item = { - .name = talloc_strdup(NULL, ""), - }; - obj_settings_list_insert_at(&res, -1, &item); - } - } - } - } - - if (dst) { - m_obj_settings_t *list = VAL(dst); - if (op == OP_PRE) { - int prepend_counter = 0; - for (int n = 0; res && res[n].name; n++) { - int label = obj_settings_list_find_by_label0(list, res[n].label); - if (label < 0) { - obj_settings_list_insert_at(&list, prepend_counter, &res[n]); - prepend_counter++; - } else { - // Prefer replacement semantics, instead of actually - // prepending. - obj_setting_free(&list[label]); - list[label] = res[n]; - } - } - talloc_free(res); - } else if (op == OP_ADD) { - for (int n = 0; res && res[n].name; n++) { - int label = obj_settings_list_find_by_label0(list, res[n].label); - if (label < 0) { - obj_settings_list_insert_at(&list, -1, &res[n]); - } else { - // Prefer replacement semantics, instead of actually - // appending. - obj_setting_free(&list[label]); - list[label] = res[n]; - } - } - talloc_free(res); - } else if (op == OP_TOGGLE) { - for (int n = 0; res && res[n].name; n++) { - int found = obj_settings_find_by_content(list, &res[n]); - if (found < 0) { - obj_settings_list_insert_at(&list, -1, &res[n]); - } else { - obj_settings_list_del_at(&list, found); - obj_setting_free(&res[n]); - } - } - talloc_free(res); - } else if (op == OP_DEL) { - for (int n = num_items - 1; n >= 0; n--) { - if (mark_del[n]) - obj_settings_list_del_at(&list, n); - } - for (int n = 0; res && res[n].name; n++) { - int found = obj_settings_find_by_content(list, &res[n]); - if (found < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: Item not found\n", BSTR_P(name)); - } else { - obj_settings_list_del_at(&list, found); - } - } - free_obj_settings_list(&res); - } else { - assert(op == OP_NONE); - free_obj_settings_list(&list); - list = res; - } - VAL(dst) = list; - } - - talloc_free(mark_del); - return 1; -} - -const m_option_type_t m_option_type_obj_settings_list = { - .name = "Object settings list", - .size = sizeof(m_obj_settings_t *), - .flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, - .parse = parse_obj_settings_list, - .copy = copy_obj_settings_list, - .free = free_obj_settings_list, -}; diff --git a/core/m_option.h b/core/m_option.h deleted file mode 100644 index 89f3caa652..0000000000 --- a/core/m_option.h +++ /dev/null @@ -1,646 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_M_OPTION_H -#define MPLAYER_M_OPTION_H - -#include -#include -#include - -#include "config.h" -#include "core/bstr.h" -#include "audio/chmap.h" - -// m_option allows to parse, print and copy data of various types. - -typedef struct m_option_type m_option_type_t; -typedef struct m_option m_option_t; -struct m_config; - -///////////////////////////// Options types declarations //////////////////// - -// Simple types -extern const m_option_type_t m_option_type_flag; -extern const m_option_type_t m_option_type_store; -extern const m_option_type_t m_option_type_float_store; -extern const m_option_type_t m_option_type_int; -extern const m_option_type_t m_option_type_int64; -extern const m_option_type_t m_option_type_intpair; -extern const m_option_type_t m_option_type_float; -extern const m_option_type_t m_option_type_double; -extern const m_option_type_t m_option_type_string; -extern const m_option_type_t m_option_type_string_list; -extern const m_option_type_t m_option_type_time; -extern const m_option_type_t m_option_type_rel_time; -extern const m_option_type_t m_option_type_choice; - -extern const m_option_type_t m_option_type_print; -extern const m_option_type_t m_option_type_print_func; -extern const m_option_type_t m_option_type_print_func_param; -extern const m_option_type_t m_option_type_subconfig; -extern const m_option_type_t m_option_type_subconfig_struct; -extern const m_option_type_t m_option_type_imgfmt; -extern const m_option_type_t m_option_type_fourcc; -extern const m_option_type_t m_option_type_afmt; -extern const m_option_type_t m_option_type_color; -extern const m_option_type_t m_option_type_geometry; -extern const m_option_type_t m_option_type_size_box; -extern const m_option_type_t m_option_type_chmap; - -// Callback used by m_option_type_print_func options. -typedef int (*m_opt_func_full_t)(const m_option_t *, const char *, const char *); - -enum m_rel_time_type { - REL_TIME_NONE, - REL_TIME_ABSOLUTE, - REL_TIME_NEGATIVE, - REL_TIME_PERCENT, - REL_TIME_CHAPTER, -}; - -struct m_rel_time { - double pos; - enum m_rel_time_type type; -}; - -struct m_color { - uint8_t r, g, b, a; -}; - -struct m_geometry { - int x, y, w, h; - bool xy_valid : 1, wh_valid : 1; - bool w_per : 1, h_per : 1; - bool x_sign : 1, y_sign : 1, x_per : 1, y_per : 1; -}; - -void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh, - int scrw, int scrh, struct m_geometry *gm); - -struct m_obj_desc { - // Name which will be used in the option string - const char *name; - // Will be printed when "help" is passed - const char *description; - // Size of the private struct - int priv_size; - // If not NULL, default values for private struct - const void *priv_defaults; - // Options which refer to members in the private struct - const struct m_option *options; - // For free use by the implementer of m_obj_list.get_desc - const void *p; - // If not NULL, options which should be set before applying other options. - // This member is usually set my m_obj_list_find() only. - // Only works if options is not NULL. - const char *init_options; - // Don't list entries with "help" - bool hidden; -}; - -// Extra definition needed for \ref m_option_type_obj_settings_list options. -struct m_obj_list { - bool (*get_desc)(struct m_obj_desc *dst, int index); - const char *description; - // Can be set to a NULL terminated array of aliases - const char *aliases[4][5]; - // Allow a trailing ",", which adds an entry with name="" - bool allow_trailer; - // Allow unknown entries, for which a dummy entry is inserted, and whose - // options are skipped and ignored. - bool allow_unknown_entries; - // If object has no options set, assume it parses options on its own. - bool legacy_hacks; -}; - -// Find entry by name -bool m_obj_list_find(struct m_obj_desc *dst, const struct m_obj_list *list, - bstr name); - -// The data type used by \ref m_option_type_obj_settings_list. -typedef struct m_obj_settings { - // Type of the object. - char *name; - // Optional user-defined name. - char *label; - // NULL terminated array of parameter/value pairs. - char **attribs; -} m_obj_settings_t; - -// A parser to set up a list of objects. -/** It creates a NULL terminated array \ref m_obj_settings. The option priv - * field (\ref m_option::priv) must point to a \ref m_obj_list_t describing - * the available object types. - */ -extern const m_option_type_t m_option_type_obj_settings_list; - -int m_obj_parse_sub_config(struct bstr opt_name, struct bstr name, - struct bstr *pstr, struct m_config *config, - int flags, char ***ret); - -struct m_opt_choice_alternatives { - char *name; - int value; -}; - -// For OPT_STRING_VALIDATE(). Behaves like m_option_type.parse(). -typedef int (*m_opt_string_validate_fn)(const m_option_t *opt, struct bstr name, - struct bstr param); - -// m_option.priv points to this if M_OPT_TYPE_USE_SUBSTRUCT is used -struct m_sub_options { - const struct m_option *opts; - size_t size; - const void *defaults; -}; - -// FIXME: backward compatibility -#define CONF_TYPE_FLAG (&m_option_type_flag) -#define CONF_TYPE_STORE (&m_option_type_store) -#define CONF_TYPE_INT (&m_option_type_int) -#define CONF_TYPE_INT64 (&m_option_type_int64) -#define CONF_TYPE_FLOAT (&m_option_type_float) -#define CONF_TYPE_DOUBLE (&m_option_type_double) -#define CONF_TYPE_STRING (&m_option_type_string) -#define CONF_TYPE_PRINT (&m_option_type_print) -#define CONF_TYPE_PRINT_FUNC (&m_option_type_print_func) -#define CONF_TYPE_SUBCONFIG (&m_option_type_subconfig) -#define CONF_TYPE_STRING_LIST (&m_option_type_string_list) -#define CONF_TYPE_IMGFMT (&m_option_type_imgfmt) -#define CONF_TYPE_FOURCC (&m_option_type_fourcc) -#define CONF_TYPE_AFMT (&m_option_type_afmt) -#define CONF_TYPE_OBJ_SETTINGS_LIST (&m_option_type_obj_settings_list) -#define CONF_TYPE_TIME (&m_option_type_time) -#define CONF_TYPE_CHOICE (&m_option_type_choice) -#define CONF_TYPE_INT_PAIR (&m_option_type_intpair) - -// Possible option values. Code is allowed to access option data without going -// through this union. It serves for self-documentation and to get minimal -// size/alignment requirements for option values in general. -union m_option_value { - int flag; // not the C type "bool"! - int store; - float float_store; - int int_; - int64_t int64; - int intpair[2]; - float float_; - double double_; - char *string; - char **string_list; - int imgfmt; - unsigned int fourcc; - int afmt; - m_obj_settings_t *obj_settings_list; - double time; - struct m_rel_time rel_time; - struct m_color color; - struct m_geometry geometry; - struct m_geometry size_box; - struct mp_chmap chmap; -}; - -//////////////////////////////////////////////////////////////////////////// - -// Option type description -struct m_option_type { - const char *name; - // Size needed for the data. - unsigned int size; - // One of M_OPT_TYPE*. - unsigned int flags; - - // Parse the data from a string. - /** It is the only required function, all others can be NULL. - * - * \param opt The option that is parsed. - * \param name The full option name. - * \param param The parameter to parse. - * may not be an argument meant for this option - * \param dst Pointer to the memory where the data should be written. - * If NULL the parameter validity should still be checked. - * \return On error a negative value is returned, on success the number - * of arguments consumed. For details see \ref OptionParserReturn. - */ - int (*parse)(const m_option_t *opt, struct bstr name, struct bstr param, - void *dst); - - // Print back a value in string form. - /** \param opt The option to print. - * \param val Pointer to the memory holding the data to be printed. - * \return An allocated string containing the text value or (void*)-1 - * on error. - */ - char *(*print)(const m_option_t *opt, const void *val); - - // Print the value in a human readable form. Unlike print(), it doesn't - // necessarily return the exact value, and is generally not parseable with - // parse(). - char *(*pretty_print)(const m_option_t *opt, const void *val); - - // Copy data between two locations. Deep copy if the data has pointers. - /** \param opt The option to copy. - * \param dst Pointer to the destination memory. - * \param src Pointer to the source memory. - */ - void (*copy)(const m_option_t *opt, void *dst, const void *src); - - // Free the data allocated for a save slot. - /** This is only needed for dynamic types like strings. - * \param dst Pointer to the data, usually a pointer that should be freed and - * set to NULL. - */ - void (*free)(void *dst); - - // Add the value add to the value in val. For types that are not numeric, - // add gives merely the direction. The wrap parameter determines whether - // the value is clipped, or wraps around to the opposite max/min. - void (*add)(const m_option_t *opt, void *val, double add, bool wrap); - - // Clamp the value in val to the option's valid value range. - // Return values: - // M_OPT_OUT_OF_RANGE: val was invalid, and modified (clamped) to be valid - // M_OPT_INVALID: val was invalid, and can't be made valid - // 0: val was already valid and is unchanged - int (*clamp)(const m_option_t *opt, void *val); -}; - -// Option description -struct m_option { - // Option name. - const char *name; - - // Reserved for higher level APIs, it shouldn't be used by parsers. - /** The suboption parser and func types do use it. They should instead - * use the priv field but this was inherited from older versions of the - * config code. - */ - void *p; - - // Option type. - const m_option_type_t *type; - - // See \ref OptionFlags. - unsigned int flags; - - // \brief Mostly useful for numeric types, the \ref M_OPT_MIN flags must - // also be set. - double min; - - // \brief Mostly useful for numeric types, the \ref M_OPT_MAX flags must - // also be set. - double max; - - // Type dependent data (for all kinds of extended settings). - /** This used to be a function pointer to hold a 'reverse to defaults' func. - * Now it can be used to pass any type of extra args needed by the parser. - */ - void *priv; - - int new; - - int offset; - - // Initialize variable to given default before parsing options - void *defval; -}; - - -// The option has a minimum set in \ref m_option::min. -#define M_OPT_MIN (1 << 0) - -// The option has a maximum set in \ref m_option::max. -#define M_OPT_MAX (1 << 1) - -// The option has a minimum and maximum in m_option::min and m_option::max. -#define M_OPT_RANGE (M_OPT_MIN | M_OPT_MAX) - -// The option is forbidden in config files. -#define M_OPT_NOCFG (1 << 2) - -// This option can't be set per-file when used with struct m_config. -#define M_OPT_GLOBAL (1 << 4) - -// The option should be set during command line pre-parsing -#define M_OPT_PRE_PARSE (1 << 6) - -// See M_OPT_TYPE_OPTIONAL_PARAM. -#define M_OPT_OPTIONAL_PARAM (1 << 10) - -// Parse C-style escapes like "\n" (for CONF_TYPE_STRING only) -#define M_OPT_PARSE_ESCAPES (1 << 11) - -// These are kept for compatibility with older code. -#define CONF_MIN M_OPT_MIN -#define CONF_MAX M_OPT_MAX -#define CONF_RANGE M_OPT_RANGE -#define CONF_NOCFG M_OPT_NOCFG -#define CONF_GLOBAL M_OPT_GLOBAL -#define CONF_PRE_PARSE M_OPT_PRE_PARSE - -// These flags are used to describe special parser capabilities or behavior. - -// Suboption parser flag. -/** When this flag is set, m_option::p should point to another m_option - * array. Only the parse function will be called. If dst is set, it should - * create/update an array of char* containg opt/val pairs. The options in - * the child array will then be set automatically by the \ref Config. - * Also note that suboptions may be directly accessed by using - * -option:subopt blah. - */ -#define M_OPT_TYPE_HAS_CHILD (1 << 0) - -// Wildcard matching flag. -/** If set the option type has a use for option names ending with a * - * (used for -aa*), this only affects the option name matching. - */ -#define M_OPT_TYPE_ALLOW_WILDCARD (1 << 1) - -// Dynamic data type. -/** This flag indicates that the data is dynamically allocated (m_option::p - * points to a pointer). It enables a little hack in the \ref Config wich - * replaces the initial value of such variables with a dynamic copy in case - * the initial value is statically allocated (pretty common with strings). - */ -#define M_OPT_TYPE_DYNAMIC (1 << 2) - -// The parameter is optional and by default no parameter is preferred. If -// ambiguous syntax is used ("--opt value"), the command line parser will -// assume that the argument takes no parameter. In config files, these -// options can be used without "=" and value. -#define M_OPT_TYPE_OPTIONAL_PARAM (1 << 3) - -// modify M_OPT_TYPE_HAS_CHILD so that m_option::p points to -// struct m_sub_options, instead of a direct m_option array. -#define M_OPT_TYPE_USE_SUBSTRUCT (1 << 4) - -///////////////////////////// Parser flags ///////////////////////////////// - -// OptionParserReturn -// -// On success parsers return a number >= 0. -// -// To indicate that MPlayer should exit without playing anything, -// parsers return M_OPT_EXIT minus the number of parameters they -// consumed: \ref M_OPT_EXIT or \ref M_OPT_EXIT-1. -// -// On error one of the following (negative) error codes is returned: - -// For use by higher level APIs when the option name is invalid. -#define M_OPT_UNKNOWN -1 - -// Returned when a parameter is needed but wasn't provided. -#define M_OPT_MISSING_PARAM -2 - -// Returned when the given parameter couldn't be parsed. -#define M_OPT_INVALID -3 - -// Returned if the value is "out of range". The exact meaning may -// vary from type to type. -#define M_OPT_OUT_OF_RANGE -4 - -// The option doesn't take a parameter. -#define M_OPT_DISALLOW_PARAM -5 - -// Returned if the parser failed for any other reason than a bad parameter. -#define M_OPT_PARSER_ERR -6 - -// Returned when MPlayer should exit. Used by various help stuff. -/** M_OPT_EXIT must be the lowest number on this list. - */ -#define M_OPT_EXIT -7 - -char *m_option_strerror(int code); - -// Find the option matching the given name in the list. -/** \ingroup Options - * This function takes the possible wildcards into account (see - * \ref M_OPT_TYPE_ALLOW_WILDCARD). - * - * \param list Pointer to an array of \ref m_option. - * \param name Name of the option. - * \return The matching option or NULL. - */ -const m_option_t *m_option_list_find(const m_option_t *list, const char *name); - -// Helper to parse options, see \ref m_option_type::parse. -static inline int m_option_parse(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) -{ - return opt->type->parse(opt, name, param, dst); -} - -// Helper to print options, see \ref m_option_type::print. -static inline char *m_option_print(const m_option_t *opt, const void *val_ptr) -{ - if (opt->type->print) - return opt->type->print(opt, val_ptr); - else - return NULL; -} - -static inline char *m_option_pretty_print(const m_option_t *opt, - const void *val_ptr) -{ - if (opt->type->pretty_print) - return opt->type->pretty_print(opt, val_ptr); - else - return m_option_print(opt, val_ptr); -} - -// Helper around \ref m_option_type::copy. -static inline void m_option_copy(const m_option_t *opt, void *dst, - const void *src) -{ - if (opt->type->copy) - opt->type->copy(opt, dst, src); -} - -// Helper around \ref m_option_type::free. -static inline void m_option_free(const m_option_t *opt, void *dst) -{ - if (opt->type->free) - opt->type->free(dst); -} - -int m_option_required_params(const m_option_t *opt); - -// Cause a compilation warning if typeof(expr) != type. -// Should be used with pointer types only. -#define MP_EXPECT_TYPE(type, expr) (0 ? (type)0 : (expr)) - -// This behaves like offsetof(type, member), but will cause a compilation -// warning if typeof(member) != expected_member_type. -// It uses some trickery to make it compile as expression. -#define MP_CHECKED_OFFSETOF(type, member, expected_member_type) \ - (offsetof(type, member) + (0 && MP_EXPECT_TYPE(expected_member_type*, \ - &((type*)0)->member))) - - -#define OPTION_LIST_SEPARATOR ',' - -#if HAVE_DOS_PATHS -#define OPTION_PATH_SEPARATOR ';' -#else -#define OPTION_PATH_SEPARATOR ':' -#endif - -#define OPTDEF_STR(s) .defval = (void *)&(char * const){s} -#define OPTDEF_INT(i) .defval = (void *)&(const int){i} - -#define OPT_GENERAL(ctype, optname, varname, flagv, ...) \ - {.name = optname, .flags = flagv, .new = 1, \ - .offset = MP_CHECKED_OFFSETOF(OPT_BASE_STRUCT, varname, ctype), \ - __VA_ARGS__} - -#define OPT_GENERAL_NOTYPE(optname, varname, flagv, ...) \ - {.name = optname, .flags = flagv, .new = 1, \ - .offset = offsetof(OPT_BASE_STRUCT, varname), \ - __VA_ARGS__} - -#define OPT_HELPER_REMOVEPAREN(...) __VA_ARGS__ - -/* The OPT_FLAG_CONSTANTS->OPT_FLAG_CONSTANTS_ kind of redirection exists to - * make the code fully standard-conforming: the C standard requires that - * __VA_ARGS__ has at least one argument (though GCC for example would accept - * 0). Thus the first OPT_FLAG_CONSTANTS is a wrapper which just adds one - * argument to ensure __VA_ARGS__ is not empty when calling the next macro. - */ - -#define OPT_FLAG(...) \ - OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_flag, .max = 1) - -#define OPT_FLAG_CONSTANTS_(optname, varname, flags, offvalue, value, ...) \ - OPT_GENERAL(int, optname, varname, flags, \ - .min = offvalue, .max = value, __VA_ARGS__) -#define OPT_FLAG_CONSTANTS(...) \ - OPT_FLAG_CONSTANTS_(__VA_ARGS__, .type = &m_option_type_flag) - -#define OPT_FLAG_STORE(optname, varname, flags, value) \ - OPT_GENERAL(int, optname, varname, flags, .max = value, \ - .type = &m_option_type_store) - -#define OPT_FLOAT_STORE(optname, varname, flags, value) \ - OPT_GENERAL(float, optname, varname, flags, .max = value, \ - .type = &m_option_type_float_store) - -#define OPT_STRINGLIST(...) \ - OPT_GENERAL(char**, __VA_ARGS__, .type = &m_option_type_string_list) - -#define OPT_PATHLIST(...) \ - OPT_GENERAL(char**, __VA_ARGS__, .type = &m_option_type_string_list, \ - .priv = (void *)&(const char){OPTION_PATH_SEPARATOR}) - -#define OPT_INT(...) \ - OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_int) - -#define OPT_INT64(...) \ - OPT_GENERAL(int64_t, __VA_ARGS__, .type = &m_option_type_int64) - -#define OPT_RANGE_(ctype, optname, varname, flags, minval, maxval, ...) \ - OPT_GENERAL(ctype, optname, varname, (flags) | CONF_RANGE, \ - .min = minval, .max = maxval, __VA_ARGS__) - -#define OPT_INTRANGE(...) \ - OPT_RANGE_(int, __VA_ARGS__, .type = &m_option_type_int) - -#define OPT_FLOATRANGE(...) \ - OPT_RANGE_(float, __VA_ARGS__, .type = &m_option_type_float) - -#define OPT_INTPAIR(...) \ - OPT_GENERAL_NOTYPE(__VA_ARGS__, .type = &m_option_type_intpair) - -#define OPT_FLOAT(...) \ - OPT_GENERAL(float, __VA_ARGS__, .type = &m_option_type_float) - -#define OPT_DOUBLE(...) \ - OPT_GENERAL(double, __VA_ARGS__, .type = &m_option_type_double) - -#define OPT_STRING(...) \ - OPT_GENERAL(char*, __VA_ARGS__, .type = &m_option_type_string) - -#define OPT_SETTINGSLIST(optname, varname, flags, objlist) \ - OPT_GENERAL(m_obj_settings_t*, optname, varname, flags, \ - .type = &m_option_type_obj_settings_list, \ - .priv = (void*)MP_EXPECT_TYPE(const struct m_obj_list*, objlist)) - -#define OPT_IMAGEFORMAT(...) \ - OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_imgfmt) - -#define OPT_AUDIOFORMAT(...) \ - OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_afmt) - -#define OPT_CHMAP(...) \ - OPT_GENERAL(struct mp_chmap, __VA_ARGS__, .type = &m_option_type_chmap) - - -#define M_CHOICES(choices) \ - .priv = (void *)&(const struct m_opt_choice_alternatives[]){ \ - OPT_HELPER_REMOVEPAREN choices, {NULL}} - -#define OPT_CHOICE(...) \ - OPT_CHOICE_(__VA_ARGS__, .type = &m_option_type_choice) -#define OPT_CHOICE_(optname, varname, flags, choices, ...) \ - OPT_GENERAL(int, optname, varname, flags, M_CHOICES(choices), __VA_ARGS__) - -// Union of choices and an int range. The choice values can be included in the -// int range, or be completely separate - both works. -#define OPT_CHOICE_OR_INT_(optname, varname, flags, minval, maxval, choices, ...) \ - OPT_GENERAL(int, optname, varname, (flags) | CONF_RANGE, \ - .min = minval, .max = maxval, \ - M_CHOICES(choices), __VA_ARGS__) -#define OPT_CHOICE_OR_INT(...) \ - OPT_CHOICE_OR_INT_(__VA_ARGS__, .type = &m_option_type_choice) - -#define OPT_TIME(...) \ - OPT_GENERAL(double, __VA_ARGS__, .type = &m_option_type_time) - -#define OPT_REL_TIME(...) \ - OPT_GENERAL(struct m_rel_time, __VA_ARGS__, .type = &m_option_type_rel_time) - -#define OPT_COLOR(...) \ - OPT_GENERAL(struct m_color, __VA_ARGS__, .type = &m_option_type_color) - -#define OPT_GEOMETRY(...) \ - OPT_GENERAL(struct m_geometry, __VA_ARGS__, .type = &m_option_type_geometry) - -#define OPT_SIZE_BOX(...) \ - OPT_GENERAL(struct m_geometry, __VA_ARGS__, .type = &m_option_type_size_box) - -#define OPT_TRACKCHOICE(name, var) \ - OPT_CHOICE_OR_INT(name, var, 0, 0, 8190, ({"no", -2}, {"auto", -1})) - -#define OPT_STRING_VALIDATE_(optname, varname, flags, validate_fn, ...) \ - OPT_GENERAL(char*, optname, varname, flags, __VA_ARGS__, \ - .priv = MP_EXPECT_TYPE(m_opt_string_validate_fn, validate_fn)) -#define OPT_STRING_VALIDATE(...) \ - OPT_STRING_VALIDATE_(__VA_ARGS__, .type = &m_option_type_string) - -// subconf must have the type struct m_sub_options. -// All sub-options are prefixed with "name-" and are added to the current -// (containing) option list. -// If name is "", add the sub-options directly instead. -// varname refers to the field, that must be a pointer to a field described by -// the subconf struct. -#define OPT_SUBSTRUCT(name, varname, subconf, flagv) \ - OPT_GENERAL_NOTYPE(name, varname, flagv, \ - .type = &m_option_type_subconfig_struct, \ - .priv = (void*)&subconf) - -#endif /* MPLAYER_M_OPTION_H */ diff --git a/core/m_property.c b/core/m_property.c deleted file mode 100644 index f334b6fe1f..0000000000 --- a/core/m_property.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/// \file -/// \ingroup Properties - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include "talloc.h" -#include "core/m_option.h" -#include "m_property.h" -#include "core/mp_msg.h" -#include "core/mp_common.h" - -const struct m_option_type m_option_type_dummy = { - .name = "Unknown", - .flags = M_OPT_TYPE_ALLOW_WILDCARD, // make "vf*" property work -}; - -struct legacy_prop { - const char *old, *new; -}; -static const struct legacy_prop legacy_props[] = { - {"switch_video", "video"}, - {"switch_audio", "audio"}, - {"switch_program", "program"}, - {"framedropping", "framedrop"}, - {"osdlevel", "osd-level"}, - {0} -}; - -static bool translate_legacy_property(const char *name, char *buffer, - size_t buffer_size) -{ - if (strlen(name) + 1 > buffer_size) - return false; - - const char *old_name = name; - - for (int n = 0; legacy_props[n].new; n++) { - if (strcmp(name, legacy_props[n].old) == 0) { - name = legacy_props[n].new; - break; - } - } - - snprintf(buffer, buffer_size, "%s", name); - - // Old names used "_" instead of "-" - for (int n = 0; buffer[n]; n++) { - if (buffer[n] == '_') - buffer[n] = '-'; - } - - if (strcmp(old_name, buffer) != 0) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, "Warning: property '%s' is deprecated, " - "replaced with '%s'. Fix your input.conf!\n", old_name, buffer); - } - - return true; -} - -static int do_action(const m_option_t *prop_list, const char *name, - int action, void *arg, void *ctx) -{ - const char *sep; - const m_option_t *prop; - struct m_property_action_arg ka; - if ((sep = strchr(name, '/')) && sep[1]) { - int len = sep - name; - char base[len + 1]; - memcpy(base, name, len); - base[len] = 0; - prop = m_option_list_find(prop_list, base); - ka = (struct m_property_action_arg) { - .key = sep + 1, - .action = action, - .arg = arg, - }; - action = M_PROPERTY_KEY_ACTION; - arg = &ka; - } else - prop = m_option_list_find(prop_list, name); - if (!prop) - return M_PROPERTY_UNKNOWN; - int (*control)(const m_option_t*, int, void*, void*) = prop->p; - int r = control(prop, action, arg, ctx); - if (action == M_PROPERTY_GET_TYPE && r < 0 && - prop->type != &m_option_type_dummy) - { - *(struct m_option *)arg = *prop; - return M_PROPERTY_OK; - } - return r; -} - -int m_property_do(const m_option_t *prop_list, const char *in_name, - int action, void *arg, void *ctx) -{ - union m_option_value val = {0}; - int r; - - char name[64]; - if (!translate_legacy_property(in_name, name, sizeof(name))) - return M_PROPERTY_UNKNOWN; - - struct m_option opt = {0}; - r = do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx); - if (r <= 0) - return r; - assert(opt.type); - - switch (action) { - case M_PROPERTY_PRINT: { - if ((r = do_action(prop_list, name, M_PROPERTY_PRINT, arg, ctx)) >= 0) - return r; - // Fallback to m_option - if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) - return r; - char *str = m_option_pretty_print(&opt, &val); - m_option_free(&opt, &val); - *(char **)arg = str; - return str != NULL; - } - case M_PROPERTY_GET_STRING: { - if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) - return r; - char *str = m_option_print(&opt, &val); - m_option_free(&opt, &val); - *(char **)arg = str; - return str != NULL; - } - case M_PROPERTY_SET_STRING: { - // (reject 0 return value: success, but empty string with flag) - if (m_option_parse(&opt, bstr0(name), bstr0(arg), &val) <= 0) - return M_PROPERTY_ERROR; - r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx); - m_option_free(&opt, &val); - return r; - } - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sarg = arg; - if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) != - M_PROPERTY_NOT_IMPLEMENTED) - return r; - // Fallback to m_option - if (!opt.type->add) - return M_PROPERTY_NOT_IMPLEMENTED; - if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) - return r; - opt.type->add(&opt, &val, sarg->inc, sarg->wrap); - r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx); - m_option_free(&opt, &val); - return r; - } - case M_PROPERTY_SET: { - if (!opt.type->clamp) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, "Property '%s' without clamp().\n", - name); - } else { - m_option_copy(&opt, &val, arg); - r = opt.type->clamp(&opt, arg); - m_option_free(&opt, &val); - if (r != 0) { - mp_msg(MSGT_CPLAYER, MSGL_ERR, - "Property '%s': invalid value.\n", name); - return M_PROPERTY_ERROR; - } - } - return do_action(prop_list, name, M_PROPERTY_SET, arg, ctx); - } - default: - return do_action(prop_list, name, action, arg, ctx); - } -} - -static int m_property_do_bstr(const m_option_t *prop_list, bstr name, - int action, void *arg, void *ctx) -{ - char name0[64]; - if (name.len >= sizeof(name0)) - return M_PROPERTY_UNKNOWN; - snprintf(name0, sizeof(name0), "%.*s", BSTR_P(name)); - return m_property_do(prop_list, name0, action, arg, ctx); -} - -static void append_str(char **s, int *len, bstr append) -{ - MP_TARRAY_GROW(NULL, *s, *len + append.len); - memcpy(*s + *len, append.start, append.len); - *len = *len + append.len; -} - -char *m_properties_expand_string(const m_option_t *prop_list, char *str0, - void *ctx) -{ - char *ret = NULL; - int ret_len = 0; - bool skip = false; - int level = 0, skip_level = 0; - bstr str = bstr0(str0); - - while (str.len) { - if (level > 0 && bstr_eatstart0(&str, "}")) { - if (skip && level <= skip_level) - skip = false; - level--; - } else if (bstr_startswith0(str, "${") && bstr_find0(str, "}") >= 0) { - str = bstr_cut(str, 2); - level++; - - // Assume ":" and "}" can't be part of the property name - // => if ":" comes before "}", it must be for the fallback - int term_pos = bstrcspn(str, ":}"); - bstr name = bstr_splice(str, 0, term_pos < 0 ? str.len : term_pos); - str = bstr_cut(str, term_pos); - bool have_fallback = bstr_eatstart0(&str, ":"); - - if (!skip) { - bool cond_yes = bstr_eatstart0(&name, "?"); - bool cond_no = !cond_yes && bstr_eatstart0(&name, "!"); - bool raw = bstr_eatstart0(&name, "="); - int method = (raw || cond_yes || cond_no) - ? M_PROPERTY_GET_STRING : M_PROPERTY_PRINT; - - char *s = NULL; - int r = m_property_do_bstr(prop_list, name, method, &s, ctx); - if (cond_yes || cond_no) { - skip = (!!s != cond_yes); - } else { - skip = !!s; - char *append = s; - if (!s && !have_fallback && !raw) { - append = r == M_PROPERTY_UNAVAILABLE - ? "(unavailable)" : "(error)"; - } - append_str(&ret, &ret_len, bstr0(append)); - } - talloc_free(s); - if (skip) - skip_level = level; - } - } else if (level == 0 && bstr_eatstart0(&str, "$>")) { - append_str(&ret, &ret_len, str); - break; - } else { - char c; - - // Other combinations, e.g. "$x", are added verbatim - if (bstr_eatstart0(&str, "$$")) { - c = '$'; - } else if (bstr_eatstart0(&str, "$}")) { - c = '}'; - } else { - c = str.start[0]; - str = bstr_cut(str, 1); - } - - if (!skip) - MP_TARRAY_APPEND(NULL, ret, ret_len, c); - } - } - - MP_TARRAY_APPEND(NULL, ret, ret_len, '\0'); - return ret; -} - -void m_properties_print_help_list(const m_option_t *list) -{ - char min[50], max[50]; - int i, count = 0; - - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, - "\n Name Type Min Max\n\n"); - for (i = 0; list[i].name; i++) { - const m_option_t *opt = &list[i]; - if (opt->flags & M_OPT_MIN) - sprintf(min, "%-8.0f", opt->min); - else - strcpy(min, "No"); - if (opt->flags & M_OPT_MAX) - sprintf(max, "%-8.0f", opt->max); - else - strcpy(max, "No"); - mp_msg(MSGT_CFGPARSER, MSGL_INFO, - " %-20.20s %-15.15s %-10.10s %-10.10s\n", - opt->name, - opt->type->name, - min, - max); - count++; - } - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count); -} - -int m_property_int_ro(const m_option_t *prop, int action, - void *arg, int var) -{ - if (action == M_PROPERTY_GET) { - *(int *)arg = var; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_int64_ro(const struct m_option* prop, int action, void* arg, - int64_t var) -{ - if (action == M_PROPERTY_GET) { - *(int64_t *)arg = var; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_float_ro(const m_option_t *prop, int action, - void *arg, float var) -{ - if (action == M_PROPERTY_GET) { - *(float *)arg = var; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_double_ro(const m_option_t *prop, int action, - void *arg, double var) -{ - if (action == M_PROPERTY_GET) { - *(double *)arg = var; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_strdup_ro(const struct m_option* prop, int action, void* arg, - const char *var) -{ - if (action == M_PROPERTY_GET) { - if (!var) - return M_PROPERTY_UNAVAILABLE; - *(char **)arg = talloc_strdup(NULL, var); - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} diff --git a/core/m_property.h b/core/m_property.h deleted file mode 100644 index b471b94ecd..0000000000 --- a/core/m_property.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_M_PROPERTY_H -#define MPLAYER_M_PROPERTY_H - -#include -#include - -struct m_option; - -extern const struct m_option_type m_option_type_dummy; - -enum mp_property_action { - // Get the property type. This defines the fundamental data type read from - // or written to the property. - // If unimplemented, the m_option entry that defines the property is used. - // arg: m_option* - M_PROPERTY_GET_TYPE, - - // Get the current value. - // arg: pointer to a variable of the type according to the property type - M_PROPERTY_GET, - - // Set a new value. The property wrapper will make sure that only valid - // values are set (e.g. according to the property type's min/max range). - // If unimplemented, the property is read-only. - // arg: pointer to a variable of the type according to the property type - M_PROPERTY_SET, - - // Get human readable string representing the current value. - // If unimplemented, the property wrapper uses the property type as - // fallback. - // arg: char** - M_PROPERTY_PRINT, - - // Switch the property up/down by a given value. - // If unimplemented, the property wrapper uses the property type as - // fallback. - // arg: struct m_property_switch_arg* - M_PROPERTY_SWITCH, - - // Get a string containing a parsable representation. - // Can't be overridden by property implementations. - // arg: char** - M_PROPERTY_GET_STRING, - - // Set a new value from a string. The property wrapper parses this using the - // parse function provided by the property type. - // Can't be overridden by property implementations. - // arg: char* - M_PROPERTY_SET_STRING, - - // Pass down an action to a sub-property. - // arg: struct m_property_action_arg* - M_PROPERTY_KEY_ACTION, -}; - -// Argument for M_PROPERTY_SWITCH -struct m_property_switch_arg { - double inc; // value to add to property, or cycle direction - bool wrap; // whether value should wrap around on over/underflow -}; - -// Argument for M_PROPERTY_KEY_ACTION -struct m_property_action_arg { - const char* key; - int action; - void* arg; -}; - -enum mp_property_return { - // Returned on success. - M_PROPERTY_OK = 1, - - // Returned on error. - M_PROPERTY_ERROR = 0, - - // Returned when the property can't be used, for example video related - // properties while playing audio only. - M_PROPERTY_UNAVAILABLE = -1, - - // Returned if the requested action is not implemented. - M_PROPERTY_NOT_IMPLEMENTED = -2, - - // Returned when asking for a property that doesn't exist. - M_PROPERTY_UNKNOWN = -3, -}; - -// Access a property. -// action: one of m_property_action -// ctx: opaque value passed through to property implementation -// returns: one of mp_property_return -int m_property_do(const struct m_option* prop_list, const char* property_name, - int action, void* arg, void *ctx); - -// Print a list of properties. -void m_properties_print_help_list(const struct m_option* list); - -// Expand a property string. -// This function allows to print strings containing property values. -// ${NAME} is expanded to the value of property NAME. -// If NAME starts with '=', use the raw value of the property. -// ${NAME:STR} expands to the property, or STR if the property is not -// available. -// ${?NAME:STR} expands to STR if the property is available. -// ${!NAME:STR} expands to STR if the property is not available. -// General syntax: "${" ["?" | "!"] ["="] NAME ":" STR "}" -// STR is recursively expanded using the same rules. -// "$$" can be used to escape "$", and "$}" to escape "}". -// "$>" disables parsing of "$" for the rest of the string. -char* m_properties_expand_string(const struct m_option* prop_list, char *str, - void *ctx); - -// Trivial helpers for implementing properties. -int m_property_int_ro(const struct m_option* prop, int action, void* arg, - int var); -int m_property_int64_ro(const struct m_option* prop, int action, void* arg, - int64_t var); -int m_property_float_ro(const struct m_option* prop, int action, void* arg, - float var); -int m_property_double_ro(const struct m_option* prop, int action, void* arg, - double var); -int m_property_strdup_ro(const struct m_option* prop, int action, void* arg, - const char *var); - -#endif /* MPLAYER_M_PROPERTY_H */ diff --git a/core/mp_common.c b/core/mp_common.c deleted file mode 100644 index 03e3e988fd..0000000000 --- a/core/mp_common.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include "talloc.h" -#include "core/bstr.h" -#include "core/mp_common.h" - -char *mp_format_time(double time, bool fractions) -{ - if (time == MP_NOPTS_VALUE) - return talloc_strdup(NULL, "unknown"); - char sign[2] = {0}; - if (time < 0) { - time = -time; - sign[0] = '-'; - } - long long int itime = time; - long long int h, m, s; - s = itime; - h = s / 3600; - s -= h * 3600; - m = s / 60; - s -= m * 60; - char *res = talloc_asprintf(NULL, "%s%02lld:%02lld:%02lld", sign, h, m, s); - if (fractions) - res = talloc_asprintf_append(res, ".%03d", - (int)((time - itime) * 1000)); - return res; -} - -// Set rc to the union of rc and rc2 -void mp_rect_union(struct mp_rect *rc, const struct mp_rect *rc2) -{ - rc->x0 = FFMIN(rc->x0, rc2->x0); - rc->y0 = FFMIN(rc->y0, rc2->y0); - rc->x1 = FFMAX(rc->x1, rc2->x1); - rc->y1 = FFMAX(rc->y1, rc2->y1); -} - -// Set rc to the intersection of rc and src. -// Return false if the result is empty. -bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2) -{ - rc->x0 = FFMAX(rc->x0, rc2->x0); - rc->y0 = FFMAX(rc->y0, rc2->y0); - rc->x1 = FFMIN(rc->x1, rc2->x1); - rc->y1 = FFMIN(rc->y1, rc2->y1); - - return rc->x1 > rc->x0 && rc->y1 > rc->y0; -} - -// Encode the unicode codepoint as UTF-8, and append to the end of the -// talloc'ed buffer. -char *mp_append_utf8_buffer(char *buffer, uint32_t codepoint) -{ - char data[8]; - uint8_t tmp; - char *output = data; - PUT_UTF8(codepoint, tmp, *output++ = tmp;); - return talloc_strndup_append_buffer(buffer, data, output - data); -} - -// Parse a C-style escape beginning at code, and append the result to *str -// using talloc. The input string (*code) must point to the first character -// after the initial '\', and after parsing *code is set to the first character -// after the current escape. -// On error, false is returned, and all input remains unchanged. -bool mp_parse_escape(bstr *code, char **str) -{ - if (code->len < 1) - return false; - char replace = 0; - switch (code->start[0]) { - case '"': replace = '"'; break; - case '\\': replace = '\\'; break; - case 'b': replace = '\b'; break; - case 'f': replace = '\f'; break; - case 'n': replace = '\n'; break; - case 'r': replace = '\r'; break; - case 't': replace = '\t'; break; - case 'e': replace = '\x1b'; break; - case '\'': replace = '\''; break; - } - if (replace) { - *str = talloc_strndup_append_buffer(*str, &replace, 1); - *code = bstr_cut(*code, 1); - return true; - } - if (code->start[0] == 'x' && code->len >= 3) { - bstr num = bstr_splice(*code, 1, 3); - char c = bstrtoll(num, &num, 16); - if (!num.len) - return false; - *str = talloc_strndup_append_buffer(*str, &c, 1); - *code = bstr_cut(*code, 3); - return true; - } - if (code->start[0] == 'u' && code->len >= 5) { - bstr num = bstr_splice(*code, 1, 5); - int c = bstrtoll(num, &num, 16); - if (num.len) - return false; - *str = mp_append_utf8_buffer(*str, c); - *code = bstr_cut(*code, 5); - return true; - } - return false; -} diff --git a/core/mp_common.h b/core/mp_common.h deleted file mode 100644 index 71e24604ec..0000000000 --- a/core/mp_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MPCOMMON_H -#define MPLAYER_MPCOMMON_H - -#include -#include -#include - -#include "compat/compiler.h" -#include "core/mp_talloc.h" - -// both int64_t and double should be able to represent this exactly -#define MP_NOPTS_VALUE (-1LL<<63) - -#define MP_CONCAT_(a, b) a ## b -#define MP_CONCAT(a, b) MP_CONCAT_(a, b) - -#define ROUND(x) ((int)((x) < 0 ? (x) - 0.5 : (x) + 0.5)) - -#define MPMAX(a, b) ((a) > (b) ? (a) : (b)) -#define MPMIN(a, b) ((a) > (b) ? (b) : (a)) -#define MP_ARRAY_SIZE(s) (sizeof(s) / sizeof((s)[0])) - -#define CONTROL_OK 1 -#define CONTROL_TRUE 1 -#define CONTROL_FALSE 0 -#define CONTROL_UNKNOWN -1 -#define CONTROL_ERROR -2 -#define CONTROL_NA -3 - -extern const char *mplayer_version; -extern const char *mplayer_builddate; - -char *mp_format_time(double time, bool fractions); - -struct mp_rect { - int x0, y0; - int x1, y1; -}; - -void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src); -bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2); - -char *mp_append_utf8_buffer(char *buffer, uint32_t codepoint); - -struct bstr; -bool mp_parse_escape(struct bstr *code, char **str); - -#endif /* MPLAYER_MPCOMMON_H */ diff --git a/core/mp_core.h b/core/mp_core.h deleted file mode 100644 index 126c646a0b..0000000000 --- a/core/mp_core.h +++ /dev/null @@ -1,343 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MP_CORE_H -#define MPLAYER_MP_CORE_H - -#include - -#include "core/options.h" -#include "audio/mixer.h" -#include "demux/demux.h" - -// definitions used internally by the core player code - -#define INITIALIZED_VO 1 -#define INITIALIZED_AO 2 -#define INITIALIZED_VOL 4 -#define INITIALIZED_GETCH2 8 -#define INITIALIZED_STREAM 64 -#define INITIALIZED_DEMUXER 512 -#define INITIALIZED_ACODEC 1024 -#define INITIALIZED_VCODEC 2048 -#define INITIALIZED_SUB 4096 -#define INITIALIZED_ALL 0xFFFF - - -enum stop_play_reason { - KEEP_PLAYING = 0, // must be 0, numeric values of others do not matter - AT_END_OF_FILE, // file has ended normally, prepare to play next - PT_NEXT_ENTRY, // prepare to play next entry in playlist - PT_CURRENT_ENTRY, // prepare to play mpctx->playlist->current - PT_STOP, // stop playback, clear playlist - PT_RESTART, // restart previous file - PT_QUIT, // stop playback, quit player -}; - -enum exit_reason { - EXIT_NONE, - EXIT_QUIT, - EXIT_PLAYED, - EXIT_ERROR, - EXIT_NOTPLAYED, - EXIT_SOMENOTPLAYED -}; - -struct timeline_part { - double start; - double source_start; - struct demuxer *source; -}; - -struct chapter { - double start; - char *name; -}; - -enum mp_osd_seek_info { - OSD_SEEK_INFO_BAR = 1, - OSD_SEEK_INFO_TEXT = 2, - OSD_SEEK_INFO_CHAPTER_TEXT = 4, - OSD_SEEK_INFO_EDITION = 8, -}; - -struct track { - enum stream_type type; - // The type specific ID, also called aid (audio), sid (subs), vid (video). - // For UI purposes only; this ID doesn't have anything to do with any - // IDs coming from demuxers or container files. - int user_tid; - - // Same as stream->demuxer_id. -1 if not set. - int demuxer_id; - - char *title; - bool default_track; - bool attached_picture; - char *lang; - - // If this track is from an external file (e.g. subtitle file). - bool is_external; - char *external_filename; - bool auto_loaded; - - // If the track's stream changes with the timeline (ordered chapters). - bool under_timeline; - - // NULL if not backed by a demuxer (e.g. external subtitles). - // Value can change if under_timeline==true. - struct demuxer *demuxer; - // Invariant: (!demuxer && !stream) || stream->demuxer == demuxer - struct sh_stream *stream; - - // For external subtitles, which are read fully on init. Do not attempt - // to read packets from them. - bool preloaded; -}; - -enum { - MAX_NUM_VO_PTS = 100, -}; - -typedef struct MPContext { - struct mpv_global *global; - struct MPOpts *opts; - struct mp_log *log; - struct m_config *mconfig; - struct input_ctx *input; - struct osd_state *osd; - struct mp_osd_msg *osd_msg_stack; - char *terminal_osd_text; - - int add_osd_seek_info; // bitfield of enum mp_osd_seek_info - double osd_visible; // for the osd bar only - int osd_function; - double osd_function_visible; - double osd_last_update; - - struct playlist *playlist; - char *filename; // currently playing file - struct mp_resolve_result *resolve_result; - enum stop_play_reason stop_play; - unsigned int initialized_flags; // which subsystems have been initialized - - // Return code to use with PT_QUIT - enum exit_reason quit_player_rc; - int quit_custom_rc; - bool has_quit_custom_rc; - bool error_playing; - - struct demuxer **sources; - int num_sources; - - struct timeline_part *timeline; - int num_timeline_parts; - int timeline_part; - // NOTE: even if num_chapters==0, chapters being not NULL signifies presence - // of chapter metadata - struct chapter *chapters; - int num_chapters; - double video_offset; - - struct stream *stream; - struct demuxer *demuxer; - - struct track **tracks; - int num_tracks; - - // Selected tracks. NULL if no track selected. - struct track *current_track[STREAM_TYPE_COUNT]; - - struct sh_stream *sh[STREAM_TYPE_COUNT]; - struct sh_audio *sh_audio; // same as sh[STREAM_AUDIO]->audio - struct sh_video *sh_video; // same as sh[STREAM_VIDEO]->video - struct sh_sub *sh_sub; // same as sh[STREAM_SUB]->sub - - // Uses: accessing metadata (consider ordered chapters case, where the main - // demuxer defines metadata), or special purpose demuxers like TV. - struct demuxer *master_demuxer; - - mixer_t mixer; - struct ao *ao; - struct vo *video_out; - - /* We're starting playback from scratch or after a seek. Show first - * video frame immediately and reinitialize sync. */ - bool restart_playback; - /* Set if audio should be timed to start with video frame after seeking, - * not set when e.g. playing cover art */ - bool sync_audio_to_video; - /* After playback restart (above) or audio stream change, adjust audio - * stream by cutting samples or adding silence at the beginning to make - * audio playback position match video position. */ - bool syncing_audio; - bool hrseek_active; - bool hrseek_framedrop; - double hrseek_pts; - // AV sync: the next frame should be shown when the audio out has this - // much (in seconds) buffered data left. Increased when more data is - // written to the ao, decreased when moving to the next frame. - // In the audio-only case used as a timer since the last seek - // by the audio CPU usage meter. - double delay; - // AV sync: time until next frame should be shown - double time_frame; - // How long the last vo flip() call took. Used to adjust timing with - // the goal of making flip() calls finish (rather than start) at the - // specified time. - double last_vo_flip_duration; - // How much video timing has been changed to make it match the audio - // timeline. Used for status line information only. - double total_avsync_change; - // Total number of dropped frames that were "approved" to be dropped. - // Actual dropping depends on --framedrop and decoder internals. - int drop_frame_cnt; - // Number of frames dropped in a row. - int dropped_frames; - // A-V sync difference when last frame was displayed. Kept to display - // the same value if the status line is updated at a time where no new - // video frame is shown. - double last_av_difference; - /* timestamp of video frame currently visible on screen - * (or at least queued to be flipped by VO) */ - double video_pts; - double last_seek_pts; - // As video_pts, but is not reset when seeking away. (For the very short - // period of time until a new frame is decoded and shown.) - double last_vo_pts; - // Video PTS, or audio PTS if video has ended. - double playback_pts; - - // History of video frames timestamps that were queued in the VO - // This includes even skipped frames during hr-seek - double vo_pts_history_pts[MAX_NUM_VO_PTS]; - // Whether the PTS at vo_pts_history[n] is after a seek reset - uint64_t vo_pts_history_seek[MAX_NUM_VO_PTS]; - uint64_t vo_pts_history_seek_ts; - uint64_t backstep_start_seek_ts; - bool backstep_active; - - double audio_delay; - - double last_heartbeat; - double last_metadata_update; - - double mouse_timer; - unsigned int mouse_event_ts; - int mouse_waiting_hide; - - // used to prevent hanging in some error cases - double start_timestamp; - - // Timestamp from the last time some timing functions read the - // current time, in (occasionally wrapping) microseconds. Used - // to turn a new time value to a delta from last time. - int64_t last_time; - - // Used to communicate the parameters of a seek between parts - struct seek_params { - enum seek_type { - MPSEEK_NONE, MPSEEK_RELATIVE, MPSEEK_ABSOLUTE, MPSEEK_FACTOR - } type; - double amount; - int exact; // -1 = disable, 0 = default, 1 = enable - // currently not set by commands, only used internally by seek() - int direction; // -1 = backward, 0 = default, 1 = forward - } seek; - - /* Heuristic for relative chapter seeks: keep track which chapter - * the user wanted to go to, even if we aren't exactly within the - * boundaries of that chapter due to an inaccurate seek. */ - int last_chapter_seek; - double last_chapter_pts; - - struct ass_library *ass_library; - - int last_dvb_step; - int dvbin_reopen; - - bool paused; - // step this many frames, then pause - int step_frames; - // Counted down each frame, stop playback if 0 is reached. (-1 = disable) - int max_frames; - bool playing_msg_shown; - - bool paused_for_cache; - - // Set after showing warning about decoding being too slow for realtime - // playback rate. Used to avoid showing it multiple times. - bool drop_message_shown; - - struct screenshot_ctx *screenshot_ctx; - - char *track_layout_hash; - - struct encode_lavc_context *encode_lavc_ctx; -} MPContext; - - -// should not be global -extern FILE *edl_fd; -// These appear in options list -extern int forced_subs_only; - -void uninit_player(struct MPContext *mpctx, unsigned int mask); -void reinit_audio_chain(struct MPContext *mpctx); -double playing_audio_pts(struct MPContext *mpctx); -struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, int noerr); -int reinit_video_chain(struct MPContext *mpctx); -int reinit_video_filters(struct MPContext *mpctx); -int reinit_audio_filters(struct MPContext *mpctx); -void pause_player(struct MPContext *mpctx); -void unpause_player(struct MPContext *mpctx); -void add_step_frame(struct MPContext *mpctx, int dir); -void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, - int exact); -bool mp_seek_chapter(struct MPContext *mpctx, int chapter); -double get_time_length(struct MPContext *mpctx); -double get_start_time(struct MPContext *mpctx); -double get_current_time(struct MPContext *mpctx); -int get_percent_pos(struct MPContext *mpctx); -double get_current_pos_ratio(struct MPContext *mpctx, bool use_range); -int get_current_chapter(struct MPContext *mpctx); -char *chapter_display_name(struct MPContext *mpctx, int chapter); -char *chapter_name(struct MPContext *mpctx, int chapter); -double chapter_start_time(struct MPContext *mpctx, int chapter); -int get_chapter_count(struct MPContext *mpctx); -void mp_switch_track(struct MPContext *mpctx, enum stream_type type, - struct track *track); -struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type, - int tid); -bool mp_remove_track(struct MPContext *mpctx, struct track *track); -struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction); -int mp_get_cache_percent(struct MPContext *mpctx); -void mp_write_watch_later_conf(struct MPContext *mpctx); -void mp_set_playlist_entry(struct MPContext *mpctx, struct playlist_entry *e); -void mp_force_video_refresh(struct MPContext *mpctx); - -void mp_print_version(int always); - -// timeline/tl_matroska.c -void build_ordered_chapter_timeline(struct MPContext *mpctx); -// timeline/tl_edl.c -void build_edl_timeline(struct MPContext *mpctx); -// timeline/tl_cue.c -void build_cue_timeline(struct MPContext *mpctx); - -#endif /* MPLAYER_MP_CORE_H */ diff --git a/core/mp_memory_barrier.h b/core/mp_memory_barrier.h deleted file mode 100644 index e27825de8f..0000000000 --- a/core/mp_memory_barrier.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of mpv. - * Copyright (c) 2013 Stefano Pigozzi - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -// At this point both gcc and clang had __sync_synchronize support for some -// time. We only support a full memory barrier. - -#define mp_memory_barrier() __sync_synchronize() -#define mp_atomic_add_and_fetch(a, b) __sync_add_and_fetch(a, b) diff --git a/core/mp_msg.c b/core/mp_msg.c deleted file mode 100644 index ff611451c2..0000000000 --- a/core/mp_msg.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "talloc.h" - -#include "config.h" -#include "core/mpv_global.h" -#include "osdep/getch2.h" -#include "osdep/io.h" - -#ifdef CONFIG_GETTEXT -#include -#include -#endif - -#ifndef __MINGW32__ -#include -#endif - -#include "core/mp_msg.h" - -bool mp_msg_stdout_in_use = 0; - -struct mp_log_root { - /* This should, at some point, contain all mp_msg related state, instead - * of having global variables (at least as long as we don't want to - * control the terminal, which is global anyway). But for now, there is - * not much. */ - struct mpv_global *global; -}; - -struct mp_log { - struct mp_log_root *root; - const char *prefix; - const char *verbose_prefix; - int legacy_mod; -}; - -// should not exist -static bool initialized; -static struct mp_log *legacy_logs[MSGT_MAX]; - -/* maximum message length of mp_msg */ -#define MSGSIZE_MAX 6144 - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE) -#define hSTDERR GetStdHandle(STD_ERROR_HANDLE) -static short stdoutAttrs = 0; -static const unsigned char ansi2win32[10] = { - 0, - FOREGROUND_RED, - FOREGROUND_GREEN, - FOREGROUND_GREEN | FOREGROUND_RED, - FOREGROUND_BLUE, - FOREGROUND_BLUE | FOREGROUND_RED, - FOREGROUND_BLUE | FOREGROUND_GREEN, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED -}; -#endif - -int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2 -int mp_msg_level_all = MSGL_STATUS; -int verbose = 0; -int mp_msg_color = 1; -int mp_msg_module = 0; -int mp_msg_cancolor = 0; - -static int mp_msg_docolor(void) { - return mp_msg_cancolor && mp_msg_color; -} - -static void mp_msg_do_init(void){ -#ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO cinfo; - DWORD cmode = 0; - GetConsoleMode(hSTDOUT, &cmode); - cmode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); - SetConsoleMode(hSTDOUT, cmode); - SetConsoleMode(hSTDERR, cmode); - GetConsoleScreenBufferInfo(hSTDOUT, &cinfo); - stdoutAttrs = cinfo.wAttributes; -#endif -#ifndef __MINGW32__ - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(SIGTTOU, &sa, NULL); // just write to stdout if you have to -#endif - int i; - char *env = getenv("MPV_VERBOSE"); - if (env) - verbose = atoi(env); - for(i=0;ilegacy_mod, lev); -} - -static void set_msg_color(FILE* stream, int lev) -{ - static const int v_colors[10] = {9, 1, 3, 3, -1, -1, 2, 8, 8, 8}; - int c = v_colors[lev]; -#ifdef MP_ANNOY_ME - /* that's only a silly color test */ - { - int c; - static int flag = 1; - if (flag) - for(c = 0; c < 24; c++) - printf("\033[%d;3%dm*** COLOR TEST %d ***\n", c>7, c&7, c); - flag = 0; - } -#endif - if (mp_msg_docolor()) - { -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT; - if (c == -1) - c = 7; - SetConsoleTextAttribute(wstream, ansi2win32[c] | FOREGROUND_INTENSITY); -#else - if (c == -1) { - fprintf(stream, "\033[0m"); - } else { - fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7); - } -#endif - } -} - -static void print_msg_module(FILE* stream, struct mp_log *log) -{ - int mod = log->legacy_mod; - int c2 = (mod + 1) % 15 + 1; - -#ifdef _WIN32 - HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT; - if (mp_msg_docolor()) - SetConsoleTextAttribute(wstream, ansi2win32[c2&7] | FOREGROUND_INTENSITY); - fprintf(stream, "%9s", log->verbose_prefix); - if (mp_msg_docolor()) - SetConsoleTextAttribute(wstream, stdoutAttrs); -#else - if (mp_msg_docolor()) - fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7); - fprintf(stream, "%9s", log->verbose_prefix); - if (mp_msg_docolor()) - fprintf(stream, "\033[0;37m"); -#endif - fprintf(stream, ": "); -} - -static void mp_msg_log_va(struct mp_log *log, int lev, const char *format, - va_list va) -{ - char tmp[MSGSIZE_MAX]; - FILE *stream = - (mp_msg_stdout_in_use || (lev == MSGL_STATUS)) ? stderr : stdout; - static int header = 1; - // indicates if last line printed was a status line - static int statusline; - - if (!mp_msg_test_log(log, lev)) return; // do not display - vsnprintf(tmp, MSGSIZE_MAX, format, va); - tmp[MSGSIZE_MAX-2] = '\n'; - tmp[MSGSIZE_MAX-1] = 0; - - /* A status line is normally intended to be overwritten by the next - * status line, and does not end with a '\n'. If we're printing a normal - * line instead after the status one print '\n' to change line. */ - if (statusline && lev != MSGL_STATUS) - fprintf(stderr, "\n"); - statusline = lev == MSGL_STATUS; - - set_msg_color(stream, lev); - if (header) { - if (mp_msg_module) { - print_msg_module(stream, log); - set_msg_color(stream, lev); - } else if (lev >= MSGL_V || verbose) { - fprintf(stream, "[%s] ", log->verbose_prefix); - } else if (log->prefix) { - fprintf(stream, "[%s] ", log->prefix); - } - } - - size_t len = strlen(tmp); - header = len && (tmp[len-1] == '\n' || tmp[len-1] == '\r'); - - fprintf(stream, "%s", tmp); - - if (mp_msg_docolor()) - { -#ifdef _WIN32 - HANDLE *wstream = lev <= MSGL_WARN ? hSTDERR : hSTDOUT; - SetConsoleTextAttribute(wstream, stdoutAttrs); -#else - fprintf(stream, "\033[0m"); -#endif - } - fflush(stream); -} - -void mp_msg_va(int mod, int lev, const char *format, va_list va) -{ - assert(initialized); - assert(mod >= 0 && mod < MSGT_MAX); - mp_msg_log_va(legacy_logs[mod], lev, format, va); -} - -void mp_msg(int mod, int lev, const char *format, ...) -{ - va_list va; - va_start(va, format); - mp_msg_va(mod, lev, format, va); - va_end(va); -} - -char *mp_gtext(const char *string) -{ -#ifdef CONFIG_GETTEXT - /* gettext expects the global locale to be set with - * setlocale(LC_ALL, ""). However doing that would suck for a - * couple of reasons (locale stuff is badly designed and sucks in - * general). - * - * First, setting the locale, especially LC_CTYPE, changes the - * behavior of various C functions and we don't want that - we - * want isalpha() for example to always behave like in the C - * locale. - - * Second, there is no way to enforce a sane character set. All - * strings inside MPlayer must always be in utf-8, not in the - * character set specified by the system locale which could be - * something different and completely insane. The locale system - * lacks any way to say "set LC_CTYPE to utf-8, ignoring the - * default system locale if it specifies something different". We - * could try to work around that flaw by leaving LC_CTYPE to the C - * locale and only setting LC_MESSAGES (which is the variable that - * must be set to tell gettext which language to translate - * to). However if we leave LC_MESSAGES set then things like - * strerror() may produce completely garbled output when they try - * to translate their results but then try to convert some - * translated non-ASCII text to the character set specified by - * LC_CTYPE which would still be in the C locale (this doesn't - * affect gettext itself because it supports specifying the - * character set directly with bind_textdomain_codeset()). - * - * So the only solution (at least short of trying to work around - * things possibly producing non-utf-8 output) is to leave all the - * locale variables unset. Note that this means it's not possible - * to get translated output from any libraries we call if they - * only rely on the broken locale system to specify the language - * to use; this is the case with libc for example. - * - * The locale changing below is rather ugly, but hard to avoid. - * gettext doesn't support specifying the translation target - * directly, only through locale. - * The main actual problem this could cause is interference with - * other threads; that could be avoided with thread-specific - * locale changes, but such functionality is less standard and I - * think it's not worth adding pre-emptively unless someone sees - * an actual problem case. - */ - setlocale(LC_MESSAGES, ""); - string = gettext(string); - setlocale(LC_MESSAGES, "C"); -#endif - return (char *)string; -} - -void mp_tmsg(int mod, int lev, const char *format, ...) -{ - va_list va; - va_start(va, format); - mp_msg_va(mod, lev, mp_gtext(format), va); - va_end(va); -} - -// legacy names -static const char *module_text[MSGT_MAX] = { - "global", - "cplayer", - "gplayer", - "vo", - "ao", - "demuxer", - "ds", - "demux", - "header", - "avsync", - "autoq", - "cfgparser", - "decaudio", - "decvideo", - "seek", - "win32", - "open", - "dvd", - "parsees", - "lirc", - "stream", - "cache", - "mencoder", - "xacodec", - "tv", - "osdep", - "spudec", - "playtree", - "input", - "vf", - "osd", - "network", - "cpudetect", - "codeccfg", - "sws", - "vobsub", - "subreader", - "af", - "netst", - "muxer", - "osdmenu", - "identify", - "radio", - "ass", - "loader", - "statusline", - "teletext", -}; - -// Create a new log context, which uses talloc_ctx as talloc parent, and parent -// as logical parent. -// The name is the prefix put before the output. It's usually prefixed by the -// parent's name. If the name starts with "/", the parent's name is not -// prefixed (except in verbose mode), and if it starts with "!", the name is -// not printed at all (except in verbose mode). -struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, - const char *name) -{ - assert(parent); - assert(name); - struct mp_log *log = talloc_zero(talloc_ctx, struct mp_log); - log->root = parent->root; - if (name[0] == '!') { - name = &name[1]; - } else if (name[0] == '/') { - name = &name[1]; - log->prefix = talloc_strdup(log, name); - } else { - log->prefix = parent->prefix - ? talloc_asprintf(log, "%s/%s", parent->prefix, name) - : talloc_strdup(log, name); - } - log->verbose_prefix = parent->prefix - ? talloc_asprintf(log, "%s/%s", parent->prefix, name) - : talloc_strdup(log, name); - if (log->prefix && !log->prefix[0]) - log->prefix = NULL; - if (!log->verbose_prefix[0]) - log->verbose_prefix = "global"; - log->legacy_mod = parent->legacy_mod; - for (int n = 0; n < MSGT_MAX; n++) { - if (module_text[n] && strcmp(name, module_text[n]) == 0) { - log->legacy_mod = n; - break; - } - } - return log; -} - -void mp_msg_init(struct mpv_global *global) -{ - assert(!initialized); - assert(!global->log); - - struct mp_log_root *root = talloc_zero(NULL, struct mp_log_root); - root->global = global; - - struct mp_log dummy = { .root = root }; - struct mp_log *log = mp_log_new(root, &dummy, ""); - for (int n = 0; n < MSGT_MAX; n++) { - char name[80]; - snprintf(name, sizeof(name), "!%s", module_text[n]); - legacy_logs[n] = mp_log_new(root, log, name); - } - mp_msg_do_init(); - - global->log = log; - initialized = true; -} - -struct mpv_global *mp_log_get_global(struct mp_log *log) -{ - return log->root->global; -} - -void mp_msg_uninit(struct mpv_global *global) -{ - talloc_free(global->log->root); - global->log = NULL; - initialized = false; -} - -void mp_msg_log(struct mp_log *log, int lev, const char *format, ...) -{ - va_list va; - va_start(va, format); - mp_msg_log_va(log, lev, format, va); - va_end(va); -} - -void mp_tmsg_log(struct mp_log *log, int lev, const char *format, ...) -{ - va_list va; - va_start(va, format); - mp_msg_log_va(log, lev, mp_gtext(format), va); - va_end(va); -} diff --git a/core/mp_msg.h b/core/mp_msg.h deleted file mode 100644 index 4685668f01..0000000000 --- a/core/mp_msg.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MP_MSG_H -#define MPLAYER_MP_MSG_H - -#include -#include - -struct mp_log; - -// defined in mplayer.c -extern int verbose; - -/* No-op macro to mark translated strings in the sources */ -#define _(x) x - -// verbosity elevel: - -/* Only messages level MSGL_FATAL-MSGL_STATUS should be translated, - * messages level MSGL_V and above should not be translated. */ - -#define MSGL_FATAL 0 // will exit/abort -#define MSGL_ERR 1 // continues -#define MSGL_WARN 2 // only warning -#define MSGL_HINT 3 // short help message -#define MSGL_INFO 4 // -quiet -#define MSGL_STATUS 5 // v=0 -#define MSGL_V 6 // v=1 -#define MSGL_DBG2 7 // v=2 -#define MSGL_DBG3 8 // v=3 -#define MSGL_DBG4 9 // v=4 -#define MSGL_DBG5 10 // v=5 - -#define MSGL_FIXME 1 // for conversions from printf where the appropriate MSGL is not known; set equal to ERR for obtrusiveness -#define MSGT_FIXME 0 // for conversions from printf where the appropriate MSGT is not known; set equal to GLOBAL for obtrusiveness - -// code/module: - -#define MSGT_GLOBAL 0 // common player stuff errors -#define MSGT_CPLAYER 1 // console player (mplayer.c) - -#define MSGT_VO 3 // libvo -#define MSGT_AO 4 // libao - -#define MSGT_DEMUXER 5 // demuxer.c (general stuff) -#define MSGT_DS 6 // demux stream (add/read packet etc) -#define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c) -#define MSGT_HEADER 8 // fileformat-specific header (*header.c) - -#define MSGT_AVSYNC 9 // mplayer.c timer stuff -#define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff - -#define MSGT_CFGPARSER 11 // cfgparser.c - -#define MSGT_DECAUDIO 12 // av decoder -#define MSGT_DECVIDEO 13 - -#define MSGT_SEEK 14 // seeking code -#define MSGT_WIN32 15 // win32 dll stuff -#define MSGT_OPEN 16 // open.c (stream opening) -#define MSGT_DVD 17 // open.c (DVD init/read/seek) - -#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) -#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver - -#define MSGT_STREAM 20 // stream.c -#define MSGT_CACHE 21 // cache2.c - -#define MSGT_ENCODE 22 // now encode_lavc.c - -#define MSGT_XACODEC 23 // XAnim codecs - -#define MSGT_TV 24 // TV input subsystem - -#define MSGT_OSDEP 25 // OS-dependent parts - -#define MSGT_SPUDEC 26 // spudec.c - -#define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c) - -#define MSGT_INPUT 28 - -#define MSGT_VFILTER 29 - -#define MSGT_OSD 30 - -#define MSGT_NETWORK 31 - -#define MSGT_CPUDETECT 32 - -#define MSGT_CODECCFG 33 - -#define MSGT_SWS 34 - -#define MSGT_VOBSUB 35 -#define MSGT_SUBREADER 36 - -#define MSGT_AFILTER 37 // Audio filter messages - -#define MSGT_NETST 38 // Netstream - -#define MSGT_MUXER 39 // muxer layer - -#define MSGT_IDENTIFY 41 // -identify output - -#define MSGT_RADIO 42 - -#define MSGT_ASS 43 // libass messages - -#define MSGT_LOADER 44 // dll loader messages - -#define MSGT_STATUSLINE 45 // playback/encoding status line - -#define MSGT_TELETEXT 46 // Teletext decoder - -#define MSGT_MAX 47 - -int mp_msg_test(int mod, int lev); -bool mp_msg_test_log(struct mp_log *log, int lev); - -#include "config.h" -#include "core/mp_common.h" - -char *mp_gtext(const char *string); - -void mp_msg_va(int mod, int lev, const char *format, va_list va); - -void mp_msg(int mod, int lev, const char *format, ... ) PRINTF_ATTRIBUTE(3, 4); -void mp_tmsg(int mod, int lev, const char *format, ... ) PRINTF_ATTRIBUTE(3, 4); -#define mp_dbg mp_msg - -struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, - const char *name); - -void mp_msg_log(struct mp_log *log, int lev, const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); -void mp_tmsg_log(struct mp_log *log, int lev, const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); - -// Convenience macros, typically called with a pointer to a context struct -// as first argument, which has a "struct mp_log log;" member. - -#define MP_MSG(obj, lev, ...) mp_msg_log((obj)->log, lev, __VA_ARGS__) -#define MP_MSGT(obj, lev, ...) mp_msgt_log((obj)->log, lev, __VA_ARGS__) - -#define MP_FATAL(obj, ...) MP_MSG(obj, MSGL_FATAL, __VA_ARGS__) -#define MP_ERR(obj, ...) MP_MSG(obj, MSGL_ERR, __VA_ARGS__) -#define MP_WARN(obj, ...) MP_MSG(obj, MSGL_WARN, __VA_ARGS__) -#define MP_INFO(obj, ...) MP_MSG(obj, MSGL_INFO, __VA_ARGS__) -#define MP_VERBOSE(obj, ...) MP_MSG(obj, MSGL_V, __VA_ARGS__) -#define MP_DBG(obj, ...) MP_MSG(obj, MSGL_DGB2, __VA_ARGS__) -#define MP_TRACE(obj, ...) MP_MSG(obj, MSGL_DGB5, __VA_ARGS__) - -struct mpv_global; -void mp_msg_init(struct mpv_global *global); -void mp_msg_uninit(struct mpv_global *global); - -struct mpv_global *mp_log_get_global(struct mp_log *log); - -extern bool mp_msg_stdout_in_use; - -#endif /* MPLAYER_MP_MSG_H */ diff --git a/core/mp_osd.h b/core/mp_osd.h deleted file mode 100644 index 0b737f0c22..0000000000 --- a/core/mp_osd.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MP_OSD_H -#define MPLAYER_MP_OSD_H - -#include "compat/compiler.h" - -#define OSD_MSG_TEXT 1 -#define OSD_MSG_SUB_DELAY 2 -#define OSD_MSG_SPEED 3 -#define OSD_MSG_OSD_STATUS 4 -#define OSD_MSG_BAR 5 -#define OSD_MSG_PAUSE 6 -#define OSD_MSG_RADIO_CHANNEL 7 -#define OSD_MSG_TV_CHANNEL 8 -/// Base id for messages generated from the commmand to property bridge. -#define OSD_MSG_PROPERTY 0x100 -#define OSD_MSG_SUB_BASE 0x1000 - -#define MAX_OSD_LEVEL 3 -#define MAX_TERM_OSD_LEVEL 1 -#define OSD_LEVEL_INVISIBLE 4 - -#define OSD_BAR_SEEK 256 - -struct MPContext; - -void set_osd_bar(struct MPContext *mpctx, int type,const char* name,double min,double max,double val); -void set_osd_msg(struct MPContext *mpctx, int id, int level, int time, const char* fmt, ...) PRINTF_ATTRIBUTE(5,6); -void set_osd_tmsg(struct MPContext *mpctx, int id, int level, int time, const char* fmt, ...) PRINTF_ATTRIBUTE(5,6); -void rm_osd_msg(struct MPContext *mpctx, int id); - -// osd_function is the symbol appearing in the video status, such as OSD_PLAY -void set_osd_function(struct MPContext *mpctx, int osd_function); - -#endif /* MPLAYER_MP_OSD_H */ diff --git a/core/mp_ring.c b/core/mp_ring.c deleted file mode 100644 index bd94870710..0000000000 --- a/core/mp_ring.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * This file is part of mpv. - * Copyright (c) 2012 wm4 - * Copyright (c) 2013 Stefano Pigozzi - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include "talloc.h" -#include "core/mp_memory_barrier.h" -#include "core/mp_ring.h" - -struct mp_ring { - uint8_t *buffer; - - /* Positions of thes first readable/writeable chunks. Do not read this - * fields but use the atomic private accessors `mp_ring_get_wpos` - * and `mp_ring_get_rpos`. */ - uint32_t rpos, wpos; -}; - -static uint32_t mp_ring_get_wpos(struct mp_ring *buffer) -{ - mp_memory_barrier(); - return buffer->wpos; -} - -static uint32_t mp_ring_get_rpos(struct mp_ring *buffer) -{ - mp_memory_barrier(); - return buffer->rpos; -} - -struct mp_ring *mp_ring_new(void *talloc_ctx, int size) -{ - struct mp_ring *ringbuffer = - talloc_zero(talloc_ctx, struct mp_ring); - - *ringbuffer = (struct mp_ring) { - .buffer = talloc_size(talloc_ctx, size), - }; - - return ringbuffer; -} - -int mp_ring_drain(struct mp_ring *buffer, int len) -{ - int buffered = mp_ring_buffered(buffer); - int drain_len = FFMIN(len, buffered); - mp_atomic_add_and_fetch(&buffer->rpos, drain_len); - mp_memory_barrier(); - return drain_len; -} - -int mp_ring_read(struct mp_ring *buffer, unsigned char *dest, int len) -{ - if (!dest) return mp_ring_drain(buffer, len); - - int size = mp_ring_size(buffer); - int buffered = mp_ring_buffered(buffer); - int read_len = FFMIN(len, buffered); - int read_ptr = mp_ring_get_rpos(buffer) % size; - - int len1 = FFMIN(size - read_ptr, read_len); - int len2 = read_len - len1; - - memcpy(dest, buffer->buffer + read_ptr, len1); - memcpy(dest + len1, buffer->buffer, len2); - - mp_atomic_add_and_fetch(&buffer->rpos, read_len); - mp_memory_barrier(); - - return read_len; -} - -int mp_ring_read_cb(struct mp_ring *buffer, void *ctx, int len, - void (*func)(void*, void*, int)) -{ - // The point of this function is defining custom read behaviour, assume - // it's a programmers error if func is null. - assert(func); - - int size = mp_ring_size(buffer); - int buffered = mp_ring_buffered(buffer); - int read_len = FFMIN(len, buffered); - int read_ptr = mp_ring_get_rpos(buffer) % size; - - func(ctx, buffer->buffer + read_ptr, read_len); - - return mp_ring_drain(buffer, read_len); -} - -int mp_ring_write(struct mp_ring *buffer, unsigned char *src, int len) -{ - int size = mp_ring_size(buffer); - int free = mp_ring_available(buffer); - int write_len = FFMIN(len, free); - int write_ptr = mp_ring_get_wpos(buffer) % size; - - int len1 = FFMIN(size - write_ptr, write_len); - int len2 = write_len - len1; - - memcpy(buffer->buffer + write_ptr, src, len1); - memcpy(buffer->buffer, src + len1, len2); - - mp_atomic_add_and_fetch(&buffer->wpos, write_len); - mp_memory_barrier(); - - return write_len; -} - -void mp_ring_reset(struct mp_ring *buffer) -{ - buffer->wpos = buffer->rpos = 0; - mp_memory_barrier(); -} - -int mp_ring_available(struct mp_ring *buffer) -{ - return mp_ring_size(buffer) - mp_ring_buffered(buffer); -} - -int mp_ring_size(struct mp_ring *buffer) -{ - return talloc_get_size(buffer->buffer); -} - -int mp_ring_buffered(struct mp_ring *buffer) -{ - return (mp_ring_get_wpos(buffer) - mp_ring_get_rpos(buffer)); -} - -char *mp_ring_repr(struct mp_ring *buffer, void *talloc_ctx) -{ - return talloc_asprintf( - talloc_ctx, - "Ringbuffer { .size = %dB, .buffered = %dB, .available = %dB }", - mp_ring_size(buffer), - mp_ring_buffered(buffer), - mp_ring_available(buffer)); -} diff --git a/core/mp_ring.h b/core/mp_ring.h deleted file mode 100644 index ba104af625..0000000000 --- a/core/mp_ring.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of mpv. - * Copyright (c) 2012 wm4 - * Copyright (c) 2013 Stefano Pigozzi - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPV_MP_RING_H -#define MPV_MP_RING_H - -/** - * A simple non-blocking SPSC (single producer, single consumer) ringbuffer - * implementation. Thread safety is accomplished through atomic operations. - */ - -struct mp_ring; - -/** - * Instantiate a new ringbuffer - * - * talloc_ctx: talloc context of the newly created object - * size: total size in bytes - * return: the newly created ringbuffer - */ -struct mp_ring *mp_ring_new(void *talloc_ctx, int size); - -/** - * Read data from the ringbuffer - * - * buffer: target ringbuffer instance - * dest: destination buffer for the read data. If NULL read data is discarded. - * len: maximum number of bytes to read - * return: number of bytes read - */ -int mp_ring_read(struct mp_ring *buffer, unsigned char *dest, int len); - -/** - * Read data from the ringbuffer - * - * This function behaves similarly to `av_fifo_generic_read` and was actually - * added for compatibility with code that was written for it. - * This function will drain the returned amount of bytes from the ringbuffer - * so you don't have to handle that in inside `func`. - * - * buffer: target ringbuffer instance - * ctx: context for the callback function - * len: maximum number of bytes to read - * func: callback function to customize reading behaviour. It will be called - * by `mp_ring_read_cb` with the following parameters: - * ctx: context data provided to `mp_ring_read_cb` - * src: source buffer to read from - * len: the *exact* amount of bytes to read. These will be drained - * by the ring after this callback is called. - * return: number of bytes read - */ -int mp_ring_read_cb(struct mp_ring *buffer, void *ctx, int len, - void (*func)(void *ctx, void *src, int len)); - -/** - * Write data to the ringbuffer - * - * buffer: target ringbuffer instance - * src: source buffer for the write data - * len: maximum number of bytes to write - * return: number of bytes written - */ -int mp_ring_write(struct mp_ring *buffer, unsigned char *src, int len); - -/** - * Drain data from the ringbuffer - * - * buffer: target ringbuffer instance - * len: maximum number of bytes to drain - * return: number of bytes drained - */ -int mp_ring_drain(struct mp_ring *buffer, int len); - -/** - * Reset the ringbuffer discarding any content - * - * buffer: target ringbuffer instance - */ -void mp_ring_reset(struct mp_ring *buffer); - -/** - * Get the available size for writing - * - * buffer: target ringbuffer instance - * return: number of bytes that can be written - */ -int mp_ring_available(struct mp_ring *buffer); - -/** - * Get the total size - * - * buffer: target ringbuffer instance - * return: total ringbuffer size in bytes - */ -int mp_ring_size(struct mp_ring *buffer); - -/** - * Get the available size for reading - * - * buffer: target ringbuffer instance - * return: number of bytes ready for reading - */ -int mp_ring_buffered(struct mp_ring *buffer); - -/** - * Get a string representation of the ringbuffer - * - * buffer: target ringbuffer instance - * talloc_ctx: talloc context of the newly created string - * return: string representing the ringbuffer - */ -char *mp_ring_repr(struct mp_ring *buffer, void *talloc_ctx); - -#endif diff --git a/core/mp_talloc.h b/core/mp_talloc.h deleted file mode 100644 index 1dcb0bce07..0000000000 --- a/core/mp_talloc.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPV_TALLOC_H -#define MPV_TALLOC_H - -#include "talloc.h" -#include "compat/compiler.h" - -#define MP_TALLOC_ELEMS(p) (talloc_get_size(p) / sizeof((p)[0])) -#define MP_GROW_ARRAY(p, nextidx) do { \ - if ((nextidx) == MP_TALLOC_ELEMS(p)) \ - (p) = talloc_realloc_size(NULL, p, talloc_get_size(p) * 2); } while (0) -#define MP_RESIZE_ARRAY(ctx, p, count) do { \ - (p) = talloc_realloc_size((ctx), p, (count) * sizeof((p)[0])); } while (0) - -#define MP_TARRAY_GROW(ctx, p, nextidx) \ - do { \ - size_t nextidx_ = (nextidx); \ - size_t nelems_ = MP_TALLOC_ELEMS(p); \ - if (nextidx_ >= nelems_) \ - (p) = talloc_realloc_size(ctx, p, \ - (nextidx_ + 1) * sizeof((p)[0]) * 2);\ - } while (0) - -#define MP_TARRAY_APPEND(ctx, p, idxvar, ...) \ - do { \ - MP_TARRAY_GROW(ctx, p, idxvar); \ - (p)[(idxvar)] = (MP_EXPAND_ARGS(__VA_ARGS__));\ - (idxvar)++; \ - } while (0) - -// Doesn't actually free any memory, or do any other talloc calls. -#define MP_TARRAY_REMOVE_AT(p, idxvar, at) \ - do { \ - size_t at_ = (at); \ - assert(at_ <= (idxvar)); \ - memmove((p) + at_, (p) + at_ + 1, \ - ((idxvar) - at_ - 1) * sizeof((p)[0])); \ - (idxvar)--; \ - } while (0) - -#define talloc_struct(ctx, type, ...) \ - talloc_memdup(ctx, &(type) MP_EXPAND_ARGS(__VA_ARGS__), sizeof(type)) - -#endif diff --git a/core/mplayer.c b/core/mplayer.c deleted file mode 100644 index d3872442ee..0000000000 --- a/core/mplayer.c +++ /dev/null @@ -1,4747 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef PTW32_STATIC_LIB -#include -#endif - -#include -#include -#include -#include - -#include - -#include "config.h" -#include "talloc.h" - -#include "osdep/io.h" - -#if defined(__MINGW32__) || defined(__CYGWIN__) -#include -#endif -#define WAKEUP_PERIOD 0.5 -#include -#include - -// #include -#include -#ifndef __MINGW32__ -#include -#include -#endif - -#include -#include - -#include -#include -#include -#include - -#include - -#include "core/mpv_global.h" -#include "core/mp_msg.h" -#include "av_log.h" - - -#include "core/m_option.h" -#include "core/m_config.h" -#include "core/resolve.h" -#include "core/m_property.h" - -#include "sub/find_subfiles.h" -#include "sub/dec_sub.h" -#include "sub/sd.h" - -#include "core/mp_osd.h" -#include "video/out/vo.h" -#include "core/screenshot.h" - -#include "sub/sub.h" -#include "core/cpudetect.h" - -#ifdef CONFIG_X11 -#include "video/out/x11_common.h" -#endif - -#ifdef CONFIG_COCOA -#include "osdep/macosx_application.h" -#endif - -#include "audio/out/ao.h" - -#include "core/codecs.h" - -#include "osdep/getch2.h" -#include "osdep/timer.h" - -#include "core/input/input.h" -#include "core/encode.h" - -#include "osdep/priority.h" - -#include "stream/tv.h" -#include "stream/stream_radio.h" -#ifdef CONFIG_DVBIN -#include "stream/dvbin.h" -#endif - -//**************************************************************************// -// Playtree -//**************************************************************************// -#include "core/playlist.h" -#include "core/playlist_parser.h" - -//**************************************************************************// -// Config -//**************************************************************************// -#include "core/parser-cfg.h" -#include "core/parser-mpcmd.h" - -//**************************************************************************// -// Config file -//**************************************************************************// - -#include "core/path.h" - -//**************************************************************************// -//**************************************************************************// -// Input media streaming & demultiplexer: -//**************************************************************************// - -#include "stream/stream.h" -#include "demux/demux.h" -#include "demux/stheader.h" - -#include "audio/filter/af.h" -#include "audio/decode/dec_audio.h" -#include "video/decode/dec_video.h" -#include "video/mp_image.h" -#include "video/filter/vf.h" -#include "video/decode/vd.h" - -#include "audio/mixer.h" - -#include "core/mp_core.h" -#include "core/options.h" - -const char mp_help_text[] = _( -"Usage: mpv [options] [url|path/]filename\n" -"\n" -"Basic options: (complete list in the man page)\n" -" --start=