Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 23 Nov 2011 09:50:53 +0000 (10:50 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 23 Nov 2011 09:50:53 +0000 (10:50 +0100)
Conflicts:
ext/ogg/gstoggmux.c

ext/ogg/gstoggdemux.c
ext/ogg/gstoggmux.c
ext/ogg/gstoggstream.c
ext/ogg/gstoggstream.h
gst/playback/gstplaysinkconvertbin.c

index b0907ba..ad5ab26 100644 (file)
@@ -891,9 +891,12 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
         pad->start_time = gst_ogg_stream_granule_to_time (&pad->map,
             start_granule);
         GST_DEBUG_OBJECT (ogg,
-            "start time %" GST_TIME_FORMAT " (%" GST_TIME_FORMAT ") for %s",
+            "start time %" GST_TIME_FORMAT " (%" GST_TIME_FORMAT ") for %s "
+            "from granpos %" G_GINT64_FORMAT " (granule %" G_GINT64_FORMAT ", "
+            "accumulated granule %" G_GINT64_FORMAT,
             GST_TIME_ARGS (pad->start_time), GST_TIME_ARGS (pad->start_time),
-            gst_ogg_stream_get_media_type (&pad->map));
+            gst_ogg_stream_get_media_type (&pad->map), packet->granulepos,
+            granule, pad->map.accumulated_granule);
       } else {
         packet->granulepos = gst_ogg_stream_granule_to_granulepos (&pad->map,
             pad->map.accumulated_granule, pad->keyframe_granule);
index 283505c..922409b 100644 (file)
@@ -115,7 +115,7 @@ static GstStaticPadTemplate audio_sink_factory =
     GST_PAD_REQUEST,
     GST_STATIC_CAPS
     ("audio/x-vorbis; audio/x-flac; audio/x-speex; audio/x-celt; "
-        "application/x-ogm-audio; ")
+        "application/x-ogm-audio; audio/x-opus")
     );
 
 static GstStaticPadTemplate subtitle_sink_factory =
index f09f028..49fe255 100644 (file)
@@ -127,6 +127,10 @@ gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
   if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
     return 0;
 
+  granule += pad->granule_offset;
+  if (granule < 0)
+    return 0;
+
   return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
       pad->granulerate_n);
 }
@@ -1820,6 +1824,103 @@ 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;
+
+  /* pre-skip is in samples at 48000 Hz, which matches granule one for one */
+  pad->granule_offset = -GST_READ_UINT16_LE (packet->packet + 10);
+  GST_INFO ("Opus has a pre-skip of %" G_GINT64_FORMAT " samples",
+      -pad->granule_offset);
+
+  pad->caps = gst_caps_new_simple ("audio/x-opus", NULL);
+
+  return TRUE;
+}
+
+static gboolean
+is_header_opus (GstOggStream * pad, ogg_packet * packet)
+{
+  return packet->bytes >= 8 && !memcmp (packet->packet, "Opus", 4);
+}
+
+static gint64
+packet_duration_opus (GstOggStream * pad, ogg_packet * packet)
+{
+  static const guint64 durations[32] = {
+    480, 960, 1920, 2880,       /* Silk NB */
+    480, 960, 1920, 2880,       /* Silk MB */
+    480, 960, 1920, 2880,       /* Silk WB */
+    480, 960,                   /* Hybrid SWB */
+    480, 960,                   /* Hybrid FB */
+    120, 240, 480, 960,         /* CELT NB */
+    120, 240, 480, 960,         /* CELT NB */
+    120, 240, 480, 960,         /* CELT NB */
+    120, 240, 480, 960,         /* CELT NB */
+  };
+
+  gint64 duration;
+  gint64 frame_duration;
+  gint nframes;
+  guint8 toc;
+
+  if (packet->bytes < 1)
+    return 0;
+
+  /* headers */
+  if (is_header_opus (pad, packet))
+    return 0;
+
+  toc = packet->packet[0];
+
+  frame_duration = durations[toc >> 3];
+  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 > 5760) {
+    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 / 48.f, nframes, duration / 48.f);
+  return duration;
+}
+
+static void
+extract_tags_opus (GstOggStream * pad, ogg_packet * packet)
+{
+  if (packet->bytes >= 8 && memcmp (packet->packet, "OpusTags", 8) == 0) {
+    tag_list_from_vorbiscomment_packet (packet,
+        (const guint8 *) "OpusTags", 8, &pad->taglist);
+  }
+}
+
 
 /* *INDENT-OFF* */
 /* indent hates our freedoms */
@@ -1992,6 +2093,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_opus,
+    packet_duration_opus,
+    NULL,
+    extract_tags_opus
+  },
+  {
     "\001audio\0\0\0", 9, 53,
     "application/x-ogm-audio",
     setup_ogmaudio_mapper,
index d6c4de6..a66a78c 100644 (file)
@@ -60,6 +60,7 @@ struct _GstOggStream
   gboolean have_fisbone;
   gint granulerate_n;
   gint granulerate_d;
+  gint64 granule_offset;
   guint32 preroll;
   guint granuleshift;
   gint n_header_packets;
index dbd233b..ba5efaa 100644 (file)
@@ -446,12 +446,20 @@ gst_play_sink_convert_bin_remove_elements (GstPlaySinkConvertBin * self)
 }
 
 static void
-gst_play_sink_convert_bin_finalize (GObject * object)
+gst_play_sink_convert_bin_dispose (GObject * object)
 {
   GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN_CAST (object);
 
   gst_play_sink_convert_bin_remove_elements (self);
 
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_play_sink_convert_bin_finalize (GObject * object)
+{
+  GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN_CAST (object);
+
   gst_object_unref (self->sink_proxypad);
   g_mutex_free (self->lock);
 
@@ -548,6 +556,7 @@ gst_play_sink_convert_bin_class_init (GstPlaySinkConvertBinClass * klass)
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
+  gobject_class->dispose = gst_play_sink_convert_bin_dispose;
   gobject_class->finalize = gst_play_sink_convert_bin_finalize;
 
   gst_element_class_add_pad_template (gstelement_class,