diff options
author | Torsten Jager <t.jager@gmx.de> | 2011-08-13 18:00:54 +0200 |
---|---|---|
committer | Torsten Jager <t.jager@gmx.de> | 2011-08-13 18:00:54 +0200 |
commit | 812c8af9bfb91e65a7c85a4281cc9aa0d047d9a7 (patch) | |
tree | 6da495011b227495d3f515c863f500d615e4cd7c | |
parent | de7a127259f8341ad8ee9a57cc05f1d43625d972 (diff) | |
download | xine-lib-812c8af9bfb91e65a7c85a4281cc9aa0d047d9a7.tar.gz xine-lib-812c8af9bfb91e65a7c85a4281cc9aa0d047d9a7.tar.bz2 |
ffmpeg audio crash fix (sse2 alignment)
Certain ffmpeg audio decoders use 32 bit float samples internally (wma,
eac3, ...). They are then exported to the calling application as 16 bit
integer.
That conversion is done by faster sse2 code if your processor supports it.
However, sse2 instructions require data buffers to be 16 byte aligned, or
hit a segfault otherwise.
Plain malloc() / realloc() ensures only 8 byte alignment, giving a 50%
chance of a crash.
FFmpeg internally uses aligned buffers a lot. It seems to be a good idea to
do likewise for input buffers as well, even if current version does not
strictly need it yet.
Libavutil/av_realloc() has a bug that can break the alignment when enlarging
an existing buffer. Thus I included a fixed version of it within
ff_audio_decoder.c.
-rw-r--r-- | src/combined/ffmpeg/ff_audio_decoder.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 60544ad0c..14a908d2f 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -81,13 +81,41 @@ typedef struct ff_audio_decoder_s { #include "ff_audio_list.h" +#define malloc16(s) realloc16(NULL,s) +#define free16(p) realloc16(p,0) + +static void *realloc16 (void *m, size_t s) { + unsigned int diff, diff2; + unsigned char *p = m, *q; + if (p) { + diff = p[-1]; + if (s == 0) { + free (p - diff); + return (NULL); + } + q = realloc (p - diff, s + 16); + if (!q) return (q); + diff2 = 16 - ((unsigned int)q & 15); + if (diff2 != diff) memmove (q + diff2, q + diff, s); + } else { + if (s == 0) return (NULL); + q = malloc (s + 16); + if (!q) return (q); + diff2 = 16 - ((unsigned int)q & 15); + } + q += diff2; + q[-1] = diff2; + return (q); +} + + static void ff_audio_ensure_buffer_size(ff_audio_decoder_t *this, int size) { if (size > this->bufsize) { this->bufsize = size + size / 2; xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_audio_dec: increasing buffer to %d to avoid overflow.\n"), this->bufsize); - this->buf = realloc( this->buf, this->bufsize ); + this->buf = realloc16 (this->buf, this->bufsize); } } @@ -247,7 +275,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->size = 0; - this->decode_buffer = calloc(1, AVCODEC_MAX_AUDIO_FRAME_SIZE); + this->decode_buffer = malloc16 (AVCODEC_MAX_AUDIO_FRAME_SIZE); return; } @@ -455,8 +483,8 @@ static void ff_audio_dispose (audio_decoder_t *this_gen) { this->stream->audio_out->close (this->stream->audio_out, this->stream); this->output_open = 0; - free(this->buf); - free(this->decode_buffer); + free16 (this->buf); + free16 (this->decode_buffer); if(this->context && this->context->extradata) free(this->context->extradata); |