Merge branch 'upstream/1.16' into tizen_gst_1.16.2
[platform/upstream/gst-plugins-good.git] / gst / matroska / matroska-demux.c
index 77176fb..0939164 100644 (file)
@@ -151,6 +151,8 @@ static gboolean gst_matroska_demux_handle_src_query (GstPad * pad,
 
 static gboolean gst_matroska_demux_handle_sink_event (GstPad * pad,
     GstObject * parent, GstEvent * event);
+static gboolean gst_matroska_demux_handle_sink_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
 static GstFlowReturn gst_matroska_demux_chain (GstPad * pad,
     GstObject * object, GstBuffer * buffer);
 
@@ -173,6 +175,9 @@ static GstCaps *gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext
 static GstCaps
     * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
     subtitlecontext, const gchar * codec_id, gpointer data, guint size);
+static const gchar *gst_matroska_track_encryption_algorithm_name (gint val);
+static const gchar *gst_matroska_track_encryption_cipher_mode_name (gint val);
+static const gchar *gst_matroska_track_encoding_scope_name (gint val);
 
 /* stream methods */
 static void gst_matroska_demux_reset (GstElement * element);
@@ -268,6 +273,8 @@ gst_matroska_demux_init (GstMatroskaDemux * demux)
       GST_DEBUG_FUNCPTR (gst_matroska_demux_chain));
   gst_pad_set_event_function (demux->common.sinkpad,
       GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event));
+  gst_pad_set_query_function (demux->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_query));
   gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
 
   /* init defaults for common read context */
@@ -350,6 +357,11 @@ gst_matroska_demux_reset (GstElement * element)
 
   demux->cached_length = G_MAXUINT64;
 
+  if (demux->deferred_seek_event)
+    gst_event_unref (demux->deferred_seek_event);
+  demux->deferred_seek_event = NULL;
+  demux->deferred_seek_pad = NULL;
+
   gst_flow_combiner_clear (demux->flowcombiner);
 }
 
@@ -359,12 +371,13 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
   GstMapInfo map;
   gpointer data;
   gsize size;
+  GstBuffer *out_buf = buf;
 
   g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);
 
   GST_DEBUG ("decoding buffer %p", buf);
 
-  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_buffer_map (out_buf, &map, GST_MAP_READ);
   data = map.data;
   size = map.size;
 
@@ -372,15 +385,57 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
 
   if (gst_matroska_decode_data (context->encodings, &data, &size,
           GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME, FALSE)) {
-    gst_buffer_unmap (buf, &map);
-    gst_buffer_unref (buf);
-    return gst_buffer_new_wrapped (data, size);
+    if (data != map.data) {
+      gst_buffer_unmap (out_buf, &map);
+      gst_buffer_unref (out_buf);
+      out_buf = gst_buffer_new_wrapped (data, size);
+    } else {
+      gst_buffer_unmap (out_buf, &map);
+    }
   } else {
     GST_DEBUG ("decode data failed");
-    gst_buffer_unmap (buf, &map);
-    gst_buffer_unref (buf);
+    gst_buffer_unmap (out_buf, &map);
+    gst_buffer_unref (out_buf);
     return NULL;
   }
+  /* Encrypted stream */
+  if (context->protection_info) {
+
+    GstStructure *info_protect = gst_structure_copy (context->protection_info);
+    gboolean encrypted = FALSE;
+
+    gst_buffer_map (out_buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+
+    if (gst_matroska_parse_protection_meta (&data, &size, info_protect,
+            &encrypted)) {
+      if (data != map.data) {
+        GstBuffer *tmp_buf;
+
+        gst_buffer_unmap (out_buf, &map);
+        tmp_buf = out_buf;
+        out_buf = gst_buffer_copy_region (tmp_buf, GST_BUFFER_COPY_ALL,
+            gst_buffer_get_size (tmp_buf) - size, size);
+        gst_buffer_unref (tmp_buf);
+        if (encrypted)
+          gst_buffer_add_protection_meta (out_buf, info_protect);
+        else
+          gst_structure_free (info_protect);
+      } else {
+        gst_buffer_unmap (out_buf, &map);
+        gst_structure_free (info_protect);
+      }
+    } else {
+      GST_WARNING ("Adding protection metadata failed");
+      gst_buffer_unmap (out_buf, &map);
+      gst_buffer_unref (out_buf);
+      gst_structure_free (info_protect);
+      return NULL;
+    }
+  }
+
+  return out_buf;
 }
 
 static void
