mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-18 21:35:44 +00:00
typefinding: improve jpeg typefinder
Make jpeg typefinder check more than just the first two bytes plus Exif or JFIF marker. This allows us to report MAXIMUM probability in cases where there's no Exif or JFIF marker, making typefinding stop early. Also extract width and height, because we can.
This commit is contained in:
parent
2c989ef3a7
commit
95b4de4ed7
1 changed files with 103 additions and 8 deletions
|
@ -111,6 +111,16 @@ data_scan_ctx_ensure_data (GstTypeFind * tf, DataScanCtx * c, gint min_len)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
data_scan_ctx_memcmp (GstTypeFind * tf, DataScanCtx * c, guint offset,
|
||||
const gchar * data, guint len)
|
||||
{
|
||||
if (!data_scan_ctx_ensure_data (tf, c, offset + len))
|
||||
return FALSE;
|
||||
|
||||
return (memcmp (c->data + offset, data, len) == 0);
|
||||
}
|
||||
|
||||
/*** text/plain ***/
|
||||
static gboolean xml_check_first_element (GstTypeFind * tf,
|
||||
const gchar * element, guint elen, gboolean strict);
|
||||
|
@ -2568,24 +2578,109 @@ swf_type_find (GstTypeFind * tf, gpointer unused)
|
|||
|
||||
/*** image/jpeg ***/
|
||||
|
||||
#define JPEG_MARKER_IS_START_OF_FRAME(x) \
|
||||
((x)>=0xc0 && (x) <= 0xcf && (x)!=0xc4 && (x)!=0xc8 && (x)!=0xcc)
|
||||
|
||||
static GstStaticCaps jpeg_caps = GST_STATIC_CAPS ("image/jpeg");
|
||||
|
||||
#define JPEG_CAPS (gst_static_caps_get(&jpeg_caps))
|
||||
static void
|
||||
jpeg_type_find (GstTypeFind * tf, gpointer unused)
|
||||
{
|
||||
guint8 *data = gst_type_find_peek (tf, 0, 10);
|
||||
guint8 header[2] = { 0xFF, 0xD8 };
|
||||
GstTypeFindProbability prob = GST_TYPE_FIND_POSSIBLE;
|
||||
DataScanCtx c = { 0, NULL, 0 };
|
||||
GstCaps *caps;
|
||||
guint num_markers;
|
||||
|
||||
if (data && memcmp (data, header, 2) == 0) {
|
||||
if (memcmp (data + 6, "JFIF", 4) == 0) {
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, JPEG_CAPS);
|
||||
} else if (memcmp (data + 6, "Exif", 4) == 0) {
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, JPEG_CAPS);
|
||||
if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 2)))
|
||||
return;
|
||||
|
||||
if (c.data[0] != 0xff || c.data[1] != 0xd8)
|
||||
return;
|
||||
|
||||
num_markers = 1;
|
||||
data_scan_ctx_advance (tf, &c, 2);
|
||||
|
||||
caps = gst_caps_copy (JPEG_CAPS);
|
||||
|
||||
while (data_scan_ctx_ensure_data (tf, &c, 4) && c.offset < (200 * 1024)) {
|
||||
guint16 len;
|
||||
guint8 marker;
|
||||
|
||||
if (c.data[0] != 0xff)
|
||||
break;
|
||||
|
||||
marker = c.data[1];
|
||||
if (G_UNLIKELY (marker == 0xff)) {
|
||||
data_scan_ctx_advance (tf, &c, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
data_scan_ctx_advance (tf, &c, 2);
|
||||
|
||||
/* we assume all markers we'll see before SOF have a payload length; if
|
||||
* that's not the case we'll just detect a false sync and bail out, but
|
||||
* still report POSSIBLE probability */
|
||||
len = GST_READ_UINT16_BE (c.data);
|
||||
|
||||
GST_LOG ("possible JPEG marker 0x%02x (@0x%04x), segment length %u",
|
||||
marker, c.offset, len);
|
||||
|
||||
if (!data_scan_ctx_ensure_data (tf, &c, len))
|
||||
break;
|
||||
|
||||
if (marker == 0xc4 || /* DEFINE_HUFFMAN_TABLES */
|
||||
marker == 0xcc || /* DEFINE_ARITHMETIC_CONDITIONING */
|
||||
marker == 0xdb || /* DEFINE_QUANTIZATION_TABLES */
|
||||
marker == 0xdd || /* DEFINE_RESTART_INTERVAL */
|
||||
marker == 0xfe) { /* COMMENT */
|
||||
data_scan_ctx_advance (tf, &c, len);
|
||||
++num_markers;
|
||||
} else if (marker == 0xe0 && len >= (2 + 4) && /* APP0 */
|
||||
data_scan_ctx_memcmp (tf, &c, 2, "JFIF", 4)) {
|
||||
GST_LOG ("found JFIF tag");
|
||||
prob = GST_TYPE_FIND_MAXIMUM;
|
||||
data_scan_ctx_advance (tf, &c, len);
|
||||
++num_markers;
|
||||
/* we continue until we find a start of frame marker */
|
||||
} else if (marker == 0xe1 && len >= (2 + 4) && /* APP1 */
|
||||
data_scan_ctx_memcmp (tf, &c, 2, "Exif", 4)) {
|
||||
GST_LOG ("found Exif tag");
|
||||
prob = GST_TYPE_FIND_MAXIMUM;
|
||||
data_scan_ctx_advance (tf, &c, len);
|
||||
++num_markers;
|
||||
/* we continue until we find a start of frame marker */
|
||||
} else if (marker >= 0xe0 && marker <= 0xef) { /* APPn */
|
||||
data_scan_ctx_advance (tf, &c, len);
|
||||
++num_markers;
|
||||
} else if (JPEG_MARKER_IS_START_OF_FRAME (marker) && len >= (2 + 8)) {
|
||||
int h, w;
|
||||
|
||||
h = GST_READ_UINT16_BE (c.data + 2 + 1);
|
||||
w = GST_READ_UINT16_BE (c.data + 2 + 1 + 2);
|
||||
if (h == 0 || w == 0) {
|
||||
GST_WARNING ("bad width %u and/or height %u in SOF header", w, h);
|
||||
break;
|
||||
}
|
||||
|
||||
GST_LOG ("SOF at offset %" G_GUINT64_FORMAT ", num_markers=%d, "
|
||||
"WxH=%dx%d", c.offset - 2, num_markers, w, h);
|
||||
|
||||
if (num_markers >= 5 || prob == GST_TYPE_FIND_MAXIMUM)
|
||||
prob = GST_TYPE_FIND_MAXIMUM;
|
||||
else
|
||||
prob = GST_TYPE_FIND_LIKELY;
|
||||
|
||||
gst_caps_set_simple (caps, "width", G_TYPE_INT, w,
|
||||
"height", G_TYPE_INT, h, NULL);
|
||||
} else {
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, JPEG_CAPS);
|
||||
GST_WARNING ("bad length or unexpected JPEG marker 0xff 0x%02x", marker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gst_type_find_suggest (tf, prob, caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
||||
/*** image/bmp ***/
|
||||
|
|
Loading…
Reference in a new issue