diff --git a/ChangeLog b/ChangeLog index d7a23590b4..d3837226ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-09-03 Mark Nauwelaerts + + * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state), + (gst_qtdemux_loop_state_header), (qtdemux_parse_node), + (qtdemux_parse_trak), (qtdemux_video_caps): + * gst/qtdemux/qtdemux.h: + * gst/qtdemux/qtdemux_fourcc.h: + * gst/qtdemux/qtdemux_types.c: + Add support for video/mj2 mime-type and its additional atoms/boxes. + Fixes #550646. + 2008-09-03 Stefan Kost * gst/debug/gsttaginject.c: diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 88d73ab68a..cb43553568 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -259,7 +259,8 @@ static GstStaticPadTemplate gst_qtdemux_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/quicktime; audio/x-m4a; application/x-3gp") + GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; " + "application/x-3gp") ); static GstStaticPadTemplate gst_qtdemux_videosrc_template = @@ -1032,6 +1033,7 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition) g_free (stream->segments); g_free (stream); } + qtdemux->major_brand = 0; qtdemux->n_streams = 0; qtdemux->n_video_streams = 0; qtdemux->n_audio_streams = 0; @@ -1131,6 +1133,25 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) qtdemux->state); break; } + case FOURCC_ftyp: + { + GstBuffer *ftyp; + + /* extract major brand; might come in handy for ISO vs QT issues */ + ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &ftyp); + if (ret != GST_FLOW_OK) + goto beach; + cur_offset += length; + qtdemux->offset += length; + /* only consider at least a sufficiently complete ftyp atom */ + if (length >= 20) { + qtdemux->major_brand = QT_FOURCC (GST_BUFFER_DATA (ftyp) + 8); + GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (qtdemux->major_brand)); + } + gst_buffer_unref (ftyp); + break; + } default: { GST_LOG_OBJECT (qtdemux, @@ -2627,6 +2648,11 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer, } break; } + case FOURCC_mjp2: + { + qtdemux_parse_container (qtdemux, node, buffer + 86, end); + break; + } case FOURCC_meta: { GST_DEBUG_OBJECT (qtdemux, "parsing meta atom"); @@ -3256,8 +3282,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia))) goto corrupt_file; - if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) - goto corrupt_file; + if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) { + /* be nice for some crooked mjp2 files that use mhdr for mdhd */ + if (qtdemux->major_brand != FOURCC_mjp2 || + !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr))) + goto corrupt_file; + } version = QT_UINT32 ((guint8 *) mdhd->data + 8); GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version); @@ -3391,6 +3421,75 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } break; } + case FOURCC_mjp2: + { + GNode *jp2h, *colr, *mjp2, *field, *prefix; + const guint8 *data; + guint32 fourcc = 0; + + GST_DEBUG_OBJECT (qtdemux, "found mjp2"); + /* some required atoms */ + mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2); + if (!mjp2) + break; + jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h); + if (!jp2h) + break; + colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr); + if (!colr) + break; + GST_DEBUG_OBJECT (qtdemux, "found colr"); + /* try to extract colour space info */ + if (QT_UINT8 (colr->data + 8) == 1) { + switch (QT_UINT32 (colr->data + 11)) { + case 16: + fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B'); + break; + case 17: + fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y'); + break; + case 18: + fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V'); + break; + default: + break; + } + } + + if (fourcc) + gst_caps_set_simple (stream->caps, + "fourcc", GST_TYPE_FOURCC, fourcc, NULL); + + /* some optional atoms */ + field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel); + prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x); + + /* indicate possible fields in caps */ + if (field) { + data = field->data + 8; + if (*data != 1) + gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT, + (gint) * data, NULL); + } + /* add codec_data if provided */ + if (prefix) { + GstBuffer *buf; + gint len; + + GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd"); + data = prefix->data; + len = QT_UINT32 (data); + if (len > 0x8) { + len -= 0x8; + buf = gst_buffer_new_and_alloc (len); + memcpy (GST_BUFFER_DATA (buf), data + 8, len); + gst_caps_set_simple (stream->caps, + "codec_data", GST_TYPE_BUFFER, buf, NULL); + gst_buffer_unref (buf); + } + } + break; + } case FOURCC_SVQ3: case FOURCC_VP31: { @@ -3611,6 +3710,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) case FOURCC_QDMC: { gint len = QT_UINT32 (stsd_data); + /* seems to be always = 116 = 0x74 */ break; } @@ -4430,6 +4530,12 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, _codec ("Motion-JPEG format B"); caps = gst_caps_from_string ("video/x-mjpeg-b"); break; + case GST_MAKE_FOURCC ('m', 'j', 'p', '2'): + _codec ("JPEG-2000"); + /* override to what it should be according to spec, avoid palette_data */ + stream->bits_per_sample = 24; + caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL); + break; case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'): _codec ("Sorensen video v.3"); caps = gst_caps_from_string ("video/x-svq, " "svqversion = (int) 3"); diff --git a/gst/qtdemux/qtdemux.h b/gst/qtdemux/qtdemux.h index 984f26dcb9..c887df7cd0 100644 --- a/gst/qtdemux/qtdemux.h +++ b/gst/qtdemux/qtdemux.h @@ -59,6 +59,7 @@ struct _GstQTDemux { gint n_video_streams; gint n_audio_streams; + guint major_brand; GNode *moov_node; GNode *moov_node_compressed; diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h index 96ee218e50..a030f1b626 100644 --- a/gst/qtdemux/qtdemux_fourcc.h +++ b/gst/qtdemux/qtdemux_fourcc.h @@ -24,6 +24,7 @@ G_BEGIN_DECLS +#define FOURCC_ftyp GST_MAKE_FOURCC('f','t','y','p') #define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v') #define FOURCC_mvhd GST_MAKE_FOURCC('m','v','h','d') #define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p') @@ -133,6 +134,15 @@ G_BEGIN_DECLS #define FOURCC_keyw GST_MAKE_FOURCC('k','e','y','w') #define FOURCC_kywd GST_MAKE_FOURCC('k','y','w','d') +/* ISO Motion JPEG 2000 fourcc */ +#define FOURCC_mjp2 GST_MAKE_FOURCC('m','j','p','2') +#define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h') +#define FOURCC_colr GST_MAKE_FOURCC('c','o','l','r') +#define FOURCC_fiel GST_MAKE_FOURCC('f','i','e','l') +#define FOURCC_jp2x GST_MAKE_FOURCC('j','p','2','x') +/* some buggy hardware's notion of mdhd */ +#define FOURCC_mhdr GST_MAKE_FOURCC('m','h','d','r') + /* Xiph fourcc */ #define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h') #define FOURCC_XdxT GST_MAKE_FOURCC('X','d','x','T') diff --git a/gst/qtdemux/qtdemux_types.c b/gst/qtdemux/qtdemux_types.c index 7e78077859..5a1afed993 100644 --- a/gst/qtdemux/qtdemux_types.c +++ b/gst/qtdemux/qtdemux_types.c @@ -78,6 +78,12 @@ static const QtNodeType qt_node_types[] = { {FOURCC_hint, "hint", 0,}, {FOURCC_mp4a, "mp4a", 0,}, {FOURCC_mp4v, "mp4v", 0,}, + {FOURCC_mjp2, "mjp2", 0,}, + {FOURCC_mhdr, "mhdr", QT_FLAG_CONTAINER,}, + {FOURCC_jp2h, "jp2h", QT_FLAG_CONTAINER,}, + {FOURCC_colr, "colr", 0,}, + {FOURCC_fiel, "fiel", 0,}, + {FOURCC_jp2x, "jp2x", 0,}, {FOURCC_wave, "wave", QT_FLAG_CONTAINER}, {FOURCC_appl, "appl", QT_FLAG_CONTAINER}, {FOURCC_esds, "esds", 0},