From 9d1c15dbc722268b23dce56f72806ad60a41180c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 14 Aug 2006 10:06:55 +0000 Subject: [PATCH] gst/qtdemux/qtdemux.c: Extract all references/redirections if there is more than one and sort them; also extract mini... Original commit message from CVS: * gst/qtdemux/qtdemux.c: (qtdemux_redirects_sort_func), (qtdemux_process_redirects), (qtdemux_parse_tree): Extract all references/redirections if there is more than one and sort them; also extract minimum required bitrate information if available. (#350399) --- ChangeLog | 8 +++ gst/qtdemux/qtdemux.c | 131 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 129 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7898530fd..86a31ade04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-08-14 Tim-Philipp Müller + + * gst/qtdemux/qtdemux.c: (qtdemux_redirects_sort_func), + (qtdemux_process_redirects), (qtdemux_parse_tree): + Extract all references/redirections if there is more + than one and sort them; also extract minimum required + bitrate information if available. (#350399) + 2006-08-10 Tim-Philipp Müller Patch by: Michal Benes diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index b6f65146a2..6772f9cfbf 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -1963,6 +1963,9 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux, #define FOURCC_rmda GST_MAKE_FOURCC('r','m','d','a') #define FOURCC_rdrf GST_MAKE_FOURCC('r','d','r','f') #define FOURCC__gen GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n') +#define FOURCC_rmdr GST_MAKE_FOURCC('r','m','d','r') +#define FOURCC_rmvc GST_MAKE_FOURCC('r','m','v','c') +#define FOURCC_qtim GST_MAKE_FOURCC('q','t','i','m') static void qtdemux_dump_mvhd (GstQTDemux * qtdemux, void *buffer, int depth); static void qtdemux_dump_tkhd (GstQTDemux * qtdemux, void *buffer, int depth); @@ -2908,6 +2911,86 @@ qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc) static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak); +typedef struct +{ + GstStructure *structure; /* helper for sort function */ + gchar *location; + guint min_req_bitrate; + guint min_req_qt_version; +} GstQtReference; + +static gint +qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b) +{ + GstQtReference *ref_a = (GstQtReference *) a; + GstQtReference *ref_b = (GstQtReference *) b; + + if (ref_b->min_req_qt_version != ref_a->min_req_qt_version) + return ref_b->min_req_qt_version - ref_a->min_req_qt_version; + + /* known bitrates go before unknown; higher bitrates go first */ + return ref_b->min_req_bitrate - ref_a->min_req_bitrate; +} + +static void +qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references) +{ + GstQtReference *best; + GstStructure *s; + GstMessage *msg; + GValue list_val = { 0, }; + GList *l; + + g_assert (references != NULL); + + references = g_list_sort (references, qtdemux_redirects_sort_func); + + best = (GstQtReference *) references->data; + + g_value_init (&list_val, GST_TYPE_LIST); + + for (l = references; l != NULL; l = l->next) { + GstQtReference *ref = (GstQtReference *) l->data; + GValue struct_val = { 0, }; + + ref->structure = gst_structure_new ("redirect", + "new-location", G_TYPE_STRING, ref->location, NULL); + + if (ref->min_req_bitrate > 0) { + gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT, + ref->min_req_bitrate, NULL); + } + + g_value_init (&struct_val, GST_TYPE_STRUCTURE); + g_value_set_boxed (&struct_val, ref->structure); + gst_value_list_append_value (&list_val, &struct_val); + g_value_unset (&struct_val); + /* don't free anything here yet, since we need best->structure below */ + } + + g_assert (best != NULL); + s = gst_structure_copy (best->structure); + + if (g_list_length (references) > 1) { + gst_structure_set_value (s, "locations", &list_val); + } + + g_value_unset (&list_val); + + for (l = references; l != NULL; l = l->next) { + GstQtReference *ref = (GstQtReference *) l->data; + + gst_structure_free (ref->structure); + g_free (ref->location); + g_free (ref); + } + g_list_free (references); + + GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s); + msg = gst_message_new_element (GST_OBJECT (qtdemux), s); + gst_element_post_message (GST_ELEMENT (qtdemux), msg); +} + static void qtdemux_parse_tree (GstQTDemux * qtdemux) { @@ -2921,20 +3004,48 @@ qtdemux_parse_tree (GstQTDemux * qtdemux) rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra); if (rmra) { + GList *redirects = NULL; + rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda); - if (rmda) { + while (rmda) { + GstQtReference ref = { NULL, NULL, 0, 0 }; + GNode *rmdr, *rmvc; + + if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) { + ref.min_req_bitrate = + QTDEMUX_GUINT32_GET ((guint8 *) rmdr->data + 12); + GST_LOG ("data rate atom, required bitrate = %u", + ref.min_req_bitrate); + } + + if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) { + guint32 package = QTDEMUX_FOURCC_GET ((guint8 *) rmvc->data + 12); + guint version = QTDEMUX_GUINT32_GET ((guint8 *) rmvc->data + 16); + guint bitmask = QTDEMUX_GUINT32_GET ((guint8 *) rmvc->data + 20); + guint check_type = QTDEMUX_GUINT16_GET ((guint8 *) rmvc->data + 24); + + GST_LOG ("version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x" + ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version, + bitmask, check_type); + if (package == FOURCC_qtim && check_type == 0) { + ref.min_req_qt_version = version; + } + } + rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf); if (rdrf) { - GstStructure *s; - GstMessage *msg; - - GST_LOG ("New location: %s", (char *) rdrf->data + 20); - s = gst_structure_new ("redirect", "new-location", G_TYPE_STRING, - (char *) rdrf->data + 20, NULL); - msg = gst_message_new_element (GST_OBJECT (qtdemux), s); - gst_element_post_message (GST_ELEMENT (qtdemux), msg); - return; + ref.location = g_strdup ((gchar *) rdrf->data + 20); + GST_LOG ("New location: %s", ref.location); + redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref))); } + + /* look for others */ + rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda); + } + + if (redirects != NULL) { + qtdemux_process_redirects (qtdemux, redirects); + return; } }