oggstream: reject Ogg/Opus streams with nonsensical preskip/granpos setup
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Wed, 6 Jun 2012 10:01:13 +0000 (11:01 +0100)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Wed, 6 Jun 2012 10:05:53 +0000 (11:05 +0100)
As the spec mandates.

ext/ogg/gstoggdemux.c
ext/ogg/gstoggstream.c
ext/ogg/gstoggstream.h

index cb8c2f7ef93360cd4fccf17e3c86100fd09fa8d9..348657576ba43efc6fed2c7e8fc47842a1dcab6b 100644 (file)
@@ -556,8 +556,15 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
     out_offset_end = -1;
   } else {
     if (packet->granulepos != -1) {
-      pad->current_granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
+      gint64 granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
           packet->granulepos);
+      if (granule < 0) {
+        GST_ERROR_OBJECT (ogg,
+            "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
+            packet->granulepos, granule);
+        return GST_FLOW_ERROR;
+      }
+      pad->current_granule = granule;
       pad->keyframe_granule =
           gst_ogg_stream_granulepos_to_key_granule (&pad->map,
           packet->granulepos);
@@ -866,6 +873,11 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
   if (granule != -1) {
     GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule);
     pad->current_granule = granule;
+  } else if (granule != -1) {
+    GST_ERROR_OBJECT (ogg,
+        "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
+        packet->granulepos, granule);
+    return GST_FLOW_ERROR;
   }
 
   /* restart header packet count when seeing a b_o_s page;
@@ -903,6 +915,12 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
 
         granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
             packet->granulepos);
+        if (granule < 0) {
+          GST_ERROR_OBJECT (ogg,
+              "granulepos %" G_GINT64_FORMAT " yielded granule %"
+              G_GINT64_FORMAT, packet->granulepos, granule);
+          return GST_FLOW_ERROR;
+        }
 
         if (granule > pad->map.accumulated_granule)
           start_granule = granule - pad->map.accumulated_granule;
index 2190b270676c34632f09c5814bcb8159c1f0d885..768d8cdee5b67530c627449c49a0f9945ddc21a8 100644 (file)
@@ -1873,6 +1873,7 @@ setup_opus_mapper (GstOggStream * pad, ogg_packet * packet)
   pad->granulerate_d = 1;
   pad->granuleshift = 0;
   pad->n_header_packets = 2;
+  pad->first_granpos = -1;
 
   /* pre-skip is in samples at 48000 Hz, which matches granule one for one */
   pad->granule_offset = -GST_READ_UINT16_LE (packet->packet + 10);
@@ -1890,6 +1891,29 @@ is_header_opus (GstOggStream * pad, ogg_packet * packet)
   return packet->bytes >= 8 && !memcmp (packet->packet, "Opus", 4);
 }
 
+static gint64
+granulepos_to_granule_opus (GstOggStream * pad, gint64 granulepos)
+{
+  if (granulepos == -1)
+    return -1;
+
+  /* We must reject some particular cases for the first granpos */
+
+  if (pad->first_granpos < 0 || granulepos < pad->first_granpos)
+    pad->first_granpos = granulepos;
+
+  if (pad->first_granpos == granulepos) {
+    if (granulepos < -pad->granule_offset) {
+      GST_ERROR ("Invalid Opus stream: first granulepos (%" G_GINT64_FORMAT
+          ") less than preskip (%" G_GINT64_FORMAT ")", granulepos,
+          -pad->granule_offset);
+      return -1;
+    }
+  }
+
+  return granulepos;
+}
+
 static gint64
 packet_duration_opus (GstOggStream * pad, ogg_packet * packet)
 {
@@ -2147,7 +2171,7 @@ const GstOggMap mappers[] = {
     "OpusHead", 8, 0,
     "audio/x-opus",
     setup_opus_mapper,
-    granulepos_to_granule_default,
+    granulepos_to_granule_opus,
     granule_to_granulepos_default,
     NULL,
     NULL,
index b7353a6fcd7a40d7b8d7ac8453fd86bcc4348822..f32f89bc8a83347663b9ba1f8d9a01d7112b0bc4 100644 (file)
@@ -93,6 +93,8 @@ struct _GstOggStream
   gboolean theora_has_zero_keyoffset;
   /* VP8 stuff */
   gboolean is_vp8;
+  /* opus stuff */
+  gint64 first_granpos;
   /* OGM stuff */
   gboolean is_ogm;
   gboolean is_ogm_text;