diff options
author | Jorge Zapata <jorgeluis.zapata@gmail.com> | 2013-01-22 18:44:22 +0100 |
---|---|---|
committer | Josep Torra <n770galaxy@gmail.com> | 2013-05-22 14:41:14 +0200 |
commit | 372d10bc89e9fa2cc9865f3d4f2e3e7a10817f0f (patch) | |
tree | 01ca1f7419bc83b5441578e848cfda18a4892f83 | |
parent | eaba11937aad8245d9e21a4463bda03134000487 (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.c | 115 | ||||
-rw-r--r-- | gst/isomp4/qtdemux.h | 1 | ||||
-rw-r--r-- | gst/isomp4/qtdemux_fourcc.h | 4 | ||||
-rw-r--r-- | gst/isomp4/qtdemux_types.c | 2 |
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,}, }; |