@@ -630,6 +685,8 @@ gst_matroska_demux_parse_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml,
   context->dts_only = FALSE;
   context->intra_only = FALSE;
   context->tags = gst_tag_list_new_empty ();
+  g_queue_init (&context->protection_event_queue);
+  context->protection_info = NULL;
 
   GST_DEBUG_OBJECT (demux, "Parsing a TrackEntry (%d tracks parsed so far)",
       demux->common.num_streams);
@@ -1467,6 +1524,31 @@ gst_matroska_demux_parse_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml,
         context->stream_headers, caps);
   }
 
+  if (context->encodings) {
+    GstMatroskaTrackEncoding *enc;
+    guint i;
+
+    for (i = 0; i < context->encodings->len; i++) {
+      enc = &g_array_index (context->encodings, GstMatroskaTrackEncoding, i);
+      if (enc->type == GST_MATROSKA_ENCODING_ENCRYPTION /* encryption */ ) {
+        GstStructure *s = gst_caps_get_structure (caps, 0);
+        if (!gst_structure_has_name (s, "application/x-webm-enc")) {
+          gst_structure_set (s, "original-media-type", G_TYPE_STRING,
+              gst_structure_get_name (s), NULL);
+          gst_structure_set (s, "encryption-algorithm", G_TYPE_STRING,
+              gst_matroska_track_encryption_algorithm_name (enc->enc_algo),
+              NULL);
+          gst_structure_set (s, "encoding-scope", G_TYPE_STRING,
+              gst_matroska_track_encoding_scope_name (enc->scope), NULL);
+          gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
+              gst_matroska_track_encryption_cipher_mode_name
+              (enc->enc_cipher_mode), NULL);
+          gst_structure_set_name (s, "application/x-webm-enc");
+        }
+      }
+    }
+  }
+
   context->caps = caps;
 
   /* tadaah! */
@@ -1821,9 +1903,13 @@ gst_matroska_demux_element_send_event (GstElement * element, GstEvent * event)
   if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
     /* no seeking until we are (safely) ready */
     if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
-      GST_DEBUG_OBJECT (demux, "not ready for seeking yet");
-      gst_event_unref (event);
-      return FALSE;
+      GST_DEBUG_OBJECT (demux,
+          "not ready for seeking yet, deferring seek: %" GST_PTR_FORMAT, event);
+      if (demux->deferred_seek_event)
+        gst_event_unref (demux->deferred_seek_event);
+      demux->deferred_seek_event = event;
+      demux->deferred_seek_pad = NULL;
+      return TRUE;
     }
     res = gst_matroska_demux_handle_seek_event (demux, NULL, event);
   } else {
@@ -2932,9 +3018,14 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstObject * parent,
     case GST_EVENT_SEEK:
       /* no seeking until we are (safely) ready */
       if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
-        GST_DEBUG_OBJECT (demux, "not ready for seeking yet");
-        gst_event_unref (event);
-        return FALSE;
+        GST_DEBUG_OBJECT (demux,
+            "not ready for seeking yet, deferring seek event: %" GST_PTR_FORMAT,
+            event);
+        if (demux->deferred_seek_event)
+          gst_event_unref (demux->deferred_seek_event);
+        demux->deferred_seek_event = event;
+        demux->deferred_seek_pad = pad;
+        return TRUE;
       }
 
       {
@@ -3029,6 +3120,47 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstObject * parent,
   return res;
 }
 
