summaryrefslogtreecommitdiff
path: root/xine_frontend.c
diff options
context:
space:
mode:
authorcvs2svn <admin@example.com>2009-10-21 00:02:02 +0000
committercvs2svn <admin@example.com>2009-10-21 00:02:02 +0000
commit97a97ca3358eb48de3eb7a222e487e800566569f (patch)
tree97c920d0225a1c9773a3bce2207f261d7d230123 /xine_frontend.c
parenta61961358c5a2ec92340b3f8e056bab55438f103 (diff)
downloadxineliboutput-CVS.tar.gz
xineliboutput-CVS.tar.bz2
This commit was manufactured by cvs2svn to create branch 'CVS'.CVS
Diffstat (limited to 'xine_frontend.c')
-rw-r--r--xine_frontend.c1962
1 files changed, 0 insertions, 1962 deletions
diff --git a/xine_frontend.c b/xine_frontend.c
deleted file mode 100644
index 06dd08e3..00000000
--- a/xine_frontend.c
+++ /dev/null
@@ -1,1962 +0,0 @@
-/*
- * xine_frontend.c:
- *
- * See the main source file 'xineliboutput.c' for copyright information and
- * how to reach the author.
- *
- * $Id: xine_frontend.c,v 1.103 2009-10-08 19:52:20 phintuka Exp $
- *
- */
-
-#include "features.h"
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef HAVE_LIBJPEG
-# ifdef boolean
-# define HAVE_BOOLEAN
-# endif
-# include <jpeglib.h>
-# undef boolean
-#endif
-
-#define XINE_ENGINE_INTERNAL
-#include <xine.h>
-#include <xine/xine_internal.h>
-
-#define LOG_MODULENAME "[vdr-fe] "
-#include "logdefs.h"
-
-#include "xine_frontend_internal.h"
-#include "xine/post.h"
-
-#include "xine/vo_post.h"
-#include "xine/vo_osdscaler.h"
-#include "xine/vo_osdreorder.h"
-
-#undef MIN
-#define MIN(a,b) ( (a) < (b) ? (a) : (b))
-#undef MAX
-#define MAX(a,b) ( (a) > (b) ? (a) : (b))
-
-
-static void intercept_video_driver(xine_video_port_t *video_port)
-{
- vo_driver_t *osdscaler = osdscaler_init();
- if (! wire_video_driver(video_port, osdscaler)) {
- LOGMSG("wire_video_driver() for osdscaler failed");
- osdscaler->dispose(osdscaler);
- }
-
- vo_driver_t *osdreorder = osd_reorder_init();
- if (! wire_video_driver(video_port, osdreorder)) {
- LOGMSG("wire_video_driver() for osdreorder failed");
- osdreorder->dispose(osdreorder);
- }
-}
-
-
-char *strn0cpy(char *dest, const char *src, int n)
-{
- char *s = dest;
- for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
- *dest = 0;
- return s;
-}
-
-static int guess_cpu_count(void)
-{
- static int cores = -1;
- FILE *f;
-
- if(cores >= 0)
- return cores;
-
- cores = 0;
- if(NULL != (f = fopen("/proc/cpuinfo", "r"))) {
- char buf[256];
- while (NULL != fgets(buf, 255, f))
- sscanf(buf, "processor : %d", &cores);
- fclose(f);
- }
- cores++;
-
- if(cores > 1)
- LOGMSG("Detected %d CPUs", cores);
- else
- LOGDBG("Detected single CPU. Multithreaded decoding and post processing disabled.");
-
- return cores;
-}
-
-/*
- * list available plugins
- */
-
-static void list_plugins_type(xine_t *xine, const char *msg, typeof (xine_list_audio_output_plugins) list_func)
-{
- static xine_t *tmp_xine = NULL;
- if(!xine) {
- if(!tmp_xine)
- xine_init(tmp_xine = xine_new());
- xine = tmp_xine;
- }
- const char *const *list = list_func(xine);
-
- printf("%s", msg);
- while(list && *list)
- printf(" %s", *list++);
- printf("\n");
-}
-
-void list_xine_plugins(frontend_t *fe, int verbose)
-{
- fe_t *this = (fe_t *)fe;
-
- xine_t *tmp_xine = NULL;
- xine_t *xine = this ? this->xine : NULL;
-
- if (!xine)
- xine_init(xine = tmp_xine = xine_new());
-
- list_plugins_type (xine, "Available video drivers:", xine_list_video_output_plugins);
- list_plugins_type (xine, "Available audio drivers:", xine_list_audio_output_plugins);
- if (verbose) {
- list_plugins_type (xine, "Available post plugins: ", xine_list_post_plugins);
- list_plugins_type (xine, "Available input plugins:", xine_list_input_plugins);
- list_plugins_type (xine, "Available demux plugins:", xine_list_demuxer_plugins);
- list_plugins_type (xine, "Available audio decoder plugins:", xine_list_audio_decoder_plugins);
- list_plugins_type (xine, "Available video decoder plugins:", xine_list_video_decoder_plugins);
- list_plugins_type (xine, "Available SPU decoder plugins: ", xine_list_spu_plugins);
- }
-
- if (tmp_xine)
- xine_exit(tmp_xine);
-}
-
-/*
- * detect input plugin
- */
-
-static int find_input_plugin(fe_t *this)
-{
- if(!this->input_plugin) {
- if(!this->stream || !this->stream->input_plugin ||
- !this->stream->input_plugin->input_class || this->playback_finished) {
- LOGMSG("find_input_plugin: stream not initialized or playback finished !");
- usleep(100*1000);
- return 0;
- }
-#if XINE_VERSION_CODE < 10190
- if(strcmp(this->stream->input_plugin->input_class->get_identifier(
- this->stream->input_plugin->input_class),
- MRL_ID)) {
-#else
- if(strcmp(this->stream->input_plugin->input_class->identifier,
- MRL_ID)) {
-#endif
- LOGMSG("find_input_plugin: current xine input plugin is not " MRL_ID " !");
- return 0;
- }
- this->input_plugin = (vdr_input_plugin_if_t*)this->stream->input_plugin;
- }
- return 1;
-}
-
-static void *fe_control(frontend_t *this_gen, const char *cmd);
-
-/*
- * xine callbacks
- */
-
-static double fe_dest_pixel_aspect(const fe_t *this, double video_pixel_aspect,
- int video_width, int video_height)
-{
- /*int new_cropping = 0;*/
- double result = 1.0;
-
- if(!this->scale_video) {
-
- /*#warning what to do if scaling disabled ???*/
-
- /*return video_pixel_aspect;*/
- }
-
- switch(this->aspect) {
- /* Auto */
- default: {
- double correction =
- ((double)video_width/(double)video_height) /
- ((double)this->width/(double)this->height);
-
- result = video_pixel_aspect * correction;
- if(result > (16.9/9.0 * (double)this->height/
- (double)this->width))
- result = (16.0/9.0 * (double)this->height/
- (double)this->width);
- break;
- }
- /* Default */
- case 1: result = this->display_ratio; break;
-
- /* 4:3 */
- case 2: result = (4.0/3.0 * (double)this->height/(double)this->width); break;
- /* 16:9 */
- case 3: result = (16.0/9.0 * (double)this->height/(double)this->width); break;
- /* 16:10 */
- case 4: result = (16.0/10.0 * (double)this->height/(double)this->width); break;
- /* Pan&Scan */
- case 5: {
- double aspect_diff /*= video_pixel_aspect - 1.0*/;
- /* TODO */
- /* does not work (?) */
-aspect_diff=(video_pixel_aspect*(double)video_width/(double)video_height) - 4.0 / 3.0;
- if ((aspect_diff < 0.05) && (aspect_diff > -0.05)) {
- result = (4.0/3.0 * (double)this->height/(double)this->width);
- /*LOGDBG("diff: %f", aspect_diff);*/
- /*new_cropping = 1;*/
- } else {
- result = (16.0/9.0 * (double)this->height/(double)this->width);
- }
- /*result = (4.0/3.0 * (double)this->height/(double)this->width);*/
- break;
- }
- /* center cut-out */
- case 6: {
-/*#warning center cut-out mode not implemented*/
- break;
- }
-
- }
-#if 0
- if(this->cropping && !new_cropping) {
- LOGDBG("pan&scan CROP OFF");
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, 0);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, 72);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, 0);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, 72);
- this->cropping = 0;
- }
- if(!this->cropping && new_cropping) {
- LOGDBG("pan&scan CROP ON");
- /*** Should set unscaled osd (or top & bottom will be cropped off) */
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, 0);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, 0);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, 0);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, 0);
- this->cropping = 1;
- }
-#endif
-
- return result;
-}
-
-static void fe_frame_output_cb (void *data,
- int video_width, int video_height,
- double video_pixel_aspect,
- int *dest_x, int *dest_y,
- int *dest_width, int *dest_height,
- double *dest_pixel_aspect,
- int *win_x, int *win_y)
-{
- fe_t *this = (fe_t *)data;
-
- if (!this)
- return;
-
- *dest_width = this->width;
- *dest_height = this->height;
- *dest_x = 0;
-#ifndef HAVE_XV_FIELD_ORDER
- *dest_y = 0 + this->field_order;
-#else
- *dest_y = 0;
-#endif
-
-#if 1
- if(!this->scale_video) {
- if(video_height < this->height) {
- *dest_height = video_height;
- *dest_y = (this->height - video_height) / 2;
- }
- if(video_width < this->width) {
- *dest_width = video_width;
- *dest_x = (this->width - video_width) / 2;
- }
- }
-#endif
-
- *win_x = this->xpos;
- *win_y = this->ypos;
-
- *dest_pixel_aspect = this->dest_pixel_aspect(this, video_pixel_aspect,
- video_width, video_height);
-
-#if 0
- if(this->cropping) {
- *dest_pixel_aspect = *dest_pixel_aspect * (16.0/9.0)/(4.0/3.0);
- *dest_y = *dest_y - 72;
- *dest_height = *dest_height + 144;
- }
-#endif
-
-#if 0
- /* video_out cropping works better */
- if(this->overscan) {
- int crop_x = this->overscan * this->width / 100 / 2;
- int crop_y = this->overscan * this->height / 100 / 2;
- *dest_x -= crop_x;
- *dest_y -= crop_y;
- *dest_width += crop_x;
- *dest_height += crop_y;
- }
-#endif
-
- if(!this->stream)
- return;
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO,
- (int)(10000.0*video_pixel_aspect *
- ((double)video_width)/((double)video_height)));
- if(this->video_width != video_width ||
- this->video_height != video_height) {
- xine_format_change_data_t framedata = {
- .width = video_width,
- .height = video_height,
- .aspect = 0, /* TODO */
- .pan_scan = 0,
- };
- const xine_event_t event = {
- .type = XINE_EVENT_FRAME_FORMAT_CHANGE,
- .stream = this->stream,
- .data = &framedata,
- .data_length = sizeof(framedata),
- };
- xine_event_send(this->stream, &event);
- this->video_width = video_width;
- this->video_height = video_height;
-#if 0
- /* trigger forced redraw to make cropping changes effective */
- if(this->cropping)
- xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, 100);
-#endif
- }
-
- if(this->aspect_controller) {
- double video_aspect = (video_pixel_aspect * (double)video_width / (double)video_height);
- double aspect_diff = video_aspect - this->video_aspect;
- if ((aspect_diff > 0.05) || (aspect_diff < -0.05)) {
- char cmd[4096];
- if(snprintf(cmd, sizeof(cmd), "%s %d",
- this->aspect_controller, (int)(video_aspect * 10000.0))
- < sizeof(cmd)) {
- LOGDBG("Aspect ratio changed, executing %s", cmd);
- if(system(cmd) == -1)
- LOGERR("Executing /bin/sh -c %s failed", cmd);
- this->video_aspect = video_aspect;
- }
- }
- }
-}
-
-static void xine_event_cb (void *user_data, const xine_event_t *event)
-{
- fe_t *this = (fe_t *)user_data;
-
- switch (event->type) {
- /* in local mode: vdr stream / slave stream ; in remote mode: vdr stream only */
- case XINE_EVENT_UI_PLAYBACK_FINISHED:
- LOGDBG("XINE_EVENT_UI_PLAYBACK_FINISHED");
- if(this) {
- if(event->stream == this->stream)
- this->playback_finished = 1;
- } else {
- LOGMSG("xine_event_cb: NO USER DATA !");
- }
- break;
- default: break;
- }
-}
-
-/*
- * fe_xine_init
- *
- * initialize xine engine, initialize audio and video ports, setup stream
- */
-
-#define MONO 0
-#define STEREO 1
-#define HEADPHONES 2
-#define SURROUND21 3
-#define SURROUND3 4
-#define SURROUND4 5
-#define SURROUND41 6
-#define SURROUND5 7
-#define SURROUND51 8
-#define SURROUND6 9
-#define SURROUND61 10
-#define SURROUND71 11
-#define A52_PASSTHRU 12
-
-#define x_reg_num(x...) xine_config_register_num(this->xine, x)
-#define x_reg_str(x...) xine_config_register_string(this->xine, x)
-#define x_reg_enum(x...) xine_config_register_enum(this->xine, x)
-#define x_reg_bool(x...) xine_config_register_bool(this->xine, x)
-
-#define x_upd_num(x...) this->xine->config->update_num(this->xine->config, x)
-#define x_upd_str(x...) this->xine->config->update_string(this->xine->config, x)
-
-static void configure_audio_out(const fe_t *this, const char *audio_driver, const char *audio_port)
-{
- /*
- * alsa
- */
- if(audio_driver && audio_port && !strcmp("alsa", audio_driver) && strlen(audio_port) > 0) {
-
- /* define possible speaker arrangements */
- /* From xine audio_alsa_out.c ; must be synchronized ! */
- static char *speaker_arrangement[] =
- {"Mono 1.0", "Stereo 2.0", "Headphones 2.0", "Stereo 2.1",
- "Surround 3.0", "Surround 4.0", "Surround 4.1",
- "Surround 5.0", "Surround 5.1", "Surround 6.0",
- "Surround 6.1", "Surround 7.1", "Pass Through", NULL};
-
- x_reg_enum("audio.output.speaker_arrangement",
- STEREO,
- speaker_arrangement,
- _("speaker arrangement"),
- _("Select how your speakers are arranged, "
- "this determines which speakers xine uses for sound output. "
- "The individual values are:\n\n"
- "Mono 1.0: You have only one speaker.\n"
- "Stereo 2.0: You have two speakers for left and right channel.\n"
- "Headphones 2.0: You use headphones.\n"
- "Stereo 2.1: You have two speakers for left and right channel, and one "
- "subwoofer for the low frequencies.\n"
- "Surround 3.0: You have three speakers for left, right and rear channel.\n"
- "Surround 4.0: You have four speakers for front left and right and rear "
- "left and right channels.\n"
- "Surround 4.1: You have four speakers for front left and right and rear "
- "left and right channels, and one subwoofer for the low frequencies.\n"
- "Surround 5.0: You have five speakers for front left, center and right and "
- "rear left and right channels.\n"
- "Surround 5.1: You have five speakers for front left, center and right and "
- "rear left and right channels, and one subwoofer for the low frequencies.\n"
- "Surround 6.0: You have six speakers for front left, center and right and "
- "rear left, center and right channels.\n"
- "Surround 6.1: You have six speakers for front left, center and right and "
- "rear left, center and right channels, and one subwoofer for the low frequencies.\n"
- "Surround 7.1: You have seven speakers for front left, center and right, "
- "left and right and rear left and right channels, and one subwoofer for the "
- "low frequencies.\n"
- "Pass Through: Your sound system will receive undecoded digital sound from xine. "
- "You need to connect a digital surround decoder capable of decoding the "
- "formats you want to play to your sound card's digital output."),
- 10, NULL, NULL);
-
- x_reg_str("audio.device.alsa_default_device",
- "default",
- _("device used for mono output"),
- _("xine will use this alsa device "
- "to output mono sound.\n"
- "See the alsa documentation "
- "for information on alsa devices."),
- 10, NULL, NULL);
- x_reg_str("audio.device.alsa_front_device",
- "plug:front:default",
- _("device used for stereo output"),
- _("xine will use this alsa device "
- "to output stereo sound.\n"
- "See the alsa documentation "
- "for information on alsa devices."),
- 10, NULL, NULL);
- x_reg_str("audio.device.alsa_surround51_device",
- "plug:surround51:0",
- _("device used for 5.1-channel output"),
- _("xine will use this alsa device to output "
- "5 channel plus LFE (5.1) surround sound.\n"
- "See the alsa documentation for information "
- "on alsa devices."),
- 10, NULL, NULL);
- x_reg_str("audio.device.alsa_passthrough_device",
- "iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2",
- _("device used for 5.1-channel output"),
- _("xine will use this alsa device to output "
- "undecoded digital surround sound. This can "
- "be used be external surround decoders.\nSee the "
- "alsa documentation for information on alsa "
- "devices."),
- 10, NULL, NULL);
-
- x_upd_str("audio.device.alsa_front_device", audio_port);
- x_upd_str("audio.device.alsa_default_device", audio_port);
- x_upd_str("audio.device.alsa_surround51_device", audio_port);
- if(strstr(audio_port, "iec") ||
- strstr(audio_port, "spdif")) {
- x_upd_str("audio.device.alsa_passthrough_device", audio_port);
- x_upd_num("audio.output.speaker_arrangement", A52_PASSTHRU);
- } else {
- x_upd_num("audio.output.speaker_arrangement",
- strstr(audio_port, "surround") ? SURROUND51 : STEREO);
- }
- }
-
-
- /*
- * OSS
- */
- if(audio_driver && !strcmp("oss", audio_driver) && audio_port) {
- int devnum = -2;
- if(!strcmp("default", audio_port))
- devnum = -1;
- if(!strncmp("/dev/dsp", audio_port, 8) &&
- sscanf(audio_port+8, "%d", &devnum) < 1)
- devnum = -1;
- if(!strncmp("/dev/sound/dsp", audio_port, 14) &&
- sscanf(audio_port+14, "%d", &devnum) < 1)
- devnum = -1;
- if(devnum > -2) {
- x_reg_num("audio.device.oss_device_number", -1,
- _("OSS audio device number, -1 for none"),
- _("The full audio device name is created by concatenating the "
- "OSS device name and the audio device number.\n"
- "If you do not need a number because you are happy with "
- "your system's default audio device, set this to -1.\n"
- "The range of this value is -1 or 0-15. This setting is "
- "ignored, when the OSS audio device name is set to \"auto\"."),
- 10, NULL, NULL);
- x_upd_num("audio.device.oss_device_num", devnum);
- }
- }
-}
-
-static int fe_xine_init(frontend_t *this_gen, const char *audio_driver,
- const char *audio_port,
- const char *video_driver,
- int pes_buffers,
- const char *static_post_plugins,
- const char *config_file)
-{
- fe_t *this = (fe_t*)this_gen;
- post_plugins_t *posts = NULL;
-
- if(!this)
- return 0;
-
- /* check xine-lib version */
- if(!xine_check_version(1, 1, 0)) {
- LOGERR("xine-lib is too old, require at least xine library version 1.1.0\n");
- return FE_ERROR;
- }
-
-
- /*
- * init xine engine
- */
-
- if(this->xine)
- this->fe.xine_exit(this_gen);
-
- this->stream = NULL;
- this->video_port = NULL;
- this->audio_port = NULL;
- this->input_plugin = NULL;
-
- /* create a new xine and load config file */
- this->xine = xine_new();
- if(!this->xine)
- return 0;
-
- /* Set xine engine logging verbosity */
- this->xine->verbosity = (SysLogLevel>2);
-
- /*xine_register_log_cb(this->xine, xine_log_cb, this);*/
-
- free(this->configfile);
- this->configfile = NULL;
- if (config_file)
- this->configfile = strdup(config_file);
- else if(asprintf(&this->configfile, "%s%s", xine_get_homedir(),
- "/.xine/config_xineliboutput") < 0)
- return 0;
-
- xine_config_load (this->xine, this->configfile);
-
- x_reg_num ("engine.buffers.video_num_buffers",
- 500,
- _("number of video buffers"),
- _("The number of video buffers "
- "(each is 8k in size) "
- "xine uses in its internal queue. "
- "Higher values "
- "mean smoother playback for unreliable "
- "inputs, but "
- "also increased latency and memory "
- "consumption."),
- 20, NULL, NULL);
- x_reg_bool("gui.osd_use_unscaled",
- 0,
- _("Use unscaled OSD"),
- _("Use unscaled (full screen resolution) OSD if possible"),
- 10, NULL, NULL);
-
- xine_init (this->xine);
-
- x_upd_num("video.device.xv_double_buffer", 1);
- x_upd_num("engine.buffers.video_num_buffers", pes_buffers);
-
- if(this->video_port_name) {
- if(video_driver && !strcmp(video_driver, "fb"))
- x_upd_str("video.device.fb_device", this->video_port_name);
- }
-
- this->playback_finished = 0;
-
- /* create video port */
- if(video_driver && !strcmp(video_driver, "none"))
- this->video_port = xine_open_video_driver(this->xine,
- video_driver,
- XINE_VISUAL_TYPE_NONE,
- NULL);
- else if(video_driver && !strcmp(video_driver, "dxr3"))
- this->video_port = xine_open_video_driver(this->xine,
- video_driver,
- XINE_VISUAL_TYPE_X11,
- NULL);
- else if(video_driver && !strcmp(video_driver, "aadxr3"))
- this->video_port = xine_open_video_driver(this->xine,
- video_driver,
- XINE_VISUAL_TYPE_AA,
- NULL);
- else
- this->video_port = xine_open_video_driver(this->xine,
- video_driver,
- this->xine_visual_type,
- (void *) &(this->vis));
- if(!this->video_port) {
- LOGMSG("fe_xine_init: xine_open_video_driver(\"%s\") failed",
- video_driver?video_driver:"(NULL)");
- xine_exit(this->xine);
- return 0;
- }
-
- intercept_video_driver(this->video_port);
-
- this->video_port_none = NULL;
-
- /* re-configure display size (DirectFB driver changes display mode in init) */
- if(this->update_display_size_cb)
- this->update_display_size_cb(this);
-
- /* create audio port */
-
- if(audio_driver && audio_port)
- configure_audio_out(this, audio_driver, audio_port);
-
- if(audio_driver && !strcmp(audio_driver, "auto")) {
- this->audio_port = xine_open_audio_driver (this->xine, NULL, NULL);
-#if XINE_VERSION_CODE < 10190
- } else if(audio_driver && !strcmp(audio_driver, "none")) {
- this->audio_port = _x_ao_new_port (this->xine, NULL, 1);
- this->audio_port->set_property(this->audio_port, AO_PROP_DISCARD_BUFFERS, 1);
-#endif
- } else {
- this->audio_port = xine_open_audio_driver (this->xine, audio_driver, NULL);
- }
-
- if(!this->audio_port && (audio_driver && !!strcmp(audio_driver, "none"))) {
- LOGMSG("fe_xine_init: xine_open_audio_driver(\"%s%s%s\") failed",
- audio_driver?audio_driver:"(NULL)",
- audio_port?":":"", audio_port?audio_port:"");
- }
-
- this->audio_port_none = NULL;
-
- /* create stream */
-
- this->stream = xine_stream_new(this->xine, this->audio_port, this->video_port);
- this->slave_stream = NULL;
-
- if(!this->stream) {
- LOGMSG("fe_xine_init: xine_stream_new failed");
- xine_exit(this->xine);
- return 0;
- }
-
- /* event handling */
-
- this->event_queue = xine_event_new_queue (this->stream);
- xine_event_create_listener_thread (this->event_queue, xine_event_cb, this);
-
- if(!this->event_queue)
- LOGMSG("fe_xine_init: xine_event_new_queue failed");
-
- /* misc. config */
-
- this->pes_buffers = pes_buffers;
-
- posts = this->postplugins = calloc(1, sizeof(post_plugins_t));
- posts->xine = this->xine;
- posts->audio_port = this->audio_port;
- posts->video_port = this->video_port;
- posts->video_source = posts->audio_source = this->stream;
-
- /* multithreaded decoding / post processing */
-
- if(guess_cpu_count() > 1) {
- if(!xine_check_version(1,1,9))
- LOGMSG("FFmpeg multithreaded video decoding is not supported in xine-lib < 1.1.9");
- else
- LOGMSG("Enabling FFmpeg multithreaded video decoding");
-
- /* try to enable anyway, maybe someone is using patched 1.1.8 ... */
- x_upd_num("video.processing.ffmpeg_thread_count", guess_cpu_count());
-#if 0
- LOGMSG("Enabling multithreaded post processing");
- vpplugin_parse_and_store_post(posts, "thread");
-#endif
- }
-
- /* static post plugins from command-line */
-
- if(static_post_plugins && *static_post_plugins) {
- int i;
- LOGDBG("static post plugins (from command line): %s", static_post_plugins);
- posts->static_post_plugins = strdup(static_post_plugins);
- vpplugin_parse_and_store_post(posts, posts->static_post_plugins);
- applugin_parse_and_store_post(posts, posts->static_post_plugins);
-
- for(i=0; i<posts->post_audio_elements_num; i++)
- if(posts->post_audio_elements[i])
- posts->post_audio_elements[i]->enable = 2;
- for(i=0; i<posts->post_video_elements_num; i++)
- if(posts->post_video_elements[i])
- posts->post_video_elements[i]->enable = 2;
- posts->post_video_enable = 1;
- posts->post_audio_enable = 1;
- }
-
- this->video_width = this->video_height = 0;
-
- return 1;
-}
-
-/*
- * fe_xine_open
- *
- * open xine stream
- */
-
-static int fe_xine_open(frontend_t *this_gen, const char *mrl)
-{
- fe_t *this = (fe_t*)this_gen;
- int result = 0;
- char *url = NULL;
-
- if(!this)
- return 0;
-
- this->input_plugin = NULL;
- this->playback_finished = 1;
- this->terminate_key_pressed = 0;
-
- if (asprintf(&url, "%s#nocache", mrl ? : MRL_ID "://") < 0)
- return 0;
-
- result = xine_open(this->stream, url);
-
- if(!result) {
- LOGMSG("fe_xine_open: xine_open(\"%s\") failed", url);
- free(url);
- return 0;
- }
- free(url);
-
-#if 0
- this->xine->config->update_num(this->xine->config,
- "video.output.xv_double_buffer",
- 1);
-#endif
- x_upd_num("engine.buffers.video_num_buffers", this->pes_buffers);
-
- return result;
-}
-
-/*
- * post plugin handling
- *
- */
-
-#define POST_AUDIO_VIS 0
-#define POST_AUDIO 1
-#define POST_VIDEO 2
-#define POST_VIDEO_PIP 3
-
-
-static void init_dummy_ports(fe_t *this, int on)
-{
- if(!on) {
- if(this->slave_stream)
- LOGMSG("ERROR: init_dummy_ports(false) called while port is still in use !");
-
- if(this->audio_port_none)
- xine_close_audio_driver(this->xine, this->audio_port_none);
- this->audio_port_none = NULL;
- if(this->video_port_none)
- xine_close_video_driver(this->xine, this->video_port_none);
- this->video_port_none = NULL;
- } else {
- if(! this->audio_port_none)
-#if XINE_VERSION_CODE < 10190
- this->audio_port_none = _x_ao_new_port (this->xine, NULL, 1);
-#else
- this->audio_port_none = NULL;/*xine_new_framegrab_audio_port(this->xine);*/
-#endif
- if(this->audio_port_none)
- this->audio_port_none->set_property(this->audio_port_none, AO_PROP_DISCARD_BUFFERS, 1);
- /*LOGMSG("initialized dummy audio port %x", this->audio_port_none);*/
-#if 0
- if(! this->video_port_none)
- this->video_port_none =
- _x_vo_new_port(this->xine,
- _x_load_video_output_plugin(this->xine, "none",
- XINE_VISUAL_TYPE_NONE, NULL),
- 1);
- this->video_port_none->set_property(this->video_port_none, VO_PROP_DISCARD_FRAMES, 1);
-#endif
- }
-}
-
-static void fe_post_unwire(fe_t *this)
-{
- xine_post_out_t *vo_source = xine_get_video_source(this->stream);
- xine_post_out_t *ao_source = xine_get_audio_source(this->stream);
-
- if(this->slave_stream &&
- this->slave_stream == this->postplugins->audio_source) {
- LOGDBG("unwiring slave stream audio post plugins");
- init_dummy_ports(this, 1);
-
- if(ao_source && this->audio_port_none)
- (void) xine_post_wire_audio_port(ao_source, this->audio_port_none);
-
- ao_source = xine_get_audio_source(this->slave_stream);
- if(ao_source && this->audio_port)
- (void) xine_post_wire_audio_port(ao_source, this->audio_port);
-
- } else {
- LOGDBG("unwiring audio post plugins");
- init_dummy_ports(this, 0);
- if(ao_source && this->audio_port)
- (void) xine_post_wire_audio_port(ao_source, this->audio_port);
- }
-
- if(this->slave_stream &&
- this->slave_stream == this->postplugins->video_source) {
- LOGDBG("unwiring slave stream video post plugins");
- /*init_dummy_ports(this, 1);*/
- /*(void) xine_post_wire_video_port(vo_source, this->video_port_none);*/
-
- vo_source = xine_get_video_source(this->slave_stream);
- if(vo_source && this->video_port)
- (void) xine_post_wire_video_port(vo_source, this->video_port);
-
- } else {
- LOGDBG("unwiring video post plugins");
- /*init_dummy_ports(this, 0);*/
- if(vo_source && this->video_port)
- (void) xine_post_wire_video_port(vo_source, this->video_port);
- }
-}
-
-static void fe_post_rewire(const fe_t *this)
-{
- LOGDBG("re-wiring post plugins");
- vpplugin_rewire_posts(this->postplugins);
- applugin_rewire_posts(this->postplugins);
-}
-
-static void fe_post_unload(const fe_t *this)
-{
- LOGDBG("unloading post plugins");
- vpplugin_unload_post(this->postplugins, NULL);
- applugin_unload_post(this->postplugins, NULL);
-}
-
-static void fe_post_close(const fe_t *this, const char *name, int which)
-{
- post_plugins_t *posts = this->postplugins;
-
- if(!this)
- return;
-
- if(name && !strcmp(name, "AudioVisualization")) {
- name = NULL;
- which = POST_AUDIO_VIS;
- }
- if(name && !strcmp(name, "Pip")) {
- name = NULL;
- which = POST_VIDEO_PIP;
- }
-
- /* by name */
- if(name) {
- LOGDBG("closing post plugin: %s", name);
- if(applugin_unload_post(posts, name)) {
- /*LOGDBG(" * rewiring audio");*/
- applugin_rewire_posts(posts);
- return;
- }
- if(vpplugin_unload_post(posts, name)) {
- /*LOGDBG(" * rewiring video");*/
- vpplugin_rewire_posts(posts);
- return;
- }
- return;
- }
-
- /* by type */
- if(which == POST_AUDIO_VIS || which < 0) { /* audio visualization */
- if(posts->post_vis_elements_num &&
- posts->post_vis_elements &&
- posts->post_vis_elements[0]) {
- LOGDBG("Closing audio visualization post plugins");
- if(applugin_unload_post(posts, posts->post_vis_elements[0]->name)) {
- /*LOGDBG(" * rewiring audio");*/
- applugin_rewire_posts(posts);
- }
- }
- }
-
- if(which == POST_AUDIO || which < 0) { /* audio effect(s) */
- LOGDBG("Closing audio post plugins");
- if(applugin_disable_post(posts, NULL)) {
- /*LOGDBG(" * rewiring audio");*/
- applugin_rewire_posts(posts);
- }
- }
- if(which == POST_VIDEO || which < 0) { /* video effect(s) */
- LOGDBG("Closing video post plugins");
- if(vpplugin_unload_post(posts, NULL)) {
- /*LOGDBG(" * rewiring video");*/
- vpplugin_rewire_posts(posts);
- }
- }
-
- if(which == POST_VIDEO_PIP || which < 0) { /* Picture-In-Picture */
- if(posts->post_pip_elements_num &&
- posts->post_pip_elements &&
- posts->post_pip_elements[0]) {
- LOGDBG("Closing PIP (mosaico) post plugins");
- if(vpplugin_unload_post(posts, "mosaico")) {
- /*LOGDBG(" * rewiring video");*/
- vpplugin_rewire_posts(posts);
- }
- }
- }
-}
-
-static int get_opt_val(const char *s, const char *opt)
-{
- int val = -1;
- const char *pt = strstr(s, opt);
- if(pt)
- if(1 == sscanf(pt+strlen(opt)+1, "%d", &val))
- return val;
- return -1;
-}
-
-static void fe_post_open(const fe_t *this, const char *name, const char *args)
-{
- post_plugins_t *posts = this->postplugins;
- char initstr[1024];
- int found = 0;
-
- if(!this || !this->xine || !this->stream || !name)
- return;
-
- /* pip */
- if(!strcmp(name, "Pip")) {
- posts->post_pip_enable = 1;
- name = "mosaico";
- if(!posts->post_pip_elements ||
- !posts->post_vis_elements[0] ||
- !posts->post_vis_elements[0]->enable)
- LOGMSG("enabling picture-in-picture (\"%s:%s\") post plugin", name, args);
- }
-
- if(args) {
- snprintf(initstr, sizeof(initstr), "%s:%s", name, args);
- initstr[sizeof(initstr)-1] = 0;
- } else
- strn0cpy(initstr, name, sizeof(initstr));
-
- /* swscale aspect ratio */
- if (!strcmp(name, "swscale")) {
- char *pt = strstr(initstr, "output_aspect=auto");
- if (pt) {
- char tmp[16];
- double r = 0.0;
- pt += 14;
- switch(this->aspect) {
- case 0:
- case 1: /* */ r = this->display_ratio * (double)this->width / (double)this->height; break;
- case 2: /* 4:3 */ r = 4.0/3.0; break;
- case 3: /* 16:9 */ r = 16.0/9.0; break;
- case 4: /* 16:10 */ r = 16.0/10.0; break;
- }
- /* in finnish locale decimal separator is "," - same as post plugin parameter separator :( */
- sprintf(tmp, "%04d", (int)(r*1000.0));
- strncpy(pt, tmp, 4);
- }
- }
-
- LOGDBG("opening post plugin: %s", initstr);
-
- /* close old audio visualization plugin */
- if(!strcmp(name,"goom") ||
- !strcmp(name,"oscope") ||
- !strcmp(name,"fftscope") ||
- !strcmp(name,"fftgraph") ||
- !strcmp(name,"fooviz")) {
-
- /* close if changed */
- if(posts->post_vis_elements_num &&
- posts->post_vis_elements &&
- posts->post_vis_elements[0] &&
- strcmp(name, posts->post_vis_elements[0]->name)) {
-
- fe_post_close(this, NULL, POST_AUDIO_VIS);
- }
-
- if(!found && applugin_enable_post(posts, initstr, &found)) {
- posts->post_vis_enable = 1;
- applugin_rewire_posts(posts);
-
- // goom wants options thru config ...
- if(args && !strcmp(name,"goom")) {
- int val;
- if((val = get_opt_val(initstr, "fps")) > 0)
- x_upd_num ("effects.goom.fps", val );
- if((val = get_opt_val(initstr, "width")) > 0)
- x_upd_num ("effects.goom.width", val);
- if((val = get_opt_val(initstr, "height")) > 0)
- x_upd_num ("effects.goom.height", val);
- //if((val = get_opt_val(initstr, "csc_method"))>0)
- // this->xine->config->update_enum (this->xine->config, "effects.goom.csc_method", val);
- }
- }
-
- } else {
-
- /* video filters */
- if(strcmp(name, "audiochannel") &&
- strcmp(name, "volnorm") &&
- strcmp(name, "stretch") &&
- strcmp(name, "upmix_mono") &&
- strcmp(name, "upmix") &&
- vpplugin_enable_post(posts, initstr, &found)) {
-
- posts->post_video_enable = 1;
- vpplugin_rewire_posts(posts);
- }
-
- /* audio filters */
- if(!found && applugin_enable_post(posts, initstr, &found)) {
- posts->post_audio_enable = 1;
- applugin_rewire_posts(posts);
- }
- }
-
- if(!found)
- LOGMSG("Can't load post plugin %s", name);
- else
- LOGDBG("Post plugin %s loaded and wired", name);
-}
-
-static int fe_xine_play(frontend_t *this_gen)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!this)
- return 0;
-
- fe_post_rewire(this);
-
- this->input_plugin = NULL;
- this->playback_finished = xine_play(this->stream, 0, 0) ? 0 : 1;
-
- if(!find_input_plugin(this))
- return -1;
-
- this->input_plugin->f.xine_input_event = this->keypress;
- this->input_plugin->f.fe_control = fe_control;
- this->input_plugin->f.fe_handle = this_gen;
-
- if(this->playback_finished)
- LOGMSG("Error playing " MRL_ID ":// !");
-
- char str[128];
- snprintf(str, sizeof(str), "INFO WINDOW %dx%d", this->width, this->height);
- this->fe.send_event(&this->fe, str);
-
- return !this->playback_finished;
-}
-
-static int fe_xine_stop(frontend_t *this_gen)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!this)
- return 0;
-
- this->input_plugin = NULL;
- this->playback_finished = 1;
-
- xine_stop(this->stream);
-
- fe_post_unwire(this);
-
- return 1;
-}
-
-static void fe_xine_close(frontend_t *this_gen)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!this)
- return;
-
- if (this && this->xine) {
- if(this->input_plugin) {
- this->input_plugin->f.xine_input_event = NULL;
- this->input_plugin->f.fe_control = NULL;
- }
-
- fe_xine_stop(this_gen);
-
- fe_post_unload(this);
-
- xine_close(this->stream);
- if(this->postplugins->pip_stream)
- xine_close(this->postplugins->pip_stream);
- }
-}
-
-static void fe_xine_exit(frontend_t *this_gen)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if (this && this->xine) {
-
- if(this->input_plugin || !this->playback_finished)
- fe_xine_close(this_gen);
- fe_post_unload(this);
-
- if(this->configfile) {
- xine_config_save (this->xine, this->configfile);
- free(this->configfile);
- this->configfile = NULL;
- }
- if(this->event_queue)
- xine_event_dispose_queue(this->event_queue);
- this->event_queue = NULL;
-
- if(this->stream)
- xine_dispose(this->stream);
- this->stream = NULL;
-
- if(this->postplugins->pip_stream)
- xine_dispose(this->postplugins->pip_stream);
- this->postplugins->pip_stream = NULL;
-
- if(this->slave_stream)
- xine_dispose(this->slave_stream);
- this->slave_stream = NULL;
-
- if(this->audio_port)
- xine_close_audio_driver(this->xine, this->audio_port);
- this->audio_port = NULL;
-
- init_dummy_ports(this, 0);
-
- if(this->video_port)
- xine_close_video_driver(this->xine, this->video_port);
- this->video_port = NULL;
-
- if(this->postplugins->static_post_plugins)
- free(this->postplugins->static_post_plugins);
- free(this->postplugins);
- this->postplugins = NULL;
-
- xine_exit(this->xine);
- this->xine = NULL;
- }
-}
-
-static void fe_free(frontend_t *this_gen)
-{
- if (this_gen) {
- fe_t *this = (fe_t*)this_gen;
- this->fe.fe_display_close(this_gen);
- free(this->configfile);
- free(this);
- }
-}
-
-static int fe_is_finished(frontend_t *this_gen, int slave_stream)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!this || this->playback_finished)
- return FE_XINE_ERROR;
- if(this->terminate_key_pressed)
- return FE_XINE_EXIT;
-
- if(slave_stream) {
- if(!this->slave_stream || this->slave_playback_finished)
- return FE_XINE_EXIT;
- }
-
- return FE_XINE_RUNNING;
-}
-
-/************************** hooks to input plugin ****************************/
-
-/*
- * data/control from VDR
- */
-
-static int xine_control(frontend_t *this_gen, const char *cmd)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!find_input_plugin(this))
- return -1;
-
- return this->input_plugin->f.push_input_control(this->input_plugin, cmd);
-}
-
-static int xine_osd_command(frontend_t *this_gen, struct osd_command_s *cmd) {
- fe_t *this = (fe_t*)this_gen;
-
- if(!find_input_plugin(this))
- return -1;
-
- return this->input_plugin->f.push_input_osd(this->input_plugin, cmd);
-}
-
-static int xine_queue_pes_packet(frontend_t *this_gen, const char *data, int len)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if(!find_input_plugin(this))
- return 0/*-1*/;
-
- return this->input_plugin->f.push_input_write(this->input_plugin, data, len);
-}
-
-/*
- * control from frontend to xine/vdr
- */
-
-
-static int fe_send_input_event(frontend_t *this_gen, const char *map,
- const char *key, int repeat, int release)
-{
- fe_t *this = (fe_t*)this_gen;
-
- LOGDBG("Keypress: %s %s %s %s",
- map, key, repeat?"Repeat":"", release?"Release":"");
-
- /* local mode: --> vdr callback */
- if(this->keypress) {
- this->keypress(map, key);
- return FE_OK;
- }
-
- /* remote mode: --> input plugin --> vdr */
- if (find_input_plugin(this)) {
- if (this->input_plugin->f.post_vdr_event) {
-
- char *msg = NULL;
- if (map) {
- if (asprintf(&msg, "KEY %s %s %s %s\r\n", map, key,
- repeat?"Repeat":"", release?"Release":"") < 0)
- msg = NULL;
- } else {
- if (asprintf(&msg, "KEY %s\r\n", key) < 0)
- msg = NULL;
- }
-
- if (msg) {
- int r = this->input_plugin->f.post_vdr_event(this->input_plugin, msg);
- free(msg);
- if (r > 0)
- return FE_OK;
- }
- LOGMSG("fe_send_input_event: message KEY %s lost", key);
- return FE_ERROR;
- }
- }
-
- LOGMSG("fe_send_input_event: handler not set, event lost !");
- return FE_ERROR;
-}
-
-
-static int fe_send_event(frontend_t *this_gen, const char *data)
-{
- fe_t *this = (fe_t*)this_gen;
-
- if (!data)
- return FE_ERROR;
-
- if (!strcmp(data, "TOGGLE_FULLSCREEN")) {
- if(this->toggle_fullscreen_cb)
- this->toggle_fullscreen_cb(this);
-
- } else if (!strcmp(data, "QUIT")) {
- this->terminate_key_pressed = 1;
-
- } else if(!strcmp(data, "TOGGLE_DEINTERLACE")) {
- xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE,
- xine_get_param(this->stream, XINE_PARAM_VO_DEINTERLACE) ? 0 : 1);
-
- } else if(!strncasecmp(data, "DEINTERLACE ", 12)) {
- xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE, atoi(data+12) ? 1 : 0);
-
- } else {
-
- LOGDBG("Event: %s", data);
-
- /* local mode: --> vdr callback */
- if (this->keypress) {
- this->keypress(data, NULL);
- return FE_OK;
- }
-
- /* remote mode: --> input plugin --> vdr */
- if (find_input_plugin(this)) {
- if (this->input_plugin->f.post_vdr_event) {
- char *msg = NULL;
- if (asprintf(&msg, "%s\r\n", data) < 1)
- msg = NULL;
- if (msg) {
- int r = this->input_plugin->f.post_vdr_event(this->input_plugin, msg);
- free(msg);
- return (r > 0) ? FE_OK : FE_ERROR;
- }
- return FE_ERROR;
- }
- }
- }
-
- return FE_OK;
-}
-
-/*
- * Control messages from input plugin
- */
-static void *fe_control(frontend_t *this_gen, const char *cmd)
-{
- fe_t *this = (fe_t*)this_gen;
- post_plugins_t *posts;
-
- /*LOGDBG("fe_control(\"%s\")", cmd);*/
-
- if(!cmd || !this) {
- LOGMSG("fe_control(0x%lx,0x%lx) : invalid argument",
- (unsigned long int)this_gen, (unsigned long int)cmd);
- return NULL;
- }
-
- posts = this->postplugins;
-
- if(!posts) {
- LOGMSG("fe_control : this->posts == NULL");
- return NULL;
- }
-
- if(!strncmp(cmd, "SLAVE CLOSED", 16)) {
- /*LOGMSG("fe_control : slave closed");*/
- if(this->slave_stream)
- fe_control(this_gen, "SLAVE 0x0\r\n");
- init_dummy_ports(this, 0);
- this->video_width = this->video_height = 0;
-
- } else if(!strncmp(cmd, "SLAVE 0x", 8)) {
- unsigned long pt;
- if(1 == sscanf(cmd+8, "%lx", &pt)) {
- xine_stream_t *slave_stream = (xine_stream_t*)pt;
- if(this->slave_stream != slave_stream) {
-
- fe_post_unwire(this);
-
- if(this->slave_stream) {
- /*xine_post_out_t *vo_source = xine_get_video_source(posts->slave_stream);*/
- if(this->slave_stream == this->postplugins->audio_source) {
- xine_post_out_t *ao_source = xine_get_audio_source(this->slave_stream);
- LOGMSG("unwiring slave stream from output");
- /*(void) xine_post_wire_video_port(vo_source, this->video_port_none);*/
- (void) xine_post_wire_audio_port(ao_source, this->audio_port_none);
- }
- }
-
- this->slave_stream = slave_stream;
-
- this->postplugins->video_source = this->postplugins->audio_source =
- this->slave_stream ?: this->stream;
- if(strstr(cmd, "Video")) /* video only, audio from VDR */
- this->postplugins->audio_source = this->stream;
- if(strstr(cmd, "Audio")) /* audio only, video from VDR */
- this->postplugins->video_source = this->stream;
-
- if(this->slave_stream)
- fe_post_unwire(this);
-
- fe_post_rewire(this);
- }
- this->slave_playback_finished = !slave_stream;
- this->video_width = this->video_height = 0;
- }
-
- } else if(!strncmp(cmd, "ENDOFSTREAM", 11)) {
- if(this->slave_stream)
- this->slave_playback_finished = 1;
-
- } else if(!strncmp(cmd, "SUBSTREAM ", 10)) {
- unsigned int pid;
- int x, y, w, h;
- if(5 == sscanf(cmd+10, "0x%x %d %d %d %d", &pid, &x, &y, &w, &h)) {
- char mrl[256];
- if(!posts->pip_stream)
- posts->pip_stream = xine_stream_new(this->xine,
- this->audio_port,
- this->video_port);
- LOGMSG(" PIP %d: %dx%d @ (%d,%d)", pid & 0x0f, w, h, x, y);
- LOGMSG("create pip stream done");
- sprintf(mrl, MRL_ID "+slave://0x%lx#nocache",
- (unsigned long int)this);
- if(!xine_open(posts->pip_stream, mrl) ||
- !xine_play(posts->pip_stream, 0, 0)) {
- LOGERR(" pip stream open/play failed");
- } else {
- char params[64];
- sprintf(params, "pip_num=1,x=%d,y=%d,w=%d,h=%d", x,y,w,h);
- fe_post_open(this, "Pip", params);
- return posts->pip_stream;
- }
- }
- fe_post_close(this, NULL, POST_VIDEO_PIP);
- if(posts->pip_stream) {
- xine_close(posts->pip_stream);
- xine_dispose(posts->pip_stream);
- posts->pip_stream = NULL;
- }
- return NULL;
-
- } else if(!strncmp(cmd, "POST ", 5)) {
- char *name = strdup(cmd+5), *args = name, *pt;
-
- if(NULL != (pt=strchr(name, '\r')))
- *pt = 0;
- if(NULL != (pt=strchr(name, '\n')))
- *pt = 0;
-
- while(*args && *args != ' ') /* skip name */
- args++;
- if(*args /*== ' '*/)
- *args++ = 0;
-
- while(*args && *args == ' ') /* skip whitespace between name and args */
- args++;
-
- /*this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 0);*/
- /* - locks local frontend at startup */
- if(!strncmp(args, "On", 2)) {
- args += 2;
- while(*args == ' ')
- args++;
- /*LOGDBG(" POST: %s On \"%s\"", name, args);*/
- fe_post_open(this, name, args);
- } else if(!strncmp(args, "Off", 3)) {
- /*LOGDBG(" POST: %s Off (name len=%d), name => int = %d", name, strlen(name), atoi(name));*/
- if(strlen(name) == 1)
- fe_post_close(this, NULL, atoi(name));
- else
- fe_post_close(this, name, -1);
- } else {
- LOGMSG("fe_control: POST: unknown command %s", cmd);
- }
- /*this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 0);*/
- /* - locks local frontend at startup */
- free(name);
- return NULL;
-
- } else if(!strncmp(cmd, "GRAB ", 5)) {
- int quality, width, height, jpeg, size=0;
- jpeg = !strncmp(cmd+5,"JPEG",4);
- if(3 == sscanf(cmd+5+4, "%d %d %d", &quality, &width, &height)) {
- grab_data_t *result = (grab_data_t*)malloc(sizeof(grab_data_t));
- result->data = this->fe.grab((frontend_t*)this, &size,
- jpeg, quality, width, height);
- if(result->data && (result->size=size)>0)
- return result;
- free(result->data);
- free(result);
- }
-
- } else if(!strncmp(cmd, "OVERSCAN ", 9)) {
- int overscan;
- if(1 == sscanf(cmd+9, "%d", &overscan)) {
- int crop_x = overscan * this->width / 100 / 2;
- int crop_y = overscan * this->height / 100 / 2;
- this->overscan = overscan;
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, crop_x);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, crop_y);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, crop_x);
- xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, crop_y);
- /* trigger forced redraw to make changes effective */
- xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, 100);
- }
- }
-
-
- return NULL;
-}
-
-/*
- * --- RgbToJpeg -------------------------------------------------------------
- *
- * source: vdr-1.3.42, tools.c
- * modified to accept YUV data
- *
- * - move to xine_input_vdr ?
- */
-
-#ifdef HAVE_LIBJPEG
-
-#define JPEGCOMPRESSMEM 500000
-
-typedef struct tJpegCompressData_s {
- int size;
- unsigned char *mem;
-} tJpegCompressData;
-
-static void JpegCompressInitDestination(const j_compress_ptr cinfo)
-{
- tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
- if (jcd) {
- cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM;
- cinfo->dest->next_output_byte = jcd->mem =
- (unsigned char *)malloc(jcd->size);
- }
-}
-
-static boolean JpegCompressEmptyOutputBuffer(const j_compress_ptr cinfo)
-{
- tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
- if (jcd) {
- int Used = jcd->size;
- jcd->size += JPEGCOMPRESSMEM;
- jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size);
- if (jcd->mem) {
- cinfo->dest->next_output_byte = jcd->mem + Used;
- cinfo->dest->free_in_buffer = jcd->size - Used;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static void JpegCompressTermDestination(const j_compress_ptr cinfo)
-{
- tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
- if (jcd) {
- int Used = cinfo->dest->next_output_byte - jcd->mem;
- if (Used < jcd->size) {
- jcd->size = Used;
- jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size);
- }
- }
-}
-
-static vo_frame_t *yuy2_to_yv12_frame(xine_stream_t *stream, vo_frame_t *frame)
-{
- /* convert yuy12 frames to yv12 */
- if (frame && frame->format == XINE_IMGFMT_YUY2) {
- stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0);
- vo_frame_t *img = stream->video_out->get_frame (stream->video_out,
- frame->width, frame->height,
- frame->ratio, XINE_IMGFMT_YV12,
- VO_BOTH_FIELDS);
- stream->xine->port_ticket->release(stream->xine->port_ticket, 0);
-
- if (!img) {
- LOGMSG("yuy2_to_yv12_frame: get_frame failed");
- frame->free(frame);
- return NULL;
- }
-
- init_yuv_conversion();
- yuy2_to_yv12(frame->base[0], frame->pitches[0],
- img->base[0], img->pitches[0],
- img->base[1], img->pitches[1],
- img->base[2], img->pitches[2],
- frame->width, frame->height);
-
- frame->free(frame);
- return img;
- }
-
- return frame;
-}
-
-static char *frame_compress_jpeg(fe_t *this, int *size, int quality, vo_frame_t *frame)
-{
- struct jpeg_destination_mgr jdm;
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- tJpegCompressData jcd;
-
- /* convert yuy2 frames to yv12 */
- frame = yuy2_to_yv12_frame(this->stream, frame);
-
- /* Compress JPEG */
-
- jdm.init_destination = JpegCompressInitDestination;
- jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
- jdm.term_destination = JpegCompressTermDestination;
-
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- cinfo.dest = &jdm;
-
- cinfo.client_data = &jcd;
- cinfo.image_width = frame->width;
- cinfo.image_height = frame->height;
-
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_YCbCr;
-
- switch (frame->format) {
- case XINE_IMGFMT_YV12: {
- JSAMPARRAY pp[3];
- JSAMPROW *rpY = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height);
- JSAMPROW *rpU = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height);
- JSAMPROW *rpV = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height);
- int k;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality, TRUE);
- cinfo.raw_data_in = TRUE;
-
- jpeg_set_colorspace(&cinfo, JCS_YCbCr);
- cinfo.comp_info[0].h_samp_factor =
- cinfo.comp_info[0].v_samp_factor = 2;
- cinfo.comp_info[1].h_samp_factor =
- cinfo.comp_info[1].v_samp_factor =
- cinfo.comp_info[2].h_samp_factor =
- cinfo.comp_info[2].v_samp_factor = 1;
- jpeg_start_compress(&cinfo, TRUE);
-
- for (k = 0; k < frame->height; k+=2) {
- rpY[k] = frame->base[0] + k*frame->pitches[0];
- rpY[k+1] = frame->base[0] + (k+1)*frame->pitches[0];
- rpU[k/2] = frame->base[1] + (k/2)*frame->pitches[1];
- rpV[k/2] = frame->base[2] + (k/2)*frame->pitches[2];
- }
- for (k = 0; k < frame->height; k+=2*DCTSIZE) {
- pp[0] = &rpY[k];
- pp[1] = &rpU[k/2];
- pp[2] = &rpV[k/2];
- jpeg_write_raw_data(&cinfo, pp, 2*DCTSIZE);
- }
- free(rpY);
- free(rpU);
- free(rpV);
- break;
- }
-#if 0
- case XINE_IMGFMT_RGB: {
- JSAMPROW rp[height];
- int rs, k;
-
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality, TRUE);
- jpeg_start_compress(&cinfo, TRUE);
-
- rs = frame->pitches[0];
- for (k = 0; k < height; k++)
- rp[k] = frame->base[0] + k*rs;
- jpeg_write_scanlines(&cinfo, rp, height);
- break;
- }
-#endif
- default:
- LOGMSG("fe_grab: grabbing failed (unsupported image format %d)",
- frame->format);
- break;
- }
-
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
- frame->free(frame);
-
- *size = jcd.size;
- return (char*) jcd.mem;
-}
-
-#endif /* HAVE_LIBJPEG */
-
-static vo_frame_t *yv12_to_yuy2_frame(xine_stream_t *stream, vo_frame_t *frame)
-{
- /* convert yv12 frames to yuy2 */
- if (frame && frame->format == XINE_IMGFMT_YV12) {
- stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0);
- vo_frame_t *img = stream->video_out->get_frame (stream->video_out,
- frame->width, frame->height,
- frame->ratio, XINE_IMGFMT_YUY2,
- VO_BOTH_FIELDS);
- stream->xine->port_ticket->release(stream->xine->port_ticket, 0);
-
- if (!img) {
- LOGMSG("yv12_to_yuy2_frame: get_frame failed");
- frame->free(frame);
- return NULL;
- }
-
- init_yuv_conversion();
- yv12_to_yuy2(frame->base[0], frame->pitches[0],
- frame->base[1], frame->pitches[1],
- frame->base[2], frame->pitches[2],
- img->base[0], img->pitches[0],
- frame->width, frame->height,
- frame->progressive_frame);
-
- frame->free(frame);
- return img;
- }
-
- return frame;
-}
-
-#define YCBCR_TO_RGB( y, cb, cr, r, g, b ) \
- do { \
- int _y, _cb, _cr, _r, _g, _b; \
- _y = ((y) - 16) * 76309; \
- _cb = (cb) - 128; \
- _cr = (cr) - 128; \
- _r = (_y + _cr * 104597 + 0x8000) >> 16; \
- _g = (_y - _cb * 25675 - _cr * 53279 + 0x8000) >> 16; \
- _b = (_y + _cb * 132201 + 0x8000) >> 16; \
- (r) = (_r < 0) ? 0 : ((_r > 255) ? 255 : _r); \
- (g) = (_g < 0) ? 0 : ((_g > 255) ? 255 : _g); \
- (b) = (_b < 0) ? 0 : ((_b > 255) ? 255 : _b); \
-} while (0)
-
-static char *frame_compress_pnm(fe_t *this, int *size, vo_frame_t *frame)
-{
- /* ensure yuy2 */
- if (!(frame = yv12_to_yuy2_frame(this->stream, frame)))
- return NULL;
-
- /* convert to PNM */
-
- /* allocate memory for result */
- size_t bytes = frame->width * frame->height * 3;
- uint8_t *pnm = malloc(bytes + 64);
- if (!pnm) {
- LOGMSG("fe_grab: malloc failed");
- return NULL;
- }
-
- /* PNM header */
- sprintf((char*)pnm, "P6\n%d\n%d\n255\n", frame->width, frame->height);
- int hdrlen = strlen((char*)pnm);
- uint8_t *p = pnm + hdrlen;
- uint8_t *s = frame->base[0];
- int x, y;
-
- *size = bytes + hdrlen;
-
- /* convert to RGB */
- for (y=0; y < frame->height; y++) {
- for (x=0; x < frame->width; x+=2, s+=4, p+=6) {
- YCBCR_TO_RGB(s[0], s[1], s[3], p[0], p[1], p[2]);
- YCBCR_TO_RGB(s[2], s[1], s[3], p[3], p[4], p[5]);
- }
- s = frame->base[0] + y*frame->pitches[0];
- }
-
- return (char*)pnm;
-}
-
-#ifdef XINE_GUI_SEND_GRAB_FRAME
-static char *fe_grab_raw_frame(fe_t *this, int *size, int jpeg, int quality, int width, int height, xine_grab_frame_t *frame)
-{
- frame->width = width;
- frame->height = height;
- if (xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_GRAB_FRAME, frame))
- return NULL;
-
-#ifdef HAVE_LIBJPEG
- if (jpeg) {
- /* Compress JPEG */
- struct jpeg_destination_mgr jdm;
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- tJpegCompressData jcd;
-
- jdm.init_destination = JpegCompressInitDestination;
- jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
- jdm.term_destination = JpegCompressTermDestination;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- cinfo.dest = &jdm;
- cinfo.client_data = &jcd;
- cinfo.image_width = width;
- cinfo.image_height = height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality, TRUE);
- jpeg_start_compress(&cinfo, TRUE);
-
- JSAMPROW rp[height];
- int rs = width * 3;
- int k;
- for (k = 0; k < height; k++)
- rp[k] = frame->img + k * rs;
- jpeg_write_scanlines(&cinfo, rp, height);
-
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
-
- *size = jcd.size;
- return (char*) jcd.mem;
- }
-#endif
-
- /* convert to PNM */
-
- /* allocate memory for result */
- size_t bytes = width * height * 3;
- uint8_t *pnm = malloc(bytes + 64);
- if (!pnm) {
- LOGMSG("fe_grab: malloc failed");
- return NULL;
- }
-
- /* PNM header */
- sprintf((char*)pnm, "P6\n%d\n%d\n255\n", width, height);
- int hdrlen = strlen((char*)pnm);
-
- /* copy image */
- xine_fast_memcpy(pnm + hdrlen, frame->img, bytes);
-
- *size = bytes + hdrlen;
- return (char*)pnm;
-}
-#endif
-
-static char *fe_grab(frontend_t *this_gen, int *size, int jpeg,
- int quality, int width, int height)
-{
- fe_t *this = (fe_t*)this_gen;
- vo_frame_t *frame;
-
-#ifndef HAVE_LIBJPEG
- if(jpeg) {
- LOGMSG("fe_grab: JPEG grab support was not compiled in");
- return 0;
- }
-#endif /* HAVE_LIBJPEG */
-
- if(!find_input_plugin(this))
- return 0;
-
- LOGDBG("fe_grab: grabbing %s %d %dx%d",
- jpeg ? "JPEG" : "PNM", quality, width, height);
-
- /* validate parameters */
- if ((quality < 0) || (quality > 100))
- quality = 100;
- width = (MAX(16, MIN(width, 1920)) + 1) & ~1; /* 16...1920, even */
- height = (MAX(16, MIN(width, 1200)) + 1) & ~1; /* 16...1200, even */
-
- /* get last frame */
- this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 0);
-#ifdef XINE_GUI_SEND_GRAB_FRAME
- xine_grab_frame_t *grab_frame;
- if (!xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_ALLOC_GRAB_FRAME, &grab_frame)) {
- char *img = fe_grab_raw_frame(this, size, jpeg, quality, width, height, grab_frame);
- xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame);
- this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 0);
- return img;
- }
-#endif
- frame = this->stream->video_out->get_last_frame (this->stream->video_out);
- if(frame)
- frame->lock(frame);
- this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 0);
-
- if(!frame) {
- LOGMSG("fe_grab: get_last_frame() failed");
- return NULL;
- }
-
- /* Scale image */
- if (frame->width != width || frame->height != height) {
- /* #warning TODO - scaling here */
- LOGMSG("fe_grab: scaling not implemented");
- }
-
- if (!jpeg)
- return frame_compress_pnm(this, size, frame);
-
-#ifdef HAVE_LIBJPEG
- return frame_compress_jpeg(this, size, quality, frame);
-#else /* HAVE_LIBJPEG */
- return NULL;
-#endif
-}
-
-/*
- * init_fe()
- *
- * initialize function pointers
- */
-void init_fe(fe_t *fe)
-{
- fe->fe.xine_init = fe_xine_init;
- fe->fe.xine_open = fe_xine_open;
- fe->fe.xine_play = fe_xine_play;
- fe->fe.xine_stop = fe_xine_stop;
- fe->fe.xine_close = fe_xine_close;
- fe->fe.xine_exit = fe_xine_exit;
-
- fe->fe.fe_free = fe_free;
-
- fe->fe.xine_is_finished = fe_is_finished;
-
- fe->fe.xine_osd_command = xine_osd_command;
- fe->fe.xine_control = xine_control;
- fe->fe.xine_queue_pes_packet = xine_queue_pes_packet;
-
- fe->fe.grab = fe_grab;
-
- fe->fe.send_event = fe_send_event;
- fe->fe.send_input_event = fe_send_input_event;
-
- fe->dest_pixel_aspect = fe_dest_pixel_aspect;
- fe->frame_output_handler = fe_frame_output_cb;
-}
-