}
}
+/* opus */
+
+static gboolean
+setup_opus_mapper (GstOggStream * pad, ogg_packet * packet)
+{
+ if (packet->bytes < 19)
+ return FALSE;
+
+ pad->granulerate_n = 48000;
+ pad->granulerate_d = 1;
+ pad->granuleshift = 0;
+ pad->n_header_packets = 2;
+
+ pad->caps = gst_caps_new_simple ("audio/x-opus", NULL);
+
+ return TRUE;
+}
+
+static gint64
+packet_duration_opus (GstOggStream * pad, ogg_packet * packet)
+{
+ static const guint64 durations[32] = {
+ 10000, 20000, 40000, 60000, /* Silk NB */
+ 10000, 20000, 40000, 60000, /* Silk MB */
+ 10000, 20000, 40000, 60000, /* Silk WB */
+ 10000, 20000, /* Hybrid SWB */
+ 10000, 20000, /* Hybrid FB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ };
+
+ gint64 duration;
+ gint64 frame_duration;
+ gint nframes;
+ guint8 toc;
+
+ if (packet->bytes < 1)
+ return 0;
+
+ toc = packet->packet[0];
+
+ frame_duration = durations[toc >> 3] * 1000;
+ switch (toc & 3) {
+ case 0:
+ nframes = 1;
+ break;
+ case 1:
+ nframes = 2;
+ break;
+ case 2:
+ nframes = 2;
+ break;
+ case 3:
+ if (packet->bytes < 2) {
+ GST_WARNING ("Code 3 Opus packet has less than 2 bytes");
+ return 0;
+ }
+ nframes = packet->packet[1] & 63;
+ break;
+ }
+
+ duration = nframes * frame_duration;
+ if (duration > 120 * GST_MSECOND) {
+ GST_WARNING ("Opus packet duration > 120 ms, invalid");
+ return 0;
+ }
+ GST_LOG ("Opus packet: frame size %.1f ms, %d frames, duration %.1f ms",
+ frame_duration / 1000000.f, nframes, duration / 1000000.f);
+ return (duration + 24000) / 48000;
+}
+
/* *INDENT-OFF* */
/* indent hates our freedoms */
extract_tags_vp8
},
{
+ "OpusHead", 8, 0,
+ "audio/x-opus",
+ setup_opus_mapper,
+ granulepos_to_granule_default,
+ granule_to_granulepos_default,
+ NULL,
+ is_header_count,
+ packet_duration_opus,
+ NULL,
+ extract_tags_count
+ },
+ {
"\001audio\0\0\0", 9, 53,
"application/x-ogm-audio",
setup_ogmaudio_mapper,