qtdemux: add fragmented mp4 fourccs

Adds fourcc's for tfra, tfhd, trun, sdtp, trex, mehd and
their dumps

https://bugzilla.gnome.org/show_bug.cgi?id=596321
This commit is contained in:
Marc-André Lureau 2010-03-11 15:34:49 +01:00 committed by Mark Nauwelaerts
parent c9b866a994
commit e7a1c32a4f
6 changed files with 327 additions and 1 deletions

View file

@ -92,6 +92,28 @@ qt_atom_parser_get_offset_unchecked (GstByteReader * parser, guint off_size)
} }
} }
/* size must be from 1 to 4 */
static inline guint32
qt_atom_parser_get_uint_with_size_unchecked (GstByteReader * parser,
guint size)
{
switch (size) {
case 1:
return gst_byte_reader_get_uint8_unchecked (parser);
case 2:
return gst_byte_reader_get_uint16_be_unchecked (parser);
case 3:
return gst_byte_reader_get_uint24_be_unchecked (parser);
case 4:
return gst_byte_reader_get_uint32_be_unchecked (parser);
default:
g_assert_not_reached ();
gst_byte_reader_skip_unchecked (parser, size);
break;
}
return 0;
}
static inline gboolean static inline gboolean
qt_atom_parser_get_fourcc (GstByteReader * parser, guint32 * fourcc) qt_atom_parser_get_fourcc (GstByteReader * parser, guint32 * fourcc)
{ {

View file

@ -509,6 +509,243 @@ qtdemux_dump_cmvd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
return TRUE; return TRUE;
} }
gboolean
qtdemux_dump_mfro (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
if (!qt_atom_parser_has_remaining (data, 4))
return FALSE;
GST_LOG ("%*s size: %d", depth, "", GET_UINT32 (data));
return TRUE;
}
gboolean
qtdemux_dump_tfra (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint64 time = 0, moof_offset = 0;
guint32 len = 0, num_entries = 0, ver_flags, track_id, i;
guint value_size, traf_size, trun_size, sample_size;
if (!gst_byte_reader_get_uint32_be (data, &ver_flags))
return FALSE;
GST_LOG ("%*s version/flags: %08x", depth, "", ver_flags);
if (!gst_byte_reader_get_uint32_be (data, &track_id) ||
gst_byte_reader_get_uint32_be (data, &len) ||
gst_byte_reader_get_uint32_be (data, &num_entries))
return FALSE;
GST_LOG ("%*s track ID: %u", depth, "", track_id);
GST_LOG ("%*s length: 0x%x", depth, "", len);
GST_LOG ("%*s n entries: %u", depth, "", num_entries);
value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
sample_size = (len & 3) + 1;
trun_size = ((len & 12) >> 2) + 1;
traf_size = ((len & 48) >> 4) + 1;
if (!qt_atom_parser_has_chunks (data, num_entries,
value_size + value_size + traf_size + trun_size + sample_size))
return FALSE;
for (i = 0; i < num_entries; i++) {
qt_atom_parser_get_offset (data, value_size, &time);
qt_atom_parser_get_offset (data, value_size, &moof_offset);
GST_LOG ("%*s time: %" G_GUINT64_FORMAT, depth, "", time);
GST_LOG ("%*s moof_offset: %" G_GUINT64_FORMAT,
depth, "", moof_offset);
GST_LOG ("%*s traf_number: %u", depth, "",
qt_atom_parser_get_uint_with_size_unchecked (data, traf_size));
GST_LOG ("%*s trun_number: %u", depth, "",
qt_atom_parser_get_uint_with_size_unchecked (data, trun_size));
GST_LOG ("%*s sample_number: %u", depth, "",
qt_atom_parser_get_uint_with_size_unchecked (data, sample_size));
}
return TRUE;
}
gboolean
qtdemux_dump_tfhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint32 flags, n, track_id;
guint64 base_data_offset;
if (!gst_byte_reader_skip (data, 1) ||
!gst_byte_reader_get_uint24_be (data, &flags))
return FALSE;
GST_LOG ("%*s flags: %08x", depth, "", flags);
if (!gst_byte_reader_get_uint32_be (data, &track_id))
return FALSE;
GST_LOG ("%*s track_id: %u", depth, "", track_id);
if (flags & TF_BASE_DATA_OFFSET) {
if (!gst_byte_reader_get_uint64_be (data, &base_data_offset))
return FALSE;
GST_LOG ("%*s base-data-offset: %" G_GUINT64_FORMAT,
depth, "", base_data_offset);
}
if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
if (!gst_byte_reader_get_uint32_be (data, &n))
return FALSE;
GST_LOG ("%*s sample-description-index: %u", depth, "", n);
}
if (flags & TF_DEFAULT_SAMPLE_DURATION) {
if (!gst_byte_reader_get_uint32_be (data, &n))
return FALSE;
GST_LOG ("%*s default-sample-duration: %u", depth, "", n);
}
if (flags & TF_DEFAULT_SAMPLE_SIZE) {
if (!gst_byte_reader_get_uint32_be (data, &n))
return FALSE;
GST_LOG ("%*s default-sample-size: %u", depth, "", n);
}
if (flags & TF_DEFAULT_SAMPLE_FLAGS) {
if (!gst_byte_reader_get_uint32_be (data, &n))
return FALSE;
GST_LOG ("%*s default-sample-flags: %u", depth, "", n);
}
GST_LOG ("%*s duration-is-empty: %s", depth, "",
flags & TF_DURATION_IS_EMPTY ? "yes" : "no");
return TRUE;
}
gboolean
qtdemux_dump_trun (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint32 flags, samples_count, data_offset, first_sample_flags;
guint32 sample_duration, sample_size, sample_flags, composition_time_offsets;
int i = 0;
if (!gst_byte_reader_skip (data, 1) ||
!gst_byte_reader_get_uint24_be (data, &flags))
return FALSE;
GST_LOG ("%*s flags: %08x", depth, "", flags);
if (!gst_byte_reader_get_uint32_be (data, &samples_count))
return FALSE;
GST_LOG ("%*s samples_count: %u", depth, "", samples_count);
if (flags & TR_DATA_OFFSET) {
if (!gst_byte_reader_get_uint32_be (data, &data_offset))
return FALSE;
GST_LOG ("%*s data-offset: %u", depth, "", data_offset);
}
if (flags & TR_FIRST_SAMPLE_FLAGS) {
if (!gst_byte_reader_get_uint32_be (data, &first_sample_flags))
return FALSE;
GST_LOG ("%*s first-sample-flags: %u", depth, "", first_sample_flags);
}
for (i = 0; i < samples_count; i++) {
if (flags & TR_SAMPLE_DURATION) {
if (!gst_byte_reader_get_uint32_be (data, &sample_duration))
return FALSE;
GST_LOG ("%*s sample-duration: %u", depth, "", sample_duration);
}
if (flags & TR_SAMPLE_SIZE) {
if (!gst_byte_reader_get_uint32_be (data, &sample_size))
return FALSE;
GST_LOG ("%*s sample-size: %u", depth, "", sample_size);
}
if (flags & TR_SAMPLE_FLAGS) {
if (!gst_byte_reader_get_uint32_be (data, &sample_flags))
return FALSE;
GST_LOG ("%*s sample-flags: %u", depth, "", sample_flags);
}
if (flags & TR_COMPOSITION_TIME_OFFSETS) {
if (!gst_byte_reader_get_uint32_be (data, &composition_time_offsets))
return FALSE;
GST_LOG ("%*s composition_time_offsets: %u", depth, "",
composition_time_offsets);
}
}
return TRUE;
}
gboolean
qtdemux_dump_trex (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
if (!qt_atom_parser_has_remaining (data, 4 + 4 + 4 + 4 + 4 + 4))
return FALSE;
GST_LOG ("%*s version/flags: %08x", depth, "", GET_UINT32 (data));
GST_LOG ("%*s track ID: %08x", depth, "", GET_UINT32 (data));
GST_LOG ("%*s default sample desc. index: %08x", depth, "",
GET_UINT32 (data));
GST_LOG ("%*s default sample duration: %08x", depth, "",
GET_UINT32 (data));
GST_LOG ("%*s default sample size: %08x", depth, "",
GET_UINT32 (data));
GST_LOG ("%*s default sample flags: %08x", depth, "",
GET_UINT32 (data));
return TRUE;
}
gboolean
qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint32 version;
guint64 fragment_duration;
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, &fragment_duration)) {
GST_LOG ("%*s fragment duration: %" G_GUINT64_FORMAT,
depth, "", fragment_duration);
return TRUE;
}
return FALSE;
}
gboolean
qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{
guint32 version;
guint8 val;
guint i = 1;
version = GET_UINT32 (data);
GST_LOG ("%*s version/flags: %08x", depth, "", version);
/* the sample_count is specified in the stsz or stz2 box.
* the information for a sample is stored in a single byte,
* so we read until there are no remaining bytes */
while (qt_atom_parser_has_remaining (data, 1)) {
val = GET_UINT8 (data);
GST_LOG ("%*s sample number: %d", depth, "", i);
GST_LOG ("%*s sample_depends_on: %d", depth, "",
((guint16) (val)) & 0x3);
GST_LOG ("%*s sample_is_depended_on: %d", depth, "",
((guint16) (val >> 2)) & 0x3);
GST_LOG ("%*s sample_has_redundancy: %d", depth, "",
((guint16) (val >> 4)) & 0x3);
++i;
}
return TRUE;
}
gboolean gboolean
qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth) qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth)
{ {

View file

@ -61,6 +61,20 @@ gboolean qtdemux_dump_cmvd (GstQTDemux * qtdemux, GstByteReader * data,
int depth); int depth);
gboolean qtdemux_dump_ctts (GstQTDemux * qtdemux, GstByteReader * data, gboolean qtdemux_dump_ctts (GstQTDemux * qtdemux, GstByteReader * data,
int depth); int depth);
gboolean qtdemux_dump_mfro (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_tfra (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_tfhd (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_trun (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_trex (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data,
int depth);
gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
int depth); int depth);

View file

@ -209,6 +209,20 @@ G_BEGIN_DECLS
#define FOURCC_XMP_ GST_MAKE_FOURCC('X','M','P','_') #define FOURCC_XMP_ GST_MAKE_FOURCC('X','M','P','_')
#define FOURCC_uuid GST_MAKE_FOURCC('u','u','i','d') #define FOURCC_uuid GST_MAKE_FOURCC('u','u','i','d')
/* Fragmented MP4 */
#define FOURCC_mehd GST_MAKE_FOURCC('m','e','h','d')
#define FOURCC_mfhd GST_MAKE_FOURCC('m','f','h','d')
#define FOURCC_mfra GST_MAKE_FOURCC('m','f','r','a')
#define FOURCC_mfro GST_MAKE_FOURCC('m','f','r','o')
#define FOURCC_moof GST_MAKE_FOURCC('m','o','o','f')
#define FOURCC_mvex GST_MAKE_FOURCC('m','v','e','x')
#define FOURCC_sdtp GST_MAKE_FOURCC('s','d','t','p')
#define FOURCC_tfhd GST_MAKE_FOURCC('t','f','h','d')
#define FOURCC_tfra GST_MAKE_FOURCC('t','f','r','a')
#define FOURCC_traf GST_MAKE_FOURCC('t','r','a','f')
#define FOURCC_trex GST_MAKE_FOURCC('t','r','e','x')
#define FOURCC_trun GST_MAKE_FOURCC('t','r','u','n')
G_END_DECLS G_END_DECLS
#endif /* __GST_QTDEMUX_FOURCC_H__ */ #endif /* __GST_QTDEMUX_FOURCC_H__ */

View file

@ -150,6 +150,25 @@ static const QtNodeType qt_node_types[] = {
{FOURCC_XdxT, "XdxT", 0}, {FOURCC_XdxT, "XdxT", 0},
{FOURCC_loci, "loci", 0}, {FOURCC_loci, "loci", 0},
{FOURCC_clsf, "clsf", 0}, {FOURCC_clsf, "clsf", 0},
{FOURCC_mfra, "movie fragment random access",
QT_FLAG_CONTAINER,},
{FOURCC_tfra, "track fragment random access", 0,
qtdemux_dump_tfra},
{FOURCC_mfro, "movie fragment random access offset", 0,
qtdemux_dump_mfro},
{FOURCC_moof, "movie fragment", QT_FLAG_CONTAINER,},
{FOURCC_mfhd, "movie fragment header", 0,},
{FOURCC_traf, "track fragment", QT_FLAG_CONTAINER,},
{FOURCC_tfhd, "track fragment header", 0,
qtdemux_dump_tfhd},
{FOURCC_sdtp, "independent and disposable samples", 0,
qtdemux_dump_sdtp},
{FOURCC_trun, "track fragment run", 0, qtdemux_dump_trun},
{FOURCC_mdat, "moovie data", 0, qtdemux_dump_unknown},
{FOURCC_trex, "moovie data", 0, qtdemux_dump_trex},
{FOURCC_mvex, "mvex", QT_FLAG_CONTAINER,},
{FOURCC_mehd, "movie extends header", 0,
qtdemux_dump_mehd},
{0, "unknown", 0,}, {0, "unknown", 0,},
}; };

View file

@ -55,6 +55,26 @@ struct _QtNodeType {
QtDumpFunc dump; QtDumpFunc dump;
}; };
enum TfFlags
{
TF_BASE_DATA_OFFSET = 0x000001, /* base-data-offset-present */
TF_SAMPLE_DESCRIPTION_INDEX = 0x000002, /* sample-description-index-present */
TF_DEFAULT_SAMPLE_DURATION = 0x000008, /* default-sample-duration-present */
TF_DEFAULT_SAMPLE_SIZE = 0x000010, /* default-sample-size-present */
TF_DEFAULT_SAMPLE_FLAGS = 0x000020, /* default-sample-flags-present */
TF_DURATION_IS_EMPTY = 0x100000 /* sample-composition-time-offsets-presents */
};
enum TrFlags
{
TR_DATA_OFFSET = 0x000001, /* data-offset-present */
TR_FIRST_SAMPLE_FLAGS = 0x000004, /* first-sample-flags-present */
TR_SAMPLE_DURATION = 0x000100, /* sample-duration-present */
TR_SAMPLE_SIZE = 0x000200, /* sample-size-present */
TR_SAMPLE_FLAGS = 0x000400, /* sample-flags-present */
TR_COMPOSITION_TIME_OFFSETS = 0x000800 /* sample-composition-time-offsets-presents */
};
const QtNodeType *qtdemux_type_get (guint32 fourcc); const QtNodeType *qtdemux_type_get (guint32 fourcc);
G_END_DECLS G_END_DECLS