summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_out/audio_alsa_out.c44
-rw-r--r--src/audio_out/audio_jack_out.c1141
-rw-r--r--src/audio_out/audio_oss_out.c33
-rw-r--r--src/demuxers/demux_qt.c4
-rw-r--r--src/demuxers/demux_ts.c17
-rw-r--r--src/input/input_dvb.c71
-rw-r--r--src/input/input_http.c24
-rw-r--r--src/input/input_plugin.h7
-rw-r--r--src/input/input_pnm.c2
-rw-r--r--src/input/input_rtsp.c2
-rw-r--r--src/input/input_v4l.c21
-rw-r--r--src/input/net_buf_ctrl.c23
-rw-r--r--src/input/net_buf_ctrl.h6
-rw-r--r--src/input/vcd/xine-extra.c10
-rw-r--r--src/video_out/Makefile.am2
-rw-r--r--src/video_out/video_out_xcbxv.c162
-rw-r--r--src/video_out/video_out_xv.c152
-rw-r--r--src/video_out/video_out_xvmc.c92
-rw-r--r--src/video_out/video_out_xxmc.c158
-rw-r--r--src/video_out/xv_common.h69
-rw-r--r--src/xine-engine/load_plugins.c73
-rw-r--r--src/xine-engine/xine.c35
-rw-r--r--src/xine-engine/xine_internal.h3
-rw-r--r--src/xine-utils/utils.c8
-rw-r--r--src/xine-utils/xineutils.h7
25 files changed, 1497 insertions, 669 deletions
diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c
index e68d80a71..470cd953a 100644
--- a/src/audio_out/audio_alsa_out.c
+++ b/src/audio_out/audio_alsa_out.c
@@ -1497,70 +1497,73 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
"formats you want to play to your sound card's digital output."),
0, alsa_speaker_arrangement_cb, this);
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_alsa_out : supported modes are "));
+ char *logmsg = strdup (_("audio_alsa_out : supported modes are"));
+
if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_U8))) {
this->capabilities |= AO_CAP_8BITS;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("8bit "));
+ xine_strcat_realloc (&logmsg, _(" 8bit"));
}
/* ALSA automatically appends _LE or _BE depending on the CPU */
if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S16))) {
this->capabilities |= AO_CAP_16BITS;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("16bit "));
+ xine_strcat_realloc (&logmsg, _(" 16bit"));
}
if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S24))) {
this->capabilities |= AO_CAP_24BITS;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("24bit "));
+ xine_strcat_realloc (&logmsg, _(" 24bit"));
}
if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_FLOAT))) {
this->capabilities |= AO_CAP_FLOAT32;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("32bit "));
+ xine_strcat_realloc (&logmsg, _(" 32bit"));
}
if (0 == (this->capabilities & (AO_CAP_FLOAT32 | AO_CAP_24BITS | AO_CAP_16BITS | AO_CAP_8BITS))) {
- xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
- "\naudio_alsa_out: no supported PCM format found\n");
+ xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg);
+ free (logmsg);
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG,
+ "audio_alsa_out: no supported PCM format found\n");
snd_pcm_close(this->audio_fd);
free(this);
return NULL;
}
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 1))) {
this->capabilities |= AO_CAP_MODE_MONO;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("mono "));
+ xine_strcat_realloc (&logmsg, _(" mono"));
}
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 2))) {
this->capabilities |= AO_CAP_MODE_STEREO;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("stereo "));
+ xine_strcat_realloc (&logmsg, _(" stereo"));
}
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 4)) &&
( speakers == SURROUND4 )) {
this->capabilities |= AO_CAP_MODE_4CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("4-channel "));
+ xine_strcat_realloc (&logmsg, _(" 4-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4-channel not enabled in xine config) "));
+ xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)"));
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) &&
( speakers == SURROUND41 )) {
this->capabilities |= AO_CAP_MODE_4_1CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("4.1-channel "));
+ xine_strcat_realloc (&logmsg, _(" 4.1-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4.1-channel not enabled in xine config) "));
+ xine_strcat_realloc (&logmsg, _(" (4.1-channel not enabled in xine config)"));
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) &&
( speakers == SURROUND5 )) {
this->capabilities |= AO_CAP_MODE_5CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("5-channel "));
+ xine_strcat_realloc (&logmsg, _(" 5-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5-channel not enabled in xine config) "));
+ xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)"));
if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) &&
( speakers >= SURROUND51 )) {
this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("5.1-channel "));
+ xine_strcat_realloc (&logmsg, _(" 5.1-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5.1-channel not enabled in xine config) "));
+ xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)"));
this->has_pause_resume = 0; /* This is checked at open time instead */
this->is_paused = 0;
@@ -1583,10 +1586,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
if ( speakers == A52_PASSTHRU ) {
this->capabilities |= AO_CAP_MODE_A52;
this->capabilities |= AO_CAP_MODE_AC5;
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("a/52 and DTS pass-through\n"));
+ xine_strcat_realloc (&logmsg, _(" a/52 and DTS pass-through"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_LOG, _("(a/52 and DTS pass-through not enabled in xine config)\n"));
+ xine_strcat_realloc (&logmsg, _(" (a/52 and DTS pass-through not enabled in xine config)"));
+
+ xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg);
+ free (logmsg);
/* printf("audio_alsa_out: capabilities 0x%X\n",this->capabilities); */
diff --git a/src/audio_out/audio_jack_out.c b/src/audio_out/audio_jack_out.c
index 070b96df8..8a77ab018 100644
--- a/src/audio_out/audio_jack_out.c
+++ b/src/audio_out/audio_jack_out.c
@@ -17,431 +17,942 @@
#define AO_OUT_JACK_IFACE_VERSION 8
#define GAP_TOLERANCE AO_MAX_GAP
-#define BUFSIZE 81920
+/* maximum number of channels supported, avoids lots of mallocs */
+#define MAX_CHANS 6
-typedef struct jack_driver_s {
+typedef struct jack_driver_s
+{
+ ao_driver_t ao_driver;
+ xine_t *xine;
+
+ int capabilities;
+ int mode;
+ int paused;
+ int underrun;
+
+ int32_t output_sample_rate, input_sample_rate;
+ uint32_t num_channels;
+ uint32_t bits_per_sample;
+ uint32_t bytes_per_frame;
+ uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */
+ uint32_t fragment_size;
+
+ jack_client_t *client;
+ jack_port_t *ports[MAX_CHANS];
+
+ /*! buffer for audio data */
+ unsigned char *buffer;
+
+ /*! buffer read position, may only be modified by playback thread or while it is stopped */
+ uint32_t read_pos;
+ /*! buffer write position, may only be modified by MPlayer's thread */
+ uint32_t write_pos;
+
+ struct
+ {
+ int volume;
+ int mute;
+ } mixer;
- ao_driver_t ao_driver;
- xine_t *xine;
+} jack_driver_t;
- int capabilities;
+typedef struct
+{
+ audio_driver_class_t driver_class;
+ config_values_t *config;
+ xine_t *xine;
+} jack_class_t;
- int32_t sample_rate;
- uint32_t num_channels;
- uint32_t bits_per_sample;
- uint32_t bytes_per_frame;
- jack_client_t *client;
- jack_port_t *port_1;
- jack_port_t *port_2;
- float buf_1[BUFSIZE];
- float buf_2[BUFSIZE];
- uint32_t buf_read;
- uint32_t buf_write;
+/**************************************************************
+ *
+ * Simple ringbuffer implementation
+ * Lifted from mplayer ao_jack.c
+ *
+**************************************************************/
+
+
+/*! size of one chunk, if this is too small Xine will start to "stutter" */
+/*! after a short time of playback */
+#define CHUNK_SIZE (16 * 1024)
+/*! number of "virtual" chunks the buffer consists of */
+#define NUM_CHUNKS 8
+/* This type of ring buffer may never fill up completely, at least */
+/* one byte must always be unused. */
+/* For performance reasons (alignment etc.) one whole chunk always stays */
+/* empty, not only one byte. */
+#define BUFFSIZE ((NUM_CHUNKS + 1) * CHUNK_SIZE)
+
+/**
+ * \brief get the number of free bytes in the buffer
+ * \return number of free bytes in buffer
+ *
+ * may only be called by Xine's thread
+ * return value may change between immediately following two calls,
+ * and the real number of free bytes might be larger!
+ */
+static int buf_free (jack_driver_t *this)
+{
+ int free = this->read_pos - this->write_pos - CHUNK_SIZE;
+ if (free < 0)
+ free += BUFFSIZE;
+ return free;
+}
- uint32_t volume;
- uint32_t mute;
+/**
+ * \brief get amount of data available in the buffer
+ * \return number of bytes available in buffer
+ *
+ * may only be called by the playback thread
+ * return value may change between immediately following two calls,
+ * and the real number of buffered bytes might be larger!
+ */
+static int buf_used (jack_driver_t *this)
+{
+ int used = this->write_pos - this->read_pos;
+ if (used < 0)
+ used += BUFFSIZE;
+ return used;
+}
-} jack_driver_t;
+/**
+ * \brief insert len bytes into buffer
+ * \param data data to insert
+ * \param len length of data
+ * \return number of bytes inserted into buffer
+ *
+ * If there is not enough room, the buffer is filled up
+ *
+ * TODO: Xine should really pass data as float, perhaps in V1.2?
+ */
+static int write_buffer_32 (jack_driver_t *this, unsigned char *data, int len)
+{
+ int first_len = BUFFSIZE - this->write_pos;
+ int free = buf_free (this);
+ if (len > free)
+ len = free;
+ if (first_len > len)
+ first_len = len;
+
+ /* copy from current write_pos to end of buffer */
+ memcpy (&(this->buffer[this->write_pos]), data, first_len);
+ if (len > first_len) { /* we have to wrap around */
+ /* remaining part from beginning of buffer */
+ memcpy (this->buffer, &data[first_len], len - first_len);
+ }
+ this->write_pos = (this->write_pos + len) % BUFFSIZE;
+
+ return len;
+}
+
+static int write_buffer_16 (jack_driver_t *this, unsigned char *data, int len)
+{
+ int samples_free = buf_free (this) / (sizeof (float));
+ int samples = len / 2;
+ if (samples > samples_free)
+ samples = samples_free;
+
+ /* Rename some pointers so that the next bit of gymnastics is easier to read */
+ uint32_t write_pos = this->write_pos;
+ float *p_write;
+ int16_t *p_read = (int16_t *) data;
+ int i;
+ for (i = 0; i < samples; i++) {
+ /* Read in 16bits, write out floats */
+ p_write = (float *) (&(this->buffer[write_pos]));
+ *p_write = ((float) (p_read[i])) / 32767.0f;
+ write_pos = (write_pos + sizeof (float)) % BUFFSIZE;
+ }
+ this->write_pos = write_pos;
+
+ return samples * 2;
+}
-typedef struct {
- audio_driver_class_t driver_class;
- config_values_t *config;
- xine_t *xine;
-} jack_class_t;
-static int jack_process(jack_nframes_t nframes, void *arg)
+/**
+ * \brief read data from buffer and splitting it into channels
+ * \param bufs num_bufs float buffers, each will contain the data of one channel
+ * \param cnt number of samples to read per channel
+ * \param num_bufs number of channels to split the data into
+ * \return number of samples read per channel, equals cnt unless there was too
+ * little data in the buffer
+ *
+ * Assumes the data in the buffer is of type float, the number of bytes
+ * read is res * num_bufs * sizeof(float), where res is the return value.
+ * If there is not enough data in the buffer remaining parts will be filled
+ * with silence.
+ */
+static int read_buffer (jack_driver_t *this, float **bufs, int cnt,
+ int num_bufs, float gain)
{
- jack_driver_t *this = (jack_driver_t *)arg;
- uint32_t local_buf_read = this->buf_read;
- uint32_t local_buf_write = this->buf_write;
- uint32_t src_channel, target_channel;
- uint32_t frame;
- float *buf, *out;
- float gain = 0;
-
- if (!this->client) return 0;
-
- if (!this->mute) {
- gain = (float)this->volume / 100.0;
+ int buffered = buf_used (this);
+ int i, j;
+ int orig_cnt = cnt;
+ if (cnt * sizeof (float) * num_bufs > buffered)
+ cnt = buffered / (sizeof (float) * num_bufs);
+
+ uint32_t read_pos = this->read_pos;
+ unsigned char *buffer = this->buffer;
+ for (i = 0; i < cnt; i++) {
+ for (j = 0; j < num_bufs; j++) {
+ bufs[j][i] = *((float *) (&(buffer[read_pos]))) * gain;
+ read_pos = (read_pos + sizeof (float)) % BUFFSIZE;
}
+ }
+ this->read_pos = read_pos;
+ for (i = cnt; i < orig_cnt; i++)
+ for (j = 0; j < num_bufs; j++)
+ bufs[j][i] = 0;
- for (target_channel = 0; target_channel < 2; ++target_channel) {
-
- if (target_channel < this->num_channels) src_channel = target_channel;
- else src_channel = 0;
+ return cnt;
+}
- jack_port_t *port = (target_channel ? this->port_2 : this->port_1);
- if (!port) continue;
+/**
+ * \brief fill the buffers with silence
+ * \param bufs num_bufs float buffers, each will contain the data of one channel
+ * \param cnt number of samples in each buffer
+ * \param num_bufs number of buffers
+ */
+static void silence (float **bufs, int cnt, int num_bufs)
+{
+ int i, j;
+ for (i = 0; i < cnt; i++)
+ for (j = 0; j < num_bufs; j++)
+ bufs[j][i] = 0;
+}
- buf = (src_channel ? this->buf_2 : this->buf_1);
- out = (float *)jack_port_get_buffer(port, nframes);
- local_buf_read = this->buf_read;
- frame = 0;
+/**************************************************************
+ *
+ * Jack interface functions
+ *
+**************************************************************/
- while (frame < nframes && local_buf_read != local_buf_write) {
- // local_buf_write doesn't change during this process,
- // so we can safely defer updating buf_read until after
+/**
+ * \brief stop playing and empty buffers (for seeking/pause)
+ */
+static void jack_reset (jack_driver_t *this)
+{
+ this->paused = 1;
+ this->read_pos = this->write_pos = 0;
+ this->paused = 0;
+}
- out[frame++] = buf[local_buf_read] * gain;
- if (++local_buf_read == BUFSIZE) local_buf_read = 0;
- }
+static int jack_callback (jack_nframes_t nframes, void *arg)
+{
+ jack_driver_t *this = (jack_driver_t *) arg;
- if (frame < nframes) {
-// printf("jack_process: underrun: %u required, %u available\n",
-// nframes, frame);
- while (frame < nframes) {
- out[frame++] = 0.0f;
- }
- }
+ if (!this->client) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_callback: called without a client parameter? silently trying to continue...\n");
+ return 0;
+ }
+
+ float gain = 0;
+ if (!this->mixer.mute) {
+ gain = (float) this->mixer.volume / 100.0;
+ gain *= gain; /* experiment with increasing volume range */
+ }
+
+ float *bufs[MAX_CHANS];
+ int i;
+ for (i = 0; i < this->num_channels; i++)
+ bufs[i] = jack_port_get_buffer (this->ports[i], nframes);
+
+ if (this->paused || this->underrun) {
+ silence (bufs, nframes, this->num_channels);
+ } else {
+ int frames_read = read_buffer (this, bufs, nframes, this->num_channels, gain);
+ if (frames_read < nframes) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_callback: underrun - frames read: %d\n", frames_read);
+ this->underrun = 1;
}
+ }
- this->buf_read = local_buf_read;
+ return 0;
+}
-// printf("jack_process: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write);
+static void jack_shutdown (void *arg)
+{
+ jack_driver_t *this = (jack_driver_t *) arg;
+ this->client = NULL;
+}
- return 0;
+/*
+ * Open the Jack audio device
+ * Return 1 on success, 0 on failure
+ * All error handling rests with the caller, we just try to open the device here
+ */
+static int jack_open_device (ao_driver_t *this_gen, char *jack_device,
+ int32_t *poutput_sample_rate, int num_channels)
+{
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ const char **matching_ports = NULL;
+ char *port_name = NULL;
+ jack_client_t *client = this->client;
+
+ int port_flags = JackPortIsInput;
+ int i;
+ int num_ports;
+
+ if (num_channels > MAX_CHANS) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: Invalid number of channels: %i\n",
+ num_channels);
+ goto err_out;
+ }
+ /* Try to create a client called "xine" */
+ if ((client = jack_client_new ("xine")) == 0) {
+ /* If that doesn't work it could be because running two copies of xine - try using a unique name */
+ char client_name[20];
+ sprintf (client_name, "xine (%d)", (int) getpid ());
+
+ if ((client = jack_client_new (client_name)) == 0) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "\njack_open_device: Error: Failed to connect to JACK server\n");
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: (did you start 'jackd' server?)\n");
+ goto err_out;
+ }
+ }
+
+ /* Save the new client */
+ this->client = client;
+
+ jack_reset (this);
+ jack_set_process_callback (client, jack_callback, this);
+
+ /* list matching ports */
+ if (!jack_device)
+ port_flags |= JackPortIsPhysical;
+ matching_ports = jack_get_ports (client, jack_device, NULL, port_flags);
+ for (num_ports = 0; matching_ports && matching_ports[num_ports];
+ num_ports++);
+ if (!num_ports) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: no physical ports available\n");
+ goto err_out;
+ }
+ if (num_ports < num_channels) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: not enough physical ports available\n");
+ goto err_out;
+ }
+
+ /* create output ports */
+ for (i = 0; i < num_channels; i++) {
+ char pname[50];
+ snprintf (pname, 50, "out_%d", i);
+ this->ports[i] =
+ jack_port_register (client, pname, JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ if (!this->ports[i]) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: could not create output ports? Why not?\n");
+ goto err_out;
+ }
+ }
+ if (jack_activate (client)) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: jack_activate() failed\n");
+ goto err_out;
+ }
+ for (i = 0; i < num_channels; i++) {
+ if (jack_connect
+ (client, jack_port_name (this->ports[i]), matching_ports[i])) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "jack_open_device: jack_connect() failed\n");
+ goto err_out;
+ }
+ }
+ *poutput_sample_rate = jack_get_sample_rate (client);
+
+ free (matching_ports);
+ return 1;
+
+err_out:
+ free (matching_ports);
+ if (client) {
+ jack_client_close (client);
+ this->client = NULL;
+ }
+ return 0;
}
-
-static void jack_shutdown(void *arg)
+
+/**************************************************************
+ *
+ * Xine interface functions
+ *
+**************************************************************/
+
+
+/**
+ * close the device and reset the play position
+ */
+static void ao_jack_close (ao_driver_t *this_gen)
{
- jack_driver_t *this = (jack_driver_t *)arg;
- this->client = 0;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_close: closing\n");
+
+ jack_reset (this);
+ if (this->client) {
+ jack_client_close (this->client);
+ this->client = NULL;
+ }
}
/*
* open the audio device for writing to
*/
-static int ao_jack_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode)
+static int ao_jack_open (ao_driver_t *this_gen, uint32_t bits, uint32_t rate,
+ int mode)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ config_values_t *config = this->xine->config;
+ char *jack_device;
- if (bits != 16) {
- fprintf(stderr, "ao_jack_open: bits=%u expected %u\n", bits, 16);
- return 0;
- }
+ jack_device =
+ config->lookup_entry (config, "audio.device.jack_device_name")->str_value;
- rate = jack_get_sample_rate(this->client);
- fprintf(stderr, "ao_jack_open: JACK sample rate is %u\n", rate);
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_open: ao_open rate=%d, mode=%d, bits=%d dev=%s\n", rate,
+ mode, bits, jack_device);
- switch (mode) {
- case AO_CAP_MODE_MONO:
- this->num_channels = 1;
- break;
- case AO_CAP_MODE_STEREO:
- this->num_channels = 2;
- break;
+ if ((bits != 16) && (bits != 32)) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "ao_jack_open: bits=%u expected 16 or 32bit only\n", bits);
+ return 0;
+ }
+
+ if ((mode & this->capabilities) == 0) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "ao_jack_open: unsupported mode %08x\n", mode);
+ return 0;
+ }
+
+ /* If device open already then either re-use it or close it */
+ if (this->client) {
+ if ((mode == this->mode) && (rate == this->input_sample_rate)) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_open: device already open, reusing it\n");
+ return this->output_sample_rate;
}
- this->buf_read = this->buf_write = 0;
- this->sample_rate = rate;
- this->bits_per_sample = bits;
- this->capabilities = AO_CAP_16BITS | AO_CAP_MODE_MONO | \
- AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL;
- this->bytes_per_frame = this->num_channels * (bits / 8);
+ ao_jack_close (this_gen);
+ }
+
+
+ this->mode = mode;
+ this->input_sample_rate = rate;
+ this->bits_per_sample = bits;
+ this->bytes_in_buffer = 0;
+ this->read_pos = this->write_pos = 0;
+ this->paused = 0;
+ this->underrun = 0;
+
+ /*
+ * set number of channels / a52 passthrough
+ */
+ switch (mode) {
+ case AO_CAP_MODE_MONO:
+ this->num_channels = 1;
+ break;
+ case AO_CAP_MODE_STEREO:
+ this->num_channels = 2;
+ break;
+ case AO_CAP_MODE_4CHANNEL:
+ this->num_channels = 4;
+ break;
+ case AO_CAP_MODE_4_1CHANNEL:
+ case AO_CAP_MODE_5CHANNEL:
+ case AO_CAP_MODE_5_1CHANNEL:
+ this->num_channels = 6;
+ break;
+ case AO_CAP_MODE_A52:
+ case AO_CAP_MODE_AC5:
+ /* FIXME: Is this correct...? */
+ this->num_channels = 2;
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_open: AO_CAP_MODE_A52\n");
+ break;
+ default:
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "ao_jack_open: JACK Driver does not support the requested mode: 0x%X\n",
+ mode);
+ return 0;
+ }
+
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "ao_jack_open: %d channels output\n", this->num_channels);
+ this->bytes_per_frame = (this->bits_per_sample * this->num_channels) / 8;
- fprintf(stderr, "ao_jack_open: bits=%d rate=%d, mode=%d OK\n", bits, rate, mode);
+ /*
+ * open audio device
+ */
+ if (!jack_open_device (this_gen, jack_device, &(this->output_sample_rate),
+ this->num_channels))
+ return 0;
- return rate;
+ if (this->input_sample_rate != this->output_sample_rate) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_open: audio rate : %d requested, %d provided by device\n",
+ this->input_sample_rate, this->output_sample_rate);
+ }
+
+ return this->output_sample_rate;
}
-static int ao_jack_num_channels(ao_driver_t *this_gen)
+static int ao_jack_num_channels (ao_driver_t *this_gen)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
- return this->num_channels;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ return this->num_channels;
}
-static int ao_jack_bytes_per_frame(ao_driver_t *this_gen)
+static int ao_jack_bytes_per_frame (ao_driver_t *this_gen)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
- return this->bytes_per_frame;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ return this->bytes_per_frame;
}
static int ao_jack_get_gap_tolerance (ao_driver_t *this_gen)
{
- return GAP_TOLERANCE;
+ return GAP_TOLERANCE;
}
-static int last_write_space = 0;
-
-static int ao_jack_write(ao_driver_t *this_gen, int16_t *data,
- uint32_t num_frames)
+/*
+ * Return the number of outstanding frames in all output buffers
+ * need to account for ring buffer plus Jack, plus soundcard
+ */
+static int ao_jack_delay (ao_driver_t *this_gen)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
- uint32_t frame, channel;
-
- uint32_t local_buf_read = this->buf_read;
- uint32_t local_buf_write = this->buf_write;
- uint32_t space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE;
- uint32_t first_frame = 0;
-
- int c = 0;
- while (space < num_frames) {
- if (++c == 10) return 0;
- usleep(10000);
- local_buf_read = this->buf_read;
- space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE;
- }
-
-// if (space < num_frames) return 0;
-
-// printf("ao_jack_write: %u frames on %u channels, space is %u\n", num_frames, this->num_channels, space);
- last_write_space = space;
-
- for (frame = first_frame; frame < num_frames; ++frame) {
- for (channel = 0; channel < this->num_channels; ++channel) {
- float *buf = (channel ? this->buf_2 : this->buf_1);
- int16_t sample = data[frame * this->num_channels + channel];
- buf[local_buf_write] = ((float)sample) / 32767.0f;
-// printf("%6f ", buf[local_buf_write]);
-// if (++c == 8) { printf("\n"); c = 0; }
- }
- if (++local_buf_write == BUFSIZE) local_buf_write = 0;
- }
-
- this->buf_write = local_buf_write;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ int frames_played = jack_frames_since_cycle_start (this->client);
-// printf("ao_jack_write: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write);
+ int delay = 0;
+ /* Ring Buffer always stores floats */
+ /* TODO: Unsure if the delay should be fragment_size*2 or *3? */
+ delay = buf_used (this) / (sizeof (float) * this->num_channels) +
+ this->fragment_size * 3 - frames_played;
- return 1;
+ return delay;
}
-static int ao_jack_delay (ao_driver_t *this_gen)
+ /* Write audio samples
+ * num_frames is the number of audio frames present
+ * audio frames are equivalent one sample on each channel.
+ * I.E. Stereo 16 bits audio frames are 4 bytes.
+ * MUST SIMULATE BLOCKING WRITES
+ */
+static int ao_jack_write (ao_driver_t *this_gen, int16_t *frame_buffer,
+ uint32_t num_frames)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
-
- uint32_t local_buf_read = this->buf_read;
- uint32_t local_buf_write = this->buf_write;
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ int written = 0;
+ int num_bytes = num_frames * this->bytes_per_frame;
+
+ /* First try and write all the bytes in one go */
+ this->underrun = 0;
+ /* TODO: In the future Xine should pass only floats to us, so no conversion needed */
+ if (this->bits_per_sample == 16)
+ written = write_buffer_16 (this, (char *) frame_buffer, num_bytes);
+ else if (this->bits_per_sample == 32)
+ written = write_buffer_32 (this, (char *) frame_buffer, num_bytes);
+
+ /* If this fails then need to spin and keep trying until everything written */
+ int spin_count = 0;
+ while ((written < num_bytes) && (spin_count < 40)) {
+ num_bytes -= written;
+ frame_buffer += written / 2;
+
+ /* Sleep to save CPU */
+ int until_callback =
+ this->fragment_size - jack_frames_since_cycle_start (this->client);
+ if ((until_callback < 0) || (until_callback > this->fragment_size)) {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_write: Invalid until_callback %d\n", until_callback);
+ until_callback = this->fragment_size;
+ }
+ xine_usec_sleep (((until_callback +
+ 100) * 1000.0 * 1000.0) / this->output_sample_rate);
- int delay = 0;
+ if (this->bits_per_sample == 16)
+ written = write_buffer_16 (this, (char *) frame_buffer, num_bytes);
+ else if (this->bits_per_sample == 32)
+ written = write_buffer_32 (this, (char *) frame_buffer, num_bytes);
- if (local_buf_write > local_buf_read) {
- delay = local_buf_write - local_buf_read;
- } else {
- delay = ((local_buf_write + BUFSIZE - local_buf_read) % BUFSIZE);
- }
+ if (written == 0)
+ spin_count++;
+ else
+ spin_count = 0;
- return delay;// - jack_get_buffer_size(this->client);
-}
+ if (written == 0)
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "ao_jack_write: unusual, couldn't write anything\n");
+ };
-static void ao_jack_close(ao_driver_t *this_gen)
-{
- // nothing
-}
+ if (spin_count)
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "Nonzero spin_count...%d\n", spin_count);
-static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) {
- jack_driver_t *this = (jack_driver_t *) this_gen;
- return this->capabilities;
+ return spin_count ? 0 : 1; /* return 1 on success, 0 if we got stuck for some reason */
}
-static void ao_jack_exit(ao_driver_t *this_gen)
+static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen)
{
- jack_driver_t *this = (jack_driver_t *) this_gen;
- jack_client_t *client = this->client;
- ao_jack_close(this_gen);
- this->client = 0;
- if (client) jack_client_close(client);
- free (this);
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+ return this->capabilities;
}
-static int ao_jack_get_property (ao_driver_t *this_gen, int property) {
- jack_driver_t *this = (jack_driver_t *) this_gen;
-
- switch(property) {
- case AO_PROP_PCM_VOL:
- case AO_PROP_MIXER_VOL:
-// printf("ao_jack_get_property(AO_PROP_MIXER_VOL): %u\n", this->volume);
- return this->volume;
- break;
- case AO_PROP_MUTE_VOL:
-// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", this->mute);
- return this->mute;
- break;
- }
+static void ao_jack_exit (ao_driver_t *this_gen)
+{
+ jack_driver_t *this = (jack_driver_t *) this_gen;
- return 0;
+ ao_jack_close (this_gen);
+ if (this->buffer)
+ free (this->buffer);
+ free (this);
}
-static int ao_jack_set_property (ao_driver_t *this_gen, int property, int value) {
- jack_driver_t *this = (jack_driver_t *) this_gen;
-
- switch(property) {
- case AO_PROP_PCM_VOL:
- case AO_PROP_MIXER_VOL:
-// printf("ao_jack_set_property(AO_PROP_MIXER_VOL): %u\n", value);
- this->volume = value;
- break;
- case AO_PROP_MUTE_VOL:
-// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", value);
- this->mute = value;
- break;
- }
+static int ao_jack_get_property (ao_driver_t *this_gen, int property)
+{
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+
+ switch (property) {
+ case AO_PROP_PCM_VOL:
+ case AO_PROP_MIXER_VOL:
+ return this->mixer.volume;
+ break;
+ case AO_PROP_MUTE_VOL:
+ return this->mixer.mute;
+ break;
+ }
+
+ return 0;
+}
- return ~value;
+static int ao_jack_set_property (ao_driver_t *this_gen, int property, int value)
+{
+ jack_driver_t *this = (jack_driver_t *) this_gen;
+
+ switch (property) {
+ case AO_PROP_PCM_VOL:
+ case AO_PROP_MIXER_VOL:
+ this->mixer.volume = value;
+ return value;
+ break;
+ case AO_PROP_MUTE_VOL:
+ this->mixer.mute = value;
+ return value;
+ break;
+ }
+
+ return -1;
}
-static int ao_jack_ctrl(ao_driver_t *this_gen, int cmd, ...) {
- jack_driver_t *this = (jack_driver_t *) this_gen;
+static int ao_jack_ctrl (ao_driver_t *this_gen, int cmd, ...)
+{
+ jack_driver_t *this = (jack_driver_t *) this_gen;
- switch (cmd) {
+ switch (cmd) {
- case AO_CTRL_PLAY_PAUSE:
- break;
+ case AO_CTRL_PLAY_PAUSE:
+ this->paused = 1;
+ break;
- case AO_CTRL_PLAY_RESUME:
- break;
+ case AO_CTRL_PLAY_RESUME:
+ this->paused = 0;
+ break;
- case AO_CTRL_FLUSH_BUFFERS:
-// fprintf(stderr, "ao_jack_ctrl(AO_CTRL_FLUSH_BUFFERS)\n");
- this->buf_write = this->buf_read = 0;
- break;
- }
+ case AO_CTRL_FLUSH_BUFFERS:
+ jack_reset (this);
+ break;
+ }
- return 0;
+ return 0;
}
+static void jack_speaker_arrangement_cb (void *user_data,
+ xine_cfg_entry_t *entry);
+
static ao_driver_t *open_jack_plugin (audio_driver_class_t *class_gen,
const void *data)
{
- jack_class_t *class = (jack_class_t *) class_gen;
- jack_driver_t *this;
- jack_client_t *client;
- uint32_t rate;
- const char **port_names;
- int i;
-
- if ((client = jack_client_new("xine")) == 0) {
-
- char name[20];
- sprintf(name, "xine (%d)", (int)getpid());
-
- if ((client = jack_client_new(name)) == 0) {
- fprintf(stderr, "\nopen_jack_plugin: Error: Failed to connect to JACK server\n");
- fprintf(stderr, "open_jack_plugin: (did you start 'jackd' server?)\n");
- return 0;
- }
- }
-
- this = calloc(1, sizeof (jack_driver_t));
-
- this->client = client;
-
- jack_set_process_callback(client, jack_process, this);
- jack_on_shutdown(client, jack_shutdown, this);
-
- rate = jack_get_sample_rate(client);
- fprintf(stderr, "open_jack_plugin: JACK sample rate is %u\n", rate);
-
- // We support up to 2-channel output
-
- for (i = 0; i < 2; ++i) {
- jack_port_t *port = jack_port_register
- (client, (i ? "out_r" : "out_l"),
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
- if (!port) {
- fprintf(stderr, "ao_jack_open: failed to register port %u\n", i);
- }
- if (i) this->port_2 = port;
- else this->port_1 = port;
- }
-
- this->buf_read = this->buf_write = 0;
- this->volume = 100;
- this->mute = 0;
-
- if (jack_activate(client)) {
- fprintf(stderr, "ao_jack_open: failed to activate JACK client\n");
- return 0;
- }
-
- if ((port_names = jack_get_ports(client, NULL, NULL,
- JackPortIsPhysical | JackPortIsInput)) != NULL) {
- if (port_names[0]) {
- jack_connect(client, jack_port_name(this->port_1), port_names[0]);
- }
- if (port_names[1] && this->port_2) {
- jack_connect(client, jack_port_name(this->port_2), port_names[1]);
- }
- free(port_names);
+ jack_class_t *class = (jack_class_t *) class_gen;
+ config_values_t *config = class->config;
+ jack_driver_t *this;
+
+ jack_client_t *client;
+ uint32_t rate;
+ char *jack_device;
+ const char **matching_ports = NULL;
+ const char **port_names;
+
+ /* for usability reasons, keep this in sync with audio_oss_out.c */
+ 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
+ };
+#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
+ int speakers;
+
+ /* Try to create a client called "xine" */
+ if ((client = jack_client_new ("xine")) == 0) {
+ /* If that doesn't work it could be because running two copies of xine - try using a unique name */
+ char name[20];
+ sprintf (name, "xine (%d)", (int) getpid ());
+
+ if ((client = jack_client_new (name)) == 0) {
+ xprintf (class->xine, XINE_VERBOSITY_LOG,
+ "\nopen_jack_plugin: Error: Failed to connect to JACK server\n");
+ xprintf (class->xine, XINE_VERBOSITY_LOG,
+ "open_jack_plugin: (did you start 'jackd' server?)\n");
+ return 0;
}
+ }
+
+ this = calloc(1, sizeof (jack_driver_t));
+
+ rate = jack_get_sample_rate (client);
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG,
+ "open_jack_plugin: JACK sample rate is %u\n", rate);
+
+ /* devname_val is offset used to select auto, /dev/dsp, or /dev/sound/dsp */
+ jack_device = config->register_string (config,
+ "audio.device.jack_device_name",
+ "",
+ _("JACK audio device name"),
+ _("Specifies the jack audio device name, "
+ "leave blank for the default physical output port."),
+ 10, NULL, NULL);
+
+ this->capabilities = 0;
+
+
+ /* for usability reasons, keep this in sync with audio_alsa_out.c */
+ speakers =
+ config->register_enum (config, "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."),
+ 0, jack_speaker_arrangement_cb, this);
+
+ int port_flags = JackPortIsInput;
+ int num_ports;
+ /* list matching ports */
+ if (!jack_device)
+ port_flags |= JackPortIsPhysical;
+ /* Find all the ports matching either the desired device regexp or physical output ports */
+ matching_ports = jack_get_ports (client, jack_device, NULL, port_flags);
+ /* Count 'em */
+ for (num_ports = 0; matching_ports && matching_ports[num_ports];
+ num_ports++)
+ /**/;
+ if (!num_ports) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "open_jack_plugin: no physical ports available\n");
+ goto err_out;
+ }
+
+
+/* TODO: We deliberately don't offer mono, let Xine upsample instead? */
+/* if (num_ports >= 1) { */
+/* this->capabilities |= AO_CAP_MODE_MONO; */
+/* xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono "); */
+/* } */
+
+ if (num_ports >= 2) {
+ this->capabilities |= AO_CAP_MODE_STEREO;
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG, "stereo ");
+ }
+
+ if (num_ports >= 4) {
+ if (speakers == SURROUND4) {
+ this->capabilities |= AO_CAP_MODE_4CHANNEL;
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG, "4-channel ");
+ } else
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG,
+ "(4-channel not enabled in xine config) ");
+ }
+
+ if (num_ports >= 5) {
+ if (speakers == SURROUND5) {
+ this->capabilities |= AO_CAP_MODE_5CHANNEL;
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG, "5-channel ");
+ } else
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG,
+ "(5-channel not enabled in xine config) ");
+ }
+
+ if (num_ports >= 6) {
+ if (speakers == SURROUND51) {
+ this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel ");
+ } else
+ xprintf (class->xine, XINE_VERBOSITY_DEBUG,
+ "(5.1-channel not enabled in xine config) ");
+ }
+
+ this->buffer = (unsigned char *) malloc (BUFFSIZE);
+ jack_reset (this);
+
+ this->capabilities |= AO_CAP_MIXER_VOL;
+ this->capabilities |= AO_CAP_MUTE_VOL;
+ /* TODO: Currently not respected by Xine, perhaps v1.2? */
+ this->capabilities |= AO_CAP_FLOAT32;
+
+
+ this->mixer.mute = 0;
+ this->mixer.volume = 100;
+
+ this->output_sample_rate = jack_get_sample_rate (client);
+ this->fragment_size = jack_get_buffer_size (client);
+
+ /* Close our JACK client */
+ jack_client_close (client);
+
+ this->xine = class->xine;
+
+ this->ao_driver.get_capabilities = ao_jack_get_capabilities;
+ this->ao_driver.get_property = ao_jack_get_property;
+ this->ao_driver.set_property = ao_jack_set_property;
+ this->ao_driver.open = ao_jack_open;
+ this->ao_driver.num_channels = ao_jack_num_channels;
+ this->ao_driver.bytes_per_frame = ao_jack_bytes_per_frame;
+ this->ao_driver.delay = ao_jack_delay;
+ this->ao_driver.write = ao_jack_write;
+ this->ao_driver.close = ao_jack_close;
+ this->ao_driver.exit = ao_jack_exit;
+ this->ao_driver.get_gap_tolerance = ao_jack_get_gap_tolerance;
+ this->ao_driver.control = ao_jack_ctrl;
+
+ return &this->ao_driver;
+
+err_out:
+ free (matching_ports);
+ if (client)
+ jack_client_close (client);
+ return 0;
+}
- this->sample_rate = rate;
-
- this->xine = class->xine;
- this->capabilities = AO_CAP_FLOAT32 | AO_CAP_MODE_MONO |
- AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL;
-
- this->ao_driver.get_capabilities = ao_jack_get_capabilities;
- this->ao_driver.get_property = ao_jack_get_property;
- this->ao_driver.set_property = ao_jack_set_property;
- this->ao_driver.open = ao_jack_open;
- this->ao_driver.num_channels = ao_jack_num_channels;
- this->ao_driver.bytes_per_frame = ao_jack_bytes_per_frame;
- this->ao_driver.delay = ao_jack_delay;
- this->ao_driver.write = ao_jack_write;
- this->ao_driver.close = ao_jack_close;
- this->ao_driver.exit = ao_jack_exit;
- this->ao_driver.get_gap_tolerance = ao_jack_get_gap_tolerance;
- this->ao_driver.control = ao_jack_ctrl;
-
- fprintf(stderr, "jack open_jack_plugin returning %p\n", (void *)(&this->ao_driver));
- return &this->ao_driver;
+static void jack_speaker_arrangement_cb (void *user_data,
+ xine_cfg_entry_t *entry)
+{
+ jack_driver_t *this = (jack_driver_t *) user_data;
+ int32_t value = entry->num_value;
+ if (value == SURROUND4) {
+ this->capabilities |= AO_CAP_MODE_4CHANNEL;
+ } else {
+ this->capabilities &= ~AO_CAP_MODE_4CHANNEL;
+ }
+ if (value == SURROUND41) {
+ this->capabilities |= AO_CAP_MODE_4_1CHANNEL;
+ } else {
+ this->capabilities &= ~AO_CAP_MODE_4_1CHANNEL;
+ }
+ if (value == SURROUND5) {
+ this->capabilities |= AO_CAP_MODE_5CHANNEL;
+ } else {
+ this->capabilities &= ~AO_CAP_MODE_5CHANNEL;
+ }
+ if (value >= SURROUND51) {
+ this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
+ } else {
+ this->capabilities &= ~AO_CAP_MODE_5_1CHANNEL;
+ }
}
/*
* class functions
*/
-static char* get_identifier (audio_driver_class_t *this_gen) {
- return "jack";
+static char *get_identifier (audio_driver_class_t *this_gen)
+{
+ return "jack";
}
-static char* get_description (audio_driver_class_t *this_gen) {
- return _("xine output plugin for JACK Audio Connection Kit");
+static char *get_description (audio_driver_class_t *this_gen)
+{
+ return _("xine output plugin for JACK Audio Connection Kit");
}
-static void dispose_class (audio_driver_class_t *this_gen) {
-
- jack_class_t *this = (jack_class_t *) this_gen;
- free (this);
+static void dispose_class (audio_driver_class_t *this_gen)
+{
+ jack_class_t *this = (jack_class_t *) this_gen;
+ free (this);
}
-static void *init_class (xine_t *xine, void *data) {
-
- jack_class_t *this;
-
- this = calloc(1, sizeof (jack_class_t));
+static void *init_class (xine_t *xine, void *data)
+{
+ jack_class_t *this;
- this->driver_class.open_plugin = open_jack_plugin;
- this->driver_class.get_identifier = get_identifier;
- this->driver_class.get_description = get_description;
- this->driver_class.dispose = dispose_class;
+ this = calloc(1, sizeof (jack_class_t));
- this->config = xine->config;
- this->xine = xine;
+ this->driver_class.open_plugin = open_jack_plugin;
+ this->driver_class.get_identifier = get_identifier;
+ this->driver_class.get_description = get_description;
+ this->driver_class.dispose = dispose_class;
- fprintf(stderr, "jack init_class returning %p\n", (void *)this);
+ this->config = xine->config;
+ this->xine = xine;
- return this;
+ return this;
}
-static ao_info_t ao_info_jack = {
- 6
-};
+static ao_info_t ao_info_jack = { 6 };
/*
* exported plugin catalog entry
*/
const plugin_info_t xine_plugin_info[] EXPORTED = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", XINE_VERSION_CODE /* XINE_VERSION_CODE */, &ao_info_jack, init_class },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", XINE_VERSION_CODE,
+ &ao_info_jack, init_class },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
-
diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c
index df29a43ea..2ae116970 100644
--- a/src/audio_out/audio_oss_out.c
+++ b/src/audio_out/audio_oss_out.c
@@ -877,10 +877,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
if (this->sync_method == OSS_SYNC_PROBEBUFFER) {
char *buf;
int c;
-
- xprintf(class->xine, XINE_VERBOSITY_LOG,
- _("audio_oss_out: Audio driver realtime sync disabled...\n"
- "audio_oss_out: ...probing output buffer size: "));
+
this->buffer_size = 0;
if( (buf=calloc(1, 1024)) != NULL ) {
@@ -894,7 +891,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
}
close(audio_fd);
xprintf(class->xine, XINE_VERBOSITY_LOG,
- _("%d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size);
+ _("audio_oss_out: Audio driver realtime sync disabled...\n"
+ "audio_oss_out: ...probing output buffer size: %d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size);
audio_fd=open(this->audio_dev, O_WRONLY|O_NONBLOCK);
@@ -957,48 +955,48 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
0, oss_speaker_arrangement_cb, this);
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: supported modes are ");
+ char *logmsg = strdup (_("audio_oss_out: supported modes are"));
num_channels = 1;
status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
if ( (status != -1) && (num_channels==1) ) {
this->capabilities |= AO_CAP_MODE_MONO;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono ");
+ xine_strcat_realloc (&logmsg, _(" mono"));
}
num_channels = 2;
status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
if ( (status != -1) && (num_channels==2) ) {
this->capabilities |= AO_CAP_MODE_STEREO;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "stereo ");
+ xine_strcat_realloc (&logmsg, _(" stereo"));
}
num_channels = 4;
status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
if ( (status != -1) && (num_channels==4) ) {
if ( speakers == SURROUND4 ) {
this->capabilities |= AO_CAP_MODE_4CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "4-channel ");
+ xine_strcat_realloc (&logmsg, _(" 4-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(4-channel not enabled in xine config) " );
+ xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)"));
}
num_channels = 5;
status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
if ( (status != -1) && (num_channels==5) ) {
if ( speakers == SURROUND5 ) {
this->capabilities |= AO_CAP_MODE_5CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5-channel ");
+ xine_strcat_realloc (&logmsg, _(" 5-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5-channel not enabled in xine config) " );
+ xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)"));
}
num_channels = 6;
status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
if ( (status != -1) && (num_channels==6) ) {
if ( speakers == SURROUND51 ) {
this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel ");
+ xine_strcat_realloc (&logmsg, _(" 5.1-channel"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5.1-channel not enabled in xine config) " );
+ xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)"));
}
ioctl(audio_fd,SNDCTL_DSP_GETFMTS,&caps);
@@ -1008,10 +1006,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da
if ( speakers == A52_PASSTHRU ) {
this->capabilities |= AO_CAP_MODE_A52;
this->capabilities |= AO_CAP_MODE_AC5;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "a/52-pass-through ");
+ xine_strcat_realloc (&logmsg, _(" a/52 pass-through"));
}
else
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(a/52-pass-through not enabled in xine config)");
+ xine_strcat_realloc (&logmsg, _(" (a/52 pass-through not enabled in xine config)"));
+
+ xprintf(class->xine, XINE_VERBOSITY_DEBUG, "%s\n", logmsg);
+ free (logmsg);
/*
* mixer initialisation.
diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c
index e51344798..1fa9b4327 100644
--- a/src/demuxers/demux_qt.c
+++ b/src/demuxers/demux_qt.c
@@ -3095,7 +3095,9 @@ static const char *get_mimetypes (demux_class_t *this_gen) {
return "video/quicktime: mov,qt: Quicktime animation;"
"video/x-quicktime: mov,qt: Quicktime animation;"
"audio/x-m4a: m4a,m4b: MPEG-4 audio;"
- "application/x-quicktimeplayer: qtl: Quicktime list;";
+ "application/x-quicktimeplayer: qtl: Quicktime list;"
+ "video/mp4: mp4,mpg4: MPEG-4 video;"
+ "audio/mp4: mp4,mpg4: MPEG-4 audio;";
}
static void class_dispose (demux_class_t *this_gen) {
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c
index d2df1609c..6c2adc67f 100644
--- a/src/demuxers/demux_ts.c
+++ b/src/demuxers/demux_ts.c
@@ -245,7 +245,7 @@ typedef struct {
int64_t pts;
buf_element_t *buf;
unsigned int counter;
- uint8_t descriptor_tag;
+ uint16_t descriptor_tag; /* +0x100 for PES stream IDs (no available TS descriptor tag?) */
int64_t packet_count;
int corrupted_pes;
uint32_t buffered_bytes;
@@ -983,7 +983,7 @@ static void demux_ts_pes_new(demux_ts_t*this,
unsigned int mediaIndex,
unsigned int pid,
fifo_buffer_t *fifo,
- uint8_t descriptor) {
+ uint16_t descriptor) {
demux_ts_media *m = &this->media[mediaIndex];
@@ -1240,6 +1240,15 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
}
}
+ /*
+ * Forget the current video, audio and subtitle PIDs; if the PMT has not
+ * changed, we'll pick them up again when we parse this PMT, while if the
+ * PMT has changed (e.g. an IPTV streamer that's just changed its source),
+ * we'll get new PIDs that we should follow.
+ */
+ this->audio_tracks_count = 0;
+ this->videoPid = INVALID_PID;
+ this->spu_pid = INVALID_PID;
/*
* ES definitions start here...we are going to learn upto one video
@@ -1846,7 +1855,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) {
} else if (!found) {
this->videoPid = pid;
this->videoMedia = this->media_num;
- demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, pes_stream_id);
+ demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, 0x100 + pes_stream_id);
}
if (this->videoPid != INVALID_PID) {
@@ -1873,7 +1882,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) {
this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
this->media[this->media_num].type = this->audio_tracks_count;
demux_ts_pes_new(this, this->media_num++, pid,
- this->audio_fifo,pes_stream_id);
+ this->audio_fifo, 0x100 + pes_stream_id);
this->audio_tracks_count++;
}
}
diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c
index 9f51da267..bc279b78b 100644
--- a/src/input/input_dvb.c
+++ b/src/input/input_dvb.c
@@ -291,6 +291,7 @@ typedef struct {
int numchannels;
char *autoplaylist[MAX_AUTOCHANNELS];
+ char *default_channels_conf_filename;
} dvb_input_class_t;
typedef struct {
@@ -331,6 +332,9 @@ typedef struct {
/* scratch buffer for forward seeking */
char seek_buf[BUFSIZE];
+ /* Is the GUI enabled at all? */
+ int dvb_gui_enabled;
+
/* simple vcr-like functionality */
int record_fd;
int record_paused;
@@ -369,6 +373,7 @@ static const Param bw_list [] = {
{ "BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ },
{ "BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ },
{ "BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ },
+ { "BANDWIDTH_AUTO", BANDWIDTH_AUTO },
{ NULL, 0 }
};
@@ -391,6 +396,7 @@ static const Param guard_list [] = {
{"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
{"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
{"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8},
+ {"GUARD_INTERVAL_AUTO", GUARD_INTERVAL_AUTO},
{ NULL, 0 }
};
@@ -399,6 +405,7 @@ static const Param hierarchy_list [] = {
{ "HIERARCHY_2", HIERARCHY_2 },
{ "HIERARCHY_4", HIERARCHY_4 },
{ "HIERARCHY_NONE", HIERARCHY_NONE },
+ { "HIERARCHY_AUTO", HIERARCHY_AUTO },
{ NULL, 0 }
};
@@ -417,12 +424,14 @@ static const Param qam_list [] = {
{ "QAM_256", QAM_256 },
{ "QAM_32", QAM_32 },
{ "QAM_64", QAM_64 },
+ { "QAM_AUTO", QAM_AUTO },
{ NULL, 0 }
};
static const Param transmissionmode_list [] = {
{ "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K },
{ "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K },
+ { "TRANSMISSION_MODE_AUTO", TRANSMISSION_MODE_AUTO },
{ NULL, 0 }
};
@@ -880,13 +889,15 @@ static channel_t *load_channels(xine_t *xine, xine_stream_t *stream, int *num_ch
FILE *f;
char str[BUFSIZE];
- char filename[BUFSIZE];
channel_t *channels = NULL;
int num_channels = 0;
int num_alloc = 0;
struct stat st;
-
- snprintf(filename, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir());
+ xine_cfg_entry_t channels_conf;
+ char *filename;
+
+ xine_config_lookup_entry(xine, "media.dvb.channels_conf", &channels_conf);
+ filename = channels_conf.str_value;
f = fopen(filename, "r");
if (!f) {
@@ -1141,6 +1152,8 @@ static void parse_pmt(dvb_input_plugin_t *this, const unsigned char *buf, int se
switch (buf[0]) {
case 0x01:
case 0x02:
+ case 0x10:
+ case 0x1b:
if(!has_video) {
xprintf(this->stream->xine,XINE_VERBOSITY_LOG,"input_dvb: Adding VIDEO : PID 0x%04x\n", elementary_pid);
dvb_set_pidfilter(this, VIDFILTER, elementary_pid, DMX_PES_VIDEO, DMX_OUT_TS_TAP);
@@ -1150,6 +1163,8 @@ static void parse_pmt(dvb_input_plugin_t *this, const unsigned char *buf, int se
case 0x03:
case 0x04:
+ case 0x0f:
+ case 0x11:
if(!has_audio) {
xprintf(this->stream->xine,XINE_VERBOSITY_LOG,"input_dvb: Adding AUDIO : PID 0x%04x\n", elementary_pid);
dvb_set_pidfilter(this, AUDFILTER, elementary_pid, DMX_PES_AUDIO, DMX_OUT_TS_TAP);
@@ -2492,15 +2507,13 @@ static off_t dvb_plugin_read (input_plugin_t *this_gen,
if (!this->tuned_in)
return 0;
- dvb_event_handler (this);
+ if (this->dvb_gui_enabled)
+ dvb_event_handler (this);
#ifdef LOG_READS
xprintf(this->class->xine,XINE_VERBOSITY_DEBUG,
"input_dvb: reading %" PRIdMAX " bytes...\n", (intmax_t)len);
#endif
-#ifndef DVB_NO_BUFFERING
- nbc_check_buffers (this->nbc);
-#endif
/* protect against channel changes */
have_mutex = pthread_mutex_lock(&this->channel_change_mutex);
total=0;
@@ -2757,7 +2770,12 @@ static int dvb_plugin_open(input_plugin_t * this_gen)
xine_cfg_entry_t zoomdvb;
xine_cfg_entry_t adapter;
xine_cfg_entry_t lastchannel;
+ xine_cfg_entry_t gui_enabled;
+ xine_config_lookup_entry(this->stream->xine, "media.dvb.gui_enabled", &gui_enabled);
+ this->dvb_gui_enabled = gui_enabled.num_value;
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("input_dvb: DVB GUI %s\n"), this->dvb_gui_enabled ? "enabled" : "disabled");
+
xine_config_lookup_entry(this->stream->xine, "media.dvb.adapter", &adapter);
if (!(tuner = tuner_init(this->class->xine,adapter.num_value))) {
@@ -2983,15 +3001,16 @@ static int dvb_plugin_open(input_plugin_t * this_gen)
this->event_queue = xine_event_new_queue(this->stream);
#ifdef EPG_UPDATE_IN_BACKGROUND
- /* Start the EPG updater thread. */
- this->epg_updater_stop = 0;
- if (pthread_create(&this->epg_updater_thread, NULL,
- epg_data_updater, this) != 0) {
- xprintf(
- this->class->xine, XINE_VERBOSITY_LOG,
- _("input_dvb: cannot create EPG updater thread\n"));
- return 0;
-
+ if (this->dvb_gui_enabled) {
+ /* Start the EPG updater thread. */
+ this->epg_updater_stop = 0;
+ if (pthread_create(&this->epg_updater_thread, NULL,
+ epg_data_updater, this) != 0) {
+ xprintf(
+ this->class->xine, XINE_VERBOSITY_LOG,
+ _("input_dvb: cannot create EPG updater thread\n"));
+ return 0;
+ }
}
#endif
/*
@@ -3157,6 +3176,8 @@ static void dvb_class_dispose(input_class_t * this_gen)
{
dvb_input_class_t *class = (dvb_input_class_t *) this_gen;
int x;
+
+ free(class->default_channels_conf_filename);
for(x=0;x<class->numchannels;x++)
free(class->autoplaylist[x]);
@@ -3266,6 +3287,10 @@ static void *init_class (xine_t *xine, void *data) {
this->mrls[3] = "dvbt://";
this->mrls[4] = "dvba://";
this->mrls[5] = 0;
+
+ asprintf(&this->default_channels_conf_filename,
+ "%s/.xine/channels.conf",
+ xine_get_homedir());
xprintf(this->xine,XINE_VERBOSITY_DEBUG,"init class succeeded\n");
@@ -3299,7 +3324,19 @@ static void *init_class (xine_t *xine, void *data) {
"in your system."),
0, NULL, (void *) this);
-
+ /* set to 0 to turn off the GUI built into this input plugin */
+ config->register_bool(config, "media.dvb.gui_enabled",
+ 1,
+ _("Enable the DVB GUI"),
+ _("Enable the DVB GUI, mouse controlled recording and channel switching."),
+ 21, NULL, NULL);
+ /* Override the default channels file */
+ config->register_filename(config, "media.dvb.channels_conf",
+ this->default_channels_conf_filename,
+ XINE_CONFIG_STRING_IS_FILENAME,
+ _("DVB Channels config file"),
+ _("DVB Channels config file to use instead of the ~/.xine/channels.conf file."),
+ 21, NULL, NULL);
return this;
}
diff --git a/src/input/input_http.c b/src/input/input_http.c
index dab7310c3..169a0d384 100644
--- a/src/input/input_http.c
+++ b/src/input/input_http.c
@@ -82,6 +82,8 @@ typedef struct {
char auth[BUFSIZE];
char proxyauth[BUFSIZE];
+
+ char *mime_type;
char *proto;
char *user;
@@ -592,17 +594,20 @@ static const char* http_plugin_get_mrl (input_plugin_t *this_gen) {
}
static int http_plugin_get_optional_data (input_plugin_t *this_gen,
- void *data, int data_type) {
+ void *const data, int data_type) {
+ void **const ptr = (void **const) data;
http_input_plugin_t *this = (http_input_plugin_t *) this_gen;
switch (data_type) {
case INPUT_OPTIONAL_DATA_PREVIEW:
-
memcpy (data, this->preview, this->preview_size);
return this->preview_size;
- break;
+ case INPUT_OPTIONAL_DATA_MIME_TYPE:
+ *ptr = this->mime_type;
+ case INPUT_OPTIONAL_DATA_DEMUX_MIME_TYPE:
+ return *this->mime_type ? INPUT_OPTIONAL_SUCCESS : INPUT_OPTIONAL_UNSUPPORTED;
}
return INPUT_OPTIONAL_UNSUPPORTED;
@@ -627,6 +632,7 @@ static void http_plugin_dispose (input_plugin_t *this_gen ) {
if (this->user) free(this->user);
if (this->password) free(this->password);
if (this->uri) free(this->uri);
+ if (this->mime_type) free(this->mime_type);
free (this);
}
@@ -655,7 +661,9 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
int use_proxy;
int proxyport;
int mpegurl_redirect = 0;
-
+ char mime_type[256];
+
+ mime_type[0] = 0;
use_proxy = this_class->proxyhost && strlen(this_class->proxyhost);
if (use_proxy) {
@@ -919,7 +927,11 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
/* content type */
if (!strncasecmp(this->buf, TAG_CONTENT_TYPE, sizeof(TAG_CONTENT_TYPE) - 1)) {
- if (!strncasecmp(this->buf + sizeof(TAG_CONTENT_TYPE) - 1, "video/nsv", 9)) {
+ const char *type = this->buf + sizeof (TAG_CONTENT_TYPE) - 1;
+ while (isspace (*type))
+ ++type;
+ sprintf (mime_type, "%.255s", type);
+ if (!strncasecmp (type, "video/nsv", 9)) {
lprintf("shoutcast nsv detected\n");
this->is_nsv = 1;
}
@@ -990,6 +1002,8 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
lprintf("preview_size=%"PRId64"\n", this->preview_size);
this->curpos = 0;
+ if (*mime_type)
+ this->mime_type = strdup (mime_type);
return 1;
}
diff --git a/src/input/input_plugin.h b/src/input/input_plugin.h
index 4790164d5..080e05476 100644
--- a/src/input/input_plugin.h
+++ b/src/input/input_plugin.h
@@ -307,6 +307,13 @@ struct input_plugin_s {
#define INPUT_OPTIONAL_DATA_SPULANG 3
#define INPUT_OPTIONAL_DATA_PREVIEW 7
+/* buffer is a const char **; the string is freed by the input plugin. */
+#define INPUT_OPTIONAL_DATA_MIME_TYPE 8
+/* buffer is unused; true if the demuxer should be determined by the MIME type */
+#define INPUT_OPTIONAL_DATA_DEMUX_MIME_TYPE 9
+/* buffer is a const char **; the string is static or freed by the input plugin. */
+#define INPUT_OPTIONAL_DATA_DEMUXER 10
+
#define MAX_MRL_ENTRIES 255
#define MAX_PREVIEW_SIZE 4096
diff --git a/src/input/input_pnm.c b/src/input/input_pnm.c
index 937b7c89b..669d24d28 100644
--- a/src/input/input_pnm.c
+++ b/src/input/input_pnm.c
@@ -82,8 +82,6 @@ static off_t pnm_plugin_read (input_plugin_t *this_gen,
lprintf ("pnm_plugin_read: %"PRId64" bytes ...\n", len);
- nbc_check_buffers (this->nbc);
-
n = pnm_read (this->pnm, buf, len);
this->curpos += n;
diff --git a/src/input/input_rtsp.c b/src/input/input_rtsp.c
index db16c9bc6..110c4d4b6 100644
--- a/src/input/input_rtsp.c
+++ b/src/input/input_rtsp.c
@@ -83,8 +83,6 @@ static off_t rtsp_plugin_read (input_plugin_t *this_gen,
lprintf ("rtsp_plugin_read: %"PRId64" bytes ...\n", len);
- nbc_check_buffers (this->nbc);
-
n = rtsp_session_read (this->rtsp, buf, len);
this->curpos += n;
diff --git a/src/input/input_v4l.c b/src/input/input_v4l.c
index 304f6f484..29ed9899b 100644
--- a/src/input/input_v4l.c
+++ b/src/input/input_v4l.c
@@ -97,6 +97,9 @@ static const resolution_t resolutions[] = {
#define AUDIO_DEV "plughw:0,0"
#endif
+static char *tv_standard_names[] = { "AUTO", "PAL", "NTSC", "SECAM", "OLD", NULL };
+static int tv_standard_values[] = { VIDEO_MODE_AUTO, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM, -1 };
+
#if !defined(NDELAY) && defined(O_NDELAY)
#define FNDELAY O_NDELAY
#endif
@@ -631,6 +634,7 @@ static int search_by_channel(v4l_input_plugin_t *this, char *input_source)
{
int ret = 0;
int fd = 0;
+ cfg_entry_t *tv_standard_entry;
lprintf("input_source: %s\n", input_source);
@@ -666,8 +670,17 @@ static int search_by_channel(v4l_input_plugin_t *this, char *input_source)
return -1;
}
+ tv_standard_entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
+ "media.video4linux.tv_standard");
this->tuner_name = input_source;
- ret = ioctl(fd, VIDIOCSCHAN, &this->input);
+ if (tv_standard_entry->num_value != 0) {
+ this->video_channel.norm = tv_standard_values[ tv_standard_entry->num_value ];
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ "input_v4l: TV Standard configured as STD %s (%d)\n",
+ tv_standard_names[ tv_standard_entry->num_value ], this->video_channel.norm );
+ ret = ioctl(fd, VIDIOCSCHAN, &this->video_channel);
+ } else
+ ret = ioctl(fd, VIDIOCSCHAN, &this->input);
lprintf("(%d) Set channel to %d\n", ret, this->input);
@@ -1907,7 +1920,11 @@ static void *init_video_class (xine_t *xine, void *data)
_("The name of the audio device which corresponds "
"to your Video4Linux video device."),
10, NULL, NULL);
-#endif
+#endif
+ config->register_enum (config, "media.video4linux.tv_standard", 4 /* old */,
+ tv_standard_names, _("v4l TV standard"),
+ _("Selects the TV standard of the input signals. "
+ "Either: AUTO, PAL, NTSC or SECAM. "), 20, NULL, NULL);
return this;
}
diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c
index 4a39aadfb..e27ed99f3 100644
--- a/src/input/net_buf_ctrl.c
+++ b/src/input/net_buf_ctrl.c
@@ -113,6 +113,10 @@ static void nbc_set_speed_normal (nbc_t *this) {
stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
}
+void nbc_check_buffers (nbc_t *this) {
+ /* Deprecated */
+}
+
static void display_stats (nbc_t *this) {
const char buffering[2][4] = {" ", "buf"};
const char enabled[2][4] = {"off", "on "};
@@ -560,3 +564,22 @@ void nbc_close (nbc_t *this) {
free (this);
xprintf(xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: nbc_close: done\n");
}
+
+
+void nbc_set_high_water_mark(nbc_t *this, int value) {
+/*
+ Deprecated
+ this->high_water_mark = value;
+*/
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n");
+}
+
+void nbc_set_low_water_mark(nbc_t *this, int value) {
+/*
+ Deprecated
+ this->low_water_mark = value;
+*/
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n");
+}
diff --git a/src/input/net_buf_ctrl.h b/src/input/net_buf_ctrl.h
index 3f4b4b3bf..7dfb7b0d1 100644
--- a/src/input/net_buf_ctrl.h
+++ b/src/input/net_buf_ctrl.h
@@ -29,12 +29,12 @@ typedef struct nbc_s nbc_t;
nbc_t *nbc_init (xine_stream_t *xine) XINE_MALLOC;
-void nbc_check_buffers (nbc_t *this);
+void nbc_check_buffers (nbc_t *this) XINE_DEPRECATED;
void nbc_close (nbc_t *this);
-void nbc_set_high_water_mark(nbc_t *this, int value);
+void nbc_set_high_water_mark(nbc_t *this, int value) XINE_DEPRECATED;
-void nbc_set_low_water_mark(nbc_t *this, int value);
+void nbc_set_low_water_mark(nbc_t *this, int value) XINE_DEPRECATED;
#endif
diff --git a/src/input/vcd/xine-extra.c b/src/input/vcd/xine-extra.c
index 79c962a79..e3b6da912 100644
--- a/src/input/vcd/xine-extra.c
+++ b/src/input/vcd/xine-extra.c
@@ -45,8 +45,10 @@ static xine_t *my_xine = NULL;
void
xine_vlog_msg(xine_t *this, int buf, const char *format, va_list args)
{
+ va_list copy;
+ va_copy (copy, args);
xine_vlog(this, buf, format, args);
- vfprintf(stdout, format, args);
+ vfprintf(stdout, format, copy);
}
/*! This routine is like xine_log, except it takes a va_list instead
@@ -59,8 +61,10 @@ xine_vlog_msg(xine_t *this, int buf, const char *format, va_list args)
void
xine_vlog_err(xine_t *this, int buf, const char *format, va_list args)
{
+ va_list copy;
+ va_copy (copy, args);
xine_vlog(this, buf, format, args);
- vfprintf(stderr, format, args);
+ vfprintf(stderr, format, copy);
}
/*! Call this before calling any of the xine_log_msg or xine_log_err
@@ -116,8 +120,8 @@ xine_log_err(const char *format, ...)
{
va_list args;
- va_start(args, format);
if (NULL == my_xine) return false;
+ va_start(args, format);
xine_vlog_err(my_xine, XINE_LOG_MSG, format, args);
va_end(args);
return true;
diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am
index 28aca041b..80dd1e92c 100644
--- a/src/video_out/Makefile.am
+++ b/src/video_out/Makefile.am
@@ -206,4 +206,4 @@ xineplug_vo_out_macosx_la_LDFLAGS = $(AM_LDFLAGS) \
-Wl,-framework -Wl,Cocoa -framework Cocoa -framework OpenGL
noinst_HEADERS = deinterlace.h video_out_syncfb.h \
- yuv2rgb.h x11osd.h xcbosd.h
+ yuv2rgb.h x11osd.h xcbosd.h xv_common.h
diff --git a/src/video_out/video_out_xcbxv.c b/src/video_out/video_out_xcbxv.c
index a4a3c3812..b6e5544c3 100644
--- a/src/video_out/video_out_xcbxv.c
+++ b/src/video_out/video_out_xcbxv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2004, 2007 the xine project
+ * Copyright (C) 2000-2004, 2007-2008 the xine project
*
* This file is part of xine, a free video player.
*
@@ -65,6 +65,7 @@
#include "xineutils.h"
#include "vo_scale.h"
#include "xcbosd.h"
+#include "xv_common.h"
typedef struct xv_driver_s xv_driver_t;
@@ -155,6 +156,8 @@ typedef struct {
xine_t *xine;
} xv_class_t;
+static const char *const prefer_types[] = VIDEO_DEVICE_XV_PREFER_TYPES;
+
static uint32_t xv_get_capabilities (vo_driver_t *this_gen) {
xv_driver_t *this = (xv_driver_t *) this_gen;
@@ -1101,6 +1104,8 @@ static int xv_check_yv12(xcb_connection_t *connection, xcb_xv_port_t port) {
list_formats_cookie = xcb_xv_list_image_formats(connection, port);
list_formats_reply = xcb_xv_list_image_formats_reply(connection, list_formats_cookie, NULL);
+ if (!list_formats_reply)
+ return 1; /* no formats listed; probably due to an invalid port no. */
format_it = xcb_xv_list_image_formats_format_iterator(list_formats_reply);
for (; format_it.rem; xcb_xv_image_format_info_next(&format_it))
@@ -1122,7 +1127,7 @@ static void xv_check_capability (xv_driver_t *this,
char *config_help) {
int int_default;
cfg_entry_t *entry;
- char *str_prop = xcb_xv_attribute_info_name(attr);
+ const char *str_prop = xcb_xv_attribute_info_name(attr);
xcb_xv_get_port_attribute_cookie_t get_attribute_cookie;
xcb_xv_get_port_attribute_reply_t *get_attribute_reply;
@@ -1274,14 +1279,67 @@ static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry
this->use_pitch_alignment = entry->num_value;
}
+static xcb_xv_port_t xv_open_port (xv_driver_t *this, xcb_xv_port_t port) {
+ xcb_xv_grab_port_cookie_t grab_port_cookie;
+ xcb_xv_grab_port_reply_t *grab_port_reply;
+
+ if (xv_check_yv12 (this->connection, port))
+ return 0;
+
+ grab_port_cookie = xcb_xv_grab_port (this->connection, port, XCB_CURRENT_TIME);
+ grab_port_reply = xcb_xv_grab_port_reply (this->connection, grab_port_cookie, NULL);
+
+ if (grab_port_reply && (grab_port_reply->result == XCB_GRAB_STATUS_SUCCESS))
+ {
+ free (grab_port_reply);
+ return port;
+ }
+ free (grab_port_reply);
+ return 0;
+}
+
+static xcb_xv_adaptor_info_iterator_t *
+xv_find_adaptor_by_port (int port, xcb_xv_adaptor_info_iterator_t *adaptor_it)
+{
+ for (; adaptor_it->rem; xcb_xv_adaptor_info_next(adaptor_it))
+ if (adaptor_it->data->type & XCB_XV_TYPE_IMAGE_MASK)
+ if (port >= adaptor_it->data->base_id &&
+ port < adaptor_it->data->base_id + adaptor_it->data->num_ports)
+ return adaptor_it;
+ return NULL; /* shouldn't happen */
+}
+
+static xcb_xv_port_t xv_autodetect_port(xv_driver_t *this,
+ xcb_xv_adaptor_info_iterator_t *adaptor_it,
+ xcb_xv_port_t base,
+ xv_prefertype prefer_type)
+{
+ xcb_xv_adaptor_info_iterator_t *start = adaptor_it;
+
+ for (; adaptor_it->rem; xcb_xv_adaptor_info_next(adaptor_it))
+ if (adaptor_it->data->type & XCB_XV_TYPE_IMAGE_MASK &&
+ (prefer_type == xv_prefer_none ||
+ strcasestr (xcb_xv_adaptor_info_name (adaptor_it->data), prefer_types[prefer_type])))
+ {
+ int j;
+ for (j = 0; j < adaptor_it->data->num_ports; ++j)
+ {
+ xcb_xv_port_t port = adaptor_it->data->base_id + j;
+ if (port >= base && xv_open_port (this, port))
+ return port;
+ }
+ }
+ return 0;
+}
+
static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *visual_gen) {
xv_class_t *class = (xv_class_t *) class_gen;
config_values_t *config = class->config;
xv_driver_t *this;
int i;
xcb_visual_t *visual = (xcb_visual_t *) visual_gen;
- unsigned int j;
xcb_xv_port_t xv_port;
+ xv_prefertype prefer_type;
const xcb_query_extension_reply_t *query_extension_reply;
@@ -1331,28 +1389,26 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis
}
adaptor_it = xcb_xv_query_adaptors_info_iterator(query_adaptors_reply);
-
- xv_port = 0;
-
- for (; adaptor_it.rem && !xv_port; xcb_xv_adaptor_info_next(&adaptor_it)) {
-
- if (adaptor_it.data->type & XCB_XV_TYPE_IMAGE_MASK) {
-
- for (j = 0; j < adaptor_it.data->num_ports; j++)
- if (!xv_check_yv12(this->connection, adaptor_it.data->base_id + j)) {
- xcb_xv_grab_port_cookie_t grab_port_cookie;
- xcb_xv_grab_port_reply_t *grab_port_reply;
- grab_port_cookie = xcb_xv_grab_port(this->connection, adaptor_it.data->base_id + j, XCB_CURRENT_TIME);
- grab_port_reply = xcb_xv_grab_port_reply(this->connection, grab_port_cookie, NULL);
- if (grab_port_reply && (grab_port_reply->result == XCB_GRAB_STATUS_SUCCESS)) {
- free(grab_port_reply);
- xv_port = adaptor_it.data->base_id + j;
- break;
- }
- free(grab_port_reply);
- }
- }
+ xv_port = config->register_num (config, "video.device.xv_port", 0,
+ VIDEO_DEVICE_XV_PORT_HELP,
+ 20, NULL, NULL);
+ prefer_type = config->register_enum (config, "video.device.xv_preferred_method", 0,
+ prefer_types, VIDEO_DEVICE_XV_PREFER_TYPE_HELP,
+ 10, NULL, NULL);
+
+ if (xv_port != 0) {
+ if (! xv_open_port(this, xv_port)) {
+ xprintf(class->xine, XINE_VERBOSITY_NONE,
+ _("%s: could not open Xv port %d - autodetecting\n"),
+ LOG_MODULE, xv_port);
+ xv_port = xv_autodetect_port (this, &adaptor_it, xv_port, prefer_type);
+ } else
+ xv_find_adaptor_by_port (xv_port, &adaptor_it);
}
+ if (!xv_port)
+ xv_port = xv_autodetect_port (this, &adaptor_it, 0, prefer_type);
+ if (!xv_port)
+ xv_port = xv_autodetect_port (this, &adaptor_it, 0, xv_prefer_none);
if (!xv_port) {
xprintf(class->xine, XINE_VERBOSITY_LOG,
@@ -1432,10 +1488,11 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis
for (; attribute_it.rem; xcb_xv_attribute_info_next(&attribute_it)) {
if ((attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_SETTABLE) && (attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_GETTABLE)) {
+ const char *const name = xcb_xv_attribute_info_name(attribute_it.data);
/* store initial port attribute value */
- xv_store_port_attribute(this, xcb_xv_attribute_info_name(attribute_it.data));
-
- if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_HUE")) {
+ xv_store_port_attribute(this, name);
+
+ if(!strcmp(name, "XV_HUE")) {
if (!strncmp(xcb_xv_adaptor_info_name(adaptor_it.data), "NV", 2)) {
xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xcbxv: ignoring broken XV_HUE settings on NVidia cards\n");
} else {
@@ -1443,63 +1500,41 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis
adaptor_it.data->base_id,
NULL, NULL, NULL);
}
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_SATURATION")) {
+ } else if(!strcmp(name, "XV_SATURATION")) {
xv_check_capability (this, VO_PROP_SATURATION, attribute_it.data,
adaptor_it.data->base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_BRIGHTNESS")) {
+ } else if(!strcmp(name, "XV_BRIGHTNESS")) {
xv_check_capability (this, VO_PROP_BRIGHTNESS, attribute_it.data,
adaptor_it.data->base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_CONTRAST")) {
+ } else if(!strcmp(name, "XV_CONTRAST")) {
xv_check_capability (this, VO_PROP_CONTRAST, attribute_it.data,
adaptor_it.data->base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_COLORKEY")) {
+ } else if(!strcmp(name, "XV_COLORKEY")) {
xv_check_capability (this, VO_PROP_COLORKEY, attribute_it.data,
adaptor_it.data->base_id,
"video.device.xv_colorkey",
- _("video overlay colour key"),
- _("The colour key is used to tell the graphics card where to "
- "overlay the video image. Try different values, if you experience "
- "windows becoming transparent."));
-
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_AUTOPAINT_COLORKEY")) {
+ VIDEO_DEVICE_XV_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) {
xv_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attribute_it.data,
adaptor_it.data->base_id,
"video.device.xv_autopaint_colorkey",
- _("autopaint colour key"),
- _("Make Xv autopaint its colour key."));
-
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_FILTER")) {
+ VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_FILTER")) {
int xv_filter;
/* This setting is specific to Permedia 2/3 cards. */
xv_filter = config->register_range (config, "video.device.xv_filter", 0,
attribute_it.data->min, attribute_it.data->max,
- _("bilinear scaling mode"),
- _("Selects the bilinear scaling mode for Permedia cards. "
- "The individual values are:\n\n"
- "Permedia 2\n"
- "0 - disable bilinear filtering\n"
- "1 - enable bilinear filtering\n\n"
- "Permedia 3\n"
- "0 - disable bilinear filtering\n"
- "1 - horizontal linear filtering\n"
- "2 - enable full bilinear filtering"),
+ VIDEO_DEVICE_XV_FILTER_HELP,
20, xv_update_XV_FILTER, this);
config->update_num(config,"video.device.xv_filter",xv_filter);
- } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_DOUBLE_BUFFER")) {
- int xv_double_buffer;
- xv_double_buffer =
+ } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) {
+ int xv_double_buffer =
config->register_bool (config, "video.device.xv_double_buffer", 1,
- _("enable double buffering"),
- _("Double buffering will synchronize the update of the video image to the "
- "repainting of the entire screen (\"vertical retrace\"). This eliminates "
- "flickering and tearing artifacts, but will use more graphics memory."),
- 20, xv_update_XV_DOUBLE_BUFFER, this);
+ VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP,
+ 20, xv_update_XV_DOUBLE_BUFFER, this);
config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer);
} else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_SYNC_TO_VBLANK")) {
int xv_sync_to_vblank;
@@ -1557,8 +1592,7 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis
this->use_pitch_alignment =
config->register_bool (config, "video.device.xv_pitch_alignment", 0,
- _("pitch alignment workaround"),
- _("Some buggy video drivers need a workaround to function properly."),
+ VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP,
10, xv_update_xv_pitch_alignment, this);
this->deinterlace_method =
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
index e1f6d0de0..8f5da8ea0 100644
--- a/src/video_out/video_out_xv.c
+++ b/src/video_out/video_out_xv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2004 the xine project
+ * Copyright (C) 2000-2004, 2008 the xine project
*
* This file is part of xine, a free video player.
*
@@ -70,6 +70,7 @@
#include "xineutils.h"
#include "vo_scale.h"
#include "x11osd.h"
+#include "xv_common.h"
#define LOCK_DISPLAY(this) {if(this->lock_display) this->lock_display(this->user_data); \
else XLockDisplay(this->display);}
@@ -168,6 +169,8 @@ typedef struct {
static int gX11Fail;
+static const char *const prefer_types[] = VIDEO_DEVICE_XV_PREFER_TYPES;
+
static uint32_t xv_get_capabilities (vo_driver_t *this_gen) {
xv_driver_t *this = (xv_driver_t *) this_gen;
@@ -1190,14 +1193,13 @@ static int xv_check_yv12 (Display *display, XvPortID port) {
/* called xlocked */
static void xv_check_capability (xv_driver_t *this,
- int property, XvAttribute attr,
- int base_id,
+ int property, XvAttribute attr, int base_id,
char *config_name,
char *config_desc,
char *config_help) {
int int_default;
cfg_entry_t *entry;
- char *str_prop = attr.name;
+ const char *str_prop = attr.name;
/*
* some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing.
@@ -1321,6 +1323,52 @@ static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry
this->use_pitch_alignment = entry->num_value;
}
+static int xv_open_port (xv_driver_t *this, XvPortID port) {
+ int ret;
+ x11_InstallXErrorHandler (this);
+ ret = ! xv_check_yv12(this->display, port)
+ && XvGrabPort(this->display, port, 0) == Success;
+ x11_DeInstallXErrorHandler (this);
+ return ret;
+}
+
+static unsigned int
+xv_find_adaptor_by_port (int port, unsigned int adaptors,
+ XvAdaptorInfo *adaptor_info)
+{
+ unsigned int an;
+ for (an = 0; an < adaptors; an++)
+ if (adaptor_info[an].type & XvImageMask)
+ if (port >= adaptor_info[an].base_id &&
+ port < adaptor_info[an].base_id + adaptor_info[an].num_ports)
+ return an;
+ return 0; /* shouldn't happen */
+}
+
+static XvPortID xv_autodetect_port(xv_driver_t *this,
+ unsigned int adaptors,
+ XvAdaptorInfo *adaptor_info,
+ unsigned int *adaptor_num,
+ XvPortID base,
+ xv_prefertype prefer_type)
+{
+ unsigned int an, j;
+
+ for (an = 0; an < adaptors; an++)
+ if (adaptor_info[an].type & XvImageMask &&
+ (prefer_type == xv_prefer_none ||
+ strcasestr (adaptor_info[an].name, prefer_types[prefer_type])))
+ for (j = 0; j < adaptor_info[an].num_ports; j++) {
+ XvPortID port = adaptor_info[an].base_id + j;
+ if (port >= base && xv_open_port(this, port)) {
+ *adaptor_num = an;
+ return port;
+ }
+ }
+
+ return 0;
+}
+
/* expects XINE_VISUAL_TYPE_X11_2 with configurable locking */
static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *visual_gen) {
xv_class_t *class = (xv_class_t *) class_gen;
@@ -1333,12 +1381,13 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *
x11_visual_t *visual = (x11_visual_t *) visual_gen;
XColor dummy;
XvImage *myimage;
- unsigned int adaptors, j;
+ unsigned int adaptors;
unsigned int ver,rel,req,ev,err;
XShmSegmentInfo myshminfo;
XvPortID xv_port;
XvAdaptorInfo *adaptor_info;
unsigned int adaptor_num;
+ xv_prefertype prefer_type;
this = (xv_driver_t *) calloc(1, sizeof(xv_driver_t));
if (!this)
@@ -1376,25 +1425,26 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *
return NULL;
}
- xv_port = 0;
-
- for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) {
-
- if (adaptor_info[adaptor_num].type & XvImageMask) {
-
- for (j = 0; j < adaptor_info[adaptor_num].num_ports && !xv_port; j++)
- if (( !(xv_check_yv12 (this->display,
- adaptor_info[adaptor_num].base_id + j)))
- && (XvGrabPort (this->display,
- adaptor_info[adaptor_num].base_id + j,
- 0) == Success)) {
- xv_port = adaptor_info[adaptor_num].base_id + j;
- }
-
- if( xv_port )
- break;
- }
+ xv_port = config->register_num (config, "video.device.xv_port", 0,
+ VIDEO_DEVICE_XV_PORT_HELP,
+ 20, NULL, NULL);
+ prefer_type = config->register_enum (config, "video.device.xv_preferred_method", 0,
+ prefer_types, VIDEO_DEVICE_XV_PREFER_TYPE_HELP,
+ 10, NULL, NULL);
+
+ if (xv_port != 0) {
+ if (! xv_open_port(this, xv_port)) {
+ xprintf(class->xine, XINE_VERBOSITY_NONE,
+ _("%s: could not open Xv port %d - autodetecting\n"),
+ LOG_MODULE, xv_port);
+ xv_port = xv_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, xv_port, prefer_type);
+ } else
+ adaptor_num = xv_find_adaptor_by_port (xv_port, adaptors, adaptor_info);
}
+ if (!xv_port)
+ xv_port = xv_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0, prefer_type);
+ if (!xv_port)
+ xv_port = xv_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0, xv_prefer_none);
if (!xv_port) {
xprintf(class->xine, XINE_VERBOSITY_LOG,
@@ -1485,10 +1535,11 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *
for(k = 0; k < nattr; k++) {
if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) {
+ const char *const name = attr[k].name;
/* store initial port attribute value */
- xv_store_port_attribute(this, attr[k].name);
+ xv_store_port_attribute(this, name);
- if(!strcmp(attr[k].name, "XV_HUE")) {
+ if(!strcmp(name, "XV_HUE")) {
if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) {
xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xv: ignoring broken XV_HUE settings on NVidia cards\n");
} else {
@@ -1496,63 +1547,41 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *
adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
}
- } else if(!strcmp(attr[k].name, "XV_SATURATION")) {
+ } else if(!strcmp(name, "XV_SATURATION")) {
xv_check_capability (this, VO_PROP_SATURATION, attr[k],
adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) {
+ } else if(!strcmp(name, "XV_BRIGHTNESS")) {
xv_check_capability (this, VO_PROP_BRIGHTNESS, attr[k],
adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_CONTRAST")) {
+ } else if(!strcmp(name, "XV_CONTRAST")) {
xv_check_capability (this, VO_PROP_CONTRAST, attr[k],
adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_COLORKEY")) {
+ } else if(!strcmp(name, "XV_COLORKEY")) {
xv_check_capability (this, VO_PROP_COLORKEY, attr[k],
adaptor_info[adaptor_num].base_id,
"video.device.xv_colorkey",
- _("video overlay colour key"),
- _("The colour key is used to tell the graphics card where to "
- "overlay the video image. Try different values, if you experience "
- "windows becoming transparent."));
-
- } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) {
+ VIDEO_DEVICE_XV_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) {
xv_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k],
adaptor_info[adaptor_num].base_id,
"video.device.xv_autopaint_colorkey",
- _("autopaint colour key"),
- _("Make Xv autopaint its colour key."));
-
- } else if(!strcmp(attr[k].name, "XV_FILTER")) {
+ VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_FILTER")) {
int xv_filter;
/* This setting is specific to Permedia 2/3 cards. */
xv_filter = config->register_range (config, "video.device.xv_filter", 0,
attr[k].min_value, attr[k].max_value,
- _("bilinear scaling mode"),
- _("Selects the bilinear scaling mode for Permedia cards. "
- "The individual values are:\n\n"
- "Permedia 2\n"
- "0 - disable bilinear filtering\n"
- "1 - enable bilinear filtering\n\n"
- "Permedia 3\n"
- "0 - disable bilinear filtering\n"
- "1 - horizontal linear filtering\n"
- "2 - enable full bilinear filtering"),
+ VIDEO_DEVICE_XV_FILTER_HELP,
20, xv_update_XV_FILTER, this);
config->update_num(config,"video.device.xv_filter",xv_filter);
- } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) {
- int xv_double_buffer;
- xv_double_buffer =
+ } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) {
+ int xv_double_buffer =
config->register_bool (config, "video.device.xv_double_buffer", 1,
- _("enable double buffering"),
- _("Double buffering will synchronize the update of the video image to the "
- "repainting of the entire screen (\"vertical retrace\"). This eliminates "
- "flickering and tearing artifacts, but will use more graphics memory."),
- 20, xv_update_XV_DOUBLE_BUFFER, this);
+ VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP,
+ 20, xv_update_XV_DOUBLE_BUFFER, this);
config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer);
} else if(!strcmp(attr[k].name, "XV_SYNC_TO_VBLANK")) {
int xv_sync_to_vblank;
@@ -1621,8 +1650,7 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *
this->use_pitch_alignment =
config->register_bool (config, "video.device.xv_pitch_alignment", 0,
- _("pitch alignment workaround"),
- _("Some buggy video drivers need a workaround to function properly."),
+ VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP,
10, xv_update_xv_pitch_alignment, this);
this->deinterlace_method =
diff --git a/src/video_out/video_out_xvmc.c b/src/video_out/video_out_xvmc.c
index 79c2a80a3..366a03859 100644
--- a/src/video_out/video_out_xvmc.c
+++ b/src/video_out/video_out_xvmc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2004 the xine project
+ * Copyright (C) 2000-2004, 2008 the xine project
*
* This file is part of xine, a free video player.
*
@@ -75,6 +75,7 @@
#include "xineutils.h"
#include "vo_scale.h"
+#include "xv_common.h"
/* #define LOG1 */
/* #define DLOG */
@@ -225,8 +226,6 @@ typedef struct {
Display *display;
config_values_t *config;
XvPortID xv_port;
- XvAdaptorInfo *adaptor_info;
- unsigned int adaptor_num;
int surface_type_id;
unsigned int max_surface_width;
@@ -1252,13 +1251,13 @@ static void xvmc_dispose (vo_driver_t *this_gen) {
/* called xlocked */
static void xvmc_check_capability (xvmc_driver_t *this,
- int property, XvAttribute attr,
- int base_id, char *str_prop,
- char *config_name,
- char *config_desc,
- char *config_help) {
+ int property, XvAttribute attr, int base_id,
+ const char *config_name,
+ const char *config_desc,
+ const char *config_help) {
int int_default;
cfg_entry_t *entry;
+ const char *str_prop = attr.name;
/*
* some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing.
@@ -1281,13 +1280,13 @@ static void xvmc_check_capability (xvmc_driver_t *this,
if ((attr.min_value == 0) && (attr.max_value == 1)) {
this->config->register_bool (this->config, config_name, int_default,
config_desc,
- NULL, 20, xvmc_property_callback, &this->props[property]);
+ config_help, 20, xvmc_property_callback, &this->props[property]);
} else {
this->config->register_range (this->config, config_name, int_default,
this->props[property].min, this->props[property].max,
config_desc,
- NULL, 20, xvmc_property_callback, &this->props[property]);
+ config_help, 20, xvmc_property_callback, &this->props[property]);
}
entry = this->config->lookup_entry (this->config, config_name);
@@ -1333,7 +1332,6 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
xvmc_class_t *class = (xvmc_class_t *) class_gen;
config_values_t *config = class->config;
xvmc_driver_t *this = NULL;
- Display *display = NULL;
unsigned int i, formats;
XvPortID xv_port = class->xv_port;
XvAttribute *attr;
@@ -1341,13 +1339,12 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
int nattr;
x11_visual_t *visual = (x11_visual_t *) visual_gen;
XColor dummy;
+ XvAdaptorInfo *adaptor_info;
+ unsigned int adaptor_num;
/* XvImage *myimage; */
lprintf ("open_plugin\n");
- display = visual->display;
-
- /* TODO ??? */
this = calloc(1, sizeof (xvmc_driver_t));
if (!this)
@@ -1430,56 +1427,47 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
this->capabilities |= VO_CAP_XVMC_IDCT;
XLockDisplay(this->display);
- attr = XvQueryPortAttributes(display, xv_port, &nattr);
+ attr = XvQueryPortAttributes(this->display, xv_port, &nattr);
if(attr && nattr) {
int k;
for(k = 0; k < nattr; k++) {
if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) {
- if(!strcmp(attr[k].name, "XV_HUE")) {
- xvmc_check_capability (this, VO_PROP_HUE, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_HUE",
- NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_SATURATION")) {
+ const char *const name = attr[k].name;
+ if(!strcmp(name, "XV_HUE")) {
+ if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) {
+ xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n");
+ } else {
+ xvmc_check_capability (this, VO_PROP_HUE, attr[k],
+ adaptor_info[adaptor_num].base_id,
+ NULL, NULL, NULL);
+ }
+ } else if(!strcmp(name, "XV_SATURATION")) {
xvmc_check_capability (this, VO_PROP_SATURATION, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_SATURATION",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
} else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) {
xvmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_BRIGHTNESS",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_CONTRAST")) {
+ } else if(!strcmp(name, "XV_CONTRAST")) {
xvmc_check_capability (this, VO_PROP_CONTRAST, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_CONTRAST",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
-
- } else if(!strcmp(attr[k].name, "XV_COLORKEY")) {
+ } else if(!strcmp(name, "XV_COLORKEY")) {
xvmc_check_capability (this, VO_PROP_COLORKEY, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_COLORKEY",
+ adaptor_info[adaptor_num].base_id,
"video.device.xv_colorkey",
- _("video overlay colour key"),
- _("The colour key is used to tell the graphics card where to "
- "overlay the video image. Try different values, if you experience "
- "windows becoming transparent."));
-
- } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) {
+ VIDEO_DEVICE_XV_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) {
xvmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k],
- class->adaptor_info[class->adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY",
+ adaptor_info[adaptor_num].base_id,
"video.device.xv_autopaint_colorkey",
- _("autopaint colour key"),
- _("Make Xv autopaint its colour key."));
-
- } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) {
- int xvmc_double_buffer;
- xvmc_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1,
- _("enable double buffering"),
- _("Double buffering will synchronize the update of the video image to the "
- "repainting of the entire screen (\"vertical retrace\"). This eliminates "
- "flickering and tearing artifacts, but will use more graphics memory."),
- 20, xvmc_update_XV_DOUBLE_BUFFER, this);
+ VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) {
+ int xvmc_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1,
+ VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP,
+ 20, xvmc_update_XV_DOUBLE_BUFFER, this);
config->update_num(config,"video.device.xv_double_buffer",xvmc_double_buffer);
}
}
@@ -1494,7 +1482,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
/*
* check supported image formats
*/
- fo = XvListImageFormats(display, this->xv_port, (int*)&formats);
+ fo = XvListImageFormats(this->display, this->xv_port, (int*)&formats);
XUnlockDisplay(this->display);
this->xvmc_format_yv12 = 0;
@@ -1613,10 +1601,6 @@ static char* get_description (video_driver_class_t *this_gen) {
static void dispose_class (video_driver_class_t *this_gen) {
xvmc_class_t *this = (xvmc_class_t *) this_gen;
- XLockDisplay(this->display);
- XvFreeAdaptorInfo (this->adaptor_info);
- XUnlockDisplay(this->display);
-
free (this);
}
@@ -1789,8 +1773,6 @@ static void *init_class (xine_t *xine, void *visual_gen) {
this->display = display;
this->config = xine->config;
this->xv_port = xv_port;
- this->adaptor_info = adaptor_info;
- this->adaptor_num = adaptor_num;
this->surface_type_id = surface_type;
this->max_surface_width = max_width;
this->max_surface_height = max_height;
diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c
index b016a8bd1..b8d6abf83 100644
--- a/src/video_out/video_out_xxmc.c
+++ b/src/video_out/video_out_xxmc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2004 the xine project
+ * Copyright (C) 2000-2004, 2008 the xine project
* Copyright (C) 2004 the Unichrome project
*
* This file is part of xine, a free video player.
@@ -34,9 +34,9 @@
*/
-
#include "xxmc.h"
#include <unistd.h>
+#include "xv_common.h"
static int gX11Fail;
@@ -45,6 +45,7 @@ static void xxmc_frame_updates(xxmc_driver_t *driver, xxmc_frame_t *frame,
static void dispose_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo,
XvImage *myimage);
+static const char *const prefer_types[] = VIDEO_DEVICE_XV_PREFER_TYPES;
/*
* Acceleration level priority. Static for now. It may well turn out that IDCT
@@ -2061,13 +2062,13 @@ static int xxmc_check_yv12 (Display *display, XvPortID port) {
/* called xlocked */
static void xxmc_check_capability (xxmc_driver_t *this,
- int property, XvAttribute attr,
- int base_id, char *str_prop,
- char *config_name,
- char *config_desc,
- char *config_help) {
+ int property, XvAttribute attr, int base_id,
+ const char *config_name,
+ const char *config_desc,
+ const char *config_help) {
int int_default;
cfg_entry_t *entry;
+ const char *str_prop = attr.name;
if (VO_PROP_COLORKEY && (attr.max_value == ~0))
attr.max_value = 2147483615;
@@ -2197,6 +2198,52 @@ static void xxmc_update_disable_bob_for_scaled_osd(void *this_gen, xine_cfg_entr
this->disable_bob_for_scaled_osd = entry->num_value;
}
+static int xxmc_open_port (xxmc_driver_t *this, XvPortID port) {
+ int ret;
+ x11_InstallXErrorHandler (this);
+ ret = ! xxmc_check_yv12(this->display, port)
+ && XvGrabPort(this->display, port, 0) == Success;
+ x11_DeInstallXErrorHandler (this);
+ return ret;
+}
+
+static unsigned int
+xxmc_find_adaptor_by_port (int port, unsigned int adaptors,
+ XvAdaptorInfo *adaptor_info)
+{
+ unsigned int an;
+ for (an = 0; an < adaptors; an++)
+ if (adaptor_info[an].type & XvImageMask)
+ if (port >= adaptor_info[an].base_id &&
+ port < adaptor_info[an].base_id + adaptor_info[an].num_ports)
+ return an;
+ return 0; /* shouldn't happen */
+}
+
+static XvPortID xxmc_autodetect_port(xxmc_driver_t *this,
+ unsigned int adaptors,
+ XvAdaptorInfo *adaptor_info,
+ unsigned int *adaptor_num,
+ XvPortID base,
+ xv_prefertype prefer_type)
+{
+ unsigned int an, j;
+
+ for (an = 0; an < adaptors; an++)
+ if (adaptor_info[an].type & XvImageMask &&
+ (prefer_type == xv_prefer_none ||
+ strcasestr (adaptor_info[an].name, prefer_types[prefer_type])))
+ for (j = 0; j < adaptor_info[an].num_ports; j++) {
+ XvPortID port = adaptor_info[an].base_id + j;
+ if (port >= base && xxmc_open_port(this, port)) {
+ *adaptor_num = an;
+ return port;
+ }
+ }
+
+ return 0;
+}
+
static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port)
{
@@ -2365,6 +2412,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
XvPortID xv_port;
XvAdaptorInfo *adaptor_info;
unsigned int adaptor_num;
+ xv_prefertype prefer_type;
cfg_entry_t *entry;
int use_more_frames;
int use_unscaled;
@@ -2400,25 +2448,26 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
return NULL;
}
- xv_port = 0;
-
- for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) {
-
- if (adaptor_info[adaptor_num].type & XvImageMask) {
+ xv_port = config->register_num (config, "video.device.xv_port", 0,
+ VIDEO_DEVICE_XV_PORT_HELP,
+ 20, NULL, NULL);
+ prefer_type = config->register_enum (config, "video.device.xv_preferred_method", 0,
+ prefer_types, VIDEO_DEVICE_XV_PREFER_TYPE_HELP,
+ 10, NULL, NULL);
- for (j = 0; j < adaptor_info[adaptor_num].num_ports && !xv_port; j++)
- if (( !(xxmc_check_yv12 (this->display,
- adaptor_info[adaptor_num].base_id + j)))
- && (XvGrabPort (this->display,
- adaptor_info[adaptor_num].base_id + j,
- 0) == Success)) {
- xv_port = adaptor_info[adaptor_num].base_id + j;
- }
-
- if( xv_port )
- break;
- }
+ if (xv_port != 0) {
+ if (! xxmc_open_port(this, xv_port)) {
+ xprintf(class->xine, XINE_VERBOSITY_NONE,
+ _("%s: could not open Xv port %d - autodetecting\n"),
+ LOG_MODULE, xv_port);
+ xv_port = xxmc_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, xv_port, prefer_type);
+ } else
+ adaptor_num = xxmc_find_adaptor_by_port (xv_port, adaptors, adaptor_info);
}
+ if (!xv_port)
+ xv_port = xxmc_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0, prefer_type);
+ if (!xv_port)
+ xv_port = xxmc_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0, xv_prefer_none);
if (!xv_port) {
xprintf(class->xine, XINE_VERBOSITY_LOG,
@@ -2506,70 +2555,52 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
for(k = 0; k < nattr; k++) {
if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) {
- if(!strcmp(attr[k].name, "XV_HUE")) {
+ const char *const name = attr[k].name;
+ if(!strcmp(name, "XV_HUE")) {
if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) {
xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xxmc: ignoring broken XV_HUE settings on NVidia cards\n");
} else {
xxmc_check_capability (this, VO_PROP_HUE, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_HUE",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
}
- } else if(!strcmp(attr[k].name, "XV_SATURATION")) {
+ } else if(!strcmp(name, "XV_SATURATION")) {
xxmc_check_capability (this, VO_PROP_SATURATION, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_SATURATION",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
- } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) {
+ } else if(!strcmp(name, "XV_BRIGHTNESS")) {
xxmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_BRIGHTNESS",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
- } else if(!strcmp(attr[k].name, "XV_CONTRAST")) {
+ } else if(!strcmp(name, "XV_CONTRAST")) {
xxmc_check_capability (this, VO_PROP_CONTRAST, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_CONTRAST",
+ adaptor_info[adaptor_num].base_id,
NULL, NULL, NULL);
- } else if(!strcmp(attr[k].name, "XV_COLORKEY")) {
+ } else if(!strcmp(name, "XV_COLORKEY")) {
xxmc_check_capability (this, VO_PROP_COLORKEY, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_COLORKEY",
+ adaptor_info[adaptor_num].base_id,
"video.device.xv_colorkey",
- _("video overlay colour key"),
- _("The colour key is used to tell the graphics card where to "
- "overlay the video image. Try different values, if you experience "
- "windows becoming transparent."));
-
- } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) {
+ VIDEO_DEVICE_XV_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) {
xxmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k],
- adaptor_info[adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY",
+ adaptor_info[adaptor_num].base_id,
"video.device.xv_autopaint_colorkey",
- _("autopaint colour key"),
- _("Make Xv autopaint its colour key."));
-
- } else if(!strcmp(attr[k].name, "XV_FILTER")) {
+ VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
+ } else if(!strcmp(name, "XV_FILTER")) {
int xv_filter;
/* This setting is specific to Permedia 2/3 cards. */
xv_filter = config->register_range (config, "video.device.xv_filter", 0,
attr[k].min_value, attr[k].max_value,
- _("bilinear scaling mode"),
- _("Selects the bilinear scaling mode for Permedia cards. "
- "The individual values are:\n\n"
- "Permedia 2\n"
- "0 - disable bilinear filtering\n"
- "1 - enable bilinear filtering\n\n"
- "Permedia 3\n"
- "0 - disable bilinear filtering\n"
- "1 - horizontal linear filtering\n"
- "2 - enable full bilinear filtering"),
+ VIDEO_DEVICE_XV_FILTER_HELP,
20, xxmc_update_XV_FILTER, this);
config->update_num(config,"video.device.xv_filter",xv_filter);
- } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) {
- int xv_double_buffer;
- xv_double_buffer =
+ } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) {
+ int xv_double_buffer =
config->register_bool (config, "video.device.xv_double_buffer", 1,
- _("enable double buffering"),
- _("Double buffering will synchronize the update of the video image to the "
- "repainting of the entire screen (\"vertical retrace\"). This eliminates "
- "flickering and tearing artifacts, but will use more graphics memory."),
+ VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP,
20, xxmc_update_XV_DOUBLE_BUFFER, this);
config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer);
}
@@ -2635,8 +2666,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
this->use_pitch_alignment =
config->register_bool (config, "video.device.xv_pitch_alignment", 0,
- _("pitch alignment workaround"),
- _("Some buggy video drivers need a workaround to function properly."),
+ VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP,
10, xxmc_update_xv_pitch_alignment, this);
use_more_frames=
diff --git a/src/video_out/xv_common.h b/src/video_out/xv_common.h
new file mode 100644
index 000000000..259afe616
--- /dev/null
+++ b/src/video_out/xv_common.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 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
+ *
+ * xv_common.h: X11 Xv common bits
+ */
+
+#define VIDEO_DEVICE_XV_COLORKEY_HELP \
+ _("video overlay colour key"), \
+ _("The colour key is used to tell the graphics card where to " \
+ "overlay the video image. Try different values, if you "\
+ "experience windows becoming transparent.")
+
+#define VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP \
+ _("autopaint colour key"), \
+ _("Make Xv autopaint its colour key.")
+
+#define VIDEO_DEVICE_XV_FILTER_HELP \
+ _("bilinear scaling mode"), \
+ _("Selects the bilinear scaling mode for Permedia cards. " \
+ "The individual values are:\n\n" \
+ "Permedia 2\n" \
+ "0 - disable bilinear filtering\n" \
+ "1 - enable bilinear filtering\n\n" \
+ "Permedia 3\n" \
+ "0 - disable bilinear filtering\n" \
+ "1 - horizontal linear filtering\n" \
+ "2 - enable full bilinear filtering")
+
+#define VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP \
+ _("enable double buffering"), \
+ _("Double buffering will synchronize the update of the video " \
+ "image to the repainting of the entire screen (\"vertical " \
+ "retrace\"). This eliminates flickering and tearing artifacts, " \
+ "but will use more graphics memory.")
+
+#define VIDEO_DEVICE_XV_PORT_HELP \
+ _("Xv port number"), \
+ _("Selects the Xv port number to use (0 to autodetect).")
+
+#define VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP \
+ _("pitch alignment workaround"), \
+ _("Some buggy video drivers need a workaround to function properly.")
+
+typedef enum {
+ xv_prefer_none, xv_prefer_overlay, xv_prefer_textured
+} xv_prefertype;
+#define VIDEO_DEVICE_XV_PREFER_TYPES \
+ { "Any", "Overlay", "Textured Video", NULL }
+#define VIDEO_DEVICE_XV_PREFER_TYPE_HELP \
+ _("video display method preference"), \
+ _("Selects which video output method is preferred. " \
+ "Detection is done using the reported Xv adaptor names.\n" \
+ "(Only applies when auto-detecting which Xv port to use.)")
diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c
index 107e7d792..a71092761 100644
--- a/src/xine-engine/load_plugins.c
+++ b/src/xine-engine/load_plugins.c
@@ -1224,6 +1224,26 @@ void _x_free_input_plugin (xine_stream_t *stream, input_plugin_t *input) {
}
}
+static int probe_mime_type (xine_t *self, plugin_node_t *node, const char *mime_type)
+{
+ /* catalog->lock is expected to be locked */
+ if (node->plugin_class || _load_plugin_class(self, node, NULL))
+ {
+ const unsigned int mime_type_len = strlen (mime_type);
+ demux_class_t *cls = (demux_class_t *)node->plugin_class;
+ const char *mime = cls->get_mimetypes (cls);
+ while (mime)
+ {
+ while (*mime == ';' || isspace (*mime))
+ ++mime;
+ if (!strncasecmp (mime, mime_type, mime_type_len) &&
+ (!mime[mime_type_len] || mime[mime_type_len] == ':' || mime[mime_type_len] == ';'))
+ return 1;
+ mime = strchr (mime, ';');
+ }
+ }
+ return 0;
+}
static demux_plugin_t *probe_demux (xine_stream_t *stream, int method1, int method2,
input_plugin_t *input) {
@@ -1246,8 +1266,6 @@ static demux_plugin_t *probe_demux (xine_stream_t *stream, int method1, int meth
while (methods[i] != -1 && !plugin) {
int list_id, list_size;
- stream->content_detection_method = methods[i];
-
pthread_mutex_lock (&catalog->lock);
list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
@@ -1259,6 +1277,25 @@ static demux_plugin_t *probe_demux (xine_stream_t *stream, int method1, int meth
xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "load_plugins: probing demux '%s'\n", node->info->id);
if (node->plugin_class || _load_plugin_class(stream->xine, node, NULL)) {
+ const char *mime_type;
+
+ /* If detecting by MRL, try the MIME type first (but not text/plain)... */
+ stream->content_detection_method = METHOD_EXPLICIT;
+ if (methods[i] == METHOD_BY_EXTENSION &&
+ stream->input_plugin->get_optional_data &&
+ stream->input_plugin->get_optional_data (stream->input_plugin, NULL, INPUT_OPTIONAL_DATA_DEMUX_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
+ stream->input_plugin->get_optional_data (stream->input_plugin, &mime_type, INPUT_OPTIONAL_DATA_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
+ mime_type && strcasecmp (mime_type, "text/plain") &&
+ probe_mime_type (stream->xine, node, mime_type) &&
+ (plugin = ((demux_class_t *)node->plugin_class)->open_plugin (node->plugin_class, stream, input)))
+ {
+ inc_node_ref(node);
+ plugin->node = node;
+ break;
+ }
+
+ /* ... then try the extension */
+ stream->content_detection_method = methods[i];
if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
inc_node_ref(node);
plugin->node = node;
@@ -1356,6 +1393,7 @@ demux_plugin_t *_x_find_demux_plugin_last_probe(xine_stream_t *stream, const cha
i = 0;
while (methods[i] != -1 && !plugin) {
int list_id, list_size;
+ const char *mime_type;
stream->content_detection_method = methods[i];
@@ -2519,47 +2557,24 @@ char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type) {
plugin_catalog_t *catalog = self->plugin_catalog;
plugin_node_t *node;
char *id = NULL;
- char *mime_arg, *mime_demux;
- char *s;
- const char *mt;
int list_id, list_size;
- /* create a copy and convert to lower case */
- mime_arg = strdup(mime_type);
- for(s=mime_arg; *s; s++)
- *s = tolower(*s);
-
pthread_mutex_lock (&catalog->lock);
list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_DEMUX - 1]);
for (list_id = 0; (list_id < list_size) && !id; list_id++) {
- demux_class_t *cls;
node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
- if (node->plugin_class || _load_plugin_class(self, node, NULL)) {
-
- cls = (demux_class_t *)node->plugin_class;
-
- mt = cls->get_mimetypes (cls);
- if (mt) {
- mime_demux = strdup(mt);
-
- for(s=mime_demux; *s; s++)
- *s = tolower(*s);
-
- if( strstr(mime_demux, mime_arg) )
- id = strdup(node->info->id);
-
- free(mime_demux);
- }
+ if (probe_mime_type (self, node, mime_type))
+ {
+ free (id);
+ id = strdup(node->info->id);
}
}
pthread_mutex_unlock (&catalog->lock);
- free(mime_arg);
-
return id;
}
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 46d3b424f..e4e36527f 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -1185,6 +1185,27 @@ static int open_internal (xine_stream_t *stream, const char *mrl) {
/* enable buffered input plugin (request optimizer) */
stream->input_plugin = _x_cache_plugin_get_instance(stream, 0);
+ /* Let the plugin request a specific demuxer (if the user hasn't).
+ * This overrides find-by-content & find-by-extension.
+ */
+ if (!stream->demux_plugin)
+ {
+ char *default_demux = NULL;
+ stream->input_plugin->get_optional_data (stream->input_plugin, &default_demux, INPUT_OPTIONAL_DATA_DEMUXER);
+ if (default_demux)
+ {
+ stream->demux_plugin = _x_find_demux_plugin_by_name (stream, default_demux, stream->input_plugin);
+ if (stream->demux_plugin)
+ {
+ lprintf ("demux and input plugin found\n");
+ _x_meta_info_set_utf8 (stream, XINE_META_INFO_SYSTEMLAYER,
+ stream->demux_plugin->demux_class->get_identifier (stream->demux_plugin->demux_class));
+ }
+ else
+ xine_log (stream->xine, XINE_LOG_MSG, _("xine: couldn't load plugin-specified demux %s for >%s<\n"), default_demux, mrl);
+ }
+ }
+
if (!stream->demux_plugin) {
/*
@@ -2229,7 +2250,10 @@ void xine_log (xine_t *this, int buf, const char *format, ...) {
vsnprintf(buffer, SCRATCH_LINE_LEN_MAX, format, argp);
printf("%s", buffer);
va_end (argp);
- }
+ }
+
+ if (this->log_cb)
+ this->log_cb (this->log_cb_user_data, buf);
}
void xine_vlog(xine_t *this, int buf, const char *format,
@@ -2238,6 +2262,9 @@ void xine_vlog(xine_t *this, int buf, const char *format,
check_log_alloc (this, buf);
this->log_buffers[buf]->scratch_printf(this->log_buffers[buf], format, args);
+
+ if (this->log_cb)
+ this->log_cb (this->log_cb_user_data, buf);
}
char *const *xine_get_log (xine_t *this, int buf) {
@@ -2252,12 +2279,10 @@ char *const *xine_get_log (xine_t *this, int buf) {
}
void xine_register_log_cb (xine_t *this, xine_log_cb_t cb, void *user_data) {
-
- printf ("xine: xine_register_log_cb: not implemented yet.\n");
- _x_abort();
+ this->log_cb = cb;
+ this->log_cb_user_data = user_data;
}
-
int xine_get_error (xine_stream_t *stream) {
return stream->err;
}
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index 85f3d6489..f97ca0b24 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -117,6 +117,9 @@ struct xine_s {
#ifdef XINE_ENGINE_INTERNAL
xine_ticket_t *port_ticket;
pthread_mutex_t log_lock;
+
+ xine_log_cb_t log_cb;
+ void *log_cb_user_data;
#endif
};
diff --git a/src/xine-utils/utils.c b/src/xine-utils/utils.c
index 9f5d122cb..f533d69e5 100644
--- a/src/xine-utils/utils.c
+++ b/src/xine-utils/utils.c
@@ -692,3 +692,11 @@ int xine_monotonic_clock(struct timeval *tv, struct timezone *tz)
#endif
}
+
+char *xine_strcat_realloc (char **dest, char *append)
+{
+ char *newstr = realloc (*dest, (*dest ? strlen (*dest) : 0) + strlen (append) + 1);
+ if (newstr)
+ strcat (*dest = newstr, append);
+ return newstr;
+}
diff --git a/src/xine-utils/xineutils.h b/src/xine-utils/xineutils.h
index 3d630b066..5476ef2ce 100644
--- a/src/xine-utils/xineutils.h
+++ b/src/xine-utils/xineutils.h
@@ -676,6 +676,13 @@ void xine_strdupa(char *dest, char *src) XINE_PROTECTED XINE_DEPRECATED;
#define xine_strsep(STRINGP, DELIM) strsep((STRINGP), (DELIM))
#define xine_setenv(NAME, VAL, XX) setenv((NAME), (VAL), (XX))
+/**
+ * append to a string, reallocating
+ * normally, updates & returns *dest
+ * on error, *dest is unchanged & NULL is returned.
+ */
+char *xine_strcat_realloc (char **dest, char *append) XINE_PROTECTED;
+
/*
* Color Conversion Utility Functions
* The following data structures and functions facilitate the conversion