+static gboolean
+gst_matroska_demux_handle_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_BITRATE:
+    {
+      if (G_UNLIKELY (demux->cached_length == G_MAXUINT64 ||
+              demux->common.offset >= demux->cached_length)) {
+        demux->cached_length =
+            gst_matroska_read_common_get_length (&demux->common);
+      }
+
+      if (demux->cached_length < G_MAXUINT64
+          && demux->common.segment.duration > 0) {
+        /* TODO: better results based on ranges/index tables */
+        guint bitrate =
+            gst_util_uint64_scale (8 * demux->cached_length, GST_SECOND,
+            demux->common.segment.duration);
+
+        GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
+            " duration %" GST_TIME_FORMAT " resulting in a bitrate of %u",
+            demux->cached_length,
+            GST_TIME_ARGS (demux->common.segment.duration), bitrate);
+
+        gst_query_set_bitrate (query, bitrate);
+        res = TRUE;
+      }
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, (GstObject *) demux, query);
+      break;
+  }
+
+  return res;
+}
+
 static GstFlowReturn
 gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
 {
@@ -3128,6 +3260,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
   DEBUG_ELEMENT_STOP (demux, ebml, "Tracks", ret);
 
   demux->tracks_parsed = TRUE;
+  GST_DEBUG_OBJECT (demux, "signaling no more pads");
+  gst_element_no_more_pads (GST_ELEMENT (demux));
 
   return ret;
 }
@@ -3203,6 +3337,7 @@ gst_matroska_demux_update_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
         if (!gst_caps_is_equal (old_track->caps, new_track->caps)) {
           gst_pad_set_caps (new_track->pad, new_track->caps);
         }
+        gst_caps_replace (&old_track->caps, NULL);
 
         if (!gst_tag_list_is_equal (old_track->tags, new_track->tags)) {
           GST_DEBUG_OBJECT (old_track->pad, "Sending tags %p: %"
@@ -4183,6 +4318,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
     gboolean delta_unit = FALSE;
     guint64 duration = 0;
     gint64 lace_time = 0;
+    GstEvent *protect_event;
 
     stream = g_ptr_array_index (demux->common.src, stream_num);
 
@@ -4202,6 +4338,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
     } else {
       lace_time = GST_CLOCK_TIME_NONE;
     }
+    /* Send the GST_PROTECTION event */
+    while ((protect_event = g_queue_pop_head (&stream->protection_event_queue))) {
+      GST_TRACE_OBJECT (demux, "pushing protection event for stream %d:%s",
+          stream->index, GST_STR_NULL (stream->name));
+      gst_pad_push_event (stream->pad, protect_event);
+    }
 
     /* need to refresh segment info ASAP */
     if (GST_CLOCK_TIME_IS_VALID (lace_time) && demux->need_segment) {
@@ -4273,8 +4415,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
       /* If we're doing a keyframe-only trickmode, only push keyframes on video
        * streams */
       if (delta_unit
-          && demux->common.
-          segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) {
+          && demux->common.segment.
+          flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) {
         GST_LOG_OBJECT (demux, "Skipping non-keyframe on stream %d",
             stream->index);
         ret = GST_FLOW_OK;
@@ -5178,6 +5320,8 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
                 GST_DEBUG_OBJECT (demux,
                     "estimated duration as %" GST_TIME_FORMAT,
                     GST_TIME_ARGS (demux->common.segment.duration));
+
+                g_free (last);
               }
             }
 
@@ -5196,8 +5340,20 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
               demux->common.offset = demux->first_cluster_offset;
             }
 
