diff options
Diffstat (limited to 'xine/post.c')
-rw-r--r-- | xine/post.c | 868 |
1 files changed, 868 insertions, 0 deletions
diff --git a/xine/post.c b/xine/post.c new file mode 100644 index 00000000..615f8b37 --- /dev/null +++ b/xine/post.c @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2003 by Dirk Meyer + * + * This file is part of xine, a unix video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * The code is taken from xine-ui/src/xitk/post.c at changed to work with fbxine + * + * Modified for VDR xineliboutput plugin by Petri Hintukainen, 2006 + * - runtime re-configuration (load/unload, enable/disable) + * - support for multiple streams + * - support for mosaico post plugin (picture-in-picture) + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "post.h" + +#if 1 +# include <sys/types.h> +# include <linux/unistd.h> +# include <errno.h> + +# define LOG_MODULENAME "[xine-post] " +# include "../logdefs.h" + + /* from xine_frontend.c or vdr tools.c: */ + extern int SysLogLevel; /* errors and info, no debug */ + /* from xine_frontend.c: */ + extern int LogToSysLog; /* log to syslog instead of console */ + +# if !defined(XINELIBOUTPUT_DEBUG_STDOUT) && \ + !defined(XINELIBOUTPUT_DEBUG_STDERR) + +# undef x_syslog + + pid_t gettid(void); /*_syscall0(pid_t, gettid);*/ + + static void x_syslog(int level, const char *fmt, ...) + { + va_list argp; + char buf[512]; + va_start(argp, fmt); + vsnprintf(buf, 512, fmt, argp); + if(!LogToSysLog) { + printf(LOG_MODULENAME "%s\n", buf); + } else { + syslog(level, "[%d] " LOG_MODULENAME "%s", gettid(), buf); + } + va_end(argp); + } +# endif + +#else +# define LOGERR(x...) +# define LOGMSG(x...) +# define LOGDBG(x...) +# define TRACELINE (void) +#endif + +#define fe_t post_plugins_t + +typedef struct { + xine_post_t *post; + xine_post_api_t *api; + xine_post_api_descr_t *descr; + xine_post_api_parameter_t *param; + char *param_data; + + int x; + int y; + + int readonly; + + char **properties_names; +} post_object_t; + + +static int __pplugin_retrieve_parameters(post_object_t *pobj) +{ + xine_post_in_t *input_api; + + if((input_api = (xine_post_in_t *) xine_post_input(pobj->post, + "parameters"))) { + xine_post_api_t *post_api; + xine_post_api_descr_t *api_descr; + xine_post_api_parameter_t *parm; + int pnum = 0; + + post_api = (xine_post_api_t *) input_api->data; + + api_descr = post_api->get_param_descr(); + + parm = api_descr->parameter; + pobj->param_data = malloc(api_descr->struct_size); + + while(parm->type != POST_PARAM_TYPE_LAST) { + + post_api->get_parameters(pobj->post, pobj->param_data); + + if(!pnum) + pobj->properties_names = (char **) xine_xmalloc(sizeof(char *) * 2); + else + pobj->properties_names = (char **) + realloc(pobj->properties_names, sizeof(char *) * (pnum + 2)); + + pobj->properties_names[pnum] = strdup(parm->name); + pobj->properties_names[pnum + 1] = NULL; + pnum++; + parm++; + } + + pobj->api = post_api; + pobj->descr = api_descr; + pobj->param = api_descr->parameter; + + return 1; + } + + return 0; +} + +static void _pplugin_update_parameter(post_object_t *pobj) +{ + pobj->api->set_parameters(pobj->post, pobj->param_data); + pobj->api->get_parameters(pobj->post, pobj->param_data); +} + +static void __pplugin_update_parameters(xine_post_t *post, char *args) +{ + post_object_t pobj; + char *p; + + memset(&pobj, 0, sizeof(post_object_t)); + pobj.post = post; + + if(__pplugin_retrieve_parameters(&pobj)) { + int i; + + if(pobj.properties_names && args && *args) { + char *param; + + while((param = xine_strsep(&args, ",")) != NULL) { + + p = param; + + while((*p != '\0') && (*p != '=')) + p++; + + if(p && strlen(p)) { + int param_num = 0; + + *p++ = '\0'; + + while(pobj.properties_names[param_num] + && strcasecmp(pobj.properties_names[param_num], param)) + param_num++; + + if(pobj.properties_names[param_num]) { + + pobj.param = pobj.descr->parameter; + pobj.param += param_num; + pobj.readonly = pobj.param->readonly; + + switch(pobj.param->type) { + case POST_PARAM_TYPE_INT: + if(!pobj.readonly) { + if(pobj.param->enum_values) { + char **values = pobj.param->enum_values; + int i = 0; + + while(values[i]) { + if(!strcasecmp(values[i], p)) { + *(int *)(pobj.param_data + pobj.param->offset) = i; + break; + } + i++; + } + + if( !values[i] ) + *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); + } else { + *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); + } + _pplugin_update_parameter(&pobj); + } + break; + + case POST_PARAM_TYPE_DOUBLE: + if(!pobj.readonly) { + *(double *)(pobj.param_data + pobj.param->offset) = strtod(p, &p); + _pplugin_update_parameter(&pobj); + } + break; + + case POST_PARAM_TYPE_CHAR: + case POST_PARAM_TYPE_STRING: + if(!pobj.readonly) { + if(pobj.param->type == POST_PARAM_TYPE_CHAR) { + int maxlen = pobj.param->size / sizeof(char); + + snprintf((char *)(pobj.param_data + pobj.param->offset), maxlen, "%s", p); + _pplugin_update_parameter(&pobj); + } + else + fprintf(stderr, "parameter type POST_PARAM_TYPE_STRING not supported yet.\n"); + } + break; + + case POST_PARAM_TYPE_STRINGLIST: /* unsupported */ + if(!pobj.readonly) + fprintf(stderr, "parameter type POST_PARAM_TYPE_STRINGLIST not supported yet.\n"); + break; + + case POST_PARAM_TYPE_BOOL: + if(!pobj.readonly) { + *(int *)(pobj.param_data + pobj.param->offset) = ((int) strtol(p, &p, 10)) ? 1 : 0; + _pplugin_update_parameter(&pobj); + } + break; + } + } + } + } + + i = 0; + + while(pobj.properties_names[i]) { + free(pobj.properties_names[i]); + i++; + } + + free(pobj.properties_names); + } + + free(pobj.param_data); + } +} + +/* -post <name>:option1=value1,option2=value2... */ +static post_element_t **pplugin_parse_and_load(fe_t *fe, + int plugin_type, + const char *pchain, + int *post_elements_num) +{ + post_element_t **post_elements = NULL; + char *post_chain; + + *post_elements_num = 0; + + if(pchain && strlen(pchain)) { + char *p; + + xine_strdupa(post_chain, pchain); + + while((p = xine_strsep(&post_chain, ";"))) { + + if(p && strlen(p)) { + char *plugin, *args = NULL; + xine_post_t *post; + + while(*p == ' ') + p++; + + plugin = strdup(p); + + if((p = strchr(plugin, ':'))) + *p++ = '\0'; + + if(p && (strlen(p) > 1)) + args = p; +#if 0 + post = xine_post_init(fe->xine, plugin, 0, + &fe->audio_port, &fe->video_port); +#else + if(plugin_type == XINE_POST_TYPE_VIDEO_COMPOSE) { + post = xine_post_init(fe->xine, plugin, 2, + &fe->audio_port, &fe->video_port); + } else + post = xine_post_init(fe->xine, plugin, 0, + &fe->audio_port, &fe->video_port); +#endif + + if (post && plugin_type) { + if (post->type != plugin_type) { + xine_post_dispose(fe->xine, post); + post = NULL; + } + } + + if(post) { + + if(!(*post_elements_num)) + post_elements = (post_element_t **) xine_xmalloc(sizeof(post_element_t *) * 2); + else + post_elements = (post_element_t **) + realloc(post_elements, sizeof(post_element_t *) * ((*post_elements_num) + 2)); + + post_elements[(*post_elements_num)] = (post_element_t *) + xine_xmalloc(sizeof(post_element_t)); + post_elements[(*post_elements_num)]->post = post; + post_elements[(*post_elements_num)]->name = strdup(plugin); +#if 1 + post_elements[(*post_elements_num)]->args = args ? strdup(args) : NULL; + post_elements[(*post_elements_num)]->enable = 0; +#endif + (*post_elements_num)++; + post_elements[(*post_elements_num)] = NULL; + + __pplugin_update_parameters(post, args); + } + + free(plugin); + } + } + } + + return post_elements; +} + +void pplugin_parse_and_store_post(fe_t *fe, int plugin_type, + const char *post_chain) +{ + post_element_t ***_post_elements; + int *_post_elements_num; + post_element_t **posts = NULL; + int num; + + switch(plugin_type) { + case XINE_POST_TYPE_VIDEO_FILTER: + _post_elements = &fe->post_video_elements; + _post_elements_num = &fe->post_video_elements_num; + break; + case XINE_POST_TYPE_VIDEO_COMPOSE: + _post_elements = &fe->post_pip_elements; + _post_elements_num = &fe->post_pip_elements_num; + break; + case XINE_POST_TYPE_AUDIO_VISUALIZATION: + _post_elements = &fe->post_vis_elements; + _post_elements_num = &fe->post_vis_elements_num; + break; + default: + _post_elements = &fe->post_audio_elements; + _post_elements_num = &fe->post_audio_elements_num; + break; + } + + if((posts = pplugin_parse_and_load(fe, plugin_type, post_chain, &num))) { + if(*_post_elements_num) { + int i; + int ptot = *_post_elements_num + num; + + *_post_elements = (post_element_t **) realloc(*_post_elements, + sizeof(post_element_t *) * (ptot + 1)); + for(i = *_post_elements_num; i < ptot; i++) + (*_post_elements)[i] = posts[i - *_post_elements_num]; + + (*_post_elements)[i] = NULL; + (*_post_elements_num) += num; + + } + else { + *_post_elements = posts; + *_post_elements_num = num; + } + } +} + + +void vpplugin_parse_and_store_post(fe_t *fe, const char *post_chain) +{ + pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_FILTER, post_chain); + pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_COMPOSE, post_chain); +} + + +void applugin_parse_and_store_post(fe_t *fe, const char *post_chain) +{ + pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_FILTER, post_chain); + pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_VISUALIZATION, post_chain); +} + + +static void _vpplugin_unwire(fe_t *fe) +{ + xine_post_out_t *vo_source; + + vo_source = xine_get_video_source(fe->stream); + + (void) xine_post_wire_video_port(vo_source, fe->video_port); +} + + +static void _applugin_unwire(fe_t *fe) +{ + xine_post_out_t *ao_source; + + ao_source = xine_get_audio_source(fe->stream); + + (void) xine_post_wire_audio_port(ao_source, fe->audio_port); +} + + +static void _vpplugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) +{ + if(post_elements_num) { + xine_post_out_t *vo_source; + int i = 0; + + for(i = (post_elements_num - 1); i >= 0; i--) { + const char *const *outs = xine_post_list_outputs(post_elements[i]->post); + const xine_post_out_t *vo_out = xine_post_output(post_elements[i]->post, (char *) *outs); + if(i == (post_elements_num - 1)) { + xine_post_wire_video_port((xine_post_out_t *) vo_out, fe->video_port); + } + else { + const xine_post_in_t *vo_in; + int err; + + /* look for standard input names */ + vo_in = xine_post_input(post_elements[i + 1]->post, "video"); + if( !vo_in ) + vo_in = xine_post_input(post_elements[i + 1]->post, "video in"); + err = xine_post_wire((xine_post_out_t *) vo_out, + (xine_post_in_t *) vo_in); + } + } + + if(fe->post_pip_enable && + !strcmp(post_elements[0]->name, "mosaico")) { + vo_source = xine_get_video_source(fe->pip_stream); + xine_post_wire_video_port(vo_source, + post_elements[0]->post->video_input[1]); + } + + if(fe->slave_stream) + vo_source = xine_get_video_source(fe->slave_stream); + else + vo_source = xine_get_video_source(fe->stream); + xine_post_wire_video_port(vo_source, + post_elements[0]->post->video_input[0]); + } +} + + +static void _applugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) +{ + if(post_elements_num) { + xine_post_out_t *ao_source; + int i = 0; + + for(i = (post_elements_num - 1); i >= 0; i--) { + const char *const *outs = xine_post_list_outputs(post_elements[i]->post); + const xine_post_out_t *ao_out = xine_post_output(post_elements[i]->post, (char *) *outs); + + if(i == (post_elements_num - 1)) { + xine_post_wire_audio_port((xine_post_out_t *) ao_out, fe->audio_port); + } + else { + const xine_post_in_t *ao_in; + int err; + + /* look for standard input names */ + ao_in = xine_post_input(post_elements[i + 1]->post, "audio"); + if( !ao_in ) + ao_in = xine_post_input(post_elements[i + 1]->post, "audio in"); + + err = xine_post_wire((xine_post_out_t *) ao_out, (xine_post_in_t *) ao_in); + } + } + + if(fe->slave_stream) + ao_source = xine_get_audio_source(fe->slave_stream); + else + ao_source = xine_get_audio_source(fe->stream); + xine_post_wire_audio_port(ao_source, post_elements[0]->post->audio_input[0]); + } +} + +static post_element_t **_pplugin_join_deinterlace_and_post_elements(fe_t *fe, int *post_elements_num) +{ + post_element_t **post_elements; + int i = 0, j = 0, n = 0; + + *post_elements_num = 0; + if( fe->post_video_enable ) + *post_elements_num += fe->post_video_elements_num; + + if( fe->post_pip_enable ) + *post_elements_num += fe->post_pip_elements_num; + + if( *post_elements_num == 0 ) + return NULL; + + post_elements = (post_element_t **) + xine_xmalloc(sizeof(post_element_t *) * (*post_elements_num)); + + if(fe->post_pip_enable) + for( i = 0; i < fe->post_pip_elements_num; i++ ) { + if(fe->post_pip_elements[i]->enable) + post_elements[i+j-n] = fe->post_pip_elements[i]; + else + n++; + } + + if(fe->post_video_enable) + for( j = 0; j < fe->post_video_elements_num; j++ ) { + if(fe->post_video_elements[j]->enable) + post_elements[i+j-n] = fe->post_video_elements[j]; + else + n++; + } + + *post_elements_num -= n; + if( *post_elements_num == 0 ) { + free(post_elements); + return NULL; + } + + return post_elements; +} + +static post_element_t **_pplugin_join_visualization_and_post_elements(fe_t *fe, int *post_elements_num) +{ + post_element_t **post_elements; + int i = 0, j = 0, n = 0; + + *post_elements_num = 0; + if( fe->post_audio_enable ) + *post_elements_num += fe->post_audio_elements_num; + + if( fe->post_vis_enable ) + *post_elements_num += fe->post_vis_elements_num; + + if( *post_elements_num == 0 ) + return NULL; + + post_elements = (post_element_t **) + xine_xmalloc(sizeof(post_element_t *) * (*post_elements_num)); + + if(fe->post_audio_enable) + for( j = 0; j < fe->post_audio_elements_num; j++ ) { + if(fe->post_audio_elements[j]->enable) + post_elements[i+j-n] = fe->post_audio_elements[j]; + else + n++; + } + + if(fe->post_vis_enable) + for( i = 0; i < fe->post_vis_elements_num; i++ ) { + if(fe->post_vis_elements[i]->enable) + post_elements[i+j-n] = fe->post_vis_elements[i]; + else + n++; + } + + *post_elements_num -= n; + if( *post_elements_num == 0 ) { + free(post_elements); + return NULL; + } + + return post_elements; +} + +static void _vpplugin_rewire(fe_t *fe) +{ + static post_element_t **post_elements; + int post_elements_num; + + post_elements = _pplugin_join_deinterlace_and_post_elements(fe, &post_elements_num); + + if( post_elements ) { + _vpplugin_rewire_from_post_elements(fe, post_elements, post_elements_num); + + free(post_elements); + } +} + +static void _applugin_rewire(fe_t *fe) +{ + static post_element_t **post_elements; + int post_elements_num; + + post_elements = _pplugin_join_visualization_and_post_elements(fe, &post_elements_num); + + if( post_elements ) { + _applugin_rewire_from_post_elements(fe, post_elements, post_elements_num); + + free(post_elements); + } +} + +void vpplugin_rewire_posts(fe_t *fe) +{ + /*TRACELINE;*/ + _vpplugin_unwire(fe); + _vpplugin_rewire(fe); +} + +void applugin_rewire_posts(fe_t *fe) +{ + /*TRACELINE;*/ + _applugin_unwire(fe); + _applugin_rewire(fe); +} + +static int _pplugin_enable_post(post_plugins_t *fe, const char *name, + const char *args, + post_element_t **post_elements, + int post_elements_num, + int *found) +{ + int i, result = 0; + + for(i=0; i<post_elements_num; i++) + if(post_elements[i]) + if(!strcmp(post_elements[i]->name, name)) { + if(post_elements[i]->enable == 0) { + post_elements[i]->enable = 1; + result = 1; + } + + *found = 1; + + if(args && *args) { + char *tmp = strdup(args); + __pplugin_update_parameters(post_elements[i]->post, tmp); + free(tmp); + if(post_elements[i]->args) + free(post_elements[i]->args); + post_elements[i]->args = strdup(args); + } + } + + return result; +} + +static int _vpplugin_enable_post(post_plugins_t *fe, const char *name, + const char *args, int *found) +{ + return + _pplugin_enable_post(fe, name, args, fe->post_video_elements, + fe->post_video_elements_num, found) + + _pplugin_enable_post(fe, name, args, fe->post_pip_elements, + fe->post_pip_elements_num, found); +} + +static int _applugin_enable_post(post_plugins_t *fe, const char *name, + const char *args, int *found) +{ + return + _pplugin_enable_post(fe, name, args, fe->post_audio_elements, + fe->post_audio_elements_num, found) + + _pplugin_enable_post(fe, name, args, fe->post_vis_elements, + fe->post_vis_elements_num, found); +} + +static char * _pp_name(const char *initstr) +{ + char *name = strdup(initstr), *pt; + + if(NULL != (pt = strchr(name, ':'))) + *pt = 0; + + return name; +} + +static const char * _pp_args(const char *initstr) +{ + char *pt = strchr(initstr, ':'); + if(pt && *(pt+1)) + return pt+1; + return NULL; +} + +int vpplugin_enable_post(post_plugins_t *fe, const char *initstr, + int *found) +{ + char *name = _pp_name(initstr); + const char *args = _pp_args(initstr); + + int result = _vpplugin_enable_post(fe, name, args, found); + + LOGDBG(" * enable post %s --> %s, %s", name, + *found ? "found" : "not found", + result ? "enabled" : "no action"); + + if(!*found) { + LOGDBG(" * loading post %s", initstr); + vpplugin_parse_and_store_post(fe, initstr); + result = _vpplugin_enable_post(fe, name, NULL, found); + LOGDBG(" * enable post %s --> %s, %s", name, + *found ? "found" : "not found", + result ? "enabled" : "no action"); + } + + if(result) + _vpplugin_unwire(fe); + + free(name); + return result; +} + +int applugin_enable_post(post_plugins_t *fe, const char *initstr, + int *found) +{ + const char *args = _pp_args(initstr); + char *name = _pp_name(initstr); + + int result = _vpplugin_enable_post(fe, name, args, found); + + LOGDBG(" * enable post %s --> %s, %s", name, + *found ? "found" : "not found", + result ? "enabled" : "no action"); + + if(!*found) { + LOGDBG(" * loading post %s", initstr); + applugin_parse_and_store_post(fe, initstr); + result = _applugin_enable_post(fe, name, NULL, found); + LOGDBG(" * enable post %s --> %s, %s", name, + *found ? "found" : "not found", + result ? "enabled" : "no action"); + } + + if(result) + _applugin_unwire(fe); + + free(name); + return result; +} + +static int _pplugin_disable_post(post_plugins_t *fe, const char *name, + post_element_t **post_elements, + int post_elements_num) +{ + int i, result = 0; + /*TRACELINE;*/ + if(post_elements) + for(i = 0; i < post_elements_num; i++) + if(post_elements[i]) + if(!name || !strcmp(post_elements[i]->name, name)) + if(post_elements[i]->enable == 1) { + post_elements[i]->enable = 0; + result = 1; + } + return result; +} + +int vpplugin_disable_post(post_plugins_t *fe, const char *name) +{ + /*TRACELINE;*/ + if(_pplugin_disable_post(fe, name, fe->post_video_elements, + fe->post_video_elements_num) || + _pplugin_disable_post(fe, name, fe->post_pip_elements, + fe->post_pip_elements_num)) { + _vpplugin_unwire(fe); + return 1; + } + return 0; +} + +int applugin_disable_post(post_plugins_t *fe, const char *name) +{ + /*TRACELINE;*/ + if(_pplugin_disable_post(fe, name, fe->post_audio_elements, + fe->post_audio_elements_num) || + _pplugin_disable_post(fe, name, fe->post_vis_elements, + fe->post_vis_elements_num)) { + _applugin_unwire(fe); + return 1; + } + return 0; +} + +static int _pplugin_unload_post(post_plugins_t *fe, const char *name, + post_element_t ***post_elements, + int *post_elements_num) +{ + /* does not unwrire plugins ! */ + int i, j, result = 0; + /*TRACELINE;*/ + + if(!*post_elements || !*post_elements_num) + return 0; + + for(i=0; i < *post_elements_num; i++) + if((*post_elements)[i]) + if(!name || !strcmp((*post_elements)[i]->name, name)) { + + if((*post_elements)[i]->enable == 0) { + xine_post_dispose(fe->xine, (*post_elements)[i]->post); + + free((*post_elements)[i]->name); + + if((*post_elements)[i]->args) + free((*post_elements)[i]->args); + + free((*post_elements)[i]); + + for(j=i; j < *post_elements_num - 1; j++) + (*post_elements)[j] = (*post_elements)[j+1]; + + (*post_elements_num) --; + (*post_elements)[(*post_elements_num)] = 0; + + result = 1; + } else { + LOGDBG("Unload %s failed: plugin enabled and in use", name); + } + } + + if(*post_elements_num <= 0) { + if(*post_elements) + free(*post_elements); + *post_elements = NULL; + } + + return result; +} + +int vpplugin_unload_post(post_plugins_t *fe, const char *name) +{ + int result = vpplugin_disable_post(fe, name); + + /* unload already disabled plugins too (result=0) */ + _pplugin_unload_post(fe, name, &fe->post_video_elements, + &fe->post_video_elements_num); + _pplugin_unload_post(fe, name, &fe->post_pip_elements, + &fe->post_pip_elements_num); + + /* result indicates only unwiring condition, not unload result */ + return result; +} + +int applugin_unload_post(post_plugins_t *fe, const char *name) +{ + int result = applugin_disable_post(fe, name); + + /* unload already disabled plugins too (result=0) */ + _pplugin_unload_post(fe, name, &fe->post_audio_elements, + &fe->post_audio_elements_num); + _pplugin_unload_post(fe, name, &fe->post_vis_elements, + &fe->post_vis_elements_num); + + /* result indicates only unwiring condition, not unload result */ + return result; +} + + +/* end of post.c */ + |