commit fb939e5238c128ae1837430cbf838b945d4c99a9
Author: Stone Kang <stonekyx@gmail.com>
Date:   Sun Jul 28 19:42:16 2013 +0800

    Update ffmpeg.c to work with newer versions of FFmpeg
    
    Since ffmpeg 2.0, the macro AVCODEC_MAX_AUDIO_FRAME_SIZE is deprecated
    and removed. This commit simply defines the macro if it's not defined
    previously, using the same value it used to be in old versions of
    libavcodec.
    
    Actually, as my branch has been using swr_convert, where caller specifies
    the size of output buffer, even if the current size of 192000 proved to
    be not enough in the future, we can simply let swr_convert deal with the
    insufficient size by a small modification.
    
    Currently the parameters to swr_convert() still assumes that the size of
    192000 samples is always enough for the output buffer.
    
    Signed-off-by: Gregory Petrosyan <gregory.petrosyan@gmail.com>

diff --git a/Makefile b/Makefile
index 826ac51..5e3f491 100644
--- Makefile
+++ Makefile
@@ -18,6 +18,9 @@ include scripts/lib.mk
 
 CFLAGS += -D_FILE_OFFSET_BITS=64
 
+FFMPEG_CFLAGS += $(shell pkg-config --cflags libswresample)
+FFMPEG_LIBS += $(shell pkg-config --libs libswresample)
+
 CMUS_LIBS = $(PTHREAD_LIBS) $(NCURSES_LIBS) $(ICONV_LIBS) $(DL_LIBS) $(DISCID_LIBS) $(CUE_LIBS) -lm $(COMPAT_LIBS)
 
 input.o main.o ui_curses.o pulse.lo: .version
diff --git a/ffmpeg.c b/ffmpeg.c
index 93c1831..e4da4df 100644
--- ffmpeg.c
+++ ffmpeg.c
@@ -30,10 +30,16 @@
 #include <ffmpeg/avcodec.h>
 #include <ffmpeg/avformat.h>
 #include <ffmpeg/avio.h>
+#include <ffmpeg/swresample.h>
+#include <ffmpeg/opt.h>
+#include <ffmpeg/audioconvert.h>
 #else
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 #include <libavformat/avio.h>
+#include <libswresample/swresample.h>
+#include <libavutil/opt.h>
+#include <libavutil/audioconvert.h>
 #ifndef AVUTIL_MATHEMATICS_H
 #include <libavutil/mathematics.h>
 #endif
@@ -63,6 +69,10 @@
 #define AVDictionaryEntry AVMetadataTag
 #endif
 
+#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
+#endif
+
 struct ffmpeg_input {
 	AVPacket pkt;
 	int curr_pkt_size;
@@ -83,6 +93,7 @@ struct ffmpeg_private {
 	AVCodecContext *codec_context;
 	AVFormatContext *input_context;
 	AVCodec *codec;
+	SwrContext *swr;
 	int stream_index;
 
 	struct ffmpeg_input *input;
@@ -182,6 +193,7 @@ static int ffmpeg_open(struct input_plugin_data *ip_data)
 	AVCodec *codec;
 	AVCodecContext *cc = NULL;
 	AVFormatContext *ic = NULL;
+	SwrContext *swr = NULL;
 
 	ffmpeg_init();
 
@@ -241,20 +253,16 @@ static int ffmpeg_open(struct input_plugin_data *ip_data)
 			break;
 		}
 
-#if (LIBAVCODEC_VERSION_INT > ((51<<16)+(64<<8)+0))
-		if (cc->sample_fmt == AV_SAMPLE_FMT_FLT || cc->sample_fmt == AV_SAMPLE_FMT_DBL) {
-#else
-		if (cc->sample_fmt == AV_SAMPLE_FMT_FLT) {
-#endif
-			err = -IP_ERROR_SAMPLE_FORMAT;
-			break;
-		}
 		/* We assume below that no more errors follow. */
 	} while (0);
 
 	if (err < 0) {
 		/* Clean up.  cc is never opened at this point.  (See above assumption.) */
+#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
 		av_close_input_file(ic);
+#else
+		avformat_close_input(&ic);
+#endif
 		return err;
 	}
 
@@ -266,26 +274,43 @@ static int ffmpeg_open(struct input_plugin_data *ip_data)
 	priv->input = ffmpeg_input_create();
 	if (priv->input == NULL) {
 		avcodec_close(cc);
+#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
 		av_close_input_file(ic);
+#else
+		avformat_close_input(&ic);
+#endif
 		free(priv);
 		return -IP_ERROR_INTERNAL;
 	}
 	priv->output = ffmpeg_output_create();
 
+	/* Prepare for resampling. */
+	swr = swr_alloc();
+	av_opt_set_int(swr, "in_channel_layout",  av_get_default_channel_layout(cc->channels), 0);
+	av_opt_set_int(swr, "out_channel_layout", av_get_default_channel_layout(cc->channels), 0);
+	av_opt_set_int(swr, "in_sample_rate",     cc->sample_rate, 0);
+	av_opt_set_int(swr, "out_sample_rate",    cc->sample_rate, 0);
+	av_opt_set_sample_fmt(swr, "in_sample_fmt",  cc->sample_fmt, 0);
+	priv->swr = swr;
+
 	ip_data->private = priv;
 	ip_data->sf = sf_rate(cc->sample_rate) | sf_channels(cc->channels);
 	switch (cc->sample_fmt) {
 	case AV_SAMPLE_FMT_U8:
 		ip_data->sf |= sf_bits(8) | sf_signed(0);
+		av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_U8,  0);
 		break;
 	case AV_SAMPLE_FMT_S32:
 		ip_data->sf |= sf_bits(32) | sf_signed(1);
+		av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S32,  0);
 		break;
 	/* AV_SAMPLE_FMT_S16 */
 	default:
 		ip_data->sf |= sf_bits(16) | sf_signed(1);
