mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 08:11:16 +00:00
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
This commit is contained in:
parent
06de494640
commit
92a83e016a
2 changed files with 114 additions and 1 deletions
|
@ -192,6 +192,9 @@ struct _QtDemuxStream
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
guint32 fourcc;
|
guint32 fourcc;
|
||||||
|
|
||||||
|
/* if the stream has a redirect URI in its headers, we store it here */
|
||||||
|
gchar *redirect_uri;
|
||||||
|
|
||||||
/* duration/scale */
|
/* duration/scale */
|
||||||
guint64 duration; /* in timescale */
|
guint64 duration; /* in timescale */
|
||||||
guint32 timescale;
|
guint32 timescale;
|
||||||
|
@ -1679,6 +1682,7 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
|
||||||
g_free (stream->segments);
|
g_free (stream->segments);
|
||||||
if (stream->pending_tags)
|
if (stream->pending_tags)
|
||||||
gst_tag_list_free (stream->pending_tags);
|
gst_tag_list_free (stream->pending_tags);
|
||||||
|
g_free (stream->redirect_uri);
|
||||||
/* free stbl sub-atoms */
|
/* free stbl sub-atoms */
|
||||||
gst_qtdemux_stbl_free (stream);
|
gst_qtdemux_stbl_free (stream);
|
||||||
g_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.
|
/* parse the traks.
|
||||||
* With each track we associate a new QtDemuxStream that contains all the info
|
* With each track we associate a new QtDemuxStream that contains all the info
|
||||||
* about the trak.
|
* about the trak.
|
||||||
|
@ -5659,7 +5755,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
GST_FOURCC_ARGS (fourcc), stream->caps);
|
GST_FOURCC_ARGS (fourcc), stream->caps);
|
||||||
|
|
||||||
} else if (stream->subtype == FOURCC_strm) {
|
} 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_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
|
||||||
GST_FOURCC_ARGS (fourcc));
|
GST_FOURCC_ARGS (fourcc));
|
||||||
goto unknown_stream;
|
goto unknown_stream;
|
||||||
|
@ -6730,6 +6828,20 @@ qtdemux_parse_tree (GstQTDemux * qtdemux)
|
||||||
gst_message_new_tag (GST_OBJECT (qtdemux),
|
gst_message_new_tag (GST_OBJECT (qtdemux),
|
||||||
gst_tag_list_copy (qtdemux->tag_list)));
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ G_BEGIN_DECLS
|
||||||
#define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
|
#define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a')
|
||||||
#define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
|
#define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d')
|
||||||
#define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r')
|
#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_minf GST_MAKE_FOURCC('m','i','n','f')
|
||||||
#define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
|
#define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
|
||||||
#define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
|
#define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
|
||||||
|
|
Loading…
Reference in a new issue