diff options
-rw-r--r-- | gst/isomp4/qtdemux.c | 367 | ||||
-rw-r--r-- | gst/isomp4/qtdemux.h | 6 | ||||
-rw-r--r-- | gst/isomp4/qtdemux_fourcc.h | 11 | ||||
-rw-r--r-- | gst/isomp4/qtdemux_types.c | 9 |
4 files changed, 372 insertions, 21 deletions
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index fbf944a95..f769f2c97 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -344,6 +344,9 @@ struct _QtDemuxStream guint32 def_sample_duration; guint32 def_sample_size; guint32 def_sample_flags; + + gboolean encrypted; + guint32 senc_sample_index; }; enum QtDemuxState @@ -354,6 +357,16 @@ enum QtDemuxState QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */ }; +enum +{ + SIGNAL_CENC_TENC, + SIGNAL_CENC_SENC, + SIGNAL_DECRYPT, + LAST_SIGNAL +}; + +static guint gst_qtdemux_signals[LAST_SIGNAL] = { 0 }; + static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc); static GNode *qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc, GstByteReader * parser); @@ -432,6 +445,75 @@ static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux, static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux); static void +g_cclosure_marshal_BUFFER__UINT_BUFFER_UINT (GClosure * closure, + GValue * return_value, + guint n_param_values, + const GValue * param_values, + gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) +{ + typedef gpointer (*GMarshalFunc_BUFFER__UINT_BUFFER_UINT) (gpointer data1, + guint arg_1, gpointer arg_2, guint arg_3, gpointer data2); + register GMarshalFunc_BUFFER__UINT_BUFFER_UINT callback; + register GCClosure *cc = (GCClosure *) closure; + register gpointer data1, data2; + gpointer v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 4); + + 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_BUFFER__UINT_BUFFER_UINT) (marshal_data ? marshal_data : + cc->callback); + + v_return = callback (data1, + g_value_get_uint (param_values + 1), + g_value_peek_pointer (param_values + 2), + g_value_get_uint (param_values + 3), data2); + + gst_value_take_buffer (return_value, v_return); +} + +static void +g_cclosure_marshal_VOID__UINT_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__UINT_BUFFER) (gpointer data1, guint arg_1, + gpointer arg_2, gpointer data2); + register GMarshalFunc_VOID__UINT_BUFFER callback; + register GCClosure *cc = (GCClosure *) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + 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__UINT_BUFFER) (marshal_data ? marshal_data : + cc->callback); + + callback (data1, + g_value_get_uint (param_values + 1), + g_value_peek_pointer (param_values + 2), data2); +} + +static void gst_qtdemux_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); @@ -471,6 +553,64 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass) gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index); gst_tag_register_musicbrainz_tags (); + + /** + * GstQTDemux::cenc-tenc: + * @demux: the demuxer instance + * @track_id: the track identifier + * @tenc: a #GstBuffer containing tenc node + * + * This signal gets emitted whenever a tenc atom is found to allow + * the initialization of an external decrypter. + * + * Since: 0.10.31 + */ + gst_qtdemux_signals[SIGNAL_CENC_TENC] = + g_signal_new ("cenc-tenc", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstQTDemuxClass, cenc_tenc), + NULL, NULL, + g_cclosure_marshal_VOID__UINT_BUFFER, G_TYPE_NONE, 2, + G_TYPE_UINT, GST_TYPE_BUFFER); + + /** + * GstQTDemux::cenc-senc: + * @demux: the demuxer instance + * @track_id: the track identifier + * @senc: a #GstBuffer containing senc node + * + * This signal gets emitted whenever a senc atom is found to allow + * the initialization of an external decrypter. + * + * Since: 0.10.31 + */ + gst_qtdemux_signals[SIGNAL_CENC_SENC] = + g_signal_new ("cenc-senc", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstQTDemuxClass, cenc_senc), + NULL, NULL, + g_cclosure_marshal_VOID__UINT_BUFFER, G_TYPE_NONE, 2, + G_TYPE_UINT, GST_TYPE_BUFFER); + + /** + * GstQTDemux::decrypt: + * @demux: the demuxer instance + * @track_id: the track identifier + * @buffer: a #GstBuffer that has to be decrypted + * @sample_index: the sample index that might be needed for decrypt algorithm + * + * Returns: a #GstBuffer with data decrypted. + * + * This signal gets emitted whenever an encrypted buffer is available to allow + * the implemention of an external decrypter to return a new buffer with + * content decrypted. + * + * Since: 0.10.31 + */ + gst_qtdemux_signals[SIGNAL_DECRYPT] = + g_signal_new ("decrypt", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstQTDemuxClass, decrypt), + NULL, NULL, + g_cclosure_marshal_BUFFER__UINT_BUFFER_UINT, GST_TYPE_BUFFER, 3, + G_TYPE_UINT, GST_TYPE_BUFFER, G_TYPE_UINT); } static void @@ -1854,6 +1994,17 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition) GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + /* When decrypt signal is connected we support demuxing DRM */ + if (g_signal_handler_find (qtdemux, G_SIGNAL_MATCH_ID, + gst_qtdemux_signals[SIGNAL_DECRYPT], 0, NULL, NULL, NULL)) { + qtdemux->supports_drm = TRUE; + GST_INFO_OBJECT (qtdemux, "Support for DRM is enabled"); + } else { + qtdemux->supports_drm = FALSE; + } + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: break; default: @@ -2477,6 +2628,24 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, base_offset = -2; goto next; } + + /* On encrypted streams emit a signal with the senc node */ + if (stream->encrypted) { + GNode *node; + GstBuffer *buf = NULL; + node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_senc); + if (node) { + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = node->data; + GST_BUFFER_SIZE (buf) = GST_READ_UINT32_BE (node->data); + g_signal_emit (qtdemux, gst_qtdemux_signals[SIGNAL_CENC_SENC], 0, + stream->track_id, buf); + gst_buffer_unref (buf); + } + + stream->senc_sample_index = 0; + } + if (G_UNLIKELY (base_offset < -1)) goto lost_offset; /* Track Run node */ @@ -3638,6 +3807,21 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux, { GstFlowReturn ret = GST_FLOW_OK; + if (G_UNLIKELY (stream->encrypted)) { + GstBuffer *dec_buf = NULL; + + GST_DEBUG_OBJECT (qtdemux, "decrypting stream index = %d track index %d", + stream->senc_sample_index, stream->track_id); + /* send the decrypt signal */ + g_signal_emit (qtdemux, gst_qtdemux_signals[SIGNAL_DECRYPT], 0, + stream->track_id, buf, stream->senc_sample_index++, &dec_buf); + + if (dec_buf) { + gst_buffer_unref (buf); + buf = dec_buf; + } + } + if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) { gchar *url; @@ -4791,6 +4975,7 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, qtdemux_parse_container (qtdemux, node, buffer + 16, end); break; } + case FOURCC_enca: case FOURCC_mp4a: case FOURCC_alac: { @@ -4885,6 +5070,7 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, } break; } + case FOURCC_encv: case FOURCC_avc1: { GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer); @@ -6347,6 +6533,126 @@ bad_data: return 0; } +/* called whenever the scheme is cenc */ +static gboolean +qtdemux_parse_cenc (GstQTDemux * qtdemux, QtDemuxStream * stream, + guint32 scheme_version, GNode * schi) +{ + GNode *tenc; + GstBuffer *buf; + + if (scheme_version != 0x00010000) { + GST_WARNING_OBJECT (qtdemux, "Wrong version number %08x", scheme_version); + return FALSE; + } + + /* get the 'tenc' box from the 'schi' */ + if (!(tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc))) { + GST_WARNING_OBJECT (qtdemux, "No tenc found"); + return FALSE; + } + + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = tenc->data; + GST_BUFFER_SIZE (buf) = GST_READ_UINT32_BE (tenc->data); + g_signal_emit (qtdemux, gst_qtdemux_signals[SIGNAL_CENC_TENC], 0, + stream->track_id, buf); + gst_buffer_unref (buf); + + return TRUE; +} + +static void +qtdemux_parse_schm (GstQTDemux * qtdemux, GNode * schm, guint32 * scheme_type, + guint32 * scheme_version) +{ + guint32 flags; + guint32 length; + const gchar *schm_data; + + schm_data = (const gchar *) schm->data; + + length = QT_UINT32 (schm_data); + flags = QT_UINT24 (schm_data + 8); + + *scheme_type = QT_FOURCC (schm_data + 12); + *scheme_version = QT_UINT32 (schm_data + 16); + + GST_LOG_OBJECT (qtdemux, "schm type %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (*scheme_type)); + GST_LOG_OBJECT (qtdemux, "schm version %u", *scheme_version); + + if ((flags & QT_FLAG_CONTAINER) && (length > 20)) { + GST_LOG_OBJECT (qtdemux, "schm uri %.*s", length - 20, schm_data + 20); + } +} + +static gboolean +qtdemux_parse_sinf (GstQTDemux * qtdemux, QtDemuxStream * stream, + GNode * sinf, guint32 * fourcc) +{ + GNode *frma; + GNode *schm; + GNode *schi; + const guint8 *frma_data; + gboolean ret = TRUE; + guint32 scheme_type; + guint32 scheme_version; + + /* now the 'frma' */ + if (!(frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma))) { + GST_WARNING_OBJECT (qtdemux, "No frma found"); + return FALSE; + } + + frma_data = (const guint8 *) frma->data; + *fourcc = QT_FOURCC (frma_data + 8); + + /* get the scheme type box */ + if (!(schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm))) { + GST_WARNING_OBJECT (qtdemux, "No schm found"); + return FALSE; + } + + qtdemux_parse_schm (qtdemux, schm, &scheme_type, &scheme_version); + + /* get the scheme information box */ + if (!(schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi))) { + GST_WARNING_OBJECT (qtdemux, "No schi found"); + return FALSE; + } + + /* parse the data on this box */ + switch (scheme_type) { + case FOURCC_cenc: + ret = qtdemux_parse_cenc (qtdemux, stream, scheme_version, schi); + break; + + default: + GST_WARNING_OBJECT (qtdemux, + "Unsupported scheme type %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (scheme_type)); + return FALSE; + } + + return ret; +} + +static gboolean +qtdemux_parse_encx (GstQTDemux * qtdemux, QtDemuxStream * stream, + GNode * encx, guint32 * fourcc) +{ + GNode *sinf; + + /* now the 'sinf' */ + if (!(sinf = qtdemux_tree_get_child_by_type (encx, FOURCC_sinf))) { + GST_WARNING_OBJECT (qtdemux, "No sinf found"); + return FALSE; + } + + return qtdemux_parse_sinf (qtdemux, stream, sinf, fourcc); +} + /* parse the traks. * With each track we associate a new QtDemuxStream that contains all the info * about the trak. @@ -6509,14 +6815,32 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) goto corrupt_file; GST_LOG_OBJECT (qtdemux, "stsd len: %d", len); - stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4); + fourcc = QT_FOURCC (stsd_data + 16 + 4); GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->fourcc)); + GST_FOURCC_ARGS (fourcc)); - if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) || - ((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0))) + if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi)) goto error_encrypted; + /* get the real fourcc */ + if ((fourcc == FOURCC_encv) || (fourcc == FOURCC_enca)) { + GNode *encx; + + if (!qtdemux->supports_drm) + goto error_encrypted; + + if (!(encx = qtdemux_tree_get_child_by_type (stsd, fourcc))) + goto corrupt_file; + if (!qtdemux_parse_encx (qtdemux, stream, encx, &(stream->fourcc))) + goto corrupt_file; + + stream->encrypted = TRUE; + GST_LOG_OBJECT (qtdemux, "track decrypted format %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (stream->fourcc)); + } else { + stream->fourcc = fourcc; + } + if (stream->subtype == FOURCC_vide) { guint32 w = 0, h = 0; @@ -6546,7 +6870,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) QT_UINT16 (stsd_data + offset + 48)); stream->caps = - qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec); + qtdemux_video_caps (qtdemux, stream, stream->fourcc, stsd_data, &codec); if (codec) { list = gst_tag_list_new (); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, @@ -6577,7 +6901,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (esds) { gst_qtdemux_handle_esds (qtdemux, stream, esds, list); } else { - switch (fourcc) { + switch (stream->fourcc) { case FOURCC_avc1: { gint len = QT_UINT32 (stsd_data) - 0x66; @@ -6674,7 +6998,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) GNode *glbl; GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); + GST_FOURCC_ARGS (stream->fourcc)); /* codec data might be in glbl extension atom */ glbl = mp4v ? @@ -6965,7 +7289,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) GST_INFO_OBJECT (qtdemux, "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, - GST_FOURCC_ARGS (fourcc), stream->caps); + GST_FOURCC_ARGS (stream->fourcc), stream->caps); } else if (stream->subtype == FOURCC_soun) { int version, samplesize; @@ -7003,7 +7327,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) stream->bytes_per_packet = stream->bytes_per_sample; offset = 52; - switch (fourcc) { + switch (stream->fourcc) { /* Yes, these have to be hard-coded */ case FOURCC_MAC6: { @@ -7056,7 +7380,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } if (version == 0x00010000) { - switch (fourcc) { + switch (stream->fourcc) { case FOURCC_twos: case FOURCC_sowt: case FOURCC_raw_: @@ -7108,10 +7432,10 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version); } - stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0, + stream->caps = qtdemux_audio_caps (qtdemux, stream, stream->fourcc, NULL, 0, &codec); - switch (fourcc) { + switch (stream->fourcc) { case FOURCC_in24: { GNode *enda; @@ -7217,7 +7541,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) bitrate, NULL); } - mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a); + mp4a = qtdemux_tree_get_child_by_type (stsd, fourcc); wave = NULL; esds = NULL; if (mp4a) { @@ -7236,7 +7560,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) codec id as the bottom 16 bits - but byte-swapped to store in QT (which is big-endian). */ - if ((fourcc & 0xffff) == (('s' << 8) | 'm')) { + if ((stream->fourcc & 0xffff) == (('s' << 8) | 'm')) { if (len < offset + 20) { GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio"); } else { @@ -7250,7 +7574,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) const guint8 *waveheader; guint32 headerlen; - waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc); + waveheadernode = + qtdemux_tree_get_child_by_type (wavenode, stream->fourcc); if (waveheadernode) { waveheader = (const guint8 *) waveheadernode->data; headerlen = QT_UINT32 (waveheader); @@ -7285,7 +7610,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } else if (esds) { gst_qtdemux_handle_esds (qtdemux, stream, esds, list); } else { - switch (fourcc) { + switch (stream->fourcc) { #if 0 /* FIXME: what is in the chunk? */ case FOURCC_QDMC: @@ -7383,14 +7708,14 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } GST_INFO_OBJECT (qtdemux, "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, - GST_FOURCC_ARGS (fourcc), stream->caps); + GST_FOURCC_ARGS (stream->fourcc), stream->caps); } else if (stream->subtype == FOURCC_strm) { - if (fourcc == FOURCC_rtsp) { + if (stream->fourcc == FOURCC_rtsp) { stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf); } else { GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); + GST_FOURCC_ARGS (stream->fourcc)); goto unknown_stream; } stream->sampled = TRUE; @@ -7401,7 +7726,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) offset = 16; stream->caps = - qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec); + qtdemux_sub_caps (qtdemux, stream, stream->fourcc, stsd_data, &codec); if (codec) { list = gst_tag_list_new (); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, @@ -7411,7 +7736,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } /* hunt for sort-of codec data */ - switch (fourcc) { + switch (stream->fourcc) { case FOURCC_mp4s: { guint len; diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h index f2d839d7e..38a4e9feb 100644 --- a/gst/isomp4/qtdemux.h +++ b/gst/isomp4/qtdemux.h @@ -112,10 +112,16 @@ struct _GstQTDemux { gboolean upstream_seekable; gboolean upstream_size; + + /* DRM is supported only if there's a listener for decrypt signal */ + gboolean supports_drm; }; 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); + GstBuffer* (*decrypt) (GstQTDemux * demux, guint32 track_id, GstBuffer *buff, guint32 sample_index); }; GType gst_qtdemux_get_type (void); diff --git a/gst/isomp4/qtdemux_fourcc.h b/gst/isomp4/qtdemux_fourcc.h index d747825ac..5d55a2e71 100644 --- a/gst/isomp4/qtdemux_fourcc.h +++ b/gst/isomp4/qtdemux_fourcc.h @@ -238,6 +238,17 @@ G_BEGIN_DECLS /* MPEG DASH */ #define FOURCC_tfdt GST_MAKE_FOURCC('t','f','d','t') +#define FOURCC_encv GST_MAKE_FOURCC('e','n','c','v') +#define FOURCC_enca GST_MAKE_FOURCC('e','n','c','a') +#define FOURCC_sinf GST_MAKE_FOURCC('s','i','n','f') +#define FOURCC_schm GST_MAKE_FOURCC('s','c','h','m') +#define FOURCC_schi GST_MAKE_FOURCC('s','c','h','i') + +/* ISO/IEC 23001-7 */ +#define FOURCC_cenc GST_MAKE_FOURCC('c','e','n','c') +#define FOURCC_tenc GST_MAKE_FOURCC('t','e','n','c') +#define FOURCC_senc GST_MAKE_FOURCC('s','e','n','c') + G_END_DECLS #endif /* __GST_QTDEMUX_FOURCC_H__ */ diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c index 65afc8e2a..5acd548fe 100644 --- a/gst/isomp4/qtdemux_types.c +++ b/gst/isomp4/qtdemux_types.c @@ -172,6 +172,15 @@ static const QtNodeType qt_node_types[] = { {FOURCC_ovc1, "ovc1", 0}, {FOURCC_owma, "owma", 0}, {FOURCC_tfdt, "Track fragment decode time", 0, qtdemux_dump_tfdt}, + {FOURCC_frma, "frma", 0}, + {FOURCC_encv, "encv", 0}, + {FOURCC_enca, "enca", 0}, + {FOURCC_sinf, "sinf", QT_FLAG_CONTAINER,}, + {FOURCC_schm, "schm", 0}, + {FOURCC_schi, "schi", QT_FLAG_CONTAINER,}, + {FOURCC_cenc, "cenc", 0}, + {FOURCC_tenc, "tenc", 0}, + {FOURCC_senc, "senc", 0}, {0, "unknown", 0,}, }; |