summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorge Zapata <jorgeluis.zapata@gmail.com>2013-01-22 18:44:22 +0100
committerJosep Torra <n770galaxy@gmail.com>2013-05-22 14:41:14 +0200
commit372d10bc89e9fa2cc9865f3d4f2e3e7a10817f0f (patch)
tree01ca1f7419bc83b5441578e848cfda18a4892f83
parenteaba11937aad8245d9e21a4463bda03134000487 (diff)
qtdemux: Add support for pssh box and handle the piff variants
The pssh box defines the data needed for the DRM implementation to work. For that we trigger a signal whenever such atom is found. When reading the cenc related atoms, check the version adding support for piff based brands. Whenever the file has a 'piff' brand, check that we have a uuid box to send it instead of the senc one for encrypted tracks.
-rw-r--r--gst/isomp4/qtdemux.c115
-rw-r--r--gst/isomp4/qtdemux.h1
-rw-r--r--gst/isomp4/qtdemux_fourcc.h4
-rw-r--r--gst/isomp4/qtdemux_types.c2
4 files changed, 118 insertions, 4 deletions
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
index 3b5ad2835..ccf0df35f 100644
--- a/gst/isomp4/qtdemux.c
+++ b/gst/isomp4/qtdemux.c
@@ -365,6 +365,7 @@ enum
{
SIGNAL_CENC_TENC,
SIGNAL_CENC_SENC,
+ SIGNAL_PSSH,
SIGNAL_DECRYPT,
LAST_SIGNAL
};
@@ -519,6 +520,34 @@ g_cclosure_marshal_VOID__UINT_BUFFER (GClosure * closure,
}
static void
+g_cclosure_marshal_VOID__BUFFER (GClosure * closure,
+ GValue * return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue * param_values,
+ gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BUFFER) (gpointer data1,
+ gpointer arg_2, gpointer data2);
+ register GMarshalFunc_VOID__BUFFER callback;
+ register GCClosure *cc = (GCClosure *) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback =
+ (GMarshalFunc_VOID__BUFFER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1, g_value_peek_pointer (param_values + 1), data2);
+}
+
+static void
gst_qtdemux_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
@@ -596,6 +625,23 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
G_TYPE_UINT, GST_TYPE_BUFFER);
/**
+ * GstQTDemux::pssh:
+ * @demux: the demuxer instance
+ * @pssh: a #GstBuffer containing senc node
+ *
+ * This signal gets emitted whenever a pssh atom is found to allow
+ * the initialization of an external decrypter that implements the
+ * Protected Interoperable File Format (PIFF) specification.
+ *
+ * Since: 0.10.31
+ */
+ gst_qtdemux_signals[SIGNAL_PSSH] =
+ g_signal_new ("pssh", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstQTDemuxClass, pssh),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BUFFER, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
+
+ /**
* GstQTDemux::decrypt:
* @demux: the demuxer instance
* @track_id: the track identifier
@@ -2503,6 +2549,34 @@ qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id, guint32 idx)
return NULL;
}
+static inline gboolean
+qtdemux_check_brand (GstQTDemux * qtdemux, guint32 fourcc, gboolean major)
+{
+ if (major) {
+ return (qtdemux->major_brand == fourcc);
+ } else if (qtdemux->comp_brands != NULL) {
+ guint8 *data = GST_BUFFER_DATA (qtdemux->comp_brands);
+ guint size = GST_BUFFER_SIZE (qtdemux->comp_brands);
+ gboolean res = FALSE;
+
+ while (size >= 4) {
+ res = res || (QT_FOURCC (data) == fourcc);
+ data += 4;
+ size -= 4;
+ }
+ return res;
+ } else {
+ return FALSE;
+ }
+}
+
+static inline gboolean
+qtdemux_is_brand_piff (GstQTDemux * qtdemux, gboolean major)
+{
+ return qtdemux_check_brand (qtdemux, GST_MAKE_FOURCC ('p', 'i', 'f', 'f'),
+ major);
+}
+
static inline void
qtdemux_get_track_defaults (GstQTDemux * qtdemux, guint track_id,
guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags,
@@ -2700,7 +2774,14 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
if (stream->encrypted) {
GNode *node;
GstBuffer *buf = NULL;
- node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_senc);
+
+ /* check if the brand has piff, if so, find the uuid */
+ if (qtdemux_is_brand_piff (qtdemux, FALSE)) {
+ node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
+ } else {
+ node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_senc);
+ }
+
if (node) {
buf = gst_buffer_new ();
GST_BUFFER_DATA (buf) = node->data;
@@ -4836,6 +4917,7 @@ static gboolean
qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
{
GNode *cmov;
+ GNode *pssh;
qtdemux->moov_node = g_node_new ((guint8 *) buffer);
@@ -4845,6 +4927,18 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
+ pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
+ if (pssh) {
+ GstBuffer *buf;
+
+ /* for the pssh, just send the buffer completely */
+ buf = gst_buffer_new ();
+ GST_BUFFER_DATA (buf) = pssh->data;
+ GST_BUFFER_SIZE (buf) = GST_READ_UINT32_BE (pssh->data);
+ g_signal_emit (qtdemux, gst_qtdemux_signals[SIGNAL_PSSH], 0, buf);
+ gst_buffer_unref (buf);
+ }
+
cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
if (cmov) {
guint32 method;
@@ -6628,7 +6722,8 @@ qtdemux_parse_cenc (GstQTDemux * qtdemux, QtDemuxStream * stream,
GNode *tenc;
GstBuffer *buf;
- if (scheme_version != 0x00010000) {
+ /* For piff based brands, the scheme version is 0x00010001 */
+ if ((scheme_version != 0x00010000) && (scheme_version != 0x00010001)) {
GST_WARNING_OBJECT (qtdemux, "Wrong version number %08x", scheme_version);
return FALSE;
}
@@ -6714,6 +6809,11 @@ qtdemux_parse_sinf (GstQTDemux * qtdemux, QtDemuxStream * stream,
case FOURCC_cenc:
ret = qtdemux_parse_cenc (qtdemux, stream, scheme_version, schi);
break;
+ /* TODO so far every file that has a piff also has a cenc with the info
+ * duplicated, so we dont need to parse it again
+ */
+ case FOURCC_piff:
+ break;
default:
GST_WARNING_OBJECT (qtdemux,
@@ -6732,12 +6832,19 @@ qtdemux_parse_encx (GstQTDemux * qtdemux, QtDemuxStream * stream,
GNode *sinf;
/* now the 'sinf' */
- if (!(sinf = qtdemux_tree_get_child_by_type (encx, FOURCC_sinf))) {
+ sinf = qtdemux_tree_get_child_by_type (encx, FOURCC_sinf);
+ if (!sinf) {
GST_WARNING_OBJECT (qtdemux, "No sinf found");
return FALSE;
}
- return qtdemux_parse_sinf (qtdemux, stream, sinf, fourcc);
+ while (sinf) {
+ if (!qtdemux_parse_sinf (qtdemux, stream, sinf, fourcc))
+ return FALSE;
+ sinf = qtdemux_tree_get_sibling_by_type (sinf, FOURCC_sinf);
+ }
+
+ return TRUE;
}
static gboolean
diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
index 38a4e9feb..c7705190b 100644
--- a/gst/isomp4/qtdemux.h
+++ b/gst/isomp4/qtdemux.h
@@ -121,6 +121,7 @@ struct _GstQTDemuxClass {
GstElementClass parent_class;
void (*cenc_tenc) (GstQTDemux * demux, guint32 track_id, GstBuffer * tenc);
void (*cenc_senc) (GstQTDemux * demux, guint32 track_id, GstBuffer * senc);
+ void (*pssh) (GstQTDemux * demux, GstBuffer * pssh);
GstBuffer* (*decrypt) (GstQTDemux * demux, guint32 track_id, GstBuffer *buff, guint32 sample_index);
};
diff --git a/gst/isomp4/qtdemux_fourcc.h b/gst/isomp4/qtdemux_fourcc.h
index 5d55a2e71..a9b12a51a 100644
--- a/gst/isomp4/qtdemux_fourcc.h
+++ b/gst/isomp4/qtdemux_fourcc.h
@@ -249,6 +249,10 @@ G_BEGIN_DECLS
#define FOURCC_tenc GST_MAKE_FOURCC('t','e','n','c')
#define FOURCC_senc GST_MAKE_FOURCC('s','e','n','c')
+/* Portable interoperable file format (PIFF) */
+#define FOURCC_piff GST_MAKE_FOURCC('p','i','f','f')
+#define FOURCC_pssh GST_MAKE_FOURCC('p','s','s','h')
+
G_END_DECLS
#endif /* __GST_QTDEMUX_FOURCC_H__ */
diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c
index 5acd548fe..7b2d5d7e1 100644
--- a/gst/isomp4/qtdemux_types.c
+++ b/gst/isomp4/qtdemux_types.c
@@ -181,6 +181,8 @@ static const QtNodeType qt_node_types[] = {
{FOURCC_cenc, "cenc", 0},
{FOURCC_tenc, "tenc", 0},
{FOURCC_senc, "senc", 0},
+ {FOURCC_pssh, "pssh", 0},
+ {FOURCC_uuid, "uuid", 0},
{0, "unknown", 0,},
};