Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 692 lines (560 sloc) 16.268 kb
34cd7f5 @felipec Initial commit
authored
1 /*
23dbde6 @felipec Update copyrights
authored
2 * Copyright (C) 2009-2012 Felipe Contreras
34cd7f5 @felipec Initial commit
authored
3 * Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
4 *
5 * Author: Felipe Contreras <felipe.contreras@gmail.com>
6 *
7cde9a2 @felipec General cleanups
authored
7 * This file may be used under the terms of the GNU Lesser General Public
8 * License version 2.1.
c743ba9 @felipec Code-style cleanups
authored
9 */
34cd7f5 @felipec Initial commit
authored
10
880ebe4 Rename avdec to av_adec
Felipe Contreras authored
11 #include "gstav_adec.h"
34cd7f5 @felipec Initial commit
authored
12 #include "plugin.h"
13
27f3b86 Generic cleanups
Felipe Contreras authored
14 #include <libavcodec/avcodec.h>
fdd3c31 @felipec Add missing includes
authored
15 #include <libavutil/mem.h>
37bf3b5 @felipec Add support for tags
authored
16 #include <gst/tag/tag.h>
17
34cd7f5 @felipec Initial commit
authored
18 #include <stdlib.h>
19 #include <string.h> /* for memcpy */
27f3b86 Generic cleanups
Felipe Contreras authored
20 #include <stdbool.h>
34cd7f5 @felipec Initial commit
authored
21
22 #define GST_CAT_DEFAULT gstav_debug
23
24 static GstElementClass *parent_class;
25
1a40104 @felipec Increase buffer size even more
authored
26 #define BUFFER_SIZE AVCODEC_MAX_AUDIO_FRAME_SIZE
9e47242 @felipec adec: don't reset the timestamps all the time
authored
27 #define MAX_DIFF 20 * 1000000
a085ba4 @felipec Push constant sized buffers
authored
28
27f3b86 Generic cleanups
Felipe Contreras authored
29 struct oggvorbis_private {
30 unsigned int len[3];
31 unsigned char *packet[3];
32 };
33
34 struct ring {
35 size_t in, out;
36 };
37
38 struct obj {
39 GstElement element;
40 GstPad *sinkpad, *srcpad;
41 AVCodec *codec;
42 AVCodecContext *av_ctx;
43 bool got_header;
44 struct oggvorbis_private priv;
45 uint64_t timestamp;
46 AVPacket pkt;
47 uint8_t *buffer_data;
48 size_t buffer_size;
49 struct ring ring;
50 int (*header_func)(struct obj *self, GstBuffer *buf);
9246d91 @felipec adec: extra checks for timestamp jumps
authored
51 uint64_t next_timestamp;
477a434 @felipec adec: add support for more sample formats
authored
52 int bps;
3c30e64 @felipec Update to new GLib mutex API
authored
53 GMutex mutex;
27f3b86 Generic cleanups
Felipe Contreras authored
54 };
55
56 struct obj_class {
57 GstElementClass parent_class;
58 };
59
30fd6d2 @felipec Fix bytstream read functions
authored
60 static inline uint8_t get_byte(const uint8_t **b)
61 {
62 return *((*b)++);
63 }
64
65 static inline uint32_t get_le32(const uint8_t **b)
66 {
67 struct unaligned_32 { uint32_t l; } __attribute__((packed));
68 *b += sizeof(uint32_t);
69 return ((const struct unaligned_32 *)(*b - sizeof(uint32_t)))->l;
70 }
71
31e2245 @felipec Prepare to support multiple codecs
authored
72 static int
27f3b86 Generic cleanups
Felipe Contreras authored
73 default_header(struct obj *self, GstBuffer *buf)
31e2245 @felipec Prepare to support multiple codecs
authored
74 {
75 return 0;
76 }
77
34cd7f5 @felipec Initial commit
authored
78 static unsigned int
1cf1755 @felipec Trivial cleanups
authored
79 fixup_vorbis_headers(struct oggvorbis_private *priv, uint8_t **buf)
34cd7f5 @felipec Initial commit
authored
80 {
c743ba9 @felipec Code-style cleanups
authored
81 int i, offset, len;
34cd7f5 @felipec Initial commit
authored
82 unsigned char *ptr;
83
84 len = priv->len[0] + priv->len[1] + priv->len[2];
85 ptr = *buf = g_malloc0(len + len / 255 + 64);
86
87 ptr[0] = 2;
88 offset = 1;
89 offset += av_xiphlacing(&ptr[offset], priv->len[0]);
90 offset += av_xiphlacing(&ptr[offset], priv->len[1]);
91 for (i = 0; i < 3; i++) {
92 memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
93 offset += priv->len[i];
406ee99 @felipec Fix trivial leak
authored
94 g_free(priv->packet[i]);
34cd7f5 @felipec Initial commit
authored
95 }
96 *buf = g_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
97 return offset;
98 }
99
100 static int
27f3b86 Generic cleanups
Felipe Contreras authored
101 vorbis_header(struct obj *self, GstBuffer *buf)
34cd7f5 @felipec Initial commit
authored
102 {
4a86fdb @felipec Get away of gst code-style
authored
103 const uint8_t *p = buf->data;
34cd7f5 @felipec Initial commit
authored
104 struct oggvorbis_private *priv = &self->priv;
a7cd19c @felipec Update code to use pkt_type
authored
105 int pkt_type = *p;
34cd7f5 @felipec Initial commit
authored
106
a7cd19c @felipec Update code to use pkt_type
authored
107 if (!(pkt_type & 1))
34cd7f5 @felipec Initial commit
authored
108 return 0;
109
4a86fdb @felipec Get away of gst code-style
authored
110 if (buf->size < 1 || pkt_type > 5)
34cd7f5 @felipec Initial commit
authored
111 return -1;
112
4a86fdb @felipec Get away of gst code-style
authored
113 priv->len[pkt_type >> 1] = buf->size;
114 priv->packet[pkt_type >> 1] = g_malloc0(buf->size);
115 memcpy(priv->packet[pkt_type >> 1], buf->data, buf->size);
34cd7f5 @felipec Initial commit
authored
116
a7cd19c @felipec Update code to use pkt_type
authored
117 if (pkt_type == 1) {
34cd7f5 @felipec Initial commit
authored
118 /* tag */
119 unsigned blocksize, bs0, bs1;
120 p += 7; /* skip "\001vorbis" tag */
121
4a86fdb @felipec Get away of gst code-style
authored
122 if (buf->size != 30)
34cd7f5 @felipec Initial commit
authored
123 return -1;
124
30fd6d2 @felipec Fix bytstream read functions
authored
125 if (get_le32(&p) != 0)
34cd7f5 @felipec Initial commit
authored
126 return -1;
127
30fd6d2 @felipec Fix bytstream read functions
authored
128 self->av_ctx->channels = get_byte(&p);
129 self->av_ctx->sample_rate = get_le32(&p);
34cd7f5 @felipec Initial commit
authored
130 p += 4; /* max bitrate */
30fd6d2 @felipec Fix bytstream read functions
authored
131 self->av_ctx->bit_rate = get_le32(&p);
34cd7f5 @felipec Initial commit
authored
132 p += 4; /* min bitrate */
133
30fd6d2 @felipec Fix bytstream read functions
authored
134 blocksize = get_byte(&p);
34cd7f5 @felipec Initial commit
authored
135 bs0 = blocksize & 15;
136 bs1 = blocksize >> 4;
137
138 if (bs0 > bs1)
139 return -1;
140 if (bs0 < 6 || bs1 > 13)
141 return -1;
142
30fd6d2 @felipec Fix bytstream read functions
authored
143 if (get_byte(&p) != 1)
34cd7f5 @felipec Initial commit
authored
144 return -1;
145 }
a7cd19c @felipec Update code to use pkt_type
authored
146 else if (pkt_type == 3) {
34cd7f5 @felipec Initial commit
authored
147 /* comment */
148 }
149 else {
150 /* extradata */
151 self->av_ctx->extradata_size =
152 fixup_vorbis_headers(&self->priv, &self->av_ctx->extradata);
153 }
154
a7cd19c @felipec Update code to use pkt_type
authored
155 return 1;
34cd7f5 @felipec Initial commit
authored
156 }
157
ef1935d @felipec adec: skip flac headers
authored
158 static int
159 flac_header(struct obj *self, GstBuffer *buf)
160 {
161 unsigned type = (buf->data[0] & 0x7F);
162 /* frame sync code */
163 if (type == 127)
164 return 0;
165 return 1;
166 }
167
6ff451f @felipec adec: refactor calculate_timestamp()
authored
168 static inline uint32_t
169 calculate_duration(struct obj *self, uint64_t size)
93ffff8 Add timestamp calculation
Felipe Contreras authored
170 {
d1c78fb @felipec Rework timestamp handling
authored
171 uint32_t samples;
6ff451f @felipec adec: refactor calculate_timestamp()
authored
172 samples = size / (self->av_ctx->channels * (self->bps >> 3));
173 return gst_util_uint64_scale_int(samples, GST_SECOND, self->av_ctx->sample_rate);
174 }
93ffff8 Add timestamp calculation
Felipe Contreras authored
175
6ff451f @felipec adec: refactor calculate_timestamp()
authored
176 static inline void
177 calculate_timestamp(struct obj *self, GstBuffer *out_buf)
178 {
d1c78fb @felipec Rework timestamp handling
authored
179 out_buf->timestamp = self->timestamp;
6ff451f @felipec adec: refactor calculate_timestamp()
authored
180 out_buf->duration = calculate_duration(self, out_buf->size);
d1c78fb @felipec Rework timestamp handling
authored
181 self->timestamp += out_buf->duration;
93ffff8 Add timestamp calculation
Felipe Contreras authored
182 }
183
e019240 @felipec adec: refactor code into check_timestamps()
authored
184 static void
185 check_timestamps(struct obj *self, GstBuffer *buf)
186 {
187 if (G_UNLIKELY(self->timestamp == GST_CLOCK_TIME_NONE)) {
188 self->next_timestamp = self->timestamp = buf->timestamp;
9e47242 @felipec adec: don't reset the timestamps all the time
authored
189 } else if (abs(buf->timestamp - self->next_timestamp) > MAX_DIFF) {
e019240 @felipec adec: refactor code into check_timestamps()
authored
190 int64_t progress = self->next_timestamp - self->timestamp;
191
192 GST_DEBUG_OBJECT(self, "reseting timestamp: %li ns",
193 buf->timestamp - self->next_timestamp);
194 self->next_timestamp = self->timestamp = buf->timestamp;
195 self->timestamp -= progress;
196 }
197 }
198
34cd7f5 @felipec Initial commit
authored
199 static GstFlowReturn
1cf1755 @felipec Trivial cleanups
authored
200 pad_chain(GstPad *pad, GstBuffer *buf)
34cd7f5 @felipec Initial commit
authored
201 {
27f3b86 Generic cleanups
Felipe Contreras authored
202 struct obj *self;
34cd7f5 @felipec Initial commit
authored
203 GstFlowReturn ret = GST_FLOW_OK;
a43a575 @felipec adec: trivial cleanups
authored
204 AVCodecContext *av_ctx;
34cd7f5 @felipec Initial commit
authored
205
27f3b86 Generic cleanups
Felipe Contreras authored
206 self = (struct obj *)((GstObject *)pad)->parent;
a43a575 @felipec adec: trivial cleanups
authored
207 av_ctx = self->av_ctx;
34cd7f5 @felipec Initial commit
authored
208
7c1d0a1 @felipec Add some branch prediction hints
authored
209 if (G_UNLIKELY(!self->got_header)) {
31e2245 @felipec Prepare to support multiple codecs
authored
210 int hdr = self->header_func(self, buf);
34cd7f5 @felipec Initial commit
authored
211 if (!hdr) {
477a434 @felipec adec: add support for more sample formats
authored
212 GstCaps *new_caps;
213 GstStructure *s;
214 int bps;
215
4e4d7e7 @felipec Remove seq stuff; use got_header
authored
216 self->got_header = true;
a43a575 @felipec adec: trivial cleanups
authored
217 if (gst_av_codec_open(av_ctx, self->codec) < 0) {
34cd7f5 @felipec Initial commit
authored
218 ret = GST_FLOW_ERROR;
219 goto leave;
220 }
221
197e81b @felipec adec: add support for really old bps()
authored
222 #if LIBAVUTIL_VERSION_MAJOR < 51
223 bps = av_get_bits_per_sample_format(av_ctx->sample_fmt);
c35841f @felipec adec: add minor version checks
authored
224 #elif LIBAVUTIL_VERSION_MAJOR < 52 && !(LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4)
a43a575 @felipec adec: trivial cleanups
authored
225 bps = av_get_bits_per_sample_fmt(av_ctx->sample_fmt);
b2fae76 @felipec adec: avoid deprecated av_get_bits_per_sample_fmt()
authored
226 #else
227 bps = av_get_bytes_per_sample(av_ctx->sample_fmt) << 3;
228 #endif
199306b @felipec adec: avoid FF_API_GET_BITS_PER_SAMPLE_FMT
authored
229
477a434 @felipec adec: add support for more sample formats
authored
230 self->bps = bps;
231
232 s = gst_structure_new("audio/x-raw-int",
a43a575 @felipec adec: trivial cleanups
authored
233 "rate", G_TYPE_INT, av_ctx->sample_rate,
234 "channels", G_TYPE_INT, av_ctx->channels,
477a434 @felipec adec: add support for more sample formats
authored
235 "endianness", G_TYPE_INT, G_BYTE_ORDER,
236 "width", G_TYPE_INT, bps,
237 NULL);
34cd7f5 @felipec Initial commit
authored
238
a43a575 @felipec adec: trivial cleanups
authored
239 switch (av_ctx->sample_fmt) {
6f6fc73 @felipec adec: add support for old sample_fmt
authored
240 #if LIBAVCODEC_VERSION_MAJOR < 54
241 case SAMPLE_FMT_S16:
242 case SAMPLE_FMT_S32:
243 #else
477a434 @felipec adec: add support for more sample formats
authored
244 case AV_SAMPLE_FMT_S16:
245 case AV_SAMPLE_FMT_S32:
6f6fc73 @felipec adec: add support for old sample_fmt
authored
246 #endif
477a434 @felipec adec: add support for more sample formats
authored
247 gst_structure_set(s,
c743ba9 @felipec Code-style cleanups
authored
248 "signed", G_TYPE_BOOLEAN, TRUE,
477a434 @felipec adec: add support for more sample formats
authored
249 "depth", G_TYPE_INT, bps,
c743ba9 @felipec Code-style cleanups
authored
250 NULL);
477a434 @felipec adec: add support for more sample formats
authored
251 break;
252 default:
253 break;
34cd7f5 @felipec Initial commit
authored
254 }
477a434 @felipec adec: add support for more sample formats
authored
255
256 new_caps = gst_caps_new_full(s, NULL);
257
258 GST_INFO_OBJECT(self, "caps are: %" GST_PTR_FORMAT, new_caps);
259 gst_pad_set_caps(self->srcpad, new_caps);
260 gst_caps_unref(new_caps);
34cd7f5 @felipec Initial commit
authored
261 }
262 }
263
7c1d0a1 @felipec Add some branch prediction hints
authored
264 if (G_LIKELY(self->got_header)) {
34cd7f5 @felipec Initial commit
authored
265 AVPacket pkt;
266
267 av_init_packet(&pkt);
53c6071 @felipec Add padding to input buffer
authored
268 pkt.data = self->pkt.data;
4a86fdb @felipec Get away of gst code-style
authored
269 pkt.size = buf->size;
34cd7f5 @felipec Initial commit
authored
270
53c6071 @felipec Add padding to input buffer
authored
271 memcpy(pkt.data, buf->data, buf->size);
272 memset(pkt.data + pkt.size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
273
e019240 @felipec adec: refactor code into check_timestamps()
authored
274 check_timestamps(self, buf);
9246d91 @felipec adec: extra checks for timestamp jumps
authored
275
6c0bfe9 @felipec adec: fix for buffers without duration
authored
276 if (buf->duration != GST_CLOCK_TIME_NONE)
277 self->next_timestamp += buf->duration;
d1c78fb @felipec Rework timestamp handling
authored
278
a0b08ce @felipec Properly handle the amount of data processed
authored
279 do {
280 void *buffer_data;
281 int buffer_size;
282 int read;
b3d48ea adec: allow BUFFER_SIZE of 0
Felipe Contreras authored
283 unsigned total_buffer_size;
a0b08ce @felipec Properly handle the amount of data processed
authored
284
3975ba2 @felipec Don't use AVPacket for output buffer
authored
285 buffer_data = self->buffer_data + self->ring.in;
7f1c394 @felipec Fix buffer size
authored
286 buffer_size = self->buffer_size - self->ring.in;
c35841f @felipec adec: add minor version checks
authored
287 #if LIBAVCODEC_VERSION_MAJOR < 54 && !(LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 25)
3c30e64 @felipec Update to new GLib mutex API
authored
288 g_mutex_lock(&self->mutex);
a43a575 @felipec adec: trivial cleanups
authored
289 read = avcodec_decode_audio3(av_ctx, buffer_data, &buffer_size, &pkt);
3c30e64 @felipec Update to new GLib mutex API
authored
290 g_mutex_unlock(&self->mutex);
719e87d @felipec Catch errors
authored
291 if (read < 0) {
b730d76 @felipec vdec: don't fail on avcodec errors
authored
292 GST_WARNING_OBJECT(self, "error: %i", read);
719e87d @felipec Catch errors
authored
293 break;
294 }
f3900fe @felipec Update to avcodec_decode_audio4
authored
295 #else
296 AVFrame frame;
297 int got_frame = 0, planar, plane_size;
298
3c30e64 @felipec Update to new GLib mutex API
authored
299 g_mutex_lock(&self->mutex);
f3900fe @felipec Update to avcodec_decode_audio4
authored
300 read = avcodec_decode_audio4(av_ctx, &frame, &got_frame, &pkt);
3c30e64 @felipec Update to new GLib mutex API
authored
301 g_mutex_unlock(&self->mutex);
f3900fe @felipec Update to avcodec_decode_audio4
authored
302 if (read < 0) {
303 GST_WARNING_OBJECT(self, "error: %i", read);
304 break;
305 }
306
307 if (!got_frame)
308 goto next;
309
310 planar = av_sample_fmt_is_planar(av_ctx->sample_fmt);
311 buffer_size = av_samples_get_buffer_size(&plane_size, av_ctx->channels,
312 frame.nb_samples, av_ctx->sample_fmt, 1);
313
314 memcpy(buffer_data, frame.extended_data[0], plane_size);
315
316 if (planar && av_ctx->channels > 1) {
317 uint8_t *out = ((uint8_t *)buffer_data) + plane_size;
318 for (int ch = 1; ch < av_ctx->channels; ch++) {
319 memcpy(out, frame.extended_data[ch], plane_size);
320 out += plane_size;
321 }
322 }
323 #endif
a0b08ce @felipec Properly handle the amount of data processed
authored
324
6c0bfe9 @felipec adec: fix for buffers without duration
authored
325 if (buf->duration == GST_CLOCK_TIME_NONE)
326 self->next_timestamp += calculate_duration(self, buffer_size);
327
a0b08ce @felipec Properly handle the amount of data processed
authored
328 self->ring.in += buffer_size;
1a40104 @felipec Increase buffer size even more
authored
329 if (self->ring.in >= 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE) {
73f0c94 @felipec Fix memory overwrite
authored
330 memmove(self->buffer_data,
3975ba2 @felipec Don't use AVPacket for output buffer
authored
331 self->buffer_data + self->ring.out,
a0b08ce @felipec Properly handle the amount of data processed
authored
332 self->ring.in - self->ring.out);
333 self->ring.in -= self->ring.out;
334 self->ring.out = 0;
335 }
a7ebf3a @felipec Fix timestamps
authored
336
b3d48ea adec: allow BUFFER_SIZE of 0
Felipe Contreras authored
337 if (BUFFER_SIZE > 0)
338 total_buffer_size = BUFFER_SIZE;
339 else
340 total_buffer_size = buffer_size;
341
342 if (self->ring.in - self->ring.out >= total_buffer_size) {
a0b08ce @felipec Properly handle the amount of data processed
authored
343 GstBuffer *out_buf;
b3d48ea adec: allow BUFFER_SIZE of 0
Felipe Contreras authored
344 out_buf = gst_buffer_new_and_alloc(total_buffer_size);
fcc000d @felipec adec: fix buffer overwrite
authored
345 memcpy(out_buf->data, self->buffer_data + self->ring.out, out_buf->size);
a0b08ce @felipec Properly handle the amount of data processed
authored
346 calculate_timestamp(self, out_buf);
347 gst_buffer_set_caps(out_buf, self->srcpad->caps);
a085ba4 @felipec Push constant sized buffers
authored
348
a0b08ce @felipec Properly handle the amount of data processed
authored
349 self->ring.out += out_buf->size;
350
351 ret = gst_pad_push(self->srcpad, out_buf);
352 }
c35841f @felipec adec: add minor version checks
authored
353 #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 25)
f3900fe @felipec Update to avcodec_decode_audio4
authored
354 next:
355 #endif
a0b08ce @felipec Properly handle the amount of data processed
authored
356 pkt.size -= read;
357 pkt.data += read;
358 } while (pkt.size > 0);
34cd7f5 @felipec Initial commit
authored
359 }
360
361 leave:
362 gst_buffer_unref(buf);
363
364 return ret;
365 }
366
367 static GstStateChangeReturn
1cf1755 @felipec Trivial cleanups
authored
368 change_state(GstElement *element, GstStateChange transition)
34cd7f5 @felipec Initial commit
authored
369 {
370 GstStateChangeReturn ret;
27f3b86 Generic cleanups
Felipe Contreras authored
371 struct obj *self;
34cd7f5 @felipec Initial commit
authored
372
27f3b86 Generic cleanups
Felipe Contreras authored
373 self = (struct obj *)element;
34cd7f5 @felipec Initial commit
authored
374
375 switch (transition) {
c743ba9 @felipec Code-style cleanups
authored
376 case GST_STATE_CHANGE_NULL_TO_READY:
4e4d7e7 @felipec Remove seq stuff; use got_header
authored
377 self->got_header = false;
53c6071 @felipec Add padding to input buffer
authored
378 av_new_packet(&self->pkt, AVCODEC_MAX_AUDIO_FRAME_SIZE);
1a40104 @felipec Increase buffer size even more
authored
379 self->buffer_size = 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
3975ba2 @felipec Don't use AVPacket for output buffer
authored
380 self->buffer_data = av_malloc(self->buffer_size);
c743ba9 @felipec Code-style cleanups
authored
381 break;
382
383 default:
384 break;
34cd7f5 @felipec Initial commit
authored
385 }
386
4a86fdb @felipec Get away of gst code-style
authored
387 ret = parent_class->change_state(element, transition);
34cd7f5 @felipec Initial commit
authored
388
389 if (ret == GST_STATE_CHANGE_FAILURE)
390 return ret;
391
392 switch (transition) {
c743ba9 @felipec Code-style cleanups
authored
393 case GST_STATE_CHANGE_READY_TO_NULL:
fddff1a @felipec Plug a few leaks
authored
394 if (self->av_ctx) {
bca0f41 @felipec Provide avcodec_{open,close} mutex safety
authored
395 gst_av_codec_close(self->av_ctx);
da21fbe @felipec adec: fix possible memleak
authored
396 av_freep(&self->av_ctx->extradata);
fddff1a @felipec Plug a few leaks
authored
397 av_freep(&self->av_ctx);
398 }
53c6071 @felipec Add padding to input buffer
authored
399 av_free_packet(&self->pkt);
3975ba2 @felipec Don't use AVPacket for output buffer
authored
400 av_freep(&self->buffer_data);
c743ba9 @felipec Code-style cleanups
authored
401 break;
34cd7f5 @felipec Initial commit
authored
402
c743ba9 @felipec Code-style cleanups
authored
403 default:
404 break;
34cd7f5 @felipec Initial commit
authored
405 }
406
407 return ret;
408 }
409
31e2245 @felipec Prepare to support multiple codecs
authored
410 static gboolean
14bbe77 Improve seeking
Felipe Contreras authored
411 sink_event(GstPad *pad, GstEvent *event)
412 {
413 struct obj *self;
414 gboolean ret = TRUE;
415
416 self = (struct obj *)(gst_pad_get_parent(pad));
417
418 switch (event->type) {
419 case GST_EVENT_FLUSH_START:
420 self->timestamp = GST_CLOCK_TIME_NONE;
3c30e64 @felipec Update to new GLib mutex API
authored
421 g_mutex_lock(&self->mutex);
a8d2e12 @felipec Add support for flushing
authored
422 avcodec_flush_buffers(self->av_ctx);
3c30e64 @felipec Update to new GLib mutex API
authored
423 g_mutex_unlock(&self->mutex);
14bbe77 Improve seeking
Felipe Contreras authored
424 break;
42886da @felipec adec: flush buffer on EOS
authored
425 case GST_EVENT_EOS: {
426 /* flush current buffer */
427 GstBuffer *out_buf;
428 GstFlowReturn r;
429
430 out_buf = gst_buffer_new_and_alloc(self->ring.in - self->ring.out);
431 memcpy(out_buf->data, self->buffer_data + self->ring.out, out_buf->size);
432 calculate_timestamp(self, out_buf);
433 gst_buffer_set_caps(out_buf, self->srcpad->caps);
434
435 self->ring.out += out_buf->size;
436
437 r = gst_pad_push(self->srcpad, out_buf);
438 if (r != GST_FLOW_OK)
439 goto leave;
440 break;
441 }
14bbe77 Improve seeking
Felipe Contreras authored
442 default:
443 break;
444 }
445
745c225 @felipec adec: trivial reorganization
authored
446 ret = gst_pad_push_event(self->srcpad, event);
447
42886da @felipec adec: flush buffer on EOS
authored
448 leave:
14bbe77 Improve seeking
Felipe Contreras authored
449 gst_object_unref(self);
450
451 return ret;
452 }
453
454 static gboolean
1cf1755 @felipec Trivial cleanups
authored
455 sink_setcaps(GstPad *pad, GstCaps *caps)
31e2245 @felipec Prepare to support multiple codecs
authored
456 {
27f3b86 Generic cleanups
Felipe Contreras authored
457 struct obj *self;
31e2245 @felipec Prepare to support multiple codecs
authored
458 GstStructure *in_struc;
459 const char *name;
460 int codec_id;
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
461 AVCodecContext *ctx;
45291a4 @felipec adec: pass codec-data to the codec
authored
462 const GValue *codec_data;
463 GstBuffer *buf;
31e2245 @felipec Prepare to support multiple codecs
authored
464
27f3b86 Generic cleanups
Felipe Contreras authored
465 self = (struct obj *)((GstObject *)pad)->parent;
31e2245 @felipec Prepare to support multiple codecs
authored
466
467 in_struc = gst_caps_get_structure(caps, 0);
468
469 name = gst_structure_get_name(in_struc);
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
470 if (strcmp(name, "audio/x-vorbis") == 0)
31e2245 @felipec Prepare to support multiple codecs
authored
471 codec_id = CODEC_ID_VORBIS;
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
472 else if (strcmp(name, "audio/x-flac") == 0)
473 codec_id = CODEC_ID_FLAC;
6e29ac6 @felipec adec: add support for AAC
authored
474 else if (strcmp(name, "audio/mpeg") == 0) {
475 int version;
476 gst_structure_get_int(in_struc, "mpegversion", &version);
477 switch (version) {
478 case 1:
479 codec_id = CODEC_ID_MP3;
480 break;
481 case 2:
482 case 4:
483 codec_id = CODEC_ID_AAC;
484 break;
485 default:
486 codec_id = CODEC_ID_NONE;
487 }
488 } else
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
489 codec_id = CODEC_ID_NONE;
490
491 self->codec = avcodec_find_decoder(codec_id);
492 if (!self->codec)
493 return false;
494
495 self->av_ctx = ctx = avcodec_alloc_context3(self->codec);
496
497 switch (codec_id) {
498 case CODEC_ID_VORBIS:
31e2245 @felipec Prepare to support multiple codecs
authored
499 self->header_func = vorbis_header;
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
500 break;
501 case CODEC_ID_FLAC: {
b9df0b3 @felipec Add support for FLAC
authored
502 const GValue *stream_header;
503 const GValue *stream_info;
504 GstBuffer *buf;
505
ef1935d @felipec adec: skip flac headers
authored
506 self->header_func = flac_header;
b9df0b3 @felipec Add support for FLAC
authored
507
508 stream_header = gst_structure_get_value(in_struc, "streamheader");
509 if (!stream_header)
0457aff @felipec adec: missing streamheader in flac is not fatal
authored
510 return true;
b9df0b3 @felipec Add support for FLAC
authored
511
512 stream_info = gst_value_array_get_value(stream_header, 0);
513
514 buf = gst_value_get_buffer(stream_info);
515 buf->data += 17;
516 buf->size -= 17;
517
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
518 ctx->extradata = malloc(buf->size + FF_INPUT_BUFFER_PADDING_SIZE);
519 memcpy(ctx->extradata, buf->data, buf->size);
be2c8c5 @felipec adec: improve extradata allocation
authored
520 memset(ctx->extradata + buf->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
521 ctx->extradata_size = buf->size;
522 break;
523 }
6e29ac6 @felipec adec: add support for AAC
authored
524 case CODEC_ID_MP3:
525 case CODEC_ID_AAC: {
2c2b4f9 @felipec Update to avcodec_alloc_context3
authored
526 gst_structure_get_int(in_struc, "rate", &ctx->sample_rate);
527 gst_structure_get_int(in_struc, "channels", &ctx->channels);
528 break;
b9df0b3 @felipec Add support for FLAC
authored
529 }
6443d77 @felipec Add support for MP3
authored
530 }
45291a4 @felipec adec: pass codec-data to the codec
authored
531
532 codec_data = gst_structure_get_value(in_struc, "codec_data");
533 if (!codec_data)
534 goto next;
535 buf = gst_value_get_buffer(codec_data);
536 if (!buf)
537 goto next;
538 ctx->extradata = av_malloc(buf->size + FF_INPUT_BUFFER_PADDING_SIZE);
539 memcpy(ctx->extradata, buf->data, buf->size);
540 memset(ctx->extradata + buf->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
541 ctx->extradata_size = buf->size;
542
543 next:
31e2245 @felipec Prepare to support multiple codecs
authored
544 return true;
545 }
546
34cd7f5 @felipec Initial commit
authored
547 static GstCaps *
548 generate_src_template(void)
549 {
550 GstCaps *caps = NULL;
551
552 caps = gst_caps_new_simple("audio/x-raw-int",
c743ba9 @felipec Code-style cleanups
authored
553 "rate", GST_TYPE_INT_RANGE, 8000, 96000,
554 "signed", G_TYPE_BOOLEAN, TRUE,
555 "endianness", G_TYPE_INT, G_BYTE_ORDER,
477a434 @felipec adec: add support for more sample formats
authored
556 "width", GST_TYPE_INT_RANGE, 16, 32,
557 "depth", GST_TYPE_INT_RANGE, 16, 32,
c743ba9 @felipec Code-style cleanups
authored
558 "channels", GST_TYPE_INT_RANGE, 1, 256,
559 NULL);
34cd7f5 @felipec Initial commit
authored
560
561 return caps;
562 }
563
564 static GstCaps *
565 generate_sink_template(void)
566 {
b9df0b3 @felipec Add support for FLAC
authored
567 GstCaps *caps;
568 GstStructure *struc;
569
570 caps = gst_caps_new_empty();
571
572 struc = gst_structure_new("audio/x-vorbis",
573 NULL);
574
575 gst_caps_append_structure(caps, struc);
34cd7f5 @felipec Initial commit
authored
576
b9df0b3 @felipec Add support for FLAC
authored
577 struc = gst_structure_new("audio/x-flac",
578 "framed", G_TYPE_BOOLEAN, TRUE,
c743ba9 @felipec Code-style cleanups
authored
579 NULL);
34cd7f5 @felipec Initial commit
authored
580
b9df0b3 @felipec Add support for FLAC
authored
581 gst_caps_append_structure(caps, struc);
6443d77 @felipec Add support for MP3
authored
582
583 struc = gst_structure_new("audio/mpeg",
584 "mpegversion", G_TYPE_INT, 1,
4e5db8d @felipec adec: add support for all MPEG-1 audio
authored
585 "layer", GST_TYPE_INT_RANGE, 1, 3,
6443d77 @felipec Add support for MP3
authored
586 "parsed", G_TYPE_BOOLEAN, TRUE,
587 NULL);
588
589 gst_caps_append_structure(caps, struc);
6e29ac6 @felipec adec: add support for AAC
authored
590
591 struc = gst_structure_new("audio/mpeg",
592 "mpegversion", G_TYPE_INT, 4,
593 "framed", G_TYPE_BOOLEAN, TRUE,
594 NULL);
595
596 gst_caps_append_structure(caps, struc);
b9df0b3 @felipec Add support for FLAC
authored
597
34cd7f5 @felipec Initial commit
authored
598 return caps;
599 }
600
601 static void
1cf1755 @felipec Trivial cleanups
authored
602 instance_init(GTypeInstance *instance, void *g_class)
34cd7f5 @felipec Initial commit
authored
603 {
27f3b86 Generic cleanups
Felipe Contreras authored
604 struct obj *self = (struct obj *)instance;
4a86fdb @felipec Get away of gst code-style
authored
605 GstElementClass *element_class = g_class;
34cd7f5 @felipec Initial commit
authored
606
607 self->sinkpad =
608 gst_pad_new_from_template(gst_element_class_get_pad_template(element_class, "sink"), "sink");
609
610 gst_pad_set_chain_function(self->sinkpad, pad_chain);
14bbe77 Improve seeking
Felipe Contreras authored
611 gst_pad_set_event_function(self->sinkpad, sink_event);
34cd7f5 @felipec Initial commit
authored
612
613 self->srcpad =
614 gst_pad_new_from_template(gst_element_class_get_pad_template(element_class, "src"), "src");
615
616 gst_pad_use_fixed_caps(self->srcpad);
617
4a86fdb @felipec Get away of gst code-style
authored
618 gst_element_add_pad((GstElement *)self, self->sinkpad);
619 gst_element_add_pad((GstElement *)self, self->srcpad);
31e2245 @felipec Prepare to support multiple codecs
authored
620
621 gst_pad_set_setcaps_function(self->sinkpad, sink_setcaps);
622
623 self->header_func = default_header;
d1c78fb @felipec Rework timestamp handling
authored
624 self->timestamp = GST_CLOCK_TIME_NONE;
3c30e64 @felipec Update to new GLib mutex API
authored
625 g_mutex_init(&self->mutex);
a8d2e12 @felipec Add support for flushing
authored
626 }
627
628 static void
629 finalize(GObject *obj)
630 {
631 struct obj *self = (struct obj *)obj;
3c30e64 @felipec Update to new GLib mutex API
authored
632 g_mutex_clear(&self->mutex);
a8d2e12 @felipec Add support for flushing
authored
633 ((GObjectClass *)parent_class)->finalize(obj);
34cd7f5 @felipec Initial commit
authored
634 }
635
636 static void
1cf1755 @felipec Trivial cleanups
authored
637 base_init(void *g_class)
34cd7f5 @felipec Initial commit
authored
638 {
4a86fdb @felipec Get away of gst code-style
authored
639 GstElementClass *element_class = g_class;
34cd7f5 @felipec Initial commit
authored
640 GstPadTemplate *template;
641
aabacca @felipec Avoid deprecated gst_element_class_set_details
authored
642 gst_element_class_set_details_simple(element_class,
643 "av audio decoder",
644 "Coder/Decoder/Audio",
645 "Audio decoder wrapper for libavcodec",
646 "Felipe Contreras");
34cd7f5 @felipec Initial commit
authored
647
648 template = gst_pad_template_new("src", GST_PAD_SRC,
c743ba9 @felipec Code-style cleanups
authored
649 GST_PAD_ALWAYS,
650 generate_src_template());
34cd7f5 @felipec Initial commit
authored
651
652 gst_element_class_add_pad_template(element_class, template);
653
654 template = gst_pad_template_new("sink", GST_PAD_SINK,
c743ba9 @felipec Code-style cleanups
authored
655 GST_PAD_ALWAYS,
656 generate_sink_template());
34cd7f5 @felipec Initial commit
authored
657
658 gst_element_class_add_pad_template(element_class, template);
659 }
660
661 static void
1cf1755 @felipec Trivial cleanups
authored
662 class_init(void *g_class, void *class_data)
34cd7f5 @felipec Initial commit
authored
663 {
4a86fdb @felipec Get away of gst code-style
authored
664 GstElementClass *gstelement_class = g_class;
a8d2e12 @felipec Add support for flushing
authored
665 GObjectClass *gobject_class = g_class;
34cd7f5 @felipec Initial commit
authored
666
667 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
668
669 gstelement_class->change_state = change_state;
a8d2e12 @felipec Add support for flushing
authored
670 gobject_class->finalize = finalize;
34cd7f5 @felipec Initial commit
authored
671 }
672
673 GType
880ebe4 Rename avdec to av_adec
Felipe Contreras authored
674 gst_av_adec_get_type(void)
34cd7f5 @felipec Initial commit
authored
675 {
528f20a @felipec Trivial cleanup
authored
676 static GType type;
34cd7f5 @felipec Initial commit
authored
677
678 if (G_UNLIKELY(type == 0)) {
679 GTypeInfo type_info = {
27f3b86 Generic cleanups
Felipe Contreras authored
680 .class_size = sizeof(struct obj_class),
34cd7f5 @felipec Initial commit
authored
681 .class_init = class_init,
682 .base_init = base_init,
27f3b86 Generic cleanups
Felipe Contreras authored
683 .instance_size = sizeof(struct obj),
34cd7f5 @felipec Initial commit
authored
684 .instance_init = instance_init,
685 };
686
880ebe4 Rename avdec to av_adec
Felipe Contreras authored
687 type = g_type_register_static(GST_TYPE_ELEMENT, "GstAVAudioDec", &type_info, 0);
34cd7f5 @felipec Initial commit
authored
688 }
689
690 return type;
691 }
Something went wrong with that request. Please try again.