1 /* GStreamer
2 * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * Copyright (C) <2011-2012> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /**
24 * SECTION:element-opusparse
25 * @title: opusparse
26 * @see_also: opusenc, opusdec
27 *
28 * This element parses OPUS packets.
29 *
30 * ## Example pipelines
31 * |[
32 * gst-launch-1.0 -v filesrc location=opusdata ! opusparse ! opusdec ! audioconvert ! audioresample ! alsasink
33 * ]| Decode and plays an unmuxed Opus file.
34 *
35 */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <string.h>
42 #include <opus.h>
43 #include "gstopusheader.h"
44 #include "gstopusparse.h"
45
46 #include <gst/audio/audio.h>
47 #include <gst/pbutils/pbutils.h>
48 #include <gst/tag/tag.h>
49
50 GST_DEBUG_CATEGORY_STATIC (opusparse_debug);
51 #define GST_CAT_DEFAULT opusparse_debug
52
53 #define MAX_PAYLOAD_BYTES 1500
54
55 static GstStaticPadTemplate opus_parse_src_factory =
56 GST_STATIC_PAD_TEMPLATE ("src",
57 GST_PAD_SRC,
58 GST_PAD_ALWAYS,
59 GST_STATIC_CAPS ("audio/x-opus, framed = (boolean) true")
60 );
61
62 static GstStaticPadTemplate opus_parse_sink_factory =
63 GST_STATIC_PAD_TEMPLATE ("sink",
64 GST_PAD_SINK,
65 GST_PAD_ALWAYS,
66 GST_STATIC_CAPS ("audio/x-opus")
67 );
68
69
70
71 static gboolean gst_opus_parse_start (GstBaseParse * parse);
72 static gboolean gst_opus_parse_stop (GstBaseParse * parse);
73 static GstFlowReturn gst_opus_parse_handle_frame (GstBaseParse * base,
74 GstBaseParseFrame * frame, gint * skip);
75 static GstFlowReturn gst_opus_parse_parse_frame (GstBaseParse * base,
76 GstBaseParseFrame * frame);
77 static gboolean opusparse_element_init (GstPlugin * plugin);
78
79 G_DEFINE_TYPE (GstOpusParse, gst_opus_parse, GST_TYPE_BASE_PARSE);
80 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (opusparse, opusparse_element_init);
81
82 static void
gst_opus_parse_class_init(GstOpusParseClass * klass)83 gst_opus_parse_class_init (GstOpusParseClass * klass)
84 {
85 GstBaseParseClass *bpclass;
86 GstElementClass *element_class;
87
88 bpclass = (GstBaseParseClass *) klass;
89 element_class = (GstElementClass *) klass;
90
91 bpclass->start = GST_DEBUG_FUNCPTR (gst_opus_parse_start);
92 bpclass->stop = GST_DEBUG_FUNCPTR (gst_opus_parse_stop);
93 bpclass->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_parse_handle_frame);
94
95 gst_element_class_add_static_pad_template (element_class,
96 &opus_parse_src_factory);
97 gst_element_class_add_static_pad_template (element_class,
98 &opus_parse_sink_factory);
99 gst_element_class_set_static_metadata (element_class, "Opus audio parser",
100 "Codec/Parser/Audio", "parses opus audio streams",
101 "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>");
102
103 GST_DEBUG_CATEGORY_INIT (opusparse_debug, "opusparse", 0,
104 "opus parsing element");
105 }
106
107 static void
gst_opus_parse_init(GstOpusParse * parse)108 gst_opus_parse_init (GstOpusParse * parse)
109 {
110 parse->header_sent = FALSE;
111 parse->got_headers = FALSE;
112 parse->pre_skip = 0;
113 }
114
115 static gboolean
gst_opus_parse_start(GstBaseParse * base)116 gst_opus_parse_start (GstBaseParse * base)
117 {
118 GstOpusParse *parse = GST_OPUS_PARSE (base);
119
120 parse->header_sent = FALSE;
121 parse->got_headers = FALSE;
122 parse->pre_skip = 0;
123 parse->next_ts = 0;
124
125 return TRUE;
126 }
127
128 static gboolean
gst_opus_parse_stop(GstBaseParse * base)129 gst_opus_parse_stop (GstBaseParse * base)
130 {
131 GstOpusParse *parse = GST_OPUS_PARSE (base);
132
133 parse->header_sent = FALSE;
134 parse->got_headers = FALSE;
135 parse->pre_skip = 0;
136
137 return TRUE;
138 }
139
140 static GstFlowReturn
gst_opus_parse_handle_frame(GstBaseParse * base,GstBaseParseFrame * frame,gint * skip)141 gst_opus_parse_handle_frame (GstBaseParse * base,
142 GstBaseParseFrame * frame, gint * skip)
143 {
144 GstOpusParse *parse;
145 guint8 *data;
146 gsize size;
147 guint32 packet_size;
148 int ret = FALSE;
149 const unsigned char *frames[48];
150 unsigned char toc;
151 short frame_sizes[48];
152 int payload_offset;
153 int packet_offset = 0;
154 gboolean is_header, is_idheader, is_commentheader;
155 GstMapInfo map;
156
157 parse = GST_OPUS_PARSE (base);
158
159 *skip = -1;
160
161 gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
162 data = map.data;
163 size = map.size;
164 GST_DEBUG_OBJECT (parse,
165 "Checking for frame, %" G_GSIZE_FORMAT " bytes in buffer", size);
166
167 /* check for headers */
168 is_idheader = gst_opus_header_is_id_header (frame->buffer);
169 is_commentheader = gst_opus_header_is_comment_header (frame->buffer);
170 is_header = is_idheader || is_commentheader;
171
172 if (!is_header) {
173 int nframes;
174
175 /* Next, check if there's an Opus packet there */
176 nframes =
177 opus_packet_parse (data, size, &toc, frames, frame_sizes,
178 &payload_offset);
179
180 if (nframes < 0) {
181 /* Then, check for the test vector framing */
182 GST_DEBUG_OBJECT (parse,
183 "No Opus packet found, trying test vector framing");
184 if (size < 4) {
185 GST_DEBUG_OBJECT (parse, "Too small");
186 goto beach;
187 }
188 packet_size = GST_READ_UINT32_BE (data);
189 GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
190 if (packet_size > MAX_PAYLOAD_BYTES) {
191 GST_DEBUG_OBJECT (parse, "Too large");
192 goto beach;
193 }
194 if (packet_size > size - 4) {
195 GST_DEBUG_OBJECT (parse, "Truncated");
196 goto beach;
197 }
198 nframes =
199 opus_packet_parse (data + 8, packet_size, &toc, frames, frame_sizes,
200 &payload_offset);
201 if (nframes < 0) {
202 GST_DEBUG_OBJECT (parse, "No test vector framing either");
203 goto beach;
204 }
205
206 packet_offset = 8;
207
208 /* for ad hoc framing, heed the framing, so we eat any padding */
209 payload_offset = packet_size;
210 } else {
211 /* Add up all the frame sizes found */
212 int f;
213 for (f = 0; f < nframes; ++f)
214 payload_offset += frame_sizes[f];
215 }
216 }
217
218 if (is_header) {
219 *skip = 0;
220 } else {
221 *skip = packet_offset;
222 size = payload_offset;
223 }
224
225 GST_DEBUG_OBJECT (parse,
226 "Got Opus packet at offset %d, %" G_GSIZE_FORMAT " bytes", *skip, size);
227 ret = TRUE;
228
229 beach:
230 gst_buffer_unmap (frame->buffer, &map);
231
232 /* convert old style result to new one */
233 if (!ret) {
234 if (*skip < 0)
235 *skip = 1;
236 return GST_FLOW_OK;
237 }
238
239 /* always skip first if needed */
240 if (*skip > 0)
241 return GST_FLOW_OK;
242
243 /* normalize again */
244 if (*skip < 0)
245 *skip = 0;
246
247 /* not enough */
248 if (size > map.size)
249 return GST_FLOW_OK;
250
251 /* FIXME some day ... should not mess with buffer itself */
252 if (!parse->got_headers) {
253 gst_buffer_replace (&frame->buffer,
254 gst_buffer_copy_region (frame->buffer, GST_BUFFER_COPY_ALL, 0, size));
255 gst_buffer_unref (frame->buffer);
256 }
257
258 ret = gst_opus_parse_parse_frame (base, frame);
259
260 if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
261 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
262 ret = GST_FLOW_OK;
263 }
264 if (ret == GST_FLOW_OK)
265 ret = gst_base_parse_finish_frame (base, frame, size);
266
267 return ret;
268 }
269
270 /* Adapted copy of the one in gstoggstream.c... */
271 static guint64
packet_duration_opus(const guint8 * data,size_t len)272 packet_duration_opus (const guint8 * data, size_t len)
273 {
274 static const guint64 durations[32] = {
275 10000, 20000, 40000, 60000, /* Silk NB */
276 10000, 20000, 40000, 60000, /* Silk MB */
277 10000, 20000, 40000, 60000, /* Silk WB */
278 10000, 20000, /* Hybrid SWB */
279 10000, 20000, /* Hybrid FB */
280 2500, 5000, 10000, 20000, /* CELT NB */
281 2500, 5000, 10000, 20000, /* CELT NB */
282 2500, 5000, 10000, 20000, /* CELT NB */
283 2500, 5000, 10000, 20000, /* CELT NB */
284 };
285
286 gint64 duration;
287 gint64 frame_duration;
288 gint nframes = 0;
289 guint8 toc;
290
291 if (len < 1)
292 return 0;
293
294 toc = data[0];
295
296 frame_duration = durations[toc >> 3] * 1000;
297 switch (toc & 3) {
298 case 0:
299 nframes = 1;
300 break;
301 case 1:
302 nframes = 2;
303 break;
304 case 2:
305 nframes = 2;
306 break;
307 case 3:
308 if (len < 2) {
309 GST_WARNING ("Code 3 Opus packet has less than 2 bytes");
310 return 0;
311 }
312 nframes = data[1] & 63;
313 break;
314 }
315
316 duration = nframes * frame_duration;
317 if (duration > 120 * GST_MSECOND) {
318 GST_WARNING ("Opus packet duration > 120 ms, invalid");
319 return 0;
320 }
321 GST_LOG ("Opus packet: frame size %.1f ms, %d frames, duration %.1f ms",
322 frame_duration / 1000000.f, nframes, duration / 1000000.f);
323 return duration;
324 }
325
326 static GstFlowReturn
gst_opus_parse_parse_frame(GstBaseParse * base,GstBaseParseFrame * frame)327 gst_opus_parse_parse_frame (GstBaseParse * base, GstBaseParseFrame * frame)
328 {
329 guint64 duration;
330 GstOpusParse *parse;
331 gboolean is_idheader, is_commentheader;
332 GstMapInfo map;
333 GstAudioClippingMeta *cmeta =
334 gst_buffer_get_audio_clipping_meta (frame->buffer);
335
336 parse = GST_OPUS_PARSE (base);
337
338 g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
339
340 is_idheader = gst_opus_header_is_id_header (frame->buffer);
341 is_commentheader = gst_opus_header_is_comment_header (frame->buffer);
342
343 if (!parse->got_headers || !parse->header_sent) {
344 GstCaps *caps;
345
346 /* Opus streams can decode to 1 or 2 channels, so use the header
347 value if we have one, or 2 otherwise */
348 if (is_idheader) {
349 gst_buffer_replace (&parse->id_header, frame->buffer);
350 GST_DEBUG_OBJECT (parse, "Found ID header, keeping");
351 return GST_BASE_PARSE_FLOW_DROPPED;
352 } else if (is_commentheader) {
353 gst_buffer_replace (&parse->comment_header, frame->buffer);
354 GST_DEBUG_OBJECT (parse, "Found comment header, keeping");
355 return GST_BASE_PARSE_FLOW_DROPPED;
356 }
357
358 parse->got_headers = TRUE;
359
360 if (cmeta && cmeta->start) {
361 parse->pre_skip += cmeta->start;
362
363 gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
364 duration = packet_duration_opus (map.data, map.size);
365 gst_buffer_unmap (frame->buffer, &map);
366
367 /* Queue frame for later once we know all initial padding */
368 if (duration == cmeta->start) {
369 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_QUEUE;
370 }
371 }
372
373 if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_QUEUE)) {
374 GstCaps *sink_caps;
375 guint32 sample_rate = 48000;
376 guint8 n_channels, n_streams, n_stereo_streams, channel_mapping_family;
377 guint8 channel_mapping[256];
378 GstBuffer *id_header;
379 guint16 pre_skip = 0;
380 gint16 gain = 0;
381
382 if (parse->id_header) {
383 gst_buffer_map (parse->id_header, &map, GST_MAP_READWRITE);
384 pre_skip = GST_READ_UINT16_LE (map.data + 10);
385 gain = GST_READ_UINT16_LE (map.data + 16);
386 gst_buffer_unmap (parse->id_header, &map);
387 }
388
389 sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
390 if (!sink_caps
391 || !gst_codec_utils_opus_parse_caps (sink_caps, &sample_rate,
392 &n_channels, &channel_mapping_family, &n_streams,
393 &n_stereo_streams, channel_mapping)) {
394 GST_INFO_OBJECT (parse,
395 "No headers and no caps, blindly setting up canonical stereo");
396 n_channels = 2;
397 n_streams = 1;
398 n_stereo_streams = 1;
399 channel_mapping_family = 0;
400 channel_mapping[0] = 0;
401 channel_mapping[1] = 1;
402 }
403 if (sink_caps)
404 gst_caps_unref (sink_caps);
405
406 id_header =
407 gst_codec_utils_opus_create_header (sample_rate, n_channels,
408 channel_mapping_family, n_streams, n_stereo_streams,
409 channel_mapping, pre_skip, gain);
410 caps = gst_codec_utils_opus_create_caps_from_header (id_header, NULL);
411 gst_buffer_unref (id_header);
412
413 gst_buffer_replace (&parse->id_header, NULL);
414 gst_buffer_replace (&parse->comment_header, NULL);
415
416 gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
417 gst_caps_unref (caps);
418 parse->header_sent = TRUE;
419 }
420 }
421
422 GST_BUFFER_TIMESTAMP (frame->buffer) = parse->next_ts;
423
424 gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
425 duration = packet_duration_opus (map.data, map.size);
426 gst_buffer_unmap (frame->buffer, &map);
427 parse->next_ts += duration;
428
429 GST_BUFFER_DURATION (frame->buffer) = duration;
430 GST_BUFFER_OFFSET_END (frame->buffer) =
431 gst_util_uint64_scale (parse->next_ts, 48000, GST_SECOND);
432 GST_BUFFER_OFFSET (frame->buffer) = parse->next_ts;
433
434 return GST_FLOW_OK;
435 }
436
437 static gboolean
opusparse_element_init(GstPlugin * plugin)438 opusparse_element_init (GstPlugin * plugin)
439 {
440 if (!gst_element_register (plugin, "opusparse", GST_RANK_NONE,
441 GST_TYPE_OPUS_PARSE))
442 return FALSE;
443
444 gst_tag_register_musicbrainz_tags ();
445 return TRUE;
446 }
447