[gst-cvs] gst-plugins-good: qtdemux: Handle another kind of redirect trak
Thiago Sousa Santos
thiagoss at kemper.freedesktop.org
Fri Jan 15 08:45:09 PST 2010
Module: gst-plugins-good
Branch: master
Commit: 92a83e016aa0824549a8e913f8bfa8ee105b0a44
URL: http://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=92a83e016aa0824549a8e913f8bfa8ee105b0a44
Author: Thiago Santos <thiago.sousa.santos at collabora.co.uk>
Date: Thu Jan 14 17:11:13 2010 -0300
qtdemux: Handle another kind of redirect trak
Some traks might contain a redirect rtsp uri inside
hndl atom (which is a dref atom entry). This commit makes qtdemux
post a message when it finds one of these traks and there are
no other traks.
Fixes #597497
---
gst/qtdemux/qtdemux.c | 114 +++++++++++++++++++++++++++++++++++++++++-
gst/qtdemux/qtdemux_fourcc.h | 1 +
2 files changed, 114 insertions(+), 1 deletions(-)
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c
index da86c72..469145c 100644
--- a/gst/qtdemux/qtdemux.c
+++ b/gst/qtdemux/qtdemux.c
@@ -192,6 +192,9 @@ struct _QtDemuxStream
GstCaps *caps;
guint32 fourcc;
+ /* if the stream has a redirect URI in its headers, we store it here */
+ gchar *redirect_uri;
+
/* duration/scale */
guint64 duration; /* in timescale */
guint32 timescale;
@@ -1679,6 +1682,7 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
g_free (stream->segments);
if (stream->pending_tags)
gst_tag_list_free (stream->pending_tags);
+ g_free (stream->redirect_uri);
/* free stbl sub-atoms */
gst_qtdemux_stbl_free (stream);
g_free (stream);
@@ -4854,6 +4858,98 @@ end:
}
}
+static gchar *
+qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
+{
+ GNode *hndl;
+ GNode *dinf;
+ GstByteReader dref;
+ gchar *uri = NULL;
+
+ /*
+ * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
+ * atom that might contain a 'data' atom with the rtsp uri.
+ * This case was reported in bug #597497, some info about
+ * the hndl atom can be found in TN1195
+ */
+ dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
+ GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
+
+ if (dinf) {
+ guint32 dref_num_entries;
+ if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
+ gst_byte_reader_skip (&dref, 4) &&
+ gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
+ gint i;
+ hndl = NULL;
+
+ /* search dref entries for hndl atom */
+ for (i = 0; i < dref_num_entries; i++) {
+ guint32 size, type;
+ guint8 string_len;
+ if (gst_byte_reader_get_uint32_be (&dref, &size) &&
+ qt_atom_parser_get_fourcc (&dref, &type)) {
+ if (type == FOURCC_hndl) {
+ GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
+
+ /* skip data reference handle bytes and the
+ * following pascal string and some extra 4
+ * bytes I have no idea what are */
+ if (!gst_byte_reader_skip (&dref, 4) ||
+ !gst_byte_reader_get_uint8 (&dref, &string_len) ||
+ !gst_byte_reader_skip (&dref, string_len + 4)) {
+ GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
+ break;
+ }
+
+ /* iterate over the atoms to find the data atom */
+ while (gst_byte_reader_get_remaining (&dref) >= 8) {
+ guint32 atom_size;
+ guint32 atom_type;
+
+ if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
+ qt_atom_parser_get_fourcc (&dref, &atom_type)) {
+ if (atom_type == FOURCC_data) {
+ const guint8 *uri_aux = NULL;
+
+ /* found the data atom that might contain the rtsp uri */
+ GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
+ "hndl atom, interpreting it as an URI");
+ if (gst_byte_reader_peek_data (&dref, atom_size - 8,
+ &uri_aux)) {
+ if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
+ uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
+ else
+ GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
+ "didn't contain a rtsp address");
+ } else {
+ GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
+ "atom contents");
+ }
+ break;
+ }
+ /* skipping to the next entry */
+ gst_byte_reader_skip (&dref, atom_size - 8);
+ } else {
+ GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
+ "atom header");
+ break;
+ }
+ }
+ break;
+ }
+ /* skip to the next entry */
+ gst_byte_reader_skip (&dref, size - 8);
+ } else {
+ GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
+ }
+ }
+ GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
+ }
+ }
+ return uri;
+}
+
/* parse the traks.
* With each track we associate a new QtDemuxStream that contains all the info
* about the trak.
@@ -5659,7 +5755,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
GST_FOURCC_ARGS (fourcc), stream->caps);
} else if (stream->subtype == FOURCC_strm) {
- if (fourcc != FOURCC_rtsp) {
+ if (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));
goto unknown_stream;
@@ -6730,6 +6828,20 @@ qtdemux_parse_tree (GstQTDemux * qtdemux)
gst_message_new_tag (GST_OBJECT (qtdemux),
gst_tag_list_copy (qtdemux->tag_list)));
+ /* check if we should post a redirect in case there is a single trak
+ * and it is a redirecting trak */
+ if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
+ GstMessage *m;
+ GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
+ "a external content");
+ m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
+ gst_structure_new ("redirect",
+ "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
+ NULL));
+ gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
+ qtdemux->posted_redirect = TRUE;
+ }
+
return TRUE;
}
diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h
index 3528383..57a2e63 100644
--- a/gst/qtdemux/qtdemux_fourcc.h
+++ b/gst/qtdemux/qtdemux_fourcc.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
#define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
#define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
#define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r')
+#define FOURCC_hndl GST_MAKE_FOURCC('h','n','d','l')
#define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f')
#define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
#define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
More information about the Gstreamer-commits
mailing list