diff options
author | Stefan BrĂ¼ns <stefan.bruens@rwth-aachen.de> | 2020-05-02 03:21:00 +0300 |
---|---|---|
committer | StefanBruens <stefan.bruens@rwth-aachen.de> | 2020-09-16 03:59:34 +0300 |
commit | ee3ea2a94d839092a5c518125dac5584a37c6c99 (patch) | |
tree | 5a659ef06fd5e19df62a59e0cd4f6e15b1e2c3ee /gst | |
parent | 6e68873d7f4076e3d659b83c2ea20fbfecc5e07c (diff) |
qtdemux: Add support for AAX encrypted audio streams
This is modelled after the DASH Common Encryption scheme, but is somewhat
simpler as more parts are fixed, i.e. just one encryption scheme.
The output caps are fixed to 'application/x-aavd'. All information
required for decryption are part of the 'adrm' atom, which is passed
on as a property. The property is attached to the buffer.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/577>
Diffstat (limited to 'gst')
-rw-r--r-- | gst/isomp4/qtdemux.c | 96 |
1 files changed, 92 insertions, 4 deletions
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 2929cb4a9..146f409cb 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -111,6 +111,7 @@ GST_DEBUG_CATEGORY (qtdemux_debug); #define GST_CAT_DEFAULT qtdemux_debug typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo; +typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo; /* Macros for converting to/from timescale */ #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale)) @@ -234,6 +235,11 @@ struct _QtDemuxCencSampleSetInfo GPtrArray *crypto_info; }; +struct _QtDemuxAavdEncryptionInfo +{ + GstStructure *default_properties; +}; + static const gchar * qt_demux_state_string (enum QtDemuxState state) { @@ -2526,6 +2532,12 @@ gst_qtdemux_stream_clear (QtDemuxStream * stream) if (info->crypto_info) g_ptr_array_free (info->crypto_info, TRUE); } + if (stream->protection_scheme_type == FOURCC_aavd) { + QtDemuxAavdEncryptionInfo *info = + (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info; + if (info->default_properties) + gst_structure_free (info->default_properties); + } g_free (stream->protection_scheme_info); stream->protection_scheme_info = NULL; } @@ -5694,6 +5706,16 @@ gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream, GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad)); + if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) { + GstStructure *crypto_info; + QtDemuxAavdEncryptionInfo *info = + (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info; + + crypto_info = gst_structure_copy (info->default_properties); + if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) + GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer"); + } + if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) { GstStructure *crypto_info; QtDemuxCencSampleSetInfo *info = @@ -8271,6 +8293,17 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux, g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1, FALSE); + if (stream->protection_scheme_type == FOURCC_aavd) { + s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0); + if (!gst_structure_has_name (s, "application/x-aavd")) { + gst_structure_set (s, + "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), + NULL); + gst_structure_set_name (s, "application/x-aavd"); + } + return TRUE; + } + if (stream->protection_scheme_type != FOURCC_cenc) { GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme: %" GST_FOURCC_FORMAT, @@ -10249,6 +10282,42 @@ qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux, } } +static gboolean +qtdemux_parse_protection_aavd (GstQTDemux * qtdemux, + QtDemuxStream * stream, GNode * container, guint32 * original_fmt) +{ + GNode *adrm; + guint32 adrm_size; + GstBuffer *adrm_buf = NULL; + QtDemuxAavdEncryptionInfo *info; + + adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm); + if (G_UNLIKELY (!adrm)) { + GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box"); + return FALSE; + } + adrm_size = QT_UINT32 (adrm->data); + adrm_buf = + gst_buffer_new_wrapped (g_memdup (adrm->data, adrm_size), adrm_size); + + stream->protection_scheme_type = FOURCC_aavd; + + if (!stream->protection_scheme_info) + stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1); + + info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info; + + if (info->default_properties) + gst_structure_free (info->default_properties); + info->default_properties = gst_structure_new ("application/x-aavd", + "encrypted", G_TYPE_BOOLEAN, TRUE, + "adrm", GST_TYPE_BUFFER, adrm_buf, NULL); + gst_buffer_unref (adrm_buf); + + *original_fmt = FOURCC_mp4a; + return TRUE; +} + /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for * protected streams (sinf, frma, schm and schi); if the protection scheme is * Common Encryption (cenc), the function will also parse the tenc box (defined @@ -10697,6 +10766,19 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi)) goto error_encrypted; + if (fourcc == FOURCC_aavd) { + if (stream->subtype != FOURCC_soun) { + GST_ERROR_OBJECT (qtdemux, + "Unexpeced stsd type 'aavd' outside 'soun' track"); + } else { + /* encrypted audio with sound sample description v0 */ + GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc); + stream->protected = TRUE; + if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc)) + GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info"); + } + } + if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) { /* FIXME this looks wrong, there might be multiple children * with the same type */ @@ -12245,16 +12327,22 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) GST_TAG_BITRATE, bitrate, NULL); } + esds = NULL; mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index); if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) { - if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) - mp4a = NULL; - else if (!stream->protected) + if (stream->protected) { + if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) { + esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds); + } + if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) { + mp4a = NULL; + } + } else { mp4a = NULL; + } } wave = NULL; - esds = NULL; if (mp4a) { wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave); if (wave) |