ogg: add opus support
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Sat, 19 Nov 2011 16:06:09 +0000 (16:06 +0000)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Sat, 19 Nov 2011 16:06:09 +0000 (16:06 +0000)
ext/ogg/gstoggmux.c
ext/ogg/gstoggstream.c

index 186e87d..5341d6c 100644 (file)
@@ -107,7 +107,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d",
         "audio/x-vorbis; audio/x-flac; audio/x-speex; audio/x-celt; "
         "application/x-ogm-video; application/x-ogm-audio; video/x-dirac; "
         "video/x-smoke; video/x-vp8; text/x-cmml, encoded = (boolean) TRUE; "
-        "subtitle/x-kate; application/x-kate")
+        "subtitle/x-kate; application/x-kate; audio/x-opus")
     );
 
 static void gst_ogg_mux_base_init (gpointer g_class);
index a26791d..08cfca7 100644 (file)
@@ -1845,6 +1845,79 @@ extract_tags_kate (GstOggStream * pad, ogg_packet * packet)
   }
 }
 
+/* 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 */
@@ -2017,6 +2090,18 @@ const GstOggMap mappers[] = {
     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,