summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Trofimovich <slyfox@gentoo.org>2016-04-02 11:43:39 +0100
committerSergei Trofimovich <slyfox@gentoo.org>2016-04-02 11:43:47 +0100
commit45fc303a416aa252542c49b9383ad148f9022974 (patch)
treeff4c5ee6ab5050b02ad2cd0f2d09ea421b911bcf /media-sound
parentdev-libs/libplatform: Version bump (diff)
downloadgentoo-45fc303a416aa252542c49b9383ad148f9022974.tar.gz
gentoo-45fc303a416aa252542c49b9383ad148f9022974.tar.bz2
gentoo-45fc303a416aa252542c49b9383ad148f9022974.zip
media-sound/xmms2: support stable API for libav, bug #540890
Latest stable media-video/ffmpeg-2.8.6 provides both functions: avcodec_decode_audio3 avcodec_decode_audio4 While latest stable media-video/libav-11.3 provides only avcodec_decode_audio4 Pulled large patchset from upstream to support audio4 API. Builds fine on both stable virtual/ffmpeg implementations and unstable libav. Reported-by: Toralf Förster Bug: https://bugs.gentoo.org/540890 Package-Manager: portage-2.2.28
Diffstat (limited to 'media-sound')
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p1.patch123
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p2.patch171
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p3.patch388
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p4.patch296
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p5.patch154
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p6.patch106
-rw-r--r--media-sound/xmms2/files/xmms2-0.8-audio4-p7.patch147
-rw-r--r--media-sound/xmms2/xmms2-0.8-r2.ebuild7
8 files changed, 1392 insertions, 0 deletions
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p1.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p1.patch
new file mode 100644
index 000000000000..21ed6492a44d
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p1.patch
@@ -0,0 +1,123 @@
+commit 8831bc77d705c03b3f8081de0520dd10afa85c69
+Author: Uli Franke <cls@nebadje.org>
+Date: Tue Jan 17 23:23:46 2012 +0100
+
+ BUG(2509): Avoid unaligned reads in avcodec xform.
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index fe58fc5..1b4a659 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -36,6 +36,9 @@ typedef struct {
+ guint buffer_size;
+ gboolean no_demuxer;
+
++ gchar *read_out_buffer;
++ gint read_out_buffer_size;
++
+ guint channels;
+ guint samplerate;
+ xmms_sample_format_t sampleformat;
+@@ -107,6 +110,7 @@ xmms_avcodec_destroy (xmms_xform_t *xform)
+
+ avcodec_close (data->codecctx);
+ av_free (data->codecctx);
++ av_free (data->read_out_buffer);
+
+ g_string_free (data->outbuf, TRUE);
+ g_free (data->buffer);
+@@ -132,6 +136,9 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->buffer_size = AVCODEC_BUFFER_SIZE;
+ data->codecctx = NULL;
+
++ data->read_out_buffer = av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
++ data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
++
+ xmms_xform_private_data_set (xform, data);
+
+ avcodec_init ();
+@@ -196,7 +203,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ } else {
+ /* A demuxer plugin forgot to give decoder config? */
+ xmms_log_error ("Decoder config data not found!");
+- return FALSE;
++ goto err;
+ }
+ }
+
+@@ -220,7 +227,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+
+ /* some codecs need to have something read before they set
+ * the samplerate and channels correctly, unfortunately... */
+- if ((ret = xmms_avcodec_read (xform, buf, 42, &error)) > 0) {
++ if ((ret = xmms_avcodec_read (xform, buf, sizeof (buf), &error)) > 0) {
+ g_string_insert_len (data->outbuf, 0, buf, ret);
+ } else {
+ XMMS_DBG ("First read failed, codec is not working...");
+@@ -251,6 +258,9 @@ err:
+ if (data->codecctx) {
+ av_free (data->codecctx);
+ }
++ if (data->read_out_buffer) {
++ av_free (data->read_out_buffer);
++ }
+ g_string_free (data->outbuf, TRUE);
+ g_free (data->extradata);
+ g_free (data);
+@@ -263,8 +273,7 @@ xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len,
+ xmms_error_t *error)
+ {
+ xmms_avcodec_data_t *data;
+- char outbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
+- gint outbufsize, bytes_read = 0;
++ gint bytes_read = 0;
+ guint size;
+
+ data = xmms_xform_private_data_get (xform);
+@@ -330,9 +339,9 @@ xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len,
+ packet.data = data->buffer;
+ packet.size = data->buffer_length;
+
+- outbufsize = sizeof (outbuf);
+- bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) outbuf,
+- &outbufsize, &packet);
++ data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
++ bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) data->read_out_buffer,
++ &data->read_out_buffer_size, &packet);
+
+ /* The DTS decoder of ffmpeg is buggy and always returns
+ * the input buffer length, get frame length from header */
+@@ -354,8 +363,8 @@ xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len,
+
+ data->buffer_length -= bytes_read;
+
+- if (outbufsize > 0) {
+- g_string_append_len (data->outbuf, outbuf, outbufsize);
++ if (data->read_out_buffer_size > 0) {
++ g_string_append_len (data->outbuf, data->read_out_buffer, data->read_out_buffer_size);
+ }
+
+ size = MIN (data->outbuf->len, len);
+@@ -371,8 +380,7 @@ static gint64
+ xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err)
+ {
+ xmms_avcodec_data_t *data;
+- char outbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
+- gint outbufsize, bytes_read = 0;
++ gint bytes_read = 0;
+ gint64 ret = -1;
+
+ g_return_val_if_fail (xform, -1);
+@@ -396,9 +404,9 @@ xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t w
+ packet.data = data->buffer;
+ packet.size = data->buffer_length;
+
+- outbufsize = sizeof (outbuf);
+- bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) outbuf,
+- &outbufsize, &packet);
++ data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
++ bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) data->read_out_buffer,
++ &data->read_out_buffer_size, &packet);
+
+ if (bytes_read < 0 || bytes_read > data->buffer_length) {
+ XMMS_DBG ("Error decoding data!");
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p2.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p2.patch
new file mode 100644
index 000000000000..46b5b1d3b926
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p2.patch
@@ -0,0 +1,171 @@
+commit b614459dc1ea353d6c24b4a77c7f92a5577d5bc3
+Author: Uli Franke <cls@nebadje.org>
+Date: Thu Jan 19 11:53:57 2012 +0100
+
+ BUG(2510): Add more bitrates/samplerates to AAC/ALAC.
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index 1b4a659..b32de4d 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -60,6 +60,7 @@ static gint xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len
+ xmms_error_t *error);
+ static gint64 xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples,
+ xmms_xform_seek_mode_t whence, xmms_error_t *err);
++static xmms_sample_format_t xmms_avcodec_translate_sample_format (enum AVSampleFormat av_sample_format);
+
+ /*
+ * Plugin header
+@@ -168,12 +169,12 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->channels = ret;
+ }
+
+- /* bitrate required for WMA files */
++ /* Required by WMA xform. */
+ xmms_xform_auxdata_get_int (xform,
+ "bitrate",
+ &data->bitrate);
+
+- /* ALAC and MAC require bits per sample field to be 16 */
++ /* Required by tta and apefile xforms. */
+ xmms_xform_auxdata_get_int (xform,
+ "samplebits",
+ &data->samplebits);
+@@ -238,12 +239,17 @@ xmms_avcodec_init (xmms_xform_t *xform)
+
+ data->samplerate = data->codecctx->sample_rate;
+ data->channels = data->codecctx->channels;
++ data->sampleformat = xmms_avcodec_translate_sample_format (data->codecctx->sample_fmt);
++ if (data->sampleformat == XMMS_SAMPLE_FORMAT_UNKNOWN) {
++ avcodec_close (data->codecctx);
++ goto err;
++ }
+
+ xmms_xform_outdata_type_add (xform,
+ XMMS_STREAM_TYPE_MIMETYPE,
+ "audio/pcm",
+ XMMS_STREAM_TYPE_FMT_FORMAT,
+- XMMS_SAMPLE_FORMAT_S16,
++ data->sampleformat,
+ XMMS_STREAM_TYPE_FMT_CHANNELS,
+ data->channels,
+ XMMS_STREAM_TYPE_FMT_SAMPLERATE,
+@@ -428,3 +434,23 @@ xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t w
+
+ return ret;
+ }
++
++static xmms_sample_format_t
++xmms_avcodec_translate_sample_format (enum AVSampleFormat av_sample_format)
++{
++ switch (av_sample_format) {
++ case AV_SAMPLE_FMT_U8:
++ return XMMS_SAMPLE_FORMAT_U8;
++ case AV_SAMPLE_FMT_S16:
++ return XMMS_SAMPLE_FORMAT_S16;
++ case AV_SAMPLE_FMT_S32:
++ return XMMS_SAMPLE_FORMAT_S32;
++ case AV_SAMPLE_FMT_FLT:
++ return XMMS_SAMPLE_FORMAT_FLOAT;
++ case AV_SAMPLE_FMT_DBL:
++ return XMMS_SAMPLE_FORMAT_DOUBLE;
++ default:
++ XMMS_DBG ("AVSampleFormat (%i) not supported.", av_sample_format);
++ return XMMS_SAMPLE_FORMAT_UNKNOWN;
++ }
++}
+diff --git a/src/plugins/mp4/mp4.c b/src/plugins/mp4/mp4.c
+index 7c915c4..3ee9357 100644
+--- a/src/plugins/mp4/mp4.c
++++ b/src/plugins/mp4/mp4.c
+@@ -186,9 +186,6 @@ xmms_mp4_init (xmms_xform_t *xform)
+ xmms_xform_auxdata_set_bin (xform, "decoder_config", tmpbuf, tmpbuflen);
+ g_free (tmpbuf);
+
+- /* This is only for ALAC to set 16-bit samples, ignored for AAC */
+- xmms_xform_auxdata_set_int (xform, "samplebits", 16);
+-
+ xmms_mp4_get_mediainfo (xform);
+
+ XMMS_DBG ("MP4 demuxer inited successfully!");
+@@ -288,7 +285,7 @@ xmms_mp4_get_mediainfo (xmms_xform_t *xform)
+ data = xmms_xform_private_data_get (xform);
+ g_return_if_fail (data);
+
+- if ((temp = mp4ff_get_sample_rate (data->mp4ff, data->track)) >= 0) {
++ if ((temp = mp4ff_get_sample_rate (data->mp4ff, data->track)) > 0) {
+ glong srate = temp;
+
+ if ((temp = mp4ff_get_track_duration_use_offsets (data->mp4ff,
+@@ -492,7 +489,7 @@ xmms_mp4_get_track (xmms_xform_t *xform, mp4ff_t *infile)
+ case 0x69: /* MPEG-2 audio */
+ case 0x6B: /* MPEG-1 audio */
+ continue;
+- case 0xff:
++ case 0xff: /* ALAC */
+ chans = mp4ff_get_channel_count (infile, i);
+ rate = mp4ff_get_sample_rate (infile, i);
+ if (chans <= 0 || rate <= 0) {
+diff --git a/src/plugins/mp4/mp4ff/README.xmms2 b/src/plugins/mp4/mp4ff/README.xmms2
+index c2737c5..8021618 100644
+--- a/src/plugins/mp4/mp4ff/README.xmms2
++++ b/src/plugins/mp4/mp4ff/README.xmms2
+@@ -12,3 +12,4 @@ Changes:
+ * Add value_length variable to tag type and use it when adding new item-value pairs,
+ necessary for cover art since it's binary data and can't be handled as a string
+ * Add support for Apple Lossless audio files
++ * Add a workaround for supporting higher samplerates.
+diff --git a/src/plugins/mp4/mp4ff/mp4ff.c b/src/plugins/mp4/mp4ff/mp4ff.c
+index ee7f7fb..b6f0a37 100644
+--- a/src/plugins/mp4/mp4ff/mp4ff.c
++++ b/src/plugins/mp4/mp4ff/mp4ff.c
+@@ -32,6 +32,8 @@
+ #include <string.h>
+ #include "mp4ffint.h"
+
++static uint32_t mp4ff_normalize_flawed_sample_rate (uint16_t samplerate);
++
+ mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f)
+ {
+ mp4ff_t *ff = malloc(sizeof(mp4ff_t));
+@@ -304,12 +306,39 @@ int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
+ return total;
+ }
+
++static uint32_t
++mp4ff_normalize_flawed_sample_rate (uint16_t samplerate)
++{
++ /* A list of common rates can be found at
++ * http://en.wikipedia.org/wiki/Sampling_rate */
++ uint32_t rates[] = {8000, 11025, 16000, 22050, 32000, 44056, 44100,
++ 47250, 48000, 50000, 50400, 88200, 96000, 176400,
++ 192000, 352800, 384000, 0};
++ uint32_t* rate;
++
++ /* First check standard rates. */
++ for (rate = rates; *rate; rate++) {
++ if (*rate == samplerate) {
++ return *rate;
++ }
++ }
++
++ /* No standard rates matching - check if sample rate got truncated when
++ * added to MP4 container */
++ for (rate = rates; *rate; rate++) {
++ if ((*rate & 0x0000FFFF) == samplerate) {
++ return *rate;
++ }
++ }
+
++ /* Failed to find a standard rate - we give up returning the original rate */
++ return samplerate;
++}
+
+
+ uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track)
+ {
+- return f->track[track]->sampleRate;
++ return mp4ff_normalize_flawed_sample_rate (f->track[track]->sampleRate);
+ }
+
+ uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track)
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p3.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p3.patch
new file mode 100644
index 000000000000..a9145c0d3d26
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p3.patch
@@ -0,0 +1,388 @@
+commit 4d0682030e20a8ed218f4ff924554f93d276d9ee
+Author: Anthony Garcia <lagg@lavabit.com>
+Date: Thu Apr 22 16:59:37 2010 -0700
+
+ OTHER: Cleanup
+
+ Re-enabled nellymoser (ffmpeg appears to be okay with it now)
+
+ Fixed possible infinite loop in the code that handles the data (if any)
+ between the header and tag data.
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index 6c9fea8..5554056 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -90,7 +90,7 @@ xmms_avcodec_plugin_setup (xmms_xform_plugin_t *xform_plugin)
+ xmms_magic_add ("A/52 (AC-3) header", "audio/x-ffmpeg-ac3",
+ "0 beshort 0x0b77", NULL);
+ xmms_magic_add ("DTS header", "audio/x-ffmpeg-dca",
+- "0 belong 0x7ffe8001", NULL);
++ "0 belong 0x7ffe8001", NULL);
+
+ xmms_xform_plugin_indata_add (xform_plugin,
+ XMMS_STREAM_TYPE_MIMETYPE,
+@@ -197,7 +197,8 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ !strcmp (data->codec_id, "adpcm_swf") ||
+ !strcmp (data->codec_id, "pcm_s16le") ||
+ !strcmp (data->codec_id, "ac3") ||
+- !strcmp (data->codec_id, "dca")) {
++ !strcmp (data->codec_id, "dca") ||
++ !strcmp (data->codec_id, "nellymoser")) {
+ /* number 1024 taken from libavformat raw.c RAW_PACKET_SIZE */
+ data->extradata = g_malloc0 (1024);
+ data->extradata_size = 1024;
+diff --git a/src/plugins/flv/flv.c b/src/plugins/flv/flv.c
+index 440010c..266fea6 100644
+--- a/src/plugins/flv/flv.c
++++ b/src/plugins/flv/flv.c
+@@ -25,29 +25,41 @@
+ * and other info, then data
+ */
+ #define FLV_TAG_SIZE 11
+-/* random constant */
+ #define FLV_CHUNK_SIZE 4096
+
+-/* let libavcodec take care of swapping sample bytes */
+-static const gchar *mime_pcm_s16le = "audio/x-ffmpeg-pcm_s16le";
+-static const gchar *fmt_mime[11] = {
+- /* Supported when samples are 8 bit
+- * (otherwise there's no way of knowing endianness)
+- */
+- "audio/pcm",
+- "audio/x-ffmpeg-adpcm_swf",
+- "audio/mpeg",
+- /* if bps is 8 bit u8
+- * if bps is 16 bit sle16
+- */
+- "audio/pcm",
+- /* libavcodec can't handle nelly without dying yet */
+- /*"audio/x-ffmpeg-nellymoser",
+- "audio/x-ffmpeg-nellymoser",
+- "audio/x-ffmpeg-nellymoser",*/
+- "", "", "",
+- "", "", "",
+- "audio/aac"
++typedef enum {
++ /* Only u8 bit samples since
++ there's no way to determine endianness
++ */
++ CODEC_PCM_HOST,
++ CODEC_ADPCM,
++ CODEC_MP3,
++ /* 8 bps: unsigned
++ 16 bps: signed
++ */
++ CODEC_PCM_LE,
++ CODEC_NELLYMOSER_16K,
++ CODEC_NELLYMOSER_8K,
++ /* Uses the sample rate in
++ the tag as normal
++ */
++ CODEC_NELLYMOSER,
++ CODEC_AAC = 10
++} xmms_flv_codec_id;
++
++struct xmms_flv_codec_table {
++ xmms_flv_codec_id id;
++ const gchar *mime;
++} static flv_codecs[] = {
++ {CODEC_PCM_HOST, "audio/pcm"},
++ {CODEC_ADPCM, "audio/x-ffmpeg-adpcm_swf"},
++ {CODEC_MP3, "audio/mpeg"},
++ /* Will be audio/x-ffmpeg-pcm_s16le if bps is 16 */
++ {CODEC_PCM_LE, "audio/pcm"},
++ {CODEC_NELLYMOSER_16K, "audio/x-ffmpeg-nellymoser"},
++ {CODEC_NELLYMOSER_8K, "audio/x-ffmpeg-nellymoser"},
++ {CODEC_NELLYMOSER, "audio/x-ffmpeg-nellymoser"},
++ {CODEC_AAC, "audio/aac"}
+ };
+
+ typedef struct {
+@@ -111,23 +123,26 @@ static gboolean
+ xmms_flv_init (xmms_xform_t *xform)
+ {
+ xmms_sample_format_t bps;
+- gint readret;
++ gint readret, i;
+ guint8 channels, flags, format;
+- guint8 header[FLV_TAG_SIZE + 5];
+- const gchar *mime;
++ guint8 header[FLV_TAG_SIZE + 1];
+ guint32 dataoffset, samplerate;
+ xmms_error_t err;
+ xmms_flv_data_t *flvdata;
++ struct xmms_flv_codec_table *codec = NULL;
++
++ flvdata = g_new0 (xmms_flv_data_t, 1);
++ xmms_xform_private_data_set (xform, flvdata);
+
+ readret = xmms_xform_read (xform, header, FLV_HDR_SIZE, &err);
+ if (readret != FLV_HDR_SIZE) {
+ xmms_log_error ("Header read error");
+- return FALSE;
++ goto init_err;
+ }
+
+ if ((header[4] & HAS_AUDIO) != HAS_AUDIO) {
+ xmms_log_error ("FLV has no audio stream");
+- return FALSE;
++ goto init_err;
+ }
+
+ dataoffset = get_be32 (&header[5]) - FLV_HDR_SIZE;
+@@ -140,7 +155,7 @@ xmms_flv_init (xmms_xform_t *xform)
+ dataoffset : FLV_HDR_SIZE, &err);
+ if (readret <= 0) {
+ xmms_log_error ("Error reading header:tag body gap");
+- return FALSE;
++ goto init_err;
+ }
+
+ dataoffset -= readret;
+@@ -148,86 +163,99 @@ xmms_flv_init (xmms_xform_t *xform)
+
+ if (next_audio_tag (xform) <= 0) {
+ xmms_log_error ("Can't find first audio tag");
+- return FALSE;
++ goto init_err;
+ }
+
+- if (xmms_xform_peek (xform, header, FLV_TAG_SIZE + 5, &err) < FLV_TAG_SIZE + 5) {
++ if (xmms_xform_read (xform, header, FLV_TAG_SIZE + 1, &err) < FLV_TAG_SIZE + 1) {
+ xmms_log_error ("Can't read first audio tag");
+- return FALSE;
++ goto init_err;
+ }
+
+- flags = header[FLV_TAG_SIZE + 4];
++ flags = header[11];
+ XMMS_DBG ("Audio flags: %X", flags);
+
+- switch (flags&12) {
+- case 0: samplerate = 5512; break;
+- case 4: samplerate = 11025; break;
+- case 8: samplerate = 22050; break;
+- case 12: samplerate = 44100; break;
+- default: samplerate = 8000; break;
++ format = flags >> 4;
++ for (i = 0; i < G_N_ELEMENTS (flv_codecs); i++) {
++ if (flv_codecs[i].id == format) {
++ codec = &flv_codecs[i];
++ break;
++ }
+ }
+
+- if (flags&2) {
+- bps = XMMS_SAMPLE_FORMAT_S16;
++ if (flags & 1) {
++ channels = 2;
+ } else {
+- bps = XMMS_SAMPLE_FORMAT_U8;
++ channels = 1;
+ }
+
+- if (flags&1) {
+- channels = 2;
++ if (flags & 2) {
++ bps = XMMS_SAMPLE_FORMAT_S16;
+ } else {
+- channels = 1;
++ bps = XMMS_SAMPLE_FORMAT_U8;
+ }
+
+- format = flags >> 4;
+- mime = (format <= 10)? fmt_mime[format] : NULL;
+- switch (format) {
+- case 0:
+- /* If the flv has an HE PCM audio stream, the
+- * samples must be unsigned and 8 bits long
+- */
+- if (bps != XMMS_SAMPLE_FORMAT_U8) {
+- xmms_log_error ("Only u8 HE PCM is supported");
+- return FALSE;
+- }
+- break;
+- case 3:
+- if (bps == XMMS_SAMPLE_FORMAT_S16) {
+- mime = mime_pcm_s16le;
+- }
+- break;
++ switch ((flags & 12) >> 2) {
++ case 0: samplerate = 5512; break;
++ case 1: samplerate = 11025; break;
++ case 2: samplerate = 22050; break;
++ case 3: samplerate = 44100; break;
++ default: samplerate = 8000; break;
+ }
+
+- if (mime && *mime) {
+- flvdata = g_new0 (xmms_flv_data_t, 1);
++ if (codec) {
++ switch (codec->id) {
++ case CODEC_PCM_HOST:
++ if (bps != XMMS_SAMPLE_FORMAT_U8) {
++ xmms_log_error ("Only u8 HE PCM is supported");
++ goto init_err;
++ }
++ break;
++ case CODEC_PCM_LE:
++ if (bps == XMMS_SAMPLE_FORMAT_S16) {
++ codec->mime = "audio/x-ffmpeg-pcm_s16le";
++ }
++ break;
++ case CODEC_NELLYMOSER_16K:
++ samplerate = 16000;
++ break;
++ case CODEC_NELLYMOSER_8K:
++ samplerate = 8000;
++ break;
++ default:
++ break;
++ }
++
+ flvdata->format = format;
++ flvdata->last_datasize = get_be24 (&header[1]) - 1;
+
+ XMMS_DBG ("Rate: %d, bps: %d, channels: %d", samplerate,
+ bps, channels);
+
+- xmms_xform_private_data_set (xform, flvdata);
+ xmms_xform_outdata_type_add (xform,
+ XMMS_STREAM_TYPE_MIMETYPE,
+- mime,
+- XMMS_STREAM_TYPE_FMT_SAMPLERATE,
+- samplerate,
+- XMMS_STREAM_TYPE_FMT_FORMAT,
+- bps,
+- XMMS_STREAM_TYPE_FMT_CHANNELS,
+- channels,
+- XMMS_STREAM_TYPE_END);
++ codec->mime,
++ XMMS_STREAM_TYPE_FMT_SAMPLERATE,
++ samplerate,
++ XMMS_STREAM_TYPE_FMT_FORMAT,
++ bps,
++ XMMS_STREAM_TYPE_FMT_CHANNELS,
++ channels,
++ XMMS_STREAM_TYPE_END);
+ return TRUE;
+ } else {
+ xmms_log_error ("Unsupported audio format");
+- return FALSE;
+ }
++
++init_err:
++ g_free (flvdata);
++ return FALSE;
+ }
+
+ static gint
+ xmms_flv_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
+ {
+- gint ret = 0, thismuch = FLV_TAG_SIZE + 5;
+- guint8 header[FLV_TAG_SIZE + 6], gap = 1;
++ gint ret = 0, thismuch = FLV_TAG_SIZE + 1;
++ guint8 header[FLV_TAG_SIZE + 1];
+ xmms_flv_data_t *data = NULL;
+
+ data = xmms_xform_private_data_get (xform);
+@@ -236,12 +264,8 @@ xmms_flv_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *
+ xmms_xform_auxdata_barrier (xform);
+ ret = next_audio_tag (xform);
+ if (ret > 0) {
+- if (data->format == 10) {
+- thismuch++;
+- gap++;
+- }
+ if (xmms_xform_read (xform, header, thismuch, err) == thismuch) {
+- data->last_datasize = get_be24 (&header[5]) - gap;
++ data->last_datasize = get_be24 (&header[1]) - 1;
+ } else {
+ xmms_log_error ("Need %d bytes", thismuch);
+ return -1;
+@@ -280,40 +304,51 @@ xmms_flv_destroy (xmms_xform_t *xform)
+ static gint
+ next_audio_tag (xmms_xform_t *xform)
+ {
+- guint8 header[FLV_TAG_SIZE + 4];
++ guint8 header[FLV_TAG_SIZE];
+ guint8 dumb[FLV_CHUNK_SIZE];
+ gint ret = 0;
+ xmms_error_t err;
+- guint32 datasize = 0;
++ xmms_flv_data_t *data;
++
++ data = xmms_xform_private_data_get (xform);
+
+ do {
+- /* there's a last 4 bytes at the end of an FLV giving the final
+- * tag's size, this isn't an error
+- */
+- ret = xmms_xform_peek (xform, header, FLV_TAG_SIZE + 4, &err);
+- if ((ret < FLV_TAG_SIZE) && (ret > -1)) {
+- ret = 0;
+- break;
+- } else if (ret == -1) {
+- xmms_log_error ("%s", xmms_error_message_get (&err));
+- break;
+- }
++ /* If > 0 assume we're in the middle of a tag's data */
++ if (!data->last_datasize) {
++ /* There are 4 bytes before an actual tag giving
++ the previous tag's size. The first size in an
++ flv is always 0.
++ */
++ if (xmms_xform_read (xform, header, 4, &err) != 4) {
++ xmms_log_error ("Couldn't read last tag size");
++ return -1;
++ }
+
+- if (header[4] == 8) {
+- /* woo audio tag! */
+- break;
+- }
++ ret = xmms_xform_peek (xform, header, FLV_TAG_SIZE, &err);
++ if ((ret < FLV_TAG_SIZE) && (ret > -1)) {
++ return 0;
++ } else if (ret == -1) {
++ xmms_log_error ("%s", xmms_error_message_get (&err));
++ return ret;
++ }
++
++ if (header[0] == 8) {
++ /* woo audio tag! */
++ break;
++ }
+
+- ret = xmms_xform_read (xform, header, FLV_TAG_SIZE + 4, &err);
+- if (ret <= 0) { return ret; }
++ if ((ret = xmms_xform_read (xform, header, FLV_TAG_SIZE, &err)) <= 0) {
++ return ret;
++ }
+
+- datasize = get_be24 (&header[5]);
++ data->last_datasize = get_be24 (&header[1]);
++ }
+
+- while (datasize) {
++ while (data->last_datasize) {
+ ret = xmms_xform_read (xform, dumb,
+- (datasize < FLV_CHUNK_SIZE) ?
+- datasize : FLV_CHUNK_SIZE,
+- &err);
++ (data->last_datasize < FLV_CHUNK_SIZE) ?
++ data->last_datasize : FLV_CHUNK_SIZE,
++ &err);
+ if (ret == 0) {
+ xmms_log_error ("Data field short!");
+ break;
+@@ -323,7 +358,7 @@ next_audio_tag (xmms_xform_t *xform)
+ break;
+ }
+
+- datasize -= ret;
++ data->last_datasize -= ret;
+ }
+
+ } while (ret);
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p4.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p4.patch
new file mode 100644
index 000000000000..552f202df19d
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p4.patch
@@ -0,0 +1,296 @@
+commit 4198d9bf5dff517740ed51b22313367f156107e1
+Author: Erik Massop <e.massop@hccnet.nl>
+Date: Sun Dec 22 17:19:30 2013 +0100
+
+ OTHER: Split xmms_avcodec_read, remove some duplicate code
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index 5b9b606..eed7964 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -57,6 +57,9 @@ typedef struct {
+ static gboolean xmms_avcodec_plugin_setup (xmms_xform_plugin_t *xform_plugin);
+ static gboolean xmms_avcodec_init (xmms_xform_t *xform);
+ static void xmms_avcodec_destroy (xmms_xform_t *xform);
++static gint xmms_avcodec_internal_read_some (xmms_xform_t *xform, xmms_avcodec_data_t *data, xmms_error_t *error);
++static gint xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data);
++static void xmms_avcodec_internal_append (xmms_avcodec_data_t *data);
+ static gint xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len,
+ xmms_error_t *error);
+ static gint64 xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples,
+@@ -281,101 +284,24 @@ xmms_avcodec_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len,
+ xmms_error_t *error)
+ {
+ xmms_avcodec_data_t *data;
+- gint bytes_read = 0;
+ guint size;
+
+ data = xmms_xform_private_data_get (xform);
+ g_return_val_if_fail (data, -1);
+
+- size = MIN (data->outbuf->len, len);
+- while (size == 0) {
+- AVPacket packet;
+- av_init_packet (&packet);
++ while (0 == (size = MIN (data->outbuf->len, len))) {
++ gint res;
+
+ if (data->no_demuxer || data->buffer_length == 0) {
+- gint read_total;
+-
+- bytes_read = xmms_xform_read (xform,
+- (gchar *) (data->buffer + data->buffer_length),
+- data->buffer_size - data->buffer_length,
+- error);
+-
+- if (bytes_read < 0) {
+- XMMS_DBG ("Error while reading data");
+- return bytes_read;
+- } else if (bytes_read == 0) {
+- XMMS_DBG ("EOF");
+- return 0;
+- }
+-
+- read_total = bytes_read;
+-
+- /* If we have a demuxer plugin, make sure we read the whole packet */
+- while (read_total == data->buffer_size && !data->no_demuxer) {
+- /* multiply the buffer size and try to read again */
+- data->buffer = g_realloc (data->buffer, data->buffer_size * 2);
+- bytes_read = xmms_xform_read (xform,
+- (gchar *) data->buffer +
+- data->buffer_size,
+- data->buffer_size,
+- error);
+- data->buffer_size *= 2;
+-
+- if (bytes_read < 0) {
+- XMMS_DBG ("Error while reading data");
+- return bytes_read;
+- }
+-
+- read_total += bytes_read;
+-
+- if (read_total < data->buffer_size) {
+- /* finally double the buffer size for performance reasons, the
+- * hotspot handling likes to fit two frames in the buffer */
+- data->buffer = g_realloc (data->buffer, data->buffer_size * 2);
+- data->buffer_size *= 2;
+- XMMS_DBG ("Reallocated avcodec internal buffer to be %d bytes",
+- data->buffer_size);
+-
+- break;
+- }
+- }
+-
+- /* Update the buffer length */
+- data->buffer_length += read_total;
+- }
+-
+- packet.data = data->buffer;
+- packet.size = data->buffer_length;
+-
+- data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+- bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) data->read_out_buffer,
+- &data->read_out_buffer_size, &packet);
++ gint bytes_read;
+
+- /* The DTS decoder of ffmpeg is buggy and always returns
+- * the input buffer length, get frame length from header */
+- if (!strcmp (data->codec_id, "dca") && bytes_read > 0) {
+- bytes_read = ((int)data->buffer[5] << 12) |
+- ((int)data->buffer[6] << 4) |
+- ((int)data->buffer[7] >> 4);
+- bytes_read = (bytes_read & 0x3fff) + 1;
++ bytes_read = xmms_avcodec_internal_read_some (xform, data, error);
++ if (bytes_read <= 0) { return bytes_read; }
+ }
+
+- if (bytes_read < 0 || bytes_read > data->buffer_length) {
+- XMMS_DBG ("Error decoding data!");
+- return -1;
+- } else if (bytes_read != data->buffer_length) {
+- g_memmove (data->buffer,
+- data->buffer + bytes_read,
+- data->buffer_length - bytes_read);
+- }
+-
+- data->buffer_length -= bytes_read;
+-
+- if (data->read_out_buffer_size > 0) {
+- g_string_append_len (data->outbuf, data->read_out_buffer, data->read_out_buffer_size);
+- }
+-
+- size = MIN (data->outbuf->len, len);
++ res = xmms_avcodec_internal_decode_some (data);
++ if (res < 0) { return res; }
++ if (res > 0) { xmms_avcodec_internal_append (data); }
+ }
+
+ memcpy (buf, data->outbuf->str, size);
+@@ -388,7 +314,6 @@ static gint64
+ xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err)
+ {
+ xmms_avcodec_data_t *data;
+- gint bytes_read = 0;
+ gint64 ret = -1;
+
+ g_return_val_if_fail (xform, -1);
+@@ -406,23 +331,11 @@ xmms_avcodec_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t w
+
+ /* The buggy ape decoder doesn't flush buffers, so we need to finish decoding
+ * the frame before seeking to avoid segfaults... this hack sucks */
++ /* FIXME: Is ^^^ still true? */
+ while (data->buffer_length > 0) {
+- AVPacket packet;
+- av_init_packet (&packet);
+- packet.data = data->buffer;
+- packet.size = data->buffer_length;
+-
+- data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+- bytes_read = avcodec_decode_audio3 (data->codecctx, (short *) data->read_out_buffer,
+- &data->read_out_buffer_size, &packet);
+-
+- if (bytes_read < 0 || bytes_read > data->buffer_length) {
+- XMMS_DBG ("Error decoding data!");
++ if (xmms_avcodec_internal_decode_some (data) < 0) {
+ return -1;
+ }
+-
+- data->buffer_length -= bytes_read;
+- g_memmove (data->buffer, data->buffer + bytes_read, data->buffer_length);
+ }
+
+ ret = xmms_xform_seek (xform, samples, whence, err);
+@@ -456,3 +369,131 @@ xmms_avcodec_translate_sample_format (enum AVSampleFormat av_sample_format)
+ return XMMS_SAMPLE_FORMAT_UNKNOWN;
+ }
+ }
++
++/*
++Read some data from our source of data to data->buffer, updating buffer_length
++and buffer_size as needed.
++
++Returns: on error: negative
++ on EOF: zero
++ otherwise: number of bytes read.
++*/
++static gint
++xmms_avcodec_internal_read_some (xmms_xform_t *xform,
++ xmms_avcodec_data_t *data,
++ xmms_error_t *error)
++{
++ gint bytes_read, read_total;
++
++ bytes_read = xmms_xform_read (xform,
++ (gchar *) (data->buffer + data->buffer_length),
++ data->buffer_size - data->buffer_length,
++ error);
++
++ if (bytes_read < 0) {
++ XMMS_DBG ("Error while reading data");
++ return bytes_read;
++ } else if (bytes_read == 0) {
++ XMMS_DBG ("EOF");
++ return 0;
++ }
++
++ read_total = bytes_read;
++
++ /* If we have a demuxer plugin, make sure we read the whole packet */
++ while (read_total == data->buffer_size && !data->no_demuxer) {
++ /* multiply the buffer size and try to read again */
++ data->buffer = g_realloc (data->buffer, data->buffer_size * 2);
++ bytes_read = xmms_xform_read (xform,
++ (gchar *) data->buffer +
++ data->buffer_size,
++ data->buffer_size,
++ error);
++ data->buffer_size *= 2;
++
++ if (bytes_read < 0) {
++ XMMS_DBG ("Error while reading data");
++ return bytes_read;
++ }
++
++ read_total += bytes_read;
++
++ if (read_total < data->buffer_size) {
++ /* finally double the buffer size for performance reasons, the
++ * hotspot handling likes to fit two frames in the buffer */
++ data->buffer = g_realloc (data->buffer, data->buffer_size * 2);
++ data->buffer_size *= 2;
++ XMMS_DBG ("Reallocated avcodec internal buffer to be %d bytes",
++ data->buffer_size);
++
++ break;
++ }
++ }
++
++ /* Update the buffer length */
++ data->buffer_length += read_total;
++
++ return read_total;
++}
++
++/*
++Decode some data from data->buffer[0..data->buffer_length-1] to
++data->read_out_buffer. Number of bytes in data->read_out_buffer
++is stored in data->read_out_buffer_size.
++
++Returns: on error: negative
++ on no new data produced: zero
++ otherwise: positive
++
++FIXME: data->buffer should be at least data->buffer_length +
++FF_INPUT_BUFFER_PADDING_SIZE long.
++*/
++static gint
++xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data)
++{
++ gint bytes_read = 0;
++ AVPacket packet;
++
++ av_init_packet (&packet);
++ packet.data = data->buffer;
++ packet.size = data->buffer_length;
++
++ data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
++ bytes_read = avcodec_decode_audio3 (data->codecctx,
++ (short *) data->read_out_buffer,
++ &data->read_out_buffer_size, &packet);
++
++ /* The DTS decoder of ffmpeg is buggy and always returns
++ * the input buffer length, get frame length from header */
++ /* FIXME: Is ^^^^ still true? */
++ if (!strcmp (data->codec_id, "dca") && bytes_read > 0) {
++ bytes_read = ((int)data->buffer[5] << 12) |
++ ((int)data->buffer[6] << 4) |
++ ((int)data->buffer[7] >> 4);
++ bytes_read = (bytes_read & 0x3fff) + 1;
++ }
++
++ if (bytes_read < 0 || bytes_read > data->buffer_length) {
++ XMMS_DBG ("Error decoding data!");
++ return -1;
++ }
++
++ if (bytes_read < data->buffer_length) {
++ data->buffer_length -= bytes_read;
++ g_memmove (data->buffer,
++ data->buffer + bytes_read,
++ data->buffer_length);
++ } else {
++ data->buffer_length = 0;
++ }
++
++ return data->read_out_buffer_size;
++}
++
++static void
++xmms_avcodec_internal_append (xmms_avcodec_data_t *data)
++{
++ g_string_append_len (data->outbuf,
++ (gchar *) data->read_out_buffer,
++ data->read_out_buffer_size);
++}
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p5.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p5.patch
new file mode 100644
index 000000000000..8ed5bb4a24a5
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p5.patch
@@ -0,0 +1,154 @@
+commit d44312fb14bde0ab47ee6de1b3fe7435d4a97c99
+Author: Erik Massop <e.massop@hccnet.nl>
+Date: Sun Dec 22 20:01:18 2013 +0100
+
+ BUG(2572): Use avcodec_decode_audio4
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index 266a607..a41a675 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -37,8 +37,7 @@ typedef struct {
+ guint buffer_size;
+ gboolean no_demuxer;
+
+- gchar *read_out_buffer;
+- gint read_out_buffer_size;
++ AVFrame *read_out_frame;
+
+ guint channels;
+ guint samplerate;
+@@ -125,7 +124,7 @@ xmms_avcodec_destroy (xmms_xform_t *xform)
+
+ avcodec_close (data->codecctx);
+ av_free (data->codecctx);
+- av_free (data->read_out_buffer);
++ avcodec_free_frame (&data->read_out_frame);
+
+ g_string_free (data->outbuf, TRUE);
+ g_free (data->buffer);
+@@ -151,8 +150,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->buffer_size = AVCODEC_BUFFER_SIZE;
+ data->codecctx = NULL;
+
+- data->read_out_buffer = av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
+- data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
++ data->read_out_frame = avcodec_alloc_frame ();
+
+ xmms_xform_private_data_set (xform, data);
+
+@@ -233,6 +231,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->codecctx->extradata_size = data->extradata_size;
+ data->codecctx->codec_id = codec->id;
+ data->codecctx->codec_type = codec->type;
++ data->codecctx->refcounted_frames = 0;
+
+ if (avcodec_open2 (data->codecctx, codec, NULL) < 0) {
+ XMMS_DBG ("Opening decoder '%s' failed", codec->name);
+@@ -279,8 +278,8 @@ err:
+ if (data->codecctx) {
+ av_free (data->codecctx);
+ }
+- if (data->read_out_buffer) {
+- av_free (data->read_out_buffer);
++ if (data->read_out_frame) {
++ avcodec_free_frame (&data->read_out_frame);
+ }
+ g_string_free (data->outbuf, TRUE);
+ g_free (data->extradata);
+@@ -365,17 +364,23 @@ xmms_avcodec_translate_sample_format (enum AVSampleFormat av_sample_format)
+ {
+ switch (av_sample_format) {
+ case AV_SAMPLE_FMT_U8:
++ case AV_SAMPLE_FMT_U8P:
+ return XMMS_SAMPLE_FORMAT_U8;
+ case AV_SAMPLE_FMT_S16:
++ case AV_SAMPLE_FMT_S16P:
+ return XMMS_SAMPLE_FORMAT_S16;
+ case AV_SAMPLE_FMT_S32:
++ case AV_SAMPLE_FMT_S32P:
+ return XMMS_SAMPLE_FORMAT_S32;
+ case AV_SAMPLE_FMT_FLT:
++ case AV_SAMPLE_FMT_FLTP:
+ return XMMS_SAMPLE_FORMAT_FLOAT;
+ case AV_SAMPLE_FMT_DBL:
++ case AV_SAMPLE_FMT_DBLP:
+ return XMMS_SAMPLE_FORMAT_DOUBLE;
+ default:
+- XMMS_DBG ("AVSampleFormat (%i) not supported.", av_sample_format);
++ XMMS_DBG ("AVSampleFormat (%i: %s) not supported.", av_sample_format,
++ av_get_sample_fmt_name (av_sample_format));
+ return XMMS_SAMPLE_FORMAT_UNKNOWN;
+ }
+ }
+@@ -448,8 +453,7 @@ xmms_avcodec_internal_read_some (xmms_xform_t *xform,
+
+ /*
+ Decode some data from data->buffer[0..data->buffer_length-1] to
+-data->read_out_buffer. Number of bytes in data->read_out_buffer
+-is stored in data->read_out_buffer_size.
++data->read_out_frame
+
+ Returns: on error: negative
+ on no new data produced: zero
+@@ -461,6 +465,7 @@ FF_INPUT_BUFFER_PADDING_SIZE long.
+ static gint
+ xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data)
+ {
++ int got_frame = 0;
+ gint bytes_read = 0;
+ AVPacket packet;
+
+@@ -468,10 +473,10 @@ xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data)
+ packet.data = data->buffer;
+ packet.size = data->buffer_length;
+
+- data->read_out_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+- bytes_read = avcodec_decode_audio3 (data->codecctx,
+- (short *) data->read_out_buffer,
+- &data->read_out_buffer_size, &packet);
++ avcodec_get_frame_defaults (data->read_out_frame);
++
++ bytes_read = avcodec_decode_audio4 (
++ data->codecctx, data->read_out_frame, &got_frame, &packet);
+
+ /* The DTS decoder of ffmpeg is buggy and always returns
+ * the input buffer length, get frame length from header */
+@@ -497,13 +502,33 @@ xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data)
+ data->buffer_length = 0;
+ }
+
+- return data->read_out_buffer_size;
++ return got_frame ? 1 : 0;
+ }
+
+ static void
+ xmms_avcodec_internal_append (xmms_avcodec_data_t *data)
+ {
+- g_string_append_len (data->outbuf,
+- (gchar *) data->read_out_buffer,
+- data->read_out_buffer_size);
++ enum AVSampleFormat fmt = (enum AVSampleFormat) data->read_out_frame->format;
++ int samples = data->read_out_frame->nb_samples;
++ int channels = data->codecctx->channels;
++ int bps = av_get_bytes_per_sample (fmt);
++
++ if (av_sample_fmt_is_planar (fmt)) {
++ /* Convert from planar to packed format */
++ gint i, j;
++
++ for (i = 0; i < samples; i++) {
++ for (j = 0; j < channels; j++) {
++ g_string_append_len (
++ data->outbuf,
++ (gchar *) (data->read_out_frame->extended_data[j] + i*bps),
++ bps
++ );
++ }
++ }
++ } else {
++ g_string_append_len (data->outbuf,
++ (gchar *) data->read_out_frame->extended_data[0],
++ samples * channels * bps);
++ }
+ }
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p6.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p6.patch
new file mode 100644
index 000000000000..b1bc1c5d609b
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p6.patch
@@ -0,0 +1,106 @@
+commit fc66249e69f53eef709c5210546fdd92e1c89554
+Author: Erik Massop <e.massop@hccnet.nl>
+Date: Sun Dec 22 23:04:08 2013 +0100
+
+ OTHER: Some compatibility with different avcodec versions
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index a41a675..023833d 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -124,7 +124,7 @@ xmms_avcodec_destroy (xmms_xform_t *xform)
+
+ avcodec_close (data->codecctx);
+ av_free (data->codecctx);
+- avcodec_free_frame (&data->read_out_frame);
++ av_frame_free (&data->read_out_frame);
+
+ g_string_free (data->outbuf, TRUE);
+ g_free (data->buffer);
+@@ -150,7 +150,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->buffer_size = AVCODEC_BUFFER_SIZE;
+ data->codecctx = NULL;
+
+- data->read_out_frame = avcodec_alloc_frame ();
++ data->read_out_frame = av_frame_alloc ();
+
+ xmms_xform_private_data_set (xform, data);
+
+@@ -231,7 +231,6 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->codecctx->extradata_size = data->extradata_size;
+ data->codecctx->codec_id = codec->id;
+ data->codecctx->codec_type = codec->type;
+- data->codecctx->refcounted_frames = 0;
+
+ if (avcodec_open2 (data->codecctx, codec, NULL) < 0) {
+ XMMS_DBG ("Opening decoder '%s' failed", codec->name);
+@@ -473,7 +472,8 @@ xmms_avcodec_internal_decode_some (xmms_avcodec_data_t *data)
+ packet.data = data->buffer;
+ packet.size = data->buffer_length;
+
+- avcodec_get_frame_defaults (data->read_out_frame);
++ /* clear buffers and reset fields to defaults */
++ av_frame_unref (data->read_out_frame);
+
+ bytes_read = avcodec_decode_audio4 (
+ data->codecctx, data->read_out_frame, &got_frame, &packet);
+diff --git a/src/plugins/avcodec/avcodec_compat.h b/src/plugins/avcodec/avcodec_compat.h
+index 73ac2ab..e74b3f8 100644
+--- a/src/plugins/avcodec/avcodec_compat.h
++++ b/src/plugins/avcodec/avcodec_compat.h
+@@ -83,3 +83,17 @@ typedef struct AVPacket {
+ # define avcodec_open2(avctx, codec, options) \
+ avcodec_open(avctx, codec)
+ #endif
++
++/* Map avcodec_free_frame to av_freep if the former doesn't exist.
++ * (This is in versions earlier than 54.28.0 (libav) or 54.59.100 (ffmpeg)) */
++#if ! HAVE_AVCODEC_FREE_FRAME
++# define avcodec_free_frame av_freep
++#endif
++
++/* Map av_frame_alloc, av_frame_unref, av_frame_free into their
++ * deprecated versions in versions earlier than 55.28.1 */
++#if LIBAVCODEC_VERSION_INT < 0x371c01
++# define av_frame_alloc avcodec_alloc_frame
++# define av_frame_unref avcodec_get_frame_defaults
++# define av_frame_free avcodec_free_frame
++#endif
+diff --git a/src/plugins/avcodec/wscript b/src/plugins/avcodec/wscript
+index 03ba7d8..d367816 100644
+--- a/src/plugins/avcodec/wscript
++++ b/src/plugins/avcodec/wscript
+@@ -1,10 +1,33 @@
+ from waftools.plugin import plugin
+
++## Code fragments for configuration
++avcodec_free_frame_fragment = """
++#ifdef HAVE_LIBAVCODEC_AVCODEC_H
++# include "libavcodec/avcodec.h"
++#else
++# include "avcodec.h"
++#endif
++int main(void) {
++ AVFrame *frame;
++
++ avcodec_free_frame (&frame);
++
++ return 0;
++}
++"""
++
+ def plugin_configure(conf):
+ conf.check_cfg(package="libavcodec", uselib_store="avcodec",
+ args="--cflags --libs")
+ conf.check_cc(header_name="avcodec.h", uselib="avcodec", type="cshlib", mandatory=False)
+ conf.check_cc(header_name="libavcodec/avcodec.h", uselib="avcodec", type="cshlib", mandatory=False)
+
++ # non-mandatory function avcodec_free_frame since
++ # * ffmpeg: commit 46a3595, lavc 54.59.100, release 1.0
++ # * libav: commit a42aada, lavc 54.28.0, release 9
++ conf.check_cc(fragment=avcodec_free_frame_fragment, uselib="avcodec",
++ uselib_store="avcodec_free_frame",
++ msg="Checking for function avcodec_free_frame", mandatory=False)
++
+ configure, build = plugin('avcodec', configure=plugin_configure,
+ libs=["avcodec"])
diff --git a/media-sound/xmms2/files/xmms2-0.8-audio4-p7.patch b/media-sound/xmms2/files/xmms2-0.8-audio4-p7.patch
new file mode 100644
index 000000000000..2d4bafd95a7d
--- /dev/null
+++ b/media-sound/xmms2/files/xmms2-0.8-audio4-p7.patch
@@ -0,0 +1,147 @@
+commit f460440b3f2a9db1a9deef3faf7dae6e626dd7b5
+Author: Erik Massop <e.massop@hccnet.nl>
+Date: Sun Dec 22 23:34:12 2013 +0100
+
+ OTHER: Require avcodec_decode_audio4
+
+ This was introduced in versions 53.40.0 (ffmpeg) and 53.25.0 (libav) of
+ avcodec. Hence we drop compatibility for earlier versions.
+
+diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
+index 023833d..6d0b667 100644
+--- a/src/plugins/avcodec/avcodec.c
++++ b/src/plugins/avcodec/avcodec.c
+@@ -154,7 +154,6 @@ xmms_avcodec_init (xmms_xform_t *xform)
+
+ xmms_xform_private_data_set (xform, data);
+
+- avcodec_init ();
+ avcodec_register_all ();
+
+ mimetype = xmms_xform_indata_get_str (xform,
+@@ -225,7 +224,7 @@ xmms_avcodec_init (xmms_xform_t *xform)
+ data->codecctx->sample_rate = data->samplerate;
+ data->codecctx->channels = data->channels;
+ data->codecctx->bit_rate = data->bitrate;
+- CONTEXT_BPS (data->codecctx) = data->samplebits;
++ data->codecctx->bits_per_coded_sample = data->samplebits;
+ data->codecctx->block_align = data->block_align;
+ data->codecctx->extradata = data->extradata;
+ data->codecctx->extradata_size = data->extradata_size;
+diff --git a/src/plugins/avcodec/avcodec_compat.h b/src/plugins/avcodec/avcodec_compat.h
+index e74b3f8..b50fa4b 100644
+--- a/src/plugins/avcodec/avcodec_compat.h
++++ b/src/plugins/avcodec/avcodec_compat.h
+@@ -21,69 +21,6 @@
+ # include "avcodec.h"
+ #endif
+
+-/* Map avcodec_decode_audio2 into the deprecated version
+- * avcodec_decode_audio in versions earlier than 51.28 */
+-#if LIBAVCODEC_VERSION_INT < 0x331c00
+-# define avcodec_decode_audio2 avcodec_decode_audio
+-#endif
+-
+-/* Handle API change that happened in libavcodec 52.00 */
+-#if LIBAVCODEC_VERSION_INT < 0x340000
+-# define CONTEXT_BPS(codecctx) (codecctx)->bits_per_sample
+-#else
+-# define CONTEXT_BPS(codecctx) (codecctx)->bits_per_coded_sample
+-#endif
+-
+-/* Before 52.23 AVPacket was defined in avformat.h which we
+- * do not want to depend on, so we define part of it manually
+- * on versions smaller than 52.23 (this makes me cry) */
+-#if LIBAVCODEC_VERSION_INT < 0x341700
+-typedef struct AVPacket {
+- uint8_t *data;
+- int size;
+-} AVPacket;
+-#endif
+-
+-/* Same thing as above for av_init_packet and version 52.25 */
+-#if LIBAVCODEC_VERSION_INT < 0x341900
+-# define av_init_packet(pkt) do { \
+- (pkt)->data = NULL; \
+- (pkt)->size = 0; \
+- } while(0)
+-#endif
+-
+-/* Map avcodec_decode_audio3 into the deprecated version
+- * avcodec_decode_audio2 in versions earlier than 52.26 */
+-#if LIBAVCODEC_VERSION_INT < 0x341a00
+-# define avcodec_decode_audio3(avctx, samples, frame_size_ptr, avpkt) \
+- avcodec_decode_audio2(avctx, samples, frame_size_ptr, \
+- (avpkt)->data, (avpkt)->size)
+-#endif
+-
+-/* Handle API change that happened in libavcodec 52.64 */
+-#if LIBAVCODEC_VERSION_INT < 0x344000
+-# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
+-#endif
+-
+-/* Calling avcodec_init is not necessary after 53.04 (ffmpeg 0.9) */
+-#if LIBAVCODEC_VERSION_INT >= 0x350400
+-# define avcodec_init()
+-#endif
+-
+-/* Map avcodec_alloc_context3 into the deprecated version
+- * avcodec_alloc_context in versions earlier than 53.04 (ffmpeg 0.9) */
+-#if LIBAVCODEC_VERSION_INT < 0x350400
+-# define avcodec_alloc_context3(codec) \
+- avcodec_alloc_context()
+-#endif
+-
+-/* Map avcodec_open2 into the deprecated version
+- * avcodec_open in versions earlier than 53.04 (ffmpeg 0.9) */
+-#if LIBAVCODEC_VERSION_INT < 0x350400
+-# define avcodec_open2(avctx, codec, options) \
+- avcodec_open(avctx, codec)
+-#endif
+-
+ /* Map avcodec_free_frame to av_freep if the former doesn't exist.
+ * (This is in versions earlier than 54.28.0 (libav) or 54.59.100 (ffmpeg)) */
+ #if ! HAVE_AVCODEC_FREE_FRAME
+diff --git a/src/plugins/avcodec/wscript b/src/plugins/avcodec/wscript
+index d367816..00b182b 100644
+--- a/src/plugins/avcodec/wscript
++++ b/src/plugins/avcodec/wscript
+@@ -1,6 +1,24 @@
+ from waftools.plugin import plugin
+
+ ## Code fragments for configuration
++avcodec_decode_audio4_fragment = """
++#ifdef HAVE_LIBAVCODEC_AVCODEC_H
++# include "libavcodec/avcodec.h"
++#else
++# include "avcodec.h"
++#endif
++int main(void) {
++ AVCodecContext *ctx;
++ AVFrame *frame;
++ int got_frame;
++ AVPacket *pkt;
++
++ avcodec_decode_audio4 (ctx, frame, &got_frame, pkt);
++
++ return 0;
++}
++"""
++
+ avcodec_free_frame_fragment = """
+ #ifdef HAVE_LIBAVCODEC_AVCODEC_H
+ # include "libavcodec/avcodec.h"
+@@ -22,6 +40,13 @@ def plugin_configure(conf):
+ conf.check_cc(header_name="avcodec.h", uselib="avcodec", type="cshlib", mandatory=False)
+ conf.check_cc(header_name="libavcodec/avcodec.h", uselib="avcodec", type="cshlib", mandatory=False)
+
++ # mandatory function avcodec_decode_audio4 available since
++ # * ffmpeg: commit e4de716, lavc 53.40.0, release 0.9
++ # * libav: commit 0eea212, lavc 53.25.0, release 0.8
++ conf.check_cc(fragment=avcodec_decode_audio4_fragment, uselib="avcodec",
++ uselib_store="avcodec_decode_audio4",
++ msg="Checking for function avcodec_decode_audio4", mandatory=True)
++
+ # non-mandatory function avcodec_free_frame since
+ # * ffmpeg: commit 46a3595, lavc 54.59.100, release 1.0
+ # * libav: commit a42aada, lavc 54.28.0, release 9
diff --git a/media-sound/xmms2/xmms2-0.8-r2.ebuild b/media-sound/xmms2/xmms2-0.8-r2.ebuild
index 4661d2d4af6a..4500c37e84e4 100644
--- a/media-sound/xmms2/xmms2-0.8-r2.ebuild
+++ b/media-sound/xmms2/xmms2-0.8-r2.ebuild
@@ -116,6 +116,13 @@ src_prepare() {
epatch "${FILESDIR}/${P}"-ffmpeg2.patch #536232
epatch "${FILESDIR}/${P}"-cpython.patch
epatch "${FILESDIR}/${P}"-modpug.patch #536046
+ epatch "${FILESDIR}/${P}"-audio4-p1.patch
+ epatch "${FILESDIR}/${P}"-audio4-p2.patch
+ epatch "${FILESDIR}/${P}"-audio4-p3.patch
+ epatch "${FILESDIR}/${P}"-audio4-p4.patch
+ epatch "${FILESDIR}/${P}"-audio4-p5.patch
+ epatch "${FILESDIR}/${P}"-audio4-p6.patch
+ epatch "${FILESDIR}/${P}"-audio4-p7.patch
if has_version dev-libs/libcdio-paranoia; then
sed -i -e 's:cdio/cdda.h:cdio/paranoia/cdda.h:' src/plugins/cdda/cdda.c || die