summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Jager <t.jager@gmx.de>2011-08-13 18:00:54 +0200
committerTorsten Jager <t.jager@gmx.de>2011-08-13 18:00:54 +0200
commit812c8af9bfb91e65a7c85a4281cc9aa0d047d9a7 (patch)
tree6da495011b227495d3f515c863f500d615e4cd7c
parentde7a127259f8341ad8ee9a57cc05f1d43625d972 (diff)
downloadxine-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.c36
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);