+		av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16,  0);
 		break;
 	}
+	swr_init(swr);
 #ifdef WORDS_BIGENDIAN
 	ip_data->sf |= sf_bigendian(1);
 #endif
@@ -301,7 +326,12 @@ static int ffmpeg_close(struct input_plugin_data *ip_data)
 	struct ffmpeg_private *priv = ip_data->private;
 
 	avcodec_close(priv->codec_context);
+#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
 	av_close_input_file(priv->input_context);
+#else
+	avformat_close_input(&priv->input_context);
+#endif
+	swr_free(&priv->swr);
 	ffmpeg_input_free(priv->input);
 	ffmpeg_output_free(priv->output);
 	free(priv);
@@ -314,8 +344,12 @@ static int ffmpeg_close(struct input_plugin_data *ip_data)
  * It returns < 0 on error.  0 on EOF.
  */
 static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct ffmpeg_input *input,
-			      struct ffmpeg_output *output)
+			      struct ffmpeg_output *output, SwrContext *swr)
 {
+#if (LIBAVCODEC_VERSION_INT >= ((53<<16) + (25<<8) + 0))
+	AVFrame *frame = avcodec_alloc_frame();
+	int got_frame;
+#endif
 	while (1) {
 		/* frame_size specifies the size of output->buffer for
 		 * avcodec_decode_audio2. */
@@ -326,6 +360,9 @@ static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct ff
 			av_free_packet(&input->pkt);
 			if (av_read_frame(ic, &input->pkt) < 0) {
 				/* Force EOF once we can read no longer. */
+#if (LIBAVCODEC_VERSION_INT >= ((53<<16) + (25<<8) + 0))
+				avcodec_free_frame(&frame);
+#endif
 				return 0;
 			}
 			input->curr_pkt_size = input->pkt.size;
@@ -345,7 +382,7 @@ static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct ff
 #elif (LIBAVCODEC_VERSION_INT <= ((52<<16) + (25<<8) + 0))
 		len = avcodec_decode_audio2(cc, (int16_t *) output->buffer, &frame_size,
 				input->curr_pkt_buf, input->curr_pkt_size);
-#else
+#elif (LIBAVCODEC_VERSION_INT < ((53<<16) + (25<<8) + 0))
 		{
 			AVPacket avpkt;
 			av_init_packet(&avpkt);
@@ -354,6 +391,14 @@ static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct ff
 			len = avcodec_decode_audio3(cc, (int16_t *) output->buffer, &frame_size, &avpkt);
 			av_free_packet(&avpkt);
 		}
+#else
+		{
+			AVPacket avpkt;
+			av_new_packet(&avpkt, input->curr_pkt_size);
+			memcpy(avpkt.data, input->curr_pkt_buf, input->curr_pkt_size);
+			len = avcodec_decode_audio4(cc, frame, &got_frame, &avpkt);
+			av_free_packet(&avpkt);
+		}
 #endif
 		if (len < 0) {
 			/* this is often reached when seeking, not sure why */
@@ -362,11 +407,27 @@ static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct ff
 		}
 		input->curr_pkt_size -= len;
 		input->curr_pkt_buf += len;
+#if (LIBAVCODEC_VERSION_INT < ((53<<16) + (25<<8) + 0))
 		if (frame_size > 0) {
 			output->buffer_pos = output->buffer;
 			output->buffer_used_len = frame_size;
 			return frame_size;
 		}
+#else
+		if (got_frame) {
+			int res = swr_convert(swr,
+					&output->buffer,
+					frame->nb_samples,
+					(const uint8_t **)frame->extended_data,
+					frame->nb_samples);
+			if (res < 0)
+				res = 0;
+			output->buffer_pos = output->buffer;
+			output->buffer_used_len = res * cc->channels * sizeof(int16_t);
+			avcodec_free_frame(&frame);
+			return output->buffer_used_len;
+		}
+#endif
 	}
 	/* This should never get here. */
 	return -IP_ERROR_INTERNAL;
@@ -380,7 +441,8 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun
 	int out_size;
 
 	if (output->buffer_used_len == 0) {
-		rc = ffmpeg_fill_buffer(priv->input_context, priv->codec_context, priv->input, priv->output);
+		rc = ffmpeg_fill_buffer(priv->input_context, priv->codec_context,
+				priv->input, priv->output, priv->swr);
 		if (rc <= 0) {
 			return rc;
 		}
