diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 44 | ||||
-rw-r--r-- | src/audio_out/audio_jack_out.c | 1141 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 33 | ||||
-rw-r--r-- | src/demuxers/demux_qt.c | 4 | ||||
-rw-r--r-- | src/demuxers/demux_ts.c | 17 | ||||
-rw-r--r-- | src/input/input_dvb.c | 71 | ||||
-rw-r--r-- | src/input/input_http.c | 24 | ||||
-rw-r--r-- | src/input/input_plugin.h | 7 | ||||
-rw-r--r-- | src/input/input_pnm.c | 2 | ||||
-rw-r--r-- | src/input/input_rtsp.c | 2 | ||||
-rw-r--r-- | src/input/input_v4l.c | 21 | ||||
-rw-r--r-- | src/input/net_buf_ctrl.c | 23 | ||||
-rw-r--r-- | src/input/net_buf_ctrl.h | 6 | ||||
-rw-r--r-- | src/input/vcd/xine-extra.c | 10 | ||||
-rw-r--r-- | src/video_out/Makefile.am | 2 | ||||
-rw-r--r-- | src/video_out/video_out_xcbxv.c | 162 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 152 | ||||
-rw-r--r-- | src/video_out/video_out_xvmc.c | 92 | ||||
-rw-r--r-- | src/video_out/video_out_xxmc.c | 158 | ||||
-rw-r--r-- | src/video_out/xv_common.h | 69 | ||||
-rw-r--r-- | src/xine-engine/load_plugins.c | 73 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 35 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 3 | ||||
-rw-r--r-- | src/xine-utils/utils.c | 8 | ||||
-rw-r--r-- | src/xine-utils/xineutils.h | 7 |
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 |