mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
qtdemux: added support for cbcs encryption scheme
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/865>
This commit is contained in:
parent
7b7e49de31
commit
61d204ab22
2 changed files with 110 additions and 29 deletions
|
@ -402,6 +402,7 @@ G_BEGIN_DECLS
|
|||
#define FOURCC_pssh GST_MAKE_FOURCC('p','s','s','h')
|
||||
#define FOURCC_tenc GST_MAKE_FOURCC('t','e','n','c')
|
||||
#define FOURCC_cenc GST_MAKE_FOURCC('c','e','n','c')
|
||||
#define FOURCC_cbcs GST_MAKE_FOURCC('c','b','c','s')
|
||||
|
||||
/* Audible AAX encrypted audio */
|
||||
#define FOURCC_aavd GST_MAKE_FOURCC('a','a','v','d')
|
||||
|
|
|
@ -2524,7 +2524,8 @@ gst_qtdemux_stream_clear (QtDemuxStream * stream)
|
|||
stream->sent_eos = FALSE;
|
||||
stream->protected = FALSE;
|
||||
if (stream->protection_scheme_info) {
|
||||
if (stream->protection_scheme_type == FOURCC_cenc) {
|
||||
if (stream->protection_scheme_type == FOURCC_cenc
|
||||
|| stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
QtDemuxCencSampleSetInfo *info =
|
||||
(QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
|
||||
if (info->default_properties)
|
||||
|
@ -2664,22 +2665,43 @@ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
|
|||
}
|
||||
|
||||
static void
|
||||
qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
|
||||
QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
|
||||
const guint8 * kid)
|
||||
qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
|
||||
QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
|
||||
guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
|
||||
guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
|
||||
const guint8 * constant_iv)
|
||||
{
|
||||
const gchar *protection_scheme_type_mime =
|
||||
protection_scheme_type ==
|
||||
FOURCC_cbcs ? "application/x-cbcs" : "application/x-cenc";
|
||||
GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
|
||||
gst_buffer_fill (kid_buf, 0, kid, 16);
|
||||
if (info->default_properties)
|
||||
gst_structure_free (info->default_properties);
|
||||
info->default_properties =
|
||||
gst_structure_new ("application/x-cenc",
|
||||
gst_structure_new (protection_scheme_type_mime,
|
||||
"iv_size", G_TYPE_UINT, iv_size,
|
||||
"encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
|
||||
"kid", GST_TYPE_BUFFER, kid_buf, NULL);
|
||||
GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
|
||||
"is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
|
||||
gst_buffer_unref (kid_buf);
|
||||
if (protection_scheme_type == FOURCC_cbcs) {
|
||||
if (crypt_byte_block != 0 || skip_byte_block != 0) {
|
||||
gst_structure_set (info->default_properties, "crypt_byte_block",
|
||||
G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
|
||||
skip_byte_block, NULL);
|
||||
}
|
||||
if (constant_iv != NULL) {
|
||||
GstBuffer *constant_iv_buf =
|
||||
gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
|
||||
gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
|
||||
gst_structure_set (info->default_properties, "constant_iv_size",
|
||||
G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
|
||||
NULL);
|
||||
gst_buffer_unref (constant_iv_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -2711,8 +2733,8 @@ qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
|
|||
if (!gst_byte_reader_get_data (br, 16, &kid))
|
||||
return FALSE;
|
||||
|
||||
qtdemux_update_default_sample_encryption_settings (qtdemux, info,
|
||||
is_encrypted, iv_size, kid);
|
||||
qtdemux_update_default_sample_cenc_settings (qtdemux, info,
|
||||
is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
|
||||
gst_structure_set (info->default_properties, "piff_algorithm_id",
|
||||
G_TYPE_UINT, algorithm_id, NULL);
|
||||
return TRUE;
|
||||
|
@ -3727,9 +3749,10 @@ qtdemux_gst_structure_free (GstStructure * gststructure)
|
|||
}
|
||||
}
|
||||
|
||||
/* Parses auxiliary information relating to samples protected using Common
|
||||
* Encryption (cenc); the format of this information is defined in
|
||||
* ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
|
||||
/* Parses auxiliary information relating to samples protected using
|
||||
* Common Encryption (cenc and cbcs); the format of this information
|
||||
* is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
|
||||
* otherwise. */
|
||||
static gboolean
|
||||
qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||
GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
|
||||
|
@ -3787,6 +3810,7 @@ qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
guint8 *data;
|
||||
guint iv_size;
|
||||
GstBuffer *buf;
|
||||
gboolean could_read_iv;
|
||||
|
||||
properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
|
||||
if (properties == NULL) {
|
||||
|
@ -3798,14 +3822,29 @@ qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
gst_structure_free (properties);
|
||||
return FALSE;
|
||||
}
|
||||
if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
|
||||
could_read_iv =
|
||||
iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
|
||||
if (could_read_iv) {
|
||||
buf = gst_buffer_new_wrapped (data, iv_size);
|
||||
gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
|
||||
gst_buffer_unref (buf);
|
||||
} else if (stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
const GValue *constant_iv_size_value =
|
||||
gst_structure_get_value (properties, "constant_iv_size");
|
||||
const GValue *constant_iv_value =
|
||||
gst_structure_get_value (properties, "iv");
|
||||
if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
|
||||
GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
|
||||
gst_structure_free (properties);
|
||||
return FALSE;
|
||||
}
|
||||
gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
|
||||
gst_structure_remove_field (properties, "constant_iv_size");
|
||||
} else if (stream->protection_scheme_type == FOURCC_cenc) {
|
||||
GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
|
||||
gst_structure_free (properties);
|
||||
return FALSE;
|
||||
}
|
||||
buf = gst_buffer_new_wrapped (data, iv_size);
|
||||
gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
|
||||
gst_buffer_unref (buf);
|
||||
size = info_sizes[i];
|
||||
if (size > iv_size) {
|
||||
if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
|
||||
|
@ -3988,7 +4027,8 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
|||
}
|
||||
if (base_offset > -1 && base_offset > qtdemux->moof_offset)
|
||||
offset += (guint64) (base_offset - qtdemux->moof_offset);
|
||||
if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
|
||||
if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
|
||||
&& info_type_parameter == 0U) {
|
||||
GstByteReader br;
|
||||
if (offset > length) {
|
||||
GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
|
||||
|
@ -5726,7 +5766,8 @@ gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
|
||||
}
|
||||
|
||||
if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
|
||||
if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
|
||||
|| stream->protection_scheme_type == FOURCC_cbcs)) {
|
||||
GstStructure *crypto_info;
|
||||
QtDemuxCencSampleSetInfo *info =
|
||||
(QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
|
||||
|
@ -5740,8 +5781,19 @@ gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
}
|
||||
|
||||
if (info->crypto_info == NULL) {
|
||||
GST_DEBUG_OBJECT (qtdemux,
|
||||
"cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
|
||||
if (stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
|
||||
if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
|
||||
GST_ERROR_OBJECT (qtdemux,
|
||||
"failed to attach cbcs metadata to buffer");
|
||||
qtdemux_gst_structure_free (crypto_info);
|
||||
} else {
|
||||
GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (qtdemux,
|
||||
"cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
|
||||
}
|
||||
} else {
|
||||
/* The end of the crypto_info array matches our n_samples position,
|
||||
* so count backward from there */
|
||||
|
@ -6114,7 +6166,8 @@ gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
|
|||
|
||||
if (stream->protection_scheme_info) {
|
||||
/* Clear out any old cenc crypto info entries as we'll move to a new moof */
|
||||
if (stream->protection_scheme_type == FOURCC_cenc) {
|
||||
if (stream->protection_scheme_type == FOURCC_cenc
|
||||
|| stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
QtDemuxCencSampleSetInfo *info =
|
||||
(QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
|
||||
if (info->crypto_info) {
|
||||
|
@ -8314,7 +8367,8 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
if (stream->protection_scheme_type != FOURCC_cenc) {
|
||||
if (stream->protection_scheme_type != FOURCC_cenc
|
||||
&& stream->protection_scheme_type != FOURCC_cbcs) {
|
||||
GST_ERROR_OBJECT (qtdemux,
|
||||
"unsupported protection scheme: %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (stream->protection_scheme_type));
|
||||
|
@ -8322,10 +8376,13 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
|
|||
}
|
||||
|
||||
s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
|
||||
if (!gst_structure_has_name (s, "application/x-cenc")) {
|
||||
if (!gst_structure_has_name (s, "application/x-cenc")
|
||||
&& !gst_structure_has_name (s, "application/x-cbcs")) {
|
||||
gst_structure_set (s,
|
||||
"original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
|
||||
gst_structure_set_name (s, "application/x-cenc");
|
||||
gst_structure_set_name (s,
|
||||
stream->protection_scheme_type ==
|
||||
FOURCC_cbcs ? "application/x-cbcs" : "application/x-cenc");
|
||||
}
|
||||
|
||||
if (qtdemux->protection_system_ids == NULL) {
|
||||
|
@ -10361,7 +10418,8 @@ qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
|
|||
|
||||
sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
|
||||
if (G_UNLIKELY (!sinf)) {
|
||||
if (stream->protection_scheme_type == FOURCC_cenc) {
|
||||
if (stream->protection_scheme_type == FOURCC_cenc
|
||||
|| stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
|
||||
"mandatory for Common Encryption");
|
||||
return FALSE;
|
||||
|
@ -10400,7 +10458,8 @@ qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
|
|||
return FALSE;
|
||||
}
|
||||
if (stream->protection_scheme_type != FOURCC_cenc &&
|
||||
stream->protection_scheme_type != FOURCC_piff) {
|
||||
stream->protection_scheme_type != FOURCC_piff &&
|
||||
stream->protection_scheme_type != FOURCC_cbcs) {
|
||||
GST_ERROR_OBJECT (qtdemux,
|
||||
"Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (stream->protection_scheme_type));
|
||||
|
@ -10413,10 +10472,15 @@ qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
|
|||
|
||||
info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
|
||||
|
||||
if (stream->protection_scheme_type == FOURCC_cenc) {
|
||||
guint32 is_encrypted;
|
||||
if (stream->protection_scheme_type == FOURCC_cenc
|
||||
|| stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
guint8 is_encrypted;
|
||||
guint8 iv_size;
|
||||
guint8 constant_iv_size = 0;
|
||||
const guint8 *default_kid;
|
||||
guint8 crypt_byte_block = 0;
|
||||
guint8 skip_byte_block = 0;
|
||||
const guint8 *constant_iv = NULL;
|
||||
|
||||
tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
|
||||
if (!tenc) {
|
||||
|
@ -10425,11 +10489,27 @@ qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
|
|||
return FALSE;
|
||||
}
|
||||
tenc_data = (const guint8 *) tenc->data + 12;
|
||||
is_encrypted = QT_UINT24 (tenc_data);
|
||||
is_encrypted = QT_UINT8 (tenc_data + 2);
|
||||
iv_size = QT_UINT8 (tenc_data + 3);
|
||||
default_kid = (tenc_data + 4);
|
||||
qtdemux_update_default_sample_encryption_settings (qtdemux, info,
|
||||
is_encrypted, iv_size, default_kid);
|
||||
if (stream->protection_scheme_type == FOURCC_cbcs) {
|
||||
guint8 possible_pattern_info;
|
||||
if (iv_size == 0) {
|
||||
constant_iv_size = QT_UINT8 (tenc_data + 20);
|
||||
if (constant_iv_size != 8 && constant_iv_size != 16) {
|
||||
GST_ERROR_OBJECT (qtdemux,
|
||||
"constant IV size should be 8 or 16, not %hhu", constant_iv_size);
|
||||
return FALSE;
|
||||
}
|
||||
constant_iv = (tenc_data + 21);
|
||||
}
|
||||
possible_pattern_info = QT_UINT8 (tenc_data + 1);
|
||||
crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
|
||||
skip_byte_block = possible_pattern_info & 0x0f;
|
||||
}
|
||||
qtdemux_update_default_sample_cenc_settings (qtdemux, info,
|
||||
is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
|
||||
crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
|
||||
} else if (stream->protection_scheme_type == FOURCC_piff) {
|
||||
GstByteReader br;
|
||||
static const guint8 piff_track_encryption_uuid[] = {
|
||||
|
|
Loading…
Reference in a new issue