/* * Copyright (C) 2000-2004 the xine project * * This file is part of xine, a free 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA */ /* * simple switch video post plugin */ #define LOG_MODULE "switch" #define LOG_VERBOSE /* #define LOG */ #include "xine_internal.h" #include "post.h" /* FIXME: This plugin needs to handle overlays as well. */ /* plugin class initialization function */ static void *switch_init_plugin(xine_t *xine, void *); /* plugin catalog information */ static const post_info_t switch_special_info = { XINE_POST_TYPE_VIDEO_COMPOSE }; const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ { PLUGIN_POST, 9, "switch", XINE_VERSION_CODE, &switch_special_info, &switch_init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; typedef struct switch_parameter_s { unsigned int select; } switch_parameter_t; START_PARAM_DESCR(switch_parameter_t) PARAM_ITEM(POST_PARAM_TYPE_INT, select, NULL, 1, INT_MAX, 1, "the input source which will be passed through to the output") END_PARAM_DESCR(switch_param_descr) typedef struct post_class_switch_s post_class_switch_t; typedef struct post_switch_s post_switch_t; struct post_class_switch_s { post_class_t class; xine_t *xine; }; /* plugin structure */ struct post_switch_s { post_plugin_t post; xine_post_in_t parameter_input; int64_t vpts_limit; pthread_cond_t display_condition_changed; int64_t skip_vpts; int skip; pthread_mutex_t mutex; unsigned int source_count; unsigned int selected_source; }; /* plugin class functions */ static post_plugin_t *switch_open_plugin(post_class_t *class_gen, int inputs, xine_audio_port_t **audio_target, xine_video_port_t **video_target); static char *switch_get_identifier(post_class_t *class_gen); static char *switch_get_description(post_class_t *class_gen); static void switch_class_dispose(post_class_t *class_gen); /* plugin instance functions */ static void switch_dispose(post_plugin_t *this_gen); /* parameter functions */ static xine_post_api_descr_t *switch_get_param_descr(void); static int switch_set_parameters(xine_post_t *this_gen, void *param_gen); static int switch_get_parameters(xine_post_t *this_gen, void *param_gen); static char *switch_get_help(void); /* replaced vo_frame functions */ static int switch_draw(vo_frame_t *frame, xine_stream_t *stream); static void *switch_init_plugin(xine_t *xine, void *data) { post_class_switch_t *this = calloc(1, sizeof(post_class_switch_t)); if (!this) return NULL; this->class.open_plugin = switch_open_plugin; this->class.get_identifier = switch_get_identifier; this->class.get_description = switch_get_description; this->class.dispose = switch_class_dispose; this->xine = xine; return &this->class; } static post_plugin_t *switch_open_plugin(post_class_t *class_gen, int inputs, xine_audio_port_t **audio_target, xine_video_port_t **video_target) { post_switch_t *this = calloc(1, sizeof(post_switch_t)); post_in_t *input; xine_post_in_t *input_api; post_out_t *output; post_video_port_t *port; static xine_post_api_t post_api = { switch_set_parameters, switch_get_parameters, switch_get_param_descr, switch_get_help }; int i; lprintf("switch open\n"); if (inputs < 2 || !this || !video_target || !video_target[0]) { free(this); return NULL; } _x_post_init(&this->post, 0, inputs); this->source_count = inputs; this->selected_source = 1; pthread_cond_init(&this->display_condition_changed, NULL); pthread_mutex_init(&this->mutex, NULL); port = _x_post_intercept_video_port(&this->post, video_target[0], &input, &output); port->new_frame->draw = switch_draw; port->port_lock = &this->mutex; port->frame_lock = &this->mutex; this->post.xine_post.video_input[0] = &port->new_port; for (i = 1; i < inputs; i++) { port = _x_post_intercept_video_port(&this->post, video_target[0], &input, NULL); port->new_frame->draw = switch_draw; port->port_lock = &this->mutex; port->frame_lock = &this->mutex; this->post.xine_post.video_input[i] = &port->new_port; } input_api = &this->parameter_input; input_api->name = "parameters"; input_api->type = XINE_POST_DATA_PARAMETERS; input_api->data = &post_api; xine_list_push_back(this->post.input, input_api); this->post.dispose = switch_dispose; return &this->post; } static char *switch_get_identifier(post_class_t *class_gen) { return "switch"; } static char *switch_get_description(post_class_t *class_gen) { return "Switch is a post plugin able to switch at any time between different streams"; } static void switch_class_dispose(post_class_t *class_gen) { free(class_gen); } static void switch_dispose(post_plugin_t *this_gen) { post_switch_t *this = (post_switch_t *)this_gen; if (_x_post_dispose(this_gen)) { pthread_cond_destroy(&this->display_condition_changed); pthread_mutex_destroy(&this->mutex); free(this); } } static xine_post_api_descr_t *switch_get_param_descr(void) { return &switch_param_descr; } static int switch_set_parameters(xine_post_t *this_gen, void *param_gen) { post_switch_t *this = (post_switch_t *)this_gen; switch_parameter_t *param = (switch_parameter_t *)param_gen; if (param->select > this->source_count) return 0; pthread_mutex_lock(&this->mutex); this->selected_source = param->select; pthread_mutex_unlock(&this->mutex); pthread_cond_broadcast(&this->display_condition_changed); return 1; } static int switch_get_parameters(xine_post_t *this_gen, void *param_gen) { post_switch_t *this = (post_switch_t *)this_gen; switch_parameter_t *param = (switch_parameter_t *)param_gen; param->select = this->selected_source; return 1; } static char *switch_get_help(void) { return _("Switch can be used for fast switching between multiple inputs.\n" "\n" "Parameters\n" " select: the number of the input which will be passed to the output\n"); } static int switch_draw(vo_frame_t *frame, xine_stream_t *stream) { post_video_port_t *port = (post_video_port_t *)frame->port; post_switch_t *this = (post_switch_t *)port->post; int source_num, skip; for (source_num = 1; source_num <= this->source_count; source_num++) if (this->post.xine_post.video_input[source_num-1] == frame->port) break; _x_assert(source_num <= this->source_count); pthread_mutex_lock(&this->mutex); /* the original output will probably never see this frame again */ _x_post_frame_u_turn(frame, stream); while (this->selected_source != source_num && (frame->vpts > this->vpts_limit || !this->vpts_limit)) /* we are too early */ pthread_cond_wait(&this->display_condition_changed, &this->mutex); if (this->selected_source == source_num) { _x_post_frame_copy_down(frame, frame->next); skip = frame->next->draw(frame->next, XINE_ANON_STREAM); _x_post_frame_copy_up(frame, frame->next); this->vpts_limit = frame->vpts + frame->duration; if (skip) { this->skip = skip; this->skip_vpts = frame->vpts; } else this->skip = 0; pthread_mutex_unlock(&this->mutex); pthread_cond_broadcast(&this->display_condition_changed); } else { if (this->skip && frame->vpts <= this->skip_vpts) skip = this->skip; else skip = 0; pthread_mutex_unlock(&this->mutex); } return skip; }