From c917d65e6df0b5d585f905c7ad78a8a0a44b2cb0 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 20 Oct 2009 17:20:55 +0200 Subject: [PATCH] qtdemux: unpack more information into image/x-j2c caps * gst/qtdemux/qtdemux_fourcc.h: Add new fourccs for use by the mj2 unpacker. * gst/qtdemux/qtdemux.c (qtdemux_parse_trak): Unpack JPEG2000 component mapping and channel definitions from the jp2h header. Will add component-map and channel-definitions elements to the caps if the component maps or channel definitions are nonstandard, where standard order means RGB, 444 packed YUV, or greyscale, with no alpha channel. Fixes #598915. --- gst/qtdemux/qtdemux.c | 124 +++++++++++++++++++++++++++++++++-- gst/qtdemux/qtdemux_fourcc.h | 3 + 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 6387c883f1..fae3743d67 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -4537,9 +4537,15 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } case FOURCC_mjp2: { - GNode *jp2h, *colr, *mjp2, *field, *prefix; + /* see annex I of the jpeg2000 spec */ + GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef; const guint8 *data; guint32 fourcc = 0; + gint ncomp = 0; + guint32 ncomp_map = 0; + gint32 *comp_map = NULL; + guint32 nchan_def = 0; + gint32 *chan_def = NULL; GST_DEBUG_OBJECT (qtdemux, "found mjp2"); /* some required atoms */ @@ -4549,11 +4555,19 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h); if (!jp2h) break; + + /* number of components; redundant with info in codestream, but useful + to a muxer */ + ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr); + if (!ihdr || QT_UINT32 (ihdr->data) != 22) + break; + ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16); + 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 */ + /* extract colour space info */ if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) { switch (QT_UINT32 ((guint8 *) colr->data + 11)) { case 16: @@ -4569,10 +4583,110 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) break; } } + if (!fourcc) + /* colr is required, and only values 16, 17, and 18 are specified, + so error if we have no fourcc */ + break; - if (fourcc) - gst_caps_set_simple (stream->caps, - "fourcc", GST_TYPE_FOURCC, fourcc, NULL); + /* extract component mapping */ + cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap); + if (cmap) { + guint32 cmap_len = 0; + int i; + cmap_len = QT_UINT32 (cmap->data); + if (cmap_len >= 8) { + /* normal box, subtract off header */ + cmap_len -= 8; + /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */ + if (cmap_len % 4 == 0) { + ncomp_map = (cmap_len / 4); + comp_map = g_new0 (gint32, ncomp_map); + for (i = 0; i < ncomp_map; i++) { + guint16 cmp; + guint8 mtyp, pcol; + cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4); + mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2); + pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3); + comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp; + } + } + } + } + /* extract channel definitions */ + cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef); + if (cdef) { + guint32 cdef_len = 0; + int i; + cdef_len = QT_UINT32 (cdef->data); + if (cdef_len >= 10) { + /* normal box, subtract off header and len */ + cdef_len -= 10; + /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */ + if (cdef_len % 6 == 0) { + nchan_def = (cdef_len / 6); + chan_def = g_new0 (gint32, nchan_def); + for (i = 0; i < nchan_def; i++) + chan_def[i] = -1; + for (i = 0; i < nchan_def; i++) { + guint16 cn, typ, asoc; + cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6); + typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2); + asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4); + if (cn < nchan_def) { + switch (typ) { + case 0: + chan_def[cn] = asoc; + break; + case 1: + chan_def[cn] = 0; /* alpha */ + break; + default: + chan_def[cn] = -typ; + } + } + } + } + } + } + + gst_caps_set_simple (stream->caps, + "num-components", G_TYPE_INT, ncomp, NULL); + gst_caps_set_simple (stream->caps, + "fourcc", GST_TYPE_FOURCC, fourcc, NULL); + + if (comp_map) { + GValue arr = { 0, }; + GValue elt = { 0, }; + int i; + g_value_init (&arr, GST_TYPE_ARRAY); + g_value_init (&elt, G_TYPE_INT); + for (i = 0; i < ncomp_map; i++) { + g_value_set_int (&elt, comp_map[i]); + gst_value_array_append_value (&arr, &elt); + } + gst_structure_set_value (gst_caps_get_structure (stream->caps, 0), + "component-map", &arr); + g_value_unset (&elt); + g_value_unset (&arr); + g_free (comp_map); + } + + if (chan_def) { + GValue arr = { 0, }; + GValue elt = { 0, }; + int i; + g_value_init (&arr, GST_TYPE_ARRAY); + g_value_init (&elt, G_TYPE_INT); + for (i = 0; i < nchan_def; i++) { + g_value_set_int (&elt, chan_def[i]); + gst_value_array_append_value (&arr, &elt); + } + gst_structure_set_value (gst_caps_get_structure (stream->caps, 0), + "channel-definitions", &arr); + g_value_unset (&elt); + g_value_unset (&arr); + g_free (chan_def); + } /* some optional atoms */ field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel); diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h index a503941046..952d079697 100644 --- a/gst/qtdemux/qtdemux_fourcc.h +++ b/gst/qtdemux/qtdemux_fourcc.h @@ -164,9 +164,12 @@ G_BEGIN_DECLS /* 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_ihdr GST_MAKE_FOURCC('i','h','d','r') #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') +#define FOURCC_cmap GST_MAKE_FOURCC('c','m','a','p') +#define FOURCC_cdef GST_MAKE_FOURCC('c','d','e','f') /* some buggy hardware's notion of mdhd */ #define FOURCC_mhdr GST_MAKE_FOURCC('m','h','d','r')