summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Corvoysier <david.corvoysier@orange.com>2012-07-03 17:50:24 +0200
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2012-08-28 16:33:07 +0200
commitfa657ff5715a0211870b2e95c8f2c1b0d7347d21 (patch)
treeec41734972731010b2eecbdf9e472716d901c1c7
parent0ef54f19b4720aca0b5aae1e728ef9842ed2c7a8 (diff)
isomp4: add DASH tfdt box support
MPEG DASH has defined a set of new boxes to specify duration, indexes and offsets of ISOBMFF fragments. The Track Fragment Base Media Decode Time (tfdt) Box can in particular be included inside a traf box to specify the absolute decode time, measured on the media timeline, of the first sample in decode order in the track fragment. This information can be used by the isomp4 demux to find out the current position of an MP4 fragment in the timeline. This patch adds code to isomp4 to: - parse the tfdt box - adjust the time/position member of the new segment sent when playback starts Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677535
-rw-r--r--gst/isomp4/qtdemux.c52
-rw-r--r--gst/isomp4/qtdemux_dump.c22
-rw-r--r--gst/isomp4/qtdemux_dump.h2
-rw-r--r--gst/isomp4/qtdemux_fourcc.h3
-rw-r--r--gst/isomp4/qtdemux_types.c1
5 files changed, 78 insertions, 2 deletions
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
index eaa51d46c..66099697f 100644
--- a/gst/isomp4/qtdemux.c
+++ b/gst/isomp4/qtdemux.c
@@ -2389,11 +2389,43 @@ unknown_stream:
}
static gboolean
+qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
+ guint64 * decode_time)
+{
+ guint32 version = 0;
+
+ if (!gst_byte_reader_get_uint32_be (br, &version))
+ return FALSE;
+
+ version >>= 24;
+ if (version == 1) {
+ if (!gst_byte_reader_get_uint64_be (br, decode_time))
+ goto failed;
+ } else {
+ guint32 dec_time = 0;
+ if (!gst_byte_reader_get_uint32_be (br, &dec_time))
+ goto failed;
+ *decode_time = dec_time;
+ }
+
+ GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
+ *decode_time);
+
+ return TRUE;
+
+failed:
+ {
+ GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
+ return FALSE;
+ }
+}
+
+static gboolean
qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
guint64 moof_offset, QtDemuxStream * stream)
{
- GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
- GstByteReader trun_data, tfhd_data;
+ GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node;
+ GstByteReader trun_data, tfhd_data, tfdt_data;
guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
gint64 base_offset, running_offset;
@@ -2416,6 +2448,22 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
&ds_size, &ds_flags, &base_offset))
goto missing_tfhd;
+ tfdt_node =
+ qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
+ &tfdt_data);
+ if (tfdt_node) {
+ guint64 decode_time = 0;
+ qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
+ /* If there is a new segment pending, update the time/position */
+ if (qtdemux->pending_newsegment) {
+ gst_event_replace (&qtdemux->pending_newsegment,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
+ 0, GST_CLOCK_TIME_NONE,
+ gst_util_uint64_scale (decode_time,
+ GST_SECOND, stream->timescale)));
+ }
+ }
+
if (G_UNLIKELY (!stream)) {
/* we lost track of offset, we'll need to regain it,
* but can delay complaining until later or avoid doing so altogether */
diff --git a/gst/isomp4/qtdemux_dump.c b/gst/isomp4/qtdemux_dump.c
index fa6676758..e8dd57e0a 100644
--- a/gst/isomp4/qtdemux_dump.c
+++ b/gst/isomp4/qtdemux_dump.c
@@ -721,6 +721,28 @@ qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
}
gboolean
+qtdemux_dump_tfdt (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+ guint32 version = 0;
+ guint64 decode_time;
+ guint value_size;
+
+ if (!gst_byte_reader_get_uint32_be (data, &version))
+ return FALSE;
+
+ GST_LOG ("%*s version/flags: %08x", depth, "", version);
+
+ value_size = ((version >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+ if (qt_atom_parser_get_offset (data, value_size, &decode_time)) {
+ GST_LOG ("%*s Track fragment decode time: %" G_GUINT64_FORMAT,
+ depth, "", decode_time);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint32 version;
diff --git a/gst/isomp4/qtdemux_dump.h b/gst/isomp4/qtdemux_dump.h
index 9bb1f95d4..d5486eebf 100644
--- a/gst/isomp4/qtdemux_dump.h
+++ b/gst/isomp4/qtdemux_dump.h
@@ -75,6 +75,8 @@ gboolean qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
+gboolean qtdemux_dump_tfdt (GstQTDemux * qtdemux, GstByteReader * data,
+ int depth);
gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
diff --git a/gst/isomp4/qtdemux_fourcc.h b/gst/isomp4/qtdemux_fourcc.h
index 6666a94e5..f2a349291 100644
--- a/gst/isomp4/qtdemux_fourcc.h
+++ b/gst/isomp4/qtdemux_fourcc.h
@@ -230,6 +230,9 @@ G_BEGIN_DECLS
#define FOURCC_ovc1 GST_MAKE_FOURCC('o','v','c','1')
#define FOURCC_owma GST_MAKE_FOURCC('o','w','m','a')
+/* MPEG DASH */
+#define FOURCC_tfdt GST_MAKE_FOURCC('t','f','d','t')
+
G_END_DECLS
#endif /* __GST_QTDEMUX_FOURCC_H__ */
diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c
index 38da35b3d..65afc8e2a 100644
--- a/gst/isomp4/qtdemux_types.c
+++ b/gst/isomp4/qtdemux_types.c
@@ -171,6 +171,7 @@ static const QtNodeType qt_node_types[] = {
qtdemux_dump_mehd},
{FOURCC_ovc1, "ovc1", 0},
{FOURCC_owma, "owma", 0},
+ {FOURCC_tfdt, "Track fragment decode time", 0, qtdemux_dump_tfdt},
{0, "unknown", 0,},
};