[WPE] Bump GStreamer packages in jhbuild.modules to 1.10.5
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Jul 2017 14:59:25 +0000 (14:59 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Jul 2017 14:59:25 +0000 (14:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174350

Reviewed by Xabier Rodriguez-Calvar.

Bump the various GStreamer dependencies listed in WPE's Jhbuild modules file
to the 1.10.5 version. One gstreamer patch is added. The two gst-plugins-bad
patches are removed. The patches for gst-plugins-good are updated, removing
the stale ones and adding the additional changes to qtdemux, souphttpsrc and
rtpbin elements that will help with the EMEv3 development.

* wpe/jhbuild.modules:
* wpe/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch: Removed.
* wpe/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch: Removed.
* wpe/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch: Added.
* wpe/patches/gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch: Added.
* wpe/patches/gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch: Added.
* wpe/patches/gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch: Added.
* wpe/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch: Removed.
* wpe/patches/gst-plugins-good-use-the-tfdt-decode-time.patch: Removed.
* wpe/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219329 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/wpe/jhbuild.modules
Tools/wpe/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch [deleted file]
Tools/wpe/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch [deleted file]
Tools/wpe/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch [new file with mode: 0644]
Tools/wpe/patches/gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch [new file with mode: 0644]
Tools/wpe/patches/gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch [new file with mode: 0644]
Tools/wpe/patches/gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch [new file with mode: 0644]
Tools/wpe/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch [deleted file]
Tools/wpe/patches/gst-plugins-good-use-the-tfdt-decode-time.patch [deleted file]
Tools/wpe/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch [new file with mode: 0644]

index cfb28e8..949c9d6 100644 (file)
@@ -1,3 +1,27 @@
+2017-07-11  Zan Dobersek  <zdobersek@igalia.com>
+
+        [WPE] Bump GStreamer packages in jhbuild.modules to 1.10.5
+        https://bugs.webkit.org/show_bug.cgi?id=174350
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Bump the various GStreamer dependencies listed in WPE's Jhbuild modules file
+        to the 1.10.5 version. One gstreamer patch is added. The two gst-plugins-bad
+        patches are removed. The patches for gst-plugins-good are updated, removing
+        the stale ones and adding the additional changes to qtdemux, souphttpsrc and
+        rtpbin elements that will help with the EMEv3 development.
+
+        * wpe/jhbuild.modules:
+        * wpe/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch: Removed.
+        * wpe/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch: Removed.
+        * wpe/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch: Added.
+        * wpe/patches/gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch: Added.
+        * wpe/patches/gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch: Added.
+        * wpe/patches/gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch: Added.
+        * wpe/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch: Removed.
+        * wpe/patches/gst-plugins-good-use-the-tfdt-decode-time.patch: Removed.
+        * wpe/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch: Added.
+
 2017-07-10  John Wilander  <wilander@apple.com>
 
         Resource Load Statistics: Prune statistics in orders of importance
index 3bcc1bb..a349c9b 100644 (file)
     <dependencies>
       <dep package="orc"/>
     </dependencies>
-    <branch module="gstreamer/gstreamer-${version}.tar.xz" version="1.8.1"
+    <branch module="gstreamer/gstreamer-${version}.tar.xz" version="1.10.5"
             repo="gstreamer"
-            hash="sha256:5a3722fb9302dd977c17ced4240293dc777cb716dc98c8cca63d75c27e5e3107"
-            md5sum="711ada79b63e47ac96adb4e5444dc908">
-      <patch file="gstreamer-typefind-Only-push-a-CAPS-event-downstream-if-the-.patch" strip="1"/>
+            hash="sha256:bc06243600817f637029da29d089d5908d1d266542f68bf6626a10c5f05f1f1d">
+      <patch file="gstreamer-0001-protection-added-function-to-filter-system-ids.patch" strip="1"/>
     </branch>
   </autotools>
 
     <dependencies>
       <dep package="gstreamer"/>
     </dependencies>
-    <branch module="gst-plugins-base/gst-plugins-base-${version}.tar.xz" version="1.8.1"
+    <branch module="gst-plugins-base/gst-plugins-base-${version}.tar.xz" version="1.10.5"
             repo="gstreamer"
-            hash="sha256:15a9de985cd265c344e359f5b19347df4021b7611ed2c2d91917cb900f2fad6f"
-            md5sum="5421edfeb7479d5f5776e917ba30e24e"/>
+            hash="sha256:1c401a79bd1e4521c6ef1b66579bddedd9136e164e54792aab4bfcf3485bf9a7"/>
   </autotools>
 
   <autotools id="gst-plugins-good" autogen-sh="configure" autogenargs="--disable-examples --disable-soup --disable-gtk-doc">
       <dep package="gst-plugins-base"/>
     </dependencies>
 
-    <branch module="gst-plugins-good/gst-plugins-good-${version}.tar.xz" version="1.8.1"
+    <branch module="gst-plugins-good/gst-plugins-good-${version}.tar.xz" version="1.10.5"
             repo="gstreamer"
-            hash="sha256:2103e17921d67894e82eafdd64fb9b06518599952fd93e625bfbc83ffead0972"
-            md5sum="3eabe7277681b9bef8a64c312de03d47">
-      <patch file="gst-plugins-good-use-the-tfdt-decode-time.patch" strip="1"/>
-      <patch file="gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch" strip="1"/>
+            hash="sha256:be053f6ed716eeb517cec148cec637cdce571c6e04d5c21409e2876fb76c7639">
+      <patch file="gst-plugins-good-0003-rtpbin-receive-bundle-support.patch" strip="1"/>
+      <patch file="gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch" strip="1"/>
+      <patch file="gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch" strip="1"/>
+      <patch file="gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch" strip="1"/>
     </branch>
   </autotools>
 
     <dependencies>
       <dep package="gst-plugins-base"/>
     </dependencies>
-    <branch module="gst-plugins-bad/gst-plugins-bad-${version}.tar.xz" version="1.8.1"
+    <branch module="gst-plugins-bad/gst-plugins-bad-${version}.tar.xz" version="1.10.5"
             repo="gstreamer"
-            hash="sha256:0bbd58f363734fc0c4a620b2d6fb01d427fdafdbda7b90b4e15d03b751ca40f5"
-            md5sum="e508da2a8a5c3d12264fe3415be2f451">
-      <patch file="gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch" strip="1"/>
-      <patch file="gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch" strip="1"/>
+            hash="sha256:c5806040bb83b43be86ce592e6a19c5d83d7776f7d9f434eb4b911c4efff3573">
     </branch>
   </autotools>
 
     <dependencies>
       <dep package="gst-plugins-base"/>
     </dependencies>
-    <branch module="gst-libav/gst-libav-${version}.tar.xz" version="1.8.1"
+    <branch module="gst-libav/gst-libav-${version}.tar.xz" version="1.10.5"
             repo="gstreamer"
-            hash="sha256:44a49108c3531b5ac4f346a2247cd7fbafb0e8ab394394cb6d75a70300b38933"
-            md5sum="85f1a047606ca9e08493d7b6b42df462"/>
+            hash="sha256:e4d2f315f478d47281fbfdfbd590a63d23704ca37911d7142d5992616f4b28d3"/>
   </autotools>
 
   <cmake id="wpe">
diff --git a/Tools/wpe/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch b/Tools/wpe/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch
deleted file mode 100644 (file)
index 5d1064e..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-From e938933167c494cdca443334f658b02a03c4486b Mon Sep 17 00:00:00 2001
-From: Daiki Ueno <dueno@redhat.com>
-Date: Wed, 26 Oct 2016 14:51:01 +0200
-Subject: [PATCH] dtls: port to OpenSSL 1.1.0
-
-Changes are:
-
-- Use the wrapper functions to access opaque data types.  To preserve
-  backward compatibility, define fallback definitions
-
-- Remove the use of idiom "pqueue_size(ssl->d1->sent_messages)", since
-  there is no replacement
-
-- Use RSA_generate_key_ex instead of the deprecated RSA_generate_key
-
-https://bugzilla.gnome.org/show_bug.cgi?id=773540
----
- ext/dtls/gstdtlscertificate.c | 15 ++++++++
- ext/dtls/gstdtlsconnection.c  | 87 ++++++++++++++++++++++++++++++++++++++-----
- 2 files changed, 93 insertions(+), 9 deletions(-)
-
-diff --git a/ext/dtls/gstdtlscertificate.c b/ext/dtls/gstdtlscertificate.c
-index 95fbb83..c1c9602 100644
---- a/ext/dtls/gstdtlscertificate.c
-+++ b/ext/dtls/gstdtlscertificate.c
-@@ -199,7 +199,22 @@ init_generated (GstDtlsCertificate * self)
-     priv->private_key = NULL;
-     return;
-   }
-+
-+  /* XXX: RSA_generate_key is actually deprecated in 0.9.8 */
-+#if OPENSSL_VERSION_NUMBER < 0x10100001L
-   rsa = RSA_generate_key (2048, RSA_F4, NULL, NULL);
-+#else
-+  rsa = RSA_new ();
-+  if (rsa != NULL) {
-+    BIGNUM *e = BN_new ();
-+    if (e != NULL && BN_set_word (e, RSA_F4)
-+        && RSA_generate_key_ex (rsa, 2048, e, NULL)) {
-+      RSA_free (rsa);
-+      rsa = NULL;
-+    }
-+    BN_free (e);
-+  }
-+#endif
-   if (!rsa) {
-     GST_WARNING_OBJECT (self, "failed to generate RSA");
-diff --git a/ext/dtls/gstdtlsconnection.c b/ext/dtls/gstdtlsconnection.c
-index 36f6d63..728f5a7 100644
---- a/ext/dtls/gstdtlsconnection.c
-+++ b/ext/dtls/gstdtlsconnection.c
-@@ -42,6 +42,8 @@
- #include <openssl/err.h>
- #include <openssl/ssl.h>
-+#include <string.h>
-+
- GST_DEBUG_CATEGORY_STATIC (gst_dtls_connection_debug);
- #define GST_CAT_DEFAULT gst_dtls_connection_debug
- G_DEFINE_TYPE_WITH_CODE (GstDtlsConnection, gst_dtls_connection, G_TYPE_OBJECT,
-@@ -216,6 +218,38 @@ gst_dtls_connection_finalize (GObject * gobject)
-   G_OBJECT_CLASS (gst_dtls_connection_parent_class)->finalize (gobject);
- }
-+#if OPENSSL_VERSION_NUMBER < 0x10100001L
-+static void
-+BIO_set_data (BIO * bio, void *ptr)
-+{
-+  bio->ptr = ptr;
-+}
-+
-+static void *
-+BIO_get_data (BIO * bio)
-+{
-+  return bio->ptr;
-+}
-+
-+static void
-+BIO_set_shutdown (BIO * bio, int shutdown)
-+{
-+  bio->shutdown = shutdown;
-+}
-+
-+static void
-+BIO_set_init (BIO * bio, int init)
-+{
-+  bio->init = init;
-+}
-+
-+static X509 *
-+X509_STORE_CTX_get0_cert (X509_STORE_CTX * ctx)
-+{
-+  return ctx->cert;
-+}
-+#endif
-+
- static void
- gst_dtls_connection_set_property (GObject * object, guint prop_id,
-     const GValue * value, GParamSpec * pspec)
-@@ -239,7 +273,7 @@ gst_dtls_connection_set_property (GObject * object, guint prop_id,
-       priv->bio = BIO_new (BIO_s_gst_dtls_connection ());
-       g_return_if_fail (priv->bio);
--      priv->bio->ptr = self;
-+      BIO_set_data (priv->bio, self);
-       SSL_set_bio (priv->ssl, priv->bio, priv->bio);
-       SSL_set_verify (priv->ssl,
-@@ -573,6 +607,7 @@ log_state (GstDtlsConnection * self, const gchar * str)
-   states |= (! !SSL_want_write (priv->ssl) << 20);
-   states |= (! !SSL_want_read (priv->ssl) << 24);
-+#if OPENSSL_VERSION_NUMBER < 0x10100001L
-   GST_LOG_OBJECT (self, "%s: role=%s buf=(%d,%p:%d/%d) %x|%x %s",
-       str,
-       priv->is_client ? "client" : "server",
-@@ -581,6 +616,15 @@ log_state (GstDtlsConnection * self, const gchar * str)
-       priv->bio_buffer_offset,
-       priv->bio_buffer_len,
-       states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl));
-+#else
-+  GST_LOG_OBJECT (self, "%s: role=%s buf=(%p:%d/%d) %x|%x %s",
-+      str,
-+      priv->is_client ? "client" : "server",
-+      priv->bio_buffer,
-+      priv->bio_buffer_offset,
-+      priv->bio_buffer_len,
-+      states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl));
-+#endif
- }
- static void
-@@ -737,7 +781,7 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
-   self = SSL_get_ex_data (ssl, connection_ex_index);
-   g_return_val_if_fail (GST_IS_DTLS_CONNECTION (self), FALSE);
--  pem = _gst_dtls_x509_to_pem (x509_ctx->cert);
-+  pem = _gst_dtls_x509_to_pem (X509_STORE_CTX_get0_cert (x509_ctx));
-   if (!pem) {
-     GST_WARNING_OBJECT (self,
-@@ -749,7 +793,8 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
-       gint len;
-       len =
--          X509_NAME_print_ex (bio, X509_get_subject_name (x509_ctx->cert), 1,
-+          X509_NAME_print_ex (bio,
-+          X509_get_subject_name (X509_STORE_CTX_get0_cert (x509_ctx)), 1,
-           XN_FLAG_MULTILINE);
-       BIO_read (bio, buffer, len);
-       buffer[len] = '\0';
-@@ -777,6 +822,7 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
-     ########  ####  #######
- */
-+#if OPENSSL_VERSION_NUMBER < 0x10100001L
- static BIO_METHOD custom_bio_methods = {
-   BIO_TYPE_BIO,
-   "stream",
-@@ -795,11 +841,34 @@ BIO_s_gst_dtls_connection (void)
- {
-   return &custom_bio_methods;
- }
-+#else
-+static BIO_METHOD *custom_bio_methods;
-+
-+static BIO_METHOD *
-+BIO_s_gst_dtls_connection (void)
-+{
-+  if (custom_bio_methods != NULL)
-+    return custom_bio_methods;
-+
-+  custom_bio_methods = BIO_meth_new (BIO_TYPE_BIO, "stream");
-+  if (custom_bio_methods == NULL
-+      || !BIO_meth_set_write (custom_bio_methods, bio_method_write)
-+      || !BIO_meth_set_read (custom_bio_methods, bio_method_read)
-+      || !BIO_meth_set_ctrl (custom_bio_methods, bio_method_ctrl)
-+      || !BIO_meth_set_create (custom_bio_methods, bio_method_new)
-+      || !BIO_meth_set_destroy (custom_bio_methods, bio_method_free)) {
-+    BIO_meth_free (custom_bio_methods);
-+    return NULL;
-+  }
-+
-+  return custom_bio_methods;
-+}
-+#endif
- static int
- bio_method_write (BIO * bio, const char *data, int size)
- {
--  GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
-+  GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
-   GST_LOG_OBJECT (self, "BIO: writing %d", size);
-@@ -824,7 +893,7 @@ bio_method_write (BIO * bio, const char *data, int size)
- static int
- bio_method_read (BIO * bio, char *out_buffer, int size)
- {
--  GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
-+  GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
-   GstDtlsConnectionPrivate *priv = self->priv;
-   guint internal_size;
-   gint copy_size;
-@@ -868,7 +937,7 @@ bio_method_read (BIO * bio, char *out_buffer, int size)
- static long
- bio_method_ctrl (BIO * bio, int cmd, long arg1, void *arg2)
- {
--  GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
-+  GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
-   GstDtlsConnectionPrivate *priv = self->priv;
-   switch (cmd) {
-@@ -916,8 +985,8 @@ bio_method_new (BIO * bio)
- {
-   GST_LOG_OBJECT (NULL, "BIO: new");
--  bio->shutdown = 0;
--  bio->init = 1;
-+  BIO_set_shutdown (bio, 0);
-+  BIO_set_init (bio, 1);
-   return 1;
- }
-@@ -930,6 +999,6 @@ bio_method_free (BIO * bio)
-     return 0;
-   }
--  GST_LOG_OBJECT (GST_DTLS_CONNECTION (bio->ptr), "BIO free");
-+  GST_LOG_OBJECT (GST_DTLS_CONNECTION (BIO_get_data (bio)), "BIO free");
-   return 0;
- }
--- 
-2.10.2
-
diff --git a/Tools/wpe/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch b/Tools/wpe/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch
deleted file mode 100644 (file)
index c668773..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From 3a069193e25364ebdacac86f4b03022c151ea29c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
-Date: Mon, 14 Nov 2016 11:32:17 +0200
-Subject: [PATCH] dtlscertificate: Fix error checking in RSA_generate_key_ex()
- usage
-
-Was broken during the port for OpenSSL 1.1.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=774328
----
- ext/dtls/gstdtlscertificate.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/ext/dtls/gstdtlscertificate.c b/ext/dtls/gstdtlscertificate.c
-index c1c9602..c2d9bb2 100644
---- a/ext/dtls/gstdtlscertificate.c
-+++ b/ext/dtls/gstdtlscertificate.c
-@@ -207,12 +207,13 @@ init_generated (GstDtlsCertificate * self)
-   rsa = RSA_new ();
-   if (rsa != NULL) {
-     BIGNUM *e = BN_new ();
--    if (e != NULL && BN_set_word (e, RSA_F4)
--        && RSA_generate_key_ex (rsa, 2048, e, NULL)) {
-+    if (e == NULL || !BN_set_word (e, RSA_F4)
-+        || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
-       RSA_free (rsa);
-       rsa = NULL;
-     }
--    BN_free (e);
-+    if (e)
-+      BN_free (e);
-   }
- #endif
--- 
-2.10.2
-
diff --git a/Tools/wpe/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch b/Tools/wpe/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch
new file mode 100644 (file)
index 0000000..ff89c81
--- /dev/null
@@ -0,0 +1,1018 @@
+From dcd3ce9751cdef0b5ab1fa118355f92bdfe82cb3 Mon Sep 17 00:00:00 2001
+From: Philippe Normand <philn@igalia.com>
+Date: Wed, 16 Nov 2016 08:56:34 +0100
+Subject: [PATCH] rtpbin: receive bundle support
+
+A new signal named on-bundled-ssrc is provided and can be
+used by the application to redirect a stream to a different
+GstRtpSession or to keep the RTX stream grouped within the
+GstRtpSession of the same media type.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=772740
+---
+ docs/plugins/gst-plugins-good-plugins.signals |   8 +
+ gst/rtpmanager/gstrtpbin.c                    | 562 ++++++++++++++++++--------
+ gst/rtpmanager/gstrtpbin.h                    |   2 +
+ tests/check/Makefile.am                       |   4 +
+ tests/check/elements/.gitignore               |   1 +
+ tests/check/elements/rtpbundle.c              | 390 ++++++++++++++++++
+ tests/check/meson.build                       |   1 +
+ tests/examples/rtp/.gitignore                 |   2 +
+ tests/examples/rtp/Makefile.am                |  10 +-
+ tests/examples/rtp/client-rtpbundle.c         | 266 ++++++++++++
+ tests/examples/rtp/server-rtpbundle.c         | 179 ++++++++
+ 11 files changed, 1265 insertions(+), 160 deletions(-)
+ create mode 100644 tests/check/elements/rtpbundle.c
+ create mode 100644 tests/examples/rtp/client-rtpbundle.c
+ create mode 100644 tests/examples/rtp/server-rtpbundle.c
+
+diff --git a/docs/plugins/gst-plugins-good-plugins.signals b/docs/plugins/gst-plugins-good-plugins.signals
+index 3db17e9..44bbdda 100644
+--- a/docs/plugins/gst-plugins-good-plugins.signals
++++ b/docs/plugins/gst-plugins-good-plugins.signals
+@@ -375,6 +375,14 @@ guint  arg1
+ </SIGNAL>
+ <SIGNAL>
++<NAME>GstRtpBin::on-bundled-ssrc</NAME>
++<RETURNS>guint</RETURNS>
++<FLAGS>l</FLAGS>
++GstRtpBin *gstrtpbin
++guint  arg1
++</SIGNAL>
++
++<SIGNAL>
+ <NAME>GstRtpJitterBuffer::clear-pt-map</NAME>
+ <RETURNS>void</RETURNS>
+ <FLAGS>la</FLAGS>
+diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
+index 648adb9..f58de01 100644
+--- a/gst/rtpmanager/gstrtpbin.c
++++ b/gst/rtpmanager/gstrtpbin.c
+@@ -53,6 +53,13 @@
+  * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
+  * send_rtp_src_\%u pad after updating its internal state.
+  *
++ * #GstRtpBin can also demultiplex incoming bundled streams. The first
++ * #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
++ * based on their SSRC and potentially dispatched to a different #GstRtpSession.
++ * Because retransmission SSRCs need to be merged with the corresponding media
++ * stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
++ * application can find out to which session the SSRC belongs.
++ *
+  * The session manager needs the clock-rate of the payload types it is handling
+  * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
+  * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
+@@ -276,6 +283,8 @@ enum
+   SIGNAL_ON_NEW_SENDER_SSRC,
+   SIGNAL_ON_SENDER_SSRC_ACTIVE,
++  SIGNAL_ON_BUNDLED_SSRC,
++
+   LAST_SIGNAL
+ };
+@@ -362,6 +371,14 @@ static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
+ static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
++static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
++static GstPad *complete_session_sink (GstRtpBin * rtpbin,
++    GstRtpBinSession * session, gboolean bundle_demuxer_needed);
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid);
++static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
++    GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);
+ /* Manages the RTP stream for one SSRC.
+  *
+@@ -428,6 +445,12 @@ struct _GstRtpBinSession
+   gulong demux_newpad_sig;
+   gulong demux_padremoved_sig;
++  /* Bundling support */
++  GstElement *rtp_funnel;
++  GstElement *rtcp_funnel;
++  GstElement *bundle_demux;
++  gulong bundle_demux_newpad_sig;
++
+   GMutex lock;
+   /* list of GstRtpBinStream */
+@@ -629,6 +652,96 @@ ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+   GST_RTP_BIN_UNLOCK (rtpbin);
+ }
++static void
++new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
++    GstRtpBinSession * session)
++{
++  GValue result = G_VALUE_INIT;
++  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
++  guint session_id = 0;
++  GstRtpBinSession *target_session = NULL;
++  GstRtpBin *rtpbin = session->bin;
++  gchar *name;
++  GstPad *src_pad;
++  GstPad *recv_rtp_sink = NULL;
++  GstPad *recv_rtcp_sink = NULL;
++  GstPadLinkReturn ret;
++
++  GST_RTP_BIN_DYN_LOCK (rtpbin);
++  GST_DEBUG_OBJECT (rtpbin, "new bundled SSRC pad %08x, %s:%s", ssrc,
++      GST_DEBUG_PAD_NAME (pad));
++
++  g_value_init (&result, G_TYPE_UINT);
++  g_value_init (&params[0], GST_TYPE_ELEMENT);
++  g_value_set_object (&params[0], rtpbin);
++  g_value_init (&params[1], G_TYPE_UINT);
++  g_value_set_uint (&params[1], ssrc);
++
++  g_signal_emitv (params,
++      gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &result);
++  g_value_unset (&params[0]);
++
++  session_id = g_value_get_uint (&result);
++  if (session_id == 0) {
++    target_session = session;
++  } else {
++    target_session = find_session_by_id (rtpbin, (gint) session_id);
++    if (!target_session) {
++      target_session = create_session (rtpbin, session_id);
++    }
++    if (!target_session->recv_rtp_sink) {
++      recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
++    }
++
++    if (!target_session->recv_rtp_src)
++      complete_session_receiver (rtpbin, target_session, session_id);
++
++    if (!target_session->recv_rtcp_sink) {
++      recv_rtcp_sink =
++          complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
++    }
++  }
++
++  GST_DEBUG_OBJECT (rtpbin, "Assigning bundled ssrc %u to session %u", ssrc,
++      session_id);
++
++  if (!recv_rtp_sink) {
++    recv_rtp_sink =
++        gst_element_get_request_pad (target_session->rtp_funnel, "sink_%u");
++  }
++
++  if (!recv_rtcp_sink) {
++    recv_rtcp_sink =
++        gst_element_get_request_pad (target_session->rtcp_funnel, "sink_%u");
++  }
++
++  name = g_strdup_printf ("src_%u", ssrc);
++  src_pad = gst_element_get_static_pad (element, name);
++  ret = gst_pad_link (src_pad, recv_rtp_sink);
++  g_free (name);
++  gst_object_unref (src_pad);
++  gst_object_unref (recv_rtp_sink);
++  if (ret != GST_PAD_LINK_OK) {
++    g_warning
++        ("rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u",
++        session_id);
++  }
++
++  name = g_strdup_printf ("rtcp_src_%u", ssrc);
++  src_pad = gst_element_get_static_pad (element, name);
++  gst_pad_link (src_pad, recv_rtcp_sink);
++  g_free (name);
++  gst_object_unref (src_pad);
++  gst_object_unref (recv_rtcp_sink);
++  if (ret != GST_PAD_LINK_OK) {
++    g_warning
++        ("rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u",
++        session_id);
++  }
++
++  GST_RTP_BIN_DYN_UNLOCK (rtpbin);
++}
++
+ /* create a session with the given id.  Must be called with RTP_BIN_LOCK */
+ static GstRtpBinSession *
+ create_session (GstRtpBin * rtpbin, gint id)
+@@ -649,6 +762,10 @@ create_session (GstRtpBin * rtpbin, gint id)
+   sess->bin = rtpbin;
+   sess->session = session;
+   sess->demux = demux;
++
++  sess->rtp_funnel = gst_element_factory_make ("funnel", NULL);
++  sess->rtcp_funnel = gst_element_factory_make ("funnel", NULL);
++
+   sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
+       (GDestroyNotify) gst_caps_unref);
+   rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
+@@ -696,6 +813,8 @@ create_session (GstRtpBin * rtpbin, gint id)
+   gst_bin_add (GST_BIN_CAST (rtpbin), session);
+   gst_bin_add (GST_BIN_CAST (rtpbin), demux);
++  gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtp_funnel);
++  gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtcp_funnel);
+   GST_OBJECT_LOCK (rtpbin);
+   target = GST_STATE_TARGET (rtpbin);
+@@ -704,6 +823,8 @@ create_session (GstRtpBin * rtpbin, gint id)
+   /* change state only to what's needed */
+   gst_element_set_state (demux, target);
+   gst_element_set_state (session, target);
++  gst_element_set_state (sess->rtp_funnel, target);
++  gst_element_set_state (sess->rtcp_funnel, target);
+   return sess;
+@@ -807,7 +928,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+   GValue ret = { 0 };
+   GValue args[3] = { {0}, {0}, {0} };
+-  GST_DEBUG ("searching pt %d in cache", pt);
++  GST_DEBUG ("searching pt %u in cache", pt);
+   GST_RTP_SESSION_LOCK (session);
+@@ -820,7 +941,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+   bin = session->bin;
+-  GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
++  GST_DEBUG ("emiting signal for pt %u in session %u", pt, session->id);
+   /* not in cache, send signal to request caps */
+   g_value_init (&args[0], GST_TYPE_ELEMENT);
+@@ -856,7 +977,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+   if (!caps)
+     goto no_caps;
+-  GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
++  GST_DEBUG ("caching pt %u as %" GST_PTR_FORMAT, pt, caps);
+   /* store in cache, take additional ref */
+   g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
+@@ -947,7 +1068,7 @@ gst_rtp_bin_get_session (GstRtpBin * bin, guint session_id)
+   GstElement *ret = NULL;
+   GST_RTP_BIN_LOCK (bin);
+-  GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %d", session_id);
++  GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %u", session_id);
+   session = find_session_by_id (bin, (gint) session_id);
+   if (session) {
+     ret = gst_object_ref (session->session);
+@@ -964,7 +1085,7 @@ gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
+   GstRtpBinSession *session;
+   GST_RTP_BIN_LOCK (bin);
+-  GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %d",
++  GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %u",
+       session_id);
+   session = find_session_by_id (bin, (gint) session_id);
+   if (session) {
+@@ -2194,6 +2315,29 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
+           on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
+       G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
++
++  /**
++   * GstRtpBin::on-bundled-ssrc:
++   * @rtpbin: the object which received the signal
++   * @ssrc: the bundled SSRC
++   *
++   * Notify of a new incoming bundled SSRC. If no handler is connected to the
++   * signal then the #GstRtpSession created for the recv_rtp_sink_\%u
++   * request pad will be managing this new SSRC. However if there is a handler
++   * connected then the application can decided to dispatch this new stream to
++   * another session by providing its ID as return value of the handler. This
++   * can be particularly useful to keep retransmission SSRCs grouped with the
++   * session for which they handle retransmission.
++   *
++   * Since: 1.12
++   */
++  gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
++      g_signal_new ("on-bundled-ssrc", G_TYPE_FROM_CLASS (klass),
++      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
++          on_bundled_ssrc), NULL, NULL,
++      g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
++
++
+   g_object_class_install_property (gobject_class, PROP_SDES,
+       g_param_spec_boxed ("sdes", "SDES",
+           "The SDES items of this session",
+@@ -3021,7 +3165,7 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,
+   rtpbin = stream->bin;
+-  GST_DEBUG ("new payload pad %d", pt);
++  GST_DEBUG_OBJECT (rtpbin, "new payload pad %u", pt);
+   GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
+@@ -3078,7 +3222,7 @@ pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
+   rtpbin = session->bin;
+-  GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
++  GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %u in session %u", pt,
+       session->id);
+   caps = get_pt_map (session, pt);
+@@ -3099,7 +3243,7 @@ static void
+ payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
+ {
+   GST_DEBUG_OBJECT (session->bin,
+-      "emiting signal for pt type changed to %d in session %d", pt,
++      "emiting signal for pt type changed to %u in session %u", pt,
+       session->id);
+   g_signal_emit (session->bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
+@@ -3246,15 +3390,42 @@ no_stream:
+   }
+ }
+-static gboolean
+-complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
++static void
++session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
++{
++  GstRtpBin *rtpbin;
++
++  if (session->bundle_demux)
++    return;
++
++  rtpbin = session->bin;
++  if (g_signal_has_handler_pending (rtpbin,
++          gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
++    GST_DEBUG_OBJECT (rtpbin, "Adding a bundle SSRC demuxer to session %u",
++        session->id);
++    session->bundle_demux = gst_element_factory_make ("rtpssrcdemux", NULL);
++    session->bundle_demux_newpad_sig = g_signal_connect (session->bundle_demux,
++        "new-ssrc-pad", (GCallback) new_bundled_ssrc_pad_found, session);
++
++    gst_bin_add (GST_BIN_CAST (rtpbin), session->bundle_demux);
++    gst_element_sync_state_with_parent (session->bundle_demux);
++  } else {
++    GST_DEBUG_OBJECT (rtpbin,
++        "No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u",
++        session->id);
++  }
++}
++
++static GstPad *
++complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    gboolean bundle_demuxer_needed)
+ {
+-  gchar *gname;
+   guint sessid = session->id;
+   GstPad *recv_rtp_sink;
++  GstPad *funnel_src;
+   GstElement *decoder;
+-  GstElementClass *klass;
+-  GstPadTemplate *templ;
++
++  g_assert (!session->recv_rtp_sink);
+   /* get recv_rtp pad and store */
+   session->recv_rtp_sink =
+@@ -3265,6 +3436,9 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   g_signal_connect (session->recv_rtp_sink, "notify::caps",
+       (GCallback) caps_changed, session);
++  if (bundle_demuxer_needed)
++    session_maybe_create_bundle_demuxer (session);
++
+   GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
+   decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
+   if (decoder) {
+@@ -3282,7 +3456,14 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     if (decsrc == NULL)
+       goto dec_src_failed;
+-    ret = gst_pad_link (decsrc, session->recv_rtp_sink);
++    if (session->bundle_demux) {
++      GstPad *demux_sink;
++      demux_sink = gst_element_get_static_pad (session->bundle_demux, "sink");
++      ret = gst_pad_link (decsrc, demux_sink);
++      gst_object_unref (demux_sink);
++    } else {
++      ret = gst_pad_link (decsrc, session->recv_rtp_sink);
++    }
+     gst_object_unref (decsrc);
+     if (ret != GST_PAD_LINK_OK)
+@@ -3290,81 +3471,54 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   } else {
+     GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
+-    recv_rtp_sink = gst_object_ref (session->recv_rtp_sink);
++    if (session->bundle_demux) {
++      recv_rtp_sink =
++          gst_element_get_static_pad (session->bundle_demux, "sink");
++    } else {
++      recv_rtp_sink =
++          gst_element_get_request_pad (session->rtp_funnel, "sink_%u");
++    }
+   }
+-  GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
+-  klass = GST_ELEMENT_GET_CLASS (rtpbin);
+-  gname = g_strdup_printf ("recv_rtp_sink_%u", sessid);
+-  templ = gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u");
+-  session->recv_rtp_sink_ghost =
+-      gst_ghost_pad_new_from_template (gname, recv_rtp_sink, templ);
+-  gst_object_unref (recv_rtp_sink);
+-  gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
+-  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
+-  g_free (gname);
++  funnel_src = gst_element_get_static_pad (session->rtp_funnel, "src");
++  gst_pad_link (funnel_src, session->recv_rtp_sink);
++  gst_object_unref (funnel_src);
+-  return TRUE;
++  return recv_rtp_sink;
+   /* ERRORS */
+ pad_failed:
+   {
+     g_warning ("rtpbin: failed to get session recv_rtp_sink pad");
+-    return FALSE;
++    return NULL;
+   }
+ dec_sink_failed:
+   {
+-    g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
+-    return FALSE;
++    g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
++    return NULL;
+   }
+ dec_src_failed:
+   {
+-    g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
+     gst_object_unref (recv_rtp_sink);
+-    return FALSE;
++    return NULL;
+   }
+ dec_link_failed:
+   {
+-    g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
++    g_warning ("rtpbin: failed to link rtp decoder for session %u", sessid);
+     gst_object_unref (recv_rtp_sink);
+-    return FALSE;
++    return NULL;
+   }
+ }
+-/* Create a pad for receiving RTP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+-static GstPad *
+-create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid)
+ {
+-  guint sessid;
+   GstElement *aux;
+   GstPad *recv_rtp_src;
+-  GstRtpBinSession *session;
+-
+-  /* first get the session number */
+-  if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
+-    goto no_name;
+-
+-  GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
+-  /* get or create session */
+-  session = find_session_by_id (rtpbin, sessid);
+-  if (!session) {
+-    GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
+-    /* create session now */
+-    session = create_session (rtpbin, sessid);
+-    if (session == NULL)
+-      goto create_error;
+-  }
+-
+-  /* check if pad was requested */
+-  if (session->recv_rtp_sink_ghost != NULL)
+-    return session->recv_rtp_sink_ghost;
+-
+-  /* setup the session sink pad */
+-  if (!complete_session_sink (rtpbin, session))
+-    goto session_sink_failed;
++  g_assert (!session->recv_rtp_src);
+   session->recv_rtp_src =
+       gst_element_get_static_pad (session->session, "recv_rtp_src");
+@@ -3381,7 +3535,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     GST_DEBUG_OBJECT (rtpbin, "linking AUX receiver");
+-    pname = g_strdup_printf ("sink_%d", sessid);
++    pname = g_strdup_printf ("sink_%u", sessid);
+     auxsink = gst_element_get_static_pad (aux, pname);
+     g_free (pname);
+     if (auxsink == NULL)
+@@ -3394,7 +3548,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     /* this can be NULL when this AUX element is not to be linked to
+      * an SSRC demuxer */
+-    pname = g_strdup_printf ("src_%d", sessid);
++    pname = g_strdup_printf ("src_%u", sessid);
+     recv_rtp_src = gst_element_get_static_pad (aux, pname);
+     g_free (pname);
+   } else {
+@@ -3408,8 +3562,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     sinkdpad = gst_element_get_static_pad (session->demux, "sink");
+     GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
+     gst_pad_link_full (recv_rtp_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+-    gst_object_unref (recv_rtp_src);
+     gst_object_unref (sinkdpad);
++    gst_object_unref (recv_rtp_src);
+     /* connect to the new-ssrc-pad signal of the SSRC demuxer */
+     session->demux_newpad_sig = g_signal_connect (session->demux,
+@@ -3417,6 +3571,71 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     session->demux_padremoved_sig = g_signal_connect (session->demux,
+         "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
+   }
++
++  return;
++
++pad_failed:
++  {
++    g_warning ("rtpbin: failed to get session recv_rtp_src pad");
++    return;
++  }
++aux_sink_failed:
++  {
++    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
++    return;
++  }
++aux_link_failed:
++  {
++    g_warning ("rtpbin: failed to link AUX pad to session %u", sessid);
++    return;
++  }
++}
++
++/* Create a pad for receiving RTP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++{
++  guint sessid;
++  GstRtpBinSession *session;
++  GstPad *recv_rtp_sink;
++
++  /* first get the session number */
++  if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
++    goto no_name;
++
++  GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
++
++  /* get or create session */
++  session = find_session_by_id (rtpbin, sessid);
++  if (!session) {
++    GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
++    /* create session now */
++    session = create_session (rtpbin, sessid);
++    if (session == NULL)
++      goto create_error;
++  }
++
++  /* check if pad was requested */
++  if (session->recv_rtp_sink_ghost != NULL)
++    return session->recv_rtp_sink_ghost;
++
++  /* setup the session sink pad */
++  recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
++  if (!recv_rtp_sink)
++    goto session_sink_failed;
++
++
++  GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
++  session->recv_rtp_sink_ghost =
++      gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
++  gst_object_unref (recv_rtp_sink);
++  gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
++  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
++
++  complete_session_receiver (rtpbin, session, sessid);
++
+   return session->recv_rtp_sink_ghost;
+   /* ERRORS */
+@@ -3435,21 +3654,6 @@ session_sink_failed:
+     /* warning already done */
+     return NULL;
+   }
+-pad_failed:
+-  {
+-    g_warning ("rtpbin: failed to get session recv_rtp_src pad");
+-    return NULL;
+-  }
+-aux_sink_failed:
+-  {
+-    g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
+-    return NULL;
+-  }
+-aux_link_failed:
+-  {
+-    g_warning ("rtpbin: failed to link AUX pad to session %d", sessid);
+-    return NULL;
+-  }
+ }
+ static void
+@@ -3463,6 +3667,11 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
+     session->demux_padremoved_sig = 0;
+   }
++  if (session->bundle_demux_newpad_sig) {
++    g_signal_handler_disconnect (session->bundle_demux,
++        session->bundle_demux_newpad_sig);
++    session->bundle_demux_newpad_sig = 0;
++  }
+   if (session->recv_rtp_src) {
+     gst_object_unref (session->recv_rtp_src);
+     session->recv_rtp_src = NULL;
+@@ -3480,37 +3689,14 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   }
+ }
+-/* Create a pad for receiving RTCP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+ static GstPad *
+-create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+-    const gchar * name)
++complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
++    guint sessid, gboolean bundle_demuxer_needed)
+ {
+-  guint sessid;
+   GstElement *decoder;
+-  GstRtpBinSession *session;
+-  GstPad *sinkdpad, *decsink;
+-
+-  /* first get the session number */
+-  if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
+-    goto no_name;
+-
+-  GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
+-
+-  /* get or create the session */
+-  session = find_session_by_id (rtpbin, sessid);
+-  if (!session) {
+-    GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
+-    /* create session now */
+-    session = create_session (rtpbin, sessid);
+-    if (session == NULL)
+-      goto create_error;
+-  }
+-
+-  /* check if pad was requested */
+-  if (session->recv_rtcp_sink_ghost != NULL)
+-    return session->recv_rtcp_sink_ghost;
++  GstPad *sinkdpad;
++  GstPad *decsink = NULL;
++  GstPad *funnel_src;
+   /* get recv_rtp pad and store */
+   GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
+@@ -3519,6 +3705,9 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+   if (session->recv_rtcp_sink == NULL)
+     goto pad_failed;
++  if (bundle_demuxer_needed)
++    session_maybe_create_bundle_demuxer (session);
++
+   GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
+   decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
+   if (decoder) {
+@@ -3535,14 +3724,26 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+     if (decsrc == NULL)
+       goto dec_src_failed;
+-    ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
++    if (session->bundle_demux) {
++      GstPad *demux_sink;
++      demux_sink =
++          gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
++      ret = gst_pad_link (decsrc, demux_sink);
++      gst_object_unref (demux_sink);
++    } else {
++      ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
++    }
+     gst_object_unref (decsrc);
+     if (ret != GST_PAD_LINK_OK)
+       goto dec_link_failed;
+   } else {
+     GST_DEBUG_OBJECT (rtpbin, "no RTCP decoder given");
+-    decsink = gst_object_ref (session->recv_rtcp_sink);
++    if (session->bundle_demux) {
++      decsink = gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
++    } else {
++      decsink = gst_element_get_request_pad (session->rtcp_funnel, "sink_%u");
++    }
+   }
+   /* get srcpad, link to SSRCDemux */
+@@ -3556,26 +3757,12 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+   gst_pad_link_full (session->sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+   gst_object_unref (sinkdpad);
+-  session->recv_rtcp_sink_ghost =
+-      gst_ghost_pad_new_from_template (name, decsink, templ);
+-  gst_object_unref (decsink);
+-  gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
+-  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+-      session->recv_rtcp_sink_ghost);
++  funnel_src = gst_element_get_static_pad (session->rtcp_funnel, "src");
++  gst_pad_link (funnel_src, session->recv_rtcp_sink);
++  gst_object_unref (funnel_src);
+-  return session->recv_rtcp_sink_ghost;
++  return decsink;
+-  /* ERRORS */
+-no_name:
+-  {
+-    g_warning ("rtpbin: invalid name given");
+-    return NULL;
+-  }
+-create_error:
+-  {
+-    /* create_session already warned */
+-    return NULL;
+-  }
+ pad_failed:
+   {
+     g_warning ("rtpbin: failed to get session rtcp_sink pad");
+@@ -3583,25 +3770,82 @@ pad_failed:
+   }
+ dec_sink_failed:
+   {
+-    g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
+     return NULL;
+   }
+ dec_src_failed:
+   {
+-    g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
+-    gst_object_unref (decsink);
+-    return NULL;
++    g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
++    goto cleanup;
+   }
+ dec_link_failed:
+   {
+-    g_warning ("rtpbin: failed to link rtcp decoder for session %d", sessid);
+-    gst_object_unref (decsink);
+-    return NULL;
++    g_warning ("rtpbin: failed to link rtcp decoder for session %u", sessid);
++    goto cleanup;
+   }
+ src_pad_failed:
+   {
+     g_warning ("rtpbin: failed to get session sync_src pad");
+-    gst_object_unref (decsink);
++  }
++
++cleanup:
++  gst_object_unref (decsink);
++  return NULL;
++}
++
++/* Create a pad for receiving RTCP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
++    const gchar * name)
++{
++  guint sessid;
++  GstRtpBinSession *session;
++  GstPad *decsink = NULL;
++
++  /* first get the session number */
++  if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
++    goto no_name;
++
++  GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
++
++  /* get or create the session */
++  session = find_session_by_id (rtpbin, sessid);
++  if (!session) {
++    GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
++    /* create session now */
++    session = create_session (rtpbin, sessid);
++    if (session == NULL)
++      goto create_error;
++  }
++
++  /* check if pad was requested */
++  if (session->recv_rtcp_sink_ghost != NULL)
++    return session->recv_rtcp_sink_ghost;
++
++  decsink = complete_session_rtcp (rtpbin, session, sessid, TRUE);
++  if (!decsink)
++    goto create_error;
++
++  session->recv_rtcp_sink_ghost =
++      gst_ghost_pad_new_from_template (name, decsink, templ);
++  gst_object_unref (decsink);
++  gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
++  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
++      session->recv_rtcp_sink_ghost);
++
++  return session->recv_rtcp_sink_ghost;
++
++  /* ERRORS */
++no_name:
++  {
++    g_warning ("rtpbin: invalid name given");
++    return NULL;
++  }
++create_error:
++  {
++    /* create_session already warned */
+     return NULL;
+   }
+ }
+@@ -3651,7 +3895,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     GstPadLinkReturn ret;
+     GST_DEBUG_OBJECT (rtpbin, "linking RTP encoder");
+-    ename = g_strdup_printf ("rtp_src_%d", sessid);
++    ename = g_strdup_printf ("rtp_src_%u", sessid);
+     encsrc = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+@@ -3660,7 +3904,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+     send_rtp_src = encsrc;
+-    ename = g_strdup_printf ("rtp_sink_%d", sessid);
++    ename = g_strdup_printf ("rtp_sink_%u", sessid);
+     encsink = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsink == NULL)
+@@ -3694,23 +3938,23 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+   /* ERRORS */
+ no_srcpad:
+   {
+-    g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get rtp source pad for session %u", sessid);
+     return FALSE;
+   }
+ enc_src_failed:
+   {
+-    g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+     return FALSE;
+   }
+ enc_sink_failed:
+   {
+-    g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+     gst_object_unref (send_rtp_src);
+     return FALSE;
+   }
+ enc_link_failed:
+   {
+-    g_warning ("rtpbin: failed to link rtp encoder for session %d", sessid);
++    g_warning ("rtpbin: failed to link rtp encoder for session %u", sessid);
+     gst_object_unref (send_rtp_src);
+     return FALSE;
+   }
+@@ -3772,22 +4016,22 @@ create_error:
+   }
+ existing_session:
+   {
+-    g_warning ("rtpbin: session %d is already a sender", sessid);
++    g_warning ("rtpbin: session %u is already a sender", sessid);
+     return FALSE;
+   }
+ pad_failed:
+   {
+-    g_warning ("rtpbin: failed to get session pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+     return FALSE;
+   }
+ aux_link_failed:
+   {
+-    g_warning ("rtpbin: failed to link AUX for session %d", sessid);
++    g_warning ("rtpbin: failed to link AUX for session %u", sessid);
+     return FALSE;
+   }
+ session_src_failed:
+   {
+-    g_warning ("rtpbin: failed to complete AUX for session %d", sessid);
++    g_warning ("rtpbin: failed to complete AUX for session %u", sessid);
+     return FALSE;
+   }
+ }
+@@ -3847,7 +4091,7 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     if (!setup_aux_sender (rtpbin, session, aux))
+       goto aux_session_failed;
+-    pname = g_strdup_printf ("sink_%d", sessid);
++    pname = g_strdup_printf ("sink_%u", sessid);
+     send_rtp_sink = gst_element_get_static_pad (aux, pname);
+     g_free (pname);
+@@ -3887,27 +4131,27 @@ create_error:
+   }
+ existing_session:
+   {
+-    g_warning ("rtpbin: session %d is already in use", sessid);
++    g_warning ("rtpbin: session %u is already in use", sessid);
+     return NULL;
+   }
+ aux_session_failed:
+   {
+-    g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+     return NULL;
+   }
+ aux_sink_failed:
+   {
+-    g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+     return NULL;
+   }
+ pad_failed:
+   {
+-    g_warning ("rtpbin: failed to get session pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+     return NULL;
+   }
+ session_src_failed:
+   {
+-    g_warning ("rtpbin: failed to setup source pads for session %d", sessid);
++    g_warning ("rtpbin: failed to setup source pads for session %u", sessid);
+     return NULL;
+   }
+ }
+@@ -3978,13 +4222,13 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+     GST_DEBUG_OBJECT (rtpbin, "linking RTCP encoder");
+-    ename = g_strdup_printf ("rtcp_src_%d", sessid);
++    ename = g_strdup_printf ("rtcp_src_%u", sessid);
+     encsrc = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsrc == NULL)
+       goto enc_src_failed;
+-    ename = g_strdup_printf ("rtcp_sink_%d", sessid);
++    ename = g_strdup_printf ("rtcp_sink_%u", sessid);
+     encsink = gst_element_get_static_pad (encoder, ename);
+     g_free (ename);
+     if (encsink == NULL)
+@@ -4021,23 +4265,23 @@ no_session:
+   }
+ pad_failed:
+   {
+-    g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get rtcp pad for session %u", sessid);
+     return NULL;
+   }
+ enc_src_failed:
+   {
+-    g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+     return NULL;
+   }
+ enc_sink_failed:
+   {
+-    g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
++    g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+     gst_object_unref (encsrc);
+     return NULL;
+   }
+ enc_link_failed:
+   {
+-    g_warning ("rtpbin: failed to link rtcp encoder for session %d", sessid);
++    g_warning ("rtpbin: failed to link rtcp encoder for session %u", sessid);
+     gst_object_unref (encsrc);
+     return NULL;
+   }
+diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h
+index fb13a47..384b76d 100644
+--- a/gst/rtpmanager/gstrtpbin.h
++++ b/gst/rtpmanager/gstrtpbin.h
+@@ -127,6 +127,8 @@ struct _GstRtpBinClass {
+   void     (*on_new_sender_ssrc)      (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+   void     (*on_sender_ssrc_active)   (GstRtpBin *rtpbin, guint session, guint32 ssrc);
++
++  guint    (*on_bundled_ssrc)         (GstRtpBin *rtpbin, guint ssrc);
+ };
+ GType gst_rtp_bin_get_type (void);
diff --git a/Tools/wpe/patches/gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch b/Tools/wpe/patches/gst-plugins-good-0005-souphttpsrc-cookie-jar-and-context-query-support.patch
new file mode 100644 (file)
index 0000000..84edbd6
--- /dev/null
@@ -0,0 +1,120 @@
+From 8e03a63fd55f5ae447994579890e8630b27f4a1b Mon Sep 17 00:00:00 2001
+From: Philippe Normand <philn@igalia.com>
+Date: Wed, 28 Oct 2015 12:00:09 +0100
+Subject: [PATCH 2/3] souphttpsrc: cookie jar and context query support
+
+Use a volatile Cookie jar to store cookies and handle the context
+query so that session data can be shared with other elements (like
+adaptivedemux).
+
+https://bugzilla.gnome.org/show_bug.cgi?id=726314
+---
+ ext/soup/gstsouphttpsrc.c | 41 +++++++++++++++++++++++++++++++++++++++--
+ ext/soup/gstsouphttpsrc.h |  1 +
+ 2 files changed, 40 insertions(+), 2 deletions(-)
+
+diff --git a/ext/soup/gstsouphttpsrc.c b/ext/soup/gstsouphttpsrc.c
+index fc7cba7..0d3e886 100644
+--- a/ext/soup/gstsouphttpsrc.c
++++ b/ext/soup/gstsouphttpsrc.c
+@@ -482,6 +482,7 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
+   src->cookies = NULL;
+   src->iradio_mode = DEFAULT_IRADIO_MODE;
+   src->session = NULL;
++  src->cookie_jar = NULL;
+   src->msg = NULL;
+   src->timeout = DEFAULT_TIMEOUT;
+   src->log_level = DEFAULT_SOUP_LOG_LEVEL;
+@@ -943,6 +944,9 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
+     soup_session_remove_feature_by_type (src->session,
+         SOUP_TYPE_CONTENT_DECODER);
++  src->cookie_jar = soup_cookie_jar_new ();
++  soup_session_add_feature (src->session,
++      SOUP_SESSION_FEATURE (src->cookie_jar));
+   return TRUE;
+ }
+@@ -958,6 +962,11 @@ gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
+     src->msg = NULL;
+   }
++  if (src->cookie_jar) {
++    g_object_unref (src->cookie_jar);
++    src->cookie_jar = NULL;
++  }
++
+   if (src->session) {
+     soup_session_abort (src->session);
+     g_object_unref (src->session);
+@@ -1426,11 +1435,12 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
+   }
+   if (src->cookies) {
+     gchar **cookie;
++    SoupURI *uri = soup_uri_new (src->location);
+     for (cookie = src->cookies; *cookie != NULL; cookie++) {
+-      soup_message_headers_append (src->msg->request_headers, "Cookie",
+-          *cookie);
++      soup_cookie_jar_set_cookie (src->cookie_jar, uri, *cookie);
+     }
++    soup_uri_free (uri);
+   }
+   soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
+@@ -1910,6 +1920,12 @@ gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
+   gboolean ret;
+   GstSchedulingFlags flags;
+   gint minsize, maxsize, align;
++  GstContext *context;
++  GstStructure *context_structure;
++  char *cookie;
++  const gchar *cookies[2];
++  const gchar *context_type;
++  SoupURI *uri;
+   switch (GST_QUERY_TYPE (query)) {
+     case GST_QUERY_URI:
+@@ -1921,6 +1937,27 @@ gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
+       }
+       ret = TRUE;
+       break;
++    case GST_QUERY_CONTEXT:
++      if (gst_query_parse_context_type (query, &context_type)
++          && !g_strcmp0 (context_type, "http-headers")) {
++        uri = soup_uri_new (src->location);
++        cookie = soup_cookie_jar_get_cookies (src->cookie_jar, uri, TRUE);
++        context = gst_context_new ("http-headers", FALSE);
++        gst_context_make_writable (context);
++        context_structure = gst_context_writable_structure (context);
++        if (cookie != NULL) {
++          cookies[0] = cookie;
++          cookies[1] = NULL;
++          gst_structure_set (context_structure, "cookies", G_TYPE_STRV, cookies,
++              NULL);
++          g_free (cookie);
++        }
++        gst_query_set_context (query, context);
++        soup_uri_free (uri);
++        ret = TRUE;
++        break;
++      }
++
+     default:
+       ret = FALSE;
+       break;
+diff --git a/ext/soup/gstsouphttpsrc.h b/ext/soup/gstsouphttpsrc.h
+index dd01656..9c6bb5c 100644
+--- a/ext/soup/gstsouphttpsrc.h
++++ b/ext/soup/gstsouphttpsrc.h
+@@ -60,6 +60,7 @@ struct _GstSoupHTTPSrc {
+   gchar *proxy_pw;             /* Authentication user password for proxy URI. */
+   gchar **cookies;             /* HTTP request cookies. */
+   SoupSession *session;        /* Async context. */
++  SoupCookieJar *cookie_jar;   /* Volatile HTTP cookie storage */
+   SoupMessage *msg;            /* Request message. */
+   GstFlowReturn ret;           /* Return code from callback. */
+   gint retry_count;            /* Number of retries since we received data */
+-- 
+1.8.3.2
+
diff --git a/Tools/wpe/patches/gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch b/Tools/wpe/patches/gst-plugins-good-0006-qtdemux-add-context-for-a-preferred-protection.patch
new file mode 100644 (file)
index 0000000..0ddfece
--- /dev/null
@@ -0,0 +1,329 @@
+From 9d7201ca76e7875cddd106df06b4d7637c025465 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Wed, 21 Jun 2017 17:59:21 +0200
+Subject: [PATCH 2/3] qtdemux: add context for a preferred protection
+
+qtdemux selected the first system corresponding to a working GStreamer
+decryptor. With this change, before selecting that decryptor, qtdemux
+will check if it has context (a preferred decryptor id) and if not, it
+will request it.
+
+The request includes track-id, available key system ids for the
+available decryptors and even the events so that the init data is
+accessible.
+
+[eocanha@igalia.com: select the preferred protection system even if not available]
+
+Test "4. ClearKeyVideo" in YouTube leanback EME conformance tests 2016 for
+H.264[1] uses a media file[2] with cenc encryption which embeds 'pssh' boxes
+with the init data for the Playready and Widevine encryption systems, but not
+for the ClearKey encryption system (as defined by the EMEv0.1b spec[3] and with
+the encryption system id defined in [4]).
+
+Instead, the ClearKey encryption system is manually selected by the web page
+code (even if not originally detected by qtdemux) and the proper decryption key
+is dispatched to the decryptor, which can then decrypt the video successfully.
+
+[1] http://yt-dash-mse-test.commondatastorage.googleapis.com/unit-tests/2016.html?test_type=encryptedmedia-test&webm=false
+[2] http://yt-dash-mse-test.commondatastorage.googleapis.com/unit-tests/media/car_cenc-20120827-86.mp4
+[3] https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#simple-decryption-clear-key
+[4] https://www.w3.org/Bugs/Public/show_bug.cgi?id=24027#c2
+
+https://bugzilla.gnome.org/show_bug.cgi?id=770107
+---
+ gst/isomp4/qtdemux.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ gst/isomp4/qtdemux.h |   1 +
+ 2 files changed, 195 insertions(+), 6 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 0a41b26f2..ae57bdf9b 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -513,6 +513,8 @@ static GstIndex *gst_qtdemux_get_index (GstElement * element);
+ #endif
+ static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
+     GstStateChange transition);
++static void gst_qtdemux_set_context (GstElement * element,
++    GstContext * context);
+ static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
+ static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
+     GstObject * parent, GstPadMode mode, gboolean active);
+@@ -602,6 +604,7 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
+   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
+   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
+ #endif
++  gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
+   gst_tag_register_musicbrainz_tags ();
+@@ -660,6 +663,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+   qtdemux->cenc_aux_info_sizes = NULL;
+   qtdemux->cenc_aux_sample_count = 0;
+   qtdemux->protection_system_ids = NULL;
++  qtdemux->preferred_protection_system_id = NULL;
+   g_queue_init (&qtdemux->protection_event_queue);
+   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+   qtdemux->tag_list = gst_tag_list_new_empty ();
+@@ -2113,6 +2117,10 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
+       qtdemux->protection_system_ids = NULL;
+     }
++    if (qtdemux->preferred_protection_system_id) {
++      g_free (qtdemux->preferred_protection_system_id);
++      qtdemux->preferred_protection_system_id = NULL;
++    }
+   } else if (qtdemux->mss_mode) {
+     gst_flow_combiner_reset (qtdemux->flowcombiner);
+     for (n = 0; n < qtdemux->n_streams; n++)
+@@ -2590,6 +2598,28 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
+ }
+ static void
++gst_qtdemux_set_context (GstElement * element, GstContext * context)
++{
++  GstQTDemux *qtdemux = GST_QTDEMUX (element);
++
++  g_return_if_fail (GST_IS_CONTEXT (context));
++
++  if (gst_context_has_context_type (context,
++          "drm-preferred-decryption-system-id")) {
++    const GstStructure *s;
++
++    s = gst_context_get_structure (context);
++    g_free (qtdemux->preferred_protection_system_id);
++    qtdemux->preferred_protection_system_id =
++        g_strdup (gst_structure_get_string (s, "decryption-system-id"));
++    GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
++        qtdemux->preferred_protection_system_id);
++  }
++
++  GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
++}
++
++static void
+ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+ {
+   /* counts as header data */
+@@ -3819,6 +3849,8 @@ qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
+   event = gst_event_new_protection (sysid_string, pssh,
+       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
+   for (i = 0; i < qtdemux->n_streams; ++i) {
++    GST_TRACE_OBJECT (qtdemux,
++        "adding protection event for stream %d and system %s", i, sysid_string);
+     g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
+         gst_event_ref (event));
+   }
+@@ -5529,6 +5561,8 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
+     GstEvent *event;
+     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
++      GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
++          GST_PTR_FORMAT, event);
+       gst_pad_push_event (stream->pad, event);
+     }
+@@ -7688,11 +7722,141 @@ qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
+ }
+ static gboolean
++pad_query (const GValue * item, GValue * value, gpointer user_data)
++{
++  GstPad *pad = g_value_get_object (item);
++  GstQuery *query = user_data;
++  gboolean res;
++
++  res = gst_pad_peer_query (pad, query);
++
++  if (res) {
++    g_value_set_boolean (value, TRUE);
++    return FALSE;
++  }
++
++  GST_INFO_OBJECT (pad, "pad peer query failed");
++  return TRUE;
++}
++
++static gboolean
++gst_qtdemux_run_query (GstElement * element, GstQuery * query,
++    GstPadDirection direction)
++{
++  GstIterator *it;
++  GstIteratorFoldFunction func = pad_query;
++  GValue res = { 0, };
++
++  g_value_init (&res, G_TYPE_BOOLEAN);
++  g_value_set_boolean (&res, FALSE);
++
++  /* Ask neighbor */
++  if (direction == GST_PAD_SRC)
++    it = gst_element_iterate_src_pads (element);
++  else
++    it = gst_element_iterate_sink_pads (element);
++
++  while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
++    gst_iterator_resync (it);
++
++  gst_iterator_free (it);
++
++  return g_value_get_boolean (&res);
++}
++
++static void
++gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
++    QtDemuxStream * stream)
++{
++  GstQuery *query;
++  GstContext *ctxt;
++  GstElement *element = GST_ELEMENT (qtdemux);
++  GstStructure *st;
++  gchar **filtered_sys_ids;
++  GValue event_list = G_VALUE_INIT;
++  GList *walk;
++
++  /* 1. Check if we already have the context. */
++  if (qtdemux->preferred_protection_system_id != NULL) {
++    GST_LOG_OBJECT (element,
++        "already have the protection context, no need to request it again");
++    return;
++  }
++
++  g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++  filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
++      (const gchar **) qtdemux->protection_system_ids->pdata);
++  g_ptr_array_remove_index (qtdemux->protection_system_ids,
++      qtdemux->protection_system_ids->len - 1);
++  GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
++      "decryptors for %u of them, running context request",
++      qtdemux->protection_system_ids->len, g_strv_length (filtered_sys_ids));
++
++  if (stream->protection_scheme_event_queue.length) {
++    GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
++        stream->protection_scheme_event_queue.length);
++    walk = stream->protection_scheme_event_queue.tail;
++  } else {
++    GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
++        qtdemux->protection_event_queue.length);
++    walk = qtdemux->protection_event_queue.tail;
++  }
++
++  g_value_init (&event_list, GST_TYPE_LIST);
++  for (; walk; walk = g_list_previous (walk)) {
++    GValue *event_value = g_new0 (GValue, 1);
++    g_value_init (event_value, GST_TYPE_EVENT);
++    g_value_set_boxed (event_value, walk->data);
++    gst_value_list_append_and_take_value (&event_list, event_value);
++  }
++
++  /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
++   *      check if downstream already has a context of the specific type
++   *  2b) Query upstream as above.
++   */
++  query = gst_query_new_context ("drm-preferred-decryption-system-id");
++  st = gst_query_writable_structure (query);
++  gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++      "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++  gst_structure_set_value (st, "stream-encryption-events", &event_list);
++  if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
++    gst_query_parse_context (query, &ctxt);
++    GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
++    gst_element_set_context (element, ctxt);
++  } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
++    gst_query_parse_context (query, &ctxt);
++    GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
++    gst_element_set_context (element, ctxt);
++  } else {
++    /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
++     *    the required context type and afterwards check if a
++     *    usable context was set now as in 1). The message could
++     *    be handled by the parent bins of the element and the
++     *    application.
++     */
++    GstMessage *msg;
++
++    GST_INFO_OBJECT (element, "posting need context message");
++    msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
++        "drm-preferred-decryption-system-id");
++    st = (GstStructure *) gst_message_get_structure (msg);
++    gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++        "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++    gst_structure_set_value (st, "stream-encryption-events", &event_list);
++    gst_element_post_message (element, msg);
++  }
++
++  g_strfreev (filtered_sys_ids);
++  g_value_unset (&event_list);
++  gst_query_unref (query);
++}
++
++static gboolean
+ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+     QtDemuxStream * stream)
+ {
+   GstStructure *s;
+-  const gchar *selected_system;
++  const gchar *selected_system = NULL;
+   g_return_val_if_fail (qtdemux != NULL, FALSE);
+   g_return_val_if_fail (stream != NULL, FALSE);
+@@ -7708,17 +7872,41 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+         "cenc protection system information has been found");
+     return FALSE;
+   }
+-  g_ptr_array_add (qtdemux->protection_system_ids, NULL);
+-  selected_system = gst_protection_select_system ((const gchar **)
+-      qtdemux->protection_system_ids->pdata);
+-  g_ptr_array_remove_index (qtdemux->protection_system_ids,
+-      qtdemux->protection_system_ids->len - 1);
++
++  gst_qtdemux_request_protection_context (qtdemux, stream);
++  if (qtdemux->preferred_protection_system_id != NULL) {
++    const gchar *preferred_system_array[] =
++        { qtdemux->preferred_protection_system_id, NULL };
++
++    selected_system = gst_protection_select_system (preferred_system_array);
++
++    if (selected_system) {
++      GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
++          qtdemux->preferred_protection_system_id);
++    } else {
++      GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
++          "because there is no available decryptor",
++          qtdemux->preferred_protection_system_id);
++    }
++  }
++
++  if (!selected_system) {
++    g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++    selected_system = gst_protection_select_system ((const gchar **)
++        qtdemux->protection_system_ids->pdata);
++    g_ptr_array_remove_index (qtdemux->protection_system_ids,
++        qtdemux->protection_system_ids->len - 1);
++  }
++
+   if (!selected_system) {
+     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
+         "suitable decryptor element has been found");
+     return FALSE;
+   }
++  GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
++      selected_system);
++
+   s = gst_caps_get_structure (stream->caps, 0);
+   if (!gst_structure_has_name (s, "application/x-cenc")) {
+     gst_structure_set (s,
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index ebd725871..b3d64a4e8 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -154,6 +154,7 @@ struct _GstQTDemux {
+   guint64 cenc_aux_info_offset;
+   guint8 *cenc_aux_info_sizes;
+   guint32 cenc_aux_sample_count;
++  gchar *preferred_protection_system_id;
+   /*
+-- 
+2.11.0
+
diff --git a/Tools/wpe/patches/gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch b/Tools/wpe/patches/gst-plugins-good-0008-qtdemux-also-push-buffers-without-encryption-info-in.patch
new file mode 100644 (file)
index 0000000..95021cc
--- /dev/null
@@ -0,0 +1,50 @@
+From 78559bc5db3495f12b0284e4be5fc8bfcd7041e2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Enrique=20Oca=C3=B1a=20Gonz=C3=A1lez?= <eocanha@igalia.com>
+Date: Mon, 24 Apr 2017 17:22:02 +0000
+Subject: [PATCH] qtdemux: also push buffers without encryption info instead of
+ dropping them
+
+---
+ gst/isomp4/qtdemux.c | 26 ++++++++++++--------------
+ 1 file changed, 12 insertions(+), 14 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 6b0c820..7b71237 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -5421,20 +5421,18 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
+         gst_pad_push_event (stream->pad, event);
+     }
+-    if (info->crypto_info == NULL) {
+-      GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
+-      gst_buffer_unref (buf);
+-      goto exit;
+-    }
+-
+-    index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
+-    if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
+-      /* steal structure from array */
+-      crypto_info = g_ptr_array_index (info->crypto_info, index);
+-      g_ptr_array_index (info->crypto_info, index) = NULL;
+-      GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
+-      if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
+-        GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
++    if (info->crypto_info == NULL)
++      GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
++    else {
++      index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
++      if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
++        /* steal structure from array */
++        crypto_info = g_ptr_array_index (info->crypto_info, index);
++        g_ptr_array_index (info->crypto_info, index) = NULL;
++        GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
++        if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
++          GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
++      }
+     }
+   }
+-- 
+1.8.3.2
+
diff --git a/Tools/wpe/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch b/Tools/wpe/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch
deleted file mode 100644 (file)
index 3a60db4..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-From 1a81bd90d4a3e59d6669a0bbfa456f1ed4e5db48 Mon Sep 17 00:00:00 2001
-From: Xabier Rodriguez Calvar <calvaris@igalia.com>
-Date: Thu, 7 Apr 2016 13:57:16 +0200
-Subject: [PATCH] Revert "qtdemux: expose streams with first moof for
- fragmented format"
-
-This reverts commit d8bb6687ea251570c331038279a43d448167d6ad.
----
- gst/isomp4/qtdemux.c | 54 ++++++++++++++++------------------------------------
- gst/isomp4/qtdemux.h |  1 -
- 2 files changed, 16 insertions(+), 39 deletions(-)
-
-diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
-index 39be163..9636b4b 100644
---- a/gst/isomp4/qtdemux.c
-+++ b/gst/isomp4/qtdemux.c
-@@ -609,7 +609,6 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
-   qtdemux->state = QTDEMUX_STATE_INITIAL;
-   qtdemux->pullbased = FALSE;
-   qtdemux->posted_redirect = FALSE;
--  qtdemux->pending_configure = FALSE;
-   qtdemux->neededbytes = 16;
-   qtdemux->todrop = 0;
-   qtdemux->adapter = gst_adapter_new ();
-@@ -2049,7 +2048,6 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
-     gst_caps_replace (&qtdemux->media_caps, NULL);
-     qtdemux->timescale = 0;
-     qtdemux->got_moov = FALSE;
--    qtdemux->pending_configure = FALSE;
-   } else if (qtdemux->mss_mode) {
-     gst_flow_combiner_reset (qtdemux->flowcombiner);
-     for (n = 0; n < qtdemux->n_streams; n++)
-@@ -6104,7 +6102,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
-             &fourcc);
-         if (fourcc == FOURCC_moov) {
-           gint n;
--          gboolean got_samples = FALSE;
-           /* in usual fragmented setup we could try to scan for more
-            * and end up at the the moov (after mdat) again */
-@@ -6136,27 +6133,19 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
-             qtdemux_node_dump (demux, demux->moov_node);
-             qtdemux_parse_tree (demux);
-             qtdemux_prepare_streams (demux);
-+            if (!demux->got_moov)
-+              qtdemux_expose_streams (demux);
-+            else {
--            for (n = 0; n < demux->n_streams; n++) {
--              QtDemuxStream *stream = demux->streams[n];
--              got_samples |= stream->stbl_index >= 0;
--            }
--            if (!demux->fragmented || got_samples) {
--              if (!demux->got_moov) {
--                qtdemux_expose_streams (demux);
--              } else {
--                for (n = 0; n < demux->n_streams; n++) {
--                  QtDemuxStream *stream = demux->streams[n];
--                  gst_qtdemux_configure_stream (demux, stream);
--                }
-+              for (n = 0; n < demux->n_streams; n++) {
-+                QtDemuxStream *stream = demux->streams[n];
-+
-+                gst_qtdemux_configure_stream (demux, stream);
-               }
--              gst_qtdemux_check_send_pending_segment (demux);
--              demux->pending_configure = FALSE;
--            } else {
--              demux->pending_configure = TRUE;
-             }
-             demux->got_moov = TRUE;
-+            gst_qtdemux_check_send_pending_segment (demux);
-             /* fragmented streams headers shouldn't contain edts atoms */
-             if (!demux->fragmented) {
-@@ -6175,7 +6164,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
-             guint64 dist = 0;
-             GstClockTime prev_pts;
-             guint64 prev_offset;
--            gint n;
-             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
-@@ -6209,25 +6197,15 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
-               ret = GST_FLOW_ERROR;
-               goto done;
-             }
--            /* in MSS we need to expose the pads after the first moof as we won't get a moov 
--             * Also, fragmented format need to be exposed if a moov have no valid sample data */
--            if (demux->mss_mode || demux->pending_configure) {
--              if (!demux->exposed) {
--                if (!demux->pending_newsegment) {
--                  GstSegment segment;
--                  gst_segment_init (&segment, GST_FORMAT_TIME);
--                  GST_DEBUG_OBJECT (demux, "new pending_newsegment");
--                  demux->pending_newsegment = gst_event_new_segment (&segment);
--                }
--                qtdemux_expose_streams (demux);
--              } else {
--                for (n = 0; n < demux->n_streams; n++) {
--                  QtDemuxStream *stream = demux->streams[n];
--                  gst_qtdemux_configure_stream (demux, stream);
--                }
-+            /* in MSS we need to expose the pads after the first moof as we won't get a moov */
-+            if (demux->mss_mode && !demux->exposed) {
-+              if (!demux->pending_newsegment) {
-+                GstSegment segment;
-+                gst_segment_init (&segment, GST_FORMAT_TIME);
-+                GST_DEBUG_OBJECT (demux, "new pending_newsegment");
-+                demux->pending_newsegment = gst_event_new_segment (&segment);
-               }
--              gst_qtdemux_check_send_pending_segment (demux);
--              demux->pending_configure = FALSE;
-+              qtdemux_expose_streams (demux);
-             }
-           } else {
-             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
-diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
-index 6061215..ecf0c63 100644
---- a/gst/isomp4/qtdemux.h
-+++ b/gst/isomp4/qtdemux.h
-@@ -89,7 +89,6 @@ struct _GstQTDemux {
-   gboolean posted_redirect;
-   /* push based variables */
--  gboolean pending_configure;
-   guint neededbytes;
-   guint todrop;
-   GstAdapter *adapter;
--- 
-2.8.0.rc3
-
diff --git a/Tools/wpe/patches/gst-plugins-good-use-the-tfdt-decode-time.patch b/Tools/wpe/patches/gst-plugins-good-use-the-tfdt-decode-time.patch
deleted file mode 100644 (file)
index 1e9dd97..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-From 46d3e0faa922643094a5e46a32e4f82f774ae772 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Enrique=20Oca=C3=B1a=20Gonz=C3=A1lez?= <eocanha@igalia.com>
-Date: Tue, 10 Nov 2015 13:09:00 +0100
-Subject: [PATCH] Use the tfdt decode time when it's significantly different
- than the time in the last sample if always-honor-tfdt is enabled
-
-https://bugzilla.gnome.org/show_bug.cgi?id=754230
----
- gst/isomp4/qtdemux.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- gst/isomp4/qtdemux.h |  1 +
- 2 files changed, 73 insertions(+)
-
-diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
-index 880595e..d8b54f0 100644
---- a/gst/isomp4/qtdemux.c
-+++ b/gst/isomp4/qtdemux.c
-@@ -535,6 +535,11 @@ static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
-     const gchar * id);
- static void qtdemux_gst_structure_free (GstStructure * gststructure);
-+static void gst_qtdemux_set_property (GObject * object, guint prop_id,
-+    const GValue * value, GParamSpec * spec);
-+static void gst_qtdemux_get_property (GObject * object, guint prop_id,
-+    GValue * value, GParamSpec * spec);
-+
- static void
- gst_qtdemux_class_init (GstQTDemuxClass * klass)
- {
-@@ -546,8 +551,21 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
-   parent_class = g_type_class_peek_parent (klass);
-+  gobject_class->set_property = gst_qtdemux_set_property;
-+  gobject_class->get_property = gst_qtdemux_get_property;
-+
-   gobject_class->dispose = gst_qtdemux_dispose;
-+ /**
-+   * GstQtDemux::always-honor-tfdt:
-+   *
-+   * Requests the demuxer to respect what the TFDT atom says in order to produce presentation timestamps. Defaults to FALSE.
-+   */
-+  g_object_class_install_property (gobject_class, PROP_ALWAYS_HONOR_TFDT,
-+      g_param_spec_boolean ("always-honor-tfdt", "Always honor TFDT",
-+          "When enabled, TFDT atom will always be respected in order to produce presentation timestamps",
-+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-+
-   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
- #if 0
-   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
-@@ -611,6 +629,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
-   qtdemux->cenc_aux_info_sizes = NULL;
-   qtdemux->cenc_aux_sample_count = 0;
-   qtdemux->protection_system_ids = NULL;
-+  qtdemux->always_honor_tfdt = FALSE;
-   g_queue_init (&qtdemux->protection_event_queue);
-   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
-   qtdemux->flowcombiner = gst_flow_combiner_new ();
-@@ -639,6 +658,42 @@ gst_qtdemux_dispose (GObject * object)
- }
- static void
-+gst_qtdemux_set_property (GObject * object, guint prop_id,
-+    const GValue * value, GParamSpec * pspec)
-+{
-+  GstQTDemux *qtdemux = GST_QTDEMUX (object);
-+
-+  switch (prop_id) {
-+    case PROP_ALWAYS_HONOR_TFDT:
-+      GST_OBJECT_LOCK (qtdemux);
-+      qtdemux->always_honor_tfdt = g_value_get_boolean (value);
-+      GST_OBJECT_UNLOCK (qtdemux);
-+      break;
-+    default:
-+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-+      break;
-+  }
-+}
-+
-+static void
-+gst_qtdemux_get_property (GObject * object, guint prop_id, GValue * value,
-+    GParamSpec * pspec)
-+{
-+  GstQTDemux *qtdemux = GST_QTDEMUX (object);
-+
-+  switch (prop_id) {
-+    case PROP_ALWAYS_HONOR_TFDT:
-+      GST_OBJECT_LOCK (qtdemux);
-+      g_value_set_boolean (value, qtdemux->always_honor_tfdt);
-+      GST_OBJECT_UNLOCK (qtdemux);
-+      break;
-+    default:
-+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-+      break;
-+  }
-+}
-+
-+static void
- gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
- {
-   if (qtdemux->posted_redirect) {
-@@ -2995,6 +3050,16 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
-           stream->samples[stream->n_samples - 1].timestamp +
-           stream->samples[stream->n_samples - 1].duration;
-+      /* If we're always honoring TFDT and there's a significative difference
-+       * between the decode_ts and the timestamp, prefer decode_ts */
-+      if (qtdemux->always_honor_tfdt == TRUE
-+          && abs (decode_ts - timestamp) >
-+          stream->samples[stream->n_samples - 1].duration) {
-+        GST_INFO_OBJECT (qtdemux,
-+            "decode_ts is significantly different from timestamp, using decode_ts");
-+        timestamp = decode_ts;
-+      }
-+
-       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
-       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
-           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
-diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
-index 53bd071..ecf0c63 100644
---- a/gst/isomp4/qtdemux.h
-+++ b/gst/isomp4/qtdemux.h
-@@ -154,12 +154,20 @@ struct _GstQTDemux {
-   guint8 *cenc_aux_info_sizes;
-   guint32 cenc_aux_sample_count;
-+  gboolean always_honor_tfdt;
- };
- struct _GstQTDemuxClass {
-   GstElementClass parent_class;
- };
-+/* props */
-+enum
-+{
-+  PROP_0,
-+  PROP_ALWAYS_HONOR_TFDT
-+};
-+
- GType gst_qtdemux_get_type (void);
- G_END_DECLS
--- 
-2.6.1
-
diff --git a/Tools/wpe/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch b/Tools/wpe/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch
new file mode 100644 (file)
index 0000000..e72ef6c
--- /dev/null
@@ -0,0 +1,77 @@
+From 7772eb350591682b6a315c8a87a58131f731f1d4 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Wed, 19 Oct 2016 16:44:16 +0200
+Subject: [PATCH] protection: added function to filter system ids
+
+gst_protection_filter_systems_by_available_decryptors takes an array of
+strings and returns a new array of strings filtered by the avaible
+decryptors for them so the ones you get are the ones that you should be
+able to decrypt.
+---
+ gst/gstprotection.c | 36 ++++++++++++++++++++++++++++++++++++
+ gst/gstprotection.h |  2 ++
+ 2 files changed, 38 insertions(+)
+
+diff --git a/gst/gstprotection.c b/gst/gstprotection.c
+index 8ee52ea..2d7e5e0 100644
+--- a/gst/gstprotection.c
++++ b/gst/gstprotection.c
+@@ -191,6 +191,42 @@ gst_protection_select_system (const gchar ** system_identifiers)
+   return retval;
+ }
++gchar **
++gst_protection_filter_systems_by_available_decryptors (const gchar **
++    system_identifiers)
++{
++  GList *decryptors, *walk;
++  gchar **retval;
++  guint i = 0, decryptors_number;
++
++  decryptors =
++      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECRYPTOR,
++      GST_RANK_MARGINAL);
++
++  decryptors_number = g_list_length (decryptors);
++  retval = g_new (gchar *, decryptors_number + 1);
++
++  GST_TRACE ("found %u decrytors", decryptors_number);
++
++  for (walk = decryptors; walk; walk = g_list_next (walk)) {
++    GstElementFactory *fact = (GstElementFactory *) walk->data;
++
++    const char *found_sys_id =
++        gst_protection_factory_check (fact, system_identifiers);
++    GST_TRACE ("factory %s is valid for %s", GST_OBJECT_NAME (fact),
++        found_sys_id);
++
++    if (found_sys_id) {
++      retval[i++] = g_strdup (found_sys_id);
++    }
++  }
++  retval[i] = NULL;
++
++  gst_plugin_feature_list_free (decryptors);
++
++  return retval;
++}
++
+ static const gchar *
+ gst_protection_factory_check (GstElementFactory * fact,
+     const gchar ** system_identifiers)
+diff --git a/gst/gstprotection.h b/gst/gstprotection.h
+index f2f54c4..95976c5 100644
+--- a/gst/gstprotection.h
++++ b/gst/gstprotection.h
+@@ -66,6 +66,8 @@ GstProtectionMeta *gst_buffer_add_protection_meta (GstBuffer * buffer,
+     GstStructure * info);
+ const gchar *gst_protection_select_system (const gchar ** system_identifiers);
++gchar ** gst_protection_filter_systems_by_available_decryptors (
++    const gchar ** system_identifiers);
+ G_END_DECLS
+ #endif /* __GST_PROTECTION_META_H__ */
+-- 
+2.10.2
+