summaryrefslogtreecommitdiff
blob: 8ed5bb4a24a5fa072e15808b602d0f0c6aa9f9cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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);
+	}
 }