-            GST_DEBUG_OBJECT (demux, "signaling no more pads");
-            gst_element_no_more_pads (GST_ELEMENT (demux));
+            if (demux->deferred_seek_event) {
+              GstEvent *seek_event;
+              GstPad *seek_pad;
+              seek_event = demux->deferred_seek_event;
+              seek_pad = demux->deferred_seek_pad;
+              demux->deferred_seek_event = NULL;
+              demux->deferred_seek_pad = NULL;
+              GST_DEBUG_OBJECT (demux,
+                  "Handling deferred seek event: %" GST_PTR_FORMAT, seek_event);
+              gst_matroska_demux_handle_seek_event (demux, seek_pad,
+                  seek_event);
+              gst_event_unref (seek_event);
+            }
+
             /* send initial segment - we wait till we know the first
                incoming timestamp, so we can properly set the start of
                the segment. */
@@ -5350,6 +5506,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
         }
         case GST_MATROSKA_ID_POSITION:
         case GST_MATROSKA_ID_ENCRYPTEDBLOCK:
+          /* The WebM doesn't support the EncryptedBlock element.
+           * The Matroska spec doesn't give us more detail, how to parse this element,
+           * for example the field TransformID isn't specified yet.*/
         case GST_MATROSKA_ID_SILENTTRACKS:
           GST_DEBUG_OBJECT (demux,
               "Skipping Cluster subelement 0x%x - ignoring", id);
@@ -5907,8 +6066,11 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
         static GstStaticCaps intra_caps = GST_STATIC_CAPS ("image/jpeg; "
             "video/x-raw; image/png; video/x-dv; video/x-huffyuv; video/x-ffv; "
             "video/x-compressed-yuv");
+        GstCaps *tmp = gst_static_caps_get (&intra_caps);
+
         context->intra_only =
-            gst_caps_can_intersect (gst_static_caps_get (&intra_caps), caps);
+            gst_caps_can_intersect (tmp, caps);
+        gst_caps_unref(tmp);
       }
 
       if (buf)
@@ -6115,9 +6277,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
       gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
       gst_buffer_unref (priv);
     } else {
-      GST_WARNING ("No codec data found, assuming output is byte-stream");
-      gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, "byte-stream",
-          NULL);
+      GST_WARNING ("No AV1 codec data found!");
     }
     *codec_name = g_strdup_printf ("AOM AV1");
   } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
@@ -6542,8 +6702,8 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
         *riff_audio_fmt = auds.format;
 
       /* FIXME: Handle reorder map */
-      caps = gst_riff_create_audio_caps (auds.format, NULL, &auds, NULL,
-          codec_data, codec_name, NULL);
+      caps = gst_riff_create_audio_caps (auds.format, NULL, &auds, codec_data,
+          NULL, codec_name, NULL);
       if (codec_data)
         gst_buffer_unref (codec_data);
 
@@ -6915,6 +7075,37 @@ gst_matroska_demux_get_property (GObject * object,
   }
 }
 
+static const gchar *
+gst_matroska_track_encryption_algorithm_name (gint val)
+{
+  GEnumValue *en;
+  GEnumClass *enum_class =
+      g_type_class_ref (MATROSKA_TRACK_ENCRYPTION_ALGORITHM_TYPE);
+  en = g_enum_get_value (G_ENUM_CLASS (enum_class), val);
+  return en ? en->value_nick : NULL;
+}
+
+static const gchar *
+gst_matroska_track_encryption_cipher_mode_name (gint val)
+{
+  GEnumValue *en;
+  GEnumClass *enum_class =
+      g_type_class_ref (MATROSKA_TRACK_ENCRYPTION_CIPHER_MODE_TYPE);
+  en = g_enum_get_value (G_ENUM_CLASS (enum_class), val);
+  return en ? en->value_nick : NULL;
+}
+
+static const gchar *
+gst_matroska_track_encoding_scope_name (gint val)
+{
+  GEnumValue *en;
+  GEnumClass *enum_class =
+      g_type_class_ref (MATROSKA_TRACK_ENCODING_SCOPE_TYPE);
+
+  en = g_enum_get_value (G_ENUM_CLASS (enum_class), val);
+  return en ? en->value_nick : NULL;
+}
+
 gboolean
 gst_matroska_demux_plugin_init (GstPlugin * plugin)
 {