summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_out/audio_directx2_out.c460
-rw-r--r--src/audio_out/audio_pulse_out.c6
-rw-r--r--src/demuxers/demux_flac.c3
-rw-r--r--src/demuxers/demux_ts.c9
-rw-r--r--src/demuxers/id3.c1
-rw-r--r--src/libfaad/xine_faad_decoder.c27
-rw-r--r--src/libspudvb/xine_spudvb_decoder.c46
-rw-r--r--src/video_out/video_out_directx.c10
-rw-r--r--src/video_out/video_out_raw.c2
-rw-r--r--src/video_out/video_out_sdl.c16
-rw-r--r--src/xine-utils/utils.c20
11 files changed, 304 insertions, 296 deletions
diff --git a/src/audio_out/audio_directx2_out.c b/src/audio_out/audio_directx2_out.c
index 5fffd1e2d..e91e919fc 100644
--- a/src/audio_out/audio_directx2_out.c
+++ b/src/audio_out/audio_directx2_out.c
@@ -31,6 +31,9 @@
*
* Authors:
* - Frantisek Dvorak <valtri@atlas.cz>
+ * - Original version with slotted ring buffer
+ * - Matthias Ringald <mringwal@inf.ethz.ch>
+ * - non-slotted simpler version for ring buffer handling
*
* Inspiration:
* - mplayer for workarounding -lguid idea
@@ -55,8 +58,8 @@
#define LOG_MODULE "audio_directx2_out"
#define LOG_VERBOSE
/*
-#define LOG
-*/
+ #define LOG
+ */
#include "xine_internal.h"
#include "audio_out.h"
@@ -64,29 +67,33 @@
#define AO_OUT_DIRECTX2_IFACE_VERSION 8
+
+/*
+ * If GAP_TOLERANCE is lower than AO_MAX_GAP, xine will
+ * try to smooth playback without skipping frames or
+ * inserting silence.
+ */
+#define GAP_TOLERANCE (AO_MAX_GAP/3)
+
/*
* buffer size in miliseconds
* (one second takes 11-192 KB)
*/
#define BUFFER_MS 1000
-/*
- * number of parts in the buffer,
- * one is always locked for playing
+/*
+ * buffer below this threshold is considered a buffer underrun
*/
-#define PARTS 3
+#define BUFFER_MIN_MS 200
/*
* base power factor for volume remapping
*/
#define FACTOR 60.0
-
-/* experiments */
-/*#define EXACT_WAIT*/
-/*#define EXACT_SLEEP*/
-/*#define PANIC_OVERRUN*/
-
+/*
+ * buffer handler status
+ */
#define STATUS_START 0
#define STATUS_WAIT 1
#define STATUS_RUNNING 2
@@ -108,12 +115,14 @@ typedef struct {
LPDIRECTSOUND ds; /* DirectSound device */
LPDIRECTSOUNDBUFFER dsbuffer; /* DirectSound buffer */
- DSBPOSITIONNOTIFY events[PARTS]; /* position events */
- LPDIRECTSOUNDNOTIFY notify; /* notify interface */
size_t buffer_size; /* size of the buffer */
- size_t part_size; /* second half of buffer */
- size_t read_size; /* size of prepared data */
+ size_t write_pos; /* positition in ring buffer for writing*/
+
+ int status; /* current status of the driver */
+ int paused; /* paused mode */
+ int finished; /* driver finished */
+ int failed; /* don't open modal dialog again */
uint32_t bits;
uint32_t rate;
@@ -123,12 +132,6 @@ typedef struct {
int volume;
int muted;
- int status; /* current status of the driver */
- int paused; /* paused mode */
- int finished; /* driver finished */
- int failed; /* don't open modal dialog again */
- int count; /* current free part number */
-
pthread_t buffer_service; /* service thread for operating with DSB */
pthread_cond_t data_cond; /* signals on data */
pthread_mutex_t data_mutex; /* data lock */
@@ -141,16 +144,14 @@ typedef struct {
* the linking stage.
*****************************************************************************/
static const GUID IID_IDirectSoundNotify = {
- 0xB0210783, 0x89CD, 0x11D0, {0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16}
+0xB0210783, 0x89CD, 0x11D0, {0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16}
};
-static int buffer_ready(dx2_driver_t *this);
-
/* popup a dialog with error */
static void XINE_FORMAT_PRINTF(1, 2)
- error_message(const char *fmt, ...) {
+error_message(const char *fmt, ...) {
char message[256];
va_list ap;
@@ -214,7 +215,7 @@ static LPDIRECTSOUND dsound_create() {
/* destroy direct sound object */
static void dsound_destroy(LPDIRECTSOUND ds) {
- IDirectSound_Release(ds);
+ IDirectSound_Release(ds);
}
@@ -266,12 +267,10 @@ static int audio_create_buffers(dx2_driver_t *this) {
HRESULT err;
size_t buffer_size;
- buffer_size = this->rate * this->frame_size * BUFFER_MS / 1000;
+ buffer_size = this->rate * BUFFER_MS / 1000 * this->frame_size;
if (buffer_size > DSBSIZE_MAX) buffer_size = DSBSIZE_MAX;
if (buffer_size < DSBSIZE_MIN) buffer_size = DSBSIZE_MIN;
- this->part_size = (buffer_size / PARTS / this->frame_size) * this->frame_size;
- if (!this->part_size) this->part_size = this->frame_size;
- this->buffer_size = this->part_size * PARTS;
+ this->buffer_size = buffer_size;
flags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
dsound_fill_wfx(&wfx, this->bits, this->rate, this->channels, this->frame_size);
@@ -282,7 +281,7 @@ static int audio_create_buffers(dx2_driver_t *this) {
return 0;
}
- lprintf("created direct sound buffer, size = %u, part = %u\n", this->buffer_size, this->part_size);
+ lprintf("created direct sound buffer, size = %u\n", this->buffer_size);
return 1;
}
@@ -293,43 +292,6 @@ static void audio_destroy_buffers(dx2_driver_t *this) {
}
-/* create position events */
-static int audio_create_events(dx2_driver_t *this) {
- HANDLE handle[PARTS];
- HRESULT err;
- int i;
-
- for (i = 0; i < PARTS; i++) {
- handle[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!handle[i]) {
- error_message(_("Unable to create buffer position events."));
- return 0;
- }
- this->events[i].dwOffset = i * this->part_size;
- this->events[i].hEventNotify = handle[i];
- }
-
- if ((err = IDirectSoundBuffer_QueryInterface(this->dsbuffer, &IID_IDirectSoundNotify, (void **)&this->notify)) != DS_OK) {
- audio_error(this, err, _("Unable to get notification interface"));
- return 0;
- }
-
- if ((err = IDirectSoundNotify_SetNotificationPositions(this->notify, PARTS, this->events)) != DS_OK) {
- audio_error(this, err, _("Unable to set notification positions"));
- IDirectSoundNotify_Release(this->notify);
- return 0;
- }
-
- return 1;
-}
-
-
-/* destroy notification interface */
-static void audio_destroy_events(dx2_driver_t *this) {
- IDirectSoundNotify_Release(this->notify);
-}
-
-
/* start playback */
static int audio_play(dx2_driver_t *this) {
HRESULT err;
@@ -385,8 +347,7 @@ static int audio_seek(dx2_driver_t *this, size_t pos) {
/* flush audio buffers */
static int audio_flush(dx2_driver_t *this) {
this->status = STATUS_WAIT;
- this->count = 0;
- this->read_size = 0;
+ this->write_pos = 0;
return audio_seek(this, 0);
}
@@ -421,12 +382,12 @@ static int audio_fill(dx2_driver_t *this, char *data, size_t size) {
HRESULT err;
/* lock a part of the buffer, begin position on free space */
- err = IDirectSoundBuffer_Lock(this->dsbuffer, (this->count * this->part_size + this->read_size) % this->buffer_size, size, &ptr1, &size1, &ptr2, &size2, 0);
+ err = IDirectSoundBuffer_Lock(this->dsbuffer, this->write_pos, size, &ptr1, &size1, &ptr2, &size2, 0);
/* try to restore the buffer, if necessary */
if (err == DSERR_BUFFERLOST) {
xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": buffer lost, tryig to restore\n"));
IDirectSoundBuffer_Restore(this->dsbuffer);
- err = IDirectSoundBuffer_Lock(this->dsbuffer, (this->count * this->part_size + this->read_size) % this->buffer_size, size, &ptr1, &size1, &ptr2, &size2, 0); }
+ err = IDirectSoundBuffer_Lock(this->dsbuffer, this->write_pos, size, &ptr1, &size1, &ptr2, &size2, 0); }
if (err != DS_OK) {
audio_error(this, err, _("Couldn't lock direct sound buffer"));
return 0;
@@ -436,19 +397,15 @@ static int audio_fill(dx2_driver_t *this, char *data, size_t size) {
if (ptr1 && size1) xine_fast_memcpy(ptr1, data, size1);
if (ptr2 && size2) xine_fast_memcpy(ptr2, data + size1, size2);
- this->read_size += size;
+ // this->read_size += size;
+ this->write_pos = (this->write_pos + size ) % this->buffer_size;
+ lprintf("size %u, write_pos %u\n", size, this->write_pos);
if ((err = IDirectSoundBuffer_Unlock(this->dsbuffer, ptr1, size1, ptr2, size2)) != DS_OK) {
audio_error(this, err, _("Couldn't unlock direct sound buffer"));
return 0;
}
- /* signal, if are waiting and need wake up */
- if ((this->status == STATUS_WAIT) && buffer_ready(this)) {
- lprintf("buffer ready, waking up\n");
- pthread_cond_signal(&this->data_cond);
- }
-
return 1;
}
@@ -458,28 +415,28 @@ static int mode2channels(uint32_t mode) {
int channels;
switch(mode) {
- case AO_CAP_MODE_MONO:
- channels = 1;
- break;
-
- case AO_CAP_MODE_STEREO:
- channels = 2;
- break;
-
- case AO_CAP_MODE_4CHANNEL:
- channels = 4;
- break;
-
- case AO_CAP_MODE_5CHANNEL:
- channels = 5;
- break;
-
- case AO_CAP_MODE_5_1CHANNEL:
- channels = 6;
- break;
-
- default:
- return 0;
+ case AO_CAP_MODE_MONO:
+ channels = 1;
+ break;
+
+ case AO_CAP_MODE_STEREO:
+ channels = 2;
+ break;
+
+ case AO_CAP_MODE_4CHANNEL:
+ channels = 4;
+ break;
+
+ case AO_CAP_MODE_5CHANNEL:
+ channels = 5;
+ break;
+
+ case AO_CAP_MODE_5_1CHANNEL:
+ channels = 6;
+ break;
+
+ default:
+ return 0;
}
return channels;
@@ -556,109 +513,96 @@ static int test_capabilities(dx2_driver_t *this) {
/* size of free space in the ring buffer */
static size_t buffer_free_size(dx2_driver_t *this) {
- size_t used_full_size;
+
+ int ret;
+ size_t play_pos;
+ size_t free_space;
- used_full_size = this->read_size + ((this->status != STATUS_WAIT) ? this->part_size : 0);
- _x_assert(used_full_size <= this->buffer_size);
- return this->buffer_size - used_full_size;
+ // get current play pos
+ ret = audio_tell(this, &play_pos);
+ if (!ret)
+ return 0;
+
+ // calc free space (-1)
+ free_space = (this->buffer_size + play_pos - this->write_pos - 1) % this->buffer_size;
+
+ return free_space;
}
-/* enough data in the ring buffer for playing next part? */
-static int buffer_ready(dx2_driver_t *this) {
- return this->read_size >= this->part_size;
+/* size of occupied space in the ring buffer */
+static size_t buffer_occupied_size(dx2_driver_t *this) {
+ int ret;
+ size_t play_pos;
+ size_t used_space;
+
+ // get current play pos
+ ret = audio_tell(this, &play_pos);
+ if (!ret) return 0;
+
+ // calc used space
+ used_space = (this->buffer_size + this->write_pos - play_pos) % this->buffer_size;
+
+ return used_space;
}
/* service thread working with direct sound buffer */
static void *buffer_service(void *data) {
dx2_driver_t *this = (dx2_driver_t *)data;
- HANDLE handles[PARTS];
DWORD ret;
- int i;
-#if defined(EXACT_SLEEP) || defined(EXACT_WAIT)
- size_t play_pos, req_delay;
-#endif
+ size_t play_pos;
+ size_t buffer_min;
+ size_t data_in_buffer;
/* prepare empty buffer */
audio_flush(this);
- for (i = 0; i < PARTS; i++) handles[i] = this->events[i].hEventNotify;
-
+ /* prepare min buffer fill */
+ buffer_min = BUFFER_MIN_MS * this->rate / 1000 * this->frame_size;
+
/* we live! */
pthread_mutex_lock(&this->data_mutex);
pthread_cond_signal(&this->data_cond);
pthread_mutex_unlock(&this->data_mutex);
while (!this->finished) {
+
pthread_mutex_lock(&this->data_mutex);
- if (!buffer_ready(this)) {
- if (!audio_stop(this)) goto fail;
- lprintf("no data (count=%d,free=%" PRIsizet ",avail=%" PRIsizet "), sleeping...\n", this->count, buffer_free_size(this), this->read_size);
- this->status = STATUS_WAIT;
- pthread_cond_wait(&this->data_cond, &this->data_mutex);
- lprintf("wake up (count=%d,free=%" PRIsizet "--,avail=%" PRIsizet ")\n", this->count, buffer_free_size(this), this->read_size);
- if (this->finished) goto finished;
- if (!audio_seek(this, this->count * this->part_size)) goto fail;
- if (!this->paused) {
- if (!audio_play(this)) goto fail;
- }
- this->status = STATUS_RUNNING;
- this->count = (this->count + 1) % PARTS;
- this->read_size -= this->part_size;
- pthread_mutex_unlock(&this->data_mutex);
- lprintf("wait for playback (newcount=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", this->count, buffer_free_size(this), this->read_size);
- do {
- ret = WaitForMultipleObjects(PARTS, handles, FALSE, 250) - WAIT_OBJECT_0;
+ switch( this->status){
+
+ case STATUS_WAIT:
+
+ // pre: stop/buffer flushed
+ lprintf("no data, sleeping...\n");
+ pthread_cond_wait(&this->data_cond, &this->data_mutex);
+ lprintf("woke up (write_pos=%d,free=%" PRIsizet")\n", this->write_pos, buffer_free_size(this));
if (this->finished) goto finished;
- } while (ret > PARTS);
- lprintf("playback started (newcount=%d,ev=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", this->count, ret, buffer_free_size(this), this->read_size);
- _x_assert(ret == ((PARTS + this->count - 1) % PARTS));
- } else {
- this->count = (this->count + 1) % PARTS;
- this->read_size -= this->part_size;
- pthread_mutex_unlock(&this->data_mutex);
- }
- lprintf("waiting for sound event(count=%d,free=%" PRIsizet ",avail=%" PRIsizet ")...\n", this->count, buffer_free_size(this), this->read_size);
- do {
- ret = WaitForMultipleObjects(PARTS, handles, FALSE, 250) - WAIT_OBJECT_0;
- if (this->finished) goto finished;
- } while (ret > PARTS);
- lprintf("end wait(ev=%" PRIdword ",count=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", ret, this->count, buffer_free_size(this), this->read_size);
-#ifdef PANIC_OVERRUN
- _x_abort(ret == this->count);
-#else
- if (ret != this->count) {
- xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": play cursor overran, flushing buffers\n"));
- pthread_mutex_lock(&this->data_mutex);
- if (!audio_stop(this)) goto fail;
- if (!audio_flush(this)) goto fail;
- pthread_mutex_unlock(&this->data_mutex);
- }
-#endif
-
-#if defined(EXACT_SLEEP) || defined(EXACT_WAIT)
- /* ugly hack: wait for right time, + little over for sure */
- pthread_mutex_lock(&this->data_mutex);
- if (!audio_tell(this, &play_pos)) goto fail;
- req_delay = (this->buffer_size + play_pos - this->count * this->part_size) % this->buffer_size;
- pthread_mutex_unlock(&this->data_mutex);
- if (req_delay > (this->buffer_size >> 1)) {
- long delay;
-
- delay = 1000 * (this->buffer_size - req_delay) / (this->frame_size * this->rate) + 1 + BUFFER_MS / PARTS / 4;
- xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": delayed by %ld msec\n"), delay);
- printf("should be delayed %ld msec\n", delay);
-#ifdef EXACT_SLEEP
- xine_usec_sleep(delay * 1000);
-#endif
-#ifdef EXACT_WAIT
- WaitForMultipleObjects(PARTS, handles, FALSE, delay);
-#endif
+ if (!audio_seek(this, 0)) goto fail;
+ if (!this->paused) {
+ if (!audio_play(this)) goto fail;
+ }
+ this->status = STATUS_RUNNING;
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
+
+ case STATUS_RUNNING:
+
+ // check for buffer underrun
+ data_in_buffer = buffer_occupied_size(this);
+ if ( data_in_buffer < buffer_min){
+ xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": play cursor overran (data %u, min %u), flushing buffers\n"),
+ data_in_buffer, buffer_min);
+ if (!audio_stop(this)) goto fail;
+ if (!audio_flush(this)) goto fail;
+ }
+ pthread_mutex_unlock(&this->data_mutex);
+
+ // just wait BUFFER_MIN_MS before next check
+ xine_usec_sleep(BUFFER_MIN_MS * 1000);
+ break;
}
-#endif
}
-
return NULL;
fail:
@@ -683,15 +627,15 @@ static int ao_dx2_get_property(ao_driver_t *this_gen, int property) {
switch(property) {
- case AO_PROP_MIXER_VOL:
- case AO_PROP_PCM_VOL:
- return this->volume;
+ case AO_PROP_MIXER_VOL:
+ case AO_PROP_PCM_VOL:
+ return this->volume;
- case AO_PROP_MUTE_VOL:
- return this->muted;
+ case AO_PROP_MUTE_VOL:
+ return this->muted;
- default:
- return 0;
+ default:
+ return 0;
}
}
@@ -702,26 +646,26 @@ static int ao_dx2_set_property(ao_driver_t *this_gen, int property, int value) {
switch(property) {
- case AO_PROP_MIXER_VOL:
- case AO_PROP_PCM_VOL:
- lprintf("set volume to %d\n", value);
- pthread_mutex_lock(&this->data_mutex);
- if (!this->muted) {
- if (this->dsbuffer && !audio_set_volume(this, value)) return ~value;
- }
- this->volume = value;
- pthread_mutex_unlock(&this->data_mutex);
- break;
+ case AO_PROP_MIXER_VOL:
+ case AO_PROP_PCM_VOL:
+ lprintf("set volume to %d\n", value);
+ pthread_mutex_lock(&this->data_mutex);
+ if (!this->muted) {
+ if (this->dsbuffer && !audio_set_volume(this, value)) return ~value;
+ }
+ this->volume = value;
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
- case AO_PROP_MUTE_VOL:
- pthread_mutex_lock(&this->data_mutex);
- if (this->dsbuffer && !audio_set_volume(this, value ? 0 : this->volume)) return ~value;
- this->muted = value;
- pthread_mutex_unlock(&this->data_mutex);
- break;
+ case AO_PROP_MUTE_VOL:
+ pthread_mutex_lock(&this->data_mutex);
+ if (this->dsbuffer && !audio_set_volume(this, value ? 0 : this->volume)) return ~value;
+ this->muted = value;
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
- default:
- return ~value;
+ default:
+ return ~value;
}
@@ -747,18 +691,17 @@ static int ao_dx2_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int
this->status = STATUS_START;
if (!audio_create_buffers(this)) return 0;
- if (!audio_create_events(this)) goto fail_buffers;
- if (!audio_set_volume(this, this->volume)) goto fail_events;
+ if (!audio_set_volume(this, this->volume)) goto fail_buffers;
if (pthread_cond_init(&this->data_cond, NULL) != 0) {
xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't create pthread condition: %s\n"), strerror(errno));
- goto fail_events;
+ goto fail_buffers;
}
if (pthread_mutex_init(&this->data_mutex, NULL) != 0) {
xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't create pthread mutex: %s\n"), strerror(errno));
goto fail_cond;
}
-
+
/* creating the service thread and waiting for its signal */
pthread_mutex_lock(&this->data_mutex);
if (pthread_create(&this->buffer_service, NULL, buffer_service, this) != 0) {
@@ -775,8 +718,6 @@ fail_mutex:
pthread_mutex_destroy(&this->data_mutex);
fail_cond:
pthread_cond_destroy(&this->data_cond);
-fail_events:
- audio_destroy_events(this);
fail_buffers:
audio_destroy_buffers(this);
return 0;
@@ -803,22 +744,26 @@ static int ao_dx2_bytes_per_frame(ao_driver_t *this_gen) {
static int ao_dx2_delay(ao_driver_t *this_gen) {
dx2_driver_t *this = (dx2_driver_t *)this_gen;
- int frames;
- size_t final_pos, play_pos;
-
- if (this->status != STATUS_RUNNING) return this->read_size / this->frame_size;
+ int frames = 0;
+ int ret;
+ size_t play_pos;
pthread_mutex_lock(&this->data_mutex);
- if (!audio_tell(this, &play_pos)) {
- pthread_mutex_unlock(&this->data_mutex);
- return 0;
- }
- final_pos = this->read_size + (((PARTS + this->count - 1) % PARTS) + 1) * this->part_size - 1;
- frames = (this->buffer_size + final_pos - play_pos) % this->buffer_size / this->frame_size;
+
+ if (this->status != STATUS_RUNNING){
+ frames = this->write_pos / this->frame_size;
+ } else {
+ ret = audio_tell(this, &play_pos);
+ if (ret){
+ frames = buffer_occupied_size(this) / this->frame_size;
+ }
+ }
+
pthread_mutex_unlock(&this->data_mutex);
#ifdef LOG
- if ((rand() % 10) == 0) lprintf("frames=%d, play_pos=%" PRIdword ", block=%" PRIsizet "..%" PRIsizet "\n", frames, play_pos, final_pos - this->part_size + 1, final_pos);
+ if ((rand() % 10) == 0)
+ lprintf("frames=%d, play_pos=%" PRIdword ", write_pos=%u\n", frames, play_pos, this->write_pos);
#endif
return frames;
@@ -840,7 +785,7 @@ static int ao_dx2_write(ao_driver_t *this_gen, int16_t* audio_data, uint32_t num
while (((free_size = buffer_free_size(this)) == 0) && !this->finished) {
lprintf("buffer full, waiting\n");
pthread_mutex_unlock(&this->data_mutex);
- xine_usec_sleep(1000 * BUFFER_MS / PARTS / 5);
+ xine_usec_sleep(1000 * BUFFER_MS / 10);
pthread_mutex_lock(&this->data_mutex);
}
if (free_size >= input_size) size = input_size;
@@ -856,6 +801,12 @@ static int ao_dx2_write(ao_driver_t *this_gen, int16_t* audio_data, uint32_t num
input_size -= size;
}
+ /* signal, if are waiting and need wake up */
+ if ((this->status == STATUS_WAIT) && (buffer_occupied_size(this) > BUFFER_MIN_MS * this->rate / 1000 * this->frame_size)) {
+ lprintf("buffer ready, waking up\n");
+ pthread_cond_signal(&this->data_cond);
+ }
+
return 1;
}
@@ -881,7 +832,6 @@ static void ao_dx2_close(ao_driver_t *this_gen) {
if (pthread_mutex_destroy(&this->data_mutex) != 0) {
xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't destroy pthread mutex: %s\n"), strerror(errno));
}
- audio_destroy_events(this);
audio_destroy_buffers(this);
}
@@ -896,12 +846,8 @@ static void ao_dx2_exit(ao_driver_t *this_gen) {
}
-/*
- * TODO: check
- */
static int ao_dx2_get_gap_tolerance(ao_driver_t *this_gen) {
- /* half of part of the buffer in pts (1 msec = 90 pts) */
- return (90 * (BUFFER_MS / PARTS)) >> 1;
+ return GAP_TOLERANCE;
}
@@ -910,36 +856,36 @@ static int ao_dx2_control(ao_driver_t *this_gen, int cmd, ...) {
switch(cmd) {
- case AO_CTRL_PLAY_PAUSE:
- lprintf("control pause\n");
- pthread_mutex_lock(&this->data_mutex);
- if (!this->paused) {
- audio_stop(this);
- this->paused = 1;
- }
- pthread_mutex_unlock(&this->data_mutex);
- break;
+ case AO_CTRL_PLAY_PAUSE:
+ lprintf("control pause\n");
+ pthread_mutex_lock(&this->data_mutex);
+ if (!this->paused) {
+ audio_stop(this);
+ this->paused = 1;
+ }
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
- case AO_CTRL_PLAY_RESUME:
- lprintf("control resume\n");
- pthread_mutex_lock(&this->data_mutex);
- if (this->paused) {
- if (this->status != STATUS_WAIT) audio_play(this);
- this->paused = 0;
- }
- pthread_mutex_unlock(&this->data_mutex);
- break;
-
- case AO_CTRL_FLUSH_BUFFERS:
- lprintf("control flush\n");
- pthread_mutex_lock(&this->data_mutex);
- audio_stop(this);
- audio_flush(this);
- pthread_mutex_unlock(&this->data_mutex);
- break;
+ case AO_CTRL_PLAY_RESUME:
+ lprintf("control resume\n");
+ pthread_mutex_lock(&this->data_mutex);
+ if (this->paused) {
+ if (this->status != STATUS_WAIT) audio_play(this);
+ this->paused = 0;
+ }
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
+
+ case AO_CTRL_FLUSH_BUFFERS:
+ lprintf("control flush\n");
+ pthread_mutex_lock(&this->data_mutex);
+ audio_stop(this);
+ audio_flush(this);
+ pthread_mutex_unlock(&this->data_mutex);
+ break;
- default:
- xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": unknown control command %d\n"), cmd);
+ default:
+ xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": unknown control command %d\n"), cmd);
}
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index dfae98c31..4b66fbaed 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -218,7 +218,8 @@ static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info
this->cvolume = info->volume;
this->swvolume = pa_cvolume_avg(&info->volume);
-#ifdef HAVE_PULSEAUDIO_0_9_7
+#if PA_PROTOCOL_VERSION >= 11
+ /* PulseAudio 0.9.7 and newer */
this->muted = info->mute;
#else
this->muted = pa_cvolume_is_muted (&this->cvolume);
@@ -665,7 +666,8 @@ static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value
this->muted = value;
-#ifdef HAVE_PULSEAUDIO_0_9_7
+#if PA_PROTOCOL_VERSION >= 11
+ /* PulseAudio 0.9.7 and newer */
o = pa_context_set_sink_input_mute(this->context, pa_stream_get_index(this->stream),
value, __xine_pa_context_success_callback, this);
#else
diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c
index e6d6f6376..0cc2fc6b6 100644
--- a/src/demuxers/demux_flac.c
+++ b/src/demuxers/demux_flac.c
@@ -232,6 +232,9 @@ static int open_flac_file(demux_flac_t *flac) {
} else if ((strncasecmp ("ARTIST=", comment, 7) == 0)
&& (length - 7 > 0)) {
_x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_ARTIST, comment + 7);
+ } else if ((strncasecmp ("COMPOSER=", comment, 9) == 0)
+ && (length - 9 > 0)) {
+ _x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_COMPOSER, comment + 9);
} else if ((strncasecmp ("ALBUM=", comment, 6) == 0)
&& (length - 6 > 0)) {
_x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_ALBUM, comment + 6);
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c
index 6c2adc67f..55e06c033 100644
--- a/src/demuxers/demux_ts.c
+++ b/src/demuxers/demux_ts.c
@@ -249,6 +249,7 @@ typedef struct {
int64_t packet_count;
int corrupted_pes;
uint32_t buffered_bytes;
+ int autodetected;
} demux_ts_media;
@@ -932,9 +933,11 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts,
m->buf->free_buffer(m->buf);
m->buf = NULL;
- if (m->corrupted_pes > CORRUPT_PES_THRESHOLD) {
- if (this->videoPid == m->pid)
+ if (m->corrupted_pes > CORRUPT_PES_THRESHOLD && m->autodetected) {
+ if (this->videoPid == m->pid) {
this->videoPid = INVALID_PID;
+ this->last_pmt_crc = 0;
+ }
} else {
m->corrupted_pes++;
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
@@ -1855,6 +1858,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) {
} else if (!found) {
this->videoPid = pid;
this->videoMedia = this->media_num;
+ this->media[this->videoMedia].autodetected = 1;
demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, 0x100 + pes_stream_id);
}
@@ -2269,6 +2273,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen,
for (i = 0; i < MAX_PIDS; i++) {
this->media[i].pid = INVALID_PID;
this->media[i].buf = NULL;
+ this->media[i].autodetected = 0;
}
for (i = 0; i < MAX_PMTS; i++) {
diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c
index 3c03fdc68..ba8f50676 100644
--- a/src/demuxers/id3.c
+++ b/src/demuxers/id3.c
@@ -767,6 +767,7 @@ static int id3v24_interp_frame(input_plugin_t *input,
break;
case ( FOURCC_TAG('T', 'Y', 'E', 'R') ):
+ case ( FOURCC_TAG('T', 'D', 'R', 'C') ):
_x_meta_info_set_generic(stream, XINE_META_INFO_YEAR, buf + 1, id3_encoding[enc]);
break;
diff --git a/src/libfaad/xine_faad_decoder.c b/src/libfaad/xine_faad_decoder.c
index ae71af155..9c657610e 100644
--- a/src/libfaad/xine_faad_decoder.c
+++ b/src/libfaad/xine_faad_decoder.c
@@ -275,7 +275,32 @@ static void faad_decode_audio ( faad_decoder_t *this, int end_frame ) {
lprintf("decoded %d/%d output %ld\n",
used, this->size, this->faac_finfo.samples );
-
+
+ /* Performing necessary channel reordering because aac uses a different
+ * layout than alsa:
+ *
+ * aac 5.1 channel layout: c l r ls rs lfe
+ * alsa 5.1 channel layout: l r ls rs c lfe
+ *
+ * Reordering is only necessary for 5.0 and above. Currently only 5.0
+ * and 5.1 is being taken care of, the rest will stay in the wrong order
+ * for now.
+ *
+ * WARNING: the following needs a output format of 16 bits per sample.
+ * TODO: - reorder while copying (in the while() loop) and optimizing
+ */
+ if(this->num_channels == 5 || this->num_channels == 6)
+ {
+ int i = 0;
+ uint16_t* buf = (uint16_t*)(sample_buffer);
+
+ for(; i < this->faac_finfo.samples; i += this->num_channels) {
+ uint16_t center = buf[i];
+ *((uint64_t*)(buf + i)) = *((uint64_t*)(buf + i + 1));
+ buf[i + 4] = center;
+ }
+ }
+
while( decoded ) {
audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out);
diff --git a/src/libspudvb/xine_spudvb_decoder.c b/src/libspudvb/xine_spudvb_decoder.c
index 957374799..8a4fe6926 100644
--- a/src/libspudvb/xine_spudvb_decoder.c
+++ b/src/libspudvb/xine_spudvb_decoder.c
@@ -48,6 +48,7 @@ typedef struct {
} page_t;
typedef struct {
+ int version_number;
int width, height;
int empty;
int depth;
@@ -166,20 +167,18 @@ static void update_region (dvb_spu_decoder_t * this, int region_id, int region_w
lprintf( "can't allocate mem for region %d\n", region_id );
return;
}
- fill_color = 15;
fill = 1;
}
-
+
if ( fill ) {
memset( reg->img, fill_color, region_width*region_height );
reg->empty = 1;
#ifdef LOG
- printf("SPUDVB : FILL REGION %d\n", region_id);
+ printf("SPUDVB : FILL REGION %d\n", region_id);
#endif
}
reg->width = region_width;
reg->height = region_height;
- page->regions[region_id].is_visible = 1;
}
@@ -409,17 +408,18 @@ static void process_page_composition_segment (dvb_spu_decoder_t * this)
const int j = dvbsub->i + segment_length;
dvbsub->page.page_time_out = dvbsub->buf[dvbsub->i++];
+ if ( dvbsub->page.page_time_out>6 ) /* some timeout are insane, e.g. 65s ! */
+ dvbsub->page.page_time_out = 6;
- dvbsub->page.page_version_number = (dvbsub->buf[dvbsub->i] & 0xf0) >> 4;
+ int version = (dvbsub->buf[dvbsub->i] & 0xf0) >> 4;
+ if ( version == dvbsub->page.page_version_number )
+ return;
+ dvbsub->page.page_version_number = version;
dvbsub->page.page_state = (dvbsub->buf[dvbsub->i] & 0x0c) >> 2;
dvbsub->i++;
- if (dvbsub->page.page_state==2) {
- int r;
- for (r=0; r<MAX_REGIONS; r++)
- dvbsub->page.regions[r].is_visible = 0;
- }
- else if ( dvbsub->page.page_state!=0 && dvbsub->page.page_state!=1 ) {
- return;
+ int r;
+ for (r=0; r<MAX_REGIONS; r++) { /* reset */
+ dvbsub->page.regions[r].is_visible = 0;
}
while (dvbsub->i < j) {
@@ -432,6 +432,7 @@ static void process_page_composition_segment (dvb_spu_decoder_t * this)
dvbsub->page.regions[region_id].x = region_x;
dvbsub->page.regions[region_id].y = region_y;
+ dvbsub->page.regions[region_id].is_visible = 1;
}
}
@@ -465,6 +466,11 @@ static void process_region_composition_segment (dvb_spu_decoder_t * this)
if(region_id>=MAX_REGIONS)
return;
+
+ if ( dvbsub->regions[region_id].version_number == region_version_number )
+ return;
+
+ dvbsub->regions[region_id].version_number = region_version_number;
/* Check if region size has changed and fill background. */
update_region (this, region_id, region_width, region_height, region_fill_flag, region_4_bit_pixel_code);
@@ -673,6 +679,9 @@ static void draw_subtitles (dvb_spu_decoder_t * this)
printf("SPUDVB: this->vpts=%llu\n",this->vpts);
#endif
for ( r=0; r<MAX_REGIONS; r++ ) {
+#ifdef LOG
+ printf("SPUDVB : region=%d, visible=%d, osd=%d, empty=%d\n", r, this->dvbsub->page.regions[r].is_visible, this->dvbsub->regions[r].osd?1:0, this->dvbsub->regions[r].empty );
+#endif
if ( this->dvbsub->page.regions[r].is_visible && this->dvbsub->regions[r].osd && !this->dvbsub->regions[r].empty ) {
this->stream->osd_renderer->set_position( this->dvbsub->regions[r].osd, this->dvbsub->page.regions[r].x, this->dvbsub->page.regions[r].y );
this->stream->osd_renderer->show( this->dvbsub->regions[r].osd, this->vpts );
@@ -761,6 +770,9 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
this->vpts = vpts;
}
+ /* completely ignore pts since it makes a lot of problems with various providers */
+ this->vpts = 0;
+
/* process the pes section */
const int PES_packet_length = this->pes_pkt_size;
@@ -791,10 +803,10 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
/* SEGMENT_DATA_FIELD */
switch (segment_type) {
case 0x10:
- process_page_composition_segment (this);
+ process_page_composition_segment(this);
break;
case 0x11:
- process_region_composition_segment (this);
+ process_region_composition_segment(this);
break;
case 0x12:
process_CLUT_definition_segment(this);
@@ -802,8 +814,8 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
case 0x13:
process_object_data_segment (this);
break;
- case 0x80: /* Page is now completely rendered */
- draw_subtitles( this );
+ case 0x80:
+ draw_subtitles( this ); /* Page is now completely rendered */
break;
default:
return;
@@ -824,7 +836,9 @@ static void spudec_reset (spu_decoder_t * this_gen)
for ( i=0; i<MAX_REGIONS; i++ ) {
if ( this->dvbsub->regions[i].osd )
this->stream->osd_renderer->hide(this->dvbsub->regions[i].osd, 0);
+ this->dvbsub->regions[i].version_number = -1;
}
+ this->dvbsub->page.page_version_number = -1;
pthread_mutex_unlock(&this->dvbsub_osd_mutex);
}
diff --git a/src/video_out/video_out_directx.c b/src/video_out/video_out_directx.c
index f1136eab0..529968bec 100644
--- a/src/video_out/video_out_directx.c
+++ b/src/video_out/video_out_directx.c
@@ -117,7 +117,7 @@ typedef struct {
yuv2rgb_t *yuv2rgb; /* used for format conversion */
int mode; /* rgb mode */
int bytespp; /* rgb bits per pixel */
-
+ DDPIXELFORMAT primary_pixel_format;
alphablend_t alphablend_extra_data;
} win32_driver_t;
@@ -367,8 +367,9 @@ static boolean CreateSecondary( win32_driver_t * win32_driver, int width, int he
lprintf("CreateSecondary() - Falling back to back buffer same as primary\n");
lprintf("CreateSecondary() - act_format = (NATIVE) %d\n", IMGFMT_NATIVE);
- ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
+ ddsd.ddpfPixelFormat = win32_driver->primary_pixel_format;
win32_driver->act_format = IMGFMT_NATIVE;
if( IDirectDraw_CreateSurface( win32_driver->ddobj, &ddsd, &win32_driver->secondary, 0 ) == DD_OK )
@@ -429,6 +430,10 @@ static boolean CheckPixelFormat( win32_driver_t * win32_driver )
Error( 0, "IDirectDrawSurface_GetPixelFormat ( CheckPixelFormat ) : error 0x%lx", result );
return 0;
}
+
+ /* store pixel format for CreateSecondary */
+
+ win32_driver->primary_pixel_format = ddpf;
/* TODO : support paletized video modes */
@@ -478,6 +483,7 @@ static boolean CheckPixelFormat( win32_driver_t * win32_driver )
win32_driver->mode = MODE_15_BGR;
}
+ lprintf("win32 mode: %u\n", win32_driver->mode);
return TRUE;
}
diff --git a/src/video_out/video_out_raw.c b/src/video_out/video_out_raw.c
index 45cfc1eda..0d4bf445a 100644
--- a/src/video_out/video_out_raw.c
+++ b/src/video_out/video_out_raw.c
@@ -473,7 +473,7 @@ static int raw_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *da
static uint32_t raw_get_capabilities (vo_driver_t *this_gen)
{
- uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2;
+ uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP;
return capabilities;
}
diff --git a/src/video_out/video_out_sdl.c b/src/video_out/video_out_sdl.c
index b53d1d31c..89150f5d0 100644
--- a/src/video_out/video_out_sdl.c
+++ b/src/video_out/video_out_sdl.c
@@ -469,9 +469,11 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
sdl_driver_t *this;
const SDL_VideoInfo *vidInfo;
-#ifdef HAVE_X11
+#if defined(HAVE_X11) || defined(WIN32)
static char SDL_windowhack[32];
x11_visual_t *visual = (x11_visual_t *) visual_gen;
+#endif
+#ifdef HAVE_X11
XWindowAttributes window_attributes;
#endif
@@ -502,14 +504,18 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi
_x_vo_scale_init( &this->sc, 0, 0, config);
this->sc.frame_output_cb = visual->frame_output_cb;
this->sc.user_data = visual->user_data;
-
- /* set SDL to use our existing X11 window */
- sprintf(SDL_windowhack,"SDL_WINDOWID=0x%x", (uint32_t) this->drawable );
- putenv(SDL_windowhack);
#else
_x_vo_scale_init( &this->sc, 0, 0, config );
#endif
+#if defined(HAVE_X11) || defined(WIN32)
+ /* set SDL to use our existing X11/win32 window */
+ if (visual->d){
+ sprintf(SDL_windowhack,"SDL_WINDOWID=0x%x", (uint32_t) visual->d);
+ putenv(SDL_windowhack);
+ }
+#endif
+
if ((SDL_Init (SDL_INIT_VIDEO)) < 0) {
xprintf (this->xine, XINE_VERBOSITY_DEBUG, "video_out_sdl: open_plugin - sdl video initialization failed.\n");
return NULL;
diff --git a/src/xine-utils/utils.c b/src/xine-utils/utils.c
index 57a92623c..689b68502 100644
--- a/src/xine-utils/utils.c
+++ b/src/xine-utils/utils.c
@@ -456,23 +456,22 @@ char *xine_chomp(char *str) {
* a thread-safe usecond sleep
*/
void xine_usec_sleep(unsigned usec) {
-#if 0
-#if HAVE_NANOSLEEP
+#ifdef WIN32
+ /* select does not work on win32 */
+ Sleep(usec / 1000);
+#else
+# if 0
+# if HAVE_NANOSLEEP
/* nanosleep is prefered on solaris, because it's mt-safe */
struct timespec ts, remaining;
-
ts.tv_sec = usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
while (nanosleep (&ts, &remaining) == -1 && errno == EINTR)
ts = remaining;
-#else
-# if WIN32
- Sleep(usec / 1000);
-# else
+# else
usleep(usec);
-# endif
-#endif
-#else
+# endif
+# else
if (usec < 10000) {
usec = 10000;
}
@@ -480,6 +479,7 @@ void xine_usec_sleep(unsigned usec) {
tm.tv_sec = usec / 1000000;
tm.tv_usec = usec % 1000000;
select(0, 0, 0, 0, &tm);
+# endif
#endif
}