diff options
Diffstat (limited to 'src')
54 files changed, 1795 insertions, 689 deletions
diff --git a/src/audio_dec/xine_dts_decoder.c b/src/audio_dec/xine_dts_decoder.c index 2b8dabd10..4f9171d6e 100644 --- a/src/audio_dec/xine_dts_decoder.c +++ b/src/audio_dec/xine_dts_decoder.c @@ -199,19 +199,27 @@ static void dts_decode_frame (dts_decoder_t *this, const int64_t pts, const int audio_buffer->num_frames = this->ac5_pcm_length; - data_out[0] = 0x72; data_out[1] = 0xf8; /* spdif syncword */ - data_out[2] = 0x1f; data_out[3] = 0x4e; /* .............. */ - data_out[4] = ac5_spdif_type; /* DTS data */ - data_out[5] = 0; /* Unknown */ - data_out[6] = (this->ac5_length << 3) & 0xff; /* ac5_length * 8 */ - data_out[7] = ((this->ac5_length ) >> 5) & 0xff; - - if( this->ac5_pcm_length ) { - if( this->ac5_pcm_length % 2) { - swab(data_in, &data_out[8], this->ac5_length ); - } else { - swab(data_in, &data_out[8], this->ac5_length + 1); + // Checking if AC5 data plus IEC958 header will fit into frames samples data + if ( this->ac5_length + 8 <= this->ac5_pcm_length * 2 * 2 ) { + data_out[0] = 0x72; data_out[1] = 0xf8; /* spdif syncword */ + data_out[2] = 0x1f; data_out[3] = 0x4e; /* .............. */ + data_out[4] = ac5_spdif_type; /* DTS data */ + data_out[5] = 0; /* Unknown */ + data_out[6] = (this->ac5_length << 3) & 0xff; /* ac5_length * 8 */ + data_out[7] = ((this->ac5_length ) >> 5) & 0xff; + + if( this->ac5_pcm_length ) { + if( this->ac5_pcm_length % 2) { + swab(data_in, &data_out[8], this->ac5_length ); + } else { + swab(data_in, &data_out[8], this->ac5_length + 1); + } } + // Transmit it without header otherwise, receivers will autodetect DTS + } else { + lprintf("AC5 data is too large (%i > %i), sending without IEC958 header\n", + this->ac5_length + 8, this->ac5_pcm_length * 2 * 2); + memcpy(data_out, data_in, this->ac5_length); } } else { /* Software decode */ diff --git a/src/audio_dec/xine_lpcm_decoder.c b/src/audio_dec/xine_lpcm_decoder.c index e84b112f4..83043cec9 100644 --- a/src/audio_dec/xine_lpcm_decoder.c +++ b/src/audio_dec/xine_lpcm_decoder.c @@ -192,18 +192,34 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { uint8_t *d = (uint8_t *)audio_buffer->mem; int n = buf->size; - while (n >= 0) { + while (n >= 3) { if ( stream_be ) { - *d++ = s[0]; - *d++ = s[1]; + if ( stream_be == this->cpu_be ) { + *d++ = s[0]; + *d++ = s[1]; + } else { + *d++ = s[1]; + *d++ = s[0]; + } } else { - *d++ = s[1]; - *d++ = s[2]; + if ( stream_be == this->cpu_be ) { + *d++ = s[1]; + *d++ = s[2]; + } + else + { + *d++ = s[2]; + *d++ = s[1]; + } } s += 3; n -= 3; } + + if ( (d - (uint8_t*)audio_buffer->mem)/2*3 < buf->size ) + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "lpcm_decoder: lost %i bytes\n", (int)(buf->size - (d - (uint8_t*)audio_buffer->mem))/2*3); + } else { memcpy (audio_buffer->mem, sample_buffer, buf->size); } diff --git a/src/audio_dec/xine_mad_decoder.c b/src/audio_dec/xine_mad_decoder.c index 74c04924f..abad70f4f 100644 --- a/src/audio_dec/xine_mad_decoder.c +++ b/src/audio_dec/xine_mad_decoder.c @@ -393,7 +393,7 @@ static const uint32_t audio_types[] = { static const decoder_info_t dec_info_audio = { audio_types, /* supported types */ - 7 /* priority */ + 8 /* priority */ }; const plugin_info_t xine_plugin_info[] EXPORTED = { diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 7cae9b300..89d79fae9 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -405,6 +405,18 @@ static int ao_oss_delay(ao_driver_t *this_gen) { if (bytes_left<=0) /* buffer ran dry */ bytes_left = 0; break; + case OSS_SYNC_GETODELAY: +#ifdef SNDCTL_DSP_GETODELAY + if (ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left)) { + perror ("audio_oss_out: DSP_GETODELAY ioctl():"); + } + if (bytes_left<0) + bytes_left = 0; + + lprintf ("%d bytes left\n", bytes_left); + + break; +#endif case OSS_SYNC_GETOPTR: if (ioctl (this->audio_fd, SNDCTL_DSP_GETOPTR, &info)) { perror ("audio_oss_out: SNDCTL_DSP_GETOPTR failed:"); @@ -424,16 +436,6 @@ static int ao_oss_delay(ao_driver_t *this_gen) { } this->last_getoptr = info.bytes; break; - case OSS_SYNC_GETODELAY: - if (ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left)) { - perror ("audio_oss_out: DSP_GETODELAY ioctl():"); - } - if (bytes_left<0) - bytes_left = 0; - - lprintf ("%d bytes left\n", bytes_left); - - break; } return bytes_left / this->bytes_per_frame; @@ -840,10 +842,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da * check if SNDCTL_DSP_GETODELAY works. if so, using it is preferred. */ +#ifdef SNDCTL_DSP_GETODELAY if (ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &info) != -1) { xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: using SNDCTL_DSP_GETODELAY\n"); this->sync_method = OSS_SYNC_GETODELAY; - } else if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) != -1) { + } else +#endif + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) != -1) { xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: using SNDCTL_DSP_GETOPTR\n"); this->sync_method = OSS_SYNC_GETOPTR; } else { diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index 0235a4321..9b811aaaf 100644 --- a/src/audio_out/audio_pulse_out.c +++ b/src/audio_out/audio_pulse_out.c @@ -1,28 +1,28 @@ -/* - * Copyright (C) 2000-2007 the xine project - * +/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * Copyright (C) 2000-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 * - * ao plugin for pulseaudio (rename of polypaudio): + * ao plugin for PulseAudio: * http://0pointer.de/lennart/projects/pulsaudio/ * - * originally written for polypaudio simple api. Lennart then suggested - * using the async api for better control (such as volume), therefore, a lot - * of this code comes from Lennart's patch to mplayer. + * Diego Petteno, Lennart Poettering */ #ifdef HAVE_CONFIG_H @@ -48,15 +48,9 @@ #define GAP_TOLERANCE AO_MAX_GAP -/* CHECKME: should this be conditional on autotools? */ -extern const char *__progname; - typedef struct { audio_driver_class_t driver_class; xine_t *xine; - - struct pa_context *context; /*< Pulseaudio connection context */ - struct pa_threaded_mainloop *mainloop; /*< Main event loop object */ } pulse_class_t; typedef struct pulse_driver_s { @@ -67,11 +61,13 @@ typedef struct pulse_driver_s { char *host; /*< The host to connect to */ char *sink; /*< The sink to connect to */ - struct pa_stream *stream; /*< Pulseaudio playback stream object */ - pthread_mutex_t info_mutex; /**< Mutex for info callback signaling */ + pa_threaded_mainloop *mainloop; /*< Main event loop object */ + pa_context *context; /*< Pulseaudio connection context */ + pa_stream *stream; /*< Pulseaudio playback stream object */ pa_volume_t swvolume; + int muted; pa_cvolume cvolume; int capabilities; @@ -82,67 +78,117 @@ typedef struct pulse_driver_s { uint32_t bits_per_sample; uint32_t bytes_per_frame; - uint32_t frames_written; - } pulse_driver_t; /** - * @brief Callback function called when a stream operation succeed - * @param stream Stream which operation has succeeded - * @param success The success value for the operation (ignored) - * @param this_Gen pulse_driver_t pointer for the PulseAudio output - * instance. + * @brief Callback function called when the state of the context is changed + * @param c Context which changed status + * @param this_gen pulse_class_t pointer for the PulseAudio output class */ -static void __xine_pa_stream_success_callback(pa_stream *const stream, const int success, - void *const mutex_gen) +static void __xine_pa_context_state_callback(pa_context *c, void *this_gen) { - pthread_mutex_t *const completion_mutex = (pthread_mutex_t*)mutex_gen; + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + switch (pa_context_get_state(c)) { + + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(this->mainloop, 0); + break; - pthread_mutex_unlock(completion_mutex); + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } } /** - * @brief Callback function called when the state of the context is changed - * @param ctx Context which operation has succeeded + * @brief Callback function called when the state of the stream is changed + * @param s Stream that changed status * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. */ -static void __xine_pa_context_status_callback(pa_context *const ctx, void *const this_gen) +static void __xine_pa_stream_state_callback(pa_stream *s, void *this_gen) { - pulse_driver_t *const this = (pulse_driver_t*)this_gen; - - switch (pa_context_get_state(ctx)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); - break; - - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + switch (pa_stream_get_state(s)) { + + case PA_STREAM_READY: + case PA_STREAM_TERMINATED: + case PA_STREAM_FAILED: + pa_threaded_mainloop_signal(this->mainloop, 0); + break; + + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; } } /** - * @brief Callback function called when a context operation succeed + * @brief Callback function called when PA asks for more audio data. + * @param s Stream on which data is requested + * @param nbytes the number of bytes PA requested + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_stream_request_callback(pa_stream *s, size_t nbytes, void *this_gen) +{ + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA notifies about something + * @param s Stream on which the notification happened + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_stream_notify_callback(pa_stream *s, void *this_gen) +{ + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA completed an operation * @param ctx Context which operation has succeeded - * @param success The success value for the operation (ignored) + * @param nbytes the number of bytes PA requested * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. */ -static void __xine_pa_context_success_callback(pa_context *const ctx, const int success, - void *const this_gen) +static void __xine_pa_stream_success_callback(pa_stream *s, int success, void *this_gen) { - pulse_driver_t *const this = (pulse_driver_t*)this_gen; + pulse_driver_t * this = (pulse_driver_t*) this_gen; - _x_assert(ctx); _x_assert(this); - _x_assert(ctx == this->pa_class->context); + if (!success) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: stream operation failed: %s\n", pa_strerror(pa_context_errno(this->context))); - pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA completed an operation + * @param c Context on which operation has succeeded + * @param nbytes the number of bytes PA requested + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_context_success_callback(pa_context *c, int success, void *this_gen) +{ + pulse_driver_t *this = (pulse_driver_t*) this_gen; + + if (!success) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: context operation failed: %s\n", pa_strerror(pa_context_errno(this->context))); + + pa_threaded_mainloop_signal(this->mainloop, 0); } /** @@ -156,14 +202,14 @@ static void __xine_pa_context_success_callback(pa_context *const ctx, const int * This function saves the volume field of the passed structure to the * @c cvolume variable of the output instance. */ -static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_input_info *const info, - const int is_last, void *const userdata) { +static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info, + int is_last, void *userdata) { pulse_driver_t *const this = (pulse_driver_t *) userdata; if (is_last < 0) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); + pa_strerror(pa_context_errno(this->context))); return; } @@ -171,36 +217,90 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in return; this->cvolume = info->volume; + this->swvolume = pa_sw_volume_to_linear(pa_cvolume_avg(&info->volume)); + this->muted = info->mute; +} + +static int connect_context(pulse_driver_t *this) { + + if (this->context && (pa_context_get_state(this->context) == PA_CONTEXT_FAILED || + pa_context_get_state(this->context) == PA_CONTEXT_TERMINATED)) { + pa_context_unref(this->context); + this->context = NULL; + } + + if (!this->context) { + char fn[PATH_MAX], *p; + + if (pa_get_binary_name(fn, sizeof(fn))) + p = pa_path_get_filename(fn); + else + p = "Xine"; + + this->context = pa_context_new(pa_threaded_mainloop_get_api(this->mainloop), p); + _x_assert(this->context); + + pa_context_set_state_callback(this->context, __xine_pa_context_state_callback, this); + } + + if (pa_context_get_state(this->context) == PA_CONTEXT_UNCONNECTED) { + + if (pa_context_connect(this->context, this->host, 0, NULL) < 0) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object %s\n", pa_strerror(pa_context_errno(this->context))); + return -1; + } + } + + for (;;) { + pa_context_state_t state = pa_context_get_state(this->context); + + if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context))); + return -1; + } + + if (state == PA_CONTEXT_READY) + break; + + pa_threaded_mainloop_wait(this->mainloop); + } - pthread_mutex_unlock(&this->info_mutex); + return 0; } /* * open the audio device for writing to */ static int ao_pulse_open(ao_driver_t *this_gen, - uint32_t bits, uint32_t rate, int mode) + uint32_t bits, uint32_t rate, int mode) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - struct pa_sample_spec ss; - struct pa_buffer_attr a; - pa_stream_state_t streamstate; + pa_sample_spec ss; + pa_channel_map cm; + int r; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); + "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); if ( (mode & this->capabilities) == 0 ) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: unsupported mode %08x\n", mode); return 0; } + pa_threaded_mainloop_lock(this->mainloop); + if (this->stream) { - if ( mode == this->mode && rate == this->sample_rate && - bits == this->bits_per_sample ) + if (mode == this->mode && rate == this->sample_rate && + bits == this->bits_per_sample) { + + pa_threaded_mainloop_unlock(this->mainloop); return this->sample_rate; + } - this_gen->close(this_gen); + pa_stream_disconnect(this->stream); + pa_stream_unref(this->stream); + this->stream = NULL; } this->mode = mode; @@ -221,6 +321,8 @@ static int ao_pulse_open(ao_driver_t *this_gen, case 32: ss.format = PA_SAMPLE_FLOAT32NE; break; + default: + _x_assert(!"Should not be reached"); } if (!pa_sample_spec_valid(&ss)) { @@ -228,70 +330,86 @@ static int ao_pulse_open(ao_driver_t *this_gen, goto fail; } - if ( this->pa_class->context && pa_context_get_state(this->pa_class->context) > PA_CONTEXT_READY ) { - pa_context_unref(this->pa_class->context); - this->pa_class->context = NULL; - } - - if ( this->pa_class->context == NULL ) { - this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop), - __progname); - } + cm.channels = ss.channels; - pa_context_ref(this->pa_class->context); - - if ( pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED ) { - int ret; + switch (mode) { + case AO_CAP_MODE_MONO: + cm.map[0] = PA_CHANNEL_POSITION_MONO; + _x_assert(cm.channels == 1); + break; - pa_threaded_mainloop_lock(this->pa_class->mainloop); - ret = pa_context_connect(this->pa_class->context, this->host, 1, NULL); - if ( ret < 0 ) - goto fail_unlock; + case AO_CAP_MODE_STEREO: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + _x_assert(cm.channels == 2); + break; - pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this); + case AO_CAP_MODE_4CHANNEL: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + _x_assert(cm.channels == 4); + break; - pa_threaded_mainloop_wait(this->pa_class->mainloop); - pa_threaded_mainloop_unlock(this->pa_class->mainloop); + case AO_CAP_MODE_4_1CHANNEL: + case AO_CAP_MODE_5CHANNEL: + case AO_CAP_MODE_5_1CHANNEL: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + cm.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + cm.map[5] = PA_CHANNEL_POSITION_LFE; + cm.channels = 6; + break; + default: + _x_assert(!"Should not be reached"); } - if (pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to connect to server: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); + if (!pa_channel_map_valid(&cm)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Invalid channel map\n"); goto fail; } - this->stream = pa_stream_new(this->pa_class->context, "audio stream", &ss, NULL); + if (connect_context(this) < 0) + goto fail; + + _x_assert(!this->stream); + this->stream = pa_stream_new(this->context, "Audio Stream", &ss, &cm); _x_assert(this->stream); - a.maxlength = pa_bytes_per_second(&ss)*1; - a.tlength = a.maxlength*9/10; - a.prebuf = a.tlength/2; - a.minreq = a.tlength/10; + pa_stream_set_state_callback(this->stream, __xine_pa_stream_state_callback, this); + pa_stream_set_write_callback(this->stream, __xine_pa_stream_request_callback, this); + pa_stream_set_latency_update_callback(this->stream, __xine_pa_stream_notify_callback, this); - pa_stream_connect_playback(this->stream, this->sink, &a, - PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, + r = pa_stream_connect_playback(this->stream, this->sink, NULL, + PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - do { - xine_usec_sleep (100); + for (;;) { + pa_context_state_t cstate = pa_context_get_state(this->context); + pa_stream_state_t sstate = pa_stream_get_state(this->stream); - streamstate = pa_stream_get_state(this->stream); - } while (streamstate < PA_STREAM_READY); - - if (streamstate != PA_STREAM_READY) { - xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_pulse_out: Failed to connect to server: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); - goto fail; + if (cstate == PA_CONTEXT_FAILED || cstate == PA_CONTEXT_TERMINATED || + sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context))); + goto fail; + } + + if (sstate == PA_STREAM_READY) + break; + + pa_threaded_mainloop_wait(this->mainloop); } - this->frames_written = 0; - this->ao_driver.set_property(this, AO_PROP_PCM_VOL, 100); + pa_threaded_mainloop_unlock(this->mainloop); return this->sample_rate; - fail_unlock: - pa_threaded_mainloop_unlock(this->pa_class->mainloop); fail: + + pa_threaded_mainloop_unlock(this->mainloop); this_gen->close(this_gen); return 0; } @@ -319,217 +437,348 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data, { pulse_driver_t *this = (pulse_driver_t *) this_gen; size_t size = num_frames * this->bytes_per_frame; - int ret = 0; - - if ( !this->stream || !this->pa_class->context) - return -1; + int ret = -1; + size_t done = 0; - switch( pa_stream_get_state(this->stream) ) { - case PA_STREAM_READY: - while (size > 0) { - size_t l; + pa_threaded_mainloop_lock(this->mainloop); - while (!(l = pa_stream_writable_size(this->stream))) { - xine_usec_sleep (10000); - } + while (size > 0) { + size_t l; - if (l > size) - l = size; - - pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); - data = (int16_t *) ((uint8_t*) data + l); - size -= l; - } + for (;;) { + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + goto finish; - this->frames_written += num_frames; + if ((l = pa_stream_writable_size(this->stream)) == (size_t) -1) + goto finish; - if (pa_stream_get_state(this->stream) == PA_STREAM_READY) - ret = 1; + if (l > 0) + break; - break; + pa_threaded_mainloop_wait(this->mainloop); + } + + if (l > size) + l = size; + + pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); + data = (int16_t *) ((uint8_t*) data + l); + size -= l; + done += l; } + ret = done; + +finish: + + pa_threaded_mainloop_unlock(this->mainloop); + +/* fprintf(stderr, "write-out\n"); */ + return ret; -} +} static int ao_pulse_delay (ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - pa_usec_t latency = 0; - unsigned int delay_frames; + int ret = 0; - if ( ! this->stream ) return this->frames_written; +/* fprintf(stderr, "delay-in\n"); */ - if (pa_stream_get_latency(this->stream, &latency, NULL) < 0) { - pa_context_unref(this->pa_class->context); - this->pa_class->context = NULL; + pa_threaded_mainloop_lock(this->mainloop); - pa_stream_disconnect(this->stream); - pa_stream_unref(this->stream); - this->stream = NULL; + for (;;) { + pa_usec_t latency = 0; - return 0; + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + goto finish; + + if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0) { + ret = (int) ((latency * this->sample_rate) / 1000000); + goto finish; + } + + if (pa_context_errno(this->context) != PA_ERR_NODATA) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to query latency: %s\n", pa_strerror(pa_context_errno(this->context))); + goto finish; + } + + pa_threaded_mainloop_wait(this->mainloop); } - /* convert latency (us) to frame units. */ - delay_frames = (int)(latency * this->sample_rate / 1000000); +finish: + + pa_threaded_mainloop_unlock(this->mainloop); - if( delay_frames > this->frames_written ) - return this->frames_written; - else - return delay_frames; + return ret; } static void ao_pulse_close(ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - - if (this->stream) { - if (pa_stream_get_state(this->stream) == PA_STREAM_READY) { - pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback); - pa_stream_drain(this->stream, __xine_pa_stream_success_callback, &completion_callback); - pthread_mutex_lock(&completion_callback); - pthread_mutex_destroy(&completion_callback); - } + pa_threaded_mainloop_lock(this->mainloop); + if (this->stream) { pa_stream_disconnect(this->stream); pa_stream_unref(this->stream); this->stream = NULL; - - pa_context_unref(this->pa_class->context); } + + pa_threaded_mainloop_unlock(this->mainloop); } static uint32_t ao_pulse_get_capabilities (ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; + return this->capabilities; } -static void ao_pulse_exit(ao_driver_t *this_gen) -{ +static void ao_pulse_exit(ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - free (this); + ao_pulse_close(this_gen); + + pa_threaded_mainloop_lock(this->mainloop); + + if (this->context) { + pa_context_disconnect(this->context); + pa_context_unref(this->context); + } + + pa_threaded_mainloop_unlock(this->mainloop); + + pa_threaded_mainloop_free(this->mainloop); + + free(this->host); + free(this->sink); + free(this); +} + +static int wait_for_operation(pulse_driver_t *this, pa_operation *o) { + + for (;;) { + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + return -1; + + if (pa_operation_get_state(o) != PA_OPERATION_RUNNING) + return 0; + + pa_threaded_mainloop_wait(this->mainloop); + } } static int ao_pulse_get_property (ao_driver_t *this_gen, int property) { pulse_driver_t *this = (pulse_driver_t *) this_gen; int result = 0; + pa_operation *o = NULL; - if ( ! this->stream || ! this->pa_class->context ) + pa_threaded_mainloop_lock(this->mainloop); + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); return 0; + } switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: - { - pthread_mutex_lock(&this->info_mutex); - pa_operation *o = pa_context_get_sink_input_info(this->pa_class->context, - pa_stream_get_index(this->stream), - __xine_pa_sink_info_callback, this); - if ( ! o ) return 0; - pthread_mutex_lock(&this->info_mutex); pthread_mutex_unlock(&this->info_mutex); - - result = (pa_sw_volume_to_linear(this->swvolume)*100); - } - break; - case AO_PROP_MUTE_VOL: - result = pa_cvolume_is_muted(&this->cvolume); - break; + case AO_PROP_MUTE_VOL: + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + + o = pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream), + __xine_pa_sink_info_callback, this); + + break; + } + + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); } - + + switch(property) { + + case AO_PROP_MUTE_VOL: + result = this->muted; + break; + + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + result = (int) (pa_sw_volume_to_linear(this->swvolume)*100); + break; + } + + pa_threaded_mainloop_unlock(this->mainloop); + return result; } static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value) { pulse_driver_t *this = (pulse_driver_t *) this_gen; int result = ~value; + pa_operation *o = NULL; - if ( ! this->stream || ! this->pa_class->context ) - return result; + pa_threaded_mainloop_lock(this->mainloop); + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); + return 0; + } switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: - this->swvolume = pa_sw_volume_from_linear((double)value/100.0); - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: - pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), - &this->cvolume, __xine_pa_context_success_callback, this); + this->swvolume = pa_sw_volume_from_linear((double)value/100.0); + pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); - result = value; - break; + o = pa_context_set_sink_input_volume(this->context, pa_stream_get_index(this->stream), + &this->cvolume, __xine_pa_context_success_callback, this); - case AO_PROP_MUTE_VOL: - if ( value ) - pa_cvolume_mute(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels); - else - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + result = value; + break; + + case AO_PROP_MUTE_VOL: - pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), - &this->cvolume, __xine_pa_context_success_callback, this); - - result = value; - break; + this->muted = value; + + o = pa_context_set_sink_input_mute(this->context, pa_stream_get_index(this->stream), + value, __xine_pa_context_success_callback, this); + + result = value; + } + + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); } - + + pa_threaded_mainloop_unlock(this->mainloop); + return result; } static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { pulse_driver_t *this = (pulse_driver_t *) this_gen; + pa_operation *o = NULL; + + pa_threaded_mainloop_lock(this->mainloop); - if ( ! this->stream ) return 0; + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); + return 0; + } switch (cmd) { - case AO_CTRL_FLUSH_BUFFERS: - _x_assert(this->stream && this->pa_class->context); + case AO_CTRL_FLUSH_BUFFERS: - if(pa_stream_get_state(this->stream) == PA_STREAM_READY) { - pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback); - pa_stream_flush(this->stream, __xine_pa_stream_success_callback, &completion_callback); + o = pa_stream_flush(this->stream, __xine_pa_stream_success_callback, this); + break; - pthread_mutex_lock(&completion_callback); - pthread_mutex_destroy(&completion_callback); - } + case AO_CTRL_PLAY_RESUME: + case AO_CTRL_PLAY_PAUSE: - this->frames_written = 0; + o = pa_stream_cork(this->stream, cmd == AO_CTRL_PLAY_PAUSE, __xine_pa_stream_success_callback, this); + break; + } - break; + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); } + pa_threaded_mainloop_unlock(this->mainloop); + return 0; } static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { pulse_class_t *class = (pulse_class_t *) class_gen; pulse_driver_t *this; - char *device; + const char* device; + int r; lprintf ("audio_pulse_out: open_plugin called\n"); this = (pulse_driver_t *) xine_xmalloc (sizeof (pulse_driver_t)); if (!this) return NULL; + this->xine = class->xine; + this->host = NULL; + this->sink = NULL; + this->context = NULL; + this->mainloop = NULL; + + device = class->xine->config->register_string(class->xine->config, + "audio.pulseaudio_device", + "", + _("device used for pulseaudio"), + _("use 'server[:sink]' for setting the " + "pulseaudio sink device."), + 10, NULL, + NULL); + + if (device && *device) { + char *sep = strrchr(device, ':'); + if ( sep ) { + if (!(this->host = strndup(device, sep-device))) { + free(this); + return NULL; + } + + if (!(this->sink = strdup(sep+1))) { + free(this->host); + free(this); + return NULL; + } + } else { + + if (!(this->host = strdup(device))) { + free(this); + return NULL; + } + } + } + + this->mainloop = pa_threaded_mainloop_new(); + _x_assert(this->mainloop); + pa_threaded_mainloop_start(this->mainloop); /* * set capabilities */ - this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | - AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | - AO_CAP_MODE_5_1CHANNEL | AO_CAP_MIXER_VOL | - AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS | - AO_CAP_16BITS | AO_CAP_FLOAT32; + this->capabilities = + AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | + AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL | + AO_CAP_MIXER_VOL | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | + AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_FLOAT32; this->sample_rate = 0; - this->host = NULL; - this->sink = NULL; - + this->ao_driver.get_capabilities = ao_pulse_get_capabilities; this->ao_driver.get_property = ao_pulse_get_property; this->ao_driver.set_property = ao_pulse_set_property; @@ -541,33 +790,22 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->ao_driver.close = ao_pulse_close; this->ao_driver.exit = ao_pulse_exit; this->ao_driver.get_gap_tolerance = ao_pulse_get_gap_tolerance; - this->ao_driver.control = ao_pulse_ctrl; - - device = this->xine->config->register_string(this->xine->config, - "audio.pulseaudio_device", - "", - _("device used for pulseaudio"), - _("use 'server[:sink]' for setting the " - "pulseaudio sink device."), - 10, NULL, - NULL); - - if (device && *device) { - char *sep = strchr(device, ':'); - if ( sep ) { - this->host = strndup(device, sep-device); - this->sink = strdup(&sep[1]); - } else - this->host = strdup(device); - } - - pthread_mutex_init(&this->info_mutex, NULL); + this->ao_driver.control = ao_pulse_ctrl; xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n", this->host ? this->host : "(null)", this->sink ? this->sink : "(null)"); this->pa_class = class; + pa_threaded_mainloop_lock(this->mainloop); + r = connect_context(this); + pa_threaded_mainloop_unlock(this->mainloop); + + if (r < 0) { + ao_pulse_exit((ao_driver_t *) this); + return NULL; + } + return &this->ao_driver; } @@ -579,13 +817,7 @@ static void dispose_class (audio_driver_class_t *this_gen) { pulse_class_t *this = (pulse_class_t *) this_gen; - if ( this->context ) - pa_context_unref(this->context); - - pa_threaded_mainloop_stop(this->mainloop); - pa_threaded_mainloop_free(this->mainloop); - - free (this); + free(this); } static void *init_class (xine_t *xine, void *data) { @@ -598,25 +830,17 @@ static void *init_class (xine_t *xine, void *data) { if (!this) return NULL; + this->xine = xine; this->driver_class.open_plugin = open_plugin; this->driver_class.dispose = dispose_class; this->driver_class.identifier = "pulseaudio"; this->driver_class.description = N_("xine audio output plugin using pulseaudio sound server"); - this->xine = xine; - - this->mainloop = pa_threaded_mainloop_new(); - _x_assert(this->mainloop); - - pa_threaded_mainloop_start(this->mainloop); - - this->context = NULL; - return this; } static const ao_info_t ao_info_pulse = { - 6 + 12 }; /* @@ -628,5 +852,3 @@ const plugin_info_t xine_plugin_info[] EXPORTED = { { PLUGIN_AUDIO_OUT, 9, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - - diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index b7f966325..27fe18d9c 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -78,6 +78,7 @@ static const ff_codec_t ff_audio_lookup[] = { {BUF_AUDIO_14_4, CODEC_ID_RA_144, "Real 14.4 (ffmpeg)"}, {BUF_AUDIO_28_8, CODEC_ID_RA_288, "Real 28.8 (ffmpeg)"}, {BUF_AUDIO_MPEG, CODEC_ID_MP3, "MP3 (ffmpeg)"}, + {BUF_AUDIO_MP3ADU, CODEC_ID_MP3ADU, "MPEG-3 adu (ffmpeg)"}, {BUF_AUDIO_MSADPCM, CODEC_ID_ADPCM_MS, "MS ADPCM (ffmpeg)"}, {BUF_AUDIO_QTIMAADPCM, CODEC_ID_ADPCM_IMA_QT, "QT IMA ADPCM (ffmpeg)"}, {BUF_AUDIO_MSIMAADPCM, CODEC_ID_ADPCM_IMA_WAV, "MS IMA ADPCM (ffmpeg)"}, @@ -198,8 +199,8 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->audio_channels = this->buf[0x37]; /* this->audio_bits = buf->content[0x35] */ - this->context->block_align = _X_BE_16(&this->buf[0x2A]); - + this->context->block_align = _X_BE_32(&this->buf[0x18]); + this->context->extradata_size = 5*sizeof(short); this->context->extradata = xine_xmalloc(this->context->extradata_size); @@ -210,7 +211,49 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) ptr[2] = _X_BE_16(&this->buf[0x16]); /* subpacket flavour */ ptr[3] = _X_BE_32(&this->buf[0x18]); /* coded frame size */ ptr[4] = 0; /* codec's data length */ + + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "ffmpeg_audio_dec: 28_8 audio channels %d bits %d sample rate %d block align %d\n", + this->audio_channels, this->audio_bits, this->audio_sample_rate, + this->context->block_align); break; + case BUF_AUDIO_COOK: + { + int version; + int data_len; + int extradata; + + version = _X_BE_16 (this->buf+4); + if (version == 4) { + this->audio_sample_rate = _X_BE_16 (this->buf+48); + this->audio_bits = _X_BE_16 (this->buf+52); + this->audio_channels = _X_BE_16 (this->buf+54); + data_len = _X_BE_32 (this->buf+67); + extradata = 71; + } else { + this->audio_sample_rate = _X_BE_16 (this->buf+54); + this->audio_bits = _X_BE_16 (this->buf+58); + this->audio_channels = _X_BE_16 (this->buf+60); + data_len = _X_BE_32 (this->buf+74); + extradata = 78; + } + this->context->block_align = _X_BE_16 (this->buf+44); + + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "ffmpeg_audio_dec: cook audio channels %d bits %d sample rate %d block align %d\n", + this->audio_channels, this->audio_bits, this->audio_sample_rate, + this->context->block_align); + + if (extradata + data_len > this->size) + break; /* abort early - extradata length is bad */ + + this->context->extradata_size = data_len; + this->context->extradata = xine_xmalloc(this->context->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + xine_fast_memcpy (this->context->extradata, this->buf + extradata, + this->context->extradata_size); + break; + } default: xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "ffmpeg_audio_dec: unknown header with buf type 0x%X\n", codec_type); @@ -227,6 +270,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->context->sample_rate = this->audio_sample_rate; this->context->channels = this->audio_channels; this->context->codec_id = this->codec->id; + this->context->codec_type = this->codec->type; this->context->codec_tag = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC); this->size = 0; @@ -266,7 +310,26 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->decoder_ok = 1; } + if( buf->decoder_flags & BUF_FLAG_PREVIEW ) + return; + + ff_audio_ensure_buffer_size(this, this->size + buf->size); + xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); + this->size += buf->size; + if (!this->output_open) { + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + avcodec_decode_audio (this->context, + (int16_t *)this->decode_buffer, + &decode_buffer_size, + &this->buf[0], + this->size); + this->audio_bits = this->context->bits_per_sample; + this->audio_sample_rate = this->context->sample_rate; + this->audio_channels = this->context->channels; + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) + return; + } this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, this->stream, this->audio_bits, this->audio_sample_rate, _x_ao_channels2mode(this->audio_channels)); @@ -276,13 +339,6 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) if (!this->output_open) return; - if( buf->decoder_flags & BUF_FLAG_PREVIEW ) - return; - - ff_audio_ensure_buffer_size(this, this->size + buf->size); - xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); - this->size += buf->size; - if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */ offset = 0; @@ -323,7 +379,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) /* fill up this buffer */ xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out], - bytes_to_send); + bytes_to_send); /* byte count / 2 (bytes / sample) / channels */ audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels; @@ -354,7 +410,8 @@ static void ff_audio_reset (audio_decoder_t *this_gen) { if( this->context && this->decoder_ok ) { pthread_mutex_lock (&ffmpeg_lock); avcodec_close (this->context); - avcodec_open (this->context, this->codec); + if (avcodec_open (this->context, this->codec) < 0) + this->decoder_ok = 0; pthread_mutex_unlock (&ffmpeg_lock); } } @@ -468,5 +525,5 @@ static const uint32_t supported_audio_types[] = { decoder_info_t dec_info_ffmpeg_audio = { supported_audio_types, /* supported types */ - 6 /* priority */ + 7 /* priority */ }; diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index fcc6b9283..951e12deb 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -44,11 +44,7 @@ #include "ffmpeg_decoder.h" #include "ff_mpeg_parser.h" -#ifdef HAVE_FFMPEG_AVCODEC_H -# include <postprocess.h> -#else -# include <libpostproc/postprocess.h> -#endif +#include <postprocess.h> #define VIDEOBUFSIZE (128*1024) #define SLICE_BUFFER_SIZE (1194*1024) @@ -943,6 +939,26 @@ static void ff_handle_header_buffer (ff_video_decoder_t *this, buf_element_t *bu this->context->slice_offset = xine_xmalloc(sizeof(int)*SLICE_OFFSET_SIZE); this->slice_offset_size = SLICE_OFFSET_SIZE; + this->context->extradata_size = this->size - 26; + if (this->context->extradata_size < 8) { + this->context->extradata_size= 8; + this->context->extradata = malloc(this->context->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + ((uint32_t *)this->context->extradata)[0] = 0; + if (codec_type == BUF_VIDEO_RV10) + ((uint32_t *)this->context->extradata)[1] = 0x10000000; + else + ((uint32_t *)this->context->extradata)[1] = 0x10003001; + } else { + this->context->extradata = malloc(this->context->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + memcpy(this->context->extradata, this->buf + 26, + this->context->extradata_size); + } + + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "ffmpeg_video_dec: buf size %d\n", this->size); + lprintf("w=%d, h=%d\n", this->bih.biWidth, this->bih.biHeight); break; diff --git a/src/combined/ffmpeg/ffmpeg_decoder.h b/src/combined/ffmpeg/ffmpeg_decoder.h index adf0908dd..bfe71a6b1 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.h +++ b/src/combined/ffmpeg/ffmpeg_decoder.h @@ -25,11 +25,7 @@ #include "config.h" #endif -#ifdef HAVE_FFMPEG_AVCODEC_H -# include <avcodec.h> -#else -# include <libavcodec/avcodec.h> -#endif +#include <avcodec.h> typedef struct ff_codec_s { uint32_t type; diff --git a/src/combined/wavpack_combined.c b/src/combined/wavpack_combined.c index 8a4b488ae..ca54635e7 100644 --- a/src/combined/wavpack_combined.c +++ b/src/combined/wavpack_combined.c @@ -33,7 +33,7 @@ static const uint32_t audio_types[] = { static const decoder_info_t decoder_info_wv = { audio_types, /* supported types */ - 7 /* priority */ + 8 /* priority */ }; const plugin_info_t xine_plugin_info[] EXPORTED = { diff --git a/src/combined/wavpack_demuxer.c b/src/combined/wavpack_demuxer.c index 403d136d1..e32c17e4e 100644 --- a/src/combined/wavpack_demuxer.c +++ b/src/combined/wavpack_demuxer.c @@ -368,8 +368,8 @@ void *demux_wv_init_plugin (xine_t *const xine, void *const data) { this->demux_class.open_plugin = open_plugin; this->demux_class.description = N_("Wavpack demux plugin"); this->demux_class.identifier = "Wavpack"; - this->demux_class.mimetypes = "audio/x-wavpack"; - this->demux_class.extensions = "wv"; + this->demux_class.mimetypes = "audio/x-wavpack: wv,wvp: WavPack audio;"; + this->demux_class.extensions = "wv wvp"; this->demux_class.dispose = default_demux_class_dispose; return this; diff --git a/src/combined/xine_ogg_demuxer.c b/src/combined/xine_ogg_demuxer.c index 88fcea08a..52788612f 100644 --- a/src/combined/xine_ogg_demuxer.c +++ b/src/combined/xine_ogg_demuxer.c @@ -1208,7 +1208,7 @@ static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_p static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { xine_flac_metadata_header header; - xine_flac_streaminfo_block streaminfo; + xine_flac_streaminfo_block streaminfo = {}; buf_element_t *buf; xine_waveformatex wave; @@ -2110,6 +2110,9 @@ static void *ogg_init_class (xine_t *xine, void *data) { this->demux_class.identifier = "OGG"; this->demux_class.mimetypes = "application/ogg: ogx: Ogg Stream;" + "application/x-ogm: ogx: Ogg Stream;" + "application/x-ogm-audio: oga: Ogg Audio;" + "application/x-ogm-video: ogv: Ogg Video;" "application/x-ogg: ogx: Ogg Stream;" "audio/ogg: oga: Ogg Audio;" "audio/x-ogg: oga: Ogg Audio;" diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index 596d7dbd0..e2ee826ec 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -8,7 +8,7 @@ AM_LDFLAGS = $(xineplug_ldflags) # --------- # All of xine demuxer plugins should be named like the scheme "xineplug_dmx_" -noinst_HEADERS = asfheader.h qtpalette.h group_games.h group_audio.h id3.h ebml.h matroska.h iff.h flacutils.h +noinst_HEADERS = asfheader.h qtpalette.h group_games.h group_audio.h id3.h ebml.h matroska.h iff.h flacutils.h real_common.h if ENABLE_ASF asf_module = xineplug_dmx_asf.la diff --git a/src/demuxers/asfheader.c b/src/demuxers/asfheader.c index 75ad11c75..d602445a0 100644 --- a/src/demuxers/asfheader.c +++ b/src/demuxers/asfheader.c @@ -394,7 +394,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin if (asf_stream_extension->stream_name_count) {
asf_stream_extension->stream_names = malloc (asf_stream_extension->stream_name_count * sizeof(void*));
for (i = 0; i < asf_stream_extension->stream_name_count; i++) {
- uint16_t lang_index, length;
+ uint16_t lang_index, length = 0;
asf_reader_get_16(&reader, &lang_index);
asf_reader_get_16(&reader, &length);
asf_stream_extension->stream_names[i] = (char*)asf_reader_get_bytes(&reader, length); /* store them */
@@ -406,7 +406,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin for (i = 0; i < asf_stream_extension->payload_extension_system_count; i++) {
GUID guid;
uint16_t data_size;
- uint32_t length;
+ uint32_t length = 0;
asf_reader_get_guid(&reader, &guid);
asf_reader_get_16(&reader, &data_size);
asf_reader_get_32(&reader, &length);
@@ -422,7 +422,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin /* embeded stream properties */
if (asf_reader_get_size(&reader) >= 24) {
GUID guid;
- uint64_t object_length;
+ uint64_t object_length = 0;
asf_reader_get_guid(&reader, &guid);
asf_reader_get_64(&reader, &object_length);
@@ -485,8 +485,8 @@ static int asf_header_parse_stream_bitrate_properties(asf_header_t *header_pub, lprintf (" bitrate count: %d\n", bitrate_count);
for(i = 0; i < bitrate_count; i++) {
- uint16_t flags;
- uint32_t bitrate;
+ uint16_t flags = 0;
+ uint32_t bitrate = 0;
int stream_number;
uint8_t *bitrate_pointer;
@@ -528,7 +528,7 @@ static int asf_header_parse_header_extension(asf_header_t *header, uint8_t *buff GUID guid;
int object_id;
- uint64_t object_length, object_data_length;
+ uint64_t object_length = 0, object_data_length;
if (asf_reader_get_size(&reader) < 24) {
printf("invalid buffer size\n");
@@ -633,7 +633,7 @@ asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) { GUID guid;
int object_id;
- uint64_t object_length, object_data_length;
+ uint64_t object_length = 0, object_data_length;
if (asf_reader_get_size(&reader) < 24) {
printf("invalid buffer size\n");
diff --git a/src/demuxers/demux_4xm.c b/src/demuxers/demux_4xm.c index 6256cb042..264806421 100644 --- a/src/demuxers/demux_4xm.c +++ b/src/demuxers/demux_4xm.c @@ -159,7 +159,7 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { /* read the whole header */ header_size = _X_LE_32(&preview[4]) - 4; header = xine_xmalloc(header_size); - if (fourxm->input->read(fourxm->input, header, header_size) != header_size) { + if (!header || fourxm->input->read(fourxm->input, header, header_size) != header_size) { free(header); return 0; } diff --git a/src/demuxers/demux_aiff.c b/src/demuxers/demux_aiff.c index 51bc624e3..06ff65680 100644 --- a/src/demuxers/demux_aiff.c +++ b/src/demuxers/demux_aiff.c @@ -46,6 +46,10 @@ #define COMM_TAG FOURCC_TAG('C', 'O', 'M', 'M') #define SSND_TAG FOURCC_TAG('S', 'S', 'N', 'D') #define APCM_TAG FOURCC_TAG('A', 'P', 'C', 'M') +#define NAME_TAG FOURCC_TAG('N', 'A', 'M', 'E') +#define AUTH_TAG FOURCC_TAG('A', 'U', 'T', 'H') +#define COPY_TAG FOURCC_TAG('(', 'c', ')', ' ') +#define ANNO_TAG FOURCC_TAG('A', 'N', 'N', 'O') #define PREAMBLE_SIZE 8 #define AIFF_SIGNATURE_SIZE 12 @@ -80,6 +84,24 @@ typedef struct { demux_class_t demux_class; } demux_aiff_class_t; +/* converts IEEE 80bit extended into int, based on FFMPEG code */ +int extended_to_int(const unsigned char p[10]) +{ + uint64_t m = 0; + int e, i; + + for (i = 0; i < 8; i++) + m = (m<<8) + p[2+i];; + e = (((int)p[0]&0x7f)<<8) | p[1]; + if (e == 0x7fff && m) + return 0.0/0.0; + e -= 16383 + 63; + + if (p[0]&0x80) + m= -m; + return (int) ldexp(m, e); +} + /* returns 1 if the AIFF file was opened successfully, 0 otherwise */ static int open_aiff_file(demux_aiff_t *this) { @@ -87,6 +109,7 @@ static int open_aiff_file(demux_aiff_t *this) { unsigned char preamble[PREAMBLE_SIZE]; unsigned int chunk_type; unsigned int chunk_size; + unsigned char extended_sample_rate[10]; if (_x_demux_read_header(this->input, signature, AIFF_SIGNATURE_SIZE) != AIFF_SIGNATURE_SIZE) return 0; @@ -135,7 +158,8 @@ static int open_aiff_file(demux_aiff_t *this) { this->audio_channels = _X_BE_16(&buffer[0]); this->audio_frames = _X_BE_32(&buffer[2]); this->audio_bits = _X_BE_16(&buffer[6]); - this->audio_sample_rate = _X_BE_16(&buffer[0x0A]); + memcpy(&extended_sample_rate, &buffer[8], sizeof(extended_sample_rate)); + this->audio_sample_rate = extended_to_int(extended_sample_rate); this->audio_bytes_per_second = this->audio_channels * (this->audio_bits / 8) * this->audio_sample_rate; @@ -150,11 +174,18 @@ static int open_aiff_file(demux_aiff_t *this) { (this->audio_bits / 8); this->running_time = (this->audio_frames / this->audio_sample_rate) * 1000; - this->audio_block_align = PCM_BLOCK_ALIGN; + /* we should send only complete frames to decoder, as it + * doesn't handle underconsumption yet */ + this->audio_block_align = PCM_BLOCK_ALIGN - PCM_BLOCK_ALIGN % (this->audio_bits / 8 * this->audio_channels); break; } else { + /* if chunk contains metadata, it will be word-aligned (as seen at sox and ffmpeg) */ + if ( ((chunk_type == NAME_TAG) || (chunk_type==AUTH_TAG) || + (chunk_type == COPY_TAG) || (chunk_type==ANNO_TAG)) && (chunk_size&1)) + chunk_size++; + /* unrecognized; skip it */ this->input->seek(this->input, chunk_size, SEEK_CUR); } diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c index 27dfce443..e06caf94f 100644 --- a/src/demuxers/demux_avi.c +++ b/src/demuxers/demux_avi.c @@ -973,6 +973,10 @@ static avi_t *AVI_init(demux_avi_t *this) { xine_waveformatex *wavex; wavex = (xine_waveformatex *)malloc(n); + if (!wavex) { + this->AVI_errno = AVI_ERR_NO_MEM; + return 0; + } memcpy((void *)wavex, hdrl_data+i, n); _x_waveformatex_le2me( wavex ); @@ -1237,6 +1241,9 @@ static avi_t *AVI_init(demux_avi_t *this) { /* read from file */ chunk_start = en = malloc (AVI->video_superindex->aIndex[j].dwSize+hdrl_len); + if (!chunk_start) + ERR_EXIT(AVI_ERR_NO_MEM); + if (this->input->seek(this->input, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { lprintf("cannot seek to 0x%" PRIx64 "\n", AVI->video_superindex->aIndex[j].qwOffset); free(chunk_start); @@ -1308,6 +1315,9 @@ static avi_t *AVI_init(demux_avi_t *this) { /* read from file */ chunk_start = en = malloc (audio->audio_superindex->aIndex[j].dwSize+hdrl_len); + if (!chunk_start) + ERR_EXIT(AVI_ERR_NO_MEM); + if (this->input->seek(this->input, audio->audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { lprintf("cannot seek to 0x%" PRIx64 "\n", audio->audio_superindex->aIndex[j].qwOffset); free(chunk_start); diff --git a/src/demuxers/demux_dts.c b/src/demuxers/demux_dts.c index 9d3313a72..750d212f5 100644 --- a/src/demuxers/demux_dts.c +++ b/src/demuxers/demux_dts.c @@ -140,29 +140,63 @@ static int open_dts_file(demux_dts_t *this) { } } + /* DTS bitstream encoding version + * -1 - not detected + * 0 - 16 bits and big endian + * 1 - 16 bits and low endian (detection not implemented) + * 2 - 14 bits and big endian (detection not implemented) + * 3 - 14 bits and low endian + */ + int dts_version = -1; + /* Look for a valid DTS syncword */ for (i=offset; i<peak_size-1; i++) { + /* 16 bits and big endian bitstream */ + if (syncword == 0x7ffe8001) { + dts_version = 0; + break; + } /* 14 bits and little endian bitstream */ - if ((syncword == 0xff1f00e8) && - ((peak[i] & 0xf0) == 0xf0) && (peak[i+1] == 0x07)) { - this->data_start = i-4; - lprintf("found DTS syncword at offset %d\n", i-4); - break; + else if ((syncword == 0xff1f00e8) && + ((peak[i] & 0xf0) == 0xf0) && (peak[i+1] == 0x07)) { + dts_version = 3; + break; } syncword = (syncword << 8) | peak[i]; } + if (dts_version == -1) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": unsupported DTS stream type, or not a DTS stream\n"); + return 0; + } + + this->data_start = i-4; + lprintf("found DTS syncword at offset %d\n", i-4); + if (i < peak_size-9) { unsigned int nblks, fsize, sfreq; + switch (dts_version) + { + case 0: /* BE16 */ + nblks = ((peak[this->data_start+4] & 0x01) << 6) | + ((peak[this->data_start+5] & 0xfc) >> 2); + fsize = (((peak[this->data_start+5] & 0x03) << 12) |(peak[this->data_start+6] << 4) | + ((peak[this->data_start+7] & 0xf0) >> 4)) + 1; + sfreq = (peak[this->data_start+8] & 0x3c) >> 2; + break; - /* 14 bits and little endian bitstream */ - nblks = ((peak[this->data_start+4] & 0x07) << 4) | - ((peak[this->data_start+7] & 0x3c) >> 2); - fsize = (((peak[this->data_start+7] & 0x03) << 12) | - (peak[this->data_start+6] << 4) | - ((peak[this->data_start+9] & 0x3c) >> 2)) + 1; - sfreq = peak[this->data_start+8] & 0x0f; + case 3: /* LE14 */ + nblks = ((peak[this->data_start+4] & 0x07) << 4) | + ((peak[this->data_start+7] & 0x3c) >> 2); + fsize = (((peak[this->data_start+7] & 0x03) << 12) | + (peak[this->data_start+6] << 4) | + ((peak[this->data_start+9] & 0x3c) >> 2)) + 1; + sfreq = peak[this->data_start+8] & 0x0f; + break; + + } if ((sfreq > sizeof(dts_sample_rates)/sizeof(int)) || (dts_sample_rates[sfreq] == 0)) @@ -170,7 +204,19 @@ static int open_dts_file(demux_dts_t *this) { /* Big assumption - this is CBR data */ this->samples_per_frame = (nblks + 1) * 32; - this->frame_size = fsize * 8 / 14 * 2; + + switch (dts_version) + { + case 0: /* BE16 */ + case 1: /* LE16 */ + this->frame_size = fsize * 8 / 16 * 2; + break; + case 2: /* BE14 */ + case 3: /* LE14 */ + this->frame_size = fsize * 8 / 14 * 2; + break; + } + this->sample_rate = dts_sample_rates[sfreq]; lprintf("samples per frame: %d\n", this->samples_per_frame); diff --git a/src/demuxers/demux_film.c b/src/demuxers/demux_film.c index 193d8850b..f7b514e4b 100644 --- a/src/demuxers/demux_film.c +++ b/src/demuxers/demux_film.c @@ -260,6 +260,8 @@ static int open_film_file(demux_film_t *film) { film->sample_count = _X_BE_32(&film_header[i + 12]); film->sample_table = xine_xcalloc(film->sample_count, sizeof(film_sample_t)); + if (!film->sample_table) + goto film_abort; for (j = 0; j < film->sample_count; j++) { film->sample_table[j].sample_offset = @@ -335,11 +337,14 @@ static int open_film_file(demux_film_t *film) { free(film->interleave_buffer); film->interleave_buffer = xine_xmalloc(film->sample_table[0].sample_size); + if (!film->interleave_buffer) + goto film_abort; } break; default: xine_log(film->stream->xine, XINE_LOG_MSG, _("unrecognized FILM chunk\n")); + film_abort: free (film->interleave_buffer); free (film->sample_table); free (film_header); diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c index ed974a69c..94c599562 100644 --- a/src/demuxers/demux_flac.c +++ b/src/demuxers/demux_flac.c @@ -166,6 +166,8 @@ static int open_flac_file(demux_flac_t *flac) { flac->seekpoint_count = block_length / FLAC_SEEKPOINT_SIZE; flac->seekpoints = xine_xcalloc(flac->seekpoint_count, sizeof(flac_seekpoint_t)); + if (flac->seekpoint_count && !flac->seekpoints) + return 0; for (i = 0; i < flac->seekpoint_count; i++) { if (flac->input->read(flac->input, buffer, FLAC_SEEKPOINT_SIZE) != FLAC_SEEKPOINT_SIZE) return 0; diff --git a/src/demuxers/demux_flv.c b/src/demuxers/demux_flv.c index 38855c027..e111468aa 100644 --- a/src/demuxers/demux_flv.c +++ b/src/demuxers/demux_flv.c @@ -85,7 +85,7 @@ typedef struct { off_t filesize; flv_index_entry_t *index; - int num_indices; + unsigned int num_indices; unsigned int cur_pts; @@ -209,7 +209,7 @@ static int parse_flv_var(demux_flv_t *this, unsigned char *end = buf + size; char *str; unsigned char type; - int len, num; + unsigned int len, num; if (size < 1) return 0; @@ -283,6 +283,8 @@ static int parse_flv_var(demux_flv_t *this, str = tmp + 2; tmp += len + 2; len = parse_flv_var(this, tmp, end-tmp, str, len); + if (!len) + return 0; tmp += len; } if (*tmp++ != FLV_DATA_TYPE_ENDOBJECT) @@ -298,6 +300,8 @@ static int parse_flv_var(demux_flv_t *this, str = tmp + 2; tmp += len + 2; len = parse_flv_var(this, tmp, end-tmp, str, len); + if (!len) + return 0; tmp += len; } break; @@ -310,6 +314,8 @@ static int parse_flv_var(demux_flv_t *this, if (this->index) free(this->index); this->index = xine_xcalloc(num, sizeof(flv_index_entry_t)); + if (!this->index) + return 0; this->num_indices = num; } for (num = 0; num < this->num_indices && tmp < end; num++) { @@ -326,6 +332,8 @@ static int parse_flv_var(demux_flv_t *this, if (this->index) free(this->index); this->index = xine_xcalloc(num, sizeof(flv_index_entry_t)); + if (!this->index) + return 0; this->num_indices = num; } for (num = 0; num < this->num_indices && tmp < end; num++) { @@ -339,6 +347,8 @@ static int parse_flv_var(demux_flv_t *this, } while (num-- && tmp < end) { len = parse_flv_var(this, tmp, end-tmp, NULL, 0); + if (!len) + return 0; tmp += len; } break; @@ -360,7 +370,7 @@ static void parse_flv_script(demux_flv_t *this, int size) { unsigned char *end = buf + size; int len; - if (this->input->read(this->input, buf, size ) != size) { + if (!buf || this->input->read(this->input, buf, size ) != size) { this->status = DEMUX_FINISHED; free(buf); return; diff --git a/src/demuxers/demux_iff.c b/src/demuxers/demux_iff.c index 665d29cd2..dcef148b4 100644 --- a/src/demuxers/demux_iff.c +++ b/src/demuxers/demux_iff.c @@ -401,7 +401,7 @@ static int read_iff_chunk(demux_iff_t *this) { this->cmap_num = junk_size / PIC_SIZE_OF_COLOR_REGISTER; this->cmap = (ColorRegister *)xine_xmalloc(junk_size); this->video_send_palette = 1; - if (this->input->read(this->input, (char *)this->cmap, junk_size) != junk_size) + if (!this->cmap || this->input->read(this->input, (char *)this->cmap, junk_size) != junk_size) return 0; break; case IFF_GRAB_CHUNK: @@ -709,11 +709,19 @@ static int demux_iff_send_chunk(demux_plugin_t *this_gen) { /* load the whole chunk into the buffer */ if (this->audio_buffer_filled == 0) { if (this->audio_interleave_buffer_size > 0) + { this->audio_interleave_buffer = xine_xmalloc(this->audio_interleave_buffer_size); + if (!this->audio_interleave_buffer) + return this->status = DEMUX_FINISHED; + } if (this->audio_read_buffer_size > 0) + { this->audio_read_buffer = xine_xmalloc(this->audio_read_buffer_size); + if (!this->audio_read_buffer) + return this->status = DEMUX_FINISHED; + } if (this->audio_read_buffer) { if (this->input->read(this->input, this->audio_read_buffer, this->data_size) != this->data_size) { diff --git a/src/demuxers/demux_ipmovie.c b/src/demuxers/demux_ipmovie.c index 4d08af6fa..88fd70811 100644 --- a/src/demuxers/demux_ipmovie.c +++ b/src/demuxers/demux_ipmovie.c @@ -283,9 +283,10 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { this->bih.biWidth = _X_LE_16(&scratch[0]) * 8; this->bih.biHeight = _X_LE_16(&scratch[2]) * 8; /* set up staging area for decode map */ - this->decode_map_size = (this->bih.biWidth * this->bih.biHeight) / - (8 * 8) / 2; + this->decode_map_size = (this->bih.biWidth / 8) * (this->bih.biHeight / 8) / 2; this->decode_map = xine_xmalloc(this->decode_map_size); + if (!this->decode_map) + this->status = DEMUX_FINISHED; lprintf("video resolution: %d x %d\n", this->bih.biWidth, this->bih.biHeight); break; diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index ec932aacb..713995e97 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -635,9 +635,7 @@ static void init_codec_xiph(demux_matroska_t *this, matroska_track_t *track) { } buf->size = frame[i]; - buf->decoder_flags = BUF_FLAG_HEADER; - if (i == 2) - buf->decoder_flags |= BUF_FLAG_FRAME_END; + buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_FRAME_START | BUF_FLAG_FRAME_END; buf->type = track->buf_type; buf->pts = 0; @@ -1179,13 +1177,10 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { break; case MATROSKA_ID_TR_CODECID: { - char *codec_id = malloc (elem.len + 1); + char *codec_id = ebml_alloc_read_ascii (ebml, &elem); lprintf("CodecID\n"); - if (!ebml_read_ascii(ebml, &elem, codec_id)) { - free(codec_id); + if (!codec_id) return 0; - } - codec_id[elem.len] = '\0'; track->codec_id = codec_id; } break; @@ -1203,13 +1198,10 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { break; case MATROSKA_ID_TR_LANGUAGE: { - char *language = malloc (elem.len + 1); + char *language = ebml_alloc_read_ascii (ebml, &elem); lprintf("Language\n"); - if (!ebml_read_ascii(ebml, &elem, language)) { - free(language); + if (!language) return 0; - } - language[elem.len] = '\0'; track->language = language; } break; @@ -2893,7 +2885,8 @@ static void *init_class (xine_t *xine, void *data) { this->demux_class.open_plugin = open_plugin; this->demux_class.description = N_("matroska demux plugin"); this->demux_class.identifier = "matroska"; - this->demux_class.mimetypes = "video/mkv: mkv: matroska;"; + this->demux_class.mimetypes = "video/mkv: mkv: matroska;" + "video/x-matroska: mkv: matroska;"; this->demux_class.extensions = "mkv"; this->demux_class.dispose = default_demux_class_dispose; diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index ecd2c319a..b8e0acb12 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -746,8 +746,10 @@ static char *parse_data_atom(const uint8_t *data_atom) { } alloc_str = xine_xmalloc(alloc_size); - xine_fast_memcpy(alloc_str, &data_atom[16], alloc_size-1); - alloc_str[alloc_size-1] = '\0'; + if (alloc_str) { + xine_fast_memcpy(alloc_str, &data_atom[16], alloc_size-1); + alloc_str[alloc_size-1] = '\0'; + } debug_meta_load("demux_qt: got a string of size %zd (%s)\n", alloc_size, alloc_str); @@ -954,8 +956,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt elst atom (edit list atom): %d entries\n", trak->edit_list_count); - trak->edit_list_table = (edit_list_table_t *)xine_xmalloc( - trak->edit_list_count * sizeof(edit_list_table_t)); + trak->edit_list_table = (edit_list_table_t *)calloc( + trak->edit_list_count, sizeof(edit_list_table_t)); if (!trak->edit_list_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1023,6 +1025,10 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].video.properties_atom_size = current_stsd_atom_size - 4; trak->stsd_atoms[k].video.properties_atom = xine_xmalloc(trak->stsd_atoms[k].video.properties_atom_size); + if (!trak->stsd_atoms[k].video.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].video.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].video.properties_atom_size); @@ -1162,6 +1168,10 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.properties_atom_size = current_stsd_atom_size - 4; trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].audio.properties_atom_size); @@ -1278,6 +1288,10 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.properties_atom_size = 36; trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos + 0x20], trak->stsd_atoms[k].audio.properties_atom_size); @@ -1299,6 +1313,10 @@ static qt_error parse_trak_atom (qt_trak *trak, (current_atom_size >= (0x4C + wave_size))) { trak->stsd_atoms[k].audio.wave_size = wave_size; trak->stsd_atoms[k].audio.wave = xine_xmalloc(wave_size); + if (!trak->stsd_atoms[k].audio.wave) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.wave, &trak_atom[atom_pos + 0x4C], wave_size); _x_waveformatex_le2me(trak->stsd_atoms[k].audio.wave); @@ -1368,8 +1386,16 @@ static qt_error parse_trak_atom (qt_trak *trak, j += mp4_read_descr_len( &trak_atom[j], &len ); debug_atom_load(" decoder config is %d (0x%X) bytes long\n", len, len); + if (len > current_atom_size - (j - i)) { + last_error = QT_NOT_A_VALID_FILE; + goto free_trak; + } trak->decoder_config = realloc(trak->decoder_config, len); trak->decoder_config_len = len; + if (!trak->decoder_config) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->decoder_config,&trak_atom[j],len); } } @@ -1399,8 +1425,8 @@ static qt_error parse_trak_atom (qt_trak *trak, /* allocate space and load table only if sample size is 0 */ if (trak->sample_size == 0) { - trak->sample_size_table = (unsigned int *)malloc( - trak->sample_size_count * sizeof(unsigned int)); + trak->sample_size_table = (unsigned int *)calloc( + trak->sample_size_count, sizeof(unsigned int)); if (!trak->sample_size_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1430,8 +1456,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stss atom (sample sync atom): %d sync samples\n", trak->sync_sample_count); - trak->sync_sample_table = (unsigned int *)malloc( - trak->sync_sample_count * sizeof(unsigned int)); + trak->sync_sample_table = (unsigned int *)calloc( + trak->sync_sample_count, sizeof(unsigned int)); if (!trak->sync_sample_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1614,6 +1640,9 @@ static qt_error parse_reference_atom (reference_t *ref, size_t string_size = _X_BE_32(&ref_atom[i + 12]); size_t url_offset = 0; + if (string_size >= current_atom_size || i + string_size >= ref_atom_size) + return QT_NOT_A_VALID_FILE; + /* if the URL starts with "http://", copy it */ if ( memcmp(&ref_atom[i + 16], "http://", 7) && memcmp(&ref_atom[i + 16], "rtsp://", 7) && @@ -2054,8 +2083,12 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, info->references = (reference_t *)realloc(info->references, info->reference_count * sizeof(reference_t)); - parse_reference_atom(&info->references[info->reference_count - 1], - &moov_atom[i - 4], info->base_mrl); + error = parse_reference_atom(&info->references[info->reference_count - 1], + &moov_atom[i - 4], info->base_mrl); + if (error != QT_OK) { + info->last_error = error; + return; + } break; default: diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index 41c6fb4a2..cc6a214e0 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -55,6 +55,8 @@ #include <xine/demux.h> #include "bswap.h" +#include "real_common.h" + #define FOURCC_TAG BE_FOURCC #define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') @@ -113,6 +115,12 @@ typedef struct { int index_entries; mdpr_t *mdpr; + int sps, cfs, w, h; + int block_align; + int frame_size; + uint8_t *frame_buffer; + uint32_t frame_num_bytes; + uint32_t sub_packet_cnt; } real_stream_t; typedef struct { @@ -168,14 +176,14 @@ typedef struct { demux_class_t demux_class; } demux_real_class_t; - static void real_parse_index(demux_real_t *this) { off_t next_index_chunk = this->index_start; off_t original_pos = this->input->get_current_pos(this->input); unsigned char index_chunk_header[INDEX_CHUNK_HEADER_SIZE]; unsigned char index_record[INDEX_RECORD_SIZE]; - int i, entries, stream_num; + int i; + unsigned int entries, stream_num; real_index_entry_t **index; while(next_index_chunk) { @@ -230,10 +238,11 @@ static void real_parse_index(demux_real_t *this) { } } - if(index && entries) { + if(index && entries) /* Allocate memory for index */ *index = xine_xcalloc(entries, sizeof(real_index_entry_t)); + if(index && entries && *index) { /* Read index */ for(i = 0; i < entries; i++) { if(this->input->read(this->input, index_record, INDEX_RECORD_SIZE) @@ -308,6 +317,64 @@ static void real_free_mdpr (mdpr_t *mdpr) { free (mdpr); } +static void real_parse_audio_specific_data (demux_real_t *this, + real_stream_t * stream, + uint8_t * data, int len) +{ + int coded_frame_size; + int codec_data_length; + int coded_frame_size2; + int subpacket_size; + + coded_frame_size = _X_BE_32 (data+24); + codec_data_length = _X_BE_16 (data+40); + coded_frame_size2 = _X_BE_16 (data+42); + subpacket_size = _X_BE_16 (data+44); + + stream->sps = subpacket_size; + stream->w = coded_frame_size2; + stream->h = codec_data_length; + stream->block_align = coded_frame_size2; + stream->cfs = coded_frame_size; + + switch (stream->buf_type) { + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + stream->block_align = subpacket_size; + break; + + case BUF_AUDIO_14_4: + break; + + case BUF_AUDIO_28_8: + stream->block_align = stream->cfs; + break; + + case BUF_AUDIO_SIPRO: + /* this->block_align = 19; */ + break; + + default: + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: error, i don't handle buf type 0x%08x\n", stream->buf_type); + } + + if (stream->sps) { + stream->frame_size = stream->w / stream->sps * stream->h * stream->sps; + stream->frame_buffer = xine_xmalloc (stream->frame_size); + stream->frame_num_bytes = 0; + } else { + stream->frame_size = stream->w * stream->h; + stream->frame_buffer = xine_xmalloc (stream->frame_size); + stream->frame_num_bytes = 0; + } + stream->sub_packet_cnt = 0; + + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: buf type 0x%08x frame size %dblock align %d\n", stream->buf_type, + stream->frame_size, stream->block_align); + +} static void real_parse_headers (demux_real_t *this) { @@ -418,8 +485,16 @@ static void real_parse_headers (demux_real_t *this) { mdpr = real_parse_mdpr (chunk_buffer); lprintf ("parsing type specific data...\n"); + if(!strcmp(mdpr->mime_type, "audio/X-MP3-draft-00")) { + lprintf ("mpeg layer 3 audio detected...\n"); - if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { + fourcc = ME_FOURCC('a', 'd', 'u', 0x55); + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; + this->num_audio_streams++; + } else if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { int version, len; if(this->num_audio_streams == MAX_AUDIO_STREAMS) { @@ -457,6 +532,10 @@ static void real_parse_headers (demux_real_t *this) { this->audio_streams[this->num_audio_streams].index = NULL; this->audio_streams[this->num_audio_streams].mdpr = mdpr; + real_parse_audio_specific_data (this, + &this->audio_streams[this->num_audio_streams], + mdpr->type_specific_data, + mdpr->type_specific_len); this->num_audio_streams++; if (!this->audio_streams[this->num_audio_streams].buf_type) @@ -745,6 +824,13 @@ unknown: memcpy(buf->content, mdpr->type_specific_data + 79, buf->decoder_info[2]); + } else if(buf->type == BUF_AUDIO_MP3ADU) { + buf->decoder_flags |= BUF_FLAG_STDHEADER | BUF_FLAG_FRAME_END; + buf->size = 0; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = 0; + buf->decoder_info[2] = 0; + buf->decoder_info[3] = 0; } else { memcpy(buf->content, mdpr->type_specific_data, mdpr->type_specific_len); @@ -983,6 +1069,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { off_t offset, input_length = 0; int normpos = 0; + read_next_packet: if(this->reference_mode) return demux_real_parse_references(this); @@ -1320,6 +1407,64 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { } free(sizes); + } else if (this->audio_stream->buf_type == BUF_AUDIO_COOK || + this->audio_stream->buf_type == BUF_AUDIO_ATRK || + this->audio_stream->buf_type == BUF_AUDIO_28_8 || + this->audio_stream->buf_type == BUF_AUDIO_SIPRO) { + /* reorder */ + uint8_t * buffer = this->audio_stream->frame_buffer; + int sps = this->audio_stream->sps; + int sph = this->audio_stream->h; + int cfs = this->audio_stream->cfs; + int w = this->audio_stream->w; + int spc = this->audio_stream->sub_packet_cnt; + int x, pos; + + switch (this->audio_stream->buf_type) { + case BUF_AUDIO_28_8: + for (x = 0; x < sph / 2; x++) { + pos = x * 2 * w + spc * cfs; + if(this->input->read(this->input, buffer + pos, cfs) < cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + for (x = 0; x < w / sps; x++) { + pos = sps * (sph * x + ((sph + 1) / 2) * (spc & 1) + (spc >> 1)); + if(this->input->read(this->input, buffer + pos, sps) < sps) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_SIPRO: + pos = spc * w; + if(this->input->read(this->input, buffer + pos, w) < w) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + if (spc == sph - 1) + demux_real_sipro_swap (buffer, sph * w * 2 / 96); + break; + } + if(++this->audio_stream->sub_packet_cnt == sph) { + this->audio_stream->sub_packet_cnt = 0; + _x_demux_send_data(this->audio_fifo, buffer, this->audio_stream->frame_size, + pts, this->audio_stream->buf_type, 0, normpos, input_time, + this->duration, 0); + } } else { if(_x_demux_read_send_data(this->audio_fifo, this->input, size, pts, this->audio_stream->buf_type, 0, normpos, @@ -1469,6 +1614,9 @@ static int demux_real_seek (demux_plugin_t *this_gen, this->input->seek(this->input, index[i].offset, SEEK_SET); if(playing) { + if(this->audio_stream) + this->audio_stream->sub_packet_cnt = 0; + this->buf_flag_seek = 1; _x_demux_flush_engine(this->stream); } @@ -1505,6 +1653,7 @@ static void demux_real_dispose (demux_plugin_t *this_gen) { for(i = 0; i < this->num_audio_streams; i++) { real_free_mdpr(this->audio_streams[i].mdpr); free(this->audio_streams[i].index); + free(this->audio_streams[i].frame_buffer); } free(this->fragment_tab); diff --git a/src/demuxers/demux_realaudio.c b/src/demuxers/demux_realaudio.c index 732ddfcc4..2873a522e 100644 --- a/src/demuxers/demux_realaudio.c +++ b/src/demuxers/demux_realaudio.c @@ -41,6 +41,8 @@ #include "bswap.h" #include "group_audio.h" +#include "real_common.h" + #define RA_FILE_HEADER_PREV_SIZE 22 typedef struct { @@ -62,6 +64,10 @@ typedef struct { off_t data_start; off_t data_size; + int sps, cfs, w, h; + int frame_size; + uint8_t *frame_buffer; + unsigned char *header; unsigned int header_size; } demux_ra_t; @@ -70,6 +76,9 @@ typedef struct { demux_class_t demux_class; } demux_ra_class_t; +/* Map flavour to bytes per second */ +static int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second + /* returns 1 if the RealAudio file was opened successfully, 0 otherwise */ static int open_ra_file(demux_ra_t *this) { unsigned char file_header[RA_FILE_HEADER_PREV_SIZE], len; @@ -103,7 +112,7 @@ static int open_ra_file(demux_ra_t *this) { /* allocate for and read header data */ this->header = xine_xmalloc(this->header_size); - if (_x_demux_read_header(this->input, this->header, this->header_size) != this->header_size) { + if (!this->header || _x_demux_read_header(this->input, this->header, this->header_size) != this->header_size) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: unable to read header\n"); free(this->header); return 0; @@ -165,20 +174,41 @@ static int open_ra_file(demux_ra_t *this) { offset++; /* Fourcc for version 3 comes after meta info */ - if((version == 3) && ((offset+7) <= this->header_size)) { - if(this->header[offset+2] == 4) - this->fourcc = _X_ME_32(&this->header[offset+3]); - else { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); - free(this->header); - return 0; + if(version == 3) { + if (((offset+7) <= this->header_size)) { + if(this->header[offset+2] == 4) + this->fourcc = _X_ME_32(&this->header[offset+3]); + else { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); + free(this->header); + return 0; + } + } else { + this->fourcc = ME_FOURCC('l', 'p', 'c', 'J'); } } _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, this->fourcc); this->audio_type = _x_formattag_to_buf_audio(this->fourcc); + if (version == 4) { + this->sps = _X_BE_16 (this->header+44); + this->w = _X_BE_16 (this->header+42); + this->h = _X_BE_16 (this->header+40); + this->cfs = _X_BE_32 (this->header+24); + if (this->sps) { + this->frame_size = this->sps * this->h * this->sps; + this->frame_buffer = xine_xmalloc (this->frame_size); + } else { + this->frame_size = this->w * this->h; + this->frame_buffer = xine_xmalloc (this->frame_size); + } + + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) + this->block_align = this->cfs; + } + /* seek to start of data */ this->data_start = this->header_size; if (this->input->seek(this->input, this->data_start, SEEK_SET) != @@ -212,7 +242,45 @@ static int demux_ra_send_chunk(demux_plugin_t *this_gen) { this->seek_flag = 0; } - if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) { + int x; + uint8_t * buffer; + + buffer = this->frame_buffer; + if (this->audio_type == BUF_AUDIO_SIPRO) { + int n; + int len = this->h * this->w; + if(this->input->read(this->input, this->frame_buffer, len) < len) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + demux_real_sipro_swap (this->frame_buffer, len * 2 / 96); + } else { + int x, y; + int pos; + + for (y = 0; y < this->h; y++) + for (x = 0; x < this->h / 2; x++) { + pos = x * 2 * this->w + y * this->cfs; + if(this->input->read(this->input, this->frame_buffer + pos, + this->cfs) < this->cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + } + + _x_demux_send_data(this->audio_fifo, + buffer, this->frame_size, + current_pts, this->audio_type, 0, + current_normpos, current_pts / 90, 0, 0); + } else if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, current_pts, this->audio_type, 0, current_normpos, current_pts / 90, 0, 0) < 0) { this->status = DEMUX_FINISHED; @@ -298,6 +366,7 @@ static void demux_ra_dispose (demux_plugin_t *this_gen) { demux_ra_t *this = (demux_ra_t *) this_gen; free(this->header); + free(this->frame_buffer); free(this); } @@ -329,6 +398,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this = xine_xmalloc (sizeof (demux_ra_t)); this->stream = stream; this->input = input; + this->frame_buffer = NULL; this->demux_plugin.send_headers = demux_ra_send_headers; this->demux_plugin.send_chunk = demux_ra_send_chunk; diff --git a/src/demuxers/demux_vmd.c b/src/demuxers/demux_vmd.c index c2902eac1..d1d98f534 100644 --- a/src/demuxers/demux_vmd.c +++ b/src/demuxers/demux_vmd.c @@ -168,7 +168,7 @@ static int open_vmd_file(demux_vmd_t *this) { return 0; } - this->frame_table = xine_xmalloc(this->frame_count * sizeof(vmd_frame_t)); + this->frame_table = calloc(this->frame_count, sizeof(vmd_frame_t)); current_offset = this->data_start = _X_LE_32(&vmd_header[20]); this->data_size = toc_offset - this->data_start; diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c index b8f0d0194..2beb43291 100644 --- a/src/demuxers/demux_wav.c +++ b/src/demuxers/demux_wav.c @@ -41,9 +41,11 @@ #include "bswap.h" #include "group_audio.h" -#define WAV_SIGNATURE_SIZE 16 +#define WAV_SIGNATURE_SIZE 12 /* this is the hex value for 'data' */ #define data_TAG 0x61746164 +/* this is the hex value for 'fmt ' */ +#define fmt_TAG 0x20746D66 #define PCM_BLOCK_ALIGN 1024 #define PREFERED_BLOCK_SIZE 4096 @@ -73,31 +75,63 @@ typedef struct { static int demux_wav_get_stream_length (demux_plugin_t *this_gen); +/* searches for the chunk with the given tag from the beginning of WAV file + * returns 1 if chunk was found, 0 otherwise, + * fills chunk_size and chunk_pos if chunk was found + * NOTE: chunk_pos is set to the position of the first byte of chunk data */ +static int find_chunk_by_tag(demux_wav_t *this, const uint32_t given_chunk_tag, + uint32_t *found_chunk_size, off_t *found_chunk_pos) { + uint32_t chunk_tag; + uint32_t chunk_size; + uint8_t chunk_preamble[8]; + + /* search for the chunks from the start of the WAV file */ + this->input->seek(this->input, WAV_SIGNATURE_SIZE, SEEK_SET); + + while (1) { + if (this->input->read(this->input, chunk_preamble, 8) != 8) { + return 0; + } + + chunk_tag = _X_LE_32(&chunk_preamble[0]); + chunk_size = _X_LE_32(&chunk_preamble[4]); + + if (chunk_tag == given_chunk_tag) { + if (found_chunk_size) + *found_chunk_size = _X_LE_32(&chunk_preamble[4]); + if (found_chunk_pos) + *found_chunk_pos = this->input->get_current_pos(this->input); + return 1; + } else { + this->input->seek(this->input, chunk_size, SEEK_CUR); + } + } +} + /* returns 1 if the WAV file was opened successfully, 0 otherwise */ static int open_wav_file(demux_wav_t *this) { uint8_t signature[WAV_SIGNATURE_SIZE]; uint32_t chunk_tag; uint32_t chunk_size; uint8_t chunk_preamble[8]; + off_t wave_pos; /* check the signature */ if (_x_demux_read_header(this->input, signature, WAV_SIGNATURE_SIZE) != WAV_SIGNATURE_SIZE) return 0; - if (memcmp(signature, "RIFF", 4) || memcmp(&signature[8], "WAVEfmt ", 8) ) + if (memcmp(signature, "RIFF", 4) || memcmp(&signature[8], "WAVE", 4) ) return 0; - /* file is qualified; skip over the header bytes in the stream */ - this->input->seek(this->input, WAV_SIGNATURE_SIZE, SEEK_SET); - - /* go after the format structure */ - if (this->input->read(this->input, - (unsigned char *)&this->wave_size, 4) != 4) + /* search for the 'fmt ' chunk first */ + wave_pos = 0; + if (find_chunk_by_tag(this, fmt_TAG, &this->wave_size, &wave_pos)==0) return 0; - this->wave_size = le2me_32(this->wave_size); + + this->input->seek(this->input, wave_pos, SEEK_SET); this->wave = xine_xmalloc( this->wave_size ); - - if (this->input->read(this->input, (void *)this->wave, this->wave_size) != + + if (!this->wave || this->input->read(this->input, (void *)this->wave, this->wave_size) != this->wave_size) { free (this->wave); return 0; @@ -113,28 +147,21 @@ static int open_wav_file(demux_wav_t *this) { return 0; } - /* traverse through the chunks to find the 'data' chunk */ + /* search for the 'data' chunk */ this->data_start = this->data_size = 0; - while (this->data_start == 0) { - - if (this->input->read(this->input, chunk_preamble, 8) != 8) { - free (this->wave); - return 0; - } - chunk_tag = _X_LE_32(&chunk_preamble[0]); - chunk_size = _X_LE_32(&chunk_preamble[4]); - - if (chunk_tag == data_TAG) { - this->data_start = this->input->get_current_pos(this->input); - /* Get the data length from the file itself, instead of the data - * TAG, for broken files */ - this->data_size = this->input->get_length(this->input); - } else { - this->input->seek(this->input, chunk_size, SEEK_CUR); - } + if (find_chunk_by_tag(this, data_TAG, &this->data_size, &this->data_start)==0) + { + free (this->wave); + return 0; + } + else + { + /* Get the data length from the file itself, instead of the data + * TAG, for broken files */ + this->input->seek(this->input, this->data_start, SEEK_SET); + this->data_size = this->input->get_length(this->input); + return 1; } - - return 1; } static int demux_wav_send_chunk(demux_plugin_t *this_gen) { diff --git a/src/demuxers/demux_wc3movie.c b/src/demuxers/demux_wc3movie.c index bb9a40306..5be59b12b 100644 --- a/src/demuxers/demux_wc3movie.c +++ b/src/demuxers/demux_wc3movie.c @@ -387,6 +387,12 @@ static int open_mve_file(demux_mve_t *this) { /* load the palette chunks */ this->palettes = xine_xcalloc(this->number_of_shots, PALETTE_SIZE * sizeof(palette_entry_t)); + + if (!this->shot_offsets || !this->palettes) { + free (this->shot_offsets); + return 0; + } + for (i = 0; i < this->number_of_shots; i++) { /* make sure there was a valid palette chunk preamble */ if (this->input->read(this->input, preamble, PREAMBLE_SIZE) != @@ -458,8 +464,9 @@ static int open_mve_file(demux_mve_t *this) { case BNAM_TAG: /* load the name into the stream attributes */ - title = realloc (title, chunk_size); - if (this->input->read(this->input, title, chunk_size) != chunk_size) { + free (title); + title = malloc (chunk_size); + if (!title || this->input->read(this->input, title, chunk_size) != chunk_size) { free (title); free (this->palettes); free (this->shot_offsets); diff --git a/src/demuxers/ebml.c b/src/demuxers/ebml.c index 41a91371e..1e9a456d2 100644 --- a/src/demuxers/ebml.c +++ b/src/demuxers/ebml.c @@ -310,7 +310,25 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { return ebml_read_ascii (ebml, elem, str); } +#endif + +char *ebml_alloc_read_ascii (ebml_parser_t *ebml, ebml_elem_t *elem) +{ + char *text; + if (elem->len >= 4096) + return NULL; + text = malloc(elem->len + 1); + if (text) + { + text[elem->len] = '\0'; + if (ebml_read_ascii (ebml, elem, text)) + return text; + free (text); + } + return NULL; +} +#if 0 int ebml_read_date (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date) { return ebml_read_sint (ebml, elem, date); } @@ -414,10 +432,8 @@ int ebml_check_header(ebml_parser_t *ebml) { } case EBML_ID_DOCTYPE: { - char *text = malloc(elem.len + 1); - - text[elem.len] = '\0'; - if (!ebml_read_ascii (ebml, &elem, text)) + char *text = ebml_alloc_read_ascii (ebml, &elem); + if (!text) return 0; lprintf("doctype: %s\n", text); diff --git a/src/demuxers/ebml.h b/src/demuxers/ebml.h index 31d825e35..a090bb130 100644 --- a/src/demuxers/ebml.h +++ b/src/demuxers/ebml.h @@ -93,7 +93,11 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); #if 0 int ebml_read_utf8(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); +#endif + +char *ebml_alloc_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem); +#if 0 int ebml_read_date(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date); #endif diff --git a/src/demuxers/real_common.h b/src/demuxers/real_common.h new file mode 100644 index 000000000..4945a65ff --- /dev/null +++ b/src/demuxers/real_common.h @@ -0,0 +1,56 @@ +/* + * 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 + */ + +static inline void demux_real_sipro_swap (char buffer[], int bs) +{ + /* bs = nybbles per subpacket */ + static const unsigned char sipr_swaps[38][2] = { + {0, 63}, {1, 22}, {2, 44}, {3, 90}, {5, 81}, {7, 31}, {8, 86}, {9, 58}, + {10, 36}, {12, 68}, {13, 39}, {14, 73}, {15, 53}, {16, 69}, {17, 57}, + {19, 88}, {20, 34}, {21, 71}, {24, 46}, {25, 94}, {26, 54}, {28, 75}, + {29, 50}, {32, 70}, {33, 92}, {35, 74}, {38, 85}, {40, 56}, {42, 87}, + {43, 65}, {45, 59}, {48, 79}, {49, 93}, {51, 89}, {55, 95}, {61, 76}, + {67, 83}, {77, 80} + }; + int n; + + for (n = 0; n < 38; ++n) + { + int j; + int i = bs * sipr_swaps[n][0]; + int o = bs * sipr_swaps[n][1]; + /* swap nibbles of block 'i' with 'o' TODO: optimize */ + for (j = 0; j < bs; ++j) + { + int x = (i & 1) ? (buffer[i >> 1] >> 4) : (buffer[i >> 1] & 0x0F); + int y = (o & 1) ? (buffer[o >> 1] >> 4) : (buffer[o >> 1] & 0x0F); + if (o & 1) + buffer[o >> 1] = (buffer[o >> 1] & 0x0F) | (x << 4); + else + buffer[o >> 1] = (buffer[o >> 1] & 0xF0) | x; + if (i & 1) + buffer[i >> 1] = (buffer[i >> 1] & 0x0F) | (y << 4); + else + buffer[i >> 1] = (buffer[i >> 1] & 0xF0) | y; + ++i; + ++o; + } + } +} diff --git a/src/input/libdvdnav/dvd_reader.c b/src/input/libdvdnav/dvd_reader.c index c15a5c3f5..4144b9133 100644 --- a/src/input/libdvdnav/dvd_reader.c +++ b/src/input/libdvdnav/dvd_reader.c @@ -1037,6 +1037,28 @@ int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset ) return offset; } +int32_t DVDFileSeekForce( dvd_file_t *dvd_file, int offset, int force_size ) +{ + /* Check arguments. */ + if( dvd_file == NULL || offset < 0 ) + return -1; + + if( dvd_file->dvd->isImageFile ) { + if( force_size < 0 ) + force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1; + if( dvd_file->filesize < force_size) { + dvd_file->filesize = force_size; + fprintf(stderr, "libdvdread: Ignored UDF provided size of file.\n"); + } + } + + if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { + return -1; + } + dvd_file->seek_pos = (uint32_t) offset; + return offset; +} + ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) { unsigned char *secbuf_base, *secbuf; @@ -1077,7 +1099,7 @@ ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) memcpy( data, &(secbuf[ seek_byte ]), byte_size ); free( secbuf_base ); - dvd_file->seek_pos += byte_size; + DVDFileSeekForce(dvd_file, dvd_file->seek_pos + byte_size, -1); return byte_size; } diff --git a/src/input/libdvdnav/dvd_reader.h b/src/input/libdvdnav/dvd_reader.h index bb3f5053b..e1b051c00 100644 --- a/src/input/libdvdnav/dvd_reader.h +++ b/src/input/libdvdnav/dvd_reader.h @@ -171,6 +171,8 @@ ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * ); */ int32_t DVDFileSeek( dvd_file_t *, int32_t ); +int32_t DVDFileSeekForce( dvd_file_t *, int, int ); + /** * Reads the given number of bytes from the file. This call can only be used * on the information files, and may not be used for reading from a VOB. This diff --git a/src/input/libdvdnav/ifo_read.c b/src/input/libdvdnav/ifo_read.c index 8f47d2a54..bc1ba580b 100644 --- a/src/input/libdvdnav/ifo_read.c +++ b/src/input/libdvdnav/ifo_read.c @@ -93,6 +93,10 @@ static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { return (DVDFileSeek(dvd_file, (int)offset) == (int)offset); } +static inline int32_t DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) { + return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset); +} + ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) { ifo_handle_t *ifofile; @@ -1507,7 +1511,7 @@ static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile, unsigned int i; int info_length; - if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) + if(!DVDFileSeekForce_(ifofile->file, sector * DVD_BLOCK_LEN, sector)) return 0; if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE))) diff --git a/src/input/libreal/sdpplin.c b/src/input/libreal/sdpplin.c index fbc64957b..4ef8f5f03 100644 --- a/src/input/libreal/sdpplin.c +++ b/src/input/libreal/sdpplin.c @@ -84,7 +84,14 @@ static sdpplin_stream_t *sdpplin_parse_stream(char **data) { handled=0; if(filter(*data,"a=control:streamid=",&buf)) { - desc->stream_id=atoi(buf); + /* This way negative values are mapped to unfeasibly high + * values, and will be discarded afterward + */ + unsigned long tmp = strtoul(buf, NULL, 10); + if ( tmp > UINT16_MAX ) + lprintf("stream id out of bound: %lu\n", tmp); + else + desc->stream_id=tmp; handled=1; *data=nl(*data); } @@ -192,7 +199,10 @@ sdpplin_t *sdpplin_parse(char *data) { } stream=sdpplin_parse_stream(&data); lprintf("got data for stream id %u\n", stream->stream_id); - desc->stream[stream->stream_id]=stream; + if ( stream->stream_id >= desc->stream_count ) + lprintf("stream id %u is greater than stream count %u\n", stream->stream_id, desc->stream_count); + else + desc->stream[stream->stream_id]=stream; continue; } @@ -233,7 +243,14 @@ sdpplin_t *sdpplin_parse(char *data) { } if(filter(data,"a=StreamCount:integer;",&buf)) { - desc->stream_count=atoi(buf); + /* This way negative values are mapped to unfeasibly high + * values, and will be discarded afterward + */ + unsigned long tmp = strtoul(buf, NULL, 10); + if ( tmp > UINT16_MAX ) + lprintf("stream count out of bound: %lu\n", tmp); + else + desc->stream_count = tmp; desc->stream = calloc(desc->stream_count, sizeof(sdpplin_stream_t*)); handled=1; data=nl(data); diff --git a/src/input/libreal/sdpplin.h b/src/input/libreal/sdpplin.h index cb3b434d4..72cbaf731 100644 --- a/src/input/libreal/sdpplin.h +++ b/src/input/libreal/sdpplin.h @@ -37,7 +37,7 @@ typedef struct { char *id; char *bandwidth; - int stream_id; + uint16_t stream_id; char *range; char *length; char *rtpmap; @@ -81,7 +81,7 @@ typedef struct { int flags; int is_real_data_type; - int stream_count; + uint16_t stream_count; char *title; char *author; char *copyright; diff --git a/src/libreal/xine_real_audio_decoder.c b/src/libreal/xine_real_audio_decoder.c index b9231a2b7..a12518c1e 100644 --- a/src/libreal/xine_real_audio_decoder.c +++ b/src/libreal/xine_real_audio_decoder.c @@ -51,6 +51,8 @@ typedef struct { /* empty so far */ } real_class_t; +typedef void * ra_codec_t; + typedef struct realdec_decoder_s { audio_decoder_t audio_decoder; @@ -60,18 +62,18 @@ typedef struct realdec_decoder_s { void *ra_handle; - unsigned long (*raCloseCodec)(void*); - unsigned long (*raDecode)(void*, char*,unsigned long,char*,unsigned int*,long); - unsigned long (*raFlush)(unsigned long,unsigned long,unsigned long); - unsigned long (*raFreeDecoder)(void*); - void* (*raGetFlavorProperty)(void*,unsigned long,unsigned long,int*); - unsigned long (*raInitDecoder)(void*, void*); - unsigned long (*raOpenCodec2)(void*); - unsigned long (*raSetFlavor)(void*,unsigned long); - void (*raSetDLLAccessPath)(char*); - void (*raSetPwd)(char*,char*); + uint32_t (*raCloseCodec)(ra_codec_t); + uint32_t (*raDecode)(ra_codec_t, char *, uint32_t, char *, uint32_t *, uint32_t); + uint32_t (*raFlush)(ra_codec_t, char *, uint32_t *); + uint32_t (*raFreeDecoder)(ra_codec_t); + void * (*raGetFlavorProperty)(ra_codec_t, uint16_t, uint16_t, uint16_t *); + uint32_t (*raInitDecoder)(ra_codec_t, void *); + uint32_t (*raOpenCodec2)(ra_codec_t *, const char *); + uint32_t (*raSetFlavor)(ra_codec_t, uint16_t); + void (*raSetDLLAccessPath)(char *); + void (*raSetPwd)(ra_codec_t, char *); - void *context; + ra_codec_t context; int sps, w, h; int block_align; @@ -92,14 +94,14 @@ typedef struct realdec_decoder_s { } realdec_decoder_t; typedef struct { - int samplerate; - short bits; - short channels; - int unk1; - int subpacket_size; - int coded_frame_size; - int codec_data_length; - void *extras; + uint32_t samplerate; + uint16_t bits; + uint16_t channels; + uint16_t quality; + uint32_t subpacket_size; + uint32_t coded_frame_size; + uint32_t codec_data_length; + void *extras; } ra_init_t; static int load_syms_linux (realdec_decoder_t *this, const char *const codec_name, const char *const codec_alternate) { @@ -216,13 +218,14 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "Cook"); if (!load_syms_linux (this, "cook.so", "cook.so.6.0")) return 0; + this->block_align = subpacket_size; break; case BUF_AUDIO_ATRK: _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "Atrac"); if (!load_syms_linux (this, "atrc.so", "atrc.so.6.0")) return 0; - this->block_align = 384; + this->block_align = subpacket_size; break; case BUF_AUDIO_14_4: @@ -254,7 +257,7 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { * init codec */ - result = this->raOpenCodec2 (&this->context); + result = this->raOpenCodec2 (&this->context, NULL); if (result) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libareal: error in raOpenCodec2: %d\n", result); return 0; @@ -266,7 +269,7 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { init_data.samplerate = samples_per_sec; init_data.bits = bits_per_sample; init_data.channels = num_channels; - init_data.unk1 = 100; /* ??? */ + init_data.quality = 100; /* ??? */ init_data.subpacket_size = subpacket_size; /* subpacket size */ init_data.coded_frame_size = coded_frame_size; /* coded frame size */ init_data.codec_data_length = data_len; /* codec data length */ @@ -350,13 +353,6 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { return 1; } -static const unsigned char sipr_swaps[38][2]={ - {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68}, - {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46}, - {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56}, - {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83}, - {77,80} }; - static void realdec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { realdec_decoder_t *this = (realdec_decoder_t *) this_gen; @@ -383,116 +379,32 @@ static void realdec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->pts = buf->pts; size = buf->size; - while (size) { + int need; - int needed; - - needed = this->frame_size - this->frame_num_bytes; - - if (needed>size) { - - memcpy (this->frame_buffer+this->frame_num_bytes, buf->content, size); + need = this->frame_size - this->frame_num_bytes; + if (size < need) { + memcpy (this->frame_buffer + this->frame_num_bytes, + buf->content + buf->size - size, size); this->frame_num_bytes += size; - - lprintf ("buffering %d/%d bytes\n", this->frame_num_bytes, this->frame_size); - size = 0; - } else { - - int result; - int len =-1; - int n; - int sps = this->sps; - int w = this->w; - int h = this->h; audio_buffer_t *audio_buffer; + int n, len; + int result; - lprintf ("buffering %d bytes\n", needed); - - memcpy (this->frame_buffer+this->frame_num_bytes, buf->content, needed); - - size -= needed; + memcpy (this->frame_buffer + this->frame_num_bytes, + buf->content + buf->size - size, need); + size -= need; this->frame_num_bytes = 0; - lprintf ("frame completed. reordering...\n"); - lprintf ("bs=%d sps=%d w=%d h=%d \n",/*sh->wf->nBlockAlign*/-1,sps,w,h); - - if (!sps) { - - int j,n; - int bs=h*w*2/96; /* nibbles per subpacket */ - unsigned char *p=this->frame_buffer; - - /* 'sipr' way */ - /* demux_read_data(sh->ds, p, h*w); */ - for (n=0;n<38;n++){ - int i=bs*sipr_swaps[n][0]; - int o=bs*sipr_swaps[n][1]; - /* swap nibbles of block 'i' with 'o' TODO: optimize */ - for (j=0;j<bs;j++) { - int x=(i&1) ? (p[(i>>1)]>>4) : (p[(i>>1)]&15); - int y=(o&1) ? (p[(o>>1)]>>4) : (p[(o>>1)]&15); - if (o&1) - p[(o>>1)]=(p[(o>>1)]&0x0F)|(x<<4); - else - p[(o>>1)]=(p[(o>>1)]&0xF0)|x; - - if (i&1) - p[(i>>1)]=(p[(i>>1)]&0x0F)|(y<<4); - else - p[(i>>1)]=(p[(i>>1)]&0xF0)|y; - - ++i; - ++o; - } - } - /* - sh->a_in_buffer_size= - sh->a_in_buffer_len=w*h; - */ - - } else { - int x, y; - uint8_t *s; - - /* 'cook' way */ - - w /= sps; s = this->frame_buffer; - - for (y=0; y<h; y++) - - for (x=0; x<w; x++) { - - lprintf ("x=%d, y=%d, off %d\n", - x, y, sps*(h*x+((h+1)/2)*(y&1)+(y>>1))); - - memcpy (this->frame_reordered+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), - s, sps); - s+=sps; - - /* demux_read_data(sh->ds, sh->a_in_buffer+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), - sps); */ - - } - /* - sh->a_in_buffer_size= - sh->a_in_buffer_len=w*h*sps; - */ - } - -#ifdef LOG - xine_hexdump (this->frame_reordered, buf->size); -#endif - n = 0; - while (n<this->frame_size) { + while (n < this->frame_size) { audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); result = this->raDecode (this->context, - this->frame_reordered+n, + this->frame_buffer + n, this->block_align, (char *) audio_buffer->mem, &len, -1); @@ -506,7 +418,7 @@ static void realdec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - n+=this->block_align; + n += this->block_align; } } } @@ -609,5 +521,5 @@ static const uint32_t audio_types[] = { const decoder_info_t dec_info_realaudio = { audio_types, /* supported types */ - 7 /* priority */ + 6 /* priority */ }; diff --git a/src/libreal/xine_real_video_decoder.c b/src/libreal/xine_real_video_decoder.c index 28fddafda..2b5eafa16 100644 --- a/src/libreal/xine_real_video_decoder.c +++ b/src/libreal/xine_real_video_decoder.c @@ -63,9 +63,9 @@ typedef struct realdec_decoder_s { uint32_t (*rvyuv_custom_message)(void*, void*); uint32_t (*rvyuv_free)(void*); - uint32_t (*rvyuv_hive_message)(uint32_t, uint32_t); + uint32_t (*rvyuv_hive_message)(uint32_t, void*); uint32_t (*rvyuv_init)(void*, void*); /* initdata,context */ - uint32_t (*rvyuv_transform)(char*, char*, void*, uint32_t*,void*); + uint32_t (*rvyuv_transform)(char*, char*, void*, void*, void*); void *context; @@ -113,13 +113,21 @@ typedef struct cmsg_data_s { typedef struct transform_in_s { uint32_t len; - uint32_t unknown1; - uint32_t chunks; - uint32_t* extra; - uint32_t unknown2; + uint32_t interpolate; + uint32_t nsegments; + void *segments; + uint32_t flags; uint32_t timestamp; } transform_in_t; +typedef struct { + uint32_t frames; + uint32_t notes; + uint32_t timestamp; + uint32_t width; + uint32_t height; +} transform_out_t; + /* * real codec loader */ @@ -169,7 +177,6 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { int result; rv_init_t init_data = {11, 0, 0, 0, 0, 0, 1, 0}; /* rv30 */ - switch (buf->type) { case BUF_VIDEO_RV20: _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Real Video 2.0"); @@ -258,7 +265,7 @@ static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { #ifdef LOG printf ("libreal: CustomMessage cmsg_data:\n"); - xine_hexdump ((uint8_t *) cmsg_data, sizeof (cmsg_data)); + xine_hexdump ((uint8_t *) &cmsg_data, sizeof (cmsg_data)); printf ("libreal: cmsg24:\n"); xine_hexdump ((uint8_t *) cmsg24, (buf->size - 34 + 2) * sizeof(uint32_t)); #endif @@ -342,7 +349,7 @@ static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) int result; vo_frame_t *img; - uint32_t transform_out[5]; + transform_out_t transform_out; transform_in_t transform_in = { this->chunk_buffer_size, /* length of the packet (sub-packets appended) */ @@ -369,7 +376,7 @@ static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) xine_hexdump (this->chunk_buffer, this->chunk_buffer_size); printf ("libreal: transform_in:\n"); - xine_hexdump ((uint8_t *) transform_in, 6 * 4); + xine_hexdump ((uint8_t *) &transform_in, sizeof(rv_xform_in_t)); printf ("libreal: chunk_table:\n"); xine_hexdump ((uint8_t *) buf->decoder_info_ptr[2], @@ -379,21 +386,21 @@ static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) result = this->rvyuv_transform (this->chunk_buffer, this->frame_buffer, &transform_in, - transform_out, + &transform_out, this->context); lprintf ("transform result: %08x\n", result); lprintf ("transform_out:\n"); - #ifdef LOG - xine_hexdump ((uint8_t *) transform_out, 5 * 4); - #endif +#ifdef LOG + xine_hexdump ((uint8_t *) &transform_out, 5 * 4); +#endif /* Sometimes the stream contains video of a different size * to that specified in the realmedia header */ - if(transform_out[0] && ((transform_out[3] != this->width) || - (transform_out[4] != this->height))) { - this->width = transform_out[3]; - this->height = transform_out[4]; + if(transform_out.frames && ((transform_out.width != this->width) || + (transform_out.height != this->height))) { + this->width = transform_out.width; + this->height = transform_out.height; this->frame_size = this->width * this->height; @@ -531,8 +538,7 @@ void *init_realvdec (xine_t *xine, void *data) { * exported plugin catalog entry */ -static const uint32_t supported_types[] = { BUF_VIDEO_RV20, - BUF_VIDEO_RV30, +static const uint32_t supported_types[] = { BUF_VIDEO_RV30, BUF_VIDEO_RV40, 0 }; diff --git a/src/vdr/input_vdr.c b/src/vdr/input_vdr.c index 154bb9b56..ade2ecfa1 100644 --- a/src/vdr/input_vdr.c +++ b/src/vdr/input_vdr.c @@ -61,8 +61,19 @@ */ +typedef struct vdr_input_plugin_s vdr_input_plugin_t; + typedef struct { + metronom_t metronom; + metronom_t *stream_metronom; + vdr_input_plugin_t *input; +} +vdr_metronom_t; + + +struct vdr_input_plugin_s +{ input_plugin_t input_plugin; xine_stream_t *stream; @@ -111,9 +122,12 @@ typedef struct uint16_t image16_9_zoom_x; uint16_t image16_9_zoom_y; -} -vdr_input_plugin_t; + uint8_t find_sync_point; + pthread_mutex_t find_sync_point_lock; + vdr_metronom_t metronom; + int last_disc_type; +}; typedef struct @@ -581,7 +595,13 @@ static off_t vdr_execute_rpc_command(vdr_input_plugin_t *this) int orig_speed = xine_get_param(this->stream, XINE_PARAM_FINE_SPEED); if (orig_speed <= 0) xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL); -fprintf(stderr, "+++ CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); +fprintf(stderr, "+++ CLEAR(%d%c): sync point: %02x\n", data->n, data->s ? 'b' : 'a', data->i); + if (!data->s) + { + pthread_mutex_lock(&this->find_sync_point_lock); + this->find_sync_point = data->i; + pthread_mutex_unlock(&this->find_sync_point_lock); + } /* if (!this->dont_change_xine_volume) xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, 0); @@ -952,33 +972,9 @@ fprintf(stderr, "ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß\n"); int height = 0; int ratio_code = 0; int format = 0; - - int orig_speed = xine_get_param(this->stream, XINE_PARAM_FINE_SPEED); - if (XINE_SPEED_PAUSE != orig_speed) - xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_SPEED_PAUSE); - - if (xine_get_current_frame(this->stream, &width, &height, &ratio_code, &format, 0)) + + if (xine_get_current_frame_alloc(this->stream, &width, &height, &ratio_code, &format, &img, &frame_size)) { - switch (format) - { - case XINE_IMGFMT_YV12: - frame_size = width * height - + ((width + 1) / 2) * ((height + 1) / 2) - + ((width + 1) / 2) * ((height + 1) / 2); - break; - - case XINE_IMGFMT_YUY2: - frame_size = width * height - + ((width + 1) / 2) * height - + ((width + 1) / 2) * height; - break; - } - - img = xine_xmalloc(frame_size); - - if (!xine_get_current_frame(this->stream, &width, &height, &ratio_code, &format, img)) - frame_size = 0; - if (ratio_code == XINE_VO_ASPECT_SQUARE) ratio_code = 10000; else if (ratio_code == XINE_VO_ASPECT_4_3) @@ -987,17 +983,15 @@ fprintf(stderr, "ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß\n"); ratio_code = 17778; else if (ratio_code == XINE_VO_ASPECT_DVB) ratio_code = 21100; - - if (0 == frame_size) - { - width = 0; - height = 0; - ratio_code = 0; - } } - - if (XINE_SPEED_PAUSE != orig_speed) - xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, orig_speed); + + if (!img) + { + frame_size = 0, + width = 0; + height = 0; + ratio_code = 0; + } { result_grab_image_t result_grab_image; @@ -1011,13 +1005,12 @@ fprintf(stderr, "ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß\n"); if (sizeof (result_grab_image) == vdr_write(this->fh_result, &result_grab_image, sizeof (result_grab_image))) { - if (frame_size == vdr_write(this->fh_result, img, frame_size)) + if (!frame_size || (frame_size == vdr_write(this->fh_result, img, frame_size))) ret_val = 0; } } - if (img) - free(img); + free(img); if (ret_val != 0) return ret_val; @@ -1034,8 +1027,7 @@ fprintf(stderr, "ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß\n"); result_get_pts.header.func = data->header.func; result_get_pts.header.len = sizeof (result_get_pts); - result_get_pts.pts = xine_get_current_vpts(this->stream) - this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); - + result_get_pts.pts = (this->last_disc_type == DISC_STREAMSTART) ? -2 : (xine_get_current_vpts(this->stream) - this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET)); if (sizeof (result_get_pts) != vdr_write(this->fh_result, &result_get_pts, sizeof (result_get_pts))) return -1; } @@ -1311,7 +1303,7 @@ static off_t vdr_plugin_read(input_plugin_t *this_gen, void *buf_gen, off_t len) { vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - char *buf = (char *)buf_gen; + uint8_t *buf = (uint8_t *)buf_gen; off_t n, total; #ifdef LOG_READ lprintf ("reading %lld bytes...\n", len); @@ -1336,7 +1328,7 @@ static off_t vdr_plugin_read(input_plugin_t *this_gen, int retries = 0; do { - n = vdr_read_abort (this->stream, this->fh, &buf[total], len-total); + n = vdr_read_abort (this->stream, this->fh, (char *)&buf[total], len-total); if (0 == n) lprintf("read 0, retries: %d\n", retries); } @@ -1357,6 +1349,53 @@ static off_t vdr_plugin_read(input_plugin_t *this_gen, this->curpos += n; total += n; } + + if (this->find_sync_point + && total == 6) + { + pthread_mutex_lock(&this->find_sync_point_lock); + + while (this->find_sync_point + && total == 6 + && buf[0] == 0x00 + && buf[1] == 0x00 + && buf[2] == 0x01) + { + int l, sp; + + if (buf[3] == 0xbe + && buf[4] == 0xff) + { +//fprintf(stderr, "------- seen sync point: %02x, waiting for: %02x\n", buf[5], this->find_sync_point); + if (buf[5] == this->find_sync_point) + { + this->find_sync_point = 0; + break; + } + } + + if ((buf[3] & 0xf0) != 0xe0 + && (buf[3] & 0xe0) != 0xc0 + && buf[3] != 0xbd + && buf[3] != 0xbe) + { + break; + } + + l = buf[4] * 256 + buf[5]; + if (l <= 0) + break; + + sp = this->find_sync_point; + this->find_sync_point = 0; + this_gen->seek(this_gen, l, SEEK_CUR); + total = this_gen->read(this_gen, buf, 6); + this->find_sync_point = sp; + } + + pthread_mutex_unlock(&this->find_sync_point_lock); + } + return total; } @@ -1512,6 +1551,7 @@ static void vdr_plugin_dispose(input_plugin_t *this_gen) pthread_cond_destroy(&this->rpc_thread_shutdown_cond); pthread_mutex_destroy(&this->rpc_thread_shutdown_lock); + pthread_mutex_destroy(&this->find_sync_point_lock); pthread_mutex_destroy(&this->adjust_zoom_lock); if (this->fh_result != -1) @@ -1539,6 +1579,10 @@ static void vdr_plugin_dispose(input_plugin_t *this_gen) close(this->fh); free(this->mrl); + + this->stream->metronom = this->metronom.stream_metronom; + this->metronom.stream_metronom = 0; + free(this); } @@ -1608,6 +1652,12 @@ static int vdr_plugin_open_fifo_mrl(input_plugin_t *this_gen) fcntl(this->fh, F_SETFL, ~O_NONBLOCK & fcntl(this->fh, F_GETFL, 0)); + /* eat initial handshake byte */ + { + char b; + read(this->fh, &b, 1); + } + { char *filename_control = 0; asprintf(&filename_control, "%s.control", filename); @@ -1946,6 +1996,69 @@ static void event_handler(void *user_data, const xine_event_t *event) _("%s: input event write: %s.\n"), LOG_MODULE, strerror(errno)); } + +static void vdr_metronom_set_audio_rate(metronom_t *self, int64_t pts_per_smpls) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->set_audio_rate(this->stream_metronom, pts_per_smpls); +} + +static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->got_video_frame(this->stream_metronom, frame); +} + +static int64_t vdr_metronom_got_audio_samples(metronom_t *self, int64_t pts, int nsamples) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + return this->stream_metronom->got_audio_samples(this->stream_metronom, pts, nsamples); +} + +static int64_t vdr_metronom_got_spu_packet(metronom_t *self, int64_t pts) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + return this->stream_metronom->got_spu_packet(this->stream_metronom, pts); +} + +static void vdr_metronom_handle_audio_discontinuity(metronom_t *self, int type, int64_t disc_off) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->handle_audio_discontinuity(this->stream_metronom, type, disc_off); + this->input->last_disc_type = type; +} + +static void vdr_metronom_handle_video_discontinuity(metronom_t *self, int type, int64_t disc_off) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->handle_video_discontinuity(this->stream_metronom, type, disc_off); + this->input->last_disc_type = type; +} + +static void vdr_metronom_set_option(metronom_t *self, int option, int64_t value) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->set_option(this->stream_metronom, option, value); +} + +static int64_t vdr_metronom_get_option(metronom_t *self, int option) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + return this->stream_metronom->get_option(this->stream_metronom, option); +} + +static void vdr_metronom_set_master(metronom_t *self, metronom_t *master) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->set_master(this->stream_metronom, master); +} + +static void vdr_metronom_exit(metronom_t *self) +{ + _x_abort(); +} + + static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_stream_t *stream, const char *data) { @@ -2017,6 +2130,7 @@ static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_strea pthread_mutex_init(&this->rpc_thread_shutdown_lock, 0); pthread_cond_init(&this->rpc_thread_shutdown_cond, 0); + pthread_mutex_init(&this->find_sync_point_lock, 0); pthread_mutex_init(&this->adjust_zoom_lock, 0); this->image4_3_zoom_x = 0; this->image4_3_zoom_y = 0; @@ -2027,6 +2141,21 @@ static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_strea if (this->event_queue) xine_event_create_listener_thread(this->event_queue, event_handler, this); + this->metronom.input = this; + this->metronom.metronom.set_audio_rate = vdr_metronom_set_audio_rate; + this->metronom.metronom.got_video_frame = vdr_metronom_got_video_frame; + this->metronom.metronom.got_audio_samples = vdr_metronom_got_audio_samples; + this->metronom.metronom.got_spu_packet = vdr_metronom_got_spu_packet; + this->metronom.metronom.handle_audio_discontinuity = vdr_metronom_handle_audio_discontinuity; + this->metronom.metronom.handle_video_discontinuity = vdr_metronom_handle_video_discontinuity; + this->metronom.metronom.set_option = vdr_metronom_set_option; + this->metronom.metronom.get_option = vdr_metronom_get_option; + this->metronom.metronom.set_master = vdr_metronom_set_master; + this->metronom.metronom.exit = vdr_metronom_exit; + + this->metronom.stream_metronom = stream->metronom; + stream->metronom = &this->metronom.metronom; + return &this->input_plugin; } @@ -2039,7 +2168,7 @@ static char **vdr_class_get_autoplay_list(input_class_t *this_gen, vdr_input_class_t *class = (vdr_input_class_t *)this_gen; *num_files = 1; - return class->mrls; + return (char **)class->mrls; } void *vdr_input_init_plugin(xine_t *xine, void *data) diff --git a/src/video_dec/libmpeg2/decode.c b/src/video_dec/libmpeg2/decode.c index 33d8b7ca9..e9700d95f 100644 --- a/src/video_dec/libmpeg2/decode.c +++ b/src/video_dec/libmpeg2/decode.c @@ -460,9 +460,10 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, break; case 0xb7: /* sequence end code */ -#ifdef LOG_PAN_SCAN - printf ("libmpeg2: sequence end code not handled\n"); -#endif + mpeg2_flush(mpeg2dec); + mpeg2dec->is_sequence_needed = 1; + break; + case 0xb8: /* group of pictures start code */ if (mpeg2_header_group_of_pictures (picture, buffer)) { printf ("libmpeg2: bad group of pictures\n"); diff --git a/src/video_out/video_out_macosx.m b/src/video_out/video_out_macosx.m index 9c65d579d..085387a44 100644 --- a/src/video_out/video_out_macosx.m +++ b/src/video_out/video_out_macosx.m @@ -36,11 +36,11 @@ #define LOG */ -#include "video_out.h" -#include "vo_scale.h" #include "xine.h" -#include "xine_internal.h" -#include "xineutils.h" +#include "xine/video_out.h" +#include "xine/vo_scale.h" +#include "xine/xine_internal.h" +#include "xine/xineutils.h" #include "macosx/video_window.h" @@ -207,7 +207,7 @@ static void macosx_display_frame(vo_driver_t *vo_driver, vo_frame_t *vo_frame) { break; case XINE_IMGFMT_YUY2: xine_fast_memcpy (texture_buffer, vo_frame->base[0], - vo_frame->pitches[0] * vo_frame->height * 2); + vo_frame->pitches[0] * vo_frame->height); [driver->view updateTexture]; break; default: @@ -358,7 +358,7 @@ static void *init_class (xine_t *xine, void *visual) { this->driver_class.open_plugin = open_plugin; this->driver_class.identifier = "MacOSX"; this->driver_class.description = N_("xine video output plugin for Mac OS X"); - this->driver_class.dispose = default_video_driver_class; + this->driver_class.dispose = default_video_driver_class_dispose; this->config = xine->config; this->xine = xine; diff --git a/src/video_out/video_out_xcbxv.c b/src/video_out/video_out_xcbxv.c index d77917a70..e267f98fb 100644 --- a/src/video_out/video_out_xcbxv.c +++ b/src/video_out/video_out_xcbxv.c @@ -151,6 +151,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; @@ -1145,10 +1147,15 @@ xv_find_adaptor_by_port (int port, xcb_xv_adaptor_info_iterator_t *adaptor_it) 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) + 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) + 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) @@ -1168,6 +1175,7 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis int i; xcb_visual_t *visual = (xcb_visual_t *) visual_gen; xcb_xv_port_t xv_port; + xv_prefertype prefer_type; const xcb_query_extension_reply_t *query_extension_reply; @@ -1219,19 +1227,24 @@ 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 = config->register_num (config, "video.device.xv_port", 0, VIDEO_DEVICE_XV_PORT_HELP, - 10, NULL, NULL); + 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); + 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); + 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, diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index a874e4cdf..0026bd8af 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.c @@ -164,6 +164,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; @@ -1178,11 +1180,15 @@ static XvPortID xv_autodetect_port(xv_driver_t *this, unsigned int adaptors, XvAdaptorInfo *adaptor_info, unsigned int *adaptor_num, - XvPortID base) { + XvPortID base, + xv_prefertype prefer_type) +{ unsigned int an, j; for (an = 0; an < adaptors; an++) - if (adaptor_info[an].type & XvImageMask) + 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)) { @@ -1212,6 +1218,7 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * XvPortID xv_port; XvAdaptorInfo *adaptor_info; unsigned int adaptor_num; + xv_prefertype prefer_type; this = (xv_driver_t *) xine_xmalloc (sizeof (xv_driver_t)); if (!this) @@ -1251,19 +1258,24 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * xv_port = config->register_num (config, "video.device.xv_port", 0, VIDEO_DEVICE_XV_PORT_HELP, - 10, NULL, NULL); + 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); + 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); + 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, diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c index 1ef3652a9..bd8a76046 100644 --- a/src/video_out/video_out_xxmc.c +++ b/src/video_out/video_out_xxmc.c @@ -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 @@ -2263,11 +2264,15 @@ static XvPortID xxmc_autodetect_port(xxmc_driver_t *this, unsigned int adaptors, XvAdaptorInfo *adaptor_info, unsigned int *adaptor_num, - XvPortID base) { + XvPortID base, + xv_prefertype prefer_type) +{ unsigned int an, j; for (an = 0; an < adaptors; an++) - if (adaptor_info[an].type & XvImageMask) + 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)) { @@ -2443,6 +2448,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; @@ -2480,19 +2486,24 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi xv_port = config->register_num (config, "video.device.xv_port", 0, VIDEO_DEVICE_XV_PORT_HELP, - 10, NULL, NULL); + 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 (! 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); + 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); + 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, diff --git a/src/video_out/xv_common.h b/src/video_out/xv_common.h index ee2ab9a10..259afe616 100644 --- a/src/video_out/xv_common.h +++ b/src/video_out/xv_common.h @@ -56,3 +56,14 @@ #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/buffer_types.c b/src/xine-engine/buffer_types.c index b0e01db31..15b5ff952 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -808,6 +808,14 @@ static const audio_db_t audio_db[] = { }, { { + ME_FOURCC('a', 'd', 'u', 0x55), + 0 + }, + BUF_AUDIO_MP3ADU, + "MPEG layer-3 adu" +}, +{ + { ME_FOURCC('t','w','o','s'), ME_FOURCC('i','n','2','4'), 0 diff --git a/src/xine-engine/configfile.c b/src/xine-engine/configfile.c index a41abf193..9f67b7503 100644 --- a/src/xine-engine/configfile.c +++ b/src/xine-engine/configfile.c @@ -1458,7 +1458,7 @@ static char* config_register_serialized_entry (config_values_t *this, const char if (!bytes) goto exit; if ((value_count < 0) || (value_count > 256)) goto exit; - enum_values = malloc (sizeof(void*) * value_count + 1); + enum_values = calloc (value_count + 1, sizeof(void*)); for (i = 0; i < value_count; i++) { pos += bytes = get_string(output, output_len, pos, &enum_values[i]); if (!bytes) goto exit; diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c index 232e0342e..e641bbf77 100644 --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -198,6 +198,7 @@ void _x_demux_control_headers_done (xine_stream_t *stream) { } stream->demux_action_pending = 0; + pthread_cond_signal(&stream->demux_resume); lprintf ("headers processed.\n"); @@ -284,12 +285,14 @@ static void *demux_loop (void *stream_gen) { /* someone may want to interrupt us */ if( stream->demux_action_pending ) { - pthread_mutex_unlock( &stream->demux_lock ); + struct timeval tv; + struct timespec ts; - lprintf ("sched_yield\n"); - - sched_yield(); - pthread_mutex_lock( &stream->demux_lock ); + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = (tv.tv_usec + 100000) * 1000; + + pthread_cond_timedwait (&stream->demux_resume, &stream->demux_lock, &ts); } } @@ -365,6 +368,7 @@ int _x_demux_start_thread (xine_stream_t *stream) { stream->demux_action_pending = 1; pthread_mutex_lock( &stream->demux_lock ); stream->demux_action_pending = 0; + pthread_cond_signal(&stream->demux_resume); if( !stream->demux_thread_running ) { @@ -396,6 +400,7 @@ int _x_demux_stop_thread (xine_stream_t *stream) { pthread_mutex_lock( &stream->demux_lock ); stream->demux_thread_running = 0; stream->demux_action_pending = 0; + pthread_cond_signal(&stream->demux_resume); /* At that point, the demuxer has sent the last audio/video buffer, * so it's a safe place to flush the engine. diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c index 8e4a10a60..710e6dfbf 100644 --- a/src/xine-engine/load_plugins.c +++ b/src/xine-engine/load_plugins.c @@ -1339,11 +1339,13 @@ input_plugin_t *_x_find_input_plugin (xine_stream_t *stream, const char *mrl) { void _x_free_input_plugin (xine_stream_t *stream, input_plugin_t *input) { plugin_catalog_t *catalog = stream->xine->plugin_catalog; + plugin_node_t *node = input->node; input->dispose(input); - if (input->node) { + + if (node) { pthread_mutex_lock(&catalog->lock); - dec_node_ref(input->node); + dec_node_ref(node); pthread_mutex_unlock(&catalog->lock); } } @@ -1560,11 +1562,13 @@ demux_plugin_t *_x_find_demux_plugin_last_probe(xine_stream_t *stream, const cha void _x_free_demux_plugin (xine_stream_t *stream, demux_plugin_t *demux) { plugin_catalog_t *catalog = stream->xine->plugin_catalog; + plugin_node_t *node = demux->node; demux->dispose(demux); - if (demux->node) { + + if (node) { pthread_mutex_lock(&catalog->lock); - dec_node_ref(demux->node); + dec_node_ref(node); pthread_mutex_unlock(&catalog->lock); } } @@ -2054,12 +2058,13 @@ video_decoder_t *_x_get_video_decoder (xine_stream_t *stream, uint8_t stream_typ void _x_free_video_decoder (xine_stream_t *stream, video_decoder_t *vd) { plugin_catalog_t *catalog = stream->xine->plugin_catalog; + plugin_node_t *node = vd->node; vd->dispose (vd); - if (vd->node) { + if (node) { pthread_mutex_lock (&catalog->lock); - dec_node_ref(vd->node); + dec_node_ref(node); pthread_mutex_unlock (&catalog->lock); } } @@ -2403,7 +2408,7 @@ const char *const *xine_list_post_plugins_typed(xine_t *xine, uint32_t type) { else \ return NULL; \ } \ - return dgettext(ic->textdomain ? : XINE_TEXTDOMAIN, ic->description); \ + return dgettext(ic->text_domain ? : XINE_TEXTDOMAIN, ic->description); \ } \ } \ return NULL; \ diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index c6dc8a2ce..5c8d0be9d 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -36,6 +36,7 @@ #include <stdarg.h> #include <stdio.h> #include <ctype.h> +#include <unistd.h> #if defined (__linux__) || defined (__GLIBC__) #include <endian.h> #elif defined (__FreeBSD__) @@ -138,7 +139,7 @@ static int acquire_allowed_to_block(xine_ticket_t *this) { unsigned new_size; for(entry = 0; entry < this->holder_thread_count; ++entry) { - if(this->holder_threads[entry].holder == own_id) { + if(pthread_equal(this->holder_threads[entry].holder, own_id)) { /* This thread may already hold this ticket */ this->holder_threads[entry].count++; return (this->holder_threads[entry].count == 1); @@ -209,7 +210,7 @@ static int release_allowed_to_block(xine_ticket_t *this) { unsigned entry; for(entry = 0; entry < this->holder_thread_count; ++entry) { - if(this->holder_threads[entry].holder == own_id) { + if(pthread_equal(this->holder_threads[entry].holder, own_id)) { this->holder_threads[entry].count--; return this->holder_threads[entry].count == 0; } @@ -670,6 +671,7 @@ xine_stream_t *xine_stream_new (xine_t *this, pthread_mutex_init (&stream->meta_mutex, NULL); pthread_mutex_init (&stream->demux_lock, NULL); pthread_mutex_init (&stream->demux_mutex, NULL); + pthread_cond_init (&stream->demux_resume, NULL); pthread_mutex_init (&stream->event_queues_lock, NULL); pthread_mutex_init (&stream->counter_lock, NULL); pthread_cond_init (&stream->counter_changed, NULL); @@ -839,6 +841,7 @@ static inline int _x_path_looks_like_mrl (const char *path) static int open_internal (xine_stream_t *stream, const char *mrl) { const char *stream_setup = NULL; + const char *mrl_proto = NULL; int no_cache = 0; if (!mrl) { @@ -862,16 +865,31 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { /* * look for a stream_setup in MRL and try finding an input plugin */ + stream_setup = strchr (mrl, '#'); if (isalpha (*mrl)) { - stream_setup = mrl + 1; - while (isalnum (*stream_setup) || *stream_setup == '+' || *stream_setup == '-' || *stream_setup == '.') - ++stream_setup; - if (stream_setup[0] == ':' && stream_setup[1] == '/') - stream_setup = strchr (mrl, '#'); - else - stream_setup = NULL; + mrl_proto = mrl + 1; + while (isalnum (*mrl_proto) || *mrl_proto == '+' || *mrl_proto == '-' || *mrl_proto == '.') + ++mrl_proto; + if (!mrl_proto[0] || mrl_proto[0] != ':' || mrl_proto[1] != '/') + mrl_proto = NULL; + } + + /* for raw filenames we must try every '#' checking if it is part of the filename */ + if( !mrl_proto && stream_setup) { + struct stat stat_buf; + int res; + + while( stream_setup ) { + char *raw_filename = strndup (mrl, stream_setup - mrl); + + res = stat(raw_filename, &stat_buf); + free(raw_filename); + if( !res ) + break; + stream_setup = strchr(stream_setup + 1, '#'); + } } { @@ -880,12 +898,14 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { /* * find an input plugin */ - - if ((stream->input_plugin = _x_find_input_plugin (stream, input_source))) { + stream->input_plugin = _x_find_input_plugin (stream, input_source); + free(input_source); + + if ( stream->input_plugin ) { int res; xine_log (stream->xine, XINE_LOG_MSG, _("xine: found input plugin : %s\n"), - dgettext(stream->input_plugin->input_class->textdomain ? : XINE_TEXTDOMAIN, + dgettext(stream->input_plugin->input_class->text_domain ? : XINE_TEXTDOMAIN, stream->input_plugin->input_class->description)); if (stream->input_plugin->input_class->eject_media) stream->eject_class = stream->input_plugin->input_class; @@ -897,7 +917,6 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { case 1: /* Open successfull */ break; case -1: /* Open unsuccessfull, but correct plugin */ - free(input_source); stream->err = XINE_ERROR_INPUT_FAILED; _x_flush_events_queues (stream); return 0; @@ -908,8 +927,6 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { stream->err = XINE_ERROR_INPUT_FAILED; } } - - free(input_source); } if (!stream->input_plugin) { @@ -1235,7 +1252,7 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { } xine_log (stream->xine, XINE_LOG_MSG, _("xine: found demuxer plugin: %s\n"), - dgettext(stream->demux_plugin->demux_class->textdomain ? : XINE_TEXTDOMAIN, + dgettext(stream->demux_plugin->demux_class->text_domain ? : XINE_TEXTDOMAIN, stream->demux_plugin->demux_class->description)); _x_extra_info_reset( stream->current_extra_info ); @@ -1351,6 +1368,7 @@ static int play_internal (xine_stream_t *stream, int start_pos, int start_time) pthread_mutex_lock( &stream->demux_lock ); /* demux_lock taken. now demuxer is suspended */ stream->demux_action_pending = 0; + pthread_cond_signal(&stream->demux_resume); /* set normal speed again (now that demuxer/input pair is suspended) * some input plugin may have changed speed by itself, we must ensure @@ -1477,6 +1495,7 @@ static void xine_dispose_internal (xine_stream_t *stream) { pthread_mutex_destroy (&stream->current_extra_info_lock); pthread_cond_destroy (&stream->counter_changed); pthread_mutex_destroy (&stream->demux_mutex); + pthread_cond_destroy (&stream->demux_resume); pthread_mutex_destroy (&stream->demux_lock); pthread_mutex_destroy (&stream->first_frame_lock); pthread_cond_destroy (&stream->first_frame_reached); @@ -1691,6 +1710,12 @@ void xine_init (xine_t *this) { /* First of all, initialise libxdg-basedir as it's used by plugins. */ this->basedir_handle = xdgAllocHandle(); + /* + * locks + */ + pthread_mutex_init (&this->streams_lock, NULL); + pthread_mutex_init (&this->log_lock, NULL); + /* initialize color conversion tables and functions */ init_yuv_conversion(); @@ -1772,12 +1797,6 @@ void xine_init (xine_t *this) { this->streams = xine_list_new(); /* - * locks - */ - pthread_mutex_init (&this->streams_lock, NULL); - pthread_mutex_init (&this->log_lock, NULL); - - /* * start metronom clock */ @@ -1963,11 +1982,12 @@ int xine_get_pos_length (xine_stream_t *stream, int *pos_stream, return 1; } -int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, - int *ratio_code, int *format, - uint8_t *img) { +static int _x_get_current_frame_impl (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t **img, int *size, int alloc_img) { vo_frame_t *frame; + int required_size; stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0); frame = stream->video_out->get_last_frame (stream->video_out); @@ -1993,20 +2013,62 @@ int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, *format = frame->format; - if (img){ + switch (*format) { + + case XINE_IMGFMT_YV12: + required_size = *width * *height + + ((*width + 1) / 2) * ((*height + 1) / 2) + + ((*width + 1) / 2) * ((*height + 1) / 2); + break; + + case XINE_IMGFMT_YUY2: + required_size = *width * *height + + ((*width + 1) / 2) * *height + + ((*width + 1) / 2) * *height; + break; + + default: + if (*img || alloc_img) { + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, + "xine: error, snapshot function not implemented for format 0x%x\n", frame->format); + _x_abort (); + } + + required_size = 0; + } + + if (alloc_img) { + /* return size if requested */ + if (size) + *size = required_size; + /* allocate img or fail */ + if (!(*img = xine_xmalloc (required_size))) + return 0; + } else { + /* fail if supplied buffer is to small */ + if (*img && size && *size < required_size) { + *size = required_size; + return 0; + } + /* return size if requested */ + if (size) + *size = required_size; + } + + if (*img) { switch (frame->format) { case XINE_IMGFMT_YV12: yv12_to_yv12( /* Y */ frame->base[0], frame->pitches[0], - img, frame->width, + *img, frame->width, /* U */ frame->base[1], frame->pitches[1], - img+frame->width*frame->height, frame->width/2, + *img+frame->width*frame->height, frame->width/2, /* V */ frame->base[2], frame->pitches[2], - img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2, + *img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2, /* width x height */ frame->width, frame->height); break; @@ -2016,7 +2078,7 @@ int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, /* src */ frame->base[0], frame->pitches[0], /* dst */ - img, frame->width*2, + *img, frame->width*2, /* width x height */ frame->width, frame->height); break; @@ -2030,6 +2092,25 @@ int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, return 1; } +int xine_get_current_frame_alloc (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t **img, int *size) { + uint8_t *no_img = NULL; + return _x_get_current_frame_impl(stream, width, height, ratio_code, format, img ? img : &no_img, size, img != NULL); +} + +int xine_get_current_frame_s (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t *img, int *size) { + return (!img || size) && _x_get_current_frame_impl(stream, width, height, ratio_code, format, &img, size, 0); +} + +int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t *img) { + return _x_get_current_frame_impl(stream, width, height, ratio_code, format, &img, NULL, 0); +} + int xine_get_video_frame (xine_stream_t *stream, int timestamp, /* msec */ int *width, int *height, diff --git a/src/xine-utils/Makefile.am b/src/xine-utils/Makefile.am index 75cab2131..0c664b0be 100644 --- a/src/xine-utils/Makefile.am +++ b/src/xine-utils/Makefile.am @@ -32,3 +32,7 @@ libxineutils_la_SOURCES = $(pppc_files) \ sorted_array.c \ pool.c \ ring_buffer.c + +noinst_PROGRAMS = xmltest +xmltest_SOURCES = xmllexer.c xmlparser.c +xmltest_CFLAGS = -DLOG -DXINE_XML_PARSER_TEST $(AM_CFLAGS) diff --git a/src/xine-utils/xmllexer.c b/src/xine-utils/xmllexer.c index 75a1aafec..394ca397f 100644 --- a/src/xine-utils/xmllexer.c +++ b/src/xine-utils/xmllexer.c @@ -445,6 +445,8 @@ int lexer_get_token_d(char ** _tok, int * _tok_size, int fixed) { case '\"': /* " */ case ' ': case '\t': + case '\n': + case '\r': case '=': case '/': tok[tok_pos] = '\0'; diff --git a/src/xine-utils/xmlparser.c b/src/xine-utils/xmlparser.c index 8ef828105..0c3d12f59 100644 --- a/src/xine-utils/xmlparser.c +++ b/src/xine-utils/xmlparser.c @@ -837,3 +837,73 @@ void xml_parser_dump_tree (const xml_node_t *node) { node = node->next; } while (node); } + +#ifdef XINE_XML_PARSER_TEST +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void *xine_xmalloc (size_t size) +{ + return malloc (size); +} + +int main (int argc, char **argv) +{ + int i, ret = 0; + for (i = 1; argv[i]; ++i) + { + xml_node_t *tree; + int fd; + void *buf; + struct stat st; + + if (stat (argv[i], &st)) + { + perror (argv[i]); + ret = 1; + continue; + } + if (!S_ISREG (st.st_mode)) + { + printf ("%s: not a file\n", argv[i]); + ret = 1; + continue; + } + fd = open (argv[i], O_RDONLY); + if (!fd) + { + perror (argv[i]); + ret = 1; + continue; + } + buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (!buf) + { + perror (argv[i]); + if (close (fd)) + perror (argv[i]); + ret = 1; + continue; + } + + xml_parser_init (buf, st.st_size, 0); + if (!xml_parser_build_tree (&tree)) + { + puts (argv[i]); + xml_parser_dump_tree (tree); + xml_parser_free_tree (tree); + } + else + printf ("%s: parser failure\n", argv[i]); + + if (close (fd)) + { + perror (argv[i]); + ret = 1; + } + } + return ret; +} +#endif |