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.
This commit is contained in:
Andy Wingo 2009-10-20 17:20:55 +02:00
parent 3503cfa456
commit c917d65e6d
2 changed files with 122 additions and 5 deletions

View file

@ -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);

View file

@ -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')