qtdemux: extract the palette from stsd

Sometimes a palette is inside the stsd, extract it instead of always using
the default one
This commit is contained in:
Wim Taymans 2013-07-17 15:10:00 +02:00
parent 9f73447229
commit 4c97701650

View file

@ -5572,10 +5572,6 @@ gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
}
if (stream->caps) {
gboolean gray;
gint depth, palette_count;
const guint32 *palette_data = NULL;
stream->caps = gst_caps_make_writable (stream->caps);
gst_caps_set_simple (stream->caps,
@ -5608,59 +5604,6 @@ gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
}
depth = stream->bits_per_sample;
/* more than 32 bits means grayscale */
gray = (depth > 32);
/* low 32 bits specify the depth */
depth &= 0x1F;
/* different number of palette entries is determined by depth. */
palette_count = 0;
if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
palette_count = (1 << depth);
switch (palette_count) {
case 0:
break;
case 2:
palette_data = ff_qt_default_palette_2;
break;
case 4:
palette_data = ff_qt_default_palette_4;
break;
case 16:
if (gray)
palette_data = ff_qt_grayscale_palette_16;
else
palette_data = ff_qt_default_palette_16;
break;
case 256:
if (gray)
palette_data = ff_qt_grayscale_palette_256;
else
palette_data = ff_qt_default_palette_256;
break;
default:
GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
(_("The video in this file might not play correctly.")),
("unsupported palette depth %d", depth));
break;
}
if (palette_data) {
if (stream->rgb8_palette)
gst_memory_unref (stream->rgb8_palette);
stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
(gchar *) palette_data, palette_count * 4, 0, palette_count * 4,
NULL, NULL);
} else if (palette_count != 0) {
GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
(NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
gst_object_unref (stream->pad);
stream->pad = NULL;
}
}
} else if (stream->subtype == FOURCC_soun) {
if (stream->caps) {
@ -6950,7 +6893,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
guint32 tkhd_flags = 0;
guint8 tkhd_version = 0;
guint32 fourcc;
guint value_size, len;
guint value_size, stsd_len, len;
guint32 track_id;
GST_DEBUG_OBJECT (qtdemux, "parse_trak");
@ -7095,19 +7038,21 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stsd_data = (const guint8 *) stsd->data;
/* stsd should at least have one entry */
len = QT_UINT32 (stsd_data);
if (len < 24)
stsd_len = QT_UINT32 (stsd_data);
if (stsd_len < 24)
goto corrupt_file;
GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
/* and that entry should fit within stsd */
len = QT_UINT32 (stsd_data + 16);
if (len > QT_UINT32 (stsd_data) + 16)
if (len > stsd_len + 16)
goto corrupt_file;
GST_LOG_OBJECT (qtdemux, "stsd len: %d", len);
stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (stream->fourcc));
GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
((fourcc & 0xFFFFFF00) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
@ -7115,6 +7060,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
if (stream->subtype == FOURCC_vide) {
guint32 w = 0, h = 0;
gboolean gray;
gint depth, palette_size, palette_count;
guint32 *palette_data = NULL;
stream->sampled = TRUE;
@ -7138,6 +7086,100 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
stream->width, stream->height, stream->bits_per_sample,
stream->color_table_id);
depth = stream->bits_per_sample;
/* more than 32 bits means grayscale */
gray = (depth > 32);
/* low 32 bits specify the depth */
depth &= 0x1F;
/* different number of palette entries is determined by depth. */
palette_count = 0;
if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
palette_count = (1 << depth);
palette_size = palette_count * 4;
if (stream->color_table_id) {
switch (palette_count) {
case 0:
break;
case 2:
palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
break;
case 4:
palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
break;
case 16:
if (gray)
palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
else
palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
break;
case 256:
if (gray)
palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
else
palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
break;
default:
GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
(_("The video in this file might not play correctly.")),
("unsupported palette depth %d", depth));
break;
}
} else {
gint i, j, start, end;
if (len < 94)
goto corrupt_file;
/* read table */
start = QT_UINT32 (stsd_data + offset + 86);
palette_count = QT_UINT16 (stsd_data + offset + 90);
end = QT_UINT16 (stsd_data + offset + 92);
GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
start, end, palette_count);
if (end > 255)
end = 255;
if (start > end)
start = end;
if (len < 94 + (end - start) * 8)
goto corrupt_file;
/* palette is always the same size */
palette_data = g_malloc0 (256 * 4);
palette_size = 256 * 4;
for (j = 0, i = start; i <= end; j++, i++) {
guint32 a, r, g, b;
a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
(g & 0xff00) | (b >> 8);
}
}
if (palette_data) {
if (stream->rgb8_palette)
gst_memory_unref (stream->rgb8_palette);
stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
palette_data, palette_size, 0, palette_size, palette_data, g_free);
} else if (palette_count != 0) {
GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
(NULL), ("Unsupported palette depth %d", depth));
}
GST_LOG_OBJECT (qtdemux, "frame count: %u",
QT_UINT16 (stsd_data + offset + 48));
@ -9997,6 +10039,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
caps = gst_caps_new_empty_simple ("video/x-raw");
gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
_codec ("Windows Raw RGB");
break;
case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
{